vm: implementing rol/ror

This commit is contained in:
Irmen de Jong 2022-04-09 00:49:23 +02:00
parent a8cf9f5cc4
commit a0face4a28
7 changed files with 192 additions and 42 deletions

View File

@ -1,10 +1,7 @@
package prog8.codegen.virtual package prog8.codegen.virtual
import prog8.code.StStaticVariable import prog8.code.StStaticVariable
import prog8.code.ast.PtBuiltinFunctionCall import prog8.code.ast.*
import prog8.code.ast.PtIdentifier
import prog8.code.ast.PtNumber
import prog8.code.ast.PtString
import prog8.code.core.DataType import prog8.code.core.DataType
import prog8.vm.Opcode import prog8.vm.Opcode
import prog8.vm.Syscall import prog8.vm.Syscall
@ -154,6 +151,10 @@ internal class BuiltinFuncGen(private val codeGen: CodeGen, private val exprGen:
code += VmCodeInstruction(Opcode.LOAD, VmDataType.BYTE, reg1=1, value=array.length) code += VmCodeInstruction(Opcode.LOAD, VmDataType.BYTE, reg1=1, value=array.length)
code += VmCodeInstruction(Opcode.SYSCALL, value=sortSyscall.ordinal) code += VmCodeInstruction(Opcode.SYSCALL, value=sortSyscall.ordinal)
} }
"rol" -> RolRor2(Opcode.ROXL, call, resultRegister, code)
"ror" -> RolRor2(Opcode.ROXR, call, resultRegister, code)
"rol2" -> RolRor2(Opcode.ROL, call, resultRegister, code)
"ror2" -> RolRor2(Opcode.ROR, call, resultRegister, code)
else -> { else -> {
TODO("builtinfunc ${call.name}") TODO("builtinfunc ${call.name}")
// code += VmCodeInstruction(Opcode.NOP)) // code += VmCodeInstruction(Opcode.NOP))
@ -179,4 +180,17 @@ internal class BuiltinFuncGen(private val codeGen: CodeGen, private val exprGen:
return code return code
} }
private fun RolRor2(opcode: Opcode, call: PtBuiltinFunctionCall, resultRegister: Int, code: VmCodeChunk) {
// bit rotate left without carry, in-place
val vmDt = codeGen.vmType(call.args[0].type)
code += exprGen.translateExpression(call.args[0], resultRegister)
code += VmCodeInstruction(opcode, vmDt, reg1=resultRegister)
val assignment = PtAssignment(call.position)
val target = PtAssignTarget(call.position)
target.children.add(call.args[0])
assignment.children.add(target)
assignment.children.add(PtIdentifier(listOf(":vmreg-$resultRegister"), listOf(":vmreg-$resultRegister"), call.args[0].type, call.position))
code += codeGen.translateNode(assignment)
}
} }

View File

