mirror of
https://github.com/irmen/prog8.git
synced 2025-01-27 10:31:40 +00:00
more asm
This commit is contained in:
parent
ba384c9722
commit
85f6c5350c
@ -1,51 +1,53 @@
|
||||
%option enable_floats
|
||||
|
||||
|
||||
~ main {
|
||||
|
||||
sub start() {
|
||||
|
||||
byte bvar = -88
|
||||
ubyte ubvar = 222
|
||||
word wvar = -12345
|
||||
uword uwvar = 55555
|
||||
memory ubyte mub = $c400
|
||||
memory ubyte mub2 = $c401
|
||||
memory uword muw = $c500
|
||||
memory uword muw2 = $c502
|
||||
memory byte mb = $c000
|
||||
memory word mw = $c002
|
||||
|
||||
byte b
|
||||
ubyte ub = $c4
|
||||
ubyte ub2 = $c4
|
||||
uword uw = $c500
|
||||
uword uw2 = $c502
|
||||
word ww
|
||||
|
||||
|
||||
byte bv2
|
||||
ubyte ubv2
|
||||
word wv2
|
||||
uword uwv2
|
||||
mub=5
|
||||
muw=4444
|
||||
mb=-100
|
||||
mw=-23333
|
||||
|
||||
X=X
|
||||
X=X
|
||||
Y=Y
|
||||
X=A
|
||||
A=Y
|
||||
A=ubvar
|
||||
AX=XY
|
||||
XY=XY
|
||||
AY=uwvar
|
||||
XY=uwvar
|
||||
|
||||
bv2 = ub2b(ubvar)
|
||||
ubv2 = b2ub(bvar)
|
||||
wv2 = wrd(uwvar)
|
||||
uwv2 = uwrd(wvar)
|
||||
wv2 = wrd(ubvar)
|
||||
wv2 = wrd(bvar)
|
||||
uwv2 = uwrd(ubvar)
|
||||
uwv2 = uwrd(bvar)
|
||||
; b++
|
||||
; A++
|
||||
; XY++
|
||||
; mub++
|
||||
; ub++
|
||||
; uw++
|
||||
; ww++
|
||||
; mb++
|
||||
; mw++
|
||||
;
|
||||
; b--
|
||||
; A--
|
||||
; XY--
|
||||
; mub--
|
||||
; ub--
|
||||
; uw--
|
||||
; ww--
|
||||
; mb--
|
||||
; mw--
|
||||
|
||||
|
||||
return
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
~ block2 $c000 {
|
||||
|
||||
str derp="hello"
|
||||
byte v =44
|
||||
return
|
||||
}
|
||||
|
@ -1078,7 +1078,7 @@ class LiteralValue(val type: DataType,
|
||||
throw ExpressionError("cannot compare type $type with ${other.type}", other.position)
|
||||
}
|
||||
|
||||
fun intoDatatype(targettype: DataType): LiteralValue {
|
||||
fun intoDatatype(targettype: DataType): LiteralValue? {
|
||||
if(type==targettype)
|
||||
return this
|
||||
when(type) {
|
||||
@ -1139,7 +1139,7 @@ class LiteralValue(val type: DataType,
|
||||
}
|
||||
else -> {}
|
||||
}
|
||||
throw FatalAstException("invalid type conversion from $this to $targettype")
|
||||
return null // invalid type conversion from $this to $targettype
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -107,8 +107,10 @@ class StatementReorderer(private val namespace: INameScope, private val heap: He
|
||||
vardeclsToAdd[scope]!!.add(decl.asDefaultValueDecl())
|
||||
val declvalue = decl.value!!
|
||||
val value =
|
||||
if(declvalue is LiteralValue)
|
||||
declvalue.intoDatatype(decl.datatype)
|
||||
if(declvalue is LiteralValue) {
|
||||
val converted = declvalue.intoDatatype(decl.datatype)
|
||||
converted ?: declvalue
|
||||
}
|
||||
else
|
||||
declvalue
|
||||
return VariableInitializationAssignment(
|
||||
|
@ -187,7 +187,7 @@ private class StatementTranslator(private val prog: IntermediateProgram,
|
||||
}
|
||||
|
||||
private fun processVariables(scope: INameScope) {
|
||||
for(variable in scope.statements.asSequence().filter {it is VarDecl}.map { it as VarDecl })
|
||||
for(variable in scope.statements.asSequence().filter {it is VarDecl && it.type==VarDeclType.VAR}.map { it as VarDecl })
|
||||
prog.variable(variable.scopedname, variable)
|
||||
for(subscope in scope.subScopes())
|
||||
processVariables(subscope.value)
|
||||
@ -343,6 +343,19 @@ private class StatementTranslator(private val prog: IntermediateProgram,
|
||||
}
|
||||
}
|
||||
|
||||
private fun opcodePopmem(dt: DataType): Opcode {
|
||||
return when (dt) {
|
||||
DataType.UBYTE -> Opcode.POP_MEM_UB
|
||||
DataType.BYTE -> Opcode.POP_MEM_B
|
||||
DataType.UWORD -> Opcode.POP_MEM_UW
|
||||
DataType.WORD -> Opcode.POP_MEM_W
|
||||
DataType.FLOAT -> Opcode.POP_MEM_FLOAT
|
||||
DataType.STR, DataType.STR_P, DataType.STR_S, DataType.STR_PS,
|
||||
DataType.ARRAY_UB, DataType.ARRAY_UW, DataType.ARRAY_F, DataType.MATRIX_UB,
|
||||
DataType.ARRAY_B, DataType.ARRAY_W, DataType.MATRIX_B -> Opcode.POP_MEM_UW
|
||||
}
|
||||
}
|
||||
|
||||
private fun opcodeDecvar(reg: Register): Opcode {
|
||||
return when(reg) {
|
||||
Register.A, Register.X, Register.Y -> Opcode.DEC_VAR_UB
|
||||
@ -1109,7 +1122,8 @@ private class StatementTranslator(private val prog: IntermediateProgram,
|
||||
if(valueDt!=targetDt) {
|
||||
// convert value to target datatype if possible
|
||||
when(targetDt) {
|
||||
DataType.UBYTE, DataType.BYTE -> throw CompilerException("incompatible data types valueDt=$valueDt targetDt=$targetDt at $stmt")
|
||||
DataType.UBYTE, DataType.BYTE ->
|
||||
throw CompilerException("incompatible data types valueDt=$valueDt targetDt=$targetDt at $stmt")
|
||||
DataType.UWORD, DataType.WORD -> {
|
||||
when (valueDt) {
|
||||
DataType.UBYTE -> prog.instr(Opcode.UB2UWORD)
|
||||
@ -1161,13 +1175,21 @@ private class StatementTranslator(private val prog: IntermediateProgram,
|
||||
when {
|
||||
stmt.target.identifier!=null -> {
|
||||
val target = stmt.target.identifier!!.targetStatement(namespace)!!
|
||||
when(target) {
|
||||
is VarDecl -> {
|
||||
if (target is VarDecl) {
|
||||
when(target.type) {
|
||||
VarDeclType.VAR -> {
|
||||
val opcode = opcodePopvar(stmt.target.determineDatatype(namespace, heap, stmt)!!)
|
||||
prog.instr(opcode, callLabel = target.scopedname)
|
||||
}
|
||||
else -> throw CompilerException("invalid assignment target type ${target::class}")
|
||||
VarDeclType.MEMORY -> {
|
||||
val opcode = opcodePopmem(stmt.target.determineDatatype(namespace, heap, stmt)!!)
|
||||
val address = target.value?.constValue(namespace, heap)!!.asIntegerValue!!
|
||||
prog.instr(opcode, Value(DataType.UWORD, address))
|
||||
}
|
||||
VarDeclType.CONST -> throw CompilerException("cannot assign to const")
|
||||
}
|
||||
}
|
||||
else throw CompilerException("invalid assignment target type ${target::class}")
|
||||
}
|
||||
stmt.target.register!=null -> {
|
||||
val opcode=opcodePopvar(stmt.target.register!!)
|
||||
|
@ -1,9 +1,6 @@
|
||||
package prog8.compiler.intermediate
|
||||
|
||||
import prog8.ast.DataType
|
||||
import prog8.ast.LiteralValue
|
||||
import prog8.ast.Position
|
||||
import prog8.ast.VarDecl
|
||||
import prog8.ast.*
|
||||
import prog8.compiler.CompilerException
|
||||
import prog8.compiler.HeapValues
|
||||
import java.io.PrintStream
|
||||
@ -246,6 +243,8 @@ class IntermediateProgram(val name: String, var loadAddress: Int, val heap: Heap
|
||||
}
|
||||
|
||||
fun variable(scopedname: String, decl: VarDecl) {
|
||||
if(decl.type!=VarDeclType.VAR)
|
||||
return // const and memory variables don't require storage
|
||||
val value = when(decl.datatype) {
|
||||
DataType.UBYTE, DataType.BYTE, DataType.UWORD, DataType.WORD, DataType.FLOAT -> Value(decl.datatype, (decl.value as LiteralValue).asNumericValue!!)
|
||||
DataType.STR, DataType.STR_P, DataType.STR_S, DataType.STR_PS -> {
|
||||
|
@ -1,13 +1,10 @@
|
||||
package prog8.compiler.target.c64
|
||||
|
||||
import prog8.compiler.CompilationOptions
|
||||
import prog8.compiler.LauncherType
|
||||
import prog8.compiler.OutputType
|
||||
import prog8.compiler.*
|
||||
import prog8.compiler.intermediate.Instruction
|
||||
import prog8.compiler.intermediate.IntermediateProgram
|
||||
import prog8.compiler.intermediate.LabelInstr
|
||||
import prog8.compiler.intermediate.Opcode
|
||||
import prog8.compiler.toHex
|
||||
import java.io.File
|
||||
import java.util.*
|
||||
|
||||
@ -67,6 +64,11 @@ class AsmGen(val options: CompilationOptions) {
|
||||
// todo zeropage if it's there
|
||||
for(block in program.blocks)
|
||||
out("\tjsr ${block.scopedname}._prog8_init")
|
||||
out("\tlda #0")
|
||||
out("\ttay")
|
||||
out("\ttax")
|
||||
out("\tdex\t; init estack pointer to \$ff")
|
||||
out("\tclc")
|
||||
out("\tjmp main.start\t; jump to program entrypoint")
|
||||
}
|
||||
|
||||
@ -94,6 +96,63 @@ class AsmGen(val options: CompilationOptions) {
|
||||
|
||||
private val registerStrings = setOf("A", "X", "Y", "AX", "AY", "XY")
|
||||
|
||||
|
||||
// note: to put stuff on the stack, we use Absolute,X addressing mode which is 3 bytes / 4 cycles
|
||||
// possible space optimization is to use zeropage (indirect),Y which is 2 bytes, but 5 cycles
|
||||
|
||||
private fun pushByte(byte: Int, out: (String) -> Unit) {
|
||||
out("\tlda #${byte.toHex()}")
|
||||
out("\tsta ${ESTACK_LO.toHex()},x")
|
||||
out("\tdex")
|
||||
}
|
||||
|
||||
private fun pushMemByte(address: Int, out: (String) -> Unit) {
|
||||
out("\tlda ${address.toHex()}")
|
||||
out("\tsta ${ESTACK_LO.toHex()},x")
|
||||
out("\tdex")
|
||||
}
|
||||
|
||||
private fun pushVarByte(name: String, out: (String) -> Unit) {
|
||||
out("\tlda $name")
|
||||
out("\tsta ${ESTACK_LO.toHex()},x")
|
||||
out("\tdex")
|
||||
}
|
||||
|
||||
private fun pushWord(word: Int, out: (String) -> Unit) {
|
||||
out("\tlda #<${word.toHex()}")
|
||||
out("\tsta ${ESTACK_LO.toHex()},x")
|
||||
out("\tlda #>${word.toHex()}")
|
||||
out("\tsta ${ESTACK_HI.toHex()},x")
|
||||
out("\tdex")
|
||||
}
|
||||
|
||||
private fun pushMemWord(address: Int, out: (String) -> Unit) {
|
||||
out("\tlda ${address.toHex()}")
|
||||
out("\tsta ${ESTACK_LO.toHex()},x")
|
||||
out("\tlda ${(address+1).toHex()}")
|
||||
out("\tsta ${ESTACK_HI.toHex()},x")
|
||||
out("\tdex")
|
||||
}
|
||||
|
||||
private fun pushVarWord(name: String, out: (String) -> Unit) {
|
||||
out("\tlda $name")
|
||||
out("\tsta ${ESTACK_LO.toHex()},x")
|
||||
out("\tlda $name+1")
|
||||
out("\tsta ${ESTACK_HI.toHex()},x")
|
||||
out("\tdex")
|
||||
}
|
||||
|
||||
private fun popByteA(out: (String) -> Unit) {
|
||||
out("\tinx")
|
||||
out("\tlda ${ESTACK_LO.toHex()},x")
|
||||
}
|
||||
|
||||
private fun popWordAY(out: (String) -> Unit) {
|
||||
out("\tinx")
|
||||
out("\tlda ${ESTACK_LO.toHex()},x")
|
||||
out("\tldy ${ESTACK_HI.toHex()},x")
|
||||
}
|
||||
|
||||
private fun ins2asm(out: (String) -> Unit, insIdx: Int, ins: Instruction, block: IntermediateProgram.ProgramBlock): Int {
|
||||
if(ins is LabelInstr) {
|
||||
if(ins.name==block.shortname)
|
||||
@ -102,7 +161,6 @@ class AsmGen(val options: CompilationOptions) {
|
||||
out(ins.name.substring(block.shortname.length+1))
|
||||
else
|
||||
out(ins.name)
|
||||
out("\trts") // todo weg
|
||||
return 0
|
||||
}
|
||||
when(ins.opcode) {
|
||||
@ -113,53 +171,48 @@ class AsmGen(val options: CompilationOptions) {
|
||||
Opcode.CLC -> out("\tclc")
|
||||
Opcode.SEI -> out("\tsei")
|
||||
Opcode.CLI -> out("\tcli")
|
||||
Opcode.RETURN -> out("\trts") // todo is return really this simple?
|
||||
Opcode.B2UB -> {} // is a no-op, just carry on with the byte as-is
|
||||
Opcode.UB2B -> {} // is a no-op, just carry on with the byte as-is
|
||||
Opcode.RSAVE -> out("\tphp\n\tpha\n\ttxa\n\tpha\n\ttya\n\tpha")
|
||||
Opcode.RRESTORE -> out("\tpla\n\ttay\n\tpla\n\ttax\n\tpla\n\tplp")
|
||||
Opcode.PUSH_BYTE -> {
|
||||
// check if we load a register (X, Y) with constant value
|
||||
val nextIns = block.getIns(insIdx+1)
|
||||
if(nextIns.opcode==Opcode.POP_VAR_BYTE && nextIns.callLabel in registerStrings) {
|
||||
out("\tld${nextIns.callLabel!!.toLowerCase()} #${ins.arg!!.integerValue().toHex()}")
|
||||
return 1 // skip 1
|
||||
}
|
||||
// todo push_byte
|
||||
}
|
||||
Opcode.PUSH_WORD -> {
|
||||
// check if we load a register (AX, AY, XY) with constant value
|
||||
val nextIns = block.getIns(insIdx+1)
|
||||
if(nextIns.opcode==Opcode.POP_VAR_WORD && nextIns.callLabel in registerStrings) {
|
||||
val regs = nextIns.callLabel!!.toLowerCase()
|
||||
val value = ins.arg!!.integerValue().toHex()
|
||||
out("\tld${regs[0]} #<$value")
|
||||
out("\tld${regs[1]} #>$value")
|
||||
return 1 // skip 1
|
||||
}
|
||||
// todo push_word
|
||||
}
|
||||
Opcode.DISCARD_BYTE -> out("\tinx") // remove 1 (2) bytes from stack
|
||||
Opcode.DISCARD_WORD -> out("\tinx") // remove 2 bytes from stack
|
||||
Opcode.DISCARD_FLOAT -> out("\tinx\n\tinx\n\tinx") // remove 5 (6) bytes from stack
|
||||
Opcode.COPY_VAR_BYTE -> {
|
||||
if(ins.callLabel2 in registerStrings) {
|
||||
when {
|
||||
ins.callLabel2 in registerStrings -> {
|
||||
if(ins.callLabel in registerStrings) {
|
||||
// copying register -> register
|
||||
when {
|
||||
ins.callLabel == "A" -> out("\tta${ins.callLabel2!!.toLowerCase()}")
|
||||
ins.callLabel == "X" -> if (ins.callLabel2 == "Y") {
|
||||
// 6502 doesn't have txy
|
||||
out("\ttxa\n\ttay")
|
||||
} else out("\ttxa")
|
||||
ins.callLabel == "Y" -> if (ins.callLabel2 == "X") {
|
||||
// 6502 doesn't have tyx
|
||||
out("\ttya\n\ttax")
|
||||
} else out("\ttya")
|
||||
ins.callLabel == "X" ->
|
||||
if (ins.callLabel2 == "Y")
|
||||
out("\ttxa\n\ttay") // 6502 doesn't have txy
|
||||
else
|
||||
out("\ttxa")
|
||||
ins.callLabel == "Y" ->
|
||||
if (ins.callLabel2 == "X")
|
||||
out("\ttya\n\ttax") // 6502 doesn't have tyx
|
||||
else
|
||||
out("\ttya")
|
||||
}
|
||||
return 0
|
||||
}
|
||||
// var -> reg
|
||||
out("\tld${ins.callLabel2!!.toLowerCase()} ${ins.callLabel}")
|
||||
}
|
||||
ins.callLabel in registerStrings ->
|
||||
// reg -> var
|
||||
out("\tst${ins.callLabel!!.toLowerCase()} ${ins.callLabel2}")
|
||||
else ->
|
||||
// var -> var
|
||||
out("\tlda ${ins.callLabel}\n\tsta ${ins.callLabel2}")
|
||||
}
|
||||
// todo copy_var_byte
|
||||
}
|
||||
Opcode.COPY_VAR_WORD -> {
|
||||
if(ins.callLabel2 in registerStrings) {
|
||||
when {
|
||||
ins.callLabel2 in registerStrings -> {
|
||||
if(ins.callLabel in registerStrings) {
|
||||
// copying registerpair -> registerpair
|
||||
when {
|
||||
@ -178,22 +231,186 @@ class AsmGen(val options: CompilationOptions) {
|
||||
}
|
||||
return 0
|
||||
}
|
||||
// wvar -> regpair
|
||||
val regpair = ins.callLabel2!!.toLowerCase()
|
||||
out("\tld${regpair[0]} ${ins.callLabel}")
|
||||
out("\tld${regpair[1]} ${ins.callLabel}+1")
|
||||
}
|
||||
// todo copy_var_byte
|
||||
ins.callLabel in registerStrings -> {
|
||||
// regpair->wvar
|
||||
val regpair = ins.callLabel!!.toLowerCase()
|
||||
out("\tst${regpair[0]} ${ins.callLabel2}")
|
||||
out("\tst${regpair[1]} ${ins.callLabel2}+1")
|
||||
}
|
||||
else-> {}
|
||||
// Opcode.PUSH_FLOAT -> TODO()
|
||||
// Opcode.PUSH_MEM_B -> TODO()
|
||||
// Opcode.PUSH_MEM_UB -> TODO()
|
||||
// Opcode.PUSH_MEM_W -> TODO()
|
||||
// Opcode.PUSH_MEM_UW -> TODO()
|
||||
// Opcode.PUSH_MEM_FLOAT -> TODO()
|
||||
// Opcode.PUSH_VAR_BYTE -> TODO()
|
||||
// Opcode.PUSH_VAR_WORD -> TODO()
|
||||
// Opcode.PUSH_VAR_FLOAT -> TODO()
|
||||
// Opcode.DISCARD_BYTE -> TODO()
|
||||
// Opcode.DISCARD_WORD -> TODO()
|
||||
// Opcode.DISCARD_FLOAT -> TODO()
|
||||
else -> {
|
||||
// wvar->wvar
|
||||
out("\tlda ${ins.callLabel}\n\tsta ${ins.callLabel2}")
|
||||
out("\tlda ${ins.callLabel}+1\n\tsta ${ins.callLabel2}+1")
|
||||
}
|
||||
}
|
||||
}
|
||||
Opcode.PUSH_BYTE -> {
|
||||
val nextIns = block.getIns(insIdx+1)
|
||||
if(nextIns==Opcode.DISCARD_BYTE)
|
||||
throw CompilerException("discard after push should have been removed")
|
||||
if(nextIns.opcode==Opcode.POP_VAR_BYTE) {
|
||||
if(nextIns.callLabel in registerStrings) {
|
||||
// load a register with constant value
|
||||
out("\tld${nextIns.callLabel!!.toLowerCase()} #${ins.arg!!.integerValue().toHex()}")
|
||||
return 1 // skip 1
|
||||
}
|
||||
// load a variable with a constant value
|
||||
out("\tlda #${ins.arg!!.integerValue().toHex()}")
|
||||
out("\tsta ${nextIns.callLabel}")
|
||||
return 1 // skip 1
|
||||
}
|
||||
if(nextIns.opcode==Opcode.POP_MEM_B || nextIns.opcode==Opcode.POP_MEM_UB) {
|
||||
// memory location = constant value
|
||||
out("\tlda #${ins.arg!!.integerValue().toHex()}")
|
||||
out("\tsta ${nextIns.arg!!.integerValue().toHex()}")
|
||||
return 1 // skip 1
|
||||
}
|
||||
// byte onto stack
|
||||
pushByte(ins.arg!!.integerValue(), out)
|
||||
}
|
||||
Opcode.PUSH_MEM_UB, Opcode.PUSH_MEM_B -> {
|
||||
val nextIns = block.getIns(insIdx+1)
|
||||
if(nextIns==Opcode.DISCARD_BYTE)
|
||||
throw CompilerException("discard after push should have been removed")
|
||||
if(nextIns.opcode==Opcode.POP_VAR_BYTE) {
|
||||
if(nextIns.callLabel in registerStrings) {
|
||||
// load a register with memory location
|
||||
out("\tld${nextIns.callLabel!!.toLowerCase()} ${ins.arg!!.integerValue().toHex()}")
|
||||
return 1 // skip 1
|
||||
}
|
||||
// load var with mem b
|
||||
out("\tlda ${ins.arg!!.integerValue().toHex()}\n\tsta ${nextIns.callLabel}")
|
||||
return 1 // skip 1
|
||||
}
|
||||
if(nextIns.opcode==Opcode.POP_MEM_B || nextIns.opcode==Opcode.POP_MEM_UB) {
|
||||
// copy byte from mem -> mem
|
||||
out("\tlda ${ins.arg!!.integerValue().toHex()}\n\tsta ${nextIns.arg!!.integerValue().toHex()}")
|
||||
return 1 // skip 1
|
||||
}
|
||||
// byte from memory onto stack
|
||||
pushMemByte(ins.arg!!.integerValue(), out)
|
||||
}
|
||||
Opcode.PUSH_VAR_BYTE -> {
|
||||
val nextIns = block.getIns(insIdx+1)
|
||||
if(nextIns==Opcode.DISCARD_BYTE)
|
||||
throw CompilerException("discard after push should have been removed")
|
||||
if(nextIns.opcode==Opcode.POP_VAR_BYTE)
|
||||
throw CompilerException("push var+pop var should have been replaced by copy var")
|
||||
if(nextIns.opcode==Opcode.POP_MEM_B || nextIns.opcode==Opcode.POP_MEM_UB) {
|
||||
// copy byte from var -> mem
|
||||
out("\tlda ${ins.callLabel}\n\tsta ${nextIns.arg!!.integerValue().toHex()}")
|
||||
return 1 // skip 1
|
||||
}
|
||||
// byte from variable onto stack
|
||||
pushVarByte(ins.callLabel!!, out)
|
||||
}
|
||||
Opcode.PUSH_WORD -> {
|
||||
val nextIns = block.getIns(insIdx+1)
|
||||
if(nextIns==Opcode.DISCARD_WORD)
|
||||
throw CompilerException("discard after push should have been removed")
|
||||
if(nextIns.opcode==Opcode.POP_VAR_WORD) {
|
||||
val value = ins.arg!!.integerValue()
|
||||
if(nextIns.callLabel in registerStrings) {
|
||||
// we load a register (AX, AY, XY) with constant value
|
||||
val regs = nextIns.callLabel!!.toLowerCase()
|
||||
out("\tld${regs[0]} #<${value.toHex()}")
|
||||
out("\tld${regs[1]} #>${value.toHex()}")
|
||||
return 1 // skip 1
|
||||
}
|
||||
// load a word variable with a constant value
|
||||
out("\tlda #<${value.toHex()}")
|
||||
out("\tsta ${nextIns.callLabel}")
|
||||
out("\tlda #>${value.toHex()}")
|
||||
out("\tsta ${nextIns.callLabel}+1")
|
||||
return 1 // skip 1
|
||||
}
|
||||
if(nextIns.opcode==Opcode.POP_MEM_W || nextIns.opcode==Opcode.POP_MEM_UW) {
|
||||
// we're loading a word into memory
|
||||
out("\tlda #<${ins.arg!!.integerValue().toHex()}")
|
||||
out("\tsta ${nextIns.arg!!.integerValue().toHex()}")
|
||||
out("\tlda #>${ins.arg.integerValue().toHex()}")
|
||||
out("\tsta ${(nextIns.arg.integerValue()+1).toHex()}")
|
||||
return 1 // skip 1
|
||||
}
|
||||
pushWord(ins.arg!!.integerValue(), out)
|
||||
}
|
||||
Opcode.PUSH_MEM_UW, Opcode.PUSH_MEM_W -> {
|
||||
val nextIns = block.getIns(insIdx+1)
|
||||
if(nextIns==Opcode.DISCARD_WORD)
|
||||
throw CompilerException("discard after push should have been removed")
|
||||
if(nextIns.opcode==Opcode.POP_VAR_WORD) {
|
||||
if(nextIns.callLabel in registerStrings) {
|
||||
// load a register (AX, AY, XY) with word from memory
|
||||
val regs = nextIns.callLabel!!.toLowerCase()
|
||||
val value = ins.arg!!.integerValue()
|
||||
out("\tld${regs[0]} ${value.toHex()}")
|
||||
out("\tld${regs[1]} ${(value + 1).toHex()}")
|
||||
return 1 // skip 1
|
||||
}
|
||||
// load var with mem word
|
||||
out("\tlda ${ins.arg!!.integerValue().toHex()}")
|
||||
out("\tsta ${nextIns.callLabel}")
|
||||
out("\tlda ${(ins.arg.integerValue()+1).toHex()}")
|
||||
out("\tsta ${nextIns.callLabel}+1")
|
||||
return 1 // skip 1
|
||||
}
|
||||
if(nextIns.opcode==Opcode.POP_MEM_W || nextIns.opcode==Opcode.POP_MEM_UW) {
|
||||
// copy word mem->mem
|
||||
out("\tlda ${ins.arg!!.integerValue().toHex()}")
|
||||
out("\tsta ${nextIns.arg!!.integerValue().toHex()}")
|
||||
out("\tlda ${(ins.arg.integerValue()+1).toHex()}")
|
||||
out("\tsta ${(nextIns.arg.integerValue()+1).toHex()}")
|
||||
return 1 // skip 1
|
||||
}
|
||||
// word from memory onto stack
|
||||
pushMemWord(ins.arg!!.integerValue(), out)
|
||||
}
|
||||
Opcode.PUSH_VAR_WORD -> {
|
||||
val nextIns = block.getIns(insIdx+1)
|
||||
if(nextIns==Opcode.DISCARD_FLOAT)
|
||||
throw CompilerException("discard after push should have been removed")
|
||||
if(nextIns.opcode==Opcode.POP_VAR_WORD)
|
||||
throw CompilerException("push var+pop var should have been replaced by copy var")
|
||||
if(nextIns.opcode==Opcode.POP_MEM_W || nextIns.opcode==Opcode.POP_MEM_UW) {
|
||||
// copy word from var -> mem
|
||||
out("\tlda ${ins.callLabel}\n\tsta ${nextIns.arg!!.integerValue().toHex()}")
|
||||
return 1 // skip 1
|
||||
}
|
||||
// word from memory onto stack
|
||||
pushVarWord(ins.callLabel!!, out)
|
||||
}
|
||||
Opcode.PUSH_FLOAT -> {
|
||||
val nextIns = block.getIns(insIdx+1)
|
||||
if(nextIns==Opcode.DISCARD_FLOAT)
|
||||
throw CompilerException("discard after push should have been removed")
|
||||
if(!options.floats)
|
||||
throw CompilerException("floats not enabled")
|
||||
TODO("push float")
|
||||
}
|
||||
Opcode.PUSH_VAR_FLOAT -> {
|
||||
val nextIns = block.getIns(insIdx+1)
|
||||
if(nextIns==Opcode.DISCARD_FLOAT)
|
||||
throw CompilerException("discard after push should have been removed")
|
||||
if(nextIns.opcode==Opcode.POP_VAR_FLOAT)
|
||||
throw CompilerException("push var+pop var should have been replaced by copy var")
|
||||
if(!options.floats)
|
||||
throw CompilerException("floats not enabled")
|
||||
TODO("push var float")
|
||||
}
|
||||
Opcode.PUSH_MEM_FLOAT -> {
|
||||
val nextIns = block.getIns(insIdx+1)
|
||||
if(nextIns==Opcode.DISCARD_FLOAT)
|
||||
throw CompilerException("discard after push should have been removed")
|
||||
if(!options.floats)
|
||||
throw CompilerException("floats not enabled")
|
||||
TODO("push mem float")
|
||||
}
|
||||
else-> TODO("asm for $ins")
|
||||
// Opcode.POP_MEM_B -> TODO()
|
||||
// Opcode.POP_MEM_UB -> TODO()
|
||||
// Opcode.POP_MEM_W -> TODO()
|
||||
@ -202,9 +419,27 @@ class AsmGen(val options: CompilationOptions) {
|
||||
// Opcode.POP_VAR_BYTE -> TODO()
|
||||
// Opcode.POP_VAR_WORD -> TODO()
|
||||
// Opcode.POP_VAR_FLOAT -> TODO()
|
||||
// Opcode.COPY_VAR_BYTE -> TODO()
|
||||
// Opcode.COPY_VAR_WORD -> TODO()
|
||||
// Opcode.COPY_VAR_FLOAT -> TODO()
|
||||
// Opcode.INC_B -> TODO()
|
||||
// Opcode.INC_UB -> TODO()
|
||||
// Opcode.INC_W -> TODO()
|
||||
// Opcode.INC_UW -> TODO()
|
||||
// Opcode.INC_F -> TODO()
|
||||
// Opcode.INC_VAR_B -> TODO()
|
||||
// Opcode.INC_VAR_UB -> TODO()
|
||||
// Opcode.INC_VAR_W -> TODO()
|
||||
// Opcode.INC_VAR_UW -> TODO()
|
||||
// Opcode.INC_VAR_F -> TODO()
|
||||
// Opcode.DEC_B -> TODO()
|
||||
// Opcode.DEC_UB -> TODO()
|
||||
// Opcode.DEC_W -> TODO()
|
||||
// Opcode.DEC_UW -> TODO()
|
||||
// Opcode.DEC_F -> TODO()
|
||||
// Opcode.DEC_VAR_B -> TODO()
|
||||
// Opcode.DEC_VAR_UB -> TODO()
|
||||
// Opcode.DEC_VAR_W -> TODO()
|
||||
// Opcode.DEC_VAR_UW -> TODO()
|
||||
// Opcode.DEC_VAR_F -> TODO()
|
||||
// Opcode.ADD_UB -> TODO()
|
||||
// Opcode.ADD_B -> TODO()
|
||||
// Opcode.ADD_UW -> TODO()
|
||||
@ -304,26 +539,6 @@ class AsmGen(val options: CompilationOptions) {
|
||||
// Opcode.XOR_WORD -> TODO()
|
||||
// Opcode.NOT_BYTE -> TODO()
|
||||
// Opcode.NOT_WORD -> TODO()
|
||||
// Opcode.INC_B -> TODO()
|
||||
// Opcode.INC_UB -> TODO()
|
||||
// Opcode.INC_W -> TODO()
|
||||
// Opcode.INC_UW -> TODO()
|
||||
// Opcode.INC_F -> TODO()
|
||||
// Opcode.INC_VAR_B -> TODO()
|
||||
// Opcode.INC_VAR_UB -> TODO()
|
||||
// Opcode.INC_VAR_W -> TODO()
|
||||
// Opcode.INC_VAR_UW -> TODO()
|
||||
// Opcode.INC_VAR_F -> TODO()
|
||||
// Opcode.DEC_B -> TODO()
|
||||
// Opcode.DEC_UB -> TODO()
|
||||
// Opcode.DEC_W -> TODO()
|
||||
// Opcode.DEC_UW -> TODO()
|
||||
// Opcode.DEC_F -> TODO()
|
||||
// Opcode.DEC_VAR_B -> TODO()
|
||||
// Opcode.DEC_VAR_UB -> TODO()
|
||||
// Opcode.DEC_VAR_W -> TODO()
|
||||
// Opcode.DEC_VAR_UW -> TODO()
|
||||
// Opcode.DEC_VAR_F -> TODO()
|
||||
// Opcode.LESS_B -> TODO()
|
||||
// Opcode.LESS_UB -> TODO()
|
||||
// Opcode.LESS_W -> TODO()
|
||||
@ -364,7 +579,6 @@ class AsmGen(val options: CompilationOptions) {
|
||||
// Opcode.BNEG -> TODO()
|
||||
// Opcode.BPOS -> TODO()
|
||||
// Opcode.CALL -> TODO()
|
||||
// Opcode.RETURN -> TODO()
|
||||
// Opcode.SYSCALL -> TODO()
|
||||
// Opcode.BREAKPOINT -> TODO()
|
||||
}
|
||||
|
@ -52,6 +52,6 @@ class AssemblyProgram(val name: String) {
|
||||
breakpoints.add(0, "; vice monitor breakpoint list now follows")
|
||||
breakpoints.add(1, "; $num breakpoints have been defined")
|
||||
breakpoints.add(2, "del")
|
||||
File(viceMonListFile).appendText(breakpoints.joinToString("\n"))
|
||||
File(viceMonListFile).appendText(breakpoints.joinToString("\n")+"\n")
|
||||
}
|
||||
}
|
@ -15,6 +15,10 @@ const val FLOAT_MAX_NEGATIVE = -1.7014118345e+38
|
||||
const val BASIC_LOAD_ADDRESS = 0x0801
|
||||
const val RAW_LOAD_ADDRESS = 0xc000
|
||||
|
||||
// the 2*256 byte evaluation stack (on which bytes, words, and even floats are stored during calculations)
|
||||
const val ESTACK_LO = 0xce00 // $ce00-$ceff inclusive
|
||||
const val ESTACK_HI = 0xcf00 // $cf00-$cfff inclusive
|
||||
|
||||
|
||||
class C64Zeropage(options: CompilationOptions) : Zeropage(options) {
|
||||
|
||||
|
@ -553,29 +553,59 @@ class ConstantFolding(private val namespace: INameScope, private val heap: HeapV
|
||||
// see if we can promote/convert a literal value to the required datatype
|
||||
when(targetDt) {
|
||||
DataType.UWORD -> {
|
||||
// we can convert to UWORD: any UBYTE, BYTE/WORD that are >=0, FLOAT that's an integer 0..65535
|
||||
if(lv.type==DataType.UBYTE)
|
||||
assignment.value = LiteralValue(DataType.UWORD, wordvalue = lv.asIntegerValue, position=lv.position)
|
||||
else if(lv.type==DataType.BYTE && lv.bytevalue!!>=0)
|
||||
assignment.value = LiteralValue(DataType.UWORD, wordvalue = lv.asIntegerValue, position=lv.position)
|
||||
else if(lv.type==DataType.WORD && lv.bytevalue!!>=0)
|
||||
assignment.value = LiteralValue(DataType.UWORD, wordvalue = lv.asIntegerValue, position=lv.position)
|
||||
else if(lv.type==DataType.FLOAT) {
|
||||
val d = lv.floatvalue!!
|
||||
if(floor(d)==d && d in 0..65535) {
|
||||
if(floor(d)==d && d in 0..65535)
|
||||
assignment.value = LiteralValue(DataType.UWORD, wordvalue=floor(d).toInt(), position=lv.position)
|
||||
}
|
||||
}
|
||||
DataType.UBYTE -> {
|
||||
// we can convert to UBYTE: UWORD <=255, BYTE >=0, FLOAT that's an integer 0..255
|
||||
if(lv.type==DataType.UWORD && lv.wordvalue!! <= 255)
|
||||
assignment.value = LiteralValue(DataType.UBYTE, lv.wordvalue.toShort(), position=lv.position)
|
||||
else if(lv.type==DataType.BYTE && lv.bytevalue!! >=0)
|
||||
assignment.value = LiteralValue(DataType.UBYTE, lv.bytevalue.toShort(), position=lv.position)
|
||||
else if(lv.type==DataType.FLOAT) {
|
||||
val d = lv.floatvalue!!
|
||||
if(floor(d)==d && d in 0..255)
|
||||
assignment.value = LiteralValue(DataType.UBYTE, floor(d).toShort(), position=lv.position)
|
||||
}
|
||||
}
|
||||
DataType.BYTE -> {
|
||||
// we can convert to BYTE: UWORD/UBYTE <= 127, FLOAT that's an integer 0..127
|
||||
if(lv.type==DataType.UWORD && lv.wordvalue!! <= 127)
|
||||
assignment.value = LiteralValue(DataType.BYTE, lv.wordvalue.toShort(), position=lv.position)
|
||||
else if(lv.type==DataType.UBYTE && lv.bytevalue!! <= 127)
|
||||
assignment.value = LiteralValue(DataType.BYTE, lv.bytevalue, position=lv.position)
|
||||
else if(lv.type==DataType.FLOAT) {
|
||||
val d = lv.floatvalue!!
|
||||
if(floor(d)==d && d in 0..127)
|
||||
assignment.value = LiteralValue(DataType.BYTE, floor(d).toShort(), position=lv.position)
|
||||
}
|
||||
}
|
||||
DataType.WORD -> {
|
||||
// we can convert to WORD: any UBYTE/BYTE, UWORD <= 32767, FLOAT that's an integer -32768..32767
|
||||
if(lv.type==DataType.UBYTE || lv.type==DataType.BYTE)
|
||||
assignment.value = LiteralValue(DataType.WORD, lv.bytevalue!!, position=lv.position)
|
||||
else if(lv.type==DataType.UWORD && lv.wordvalue!! <= 32767)
|
||||
assignment.value = LiteralValue(DataType.WORD, wordvalue=lv.wordvalue, position=lv.position)
|
||||
else if(lv.type==DataType.FLOAT) {
|
||||
val d = lv.floatvalue!!
|
||||
if(floor(d)==d && d in -32768..32767)
|
||||
assignment.value = LiteralValue(DataType.BYTE, floor(d).toShort(), position=lv.position)
|
||||
}
|
||||
}
|
||||
DataType.FLOAT -> {
|
||||
if(lv.isNumeric)
|
||||
assignment.value = LiteralValue(DataType.FLOAT, floatvalue= lv.asNumericValue?.toDouble(), position=lv.position)
|
||||
}
|
||||
DataType.UBYTE -> {
|
||||
if(lv.type==DataType.UWORD && lv.asIntegerValue in 0..255) {
|
||||
assignment.value = LiteralValue(DataType.UBYTE, lv.asIntegerValue?.toShort(), position=lv.position)
|
||||
} else if(lv.type==DataType.FLOAT) {
|
||||
val d = lv.floatvalue!!
|
||||
if(floor(d)==d && d in 0..255) {
|
||||
assignment.value = LiteralValue(DataType.UBYTE, floor(d).toShort(), position=lv.position)
|
||||
}
|
||||
}
|
||||
}
|
||||
else -> {}
|
||||
}
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user