mirror of
https://github.com/irmen/prog8.git
synced 2024-09-07 19:54:26 +00:00
more asm
This commit is contained in:
parent
1e0ce40d1d
commit
067426016d
@ -1,29 +1,5 @@
|
||||
%import c64utils
|
||||
|
||||
~ block2 $4000 {
|
||||
return
|
||||
}
|
||||
|
||||
~ block3 $3000 {
|
||||
return
|
||||
}
|
||||
|
||||
~ blockNoAddr1 {
|
||||
return
|
||||
}
|
||||
|
||||
~ blockNoAddr2 {
|
||||
return
|
||||
}
|
||||
|
||||
~ block4 $6000 {
|
||||
return
|
||||
}
|
||||
|
||||
~ blockNoAddr3 {
|
||||
return
|
||||
}
|
||||
|
||||
%import mathlib
|
||||
|
||||
~ main {
|
||||
|
||||
@ -33,10 +9,29 @@ sub start() {
|
||||
const ubyte border_color = 2
|
||||
const ubyte cursor_color = 7
|
||||
|
||||
c64.BGCOL0 = screen_color
|
||||
c64.EXTCOL = border_color
|
||||
c64.COLOR = cursor_color
|
||||
ubyte ubb
|
||||
uword uww
|
||||
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
|
||||
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -544,6 +544,16 @@ class AstChecker(private val namespace: INameScope,
|
||||
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 {
|
||||
when(expr.operator){
|
||||
"/", "//", "%" -> {
|
||||
|
@ -39,6 +39,11 @@ class IntermediateProgram(val name: String, var loadAddress: Int, val heap: Heap
|
||||
|
||||
fun optimize() {
|
||||
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()
|
||||
optimizeVariableCopying()
|
||||
optimizeMultipleSequentialLineInstrs()
|
||||
|
@ -143,21 +143,11 @@ enum class Opcode {
|
||||
NOT_WORD,
|
||||
|
||||
// increment, decrement
|
||||
INC_B,
|
||||
INC_UB,
|
||||
INC_W,
|
||||
INC_UW,
|
||||
INC_F,
|
||||
INC_VAR_B,
|
||||
INC_VAR_UB,
|
||||
INC_VAR_W,
|
||||
INC_VAR_UW,
|
||||
INC_VAR_F,
|
||||
DEC_B,
|
||||
DEC_UB,
|
||||
DEC_W,
|
||||
DEC_UW,
|
||||
DEC_F,
|
||||
DEC_VAR_B,
|
||||
DEC_VAR_UB,
|
||||
DEC_VAR_W,
|
||||
|
@ -17,16 +17,21 @@ class AsmGen(val options: CompilationOptions, val program: IntermediateProgram,
|
||||
private lateinit var output: PrintWriter
|
||||
|
||||
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.
|
||||
// Also, convert invalid label names (such as "<<<anonymous-1>>>") to something that's allowed.
|
||||
val newblocks = mutableListOf<IntermediateProgram.ProgramBlock>()
|
||||
for(block in program.blocks) {
|
||||
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 newinstructions = block.instructions.asSequence().map {
|
||||
it as? LabelInstr ?: Instruction(it.opcode, it.arg,
|
||||
when {
|
||||
it is LabelInstr -> LabelInstr(symname(it.name, block))
|
||||
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()
|
||||
val newConstants = block.integerConstants.map { symname(it.key, block) to it.value }.toMap().toMutableMap()
|
||||
newblocks.add(IntermediateProgram.ProgramBlock(
|
||||
@ -67,8 +72,14 @@ class AsmGen(val options: CompilationOptions, val program: IntermediateProgram,
|
||||
return AssemblyProgram(program.name)
|
||||
}
|
||||
|
||||
private fun symname(scoped: String, block: IntermediateProgram.ProgramBlock) =
|
||||
if (scoped.startsWith("${block.shortname}.")) scoped.substring(block.shortname.length+1) else scoped
|
||||
private fun symname(scoped: String, block: IntermediateProgram.ProgramBlock): String {
|
||||
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) {
|
||||
// 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) {
|
||||
out("\tlda #${byte.toHex()}")
|
||||
pushByteA()
|
||||
}
|
||||
|
||||
private fun pushByteA() {
|
||||
out("\tsta ${ESTACK_LO.toHex()},x")
|
||||
out("\tdex")
|
||||
}
|
||||
@ -311,7 +326,14 @@ class AsmGen(val options: CompilationOptions, val program: IntermediateProgram,
|
||||
private fun pushWord(word: Int) {
|
||||
out("\tlda #<${word.toHex()}")
|
||||
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("\tdex")
|
||||
}
|
||||
@ -350,6 +372,17 @@ class AsmGen(val options: CompilationOptions, val program: IntermediateProgram,
|
||||
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 {
|
||||
if(ins is LabelInstr) {
|
||||
if(ins.name==block.shortname)
|
||||
@ -369,6 +402,7 @@ class AsmGen(val options: CompilationOptions, val program: IntermediateProgram,
|
||||
Opcode.SEI -> out("\tsei")
|
||||
Opcode.CLI -> out("\tcli")
|
||||
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.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")
|
||||
@ -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_WORD -> out("\tinx") // remove 2 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 -> {
|
||||
when {
|
||||
ins.callLabel2 in registerStrings -> {
|
||||
@ -504,6 +539,7 @@ class AsmGen(val options: CompilationOptions, val program: IntermediateProgram,
|
||||
return 1 // skip 1
|
||||
}
|
||||
// byte from variable onto stack
|
||||
TODO("can be register")
|
||||
pushVarByte(ins.callLabel!!)
|
||||
}
|
||||
Opcode.PUSH_WORD -> {
|
||||
@ -579,6 +615,7 @@ class AsmGen(val options: CompilationOptions, val program: IntermediateProgram,
|
||||
return 1 // skip 1
|
||||
}
|
||||
// word from memory onto stack
|
||||
TODO("can be register")
|
||||
pushVarWord(ins.callLabel!!)
|
||||
}
|
||||
Opcode.PUSH_FLOAT -> {
|
||||
@ -630,44 +667,79 @@ class AsmGen(val options: CompilationOptions, val program: IntermediateProgram,
|
||||
}
|
||||
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")
|
||||
// Opcode.POP_MEM_B -> TODO()
|
||||
// Opcode.POP_MEM_UB -> TODO()
|
||||
// Opcode.POP_MEM_W -> TODO()
|
||||
// Opcode.POP_MEM_UW -> TODO()
|
||||
// Opcode.POP_MEM_FLOAT -> TODO()
|
||||
// Opcode.POP_VAR_BYTE -> TODO()
|
||||
// Opcode.POP_VAR_WORD -> TODO()
|
||||
// Opcode.POP_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_UW -> 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_UW -> TODO()
|
||||
// Opcode.DEC_VAR_F -> TODO()
|
||||
// Opcode.ADD_UB -> TODO()
|
||||
// Opcode.ADD_B -> TODO()
|
||||
// Opcode.ADD_UW -> TODO()
|
||||
// Opcode.ADD_W -> TODO()
|
||||
// Opcode.ADD_F -> TODO()
|
||||
// Opcode.SUB_UB -> TODO()
|
||||
// Opcode.SUB_B -> TODO()
|
||||
// Opcode.SUB_UW -> TODO()
|
||||
// Opcode.SUB_W -> TODO()
|
||||
// Opcode.SUB_F -> TODO()
|
||||
@ -696,7 +768,6 @@ class AsmGen(val options: CompilationOptions, val program: IntermediateProgram,
|
||||
// Opcode.POW_UW -> TODO()
|
||||
// Opcode.POW_W -> TODO()
|
||||
// Opcode.POW_F -> TODO()
|
||||
// Opcode.NEG_B -> TODO()
|
||||
// Opcode.NEG_W -> TODO()
|
||||
// Opcode.NEG_F -> TODO()
|
||||
// Opcode.SHL_BYTE -> TODO()
|
||||
@ -741,8 +812,6 @@ class AsmGen(val options: CompilationOptions, val program: IntermediateProgram,
|
||||
// Opcode.BITOR_WORD -> TODO()
|
||||
// Opcode.BITXOR_BYTE -> TODO()
|
||||
// Opcode.BITXOR_WORD -> TODO()
|
||||
// Opcode.INV_BYTE -> TODO()
|
||||
// Opcode.INV_WORD -> TODO()
|
||||
// Opcode.LSB -> TODO()
|
||||
// Opcode.MSB -> TODO()
|
||||
// Opcode.B2WORD -> TODO()
|
||||
@ -758,8 +827,6 @@ class AsmGen(val options: CompilationOptions, val program: IntermediateProgram,
|
||||
// Opcode.OR_WORD -> TODO()
|
||||
// Opcode.XOR_BYTE -> TODO()
|
||||
// Opcode.XOR_WORD -> TODO()
|
||||
// Opcode.NOT_BYTE -> TODO()
|
||||
// Opcode.NOT_WORD -> TODO()
|
||||
// Opcode.LESS_B -> TODO()
|
||||
// Opcode.LESS_UB -> 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_WORD -> TODO()
|
||||
// Opcode.WRITE_INDEXED_VAR_FLOAT -> TODO()
|
||||
// Opcode.JUMP -> TODO()
|
||||
// Opcode.BCS -> TODO()
|
||||
// Opcode.BCC -> TODO()
|
||||
// Opcode.BZ -> TODO()
|
||||
|
@ -13,7 +13,7 @@ class AssemblyProgram(val name: String) {
|
||||
println("Generating machine code program...")
|
||||
|
||||
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) {
|
||||
OutputType.PRG -> {
|
||||
|
@ -13,7 +13,7 @@ import prog8.functions.BuiltinFunctions
|
||||
todo remove if statements with empty statement blocks
|
||||
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: 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 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) )
|
||||
|
@ -633,56 +633,6 @@ class StackVm(private var traceOutputFile: String?) {
|
||||
checkDt(v, DataType.UWORD)
|
||||
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.SEC -> P_carry = true
|
||||
Opcode.CLC -> P_carry = false
|
||||
|
@ -424,26 +424,6 @@ class TestStackVmOpcodes {
|
||||
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
|
||||
fun testNeg() {
|
||||
testUnaryOperator(Value(DataType.BYTE, 12), Opcode.NEG_B, Value(DataType.BYTE, -12))
|
||||
|
@ -7,80 +7,80 @@
|
||||
|
||||
|
||||
~ c64 {
|
||||
memory byte SCRATCH_ZP1 = $02 ; scratch register #1 in ZP
|
||||
memory byte SCRATCH_ZP2 = $03 ; scratch register #2 in ZP
|
||||
memory word SCRATCH_ZPWORD1 = $fb ; scratch word in ZP ($fb/$fc)
|
||||
memory word SCRATCH_ZPWORD2 = $fd ; scratch word in ZP ($fd/$fe)
|
||||
memory ubyte SCRATCH_ZP1 = $02 ; scratch register #1 in ZP
|
||||
memory ubyte SCRATCH_ZP2 = $03 ; scratch register #2 in ZP
|
||||
memory uword SCRATCH_ZPWORD1 = $fb ; scratch word in ZP ($fb/$fc)
|
||||
memory uword SCRATCH_ZPWORD2 = $fd ; scratch word in ZP ($fd/$fe)
|
||||
|
||||
|
||||
memory byte TIME_HI = $a0 ; software jiffy clock, hi byte
|
||||
memory byte TIME_MID = $a1 ; .. mid byte
|
||||
memory byte TIME_LO = $a2 ; .. lo byte. Updated by IRQ every 1/60 sec
|
||||
memory byte STKEY = $91 ; various keyboard statuses (updated by IRQ)
|
||||
memory byte SFDX = $cb ; current key pressed (matrix value) (updated by IRQ)
|
||||
memory ubyte TIME_HI = $a0 ; software jiffy clock, hi byte
|
||||
memory ubyte TIME_MID = $a1 ; .. mid byte
|
||||
memory ubyte TIME_LO = $a2 ; .. lo byte. Updated by IRQ every 1/60 sec
|
||||
memory ubyte STKEY = $91 ; various keyboard statuses (updated by IRQ)
|
||||
memory ubyte SFDX = $cb ; current key pressed (matrix value) (updated by IRQ)
|
||||
|
||||
memory byte COLOR = $0286 ; cursor color
|
||||
memory byte HIBASE = $0288 ; screen base address / 256 (hi-byte of screen memory address)
|
||||
memory word CINV = $0314 ; IRQ vector
|
||||
memory word 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 word IRQ_VEC = $FFFE ; 6502 interrupt vector, determined by the kernal if banked in
|
||||
memory ubyte COLOR = $0286 ; cursor color
|
||||
memory ubyte HIBASE = $0288 ; screen base address / 256 (hi-byte of screen memory address)
|
||||
memory uword CINV = $0314 ; IRQ vector
|
||||
memory uword NMI_VEC = $FFFA ; 6502 nmi vector, determined by the kernal if banked in
|
||||
memory uword RESET_VEC = $FFFC ; 6502 reset 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 byte[40, 25] Colors = $d800 ; character screen colors
|
||||
memory ubyte[40, 25] Screen = $0400 ; default character screen matrix
|
||||
memory ubyte[40, 25] Colors = $d800 ; character screen colors
|
||||
|
||||
|
||||
; ---- VIC-II registers ----
|
||||
|
||||
memory byte SP0X = $d000
|
||||
memory byte SP0Y = $d001
|
||||
memory byte SP1X = $d002
|
||||
memory byte SP1Y = $d003
|
||||
memory byte SP2X = $d004
|
||||
memory byte SP2Y = $d005
|
||||
memory byte SP3X = $d006
|
||||
memory byte SP3Y = $d007
|
||||
memory byte SP4X = $d008
|
||||
memory byte SP4Y = $d009
|
||||
memory byte SP5X = $d00a
|
||||
memory byte SP5Y = $d00b
|
||||
memory byte SP6X = $d00c
|
||||
memory byte SP6Y = $d00d
|
||||
memory byte SP7X = $d00e
|
||||
memory byte SP7Y = $d00f
|
||||
memory ubyte SP0X = $d000
|
||||
memory ubyte SP0Y = $d001
|
||||
memory ubyte SP1X = $d002
|
||||
memory ubyte SP1Y = $d003
|
||||
memory ubyte SP2X = $d004
|
||||
memory ubyte SP2Y = $d005
|
||||
memory ubyte SP3X = $d006
|
||||
memory ubyte SP3Y = $d007
|
||||
memory ubyte SP4X = $d008
|
||||
memory ubyte SP4Y = $d009
|
||||
memory ubyte SP5X = $d00a
|
||||
memory ubyte SP5Y = $d00b
|
||||
memory ubyte SP6X = $d00c
|
||||
memory ubyte SP6Y = $d00d
|
||||
memory ubyte SP7X = $d00e
|
||||
memory ubyte SP7Y = $d00f
|
||||
|
||||
memory byte MSIGX = $d010
|
||||
memory byte SCROLY = $d011
|
||||
memory byte RASTER = $d012
|
||||
memory byte LPENX = $d013
|
||||
memory byte LPENY = $d014
|
||||
memory byte SPENA = $d015
|
||||
memory byte SCROLX = $d016
|
||||
memory byte YXPAND = $d017
|
||||
memory byte VMCSB = $d018
|
||||
memory byte VICIRQ = $d019
|
||||
memory byte IREQMASK = $d01a
|
||||
memory byte SPBGPR = $d01b
|
||||
memory byte SPMC = $d01c
|
||||
memory byte XXPAND = $d01d
|
||||
memory byte SPSPCL = $d01e
|
||||
memory byte SPBGCL = $d01f
|
||||
memory ubyte MSIGX = $d010
|
||||
memory ubyte SCROLY = $d011
|
||||
memory ubyte RASTER = $d012
|
||||
memory ubyte LPENX = $d013
|
||||
memory ubyte LPENY = $d014
|
||||
memory ubyte SPENA = $d015
|
||||
memory ubyte SCROLX = $d016
|
||||
memory ubyte YXPAND = $d017
|
||||
memory ubyte VMCSB = $d018
|
||||
memory ubyte VICIRQ = $d019
|
||||
memory ubyte IREQMASK = $d01a
|
||||
memory ubyte SPBGPR = $d01b
|
||||
memory ubyte SPMC = $d01c
|
||||
memory ubyte XXPAND = $d01d
|
||||
memory ubyte SPSPCL = $d01e
|
||||
memory ubyte SPBGCL = $d01f
|
||||
|
||||
memory byte EXTCOL = $d020 ; border color
|
||||
memory byte BGCOL0 = $d021 ; screen color
|
||||
memory byte BGCOL1 = $d022
|
||||
memory byte BGCOL2 = $d023
|
||||
memory byte BGCOL4 = $d024
|
||||
memory byte SPMC0 = $d025
|
||||
memory byte SPMC1 = $d026
|
||||
memory byte SP0COL = $d027
|
||||
memory byte SP1COL = $d028
|
||||
memory byte SP2COL = $d029
|
||||
memory byte SP3COL = $d02a
|
||||
memory byte SP4COL = $d02b
|
||||
memory byte SP5COL = $d02c
|
||||
memory byte SP6COL = $d02d
|
||||
memory byte SP7COL = $d02e
|
||||
memory ubyte EXTCOL = $d020 ; border color
|
||||
memory ubyte BGCOL0 = $d021 ; screen color
|
||||
memory ubyte BGCOL1 = $d022
|
||||
memory ubyte BGCOL2 = $d023
|
||||
memory ubyte BGCOL4 = $d024
|
||||
memory ubyte SPMC0 = $d025
|
||||
memory ubyte SPMC1 = $d026
|
||||
memory ubyte SP0COL = $d027
|
||||
memory ubyte SP1COL = $d028
|
||||
memory ubyte SP2COL = $d029
|
||||
memory ubyte SP3COL = $d02a
|
||||
memory ubyte SP4COL = $d02b
|
||||
memory ubyte SP5COL = $d02c
|
||||
memory ubyte SP6COL = $d02d
|
||||
memory ubyte SP7COL = $d02e
|
||||
|
||||
; ---- end of VIC-II registers ----
|
||||
|
||||
|
@ -12,14 +12,14 @@
|
||||
|
||||
~ math {
|
||||
; note: the following ZP scratch registers must be the same as in c64lib
|
||||
memory byte SCRATCH_ZP1 = $02 ; scratch register #1 in ZP
|
||||
memory byte SCRATCH_ZP2 = $03 ; scratch register #2 in ZP
|
||||
memory word SCRATCH_ZPWORD1 = $fb ; scratch word in ZP ($fb/$fc)
|
||||
memory word SCRATCH_ZPWORD2 = $fd ; scratch word in ZP ($fd/$fe)
|
||||
memory ubyte SCRATCH_ZP1 = $02 ; scratch register #1 in ZP
|
||||
memory ubyte SCRATCH_ZP2 = $03 ; scratch register #2 in ZP
|
||||
memory uword SCRATCH_ZPWORD1 = $fb ; scratch word in ZP ($fb/$fc)
|
||||
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)
|
||||
%asm {{
|
||||
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)
|
||||
%asm {{
|
||||
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)
|
||||
%asm {{
|
||||
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
|
||||
sub multiply_words (number: XY) -> (?) {
|
||||
asmsub multiply_words (number: uword @ XY) -> clobbers(A,X) -> () {
|
||||
; ---- 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
|
||||
; 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)
|
||||
; division by zero will result in quotient = 255 and remainder = original number
|
||||
%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
|
||||
; 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
|
||||
@ -172,7 +172,7 @@ remainder = SCRATCH_ZP1
|
||||
}
|
||||
|
||||
|
||||
sub randbyte () -> (A) {
|
||||
asmsub randbyte () -> clobbers() -> (ubyte @ A) {
|
||||
; ---- 8-bit pseudo random number generator into A
|
||||
|
||||
%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
|
||||
|
||||
%asm {{
|
||||
|
Loading…
Reference in New Issue
Block a user