simplified opcodes (removed COPY_XXX and MEM signed/unsigned distinction)

This commit is contained in:
Irmen de Jong 2018-10-27 22:08:46 +02:00
parent f4e2641f7c
commit 7c4846700b
11 changed files with 131 additions and 403 deletions

View File

@ -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]

View File

@ -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")
}

View File

@ -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)
}
}

View File

@ -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
}
}

View File

@ -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"
}

View File

@ -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 -> {}
}
}

View File

@ -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
)

View File

@ -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()}"

View File

@ -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('$')) {

View File

@ -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)

View File

@ -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))