restructure c64 machinedefinition

This commit is contained in:
Irmen de Jong 2019-07-13 03:16:48 +02:00
parent 1f5420010d
commit 87c28cfdbc
14 changed files with 421 additions and 399 deletions

View File

@ -7,8 +7,8 @@ import prog8.ast.expressions.*
import prog8.ast.statements.*
import prog8.compiler.CompilationOptions
import prog8.compiler.HeapValues
import prog8.compiler.target.c64.FLOAT_MAX_NEGATIVE
import prog8.compiler.target.c64.FLOAT_MAX_POSITIVE
import prog8.compiler.target.c64.MachineDefinition.FLOAT_MAX_NEGATIVE
import prog8.compiler.target.c64.MachineDefinition.FLOAT_MAX_POSITIVE
import prog8.functions.BuiltinFunctions
import java.io.File

View File

@ -6,7 +6,7 @@ import prog8.ast.expressions.*
import prog8.ast.processing.IAstModifyingVisitor
import prog8.ast.processing.IAstVisitor
import prog8.compiler.HeapValues
import prog8.compiler.target.c64.Mflpt5
import prog8.compiler.target.c64.MachineDefinition
class BuiltinFunctionStatementPlaceholder(val name: String, override val position: Position) : IStatement {
@ -757,7 +757,7 @@ class StructDecl(override val name: String,
when {
decl.datatype in ByteDatatypes -> 8
decl.datatype in WordDatatypes -> 16
decl.datatype==DataType.FLOAT -> Mflpt5.MemorySize
decl.datatype==DataType.FLOAT -> MachineDefinition.Mflpt5.MemorySize
decl.datatype in StringDatatypes -> TODO("stringvalue size")
decl.datatype in ArrayDatatypes -> decl.arraysize!!.size()!!
decl.datatype==DataType.STRUCT -> decl.struct!!.memorySize

View File

@ -7,7 +7,7 @@ import prog8.ast.base.checkValid
import prog8.ast.base.reorderStatements
import prog8.ast.statements.Directive
import prog8.compiler.target.c64.AsmGen
import prog8.compiler.target.c64.C64Zeropage
import prog8.compiler.target.c64.MachineDefinition
import prog8.optimizer.constantFold
import prog8.optimizer.optimizeStatements
import prog8.optimizer.simplifyExpressions
@ -108,7 +108,7 @@ fun compileProgram(filepath: Path,
}
if (writeAssembly) {
val zeropage = C64Zeropage(compilerOptions)
val zeropage = MachineDefinition.C64Zeropage(compilerOptions)
intermediate.allocateZeropage(zeropage)
val assembly = AsmGen(compilerOptions, intermediate, programAst.heap, zeropage).compileToAssembly(optimize)
assembly.assemble(compilerOptions)

View File

@ -147,7 +147,7 @@ class AsmGen(private val options: CompilationOptions, private val program: Inter
return name.replace("-", "")
}
private fun makeFloatFill(flt: Mflpt5): String {
private fun makeFloatFill(flt: MachineDefinition.Mflpt5): String {
val b0 = "$"+flt.b0.toString(16).padStart(2, '0')
val b1 = "$"+flt.b1.toString(16).padStart(2, '0')
val b2 = "$"+flt.b2.toString(16).padStart(2, '0')
@ -165,7 +165,8 @@ class AsmGen(private val options: CompilationOptions, private val program: Inter
out("\n.cpu '6502'\n.enc 'none'\n")
if(program.loadAddress==0) // fix load address
program.loadAddress = if(options.launcher==LauncherType.BASIC) BASIC_LOAD_ADDRESS else RAW_LOAD_ADDRESS
program.loadAddress = if(options.launcher==LauncherType.BASIC)
MachineDefinition.BASIC_LOAD_ADDRESS else MachineDefinition.RAW_LOAD_ADDRESS
when {
options.launcher == LauncherType.BASIC -> {
@ -221,7 +222,7 @@ class AsmGen(private val options: CompilationOptions, private val program: Inter
// the global list of all floating point constants for the whole program
for(flt in globalFloatConsts) {
val floatFill = makeFloatFill(Mflpt5.fromNumber(flt.key))
val floatFill = makeFloatFill(MachineDefinition.Mflpt5.fromNumber(flt.key))
out("${flt.value}\t.byte $floatFill ; float ${flt.key}")
}
}
@ -371,7 +372,7 @@ class AsmGen(private val options: CompilationOptions, private val program: Inter
DataType.ARRAY_F -> {
// float arraysize
val array = heap.get(value.heapId!!).doubleArray!!
val floatFills = array.map { makeFloatFill(Mflpt5.fromNumber(it)) }
val floatFills = array.map { makeFloatFill(MachineDefinition.Mflpt5.fromNumber(it)) }
out(varname)
for(f in array.zip(floatFills))
out(" .byte ${f.second} ; float ${f.first}")
@ -574,14 +575,14 @@ class AsmGen(private val options: CompilationOptions, private val program: Inter
Opcode.DEC_INDEXED_VAR_W, Opcode.DEC_INDEXED_VAR_UW -> AsmFragment(" lda $variable+${index*2} | bne + | dec $variable+${index*2+1} |+ | dec $variable+${index*2}")
Opcode.INC_INDEXED_VAR_FLOAT -> AsmFragment(
"""
lda #<($variable+${index*Mflpt5.MemorySize})
ldy #>($variable+${index*Mflpt5.MemorySize})
lda #<($variable+${index* MachineDefinition.Mflpt5.MemorySize})
ldy #>($variable+${index* MachineDefinition.Mflpt5.MemorySize})
jsr c64flt.inc_var_f
""")
Opcode.DEC_INDEXED_VAR_FLOAT -> AsmFragment(
"""
lda #<($variable+${index*Mflpt5.MemorySize})
ldy #>($variable+${index*Mflpt5.MemorySize})
lda #<($variable+${index* MachineDefinition.Mflpt5.MemorySize})
ldy #>($variable+${index* MachineDefinition.Mflpt5.MemorySize})
jsr c64flt.dec_var_f
""")
@ -591,8 +592,8 @@ class AsmGen(private val options: CompilationOptions, private val program: Inter
private fun sameIndexedVarOperation(variable: String, indexVar: String, ins: Instruction): AsmFragment? {
// an in place operation that consists of a push-value / op / push-index-var / pop-into-indexed-var
val saveX = " stx ${C64Zeropage.SCRATCH_B1} |"
val restoreX = " | ldx ${C64Zeropage.SCRATCH_B1}"
val saveX = " stx ${MachineDefinition.C64Zeropage.SCRATCH_B1} |"
val restoreX = " | ldx ${MachineDefinition.C64Zeropage.SCRATCH_B1}"
val loadXWord: String
val loadX: String

View File

@ -1,6 +1,7 @@
package prog8.compiler.target.c64
import prog8.compiler.toHex
import prog8.compiler.target.c64.MachineDefinition.ESTACK_LO_HEX
import prog8.compiler.target.c64.MachineDefinition.ESTACK_LO_PLUS1_HEX
// note: see https://wiki.nesdev.com/w/index.php/6502_assembly_optimisations
@ -69,10 +70,10 @@ fun optimizeCmpSequence(linesByFour: List<List<IndexedValue<String>>>): List<Int
// the repeated lda can be removed
val removeLines = mutableListOf<Int>()
for(lines in linesByFour) {
if(lines[0].value.trim()=="lda ${(ESTACK_LO+1).toHex()},x" &&
if(lines[0].value.trim()=="lda $ESTACK_LO_PLUS1_HEX,x" &&
lines[1].value.trim().startsWith("cmp ") &&
lines[2].value.trim().startsWith("beq ") &&
lines[3].value.trim()=="lda ${(ESTACK_LO+1).toHex()},x") {
lines[3].value.trim()=="lda $ESTACK_LO_PLUS1_HEX,x") {
removeLines.add(lines[3].index) // remove the second lda
}
}
@ -84,10 +85,10 @@ fun optimizeUselessStackByteWrites(linesByFour: List<List<IndexedValue<String>>>
// this is a lot harder for word values because the instruction sequence varies.
val removeLines = mutableListOf<Int>()
for(lines in linesByFour) {
if(lines[0].value.trim()=="sta ${ESTACK_LO.toHex()},x" &&
if(lines[0].value.trim()=="sta $ESTACK_LO_HEX,x" &&
lines[1].value.trim()=="dex" &&
lines[2].value.trim()=="inx" &&
lines[3].value.trim()=="lda ${ESTACK_LO.toHex()},x") {
lines[3].value.trim()=="lda $ESTACK_LO_HEX,x") {
removeLines.add(lines[0].index)
removeLines.add(lines[1].index)
removeLines.add(lines[2].index)

View File

@ -3,6 +3,11 @@ package prog8.compiler.target.c64
import prog8.ast.base.printWarning
import prog8.compiler.intermediate.Instruction
import prog8.compiler.intermediate.Opcode
import prog8.compiler.target.c64.MachineDefinition.ESTACK_HI_HEX
import prog8.compiler.target.c64.MachineDefinition.ESTACK_LO_HEX
import prog8.compiler.target.c64.MachineDefinition.ESTACK_LO_PLUS1_HEX
import prog8.compiler.target.c64.MachineDefinition.ESTACK_HI_PLUS1_HEX
import prog8.compiler.target.c64.MachineDefinition.C64Zeropage
import prog8.compiler.toHex
// note: see https://wiki.nesdev.com/w/index.php/6502_assembly_optimisations
@ -1371,7 +1376,7 @@ internal val patterns = listOf<AsmPattern>(
},
// floatvar = floatarray[index]
AsmPattern(listOf(Opcode.PUSH_BYTE, Opcode.READ_INDEXED_VAR_FLOAT, Opcode.POP_VAR_FLOAT)) { segment ->
val index = intVal(segment[0]) * Mflpt5.MemorySize
val index = intVal(segment[0]) * MachineDefinition.Mflpt5.MemorySize
"""
lda #<${segment[1].callLabel}+$index
ldy #>${segment[1].callLabel}+$index
@ -1570,7 +1575,7 @@ internal val patterns = listOf<AsmPattern>(
},
// memfloat = floatarray[index]
AsmPattern(listOf(Opcode.PUSH_BYTE, Opcode.READ_INDEXED_VAR_FLOAT, Opcode.POP_MEM_FLOAT)) { segment ->
val index = intVal(segment[0]) * Mflpt5.MemorySize
val index = intVal(segment[0]) * MachineDefinition.Mflpt5.MemorySize
"""
lda #<${segment[1].callLabel}+$index
ldy #>${segment[1].callLabel}+$index
@ -1584,7 +1589,7 @@ internal val patterns = listOf<AsmPattern>(
// floatarray[idxbyte] = float
AsmPattern(listOf(Opcode.PUSH_FLOAT, Opcode.PUSH_BYTE, Opcode.WRITE_INDEXED_VAR_FLOAT)) { segment ->
val floatConst = getFloatConst(segment[0].arg!!)
val index = intVal(segment[1]) * Mflpt5.MemorySize
val index = intVal(segment[1]) * MachineDefinition.Mflpt5.MemorySize
"""
lda #<$floatConst
ldy #>$floatConst
@ -1597,7 +1602,7 @@ internal val patterns = listOf<AsmPattern>(
},
// floatarray[idxbyte] = floatvar
AsmPattern(listOf(Opcode.PUSH_VAR_FLOAT, Opcode.PUSH_BYTE, Opcode.WRITE_INDEXED_VAR_FLOAT)) { segment ->
val index = intVal(segment[1]) * Mflpt5.MemorySize
val index = intVal(segment[1]) * MachineDefinition.Mflpt5.MemorySize
"""
lda #<${segment[0].callLabel}
ldy #>${segment[0].callLabel}
@ -1610,7 +1615,7 @@ internal val patterns = listOf<AsmPattern>(
},
// floatarray[idxbyte] = memfloat
AsmPattern(listOf(Opcode.PUSH_MEM_FLOAT, Opcode.PUSH_BYTE, Opcode.WRITE_INDEXED_VAR_FLOAT)) { segment ->
val index = intVal(segment[1]) * Mflpt5.MemorySize
val index = intVal(segment[1]) * MachineDefinition.Mflpt5.MemorySize
"""
lda #<${hexVal(segment[0])}
ldy #>${hexVal(segment[0])}
@ -1623,8 +1628,8 @@ internal val patterns = listOf<AsmPattern>(
},
// floatarray[idx2] = floatarray[idx1]
AsmPattern(listOf(Opcode.PUSH_BYTE, Opcode.READ_INDEXED_VAR_FLOAT, Opcode.PUSH_BYTE, Opcode.WRITE_INDEXED_VAR_FLOAT)) { segment ->
val index1 = intVal(segment[0]) * Mflpt5.MemorySize
val index2 = intVal(segment[2]) * Mflpt5.MemorySize
val index1 = intVal(segment[0]) * MachineDefinition.Mflpt5.MemorySize
val index2 = intVal(segment[2]) * MachineDefinition.Mflpt5.MemorySize
"""
lda #<(${segment[1].callLabel}+$index1)
ldy #>(${segment[1].callLabel}+$index1)
@ -1759,16 +1764,16 @@ internal val patterns = listOf<AsmPattern>(
// push word var as (u)byte
AsmPattern(listOf(Opcode.PUSH_VAR_WORD, Opcode.CAST_W_TO_UB),
listOf(Opcode.PUSH_VAR_WORD, Opcode.CAST_W_TO_B)) { segment ->
" lda ${segment[0].callLabel} | sta ${ESTACK_LO.toHex()},x | dex "
" lda ${segment[0].callLabel} | sta $ESTACK_LO_HEX,x | dex "
},
// push uword var as (u)byte
AsmPattern(listOf(Opcode.PUSH_VAR_WORD, Opcode.CAST_UW_TO_UB),
listOf(Opcode.PUSH_VAR_WORD, Opcode.CAST_UW_TO_B)) { segment ->
" lda ${segment[0].callLabel} | sta ${ESTACK_LO.toHex()},x | dex "
" lda ${segment[0].callLabel} | sta $ESTACK_LO_HEX,x | dex "
},
// push msb(word var)
AsmPattern(listOf(Opcode.PUSH_VAR_WORD, Opcode.MSB)) { segment ->
" lda ${segment[0].callLabel}+1 | sta ${ESTACK_LO.toHex()},x | dex "
" lda ${segment[0].callLabel}+1 | sta $ESTACK_LO_HEX,x | dex "
},
// set a register pair to a certain memory address (of a variable)
@ -1785,29 +1790,29 @@ internal val patterns = listOf<AsmPattern>(
// push memory byte | bytevalue
AsmPattern(listOf(Opcode.PUSH_MEM_B, Opcode.PUSH_BYTE, Opcode.BITOR_BYTE),
listOf(Opcode.PUSH_MEM_UB, Opcode.PUSH_BYTE, Opcode.BITOR_BYTE)) { segment ->
" lda ${hexVal(segment[0])} | ora #${hexVal(segment[1])} | sta ${ESTACK_LO.toHex()},x | dex "
" lda ${hexVal(segment[0])} | ora #${hexVal(segment[1])} | sta $ESTACK_LO_HEX,x | dex "
},
// push memory byte & bytevalue
AsmPattern(listOf(Opcode.PUSH_MEM_B, Opcode.PUSH_BYTE, Opcode.BITAND_BYTE),
listOf(Opcode.PUSH_MEM_UB, Opcode.PUSH_BYTE, Opcode.BITAND_BYTE)) { segment ->
" lda ${hexVal(segment[0])} | and #${hexVal(segment[1])} | sta ${ESTACK_LO.toHex()},x | dex "
" lda ${hexVal(segment[0])} | and #${hexVal(segment[1])} | sta $ESTACK_LO_HEX,x | dex "
},
// push memory byte ^ bytevalue
AsmPattern(listOf(Opcode.PUSH_MEM_B, Opcode.PUSH_BYTE, Opcode.BITXOR_BYTE),
listOf(Opcode.PUSH_MEM_UB, Opcode.PUSH_BYTE, Opcode.BITXOR_BYTE)) { segment ->
" lda ${hexVal(segment[0])} | eor #${hexVal(segment[1])} | sta ${ESTACK_LO.toHex()},x | dex "
" lda ${hexVal(segment[0])} | eor #${hexVal(segment[1])} | sta $ESTACK_LO_HEX,x | dex "
},
// push var byte | bytevalue
AsmPattern(listOf(Opcode.PUSH_VAR_BYTE, Opcode.PUSH_BYTE, Opcode.BITOR_BYTE)) { segment ->
" lda ${segment[0].callLabel} | ora #${hexVal(segment[1])} | sta ${ESTACK_LO.toHex()},x | dex "
" lda ${segment[0].callLabel} | ora #${hexVal(segment[1])} | sta $ESTACK_LO_HEX,x | dex "
},
// push var byte & bytevalue
AsmPattern(listOf(Opcode.PUSH_VAR_BYTE, Opcode.PUSH_BYTE, Opcode.BITAND_BYTE)) { segment ->
" lda ${segment[0].callLabel} | and #${hexVal(segment[1])} | sta ${ESTACK_LO.toHex()},x | dex "
" lda ${segment[0].callLabel} | and #${hexVal(segment[1])} | sta $ESTACK_LO_HEX,x | dex "
},
// push var byte ^ bytevalue
AsmPattern(listOf(Opcode.PUSH_VAR_BYTE, Opcode.PUSH_BYTE, Opcode.BITXOR_BYTE)) { segment ->
" lda ${segment[0].callLabel} | eor #${hexVal(segment[1])} | sta ${ESTACK_LO.toHex()},x | dex "
" lda ${segment[0].callLabel} | eor #${hexVal(segment[1])} | sta $ESTACK_LO_HEX,x | dex "
},
// push memory word | wordvalue
@ -1816,10 +1821,10 @@ internal val patterns = listOf<AsmPattern>(
"""
lda ${hexVal(segment[0])}
ora #<${hexVal(segment[1])}
sta ${ESTACK_LO.toHex()},x
sta $ESTACK_LO_HEX,x
lda ${hexValPlusOne(segment[0])}
ora #>${hexVal(segment[1])}
sta ${ESTACK_HI.toHex()},x
sta $ESTACK_HI_HEX,x
dex
"""
},
@ -1829,10 +1834,10 @@ internal val patterns = listOf<AsmPattern>(
"""
lda ${hexVal(segment[0])}
and #<${hexVal(segment[1])}
sta ${ESTACK_LO.toHex()},x
sta $ESTACK_LO_HEX,x
lda ${hexValPlusOne(segment[0])}
and #>${hexVal(segment[1])}
sta ${ESTACK_HI.toHex()},x
sta $ESTACK_HI_HEX,x
dex
"""
},
@ -1842,10 +1847,10 @@ internal val patterns = listOf<AsmPattern>(
"""
lda ${hexVal(segment[0])}
eor #<${hexVal(segment[1])}
sta ${ESTACK_LO.toHex()},x
sta $ESTACK_LO_HEX,x
lda ${hexValPlusOne(segment[0])}
eor #>${hexVal(segment[1])}
sta ${ESTACK_HI.toHex()},x
sta $ESTACK_HI_HEX,x
dex
"""
},
@ -1854,10 +1859,10 @@ internal val patterns = listOf<AsmPattern>(
"""
lda ${segment[0].callLabel}
ora #<${hexVal(segment[1])}
sta ${ESTACK_LO.toHex()},x
sta $ESTACK_LO_HEX,x
lda ${segment[0].callLabel}+1
ora #>${hexVal(segment[1])}
sta ${ESTACK_HI.toHex()},x
sta $ESTACK_HI_HEX,x
dex
"""
},
@ -1866,10 +1871,10 @@ internal val patterns = listOf<AsmPattern>(
"""
lda ${segment[0].callLabel}
and #<${hexVal(segment[1])}
sta ${ESTACK_LO.toHex()},x
sta $ESTACK_LO_HEX,x
lda ${segment[0].callLabel}+1
and #>${hexVal(segment[1])}
sta ${ESTACK_HI.toHex()},x
sta $ESTACK_HI_HEX,x
dex
"""
},
@ -1878,10 +1883,10 @@ internal val patterns = listOf<AsmPattern>(
"""
lda ${segment[0].callLabel}
eor #<${hexVal(segment[1])}
sta ${ESTACK_LO.toHex()},x
sta $ESTACK_LO_HEX,x
lda ${segment[0].callLabel}+1
eor #>${hexVal(segment[1])}
sta ${ESTACK_HI.toHex()},x
sta $ESTACK_HI_HEX,x
dex
"""
},
@ -1974,27 +1979,27 @@ internal val patterns = listOf<AsmPattern>(
AsmPattern(listOf(Opcode.PUSH_VAR_BYTE, Opcode.PUSH_VAR_BYTE, Opcode.MKWORD)) { segment ->
"""
lda ${segment[0].callLabel}
sta ${ESTACK_LO.toHex()},x
sta $ESTACK_LO_HEX,x
lda ${segment[1].callLabel}
sta ${ESTACK_HI.toHex()},x
sta $ESTACK_HI_HEX,x
dex
"""
},
AsmPattern(listOf(Opcode.PUSH_BYTE, Opcode.PUSH_VAR_BYTE, Opcode.MKWORD)) { segment ->
"""
lda #${hexVal(segment[0])}
sta ${ESTACK_LO.toHex()},x
sta $ESTACK_LO_HEX,x
lda ${segment[1].callLabel}
sta ${ESTACK_HI.toHex()},x
sta $ESTACK_HI_HEX,x
dex
"""
},
AsmPattern(listOf(Opcode.PUSH_VAR_BYTE, Opcode.PUSH_BYTE, Opcode.MKWORD)) { segment ->
"""
lda ${segment[0].callLabel}
sta ${ESTACK_LO.toHex()},x
sta $ESTACK_LO_HEX,x
lda #${hexVal(segment[1])}
sta ${ESTACK_HI.toHex()},x
sta $ESTACK_HI_HEX,x
dex
"""
},
@ -2035,28 +2040,28 @@ internal val patterns = listOf<AsmPattern>(
AsmPattern(listOf(Opcode.PUSH_BYTE, Opcode.ADD_B), listOf(Opcode.PUSH_BYTE, Opcode.ADD_UB)) { segment ->
val amount = segment[0].arg!!.integerValue()
if (amount in 1..2) {
" inc ${(ESTACK_LO + 1).toHex()},x | ".repeat(amount)
" inc $ESTACK_LO_PLUS1_HEX,x | ".repeat(amount)
} else
null
},
AsmPattern(listOf(Opcode.PUSH_WORD, Opcode.ADD_UW), listOf(Opcode.PUSH_WORD, Opcode.ADD_W)) { segment ->
val amount = segment[0].arg!!.integerValue()
if (amount in 1..2) {
" inc ${(ESTACK_LO + 1).toHex()},x | bne + | inc ${(ESTACK_HI + 1).toHex()},x |+ | ".repeat(amount)
" inc $ESTACK_LO_PLUS1_HEX,x | bne + | inc $ESTACK_HI_PLUS1_HEX,x |+ | ".repeat(amount)
} else
null
},
AsmPattern(listOf(Opcode.PUSH_BYTE, Opcode.SUB_B), listOf(Opcode.PUSH_BYTE, Opcode.SUB_UB)) { segment ->
val amount = segment[0].arg!!.integerValue()
if (amount in 1..2) {
" dec ${(ESTACK_LO + 1).toHex()},x | ".repeat(amount)
" dec $ESTACK_LO_PLUS1_HEX,x | ".repeat(amount)
} else
null
},
AsmPattern(listOf(Opcode.PUSH_WORD, Opcode.SUB_UW), listOf(Opcode.PUSH_WORD, Opcode.SUB_W)) { segment ->
val amount = segment[0].arg!!.integerValue()
if (amount in 1..2) {
" lda ${(ESTACK_LO + 1).toHex()},x | bne + | dec ${(ESTACK_HI + 1).toHex()},x |+ | dec ${(ESTACK_LO + 1).toHex()},x | ".repeat(amount)
" lda $ESTACK_LO_PLUS1_HEX,x | bne + | dec $ESTACK_HI_PLUS1_HEX,x |+ | dec $ESTACK_LO_PLUS1_HEX,x | ".repeat(amount)
} else
null
},
@ -2109,14 +2114,14 @@ internal val patterns = listOf<AsmPattern>(
AsmPattern(listOf(Opcode.PUSH_BYTE, Opcode.MUL_B), listOf(Opcode.PUSH_BYTE, Opcode.MUL_UB)) { segment ->
val amount = segment[0].arg!!.integerValue()
val result = optimizedIntMultiplicationsOnStack(segment[1], amount)
result ?: " lda #${hexVal(segment[0])} | sta ${ESTACK_LO.toHex()},x | dex | jsr prog8_lib.mul_byte"
result ?: " lda #${hexVal(segment[0])} | sta $ESTACK_LO_HEX,x | dex | jsr prog8_lib.mul_byte"
},
AsmPattern(listOf(Opcode.PUSH_WORD, Opcode.MUL_W), listOf(Opcode.PUSH_WORD, Opcode.MUL_UW)) { segment ->
val amount = segment[0].arg!!.integerValue()
val result = optimizedIntMultiplicationsOnStack(segment[1], amount)
if (result != null) result else {
val value = hexVal(segment[0])
" lda #<$value | sta ${ESTACK_LO.toHex()},x | lda #>$value | sta ${ESTACK_HI.toHex()},x | dex | jsr prog8_lib.mul_word"
" lda #<$value | sta $ESTACK_LO_HEX,x | lda #>$value | sta $ESTACK_HI_HEX,x | dex | jsr prog8_lib.mul_word"
}
},
@ -2310,10 +2315,10 @@ internal val patterns = listOf<AsmPattern>(
AsmPattern(listOf(Opcode.DUP_W, Opcode.CMP_UW),
listOf(Opcode.DUP_W, Opcode.CMP_W)) { segment ->
"""
lda ${(ESTACK_HI+1).toHex()},x
lda $ESTACK_HI_PLUS1_HEX,x
cmp #>${segment[1].arg!!.integerValue().toHex()}
bne +
lda ${(ESTACK_LO+1).toHex()},x
lda $ESTACK_LO_PLUS1_HEX,x
cmp #<${segment[1].arg!!.integerValue().toHex()}
; bne + not necessary?
; lda #0 not necessary?
@ -2322,7 +2327,7 @@ internal val patterns = listOf<AsmPattern>(
},
AsmPattern(listOf(Opcode.DUP_B, Opcode.CMP_UB),
listOf(Opcode.DUP_B, Opcode.CMP_B)) { segment ->
""" lda ${(ESTACK_LO+1).toHex()},x | cmp #${segment[1].arg!!.integerValue().toHex()} """
""" lda $ESTACK_LO_PLUS1_HEX,x | cmp #${segment[1].arg!!.integerValue().toHex()} """
}
)

View File

@ -1,242 +0,0 @@
package prog8.compiler.target.c64
import prog8.compiler.CompilationOptions
import prog8.compiler.CompilerException
import prog8.compiler.Zeropage
import prog8.compiler.ZeropageType
import java.awt.Color
import java.awt.image.BufferedImage
import javax.imageio.ImageIO
import kotlin.math.absoluteValue
import kotlin.math.pow
// 5-byte cbm MFLPT format limitations:
const val FLOAT_MAX_POSITIVE = 1.7014118345e+38 // bytes: 255,127,255,255,255
const val FLOAT_MAX_NEGATIVE = -1.7014118345e+38 // bytes: 255,255,255,255,255
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) {
companion object {
const val SCRATCH_B1 = 0x02
const val SCRATCH_REG = 0x03 // temp storage for a register
const val SCRATCH_REG_X = 0xfa // temp storage for register X (the evaluation stack pointer)
const val SCRATCH_W1 = 0xfb // $fb+$fc
const val SCRATCH_W2 = 0xfd // $fd+$fe
}
override val exitProgramStrategy: ExitProgramStrategy = when(options.zeropage) {
ZeropageType.BASICSAFE -> ExitProgramStrategy.CLEAN_EXIT
ZeropageType.FLOATSAFE, ZeropageType.KERNALSAFE, ZeropageType.FULL -> ExitProgramStrategy.SYSTEM_RESET
}
init {
if(options.floats && options.zeropage!=ZeropageType.FLOATSAFE && options.zeropage!=ZeropageType.BASICSAFE)
throw CompilerException("when floats are enabled, zero page type should be 'floatsafe' or 'basicsafe'")
if(options.zeropage == ZeropageType.FULL) {
free.addAll(0x04 .. 0xf9)
free.add(0xff)
free.removeAll(listOf(SCRATCH_B1, SCRATCH_REG, SCRATCH_REG_X, SCRATCH_W1, SCRATCH_W1+1, SCRATCH_W2, SCRATCH_W2+1))
free.removeAll(listOf(0xa0, 0xa1, 0xa2, 0x91, 0xc0, 0xc5, 0xcb, 0xf5, 0xf6)) // these are updated by IRQ
} else {
if(options.zeropage == ZeropageType.KERNALSAFE || options.zeropage == ZeropageType.FLOATSAFE) {
free.addAll(listOf(0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11,
0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x20, 0x21,
0x22, 0x23, 0x24, 0x25,
0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46,
0x47, 0x48, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, 0x51, 0x52, 0x53,
0x57, 0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f, 0x60,
0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68,
0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f, 0x70, 0x71, 0x72,
0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7a, 0x7b, 0x7c,
0x7d, 0x7e, 0x7f, 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8a,
0x8b, 0x8c, 0x8d, 0x8e, 0x8f, 0xff
// 0x90-0xfa is 'kernel work storage area'
))
}
if(options.zeropage == ZeropageType.FLOATSAFE) {
// remove the zero page locations used for floating point operations from the free list
free.removeAll(listOf(
0x12, 0x26, 0x27, 0x28, 0x29, 0x2a,
0x57, 0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f, 0x60,
0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68,
0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f, 0x70, 0x71, 0x72,
0x8b, 0x8c, 0x8d, 0x8e, 0x8f, 0xf
))
}
// add the other free Zp addresses,
// these are valid for the C-64 (when no RS232 I/O is performed) but to keep BASIC running fully:
free.addAll(listOf(0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0d, 0x0e,
0x94, 0x95, 0xa7, 0xa8, 0xa9, 0xaa,
0xb5, 0xb6, 0xf7, 0xf8, 0xf9))
}
assert(SCRATCH_B1 !in free)
assert(SCRATCH_REG !in free)
assert(SCRATCH_REG_X !in free)
assert(SCRATCH_W1 !in free)
assert(SCRATCH_W2 !in free)
for(reserved in options.zpReserved)
reserve(reserved)
}
}
data class Mflpt5(val b0: Short, val b1: Short, val b2: Short, val b3: Short, val b4: Short) {
companion object {
const val MemorySize = 5
val zero = Mflpt5(0, 0,0,0,0)
fun fromNumber(num: Number): Mflpt5 {
// see https://en.wikipedia.org/wiki/Microsoft_Binary_Format
// and https://sourceforge.net/p/acme-crossass/code-0/62/tree/trunk/ACME_Lib/cbm/mflpt.a
// and https://en.wikipedia.org/wiki/IEEE_754-1985
val flt = num.toDouble()
if(flt < FLOAT_MAX_NEGATIVE || flt > FLOAT_MAX_POSITIVE)
throw CompilerException("floating point number out of 5-byte mflpt range: $this")
if(flt==0.0)
return zero
val sign = if(flt<0.0) 0x80L else 0x00L
var exponent = 128 + 32 // 128 is cbm's bias, 32 is this algo's bias
var mantissa = flt.absoluteValue
// if mantissa is too large, shift right and adjust exponent
while(mantissa >= 0x100000000) {
mantissa /= 2.0
exponent ++
}
// if mantissa is too small, shift left and adjust exponent
while(mantissa < 0x80000000) {
mantissa *= 2.0
exponent --
}
return when {
exponent<0 -> zero // underflow, use zero instead
exponent>255 -> throw CompilerException("floating point overflow: $this")
exponent==0 -> zero
else -> {
val mantLong = mantissa.toLong()
Mflpt5(
exponent.toShort(),
(mantLong.and(0x7f000000L) ushr 24).or(sign).toShort(),
(mantLong.and(0x00ff0000L) ushr 16).toShort(),
(mantLong.and(0x0000ff00L) ushr 8).toShort(),
(mantLong.and(0x000000ffL)).toShort())
}
}
}
}
fun toDouble(): Double {
if(this == zero) return 0.0
val exp = b0 - 128
val sign = (b1.toInt() and 0x80) > 0
val number = 0x80000000L.or(b1.toLong() shl 24).or(b2.toLong() shl 16).or(b3.toLong() shl 8).or(b4.toLong())
val result = number.toDouble() * (2.0).pow(exp) / 0x100000000
return if(sign) -result else result
}
}
object Charset {
private val normalImg = ImageIO.read(javaClass.getResource("/charset/c64/charset-normal.png"))
private val shiftedImg = ImageIO.read(javaClass.getResource("/charset/c64/charset-shifted.png"))
private fun scanChars(img: BufferedImage): Array<BufferedImage> {
val transparent = BufferedImage(img.width, img.height, BufferedImage.TYPE_INT_ARGB)
transparent.createGraphics().drawImage(img, 0, 0, null)
val black = Color(0,0,0).rgb
val nopixel = Color(0,0,0,0).rgb
for(y in 0 until transparent.height) {
for(x in 0 until transparent.width) {
val col = transparent.getRGB(x, y)
if(col==black)
transparent.setRGB(x, y, nopixel)
}
}
val numColumns = transparent.width / 8
val charImages = (0..255).map {
val charX = it % numColumns
val charY = it/ numColumns
transparent.getSubimage(charX*8, charY*8, 8, 8)
}
return charImages.toTypedArray()
}
val normalChars = scanChars(normalImg)
val shiftedChars = scanChars(shiftedImg)
private val coloredNormalChars = mutableMapOf<Short, Array<BufferedImage>>()
fun getColoredChar(screenCode: Short, color: Short): BufferedImage {
val colorIdx = (color % Colors.palette.size).toShort()
val chars = coloredNormalChars[colorIdx]
if(chars!=null)
return chars[screenCode.toInt()]
val coloredChars = mutableListOf<BufferedImage>()
val transparent = Color(0,0,0,0).rgb
val rgb = Colors.palette[colorIdx.toInt()].rgb
for(c in normalChars) {
val colored = c.copy()
for(y in 0 until colored.height)
for(x in 0 until colored.width) {
if(colored.getRGB(x, y)!=transparent) {
colored.setRGB(x, y, rgb)
}
}
coloredChars.add(colored)
}
coloredNormalChars[colorIdx] = coloredChars.toTypedArray()
return coloredNormalChars.getValue(colorIdx)[screenCode.toInt()]
}
}
private fun BufferedImage.copy(): BufferedImage {
val bcopy = BufferedImage(this.width, this.height, this.type)
val g = bcopy.graphics
g.drawImage(this, 0, 0, null)
g.dispose()
return bcopy
}
object Colors {
val palette = listOf( // this is Pepto's Commodore-64 palette http://www.pepto.de/projects/colorvic/
Color(0x000000), // 0 = black
Color(0xFFFFFF), // 1 = white
Color(0x813338), // 2 = red
Color(0x75cec8), // 3 = cyan
Color(0x8e3c97), // 4 = purple
Color(0x56ac4d), // 5 = green
Color(0x2e2c9b), // 6 = blue
Color(0xedf171), // 7 = yellow
Color(0x8e5029), // 8 = orange
Color(0x553800), // 9 = brown
Color(0xc46c71), // 10 = light red
Color(0x4a4a4a), // 11 = dark grey
Color(0x7b7b7b), // 12 = medium grey
Color(0xa9ff9f), // 13 = light green
Color(0x706deb), // 14 = light blue
Color(0xb2b2b2) // 15 = light grey
)
}

View File

@ -0,0 +1,247 @@
package prog8.compiler.target.c64
import prog8.compiler.*
import java.awt.Color
import java.awt.image.BufferedImage
import javax.imageio.ImageIO
import kotlin.math.absoluteValue
import kotlin.math.pow
object MachineDefinition {
// 5-byte cbm MFLPT format limitations:
const val FLOAT_MAX_POSITIVE = 1.7014118345e+38 // bytes: 255,127,255,255,255
const val FLOAT_MAX_NEGATIVE = -1.7014118345e+38 // bytes: 255,255,255,255,255
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)
// and some heavily used string constants derived from the two values above
const val ESTACK_LO_VALUE = 0xce00 // $ce00-$ceff inclusive
const val ESTACK_HI_VALUE = 0xcf00 // $cf00-$cfff inclusive
const val ESTACK_LO_HEX = "\$ce00"
const val ESTACK_LO_PLUS1_HEX = "\$ce01"
const val ESTACK_LO_PLUS2_HEX = "\$ce02"
const val ESTACK_HI_HEX = "\$cf00"
const val ESTACK_HI_PLUS1_HEX = "\$cf01"
const val ESTACK_HI_PLUS2_HEX = "\$cf02"
class C64Zeropage(options: CompilationOptions) : Zeropage(options) {
companion object {
const val SCRATCH_B1 = 0x02
const val SCRATCH_REG = 0x03 // temp storage for a register
const val SCRATCH_REG_X = 0xfa // temp storage for register X (the evaluation stack pointer)
const val SCRATCH_W1 = 0xfb // $fb+$fc
const val SCRATCH_W2 = 0xfd // $fd+$fe
}
override val exitProgramStrategy: ExitProgramStrategy = when (options.zeropage) {
ZeropageType.BASICSAFE -> ExitProgramStrategy.CLEAN_EXIT
ZeropageType.FLOATSAFE, ZeropageType.KERNALSAFE, ZeropageType.FULL -> ExitProgramStrategy.SYSTEM_RESET
}
init {
if (options.floats && options.zeropage != ZeropageType.FLOATSAFE && options.zeropage != ZeropageType.BASICSAFE)
throw CompilerException("when floats are enabled, zero page type should be 'floatsafe' or 'basicsafe'")
if (options.zeropage == ZeropageType.FULL) {
free.addAll(0x04..0xf9)
free.add(0xff)
free.removeAll(listOf(SCRATCH_B1, SCRATCH_REG, SCRATCH_REG_X, SCRATCH_W1, SCRATCH_W1 + 1, SCRATCH_W2, SCRATCH_W2 + 1))
free.removeAll(listOf(0xa0, 0xa1, 0xa2, 0x91, 0xc0, 0xc5, 0xcb, 0xf5, 0xf6)) // these are updated by IRQ
} else {
if (options.zeropage == ZeropageType.KERNALSAFE || options.zeropage == ZeropageType.FLOATSAFE) {
free.addAll(listOf(0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11,
0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x20, 0x21,
0x22, 0x23, 0x24, 0x25,
0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46,
0x47, 0x48, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, 0x51, 0x52, 0x53,
0x57, 0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f, 0x60,
0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68,
0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f, 0x70, 0x71, 0x72,
0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7a, 0x7b, 0x7c,
0x7d, 0x7e, 0x7f, 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8a,
0x8b, 0x8c, 0x8d, 0x8e, 0x8f, 0xff
// 0x90-0xfa is 'kernel work storage area'
))
}
if (options.zeropage == ZeropageType.FLOATSAFE) {
// remove the zero page locations used for floating point operations from the free list
free.removeAll(listOf(
0x12, 0x26, 0x27, 0x28, 0x29, 0x2a,
0x57, 0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f, 0x60,
0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68,
0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f, 0x70, 0x71, 0x72,
0x8b, 0x8c, 0x8d, 0x8e, 0x8f, 0xf
))
}
// add the other free Zp addresses,
// these are valid for the C-64 (when no RS232 I/O is performed) but to keep BASIC running fully:
free.addAll(listOf(0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0d, 0x0e,
0x94, 0x95, 0xa7, 0xa8, 0xa9, 0xaa,
0xb5, 0xb6, 0xf7, 0xf8, 0xf9))
}
assert(SCRATCH_B1 !in free)
assert(SCRATCH_REG !in free)
assert(SCRATCH_REG_X !in free)
assert(SCRATCH_W1 !in free)
assert(SCRATCH_W2 !in free)
for (reserved in options.zpReserved)
reserve(reserved)
}
}
data class Mflpt5(val b0: Short, val b1: Short, val b2: Short, val b3: Short, val b4: Short) {
companion object {
const val MemorySize = 5
val zero = Mflpt5(0, 0, 0, 0, 0)
fun fromNumber(num: Number): Mflpt5 {
// see https://en.wikipedia.org/wiki/Microsoft_Binary_Format
// and https://sourceforge.net/p/acme-crossass/code-0/62/tree/trunk/ACME_Lib/cbm/mflpt.a
// and https://en.wikipedia.org/wiki/IEEE_754-1985
val flt = num.toDouble()
if (flt < FLOAT_MAX_NEGATIVE || flt > FLOAT_MAX_POSITIVE)
throw CompilerException("floating point number out of 5-byte mflpt range: $this")
if (flt == 0.0)
return zero
val sign = if (flt < 0.0) 0x80L else 0x00L
var exponent = 128 + 32 // 128 is cbm's bias, 32 is this algo's bias
var mantissa = flt.absoluteValue
// if mantissa is too large, shift right and adjust exponent
while (mantissa >= 0x100000000) {
mantissa /= 2.0
exponent++
}
// if mantissa is too small, shift left and adjust exponent
while (mantissa < 0x80000000) {
mantissa *= 2.0
exponent--
}
return when {
exponent < 0 -> zero // underflow, use zero instead
exponent > 255 -> throw CompilerException("floating point overflow: $this")
exponent == 0 -> zero
else -> {
val mantLong = mantissa.toLong()
Mflpt5(
exponent.toShort(),
(mantLong.and(0x7f000000L) ushr 24).or(sign).toShort(),
(mantLong.and(0x00ff0000L) ushr 16).toShort(),
(mantLong.and(0x0000ff00L) ushr 8).toShort(),
(mantLong.and(0x000000ffL)).toShort())
}
}
}
}
fun toDouble(): Double {
if (this == zero) return 0.0
val exp = b0 - 128
val sign = (b1.toInt() and 0x80) > 0
val number = 0x80000000L.or(b1.toLong() shl 24).or(b2.toLong() shl 16).or(b3.toLong() shl 8).or(b4.toLong())
val result = number.toDouble() * (2.0).pow(exp) / 0x100000000
return if (sign) -result else result
}
}
object Charset {
private val normalImg = ImageIO.read(javaClass.getResource("/charset/c64/charset-normal.png"))
private val shiftedImg = ImageIO.read(javaClass.getResource("/charset/c64/charset-shifted.png"))
private fun scanChars(img: BufferedImage): Array<BufferedImage> {
val transparent = BufferedImage(img.width, img.height, BufferedImage.TYPE_INT_ARGB)
transparent.createGraphics().drawImage(img, 0, 0, null)
val black = Color(0, 0, 0).rgb
val nopixel = Color(0, 0, 0, 0).rgb
for (y in 0 until transparent.height) {
for (x in 0 until transparent.width) {
val col = transparent.getRGB(x, y)
if (col == black)
transparent.setRGB(x, y, nopixel)
}
}
val numColumns = transparent.width / 8
val charImages = (0..255).map {
val charX = it % numColumns
val charY = it / numColumns
transparent.getSubimage(charX * 8, charY * 8, 8, 8)
}
return charImages.toTypedArray()
}
val normalChars = scanChars(normalImg)
val shiftedChars = scanChars(shiftedImg)
private val coloredNormalChars = mutableMapOf<Short, Array<BufferedImage>>()
fun getColoredChar(screenCode: Short, color: Short): BufferedImage {
val colorIdx = (color % colorPalette.size).toShort()
val chars = coloredNormalChars[colorIdx]
if (chars != null)
return chars[screenCode.toInt()]
val coloredChars = mutableListOf<BufferedImage>()
val transparent = Color(0, 0, 0, 0).rgb
val rgb = colorPalette[colorIdx.toInt()].rgb
for (c in normalChars) {
val colored = c.copy()
for (y in 0 until colored.height)
for (x in 0 until colored.width) {
if (colored.getRGB(x, y) != transparent) {
colored.setRGB(x, y, rgb)
}
}
coloredChars.add(colored)
}
coloredNormalChars[colorIdx] = coloredChars.toTypedArray()
return coloredNormalChars.getValue(colorIdx)[screenCode.toInt()]
}
}
private fun BufferedImage.copy(): BufferedImage {
val bcopy = BufferedImage(this.width, this.height, this.type)
val g = bcopy.graphics
g.drawImage(this, 0, 0, null)
g.dispose()
return bcopy
}
val colorPalette = listOf( // this is Pepto's Commodore-64 palette http://www.pepto.de/projects/colorvic/
Color(0x000000), // 0 = black
Color(0xFFFFFF), // 1 = white
Color(0x813338), // 2 = red
Color(0x75cec8), // 3 = cyan
Color(0x8e3c97), // 4 = purple
Color(0x56ac4d), // 5 = green
Color(0x2e2c9b), // 6 = blue
Color(0xedf171), // 7 = yellow
Color(0x8e5029), // 8 = orange
Color(0x553800), // 9 = brown
Color(0xc46c71), // 10 = light red
Color(0x4a4a4a), // 11 = dark grey
Color(0x7b7b7b), // 12 = medium grey
Color(0xa9ff9f), // 13 = light green
Color(0x706deb), // 14 = light blue
Color(0xb2b2b2) // 15 = light grey
)
}

View File

@ -8,6 +8,13 @@ import prog8.compiler.intermediate.Opcode
import prog8.compiler.toHex
import prog8.vm.stackvm.Syscall
import prog8.vm.stackvm.syscallsForStackVm
import prog8.compiler.target.c64.MachineDefinition.C64Zeropage
import prog8.compiler.target.c64.MachineDefinition.ESTACK_HI_HEX
import prog8.compiler.target.c64.MachineDefinition.ESTACK_LO_HEX
import prog8.compiler.target.c64.MachineDefinition.ESTACK_LO_PLUS1_HEX
import prog8.compiler.target.c64.MachineDefinition.ESTACK_LO_PLUS2_HEX
import prog8.compiler.target.c64.MachineDefinition.ESTACK_HI_PLUS1_HEX
import prog8.compiler.target.c64.MachineDefinition.ESTACK_HI_PLUS2_HEX
// note: see https://wiki.nesdev.com/w/index.php/6502_assembly_optimisations
@ -66,23 +73,23 @@ internal fun simpleInstr2Asm(ins: Instruction, block: IntermediateProgram.Progra
Opcode.DISCARD_WORD -> " inx"
Opcode.DISCARD_FLOAT -> " inx | inx | inx"
Opcode.DUP_B -> {
" lda ${(ESTACK_LO+1).toHex()},x | sta ${ESTACK_LO.toHex()},x | dex | ;DUP_B "
" lda $ESTACK_LO_PLUS1_HEX,x | sta $ESTACK_LO_HEX,x | dex | ;DUP_B "
}
Opcode.DUP_W -> {
" lda ${(ESTACK_LO+1).toHex()},x | sta ${ESTACK_LO.toHex()},x | lda ${(ESTACK_HI+1).toHex()},x | sta ${ESTACK_HI.toHex()},x | dex "
" lda $ESTACK_LO_PLUS1_HEX,x | sta $ESTACK_LO_HEX,x | lda $ESTACK_HI_PLUS1_HEX,x | sta $ESTACK_HI_HEX,x | dex "
}
Opcode.CMP_B, Opcode.CMP_UB -> {
" inx | lda ${ESTACK_LO.toHex()},x | cmp #${ins.arg!!.integerValue().toHex()} | ;CMP_B "
" inx | lda $ESTACK_LO_HEX,x | cmp #${ins.arg!!.integerValue().toHex()} | ;CMP_B "
}
Opcode.CMP_W, Opcode.CMP_UW -> {
"""
inx
lda ${ESTACK_HI.toHex()},x
lda $ESTACK_HI_HEX,x
cmp #>${ins.arg!!.integerValue().toHex()}
bne +
lda ${ESTACK_LO.toHex()},x
lda $ESTACK_LO_HEX,x
cmp #<${ins.arg.integerValue().toHex()}
; bne + not necessary?
; lda #0 not necessary?
@ -130,11 +137,11 @@ internal fun simpleInstr2Asm(ins: Instruction, block: IntermediateProgram.Progra
}
Opcode.PUSH_BYTE -> {
" lda #${hexVal(ins)} | sta ${ESTACK_LO.toHex()},x | dex"
" lda #${hexVal(ins)} | sta $ESTACK_LO_HEX,x | dex"
}
Opcode.PUSH_WORD -> {
val value = hexVal(ins)
" lda #<$value | sta ${ESTACK_LO.toHex()},x | lda #>$value | sta ${ESTACK_HI.toHex()},x | dex"
" lda #<$value | sta $ESTACK_LO_HEX,x | lda #>$value | sta $ESTACK_HI_HEX,x | dex"
}
Opcode.PUSH_FLOAT -> {
val floatConst = getFloatConst(ins.arg!!)
@ -143,28 +150,28 @@ internal fun simpleInstr2Asm(ins: Instruction, block: IntermediateProgram.Progra
Opcode.PUSH_VAR_BYTE -> {
when(ins.callLabel) {
"X" -> throw CompilerException("makes no sense to push X, it's used as a stack pointer itself. You should probably not use the X register (or only in trivial assignments)")
"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"
"A" -> " sta $ESTACK_LO_HEX,x | dex"
"Y" -> " tya | sta $ESTACK_LO_HEX,x | dex"
else -> " lda ${ins.callLabel} | sta $ESTACK_LO_HEX,x | dex"
}
}
Opcode.PUSH_VAR_WORD -> {
" lda ${ins.callLabel} | sta ${ESTACK_LO.toHex()},x | lda ${ins.callLabel}+1 | sta ${ESTACK_HI.toHex()},x | dex"
" lda ${ins.callLabel} | sta $ESTACK_LO_HEX,x | lda ${ins.callLabel}+1 | sta $ESTACK_HI_HEX,x | dex"
}
Opcode.PUSH_VAR_FLOAT -> " lda #<${ins.callLabel} | ldy #>${ins.callLabel}| jsr c64flt.push_float"
Opcode.PUSH_MEM_B, Opcode.PUSH_MEM_UB -> {
"""
lda ${hexVal(ins)}
sta ${ESTACK_LO.toHex()},x
sta $ESTACK_LO_HEX,x
dex
"""
}
Opcode.PUSH_MEM_W, Opcode.PUSH_MEM_UW -> {
"""
lda ${hexVal(ins)}
sta ${ESTACK_LO.toHex()},x
sta $ESTACK_LO_HEX,x
lda ${hexValPlusOne(ins)}
sta ${ESTACK_HI.toHex()},x
sta $ESTACK_HI_HEX,x
dex
"""
}
@ -173,43 +180,43 @@ internal fun simpleInstr2Asm(ins: Instruction, block: IntermediateProgram.Progra
}
Opcode.PUSH_MEMREAD -> {
"""
lda ${(ESTACK_LO+1).toHex()},x
lda $ESTACK_LO_PLUS1_HEX,x
sta (+) +1
lda ${(ESTACK_HI+1).toHex()},x
lda $ESTACK_HI_PLUS1_HEX,x
sta (+) +2
+ lda 65535 ; modified
sta ${(ESTACK_LO+1).toHex()},x
sta $ESTACK_LO_PLUS1_HEX,x
"""
}
Opcode.PUSH_REGAY_WORD -> {
" sta ${ESTACK_LO.toHex()},x | tya | sta ${ESTACK_HI.toHex()},x | dex "
" sta $ESTACK_LO_HEX,x | tya | sta $ESTACK_HI_HEX,x | dex "
}
Opcode.PUSH_ADDR_HEAPVAR -> {
" lda #<${ins.callLabel} | sta ${ESTACK_LO.toHex()},x | lda #>${ins.callLabel} | sta ${ESTACK_HI.toHex()},x | dex"
" lda #<${ins.callLabel} | sta $ESTACK_LO_HEX,x | lda #>${ins.callLabel} | sta $ESTACK_HI_HEX,x | dex"
}
Opcode.POP_REGAX_WORD -> throw AssemblyError("cannot load X register from stack because it's used as the stack pointer itself")
Opcode.POP_REGXY_WORD -> throw AssemblyError("cannot load X register from stack because it's used as the stack pointer itself")
Opcode.POP_REGAY_WORD -> {
" inx | lda ${ESTACK_LO.toHex()},x | ldy ${ESTACK_HI.toHex()},x "
" inx | lda $ESTACK_LO_HEX,x | ldy $ESTACK_HI_HEX,x "
}
Opcode.READ_INDEXED_VAR_BYTE -> {
"""
ldy ${(ESTACK_LO+1).toHex()},x
ldy $ESTACK_LO_PLUS1_HEX,x
lda ${ins.callLabel},y
sta ${(ESTACK_LO+1).toHex()},x
sta $ESTACK_LO_PLUS1_HEX,x
"""
}
Opcode.READ_INDEXED_VAR_WORD -> {
"""
lda ${(ESTACK_LO+1).toHex()},x
lda $ESTACK_LO_PLUS1_HEX,x
asl a
tay
lda ${ins.callLabel},y
sta ${(ESTACK_LO+1).toHex()},x
sta $ESTACK_LO_PLUS1_HEX,x
lda ${ins.callLabel}+1,y
sta ${(ESTACK_HI+1).toHex()},x
sta $ESTACK_HI_PLUS1_HEX,x
"""
}
Opcode.READ_INDEXED_VAR_FLOAT -> {
@ -222,22 +229,22 @@ internal fun simpleInstr2Asm(ins: Instruction, block: IntermediateProgram.Progra
Opcode.WRITE_INDEXED_VAR_BYTE -> {
"""
inx
ldy ${ESTACK_LO.toHex()},x
ldy $ESTACK_LO_HEX,x
inx
lda ${ESTACK_LO.toHex()},x
lda $ESTACK_LO_HEX,x
sta ${ins.callLabel},y
"""
}
Opcode.WRITE_INDEXED_VAR_WORD -> {
"""
inx
lda ${ESTACK_LO.toHex()},x
lda $ESTACK_LO_HEX,x
asl a
tay
inx
lda ${ESTACK_LO.toHex()},x
lda $ESTACK_LO_HEX,x
sta ${ins.callLabel},y
lda ${ESTACK_HI.toHex()},x
lda $ESTACK_HI_HEX,x
sta ${ins.callLabel}+1,y
"""
}
@ -251,16 +258,16 @@ internal fun simpleInstr2Asm(ins: Instruction, block: IntermediateProgram.Progra
Opcode.POP_MEM_BYTE -> {
"""
inx
lda ${ESTACK_LO.toHex()},x
lda $ESTACK_LO_HEX,x
sta ${hexVal(ins)}
"""
}
Opcode.POP_MEM_WORD -> {
"""
inx
lda ${ESTACK_LO.toHex()},x
lda $ESTACK_LO_HEX,x
sta ${hexVal(ins)}
lda ${ESTACK_HI.toHex()},x
lda $ESTACK_HI_HEX,x
sta ${hexValPlusOne(ins)}
"""
}
@ -270,12 +277,12 @@ internal fun simpleInstr2Asm(ins: Instruction, block: IntermediateProgram.Progra
Opcode.POP_MEMWRITE -> {
"""
inx
lda ${ESTACK_LO.toHex()},x
lda $ESTACK_LO_HEX,x
sta (+) +1
lda ${ESTACK_HI.toHex()},x
lda $ESTACK_HI_HEX,x
sta (+) +2
inx
lda ${ESTACK_LO.toHex()},x
lda $ESTACK_LO_HEX,x
+ sta 65535 ; modified
"""
}
@ -283,13 +290,13 @@ internal fun simpleInstr2Asm(ins: Instruction, block: IntermediateProgram.Progra
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}"
"A" -> " inx | lda $ESTACK_LO_HEX,x"
"Y" -> " inx | ldy $ESTACK_LO_HEX,x"
else -> " inx | lda $ESTACK_LO_HEX,x | sta ${ins.callLabel}"
}
}
Opcode.POP_VAR_WORD -> {
" inx | lda ${ESTACK_LO.toHex()},x | ldy ${ESTACK_HI.toHex()},x | sta ${ins.callLabel} | sty ${ins.callLabel}+1"
" inx | lda $ESTACK_LO_HEX,x | ldy $ESTACK_HI_HEX,x | sta ${ins.callLabel} | sty ${ins.callLabel}+1"
}
Opcode.POP_VAR_FLOAT -> {
" lda #<${ins.callLabel} | ldy #>${ins.callLabel} | jsr c64flt.pop_float"
@ -316,9 +323,9 @@ internal fun simpleInstr2Asm(ins: Instruction, block: IntermediateProgram.Progra
Opcode.POP_INC_MEMORY -> {
"""
inx
lda ${ESTACK_LO.toHex()},x
lda $ESTACK_LO_HEX,x
sta (+) +1
lda ${ESTACK_HI.toHex()},x
lda $ESTACK_HI_HEX,x
sta (+) +2
+ inc 65535 ; modified
"""
@ -326,9 +333,9 @@ internal fun simpleInstr2Asm(ins: Instruction, block: IntermediateProgram.Progra
Opcode.POP_DEC_MEMORY -> {
"""
inx
lda ${ESTACK_LO.toHex()},x
lda $ESTACK_LO_HEX,x
sta (+) +1
lda ${ESTACK_HI.toHex()},x
lda $ESTACK_HI_HEX,x
sta (+) +2
+ dec 65535 ; modified
"""
@ -353,8 +360,8 @@ internal fun simpleInstr2Asm(ins: Instruction, block: IntermediateProgram.Progra
}
Opcode.INC_MEMORY -> " inc ${hexVal(ins)}"
Opcode.DEC_MEMORY -> " dec ${hexVal(ins)}"
Opcode.INC_INDEXED_VAR_B, Opcode.INC_INDEXED_VAR_UB -> " inx | txa | pha | lda ${ESTACK_LO.toHex()},x | tax | inc ${ins.callLabel},x | pla | tax"
Opcode.DEC_INDEXED_VAR_B, Opcode.DEC_INDEXED_VAR_UB -> " inx | txa | pha | lda ${ESTACK_LO.toHex()},x | tax | dec ${ins.callLabel},x | pla | tax"
Opcode.INC_INDEXED_VAR_B, Opcode.INC_INDEXED_VAR_UB -> " inx | txa | pha | lda $ESTACK_LO_HEX,x | tax | inc ${ins.callLabel},x | pla | tax"
Opcode.DEC_INDEXED_VAR_B, Opcode.DEC_INDEXED_VAR_UB -> " inx | txa | pha | lda $ESTACK_LO_HEX,x | tax | dec ${ins.callLabel},x | pla | tax"
Opcode.NEG_B -> " jsr prog8_lib.neg_b"
Opcode.NEG_W -> " jsr prog8_lib.neg_w"
@ -365,9 +372,9 @@ internal fun simpleInstr2Asm(ins: Instruction, block: IntermediateProgram.Progra
Opcode.POW_F -> " jsr c64flt.pow_f"
Opcode.INV_BYTE -> {
"""
lda ${(ESTACK_LO + 1).toHex()},x
lda $ESTACK_LO_PLUS1_HEX,x
eor #255
sta ${(ESTACK_LO + 1).toHex()},x
sta $ESTACK_LO_PLUS1_HEX,x
"""
}
Opcode.INV_WORD -> " jsr prog8_lib.inv_word"
@ -409,7 +416,7 @@ internal fun simpleInstr2Asm(ins: Instruction, block: IntermediateProgram.Progra
val label = ins.callLabel ?: hexVal(ins)
"""
inx
lda ${(ESTACK_LO).toHex()},x
lda $ESTACK_LO_HEX,x
beq $label
"""
}
@ -417,9 +424,9 @@ internal fun simpleInstr2Asm(ins: Instruction, block: IntermediateProgram.Progra
val label = ins.callLabel ?: hexVal(ins)
"""
inx
lda ${(ESTACK_LO).toHex()},x
lda $ESTACK_LO_HEX,x
beq $label
lda ${(ESTACK_HI).toHex()},x
lda $ESTACK_HI_HEX,x
beq $label
"""
}
@ -427,7 +434,7 @@ internal fun simpleInstr2Asm(ins: Instruction, block: IntermediateProgram.Progra
val label = ins.callLabel ?: hexVal(ins)
"""
inx
lda ${(ESTACK_LO).toHex()},x
lda $ESTACK_LO_HEX,x
bne $label
"""
}
@ -435,9 +442,9 @@ internal fun simpleInstr2Asm(ins: Instruction, block: IntermediateProgram.Progra
val label = ins.callLabel ?: hexVal(ins)
"""
inx
lda ${(ESTACK_LO).toHex()},x
lda $ESTACK_LO_HEX,x
bne $label
lda ${(ESTACK_HI).toHex()},x
lda $ESTACK_HI_HEX,x
bne $label
"""
}
@ -457,27 +464,27 @@ internal fun simpleInstr2Asm(ins: Instruction, block: IntermediateProgram.Progra
Opcode.CAST_F_TO_B -> " jsr c64flt.stack_float2w"
Opcode.CAST_F_TO_UW -> " jsr c64flt.stack_float2uw"
Opcode.CAST_F_TO_W -> " jsr c64flt.stack_float2w"
Opcode.CAST_UB_TO_UW, Opcode.CAST_UB_TO_W -> " lda #0 | sta ${(ESTACK_HI+1).toHex()},x" // clear the msb
Opcode.CAST_B_TO_UW, Opcode.CAST_B_TO_W -> " lda ${(ESTACK_LO+1).toHex()},x | ${signExtendA("${(ESTACK_HI+1).toHex()},x")}" // sign extend the lsb
Opcode.MSB -> " lda ${(ESTACK_HI+1).toHex()},x | sta ${(ESTACK_LO+1).toHex()},x"
Opcode.MKWORD -> " inx | lda ${ESTACK_LO.toHex()},x | sta ${(ESTACK_HI+1).toHex()},x "
Opcode.CAST_UB_TO_UW, Opcode.CAST_UB_TO_W -> " lda #0 | sta $ESTACK_HI_PLUS1_HEX,x" // clear the msb
Opcode.CAST_B_TO_UW, Opcode.CAST_B_TO_W -> " lda $ESTACK_LO_PLUS1_HEX,x | ${signExtendA("$ESTACK_HI_PLUS1_HEX,x")}" // sign extend the lsb
Opcode.MSB -> " lda $ESTACK_HI_PLUS1_HEX,x | sta $ESTACK_LO_PLUS1_HEX,x"
Opcode.MKWORD -> " inx | lda $ESTACK_LO_HEX,x | sta $ESTACK_HI_PLUS1_HEX,x "
Opcode.ADD_UB, Opcode.ADD_B -> { // TODO inline better (pattern with more opcodes)
"""
lda ${(ESTACK_LO + 2).toHex()},x
lda $ESTACK_LO_PLUS2_HEX,x
clc
adc ${(ESTACK_LO + 1).toHex()},x
adc $ESTACK_LO_PLUS1_HEX,x
inx
sta ${(ESTACK_LO + 1).toHex()},x
sta $ESTACK_LO_PLUS1_HEX,x
"""
}
Opcode.SUB_UB, Opcode.SUB_B -> { // TODO inline better (pattern with more opcodes)
"""
lda ${(ESTACK_LO + 2).toHex()},x
lda $ESTACK_LO_PLUS2_HEX,x
sec
sbc ${(ESTACK_LO + 1).toHex()},x
sbc $ESTACK_LO_PLUS1_HEX,x
inx
sta ${(ESTACK_LO + 1).toHex()},x
sta $ESTACK_LO_PLUS1_HEX,x
"""
}
Opcode.ADD_W, Opcode.ADD_UW -> " jsr prog8_lib.add_w"
@ -541,12 +548,12 @@ internal fun simpleInstr2Asm(ins: Instruction, block: IntermediateProgram.Progra
Opcode.LESSEQ_W -> " jsr prog8_lib.lesseq_w"
Opcode.LESSEQ_F -> " jsr c64flt.lesseq_f"
Opcode.SHIFTEDL_BYTE -> " asl ${(ESTACK_LO+1).toHex()},x"
Opcode.SHIFTEDL_WORD -> " asl ${(ESTACK_LO+1).toHex()},x | rol ${(ESTACK_HI+1).toHex()},x"
Opcode.SHIFTEDR_SBYTE -> " lda ${(ESTACK_LO+1).toHex()},x | asl a | ror ${(ESTACK_LO+1).toHex()},x"
Opcode.SHIFTEDR_UBYTE -> " lsr ${(ESTACK_LO+1).toHex()},x"
Opcode.SHIFTEDR_SWORD -> " lda ${(ESTACK_HI+1).toHex()},x | asl a | ror ${(ESTACK_HI+1).toHex()},x | ror ${(ESTACK_LO+1).toHex()},x"
Opcode.SHIFTEDR_UWORD -> " lsr ${(ESTACK_HI+1).toHex()},x | ror ${(ESTACK_LO+1).toHex()},x"
Opcode.SHIFTEDL_BYTE -> " asl $ESTACK_LO_PLUS1_HEX,x"
Opcode.SHIFTEDL_WORD -> " asl $ESTACK_LO_PLUS1_HEX,x | rol $ESTACK_HI_PLUS1_HEX,x"
Opcode.SHIFTEDR_SBYTE -> " lda $ESTACK_LO_PLUS1_HEX,x | asl a | ror $ESTACK_LO_PLUS1_HEX,x"
Opcode.SHIFTEDR_UBYTE -> " lsr $ESTACK_LO_PLUS1_HEX,x"
Opcode.SHIFTEDR_SWORD -> " lda $ESTACK_HI_PLUS1_HEX,x | asl a | ror $ESTACK_HI_PLUS1_HEX,x | ror $ESTACK_LO_PLUS1_HEX,x"
Opcode.SHIFTEDR_UWORD -> " lsr $ESTACK_HI_PLUS1_HEX,x | ror $ESTACK_LO_PLUS1_HEX,x"
else -> null
}

View File

@ -7,8 +7,8 @@ import prog8.ast.processing.IAstModifyingVisitor
import prog8.ast.statements.*
import prog8.compiler.HeapValues
import prog8.compiler.IntegerOrAddressOf
import prog8.compiler.target.c64.FLOAT_MAX_NEGATIVE
import prog8.compiler.target.c64.FLOAT_MAX_POSITIVE
import prog8.compiler.target.c64.MachineDefinition.FLOAT_MAX_NEGATIVE
import prog8.compiler.target.c64.MachineDefinition.FLOAT_MAX_POSITIVE
import kotlin.math.floor

View File

@ -6,7 +6,7 @@ import prog8.ast.base.initvarsSubName
import prog8.ast.expressions.IdentifierReference
import prog8.ast.expressions.LiteralValue
import prog8.ast.statements.*
import prog8.compiler.target.c64.Mflpt5
import prog8.compiler.target.c64.MachineDefinition
import prog8.vm.RuntimeValue
import prog8.vm.RuntimeValueRange
import prog8.compiler.target.c64.Petscii
@ -621,7 +621,7 @@ class AstVm(val program: Program) {
DataType.BYTE -> mem.setSByte(address+index, value.byteval!!)
DataType.UWORD -> mem.setUWord(address+index*2, value.wordval!!)
DataType.WORD -> mem.setSWord(address+index*2, value.wordval!!)
DataType.FLOAT -> mem.setFloat(address+index*Mflpt5.MemorySize, value.floatval!!)
DataType.FLOAT -> mem.setFloat(address+index* MachineDefinition.Mflpt5.MemorySize, value.floatval!!)
else -> throw VmExecutionException("strange array elt type $elementType")
}
}

View File

@ -1,6 +1,6 @@
package prog8.vm.astvm
import prog8.compiler.target.c64.Mflpt5
import prog8.compiler.target.c64.MachineDefinition
import prog8.compiler.target.c64.Petscii
import kotlin.math.abs
@ -80,7 +80,7 @@ class Memory(private val readObserver: (address: Int, value: Short) -> Short,
}
fun setFloat(address: Int, value: Double) {
val mflpt5 = Mflpt5.fromNumber(value)
val mflpt5 = MachineDefinition.Mflpt5.fromNumber(value)
setUByte(address, mflpt5.b0)
setUByte(address+1, mflpt5.b1)
setUByte(address+2, mflpt5.b2)
@ -89,7 +89,7 @@ class Memory(private val readObserver: (address: Int, value: Short) -> Short,
}
fun getFloat(address: Int): Double {
return Mflpt5(getUByte(address), getUByte(address + 1), getUByte(address + 2),
return MachineDefinition.Mflpt5(getUByte(address), getUByte(address + 1), getUByte(address + 2),
getUByte(address + 3), getUByte(address + 4)).toDouble()
}

View File

@ -1,7 +1,6 @@
package prog8.vm.astvm
import prog8.compiler.target.c64.Charset
import prog8.compiler.target.c64.Colors
import prog8.compiler.target.c64.MachineDefinition
import prog8.compiler.target.c64.Petscii
import java.awt.*
import java.awt.event.KeyEvent
@ -51,16 +50,16 @@ class BitmapScreenPanel : KeyListener, JPanel() {
}
fun clearScreen(color: Short) {
g2d.background = Colors.palette[color % Colors.palette.size]
g2d.background = MachineDefinition.colorPalette[color % MachineDefinition.colorPalette.size]
g2d.clearRect(0, 0, SCREENWIDTH, SCREENHEIGHT)
cursorX = 0
cursorY = 0
}
fun setPixel(x: Int, y: Int, color: Short) {
image.setRGB(x, y, Colors.palette[color % Colors.palette.size].rgb)
image.setRGB(x, y, MachineDefinition.colorPalette[color % MachineDefinition.colorPalette.size].rgb)
}
fun drawLine(x1: Int, y1: Int, x2: Int, y2: Int, color: Short) {
g2d.color = Colors.palette[color % Colors.palette.size]
g2d.color = MachineDefinition.colorPalette[color % MachineDefinition.colorPalette.size]
g2d.drawLine(x1, y1, x2, y2)
}
@ -95,7 +94,7 @@ class BitmapScreenPanel : KeyListener, JPanel() {
val graphics = image.graphics as Graphics2D
graphics.drawImage(screen, 0, -8, null)
val color = graphics.color
graphics.color = Colors.palette[6]
graphics.color = MachineDefinition.colorPalette[6]
graphics.fillRect(0, 24*8, SCREENWIDTH, 25*8)
graphics.color=color
cursorY--
@ -103,7 +102,7 @@ class BitmapScreenPanel : KeyListener, JPanel() {
}
fun writeTextAt(x: Int, y: Int, text: String, color: Short, lowercase: Boolean, inverseVideo: Boolean=false) {
val colorIdx = (color % Colors.palette.size).toShort()
val colorIdx = (color % MachineDefinition.colorPalette.size).toShort()
var xx=x
for(clearx in xx until xx+text.length) {
g2d.clearRect(8*clearx, 8*y, 8, 8)
@ -117,16 +116,16 @@ class BitmapScreenPanel : KeyListener, JPanel() {
fun setPetscii(x: Int, y: Int, petscii: Short, color: Short, inverseVideo: Boolean) {
g2d.clearRect(8*x, 8*y, 8, 8)
val colorIdx = (color % Colors.palette.size).toShort()
val colorIdx = (color % MachineDefinition.colorPalette.size).toShort()
val screencode = Petscii.petscii2scr(petscii, inverseVideo)
val coloredImage = Charset.getColoredChar(screencode, colorIdx)
val coloredImage = MachineDefinition.Charset.getColoredChar(screencode, colorIdx)
g2d.drawImage(coloredImage, 8*x, 8*y , null)
}
fun setChar(x: Int, y: Int, screencode: Short, color: Short) {
g2d.clearRect(8*x, 8*y, 8, 8)
val colorIdx = (color % Colors.palette.size).toShort()
val coloredImage = Charset.getColoredChar(screencode, colorIdx)
val colorIdx = (color % MachineDefinition.colorPalette.size).toShort()
val coloredImage = MachineDefinition.Charset.getColoredChar(screencode, colorIdx)
g2d.drawImage(coloredImage, 8*x, 8*y , null)
}
@ -160,19 +159,19 @@ class ScreenDialog(title: String) : JFrame(title) {
// the borders (top, left, right, bottom)
val borderTop = JPanel().apply {
preferredSize = Dimension(BitmapScreenPanel.SCALING * (BitmapScreenPanel.SCREENWIDTH +2*borderWidth), BitmapScreenPanel.SCALING * borderWidth)
background = Colors.palette[14]
background = MachineDefinition.colorPalette[14]
}
val borderBottom = JPanel().apply {
preferredSize =Dimension(BitmapScreenPanel.SCALING * (BitmapScreenPanel.SCREENWIDTH +2*borderWidth), BitmapScreenPanel.SCALING * borderWidth)
background = Colors.palette[14]
background = MachineDefinition.colorPalette[14]
}
val borderLeft = JPanel().apply {
preferredSize =Dimension(BitmapScreenPanel.SCALING * borderWidth, BitmapScreenPanel.SCALING * BitmapScreenPanel.SCREENHEIGHT)
background = Colors.palette[14]
background = MachineDefinition.colorPalette[14]
}
val borderRight = JPanel().apply {
preferredSize =Dimension(BitmapScreenPanel.SCALING * borderWidth, BitmapScreenPanel.SCALING * BitmapScreenPanel.SCREENHEIGHT)
background = Colors.palette[14]
background = MachineDefinition.colorPalette[14]
}
var c = GridBagConstraints()
c.gridx=0; c.gridy=1; c.gridwidth=3

View File

@ -10,7 +10,11 @@ import prog8.ast.base.Position
import prog8.ast.expressions.LiteralValue
import prog8.vm.RuntimeValue
import prog8.compiler.*
import prog8.compiler.target.c64.*
import prog8.compiler.target.c64.MachineDefinition.Mflpt5
import prog8.compiler.target.c64.MachineDefinition.FLOAT_MAX_NEGATIVE
import prog8.compiler.target.c64.MachineDefinition.FLOAT_MAX_POSITIVE
import prog8.compiler.target.c64.MachineDefinition.C64Zeropage
import prog8.compiler.target.c64.Petscii
import java.io.CharConversionException
import kotlin.test.*