more ++ and -- code, 'dontuse' zeropage option

This commit is contained in:
Irmen de Jong 2019-08-04 21:38:14 +02:00
parent 309c82fc9e
commit 2c3b8a9819
7 changed files with 149 additions and 39 deletions

View File

@ -622,8 +622,9 @@ internal class AstChecker(private val program: Program,
directive.args[0].name != "basicsafe" && directive.args[0].name != "basicsafe" &&
directive.args[0].name != "floatsafe" && directive.args[0].name != "floatsafe" &&
directive.args[0].name != "kernalsafe" && directive.args[0].name != "kernalsafe" &&
directive.args[0].name != "dontuse" &&
directive.args[0].name != "full") directive.args[0].name != "full")
err("invalid zp type, expected basicsafe, floatsafe, kernalsafe, or full") err("invalid zp type, expected basicsafe, floatsafe, kernalsafe, dontuse, or full")
} }
"%zpreserved" -> { "%zpreserved" -> {
if(directive.parent !is Module) err("this directive may only occur at module level") if(directive.parent !is Module) err("this directive may only occur at module level")

View File

@ -24,7 +24,8 @@ enum class ZeropageType {
BASICSAFE, BASICSAFE,
FLOATSAFE, FLOATSAFE,
KERNALSAFE, KERNALSAFE,
FULL FULL,
DONTUSE
} }
data class IntegerOrAddressOf(val integer: Int?, val addressOf: AddressOf?) data class IntegerOrAddressOf(val integer: Int?, val addressOf: AddressOf?)

View File

@ -42,14 +42,14 @@ object MachineDefinition {
} }
override val exitProgramStrategy: ExitProgramStrategy = when (options.zeropage) { override val exitProgramStrategy: ExitProgramStrategy = when (options.zeropage) {
ZeropageType.BASICSAFE -> ExitProgramStrategy.CLEAN_EXIT ZeropageType.BASICSAFE, ZeropageType.DONTUSE -> ExitProgramStrategy.CLEAN_EXIT
ZeropageType.FLOATSAFE, ZeropageType.KERNALSAFE, ZeropageType.FULL -> ExitProgramStrategy.SYSTEM_RESET ZeropageType.FLOATSAFE, ZeropageType.KERNALSAFE, ZeropageType.FULL -> ExitProgramStrategy.SYSTEM_RESET
} }
init { init {
if (options.floats && options.zeropage != ZeropageType.FLOATSAFE && options.zeropage != ZeropageType.BASICSAFE) if (options.floats && options.zeropage !in setOf(ZeropageType.FLOATSAFE, ZeropageType.BASICSAFE, ZeropageType.DONTUSE ))
throw CompilerException("when floats are enabled, zero page type should be 'floatsafe' or 'basicsafe'") throw CompilerException("when floats are enabled, zero page type should be 'floatsafe' or 'basicsafe' or 'dontuse'")
if (options.zeropage == ZeropageType.FULL) { if (options.zeropage == ZeropageType.FULL) {
free.addAll(0x04..0xf9) free.addAll(0x04..0xf9)
@ -84,11 +84,16 @@ object MachineDefinition {
)) ))
} }
// add the other free Zp addresses, if(options.zeropage==ZeropageType.BASICSAFE) {
// these are valid for the C-64 (when no RS232 I/O is performed) but to keep BASIC running fully: // add the other free Zp addresses,
free.addAll(listOf(0x04, 0x05, 0x06, 0x0a, 0x0e, // these are valid for the C-64 (when no RS232 I/O is performed) but to keep BASIC running fully:
0x94, 0x95, 0xa7, 0xa8, 0xa9, 0xaa, free.addAll(listOf(0x04, 0x05, 0x06, 0x0a, 0x0e,
0xb5, 0xb6, 0xf7, 0xf8, 0xf9)) 0x94, 0x95, 0xa7, 0xa8, 0xa9, 0xaa,
0xb5, 0xb6, 0xf7, 0xf8, 0xf9))
} else {
// don't use the zeropage at all
free.clear()
}
} }
assert(SCRATCH_B1 !in free) assert(SCRATCH_B1 !in free)
assert(SCRATCH_REG !in free) assert(SCRATCH_REG !in free)

View File

