This commit is contained in:
Irmen de Jong 2018-10-17 01:01:01 +02:00
parent 1e0ce40d1d
commit 067426016d
11 changed files with 217 additions and 221 deletions

View File

@ -1,29 +1,5 @@
%import c64utils %import c64utils
%import mathlib
~ block2 $4000 {
return
}
~ block3 $3000 {
return
}
~ blockNoAddr1 {
return
}
~ blockNoAddr2 {
return
}
~ block4 $6000 {
return
}
~ blockNoAddr3 {
return
}
~ main { ~ main {
@ -33,10 +9,29 @@ sub start() {
const ubyte border_color = 2 const ubyte border_color = 2
const ubyte cursor_color = 7 const ubyte cursor_color = 7
c64.BGCOL0 = screen_color ubyte ubb
c64.EXTCOL = border_color uword uww
c64.COLOR = cursor_color byte color
byte color2
AX=XY
uww=XY
AY=uww
A++
X++
;AY++
A = ~X
A = not Y
ubb = ~ubb
uww = ~uww
color2 = ~color
uww = not uww
return return
} }
} }

View File

@ -544,6 +544,16 @@ class AstChecker(private val namespace: INameScope,
return lv return lv
} }
override fun process(expr: PrefixExpression): IExpression {
if(expr.operator=="-") {
val dt = expr.resultingDatatype(namespace, heap)
if (dt != DataType.BYTE && dt != DataType.WORD && dt != DataType.FLOAT) {
checkResult.add(ExpressionError("can only take negative of a signed number type", expr.position))
}
}
return super.process(expr)
}
override fun process(expr: BinaryExpression): IExpression { override fun process(expr: BinaryExpression): IExpression {
when(expr.operator){ when(expr.operator){
"/", "//", "%" -> { "/", "//", "%" -> {

View File

@ -39,6 +39,11 @@ class IntermediateProgram(val name: String, var loadAddress: Int, val heap: Heap
fun optimize() { fun optimize() {
println("Optimizing stackVM code...") println("Optimizing stackVM code...")
// remove nops (that are not a label)
for (blk in blocks) {
blk.instructions.removeIf { it.opcode== Opcode.NOP && it !is LabelInstr }
}
optimizeDataConversionAndUselessDiscards() optimizeDataConversionAndUselessDiscards()
optimizeVariableCopying() optimizeVariableCopying()
optimizeMultipleSequentialLineInstrs() optimizeMultipleSequentialLineInstrs()

View File

@ -143,21 +143,11 @@ enum class Opcode {
NOT_WORD, NOT_WORD,
// increment, decrement // increment, decrement
INC_B,
INC_UB,
INC_W,
INC_UW,
INC_F,
INC_VAR_B, INC_VAR_B,
INC_VAR_UB, INC_VAR_UB,
INC_VAR_W, INC_VAR_W,
INC_VAR_UW, INC_VAR_UW,
INC_VAR_F, INC_VAR_F,
DEC_B,
DEC_UB,
DEC_W,
DEC_UW,
DEC_F,
DEC_VAR_B, DEC_VAR_B,
DEC_VAR_UB, DEC_VAR_UB,
DEC_VAR_W, DEC_VAR_W,

View File

@ -17,16 +17,21 @@ class AsmGen(val options: CompilationOptions, val program: IntermediateProgram,
private lateinit var output: PrintWriter private lateinit var output: PrintWriter
init { init {
// because 64tass understands scoped names via .proc / .block, // Because 64tass understands scoped names via .proc / .block,
// we'll strip the block prefix from all scoped names in the program. // we'll strip the block prefix from all scoped names in the program.
// Also, convert invalid label names (such as "<<<anonymous-1>>>") to something that's allowed.
val newblocks = mutableListOf<IntermediateProgram.ProgramBlock>() val newblocks = mutableListOf<IntermediateProgram.ProgramBlock>()
for(block in program.blocks) { for(block in program.blocks) {
val newvars = block.variables.map { symname(it.key, block) to it.value }.toMap().toMutableMap() val newvars = block.variables.map { symname(it.key, block) to it.value }.toMap().toMutableMap()
val newlabels = block.labels.map { symname(it.key, block) to it.value}.toMap().toMutableMap() val newlabels = block.labels.map { symname(it.key, block) to it.value}.toMap().toMutableMap()
val newinstructions = block.instructions.asSequence().map { val newinstructions = block.instructions.asSequence().map {
it as? LabelInstr ?: Instruction(it.opcode, it.arg, when {
if(it.callLabel!=null) symname(it.callLabel, block) else null, it is LabelInstr -> LabelInstr(symname(it.name, block))
if(it.callLabel2!=null) symname(it.callLabel2, block) else null) it.opcode == Opcode.INLINE_ASSEMBLY -> it
else -> Instruction(it.opcode, it.arg,
if (it.callLabel != null) symname(it.callLabel, block) else null,
if (it.callLabel2 != null) symname(it.callLabel2, block) else null)
}
}.toMutableList() }.toMutableList()
val newConstants = block.integerConstants.map { symname(it.key, block) to it.value }.toMap().toMutableMap() val newConstants = block.integerConstants.map { symname(it.key, block) to it.value }.toMap().toMutableMap()
newblocks.add(IntermediateProgram.ProgramBlock( newblocks.add(IntermediateProgram.ProgramBlock(
@ -67,8 +72,14 @@ class AsmGen(val options: CompilationOptions, val program: IntermediateProgram,
return AssemblyProgram(program.name) return AssemblyProgram(program.name)
} }
private fun symname(scoped: String, block: IntermediateProgram.ProgramBlock) = private fun symname(scoped: String, block: IntermediateProgram.ProgramBlock): String {
if (scoped.startsWith("${block.shortname}.")) scoped.substring(block.shortname.length+1) else scoped val name = if (scoped.startsWith("${block.shortname}.")) scoped.substring(block.shortname.length+1) else scoped
val validName = name.replace("<<<", "prog8_").replace(">>>", "")
if(validName=="-")
return "-"
return validName.replace("-", "").replace(".", "_")
}
private fun copyFloat(source: String, target: String) { private fun copyFloat(source: String, target: String) {
// todo: optimize this to bulk copy all floats in the same loop // todo: optimize this to bulk copy all floats in the same loop
@ -292,6 +303,10 @@ class AsmGen(val options: CompilationOptions, val program: IntermediateProgram,
private fun pushByte(byte: Int) { private fun pushByte(byte: Int) {
out("\tlda #${byte.toHex()}") out("\tlda #${byte.toHex()}")
pushByteA()
}
private fun pushByteA() {
out("\tsta ${ESTACK_LO.toHex()},x") out("\tsta ${ESTACK_LO.toHex()},x")
out("\tdex") out("\tdex")
} }
@ -311,7 +326,14 @@ class AsmGen(val options: CompilationOptions, val program: IntermediateProgram,
private fun pushWord(word: Int) { private fun pushWord(word: Int) {
out("\tlda #<${word.toHex()}") out("\tlda #<${word.toHex()}")
out("\tsta ${ESTACK_LO.toHex()},x") out("\tsta ${ESTACK_LO.toHex()},x")
out("\tlda #>${word.toHex()}") out("\tlda #<${word.toHex()}")
out("\tsta ${ESTACK_HI.toHex()},x")
out("\tdex")
}
private fun pushWordAY() {
out("\tsta ${ESTACK_LO.toHex()},x")
out("\ttya")
out("\tsta ${ESTACK_HI.toHex()},x") out("\tsta ${ESTACK_HI.toHex()},x")
out("\tdex") out("\tdex")
} }
@ -350,6 +372,17 @@ class AsmGen(val options: CompilationOptions, val program: IntermediateProgram,
out("\tdex") out("\tdex")
} }
private fun popByteA() {
out("\tinx")
out("\tlda ${ESTACK_LO.toHex()},x")
}
private fun popWordAY() {
out("\ninx")
out("\tlda ${ESTACK_LO.toHex()},x")
out("\tldy ${ESTACK_HI.toHex()},x")
}
private fun instr2asm(insIdx: Int, ins: Instruction, block: IntermediateProgram.ProgramBlock): Int { private fun instr2asm(insIdx: Int, ins: Instruction, block: IntermediateProgram.ProgramBlock): Int {
if(ins is LabelInstr) { if(ins is LabelInstr) {
if(ins.name==block.shortname) if(ins.name==block.shortname)
@ -369,6 +402,7 @@ class AsmGen(val options: CompilationOptions, val program: IntermediateProgram,
Opcode.SEI -> out("\tsei") Opcode.SEI -> out("\tsei")
Opcode.CLI -> out("\tcli") Opcode.CLI -> out("\tcli")
Opcode.RETURN -> out("\trts") // todo is return really this simple? Opcode.RETURN -> out("\trts") // todo is return really this simple?
Opcode.JUMP -> out("\tjmp ${ins.callLabel}")
Opcode.B2UB -> {} // is a no-op, just carry on with the byte as-is Opcode.B2UB -> {} // is a no-op, just carry on with the byte as-is
Opcode.UB2B -> {} // is a no-op, just carry on with the byte as-is Opcode.UB2B -> {} // is a no-op, just carry on with the byte as-is
Opcode.RSAVE -> out("\tphp\n\tpha\n\ttxa\n\tpha\n\ttya\n\tpha") Opcode.RSAVE -> out("\tphp\n\tpha\n\ttxa\n\tpha\n\ttya\n\tpha")
@ -376,6 +410,7 @@ class AsmGen(val options: CompilationOptions, val program: IntermediateProgram,
Opcode.DISCARD_BYTE -> out("\tinx") // remove 1 (2) bytes from stack Opcode.DISCARD_BYTE -> out("\tinx") // remove 1 (2) bytes from stack
Opcode.DISCARD_WORD -> out("\tinx") // remove 2 bytes from stack Opcode.DISCARD_WORD -> out("\tinx") // remove 2 bytes from stack
Opcode.DISCARD_FLOAT -> out("\tinx\n\tinx\n\tinx") // remove 5 (6) bytes from stack Opcode.DISCARD_FLOAT -> out("\tinx\n\tinx\n\tinx") // remove 5 (6) bytes from stack
Opcode.INLINE_ASSEMBLY -> out(ins.callLabel) // All of the inline assembly is stored in the calllabel property.
Opcode.COPY_VAR_BYTE -> { Opcode.COPY_VAR_BYTE -> {
when { when {
ins.callLabel2 in registerStrings -> { ins.callLabel2 in registerStrings -> {
@ -504,6 +539,7 @@ class AsmGen(val options: CompilationOptions, val program: IntermediateProgram,
return 1 // skip 1 return 1 // skip 1
} }
// byte from variable onto stack // byte from variable onto stack
TODO("can be register")
pushVarByte(ins.callLabel!!) pushVarByte(ins.callLabel!!)
} }
Opcode.PUSH_WORD -> { Opcode.PUSH_WORD -> {
@ -579,6 +615,7 @@ class AsmGen(val options: CompilationOptions, val program: IntermediateProgram,
return 1 // skip 1 return 1 // skip 1
} }
// word from memory onto stack // word from memory onto stack
TODO("can be register")
pushVarWord(ins.callLabel!!) pushVarWord(ins.callLabel!!)
} }
Opcode.PUSH_FLOAT -> { Opcode.PUSH_FLOAT -> {
@ -630,44 +667,79 @@ class AsmGen(val options: CompilationOptions, val program: IntermediateProgram,
} }
pushFloat(ins.arg!!.integerValue().toHex()) pushFloat(ins.arg!!.integerValue().toHex())
} }
Opcode.INLINE_ASSEMBLY -> out(ins.callLabel) // All of the inline assembly is stored in the calllabel property. Opcode.INC_VAR_UB, Opcode.INC_VAR_B -> {
TODO("can be register")
out("\tinc ${ins.callLabel}")
}
Opcode.DEC_VAR_UB, Opcode.DEC_VAR_B -> {
TODO("can be register")
out("\tdec ${ins.callLabel}")
}
Opcode.ADD_UB, Opcode.ADD_B -> {
out("\tlda ${(ESTACK_LO+2).toHex()},x")
out("\tclc\n\tadc ${(ESTACK_LO+1).toHex()},x")
out("\tsta ${(ESTACK_LO+2).toHex()},x")
out("\tinx")
}
Opcode.SUB_UB, Opcode.SUB_B -> {
out("\tlda ${(ESTACK_LO+2).toHex()},x")
out("\tsec\n\tsbc ${(ESTACK_LO+1).toHex()},x")
out("\tsta ${(ESTACK_LO+2).toHex()},x")
out("\tinx")
}
Opcode.POP_MEM_UB, Opcode.POP_MEM_B -> {
popByteA()
out("\tsta ${ins.arg!!.integerValue().toHex()}")
}
Opcode.POP_VAR_BYTE -> {
popByteA()
TODO("can be register")
out("\tsta ${ins.callLabel}")
}
Opcode.POP_VAR_WORD -> {
popWordAY()
TODO("can be register")
out("\tsta ${ins.callLabel}")
out("\tsty ${ins.callLabel}+1")
}
Opcode.NEG_B -> {
popByteA()
out("\teor #\$ff")
out("\tsec\n\tadc #0")
pushByteA()
}
Opcode.INV_BYTE, Opcode.NOT_BYTE -> {
popByteA()
out("\teor #\$ff")
pushByteA()
}
Opcode.INV_WORD, Opcode.NOT_WORD -> {
popWordAY()
out("\teor #\$ff")
out("\tpha")
out("\ttya")
out("\teor #\$ff")
out("\ttay")
out("\tpla")
pushWordAY()
}
else-> TODO("asm for $ins") else-> TODO("asm for $ins")
// Opcode.POP_MEM_B -> TODO()
// Opcode.POP_MEM_UB -> TODO()
// Opcode.POP_MEM_W -> TODO() // Opcode.POP_MEM_W -> TODO()
// Opcode.POP_MEM_UW -> TODO() // Opcode.POP_MEM_UW -> TODO()
// Opcode.POP_MEM_FLOAT -> TODO() // Opcode.POP_MEM_FLOAT -> TODO()
// Opcode.POP_VAR_BYTE -> TODO()
// Opcode.POP_VAR_WORD -> TODO() // Opcode.POP_VAR_WORD -> TODO()
// Opcode.POP_VAR_FLOAT -> TODO() // Opcode.POP_VAR_FLOAT -> TODO()
// Opcode.COPY_VAR_FLOAT -> TODO() // Opcode.COPY_VAR_FLOAT -> TODO()
// Opcode.INC_B -> TODO()
// Opcode.INC_UB -> TODO()
// Opcode.INC_W -> TODO()
// Opcode.INC_UW -> TODO()
// Opcode.INC_F -> TODO()
// Opcode.INC_VAR_B -> TODO()
// Opcode.INC_VAR_UB -> TODO()
// Opcode.INC_VAR_W -> TODO() // Opcode.INC_VAR_W -> TODO()
// Opcode.INC_VAR_UW -> TODO() // Opcode.INC_VAR_UW -> TODO()
// Opcode.INC_VAR_F -> TODO() // Opcode.INC_VAR_F -> TODO()
// Opcode.DEC_B -> TODO()
// Opcode.DEC_UB -> TODO()
// Opcode.DEC_W -> TODO()
// Opcode.DEC_UW -> TODO()
// Opcode.DEC_F -> TODO()
// Opcode.DEC_VAR_B -> TODO()
// Opcode.DEC_VAR_UB -> TODO()
// Opcode.DEC_VAR_W -> TODO() // Opcode.DEC_VAR_W -> TODO()
// Opcode.DEC_VAR_UW -> TODO() // Opcode.DEC_VAR_UW -> TODO()
// Opcode.DEC_VAR_F -> TODO() // Opcode.DEC_VAR_F -> TODO()
// Opcode.ADD_UB -> TODO()
// Opcode.ADD_B -> TODO()
// Opcode.ADD_UW -> TODO() // Opcode.ADD_UW -> TODO()
// Opcode.ADD_W -> TODO() // Opcode.ADD_W -> TODO()
// Opcode.ADD_F -> TODO() // Opcode.ADD_F -> TODO()
// Opcode.SUB_UB -> TODO()
// Opcode.SUB_B -> TODO()
// Opcode.SUB_UW -> TODO() // Opcode.SUB_UW -> TODO()
// Opcode.SUB_W -> TODO() // Opcode.SUB_W -> TODO()
// Opcode.SUB_F -> TODO() // Opcode.SUB_F -> TODO()
@ -696,7 +768,6 @@ class AsmGen(val options: CompilationOptions, val program: IntermediateProgram,
// Opcode.POW_UW -> TODO() // Opcode.POW_UW -> TODO()
// Opcode.POW_W -> TODO() // Opcode.POW_W -> TODO()
// Opcode.POW_F -> TODO() // Opcode.POW_F -> TODO()
// Opcode.NEG_B -> TODO()
// Opcode.NEG_W -> TODO() // Opcode.NEG_W -> TODO()
// Opcode.NEG_F -> TODO() // Opcode.NEG_F -> TODO()
// Opcode.SHL_BYTE -> TODO() // Opcode.SHL_BYTE -> TODO()
@ -741,8 +812,6 @@ class AsmGen(val options: CompilationOptions, val program: IntermediateProgram,
// Opcode.BITOR_WORD -> TODO() // Opcode.BITOR_WORD -> TODO()
// Opcode.BITXOR_BYTE -> TODO() // Opcode.BITXOR_BYTE -> TODO()
// Opcode.BITXOR_WORD -> TODO() // Opcode.BITXOR_WORD -> TODO()
// Opcode.INV_BYTE -> TODO()
// Opcode.INV_WORD -> TODO()
// Opcode.LSB -> TODO() // Opcode.LSB -> TODO()
// Opcode.MSB -> TODO() // Opcode.MSB -> TODO()
// Opcode.B2WORD -> TODO() // Opcode.B2WORD -> TODO()
@ -758,8 +827,6 @@ class AsmGen(val options: CompilationOptions, val program: IntermediateProgram,
// Opcode.OR_WORD -> TODO() // Opcode.OR_WORD -> TODO()
// Opcode.XOR_BYTE -> TODO() // Opcode.XOR_BYTE -> TODO()
// Opcode.XOR_WORD -> TODO() // Opcode.XOR_WORD -> TODO()
// Opcode.NOT_BYTE -> TODO()
// Opcode.NOT_WORD -> TODO()
// Opcode.LESS_B -> TODO() // Opcode.LESS_B -> TODO()
// Opcode.LESS_UB -> TODO() // Opcode.LESS_UB -> TODO()
// Opcode.LESS_W -> TODO() // Opcode.LESS_W -> TODO()
@ -792,7 +859,6 @@ class AsmGen(val options: CompilationOptions, val program: IntermediateProgram,
// Opcode.WRITE_INDEXED_VAR_BYTE -> TODO() // Opcode.WRITE_INDEXED_VAR_BYTE -> TODO()
// Opcode.WRITE_INDEXED_VAR_WORD -> TODO() // Opcode.WRITE_INDEXED_VAR_WORD -> TODO()
// Opcode.WRITE_INDEXED_VAR_FLOAT -> TODO() // Opcode.WRITE_INDEXED_VAR_FLOAT -> TODO()
// Opcode.JUMP -> TODO()
// Opcode.BCS -> TODO() // Opcode.BCS -> TODO()
// Opcode.BCC -> TODO() // Opcode.BCC -> TODO()
// Opcode.BZ -> TODO() // Opcode.BZ -> TODO()

View File

@ -13,7 +13,7 @@ class AssemblyProgram(val name: String) {
println("Generating machine code program...") println("Generating machine code program...")
val command = mutableListOf("64tass", "--ascii", "--case-sensitive", "-Wall", "-Wno-strict-bool", val command = mutableListOf("64tass", "--ascii", "--case-sensitive", "-Wall", "-Wno-strict-bool",
"--dump-labels", "--vice-labels", "-l", viceMonListFile, "--no-monitor") "-Werror", "--dump-labels", "--vice-labels", "-l", viceMonListFile, "--no-monitor")
val outFile = when(options.output) { val outFile = when(options.output) {
OutputType.PRG -> { OutputType.PRG -> {

View File

@ -13,7 +13,7 @@ import prog8.functions.BuiltinFunctions
todo remove if statements with empty statement blocks todo remove if statements with empty statement blocks
todo replace if statements with only else block todo replace if statements with only else block
todo statement optimization: create augmented assignment from assignment that only refers to its lvalue (A=A+10, A=4*A, ...) todo statement optimization: create augmented assignment from assignment that only refers to its lvalue (A=A+10, A=4*A, ...)
todo statement optimization: X+=1, X-=1 --> X++/X-- , todo statement optimization: X+=1, X-=1 --> X++/X-- (to 3? 4? incs/decs in a row after that use arithmetic)
todo remove statements that have no effect X=X , X+=0, X-=0, X*=1, X/=1, X//=1, A |= 0, A ^= 0, A<<=0, etc etc todo remove statements that have no effect X=X , X+=0, X-=0, X*=1, X/=1, X//=1, A |= 0, A ^= 0, A<<=0, etc etc
todo optimize addition with self into shift 1 (A+=A -> A<<=1) todo optimize addition with self into shift 1 (A+=A -> A<<=1)
todo assignment optimization: optimize some simple multiplications and divisions into shifts (A*=2 -> lsl(A), X=X/2 -> lsr(X) ) todo assignment optimization: optimize some simple multiplications and divisions into shifts (A*=2 -> lsl(A), X=X/2 -> lsr(X) )

View File

@ -633,56 +633,6 @@ class StackVm(private var traceOutputFile: String?) {
checkDt(v, DataType.UWORD) checkDt(v, DataType.UWORD)
evalstack.push(v.inv()) evalstack.push(v.inv())
} }
Opcode.INC_B -> {
val v = evalstack.pop()
checkDt(v, DataType.BYTE)
evalstack.push(v.inc())
}
Opcode.INC_UB -> {
val v = evalstack.pop()
checkDt(v, DataType.UBYTE)
evalstack.push(v.inc())
}
Opcode.INC_W -> {
val v = evalstack.pop()
checkDt(v, DataType.WORD)
evalstack.push(v.inc())
}
Opcode.INC_UW -> {
val v = evalstack.pop()
checkDt(v, DataType.UWORD)
evalstack.push(v.inc())
}
Opcode.INC_F -> {
val v = evalstack.pop()
checkDt(v, DataType.FLOAT)
evalstack.push(v.inc())
}
Opcode.DEC_UB -> {
val v = evalstack.pop()
checkDt(v, DataType.UBYTE)
evalstack.push(v.dec())
}
Opcode.DEC_B -> {
val v = evalstack.pop()
checkDt(v, DataType.BYTE)
evalstack.push(v.dec())
}
Opcode.DEC_UW -> {
val v = evalstack.pop()
checkDt(v, DataType.UWORD)
evalstack.push(v.dec())
}
Opcode.DEC_W -> {
val v = evalstack.pop()
checkDt(v, DataType.WORD)
evalstack.push(v.dec())
}
Opcode.DEC_F -> {
val v = evalstack.pop()
checkDt(v, DataType.FLOAT)
evalstack.push(v.dec())
}
Opcode.SYSCALL -> dispatchSyscall(ins) Opcode.SYSCALL -> dispatchSyscall(ins)
Opcode.SEC -> P_carry = true Opcode.SEC -> P_carry = true
Opcode.CLC -> P_carry = false Opcode.CLC -> P_carry = false

View File

@ -424,26 +424,6 @@ class TestStackVmOpcodes {
testUnaryOperator(Value(DataType.UWORD, 5000), Opcode.NOT_WORD, Value(DataType.UBYTE, 0)) testUnaryOperator(Value(DataType.UWORD, 5000), Opcode.NOT_WORD, Value(DataType.UBYTE, 0))
} }
@Test
fun testInc() {
testUnaryOperator(Value(DataType.UBYTE, 255), Opcode.INC_UB, Value(DataType.UBYTE, 0))
testUnaryOperator(Value(DataType.UBYTE, 99), Opcode.INC_UB, Value(DataType.UBYTE, 100))
testUnaryOperator(Value(DataType.UWORD, 65535), Opcode.INC_UW, Value(DataType.UWORD, 0))
testUnaryOperator(Value(DataType.UWORD, 999), Opcode.INC_UW, Value(DataType.UWORD, 1000))
testUnaryOperator(Value(DataType.FLOAT, -1.0), Opcode.INC_F, Value(DataType.FLOAT, 0.0))
testUnaryOperator(Value(DataType.FLOAT, 2022.5), Opcode.INC_F, Value(DataType.FLOAT, 2023.5))
}
@Test
fun testDec() {
testUnaryOperator(Value(DataType.UBYTE, 100), Opcode.DEC_UB, Value(DataType.UBYTE, 99))
testUnaryOperator(Value(DataType.UBYTE, 0), Opcode.DEC_UB, Value(DataType.UBYTE, 255))
testUnaryOperator(Value(DataType.UWORD, 1000), Opcode.DEC_UW, Value(DataType.UWORD, 999))
testUnaryOperator(Value(DataType.UWORD, 0), Opcode.DEC_UW, Value(DataType.UWORD, 65535))
testUnaryOperator(Value(DataType.FLOAT, 0.5), Opcode.DEC_F, Value(DataType.FLOAT, -0.5))
testUnaryOperator(Value(DataType.FLOAT, 2022.5), Opcode.DEC_F, Value(DataType.FLOAT, 2021.5))
}
@Test @Test
fun testNeg() { fun testNeg() {
testUnaryOperator(Value(DataType.BYTE, 12), Opcode.NEG_B, Value(DataType.BYTE, -12)) testUnaryOperator(Value(DataType.BYTE, 12), Opcode.NEG_B, Value(DataType.BYTE, -12))

View File

@ -7,80 +7,80 @@
~ c64 { ~ c64 {
memory byte SCRATCH_ZP1 = $02 ; scratch register #1 in ZP memory ubyte SCRATCH_ZP1 = $02 ; scratch register #1 in ZP
memory byte SCRATCH_ZP2 = $03 ; scratch register #2 in ZP memory ubyte SCRATCH_ZP2 = $03 ; scratch register #2 in ZP
memory word SCRATCH_ZPWORD1 = $fb ; scratch word in ZP ($fb/$fc) memory uword SCRATCH_ZPWORD1 = $fb ; scratch word in ZP ($fb/$fc)
memory word SCRATCH_ZPWORD2 = $fd ; scratch word in ZP ($fd/$fe) memory uword SCRATCH_ZPWORD2 = $fd ; scratch word in ZP ($fd/$fe)
memory byte TIME_HI = $a0 ; software jiffy clock, hi byte memory ubyte TIME_HI = $a0 ; software jiffy clock, hi byte
memory byte TIME_MID = $a1 ; .. mid byte memory ubyte TIME_MID = $a1 ; .. mid byte
memory byte TIME_LO = $a2 ; .. lo byte. Updated by IRQ every 1/60 sec memory ubyte TIME_LO = $a2 ; .. lo byte. Updated by IRQ every 1/60 sec
memory byte STKEY = $91 ; various keyboard statuses (updated by IRQ) memory ubyte STKEY = $91 ; various keyboard statuses (updated by IRQ)
memory byte SFDX = $cb ; current key pressed (matrix value) (updated by IRQ) memory ubyte SFDX = $cb ; current key pressed (matrix value) (updated by IRQ)
memory byte COLOR = $0286 ; cursor color memory ubyte COLOR = $0286 ; cursor color
memory byte HIBASE = $0288 ; screen base address / 256 (hi-byte of screen memory address) memory ubyte HIBASE = $0288 ; screen base address / 256 (hi-byte of screen memory address)
memory word CINV = $0314 ; IRQ vector memory uword CINV = $0314 ; IRQ vector
memory word NMI_VEC = $FFFA ; 6502 nmi vector, determined by the kernal if banked in memory uword NMI_VEC = $FFFA ; 6502 nmi vector, determined by the kernal if banked in
memory word RESET_VEC = $FFFC ; 6502 reset vector, determined by the kernal if banked in memory uword RESET_VEC = $FFFC ; 6502 reset vector, determined by the kernal if banked in
memory word IRQ_VEC = $FFFE ; 6502 interrupt vector, determined by the kernal if banked in memory uword IRQ_VEC = $FFFE ; 6502 interrupt vector, determined by the kernal if banked in
memory byte[40, 25] Screen = $0400 ; default character screen matrix memory ubyte[40, 25] Screen = $0400 ; default character screen matrix
memory byte[40, 25] Colors = $d800 ; character screen colors memory ubyte[40, 25] Colors = $d800 ; character screen colors
; ---- VIC-II registers ---- ; ---- VIC-II registers ----
memory byte SP0X = $d000 memory ubyte SP0X = $d000
memory byte SP0Y = $d001 memory ubyte SP0Y = $d001
memory byte SP1X = $d002 memory ubyte SP1X = $d002
memory byte SP1Y = $d003 memory ubyte SP1Y = $d003
memory byte SP2X = $d004 memory ubyte SP2X = $d004
memory byte SP2Y = $d005 memory ubyte SP2Y = $d005
memory byte SP3X = $d006 memory ubyte SP3X = $d006
memory byte SP3Y = $d007 memory ubyte SP3Y = $d007
memory byte SP4X = $d008 memory ubyte SP4X = $d008
memory byte SP4Y = $d009 memory ubyte SP4Y = $d009
memory byte SP5X = $d00a memory ubyte SP5X = $d00a
memory byte SP5Y = $d00b memory ubyte SP5Y = $d00b
memory byte SP6X = $d00c memory ubyte SP6X = $d00c
memory byte SP6Y = $d00d memory ubyte SP6Y = $d00d
memory byte SP7X = $d00e memory ubyte SP7X = $d00e
memory byte SP7Y = $d00f memory ubyte SP7Y = $d00f
memory byte MSIGX = $d010 memory ubyte MSIGX = $d010
memory byte SCROLY = $d011 memory ubyte SCROLY = $d011
memory byte RASTER = $d012 memory ubyte RASTER = $d012
memory byte LPENX = $d013 memory ubyte LPENX = $d013
memory byte LPENY = $d014 memory ubyte LPENY = $d014
memory byte SPENA = $d015 memory ubyte SPENA = $d015
memory byte SCROLX = $d016 memory ubyte SCROLX = $d016
memory byte YXPAND = $d017 memory ubyte YXPAND = $d017
memory byte VMCSB = $d018 memory ubyte VMCSB = $d018
memory byte VICIRQ = $d019 memory ubyte VICIRQ = $d019
memory byte IREQMASK = $d01a memory ubyte IREQMASK = $d01a
memory byte SPBGPR = $d01b memory ubyte SPBGPR = $d01b
memory byte SPMC = $d01c memory ubyte SPMC = $d01c
memory byte XXPAND = $d01d memory ubyte XXPAND = $d01d
memory byte SPSPCL = $d01e memory ubyte SPSPCL = $d01e
memory byte SPBGCL = $d01f memory ubyte SPBGCL = $d01f
memory byte EXTCOL = $d020 ; border color memory ubyte EXTCOL = $d020 ; border color
memory byte BGCOL0 = $d021 ; screen color memory ubyte BGCOL0 = $d021 ; screen color
memory byte BGCOL1 = $d022 memory ubyte BGCOL1 = $d022
memory byte BGCOL2 = $d023 memory ubyte BGCOL2 = $d023
memory byte BGCOL4 = $d024 memory ubyte BGCOL4 = $d024
memory byte SPMC0 = $d025 memory ubyte SPMC0 = $d025
memory byte SPMC1 = $d026 memory ubyte SPMC1 = $d026
memory byte SP0COL = $d027 memory ubyte SP0COL = $d027
memory byte SP1COL = $d028 memory ubyte SP1COL = $d028
memory byte SP2COL = $d029 memory ubyte SP2COL = $d029
memory byte SP3COL = $d02a memory ubyte SP3COL = $d02a
memory byte SP4COL = $d02b memory ubyte SP4COL = $d02b
memory byte SP5COL = $d02c memory ubyte SP5COL = $d02c
memory byte SP6COL = $d02d memory ubyte SP6COL = $d02d
memory byte SP7COL = $d02e memory ubyte SP7COL = $d02e
; ---- end of VIC-II registers ---- ; ---- end of VIC-II registers ----

View File

@ -12,14 +12,14 @@
~ math { ~ math {
; note: the following ZP scratch registers must be the same as in c64lib ; note: the following ZP scratch registers must be the same as in c64lib
memory byte SCRATCH_ZP1 = $02 ; scratch register #1 in ZP memory ubyte SCRATCH_ZP1 = $02 ; scratch register #1 in ZP
memory byte SCRATCH_ZP2 = $03 ; scratch register #2 in ZP memory ubyte SCRATCH_ZP2 = $03 ; scratch register #2 in ZP
memory word SCRATCH_ZPWORD1 = $fb ; scratch word in ZP ($fb/$fc) memory uword SCRATCH_ZPWORD1 = $fb ; scratch word in ZP ($fb/$fc)
memory word SCRATCH_ZPWORD2 = $fd ; scratch word in ZP ($fd/$fe) memory uword SCRATCH_ZPWORD2 = $fd ; scratch word in ZP ($fd/$fe)
sub multiply_bytes (byte1: X, byte2: Y) -> (A, X?) { asmsub multiply_bytes (byte1: ubyte @ X, byte2: ubyte @ Y) -> clobbers(X) -> (ubyte @ A) {
; ---- multiply 2 bytes, result as byte in A (signed or unsigned) ; ---- multiply 2 bytes, result as byte in A (signed or unsigned)
%asm {{ %asm {{
stx SCRATCH_ZP1 stx SCRATCH_ZP1
@ -37,7 +37,7 @@ sub multiply_bytes (byte1: X, byte2: Y) -> (A, X?) {
} }
sub multiply_bytes_16 (byte1: X, byte2: Y) -> (A?, XY) { asmsub multiply_bytes_16 (byte1: ubyte @ X, byte2: ubyte @ Y) -> clobbers(A) -> (uword @ XY) {
; ---- multiply 2 bytes, result as word in X/Y (unsigned) ; ---- multiply 2 bytes, result as word in X/Y (unsigned)
%asm {{ %asm {{
lda #0 lda #0
@ -58,7 +58,7 @@ _m_with_add stx SCRATCH_ZP1
}} }}
} }
sub multiply_bytes_addA_16 (byte1: X, byte2: Y, add: A) -> (A?, XY) { asmsub multiply_bytes_addA_16 (byte1: ubyte @ X, byte2: ubyte @ Y, add: ubyte @ A) -> clobbers(A) -> (uword @ XY) {
; ---- multiply 2 bytes and add A, result as word in X/Y (unsigned) ; ---- multiply 2 bytes and add A, result as word in X/Y (unsigned)
%asm {{ %asm {{
jmp multiply_bytes_16._m_with_add jmp multiply_bytes_16._m_with_add
@ -66,7 +66,7 @@ sub multiply_bytes_addA_16 (byte1: X, byte2: Y, add: A) -> (A?, XY) {
} }
word[2] multiply_words_product = 0 word[2] multiply_words_product = 0
sub multiply_words (number: XY) -> (?) { asmsub multiply_words (number: uword @ XY) -> clobbers(A,X) -> () {
; ---- multiply two 16-bit words into a 32-bit result ; ---- multiply two 16-bit words into a 32-bit result
; input: X/Y = first 16-bit number, SCRATCH_ZPWORD1 in ZP = second 16-bit number ; input: X/Y = first 16-bit number, SCRATCH_ZPWORD1 in ZP = second 16-bit number
; output: multiply_words_product 32-bits product, LSB order (low-to-high) ; output: multiply_words_product 32-bits product, LSB order (low-to-high)
@ -100,7 +100,7 @@ mult16 lda #$00
} }
sub divmod_bytes (number: X, divisor: Y) -> (X, A) { asmsub divmod_bytes (number: ubyte @ X, divisor: ubyte @ Y) -> clobbers() -> (ubyte @ X, ubyte @ A) {
; ---- divide X by Y, result quotient in X, remainder in A (unsigned) ; ---- divide X by Y, result quotient in X, remainder in A (unsigned)
; division by zero will result in quotient = 255 and remainder = original number ; division by zero will result in quotient = 255 and remainder = original number
%asm {{ %asm {{
@ -123,7 +123,7 @@ sub divmod_bytes (number: X, divisor: Y) -> (X, A) {
}} }}
} }
sub divmod_words (divisor: XY) -> (A?, XY) { asmsub divmod_words (divisor: uword @ XY) -> clobbers(A) -> (uword @ XY) {
; ---- divide two words (16 bit each) into 16 bit results ; ---- divide two words (16 bit each) into 16 bit results
; input: SCRATCH_ZPWORD1 in ZP: 16 bit number, X/Y: 16 bit divisor ; input: SCRATCH_ZPWORD1 in ZP: 16 bit number, X/Y: 16 bit divisor
; output: SCRATCH_ZPWORD1 in ZP: 16 bit result, X/Y: 16 bit remainder ; output: SCRATCH_ZPWORD1 in ZP: 16 bit result, X/Y: 16 bit remainder
@ -172,7 +172,7 @@ remainder = SCRATCH_ZP1
} }
sub randbyte () -> (A) { asmsub randbyte () -> clobbers() -> (ubyte @ A) {
; ---- 8-bit pseudo random number generator into A ; ---- 8-bit pseudo random number generator into A
%asm {{ %asm {{
@ -194,7 +194,7 @@ _magiceors .byte $1d, $2b, $2d, $4d, $5f, $63, $65, $69
}} }}
} }
sub randword () -> (XY) { asmsub randword () -> clobbers() -> (uword @ XY) {
; ---- 16 bit pseudo random number generator into XY ; ---- 16 bit pseudo random number generator into XY
%asm {{ %asm {{