more asm output

This commit is contained in:
Irmen de Jong 2018-10-25 23:17:10 +02:00
parent 595bf7ad4b
commit 5203dad7c1
10 changed files with 760 additions and 158 deletions

View File

@ -45,6 +45,46 @@ sub start() {
memory float mfloat = $c006 memory float mfloat = $c006
memory float mfloat2 = $d006 memory float mfloat2 = $d006
;label:
;
; while A>99 {
; X=22
; }
;
; repeat {
; X=22
; } until A>99
;
; for X in 0 to 99 {
; Y=33
; }
;
; for ubyte derp in 2 to 44 {
; X=44
; }
;
; if A<22 goto label
;
; if X<22 {
; A=99
; } else {
; Y=42
; }
Y=42
AY=42
AY=42555
Y = ub
AY= ub
AY= uw
Y = mubyte
AY = mubyte
AY = muword
Y = ubarr1[2]
AY = ubarr1[2]
AY = uwarr1[2]
barr1[2]=42 barr1[2]=42
ubarr1[2]=42 ubarr1[2]=42
@ -52,6 +92,10 @@ sub start() {
uwarr1[2]=42555 uwarr1[2]=42555
farr1[2]=42.5678 farr1[2]=42.5678
ubarr1[2]=X
uwarr1[2]=XY
; farr1[2]=XY ; @todo
barr1[2] = b barr1[2] = b
ubarr1[2] = ub ubarr1[2] = ub
warr1[2] = w warr1[2] = w
@ -68,62 +112,88 @@ sub start() {
ub = ubarr1[2] ub = ubarr1[2]
w = warr1[2] w = warr1[2]
uw = uwarr1[2] uw = uwarr1[2]
fl1 = farr1[2] ; fl1 = farr1[2] ; @todo
mbyte= barr1[2] mbyte= barr1[2]
mubyte = ubarr1[2] mubyte = ubarr1[2]
mword = warr1[2] mword = warr1[2]
muword = uwarr1[2] muword = uwarr1[2]
mfloat = farr1[2] ; mfloat = farr1[2] ; @todo
barr1[2] = barr2[3] barr1[2] = barr2[3]
ubarr1[2] = ubarr2[3] ubarr1[2] = ubarr2[3]
warr1[2] = warr2[3] warr1[2] = warr2[3]
uwarr1[2] = uwarr2[3] uwarr1[2] = uwarr2[3]
farr1[2] = farr2[3] ; farr1[2] = farr2[3] ; @todo
XY[2]=42
XY[2] = ub
XY[2] = mubyte
ub = XY[2]
uw = XY[2]
;fl1 = XY[2] ; @todo
mubyte = XY[2]
muword = XY[2]
;mfloat = XY[2] ; @todo
XY[2] = AY[3] ; @todo wat is de output hiervan???
; b = 1 b = 1
; ub = 1 ub = 1
; w = 1 w = 1
; uw = 1 uw = 1
; fl1 = 2.345 fl1 = 2.345
;
; b = b2 b = b2
; ub = pixely ub = pixely
; w = w2 w = b2
; uw = uw2 w = w2
; fl1 = fl2 w = ub
; uw = ub
; b = mbyte uw = uw2
; ub = mubyte ;fl1 = ub ; @todo
; w = mword ;fl1 = b2 ; @todo
; uw = muword ;fl1 = uw2 ; @todo
; fl1 = mfloat ;fl1 = w2 ; @todo
; fl1 = fl2
; mbyte = 1
; mubyte = 1 b = mbyte
; mword = 1 ub = mubyte
; muword = 1 w = mword
; mfloat = 3.456 w = mbyte
w = mubyte
uw = mubyte
uw = muword
fl1 = mfloat
;fl1 = mbyte ; @todo
;fl1 = mword ; @todo
;fl1 = mubyte ; @todo
;fl1 = muword ; @todo
mbyte = 1
mubyte = 1
mword = 1
muword = 1
mfloat = 3.456
%breakpoint
mbyte = b
mubyte = ub
mword = w
muword = uw
mfloat = fl2
%breakpoint
mbyte = mbyte2
mubyte = mubyte2
mword = mword2
muword = muword2
mfloat = mfloat2
; %breakpoint
;
; mbyte = b
; mubyte = ub
; mword = w
; muword = uw
; mfloat = fl2
;
; %breakpoint
;
; mbyte = mbyte2
; mubyte = mubyte2
; mword = mword2
; muword = muword2
; mfloat = mfloat2
;
return return
} }

View File

@ -931,7 +931,7 @@ class AstChecker(private val namespace: INameScope,
val result = when(targetDatatype) { val result = when(targetDatatype) {
DataType.BYTE -> sourceDatatype==DataType.BYTE DataType.BYTE -> sourceDatatype==DataType.BYTE
DataType.UBYTE -> sourceDatatype==DataType.UBYTE DataType.UBYTE -> sourceDatatype==DataType.UBYTE
DataType.WORD -> sourceDatatype==DataType.BYTE || sourceDatatype==DataType.WORD DataType.WORD -> sourceDatatype==DataType.BYTE || sourceDatatype==DataType.UBYTE || sourceDatatype==DataType.WORD
DataType.UWORD -> sourceDatatype==DataType.UBYTE || sourceDatatype==DataType.UWORD DataType.UWORD -> sourceDatatype==DataType.UBYTE || sourceDatatype==DataType.UWORD
DataType.FLOAT -> sourceDatatype in NumericDatatypes DataType.FLOAT -> sourceDatatype in NumericDatatypes
DataType.STR -> sourceDatatype==DataType.STR DataType.STR -> sourceDatatype==DataType.STR

View File

@ -120,18 +120,20 @@ class AstIdentifiersChecker : IAstProcessor {
} }
override fun process(forLoop: ForLoop): IStatement { override fun process(forLoop: ForLoop): IStatement {
// if the for loop as a decltype, it means to declare the loopvar inside the loop body // if the for loop has a decltype, it means to declare the loopvar inside the loop body
// rather than reusing an already declared loopvar from an outer scope. // rather than reusing an already declared loopvar from an outer scope.
if(forLoop.loopRegister!=null && forLoop.decltype!=null) { if(forLoop.loopRegister!=null) {
checkResult.add(SyntaxError("register loop variables cannot be explicitly declared with a datatype", forLoop.position)) if(forLoop.decltype!=null)
} else { checkResult.add(SyntaxError("register loop variables cannot be explicitly declared with a datatype", forLoop.position))
val loopVar = forLoop.loopVar!! if(forLoop.loopRegister == Register.X || forLoop.loopRegister==Register.XY || forLoop.loopRegister==Register.AX)
val varName = loopVar.nameInSource.last() checkResult.add(SyntaxError("it's not possible to write to the X register because it's used as an internal pointer", forLoop.position))
} else if(forLoop.loopVar!=null) {
val varName = forLoop.loopVar.nameInSource.last()
when (forLoop.decltype) { when (forLoop.decltype) {
DataType.UBYTE, DataType.UWORD -> { DataType.UBYTE, DataType.UWORD -> {
val existing = if(forLoop.body.isEmpty()) null else forLoop.body.lookup(loopVar.nameInSource, forLoop.body.statements.first()) val existing = if(forLoop.body.isEmpty()) null else forLoop.body.lookup(forLoop.loopVar.nameInSource, forLoop.body.statements.first())
if(existing==null) { if(existing==null) {
val vardecl = VarDecl(VarDeclType.VAR, forLoop.decltype, null, varName, null, loopVar.position) val vardecl = VarDecl(VarDeclType.VAR, forLoop.decltype, null, varName, null, forLoop.loopVar.position)
vardecl.linkParents(forLoop.body) vardecl.linkParents(forLoop.body)
forLoop.body.statements.add(0, vardecl) forLoop.body.statements.add(0, vardecl)
forLoop.loopVar.parent = forLoop.body // loopvar 'is defined in the body' forLoop.loopVar.parent = forLoop.body // loopvar 'is defined in the body'
@ -143,4 +145,10 @@ class AstIdentifiersChecker : IAstProcessor {
} }
return super.process(forLoop) return super.process(forLoop)
} }
override fun process(assignTarget: AssignTarget): AssignTarget {
if(assignTarget.register==Register.X || assignTarget.register==Register.AX || assignTarget.register==Register.XY)
checkResult.add(SyntaxError("it's not possible to write to the X register because it's used as an internal pointer", assignTarget.position))
return super.process(assignTarget)
}
} }

View File

@ -440,8 +440,8 @@ private class StatementTranslator(private val prog: IntermediateProgram,
BranchCondition.CC -> Opcode.BCS BranchCondition.CC -> Opcode.BCS
BranchCondition.EQ, BranchCondition.Z -> Opcode.BNZ BranchCondition.EQ, BranchCondition.Z -> Opcode.BNZ
BranchCondition.NE, BranchCondition.NZ -> Opcode.BZ BranchCondition.NE, BranchCondition.NZ -> Opcode.BZ
BranchCondition.VS -> TODO("Opcode.BVC") BranchCondition.VS -> Opcode.BVC
BranchCondition.VC -> TODO("Opcode.BVS") BranchCondition.VC -> Opcode.BVS
BranchCondition.MI, BranchCondition.NEG -> Opcode.BPOS BranchCondition.MI, BranchCondition.NEG -> Opcode.BPOS
BranchCondition.PL, BranchCondition.POS -> Opcode.BNEG BranchCondition.PL, BranchCondition.POS -> Opcode.BNEG
} }
@ -470,6 +470,7 @@ private class StatementTranslator(private val prog: IntermediateProgram,
* An IF statement: IF (condition-expression) { stuff } else { other_stuff } * An IF statement: IF (condition-expression) { stuff } else { other_stuff }
* Which is translated into: * Which is translated into:
* <condition-expression evaluation> * <condition-expression evaluation>
* TEST
* BZ _stmt_999_else * BZ _stmt_999_else
* stuff * stuff
* JUMP _stmt_999_end * JUMP _stmt_999_end
@ -480,6 +481,7 @@ private class StatementTranslator(private val prog: IntermediateProgram,
* *
* or when there is no else block: * or when there is no else block:
* <condition-expression evaluation> * <condition-expression evaluation>
* TEST
* BZ _stmt_999_end * BZ _stmt_999_end
* stuff * stuff
* _stmt_999_end: * _stmt_999_end:
@ -491,11 +493,13 @@ private class StatementTranslator(private val prog: IntermediateProgram,
translate(stmt.condition) translate(stmt.condition)
val labelEnd = makeLabel("end") val labelEnd = makeLabel("end")
if(stmt.elsepart.isEmpty()) { if(stmt.elsepart.isEmpty()) {
prog.instr(Opcode.TEST)
prog.instr(Opcode.BZ, callLabel = labelEnd) prog.instr(Opcode.BZ, callLabel = labelEnd)
translate(stmt.truepart) translate(stmt.truepart)
prog.label(labelEnd) prog.label(labelEnd)
} else { } else {
val labelElse = makeLabel("else") val labelElse = makeLabel("else")
prog.instr(Opcode.TEST)
prog.instr(Opcode.BZ, callLabel = labelElse) prog.instr(Opcode.BZ, callLabel = labelElse)
translate(stmt.truepart) translate(stmt.truepart)
prog.instr(Opcode.JUMP, callLabel = labelEnd) prog.instr(Opcode.JUMP, callLabel = labelEnd)
@ -1473,6 +1477,7 @@ private class StatementTranslator(private val prog: IntermediateProgram,
prog.instr(opcodePush(zero.type), Value(zero.type, numElements)) prog.instr(opcodePush(zero.type), Value(zero.type, numElements))
prog.instr(opcodePushvar(zero.type), callLabel = indexVar) prog.instr(opcodePushvar(zero.type), callLabel = indexVar)
prog.instr(opcodeSub(zero.type)) prog.instr(opcodeSub(zero.type))
prog.instr(Opcode.TEST)
prog.instr(Opcode.BNZ, callLabel = loopLabel) prog.instr(Opcode.BNZ, callLabel = loopLabel)
prog.label(breakLabel) prog.label(breakLabel)
@ -1535,6 +1540,7 @@ private class StatementTranslator(private val prog: IntermediateProgram,
prog.instr(opcodePush(varDt), Value(varDt, range.last + range.step)) prog.instr(opcodePush(varDt), Value(varDt, range.last + range.step))
prog.instr(opcodePushvar(varDt), callLabel = varname) prog.instr(opcodePushvar(varDt), callLabel = varname)
prog.instr(opcodeSub(varDt)) prog.instr(opcodeSub(varDt))
prog.instr(Opcode.TEST)
prog.instr(Opcode.BNZ, callLabel = loopLabel) prog.instr(Opcode.BNZ, callLabel = loopLabel)
prog.label(breakLabel) prog.label(breakLabel)
@ -1692,6 +1698,7 @@ private class StatementTranslator(private val prog: IntermediateProgram,
* continue -> goto condition * continue -> goto condition
* continue: * continue:
* <evaluate condition> * <evaluate condition>
* test
* bnz loop * bnz loop
* break: * break:
* nop * nop
@ -1707,6 +1714,7 @@ private class StatementTranslator(private val prog: IntermediateProgram,
translate(stmt.body) translate(stmt.body)
prog.label(continueLabel) prog.label(continueLabel)
translate(stmt.condition) translate(stmt.condition)
prog.instr(Opcode.TEST)
prog.instr(Opcode.BNZ, callLabel = loopLabel) prog.instr(Opcode.BNZ, callLabel = loopLabel)
prog.label(breakLabel) prog.label(breakLabel)
prog.instr(Opcode.NOP) prog.instr(Opcode.NOP)
@ -1726,6 +1734,7 @@ private class StatementTranslator(private val prog: IntermediateProgram,
* continue -> goto condition * continue -> goto condition
* condition: * condition:
* <evaluate untilCondition> * <evaluate untilCondition>
* test
* bz goto loop * bz goto loop
* break: * break:
* nop * nop
@ -1740,6 +1749,7 @@ private class StatementTranslator(private val prog: IntermediateProgram,
translate(stmt.body) translate(stmt.body)
prog.label(continueLabel) prog.label(continueLabel)
translate(stmt.untilCondition) translate(stmt.untilCondition)
prog.instr(Opcode.TEST)
prog.instr(Opcode.BZ, callLabel = loopLabel) prog.instr(Opcode.BZ, callLabel = loopLabel)
prog.label(breakLabel) prog.label(breakLabel)
prog.instr(Opcode.NOP) prog.instr(Opcode.NOP)

View File

@ -158,6 +158,8 @@ enum class Opcode {
DEC_VAR_F, DEC_VAR_F,
// comparisons // comparisons
// @todo the comparisons now push the result back on the stack. Optimize this to work with processor flags exclusively. This does mean you can no longer use a logical boolean result as a byte 0/1 value ?
TEST, // pop top value from stack and test it. Sets cpu flags (zero, negative, overflow) accordingly.
LESS_B, LESS_B,
LESS_UB, LESS_UB,
LESS_W, LESS_W,
@ -193,16 +195,16 @@ enum class Opcode {
WRITE_INDEXED_VAR_WORD, WRITE_INDEXED_VAR_WORD,
WRITE_INDEXED_VAR_FLOAT, WRITE_INDEXED_VAR_FLOAT,
// branching // branching, without consuming a value from the stack
JUMP, JUMP,
BCS, BCS, // branch if carry set
BCC, BCC, // branch if carry clear
BZ, // branch if value on top of stack is zero BZ, // branch if zero flag
BNZ, // branch if value on top of stack is not zero BNZ, // branch if not zero flag
BNEG, // branch if value on top of stack < 0 BNEG, // branch if negative flag
BPOS, // branch if value on top of stack >= 0 BPOS, // branch if not negative flag
// BVS, // status flag V (overflow) not implemented BVS, // branch if overflow flag
// BVC, // status flag V (overflow) not implemented BVC, // branch if not overflow flag
// subroutine calling // subroutine calling
CALL, CALL,

View File

@ -400,50 +400,50 @@ class AsmGen(val options: CompilationOptions, val program: IntermediateProgram,
"_prog8_breakpoint_$breakpointCounter\tnop" "_prog8_breakpoint_$breakpointCounter\tnop"
} }
Opcode.PUSH_BYTE -> { // Opcode.PUSH_BYTE -> {
" lda #${ins.arg!!.integerValue().toHex()} | sta ${ESTACK_LO.toHex()},x | dex" // " lda #${ins.arg!!.integerValue().toHex()} | sta ${ESTACK_LO.toHex()},x | dex"
} // }
Opcode.PUSH_WORD -> { // Opcode.PUSH_WORD -> {
val value = ins.arg!!.integerValue().toHex() // val value = ins.arg!!.integerValue().toHex()
" lda #<$value | sta ${ESTACK_LO.toHex()},x | lda #>$value | sta ${ESTACK_HI.toHex()},x | dex" // " lda #<$value | sta ${ESTACK_LO.toHex()},x | lda #>$value | sta ${ESTACK_HI.toHex()},x | dex"
} // }
Opcode.PUSH_FLOAT -> { // Opcode.PUSH_FLOAT -> {
val floatConst = getFloatConst(ins.arg!!) // val floatConst = getFloatConst(ins.arg!!)
" lda #<$floatConst | ldy #>$floatConst | jsr prog8_lib.push_float" // " lda #<$floatConst | ldy #>$floatConst | jsr prog8_lib.push_float"
} // }
Opcode.PUSH_VAR_BYTE -> { // Opcode.PUSH_VAR_BYTE -> {
when(ins.callLabel) { // when(ins.callLabel) {
"X" -> throw CompilerException("makes no sense to push X, it's used as a stack pointer itself") // "X" -> throw CompilerException("makes no sense to push X, it's used as a stack pointer itself")
"A" -> " sta ${ESTACK_LO.toHex()},x | dex" // "A" -> " sta ${ESTACK_LO.toHex()},x | dex"
"Y" -> " tya | sta ${ESTACK_LO.toHex()},x | dex" // "Y" -> " tya | sta ${ESTACK_LO.toHex()},x | dex"
else -> " lda ${ins.callLabel} | sta ${ESTACK_LO.toHex()},x | dex" // else -> " lda ${ins.callLabel} | sta ${ESTACK_LO.toHex()},x | dex"
} // }
} // }
Opcode.PUSH_VAR_WORD -> { // Opcode.PUSH_VAR_WORD -> {
when (ins.callLabel) { // when (ins.callLabel) {
"AX" -> throw CompilerException("makes no sense to push X, it's used as a stack pointer itself") // "AX" -> throw CompilerException("makes no sense to push X, it's used as a stack pointer itself")
"XY" -> throw CompilerException("makes no sense to push X, it's used as a stack pointer itself") // "XY" -> throw CompilerException("makes no sense to push X, it's used as a stack pointer itself")
"AY" -> " sta ${ESTACK_LO.toHex()},x | pha | tya | sta ${ESTACK_HI.toHex()},x | pla | dex" // "AY" -> " sta ${ESTACK_LO.toHex()},x | pha | tya | sta ${ESTACK_HI.toHex()},x | pla | dex"
else -> " lda ${ins.callLabel} | ldy ${ins.callLabel}+1 | sta ${ESTACK_LO.toHex()},x | pha | tya | sta ${ESTACK_HI.toHex()},x | pla | dex" // else -> " lda ${ins.callLabel} | ldy ${ins.callLabel}+1 | sta ${ESTACK_LO.toHex()},x | pha | tya | sta ${ESTACK_HI.toHex()},x | pla | dex"
} // }
} // }
Opcode.PUSH_VAR_FLOAT -> " lda #<${ins.callLabel} | ldy #>${ins.callLabel}| jsr prog8_lib.push_float" // Opcode.PUSH_VAR_FLOAT -> " lda #<${ins.callLabel} | ldy #>${ins.callLabel}| jsr prog8_lib.push_float"
Opcode.PUSH_MEM_B, Opcode.PUSH_MEM_UB -> { // Opcode.PUSH_MEM_B, Opcode.PUSH_MEM_UB -> {
""" // """
lda ${ins.arg!!.integerValue().toHex()} // lda ${ins.arg!!.integerValue().toHex()}
sta ${ESTACK_LO.toHex()},x // sta ${ESTACK_LO.toHex()},x
dex // dex
""" // """
} // }
Opcode.PUSH_MEM_W, Opcode.PUSH_MEM_UW -> { // Opcode.PUSH_MEM_W, Opcode.PUSH_MEM_UW -> {
""" // """
lda ${ins.arg!!.integerValue().toHex()} // lda ${ins.arg!!.integerValue().toHex()}
sta ${ESTACK_LO.toHex()},x // sta ${ESTACK_LO.toHex()},x
lda ${(ins.arg.integerValue()+1).toHex()} // lda ${(ins.arg.integerValue()+1).toHex()}
sta ${ESTACK_HI.toHex()},x // sta ${ESTACK_HI.toHex()},x
dex // dex
""" // """
} // }
Opcode.POP_MEM_B, Opcode.POP_MEM_UB -> { Opcode.POP_MEM_B, Opcode.POP_MEM_UB -> {
""" """
@ -678,10 +678,12 @@ class AsmGen(val options: CompilationOptions, val program: IntermediateProgram,
Opcode.BCS -> " bcs ${ins.callLabel}" Opcode.BCS -> " bcs ${ins.callLabel}"
Opcode.BCC -> " bcc ${ins.callLabel}" Opcode.BCC -> " bcc ${ins.callLabel}"
Opcode.BZ -> " beq ${ins.callLabel}"
Opcode.BNZ -> " bne ${ins.callLabel}"
Opcode.BNEG -> " bmi ${ins.callLabel}" Opcode.BNEG -> " bmi ${ins.callLabel}"
Opcode.BPOS -> " bpl ${ins.callLabel}" Opcode.BPOS -> " bpl ${ins.callLabel}"
Opcode.BVC -> " bvc ${ins.callLabel}"
Opcode.BVS -> " bvs ${ins.callLabel}"
Opcode.BZ -> " beq ${ins.callLabel}"
Opcode.BNZ -> " bne ${ins.callLabel}"
Opcode.UB2FLOAT -> " jsr prog8_lib.ub2float" Opcode.UB2FLOAT -> " jsr prog8_lib.ub2float"
Opcode.B2FLOAT -> " jsr prog8_lib.b2float" Opcode.B2FLOAT -> " jsr prog8_lib.b2float"
Opcode.UW2FLOAT -> " jsr prog8_lib.uw2float" Opcode.UW2FLOAT -> " jsr prog8_lib.uw2float"
@ -1035,10 +1037,16 @@ class AsmGen(val options: CompilationOptions, val program: IntermediateProgram,
// assignment: mem = bytevar/ubytevar // assignment: mem = bytevar/ubytevar
AsmPattern(listOf(Opcode.PUSH_VAR_BYTE, Opcode.POP_MEM_B)) { segment -> AsmPattern(listOf(Opcode.PUSH_VAR_BYTE, Opcode.POP_MEM_B)) { segment ->
" lda ${segment[0].callLabel} | sta ${segment[1].arg!!.integerValue().toHex()}" when(segment[0].callLabel) {
"A", "X", "Y" -> TODO("$segment")
else -> " lda ${segment[0].callLabel} | sta ${segment[1].arg!!.integerValue().toHex()}"
}
}, },
AsmPattern(listOf(Opcode.PUSH_VAR_BYTE, Opcode.POP_MEM_UB)) { segment -> AsmPattern(listOf(Opcode.PUSH_VAR_BYTE, Opcode.POP_MEM_UB)) { segment ->
" lda ${segment[0].callLabel} | sta ${segment[1].arg!!.integerValue().toHex()}" when(segment[0].callLabel) {
"A", "X", "Y" -> TODO("$segment")
else -> " lda ${segment[0].callLabel} | sta ${segment[1].arg!!.integerValue().toHex()}"
}
}, },
// assignment: mem = byte/ubyte // assignment: mem = byte/ubyte
@ -1051,10 +1059,16 @@ class AsmGen(val options: CompilationOptions, val program: IntermediateProgram,
// assignment: (u)bytevar = membyte // assignment: (u)bytevar = membyte
AsmPattern(listOf(Opcode.PUSH_MEM_B, Opcode.POP_VAR_BYTE)) { segment -> AsmPattern(listOf(Opcode.PUSH_MEM_B, Opcode.POP_VAR_BYTE)) { segment ->
" lda ${segment[0].arg!!.integerValue().toHex()} | sta ${segment[1].callLabel}" when(segment[1].callLabel) {
"A", "X", "Y" -> " ld${segment[1].callLabel!!.toLowerCase()} ${segment[0].arg!!.integerValue().toHex()}"
else -> " lda ${segment[0].arg!!.integerValue().toHex()} | sta ${segment[1].callLabel}"
}
}, },
AsmPattern(listOf(Opcode.PUSH_MEM_UB, Opcode.POP_VAR_BYTE)) { segment -> AsmPattern(listOf(Opcode.PUSH_MEM_UB, Opcode.POP_VAR_BYTE)) { segment ->
" lda ${segment[0].arg!!.integerValue().toHex()} | sta ${segment[1].callLabel}" when(segment[1].callLabel) {
"A", "X", "Y" -> " ld${segment[1].callLabel!!.toLowerCase()} ${segment[0].arg!!.integerValue().toHex()}"
else -> " lda ${segment[0].arg!!.integerValue().toHex()} | sta ${segment[1].callLabel}"
}
}, },
@ -1077,20 +1091,32 @@ class AsmGen(val options: CompilationOptions, val program: IntermediateProgram,
// assignment: mem = wordvar/uwordvar // assignment: mem = wordvar/uwordvar
AsmPattern(listOf(Opcode.PUSH_VAR_WORD, Opcode.POP_MEM_W)) { segment -> AsmPattern(listOf(Opcode.PUSH_VAR_WORD, Opcode.POP_MEM_W)) { segment ->
""" when(segment[0].callLabel) {
lda ${segment[0].callLabel} "AX" -> TODO("$segment")
sta ${segment[1].arg!!.integerValue().toHex()} "AY" -> TODO("$segment")
lda ${segment[0].callLabel}+1 "XY" -> TODO("$segment")
sta ${(segment[1].arg!!.integerValue()+1).toHex()} else ->
""" """
lda ${segment[0].callLabel}
sta ${segment[1].arg!!.integerValue().toHex()}
lda ${segment[0].callLabel}+1
sta ${(segment[1].arg!!.integerValue()+1).toHex()}
"""
}
}, },
AsmPattern(listOf(Opcode.PUSH_VAR_WORD, Opcode.POP_MEM_UW)) { segment -> AsmPattern(listOf(Opcode.PUSH_VAR_WORD, Opcode.POP_MEM_UW)) { segment ->
""" when(segment[0].callLabel) {
lda ${segment[0].callLabel} "AX" -> TODO("$segment")
sta ${segment[1].arg!!.integerValue().toHex()} "AY" -> TODO("$segment")
lda ${segment[0].callLabel}+1 "XY" -> TODO("$segment")
sta ${(segment[1].arg!!.integerValue()+1).toHex()} else ->
""" """
lda ${segment[0].callLabel}
sta ${segment[1].arg!!.integerValue().toHex()}
lda ${segment[0].callLabel}+1
sta ${(segment[1].arg!!.integerValue()+1).toHex()}
"""
}
}, },
// assignment: mem = word/uword // assignment: mem = word/uword
@ -1113,20 +1139,32 @@ class AsmGen(val options: CompilationOptions, val program: IntermediateProgram,
// assignment: (u)wordvar = memword // assignment: (u)wordvar = memword
AsmPattern(listOf(Opcode.PUSH_MEM_W, Opcode.POP_VAR_WORD)) { segment -> AsmPattern(listOf(Opcode.PUSH_MEM_W, Opcode.POP_VAR_WORD)) { segment ->
""" when(segment[1].callLabel) {
lda ${segment[0].arg!!.integerValue().toHex()} "AX" -> " lda ${segment[0].arg!!.integerValue().toHex()} | ldx ${(segment[0].arg!!.integerValue()+1).toHex()}"
sta ${segment[1].callLabel} "AY" -> " lda ${segment[0].arg!!.integerValue().toHex()} | ldy ${(segment[0].arg!!.integerValue()+1).toHex()}"
lda ${(segment[0].arg!!.integerValue()+1).toHex()} "XY" -> " ldx ${segment[0].arg!!.integerValue().toHex()} | ldy ${(segment[0].arg!!.integerValue()+1).toHex()}"
sta ${segment[1].callLabel}+1 else ->
""" """
lda ${segment[0].arg!!.integerValue().toHex()}
sta ${segment[1].callLabel}
lda ${(segment[0].arg!!.integerValue()+1).toHex()}
sta ${segment[1].callLabel}+1
"""
}
}, },
AsmPattern(listOf(Opcode.PUSH_MEM_UW, Opcode.POP_VAR_WORD)) { segment -> AsmPattern(listOf(Opcode.PUSH_MEM_UW, Opcode.POP_VAR_WORD)) { segment ->
""" when(segment[1].callLabel) {
lda ${segment[0].arg!!.integerValue().toHex()} "AX" -> " lda ${segment[0].arg!!.integerValue().toHex()} | ldx ${(segment[0].arg!!.integerValue()+1).toHex()}"
sta ${segment[1].callLabel} "AY" -> " lda ${segment[0].arg!!.integerValue().toHex()} | ldy ${(segment[0].arg!!.integerValue()+1).toHex()}"
lda ${(segment[0].arg!!.integerValue()+1).toHex()} "XY" -> " ldx ${segment[0].arg!!.integerValue().toHex()} | ldy ${(segment[0].arg!!.integerValue()+1).toHex()}"
sta ${segment[1].callLabel}+1 else ->
""" """
lda ${segment[0].arg!!.integerValue().toHex()}
sta ${segment[1].callLabel}
lda ${(segment[0].arg!!.integerValue()+1).toHex()}
sta ${segment[1].callLabel}+1
"""
}
}, },
// assignment: var = float // assignment: var = float
@ -1191,17 +1229,396 @@ class AsmGen(val options: CompilationOptions, val program: IntermediateProgram,
""" """
}, },
// @todo add all indexed assignment forms // assignment: uwordvar = ubytevar
AsmPattern(listOf(Opcode.PUSH_VAR_BYTE, Opcode.UB2UWORD, Opcode.POP_VAR_WORD)) { segment ->
when(segment[0].callLabel) {
"A", "X", "Y" -> TODO("$segment")
else ->
when(segment[2].callLabel) {
"AX" -> " lda ${segment[0].callLabel} | ldx #0"
"AY" -> " lda ${segment[0].callLabel} | ldy #0"
"XY" -> " ldx ${segment[0].callLabel} | ldy #0"
else -> " lda ${segment[0].callLabel} | sta ${segment[2].callLabel} | lda #0 | sta ${segment[2].callLabel}+1"
}
}
},
// assignment: wordvar = bytevar (sign extended)
AsmPattern(listOf(Opcode.PUSH_VAR_BYTE, Opcode.B2WORD, Opcode.POP_VAR_WORD)) { segment ->
when(segment[0].callLabel) {
"A", "X", "Y" -> TODO("$segment")
else ->
when(segment[2].callLabel) {
"AX" -> TODO(" $segment")
"AY" -> TODO(" $segment")
"XY" -> TODO(" $segment")
else ->
"""
lda ${segment[0].callLabel}
sta ${segment[2].callLabel}
ora #$7f
bmi +
lda #0
+ sta ${segment[2].callLabel}+1
"""
}
}
},
// assignment: wordvar = membyte (sign extended)
AsmPattern(listOf(Opcode.PUSH_MEM_B, Opcode.B2WORD, Opcode.POP_VAR_WORD)) { segment ->
when(segment[2].callLabel) {
"AX" -> TODO("$segment")
"AY" -> TODO("$segment")
"XY" -> TODO("$segment")
else ->
"""
lda ${segment[0].arg!!.integerValue().toHex()}
sta ${segment[2].callLabel}
ora #$7f
bmi +
lda #0
+ sta ${segment[2].callLabel}+1
"""
}
},
// assignment: uwordvar = mem ubyte
AsmPattern(listOf(Opcode.PUSH_MEM_UB, Opcode.UB2UWORD, Opcode.POP_VAR_WORD)) { segment ->
when(segment[2].callLabel) {
"AX" -> " lda ${segment[0].arg!!.integerValue().toHex()} | ldx #0"
"AY" -> " lda ${segment[0].arg!!.integerValue().toHex()} | ldy #0"
"XY" -> " ldx ${segment[0].arg!!.integerValue().toHex()} | ldy #0"
else -> " lda ${segment[0].arg!!.integerValue().toHex()} | sta ${segment[2].callLabel} | lda #0 | sta ${segment[2].callLabel}+1"
}
},
// assignment: uwordvar = ubytearray[index_byte]
AsmPattern(listOf(Opcode.PUSH_BYTE, Opcode.READ_INDEXED_VAR_BYTE, Opcode.UB2UWORD, Opcode.POP_VAR_WORD)) { segment ->
val index = segment[0].arg!!.integerValue().toHex()
when(segment[1].callLabel) {
"AX" -> TODO("$segment")
"AY" -> TODO("$segment")
"XY" -> TODO("$segment")
else ->
when(segment[3].callLabel) {
"AX" -> " lda ${segment[1].callLabel}+$index | ldx #0"
"AY" -> " lda ${segment[1].callLabel}+$index | ldy #0"
"XY" -> " ldx ${segment[1].callLabel}+$index | ldy #0"
else -> " lda ${segment[1].callLabel}+$index | sta ${segment[3].callLabel} | lda #0 | sta ${segment[3].callLabel}+1"
}
}
},
// assignment: mem uword = ubytearray[index_byte]
AsmPattern(listOf(Opcode.PUSH_BYTE, Opcode.READ_INDEXED_VAR_BYTE, Opcode.UB2UWORD, Opcode.POP_MEM_UW)) { segment ->
val index = segment[0].arg!!.integerValue().toHex()
"""
lda ${segment[1].callLabel}+$index
ldy ${segment[1].callLabel}+$index+1
sta ${segment[3].arg!!.integerValue().toHex()}
sty ${(segment[3].arg!!.integerValue()+1).toHex()}
"""
},
// assignment: (u)wordvar = (u)wordarray[index_byte]
AsmPattern(listOf(Opcode.PUSH_BYTE, Opcode.READ_INDEXED_VAR_WORD, Opcode.POP_VAR_WORD)) { segment ->
val index = segment[0].arg!!.integerValue()*2
when(segment[1].callLabel) {
"AX" -> TODO("$segment")
"AY" -> TODO("$segment")
"XY" -> TODO("$segment")
else ->
when(segment[2].callLabel) {
"AX" -> " lda ${segment[1].callLabel}+$index | ldx ${segment[1].callLabel}+$index+1"
"AY" -> " lda ${segment[1].callLabel}+$index | ldy ${segment[1].callLabel}+$index+1"
"XY" -> " ldx ${segment[1].callLabel}+$index | ldy ${segment[1].callLabel}+$index+1"
else -> " lda ${segment[1].callLabel}+$index | sta ${segment[2].callLabel} | lda ${segment[1].callLabel}+$index+1,x | sta ${segment[2].callLabel}+1"
}
}
},
// assignment: bytearray[idxbyte] = byte
AsmPattern(listOf(Opcode.PUSH_BYTE, Opcode.PUSH_BYTE, Opcode.WRITE_INDEXED_VAR_BYTE)) { segment ->
val index = segment[1].arg!!.integerValue()
val value = segment[0].arg!!.integerValue().toHex()
when(segment[2].callLabel) {
"AX" -> " sta ${C64Zeropage.SCRATCH_W1} | stx ${C64Zeropage.SCRATCH_W1+1} | ldy #$index | lda #$value | sta (${C64Zeropage.SCRATCH_W1}),y"
"AY" -> " sta ${C64Zeropage.SCRATCH_W1} | sty ${C64Zeropage.SCRATCH_W1+1} | ldy #$index | lda #$value | sta (${C64Zeropage.SCRATCH_W1}),y"
"XY" -> " stx ${C64Zeropage.SCRATCH_W1} | sty ${C64Zeropage.SCRATCH_W1+1} | ldy #$index | lda #$value | sta (${C64Zeropage.SCRATCH_W1}),y"
else -> " lda #$value | sta ${segment[2].callLabel}+$index"
}
},
// assignment: bytearray[idxbyte] = bytevar
AsmPattern(listOf(Opcode.PUSH_VAR_BYTE, Opcode.PUSH_BYTE, Opcode.WRITE_INDEXED_VAR_BYTE)) { segment ->
val index = segment[1].arg!!.integerValue()
val saveValue: String
val loadValue: String
when(segment[0].callLabel) {
"A" -> {
saveValue = ""
loadValue = ""
}
"X" -> {
saveValue = ""
loadValue = "txa"
}
"Y" -> {
saveValue = "sty ${C64Zeropage.SCRATCH_B1}"
loadValue = "lda ${C64Zeropage.SCRATCH_B1}"
}
else -> {
saveValue = ""
loadValue = "lda ${segment[0].callLabel}"
}
}
when(segment[2].callLabel) {
"AX" -> " $saveValue | sta ${C64Zeropage.SCRATCH_W1} | stx ${C64Zeropage.SCRATCH_W1+1} | ldy #$index | $loadValue | sta (${C64Zeropage.SCRATCH_W1}),y"
"AY" -> " $saveValue | sta ${C64Zeropage.SCRATCH_W1} | sty ${C64Zeropage.SCRATCH_W1+1} | ldy #$index | $loadValue | sta (${C64Zeropage.SCRATCH_W1}),y"
"XY" -> " $saveValue | stx ${C64Zeropage.SCRATCH_W1} | sty ${C64Zeropage.SCRATCH_W1+1} | ldy #$index | $loadValue | sta (${C64Zeropage.SCRATCH_W1}),y"
else -> " $loadValue | sta ${segment[2].callLabel}+$index"
}
},
// assignment: bytearray[idxbyte] = membyte
AsmPattern(listOf(Opcode.PUSH_MEM_B, Opcode.PUSH_BYTE, Opcode.WRITE_INDEXED_VAR_BYTE)) { segment ->
val index = segment[1].arg!!.integerValue()
when(segment[2].callLabel) {
"AX" -> TODO("$segment")
"AY" -> TODO("$segment")
"XY" -> TODO("$segment")
else ->
"""
lda ${segment[0].arg!!.integerValue().toHex()}
sta ${segment[2].callLabel}+$index
"""
}
},
// assignment: bytearray[idxbyte] = memubyte
AsmPattern(listOf(Opcode.PUSH_MEM_UB, Opcode.PUSH_BYTE, Opcode.WRITE_INDEXED_VAR_BYTE)) { segment ->
val index = segment[1].arg!!.integerValue()
when(segment[2].callLabel) {
"AX" -> " sta ${C64Zeropage.SCRATCH_W1} | stx ${C64Zeropage.SCRATCH_W1+1} | ldy #$index | lda ${segment[0].arg!!.integerValue().toHex()} | sta (${C64Zeropage.SCRATCH_W1}),y"
"AY" -> " sta ${C64Zeropage.SCRATCH_W1} | sty ${C64Zeropage.SCRATCH_W1+1} | ldy #$index | lda ${segment[0].arg!!.integerValue().toHex()} | sta (${C64Zeropage.SCRATCH_W1}),y"
"XY" -> " stx ${C64Zeropage.SCRATCH_W1} | sty ${C64Zeropage.SCRATCH_W1+1} | ldy #$index | lda ${segment[0].arg!!.integerValue().toHex()} | sta (${C64Zeropage.SCRATCH_W1}),y"
else -> " lda ${segment[0].arg!!.integerValue().toHex()} | sta ${segment[2].callLabel}+$index"
}
},
// assignment: wordarray[idxbyte] = word
AsmPattern(listOf(Opcode.PUSH_WORD, Opcode.PUSH_BYTE, Opcode.WRITE_INDEXED_VAR_WORD)) { segment ->
val index = segment[1].arg!!.integerValue()*2
when(segment[2].callLabel) {
"AX" -> TODO("$segment")
"AY" -> TODO("$segment")
"XY" -> TODO("$segment")
else ->
"""
lda #<${segment[0].arg!!.integerValue().toHex()}
ldy #>${segment[0].arg!!.integerValue().toHex()}
sta ${segment[2].callLabel}+$index
sty ${segment[2].callLabel}+$index+1
"""
}
},
// assignment: wordarray[idxbyte] = wordvar
AsmPattern(listOf(Opcode.PUSH_VAR_WORD, Opcode.PUSH_BYTE, Opcode.WRITE_INDEXED_VAR_WORD)) { segment ->
val index = segment[1].arg!!.integerValue()*2
when(segment[0].callLabel) {
"AX" -> " sta ${segment[2].callLabel}+$index | stx ${segment[2].callLabel}+$index+1"
"AY" -> " sta ${segment[2].callLabel}+$index | sty ${segment[2].callLabel}+$index+1"
"XY" -> " stx ${segment[2].callLabel}+$index | sty ${segment[2].callLabel}+$index+1"
else ->
"""
lda ${segment[0].callLabel}
ldy ${segment[0].callLabel}+1
sta ${segment[2].callLabel}+$index
sty ${segment[2].callLabel}+$index+1
"""
}
},
// assignment: wordarray[idxbyte] = memword
AsmPattern(listOf(Opcode.PUSH_MEM_W, Opcode.PUSH_BYTE, Opcode.WRITE_INDEXED_VAR_WORD)) { segment ->
val index = segment[1].arg!!.integerValue()*2
when(segment[2].callLabel) {
"AX" -> TODO("$segment")
"AY" -> TODO("$segment")
"XY" -> TODO("$segment")
else ->
"""
lda ${segment[0].arg!!.integerValue().toHex()}
ldy ${segment[0].arg!!.integerValue().toHex()}+1
sta ${segment[2].callLabel}+$index
sty ${segment[2].callLabel}+$index+1
"""
}
},
// assignment: wordarray[idxbyte] = memuword (=same as above)
AsmPattern(listOf(Opcode.PUSH_MEM_UW, Opcode.PUSH_BYTE, Opcode.WRITE_INDEXED_VAR_WORD)) { segment ->
val index = segment[1].arg!!.integerValue()*2
when(segment[2].callLabel) {
"AX" -> TODO("$segment")
"AY" -> TODO("$segment")
"XY" -> TODO("$segment")
else ->
"""
lda ${segment[0].arg!!.integerValue().toHex()}
ldy ${segment[0].arg!!.integerValue().toHex()}+1
sta ${segment[2].callLabel}+$index
sty ${segment[2].callLabel}+$index+1
"""
}
},
// assignment: floatarray[idxbyte] = float
AsmPattern(listOf(Opcode.PUSH_FLOAT, Opcode.PUSH_BYTE, Opcode.WRITE_INDEXED_VAR_FLOAT)) { segment ->
val floatConst = getFloatConst(segment[0].arg!!)
val index = segment[1].arg!!.integerValue() * Mflpt5.MemorySize
"""
lda #<$floatConst
ldy #>$floatConst
sta ${C64Zeropage.SCRATCH_W1}
sty ${C64Zeropage.SCRATCH_W1+1}
lda #<(${segment[2].callLabel}+$index)
ldy #>(${segment[2].callLabel}+$index+1)
sta ${C64Zeropage.SCRATCH_W2}
sty ${C64Zeropage.SCRATCH_W2+1}
jsr prog8_lib.copy_float
"""
},
// assignment: floatarray[idxbyte] = floatvar
AsmPattern(listOf(Opcode.PUSH_VAR_FLOAT, Opcode.PUSH_BYTE, Opcode.WRITE_INDEXED_VAR_FLOAT)) { segment ->
val index = segment[1].arg!!.integerValue() * Mflpt5.MemorySize
"""
lda #<${segment[0].callLabel}
ldy #>${segment[0].callLabel}
sta ${C64Zeropage.SCRATCH_W1}
sty ${C64Zeropage.SCRATCH_W1+1}
lda #<(${segment[2].callLabel}+$index)
ldy #>(${segment[2].callLabel}+$index+1)
sta ${C64Zeropage.SCRATCH_W2}
sty ${C64Zeropage.SCRATCH_W2+1}
jsr prog8_lib.copy_float
"""
},
// assignment: floatarray[idxbyte] = memfloat
AsmPattern(listOf(Opcode.PUSH_MEM_FLOAT, Opcode.PUSH_BYTE, Opcode.WRITE_INDEXED_VAR_FLOAT)) { segment ->
val index = segment[1].arg!!.integerValue() * Mflpt5.MemorySize
"""
lda #<${segment[0].arg!!.integerValue().toHex()}
ldy #>${segment[0].arg!!.integerValue().toHex()}
sta ${C64Zeropage.SCRATCH_W1}
sty ${C64Zeropage.SCRATCH_W1+1}
lda #<(${segment[2].callLabel}+$index)
ldy #>(${segment[2].callLabel}+$index+1)
sta ${C64Zeropage.SCRATCH_W2}
sty ${C64Zeropage.SCRATCH_W2+1}
jsr prog8_lib.copy_float
"""
},
// assignment: var = bytearray[index] // assignment: var = bytearray[index]
AsmPattern(listOf(Opcode.PUSH_BYTE, Opcode.READ_INDEXED_VAR_BYTE, Opcode.POP_VAR_BYTE)) { segment -> AsmPattern(listOf(Opcode.PUSH_BYTE, Opcode.READ_INDEXED_VAR_BYTE, Opcode.POP_VAR_BYTE)) { segment ->
val index = segment[0].arg!!.integerValue() val index = segment[0].arg!!.integerValue()
when (segment[2].callLabel) { when(segment[1].callLabel) {
"A", "X", "Y" -> "AX" -> TODO("$segment")
" ld${segment[2].callLabel!!.toLowerCase()} ${segment[1].callLabel}+$index" "AY" -> TODO("$segment")
"XY" -> TODO("$segment")
else -> else ->
TODO("assign byte to array indexed") when (segment[2].callLabel) {
"A", "X", "Y" ->
" ld${segment[2].callLabel!!.toLowerCase()} ${segment[1].callLabel}+$index"
else ->
" lda ${segment[1].callLabel}+$index | sta ${segment[2].callLabel}"
}
}
},
// assignment: mem(u)byte = (u)bytearray[index]
AsmPattern(listOf(Opcode.PUSH_BYTE, Opcode.READ_INDEXED_VAR_BYTE, Opcode.POP_MEM_B)) { segment ->
val address = segment[2].arg!!.integerValue().toHex()
val index = segment[0].arg!!.integerValue()
when(segment[1].callLabel) {
"AX" -> " sta ${C64Zeropage.SCRATCH_W1} | stx ${C64Zeropage.SCRATCH_W1+1} | ldy #$index | lda (${C64Zeropage.SCRATCH_W1}),y | sta $address"
"AY" -> " sta ${C64Zeropage.SCRATCH_W1} | sty ${C64Zeropage.SCRATCH_W1+1} | ldy #$index | lda (${C64Zeropage.SCRATCH_W1}),y | sta $address"
"XY" -> " stx ${C64Zeropage.SCRATCH_W1} | sty ${C64Zeropage.SCRATCH_W1+1} | ldy #$index | lda (${C64Zeropage.SCRATCH_W1}),y | sta $address"
else -> " lda ${segment[1].callLabel}+$index | sta $address"
}
},
AsmPattern(listOf(Opcode.PUSH_BYTE, Opcode.READ_INDEXED_VAR_BYTE, Opcode.POP_MEM_UB)) { segment ->
val address = segment[2].arg!!.integerValue().toHex()
val index = segment[0].arg!!.integerValue()
when(segment[1].callLabel) {
"AX" -> " sta ${C64Zeropage.SCRATCH_W1} | stx ${C64Zeropage.SCRATCH_W1+1} | ldy #$index | lda (${C64Zeropage.SCRATCH_W1}),y | sta $address"
"AY" -> " sta ${C64Zeropage.SCRATCH_W1} | sty ${C64Zeropage.SCRATCH_W1+1} | ldy #$index | lda (${C64Zeropage.SCRATCH_W1}),y | sta $address"
"XY" -> " stx ${C64Zeropage.SCRATCH_W1} | sty ${C64Zeropage.SCRATCH_W1+1} | ldy #$index | lda (${C64Zeropage.SCRATCH_W1}),y | sta $address"
else -> " lda ${segment[1].callLabel}+$index | sta $address"
}
},
// assignment: mem(u)word = (u)wordarray[index]
AsmPattern(listOf(Opcode.PUSH_BYTE, Opcode.READ_INDEXED_VAR_WORD, Opcode.POP_MEM_W)) { segment ->
val index = segment[0].arg!!.integerValue()*2
when(segment[1].callLabel) {
"AX" -> TODO("$segment")
"AY" -> TODO("$segment")
"XY" -> TODO("$segment")
else ->
"""
lda ${segment[1].callLabel}+$index
ldy ${segment[1].callLabel}+1+$index
sta ${segment[2].arg!!.integerValue().toHex()}
sty ${(segment[2].arg!!.integerValue()+1).toHex()}
"""
}
},
AsmPattern(listOf(Opcode.PUSH_BYTE, Opcode.READ_INDEXED_VAR_WORD, Opcode.POP_MEM_UW)) { segment ->
val index = segment[0].arg!!.integerValue()*2
when(segment[1].callLabel) {
"AX" -> TODO("$segment")
"AY" -> TODO("$segment")
"XY" -> TODO("$segment")
else ->
"""
lda ${segment[1].callLabel}+$index
ldy ${segment[1].callLabel}+1+$index
sta ${segment[2].arg!!.integerValue().toHex()}
sty ${(segment[2].arg!!.integerValue()+1).toHex()}
"""
}
},
// assignment: bytearray2[index2] = bytearray1[index1]
AsmPattern(listOf(Opcode.PUSH_BYTE, Opcode.READ_INDEXED_VAR_BYTE, Opcode.PUSH_BYTE, Opcode.WRITE_INDEXED_VAR_BYTE)) { segment->
val index1 = segment[0].arg!!.integerValue()
val index2 = segment[2].arg!!.integerValue()
when(segment[1].callLabel) {
"AX" -> TODO("$segment")
"AY" -> TODO("$segment")
"XY" -> TODO("$segment")
else ->
when(segment[3].callLabel) {
"AX" -> " sta ${C64Zeropage.SCRATCH_W1} | stx ${C64Zeropage.SCRATCH_W1+1} | lda ${segment[1].callLabel}+$index1 | ldy #$index2 | sta (${C64Zeropage.SCRATCH_W1}),y"
"AY" -> " sta ${C64Zeropage.SCRATCH_W1} | sty ${C64Zeropage.SCRATCH_W1+1} | lda ${segment[1].callLabel}+$index1 | ldy #$index2 | sta (${C64Zeropage.SCRATCH_W1}),y"
"XY" -> " stx ${C64Zeropage.SCRATCH_W1} | sty ${C64Zeropage.SCRATCH_W1+1} | lda ${segment[1].callLabel}+$index1 | ldy #$index2 | sta (${C64Zeropage.SCRATCH_W1}),y"
else -> " lda ${segment[1].callLabel}+$index1 | sta ${segment[3].callLabel}+$index2"
}
}
},
// assignment: wordarrayw[index2] = wordarray1[index1]
AsmPattern(listOf(Opcode.PUSH_BYTE, Opcode.READ_INDEXED_VAR_WORD, Opcode.PUSH_BYTE, Opcode.WRITE_INDEXED_VAR_WORD)) { segment->
val index1 = segment[0].arg!!.integerValue()*2
val index2 = segment[2].arg!!.integerValue()*2
when(segment[1].callLabel) {
"AX" -> TODO("$segment")
"AY" -> TODO("$segment")
"XY" -> TODO("$segment")
else ->
when(segment[3].callLabel) {
"AX" -> TODO("$segment")
"AY" -> TODO("$segment")
"XY" -> TODO("$segment")
else ->
"""
lda ${segment[1].callLabel}+$index1
ldy ${segment[1].callLabel}+$index1+1
sta ${segment[3].callLabel}+$index2
sty ${segment[3].callLabel}+$index2+1
"""
}
} }
} }
) )
} }

View File

@ -18,10 +18,9 @@ import prog8.functions.BuiltinFunctions
todo optimize addition with self into shift 1 (A+=A -> A<<=1) 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) ) todo assignment optimization: optimize some simple multiplications and divisions into shifts (A*=2 -> lsl(A), X=X/2 -> lsr(X) )
todo analyse for unreachable code and remove that (f.i. code after goto or return that has no label so can never be jumped to) todo analyse for unreachable code and remove that (f.i. code after goto or return that has no label so can never be jumped to)
todo merge sequence of assignments into one (as long as the value is a constant and the target not a MEMORY type!) todo merge sequence of assignments into one to avoid repeated value loads (as long as the value is a constant and the target not a MEMORY type!)
todo report more always true/always false conditions todo report more always true/always false conditions
todo inline subroutines that are only called once todo (optionally?) inline subroutines that are "sufficiently small" (=VERY small, say 0-3 statements, otherwise code size will explode and short branches will suffer)
todo inline subroutines that are "sufficiently small"
*/ */
class StatementOptimizer(private val namespace: INameScope, private val heap: HeapValues) : IAstProcessor { class StatementOptimizer(private val namespace: INameScope, private val heap: HeapValues) : IAstProcessor {

View File

@ -100,6 +100,10 @@ class StackVm(private var traceOutputFile: String?) {
val mem = Memory() val mem = Memory()
var P_carry: Boolean = false var P_carry: Boolean = false
private set private set
var P_negative: Boolean = false
private set
var P_zero: Boolean = false
private set
var P_irqd: Boolean = false var P_irqd: Boolean = false
private set private set
var variables = mutableMapOf<String, Value>() // all variables (set of all vars used by all blocks/subroutines) key = their fully scoped name var variables = mutableMapOf<String, Value>() // all variables (set of all vars used by all blocks/subroutines) key = their fully scoped name
@ -739,13 +743,18 @@ class StackVm(private var traceOutputFile: String?) {
Opcode.BCC -> Opcode.BCC ->
return if(P_carry) ins.nextAlt!! else ins.next return if(P_carry) ins.nextAlt!! else ins.next
Opcode.BZ -> Opcode.BZ ->
return if(evalstack.pop().numericValue().toDouble()==0.0) ins.next else ins.nextAlt!! return if(P_zero) ins.next else ins.nextAlt!!
Opcode.BNZ -> Opcode.BNZ ->
return if(evalstack.pop().numericValue().toDouble()!=0.0) ins.next else ins.nextAlt!! return if(P_zero) ins.nextAlt!! else ins.next
Opcode.BNEG -> Opcode.BNEG ->
return if(evalstack.pop().numericValue().toDouble()<0.0) ins.next else ins.nextAlt!! return if(P_negative) ins.next else ins.nextAlt!!
Opcode.BPOS -> { Opcode.BPOS ->
return if (evalstack.pop().numericValue().toDouble() >= 0.0) ins.next else ins.nextAlt!! return if(P_negative) ins.nextAlt!! else ins.next
Opcode.BVS, Opcode.BVC -> throw VmExecutionException("stackVM doesn't support the overflow flag")
Opcode.TEST -> {
val value=evalstack.pop().numericValue().toDouble()
P_zero = value == 0.0
P_negative = value < 0.0
} }
Opcode.CALL -> Opcode.CALL ->
callstack.push(ins.nextAlt) callstack.push(ins.nextAlt)
@ -1329,6 +1338,8 @@ class StackVm(private var traceOutputFile: String?) {
Opcode.RSAVE -> { Opcode.RSAVE -> {
evalstack.push(Value(DataType.UBYTE, if(P_irqd) 1 else 0)) evalstack.push(Value(DataType.UBYTE, if(P_irqd) 1 else 0))
evalstack.push(Value(DataType.UBYTE, if(P_carry) 1 else 0)) evalstack.push(Value(DataType.UBYTE, if(P_carry) 1 else 0))
evalstack.push(Value(DataType.UBYTE, if(P_negative) 1 else 0))
evalstack.push(Value(DataType.UBYTE, if(P_zero) 1 else 0))
evalstack.push(variables["X"]) evalstack.push(variables["X"])
evalstack.push(variables["Y"]) evalstack.push(variables["Y"])
evalstack.push(variables["A"]) evalstack.push(variables["A"])
@ -1337,6 +1348,8 @@ class StackVm(private var traceOutputFile: String?) {
variables["A"] = evalstack.pop() variables["A"] = evalstack.pop()
variables["X"] = evalstack.pop() variables["X"] = evalstack.pop()
variables["Y"] = evalstack.pop() variables["Y"] = evalstack.pop()
P_zero = evalstack.pop().asBooleanValue
P_negative = evalstack.pop().asBooleanValue
P_carry = evalstack.pop().asBooleanValue P_carry = evalstack.pop().asBooleanValue
P_irqd = evalstack.pop().asBooleanValue P_irqd = evalstack.pop().asBooleanValue
} }

View File

@ -98,6 +98,8 @@ class TestStackVmOpcodes {
vm.load(makeProg(ins), null) vm.load(makeProg(ins), null)
assertFalse(vm.P_carry) assertFalse(vm.P_carry)
assertFalse(vm.P_irqd) assertFalse(vm.P_irqd)
assertFalse(vm.P_negative)
assertFalse(vm.P_zero)
vm.step(1) vm.step(1)
assertTrue(vm.P_carry) assertTrue(vm.P_carry)
assertFalse(vm.P_irqd) assertFalse(vm.P_irqd)
@ -862,17 +864,19 @@ class TestStackVmOpcodes {
fun testBZ() { fun testBZ() {
val ins = mutableListOf( val ins = mutableListOf(
Instruction(Opcode.PUSH_WORD, Value(DataType.UWORD, 1)), Instruction(Opcode.PUSH_WORD, Value(DataType.UWORD, 1)),
Instruction(Opcode.TEST),
Instruction(Opcode.BZ, callLabel = "label"), Instruction(Opcode.BZ, callLabel = "label"),
Instruction(Opcode.PUSH_WORD, Value(DataType.UWORD, 0)), Instruction(Opcode.PUSH_WORD, Value(DataType.UWORD, 0)),
Instruction(Opcode.TEST),
Instruction(Opcode.BZ, callLabel = "label"), Instruction(Opcode.BZ, callLabel = "label"),
Instruction(Opcode.LINE, callLabel = "string1"), Instruction(Opcode.LINE, callLabel = "string1"),
Instruction(Opcode.TERMINATE), Instruction(Opcode.TERMINATE),
Instruction(Opcode.LINE, callLabel = "string2")) Instruction(Opcode.LINE, callLabel = "string2"))
val labels = mapOf("label" to ins.last()) // points to the second LINE instruction val labels = mapOf("label" to ins.last()) // points to the second LINE instruction
vm.load(makeProg(ins, labels=labels), null) vm.load(makeProg(ins, labels=labels), null)
vm.step(2)
assertEquals("", vm.sourceLine)
vm.step(3) vm.step(3)
assertEquals("", vm.sourceLine)
vm.step(4)
assertEquals("string2", vm.sourceLine) assertEquals("string2", vm.sourceLine)
assertEquals(0, vm.callstack.size) assertEquals(0, vm.callstack.size)
assertEquals(0, vm.evalstack.size) assertEquals(0, vm.evalstack.size)
@ -882,17 +886,19 @@ class TestStackVmOpcodes {
fun testBNZ() { fun testBNZ() {
val ins = mutableListOf( val ins = mutableListOf(
Instruction(Opcode.PUSH_WORD, Value(DataType.UWORD, 0)), Instruction(Opcode.PUSH_WORD, Value(DataType.UWORD, 0)),
Instruction(Opcode.TEST),
Instruction(Opcode.BNZ, callLabel = "label"), Instruction(Opcode.BNZ, callLabel = "label"),
Instruction(Opcode.PUSH_WORD, Value(DataType.UWORD, 1)), Instruction(Opcode.PUSH_WORD, Value(DataType.UWORD, 1)),
Instruction(Opcode.TEST),
Instruction(Opcode.BNZ, callLabel = "label"), Instruction(Opcode.BNZ, callLabel = "label"),
Instruction(Opcode.LINE, callLabel = "string1"), Instruction(Opcode.LINE, callLabel = "string1"),
Instruction(Opcode.TERMINATE), Instruction(Opcode.TERMINATE),
Instruction(Opcode.LINE, callLabel = "string2")) Instruction(Opcode.LINE, callLabel = "string2"))
val labels = mapOf("label" to ins.last()) // points to the second LINE instruction val labels = mapOf("label" to ins.last()) // points to the second LINE instruction
vm.load(makeProg(ins, labels=labels), null) vm.load(makeProg(ins, labels=labels), null)
vm.step(2)
assertEquals("", vm.sourceLine)
vm.step(3) vm.step(3)
assertEquals("", vm.sourceLine)
vm.step(4)
assertEquals("string2", vm.sourceLine) assertEquals("string2", vm.sourceLine)
assertEquals(0, vm.callstack.size) assertEquals(0, vm.callstack.size)
assertEquals(0, vm.evalstack.size) assertEquals(0, vm.evalstack.size)
@ -902,21 +908,24 @@ class TestStackVmOpcodes {
fun testBNEG() { fun testBNEG() {
val ins = mutableListOf( val ins = mutableListOf(
Instruction(Opcode.PUSH_WORD, Value(DataType.UWORD, 0)), Instruction(Opcode.PUSH_WORD, Value(DataType.UWORD, 0)),
Instruction(Opcode.TEST),
Instruction(Opcode.BNEG, callLabel = "label"), Instruction(Opcode.BNEG, callLabel = "label"),
Instruction(Opcode.PUSH_WORD, Value(DataType.UWORD, 1)), Instruction(Opcode.PUSH_WORD, Value(DataType.UWORD, 1)),
Instruction(Opcode.TEST),
Instruction(Opcode.BNEG, callLabel = "label"), Instruction(Opcode.BNEG, callLabel = "label"),
Instruction(Opcode.PUSH_FLOAT, Value(DataType.FLOAT, -99)), Instruction(Opcode.PUSH_FLOAT, Value(DataType.FLOAT, -99)),
Instruction(Opcode.TEST),
Instruction(Opcode.BNEG, callLabel = "label"), Instruction(Opcode.BNEG, callLabel = "label"),
Instruction(Opcode.LINE, callLabel = "string1"), Instruction(Opcode.LINE, callLabel = "string1"),
Instruction(Opcode.TERMINATE), Instruction(Opcode.TERMINATE),
Instruction(Opcode.LINE, callLabel = "string2")) Instruction(Opcode.LINE, callLabel = "string2"))
val labels = mapOf("label" to ins.last()) // points to the second LINE instruction val labels = mapOf("label" to ins.last()) // points to the second LINE instruction
vm.load(makeProg(ins, labels=labels), null) vm.load(makeProg(ins, labels=labels), null)
vm.step(2) vm.step(3)
assertEquals("", vm.sourceLine)
vm.step(2)
assertEquals("", vm.sourceLine) assertEquals("", vm.sourceLine)
vm.step(3) vm.step(3)
assertEquals("", vm.sourceLine)
vm.step(4)
assertEquals("string2", vm.sourceLine) assertEquals("string2", vm.sourceLine)
assertEquals(0, vm.callstack.size) assertEquals(0, vm.callstack.size)
assertEquals(0, vm.evalstack.size) assertEquals(0, vm.evalstack.size)
@ -926,17 +935,19 @@ class TestStackVmOpcodes {
fun testBPOS() { fun testBPOS() {
val ins = mutableListOf( val ins = mutableListOf(
Instruction(Opcode.PUSH_FLOAT, Value(DataType.FLOAT, -99)), Instruction(Opcode.PUSH_FLOAT, Value(DataType.FLOAT, -99)),
Instruction(Opcode.TEST),
Instruction(Opcode.BPOS, callLabel = "label"), Instruction(Opcode.BPOS, callLabel = "label"),
Instruction(Opcode.PUSH_WORD, Value(DataType.UWORD, 0)), Instruction(Opcode.PUSH_WORD, Value(DataType.UWORD, 0)),
Instruction(Opcode.TEST),
Instruction(Opcode.BPOS, callLabel = "label"), Instruction(Opcode.BPOS, callLabel = "label"),
Instruction(Opcode.LINE, callLabel = "string1"), Instruction(Opcode.LINE, callLabel = "string1"),
Instruction(Opcode.TERMINATE), Instruction(Opcode.TERMINATE),
Instruction(Opcode.LINE, callLabel = "string2")) Instruction(Opcode.LINE, callLabel = "string2"))
val labels = mapOf("label" to ins.last()) // points to the second LINE instruction val labels = mapOf("label" to ins.last()) // points to the second LINE instruction
vm.load(makeProg(ins, labels=labels), null) vm.load(makeProg(ins, labels=labels), null)
vm.step(2)
assertEquals("", vm.sourceLine)
vm.step(3) vm.step(3)
assertEquals("", vm.sourceLine)
vm.step(4)
assertEquals("string2", vm.sourceLine) assertEquals("string2", vm.sourceLine)
assertEquals(0, vm.callstack.size) assertEquals(0, vm.callstack.size)
assertEquals(0, vm.evalstack.size) assertEquals(0, vm.evalstack.size)

View File

@ -29,6 +29,7 @@ ror2_word
; @todo: stubs for now ; @todo: stubs for now
; @todo: move float operations to their own library (only included when floats are enabled)
ub2float ub2float
rts rts
@ -63,6 +64,9 @@ sub_f
mul_f mul_f
rts rts
neg_f
rts
sub_uw sub_uw
rts rts
@ -72,5 +76,73 @@ less_ub
less_f less_f
rts rts
func_sin
rts
func_cos
rts
func_abs
rts
func_acos
rts
func_asin
rts
func_tan
rts
func_atan
rts
func_ln
rts
func_log2
rts
func_log10
rts
func_sqrt
rts
func_rad
rts
func_deg
rts
func_round
rts
func_floor
rts
func_ceil
rts
func_max
rts
func_min
rts
func_avg
rts
func_sum
rts
func_len
rts
func_any
rts
func_all
rts
func_rnd
rts
func_rndw
rts
func_rndf
rts
func_wrd
rts
func_uwrd
rts
func_str2byte
rts
func_str2ubyte
rts
func_str2word
rts
func_str2uword
rts
func_str2float
rts
}} }}
} }