@ -1466,21 +1466,46 @@ $endLabel""")
} }
targetArrayIdx!=null -> { targetArrayIdx!=null -> {
val index = targetArrayIdx.arrayspec.index val index = targetArrayIdx.arrayspec.index
val targetName = asmIdentifierName(targetArrayIdx.identifier) val what = asmIdentifierName(targetArrayIdx.identifier)
val elementDt = ArrayElementTypes.getValue(targetArrayIdx.identifier.targetVarDecl(program.namespace)!!.datatype) val arrayDt = targetArrayIdx.identifier.inferType(program)!!
val elementDt = ArrayElementTypes.getValue(arrayDt)
when(index) { when(index) {
is NumericLiteralValue -> { is NumericLiteralValue -> {
val indexValue = index.number.toInt() * elementDt.memorySize() val indexValue = index.number.toInt() * elementDt.memorySize()
out(if(incr) " inc $targetName+$indexValue" else " dec $targetName+$indexValue") when(elementDt) {
in ByteDatatypes -> out(if (incr) " inc $what+$indexValue" else " dec $what+$indexValue")
in WordDatatypes -> {
if(incr)
out(" inc $what+$indexValue | bne + | inc $what+$indexValue+1 |+")
else
out("""
lda $what+$indexValue
bne +
dec $what+$indexValue+1
+ dec $what+$indexValue
""")
}
DataType.FLOAT -> {
out(" lda #<$what+$indexValue | ldy #>$what+$indexValue")
out(if(incr) " jsr c64flt.inc_var_f" else " jsr c64flt.dec_var_f")
}
else -> throw AssemblyError("need numeric type")
}
} }
is RegisterExpr -> { is RegisterExpr -> {
TODO("postincrdecr $elementDt array $targetName [ $index ]") // TODO optimize common cases
translateArrayIndexIntoA(targetArrayIdx)
incrDecrArrayvalueWithIndexA(incr, arrayDt, what)
} }
is IdentifierReference -> { is IdentifierReference -> {
TODO("postincrdecr $elementDt array $targetName [ $index ]") // TODO optimize common cases
translateArrayIndexIntoA(targetArrayIdx)
incrDecrArrayvalueWithIndexA(incr, arrayDt, what)
} }
else -> { else -> {
TODO("postincrdecr $elementDt array $targetName [ $index ]") // TODO optimize common cases
translateArrayIndexIntoA(targetArrayIdx)
incrDecrArrayvalueWithIndexA(incr, arrayDt, what)
} }
} }
} }
@ -1488,6 +1513,33 @@ $endLabel""")
} }
} }
private fun incrDecrArrayvalueWithIndexA(incr: Boolean, arrayDt: DataType, arrayVarName: String) {
out(" stx ${C64Zeropage.SCRATCH_REG_X} | tax")
when(arrayDt) {
DataType.STR, DataType.STR_S,
DataType.ARRAY_UB, DataType.ARRAY_B -> {
out(if(incr) " inc $arrayVarName,x" else " dec $arrayVarName,x")
}
DataType.ARRAY_UW, DataType.ARRAY_W -> {
if(incr)
out(" inc $arrayVarName,x | bne + | inc $arrayVarName+1,x |+")
else
out("""
lda $arrayVarName,x
bne +
dec $arrayVarName+1,x
+ dec $arrayVarName
""")
}
DataType.ARRAY_F -> {
out(" lda #<$arrayVarName | ldy #>$arrayVarName")
out(if(incr) " jsr c64flt.inc_indexed_var_f" else " jsr c64flt.dec_indexed_var_f")
}
else -> throw AssemblyError("weird array dt")
}
out(" ldx ${C64Zeropage.SCRATCH_REG_X}")
}
private fun translate(jmp: Jump) { private fun translate(jmp: Jump) {
out(" jmp ${getJumpTarget(jmp)}") out(" jmp ${getJumpTarget(jmp)}")
} }
@ -1588,7 +1640,7 @@ $endLabel""")
throw AssemblyError("weird array type") throw AssemblyError("weird array type")
} }
} else { } else {
translateCalcArrayIndexIntoA(arrayExpr) translateArrayIndexIntoA(arrayExpr)
readAndPushArrayvalueWithIndexA(arrayDt, arrayExpr.identifier) readAndPushArrayvalueWithIndexA(arrayDt, arrayExpr.identifier)
} }
assignFromEvalResult(assign.target) assignFromEvalResult(assign.target)
@ -1617,8 +1669,7 @@ $endLabel""")
} }
} }
private fun translateCalcArrayIndexIntoA(expr: ArrayIndexedExpression) { private fun translateArrayIndexIntoA(expr: ArrayIndexedExpression) {
val arrayDt = expr.identifier.targetVarDecl(program.namespace)!!.datatype
val index = expr.arrayspec.index val index = expr.arrayspec.index
when (index) { when (index) {
is NumericLiteralValue -> throw AssemblyError("this should be optimized directly") is NumericLiteralValue -> throw AssemblyError("this should be optimized directly")
@ -1699,12 +1750,7 @@ $endLabel""")
when(expression) { when(expression) {
is PrefixExpression -> translateExpression(expression) is PrefixExpression -> translateExpression(expression)
is BinaryExpression -> translateExpression(expression) is BinaryExpression -> translateExpression(expression)
is ArrayIndexedExpression -> { is ArrayIndexedExpression -> translatePushFromArray(expression as ArrayIndexedExpression)
// assume *reading* from an array
translateCalcArrayIndexIntoA(expression)
val arrayDt = expression.identifier.targetVarDecl(program.namespace)!!.datatype
readAndPushArrayvalueWithIndexA(arrayDt, expression.identifier)
}
is TypecastExpression -> translateExpression(expression) is TypecastExpression -> translateExpression(expression)
is AddressOf -> translateExpression(expression) is AddressOf -> translateExpression(expression)
is DirectMemoryRead -> translateExpression(expression) is DirectMemoryRead -> translateExpression(expression)
@ -1726,6 +1772,32 @@ $endLabel""")
} }
} }
private fun translatePushFromArray(arrayExpr: ArrayIndexedExpression) {
// assume *reading* from an array
val index = arrayExpr.arrayspec.index
val arrayDt = arrayExpr.identifier.targetVarDecl(program.namespace)!!.datatype
val arrayVarName = asmIdentifierName(arrayExpr.identifier)
if(index is NumericLiteralValue) {
val elementDt = ArrayElementTypes.getValue(arrayDt)
val indexValue = index.number.toInt() * elementDt.memorySize()
when(elementDt) {
in ByteDatatypes -> {
out(" lda $arrayVarName+$indexValue | sta $ESTACK_LO_HEX,x | dex")
}
in WordDatatypes -> {
out(" lda $arrayVarName+$indexValue | sta $ESTACK_LO_HEX,x | lda $arrayVarName+$indexValue+1 | sta $ESTACK_HI_HEX,x | dex")
}
DataType.FLOAT -> {
out(" lda #<$arrayVarName+$indexValue | ldy #>$arrayVarName+$indexValue | jsr c64flt.push_float")
}
else -> throw AssemblyError("weird type")
}
} else {
translateArrayIndexIntoA(arrayExpr)
readAndPushArrayvalueWithIndexA(arrayDt, arrayExpr.identifier)
}
}
private fun translateExpression(expr: AddressOf) { private fun translateExpression(expr: AddressOf) {
val name = asmIdentifierName(expr.identifier) val name = asmIdentifierName(expr.identifier)
out(" lda #<$name | sta $ESTACK_LO_HEX,x | lda #>$name | sta $ESTACK_HI_HEX,x | dex") out(" lda #<$name | sta $ESTACK_LO_HEX,x | lda #>$name | sta $ESTACK_HI_HEX,x | dex")
@ -2398,24 +2470,20 @@ $endLabel""")
val indexValue = index.number.toInt() * MachineDefinition.Mflpt5.MemorySize val indexValue = index.number.toInt() * MachineDefinition.Mflpt5.MemorySize
out(" lda #<$arrayVarName+$indexValue | ldy #>$arrayVarName+$indexValue | jsr c64flt.pop_float") out(" lda #<$arrayVarName+$indexValue | ldy #>$arrayVarName+$indexValue | jsr c64flt.pop_float")
} else { } else {
translateCalcArrayIndexIntoA(targetArrayIdx) translateArrayIndexIntoA(targetArrayIdx)
out(" sta ${C64Zeropage.SCRATCH_REG} | asl a | asl a | clc | adc ${C64Zeropage.SCRATCH_REG}") out(" sta ${C64Zeropage.SCRATCH_REG} | asl a | asl a | clc | adc ${C64Zeropage.SCRATCH_REG}")
out(""" out("""
tay tay
lda $constFloat lda $constFloat
sta $arrayVarName,y sta $arrayVarName,y
lda $constFloat+1 lda $constFloat+1
iny sta $arrayVarName+1,y
sta $arrayVarName,y
lda $constFloat+2 lda $constFloat+2
iny sta $arrayVarName+2,y
sta $arrayVarName,y
lda $constFloat+3 lda $constFloat+3
iny sta $arrayVarName+3,y
sta $arrayVarName,y
lda $constFloat+4 lda $constFloat+4
iny sta $arrayVarName+4,y
sta $arrayVarName,y
""") // TODO use a subroutine for this """) // TODO use a subroutine for this
} }
} }

