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 != "floatsafe" &&
directive.args[0].name != "kernalsafe" &&
directive.args[0].name != "dontuse" &&
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" -> {
if(directive.parent !is Module) err("this directive may only occur at module level")

View File

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

View File

@ -42,14 +42,14 @@ object MachineDefinition {
}
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
}
init {
if (options.floats && options.zeropage != ZeropageType.FLOATSAFE && options.zeropage != ZeropageType.BASICSAFE)
throw CompilerException("when floats are enabled, zero page type should be 'floatsafe' or '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' or 'dontuse'")
if (options.zeropage == ZeropageType.FULL) {
free.addAll(0x04..0xf9)
@ -84,11 +84,16 @@ object MachineDefinition {
))
}
// add the other free Zp addresses,
// these are valid for the C-64 (when no RS232 I/O is performed) but to keep BASIC running fully:
free.addAll(listOf(0x04, 0x05, 0x06, 0x0a, 0x0e,
0x94, 0x95, 0xa7, 0xa8, 0xa9, 0xaa,
0xb5, 0xb6, 0xf7, 0xf8, 0xf9))
if(options.zeropage==ZeropageType.BASICSAFE) {
// add the other free Zp addresses,
// these are valid for the C-64 (when no RS232 I/O is performed) but to keep BASIC running fully:
free.addAll(listOf(0x04, 0x05, 0x06, 0x0a, 0x0e,
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_REG !in free)

View File

@ -1466,21 +1466,46 @@ $endLabel""")
}
targetArrayIdx!=null -> {
val index = targetArrayIdx.arrayspec.index
val targetName = asmIdentifierName(targetArrayIdx.identifier)
val elementDt = ArrayElementTypes.getValue(targetArrayIdx.identifier.targetVarDecl(program.namespace)!!.datatype)
val what = asmIdentifierName(targetArrayIdx.identifier)
val arrayDt = targetArrayIdx.identifier.inferType(program)!!
val elementDt = ArrayElementTypes.getValue(arrayDt)
when(index) {
is NumericLiteralValue -> {
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 -> {
TODO("postincrdecr $elementDt array $targetName [ $index ]")
// TODO optimize common cases
translateArrayIndexIntoA(targetArrayIdx)
incrDecrArrayvalueWithIndexA(incr, arrayDt, what)
}
is IdentifierReference -> {
TODO("postincrdecr $elementDt array $targetName [ $index ]")
// TODO optimize common cases
translateArrayIndexIntoA(targetArrayIdx)
incrDecrArrayvalueWithIndexA(incr, arrayDt, what)
}
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) {
out(" jmp ${getJumpTarget(jmp)}")
}
@ -1588,7 +1640,7 @@ $endLabel""")
throw AssemblyError("weird array type")
}
} else {
translateCalcArrayIndexIntoA(arrayExpr)
translateArrayIndexIntoA(arrayExpr)
readAndPushArrayvalueWithIndexA(arrayDt, arrayExpr.identifier)
}
assignFromEvalResult(assign.target)
@ -1617,8 +1669,7 @@ $endLabel""")
}
}
private fun translateCalcArrayIndexIntoA(expr: ArrayIndexedExpression) {
val arrayDt = expr.identifier.targetVarDecl(program.namespace)!!.datatype
private fun translateArrayIndexIntoA(expr: ArrayIndexedExpression) {
val index = expr.arrayspec.index
when (index) {
is NumericLiteralValue -> throw AssemblyError("this should be optimized directly")
@ -1699,12 +1750,7 @@ $endLabel""")
when(expression) {
is PrefixExpression -> translateExpression(expression)
is BinaryExpression -> translateExpression(expression)
is ArrayIndexedExpression -> {
// assume *reading* from an array
translateCalcArrayIndexIntoA(expression)
val arrayDt = expression.identifier.targetVarDecl(program.namespace)!!.datatype
readAndPushArrayvalueWithIndexA(arrayDt, expression.identifier)
}
is ArrayIndexedExpression -> translatePushFromArray(expression as ArrayIndexedExpression)
is TypecastExpression -> translateExpression(expression)
is AddressOf -> 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) {
val name = asmIdentifierName(expr.identifier)
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
out(" lda #<$arrayVarName+$indexValue | ldy #>$arrayVarName+$indexValue | jsr c64flt.pop_float")
} else {
translateCalcArrayIndexIntoA(targetArrayIdx)
translateArrayIndexIntoA(targetArrayIdx)
out(" sta ${C64Zeropage.SCRATCH_REG} | asl a | asl a | clc | adc ${C64Zeropage.SCRATCH_REG}")
out("""
tay
lda $constFloat
sta $arrayVarName,y
lda $constFloat+1
iny
sta $arrayVarName,y
sta $arrayVarName+1,y
lda $constFloat+2
iny
sta $arrayVarName,y
sta $arrayVarName+2,y
lda $constFloat+3
iny
sta $arrayVarName,y
sta $arrayVarName+3,y
lda $constFloat+4
iny
sta $arrayVarName,y
sta $arrayVarName+4,y
""") // TODO use a subroutine for this
}
}

View File

@ -165,6 +165,8 @@ class TestZeropage {
}
}
// TODO test dontuse option
@Test
fun testFreeSpaces() {
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.
This option makes programs smaller and faster because even more variables can
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`.

View File

@ -1,18 +1,25 @@
%import c64utils
%import c64flt
%option enable_floats
%zeropage basicsafe ; @todo dontuse
%zeropage basicsafe
main {
sub start() {
c64scr.plot(0,24)
ubyte ub=200
byte bb=-100
uword uw = 2000
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")
ub++
@ -20,15 +27,30 @@ main {
uw++
ww++
fl++
ubarr[1]++
barr[1]++
uwarr[1]++
warr[1]++
flarr[1] ++
check_ub(ub, 201)
Y=100
Y++
check_ub(Y, 101)
check_fl(fl, 100.99)
check_fl(fl, 1000.99)
check_b(bb, -99)
check_uw(uw, 2001)
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")
ub--
@ -36,16 +58,26 @@ main {
uw--
ww--
fl--
ubarr[1]--
barr[1]--
uwarr[1]--
warr[1]--
flarr[1] --
check_ub(ub, 200)
Y=100
Y--
check_ub(Y, 99)
check_fl(fl, 99.99)
check_fl(fl, 999.99)
check_b(bb, -100)
check_uw(uw, 2000)
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) {