Skip to content

Commit

Permalink
Merge branch 'master' into next_compositetypes
Browse files Browse the repository at this point in the history
# Conflicts:
#	codeGenCpu6502/src/prog8/codegen/cpu6502/AsmGen.kt
#	compiler/src/prog8/compiler/astprocessing/AstChecker.kt
#	compiler/src/prog8/compiler/astprocessing/IntermediateAstPostprocess.kt
  • Loading branch information
irmen committed Nov 11, 2024
2 parents 18f1242 + 648d9fc commit c736fa3
Show file tree
Hide file tree
Showing 37 changed files with 304 additions and 222 deletions.
7 changes: 6 additions & 1 deletion codeCore/src/prog8/code/ast/AstBase.kt
Original file line number Diff line number Diff line change
Expand Up @@ -96,7 +96,12 @@ class PtInlineAssembly(val assembly: String, val isIR: Boolean, position: Positi
}


class PtLabel(name: String, position: Position) : PtNamedNode(name, position)
class PtLabel(name: String, position: Position) : PtNamedNode(name, position) {
companion object {
// all automatically generated labels everywhere need to have the same label name prefix:
const val GeneratedLabelPrefix = "p8_label_gen_"
}
}


class PtBreakpoint(position: Position): PtNode(position)
Expand Down
5 changes: 1 addition & 4 deletions codeCore/src/prog8/code/ast/AstExpressions.kt
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,7 @@ sealed class PtExpression(val type: DataType, position: Position) : PtNode(posit
}

fun asConstInteger(): Int? = (this as? PtNumber)?.number?.toInt() ?: (this as? PtBool)?.asInt()
fun asConstValue(): Double? = (this as? PtNumber)?.number ?: (this as? PtBool)?.asInt()?.toDouble()

