mirror of
https://github.com/irmen/prog8.git
synced 2025-02-18 05:30:34 +00:00
more ++ and -- code, 'dontuse' zeropage option
This commit is contained in:
parent
309c82fc9e
commit
2c3b8a9819
@ -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")
|
||||||
|
@ -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?)
|
||||||
|
@ -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)
|
||||||
|
@ -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
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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))
|
||||||
|
@ -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`.
|
||||||
|
|
||||||
|
@ -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) {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user