@ -57,7 +57,7 @@ class CodeGen(internal val program: PtProgram,
} }
private fun translateNode(node: PtNode): VmCodeChunk { internal fun translateNode(node: PtNode): VmCodeChunk {
val code = when(node) { val code = when(node) {
is PtBlock -> translate(node) is PtBlock -> translate(node)
is PtSub -> translate(node) is PtSub -> translate(node)
@ -80,6 +80,7 @@ class CodeGen(internal val program: PtProgram,
is PtRepeatLoop -> translate(node) is PtRepeatLoop -> translate(node)
is PtLabel -> VmCodeChunk(VmCodeLabel(node.scopedName)) is PtLabel -> VmCodeChunk(VmCodeLabel(node.scopedName))
is PtBreakpoint -> VmCodeChunk(VmCodeInstruction(Opcode.BREAKPOINT)) is PtBreakpoint -> VmCodeChunk(VmCodeInstruction(Opcode.BREAKPOINT))
is PtConditionalBranch -> translate(node)
is PtAddressOf, is PtAddressOf,
is PtContainmentCheck, is PtContainmentCheck,
is PtMemoryByte, is PtMemoryByte,
@ -99,7 +100,6 @@ class CodeGen(internal val program: PtProgram,
is PtAsmSub -> throw AssemblyError("asmsub not supported on virtual machine target ${node.position}") is PtAsmSub -> throw AssemblyError("asmsub not supported on virtual machine target ${node.position}")
is PtInlineAssembly -> throw AssemblyError("inline assembly not supported on virtual machine target ${node.position}") is PtInlineAssembly -> throw AssemblyError("inline assembly not supported on virtual machine target ${node.position}")
is PtIncludeBinary -> throw AssemblyError("inline binary data not supported on virtual machine target ${node.position}") is PtIncludeBinary -> throw AssemblyError("inline binary data not supported on virtual machine target ${node.position}")
is PtConditionalBranch -> throw AssemblyError("conditional branches not supported in vm target due to lack of cpu flags ${node.position}")
else -> TODO("missing codegen for $node") else -> TODO("missing codegen for $node")
} }
if(code.lines.isNotEmpty() && node.position.line!=0) if(code.lines.isNotEmpty() && node.position.line!=0)
@ -107,6 +107,33 @@ class CodeGen(internal val program: PtProgram,
return code return code
} }
private fun translate(branch: PtConditionalBranch): VmCodeChunk {
val code = VmCodeChunk()
val elseLabel = createLabelName()
when(branch.condition) {
BranchCondition.CS -> {
code += VmCodeInstruction(Opcode.BSTCC, symbol = elseLabel)
}
BranchCondition.CC -> {
code += VmCodeInstruction(Opcode.BSTCS, symbol = elseLabel)
}
else -> {
throw AssemblyError("conditional branch ${branch.condition} not supported in vm target due to lack of cpu flags ${branch.position}")
}
}
code += translateNode(branch.trueScope)
if(branch.falseScope.children.isNotEmpty()) {
val endLabel = createLabelName()
code += VmCodeInstruction(Opcode.JUMP, symbol = endLabel)
code += VmCodeLabel(elseLabel)
code += translateNode(branch.falseScope)
code += VmCodeLabel(endLabel)
} else {
code += VmCodeLabel(elseLabel)
}
return code
}
private fun translate(whenStmt: PtWhen): VmCodeChunk { private fun translate(whenStmt: PtWhen): VmCodeChunk {
if(whenStmt.choices.children.isEmpty()) if(whenStmt.choices.children.isEmpty())
return VmCodeChunk() return VmCodeChunk()

View File

@ -90,11 +90,29 @@ sub print_ubhex (ubyte value, ubyte prefix) {
sub print_ubbin (ubyte value, ubyte prefix) { sub print_ubbin (ubyte value, ubyte prefix) {
; ---- print the ubyte in binary form ; ---- print the ubyte in binary form
; TODO use conv module? ; TODO use conv module?
if prefix
chrout('%')
repeat 8 {
rol(value)
if_cc
txt.chrout('0')
else
txt.chrout('1')
}
} }
sub print_uwbin (uword value, ubyte prefix) { sub print_uwbin (uword value, ubyte prefix) {
; ---- print the uword in binary form ; ---- print the uword in binary form
; TODO use conv module? ; TODO use conv module?
if prefix
chrout('%')
repeat 16 {
rol(value)
if_cc
txt.chrout('0')
else
txt.chrout('1')
}
} }
sub print_uwhex (uword value, ubyte prefix) { sub print_uwhex (uword value, ubyte prefix) {

View File

@ -6,6 +6,7 @@
main { main {
sub start() { sub start() {
; a "pixelshader": ; a "pixelshader":
void syscall1(8, 0) ; enable lo res creen void syscall1(8, 0) ; enable lo res creen
ubyte shifter ubyte shifter

View File

@ -14,7 +14,7 @@
<keywords keywords="&amp;;-&gt;;@;\$;and;as;asmsub;break;clobbers;do;downto;else;false;for;goto;if;if_cc;if_cs;if_eq;if_mi;if_ne;if_neg;if_nz;if_pl;if_pos;if_vc;if_vs;if_z;in;inline;not;or;repeat;return;romsub;step;sub;to;true;until;when;while;xor;~" ignore_case="false" /> <keywords keywords="&amp;;-&gt;;@;\$;and;as;asmsub;break;clobbers;do;downto;else;false;for;goto;if;if_cc;if_cs;if_eq;if_mi;if_ne;if_neg;if_nz;if_pl;if_pos;if_vc;if_vs;if_z;in;inline;not;or;repeat;return;romsub;step;sub;to;true;until;when;while;xor;~" ignore_case="false" />
<keywords2 keywords="%address;%asm;%asmbinary;%asminclude;%breakpoint;%import;%launcher;%option;%output;%zeropage;%zpreserved;iso:;petscii:;sc:" /> <keywords2 keywords="%address;%asm;%asmbinary;%asminclude;%breakpoint;%import;%launcher;%option;%output;%zeropage;%zpreserved;iso:;petscii:;sc:" />
<keywords3 keywords="@requirezp;@shared;@zp;byte;const;float;str;ubyte;uword;void;word" /> <keywords3 keywords="@requirezp;@shared;@zp;byte;const;float;str;ubyte;uword;void;word" />
<keywords4 keywords="abs;acos;all;any;asin;atan;avg;callfar;callrom;ceil;cmp;cos;cos16;cos16u;cos8;cos8u;cosr16;cosr16u;cosr8;cosr8u;deg;floor;len;ln;log2;lsb;lsl;lsr;max;memory;min;mkword;msb;peek;peekw;poke;pokew;pop;popw;push;pushw;rad;reverse;rnd;rndf;rndw;rol;rol2;ror;ror2;round;rrestore;rrestorex;rsave;rsavex;sgn;sin;sin16;sin16u;sin8;sin8u;sinr16;sinr16u;sinr8;sinr8u;sizeof;sort;sqrt;sqrt16;sum;swap;tan;|&gt;" /> <keywords4 keywords="abs;acos;all;any;asin;atan;avg;callfar;callrom;ceil;cmp;cos;cos16;cos16u;cos8;cos8u;cosr16;cosr16u;cosr8;cosr8u;deg;floor;len;ln;log2;lsb;max;memory;min;mkword;msb;peek;peekw;poke;pokew;pop;popw;push;pushw;rad;reverse;rnd;rndf;rndw;rol;rol2;ror;ror2;round;rrestore;rrestorex;rsave;rsavex;sgn;sin;sin16;sin16u;sin8;sin8u;sinr16;sinr16u;sinr8;sinr8u;sizeof;sort;sqrt;sqrt16;sum;swap;tan;|&gt;" />
</highlighting> </highlighting>
<extensionMap> <extensionMap>
<mapping ext="p8" /> <mapping ext="p8" />

View File

@ -7,6 +7,7 @@ Virtual machine:
65536 virtual registers, 16 bits wide, can also be used as 8 bits. r0-r65535 65536 virtual registers, 16 bits wide, can also be used as 8 bits. r0-r65535
65536 bytes of memory. Thus memory pointers (addresses) are limited to 16 bits. 65536 bytes of memory. Thus memory pointers (addresses) are limited to 16 bits.
Value stack, max 128 entries. Value stack, max 128 entries.
Status registers: Carry.
Instruction serialization format possibility: Instruction serialization format possibility:
@ -59,8 +60,10 @@ return - restore last saved instruction location
BRANCHING BRANCHING
--------- ---------
All have type b or w. All have type b or w except the branches that only check status bits.
bstcc location - branch to location if Status bit Carry is Clear
bstcs location - branch to location if Status bit Carry is Set
bz reg1, location - branch to location if reg1 is zero bz reg1, location - branch to location if reg1 is zero
bnz reg1, location - branch to location if reg1 is not zero bnz reg1, location - branch to location if reg1 is not zero
beq reg1, reg2, location - jump to location in program given by location, if reg1 == reg2 beq reg1, reg2, location - jump to location in program given by location, if reg1 == reg2
@ -84,7 +87,7 @@ sgts reg1, reg2, reg3 - set reg=1 if reg2 > reg3 (signed), ot
sge reg1, reg2, reg3 - set reg=1 if reg2 >= reg3 (unsigned), otherwise set reg1=0 sge reg1, reg2, reg3 - set reg=1 if reg2 >= reg3 (unsigned), otherwise set reg1=0
sges reg1, reg2, reg3 - set reg=1 if reg2 >= reg3 (signed), otherwise set reg1=0 sges reg1, reg2, reg3 - set reg=1 if reg2 >= reg3 (signed), otherwise set reg1=0
TODO: support for the prog8 special branching instructions if_XX (bcc, bcs etc.) TODO: support for the other prog8 special branching instructions if_XX (bpl, bmi etc.)
but we don't have any 'processor flags' whatsoever in the vm so it's a bit weird but we don't have any 'processor flags' whatsoever in the vm so it's a bit weird
@ -105,7 +108,7 @@ mul reg1, reg2, reg3 - unsigned multiply reg1=reg2*reg3
div reg1, reg2, reg3 - unsigned division reg1=reg2/reg3 note: division by zero yields max signed int $ff/$ffff div reg1, reg2, reg3 - unsigned division reg1=reg2/reg3 note: division by zero yields max signed int $ff/$ffff
mod reg1, reg2, reg3 - remainder (modulo) of unsigned division reg1=reg2%reg3 note: division by zero yields max signed int $ff/$ffff mod reg1, reg2, reg3 - remainder (modulo) of unsigned division reg1=reg2%reg3 note: division by zero yields max signed int $ff/$ffff
TODO signed mul/div/mod? NOTE: because mul/div are constrained (truncated) to remain in 8 or 16 bits, there is NO NEED for separate signed/unsigned mul and div instructions. The result is identical.
LOGICAL/BITWISE LOGICAL/BITWISE
@ -115,18 +118,20 @@ All have type b or w.
and reg1, reg2, reg3 - reg1 = reg2 bitwise and reg3 and reg1, reg2, reg3 - reg1 = reg2 bitwise and reg3
or reg1, reg2, reg3 - reg1 = reg2 bitwise or reg3 or reg1, reg2, reg3 - reg1 = reg2 bitwise or reg3
xor reg1, reg2, reg3 - reg1 = reg2 bitwise xor reg3 xor reg1, reg2, reg3 - reg1 = reg2 bitwise xor reg3
lsr reg1, reg2, reg3 - reg1 = shift reg2 right by reg3 bits 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) 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 lsl reg1, reg2, reg3 - reg1 = shift reg2 left by reg3 bits + set Carry to shifted bit
ror reg1, reg2, reg3 - reg1 = rotate reg2 right by reg3 bits, not using carry ror reg1 - rotate reg1 right by 1 bits, not using carry + set Carry to shifted bit
rol reg1, reg2, reg3 - reg1 = rotate reg2 left by reg3 bits, not using carry 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
TODO also add ror/rol variants using the carry bit? These do map directly on 6502 and 68k instructions. But the VM doesn't have carry status bit yet. roxl reg1 - rotate reg1 left by 1bits, using carry, + set Carry to shifted bit
MISC MISC
---- ----
clc - clear Carry status bit
sec - set Carry status bit
nop - do nothing nop - do nothing
breakpoint - trigger a breakpoint breakpoint - trigger a breakpoint
copy reg1, reg2, length - copy memory from ptrs in reg1 to reg3, length bytes copy reg1, reg2, length - copy memory from ptrs in reg1 to reg3, length bytes
@ -159,6 +164,9 @@ enum class Opcode {
CALLI, CALLI,
SYSCALL, SYSCALL,
RETURN, RETURN,
BSTCC,
BSTCS,
BZ, BZ,
BNZ, BNZ,
BEQ, BEQ,
@ -202,8 +210,12 @@ enum class Opcode {
LSR, LSR,
LSL, LSL,
ROR, ROR,
ROXR,
ROL, ROL,
ROXL,
CLC,
SEC,
PUSH, PUSH,
POP, POP,
SWAP, SWAP,
@ -249,6 +261,11 @@ data class Instruction(
format.reg3 && reg3==null) format.reg3 && reg3==null)
throw IllegalArgumentException("missing a register") throw IllegalArgumentException("missing a register")
if(!format.reg1 && reg1!=null ||
!format.reg2 && reg2!=null ||
!format.reg3 && reg3!=null)
throw IllegalArgumentException("too many registers")
if(format.value && (value==null && symbol==null)) if(format.value && (value==null && symbol==null))
throw IllegalArgumentException("missing a value or symbol") throw IllegalArgumentException("missing a value or symbol")
} }
@ -313,6 +330,9 @@ val instructionFormats = mutableMapOf(
Opcode.CALLI to InstructionFormat(NN, true, false, false, false), Opcode.CALLI to InstructionFormat(NN, true, false, false, false),
Opcode.SYSCALL to InstructionFormat(NN, false, false, false, true ), Opcode.SYSCALL to InstructionFormat(NN, false, false, false, true ),
Opcode.RETURN to InstructionFormat(NN, false, false, false, false), 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.BZ to InstructionFormat(BW, true, false, false, true ), Opcode.BZ to InstructionFormat(BW, true, false, false, true ),
Opcode.BNZ 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 ), Opcode.BEQ to InstructionFormat(BW, true, true, false, true ),
@ -355,8 +375,10 @@ val instructionFormats = mutableMapOf(
Opcode.ASR 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.LSR to InstructionFormat(BW, true, true, true, false),
Opcode.LSL to InstructionFormat(BW, true, true, true, false), Opcode.LSL to InstructionFormat(BW, true, true, true, false),
Opcode.ROR to InstructionFormat(BW, true, true, true, false), Opcode.ROR to InstructionFormat(BW, true, false, false, false),
Opcode.ROL to InstructionFormat(BW, true, true, true, false), Opcode.ROXR to InstructionFormat(BW, true, false, false, false),
Opcode.ROL to InstructionFormat(BW, true, false, false, false),
Opcode.ROXL to InstructionFormat(BW, true, false, false, false),
Opcode.COPY to InstructionFormat(NN, true, true, false, true ), Opcode.COPY to InstructionFormat(NN, true, true, false, true ),
Opcode.COPYZ to InstructionFormat(NN, true, true, false, false), Opcode.COPYZ to InstructionFormat(NN, true, true, false, false),
@ -364,5 +386,7 @@ val instructionFormats = mutableMapOf(
Opcode.PUSH to InstructionFormat(BW, true, false, false, false), Opcode.PUSH to InstructionFormat(BW, true, false, false, false),
Opcode.POP 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), Opcode.CONCAT to InstructionFormat(BW, true, true, true, false),
Opcode.CLC to InstructionFormat(NN, false, false, false, false),
Opcode.SEC to InstructionFormat(NN, false, false, false, false),
Opcode.BREAKPOINT to InstructionFormat(NN, false, false, false, false) Opcode.BREAKPOINT to InstructionFormat(NN, false, false, false, false)
) )

View File

@ -19,6 +19,7 @@ class VirtualMachine(val memory: Memory, program: List<Instruction>) {
val valueStack = Stack<Int>() // max 128 entries val valueStack = Stack<Int>() // max 128 entries
var pc = 0 var pc = 0
var stepCount = 0 var stepCount = 0
var statusCarry = false
init { init {
if(program.size>65536) if(program.size>65536)
@ -58,6 +59,7 @@ class VirtualMachine(val memory: Memory, program: List<Instruction>) {
pc = 0 pc = 0
stepCount = 0 stepCount = 0
callStack.clear() callStack.clear()
statusCarry = false
} }
fun exit() { fun exit() {
@ -97,6 +99,8 @@ class VirtualMachine(val memory: Memory, program: List<Instruction>) {
Opcode.CALLI -> InsCALLI(ins) Opcode.CALLI -> InsCALLI(ins)
Opcode.SYSCALL -> InsSYSCALL(ins) Opcode.SYSCALL -> InsSYSCALL(ins)
Opcode.RETURN -> InsRETURN() Opcode.RETURN -> InsRETURN()
Opcode.BSTCC -> InsBSTCC(ins)
Opcode.BSTCS -> InsBSTCS(ins)
Opcode.BZ -> InsBZ(ins) Opcode.BZ -> InsBZ(ins)
Opcode.BNZ -> InsBNZ(ins) Opcode.BNZ -> InsBNZ(ins)
Opcode.BEQ -> InsBEQ(ins) Opcode.BEQ -> InsBEQ(ins)
@ -138,8 +142,10 @@ class VirtualMachine(val memory: Memory, program: List<Instruction>) {
Opcode.ASR -> InsASR(ins) Opcode.ASR -> InsASR(ins)
Opcode.LSR -> InsLSR(ins) Opcode.LSR -> InsLSR(ins)
Opcode.LSL -> InsLSL(ins) Opcode.LSL -> InsLSL(ins)
Opcode.ROR -> InsROR(ins) Opcode.ROR -> InsROR(ins, false)
Opcode.ROL -> InsROL(ins) Opcode.ROXR -> InsROR(ins, true)
Opcode.ROL -> InsROL(ins, false)
Opcode.ROXL -> InsROL(ins, true)
Opcode.SWAP -> InsSWAP(ins) Opcode.SWAP -> InsSWAP(ins)
Opcode.CONCAT -> InsCONCAT(ins) Opcode.CONCAT -> InsCONCAT(ins)
Opcode.PUSH -> InsPUSH(ins) Opcode.PUSH -> InsPUSH(ins)
@ -312,6 +318,20 @@ class VirtualMachine(val memory: Memory, program: List<Instruction>) {
pc = callStack.pop() pc = callStack.pop()
} }
private fun InsBSTCC(i: Instruction) {
if(!statusCarry)
pc = i.value!!
else
pc++
}
private fun InsBSTCS(i: Instruction) {
if(statusCarry)
pc = i.value!!
else
pc++
}
private fun InsBZ(i: Instruction) { private fun InsBZ(i: Instruction) {
when(i.type!!) { when(i.type!!) {
VmDataType.BYTE -> { VmDataType.BYTE -> {
@ -666,6 +686,7 @@ class VirtualMachine(val memory: Memory, program: List<Instruction>) {
private fun InsASR(i: Instruction) { private fun InsASR(i: Instruction) {
val (left: Int, right: Int) = getLogicalOperandsS(i) val (left: Int, right: Int) = getLogicalOperandsS(i)
statusCarry = (left and 1)!=0
when(i.type!!) { when(i.type!!) {
VmDataType.BYTE -> registers.setSB(i.reg1!!, (left shr right).toByte()) VmDataType.BYTE -> registers.setSB(i.reg1!!, (left shr right).toByte())
VmDataType.WORD -> registers.setSW(i.reg1!!, (left shr right).toShort()) VmDataType.WORD -> registers.setSW(i.reg1!!, (left shr right).toShort())
@ -675,6 +696,7 @@ class VirtualMachine(val memory: Memory, program: List<Instruction>) {
private fun InsLSR(i: Instruction) { private fun InsLSR(i: Instruction) {
val (left: UInt, right: UInt) = getLogicalOperandsU(i) val (left: UInt, right: UInt) = getLogicalOperandsU(i)
statusCarry = (left and 1u)!=0u
when(i.type!!) { when(i.type!!) {
VmDataType.BYTE -> registers.setUB(i.reg1!!, (left shr right.toInt()).toUByte()) VmDataType.BYTE -> registers.setUB(i.reg1!!, (left shr right.toInt()).toUByte())
VmDataType.WORD -> registers.setUW(i.reg1!!, (left shr right.toInt()).toUShort()) VmDataType.WORD -> registers.setUW(i.reg1!!, (left shr right.toInt()).toUShort())
@ -685,28 +707,72 @@ class VirtualMachine(val memory: Memory, program: List<Instruction>) {
private fun InsLSL(i: Instruction) { private fun InsLSL(i: Instruction) {
val (left: UInt, right: UInt) = getLogicalOperandsU(i) val (left: UInt, right: UInt) = getLogicalOperandsU(i)
when(i.type!!) { when(i.type!!) {
VmDataType.BYTE -> registers.setUB(i.reg1!!, (left shl right.toInt()).toUByte()) VmDataType.BYTE -> {
VmDataType.WORD -> registers.setUW(i.reg1!!, (left shl right.toInt()).toUShort()) statusCarry = (left and 0x80u)!=0u
registers.setUB(i.reg1!!, (left shl right.toInt()).toUByte())
}
VmDataType.WORD -> {
statusCarry = (left and 0x8000u)!=0u
registers.setUW(i.reg1!!, (left shl right.toInt()).toUShort())
}
} }
pc++ pc++
} }
private fun InsROR(i: Instruction) { private fun InsROR(i: Instruction, useCarry: Boolean) {
val (left: UInt, right: UInt) = getLogicalOperandsU(i) val newStatusCarry: Boolean
when(i.type!!) { when (i.type!!) {
VmDataType.BYTE -> registers.setUB(i.reg1!!, (left.rotateRight(right.toInt()).toUByte())) VmDataType.BYTE -> {
VmDataType.WORD -> registers.setUW(i.reg1!!, (left.rotateRight(right.toInt()).toUShort())) val orig = registers.getUB(i.reg1!!)
newStatusCarry = (orig.toInt() and 1) != 0
val rotated: UByte = if (useCarry) {
val carry = if (statusCarry) 0x80u else 0x00u
(orig.toUInt().rotateRight(1) or carry).toUByte()
} else
orig.rotateRight(1)
registers.setUB(i.reg1, rotated)
}
VmDataType.WORD -> {
val orig = registers.getUW(i.reg1!!)
newStatusCarry = (orig.toInt() and 1) != 0
val rotated: UShort = if (useCarry) {
val carry = if (statusCarry) 0x8000u else 0x0000u
(orig.toUInt().rotateRight(1) or carry).toUShort()
} else
orig.rotateRight(1)
registers.setUW(i.reg1, rotated)
}
} }
pc++ pc++
statusCarry = newStatusCarry
} }
private fun InsROL(i: Instruction) { private fun InsROL(i: Instruction, useCarry: Boolean) {
val (left: UInt, right: UInt) = getLogicalOperandsU(i) val newStatusCarry: Boolean
when(i.type!!) { when (i.type!!) {
VmDataType.BYTE -> registers.setUB(i.reg1!!, (left.rotateLeft(right.toInt()).toUByte())) VmDataType.BYTE -> {
VmDataType.WORD -> registers.setUW(i.reg1!!, (left.rotateLeft(right.toInt()).toUShort())) val orig = registers.getUB(i.reg1!!)
newStatusCarry = (orig.toInt() and 0x80) != 0
val rotated: UByte = if (useCarry) {
val carry = if (statusCarry) 1u else 0u
(orig.toUInt().rotateLeft(1) or carry).toUByte()
} else
orig.rotateLeft(1)
registers.setUB(i.reg1, rotated)
}
VmDataType.WORD -> {
val orig = registers.getUW(i.reg1!!)
newStatusCarry = (orig.toInt() and 0x8000) != 0
val rotated: UShort = if (useCarry) {
val carry = if (statusCarry) 1u else 0u
(orig.toUInt().rotateLeft(1) or carry).toUShort()
} else
orig.rotateLeft(1)
registers.setUW(i.reg1, rotated)
}
} }
pc++ pc++
statusCarry = newStatusCarry
} }
private fun InsSWAP(i: Instruction) { private fun InsSWAP(i: Instruction) {