mirror of
https://github.com/irmen/prog8.git
synced 2025-02-04 17:38:37 +00:00
more asm output
This commit is contained in:
parent
ab73353cd2
commit
fba3cb7301
39
compiler/examples/mandelbrot-novm.p8
Normal file
39
compiler/examples/mandelbrot-novm.p8
Normal 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!")
|
||||||
|
}
|
||||||
|
}
|
@ -7,26 +7,26 @@
|
|||||||
|
|
||||||
sub start() {
|
sub start() {
|
||||||
|
|
||||||
const uword width = 160
|
|
||||||
const uword height = 128
|
|
||||||
ubyte pixely = 255
|
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
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -381,6 +381,7 @@ private class StatementTranslator(private val prog: IntermediateProgram,
|
|||||||
DataType.BYTE -> Opcode.DEC_VAR_B
|
DataType.BYTE -> Opcode.DEC_VAR_B
|
||||||
DataType.UWORD -> Opcode.DEC_VAR_UW
|
DataType.UWORD -> Opcode.DEC_VAR_UW
|
||||||
DataType.WORD -> Opcode.DEC_VAR_W
|
DataType.WORD -> Opcode.DEC_VAR_W
|
||||||
|
DataType.FLOAT -> Opcode.DEC_VAR_F
|
||||||
else -> throw CompilerException("can't dec type $dt")
|
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.BYTE -> Opcode.INC_VAR_B
|
||||||
DataType.UWORD -> Opcode.INC_VAR_UW
|
DataType.UWORD -> Opcode.INC_VAR_UW
|
||||||
DataType.WORD -> Opcode.INC_VAR_W
|
DataType.WORD -> Opcode.INC_VAR_W
|
||||||
|
DataType.FLOAT -> Opcode.INC_VAR_F
|
||||||
else -> throw CompilerException("can't inc type $dt")
|
else -> throw CompilerException("can't inc type $dt")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -232,3 +232,28 @@ val opcodesWithVarArgument = setOf(
|
|||||||
Opcode.READ_INDEXED_VAR_BYTE, Opcode.READ_INDEXED_VAR_WORD, Opcode.READ_INDEXED_VAR_FLOAT,
|
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
|
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
|
||||||
|
)
|
@ -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)
|
// find best patterns (matching the most of the lines, then with the smallest weight)
|
||||||
val fragments = findPatterns(ins).sortedWith(compareBy({it.segmentSize}, {it.prio}))
|
val fragments = findPatterns(ins).sortedWith(compareBy({it.segmentSize}, {it.prio}))
|
||||||
if(fragments.isEmpty()) {
|
if(fragments.isEmpty()) {
|
||||||
|
// we didn't find any matching patterns (complex multi-instruction fragments), try simple ones
|
||||||
val firstIns = ins[0]
|
val firstIns = ins[0]
|
||||||
val singleAsm = simpleInstr2Asm(firstIns)
|
val singleAsm = simpleInstr2Asm(firstIns)
|
||||||
if(singleAsm != null) {
|
if(singleAsm != null) {
|
||||||
if(singleAsm.isNotEmpty()) {
|
outputAsmFragment(singleAsm)
|
||||||
for(line in singleAsm.split('|')) {
|
|
||||||
val trimmed = if(line.startsWith(' ')) "\t"+line.trim() else line.trim()
|
|
||||||
out(trimmed)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return 1
|
return 1
|
||||||
}
|
}
|
||||||
return 0
|
return 0
|
||||||
}
|
}
|
||||||
val best = fragments[0]
|
val best = fragments[0]
|
||||||
if(best.asm.isNotEmpty()) {
|
outputAsmFragment(best.asm)
|
||||||
for (line in best.asm.split('|')) {
|
return best.segmentSize
|
||||||
val trimmed = if (line.startsWith(' ')) "\t" + line.trim() else line.trim()
|
}
|
||||||
out(trimmed)
|
|
||||||
|
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? {
|
private fun simpleInstr2Asm(ins: Instruction): String? {
|
||||||
@ -373,14 +382,98 @@ class AsmGen(val options: CompilationOptions, val program: IntermediateProgram,
|
|||||||
Opcode.DISCARD_BYTE -> " inx"
|
Opcode.DISCARD_BYTE -> " inx"
|
||||||
Opcode.DISCARD_WORD -> " inx"
|
Opcode.DISCARD_WORD -> " inx"
|
||||||
Opcode.DISCARD_FLOAT -> " inx | inx | 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 -> {
|
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 -> {
|
Opcode.PUSH_WORD -> {
|
||||||
val value = ins.arg!!.integerValue().toHex()
|
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 -> {
|
Opcode.COPY_VAR_BYTE -> {
|
||||||
when {
|
when {
|
||||||
ins.callLabel2 in registerStrings -> {
|
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 -> {
|
Opcode.INC_VAR_UB, Opcode.INC_VAR_B -> {
|
||||||
when (ins.callLabel) {
|
when (ins.callLabel) {
|
||||||
"A" -> " clc | adc #1"
|
"A" -> " clc | adc #1"
|
||||||
@ -457,9 +564,16 @@ class AsmGen(val options: CompilationOptions, val program: IntermediateProgram,
|
|||||||
"AX" -> " clc | adc #1 | bne + | inx |+"
|
"AX" -> " clc | adc #1 | bne + | inx |+"
|
||||||
"AY" -> " clc | adc #1 | bne + | iny |+"
|
"AY" -> " clc | adc #1 | bne + | iny |+"
|
||||||
"XY" -> " inx | 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 -> {
|
Opcode.DEC_VAR_UB, Opcode.DEC_VAR_B -> {
|
||||||
when (ins.callLabel) {
|
when (ins.callLabel) {
|
||||||
"A" -> " sec | sbc #1"
|
"A" -> " sec | sbc #1"
|
||||||
@ -468,87 +582,137 @@ class AsmGen(val options: CompilationOptions, val program: IntermediateProgram,
|
|||||||
else -> " dec ${ins.callLabel}"
|
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 -> {
|
Opcode.DEC_VAR_UW -> {
|
||||||
when (ins.callLabel) {
|
when (ins.callLabel) {
|
||||||
"AX" -> " cmp #0 | bne + | dex |+ | sec | sbc #1"
|
"AX" -> " cmp #0 | bne + | dex |+ | sec | sbc #1"
|
||||||
"AY" -> " cmp #0 | bne + | dey |+ | sec | sbc #1"
|
"AY" -> " cmp #0 | bne + | dey |+ | sec | sbc #1"
|
||||||
"XY" -> " txa | bne + | dey |+ | dex"
|
"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 -> {
|
Opcode.NEG_B -> {
|
||||||
" lda ${(ESTACK_LO+1).toHex()},x |" +
|
"""
|
||||||
" eor #\$ff | sec | adc #0 | " +
|
lda ${(ESTACK_LO+1).toHex()},x
|
||||||
" sta ${(ESTACK_LO+1).toHex()},x"
|
eor #255
|
||||||
|
sec
|
||||||
|
adc #0
|
||||||
|
sta ${(ESTACK_LO+1).toHex()},x
|
||||||
|
"""
|
||||||
}
|
}
|
||||||
Opcode.INV_BYTE -> {
|
Opcode.INV_BYTE -> {
|
||||||
" lda ${(ESTACK_LO+1).toHex()},x | " +
|
"""
|
||||||
" eor #\$ff | " +
|
lda ${(ESTACK_LO + 1).toHex()},x
|
||||||
" sta ${(ESTACK_LO+1).toHex()},x"
|
eor #255
|
||||||
|
sta ${(ESTACK_LO + 1).toHex()},x
|
||||||
|
"""
|
||||||
}
|
}
|
||||||
Opcode.INV_WORD -> {
|
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 -> {
|
Opcode.NOT_BYTE -> {
|
||||||
" lda ${(ESTACK_LO+1)},x " +
|
"""
|
||||||
" beq + | lda #0 | beq ++ |+ | lda #1 |+ | " +
|
lda ${(ESTACK_LO+1).toHex()},x
|
||||||
" sta ${(ESTACK_LO+1)},x"
|
beq +
|
||||||
|
lda #0
|
||||||
|
beq ++
|
||||||
|
+ lda #1
|
||||||
|
+ sta ${(ESTACK_LO+1).toHex()},x
|
||||||
|
"""
|
||||||
}
|
}
|
||||||
Opcode.NOT_WORD -> {
|
Opcode.NOT_WORD -> {
|
||||||
" lda ${(ESTACK_LO + 1).toHex()},x | ora ${(ESTACK_HI + 1).toHex()},x | " +
|
"""
|
||||||
" beq + | lda #0 | beq ++ |+ | lda #1 |+ | "+
|
lda ${(ESTACK_LO + 1).toHex()},x
|
||||||
" sta ${(ESTACK_LO + 1).toHex()},x | sta ${(ESTACK_HI + 1).toHex()},x"
|
ora ${(ESTACK_HI + 1).toHex()},x
|
||||||
}
|
beq +
|
||||||
Opcode.SYSCALL -> {
|
lda #0
|
||||||
if (ins.arg!!.numericValue() in syscallsForStackVm.map { it.callNr })
|
beq ++
|
||||||
throw CompilerException("cannot translate vm syscalls to real assembly calls - use *real* subroutine calls instead. Syscall ${ins.arg.numericValue()}")
|
+ lda #1
|
||||||
TODO("syscall $ins")
|
+ sta ${(ESTACK_LO + 1).toHex()},x | sta ${(ESTACK_HI + 1).toHex()},x
|
||||||
}
|
"""
|
||||||
Opcode.BREAKPOINT -> {
|
|
||||||
breakpointCounter++
|
|
||||||
"_prog8_breakpoint_$breakpointCounter\tnop"
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Opcode.BCS -> " bcs ${ins.callLabel}"
|
Opcode.BCS -> " bcs ${ins.callLabel}"
|
||||||
Opcode.BCC -> " bcc ${ins.callLabel}"
|
Opcode.BCC -> " bcc ${ins.callLabel}"
|
||||||
Opcode.BZ -> " beq ${ins.callLabel}"
|
Opcode.BZ -> " beq ${ins.callLabel}"
|
||||||
Opcode.BNZ -> " bne ${ins.callLabel}"
|
Opcode.BNZ -> " bne ${ins.callLabel}"
|
||||||
Opcode.BNEG -> " bmi ${ins.callLabel}"
|
Opcode.BNEG -> " bmi ${ins.callLabel}"
|
||||||
Opcode.BPOS -> " bpl ${ins.callLabel}"
|
Opcode.BPOS -> " bpl ${ins.callLabel}"
|
||||||
|
Opcode.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
|
else -> null
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -557,7 +721,72 @@ class AsmGen(val options: CompilationOptions, val program: IntermediateProgram,
|
|||||||
val opcodes = segment.map { it.opcode }
|
val opcodes = segment.map { it.opcode }
|
||||||
val result = mutableListOf<AsmFragment>()
|
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)) {
|
(opcodes[0]==Opcode.PUSH_VAR_WORD && opcodes[2]==Opcode.POP_VAR_WORD)) {
|
||||||
if (segment[0].callLabel == segment[2].callLabel) {
|
if (segment[0].callLabel == segment[2].callLabel) {
|
||||||
val fragment = sameVarOperation(segment[0].callLabel!!, segment[1])
|
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? {
|
private fun sameIndexedVarOperation(variable: String, indexVar: String, ins: Instruction): AsmFragment? {
|
||||||
val saveX = " stx ${C64Zeropage.SCRATCH_B1} |" // todo optimize to TXA when possible
|
val saveX = " stx ${C64Zeropage.SCRATCH_B1} |" // todo optimize to TXA when possible
|
||||||
val restoreX = " | ldx ${C64Zeropage.SCRATCH_B1}"
|
val restoreX = " | ldx ${C64Zeropage.SCRATCH_B1}"
|
||||||
var loadX = ""
|
val loadXWord: String
|
||||||
var loadXWord = ""
|
val loadX: String
|
||||||
|
|
||||||
when(indexVar) {
|
when(indexVar) {
|
||||||
"X" -> {
|
"X" -> {
|
||||||
|
loadX = ""
|
||||||
loadXWord = " txa | asl a | tax |"
|
loadXWord = " txa | asl a | tax |"
|
||||||
}
|
}
|
||||||
"Y" -> {
|
"Y" -> {
|
||||||
|
@ -12,8 +12,8 @@ class AssemblyProgram(val name: String) {
|
|||||||
fun assemble(options: CompilationOptions) {
|
fun assemble(options: CompilationOptions) {
|
||||||
println("Generating machine code program...")
|
println("Generating machine code program...")
|
||||||
|
|
||||||
val command = mutableListOf("64tass", "--ascii", "--case-sensitive", "-Wall", "-Wno-strict-bool",
|
val command = mutableListOf("64tass", "--ascii", "--case-sensitive", "--long-branch", "-Wall", "-Wno-strict-bool", "-Wlong-branch",
|
||||||
"-Werror", "--dump-labels", "--vice-labels", "-l", viceMonListFile, "--no-monitor")
|
"-Werror", "-Wno-error=long-branch", "--dump-labels", "--vice-labels", "-l", viceMonListFile, "--no-monitor")
|
||||||
|
|
||||||
val outFile = when(options.output) {
|
val outFile = when(options.output) {
|
||||||
OutputType.PRG -> {
|
OutputType.PRG -> {
|
||||||
|
@ -26,5 +26,51 @@ ror2_word
|
|||||||
sta SCRATCH_ZPWORD1+1
|
sta SCRATCH_ZPWORD1+1
|
||||||
+ rts
|
+ 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
|
||||||
|
|
||||||
}}
|
}}
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user