mirror of
https://github.com/irmen/prog8.git
synced 2025-02-21 10:29:03 +00:00
vm: implementing rol/ror
This commit is contained in:
parent
a8cf9f5cc4
commit
a0face4a28
@ -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)
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -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()
|
||||||
|
@ -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) {
|
||||||
|
@ -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
|
||||||
|
@ -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" />
|
<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:" />
|
<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;|>" />
|
<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>
|
</highlighting>
|
||||||
<extensionMap>
|
<extensionMap>
|
||||||
<mapping ext="p8" />
|
<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 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)
|
||||||
)
|
)
|
||||||
|
@ -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) {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user