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

View File

@ -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){
"/", "//", "%" -> {

View File

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

View File

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

View File

@ -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,
if(it.callLabel!=null) symname(it.callLabel, block) else null,
if(it.callLabel2!=null) symname(it.callLabel2, block) else null)
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()

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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