mirror of
https://github.com/irmen/prog8.git
synced 2025-02-16 22:30:46 +00:00
vm: implementing rol/ror
This commit is contained in:
parent
a8cf9f5cc4
commit
a0face4a28
@ -1,10 +1,7 @@
|
||||
package prog8.codegen.virtual
|
||||
|
||||
import prog8.code.StStaticVariable
|
||||
import prog8.code.ast.PtBuiltinFunctionCall
|
||||
import prog8.code.ast.PtIdentifier
|
||||
import prog8.code.ast.PtNumber
|
||||
import prog8.code.ast.PtString
|
||||
import prog8.code.ast.*
|
||||
import prog8.code.core.DataType
|
||||
import prog8.vm.Opcode
|
||||
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.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 -> {
|
||||
TODO("builtinfunc ${call.name}")
|
||||
// code += VmCodeInstruction(Opcode.NOP))
|
||||
@ -179,4 +180,17 @@ internal class BuiltinFuncGen(private val codeGen: CodeGen, private val exprGen:
|
||||
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)
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -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) {
|
||||
is PtBlock -> translate(node)
|
||||
is PtSub -> translate(node)
|
||||
@ -80,6 +80,7 @@ class CodeGen(internal val program: PtProgram,
|
||||
is PtRepeatLoop -> translate(node)
|
||||
is PtLabel -> VmCodeChunk(VmCodeLabel(node.scopedName))
|
||||
is PtBreakpoint -> VmCodeChunk(VmCodeInstruction(Opcode.BREAKPOINT))
|
||||
is PtConditionalBranch -> translate(node)
|
||||
is PtAddressOf,
|
||||
is PtContainmentCheck,
|
||||
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 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 PtConditionalBranch -> throw AssemblyError("conditional branches not supported in vm target due to lack of cpu flags ${node.position}")
|
||||
else -> TODO("missing codegen for $node")
|
||||
}
|
||||
if(code.lines.isNotEmpty() && node.position.line!=0)
|
||||
@ -107,6 +107,33 @@ class CodeGen(internal val program: PtProgram,
|
||||
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 {
|
||||
if(whenStmt.choices.children.isEmpty())
|
||||
return VmCodeChunk()
|
||||
|
@ -90,11 +90,29 @@ sub print_ubhex (ubyte value, ubyte prefix) {
|
||||
sub print_ubbin (ubyte value, ubyte prefix) {
|
||||
; ---- print the ubyte in binary form
|
||||
; 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) {
|
||||
; ---- print the uword in binary form
|
||||
; 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) {
|
||||
|
@ -6,6 +6,7 @@
|
||||
|
||||
main {
|
||||
sub start() {
|
||||
|
||||
; a "pixelshader":
|
||||
void syscall1(8, 0) ; enable lo res creen
|
||||
ubyte shifter
|
||||
|
@ -14,7 +14,7 @@
|
||||
<keywords keywords="&;->;@;\$;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:" />
|
||||
<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;|>" />
|
||||
<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;|>" />
|
||||
</highlighting>
|
||||
<extensionMap>
|
||||
<mapping ext="p8" />
|
||||
|
@ -7,6 +7,7 @@ Virtual machine:
|
||||
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.
|
||||
Value stack, max 128 entries.
|
||||
Status registers: Carry.
|
||||
|
||||
|
||||
Instruction serialization format possibility:
|
||||
@ -59,8 +60,10 @@ return - restore last saved instruction location
|
||||
|
||||
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
|
||||
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
|
||||
@ -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
|
||||
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
|
||||
|
||||
|
||||
@ -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
|
||||
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
|
||||
@ -115,27 +118,29 @@ 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
|
||||
asr reg1, reg2, reg3 - reg1 = shift reg2 right by reg3 bits (signed)
|
||||
lsl reg1, reg2, reg3 - reg1 = shift reg2 left by reg3 bits
|
||||
ror reg1, reg2, reg3 - reg1 = rotate reg2 right by reg3 bits, not using carry
|
||||
rol reg1, reg2, reg3 - reg1 = rotate reg2 left by reg3 bits, not using carry
|
||||
|
||||
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.
|
||||
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
|
||||
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
|
||||
roxl reg1 - rotate reg1 left by 1bits, using carry, + set Carry to shifted bit
|
||||
|
||||
|
||||
MISC
|
||||
----
|
||||
|
||||
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)
|
||||
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)
|
||||
push [b, w] reg1 - push value in reg1 on the stack
|
||||
pop [b, w] reg1 - pop value from stack into reg1
|
||||
clc - clear Carry status bit
|
||||
sec - set Carry status bit
|
||||
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)
|
||||
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)
|
||||
push [b, w] reg1 - push value in reg1 on the stack
|
||||
pop [b, w] reg1 - pop value from stack into reg1
|
||||
|
||||
*/
|
||||
|
||||
@ -159,6 +164,9 @@ enum class Opcode {
|
||||
CALLI,
|
||||
SYSCALL,
|
||||
RETURN,
|
||||
|
||||
BSTCC,
|
||||
BSTCS,
|
||||
BZ,
|
||||
BNZ,
|
||||
BEQ,
|
||||
@ -202,8 +210,12 @@ enum class Opcode {
|
||||
LSR,
|
||||
LSL,
|
||||
ROR,
|
||||
ROXR,
|
||||
ROL,
|
||||
ROXL,
|
||||
|
||||
CLC,
|
||||
SEC,
|
||||
PUSH,
|
||||
POP,
|
||||
SWAP,
|
||||
@ -249,6 +261,11 @@ data class Instruction(
|
||||
format.reg3 && reg3==null)
|
||||
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))
|
||||
throw IllegalArgumentException("missing a value or symbol")
|
||||
}
|
||||
@ -313,6 +330,9 @@ val instructionFormats = mutableMapOf(
|
||||
Opcode.CALLI to InstructionFormat(NN, true, false, false, false),
|
||||
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.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 ),
|
||||
@ -355,8 +375,10 @@ val instructionFormats = mutableMapOf(
|
||||
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.ROR to InstructionFormat(BW, true, true, true, false),
|
||||
Opcode.ROL to InstructionFormat(BW, true, true, true, 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),
|
||||
Opcode.ROXL to InstructionFormat(BW, true, false, false, false),
|
||||
|
||||
Opcode.COPY to InstructionFormat(NN, true, true, false, true ),
|
||||
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.POP to InstructionFormat(BW, true, false, false, 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)
|
||||
)
|
||||
|
@ -19,6 +19,7 @@ class VirtualMachine(val memory: Memory, program: List<Instruction>) {
|
||||
val valueStack = Stack<Int>() // max 128 entries
|
||||
var pc = 0
|
||||
var stepCount = 0
|
||||
var statusCarry = false
|
||||
|
||||
init {
|
||||
if(program.size>65536)
|
||||
@ -58,6 +59,7 @@ class VirtualMachine(val memory: Memory, program: List<Instruction>) {
|
||||
pc = 0
|
||||
stepCount = 0
|
||||
callStack.clear()
|
||||
statusCarry = false
|
||||
}
|
||||
|
||||
fun exit() {
|
||||
@ -97,6 +99,8 @@ class VirtualMachine(val memory: Memory, program: List<Instruction>) {
|
||||
Opcode.CALLI -> InsCALLI(ins)
|
||||
Opcode.SYSCALL -> InsSYSCALL(ins)
|
||||
Opcode.RETURN -> InsRETURN()
|
||||
Opcode.BSTCC -> InsBSTCC(ins)
|
||||
Opcode.BSTCS -> InsBSTCS(ins)
|
||||
Opcode.BZ -> InsBZ(ins)
|
||||
Opcode.BNZ -> InsBNZ(ins)
|
||||
Opcode.BEQ -> InsBEQ(ins)
|
||||
@ -138,8 +142,10 @@ class VirtualMachine(val memory: Memory, program: List<Instruction>) {
|
||||
Opcode.ASR -> InsASR(ins)
|
||||
Opcode.LSR -> InsLSR(ins)
|
||||
Opcode.LSL -> InsLSL(ins)
|
||||
Opcode.ROR -> InsROR(ins)
|
||||
Opcode.ROL -> InsROL(ins)
|
||||
Opcode.ROR -> InsROR(ins, false)
|
||||
Opcode.ROXR -> InsROR(ins, true)
|
||||
Opcode.ROL -> InsROL(ins, false)
|
||||
Opcode.ROXL -> InsROL(ins, true)
|
||||
Opcode.SWAP -> InsSWAP(ins)
|
||||
Opcode.CONCAT -> InsCONCAT(ins)
|
||||
Opcode.PUSH -> InsPUSH(ins)
|
||||
@ -312,6 +318,20 @@ class VirtualMachine(val memory: Memory, program: List<Instruction>) {
|
||||
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) {
|
||||
when(i.type!!) {
|
||||
VmDataType.BYTE -> {
|
||||
@ -666,6 +686,7 @@ class VirtualMachine(val memory: Memory, program: List<Instruction>) {
|
||||
|
||||
private fun InsASR(i: Instruction) {
|
||||
val (left: Int, right: Int) = getLogicalOperandsS(i)
|
||||
statusCarry = (left and 1)!=0
|
||||
when(i.type!!) {
|
||||
VmDataType.BYTE -> registers.setSB(i.reg1!!, (left shr right).toByte())
|
||||
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) {
|
||||
val (left: UInt, right: UInt) = getLogicalOperandsU(i)
|
||||
statusCarry = (left and 1u)!=0u
|
||||
when(i.type!!) {
|
||||
VmDataType.BYTE -> registers.setUB(i.reg1!!, (left shr right.toInt()).toUByte())
|
||||
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) {
|
||||
val (left: UInt, right: UInt) = getLogicalOperandsU(i)
|
||||
when(i.type!!) {
|
||||
VmDataType.BYTE -> registers.setUB(i.reg1!!, (left shl right.toInt()).toUByte())
|
||||
VmDataType.WORD -> registers.setUW(i.reg1!!, (left shl right.toInt()).toUShort())
|
||||
VmDataType.BYTE -> {
|
||||
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++
|
||||
}
|
||||
|
||||
private fun InsROR(i: Instruction) {
|
||||
val (left: UInt, right: UInt) = getLogicalOperandsU(i)
|
||||
when(i.type!!) {
|
||||
VmDataType.BYTE -> registers.setUB(i.reg1!!, (left.rotateRight(right.toInt()).toUByte()))
|
||||
VmDataType.WORD -> registers.setUW(i.reg1!!, (left.rotateRight(right.toInt()).toUShort()))
|
||||
private fun InsROR(i: Instruction, useCarry: Boolean) {
|
||||
val newStatusCarry: Boolean
|
||||
when (i.type!!) {
|
||||
VmDataType.BYTE -> {
|
||||
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++
|
||||
statusCarry = newStatusCarry
|
||||
}
|
||||
|
||||
private fun InsROL(i: Instruction) {
|
||||
val (left: UInt, right: UInt) = getLogicalOperandsU(i)
|
||||
when(i.type!!) {
|
||||
VmDataType.BYTE -> registers.setUB(i.reg1!!, (left.rotateLeft(right.toInt()).toUByte()))
|
||||
VmDataType.WORD -> registers.setUW(i.reg1!!, (left.rotateLeft(right.toInt()).toUShort()))
|
||||
private fun InsROL(i: Instruction, useCarry: Boolean) {
|
||||
val newStatusCarry: Boolean
|
||||
when (i.type!!) {
|
||||
VmDataType.BYTE -> {
|
||||
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++
|
||||
statusCarry = newStatusCarry
|
||||
}
|
||||
|
||||
private fun InsSWAP(i: Instruction) {
|
||||
|
Loading…
x
Reference in New Issue
Block a user