mirror of
https://github.com/irmen/prog8.git
synced 2024-11-26 11:49:22 +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 != "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")
|
||||
|
@ -24,7 +24,8 @@ enum class ZeropageType {
|
||||
BASICSAFE,
|
||||
FLOATSAFE,
|
||||
KERNALSAFE,
|
||||
FULL
|
||||
FULL,
|
||||
DONTUSE
|
||||
}
|
||||
|
||||
data class IntegerOrAddressOf(val integer: Int?, val addressOf: AddressOf?)
|
||||
|
@ -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)
|
||||
|
@ -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
|
||||
}
|
||||
}
|
||||
|
@ -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))
|
||||
|
@ -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`.
|
||||
|
||||
|
@ -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) {
|
||||
|
Loading…
Reference in New Issue
Block a user