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 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
}

View File

@ -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

View File

@ -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) {
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!=null) {
if(forLoop.decltype!=null)
checkResult.add(SyntaxError("register loop variables cannot be explicitly declared with a datatype", forLoop.position))
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)
}
}

View File

@ -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)

View File

@ -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,

View File

@ -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 ->
"""
lda ${segment[0].callLabel}
sta ${segment[1].arg!!.integerValue().toHex()}
lda ${segment[0].callLabel}+1
sta ${(segment[1].arg!!.integerValue()+1).toHex()}
"""
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 ->
"""
lda ${segment[0].callLabel}
sta ${segment[1].arg!!.integerValue().toHex()}
lda ${segment[0].callLabel}+1
sta ${(segment[1].arg!!.integerValue()+1).toHex()}
"""
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 ->
"""
lda ${segment[0].arg!!.integerValue().toHex()}
sta ${segment[1].callLabel}
lda ${(segment[0].arg!!.integerValue()+1).toHex()}
sta ${segment[1].callLabel}+1
"""
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 ->
"""
lda ${segment[0].arg!!.integerValue().toHex()}
sta ${segment[1].callLabel}
lda ${(segment[0].arg!!.integerValue()+1).toHex()}
sta ${segment[1].callLabel}+1
"""
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[2].callLabel) {
"A", "X", "Y" ->
" ld${segment[2].callLabel!!.toLowerCase()} ${segment[1].callLabel}+$index"
when(segment[1].callLabel) {
"AX" -> TODO("$segment")
"AY" -> TODO("$segment")
"XY" -> TODO("$segment")
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 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 {

View File

@ -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
}

View File

@ -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)

View File

@ -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
}}
}