View File

@ -165,6 +165,8 @@ class TestZeropage {
} }
} }
// TODO test dontuse option
@Test @Test
fun testFreeSpaces() { fun testFreeSpaces() {
val zp1 = C64Zeropage(CompilationOptions(OutputType.RAW, LauncherType.NONE, ZeropageType.BASICSAFE, emptyList(), true)) val zp1 = C64Zeropage(CompilationOptions(OutputType.RAW, LauncherType.NONE, ZeropageType.BASICSAFE, emptyList(), true))

View File

@ -74,6 +74,7 @@ Directives
As with ``kernalsafe``, it is not possible to cleanly exit the program, other than to reset the machine. As with ``kernalsafe``, it is not possible to cleanly exit the program, other than to reset the machine.
This option makes programs smaller and faster because even more variables can This option makes programs smaller and faster because even more variables can
be stored in the ZP (which allows for more efficient assembly code). be stored in the ZP (which allows for more efficient assembly code).
- style ``dontuse`` -- don't use *any* location in the zeropage.
Also read :ref:`zeropage`. Also read :ref:`zeropage`.

View File

@ -1,18 +1,25 @@
%import c64utils %import c64utils
%import c64flt %import c64flt
%option enable_floats %option enable_floats
%zeropage basicsafe ; @todo dontuse %zeropage basicsafe
main { main {
sub start() { sub start() {
c64scr.plot(0,24)
ubyte ub=200 ubyte ub=200
byte bb=-100 byte bb=-100
uword uw = 2000 uword uw = 2000
word ww = -1000 word ww = -1000
float fl = 99.99 float fl = 999.99
ubyte[3] ubarr = 200
byte[3] barr = -100
uword[3] uwarr = 2000
word[3] warr = -1000
float[3] flarr = 999.99
c64scr.print("++\n") c64scr.print("++\n")
ub++ ub++
@ -20,15 +27,30 @@ main {
uw++ uw++
ww++ ww++
fl++ fl++
ubarr[1]++
barr[1]++
uwarr[1]++
warr[1]++
flarr[1] ++
check_ub(ub, 201) check_ub(ub, 201)
Y=100 Y=100
Y++ Y++
check_ub(Y, 101) check_ub(Y, 101)
check_fl(fl, 100.99) check_fl(fl, 1000.99)
check_b(bb, -99) check_b(bb, -99)
check_uw(uw, 2001) check_uw(uw, 2001)
check_w(ww, -999) check_w(ww, -999)
check_ub(ubarr[0], 200)
check_fl(flarr[0], 999.99)
check_b(barr[0], -100)
check_uw(uwarr[0], 2000)
check_w(warr[0], -1000)
check_ub(ubarr[1], 201)
check_fl(flarr[1], 1000.99)
check_b(barr[1], -99)
check_uw(uwarr[1], 2001)
check_w(warr[1], -999)
c64scr.print("--\n") c64scr.print("--\n")
ub-- ub--
@ -36,16 +58,26 @@ main {
uw-- uw--
ww-- ww--
fl-- fl--
ubarr[1]--
barr[1]--
uwarr[1]--
warr[1]--
flarr[1] --
check_ub(ub, 200) check_ub(ub, 200)
Y=100 Y=100
Y-- Y--
check_ub(Y, 99) check_ub(Y, 99)
check_fl(fl, 99.99) check_fl(fl, 999.99)
check_b(bb, -100) check_b(bb, -100)
check_uw(uw, 2000) check_uw(uw, 2000)
check_w(ww, -1000) check_w(ww, -1000)
check_ub(ubarr[1], 200)
check_fl(flarr[1], 999.99)
check_b(barr[1], -100)
check_uw(uwarr[1], 2000)
check_w(warr[1], -1000)
@($0400+39) = X @($0400+400-1) = X
} }
sub check_ub(ubyte value, ubyte expected) { sub check_ub(ubyte value, ubyte expected) {