more asm output

This commit is contained in:
Irmen de Jong 2018-10-24 01:39:52 +02:00
parent ab73353cd2
commit fba3cb7301
7 changed files with 438 additions and 96 deletions

View File

@ -0,0 +1,39 @@
%import c64utils
%option enable_floats
~ main {
const uword width = 320 // 2
const uword height = 256 // 2
const uword xoffset = 40
const uword yoffset = 30
sub start() {
;vm_gfx_clearscr(11)
;vm_gfx_text(2, 1, 1, "Calculating Mandelbrot Fractal...")
for ubyte pixely in yoffset to yoffset+height-1 {
float yy = flt((pixely-yoffset))/height/3.6+0.4
for uword pixelx in xoffset to xoffset+width-1 {
float xx = flt((pixelx-xoffset))/width/3.0+0.2
float xsquared = 0.0
float ysquared = 0.0
float x = 0.0
float y = 0.0
ubyte iter = 0
while (iter<32 and xsquared+ysquared<4.0) {
y = x*y*2.0 + yy
x = xsquared - ysquared + xx
xsquared = x*x
ysquared = y*y
iter++
}
;vm_gfx_pixel(pixelx, pixely, iter)
}
}
;vm_gfx_text(11, 21, 1, "Finished!")
}
}

View File

@ -7,26 +7,26 @@
sub start() {
const uword width = 160
const uword height = 128
ubyte pixely = 255
const ubyte yoffset = 50
ubyte derp = 0
byte b = 99
byte b2 = 100
word w = 999
word w2 = 3
uword uw = 40000
uword uw2 = 3434
float fl1 = 1.1
float fl2 = 2.2
uw2 = uw
w2 = w
b2 = b
derp=pixely
fl2 = fl1
fl2++
float y11a = (pixely-30)
float y11b = (pixely-30)/128
float y11c = (pixely-30)/128/3.6
float y11d = (pixely-30)/500+0.4
float y11e = (pixely-30)/128/3.6+0.4
float y11f = flt(pixely-30)/128/3.6+0.4
float y111 = (((pixely-30)))/128/3.6+0.4
float y1 = (pixely-yoffset)/128/3.6+0.4
float y1a = flt(pixely-yoffset)/128/3.6+0.4
float y1a2 = (flt(pixely-yoffset))/128/3.6+0.4
float y1b = (pixely-40)/128/3.6+0.4
float y1c = (pixely-40.0)/128/3.6+0.4
float y2 = flt((pixely-yoffset))/128.0/3.6+0.4
float y3 = flt((pixely-yoffset))/height/3.6+0.4
float y4 = flt((pixely-yoffset))/height/3.6+0.4
return
}

View File

@ -381,6 +381,7 @@ private class StatementTranslator(private val prog: IntermediateProgram,
DataType.BYTE -> Opcode.DEC_VAR_B
DataType.UWORD -> Opcode.DEC_VAR_UW
DataType.WORD -> Opcode.DEC_VAR_W
DataType.FLOAT -> Opcode.DEC_VAR_F
else -> throw CompilerException("can't dec type $dt")
}
}
@ -391,6 +392,7 @@ private class StatementTranslator(private val prog: IntermediateProgram,
DataType.BYTE -> Opcode.INC_VAR_B
DataType.UWORD -> Opcode.INC_VAR_UW
DataType.WORD -> Opcode.INC_VAR_W
DataType.FLOAT -> Opcode.INC_VAR_F
else -> throw CompilerException("can't inc type $dt")
}
}

View File

@ -232,3 +232,28 @@ val opcodesWithVarArgument = setOf(
Opcode.READ_INDEXED_VAR_BYTE, Opcode.READ_INDEXED_VAR_WORD, Opcode.READ_INDEXED_VAR_FLOAT,
Opcode.WRITE_INDEXED_VAR_BYTE, Opcode.WRITE_INDEXED_VAR_WORD, Opcode.WRITE_INDEXED_VAR_FLOAT
)
val pushOpcodes = setOf(
Opcode.PUSH_BYTE,
Opcode.PUSH_WORD,
Opcode.PUSH_FLOAT,
Opcode.PUSH_MEM_B,
Opcode.PUSH_MEM_UB,
Opcode.PUSH_MEM_W,
Opcode.PUSH_MEM_UW,
Opcode.PUSH_MEM_FLOAT,
Opcode.PUSH_VAR_BYTE,
Opcode.PUSH_VAR_WORD,
Opcode.PUSH_VAR_FLOAT
)
val popOpcodes = setOf(
Opcode.POP_MEM_B,
Opcode.POP_MEM_UB,
Opcode.POP_MEM_W,
Opcode.POP_MEM_UW,
Opcode.POP_MEM_FLOAT,
Opcode.POP_VAR_BYTE,
Opcode.POP_VAR_WORD,
Opcode.POP_VAR_FLOAT
)