fun isSimple(): Boolean {
return when(this) {
Expand Down Expand Up @@ -376,7 +377,3 @@ class PtTypeCast(type: BaseDataType, position: Position) : PtExpression(DataType

// special node that isn't created from compiling user code, but used internally in the Intermediate Code
class PtIrRegister(val register: Int, type: DataType, position: Position) : PtExpression(type, position)


fun constValue(expr: PtExpression): Double? = if(expr is PtNumber) expr.number else if(expr is PtBool) expr.asInt().toDouble() else null
fun constIntValue(expr: PtExpression): Int? = if(expr is PtNumber) expr.number.toInt() else if(expr is PtBool) expr.asInt() else null
2 changes: 1 addition & 1 deletion codeCore/src/prog8/code/core/IMachineDefinition.kt
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ interface IMachineDefinition {
val FLOAT_MAX_POSITIVE: Double
val FLOAT_MEM_SIZE: Int
val PROGRAM_LOAD_ADDRESS : UInt
val PROGRAM_TOP_ADDRESS: UInt
val PROGRAM_MEMTOP_ADDRESS: UInt
val BSSHIGHRAM_START: UInt
val BSSHIGHRAM_END: UInt
val BSSGOLDENRAM_START: UInt
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ class AtariMachineDefinition: IMachineDefinition {
override val FLOAT_MAX_NEGATIVE = -9.999999999e97
override val FLOAT_MEM_SIZE = 6
override val PROGRAM_LOAD_ADDRESS = 0x2000u
override val PROGRAM_TOP_ADDRESS = 0xffffu // TODO what's memtop
override val PROGRAM_MEMTOP_ADDRESS = 0xffffu // TODO what's memtop?

override val BSSHIGHRAM_START = 0u // TODO
override val BSSHIGHRAM_END = 0u // TODO
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ class C128MachineDefinition: IMachineDefinition {
override val FLOAT_MAX_NEGATIVE = Mflpt5.FLOAT_MAX_NEGATIVE
override val FLOAT_MEM_SIZE = Mflpt5.FLOAT_MEM_SIZE
override val PROGRAM_LOAD_ADDRESS = 0x1c01u
override val PROGRAM_TOP_ADDRESS = 0xfeffu
override val PROGRAM_MEMTOP_ADDRESS = 0xff00u

override val BSSHIGHRAM_START = 0u // TODO
override val BSSHIGHRAM_END = 0u // TODO
Expand Down
2 changes: 1 addition & 1 deletion codeCore/src/prog8/code/target/c64/C64MachineDefinition.kt
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ class C64MachineDefinition: IMachineDefinition {
override val FLOAT_MAX_NEGATIVE = Mflpt5.FLOAT_MAX_NEGATIVE
override val FLOAT_MEM_SIZE = Mflpt5.FLOAT_MEM_SIZE
override val PROGRAM_LOAD_ADDRESS = 0x0801u
override val PROGRAM_TOP_ADDRESS = 0xcfe0u // $9fff if floats are used
override val PROGRAM_MEMTOP_ADDRESS = 0xcfe0u // $a000 if floats are used
// note that at $cfe0-$cfff are the 16 'virtual registers' R0-R15

override val BSSHIGHRAM_START = 0xc000u
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ class CX16MachineDefinition: IMachineDefinition {
override val FLOAT_MAX_NEGATIVE = Mflpt5.FLOAT_MAX_NEGATIVE
override val FLOAT_MEM_SIZE = Mflpt5.FLOAT_MEM_SIZE
override val PROGRAM_LOAD_ADDRESS = 0x0801u
override val PROGRAM_TOP_ADDRESS = 0x9effu
override val PROGRAM_MEMTOP_ADDRESS = 0x9f00u

override val BSSHIGHRAM_START = 0xa000u // hiram bank 1, 8Kb, assumed to be active
override val BSSHIGHRAM_END = 0xbfffu // Rom starts at $c000
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ class Neo6502MachineDefinition: IMachineDefinition {
override val FLOAT_MAX_NEGATIVE = -9.999999999e97
override val FLOAT_MEM_SIZE = 6
override val PROGRAM_LOAD_ADDRESS = 0x0800u
override val PROGRAM_TOP_ADDRESS = 0xfbffu
override val PROGRAM_MEMTOP_ADDRESS = 0xfc00u // kernal starts here

override val BSSHIGHRAM_START = 0u // TODO
override val BSSHIGHRAM_END = 0u // TODO
Expand Down
2 changes: 1 addition & 1 deletion codeCore/src/prog8/code/target/pet/PETMachineDefinition.kt
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ class PETMachineDefinition: IMachineDefinition {
override val FLOAT_MAX_NEGATIVE = Mflpt5.FLOAT_MAX_NEGATIVE
override val FLOAT_MEM_SIZE = Mflpt5.FLOAT_MEM_SIZE
override val PROGRAM_LOAD_ADDRESS = 0x0401u
override val PROGRAM_TOP_ADDRESS = 0x7fffu
override val PROGRAM_MEMTOP_ADDRESS = 0x8000u

override val BSSHIGHRAM_START = 0u
override val BSSHIGHRAM_END = 0u
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ class VirtualMachineDefinition: IMachineDefinition {
override val FLOAT_MAX_NEGATIVE = -Float.MAX_VALUE.toDouble()
override val FLOAT_MEM_SIZE = 8 // 64-bits double
override val PROGRAM_LOAD_ADDRESS = 0u // not actually used
override val PROGRAM_TOP_ADDRESS = 0xffffu // not actually used
override val PROGRAM_MEMTOP_ADDRESS = 0xffffu // not actually used

override val BSSHIGHRAM_START = 0u // not actually used
override val BSSHIGHRAM_END = 0u // not actually used
Expand Down
29 changes: 16 additions & 13 deletions codeGenCpu6502/src/prog8/codegen/cpu6502/AsmGen.kt
Original file line number Diff line number Diff line change
Expand Up @@ -16,15 +16,15 @@ import kotlin.io.path.writeLines
internal const val subroutineFloatEvalResultVar1 = "prog8_float_eval_result1"
internal const val subroutineFloatEvalResultVar2 = "prog8_float_eval_result2"

class AsmGen6502(val prefixSymbols: Boolean): ICodeGeneratorBackend {
class AsmGen6502(val prefixSymbols: Boolean, private val lastGeneratedLabelSequenceNr: Int): ICodeGeneratorBackend {
override fun generate(
program: PtProgram,
symbolTable: SymbolTable,
options: CompilationOptions,
errors: IErrorReporter
errors: IErrorReporter,
): IAssemblyProgram? {
val st = if(prefixSymbols) prefixSymbols(program, options, symbolTable) else symbolTable
val asmgen = AsmGen6502Internal(program, st, options, errors)
val asmgen = AsmGen6502Internal(program, st, options, errors, lastGeneratedLabelSequenceNr)
return asmgen.compileToAssembly()
}

Expand All @@ -36,7 +36,7 @@ class AsmGen6502(val prefixSymbols: Boolean): ICodeGeneratorBackend {
when(node) {
is PtAsmSub, is PtSub -> node.name = "p8s_${node.name}"
is PtBlock -> node.name = "p8b_${node.name}"
is PtLabel -> node.name = "p8l_${node.name}"
is PtLabel -> if(!node.name.startsWith(PtLabel.GeneratedLabelPrefix)) node.name = "p8l_${node.name}"
is PtConstant -> node.name = "p8c_${node.name}"
is PtVariable, is PtMemMapped, is PtSubroutineParameter -> node.name = "p8v_${node.name}"
else -> node.name = "p8_${node.name}"
Expand Down Expand Up @@ -126,11 +126,15 @@ class AsmGen6502(val prefixSymbols: Boolean): ICodeGeneratorBackend {
}

private fun prefixScopedName(name: String, type: Char): String {
if('.' !in name)
if('.' !in name) {
if(name.startsWith(PtLabel.GeneratedLabelPrefix))
return name
return "p8${type}_$name"
}
val parts = name.split('.')
val firstPrefixed = "p8b_${parts[0]}"
val lastPrefixed = "p8${type}_${parts.last()}"
val lastPart = parts.last()
val lastPrefixed = if(lastPart.startsWith(PtLabel.GeneratedLabelPrefix)) lastPart else "p8${type}_$lastPart"
// the parts in between are assumed to be subroutine scopes.
val inbetweenPrefixed = parts.drop(1).dropLast(1).map{ "p8s_$it" }
val prefixed = listOf(firstPrefixed) + inbetweenPrefixed + listOf(lastPrefixed)
Expand Down Expand Up @@ -221,7 +225,8 @@ class AsmGen6502Internal (
val program: PtProgram,
internal val symbolTable: SymbolTable,
internal val options: CompilationOptions,
internal val errors: IErrorReporter
internal val errors: IErrorReporter,
private var generatedLabelSequenceNumber: Int
) {

internal val optimizedByteMultiplications = setOf(3,5,6,7,9,10,11,12,13,14,15,20,25,40,50,80,100)
Expand Down Expand Up @@ -785,7 +790,7 @@ class AsmGen6502Internal (
when {
iterations == 0 -> {}
iterations == 1 -> translate(stmt.statements)
iterations<0 || iterations>65535 -> throw AssemblyError("invalid number of iterations")
iterations<0 || iterations>65536 -> throw AssemblyError("invalid number of iterations")
iterations <= 256 -> repeatByteCount(iterations, stmt)
else -> repeatWordCount(iterations, stmt)
}
Expand Down Expand Up @@ -825,10 +830,10 @@ class AsmGen6502Internal (
}

private fun repeatWordCount(iterations: Int, stmt: PtRepeatLoop) {
require(iterations in 257..65535) { "invalid repeat count ${stmt.position}" }
require(iterations in 257..65536) { "invalid repeat count ${stmt.position}" }
val repeatLabel = makeLabel("repeat")
val counterVar = createRepeatCounterVar(BaseDataType.UWORD, isTargetCpu(CpuType.CPU65c02), stmt)
val loopcount = if(iterations and 0x00ff == 0) iterations else iterations + 0x0100 // so that the loop can simply use a double-dec
val loopcount = if(iterations==65536) 0 else if(iterations and 0x00ff == 0) iterations else iterations + 0x0100 // so that the loop can simply use a double-dec
out("""
ldy #>$loopcount
lda #<$loopcount
Expand Down Expand Up @@ -1361,11 +1366,9 @@ $repeatLabel""")
extra
}

private var generatedLabelSequenceNumber: Int = 0

internal fun makeLabel(postfix: String): String {
generatedLabelSequenceNumber++
return "label_asm_${generatedLabelSequenceNumber}_$postfix"
return "${PtLabel.GeneratedLabelPrefix}${generatedLabelSequenceNumber}_$postfix"
}

fun assignConstFloatToPointerAY(number: PtNumber) {
Expand Down
10 changes: 7 additions & 3 deletions codeGenCpu6502/src/prog8/codegen/cpu6502/AsmsubHelpers.kt
Original file line number Diff line number Diff line change
Expand Up @@ -11,18 +11,22 @@ fun asmsub6502ArgsEvalOrder(sub: PtAsmSub): List<Int> {
// 1) cx16 virtual word registers,
// 2) paired CPU registers,
// 3) single CPU registers (order Y,X,A),
// 4) CPU Carry status flag
// 4) floating point registers (FAC1, FAC2),
// 5) CPU Carry status flag
val args = sub.parameters.withIndex()
val (cx16regs, args2) = args.partition { it.value.first.registerOrPair in Cx16VirtualRegisters }
val pairedRegisters = arrayOf(RegisterOrPair.AX, RegisterOrPair.AY, RegisterOrPair.XY)
val (pairedRegs , args3) = args2.partition { it.value.first.registerOrPair in pairedRegisters }
val (singleRegs, rest) = args3.partition { it.value.first.registerOrPair != null }
val (singleRegsMixed, rest) = args3.partition { it.value.first.registerOrPair != null }
val (singleCpuRegs, floatRegs) = singleRegsMixed.partition {it.value.first.registerOrPair != RegisterOrPair.FAC1 && it.value.first.registerOrPair != RegisterOrPair.FAC2 }

cx16regs.forEach { order += it.index }
pairedRegs.forEach { order += it.index }
singleRegs.sortedBy { it.value.first.registerOrPair!!.asCpuRegister() }.asReversed().forEach { order += it.index }
singleCpuRegs.sortedBy { it.value.first.registerOrPair!!.asCpuRegister() }.asReversed().forEach { order += it.index }
require(rest.all { it.value.first.registerOrPair==null && it.value.first.statusflag!=null})
floatRegs.forEach { order += it.index }
rest.forEach { order += it.index }
require(order.size==sub.parameters.size)

return order
}
5 changes: 3 additions & 2 deletions codeGenCpu6502/src/prog8/codegen/cpu6502/AssemblyProgram.kt
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package prog8.codegen.cpu6502

import prog8.code.ast.PtLabel
import prog8.code.core.*
import prog8.code.target.AtariTarget
import prog8.code.target.C64Target
Expand All @@ -9,7 +10,7 @@ import java.nio.file.Path

internal class AssemblyProgram(
override val name: String,
outputDir: Path,
private val outputDir: Path,
private val compTarget: ICompilationTarget) : IAssemblyProgram {

private val assemblyFile = outputDir.resolve("$name.asm")
Expand Down Expand Up @@ -147,7 +148,7 @@ internal class AssemblyProgram(
}

private fun removeGeneratedLabelsFromMonlist() {
val pattern = Regex("""al (\w+) \S+prog8_label_.+?""")
val pattern = Regex("""al (\w+) \S+${PtLabel.GeneratedLabelPrefix}.+?""")
val lines = viceMonListFile.toFile().readLines()
viceMonListFile.toFile().outputStream().bufferedWriter().use {
for (line in lines) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -287,7 +287,7 @@ internal class ProgramAndVarsGen(
}
}
asmgen.out(" ; memtop check")
asmgen.out(" .cerror * > ${options.memtopAddress.toHex()}, \"Program too long by \", * - ${options.memtopAddress.toHex()}, \" bytes, memtop=${options.memtopAddress.toHex()}\"")
asmgen.out(" .cerror * >= ${options.memtopAddress.toHex()}, \"Program too long by \", * - ${(options.memtopAddress-1u).toHex()}, \" bytes, memtop=${options.memtopAddress.toHex()}\"")
}

private fun block2asm(block: PtBlock) {
Expand Down
2 changes: 1 addition & 1 deletion codeGenCpu6502/test/TestCodegen.kt
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ class TestCodegen: FunSpec({
// xx += cx16.r0
// }
//}
val codegen = AsmGen6502(prefixSymbols = false)
val codegen = AsmGen6502(prefixSymbols = false, 0)
val program = PtProgram("test", DummyMemsizer, DummyStringEncoder)
val block = PtBlock("main",false, SourceCode.Generated("test"), PtBlock.Options(), Position.DUMMY)
val sub = PtSub("start", emptyList(), null, Position.DUMMY)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -359,7 +359,7 @@ internal class AssignmentGen(private val codeGen: IRCodeGen, private val express
val variable = targetArray.variable.name
val itemsize = codeGen.program.memsizer.memorySize(targetArray.type, null)

val fixedIndex = constIntValue(targetArray.index)
val fixedIndex = targetArray.index.asConstInteger()
val arrayLength = codeGen.symbolTable.getLength(targetArray.variable.name)
if(zero) {
if(fixedIndex!=null) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -609,6 +609,7 @@ internal class ExpressionGen(private val codeGen: IRCodeGen) {
RegisterOrPair.AX -> addInstr(result, IRInstruction(Opcode.STOREHAX, IRDataType.WORD, reg1=tr.resultReg), null)
RegisterOrPair.AY -> addInstr(result, IRInstruction(Opcode.STOREHAY, IRDataType.WORD, reg1=tr.resultReg), null)
RegisterOrPair.XY -> addInstr(result, IRInstruction(Opcode.STOREHXY, IRDataType.WORD, reg1=tr.resultReg), null)
RegisterOrPair.FAC1, RegisterOrPair.FAC2 -> TODO("floating point register parameters not supported")
in Cx16VirtualRegisters -> {
addInstr(result, IRInstruction(Opcode.STOREM, paramDt, reg1=tr.resultReg, labelSymbol = "cx16.${parameter.register.registerOrPair.toString().lowercase()}"), null)
}
Expand Down Expand Up @@ -895,7 +896,7 @@ internal class ExpressionGen(private val codeGen: IRCodeGen) {
if(binExpr.left.type.isString || binExpr.right.type.isString) {
throw AssemblyError("str compares should have been replaced with builtin function call to do the compare")
} else {
return if(constValue(binExpr.right)==0.0) {
return if(binExpr.right.asConstValue()==0.0) {
val tr = translateExpression(binExpr.left)
addToResult(result, tr, tr.resultReg, -1)
val opcode = if (notEquals) Opcode.SNZ else Opcode.SZ
Expand Down
38 changes: 25 additions & 13 deletions codeGenIntermediate/src/prog8/codegen/intermediate/IRCodeGen.kt
Original file line number Diff line number Diff line change
Expand Up @@ -1590,7 +1590,7 @@ class IRCodeGen(
}

private fun translate(repeat: PtRepeatLoop): IRCodeChunks {
when (constIntValue(repeat.count)) {
when (repeat.count.asConstInteger()) {
0 -> return emptyList()
1 -> return translateGroup(repeat.children)
256 -> {
Expand All @@ -1601,18 +1601,30 @@ class IRCodeGen(

val repeatLabel = createLabelName()
val skipRepeatLabel = createLabelName()
val irDt = irType(repeat.count.type)
val constRepeats = repeat.count.asConstInteger()
val result = mutableListOf<IRCodeChunkBase>()
val countTr = expressionEval.translateExpression(repeat.count)
addToResult(result, countTr, countTr.resultReg, -1)
if(constIntValue(repeat.count)==null) {
// check if the counter is already zero
addInstr(result, IRInstruction(Opcode.BSTEQ, labelSymbol = skipRepeatLabel), null)
}
result += labelFirstChunk(translateNode(repeat.statements), repeatLabel)
result += IRCodeChunk(null, null).also {
it += IRInstruction(Opcode.DEC, irDt, reg1 = countTr.resultReg) // sets status bits
it += IRInstruction(Opcode.BSTNE, labelSymbol = repeatLabel)
if(constRepeats==65536) {
// make use of the word wrap around to count to 65536
val resultRegister = registers.nextFree()
addInstr(result, IRInstruction(Opcode.LOAD, IRDataType.WORD, reg1=resultRegister, immediate = 0), null)
result += labelFirstChunk(translateNode(repeat.statements), repeatLabel)
result += IRCodeChunk(null, null).also {
it += IRInstruction(Opcode.DEC, IRDataType.WORD, reg1 = resultRegister) // sets status bits
it += IRInstruction(Opcode.BSTNE, labelSymbol = repeatLabel)
}
} else {
val irDt = irType(repeat.count.type)
val countTr = expressionEval.translateExpression(repeat.count)
addToResult(result, countTr, countTr.resultReg, -1)
if (repeat.count.asConstValue() == null) {
// check if the counter is already zero
addInstr(result, IRInstruction(Opcode.BSTEQ, labelSymbol = skipRepeatLabel), null)
}
result += labelFirstChunk(translateNode(repeat.statements), repeatLabel)
result += IRCodeChunk(null, null).also {
it += IRInstruction(Opcode.DEC, irDt, reg1 = countTr.resultReg) // sets status bits
it += IRInstruction(Opcode.BSTNE, labelSymbol = repeatLabel)
}
}
result += IRCodeChunk(skipRepeatLabel, null)
return result
Expand Down Expand Up @@ -1753,7 +1765,7 @@ class IRCodeGen(
private var labelSequenceNumber = 0
internal fun createLabelName(): String {
labelSequenceNumber++
return "label_gen_$labelSequenceNumber"
return "${PtLabel.GeneratedLabelPrefix}$labelSequenceNumber"
}

internal fun translateBuiltinFunc(call: PtBuiltinFunctionCall): ExpressionCodeResult
Expand Down
4 changes: 4 additions & 0 deletions compiler/res/prog8lib/c128/diskio.p8
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
%import shared_cbm_diskio

; No alterations here; everything is taken from the shared module.

4 changes: 4 additions & 0 deletions compiler/res/prog8lib/c64/diskio.p8
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
%import shared_cbm_diskio

; No alterations here; everything is taken from the shared module.

Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
; C64/C128 disk drive I/O routines.
; shared CBM (C64/C128) disk drive I/O routines.

%import textio
%import conv
%import string
%import syslib

diskio {
%option no_symbol_prefixing, ignore_unused
%option merge, no_symbol_prefixing, ignore_unused

const ubyte READ_IO_CHANNEL=12
const ubyte WRITE_IO_CHANNEL=13
Expand Down
Loading

0 comments on commit c736fa3

Please sign in to comment.