mirror of
				https://github.com/irmen/prog8.git
				synced 2025-10-31 15:16:13 +00:00 
			
		
		
		
	
		
			
				
	
	
		
			564 lines
		
	
	
		
			23 KiB
		
	
	
	
		
			Kotlin
		
	
	
	
	
	
			
		
		
	
	
			564 lines
		
	
	
		
			23 KiB
		
	
	
	
		
			Kotlin
		
	
	
	
	
	
| import io.kotest.core.spec.style.FunSpec
 | |
| import io.kotest.matchers.ints.shouldBeGreaterThan
 | |
| import io.kotest.matchers.shouldBe
 | |
| import prog8.code.SymbolTableMaker
 | |
| import prog8.code.ast.*
 | |
| import prog8.code.core.*
 | |
| import prog8.code.source.SourceCode
 | |
| import prog8.code.target.VMTarget
 | |
| import prog8.codegen.vm.VmAssemblyProgram
 | |
| import prog8.codegen.vm.VmCodeGen
 | |
| import prog8.intermediate.IRSubroutine
 | |
| import prog8.intermediate.Opcode
 | |
| 
 | |
| class TestVmCodeGen: FunSpec({
 | |
| 
 | |
|     fun getTestOptions(): CompilationOptions {
 | |
|         val target = VMTarget()
 | |
|         return CompilationOptions(
 | |
|             OutputType.RAW,
 | |
|             CbmPrgLauncherType.NONE,
 | |
|             ZeropageType.DONTUSE,
 | |
|             zpReserved = emptyList(),
 | |
|             zpAllowed = CompilationOptions.AllZeropageAllowed,
 | |
|             floats = true,
 | |
|             noSysInit = false,
 | |
|             compTarget = target,
 | |
|             loadAddress = target.machine.PROGRAM_LOAD_ADDRESS,
 | |
|             memtopAddress = 0xffffu
 | |
|         )
 | |
|     }
 | |
| 
 | |
|     test("augmented assigns") {
 | |
| //main {
 | |
| //    sub start() {
 | |
| //        ubyte[] particleX = [1,2,3]
 | |
| //        ubyte[] particleDX = [1,2,3]
 | |
| //        particleX[2] += particleDX[2]
 | |
| //
 | |
| //        word @shared xx = 1
 | |
| //        xx = -xx
 | |
| //        xx += 42
 | |
| //        xx += cx16.r0
 | |
| //    }
 | |
| //}
 | |
|         val codegen = VmCodeGen()
 | |
|         val program = PtProgram("test", DummyMemsizer, DummyStringEncoder)
 | |
|         val block = PtBlock("main", false, SourceCode.Generated("test"), PtBlock.Options(), Position.DUMMY)
 | |
|         val sub = PtSub("start", emptyList(), null, Position.DUMMY)
 | |
|         sub.add(PtVariable(
 | |
|             "pi",
 | |
|             DataType.forDt(BaseDataType.UBYTE),
 | |
|             ZeropageWish.DONTCARE,
 | |
|             0u,
 | |
|             PtNumber(BaseDataType.UBYTE, 0.0, Position.DUMMY),
 | |
|             null,
 | |
|             Position.DUMMY
 | |
|         ))
 | |
|         sub.add(PtVariable(
 | |
|             "particleX",
 | |
|             DataType.arrayFor(BaseDataType.UBYTE),
 | |
|             ZeropageWish.DONTCARE,
 | |
|             0u,
 | |
|             null,
 | |
|             3u,
 | |
|             Position.DUMMY
 | |
|         ))
 | |
|         sub.add(PtVariable(
 | |
|             "particleDX",
 | |
|             DataType.arrayFor(BaseDataType.UBYTE),
 | |
|             ZeropageWish.DONTCARE,
 | |
|             0u,
 | |
|             null,
 | |
|             3u,
 | |
|             Position.DUMMY
 | |
|         ))
 | |
|         sub.add(PtVariable(
 | |
|             "xx",
 | |
|             DataType.forDt(BaseDataType.WORD),
 | |
|             ZeropageWish.DONTCARE,
 | |
|             0u,
 | |
|             PtNumber(BaseDataType.WORD, 1.0, Position.DUMMY),
 | |
|             null,
 | |
|             Position.DUMMY
 | |
|         ))
 | |
| 
 | |
|         val assign = PtAugmentedAssign("+=", Position.DUMMY)
 | |
|         val target = PtAssignTarget(false, Position.DUMMY).also {
 | |
|             val targetIdx = PtArrayIndexer(DataType.forDt(BaseDataType.UBYTE), Position.DUMMY).also { idx ->
 | |
|                 idx.add(PtIdentifier("main.start.particleX",
 | |
|                     DataType.arrayFor(BaseDataType.UBYTE),
 | |
|                     Position.DUMMY))
 | |
|                 idx.add(PtNumber(BaseDataType.UBYTE, 2.0, Position.DUMMY))
 | |
|             }
 | |
|             it.add(targetIdx)
 | |
|         }
 | |
|         val value = PtArrayIndexer(DataType.forDt(BaseDataType.UBYTE), Position.DUMMY)
 | |
|         value.add(PtIdentifier("main.start.particleDX",
 | |
|             DataType.arrayFor(BaseDataType.UBYTE),
 | |
|             Position.DUMMY))
 | |
|         value.add(PtNumber(BaseDataType.UBYTE, 2.0, Position.DUMMY))
 | |
|         assign.add(target)
 | |
|         assign.add(value)
 | |
|         sub.add(assign)
 | |
| 
 | |
|         val prefixAssign = PtAugmentedAssign("-", Position.DUMMY)
 | |
|         val prefixTarget = PtAssignTarget(false, Position.DUMMY).also {
 | |
|             it.add(PtIdentifier("main.start.xx", DataType.forDt(BaseDataType.WORD), Position.DUMMY))
 | |
|         }
 | |
|         prefixAssign.add(prefixTarget)
 | |
|         prefixAssign.add(PtIdentifier("main.start.xx", DataType.forDt(BaseDataType.WORD), Position.DUMMY))
 | |
|         sub.add(prefixAssign)
 | |
| 
 | |
|         val numberAssign = PtAugmentedAssign("+=", Position.DUMMY)
 | |
|         val numberAssignTarget = PtAssignTarget(false, Position.DUMMY).also {
 | |
|             it.add(PtIdentifier("main.start.xx", DataType.forDt(BaseDataType.WORD), Position.DUMMY))
 | |
|         }
 | |
|         numberAssign.add(numberAssignTarget)
 | |
|         numberAssign.add(PtNumber(BaseDataType.WORD, 42.0, Position.DUMMY))
 | |
|         sub.add(numberAssign)
 | |
| 
 | |
|         val cxregAssign = PtAugmentedAssign("+=", Position.DUMMY)
 | |
|         val cxregAssignTarget = PtAssignTarget(false, Position.DUMMY).also {
 | |
|             it.add(PtIdentifier("main.start.xx", DataType.forDt(BaseDataType.WORD), Position.DUMMY))
 | |
|         }
 | |
|         cxregAssign.add(cxregAssignTarget)
 | |
|         cxregAssign.add(PtIdentifier("cx16.r0", DataType.forDt(BaseDataType.UWORD), Position.DUMMY))
 | |
|         sub.add(cxregAssign)
 | |
| 
 | |
|         block.add(sub)
 | |
|         program.add(block)
 | |
| 
 | |
|         // define the "cx16.r0" virtual register
 | |
|         val cx16block = PtBlock("cx16", false, SourceCode.Generated("test"), PtBlock.Options(), Position.DUMMY)
 | |
|         cx16block.add(PtMemMapped("r0", DataType.forDt(BaseDataType.UWORD), 100u, null, Position.DUMMY))
 | |
|         program.add(cx16block)
 | |
| 
 | |
|         val options = getTestOptions()
 | |
|         val st = SymbolTableMaker(program, options).make()
 | |
|         val errors = ErrorReporterForTests()
 | |
|         val result = codegen.generate(program, st, options, errors) as VmAssemblyProgram
 | |
|         val irChunks = (result.irProgram.blocks.first().children.single() as IRSubroutine).chunks
 | |
|         irChunks.size shouldBe 1
 | |
|     }
 | |
| 
 | |
|     test("float comparison expressions against zero") {
 | |
| //main {
 | |
| //    sub start() {
 | |
| //        float @shared f1
 | |
| //
 | |
| //        if f1==0
 | |
| //            nop
 | |
| //        if f1!=0
 | |
| //            nop
 | |
| //        if f1>0
 | |
| //            nop
 | |
| //        if f1<0
 | |
| //            nop
 | |
| //    }
 | |
| //}
 | |
|         val codegen = VmCodeGen()
 | |
|         val program = PtProgram("test", DummyMemsizer, DummyStringEncoder)
 | |
|         val block = PtBlock("main", false, SourceCode.Generated("test"), PtBlock.Options(), Position.DUMMY)
 | |
|         val sub = PtSub("start", emptyList(), null, Position.DUMMY)
 | |
|         sub.add(PtVariable(
 | |
|             "f1",
 | |
|             DataType.forDt(BaseDataType.FLOAT),
 | |
|             ZeropageWish.DONTCARE,
 | |
|             0u,
 | |
|             null,
 | |
|             null,
 | |
|             Position.DUMMY
 | |
|         ))
 | |
|         val if1 = PtIfElse(Position.DUMMY)
 | |
|         val cmp1 = PtBinaryExpression("==", DataType.forDt(BaseDataType.BOOL), Position.DUMMY)
 | |
|         cmp1.add(PtIdentifier("main.start.f1", DataType.forDt(BaseDataType.FLOAT), Position.DUMMY))
 | |
|         cmp1.add(PtNumber(BaseDataType.FLOAT, 0.0, Position.DUMMY))
 | |
|         if1.add(cmp1)
 | |
|         if1.add(PtNodeGroup().also { it.add(PtNop(Position.DUMMY)) })
 | |
|         if1.add(PtNodeGroup().also { it.add(PtNop(Position.DUMMY)) })
 | |
|         sub.add(if1)
 | |
|         val if2 = PtIfElse(Position.DUMMY)
 | |
|         val cmp2 = PtBinaryExpression("!=", DataType.forDt(BaseDataType.BOOL), Position.DUMMY)
 | |
|         cmp2.add(PtIdentifier("main.start.f1", DataType.forDt(BaseDataType.FLOAT), Position.DUMMY))
 | |
|         cmp2.add(PtNumber(BaseDataType.FLOAT, 0.0, Position.DUMMY))
 | |
|         if2.add(cmp2)
 | |
|         if2.add(PtNodeGroup().also { it.add(PtNop(Position.DUMMY)) })
 | |
|         if2.add(PtNodeGroup().also { it.add(PtNop(Position.DUMMY)) })
 | |
|         sub.add(if2)
 | |
|         val if3 = PtIfElse(Position.DUMMY)
 | |
|         val cmp3 = PtBinaryExpression("<", DataType.forDt(BaseDataType.BOOL), Position.DUMMY)
 | |
|         cmp3.add(PtIdentifier("main.start.f1", DataType.forDt(BaseDataType.FLOAT), Position.DUMMY))
 | |
|         cmp3.add(PtNumber(BaseDataType.FLOAT, 0.0, Position.DUMMY))
 | |
|         if3.add(cmp3)
 | |
|         if3.add(PtNodeGroup().also { it.add(PtNop(Position.DUMMY)) })
 | |
|         if3.add(PtNodeGroup().also { it.add(PtNop(Position.DUMMY)) })
 | |
|         sub.add(if3)
 | |
|         val if4 = PtIfElse(Position.DUMMY)
 | |
|         val cmp4 = PtBinaryExpression(">", DataType.forDt(BaseDataType.BOOL), Position.DUMMY)
 | |
|         cmp4.add(PtIdentifier("main.start.f1", DataType.forDt(BaseDataType.FLOAT), Position.DUMMY))
 | |
|         cmp4.add(PtNumber(BaseDataType.FLOAT, 0.0, Position.DUMMY))
 | |
|         if4.add(cmp4)
 | |
|         if4.add(PtNodeGroup().also { it.add(PtNop(Position.DUMMY)) })
 | |
|         if4.add(PtNodeGroup().also { it.add(PtNop(Position.DUMMY)) })
 | |
|         sub.add(if4)
 | |
|         block.add(sub)
 | |
|         program.add(block)
 | |
| 
 | |
|         val options = getTestOptions()
 | |
|         val st = SymbolTableMaker(program, options).make()
 | |
|         val errors = ErrorReporterForTests()
 | |
|         val result = codegen.generate(program, st, options, errors) as VmAssemblyProgram
 | |
|         val irChunks = (result.irProgram.blocks.first().children.single() as IRSubroutine).chunks
 | |
|         irChunks.size shouldBeGreaterThan 4
 | |
|     }
 | |
| 
 | |
|     test("float comparison expressions against nonzero") {
 | |
| //main {
 | |
| //    sub start() {
 | |
| //        float @shared f1
 | |
| //
 | |
| //        if f1==42
 | |
| //            nop
 | |
| //        if f1!=42
 | |
| //            nop
 | |
| //        if f1>42
 | |
| //            nop
 | |
| //        if f1<42
 | |
| //            nop
 | |
| //    }
 | |
| //}
 | |
|         val codegen = VmCodeGen()
 | |
|         val program = PtProgram("test", DummyMemsizer, DummyStringEncoder)
 | |
|         val block = PtBlock("main", false, SourceCode.Generated("test"), PtBlock.Options(), Position.DUMMY)
 | |
|         val sub = PtSub("start", emptyList(), null, Position.DUMMY)
 | |
|         sub.add(PtVariable(
 | |
|             "f1",
 | |
|             DataType.forDt(BaseDataType.FLOAT),
 | |
|             ZeropageWish.DONTCARE,
 | |
|             0u,
 | |
|             null,
 | |
|             null,
 | |
|             Position.DUMMY
 | |
|         ))
 | |
|         val if1 = PtIfElse(Position.DUMMY)
 | |
|         val cmp1 = PtBinaryExpression("==", DataType.forDt(BaseDataType.BOOL), Position.DUMMY)
 | |
|         cmp1.add(PtIdentifier("main.start.f1", DataType.forDt(BaseDataType.FLOAT), Position.DUMMY))
 | |
|         cmp1.add(PtNumber(BaseDataType.FLOAT, 42.0, Position.DUMMY))
 | |
|         if1.add(cmp1)
 | |
|         if1.add(PtNodeGroup().also { it.add(PtNop(Position.DUMMY)) })
 | |
|         if1.add(PtNodeGroup().also { it.add(PtNop(Position.DUMMY)) })
 | |
|         sub.add(if1)
 | |
|         val if2 = PtIfElse(Position.DUMMY)
 | |
|         val cmp2 = PtBinaryExpression("!=", DataType.forDt(BaseDataType.BOOL), Position.DUMMY)
 | |
|         cmp2.add(PtIdentifier("main.start.f1", DataType.forDt(BaseDataType.FLOAT), Position.DUMMY))
 | |
|         cmp2.add(PtNumber(BaseDataType.FLOAT, 42.0, Position.DUMMY))
 | |
|         if2.add(cmp2)
 | |
|         if2.add(PtNodeGroup().also { it.add(PtNop(Position.DUMMY)) })
 | |
|         if2.add(PtNodeGroup().also { it.add(PtNop(Position.DUMMY)) })
 | |
|         sub.add(if2)
 | |
|         val if3 = PtIfElse(Position.DUMMY)
 | |
|         val cmp3 = PtBinaryExpression("<", DataType.forDt(BaseDataType.BOOL), Position.DUMMY)
 | |
|         cmp3.add(PtIdentifier("main.start.f1", DataType.forDt(BaseDataType.FLOAT), Position.DUMMY))
 | |
|         cmp3.add(PtNumber(BaseDataType.FLOAT, 42.0, Position.DUMMY))
 | |
|         if3.add(cmp3)
 | |
|         if3.add(PtNodeGroup().also { it.add(PtNop(Position.DUMMY)) })
 | |
|         if3.add(PtNodeGroup().also { it.add(PtNop(Position.DUMMY)) })
 | |
|         sub.add(if3)
 | |
|         val if4 = PtIfElse(Position.DUMMY)
 | |
|         val cmp4 = PtBinaryExpression(">", DataType.forDt(BaseDataType.BOOL), Position.DUMMY)
 | |
|         cmp4.add(PtIdentifier("main.start.f1", DataType.forDt(BaseDataType.FLOAT), Position.DUMMY))
 | |
|         cmp4.add(PtNumber(BaseDataType.FLOAT, 42.0, Position.DUMMY))
 | |
|         if4.add(cmp4)
 | |
|         if4.add(PtNodeGroup().also { it.add(PtNop(Position.DUMMY)) })
 | |
|         if4.add(PtNodeGroup().also { it.add(PtNop(Position.DUMMY)) })
 | |
|         sub.add(if4)
 | |
|         block.add(sub)
 | |
|         program.add(block)
 | |
| 
 | |
|         val options = getTestOptions()
 | |
|         val st = SymbolTableMaker(program, options).make()
 | |
|         val errors = ErrorReporterForTests()
 | |
|         val result = codegen.generate(program, st, options, errors) as VmAssemblyProgram
 | |
|         val irChunks = (result.irProgram.blocks.first().children.single() as IRSubroutine).chunks
 | |
|         irChunks.size shouldBeGreaterThan 4
 | |
|     }
 | |
| 
 | |
|     test("float conditional jump") {
 | |
| //main {
 | |
| //    sub start() {
 | |
| //        float @shared f1
 | |
| //
 | |
| //        if f1==42
 | |
| //            goto $c000
 | |
| //        if f1>42
 | |
| //            goto $c000
 | |
| //    }
 | |
| //}
 | |
|         val codegen = VmCodeGen()
 | |
|         val program = PtProgram("test", DummyMemsizer, DummyStringEncoder)
 | |
|         val block = PtBlock("main", false, SourceCode.Generated("test"), PtBlock.Options(), Position.DUMMY)
 | |
|         val sub = PtSub("start", emptyList(), null, Position.DUMMY)
 | |
|         sub.add(PtVariable(
 | |
|             "f1",
 | |
|             DataType.forDt(BaseDataType.FLOAT),
 | |
|             ZeropageWish.DONTCARE,
 | |
|             0u,
 | |
|             null,
 | |
|             null,
 | |
|             Position.DUMMY
 | |
|         ))
 | |
|         val if1 = PtIfElse(Position.DUMMY)
 | |
|         val cmp1 = PtBinaryExpression("==", DataType.forDt(BaseDataType.BOOL), Position.DUMMY)
 | |
|         cmp1.add(PtIdentifier("main.start.f1", DataType.forDt(BaseDataType.FLOAT), Position.DUMMY))
 | |
|         cmp1.add(PtNumber(BaseDataType.FLOAT, 42.0, Position.DUMMY))
 | |
|         if1.add(cmp1)
 | |
|         if1.add(PtNodeGroup().also { it.add(PtJump(Position.DUMMY).also { it.add(PtNumber(BaseDataType.UWORD, 0xc000.toDouble(), Position.DUMMY)) }) })
 | |
|         if1.add(PtNodeGroup())
 | |
|         sub.add(if1)
 | |
|         val if2 = PtIfElse(Position.DUMMY)
 | |
|         val cmp2 = PtBinaryExpression(">", DataType.forDt(BaseDataType.BOOL), Position.DUMMY)
 | |
|         cmp2.add(PtIdentifier("main.start.f1", DataType.forDt(BaseDataType.FLOAT), Position.DUMMY))
 | |
|         cmp2.add(PtNumber(BaseDataType.FLOAT, 42.0, Position.DUMMY))
 | |
|         if2.add(cmp2)
 | |
|         if2.add(PtNodeGroup().also { it.add(PtJump(Position.DUMMY).also { it.add(PtNumber(BaseDataType.UWORD, 0xc000.toDouble(), Position.DUMMY)) }) })
 | |
|         if2.add(PtNodeGroup())
 | |
|         sub.add(if2)
 | |
|         block.add(sub)
 | |
|         program.add(block)
 | |
| 
 | |
|         val options = getTestOptions()
 | |
|         val st = SymbolTableMaker(program, options).make()
 | |
|         val errors = ErrorReporterForTests()
 | |
|         val result = codegen.generate(program, st, options, errors) as VmAssemblyProgram
 | |
|         val irChunks = (result.irProgram.blocks.first().children.single() as IRSubroutine).chunks
 | |
|         irChunks.size shouldBe 1
 | |
|     }
 | |
| 
 | |
|     test("integer comparison expressions against zero") {
 | |
| //main {
 | |
| //    sub start() {
 | |
| //        byte @shared sb1
 | |
| //
 | |
| //        if sb1==0
 | |
| //            nop
 | |
| //        if sb1!=0
 | |
| //            nop
 | |
| //        if sb1>0
 | |
| //            nop
 | |
| //        if sb1<0
 | |
| //            nop
 | |
| //    }
 | |
| //}
 | |
|         val codegen = VmCodeGen()
 | |
|         val program = PtProgram("test", DummyMemsizer, DummyStringEncoder)
 | |
|         val block = PtBlock("main", false, SourceCode.Generated("test"), PtBlock.Options(), Position.DUMMY)
 | |
|         val sub = PtSub("start", emptyList(), null, Position.DUMMY)
 | |
|         sub.add(PtVariable(
 | |
|             "sb1",
 | |
|             DataType.forDt(BaseDataType.BYTE),
 | |
|             ZeropageWish.DONTCARE,
 | |
|             0u,
 | |
|             null,
 | |
|             null,
 | |
|             Position.DUMMY
 | |
|         ))
 | |
|         val if1 = PtIfElse(Position.DUMMY)
 | |
|         val cmp1 = PtBinaryExpression("==", DataType.forDt(BaseDataType.BOOL), Position.DUMMY)
 | |
|         cmp1.add(PtIdentifier("main.start.sb1", DataType.forDt(BaseDataType.BYTE), Position.DUMMY))
 | |
|         cmp1.add(PtNumber(BaseDataType.BYTE, 0.0, Position.DUMMY))
 | |
|         if1.add(cmp1)
 | |
|         if1.add(PtNodeGroup().also { it.add(PtNop(Position.DUMMY)) })
 | |
|         if1.add(PtNodeGroup().also { it.add(PtNop(Position.DUMMY)) })
 | |
|         sub.add(if1)
 | |
|         val if2 = PtIfElse(Position.DUMMY)
 | |
|         val cmp2 = PtBinaryExpression("!=", DataType.forDt(BaseDataType.BOOL), Position.DUMMY)
 | |
|         cmp2.add(PtIdentifier("main.start.sb1", DataType.forDt(BaseDataType.BYTE), Position.DUMMY))
 | |
|         cmp2.add(PtNumber(BaseDataType.BYTE, 0.0, Position.DUMMY))
 | |
|         if2.add(cmp2)
 | |
|         if2.add(PtNodeGroup().also { it.add(PtNop(Position.DUMMY)) })
 | |
|         if2.add(PtNodeGroup().also { it.add(PtNop(Position.DUMMY)) })
 | |
|         sub.add(if2)
 | |
|         val if3 = PtIfElse(Position.DUMMY)
 | |
|         val cmp3 = PtBinaryExpression("<", DataType.forDt(BaseDataType.BOOL), Position.DUMMY)
 | |
|         cmp3.add(PtIdentifier("main.start.sb1", DataType.forDt(BaseDataType.BYTE), Position.DUMMY))
 | |
|         cmp3.add(PtNumber(BaseDataType.BYTE, 0.0, Position.DUMMY))
 | |
|         if3.add(cmp3)
 | |
|         if3.add(PtNodeGroup().also { it.add(PtNop(Position.DUMMY)) })
 | |
|         if3.add(PtNodeGroup().also { it.add(PtNop(Position.DUMMY)) })
 | |
|         sub.add(if3)
 | |
|         val if4 = PtIfElse(Position.DUMMY)
 | |
|         val cmp4 = PtBinaryExpression(">", DataType.forDt(BaseDataType.BOOL), Position.DUMMY)
 | |
|         cmp4.add(PtIdentifier("main.start.sb1", DataType.forDt(BaseDataType.BYTE), Position.DUMMY))
 | |
|         cmp4.add(PtNumber(BaseDataType.BYTE, 0.0, Position.DUMMY))
 | |
|         if4.add(cmp4)
 | |
|         if4.add(PtNodeGroup().also { it.add(PtNop(Position.DUMMY)) })
 | |
|         if4.add(PtNodeGroup().also { it.add(PtNop(Position.DUMMY)) })
 | |
|         sub.add(if4)
 | |
|         block.add(sub)
 | |
|         program.add(block)
 | |
| 
 | |
|         val options = getTestOptions()
 | |
|         val st = SymbolTableMaker(program, options).make()
 | |
|         val errors = ErrorReporterForTests()
 | |
|         val result = codegen.generate(program, st, options, errors) as VmAssemblyProgram
 | |
|         val irChunks = (result.irProgram.blocks.first().children.single() as IRSubroutine).chunks
 | |
|         irChunks.size shouldBeGreaterThan 4
 | |
|     }
 | |
| 
 | |
|     test("integer comparison expressions against nonzero") {
 | |
| //main {
 | |
| //    sub start() {
 | |
| //        byte @shared sb1
 | |
| //
 | |
| //        if sb1==42
 | |
| //            nop
 | |
| //        if sb1!=42
 | |
| //            nop
 | |
| //        if sb1>42
 | |
| //            nop
 | |
| //        if sb1<42
 | |
| //            nop
 | |
| //    }
 | |
| //}
 | |
|         val codegen = VmCodeGen()
 | |
|         val program = PtProgram("test", DummyMemsizer, DummyStringEncoder)
 | |
|         val block = PtBlock("main", false, SourceCode.Generated("test"), PtBlock.Options(), Position.DUMMY)
 | |
|         val sub = PtSub("start", emptyList(), null, Position.DUMMY)
 | |
|         sub.add(PtVariable(
 | |
|             "sb1",
 | |
|             DataType.forDt(BaseDataType.BYTE),
 | |
|             ZeropageWish.DONTCARE,
 | |
|             0u,
 | |
|             null,
 | |
|             null,
 | |
|             Position.DUMMY
 | |
|         ))
 | |
|         val if1 = PtIfElse(Position.DUMMY)
 | |
|         val cmp1 = PtBinaryExpression("==", DataType.forDt(BaseDataType.BOOL), Position.DUMMY)
 | |
|         cmp1.add(PtIdentifier("main.start.sb1", DataType.forDt(BaseDataType.BYTE), Position.DUMMY))
 | |
|         cmp1.add(PtNumber(BaseDataType.BYTE, 42.0, Position.DUMMY))
 | |
|         if1.add(cmp1)
 | |
|         if1.add(PtNodeGroup().also { it.add(PtNop(Position.DUMMY)) })
 | |
|         if1.add(PtNodeGroup().also { it.add(PtNop(Position.DUMMY)) })
 | |
|         sub.add(if1)
 | |
|         val if2 = PtIfElse(Position.DUMMY)
 | |
|         val cmp2 = PtBinaryExpression("!=", DataType.forDt(BaseDataType.BOOL), Position.DUMMY)
 | |
|         cmp2.add(PtIdentifier("main.start.sb1", DataType.forDt(BaseDataType.BYTE), Position.DUMMY))
 | |
|         cmp2.add(PtNumber(BaseDataType.BYTE, 42.0, Position.DUMMY))
 | |
|         if2.add(cmp2)
 | |
|         if2.add(PtNodeGroup().also { it.add(PtNop(Position.DUMMY)) })
 | |
|         if2.add(PtNodeGroup().also { it.add(PtNop(Position.DUMMY)) })
 | |
|         sub.add(if2)
 | |
|         val if3 = PtIfElse(Position.DUMMY)
 | |
|         val cmp3 = PtBinaryExpression("<", DataType.forDt(BaseDataType.BOOL), Position.DUMMY)
 | |
|         cmp3.add(PtIdentifier("main.start.sb1", DataType.forDt(BaseDataType.BYTE), Position.DUMMY))
 | |
|         cmp3.add(PtNumber(BaseDataType.BYTE, 42.0, Position.DUMMY))
 | |
|         if3.add(cmp3)
 | |
|         if3.add(PtNodeGroup().also { it.add(PtNop(Position.DUMMY)) })
 | |
|         if3.add(PtNodeGroup().also { it.add(PtNop(Position.DUMMY)) })
 | |
|         sub.add(if3)
 | |
|         val if4 = PtIfElse(Position.DUMMY)
 | |
|         val cmp4 = PtBinaryExpression(">", DataType.forDt(BaseDataType.BOOL), Position.DUMMY)
 | |
|         cmp4.add(PtIdentifier("main.start.sb1", DataType.forDt(BaseDataType.BYTE), Position.DUMMY))
 | |
|         cmp4.add(PtNumber(BaseDataType.BYTE, 42.0, Position.DUMMY))
 | |
|         if4.add(cmp4)
 | |
|         if4.add(PtNodeGroup().also { it.add(PtNop(Position.DUMMY)) })
 | |
|         if4.add(PtNodeGroup().also { it.add(PtNop(Position.DUMMY)) })
 | |
|         sub.add(if4)
 | |
|         block.add(sub)
 | |
|         program.add(block)
 | |
| 
 | |
|         val options = getTestOptions()
 | |
|         val st = SymbolTableMaker(program, options).make()
 | |
|         val errors = ErrorReporterForTests()
 | |
|         val result = codegen.generate(program, st, options, errors) as VmAssemblyProgram
 | |
|         val irChunks = (result.irProgram.blocks.first().children.single() as IRSubroutine).chunks
 | |
|         irChunks.size shouldBeGreaterThan 4
 | |
|     }
 | |
| 
 | |
|     test("integer conditional jump") {
 | |
| //main {
 | |
| //    sub start() {
 | |
| //        ubyte @shared ub1
 | |
| //
 | |
| //        if ub1==42
 | |
| //            goto $c000
 | |
| //        if ub1>42
 | |
| //            goto $c000
 | |
| //    }
 | |
| //}
 | |
|         val codegen = VmCodeGen()
 | |
|         val program = PtProgram("test", DummyMemsizer, DummyStringEncoder)
 | |
|         val block = PtBlock("main", false, SourceCode.Generated("test"), PtBlock.Options(), Position.DUMMY)
 | |
|         val sub = PtSub("start", emptyList(), null, Position.DUMMY)
 | |
|         sub.add(PtVariable(
 | |
|             "ub1",
 | |
|             DataType.forDt(BaseDataType.BYTE),
 | |
|             ZeropageWish.DONTCARE,
 | |
|             0u,
 | |
|             null,
 | |
|             null,
 | |
|             Position.DUMMY
 | |
|         ))
 | |
|         val if1 = PtIfElse(Position.DUMMY)
 | |
|         val cmp1 = PtBinaryExpression("==", DataType.forDt(BaseDataType.BOOL), Position.DUMMY)
 | |
|         cmp1.add(PtIdentifier("main.start.ub1", DataType.forDt(BaseDataType.UBYTE), Position.DUMMY))
 | |
|         cmp1.add(PtNumber(BaseDataType.UBYTE, 42.0, Position.DUMMY))
 | |
|         if1.add(cmp1)
 | |
|         if1.add(PtNodeGroup().also { it.add(PtJump(Position.DUMMY).also { it.add(PtNumber(BaseDataType.UWORD, 0xc000.toDouble(), Position.DUMMY)) }) })
 | |
|         if1.add(PtNodeGroup())
 | |
|         sub.add(if1)
 | |
|         val if2 = PtIfElse(Position.DUMMY)
 | |
|         val cmp2 = PtBinaryExpression(">", DataType.forDt(BaseDataType.BOOL), Position.DUMMY)
 | |
|         cmp2.add(PtIdentifier("main.start.ub1", DataType.forDt(BaseDataType.UBYTE), Position.DUMMY))
 | |
|         cmp2.add(PtNumber(BaseDataType.UBYTE, 42.0, Position.DUMMY))
 | |
|         if2.add(cmp2)
 | |
|         if2.add(PtNodeGroup().also { it.add(PtJump(Position.DUMMY).also {it.add(PtNumber(BaseDataType.UWORD, 0xc000.toDouble(), Position.DUMMY)) }) })
 | |
|         if2.add(PtNodeGroup())
 | |
|         sub.add(if2)
 | |
|         block.add(sub)
 | |
|         program.add(block)
 | |
| 
 | |
|         val options = getTestOptions()
 | |
|         val st = SymbolTableMaker(program, options).make()
 | |
|         val errors = ErrorReporterForTests()
 | |
|         val result = codegen.generate(program, st, options, errors) as VmAssemblyProgram
 | |
|         val irChunks = (result.irProgram.blocks.first().children.single() as IRSubroutine).chunks
 | |
|         irChunks.size shouldBe 1
 | |
|     }
 | |
| 
 | |
|     test("extsub allowed in ir-codegen") {
 | |
| //main {
 | |
| //    extsub $5000 = routine()
 | |
| //
 | |
| //    sub start()  {
 | |
| //        routine()
 | |
| //    }
 | |
| //}
 | |
|         val codegen = VmCodeGen()
 | |
|         val program = PtProgram("test", DummyMemsizer, DummyStringEncoder)
 | |
|         val block = PtBlock("main", false, SourceCode.Generated("test"), PtBlock.Options(), Position.DUMMY)
 | |
|         val extsub = PtAsmSub("routine", PtAsmSub.Address(null, null, 0x5000u), setOf(CpuRegister.Y), emptyList(), emptyList(), false, Position.DUMMY)
 | |
|         block.add(extsub)
 | |
|         val sub = PtSub("start", emptyList(), null, Position.DUMMY)
 | |
|         val call = PtFunctionCall("main.routine", true, DataType.forDt(BaseDataType.UNDEFINED), Position.DUMMY)
 | |
|         sub.add(call)
 | |
|         block.add(sub)
 | |
|         program.add(block)
 | |
| 
 | |
|         val options = getTestOptions()
 | |
|         val st = SymbolTableMaker(program, options).make()
 | |
|         val errors = ErrorReporterForTests()
 | |
|         val result = codegen.generate(program, st, options, errors) as VmAssemblyProgram
 | |
|         val irChunks = (result.irProgram.blocks.first().children.single() as IRSubroutine).chunks
 | |
|         irChunks.size shouldBe 1
 | |
|         irChunks[0].instructions.size shouldBe 2
 | |
|         val preparecallInstr = irChunks[0].instructions[0]
 | |
|         preparecallInstr.opcode shouldBe Opcode.PREPARECALL
 | |
|         preparecallInstr.immediate shouldBe 0
 | |
|         val callInstr = irChunks[0].instructions[1]
 | |
|         callInstr.opcode shouldBe Opcode.CALL
 | |
|         callInstr.address shouldBe 0x5000
 | |
|     }
 | |
| }) |