View File

@ -320,27 +320,36 @@ class AsmGen(val options: CompilationOptions, val program: IntermediateProgram,
// find best patterns (matching the most of the lines, then with the smallest weight)
val fragments = findPatterns(ins).sortedWith(compareBy({it.segmentSize}, {it.prio}))
if(fragments.isEmpty()) {
// we didn't find any matching patterns (complex multi-instruction fragments), try simple ones
val firstIns = ins[0]
val singleAsm = simpleInstr2Asm(firstIns)
if(singleAsm != null) {
if(singleAsm.isNotEmpty()) {
for(line in singleAsm.split('|')) {
val trimmed = if(line.startsWith(' ')) "\t"+line.trim() else line.trim()
out(trimmed)
}
}
outputAsmFragment(singleAsm)
return 1
}
return 0
}
val best = fragments[0]
if(best.asm.isNotEmpty()) {
for (line in best.asm.split('|')) {
val trimmed = if (line.startsWith(' ')) "\t" + line.trim() else line.trim()
out(trimmed)
outputAsmFragment(best.asm)
return best.segmentSize
}
private fun outputAsmFragment(singleAsm: String) {
if (singleAsm.isNotEmpty()) {
when {
singleAsm.startsWith("@inline@") -> out(singleAsm.substring(8))
'\n' in singleAsm -> for (line in singleAsm.split('\n')) {
if (line.isNotEmpty()) {
val trimmed = if (line.startsWith(' ')) "\t" + line.trim() else line.trim()
out(trimmed)
}
}
else -> for (line in singleAsm.split('|')) {
val trimmed = if (line.startsWith(' ')) "\t" + line.trim() else line.trim()
out(trimmed)
}
}
}
return best.segmentSize
}
private fun simpleInstr2Asm(ins: Instruction): String? {
@ -373,14 +382,98 @@ class AsmGen(val options: CompilationOptions, val program: IntermediateProgram,
Opcode.DISCARD_BYTE -> " inx"
Opcode.DISCARD_WORD -> " inx"
Opcode.DISCARD_FLOAT -> " inx | inx | inx"
Opcode.INLINE_ASSEMBLY -> ins.callLabel ?: "" // All of the inline assembly is stored in the calllabel property.
Opcode.INLINE_ASSEMBLY -> "@inline@" + (ins.callLabel ?: "") // All of the inline assembly is stored in the calllabel property.
Opcode.SYSCALL -> {
if (ins.arg!!.numericValue() in syscallsForStackVm.map { it.callNr })
throw CompilerException("cannot translate vm syscalls to real assembly calls - use *real* subroutine calls instead. Syscall ${ins.arg.numericValue()}")
TODO("syscall $ins")
}
Opcode.BREAKPOINT -> {
breakpointCounter++
"_prog8_breakpoint_$breakpointCounter\tnop"
}
Opcode.PUSH_BYTE -> {
" lda #${ins.arg!!.integerValue().toHex()} | sta $ESTACK_LO,x | dex"
" 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,x | lda #>$value | sta $ESTACK_HI,x | dex"
" lda #<$value | sta ${ESTACK_LO.toHex()},x | lda #>$value | sta ${ESTACK_HI.toHex()},x | dex"
}
Opcode.PUSH_FLOAT -> {
val floatConst = globalFloatConsts[ins.arg!!.numericValue().toDouble()] ?: throw AssemblyError("should have a global float const for number ${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 -> {
"""
inx
lda ${ESTACK_LO.toHex()},x
sta ${ins.arg!!.integerValue().toHex()}
"""
}
Opcode.POP_MEM_W, Opcode.POP_MEM_UW -> {
"""
inx
lda ${ESTACK_LO.toHex()},x
sta ${ins.arg!!.integerValue().toHex()}
lda ${ESTACK_HI.toHex()},x
sta ${(ins.arg.integerValue()+1).toHex()}
"""
}
Opcode.POP_VAR_BYTE -> {
when (ins.callLabel) {
"X" -> throw CompilerException("makes no sense to pop X, it's used as a stack pointer itself")
"A" -> " inx | lda ${ESTACK_LO.toHex()},x"
"Y" -> " inx | ldy ${ESTACK_LO.toHex()},x"
else -> " inx | lda ${ESTACK_LO.toHex()},x | sta ${ins.callLabel}"
}
}
Opcode.POP_VAR_WORD -> {
when (ins.callLabel) {
"AX" -> throw CompilerException("makes no sense to pop X, it's used as a stack pointer itself")
"XY" -> throw CompilerException("makes no sense to pop X, it's used as a stack pointer itself")
"AY" -> " inx | lda ${ESTACK_LO.toHex()},x | ldy ${ESTACK_HI.toHex()},x"
else -> " inx | lda ${ESTACK_LO.toHex()},x | ldy ${ESTACK_HI.toHex()},x | sta ${ins.callLabel} | sty ${ins.callLabel}+1"
}
}
Opcode.POP_VAR_FLOAT -> {
" lda #<${ins.callLabel} | ldy #>${ins.callLabel} | jsr prog8_lib.pop_var_float"
}
Opcode.COPY_VAR_BYTE -> {
when {
ins.callLabel2 in registerStrings -> {
@ -444,6 +537,20 @@ class AsmGen(val options: CompilationOptions, val program: IntermediateProgram,
}
}
}
Opcode.COPY_VAR_FLOAT -> {
"""
lda #<${ins.callLabel}
ldy #>${ins.callLabel}
sta ${C64Zeropage.SCRATCH_W1}
sty ${C64Zeropage.SCRATCH_W1+1}
lda #<${ins.callLabel2}
ldy #>${ins.callLabel2}
sta ${C64Zeropage.SCRATCH_W2}
sty ${C64Zeropage.SCRATCH_W2+1}
jsr prog8_lib.copy_float
"""
}
Opcode.INC_VAR_UB, Opcode.INC_VAR_B -> {
when (ins.callLabel) {
"A" -> " clc | adc #1"
@ -457,9 +564,16 @@ class AsmGen(val options: CompilationOptions, val program: IntermediateProgram,
"AX" -> " clc | adc #1 | bne + | inx |+"
"AY" -> " clc | adc #1 | bne + | iny |+"
"XY" -> " inx | bne + | iny |+"
else -> TODO("inc_var_uw $ins")
else -> " inc ${ins.callLabel} | bne + | inc ${ins.callLabel}+1 |+"
}
}
Opcode.INC_VAR_F -> {
"""
lda #<${ins.callLabel}
ldy #>${ins.callLabel}
jsr prog8_lib.inc_var_f
"""
}
Opcode.DEC_VAR_UB, Opcode.DEC_VAR_B -> {
when (ins.callLabel) {
"A" -> " sec | sbc #1"
@ -468,87 +582,137 @@ class AsmGen(val options: CompilationOptions, val program: IntermediateProgram,
else -> " dec ${ins.callLabel}"
}
}
Opcode.ADD_UB, Opcode.ADD_B -> {
" lda ${(ESTACK_LO + 2).toHex()},x | " +
" clc | adc ${(ESTACK_LO + 1).toHex()},x | inx" +
" sta ${(ESTACK_LO + 1).toHex()},x"
}
Opcode.SUB_UB, Opcode.SUB_B -> {
" lda ${(ESTACK_LO + 2).toHex()},x | " +
" sec | sbc ${(ESTACK_LO + 1).toHex()},x | inx" +
" sta ${(ESTACK_LO + 1).toHex()},x"
}
Opcode.POP_MEM_UB, Opcode.POP_MEM_B -> {
" inx | lda ${ESTACK_LO.toHex()},x " +
" sta ${ins.arg!!.integerValue().toHex()}"
}
Opcode.POP_MEM_W, Opcode.POP_MEM_UW -> {
" inx | lda ${ESTACK_LO.toHex()},x | ldy ${ESTACK_HI.toHex()},x | " +
" sta ${ins.callLabel} | sty ${ins.callLabel}+1"
}
Opcode.POP_VAR_BYTE -> {
when (ins.callLabel) {
"X" -> throw CompilerException("makes no sense to pop X it's used as a stack pointer itself")
"A" -> " inx | lda ${ESTACK_LO.toHex()},x"
"Y" -> " inx | ldy ${ESTACK_LO.toHex()},x"
else -> " inx | lda ${ESTACK_LO.toHex()},x | sta ${ins.callLabel}"
}
}
Opcode.POP_VAR_WORD -> {
when (ins.callLabel) {
"AX" -> throw CompilerException("makes no sense to pop X it's used as a stack pointer itself")
"XY" -> throw CompilerException("makes no sense to pop X it's used as a stack pointer itself")
"AY" -> " inx | lda ${ESTACK_LO.toHex()},x | ldy ${ESTACK_HI.toHex()},x"
else -> " inx | lda ${ESTACK_LO.toHex()},x | ldy ${ESTACK_HI.toHex()},x | sta ${ins.callLabel} | sty ${ins.callLabel}+1"
}
}
Opcode.DEC_VAR_UW -> {
when (ins.callLabel) {
"AX" -> " cmp #0 | bne + | dex |+ | sec | sbc #1"
"AY" -> " cmp #0 | bne + | dey |+ | sec | sbc #1"
"XY" -> " txa | bne + | dey |+ | dex"
else -> TODO("dec_var_uw $ins")
else -> " lda ${ins.callLabel} | bne + | dec ${ins.callLabel}+1 |+ | dec ${ins.callLabel}"
}
}
Opcode.DEC_VAR_F -> {
"""
lda #<${ins.callLabel}
ldy #>${ins.callLabel}
jsr prog8_lib.dec_var_f
"""
}
Opcode.NEG_B -> {
" lda ${(ESTACK_LO+1).toHex()},x |" +
" eor #\$ff | sec | adc #0 | " +
" sta ${(ESTACK_LO+1).toHex()},x"
"""
lda ${(ESTACK_LO+1).toHex()},x
eor #255
sec
adc #0
sta ${(ESTACK_LO+1).toHex()},x
"""
}
Opcode.INV_BYTE -> {
" lda ${(ESTACK_LO+1).toHex()},x | " +
" eor #\$ff | " +
" sta ${(ESTACK_LO+1).toHex()},x"
"""
lda ${(ESTACK_LO + 1).toHex()},x
eor #255
sta ${(ESTACK_LO + 1).toHex()},x
"""
}
Opcode.INV_WORD -> {
" lda ${(ESTACK_LO + 1).toHex()},x | eor #\$ff | sta ${(ESTACK_LO+1).toHex()},x | " +
" lda ${(ESTACK_HI + 1).toHex()},x | eor #\$ff | sta ${(ESTACK_HI+1).toHex()},x | "
"""
lda ${(ESTACK_LO + 1).toHex()},x
eor #255
sta ${(ESTACK_LO+1).toHex()},x
lda ${(ESTACK_HI + 1).toHex()},x
eor #255
sta ${(ESTACK_HI+1).toHex()},x
"""
}
Opcode.NOT_BYTE -> {
" lda ${(ESTACK_LO+1)},x " +
" beq + | lda #0 | beq ++ |+ | lda #1 |+ | " +
" sta ${(ESTACK_LO+1)},x"
"""
lda ${(ESTACK_LO+1).toHex()},x
beq +
lda #0
beq ++
+ lda #1
+ sta ${(ESTACK_LO+1).toHex()},x
"""
}
Opcode.NOT_WORD -> {
" lda ${(ESTACK_LO + 1).toHex()},x | ora ${(ESTACK_HI + 1).toHex()},x | " +
" beq + | lda #0 | beq ++ |+ | lda #1 |+ | "+
" sta ${(ESTACK_LO + 1).toHex()},x | sta ${(ESTACK_HI + 1).toHex()},x"
}
Opcode.SYSCALL -> {
if (ins.arg!!.numericValue() in syscallsForStackVm.map { it.callNr })
throw CompilerException("cannot translate vm syscalls to real assembly calls - use *real* subroutine calls instead. Syscall ${ins.arg.numericValue()}")
TODO("syscall $ins")
}
Opcode.BREAKPOINT -> {
breakpointCounter++
"_prog8_breakpoint_$breakpointCounter\tnop"
"""
lda ${(ESTACK_LO + 1).toHex()},x
ora ${(ESTACK_HI + 1).toHex()},x
beq +
lda #0
beq ++
+ lda #1
+ sta ${(ESTACK_LO + 1).toHex()},x | sta ${(ESTACK_HI + 1).toHex()},x
"""
}
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.UB2FLOAT -> " jsr prog8_lib.ub2float"
Opcode.B2FLOAT -> " jsr prog8_lib.b2float"
Opcode.UW2FLOAT -> " jsr prog8_lib.uw2float"
Opcode.W2FLOAT -> " jsr prog8_lib.w2float"
Opcode.DIV_UB -> " jsr prog8_lib.div_ub"
Opcode.DIV_B -> " jsr prog8_lib.div_b"
Opcode.DIV_F -> " jsr prog8_lib.div_f"
Opcode.DIV_W -> " jsr prog8_lib.div_w"
Opcode.DIV_UW -> " jsr prog8_lib.div_uw"
Opcode.ADD_UB, Opcode.ADD_B -> {
"""
lda ${(ESTACK_LO + 2).toHex()},x
clc
adc ${(ESTACK_LO + 1).toHex()},x
inx
sta ${(ESTACK_LO + 1).toHex()},x
"""
}
Opcode.SUB_UB, Opcode.SUB_B -> {
"""
lda ${(ESTACK_LO + 2).toHex()},x
sec
sbc ${(ESTACK_LO + 1).toHex()},x
inx
sta ${(ESTACK_LO + 1).toHex()},x
"""
}
Opcode.ADD_F -> " jsr prog8_lib.add_f"
Opcode.ADD_W -> " jsr prog8_lib.add_w" // todo or inline rather
Opcode.ADD_UW -> " jsr prog8_lib.add_uw" // todo or inline rather
Opcode.SUB_F -> " jsr prog8_lib.sub_f"
Opcode.SUB_W -> " jsr prog8_lib.sub_w" // todo or inline rather
Opcode.SUB_UW -> " jsr prog8_lib.sub_uw" // todo or inline rather
Opcode.MUL_F -> " jsr prog8_lib.mul_f"
Opcode.MUL_B -> " jsr prog8_lib.mul_b"
Opcode.MUL_UB -> " jsr prog8_lib.mul_ub"
Opcode.MUL_W -> " jsr prog8_lib.mul_w"
Opcode.MUL_UW -> " jsr prog8_lib.mul_uw"
Opcode.LESS_UB -> " jsr prog8_lib.less_ub"
Opcode.LESS_B -> " jsr prog8_lib.less_b"
Opcode.LESS_UW -> " jsr prog8_lib.less_uw"
Opcode.LESS_W -> " jsr prog8_lib.less_w"
Opcode.LESS_F -> " jsr prog8_lib.less_f"
Opcode.AND_BYTE -> {
"""
lda ${(ESTACK_LO + 2).toHex()},x
and ${(ESTACK_LO + 1).toHex()},x
inx
sta ${(ESTACK_LO + 1).toHex()},x
"""
}
Opcode.OR_BYTE -> {
"""
lda ${(ESTACK_LO + 2).toHex()},x
ora ${(ESTACK_LO + 1).toHex()},x
inx
sta ${(ESTACK_LO + 1).toHex()},x
"""
}
else -> null
}
}
@ -557,7 +721,72 @@ class AsmGen(val options: CompilationOptions, val program: IntermediateProgram,
val opcodes = segment.map { it.opcode }
val result = mutableListOf<AsmFragment>()
if((opcodes[0]==Opcode.PUSH_VAR_BYTE && opcodes[2]==Opcode.POP_VAR_BYTE) ||
// check for regular 'assignments' (a push immediately followed by a pop)
if(opcodes[0] in pushOpcodes && opcodes[1] in popOpcodes) {
when(opcodes[0]) {
Opcode.PUSH_BYTE -> when(opcodes[1]) {
Opcode.POP_VAR_BYTE -> {
result.add(AsmFragment(
" lda #${segment[0].arg!!.integerValue().toHex()} | sta ${segment[1].callLabel}",
10, 2))
}
else -> TODO("pop byte ${segment[1]}")
}
Opcode.PUSH_WORD -> when(opcodes[1]) {
Opcode.POP_VAR_WORD -> {
result.add(AsmFragment(
"""
lda #<${segment[0].arg!!.integerValue().toHex()}
sta ${segment[1].callLabel}
lda #>${segment[0].arg!!.integerValue().toHex()}
sta ${segment[1].callLabel}+1
""",
10, 2))
}
else -> TODO("pop word ${segment[1]}")
}
Opcode.PUSH_FLOAT -> {
val floatConst = globalFloatConsts[segment[0].arg!!.numericValue().toDouble()] ?: throw AssemblyError("should have a global float const for number ${segment[0].arg}")
result.add(AsmFragment(
"""
lda #<$floatConst
ldy #>$floatConst
sta ${C64Zeropage.SCRATCH_W1}
sty ${C64Zeropage.SCRATCH_W1+1}
lda #<${segment[1].callLabel}
ldy #>${segment[1].callLabel}
sta ${C64Zeropage.SCRATCH_W2}
sty ${C64Zeropage.SCRATCH_W2+1}
jsr prog8_lib.copy_float
""", 10,2))
}
Opcode.PUSH_MEM_B -> TODO("assignment ${segment[0]} --> ${segment[1]}")
Opcode.PUSH_MEM_UB -> TODO("assignment ${segment[0]} --> ${segment[1]}")
Opcode.PUSH_MEM_W -> TODO("assignment ${segment[0]} --> ${segment[1]}")
Opcode.PUSH_MEM_UW -> TODO("assignment ${segment[0]} --> ${segment[1]}")
Opcode.PUSH_MEM_FLOAT -> TODO("assignment ${segment[0]} --> ${segment[1]}")
Opcode.PUSH_VAR_BYTE -> {
if(opcodes[1] == Opcode.POP_VAR_BYTE)
throw AssemblyError("push+pop var byte should have been changed into COPY_VAR_BYTE opcode")
else TODO("assignment ${segment[0]} --> ${segment[1]}")
}
Opcode.PUSH_VAR_WORD -> {
if(opcodes[1] == Opcode.POP_VAR_WORD)
throw AssemblyError("push+pop var word should have been changed into COPY_VAR_WORD opcode")
else TODO("assignment ${segment[0]} --> ${segment[1]}")
}
Opcode.PUSH_VAR_FLOAT -> {
if(opcodes[1] == Opcode.POP_VAR_FLOAT)
throw AssemblyError("push+pop var float should have been changed into COPY_VAR_FLOAT opcode")
else TODO("assignment ${segment[0]} --> ${segment[1]}")
}
else -> throw AssemblyError("strange push opcode ${segment[0]}")
}
}
// check for operations that modify a single value, by putting it on the stack (and popping it afterwards)
else if((opcodes[0]==Opcode.PUSH_VAR_BYTE && opcodes[2]==Opcode.POP_VAR_BYTE) ||
(opcodes[0]==Opcode.PUSH_VAR_WORD && opcodes[2]==Opcode.POP_VAR_WORD)) {
if (segment[0].callLabel == segment[2].callLabel) {
val fragment = sameVarOperation(segment[0].callLabel!!, segment[1])
@ -634,11 +863,12 @@ class AsmGen(val options: CompilationOptions, val program: IntermediateProgram,
private fun sameIndexedVarOperation(variable: String, indexVar: String, ins: Instruction): AsmFragment? {
val saveX = " stx ${C64Zeropage.SCRATCH_B1} |" // todo optimize to TXA when possible
val restoreX = " | ldx ${C64Zeropage.SCRATCH_B1}"
var loadX = ""
var loadXWord = ""
val loadXWord: String
val loadX: String
when(indexVar) {
"X" -> {
loadX = ""
loadXWord = " txa | asl a | tax |"
}
"Y" -> {

View File

@ -12,8 +12,8 @@ class AssemblyProgram(val name: String) {
fun assemble(options: CompilationOptions) {
println("Generating machine code program...")
val command = mutableListOf("64tass", "--ascii", "--case-sensitive", "-Wall", "-Wno-strict-bool",
"-Werror", "--dump-labels", "--vice-labels", "-l", viceMonListFile, "--no-monitor")
val command = mutableListOf("64tass", "--ascii", "--case-sensitive", "--long-branch", "-Wall", "-Wno-strict-bool", "-Wlong-branch",
"-Werror", "-Wno-error=long-branch", "--dump-labels", "--vice-labels", "-l", viceMonListFile, "--no-monitor")
val outFile = when(options.output) {
OutputType.PRG -> {

View File

@ -26,5 +26,51 @@ ror2_word
sta SCRATCH_ZPWORD1+1
+ rts
; @todo: stubs for now
ub2float
rts
uw2float
rts
push_float
rts
pop_var_float
rts
copy_float
rts
inc_var_f
rts
dec_var_f
rts
div_f
rts
add_f
rts
sub_f
rts
mul_f
rts
sub_uw
rts
less_ub
rts
less_f
rts
}}
}