mirror of
https://github.com/irmen/prog8.git
synced 2024-11-25 19:31:36 +00:00
simplified opcodes (removed COPY_XXX and MEM signed/unsigned distinction)
This commit is contained in:
parent
f4e2641f7c
commit
7c4846700b
@ -50,12 +50,26 @@ sub start() {
|
||||
|
||||
|
||||
; all possible assignments to a BYTE VARIABLE
|
||||
|
||||
assignments:
|
||||
A = 42
|
||||
A = Y
|
||||
A = X
|
||||
Y = X
|
||||
A = ub
|
||||
X = ub
|
||||
Y = ub
|
||||
A = mubyte
|
||||
X = mubyte
|
||||
Y = mubyte
|
||||
A = ubarr1[2]
|
||||
X = ubarr1[2]
|
||||
Y = ubarr1[2]
|
||||
A = ubmatrix1[1,2]
|
||||
X = ubmatrix1[1,2]
|
||||
Y = ubmatrix1[1,2]
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
@ -459,8 +459,8 @@ class AstChecker(private val namespace: INameScope,
|
||||
if(arraySize > 51)
|
||||
err("float arrayspec length must be 1-51")
|
||||
DataType.MATRIX_B, DataType.MATRIX_UB ->
|
||||
if(arraySize > 256)
|
||||
err("invalid matrix size, must be 1-256")
|
||||
if(arraySize > 32768)
|
||||
err("invalid matrix size, must be 1-32768")
|
||||
else -> {}
|
||||
}
|
||||
}
|
||||
@ -936,8 +936,8 @@ class AstChecker(private val namespace: INameScope,
|
||||
(targetDt==DataType.MATRIX_B && value.type==DataType.ARRAY_B)) {
|
||||
val arraySpecSize = arrayspec.size()
|
||||
if(arraySpecSize!=null && arraySpecSize>0) {
|
||||
if(arraySpecSize<1 || arraySpecSize>256)
|
||||
return err("invalid matrix size, must be 1-256")
|
||||
if(arraySpecSize<1 || arraySpecSize>32768)
|
||||
return err("invalid matrix size, must be 1-32768")
|
||||
val constX = arrayspec.x.constValue(namespace, heap)
|
||||
val constY = arrayspec.y?.constValue(namespace, heap)
|
||||
if (constX?.asIntegerValue == null || (constY!=null && constY.asIntegerValue == null))
|
||||
@ -949,7 +949,7 @@ class AstChecker(private val namespace: INameScope,
|
||||
return err("initializer matrix size mismatch (expecting $expectedSize, got ${matrix.size} elements)")
|
||||
return true
|
||||
}
|
||||
return err("invalid matrix size, must be 1-256")
|
||||
return err("invalid matrix size, must be 1-32768")
|
||||
}
|
||||
return err("invalid matrix initialization value of type ${value.type} - expecting byte arrayspec")
|
||||
}
|
||||
|
@ -126,7 +126,7 @@ class AstIdentifiersChecker : IAstProcessor {
|
||||
if(forLoop.decltype!=null)
|
||||
checkResult.add(SyntaxError("register loop variables cannot be explicitly declared with a datatype", forLoop.position))
|
||||
if(forLoop.loopRegister == Register.X || forLoop.loopRegister==Register.XY || forLoop.loopRegister==Register.AX)
|
||||
checkResult.add(SyntaxError("it's not possible to write to the X register because it's used as an internal pointer", forLoop.position))
|
||||
printWarning("possible problem writing to the X register, because it's used as an internal pointer", forLoop.position)
|
||||
} else if(forLoop.loopVar!=null) {
|
||||
val varName = forLoop.loopVar.nameInSource.last()
|
||||
when (forLoop.decltype) {
|
||||
@ -148,7 +148,7 @@ class AstIdentifiersChecker : IAstProcessor {
|
||||
|
||||
override fun process(assignTarget: AssignTarget): AssignTarget {
|
||||
if(assignTarget.register==Register.X || assignTarget.register==Register.AX || assignTarget.register==Register.XY)
|
||||
checkResult.add(SyntaxError("it's not possible to write to the X register because it's used as an internal pointer", assignTarget.position))
|
||||
printWarning("possible problem writing to the X register, because it's used as an internal pointer", assignTarget.position)
|
||||
return super.process(assignTarget)
|
||||
}
|
||||
}
|
||||
|
@ -350,14 +350,12 @@ private class StatementTranslator(private val prog: IntermediateProgram,
|
||||
|
||||
private fun opcodePopmem(dt: DataType): Opcode {
|
||||
return when (dt) {
|
||||
DataType.UBYTE -> Opcode.POP_MEM_UB
|
||||
DataType.BYTE -> Opcode.POP_MEM_B
|
||||
DataType.UWORD -> Opcode.POP_MEM_UW
|
||||
DataType.WORD -> Opcode.POP_MEM_W
|
||||
DataType.UBYTE, DataType.BYTE -> Opcode.POP_MEM_BYTE
|
||||
DataType.UWORD, DataType.WORD -> Opcode.POP_MEM_WORD
|
||||
DataType.FLOAT -> Opcode.POP_MEM_FLOAT
|
||||
DataType.STR, DataType.STR_P, DataType.STR_S, DataType.STR_PS,
|
||||
DataType.ARRAY_UB, DataType.ARRAY_UW, DataType.ARRAY_F, DataType.MATRIX_UB,
|
||||
DataType.ARRAY_B, DataType.ARRAY_W, DataType.MATRIX_B -> Opcode.POP_MEM_UW
|
||||
DataType.ARRAY_B, DataType.ARRAY_W, DataType.MATRIX_B -> Opcode.POP_MEM_WORD
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -25,10 +25,6 @@ open class Instruction(val opcode: Opcode,
|
||||
// opcodes that manipulate a variable
|
||||
"${opcode.toString().toLowerCase()} ${callLabel?:""} ${callLabel2?:""}".trimEnd()
|
||||
}
|
||||
opcode in setOf(Opcode.COPY_MEM_BYTE, Opcode.COPY_MEM_WORD, Opcode.COPY_MEM_FLOAT) -> {
|
||||
// opcodes with two (address) args
|
||||
"${opcode.toString().toLowerCase()} $arg $arg2"
|
||||
}
|
||||
callLabel==null -> "${opcode.toString().toLowerCase()} $argStr"
|
||||
else -> "${opcode.toString().toLowerCase()} $callLabel $argStr"
|
||||
}
|
||||
|
@ -79,54 +79,47 @@ class IntermediateProgram(val name: String, var loadAddress: Int, val heap: Heap
|
||||
when (it[0].value.opcode) {
|
||||
Opcode.PUSH_VAR_BYTE ->
|
||||
if (it[1].value.opcode == Opcode.POP_VAR_BYTE) {
|
||||
if (it[0].value.callLabel != it[1].value.callLabel)
|
||||
instructionsToReplace[it[0].index] = Instruction(Opcode.COPY_VAR_BYTE, null, null, it[0].value.callLabel, it[1].value.callLabel)
|
||||
else
|
||||
if (it[0].value.callLabel == it[1].value.callLabel) {
|
||||
instructionsToReplace[it[0].index] = Instruction(Opcode.NOP)
|
||||
instructionsToReplace[it[1].index] = Instruction(Opcode.NOP)
|
||||
instructionsToReplace[it[1].index] = Instruction(Opcode.NOP)
|
||||
}
|
||||
}
|
||||
Opcode.PUSH_VAR_WORD ->
|
||||
if (it[1].value.opcode == Opcode.POP_VAR_WORD) {
|
||||
if (it[0].value.callLabel != it[1].value.callLabel)
|
||||
instructionsToReplace[it[0].index] = Instruction(Opcode.COPY_VAR_WORD, null, null, it[0].value.callLabel, it[1].value.callLabel)
|
||||
else
|
||||
if (it[0].value.callLabel == it[1].value.callLabel) {
|
||||
instructionsToReplace[it[0].index] = Instruction(Opcode.NOP)
|
||||
instructionsToReplace[it[1].index] = Instruction(Opcode.NOP)
|
||||
instructionsToReplace[it[1].index] = Instruction(Opcode.NOP)
|
||||
}
|
||||
}
|
||||
Opcode.PUSH_VAR_FLOAT ->
|
||||
if (it[1].value.opcode == Opcode.POP_VAR_FLOAT) {
|
||||
if (it[0].value.callLabel != it[1].value.callLabel)
|
||||
instructionsToReplace[it[0].index] = Instruction(Opcode.COPY_VAR_FLOAT, null, null, it[0].value.callLabel, it[1].value.callLabel)
|
||||
else
|
||||
if (it[0].value.callLabel == it[1].value.callLabel) {
|
||||
instructionsToReplace[it[0].index] = Instruction(Opcode.NOP)
|
||||
instructionsToReplace[it[1].index] = Instruction(Opcode.NOP)
|
||||
instructionsToReplace[it[1].index] = Instruction(Opcode.NOP)
|
||||
}
|
||||
}
|
||||
Opcode.PUSH_MEM_B, Opcode.PUSH_MEM_UB ->
|
||||
if(it[1].value.opcode == Opcode.POP_MEM_B || it[1].value.opcode == Opcode.POP_MEM_UB) {
|
||||
if(it[0].value.arg != it[1].value.arg)
|
||||
instructionsToReplace[it[0].index] = Instruction(Opcode.COPY_MEM_BYTE, it[0].value.arg, it[1].value.arg)
|
||||
else
|
||||
if(it[1].value.opcode == Opcode.POP_MEM_BYTE) {
|
||||
if(it[0].value.arg == it[1].value.arg) {
|
||||
instructionsToReplace[it[0].index] = Instruction(Opcode.NOP)
|
||||
instructionsToReplace[it[1].index] = Instruction(Opcode.NOP)
|
||||
instructionsToReplace[it[1].index] = Instruction(Opcode.NOP)
|
||||
}
|
||||
}
|
||||
Opcode.PUSH_MEM_W, Opcode.PUSH_MEM_UW ->
|
||||
if(it[1].value.opcode == Opcode.POP_MEM_W || it[1].value.opcode == Opcode.POP_MEM_UW) {
|
||||
if(it[0].value.arg != it[1].value.arg)
|
||||
instructionsToReplace[it[0].index] = Instruction(Opcode.COPY_MEM_WORD, it[0].value.arg, it[1].value.arg)
|
||||
else
|
||||
if(it[1].value.opcode == Opcode.POP_MEM_WORD) {
|
||||
if(it[0].value.arg == it[1].value.arg) {
|
||||
instructionsToReplace[it[0].index] = Instruction(Opcode.NOP)
|
||||
instructionsToReplace[it[1].index] = Instruction(Opcode.NOP)
|
||||
instructionsToReplace[it[1].index] = Instruction(Opcode.NOP)
|
||||
}
|
||||
}
|
||||
Opcode.PUSH_MEM_FLOAT ->
|
||||
if(it[1].value.opcode == Opcode.POP_MEM_FLOAT) {
|
||||
if(it[0].value.arg != it[1].value.arg)
|
||||
instructionsToReplace[it[0].index] = Instruction(Opcode.COPY_MEM_FLOAT, it[0].value.arg, it[1].value.arg)
|
||||
else
|
||||
if(it[0].value.arg == it[1].value.arg) {
|
||||
instructionsToReplace[it[0].index] = Instruction(Opcode.NOP)
|
||||
instructionsToReplace[it[1].index] = Instruction(Opcode.NOP)
|
||||
instructionsToReplace[it[1].index] = Instruction(Opcode.NOP)
|
||||
}
|
||||
}
|
||||
else -> {
|
||||
}
|
||||
else -> {}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -19,23 +19,13 @@ enum class Opcode {
|
||||
DISCARD_BYTE, // discard top byte value
|
||||
DISCARD_WORD, // discard top word value
|
||||
DISCARD_FLOAT, // discard top float value
|
||||
POP_MEM_B, // pop byte value into destination memory address
|
||||
POP_MEM_UB, // pop byte value into destination memory address
|
||||
POP_MEM_W, // pop word value into destination memory address
|
||||
POP_MEM_UW, // pop word value into destination memory address
|
||||
POP_MEM_BYTE, // pop (u)byte value into destination memory address
|
||||
POP_MEM_WORD, // pop (u)word value into destination memory address
|
||||
POP_MEM_FLOAT, // pop float value into destination memory address
|
||||
POP_VAR_BYTE, // pop byte value into variable (byte, ubyte)
|
||||
POP_VAR_WORD, // pop word value into variable (word, uword)
|
||||
POP_VAR_BYTE, // pop (u)byte value into variable
|
||||
POP_VAR_WORD, // pop (u)word value into variable
|
||||
POP_VAR_FLOAT, // pop float value into variable
|
||||
|
||||
// optimized copying of one var to another (replaces push+pop)
|
||||
COPY_VAR_BYTE,
|
||||
COPY_VAR_WORD,
|
||||
COPY_VAR_FLOAT,
|
||||
COPY_MEM_BYTE,
|
||||
COPY_MEM_WORD,
|
||||
COPY_MEM_FLOAT,
|
||||
|
||||
// numeric arithmetic
|
||||
ADD_UB,
|
||||
ADD_B,
|
||||
@ -233,32 +223,6 @@ val opcodesWithVarArgument = setOf(
|
||||
Opcode.ROL2_VAR_BYTE, Opcode.ROL2_VAR_WORD, Opcode.ROR2_VAR_BYTE, Opcode.ROR2_VAR_WORD,
|
||||
Opcode.POP_VAR_BYTE, Opcode.POP_VAR_WORD, Opcode.POP_VAR_FLOAT,
|
||||
Opcode.PUSH_VAR_BYTE, Opcode.PUSH_VAR_WORD, Opcode.PUSH_VAR_FLOAT,
|
||||
Opcode.COPY_VAR_BYTE, Opcode.COPY_VAR_WORD, Opcode.COPY_VAR_FLOAT,
|
||||
Opcode.READ_INDEXED_VAR_BYTE, Opcode.READ_INDEXED_VAR_WORD, Opcode.READ_INDEXED_VAR_FLOAT,
|
||||
Opcode.WRITE_INDEXED_VAR_BYTE, Opcode.WRITE_INDEXED_VAR_WORD, Opcode.WRITE_INDEXED_VAR_FLOAT
|
||||
)
|
||||
|
||||
val pushOpcodes = setOf(
|
||||
Opcode.PUSH_BYTE,
|
||||
Opcode.PUSH_WORD,
|
||||
Opcode.PUSH_FLOAT,
|
||||
Opcode.PUSH_MEM_B,
|
||||
Opcode.PUSH_MEM_UB,
|
||||
Opcode.PUSH_MEM_W,
|
||||
Opcode.PUSH_MEM_UW,
|
||||
Opcode.PUSH_MEM_FLOAT,
|
||||
Opcode.PUSH_VAR_BYTE,
|
||||
Opcode.PUSH_VAR_WORD,
|
||||
Opcode.PUSH_VAR_FLOAT
|
||||
)
|
||||
|
||||
val popOpcodes = setOf(
|
||||
Opcode.POP_MEM_B,
|
||||
Opcode.POP_MEM_UB,
|
||||
Opcode.POP_MEM_W,
|
||||
Opcode.POP_MEM_UW,
|
||||
Opcode.POP_MEM_FLOAT,
|
||||
Opcode.POP_VAR_BYTE,
|
||||
Opcode.POP_VAR_WORD,
|
||||
Opcode.POP_VAR_FLOAT
|
||||
)
|
||||
|
@ -445,14 +445,14 @@ class AsmGen(val options: CompilationOptions, val program: IntermediateProgram,
|
||||
// """
|
||||
// }
|
||||
|
||||
Opcode.POP_MEM_B, Opcode.POP_MEM_UB -> {
|
||||
Opcode.POP_MEM_BYTE -> {
|
||||
"""
|
||||
inx
|
||||
lda ${ESTACK_LO.toHex()},x
|
||||
sta ${ins.arg!!.integerValue().toHex()}
|
||||
"""
|
||||
}
|
||||
Opcode.POP_MEM_W, Opcode.POP_MEM_UW -> {
|
||||
Opcode.POP_MEM_WORD -> {
|
||||
"""
|
||||
inx
|
||||
lda ${ESTACK_LO.toHex()},x
|
||||
@ -481,102 +481,6 @@ class AsmGen(val options: CompilationOptions, val program: IntermediateProgram,
|
||||
" lda #<${ins.callLabel} | ldy #>${ins.callLabel} | jsr prog8_lib.pop_var_float"
|
||||
}
|
||||
|
||||
Opcode.COPY_VAR_BYTE -> {
|
||||
when {
|
||||
ins.callLabel2 in registerStrings -> {
|
||||
val reg2 = ins.callLabel2!!.toLowerCase()
|
||||
if (ins.callLabel in registerStrings) {
|
||||
val reg1 = ins.callLabel!!.toLowerCase()
|
||||
// register -> register
|
||||
return when {
|
||||
reg1 == "a" -> " ta$reg2"
|
||||
reg2 == "a" -> " t${reg1}a"
|
||||
else -> " t${reg1}a | ta$reg2" // 6502 doesn't have tyx/txy
|
||||
}
|
||||
}
|
||||
// var -> reg
|
||||
return " ld${ins.callLabel2.toLowerCase()} ${ins.callLabel}"
|
||||
}
|
||||
ins.callLabel in registerStrings ->
|
||||
// reg -> var
|
||||
return " st${ins.callLabel!!.toLowerCase()} ${ins.callLabel2}"
|
||||
else ->
|
||||
// var -> var
|
||||
return " lda ${ins.callLabel} | sta ${ins.callLabel2}"
|
||||
}
|
||||
}
|
||||
Opcode.COPY_VAR_WORD -> {
|
||||
when {
|
||||
ins.callLabel2 in registerStrings -> {
|
||||
if (ins.callLabel in registerStrings) {
|
||||
// copying registerpair -> registerpair
|
||||
when {
|
||||
ins.callLabel == "AX" -> return when (ins.callLabel2) {
|
||||
"AY" -> " txy"
|
||||
"XY" -> " stx ${C64Zeropage.SCRATCH_B1.toHex()} | tax | ldy ${C64Zeropage.SCRATCH_B1.toHex()}"
|
||||
else -> ""
|
||||
}
|
||||
ins.callLabel == "AY" -> return when (ins.callLabel2) {
|
||||
"AX" -> " sty ${C64Zeropage.SCRATCH_B1.toHex()} | ldx ${C64Zeropage.SCRATCH_B1.toHex()}"
|
||||
"XY" -> " tax"
|
||||
else -> ""
|
||||
}
|
||||
else /* XY */ -> return when (ins.callLabel2) {
|
||||
"AX" -> " txa | sty ${C64Zeropage.SCRATCH_B1.toHex()} | ldx ${C64Zeropage.SCRATCH_B1.toHex()}"
|
||||
"AY" -> " txa"
|
||||
else -> ""
|
||||
}
|
||||
}
|
||||
}
|
||||
// wvar -> regpair
|
||||
val regpair = ins.callLabel2!!.toLowerCase()
|
||||
return " ld${regpair[0]} ${ins.callLabel} | ld${regpair[1]} ${ins.callLabel}+1"
|
||||
}
|
||||
ins.callLabel in registerStrings -> {
|
||||
// regpair->wvar
|
||||
val regpair = ins.callLabel!!.toLowerCase()
|
||||
return " st${regpair[0]} ${ins.callLabel2} | st${regpair[1]} ${ins.callLabel2}+1"
|
||||
}
|
||||
else -> {
|
||||
// wvar->wvar
|
||||
return " lda ${ins.callLabel} | sta ${ins.callLabel2} | " +
|
||||
" lda ${ins.callLabel}+1 | sta ${ins.callLabel2}+1"
|
||||
}
|
||||
}
|
||||
}
|
||||
Opcode.COPY_VAR_FLOAT -> {
|
||||
"""
|
||||
lda #<${ins.callLabel}
|
||||
ldy #>${ins.callLabel}
|
||||
sta ${C64Zeropage.SCRATCH_W1}
|
||||
sty ${C64Zeropage.SCRATCH_W1+1}
|
||||
lda #<${ins.callLabel2}
|
||||
ldy #>${ins.callLabel2}
|
||||
jsr prog8_lib.copy_float
|
||||
"""
|
||||
}
|
||||
|
||||
Opcode.COPY_MEM_BYTE -> " lda ${ins.arg!!.integerValue().toHex()} | sta ${ins.arg2!!.integerValue().toHex()}"
|
||||
Opcode.COPY_MEM_WORD -> {
|
||||
"""
|
||||
lda ${ins.arg!!.integerValue().toHex()}
|
||||
sta ${ins.arg2!!.integerValue().toHex()}
|
||||
lda ${(ins.arg.integerValue()+1).toHex()}
|
||||
sta ${(ins.arg2.integerValue()+1).toHex()}
|
||||
"""
|
||||
}
|
||||
Opcode.COPY_MEM_FLOAT -> {
|
||||
"""
|
||||
lda #<${ins.arg!!.integerValue().toHex()}
|
||||
ldy #>${ins.arg.integerValue().toHex()}
|
||||
sta ${C64Zeropage.SCRATCH_W1}
|
||||
sty ${C64Zeropage.SCRATCH_W1+1}
|
||||
lda #<${ins.arg2!!.integerValue().toHex()}
|
||||
ldy #>${ins.arg2.integerValue().toHex()}
|
||||
jsr prog8_lib.copy_float
|
||||
"""
|
||||
}
|
||||
|
||||
Opcode.INC_VAR_UB, Opcode.INC_VAR_B -> {
|
||||
when (ins.callLabel) {
|
||||
"A" -> " clc | adc #1"
|
||||
@ -750,22 +654,6 @@ class AsmGen(val options: CompilationOptions, val program: IntermediateProgram,
|
||||
val opcodes = segment.map { it.opcode }
|
||||
val result = mutableListOf<AsmFragment>()
|
||||
|
||||
// check for direct var assignments that should have been converted into COPY_VAR_XXX opcodes
|
||||
if((opcodes[0]==Opcode.PUSH_VAR_BYTE && opcodes[1]==Opcode.POP_VAR_BYTE) ||
|
||||
(opcodes[0]==Opcode.PUSH_VAR_WORD && opcodes[1]==Opcode.POP_VAR_WORD) ||
|
||||
(opcodes[0]==Opcode.PUSH_VAR_FLOAT && opcodes[1]==Opcode.POP_VAR_FLOAT) ||
|
||||
(opcodes[0]==Opcode.PUSH_MEM_B && opcodes[1]==Opcode.POP_MEM_B) ||
|
||||
(opcodes[0]==Opcode.PUSH_MEM_B && opcodes[1]==Opcode.POP_MEM_UB) ||
|
||||
(opcodes[0]==Opcode.PUSH_MEM_UB && opcodes[1]==Opcode.POP_MEM_B) ||
|
||||
(opcodes[0]==Opcode.PUSH_MEM_UB && opcodes[1]==Opcode.POP_MEM_UB) ||
|
||||
(opcodes[0]==Opcode.PUSH_MEM_W && opcodes[1]==Opcode.POP_MEM_W) ||
|
||||
(opcodes[0]==Opcode.PUSH_MEM_W && opcodes[1]==Opcode.POP_MEM_UW) ||
|
||||
(opcodes[0]==Opcode.PUSH_MEM_UW && opcodes[1]==Opcode.POP_MEM_W) ||
|
||||
(opcodes[0]==Opcode.PUSH_MEM_UW && opcodes[1]==Opcode.POP_MEM_UW) ||
|
||||
(opcodes[0]==Opcode.PUSH_MEM_FLOAT && opcodes[1]==Opcode.POP_MEM_FLOAT)) {
|
||||
throw AssemblyError("push+pop var/mem should have been changed into COPY_VAR_XXX opcode")
|
||||
}
|
||||
|
||||
// check for operations that modify a single value, by putting it on the stack (and popping it afterwards)
|
||||
if((opcodes[0]==Opcode.PUSH_VAR_BYTE && opcodes[2]==Opcode.POP_VAR_BYTE) ||
|
||||
(opcodes[0]==Opcode.PUSH_VAR_WORD && opcodes[2]==Opcode.POP_VAR_WORD) ||
|
||||
@ -778,10 +666,10 @@ class AsmGen(val options: CompilationOptions, val program: IntermediateProgram,
|
||||
}
|
||||
}
|
||||
}
|
||||
else if((opcodes[0]==Opcode.PUSH_MEM_UB && opcodes[2]==Opcode.POP_MEM_UB) ||
|
||||
(opcodes[0]==Opcode.PUSH_MEM_B && opcodes[2]==Opcode.POP_MEM_B) ||
|
||||
(opcodes[0]==Opcode.PUSH_MEM_UW && opcodes[2]==Opcode.POP_MEM_UW) ||
|
||||
(opcodes[0]==Opcode.PUSH_MEM_W && opcodes[2]==Opcode.POP_MEM_W) ||
|
||||
else if((opcodes[0]==Opcode.PUSH_MEM_UB && opcodes[2]==Opcode.POP_MEM_BYTE) ||
|
||||
(opcodes[0]==Opcode.PUSH_MEM_B && opcodes[2]==Opcode.POP_MEM_BYTE) ||
|
||||
(opcodes[0]==Opcode.PUSH_MEM_UW && opcodes[2]==Opcode.POP_MEM_WORD) ||
|
||||
(opcodes[0]==Opcode.PUSH_MEM_W && opcodes[2]==Opcode.POP_MEM_WORD) ||
|
||||
(opcodes[0]==Opcode.PUSH_MEM_FLOAT && opcodes[2]==Opcode.POP_MEM_FLOAT)) {
|
||||
if(segment[0].arg==segment[2].arg) {
|
||||
val fragment = sameMemOperation(segment[0].arg!!.integerValue(), segment[1])
|
||||
@ -1022,7 +910,7 @@ class AsmGen(val options: CompilationOptions, val program: IntermediateProgram,
|
||||
private val patterns = listOf(
|
||||
|
||||
// ----------- assignment to BYTE VARIABLE ----------------
|
||||
// note: var=var is done via COPY_VAR_BYTE opcode elsewhere.
|
||||
// @todo var=var
|
||||
// var = bytevalue
|
||||
AsmPattern(listOf(Opcode.PUSH_BYTE, Opcode.POP_VAR_BYTE)) { segment ->
|
||||
when (segment[1].callLabel) {
|
||||
@ -1032,6 +920,39 @@ class AsmGen(val options: CompilationOptions, val program: IntermediateProgram,
|
||||
" lda #${segment[0].arg!!.integerValue().toHex()} | sta ${segment[1].callLabel}"
|
||||
}
|
||||
},
|
||||
// var = other var
|
||||
AsmPattern(listOf(Opcode.PUSH_VAR_BYTE, Opcode.POP_VAR_BYTE)) { segment ->
|
||||
when(segment[1].callLabel) {
|
||||
"A" ->
|
||||
when(segment[0].callLabel) {
|
||||
"A" -> null
|
||||
"X" -> " txa"
|
||||
"Y" -> " tya"
|
||||
else -> " lda ${segment[0].callLabel}"
|
||||
}
|
||||
"X" ->
|
||||
when(segment[0].callLabel) {
|
||||
"A" -> " tax"
|
||||
"X" -> null
|
||||
"Y" -> " tya | tax"
|
||||
else -> " ldx ${segment[0].callLabel}"
|
||||
}
|
||||
"Y" ->
|
||||
when(segment[0].callLabel) {
|
||||
"A" -> " tay"
|
||||
"X" -> " txa | tay"
|
||||
"Y" -> null
|
||||
else -> " ldy ${segment[0].callLabel}"
|
||||
}
|
||||
else ->
|
||||
when(segment[0].callLabel) {
|
||||
"A" -> " sta ${segment[1].callLabel}"
|
||||
"X" -> " stx ${segment[1].callLabel}"
|
||||
"Y" -> " sty ${segment[1].callLabel}"
|
||||
else -> " lda ${segment[0].callLabel} | sta ${segment[1].callLabel}"
|
||||
}
|
||||
}
|
||||
},
|
||||
// var = mem (u)byte
|
||||
AsmPattern(listOf(Opcode.PUSH_MEM_B, Opcode.POP_VAR_BYTE)) { segment ->
|
||||
when(segment[1].callLabel) {
|
||||
@ -1083,24 +1004,13 @@ class AsmGen(val options: CompilationOptions, val program: IntermediateProgram,
|
||||
|
||||
|
||||
// ----------- assignment to MEMORY BYTE ----------------
|
||||
// note: mem=mem is done via COPY_MEM_BYTE opcode elsewhere.
|
||||
// @todo mem=mem
|
||||
// mem = (u)byte value
|
||||
AsmPattern(listOf(Opcode.PUSH_BYTE, Opcode.POP_MEM_B)) { segment ->
|
||||
" lda #${segment[0].arg!!.integerValue().toHex()} | sta ${segment[1].arg!!.integerValue().toHex()}"
|
||||
},
|
||||
AsmPattern(listOf(Opcode.PUSH_BYTE, Opcode.POP_MEM_UB)) { segment ->
|
||||
AsmPattern(listOf(Opcode.PUSH_BYTE, Opcode.POP_MEM_BYTE)) { segment ->
|
||||
" lda #${segment[0].arg!!.integerValue().toHex()} | sta ${segment[1].arg!!.integerValue().toHex()}"
|
||||
},
|
||||
// mem = (u)bytevar
|
||||
AsmPattern(listOf(Opcode.PUSH_VAR_BYTE, Opcode.POP_MEM_B)) { segment ->
|
||||
when(segment[0].callLabel) {
|
||||
"A" -> " sta ${segment[1].arg!!.integerValue().toHex()}"
|
||||
"X" -> " stx ${segment[1].arg!!.integerValue().toHex()}"
|
||||
"Y" -> " sty ${segment[1].arg!!.integerValue().toHex()}"
|
||||
else -> " lda ${segment[0].callLabel} | sta ${segment[1].arg!!.integerValue().toHex()}"
|
||||
}
|
||||
},
|
||||
AsmPattern(listOf(Opcode.PUSH_VAR_BYTE, Opcode.POP_MEM_UB)) { segment ->
|
||||
AsmPattern(listOf(Opcode.PUSH_VAR_BYTE, Opcode.POP_MEM_BYTE)) { segment ->
|
||||
when(segment[0].callLabel) {
|
||||
"A" -> " sta ${segment[1].arg!!.integerValue().toHex()}"
|
||||
"X" -> " stx ${segment[1].arg!!.integerValue().toHex()}"
|
||||
@ -1109,17 +1019,7 @@ class AsmGen(val options: CompilationOptions, val program: IntermediateProgram,
|
||||
}
|
||||
},
|
||||
// mem = (u)bytearray[indexvalue]
|
||||
AsmPattern(listOf(Opcode.PUSH_BYTE, Opcode.READ_INDEXED_VAR_BYTE, Opcode.POP_MEM_B)) { segment ->
|
||||
val address = segment[2].arg!!.integerValue().toHex()
|
||||
val index = segment[0].arg!!.integerValue()
|
||||
when(segment[1].callLabel) {
|
||||
"AX" -> " sta ${C64Zeropage.SCRATCH_W1} | stx ${C64Zeropage.SCRATCH_W1+1} | ldy #$index | lda (${C64Zeropage.SCRATCH_W1}),y | sta $address"
|
||||
"AY" -> " sta ${C64Zeropage.SCRATCH_W1} | sty ${C64Zeropage.SCRATCH_W1+1} | ldy #$index | lda (${C64Zeropage.SCRATCH_W1}),y | sta $address"
|
||||
"XY" -> " stx ${C64Zeropage.SCRATCH_W1} | sty ${C64Zeropage.SCRATCH_W1+1} | ldy #$index | lda (${C64Zeropage.SCRATCH_W1}),y | sta $address"
|
||||
else -> " lda ${segment[1].callLabel}+$index | sta $address"
|
||||
}
|
||||
},
|
||||
AsmPattern(listOf(Opcode.PUSH_BYTE, Opcode.READ_INDEXED_VAR_BYTE, Opcode.POP_MEM_UB)) { segment ->
|
||||
AsmPattern(listOf(Opcode.PUSH_BYTE, Opcode.READ_INDEXED_VAR_BYTE, Opcode.POP_MEM_BYTE)) { segment ->
|
||||
val address = segment[2].arg!!.integerValue().toHex()
|
||||
val index = segment[0].arg!!.integerValue()
|
||||
when(segment[1].callLabel) {
|
||||
@ -1131,8 +1031,9 @@ class AsmGen(val options: CompilationOptions, val program: IntermediateProgram,
|
||||
},
|
||||
|
||||
|
||||
|
||||
// ----------- assignment to WORD VARIABLE ----------------
|
||||
// note: var=var is done via COPY_VAR_WORD opcode elsewhere.
|
||||
// @todo var=var
|
||||
// var = wordvalue
|
||||
AsmPattern(listOf(Opcode.PUSH_WORD, Opcode.POP_VAR_WORD)) { segment ->
|
||||
val number = segment[0].arg!!.integerValue().toHex()
|
||||
@ -1276,17 +1177,9 @@ class AsmGen(val options: CompilationOptions, val program: IntermediateProgram,
|
||||
|
||||
|
||||
// ----------- assignment to MEMORY WORD ----------------
|
||||
// note: mem=mem is done via COPY_MEM_WORD opcode elsewhere.
|
||||
// @todo mem=mem
|
||||
// mem = (u)word value
|
||||
AsmPattern(listOf(Opcode.PUSH_WORD, Opcode.POP_MEM_W)) { segment ->
|
||||
"""
|
||||
lda #<${segment[0].arg!!.integerValue().toHex()}
|
||||
sta ${segment[1].arg!!.integerValue().toHex()}
|
||||
lda #>${segment[0].arg!!.integerValue().toHex()}
|
||||
sta ${(segment[1].arg!!.integerValue()+1).toHex()}
|
||||
"""
|
||||
},
|
||||
AsmPattern(listOf(Opcode.PUSH_WORD, Opcode.POP_MEM_UW)) { segment ->
|
||||
AsmPattern(listOf(Opcode.PUSH_WORD, Opcode.POP_MEM_WORD)) { segment ->
|
||||
"""
|
||||
lda #<${segment[0].arg!!.integerValue().toHex()}
|
||||
sta ${segment[1].arg!!.integerValue().toHex()}
|
||||
@ -1295,21 +1188,7 @@ class AsmGen(val options: CompilationOptions, val program: IntermediateProgram,
|
||||
"""
|
||||
},
|
||||
// mem = (u)word var
|
||||
AsmPattern(listOf(Opcode.PUSH_VAR_WORD, Opcode.POP_MEM_W)) { segment ->
|
||||
when(segment[0].callLabel) {
|
||||
"AX" -> " sta ${segment[1].arg!!.integerValue().toHex()} | stx ${(segment[1].arg!!.integerValue()+1).toHex()}"
|
||||
"AY" -> " sta ${segment[1].arg!!.integerValue().toHex()} | sty ${(segment[1].arg!!.integerValue()+1).toHex()}"
|
||||
"XY" -> " stx ${segment[1].arg!!.integerValue().toHex()} | sty ${(segment[1].arg!!.integerValue()+1).toHex()}"
|
||||
else ->
|
||||
"""
|
||||
lda ${segment[0].callLabel}
|
||||
sta ${segment[1].arg!!.integerValue().toHex()}
|
||||
lda ${segment[0].callLabel}+1
|
||||
sta ${(segment[1].arg!!.integerValue()+1).toHex()}
|
||||
"""
|
||||
}
|
||||
},
|
||||
AsmPattern(listOf(Opcode.PUSH_VAR_WORD, Opcode.POP_MEM_UW)) { segment ->
|
||||
AsmPattern(listOf(Opcode.PUSH_VAR_WORD, Opcode.POP_MEM_WORD)) { segment ->
|
||||
when(segment[0].callLabel) {
|
||||
"AX" -> " sta ${segment[1].arg!!.integerValue().toHex()} | stx ${(segment[1].arg!!.integerValue()+1).toHex()}"
|
||||
"AY" -> " sta ${segment[1].arg!!.integerValue().toHex()} | sty ${(segment[1].arg!!.integerValue()+1).toHex()}"
|
||||
@ -1324,16 +1203,7 @@ class AsmGen(val options: CompilationOptions, val program: IntermediateProgram,
|
||||
}
|
||||
},
|
||||
// mem = (u)wordarray[indexvalue]
|
||||
AsmPattern(listOf(Opcode.PUSH_BYTE, Opcode.READ_INDEXED_VAR_WORD, Opcode.POP_MEM_W)) { segment ->
|
||||
val index = segment[0].arg!!.integerValue()*2
|
||||
"""
|
||||
lda ${segment[1].callLabel}+$index
|
||||
ldy ${segment[1].callLabel}+1+$index
|
||||
sta ${segment[2].arg!!.integerValue().toHex()}
|
||||
sty ${(segment[2].arg!!.integerValue()+1).toHex()}
|
||||
"""
|
||||
},
|
||||
AsmPattern(listOf(Opcode.PUSH_BYTE, Opcode.READ_INDEXED_VAR_WORD, Opcode.POP_MEM_UW)) { segment ->
|
||||
AsmPattern(listOf(Opcode.PUSH_BYTE, Opcode.READ_INDEXED_VAR_WORD, Opcode.POP_MEM_WORD)) { segment ->
|
||||
val index = segment[0].arg!!.integerValue()*2
|
||||
"""
|
||||
lda ${segment[1].callLabel}+$index
|
||||
@ -1343,7 +1213,7 @@ class AsmGen(val options: CompilationOptions, val program: IntermediateProgram,
|
||||
"""
|
||||
},
|
||||
// assignment: mem uword = ubytearray[index_byte]
|
||||
AsmPattern(listOf(Opcode.PUSH_BYTE, Opcode.READ_INDEXED_VAR_BYTE, Opcode.UB2UWORD, Opcode.POP_MEM_UW)) { segment ->
|
||||
AsmPattern(listOf(Opcode.PUSH_BYTE, Opcode.READ_INDEXED_VAR_BYTE, Opcode.UB2UWORD, Opcode.POP_MEM_WORD)) { segment ->
|
||||
val index = segment[0].arg!!.integerValue()
|
||||
when(segment[1].callLabel) {
|
||||
"AX" -> " sta ${C64Zeropage.SCRATCH_W1} | stx ${C64Zeropage.SCRATCH_W1+1} | ldy #$index | lda (${C64Zeropage.SCRATCH_W1}),y | sta ${segment[3].arg!!.integerValue().toHex()} | lda #0 | sta ${(segment[3].arg!!.integerValue()+1).toHex()}"
|
||||
|
@ -124,16 +124,6 @@ class Program (val name: String,
|
||||
val args = if(parts.size==2) parts[1] else null
|
||||
val instruction = when(opcode) {
|
||||
Opcode.LINE -> Instruction(opcode, null, callLabel = args)
|
||||
Opcode.COPY_VAR_BYTE, Opcode.COPY_VAR_WORD, Opcode.COPY_VAR_FLOAT -> {
|
||||
val (v1, v2) = args!!.split(splitpattern, limit = 2)
|
||||
Instruction(opcode, null, null, v1, v2)
|
||||
}
|
||||
Opcode.COPY_MEM_BYTE, Opcode.COPY_MEM_WORD, Opcode.COPY_MEM_FLOAT -> {
|
||||
val (v1, v2) = args!!.split(splitpattern, limit = 2)
|
||||
val address1 = getArgValue(v1, heap)
|
||||
val address2 = getArgValue(v2, heap)
|
||||
Instruction(opcode, address1, address2)
|
||||
}
|
||||
Opcode.JUMP, Opcode.CALL, Opcode.BNEG, Opcode.BPOS,
|
||||
Opcode.BZ, Opcode.BNZ, Opcode.BCS, Opcode.BCC -> {
|
||||
if(args!!.startsWith('$')) {
|
||||
|
@ -218,30 +218,24 @@ class StackVm(private var traceOutputFile: String?) {
|
||||
}
|
||||
}
|
||||
|
||||
private fun checkDt(value: Value?, expected: DataType) {
|
||||
if(value==null)
|
||||
throw VmExecutionException("expected value")
|
||||
if(value.type!=expected)
|
||||
throw VmExecutionException("expected $expected value, found ${value.type}")
|
||||
}
|
||||
|
||||
private fun checkDt(value: Value?, expected: Set<DataType>) {
|
||||
private fun checkDt(value: Value?, vararg expected: DataType) {
|
||||
if(value==null)
|
||||
throw VmExecutionException("expected value")
|
||||
if(value.type !in expected)
|
||||
throw VmExecutionException("incompatible type found ${value.type}")
|
||||
throw VmExecutionException("incompatible type ${value.type}")
|
||||
}
|
||||
|
||||
|
||||
private fun dispatch(ins: Instruction) : Instruction {
|
||||
traceOutput?.println("\n$ins")
|
||||
when (ins.opcode) {
|
||||
Opcode.NOP -> {}
|
||||
Opcode.PUSH_BYTE -> {
|
||||
checkDt(ins.arg, setOf(DataType.UBYTE, DataType.BYTE))
|
||||
checkDt(ins.arg, DataType.UBYTE, DataType.BYTE)
|
||||
evalstack.push(ins.arg)
|
||||
}
|
||||
Opcode.PUSH_WORD -> {
|
||||
checkDt(ins.arg, setOf(DataType.UWORD, DataType.WORD) + IterableDatatypes)
|
||||
checkDt(ins.arg, *(setOf(DataType.UWORD, DataType.WORD) + IterableDatatypes).toTypedArray())
|
||||
evalstack.push(ins.arg)
|
||||
}
|
||||
Opcode.PUSH_FLOAT -> {
|
||||
@ -280,29 +274,23 @@ class StackVm(private var traceOutputFile: String?) {
|
||||
val value = evalstack.pop()
|
||||
checkDt(value, DataType.FLOAT)
|
||||
}
|
||||
Opcode.POP_MEM_UB -> {
|
||||
Opcode.POP_MEM_BYTE -> {
|
||||
val value = evalstack.pop()
|
||||
checkDt(value, DataType.UBYTE)
|
||||
checkDt(value, DataType.BYTE, DataType.UBYTE)
|
||||
val address = ins.arg!!.integerValue()
|
||||
mem.setUByte(address, value.integerValue().toShort())
|
||||
if(value.type==DataType.BYTE)
|
||||
mem.setSByte(address, value.integerValue().toShort())
|
||||
else
|
||||
mem.setUByte(address, value.integerValue().toShort())
|
||||
}
|
||||
Opcode.POP_MEM_B -> {
|
||||
Opcode.POP_MEM_WORD -> {
|
||||
val value = evalstack.pop()
|
||||
checkDt(value, DataType.BYTE)
|
||||
checkDt(value, DataType.WORD, DataType.UWORD)
|
||||
val address = ins.arg!!.integerValue()
|
||||
mem.setSByte(address, value.integerValue().toShort())
|
||||
}
|
||||
Opcode.POP_MEM_UW -> {
|
||||
val value = evalstack.pop()
|
||||
checkDt(value, DataType.UWORD)
|
||||
val address = ins.arg!!.integerValue()
|
||||
mem.setUWord(address, value.integerValue())
|
||||
}
|
||||
Opcode.POP_MEM_W -> {
|
||||
val value = evalstack.pop()
|
||||
checkDt(value, DataType.WORD)
|
||||
val address = ins.arg!!.integerValue()
|
||||
mem.setSWord(address, value.integerValue())
|
||||
if(value.type==DataType.WORD)
|
||||
mem.setSWord(address, value.integerValue())
|
||||
else
|
||||
mem.setUWord(address, value.integerValue())
|
||||
}
|
||||
Opcode.POP_MEM_FLOAT -> {
|
||||
val value = evalstack.pop()
|
||||
@ -765,12 +753,12 @@ class StackVm(private var traceOutputFile: String?) {
|
||||
}
|
||||
Opcode.PUSH_VAR_BYTE -> {
|
||||
val value = variables[ins.callLabel] ?: throw VmExecutionException("unknown variable: ${ins.callLabel}")
|
||||
checkDt(value, setOf(DataType.UBYTE, DataType.BYTE))
|
||||
checkDt(value, DataType.UBYTE, DataType.BYTE)
|
||||
evalstack.push(value)
|
||||
}
|
||||
Opcode.PUSH_VAR_WORD -> {
|
||||
val value = variables[ins.callLabel] ?: throw VmExecutionException("unknown variable: ${ins.callLabel}")
|
||||
checkDt(value, setOf(DataType.UWORD, DataType.WORD, DataType.ARRAY_UB, DataType.ARRAY_UW, DataType.ARRAY_F, DataType.STR, DataType.STR_P, DataType.STR_S, DataType.STR_PS, DataType.MATRIX_UB))
|
||||
checkDt(value, *(setOf(DataType.UWORD, DataType.WORD) + IterableDatatypes).toTypedArray())
|
||||
evalstack.push(value)
|
||||
}
|
||||
Opcode.PUSH_VAR_FLOAT -> {
|
||||
@ -780,62 +768,22 @@ class StackVm(private var traceOutputFile: String?) {
|
||||
}
|
||||
Opcode.POP_VAR_BYTE -> {
|
||||
val value = evalstack.pop()
|
||||
checkDt(value, setOf(DataType.UBYTE, DataType.BYTE))
|
||||
checkDt(value, DataType.UBYTE, DataType.BYTE)
|
||||
val variable = variables[ins.callLabel] ?: throw VmExecutionException("unknown variable: ${ins.callLabel}")
|
||||
checkDt(variable, setOf(DataType.UBYTE, DataType.BYTE))
|
||||
checkDt(variable, DataType.UBYTE, DataType.BYTE)
|
||||
if(value.type!=variable.type)
|
||||
throw VmExecutionException("datatype mismatch")
|
||||
variables[ins.callLabel!!] = value
|
||||
}
|
||||
Opcode.POP_VAR_WORD -> {
|
||||
val value = evalstack.pop()
|
||||
checkDt(value, setOf(DataType.UWORD, DataType.WORD, DataType.STR, DataType.STR_P, DataType.STR_S, DataType.STR_PS))
|
||||
checkDt(value, DataType.UWORD, DataType.WORD, DataType.STR, DataType.STR_P, DataType.STR_S, DataType.STR_PS)
|
||||
val variable = variables[ins.callLabel] ?: throw VmExecutionException("unknown variable: ${ins.callLabel}")
|
||||
checkDt(variable, setOf(DataType.UWORD, DataType.WORD, DataType.STR, DataType.STR_P, DataType.STR_S, DataType.STR_PS))
|
||||
checkDt(variable, DataType.UWORD, DataType.WORD, DataType.STR, DataType.STR_P, DataType.STR_S, DataType.STR_PS)
|
||||
if(value.type!=variable.type)
|
||||
throw VmExecutionException("datatype mismatch")
|
||||
variables[ins.callLabel!!] = value
|
||||
}
|
||||
Opcode.COPY_VAR_BYTE -> {
|
||||
val source = variables[ins.callLabel] ?: throw VmExecutionException("unknown variable: ${ins.callLabel}")
|
||||
val dest = variables[ins.callLabel2] ?: throw VmExecutionException("unknown variable: ${ins.callLabel2}")
|
||||
checkDt(source, setOf(DataType.UBYTE, DataType.BYTE))
|
||||
checkDt(dest, setOf(DataType.UBYTE, DataType.BYTE))
|
||||
if(dest.type!=source.type)
|
||||
throw VmExecutionException("datatype mismatch")
|
||||
variables[ins.callLabel2!!] = source
|
||||
}
|
||||
Opcode.COPY_VAR_WORD -> {
|
||||
val source = variables[ins.callLabel] ?: throw VmExecutionException("unknown variable: ${ins.callLabel}")
|
||||
val dest = variables[ins.callLabel2] ?: throw VmExecutionException("unknown variable: ${ins.callLabel2}")
|
||||
checkDt(source, setOf(DataType.UWORD, DataType.WORD, DataType.STR, DataType.STR_P, DataType.STR_S, DataType.STR_PS))
|
||||
checkDt(dest, setOf(DataType.UWORD, DataType.WORD, DataType.STR, DataType.STR_P, DataType.STR_S, DataType.STR_PS))
|
||||
if(dest.type!=source.type)
|
||||
throw VmExecutionException("datatype mismatch")
|
||||
variables[ins.callLabel2!!] = source
|
||||
}
|
||||
Opcode.COPY_VAR_FLOAT -> {
|
||||
val source = variables[ins.callLabel] ?: throw VmExecutionException("unknown variable: ${ins.callLabel}")
|
||||
val dest = variables[ins.callLabel2] ?: throw VmExecutionException("unknown variable: ${ins.callLabel2}")
|
||||
checkDt(source, DataType.FLOAT)
|
||||
checkDt(dest, DataType.FLOAT)
|
||||
variables[ins.callLabel2!!] = source
|
||||
}
|
||||
Opcode.COPY_MEM_BYTE -> {
|
||||
val sourceAddr = ins.arg!!.integerValue()
|
||||
val destAddr = ins.arg2!!.integerValue()
|
||||
mem.setUByte(destAddr, mem.getUByte(sourceAddr))
|
||||
}
|
||||
Opcode.COPY_MEM_WORD -> {
|
||||
val sourceAddr = ins.arg!!.integerValue()
|
||||
val destAddr = ins.arg2!!.integerValue()
|
||||
mem.setUWord(destAddr, mem.getUWord(sourceAddr))
|
||||
}
|
||||
Opcode.COPY_MEM_FLOAT -> {
|
||||
val sourceAddr = ins.arg!!.integerValue()
|
||||
val destAddr = ins.arg2!!.integerValue()
|
||||
mem.setFloat(destAddr, mem.getFloat(sourceAddr))
|
||||
}
|
||||
Opcode.POP_VAR_FLOAT -> {
|
||||
val value = evalstack.pop()
|
||||
checkDt(value, DataType.FLOAT)
|
||||
@ -1275,7 +1223,7 @@ class StackVm(private var traceOutputFile: String?) {
|
||||
// store byte value on the stack in variable[index] (index is on the stack as well)
|
||||
val index = evalstack.pop().integerValue()
|
||||
val value = evalstack.pop()
|
||||
checkDt(value, setOf(DataType.UBYTE, DataType.BYTE))
|
||||
checkDt(value, DataType.UBYTE, DataType.BYTE)
|
||||
val variable = variables[ins.callLabel] ?: throw VmExecutionException("unknown variable: ${ins.callLabel}")
|
||||
if(variable.type==DataType.UWORD) {
|
||||
// assume the variable is a pointer (address) and write the byte value to that memory location
|
||||
@ -1302,7 +1250,7 @@ class StackVm(private var traceOutputFile: String?) {
|
||||
// store word value on the stack in variable[index] (index is on the stack as well)
|
||||
val index = evalstack.pop().integerValue()
|
||||
val value = evalstack.pop()
|
||||
checkDt(value, setOf(DataType.UWORD, DataType.WORD))
|
||||
checkDt(value, DataType.UWORD, DataType.WORD)
|
||||
val variable = variables[ins.callLabel] ?: throw VmExecutionException("unknown variable: ${ins.callLabel}")
|
||||
if(variable.type==DataType.UWORD) {
|
||||
// assume the variable is a pointer (address) and write the word value to that memory location
|
||||
@ -1570,7 +1518,7 @@ class StackVm(private var traceOutputFile: String?) {
|
||||
}
|
||||
Syscall.FUNC_WRD -> {
|
||||
val value = evalstack.pop()
|
||||
checkDt(value, setOf(DataType.UBYTE, DataType.BYTE, DataType.UWORD))
|
||||
checkDt(value, DataType.UBYTE, DataType.BYTE, DataType.UWORD)
|
||||
when(value.type) {
|
||||
DataType.UBYTE, DataType.BYTE -> evalstack.push(Value(DataType.WORD, value.integerValue()))
|
||||
DataType.UWORD -> {
|
||||
@ -1587,7 +1535,7 @@ class StackVm(private var traceOutputFile: String?) {
|
||||
}
|
||||
Syscall.FUNC_UWRD -> {
|
||||
val value = evalstack.pop()
|
||||
checkDt(value, setOf(DataType.UBYTE, DataType.BYTE, DataType.WORD))
|
||||
checkDt(value, DataType.UBYTE, DataType.BYTE, DataType.WORD)
|
||||
when(value.type) {
|
||||
DataType.UBYTE -> evalstack.push(Value(DataType.UWORD, value.integerValue()))
|
||||
DataType.UWORD -> evalstack.push(value)
|
||||
|
@ -222,10 +222,10 @@ class TestStackVmOpcodes {
|
||||
Instruction(Opcode.PUSH_WORD, Value(DataType.WORD, -23456)),
|
||||
Instruction(Opcode.PUSH_BYTE, Value(DataType.UBYTE, 177)),
|
||||
Instruction(Opcode.PUSH_BYTE, Value(DataType.BYTE, -55)),
|
||||
Instruction(Opcode.POP_MEM_B, Value(DataType.UWORD, 0x2000)),
|
||||
Instruction(Opcode.POP_MEM_UB, Value(DataType.UWORD, 0x2001)),
|
||||
Instruction(Opcode.POP_MEM_W, Value(DataType.UWORD, 0x3000)),
|
||||
Instruction(Opcode.POP_MEM_UW, Value(DataType.UWORD, 0x3002)),
|
||||
Instruction(Opcode.POP_MEM_BYTE, Value(DataType.UWORD, 0x2000)),
|
||||
Instruction(Opcode.POP_MEM_BYTE, Value(DataType.UWORD, 0x2001)),
|
||||
Instruction(Opcode.POP_MEM_WORD, Value(DataType.UWORD, 0x3000)),
|
||||
Instruction(Opcode.POP_MEM_WORD, Value(DataType.UWORD, 0x3002)),
|
||||
Instruction(Opcode.POP_MEM_FLOAT, Value(DataType.UWORD, 0x4000)))
|
||||
vm.load(makeProg(ins), null)
|
||||
assertEquals(0, vm.mem.getUWord(0x2000))
|
||||
@ -281,51 +281,6 @@ class TestStackVmOpcodes {
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testCopyVar() {
|
||||
val ins = mutableListOf(
|
||||
Instruction(Opcode.COPY_VAR_BYTE, null, null, "bvar1", "bvar2"),
|
||||
Instruction(Opcode.COPY_VAR_WORD, null, null, "wvar1", "wvar2"),
|
||||
Instruction(Opcode.COPY_VAR_FLOAT, null, null, "fvar1", "fvar2"),
|
||||
Instruction(Opcode.COPY_VAR_WORD, null, null, "wvar1", "bvar2"))
|
||||
val vars = mapOf(
|
||||
"bvar1" to Value(DataType.UBYTE, 1),
|
||||
"bvar2" to Value(DataType.UBYTE, 2),
|
||||
"wvar1" to Value(DataType.UWORD, 1111),
|
||||
"wvar2" to Value(DataType.UWORD, 2222),
|
||||
"fvar1" to Value(DataType.FLOAT, 11.11),
|
||||
"fvar2" to Value(DataType.FLOAT, 22.22)
|
||||
)
|
||||
vm.load(makeProg(ins, vars), null)
|
||||
assertEquals(12, vm.variables.size)
|
||||
vm.step(3)
|
||||
assertEquals(Value(DataType.UBYTE, 1), vm.variables["bvar2"])
|
||||
assertEquals(Value(DataType.UWORD, 1111), vm.variables["wvar2"])
|
||||
assertEquals(Value(DataType.FLOAT, 11.11), vm.variables["fvar2"])
|
||||
assertFailsWith<VmExecutionException> {
|
||||
vm.step(1)
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testCopyMem() {
|
||||
val ins = mutableListOf(
|
||||
Instruction(Opcode.COPY_MEM_BYTE, Value(DataType.UWORD, 0xc000), Value(DataType.UWORD, 0xc001)),
|
||||
Instruction(Opcode.COPY_MEM_WORD, Value(DataType.UWORD, 0xc100), Value(DataType.UWORD, 0xc102)),
|
||||
Instruction(Opcode.COPY_MEM_FLOAT, Value(DataType.UWORD, 0xc200), Value(DataType.UWORD, 0xc300)))
|
||||
val mem=mapOf(0xc000 to listOf(Value(DataType.UBYTE, 0x45)),
|
||||
0xc100 to listOf(Value(DataType.UWORD, 0xc2ca)),
|
||||
0xc200 to listOf(Value(DataType.FLOAT, 42.25)))
|
||||
vm.load(makeProg(ins, mem=mem), null)
|
||||
assertEquals(0, vm.mem.getUByte(0xc001))
|
||||
assertEquals(0, vm.mem.getUWord(0xc102))
|
||||
assertEquals(0.0, vm.mem.getFloat(0xc300))
|
||||
vm.step(3)
|
||||
assertEquals(0x45, vm.mem.getUByte(0xc001))
|
||||
assertEquals(0xc2ca, vm.mem.getUWord(0xc102))
|
||||
assertEquals(42.25, vm.mem.getFloat(0xc300))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testAdd() {
|
||||
testBinaryOperator(Value(DataType.UBYTE, 140), Opcode.ADD_UB, Value(DataType.UBYTE, 222), Value(DataType.UBYTE, 106))
|
||||
|
Loading…
Reference in New Issue
Block a user