From 30cbb6c9a87827470eafb8389d44bcaee68429e4 Mon Sep 17 00:00:00 2001 From: Irmen de Jong Date: Sun, 27 Mar 2022 21:59:46 +0200 Subject: [PATCH] implementing more of the vm --- .../src/prog8/codegen/virtual/CodeGen.kt | 18 ++- .../prog8/codegen/virtual/ExpressionGen.kt | 46 +++++++- .../codegen/virtual/VariableAllocator.kt | 24 +++- .../src/prog8/optimizer/StatementOptimizer.kt | 4 +- compiler/res/prog8lib/virtual/prog8_lib.p8 | 44 ++++---- examples/primes.p8 | 2 +- examples/test.p8 | 103 ++++++++---------- virtualmachine/src/prog8/vm/SysCalls.kt | 3 +- 8 files changed, 153 insertions(+), 91 deletions(-) diff --git a/codeGenVirtual/src/prog8/codegen/virtual/CodeGen.kt b/codeGenVirtual/src/prog8/codegen/virtual/CodeGen.kt index 5e93c5946..c53f44075 100644 --- a/codeGenVirtual/src/prog8/codegen/virtual/CodeGen.kt +++ b/codeGenVirtual/src/prog8/codegen/virtual/CodeGen.kt @@ -56,9 +56,9 @@ class CodeGen(internal val program: PtProgram, is PtNop -> VmCodeChunk() is PtReturn -> translate(node) is PtJump -> translate(node) - is PtWhen -> TODO() + is PtWhen -> TODO("when") is PtPipe -> expressionEval.translate(node, regUsage.nextFree(), regUsage) - is PtForLoop -> TODO() + is PtForLoop -> TODO("for-loop") is PtIfElse -> translate(node, regUsage) is PtPostIncrDecr -> translate(node, regUsage) is PtRepeatLoop -> translate(node, regUsage) @@ -219,7 +219,19 @@ class CodeGen(internal val program: PtProgram, code += VmCodeInstruction(ins) } else if(array!=null) { - TODO("assign to array") + val variable = array.variable.targetName + var variableAddr = allocations.get(variable) + val itemsize = program.memsizer.memorySize(array.type) + val fixedIndex = (array.index as? PtNumber)?.number?.toInt() + val vmDtArrayIdx = vmType(array.type) + if(fixedIndex!=null) { + variableAddr += fixedIndex*itemsize + code += VmCodeInstruction(Instruction(Opcode.LOADM, vmDtArrayIdx, reg1 = resultRegister, value=variableAddr)) + } else { + val indexReg = regUsage.nextFree() + code += expressionEval.translateExpression(array.index, indexReg, regUsage) + code += VmCodeInstruction(Instruction(Opcode.LOADX, vmDtArrayIdx, reg1 = resultRegister, reg2=indexReg, value=variableAddr)) + } } else if(memory!=null) { val ins = diff --git a/codeGenVirtual/src/prog8/codegen/virtual/ExpressionGen.kt b/codeGenVirtual/src/prog8/codegen/virtual/ExpressionGen.kt index 94ebc1073..9e5258686 100644 --- a/codeGenVirtual/src/prog8/codegen/virtual/ExpressionGen.kt +++ b/codeGenVirtual/src/prog8/codegen/virtual/ExpressionGen.kt @@ -365,16 +365,58 @@ internal class ExpressionGen(val codeGen: CodeGen) { val name = (call.args[0] as PtString).value val size = (call.args[1] as PtNumber).number.toUInt() val align = (call.args[2] as PtNumber).number.toUInt() - TODO("Memory($name, $size, $align)") + val existing = codeGen.allocations.getMemorySlab(name) + val address = if(existing==null) + codeGen.allocations.allocateMemorySlab(name, size, align) + else if(existing.second!=size || existing.third!=align) { + codeGen.errors.err("memory slab '$name' already exists with a different size or alignment", call.position) + return VmCodeChunk() + } + else + existing.first + code += VmCodeInstruction(Instruction(Opcode.LOAD, VmDataType.WORD, reg1=resultRegister, value=address.toInt())) } "rnd" -> { code += VmCodeInstruction(Instruction(Opcode.SYSCALL, value=Syscall.RND.ordinal)) if(resultRegister!=0) code += VmCodeInstruction(Instruction(Opcode.LOADR, VmDataType.BYTE, reg1=resultRegister, reg2=0)) } + "peek" -> { + val addressReg = regUsage.nextFree() + code += translateExpression(call.args.single(), addressReg, regUsage) + code += VmCodeInstruction(Instruction(Opcode.LOADI, VmDataType.BYTE, reg1 = resultRegister, reg2=addressReg)) + } + "peekw" -> { + val addressReg = regUsage.nextFree() + code += translateExpression(call.args.single(), addressReg, regUsage) + code += VmCodeInstruction(Instruction(Opcode.LOADI, VmDataType.WORD, reg1 = resultRegister, reg2=addressReg)) + } + "memory" -> { + val memname = (call.args[0] as PtString).value + val size = (call.args[1] as PtNumber).number.toInt() + val align = (call.args[2] as PtNumber).number.toInt() + TODO("memory '$memname', $size, $align") + } else -> { - // TODO builtin functions... TODO("builtinfunc ${call.name}") +// code += VmCodeInstruction(Instruction(Opcode.NOP)) +// for (arg in call.args) { +// code += translateExpression(arg, resultRegister, regUsage) +// code += when(arg.type) { +// in ByteDatatypes -> VmCodeInstruction(Instruction(Opcode.PUSH, VmDataType.BYTE, reg1=resultRegister)) +// in WordDatatypes -> VmCodeInstruction(Instruction(Opcode.PUSH, VmDataType.WORD, reg1=resultRegister)) +// else -> throw AssemblyError("weird arg dt") +// } +// } +// code += VmCodeInstruction(Instruction(Opcode.CALL), labelArg = listOf("_prog8_builtin", call.name)) +// for (arg in call.args) { +// code += when(arg.type) { +// in ByteDatatypes -> VmCodeInstruction(Instruction(Opcode.POP, VmDataType.BYTE, reg1=resultRegister)) +// in WordDatatypes -> VmCodeInstruction(Instruction(Opcode.POP, VmDataType.WORD, reg1=resultRegister)) +// else -> throw AssemblyError("weird arg dt") +// } +// } +// code += VmCodeInstruction(Instruction(Opcode.NOP)) } } return code diff --git a/codeGenVirtual/src/prog8/codegen/virtual/VariableAllocator.kt b/codeGenVirtual/src/prog8/codegen/virtual/VariableAllocator.kt index 223232ca6..411161bbe 100644 --- a/codeGenVirtual/src/prog8/codegen/virtual/VariableAllocator.kt +++ b/codeGenVirtual/src/prog8/codegen/virtual/VariableAllocator.kt @@ -7,7 +7,10 @@ import prog8.code.core.* class VariableAllocator(private val st: SymbolTable, private val program: PtProgram, errors: IErrorReporter) { private val allocations = mutableMapOf, Int>() - val freeStart: Int + private var freeMemoryStart: Int + + val freeMem: Int + get() = freeMemoryStart init { var nextLocation = 0 @@ -24,7 +27,7 @@ class VariableAllocator(private val st: SymbolTable, private val program: PtProg nextLocation += memsize } - freeStart = nextLocation + freeMemoryStart = nextLocation } fun get(name: List) = allocations.getValue(name) @@ -68,4 +71,21 @@ class VariableAllocator(private val st: SymbolTable, private val program: PtProg } return mm } + + private val memorySlabsInternal = mutableMapOf>() + internal val memorySlabs: Map> = memorySlabsInternal + + fun allocateMemorySlab(name: String, size: UInt, align: UInt): UInt { + val address = + if(align==0u || align==1u) + freeMemoryStart.toUInt() + else + (freeMemoryStart.toUInt() + align-1u) and (0xffffffffu xor (align-1u)) + + memorySlabsInternal[name] = Triple(address, size, align) + freeMemoryStart = (address + size).toInt() + return address + } + + fun getMemorySlab(name: String): Triple? = memorySlabsInternal[name] } diff --git a/codeOptimizers/src/prog8/optimizer/StatementOptimizer.kt b/codeOptimizers/src/prog8/optimizer/StatementOptimizer.kt index a82c6207a..b00952757 100644 --- a/codeOptimizers/src/prog8/optimizer/StatementOptimizer.kt +++ b/codeOptimizers/src/prog8/optimizer/StatementOptimizer.kt @@ -399,7 +399,7 @@ class StatementOptimizer(private val program: Program, if (rightCv == 0.0) { return listOf(IAstModification.Remove(assignment, parent as IStatementContainer)) } else if (targetDt in IntegerDatatypes && floor(rightCv) == rightCv) { - if (vardeclDt != VarDeclType.MEMORY && rightCv in 1.0..4.0) { + if (vardeclDt != VarDeclType.MEMORY && rightCv in 1.0..4.0 && compTarget.name!=VMTarget.NAME) { // replace by several INCs if it's not a memory address (inc on a memory mapped register doesn't work very well) val incs = AnonymousScope(mutableListOf(), assignment.position) repeat(rightCv.toInt()) { @@ -413,7 +413,7 @@ class StatementOptimizer(private val program: Program, if (rightCv == 0.0) { return listOf(IAstModification.Remove(assignment, parent as IStatementContainer)) } else if (targetDt in IntegerDatatypes && floor(rightCv) == rightCv) { - if (vardeclDt != VarDeclType.MEMORY && rightCv in 1.0..4.0) { + if (vardeclDt != VarDeclType.MEMORY && rightCv in 1.0..4.0 && compTarget.name!=VMTarget.NAME) { // replace by several DECs if it's not a memory address (dec on a memory mapped register doesn't work very well) val decs = AnonymousScope(mutableListOf(), assignment.position) repeat(rightCv.toInt()) { diff --git a/compiler/res/prog8lib/virtual/prog8_lib.p8 b/compiler/res/prog8lib/virtual/prog8_lib.p8 index 60b3e2326..62e966e92 100644 --- a/compiler/res/prog8lib/virtual/prog8_lib.p8 +++ b/compiler/res/prog8lib/virtual/prog8_lib.p8 @@ -8,33 +8,33 @@ prog8_lib { %option force_output sub string_contains(ubyte needle, str haystack) -> ubyte { - txt.print(">>>string elt check: ") - txt.print_ub(needle) - txt.spc() - txt.print_uwhex(haystack, true) - txt.nl() - return 0 + repeat { + if @(haystack)==0 + return false + if @(haystack)==needle + return true + haystack++ + } } sub bytearray_contains(ubyte needle, uword haystack_ptr, ubyte num_elements) -> ubyte { - txt.print(">>>bytearray elt check: ") - txt.print_ub(needle) - txt.spc() - txt.print_uwhex(haystack_ptr, true) - txt.spc() - txt.print_ub(num_elements) - txt.nl() - return 0 + haystack_ptr-- + while num_elements { + if haystack_ptr[num_elements]==needle + return true + num_elements-- + } + return false } sub wordarray_contains(ubyte needle, uword haystack_ptr, ubyte num_elements) -> ubyte { - txt.print(">>>wordarray elt check: ") - txt.print_ub(needle) - txt.spc() - txt.print_uwhex(haystack_ptr, true) - txt.spc() - txt.print_ub(num_elements) - txt.nl() - return 0 + haystack_ptr += (num_elements-1) * 2 + while num_elements { + if peekw(haystack_ptr)==needle + return true + haystack_ptr -= 2 + num_elements-- + } + return false } } diff --git a/examples/primes.p8 b/examples/primes.p8 index 377a16819..7c1619d10 100644 --- a/examples/primes.p8 +++ b/examples/primes.p8 @@ -1,5 +1,5 @@ %import textio -%import test_stack +; %import test_stack %zeropage basicsafe ; Note: this program is compatible with C64 and CX16. diff --git a/examples/test.p8 b/examples/test.p8 index d3669ae31..d51bc3e2f 100644 --- a/examples/test.p8 +++ b/examples/test.p8 @@ -1,4 +1,3 @@ -%import floats %import textio ; NOTE: meant to test to virtual machine output target (use -target vitual) @@ -8,67 +7,55 @@ main { txt.clear_screen() txt.print("Welcome to a prog8 pixel shader :-)\n") - float fl = 9.9 - fl = floats.pow(fl, 3.3) - floats.print_f(fl) + uword @shared chunk = memory("irmen", 4000, 256) + txt.print_uwhex(chunk,true) txt.nl() - ubyte ww = 65 - fl = ww - fl += 0.1 - floats.print_f(fl) + + ubyte bb = 4 + ubyte[] array = [1,2,3,4,5,6] + uword[] warray = [1111,2222,3333] + str tekst = "test" + uword ww = 19 + bb = bb in "teststring" + bb++ + bb = bb in [1,2,3,4,5,6] + bb++ + bb = bb in array + bb++ + bb = bb in tekst + bb++ + bb = ww in warray + bb++ + bb = 666 in warray + bb ++ + bb = '?' in tekst + bb++ + txt.print("bb=") + txt.print_ub(bb) txt.nl() - uword ww2 = 65432 - fl = ww2 - fl += 0.1 - floats.print_f(fl) + sys.exit(99) + syscall1(8, 0) ; enable lo res creen + ubyte shifter -; ubyte bb = 4 -; ubyte[] array = [1,2,3,4,5,6] -; uword[] warray = [1111,2222,3333] -; str tekst = "test" -; uword ww = 19 -; bb = bb in "teststring" -; bb++ -; bb = bb in [1,2,3,4,5,6] -; bb++ -; bb = bb in array -; bb++ -; bb = bb in tekst -; bb++ -; bb = ww in warray -; bb++ -; bb = 666 in warray -; bb ++ -; bb = '?' in tekst -; bb++ -; txt.print("bb=") -; txt.print_ub(bb) -; txt.nl() -; sys.exit(99) -; -; -; syscall1(8, 0) ; enable lo res creen -; ubyte shifter -; -; shifter >>= 1 -; -; repeat { -; uword xx -; uword yy = 0 -; repeat 240 { -; xx = 0 -; repeat 320 { -; syscall3(10, xx, yy, xx*yy + shifter) ; plot pixel -; xx++ -; } -; yy++ -; } -; shifter+=4 -; -; txt.print_ub(shifter) -; txt.nl() -; } + shifter >>= 1 + + repeat { + uword xx + uword yy = 0 + repeat 240 { + xx = 0 + repeat 320 { + syscall3(10, xx, yy, xx*yy + shifter) ; plot pixel + xx++ + } + yy++ + } + shifter+=4 + + txt.print_ub(shifter) + txt.nl() + } } } diff --git a/virtualmachine/src/prog8/vm/SysCalls.kt b/virtualmachine/src/prog8/vm/SysCalls.kt index ab54849b1..82a32f0f0 100644 --- a/virtualmachine/src/prog8/vm/SysCalls.kt +++ b/virtualmachine/src/prog8/vm/SysCalls.kt @@ -32,7 +32,7 @@ enum class Syscall { GFX_ENABLE, GFX_CLEAR, GFX_PLOT, - RND + RND, } object SysCalls { @@ -82,6 +82,7 @@ object SysCalls { Syscall.RND -> { vm.registers.setB(0, (Random.nextInt() ushr 3).toUByte()) } + else -> TODO("syscall ${call.name}") } } }