vm: added 1-bit variants of lsr/lsl opcodes

This commit is contained in:
Irmen de Jong 2022-04-11 00:25:00 +02:00
parent 890b1c2d52
commit ec7501782d
6 changed files with 150 additions and 67 deletions

View File

@ -133,7 +133,6 @@ internal class BuiltinFuncGen(private val codeGen: CodeGen, private val exprGen:
}
private fun funcPoke(call: PtBuiltinFunctionCall, resultRegister: Int): VmCodeChunk {
// should just be a memory write
val addressReg = codeGen.vmRegisters.nextFree()
val valueReg = codeGen.vmRegisters.nextFree()
val code = VmCodeChunk()
@ -152,7 +151,6 @@ internal class BuiltinFuncGen(private val codeGen: CodeGen, private val exprGen:
}
private fun funcPeek(call: PtBuiltinFunctionCall, resultRegister: Int): VmCodeChunk {
// should just be a memory read
val code = VmCodeChunk()
val addressReg = codeGen.vmRegisters.nextFree()
code += exprGen.translateExpression(call.args.single(), addressReg)
@ -187,6 +185,7 @@ internal class BuiltinFuncGen(private val codeGen: CodeGen, private val exprGen:
}
private fun funcLsb(call: PtBuiltinFunctionCall, resultRegister: Int): VmCodeChunk {
// TODO optimized code gen
val code = VmCodeChunk()
code += exprGen.translateExpression(call.args.single(), resultRegister)
// note: if a word result is needed, the upper byte is cleared by the typecast that follows. No need to do it here.
@ -194,9 +193,10 @@ internal class BuiltinFuncGen(private val codeGen: CodeGen, private val exprGen:
}
private fun funcMsb(call: PtBuiltinFunctionCall, resultRegister: Int): VmCodeChunk {
// TODO optimized code gen
val code = VmCodeChunk()
code += exprGen.translateExpression(call.args.single(), resultRegister)
code += VmCodeInstruction(Opcode.SWAP, VmDataType.BYTE, reg1 = resultRegister)
code += VmCodeInstruction(Opcode.MSIG, VmDataType.BYTE, reg1 = resultRegister, reg2=resultRegister)
// note: if a word result is needed, the upper byte is cleared by the typecast that follows. No need to do it here.
return code
}
@ -248,7 +248,6 @@ internal class BuiltinFuncGen(private val codeGen: CodeGen, private val exprGen:
}
private fun funcRolRor2(opcode: Opcode, call: PtBuiltinFunctionCall, resultRegister: Int): VmCodeChunk {
// bit rotate left without carry, in-place
val vmDt = codeGen.vmType(call.args[0].type)
val code = VmCodeChunk()
code += exprGen.translateExpression(call.args[0], resultRegister)

View File

@ -372,23 +372,29 @@ class CodeGen(internal val program: PtProgram,
private val powersOfTwo = (0..16).map { 2.0.pow(it.toDouble()).toInt() }
private fun multiplyByConst(dt: VmDataType, reg: Int, factor: UInt): VmCodeChunk {
internal fun multiplyByConst(dt: VmDataType, reg: Int, factor: Int): VmCodeChunk {
require(factor>=0)
val code = VmCodeChunk()
val pow2 = powersOfTwo.indexOf(factor.toInt())
if(pow2>=1) {
// just shift bits
code += VmCodeInstruction(Opcode.LSL, dt, reg1=reg, reg2=reg, reg3=pow2)
if(factor==1)
return code
val pow2 = powersOfTwo.indexOf(factor)
if(pow2==1) {
// just shift 1 bit
code += VmCodeInstruction(Opcode.LSL, dt, reg1=reg)
}
else if(pow2>=1) {
// just shift multiple bits
val pow2reg = vmRegisters.nextFree()
code += VmCodeInstruction(Opcode.LOAD, dt, reg1=pow2reg, value=pow2)
code += VmCodeInstruction(Opcode.LSLM, dt, reg1=reg, reg2=reg, reg3=pow2reg)
} else {
when(factor) {
0u -> {
code += VmCodeInstruction(Opcode.LOAD, dt, reg1=reg, value=0)
}
1u -> { /* do nothing */ }
else -> {
val factorReg = vmRegisters.nextFree()
code += VmCodeInstruction(Opcode.LOAD, dt, reg1=factorReg, value=factor.toInt())
code += VmCodeInstruction(Opcode.MUL, dt, reg1=reg, reg2=reg, reg3=factorReg)
}
if (factor == 0) {
code += VmCodeInstruction(Opcode.LOAD, dt, reg1=reg, value=0)
}
else {
val factorReg = vmRegisters.nextFree()
code += VmCodeInstruction(Opcode.LOAD, dt, reg1=factorReg, value= factor)
code += VmCodeInstruction(Opcode.MUL, dt, reg1=reg, reg2=reg, reg3=factorReg)
}
}
return code

View File

@ -145,11 +145,8 @@ internal class ExpressionGen(private val codeGen: CodeGen) {
code += VmCodeInstruction(Opcode.LOADM, vmDt, reg1=resultRegister, value=arrayLocation+memOffset)
} else {
code += translateExpression(arrayIx.index, idxReg)
if(eltSize>1) {
val factorReg = codeGen.vmRegisters.nextFree()
code += VmCodeInstruction(Opcode.LOAD, VmDataType.BYTE, reg1=factorReg, value=eltSize)
code += VmCodeInstruction(Opcode.MUL, VmDataType.BYTE, reg1=idxReg, reg2=idxReg, reg3=factorReg)
}
if(eltSize>1)
code += codeGen.multiplyByConst(VmDataType.BYTE, idxReg, eltSize)
code += VmCodeInstruction(Opcode.LOADX, vmDt, reg1=resultRegister, reg2=idxReg, value = arrayLocation)
}
return code
@ -267,6 +264,7 @@ internal class ExpressionGen(private val codeGen: CodeGen) {
val rightResultReg = codeGen.vmRegisters.nextFree()
// TODO: optimized codegen when left or right operand is known 0 or 1 or whatever. But only if this would result in a different opcode such as ADD 1 -> INC, MUL 1 -> NOP
// actually optimizing the code should not be done here but in a tailored code optimizer step.
// multiplyByConst()
val leftCode = translateExpression(binExpr.left, leftResultReg)
val rightCode = translateExpression(binExpr.right, rightResultReg)
code += leftCode
@ -299,10 +297,10 @@ internal class ExpressionGen(private val codeGen: CodeGen) {
code += VmCodeInstruction(Opcode.XOR, vmDt, reg1=resultRegister, reg2=leftResultReg, reg3=rightResultReg)
}
"<<" -> {
code += VmCodeInstruction(Opcode.LSL, vmDt, reg1=resultRegister, reg2=leftResultReg, reg3=rightResultReg)
code += VmCodeInstruction(Opcode.LSLM, vmDt, reg1=resultRegister, reg2=leftResultReg, reg3=rightResultReg)
}
">>" -> {
val opc = if(signed) Opcode.ASR else Opcode.LSR
val opc = if(signed) Opcode.ASRM else Opcode.LSRM
code += VmCodeInstruction(opc, vmDt, reg1=resultRegister, reg2=leftResultReg, reg3=rightResultReg)
}
"==" -> {

View File

@ -7,26 +7,46 @@
main {
sub start() {
pokemon(1,0)
uword value = $ea31
uword[] warray = [$aa44, $bb55, $cc66]
ubyte upperb = msb(value)
ubyte lowerb = lsb(value)
txt.print_ubhex(upperb, true)
txt.print_ubhex(lowerb, false)
txt.nl()
value = mkword(upperb, lowerb)
txt.print_uwhex(value, true)
txt.nl()
upperb = msb(warray[1])
lowerb = lsb(warray[1])
txt.print_ubhex(upperb, true)
txt.print_ubhex(lowerb, false)
txt.nl()
ubyte index=1
upperb = msb(warray[index])
lowerb = lsb(warray[index])
txt.print_ubhex(upperb, true)
txt.print_ubhex(lowerb, false)
txt.nl()
; a "pixelshader":
void syscall1(8, 0) ; enable lo res creen
ubyte shifter
; pokemon(1,0)
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
}
; ; a "pixelshader":
; void syscall1(8, 0) ; enable lo res creen
; ubyte shifter
;
; ; pokemon(1,0)
;
; 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
; }
}
}

View File

@ -118,9 +118,12 @@ All have type b or w.
and reg1, reg2, reg3 - reg1 = reg2 bitwise and reg3
or reg1, reg2, reg3 - reg1 = reg2 bitwise or reg3
xor reg1, reg2, reg3 - reg1 = reg2 bitwise xor reg3
lsr reg1, reg2, reg3 - reg1 = shift reg2 right by reg3 bits + set Carry to shifted bit
asr reg1, reg2, reg3 - reg1 = shift reg2 right by reg3 bits (signed) + set Carry to shifted bit
lsl reg1, reg2, reg3 - reg1 = shift reg2 left by reg3 bits + set Carry to shifted bit
lsrm reg1, reg2, reg3 - reg1 = multi-shift reg2 right by reg3 bits + set Carry to shifted bit
asrm reg1, reg2, reg3 - reg1 = multi-shift reg2 right by reg3 bits (signed) + set Carry to shifted bit
lslm reg1, reg2, reg3 - reg1 = multi-shift reg2 left by reg3 bits + set Carry to shifted bit
lsr reg1 - shift reg1 right by 1 bits + set Carry to shifted bit
asr reg1 - shift reg1 right by 1 bits (signed) + set Carry to shifted bit
lsl reg1 - shift reg1 left by 1 bits + set Carry to shifted bit
ror reg1 - rotate reg1 right by 1 bits, not using carry + set Carry to shifted bit
roxr reg1 - rotate reg1 right by 1 bits, using carry + set Carry to shifted bit
rol reg1 - rotate reg1 left by 1bits, not using carry + set Carry to shifted bit
@ -136,9 +139,9 @@ nop - do nothing
breakpoint - trigger a breakpoint
copy reg1, reg2, length - copy memory from ptrs in reg1 to reg3, length bytes
copyz reg1, reg2 - copy memory from ptrs in reg1 to reg3, stop after first 0-byte
swap [b, w] reg1 - swap lsb and msb in register reg1 (16 bits) or lsw and msw (32 bits)
msig [b, w] reg1, reg2 - reg1 becomes the most significant byte (or word) of the word (or int) in reg2 (.w not yet implemented; requires 32 bits regs)
swapreg reg1, reg2 - swap values in reg1 and reg2
concat [b, w] reg1, reg2, reg3 - reg1 = concatenated lsb/lsw of reg2 and lsb/lsw of reg3 into new word or int (int not yet implemented, requires 32bits regs)
concat [b, w] reg1, reg2, reg3 - reg1 = concatenated lsb/lsw of reg2 and lsb/lsw of reg3 into new word or int (int not yet implemented; requires 32bits regs)
push [b, w] reg1 - push value in reg1 on the stack
pop [b, w] reg1 - pop value from stack into reg1
@ -206,6 +209,9 @@ enum class Opcode {
AND,
OR,
XOR,
ASRM,
LSRM,
LSLM,
ASR,
LSR,
LSL,
@ -218,7 +224,7 @@ enum class Opcode {
SEC,
PUSH,
POP,
SWAP,
MSIG,
SWAPREG,
CONCAT,
COPY,
@ -331,8 +337,8 @@ val instructionFormats = mutableMapOf(
Opcode.SYSCALL to InstructionFormat(NN, false, false, false, true ),
Opcode.RETURN to InstructionFormat(NN, false, false, false, false),
Opcode.BSTCC to InstructionFormat(NN, false, false, false, true ),
Opcode.BSTCS to InstructionFormat(NN, false, false, false, true ),
Opcode.BSTCC to InstructionFormat(NN, false, false,false, true ),
Opcode.BSTCS to InstructionFormat(NN, false, false,false, true ),
Opcode.BZ to InstructionFormat(BW, true, false, false, true ),
Opcode.BNZ to InstructionFormat(BW, true, false, false, true ),
Opcode.BEQ to InstructionFormat(BW, true, true, false, true ),
@ -372,9 +378,12 @@ val instructionFormats = mutableMapOf(
Opcode.AND to InstructionFormat(BW, true, true, true, false),
Opcode.OR to InstructionFormat(BW, true, true, true, false),
Opcode.XOR to InstructionFormat(BW, true, true, true, false),
Opcode.ASR to InstructionFormat(BW, true, true, true, false),
Opcode.LSR to InstructionFormat(BW, true, true, true, false),
Opcode.LSL to InstructionFormat(BW, true, true, true, false),
Opcode.ASRM to InstructionFormat(BW, true, true, true, false),
Opcode.LSRM to InstructionFormat(BW, true, true, true, false),
Opcode.LSLM to InstructionFormat(BW, true, true, true, false),
Opcode.ASR to InstructionFormat(BW, true, false, false, false),
Opcode.LSR to InstructionFormat(BW, true, false, false, false),
Opcode.LSL to InstructionFormat(BW, true, false, false, false),
Opcode.ROR to InstructionFormat(BW, true, false, false, false),
Opcode.ROXR to InstructionFormat(BW, true, false, false, false),
Opcode.ROL to InstructionFormat(BW, true, false, false, false),
@ -382,7 +391,7 @@ val instructionFormats = mutableMapOf(
Opcode.COPY to InstructionFormat(NN, true, true, false, true ),
Opcode.COPYZ to InstructionFormat(NN, true, true, false, false),
Opcode.SWAP to InstructionFormat(BW, true, false, false, false),
Opcode.MSIG to InstructionFormat(BW, true, true, false, false),
Opcode.PUSH to InstructionFormat(BW, true, false, false, false),
Opcode.POP to InstructionFormat(BW, true, false, false, false),
Opcode.CONCAT to InstructionFormat(BW, true, true, true, false),

View File

@ -140,6 +140,9 @@ class VirtualMachine(val memory: Memory, program: List<Instruction>) {
Opcode.AND -> InsAND(ins)
Opcode.OR -> InsOR(ins)
Opcode.XOR -> InsXOR(ins)
Opcode.ASRM -> InsASRM(ins)
Opcode.LSRM -> InsLSRM(ins)
Opcode.LSLM -> InsLSLM(ins)
Opcode.ASR -> InsASR(ins)
Opcode.LSR -> InsLSR(ins)
Opcode.LSL -> InsLSL(ins)
@ -147,7 +150,7 @@ class VirtualMachine(val memory: Memory, program: List<Instruction>) {
Opcode.ROXR -> InsROR(ins, true)
Opcode.ROL -> InsROL(ins, false)
Opcode.ROXL -> InsROL(ins, true)
Opcode.SWAP -> InsSWAP(ins)
Opcode.MSIG -> InsMSIG(ins)
Opcode.CONCAT -> InsCONCAT(ins)
Opcode.PUSH -> InsPUSH(ins)
Opcode.POP -> InsPOP(ins)
@ -685,7 +688,7 @@ class VirtualMachine(val memory: Memory, program: List<Instruction>) {
pc++
}
private fun InsASR(i: Instruction) {
private fun InsASRM(i: Instruction) {
val (left: Int, right: Int) = getLogicalOperandsS(i)
statusCarry = (left and 1)!=0
when(i.type!!) {
@ -695,7 +698,23 @@ class VirtualMachine(val memory: Memory, program: List<Instruction>) {
pc++
}
private fun InsLSR(i: Instruction) {
private fun InsASR(i: Instruction) {
when(i.type!!) {
VmDataType.BYTE -> {
val value = registers.getSB(i.reg1!!).toInt()
statusCarry = (value and 1)!=0
registers.setSB(i.reg1, (value shr 1).toByte())
}
VmDataType.WORD -> {
val value = registers.getSW(i.reg1!!).toInt()
statusCarry = (value and 1)!=0
registers.setSW(i.reg1, (value shr 1).toShort())
}
}
pc++
}
private fun InsLSRM(i: Instruction) {
val (left: UInt, right: UInt) = getLogicalOperandsU(i)
statusCarry = (left and 1u)!=0u
when(i.type!!) {
@ -705,7 +724,23 @@ class VirtualMachine(val memory: Memory, program: List<Instruction>) {
pc++
}
private fun InsLSL(i: Instruction) {
private fun InsLSR(i: Instruction) {
when(i.type!!) {
VmDataType.BYTE -> {
val value = registers.getUB(i.reg1!!).toInt()
statusCarry = (value and 1)!=0
registers.setUB(i.reg1, (value shr 1).toUByte())
}
VmDataType.WORD -> {
val value = registers.getUW(i.reg1!!).toInt()
statusCarry = (value and 1)!=0
registers.setUW(i.reg1, (value shr 1).toUShort())
}
}
pc++
}
private fun InsLSLM(i: Instruction) {
val (left: UInt, right: UInt) = getLogicalOperandsU(i)
when(i.type!!) {
VmDataType.BYTE -> {
@ -720,6 +755,22 @@ class VirtualMachine(val memory: Memory, program: List<Instruction>) {
pc++
}
private fun InsLSL(i: Instruction) {
when(i.type!!) {
VmDataType.BYTE -> {
val value = registers.getUB(i.reg1!!).toInt()
statusCarry = (value and 0x80)!=0
registers.setUB(i.reg1, (value shl 1).toUByte())
}
VmDataType.WORD -> {
val value = registers.getUW(i.reg1!!).toInt()
statusCarry = (value and 0x8000)!=0
registers.setUW(i.reg1, (value shl 1).toUShort())
}
}
pc++
}
private fun InsROR(i: Instruction, useCarry: Boolean) {
val newStatusCarry: Boolean
when (i.type!!) {
@ -776,14 +827,14 @@ class VirtualMachine(val memory: Memory, program: List<Instruction>) {
statusCarry = newStatusCarry
}
private fun InsSWAP(i: Instruction) {
private fun InsMSIG(i: Instruction) {
when(i.type!!) {
VmDataType.BYTE -> {
val value = registers.getUW(i.reg1!!)
val newValue = value.toUByte()*256u + (value.toInt() ushr 8).toUInt()
registers.setUW(i.reg1, newValue.toUShort())
val value = registers.getUW(i.reg2!!)
val newValue = value.toInt() ushr 8
registers.setUB(i.reg1!!, newValue.toUByte())
}
VmDataType.WORD -> TODO("swap.w not yet supported, requires 32-bits registers")
VmDataType.WORD -> TODO("msig.w not yet supported, requires 32-bits registers")
}
pc++
}