mirror of
https://github.com/KarolS/millfork.git
synced 2024-05-31 18:41:30 +00:00
737 lines
20 KiB
Scala
737 lines
20 KiB
Scala
package millfork.test
|
||
import millfork.Cpu
|
||
import millfork.test.emu.{EmuBenchmarkRun, EmuCmosBenchmarkRun, EmuCrossPlatformBenchmarkRun, EmuUnoptimizedCrossPlatformRun}
|
||
import org.scalatest.{AppendedClues, FunSuite, Matchers}
|
||
|
||
/**
|
||
* @author Karol Stasiak
|
||
*/
|
||
class WordMathSuite extends FunSuite with Matchers with AppendedClues {
|
||
|
||
test("Word addition") {
|
||
EmuCrossPlatformBenchmarkRun(Cpu.Sixteen, Cpu.Mos, Cpu.Z80, Cpu.Intel8080, Cpu.Intel8085, Cpu.Sharp, Cpu.Intel8086)("""
|
||
| word output @$c000
|
||
| word a
|
||
| void main () {
|
||
| a = 640
|
||
| output = a
|
||
| output += a
|
||
| }
|
||
""".stripMargin)(_.readWord(0xc000) should equal(1280))
|
||
}
|
||
|
||
test("Cast word addition") {
|
||
EmuCrossPlatformBenchmarkRun(Cpu.Sixteen, Cpu.Mos, Cpu.Z80, Cpu.Intel8080, Cpu.Intel8085, Cpu.Sharp, Cpu.Intel8086)("""
|
||
| byte output @$c000
|
||
| word a
|
||
| void main () {
|
||
| output = add(155, 166)
|
||
| }
|
||
| byte add(byte a, byte b) {
|
||
| return hi(word(a) + word(b))
|
||
| }
|
||
""".stripMargin)(_.readByte(0xc000) should equal(1))
|
||
}
|
||
|
||
test("Word subtraction") {
|
||
EmuCrossPlatformBenchmarkRun(Cpu.Sixteen, Cpu.Mos, Cpu.Z80, Cpu.Intel8080, Cpu.Intel8085, Cpu.Sharp, Cpu.Intel8086)("""
|
||
| word output @$c000
|
||
| word a
|
||
| void main () {
|
||
| a = 640
|
||
| output = 740
|
||
| output -= a
|
||
| }
|
||
""".stripMargin)(_.readWord(0xc000) should equal(100))
|
||
}
|
||
|
||
test("Word subtraction 2") {
|
||
EmuCrossPlatformBenchmarkRun(Cpu.Sixteen, Cpu.Cmos, Cpu.Z80, Cpu.Intel8080, Cpu.Intel8085, Cpu.Sharp, Cpu.Intel8086)("""
|
||
| word output @$c000
|
||
| word a
|
||
| void main () {
|
||
| a = 640
|
||
| output = a
|
||
| output -= 400
|
||
| }
|
||
""".stripMargin)(_.readWord(0xc000) should equal(240))
|
||
}
|
||
|
||
test("Word subtraction 3") {
|
||
EmuCrossPlatformBenchmarkRun(Cpu.Sixteen, Cpu.Cmos, Cpu.Z80, Cpu.Intel8080, Cpu.Intel8085, Cpu.Sharp, Cpu.Intel8086)("""
|
||
| word output @$c000
|
||
| word a
|
||
| void main () {
|
||
| a = 640
|
||
| f()
|
||
| output = a - f()
|
||
| }
|
||
| word f() {
|
||
| return 400
|
||
| }
|
||
""".stripMargin)(_.readWord(0xc000) should equal(240))
|
||
}
|
||
|
||
test("Byte-to-word addition") {
|
||
EmuCrossPlatformBenchmarkRun(Cpu.Sixteen, Cpu.Mos, Cpu.Z80, Cpu.Intel8080, Cpu.Sharp, Cpu.Intel8086)("""
|
||
| word output @$c000
|
||
| word pair
|
||
| void main () {
|
||
| pair = $A5A5
|
||
| pair.lo = 1
|
||
| output = 640
|
||
| output += pair.lo
|
||
| }
|
||
""".stripMargin)(_.readWord(0xc000) should equal(641))
|
||
}
|
||
|
||
test("Literal addition") {
|
||
EmuCrossPlatformBenchmarkRun(Cpu.Sixteen, Cpu.Sixteen, Cpu.Mos, Cpu.Z80, Cpu.Intel8080, Cpu.Sharp, Cpu.Intel8086)("""
|
||
| word output @$c000
|
||
| void main () {
|
||
| output = 640
|
||
| output += -0050
|
||
| }
|
||
""".stripMargin)(_.readWord(0xc000) should equal(590))
|
||
}
|
||
|
||
test("Array element addition") {
|
||
EmuCrossPlatformBenchmarkRun(Cpu.Sixteen, Cpu.Mos, Cpu.Z80, Cpu.Intel8080, Cpu.Sharp, Cpu.Intel8086)("""
|
||
| word output @$c000
|
||
| word pair
|
||
| array b[2]
|
||
| void main () {
|
||
| byte i
|
||
| i = 1
|
||
| b[1] = 5
|
||
| pair = $A5A5
|
||
| pair.lo = 1
|
||
| output = 640
|
||
| output += b[i]
|
||
| }
|
||
""".stripMargin)(_.readWord(0xc000) should equal(645))
|
||
}
|
||
|
||
test("nesdev.com example") {
|
||
EmuCrossPlatformBenchmarkRun(Cpu.Sixteen, Cpu.Mos, Cpu.Z80, Cpu.Intel8080, Cpu.Sharp, Cpu.Intel8086)("""
|
||
| byte output @$c000
|
||
| byte tile @$C3A6
|
||
| array map [256] @$c300
|
||
| array b[2]
|
||
| void main () {
|
||
| tile = 77
|
||
| output = get(5, 6)
|
||
| }
|
||
| byte get(byte mx, byte my) {
|
||
| pointer p
|
||
| p = mx
|
||
| p <<= 5
|
||
| p += map
|
||
| return p[my]
|
||
| }
|
||
""".stripMargin) { m =>
|
||
m.readByte(0xc3a6) should equal(77)
|
||
}
|
||
}
|
||
|
||
test("nesdev.com example 2") {
|
||
EmuCrossPlatformBenchmarkRun(Cpu.Sixteen, Cpu.Mos, Cpu.Z80, Cpu.Intel8080, Cpu.Sharp, Cpu.Intel8086)("""
|
||
| byte output @$c000
|
||
| byte tile @$C3A6
|
||
| array map [256] @$c300
|
||
| array b[2]
|
||
| void main () {
|
||
| tile = 77
|
||
| output = get(5, 6)
|
||
| }
|
||
| byte get(byte mx, byte my) {
|
||
| return map[(word(mx) << 5) + my]
|
||
| }
|
||
""".stripMargin){ m =>
|
||
m.readByte(0xc3a6) should equal(77)
|
||
}
|
||
}
|
||
|
||
test("hi()/lo()") {
|
||
EmuCrossPlatformBenchmarkRun(Cpu.Sixteen, Cpu.Mos, Cpu.Z80, Cpu.Intel8080, Cpu.Sharp, Cpu.Intel8086)("""
|
||
| array output [7] @$c000
|
||
| void main () {
|
||
| output[0] = lo(33)
|
||
| output[1] = hi(33)
|
||
| output[2] = hi(w($504))
|
||
| output[3] = lo(w($209))
|
||
| output[4] = hi(s(-2))
|
||
| output[5] = lo(s(-2))
|
||
| output[6] = hi(b(200) + b(200))
|
||
| }
|
||
| word w(word w) {
|
||
| return w
|
||
| }
|
||
| byte b(byte b) {
|
||
| return b
|
||
| }
|
||
| sbyte s(sbyte s) {
|
||
| return s
|
||
| }
|
||
""".stripMargin){ m =>
|
||
m.readByte(0xc000) should equal(33)
|
||
m.readByte(0xc001) should equal(0)
|
||
m.readByte(0xc002) should equal(5)
|
||
m.readByte(0xc003) should equal(9)
|
||
m.readByte(0xc004) should equal(255)
|
||
m.readByte(0xc005) should equal(254)
|
||
m.readByte(0xc006) should equal(0)
|
||
}
|
||
}
|
||
|
||
test("Word addition 2") {
|
||
EmuCrossPlatformBenchmarkRun(Cpu.Sixteen, Cpu.Mos, Cpu.Z80, Cpu.Intel8080, Cpu.Sharp, Cpu.Intel8086)("""
|
||
| word output @$c000
|
||
| void main () {
|
||
| word v
|
||
| v = w($482)
|
||
| output = v + w($482) - 3
|
||
| }
|
||
| noinline word w(word w) {
|
||
| return w
|
||
| }
|
||
""".stripMargin){ m =>
|
||
m.readWord(0xc000) should equal(0x901)
|
||
}
|
||
}
|
||
|
||
test("Word addition 3") {
|
||
EmuCrossPlatformBenchmarkRun(Cpu.Sixteen, Cpu.Mos, Cpu.Z80, Cpu.Intel8080, Cpu.Sharp, Cpu.Intel8086)("""
|
||
| word output @$c000
|
||
| void main () {
|
||
| byte c
|
||
| c = b($82)
|
||
| output = $482 + c
|
||
| }
|
||
| noinline byte b(byte b) {
|
||
| return b
|
||
| }
|
||
""".stripMargin){ m =>
|
||
m.readWord(0xc000) should equal(0x504)
|
||
}
|
||
}
|
||
|
||
test("Word addition 4") {
|
||
EmuCrossPlatformBenchmarkRun(Cpu.Sixteen, Cpu.Mos, Cpu.Z80, Cpu.Intel8080, Cpu.Sharp, Cpu.Intel8086)("""
|
||
| word output @$c000
|
||
| void main () {
|
||
| word v
|
||
| word u
|
||
| v = w($308)
|
||
| u = w($601)
|
||
| barrier()
|
||
| output = u + v
|
||
| }
|
||
| noinline void barrier() { }
|
||
| noinline word w(word w) {
|
||
| return w
|
||
| }
|
||
""".stripMargin){ m =>
|
||
m.readWord(0xc000) should equal(0x909)
|
||
}
|
||
}
|
||
|
||
test("Word addition 5") {
|
||
EmuCrossPlatformBenchmarkRun(Cpu.Mos, Cpu.Sixteen, Cpu.Z80, Cpu.Intel8080, Cpu.Sharp, Cpu.Intel8086)("""
|
||
| word output @$c000
|
||
| void main () {
|
||
| word v
|
||
| word u
|
||
| v = $308
|
||
| output = $102
|
||
| barrier()
|
||
| output = (output.lo:output.hi) + v
|
||
| }
|
||
| noinline void barrier() { }
|
||
""".stripMargin){ m =>
|
||
m.readWord(0xc000) should equal(0x509)
|
||
}
|
||
}
|
||
|
||
test("Word bit ops 2") {
|
||
EmuCrossPlatformBenchmarkRun(Cpu.Sixteen, Cpu.Mos, Cpu.Z80, Cpu.Intel8080, Cpu.Sharp, Cpu.Intel8086)("""
|
||
| word output @$c000
|
||
| void main () {
|
||
| word v
|
||
| v = w($692)
|
||
| output = (v & w($ca2)) | 3
|
||
| }
|
||
| noinline word w(word w) {
|
||
| return w
|
||
| }
|
||
""".stripMargin){ m =>
|
||
m.readWord(0xc000) should equal(0x483)
|
||
}
|
||
}
|
||
|
||
test("Word shift") {
|
||
EmuCrossPlatformBenchmarkRun(Cpu.Sixteen, Cpu.Mos, Cpu.Z80, Cpu.Intel8080, Cpu.Sharp, Cpu.Intel8086)("""
|
||
| word output @$c000
|
||
| void main () {
|
||
| word v
|
||
| v = w($123)
|
||
| barrier()
|
||
| output = v << 1
|
||
| }
|
||
| noinline void barrier() { }
|
||
| noinline word w(word w) {
|
||
| return w
|
||
| }
|
||
""".stripMargin){ m =>
|
||
m.readWord(0xc000) should equal(0x246)
|
||
}
|
||
}
|
||
|
||
test("Word shift 2") {
|
||
EmuCrossPlatformBenchmarkRun(Cpu.Sixteen, Cpu.Mos, Cpu.Z80, Cpu.Intel8080, Cpu.Sharp, Cpu.Intel8086)("""
|
||
| word output @$c000
|
||
| void main () {
|
||
| output = five()
|
||
| output <<= 5
|
||
| }
|
||
| noinline byte five() {
|
||
| return 5
|
||
| }
|
||
""".stripMargin){ m =>
|
||
m.readWord(0xc000) should equal(5 * 32)
|
||
}
|
||
}
|
||
|
||
test("Word shift 3") {
|
||
EmuCrossPlatformBenchmarkRun(Cpu.Sixteen, Cpu.Mos, Cpu.Z80, Cpu.Intel8080, Cpu.Sharp, Cpu.Intel8086)("""
|
||
| word output @$c000
|
||
| void main () {
|
||
| output = five()
|
||
| output <<= 8
|
||
| }
|
||
| noinline byte five() {
|
||
| return 5
|
||
| }
|
||
""".stripMargin){ m =>
|
||
m.readWord(0xc000) should equal(5 * 256)
|
||
}
|
||
}
|
||
|
||
test("Word shift 4") {
|
||
EmuCrossPlatformBenchmarkRun(Cpu.Sixteen, Cpu.Mos, Cpu.Z80, Cpu.Intel8080, Cpu.Sharp, Cpu.Intel8086)("""
|
||
| word output @$c000
|
||
| void main () {
|
||
| output = five()
|
||
| output <<= 7
|
||
| }
|
||
| noinline byte five() {
|
||
| return 5
|
||
| }
|
||
""".stripMargin){ m =>
|
||
m.readWord(0xc000) should equal(5 * 128)
|
||
}
|
||
}
|
||
|
||
test("Word shift 5") {
|
||
EmuCrossPlatformBenchmarkRun(Cpu.Sixteen, Cpu.Mos, Cpu.Z80, Cpu.Intel8080, Cpu.Sharp, Cpu.Intel8086)("""
|
||
| word output @$c000
|
||
| void main () {
|
||
| output = five()
|
||
| output <<= 1
|
||
| output >>= 1
|
||
| }
|
||
| noinline byte five() {
|
||
| return 5
|
||
| }
|
||
""".stripMargin){ m =>
|
||
m.readWord(0xc000) should equal(5)
|
||
}
|
||
}
|
||
|
||
test("Word multiplication 5") {
|
||
EmuCrossPlatformBenchmarkRun(Cpu.Sixteen, Cpu.Mos, Cpu.Z80, Cpu.Intel8080, Cpu.Sharp, Cpu.Intel8086)("""
|
||
| word output @$c000
|
||
| void main () {
|
||
| output = alot()
|
||
| output *= five()
|
||
| }
|
||
| noinline word alot() {
|
||
| return 4532
|
||
| }
|
||
| noinline byte five() {
|
||
| return 5
|
||
| }
|
||
| import zp_reg
|
||
""".stripMargin){ m =>
|
||
m.readWord(0xc000) should equal(4532 * 5)
|
||
}
|
||
}
|
||
|
||
test("Word multiplication optimization") {
|
||
EmuCrossPlatformBenchmarkRun(Cpu.Mos, Cpu.Intel8080, Cpu.Sharp, Cpu.Intel8086)("""
|
||
| word output @$c000
|
||
| void main () {
|
||
| output = alot()
|
||
| output *= two()
|
||
| output *= four()
|
||
| }
|
||
| noinline word alot() {
|
||
| return 4532
|
||
| }
|
||
| inline byte four() {
|
||
| return 4
|
||
| }
|
||
| inline byte two() {
|
||
| return 2
|
||
| }
|
||
| import zp_reg
|
||
""".stripMargin){ m =>
|
||
m.readWord(0xc000) should equal(4532 * 8)
|
||
}
|
||
}
|
||
|
||
test("In-place word/byte multiplication") {
|
||
multiplyCase1(0, 0)
|
||
multiplyCase1(0, 1)
|
||
multiplyCase1(0, 2)
|
||
multiplyCase1(0, 5)
|
||
multiplyCase1(1, 0)
|
||
multiplyCase1(5, 0)
|
||
multiplyCase1(7, 0)
|
||
multiplyCase1(2, 5)
|
||
multiplyCase1(7, 2)
|
||
multiplyCase1(100, 2)
|
||
multiplyCase1(1000, 2)
|
||
multiplyCase1(54, 4)
|
||
multiplyCase1(2, 100)
|
||
multiplyCase1(500, 50)
|
||
multiplyCase1(4, 54)
|
||
}
|
||
|
||
private def multiplyCase1(x: Int, y: Int): Unit = {
|
||
EmuCrossPlatformBenchmarkRun(Cpu.Sixteen, Cpu.Mos, Cpu.Z80, Cpu.Intel8086)(
|
||
s"""
|
||
| import zp_reg
|
||
| word output @$$c000
|
||
| void main () {
|
||
| output = $x
|
||
| output *= $y
|
||
| }
|
||
""".
|
||
stripMargin)(_.readWord(0xc000) should equal(x * y) withClue s"= $x * $y")
|
||
}
|
||
|
||
test("Not-in-place word/byte multiplication") {
|
||
multiplyCase2(0, 0)
|
||
multiplyCase2(0, 1)
|
||
multiplyCase2(0, 2)
|
||
multiplyCase2(0, 5)
|
||
multiplyCase2(1, 0)
|
||
multiplyCase2(5, 0)
|
||
multiplyCase2(7, 0)
|
||
multiplyCase2(2, 5)
|
||
multiplyCase2(7, 2)
|
||
multiplyCase2(100, 2)
|
||
multiplyCase2(1000, 2)
|
||
multiplyCase2(54, 4)
|
||
multiplyCase2(2, 100)
|
||
multiplyCase2(500, 50)
|
||
multiplyCase2(4, 54)
|
||
multiplyCase2(1, 10)
|
||
multiplyCase2(12, 10)
|
||
multiplyCase2(123, 10)
|
||
multiplyCase2(1234, 10)
|
||
}
|
||
|
||
private def multiplyCase2(x: Int, y: Int): Unit = {
|
||
EmuCrossPlatformBenchmarkRun(Cpu.Mos, Cpu.Z80, Cpu.Intel8086)(
|
||
s"""
|
||
| import zp_reg
|
||
| word output1 @$$c000
|
||
| word output2 @$$c004
|
||
| word tmp
|
||
| noinline void init() {
|
||
| tmp = $x
|
||
| }
|
||
| void main () {
|
||
| init()
|
||
| output1 = $y * tmp
|
||
| output2 = tmp * $y
|
||
| }
|
||
""".
|
||
stripMargin) { m =>
|
||
m.readWord(0xc000) should equal(x * y) withClue s"= $y * $x"
|
||
m.readWord(0xc004) should equal(x * y) withClue s"= $x * $y"
|
||
}
|
||
}
|
||
|
||
test("Word division 1") {
|
||
divisionCase1(0, 1)
|
||
divisionCase1(1, 1)
|
||
divisionCase1(1, 5)
|
||
divisionCase1(6, 5)
|
||
divisionCase1(420, 11)
|
||
divisionCase1(1210, 11)
|
||
divisionCase1(35000, 45)
|
||
divisionCase1(127, 127)
|
||
divisionCase1(128, 127)
|
||
divisionCase1(51462, 1)
|
||
}
|
||
|
||
test("Word division 1 – large divisor") {
|
||
divisionCase1(127, 128)
|
||
divisionCase1(128, 128)
|
||
divisionCase1(45323, 250)
|
||
divisionCase1(4530, 200)
|
||
divisionCase1(9039, 247)
|
||
}
|
||
|
||
private def divisionCase1(x: Int, y: Int): Unit = {
|
||
EmuCrossPlatformBenchmarkRun(Cpu.Mos /*,Cpu.Z80, Cpu.Intel8080, Cpu.Sharp, Cpu.Intel8086*/)(
|
||
s"""
|
||
| import zp_reg
|
||
| word output_q1 @$$c000
|
||
| word output_m1 @$$c002
|
||
| word output_q2 @$$c004
|
||
| word output_m2 @$$c006
|
||
| void main () {
|
||
| word a
|
||
| a = f()
|
||
| output_q1 = a / $y
|
||
| output_m1 = a %% $y
|
||
| output_q2 = a
|
||
| output_m2 = a
|
||
| output_q2 /= $y
|
||
| output_m2 %%= $y
|
||
| }
|
||
| word f() = $x
|
||
""".
|
||
stripMargin) { m =>
|
||
m.readWord(0xc000) should equal(x / y) withClue s"= $x / $y"
|
||
m.readWord(0xc002) should equal(x % y) withClue s"= $x %% $y"
|
||
m.readWord(0xc004) should equal(x / y) withClue s"= $x / $y"
|
||
m.readWord(0xc006) should equal(x % y) withClue s"= $x %% $y"
|
||
}
|
||
}
|
||
|
||
test("Word division 2") {
|
||
divisionCase2(0, 1)
|
||
divisionCase2(1, 1)
|
||
divisionCase2(2, 1)
|
||
divisionCase2(250, 1)
|
||
divisionCase2(0, 3)
|
||
divisionCase2(0, 5)
|
||
divisionCase2(1, 5)
|
||
divisionCase2(6, 5)
|
||
divisionCase2(73, 5)
|
||
divisionCase2(73, 8)
|
||
divisionCase2(127, 127)
|
||
divisionCase2(128, 127)
|
||
divisionCase2(75, 5)
|
||
divisionCase2(42, 11)
|
||
divisionCase2(420, 11)
|
||
divisionCase2(1210, 11)
|
||
divisionCase2(35000, 45)
|
||
divisionCase2(35000, 2)
|
||
divisionCase2(51462, 3)
|
||
divisionCase2(51462, 1)
|
||
}
|
||
|
||
test("Word division 2 – large divisor") {
|
||
divisionCase2(127, 128)
|
||
divisionCase2(128, 128)
|
||
divisionCase2(45323, 250)
|
||
divisionCase2(4530, 200)
|
||
divisionCase2(9039, 247)
|
||
}
|
||
|
||
private def divisionCase2(x: Int, y: Int): Unit = {
|
||
EmuCrossPlatformBenchmarkRun(Cpu.Mos, Cpu.Z80, Cpu.Intel8080, Cpu.Sharp, Cpu.Intel8086)(
|
||
s"""
|
||
| import zp_reg
|
||
| word output_q1 @$$c000
|
||
| word output_m1 @$$c002
|
||
| word output_q2 @$$c004
|
||
| word output_m2 @$$c006
|
||
| void main () {
|
||
| word a
|
||
| byte b
|
||
| a = f()
|
||
| b = g()
|
||
| output_q1 = a / b
|
||
| output_m1 = a %% b
|
||
| output_q2 = a
|
||
| output_m2 = a
|
||
| output_q2 /= b
|
||
| output_m2 %%= b
|
||
| }
|
||
| word f() = $x
|
||
| noinline byte g() = $y
|
||
""".
|
||
stripMargin) { m =>
|
||
m.readWord(0xc000) should equal(x / y) withClue s"= $x / $y"
|
||
m.readWord(0xc002) should equal(x % y) withClue s"= $x %% $y"
|
||
m.readWord(0xc004) should equal(x / y) withClue s"= $x / $y"
|
||
m.readWord(0xc006) should equal(x % y) withClue s"= $x %% $y"
|
||
}
|
||
}
|
||
|
||
test("Word division 4") {
|
||
divisionCase4(0, 2)
|
||
divisionCase4(1, 2)
|
||
divisionCase4(2, 2)
|
||
divisionCase4(250, 128)
|
||
divisionCase4(0, 4)
|
||
divisionCase4(0, 8)
|
||
divisionCase4(1, 4)
|
||
divisionCase4(6, 8)
|
||
divisionCase4(73, 16)
|
||
divisionCase4(2534, 2)
|
||
divisionCase4(2534, 32)
|
||
divisionCase4(35000, 2)
|
||
divisionCase4(51462, 4)
|
||
divisionCase4(51462, 1)
|
||
}
|
||
|
||
test("Word division 4 – large divisor") {
|
||
divisionCase4(75, 128)
|
||
divisionCase4(42, 128)
|
||
divisionCase4(142, 128)
|
||
divisionCase4(9039, 247)
|
||
}
|
||
|
||
private def divisionCase4(x: Int, y: Int): Unit = {
|
||
EmuCrossPlatformBenchmarkRun(Cpu.Mos, Cpu.Z80, Cpu.Intel8080, Cpu.Sharp, Cpu.Intel8086)(
|
||
s"""
|
||
| import zp_reg
|
||
| word output_q1 @$$c000
|
||
| byte output_m1 @$$c002
|
||
| word output_q2 @$$c004
|
||
| word output_m2 @$$c006
|
||
| void main () {
|
||
| byte a
|
||
| output_q2 = g()
|
||
| output_m2 = g()
|
||
| a = f()
|
||
| output_q1 = $x / a
|
||
| output_m1 = $x %% a
|
||
| output_q2 /= a
|
||
| output_m2 %%= a
|
||
| }
|
||
| byte f() {return $y}
|
||
| noinline word g() {return $x}
|
||
""".
|
||
stripMargin) { m =>
|
||
m.readWord(0xc000) should equal(x / y) withClue s"= $x / $y"
|
||
m.readByte(0xc002) should equal(x % y) withClue s"= $x %% $y"
|
||
m.readWord(0xc004) should equal(x / y) withClue s"= $x / $y"
|
||
m.readByte(0xc006) should equal(x % y) withClue s"= $x %% $y"
|
||
}
|
||
}
|
||
|
||
test("Word/word multiplication 1") {
|
||
multiplyCaseWW1(0, 0)
|
||
multiplyCaseWW1(0, 5)
|
||
multiplyCaseWW1(7, 0)
|
||
multiplyCaseWW1(2, 5)
|
||
multiplyCaseWW1(7, 2)
|
||
multiplyCaseWW1(100, 2)
|
||
multiplyCaseWW1(1000, 2)
|
||
multiplyCaseWW1(2, 1000)
|
||
multiplyCaseWW1(1522, 1000)
|
||
multiplyCaseWW1(54, 4)
|
||
multiplyCaseWW1(35000, 9)
|
||
multiplyCaseWW1(43, 35000)
|
||
multiplyCaseWW1(53459, 48233)
|
||
}
|
||
|
||
private def multiplyCaseWW1(x: Int, y: Int): Unit = {
|
||
EmuUnoptimizedCrossPlatformRun(Cpu.Mos, Cpu.Z80, Cpu.Intel8080)(
|
||
s"""
|
||
| import zp_reg
|
||
| word output0 @$$c000
|
||
| word output1 @$$c002
|
||
| word output2 @$$c004
|
||
| void main () {
|
||
| output0 = $x
|
||
| output0 *= word($y)
|
||
| output1 = id($x) * id($y)
|
||
| }
|
||
| noinline word id(word w) = w
|
||
""".
|
||
stripMargin){m =>
|
||
m.readWord(0xc000) should equal((x * y) & 0xffff) withClue s"= $x * $y (c000)"
|
||
m.readWord(0xc002) should equal((x * y) & 0xffff) withClue s"= $x * $y (c002)"
|
||
}
|
||
}
|
||
|
||
test("Word/word division 1") {
|
||
divisionCaseWW1(0, 1)
|
||
divisionCaseWW1(0, 1000)
|
||
divisionCaseWW1(1, 1000)
|
||
divisionCaseWW1(1, 1)
|
||
divisionCaseWW1(1000, 1)
|
||
divisionCaseWW1(1000, 1000)
|
||
divisionCaseWW1(1000, 33)
|
||
divisionCaseWW1(33000, 999)
|
||
divisionCaseWW1(33000, 256)
|
||
divisionCaseWW1(33000, 16)
|
||
divisionCaseWW1(33000, 1024)
|
||
}
|
||
|
||
private def divisionCaseWW1(x: Int, y: Int): Unit = {
|
||
EmuUnoptimizedCrossPlatformRun(Cpu.Mos, Cpu.Z80, Cpu.Intel8080, Cpu.Sharp)(
|
||
s"""
|
||
| import zp_reg
|
||
| word output0 @$$c000
|
||
| word output1 @$$c002
|
||
| void main () {
|
||
| output0 = $x
|
||
| memory_barrier()
|
||
| output0 /= word($y)
|
||
| output1 = $x
|
||
| memory_barrier()
|
||
| output1 %%= word($y)
|
||
| }
|
||
| noinline word id(word w) = w
|
||
""".
|
||
stripMargin){m =>
|
||
m.readWord(0xc000) should equal((x / y) & 0xffff) withClue s"= $x / $y (c000)"
|
||
m.readWord(0xc002) should equal((x % y) & 0xffff) withClue s"= $x %% $y (c002)"
|
||
}
|
||
}
|
||
|
||
test("Sign extension in subtraction") {
|
||
for {
|
||
i <- Seq(5324, 6453, 1500)
|
||
j <- Seq(0, 1, -1, -3, -7, -128, 127)
|
||
// i <- Seq(5324)
|
||
// j <- Seq(-1)
|
||
} {
|
||
EmuUnoptimizedCrossPlatformRun(/*Cpu.Mos, */Cpu.Z80)(
|
||
s"""
|
||
| word output0 @$$c000
|
||
| word output1 @$$c002
|
||
| word output2 @$$c004
|
||
| void main () {
|
||
| sbyte tmp
|
||
| output0 = $i
|
||
| output2 = $i
|
||
| tmp = $j
|
||
| memory_barrier()
|
||
| output1 = output0 - sbyte(${j&0xff})
|
||
| memory_barrier()
|
||
| output0 -= sbyte(${j&0xff})
|
||
| output2 -= tmp
|
||
| }
|
||
| noinline word id(word w) = w
|
||
""".
|
||
stripMargin){m =>
|
||
m.readWord(0xc000) should equal((i - j) & 0xffff) withClue s"= $i - $j (c000)"
|
||
m.readWord(0xc002) should equal((i - j) & 0xffff) withClue s"= $i - $j (c002)"
|
||
m.readWord(0xc004) should equal((i - j) & 0xffff) withClue s"= $i - $j (c004)"
|
||
}
|
||
}
|
||
}
|
||
}
|