vm: add in-place bitwise or,and,xor

This commit is contained in:
Irmen de Jong 2022-05-20 19:43:21 +02:00
parent c9e8c7a290
commit 26ea1da146
6 changed files with 67 additions and 49 deletions

View File

@ -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)

View File

@ -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")

View File

@ -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.

View File

@ -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
}
}

View File

@ -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"),

View File

@ -155,7 +155,9 @@ class VirtualMachine(val memory: Memory, program: List<Instruction>) {
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<Instruction>) {
"*" -> 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<Instruction>) {
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<Instruction>) {
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!!) {