mirror of
https://github.com/irmen/prog8.git
synced 2025-01-11 13:29:45 +00:00
more asm output
This commit is contained in:
parent
595bf7ad4b
commit
5203dad7c1
@ -45,6 +45,46 @@ sub start() {
|
||||
memory float mfloat = $c006
|
||||
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
|
||||
ubarr1[2]=42
|
||||
@ -52,6 +92,10 @@ sub start() {
|
||||
uwarr1[2]=42555
|
||||
farr1[2]=42.5678
|
||||
|
||||
ubarr1[2]=X
|
||||
uwarr1[2]=XY
|
||||
; farr1[2]=XY ; @todo
|
||||
|
||||
barr1[2] = b
|
||||
ubarr1[2] = ub
|
||||
warr1[2] = w
|
||||
@ -68,62 +112,88 @@ sub start() {
|
||||
ub = ubarr1[2]
|
||||
w = warr1[2]
|
||||
uw = uwarr1[2]
|
||||
fl1 = farr1[2]
|
||||
; fl1 = farr1[2] ; @todo
|
||||
|
||||
mbyte= barr1[2]
|
||||
mubyte = ubarr1[2]
|
||||
mword = warr1[2]
|
||||
muword = uwarr1[2]
|
||||
mfloat = farr1[2]
|
||||
; mfloat = farr1[2] ; @todo
|
||||
|
||||
barr1[2] = barr2[3]
|
||||
ubarr1[2] = ubarr2[3]
|
||||
warr1[2] = warr2[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
|
||||
; ub = 1
|
||||
; w = 1
|
||||
; uw = 1
|
||||
; fl1 = 2.345
|
||||
;
|
||||
; b = b2
|
||||
; ub = pixely
|
||||
; w = w2
|
||||
; uw = uw2
|
||||
; fl1 = fl2
|
||||
;
|
||||
; b = mbyte
|
||||
; ub = mubyte
|
||||
; w = mword
|
||||
; uw = muword
|
||||
; fl1 = mfloat
|
||||
;
|
||||
; mbyte = 1
|
||||
; mubyte = 1
|
||||
; mword = 1
|
||||
; muword = 1
|
||||
; mfloat = 3.456
|
||||
b = 1
|
||||
ub = 1
|
||||
w = 1
|
||||
uw = 1
|
||||
fl1 = 2.345
|
||||
|
||||
b = b2
|
||||
ub = pixely
|
||||
w = b2
|
||||
w = w2
|
||||
w = ub
|
||||
uw = ub
|
||||
uw = uw2
|
||||
;fl1 = ub ; @todo
|
||||
;fl1 = b2 ; @todo
|
||||
;fl1 = uw2 ; @todo
|
||||
;fl1 = w2 ; @todo
|
||||
fl1 = fl2
|
||||
|
||||
b = mbyte
|
||||
ub = mubyte
|
||||
w = mword
|
||||
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
|
||||
}
|
||||
|
@ -931,7 +931,7 @@ class AstChecker(private val namespace: INameScope,
|
||||
val result = when(targetDatatype) {
|
||||
DataType.BYTE -> sourceDatatype==DataType.BYTE
|
||||
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.FLOAT -> sourceDatatype in NumericDatatypes
|
||||
DataType.STR -> sourceDatatype==DataType.STR
|
||||
|
@ -120,18 +120,20 @@ class AstIdentifiersChecker : IAstProcessor {
|
||||
}
|
||||
|
||||
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.
|
||||
if(forLoop.loopRegister!=null && forLoop.decltype!=null) {
|
||||
if(forLoop.loopRegister!=null) {
|
||||
if(forLoop.decltype!=null)
|
||||
checkResult.add(SyntaxError("register loop variables cannot be explicitly declared with a datatype", forLoop.position))
|
||||
} else {
|
||||
val loopVar = forLoop.loopVar!!
|
||||
val varName = loopVar.nameInSource.last()
|
||||
if(forLoop.loopRegister == Register.X || forLoop.loopRegister==Register.XY || forLoop.loopRegister==Register.AX)
|
||||
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) {
|
||||
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) {
|
||||
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)
|
||||
forLoop.body.statements.add(0, vardecl)
|
||||
forLoop.loopVar.parent = forLoop.body // loopvar 'is defined in the body'
|
||||
@ -143,4 +145,10 @@ class AstIdentifiersChecker : IAstProcessor {
|
||||
}
|
||||
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)
|
||||
}
|
||||
}
|
||||
|
@ -440,8 +440,8 @@ private class StatementTranslator(private val prog: IntermediateProgram,
|
||||
BranchCondition.CC -> Opcode.BCS
|
||||
BranchCondition.EQ, BranchCondition.Z -> Opcode.BNZ
|
||||
BranchCondition.NE, BranchCondition.NZ -> Opcode.BZ
|
||||
BranchCondition.VS -> TODO("Opcode.BVC")
|
||||
BranchCondition.VC -> TODO("Opcode.BVS")
|
||||
BranchCondition.VS -> Opcode.BVC
|
||||
BranchCondition.VC -> Opcode.BVS
|
||||
BranchCondition.MI, BranchCondition.NEG -> Opcode.BPOS
|
||||
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 }
|
||||
* Which is translated into:
|
||||
* <condition-expression evaluation>
|
||||
* TEST
|
||||
* BZ _stmt_999_else
|
||||
* stuff
|
||||
* JUMP _stmt_999_end
|
||||
@ -480,6 +481,7 @@ private class StatementTranslator(private val prog: IntermediateProgram,
|
||||
*
|
||||
* or when there is no else block:
|
||||
* <condition-expression evaluation>
|
||||
* TEST
|
||||
* BZ _stmt_999_end
|
||||
* stuff
|
||||
* _stmt_999_end:
|
||||
@ -491,11 +493,13 @@ private class StatementTranslator(private val prog: IntermediateProgram,
|
||||
translate(stmt.condition)
|
||||
val labelEnd = makeLabel("end")
|
||||
if(stmt.elsepart.isEmpty()) {
|
||||
prog.instr(Opcode.TEST)
|
||||
prog.instr(Opcode.BZ, callLabel = labelEnd)
|
||||
translate(stmt.truepart)
|
||||
prog.label(labelEnd)
|
||||
} else {
|
||||
val labelElse = makeLabel("else")
|
||||
prog.instr(Opcode.TEST)
|
||||
prog.instr(Opcode.BZ, callLabel = labelElse)
|
||||
translate(stmt.truepart)
|
||||
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(opcodePushvar(zero.type), callLabel = indexVar)
|
||||
prog.instr(opcodeSub(zero.type))
|
||||
prog.instr(Opcode.TEST)
|
||||
prog.instr(Opcode.BNZ, callLabel = loopLabel)
|
||||
|
||||
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(opcodePushvar(varDt), callLabel = varname)
|
||||
prog.instr(opcodeSub(varDt))
|
||||
prog.instr(Opcode.TEST)
|
||||
prog.instr(Opcode.BNZ, callLabel = loopLabel)
|
||||
|
||||
prog.label(breakLabel)
|
||||
@ -1692,6 +1698,7 @@ private class StatementTranslator(private val prog: IntermediateProgram,
|
||||
* continue -> goto condition
|
||||
* continue:
|
||||
* <evaluate condition>
|
||||
* test
|
||||
* bnz loop
|
||||
* break:
|
||||
* nop
|
||||
@ -1707,6 +1714,7 @@ private class StatementTranslator(private val prog: IntermediateProgram,
|
||||
translate(stmt.body)
|
||||
prog.label(continueLabel)
|
||||
translate(stmt.condition)
|
||||
prog.instr(Opcode.TEST)
|
||||
prog.instr(Opcode.BNZ, callLabel = loopLabel)
|
||||
prog.label(breakLabel)
|
||||
prog.instr(Opcode.NOP)
|
||||
@ -1726,6 +1734,7 @@ private class StatementTranslator(private val prog: IntermediateProgram,
|
||||
* continue -> goto condition
|
||||
* condition:
|
||||
* <evaluate untilCondition>
|
||||
* test
|
||||
* bz goto loop
|
||||
* break:
|
||||
* nop
|
||||
@ -1740,6 +1749,7 @@ private class StatementTranslator(private val prog: IntermediateProgram,
|
||||
translate(stmt.body)
|
||||
prog.label(continueLabel)
|
||||
translate(stmt.untilCondition)
|
||||
prog.instr(Opcode.TEST)
|
||||
prog.instr(Opcode.BZ, callLabel = loopLabel)
|
||||
prog.label(breakLabel)
|
||||
prog.instr(Opcode.NOP)
|
||||
|
@ -158,6 +158,8 @@ enum class Opcode {
|
||||
DEC_VAR_F,
|
||||
|
||||
// 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_UB,
|
||||
LESS_W,
|
||||
@ -193,16 +195,16 @@ enum class Opcode {
|
||||
WRITE_INDEXED_VAR_WORD,
|
||||
WRITE_INDEXED_VAR_FLOAT,
|
||||
|
||||
// branching
|
||||
// branching, without consuming a value from the stack
|
||||
JUMP,
|
||||
BCS,
|
||||
BCC,
|
||||
BZ, // branch if value on top of stack is zero
|
||||
BNZ, // branch if value on top of stack is not zero
|
||||
BNEG, // branch if value on top of stack < 0
|
||||
BPOS, // branch if value on top of stack >= 0
|
||||
// BVS, // status flag V (overflow) not implemented
|
||||
// BVC, // status flag V (overflow) not implemented
|
||||
BCS, // branch if carry set
|
||||
BCC, // branch if carry clear
|
||||
BZ, // branch if zero flag
|
||||
BNZ, // branch if not zero flag
|
||||
BNEG, // branch if negative flag
|
||||
BPOS, // branch if not negative flag
|
||||
BVS, // branch if overflow flag
|
||||
BVC, // branch if not overflow flag
|
||||
|
||||
// subroutine calling
|
||||
CALL,
|
||||
|
@ -400,50 +400,50 @@ class AsmGen(val options: CompilationOptions, val program: IntermediateProgram,
|
||||
"_prog8_breakpoint_$breakpointCounter\tnop"
|
||||
}
|
||||
|
||||
Opcode.PUSH_BYTE -> {
|
||||
" lda #${ins.arg!!.integerValue().toHex()} | sta ${ESTACK_LO.toHex()},x | dex"
|
||||
}
|
||||
Opcode.PUSH_WORD -> {
|
||||
val value = ins.arg!!.integerValue().toHex()
|
||||
" lda #<$value | sta ${ESTACK_LO.toHex()},x | lda #>$value | sta ${ESTACK_HI.toHex()},x | dex"
|
||||
}
|
||||
Opcode.PUSH_FLOAT -> {
|
||||
val floatConst = getFloatConst(ins.arg!!)
|
||||
" lda #<$floatConst | ldy #>$floatConst | jsr prog8_lib.push_float"
|
||||
}
|
||||
Opcode.PUSH_VAR_BYTE -> {
|
||||
when(ins.callLabel) {
|
||||
"X" -> throw CompilerException("makes no sense to push X, it's used as a stack pointer itself")
|
||||
"A" -> " sta ${ESTACK_LO.toHex()},x | dex"
|
||||
"Y" -> " tya | sta ${ESTACK_LO.toHex()},x | dex"
|
||||
else -> " lda ${ins.callLabel} | sta ${ESTACK_LO.toHex()},x | dex"
|
||||
}
|
||||
}
|
||||
Opcode.PUSH_VAR_WORD -> {
|
||||
when (ins.callLabel) {
|
||||
"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")
|
||||
"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"
|
||||
}
|
||||
}
|
||||
Opcode.PUSH_VAR_FLOAT -> " lda #<${ins.callLabel} | ldy #>${ins.callLabel}| jsr prog8_lib.push_float"
|
||||
Opcode.PUSH_MEM_B, Opcode.PUSH_MEM_UB -> {
|
||||
"""
|
||||
lda ${ins.arg!!.integerValue().toHex()}
|
||||
sta ${ESTACK_LO.toHex()},x
|
||||
dex
|
||||
"""
|
||||
}
|
||||
Opcode.PUSH_MEM_W, Opcode.PUSH_MEM_UW -> {
|
||||
"""
|
||||
lda ${ins.arg!!.integerValue().toHex()}
|
||||
sta ${ESTACK_LO.toHex()},x
|
||||
lda ${(ins.arg.integerValue()+1).toHex()}
|
||||
sta ${ESTACK_HI.toHex()},x
|
||||
dex
|
||||
"""
|
||||
}
|
||||
// Opcode.PUSH_BYTE -> {
|
||||
// " lda #${ins.arg!!.integerValue().toHex()} | sta ${ESTACK_LO.toHex()},x | dex"
|
||||
// }
|
||||
// Opcode.PUSH_WORD -> {
|
||||
// val value = ins.arg!!.integerValue().toHex()
|
||||
// " lda #<$value | sta ${ESTACK_LO.toHex()},x | lda #>$value | sta ${ESTACK_HI.toHex()},x | dex"
|
||||
// }
|
||||
// Opcode.PUSH_FLOAT -> {
|
||||
// val floatConst = getFloatConst(ins.arg!!)
|
||||
// " lda #<$floatConst | ldy #>$floatConst | jsr prog8_lib.push_float"
|
||||
// }
|
||||
// Opcode.PUSH_VAR_BYTE -> {
|
||||
// when(ins.callLabel) {
|
||||
// "X" -> throw CompilerException("makes no sense to push X, it's used as a stack pointer itself")
|
||||
// "A" -> " sta ${ESTACK_LO.toHex()},x | dex"
|
||||
// "Y" -> " tya | sta ${ESTACK_LO.toHex()},x | dex"
|
||||
// else -> " lda ${ins.callLabel} | sta ${ESTACK_LO.toHex()},x | dex"
|
||||
// }
|
||||
// }
|
||||
// Opcode.PUSH_VAR_WORD -> {
|
||||
// when (ins.callLabel) {
|
||||
// "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")
|
||||
// "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"
|
||||
// }
|
||||
// }
|
||||
// Opcode.PUSH_VAR_FLOAT -> " lda #<${ins.callLabel} | ldy #>${ins.callLabel}| jsr prog8_lib.push_float"
|
||||
// Opcode.PUSH_MEM_B, Opcode.PUSH_MEM_UB -> {
|
||||
// """
|
||||
// lda ${ins.arg!!.integerValue().toHex()}
|
||||
// sta ${ESTACK_LO.toHex()},x
|
||||
// dex
|
||||
// """
|
||||
// }
|
||||
// Opcode.PUSH_MEM_W, Opcode.PUSH_MEM_UW -> {
|
||||
// """
|
||||
// lda ${ins.arg!!.integerValue().toHex()}
|
||||
// sta ${ESTACK_LO.toHex()},x
|
||||
// lda ${(ins.arg.integerValue()+1).toHex()}
|
||||
// sta ${ESTACK_HI.toHex()},x
|
||||
// dex
|
||||
// """
|
||||
// }
|
||||
|
||||
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.BCC -> " bcc ${ins.callLabel}"
|
||||
Opcode.BZ -> " beq ${ins.callLabel}"
|
||||
Opcode.BNZ -> " bne ${ins.callLabel}"
|
||||
Opcode.BNEG -> " bmi ${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.B2FLOAT -> " jsr prog8_lib.b2float"
|
||||
Opcode.UW2FLOAT -> " jsr prog8_lib.uw2float"
|
||||
@ -1035,10 +1037,16 @@ class AsmGen(val options: CompilationOptions, val program: IntermediateProgram,
|
||||
|
||||
// assignment: mem = bytevar/ubytevar
|
||||
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 ->
|
||||
" 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
|
||||
@ -1051,10 +1059,16 @@ class AsmGen(val options: CompilationOptions, val program: IntermediateProgram,
|
||||
|
||||
// assignment: (u)bytevar = membyte
|
||||
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 ->
|
||||
" 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
|
||||
AsmPattern(listOf(Opcode.PUSH_VAR_WORD, Opcode.POP_MEM_W)) { segment ->
|
||||
when(segment[0].callLabel) {
|
||||
"AX" -> TODO("$segment")
|
||||
"AY" -> TODO("$segment")
|
||||
"XY" -> TODO("$segment")
|
||||
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 ->
|
||||
when(segment[0].callLabel) {
|
||||
"AX" -> TODO("$segment")
|
||||
"AY" -> TODO("$segment")
|
||||
"XY" -> TODO("$segment")
|
||||
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
|
||||
@ -1113,20 +1139,32 @@ class AsmGen(val options: CompilationOptions, val program: IntermediateProgram,
|
||||
|
||||
// assignment: (u)wordvar = memword
|
||||
AsmPattern(listOf(Opcode.PUSH_MEM_W, Opcode.POP_VAR_WORD)) { segment ->
|
||||
when(segment[1].callLabel) {
|
||||
"AX" -> " lda ${segment[0].arg!!.integerValue().toHex()} | ldx ${(segment[0].arg!!.integerValue()+1).toHex()}"
|
||||
"AY" -> " lda ${segment[0].arg!!.integerValue().toHex()} | ldy ${(segment[0].arg!!.integerValue()+1).toHex()}"
|
||||
"XY" -> " ldx ${segment[0].arg!!.integerValue().toHex()} | ldy ${(segment[0].arg!!.integerValue()+1).toHex()}"
|
||||
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 ->
|
||||
when(segment[1].callLabel) {
|
||||
"AX" -> " lda ${segment[0].arg!!.integerValue().toHex()} | ldx ${(segment[0].arg!!.integerValue()+1).toHex()}"
|
||||
"AY" -> " lda ${segment[0].arg!!.integerValue().toHex()} | ldy ${(segment[0].arg!!.integerValue()+1).toHex()}"
|
||||
"XY" -> " ldx ${segment[0].arg!!.integerValue().toHex()} | ldy ${(segment[0].arg!!.integerValue()+1).toHex()}"
|
||||
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
|
||||
@ -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]
|
||||
AsmPattern(listOf(Opcode.PUSH_BYTE, Opcode.READ_INDEXED_VAR_BYTE, Opcode.POP_VAR_BYTE)) { segment ->
|
||||
val index = segment[0].arg!!.integerValue()
|
||||
when(segment[1].callLabel) {
|
||||
"AX" -> TODO("$segment")
|
||||
"AY" -> TODO("$segment")
|
||||
"XY" -> TODO("$segment")
|
||||
else ->
|
||||
when (segment[2].callLabel) {
|
||||
"A", "X", "Y" ->
|
||||
" ld${segment[2].callLabel!!.toLowerCase()} ${segment[1].callLabel}+$index"
|
||||
else ->
|
||||
TODO("assign byte to array indexed")
|
||||
" 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
|
||||
"""
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
)
|
||||
}
|
||||
|
@ -18,10 +18,9 @@ import prog8.functions.BuiltinFunctions
|
||||
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 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 inline subroutines that are only called once
|
||||
todo inline subroutines that are "sufficiently small"
|
||||
todo (optionally?) inline subroutines that are "sufficiently small" (=VERY small, say 0-3 statements, otherwise code size will explode and short branches will suffer)
|
||||
*/
|
||||
|
||||
class StatementOptimizer(private val namespace: INameScope, private val heap: HeapValues) : IAstProcessor {
|
||||
|
@ -100,6 +100,10 @@ class StackVm(private var traceOutputFile: String?) {
|
||||
val mem = Memory()
|
||||
var P_carry: Boolean = false
|
||||
private set
|
||||
var P_negative: Boolean = false
|
||||
private set
|
||||
var P_zero: Boolean = false
|
||||
private set
|
||||
var P_irqd: Boolean = false
|
||||
private set
|
||||
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 ->
|
||||
return if(P_carry) ins.nextAlt!! else ins.next
|
||||
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 ->
|
||||
return if(evalstack.pop().numericValue().toDouble()!=0.0) ins.next else ins.nextAlt!!
|
||||
return if(P_zero) ins.nextAlt!! else ins.next
|
||||
Opcode.BNEG ->
|
||||
return if(evalstack.pop().numericValue().toDouble()<0.0) ins.next else ins.nextAlt!!
|
||||
Opcode.BPOS -> {
|
||||
return if (evalstack.pop().numericValue().toDouble() >= 0.0) ins.next else ins.nextAlt!!
|
||||
return if(P_negative) ins.next else ins.nextAlt!!
|
||||
Opcode.BPOS ->
|
||||
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 ->
|
||||
callstack.push(ins.nextAlt)
|
||||
@ -1329,6 +1338,8 @@ class StackVm(private var traceOutputFile: String?) {
|
||||
Opcode.RSAVE -> {
|
||||
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_negative) 1 else 0))
|
||||
evalstack.push(Value(DataType.UBYTE, if(P_zero) 1 else 0))
|
||||
evalstack.push(variables["X"])
|
||||
evalstack.push(variables["Y"])
|
||||
evalstack.push(variables["A"])
|
||||
@ -1337,6 +1348,8 @@ class StackVm(private var traceOutputFile: String?) {
|
||||
variables["A"] = evalstack.pop()
|
||||
variables["X"] = evalstack.pop()
|
||||
variables["Y"] = evalstack.pop()
|
||||
P_zero = evalstack.pop().asBooleanValue
|
||||
P_negative = evalstack.pop().asBooleanValue
|
||||
P_carry = evalstack.pop().asBooleanValue
|
||||
P_irqd = evalstack.pop().asBooleanValue
|
||||
}
|
||||
|
@ -98,6 +98,8 @@ class TestStackVmOpcodes {
|
||||
vm.load(makeProg(ins), null)
|
||||
assertFalse(vm.P_carry)
|
||||
assertFalse(vm.P_irqd)
|
||||
assertFalse(vm.P_negative)
|
||||
assertFalse(vm.P_zero)
|
||||
vm.step(1)
|
||||
assertTrue(vm.P_carry)
|
||||
assertFalse(vm.P_irqd)
|
||||
@ -862,17 +864,19 @@ class TestStackVmOpcodes {
|
||||
fun testBZ() {
|
||||
val ins = mutableListOf(
|
||||
Instruction(Opcode.PUSH_WORD, Value(DataType.UWORD, 1)),
|
||||
Instruction(Opcode.TEST),
|
||||
Instruction(Opcode.BZ, callLabel = "label"),
|
||||
Instruction(Opcode.PUSH_WORD, Value(DataType.UWORD, 0)),
|
||||
Instruction(Opcode.TEST),
|
||||
Instruction(Opcode.BZ, callLabel = "label"),
|
||||
Instruction(Opcode.LINE, callLabel = "string1"),
|
||||
Instruction(Opcode.TERMINATE),
|
||||
Instruction(Opcode.LINE, callLabel = "string2"))
|
||||
val labels = mapOf("label" to ins.last()) // points to the second LINE instruction
|
||||
vm.load(makeProg(ins, labels=labels), null)
|
||||
vm.step(2)
|
||||
assertEquals("", vm.sourceLine)
|
||||
vm.step(3)
|
||||
assertEquals("", vm.sourceLine)
|
||||
vm.step(4)
|
||||
assertEquals("string2", vm.sourceLine)
|
||||
assertEquals(0, vm.callstack.size)
|
||||
assertEquals(0, vm.evalstack.size)
|
||||
@ -882,17 +886,19 @@ class TestStackVmOpcodes {
|
||||
fun testBNZ() {
|
||||
val ins = mutableListOf(
|
||||
Instruction(Opcode.PUSH_WORD, Value(DataType.UWORD, 0)),
|
||||
Instruction(Opcode.TEST),
|
||||
Instruction(Opcode.BNZ, callLabel = "label"),
|
||||
Instruction(Opcode.PUSH_WORD, Value(DataType.UWORD, 1)),
|
||||
Instruction(Opcode.TEST),
|
||||
Instruction(Opcode.BNZ, callLabel = "label"),
|
||||
Instruction(Opcode.LINE, callLabel = "string1"),
|
||||
Instruction(Opcode.TERMINATE),
|
||||
Instruction(Opcode.LINE, callLabel = "string2"))
|
||||
val labels = mapOf("label" to ins.last()) // points to the second LINE instruction
|
||||
vm.load(makeProg(ins, labels=labels), null)
|
||||
vm.step(2)
|
||||
assertEquals("", vm.sourceLine)
|
||||
vm.step(3)
|
||||
assertEquals("", vm.sourceLine)
|
||||
vm.step(4)
|
||||
assertEquals("string2", vm.sourceLine)
|
||||
assertEquals(0, vm.callstack.size)
|
||||
assertEquals(0, vm.evalstack.size)
|
||||
@ -902,21 +908,24 @@ class TestStackVmOpcodes {
|
||||
fun testBNEG() {
|
||||
val ins = mutableListOf(
|
||||
Instruction(Opcode.PUSH_WORD, Value(DataType.UWORD, 0)),
|
||||
Instruction(Opcode.TEST),
|
||||
Instruction(Opcode.BNEG, callLabel = "label"),
|
||||
Instruction(Opcode.PUSH_WORD, Value(DataType.UWORD, 1)),
|
||||
Instruction(Opcode.TEST),
|
||||
Instruction(Opcode.BNEG, callLabel = "label"),
|
||||
Instruction(Opcode.PUSH_FLOAT, Value(DataType.FLOAT, -99)),
|
||||
Instruction(Opcode.TEST),
|
||||
Instruction(Opcode.BNEG, callLabel = "label"),
|
||||
Instruction(Opcode.LINE, callLabel = "string1"),
|
||||
Instruction(Opcode.TERMINATE),
|
||||
Instruction(Opcode.LINE, callLabel = "string2"))
|
||||
val labels = mapOf("label" to ins.last()) // points to the second LINE instruction
|
||||
vm.load(makeProg(ins, labels=labels), null)
|
||||
vm.step(2)
|
||||
assertEquals("", vm.sourceLine)
|
||||
vm.step(2)
|
||||
vm.step(3)
|
||||
assertEquals("", vm.sourceLine)
|
||||
vm.step(3)
|
||||
assertEquals("", vm.sourceLine)
|
||||
vm.step(4)
|
||||
assertEquals("string2", vm.sourceLine)
|
||||
assertEquals(0, vm.callstack.size)
|
||||
assertEquals(0, vm.evalstack.size)
|
||||
@ -926,17 +935,19 @@ class TestStackVmOpcodes {
|
||||
fun testBPOS() {
|
||||
val ins = mutableListOf(
|
||||
Instruction(Opcode.PUSH_FLOAT, Value(DataType.FLOAT, -99)),
|
||||
Instruction(Opcode.TEST),
|
||||
Instruction(Opcode.BPOS, callLabel = "label"),
|
||||
Instruction(Opcode.PUSH_WORD, Value(DataType.UWORD, 0)),
|
||||
Instruction(Opcode.TEST),
|
||||
Instruction(Opcode.BPOS, callLabel = "label"),
|
||||
Instruction(Opcode.LINE, callLabel = "string1"),
|
||||
Instruction(Opcode.TERMINATE),
|
||||
Instruction(Opcode.LINE, callLabel = "string2"))
|
||||
val labels = mapOf("label" to ins.last()) // points to the second LINE instruction
|
||||
vm.load(makeProg(ins, labels=labels), null)
|
||||
vm.step(2)
|
||||
assertEquals("", vm.sourceLine)
|
||||
vm.step(3)
|
||||
assertEquals("", vm.sourceLine)
|
||||
vm.step(4)
|
||||
assertEquals("string2", vm.sourceLine)
|
||||
assertEquals(0, vm.callstack.size)
|
||||
assertEquals(0, vm.evalstack.size)
|
||||
|
@ -29,6 +29,7 @@ ror2_word
|
||||
|
||||
|
||||
; @todo: stubs for now
|
||||
; @todo: move float operations to their own library (only included when floats are enabled)
|
||||
|
||||
ub2float
|
||||
rts
|
||||
@ -63,6 +64,9 @@ sub_f
|
||||
mul_f
|
||||
rts
|
||||
|
||||
neg_f
|
||||
rts
|
||||
|
||||
sub_uw
|
||||
rts
|
||||
|
||||
@ -72,5 +76,73 @@ less_ub
|
||||
less_f
|
||||
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
|
||||
|
||||
}}
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user