This commit is contained in:
Irmen de Jong 2018-10-15 02:49:59 +02:00
parent ba384c9722
commit 85f6c5350c
9 changed files with 430 additions and 157 deletions

View File

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

View File

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

View File

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

View File

@ -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 -> {
val opcode = opcodePopvar(stmt.target.determineDatatype(namespace, heap, stmt)!!)
prog.instr(opcode, callLabel = target.scopedname)
if (target is VarDecl) {
when(target.type) {
VarDeclType.VAR -> {
val opcode = opcodePopvar(stmt.target.determineDatatype(namespace, heap, stmt)!!)
prog.instr(opcode, callLabel = target.scopedname)
}
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}")
}
else throw CompilerException("invalid assignment target type ${target::class}")
}
stmt.target.register!=null -> {
val opcode=opcodePopvar(stmt.target.register!!)

View File

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

View File

@ -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,87 +171,246 @@ 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) {
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")
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")
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
}
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) {
if(ins.callLabel in registerStrings) {
// copying registerpair -> registerpair
when {
ins.callLabel == "AX" -> when (ins.callLabel2) {
"AY" -> out("\ttxy")
"XY" -> out("\tpha\n\ttxa\n\ttay\n\tpla\n\ttax")
}
ins.callLabel == "AY" -> when (ins.callLabel2) {
"AX" -> out("\tpha\n\ttya\n\ttax\n\tpla")
"XY" -> out("\ttax")
}
ins.callLabel == "XY" -> when (ins.callLabel2) {
"AX" -> out("\ttxa\n\tpha\n\ttya\n\ttax\n\tpla")
"AY" -> out("\ttxa")
when {
ins.callLabel2 in registerStrings -> {
if(ins.callLabel in registerStrings) {
// copying registerpair -> registerpair
when {
ins.callLabel == "AX" -> when (ins.callLabel2) {
"AY" -> out("\ttxy")
"XY" -> out("\tpha\n\ttxa\n\ttay\n\tpla\n\ttax")
}
ins.callLabel == "AY" -> when (ins.callLabel2) {
"AX" -> out("\tpha\n\ttya\n\ttax\n\tpla")
"XY" -> out("\ttax")
}
ins.callLabel == "XY" -> when (ins.callLabel2) {
"AX" -> out("\ttxa\n\tpha\n\ttya\n\ttax\n\tpla")
"AY" -> out("\ttxa")
}
}
return 0
}
return 0
// wvar -> regpair
val regpair = ins.callLabel2!!.toLowerCase()
out("\tld${regpair[0]} ${ins.callLabel}")
out("\tld${regpair[1]} ${ins.callLabel}+1")
}
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 -> {
// wvar->wvar
out("\tlda ${ins.callLabel}\n\tsta ${ins.callLabel2}")
out("\tlda ${ins.callLabel}+1\n\tsta ${ins.callLabel2}+1")
}
}
// todo copy_var_byte
}
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()
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()
}

View File

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

View File

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

View File

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