From 26ea1da146a5c9d7de094a64991b06e78ccd29b4 Mon Sep 17 00:00:00 2001 From: Irmen de Jong Date: Fri, 20 May 2022 19:43:21 +0200 Subject: [PATCH] vm: add in-place bitwise or,and,xor --- .../prog8/codegen/virtual/AssignmentGen.kt | 6 +-- .../prog8/codegen/virtual/ExpressionGen.kt | 24 +++++++++ docs/source/todo.rst | 2 +- examples/test.p8 | 49 +++---------------- virtualmachine/src/prog8/vm/Instructions.kt | 11 ++++- virtualmachine/src/prog8/vm/VirtualMachine.kt | 24 ++++++++- 6 files changed, 67 insertions(+), 49 deletions(-) diff --git a/codeGenVirtual/src/prog8/codegen/virtual/AssignmentGen.kt b/codeGenVirtual/src/prog8/codegen/virtual/AssignmentGen.kt index 895fcd0c3..42e178f31 100644 --- a/codeGenVirtual/src/prog8/codegen/virtual/AssignmentGen.kt +++ b/codeGenVirtual/src/prog8/codegen/virtual/AssignmentGen.kt @@ -87,9 +87,9 @@ internal class AssignmentGen(private val codeGen: CodeGen, private val expressio "-" -> return expressionEval.operatorMinusInplace(address, vmDt, operand) "*" -> return expressionEval.operatorMultiplyInplace(address, vmDt, operand) "/" -> return expressionEval.operatorDivideInplace(address, vmDt, signed, operand) - "|" -> { /* TODO */ } - "&" -> { /* TODO */ } - "^" -> { /* TODO */ } + "|" -> return expressionEval.operatorOrInplace(address, vmDt, operand) + "&" -> return expressionEval.operatorAndInplace(address, vmDt, operand) + "^" -> return expressionEval.operatorXorInplace(address, vmDt, operand) else -> {} } return fallbackAssign(origAssign) diff --git a/codeGenVirtual/src/prog8/codegen/virtual/ExpressionGen.kt b/codeGenVirtual/src/prog8/codegen/virtual/ExpressionGen.kt index 5101bde2c..a968df16a 100644 --- a/codeGenVirtual/src/prog8/codegen/virtual/ExpressionGen.kt +++ b/codeGenVirtual/src/prog8/codegen/virtual/ExpressionGen.kt @@ -477,6 +477,14 @@ internal class ExpressionGen(private val codeGen: CodeGen) { return code } + internal fun operatorXorInplace(address: Int, vmDt: VmDataType, operand: PtExpression): VmCodeChunk { + val code = VmCodeChunk() + val operandReg = codeGen.vmRegisters.nextFree() + code += translateExpression(operand, operandReg, -1) + code += VmCodeInstruction(Opcode.XORM, vmDt, reg1=operandReg, value = address) + return code + } + private fun operatorAnd(binExpr: PtBinaryExpression, vmDt: VmDataType, resultRegister: Int): VmCodeChunk { val code = VmCodeChunk() val rightResultReg = codeGen.vmRegisters.nextFree() @@ -486,6 +494,14 @@ internal class ExpressionGen(private val codeGen: CodeGen) { return code } + internal fun operatorAndInplace(address: Int, vmDt: VmDataType, operand: PtExpression): VmCodeChunk { + val code = VmCodeChunk() + val operandReg = codeGen.vmRegisters.nextFree() + code += translateExpression(operand, operandReg, -1) + code += VmCodeInstruction(Opcode.ANDM, vmDt, reg1=operandReg, value=address) + return code + } + private fun operatorOr(binExpr: PtBinaryExpression, vmDt: VmDataType, resultRegister: Int): VmCodeChunk { val code = VmCodeChunk() val rightResultReg = codeGen.vmRegisters.nextFree() @@ -495,6 +511,14 @@ internal class ExpressionGen(private val codeGen: CodeGen) { return code } + internal fun operatorOrInplace(address: Int, vmDt: VmDataType, operand: PtExpression): VmCodeChunk { + val code = VmCodeChunk() + val operandReg = codeGen.vmRegisters.nextFree() + code += translateExpression(operand, operandReg, -1) + code += VmCodeInstruction(Opcode.ORM, vmDt, reg1=operandReg, value = address) + return code + } + private fun operatorModulo(binExpr: PtBinaryExpression, vmDt: VmDataType, resultRegister: Int): VmCodeChunk { if(vmDt==VmDataType.FLOAT) throw IllegalArgumentException("floating-point modulo not supported") diff --git a/docs/source/todo.rst b/docs/source/todo.rst index bdc32d712..e213755ea 100644 --- a/docs/source/todo.rst +++ b/docs/source/todo.rst @@ -3,7 +3,6 @@ TODO For next release ^^^^^^^^^^^^^^^^ -- vm: implement the missing in-place operators in inplaceBinexpr() - complete the Inliner - add McCarthy evaluation to shortcircuit and/or expressions. First do ifs by splitting them up? Then do expressions that compute a value? @@ -27,6 +26,7 @@ Compiler: - vm: don't store symbol names in instructions to make optimizing the IR easier? but what about jumps to labels. And it's no longer readable by humans. - vm: how to remove all unused subroutines? (in the assembly codegen, we let 64tass solve this for us) - vm: rather than being able to jump to any 'address' (IPTR), use 'blocks' that have entry and exit points -> even better dead code elimination possible too +- vm: add more assignments to translateInplaceAssign() - when the vm is stable and *if* its language can get promoted to prog8 IL, the variable allocation should be changed. It's now done before the vm code generation, but the IL should probably not depend on the allocations already performed. So the CodeGen doesn't do VariableAlloc *before* the codegen, but as a last step. diff --git a/examples/test.p8 b/examples/test.p8 index b204fd66d..7ed84b973 100644 --- a/examples/test.p8 +++ b/examples/test.p8 @@ -1,51 +1,14 @@ -%import textio -%import math %zeropage dontuse ; NOTE: meant to test to virtual machine output target (use -target vitual) main { sub start() { - byte @shared xx = 11 - byte @shared yy = 62 - byte @shared yy2 = 15 - byte @shared yy3 = 127 - ubyte @shared ubx = 3 - - xx = xx + 9 - txt.print_b(xx) ; 20 - txt.nl() - xx = xx * 8 - txt.print_b(xx) ; -96 - txt.nl() - xx = xx - 7 - txt.print_b(xx) ; -103 - txt.nl() - xx = xx / 6 - txt.print_b(xx) ; -17 - txt.nl() - xx = xx * 5 - txt.print_b(xx) ; -85 - txt.nl() - txt.nl() - -; xx = xx+3*yy -; xx = xx/yy -; xx = -xx -; @($4000) = @($4000) -; @($4000) = @($4000) + 2 -; xx = xx ^ yy -; xx = xx | yy2 -; xx = xx & yy3 -; txt.print_b(xx) ; 63 -; txt.nl() -; xx = (not xx) as byte -; xx = (~xx) as byte -; xx++ -; txt.print_b(xx) ; 0 -; txt.nl() -; -; ubx = not ubx -; ubx = ~ubx + ubyte @shared xx = 11 + uword addr = $5000 + @(addr) = @(addr) + xx + xx = xx ^ 44 + xx = xx | 44 + xx = xx & 44 } } diff --git a/virtualmachine/src/prog8/vm/Instructions.kt b/virtualmachine/src/prog8/vm/Instructions.kt index 7846e8a3f..ed06b1b3d 100644 --- a/virtualmachine/src/prog8/vm/Instructions.kt +++ b/virtualmachine/src/prog8/vm/Instructions.kt @@ -9,6 +9,7 @@ Virtual machine: 65536 bytes of memory. Thus memory pointers (addresses) are limited to 16 bits. Value stack, max 128 entries of 1 byte each. Status registers: Carry, Zero, Negative. +Program to execute is not stored in this memory, it's just a separate list of instructions. Most instructions have an associated data type 'b','w','f'. (omitting it means 'b'/byte). Currently NO support for 24 or 32 bits integers. @@ -119,7 +120,9 @@ LOGICAL/BITWISE All have type b or w. and reg1, reg2 - reg1 = reg1 bitwise and reg2 +andm reg1 address - memory = memory bitwise and reg1 or reg1, reg2 - reg1 = reg1 bitwise or reg2 +orm reg1, address - memory = memory bitwise or reg1 xor reg1, reg2 - reg1 = reg1 bitwise xor reg2 xorm reg1, address - memory = memory bitwise xor reg1 not reg1 - reg1 = boolean not of reg1 (0->1 , ~0 -> 0) @@ -240,7 +243,9 @@ enum class Opcode { EXTS, AND, + ANDM, OR, + ORM, XOR, XORM, NOT, @@ -303,7 +308,9 @@ val OpcodesWithAddress = setOf( Opcode.DIVM, Opcode.DIVSM, Opcode.NOTM, - Opcode.XORM + Opcode.ORM, + Opcode.XORM, + Opcode.ANDM ) @@ -509,7 +516,9 @@ val instructionFormats = mutableMapOf( Opcode.EXT to InstructionFormat.from("BW,r1"), Opcode.EXTS to InstructionFormat.from("BW,r1"), Opcode.AND to InstructionFormat.from("BW,r1,r2"), + Opcode.ANDM to InstructionFormat.from("BW,r1,v"), Opcode.OR to InstructionFormat.from("BW,r1,r2"), + Opcode.ORM to InstructionFormat.from("BW,r1,v"), Opcode.XOR to InstructionFormat.from("BW,r1,r2"), Opcode.XORM to InstructionFormat.from("BW,r1,v"), Opcode.NOT to InstructionFormat.from("BW,r1"), diff --git a/virtualmachine/src/prog8/vm/VirtualMachine.kt b/virtualmachine/src/prog8/vm/VirtualMachine.kt index 4521a877c..1dbd7ce9d 100644 --- a/virtualmachine/src/prog8/vm/VirtualMachine.kt +++ b/virtualmachine/src/prog8/vm/VirtualMachine.kt @@ -155,7 +155,9 @@ class VirtualMachine(val memory: Memory, program: List) { Opcode.EXT -> InsEXT(ins) Opcode.EXTS -> InsEXTS(ins) Opcode.AND -> InsAND(ins) + Opcode.ANDM -> InsANDM(ins) Opcode.OR -> InsOR(ins) + Opcode.ORM -> InsORM(ins) Opcode.XOR -> InsXOR(ins) Opcode.XORM ->InsXORM(ins) Opcode.NOT -> InsNOT(ins) @@ -977,7 +979,7 @@ class VirtualMachine(val memory: Memory, program: List) { "*" -> memvalue * operand else -> throw IllegalArgumentException("operator word $operator") } - registers.setUW(reg1, result.toUShort()) + memory.setUW(address, result.toUShort()) } private fun divModWordUnsigned(operator: String, reg1: Int, reg2: Int) { @@ -1091,6 +1093,16 @@ class VirtualMachine(val memory: Memory, program: List) { pc++ } + private fun InsANDM(i: Instruction) { + val address = i.value!! + when(i.type!!) { + VmDataType.BYTE -> memory.setUB(address, (memory.getUB(address) and registers.getUB(i.reg1!!))) + VmDataType.WORD -> memory.setUW(address, (memory.getUW(address) and registers.getUW(i.reg1!!))) + VmDataType.FLOAT -> throw IllegalArgumentException("invalid float type for this instruction $i") + } + pc++ + } + private fun InsOR(i: Instruction) { val (left: UInt, right: UInt) = getLogicalOperandsU(i) when(i.type!!) { @@ -1101,6 +1113,16 @@ class VirtualMachine(val memory: Memory, program: List) { pc++ } + private fun InsORM(i: Instruction) { + val address = i.value!! + when(i.type!!) { + VmDataType.BYTE -> memory.setUB(address, (memory.getUB(address) or registers.getUB(i.reg1!!))) + VmDataType.WORD -> memory.setUW(address, (memory.getUW(address) or registers.getUW(i.reg1!!))) + VmDataType.FLOAT -> throw IllegalArgumentException("invalid float type for this instruction $i") + } + pc++ + } + private fun InsXOR(i: Instruction) { val (left: UInt, right: UInt) = getLogicalOperandsU(i) when(i.type!!) {