mirror of
https://github.com/irmen/prog8.git
synced 2025-01-11 13:29:45 +00:00
vm: added 1-bit variants of lsr/lsl opcodes
This commit is contained in:
parent
890b1c2d52
commit
ec7501782d
@ -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)
|
||||
|
@ -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
|
||||
|
@ -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)
|
||||
}
|
||||
"==" -> {
|
||||
|
@ -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
|
||||
; }
|
||||
}
|
||||
}
|
||||
|
@ -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),
|
||||
|
@ -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++
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user