mirror of
https://github.com/irmen/prog8.git
synced 2025-02-27 03:29:22 +00:00
Merge branch 'prefixing'
This commit is contained in:
commit
acb2ee53bb
@ -94,6 +94,9 @@ class SymbolTableMaker(private val program: PtProgram, private val options: Comp
|
||||
initialString = null
|
||||
numElements = node.arraySize?.toInt()
|
||||
}
|
||||
// if(node.type in SplitWordArrayTypes) {
|
||||
// TODO("split array also add _lsb and _msb to symboltable")
|
||||
// }
|
||||
StStaticVariable(node.name, node.type, initialNumeric, initialString, initialArray, numElements, node.zeropage, node)
|
||||
}
|
||||
is PtBuiltinFunctionCall -> {
|
||||
|
@ -37,16 +37,17 @@ class PtNodeGroup : PtNode(Position.DUMMY)
|
||||
sealed class PtNamedNode(var name: String, position: Position): PtNode(position) {
|
||||
// Note that as an exception, the 'name' is not read-only
|
||||
// but a var. This is to allow for cheap node renames.
|
||||
val scopedName: String by lazy {
|
||||
var namedParent: PtNode = this.parent
|
||||
if(namedParent is PtProgram)
|
||||
name
|
||||
else {
|
||||
while (namedParent !is PtNamedNode)
|
||||
namedParent = namedParent.parent
|
||||
namedParent.scopedName + "." + name
|
||||
val scopedName: String
|
||||
get() {
|
||||
var namedParent: PtNode = this.parent
|
||||
return if(namedParent is PtProgram)
|
||||
name
|
||||
else {
|
||||
while (namedParent !is PtNamedNode)
|
||||
namedParent = namedParent.parent
|
||||
namedParent.scopedName + "." + name
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -63,7 +64,9 @@ class PtProgram(
|
||||
children.asSequence().filterIsInstance<PtBlock>()
|
||||
|
||||
fun entrypoint(): PtSub? =
|
||||
allBlocks().firstOrNull { it.name == "main" }?.children?.firstOrNull { it is PtSub && (it.name == "start" || it.name=="main.start") } as PtSub?
|
||||
allBlocks().firstOrNull { it.name == "main" || it.name=="p8_main" }
|
||||
?.children
|
||||
?.firstOrNull { it is PtSub && (it.name == "start" || it.name=="main.start" || it.name=="p8_start" || it.name=="p8_main.p8_start") } as PtSub?
|
||||
}
|
||||
|
||||
|
||||
@ -71,6 +74,7 @@ class PtBlock(name: String,
|
||||
val address: UInt?,
|
||||
val library: Boolean,
|
||||
val forceOutput: Boolean,
|
||||
val noSymbolPrefixing: Boolean,
|
||||
val alignment: BlockAlignment,
|
||||
val source: SourceCode, // taken from the module the block is defined in.
|
||||
position: Position
|
||||
|
@ -20,7 +20,6 @@ class CompilationOptions(val output: OutputType,
|
||||
var asmListfile: Boolean = false,
|
||||
var experimentalCodegen: Boolean = false,
|
||||
var varsHighBank: Int? = null,
|
||||
var useNewExprCode: Boolean = false,
|
||||
var splitWordArrays: Boolean = false,
|
||||
var evalStackBaseAddress: UInt? = null,
|
||||
var outputDir: Path = Path(""),
|
||||
|
@ -3,6 +3,7 @@ package prog8.codegen.cpu6502
|
||||
import com.github.michaelbull.result.fold
|
||||
import prog8.code.StNodeType
|
||||
import prog8.code.SymbolTable
|
||||
import prog8.code.SymbolTableMaker
|
||||
import prog8.code.ast.*
|
||||
import prog8.code.core.*
|
||||
import prog8.codegen.cpu6502.assignment.*
|
||||
@ -14,18 +15,180 @@ import kotlin.io.path.writeLines
|
||||
internal const val subroutineFloatEvalResultVar1 = "prog8_float_eval_result1"
|
||||
internal const val subroutineFloatEvalResultVar2 = "prog8_float_eval_result2"
|
||||
|
||||
class AsmGen6502: ICodeGeneratorBackend {
|
||||
class AsmGen6502(val prefixSymbols: Boolean): ICodeGeneratorBackend {
|
||||
override fun generate(
|
||||
program: PtProgram,
|
||||
symbolTable: SymbolTable,
|
||||
options: CompilationOptions,
|
||||
errors: IErrorReporter
|
||||
): IAssemblyProgram? {
|
||||
val asmgen = AsmGen6502Internal(program, symbolTable, options, errors)
|
||||
val st = if(prefixSymbols) prefixSymbols(program, options, symbolTable) else symbolTable
|
||||
val asmgen = AsmGen6502Internal(program, st, options, errors)
|
||||
return asmgen.compileToAssembly()
|
||||
}
|
||||
|
||||
private fun prefixSymbols(program: PtProgram, options: CompilationOptions, st: SymbolTable): SymbolTable {
|
||||
val nodesToPrefix = mutableListOf<Pair<PtNode, Int>>() // parent + index
|
||||
val functionCallsToPrefix = mutableListOf<Pair<PtNode, Int>>() // parent + index
|
||||
|
||||
fun prefixNamedNode(node: PtNamedNode) {
|
||||
node.name = "p8_${node.name}"
|
||||
}
|
||||
|
||||
fun prefixSymbols(node: PtNode) {
|
||||
when(node) {
|
||||
is PtAsmSub -> {
|
||||
prefixNamedNode(node)
|
||||
node.parameters.forEach { (_, param) -> prefixNamedNode(param) }
|
||||
}
|
||||
is PtSub -> {
|
||||
prefixNamedNode(node)
|
||||
node.parameters.forEach { prefixNamedNode(it) }
|
||||
}
|
||||
is PtFunctionCall -> {
|
||||
val stNode = st.lookup(node.name)!!
|
||||
if(stNode.astNode.definingBlock()?.noSymbolPrefixing!=true) {
|
||||
val index = node.parent.children.indexOf(node)
|
||||
functionCallsToPrefix += node.parent to index
|
||||
}
|
||||
}
|
||||
is PtIdentifier -> {
|
||||
var lookupName = node.name
|
||||
if(node.type in SplitWordArrayTypes && (lookupName.endsWith("_lsb") || lookupName.endsWith("_msb"))) {
|
||||
lookupName = lookupName.dropLast(4)
|
||||
}
|
||||
val stNode = st.lookup(lookupName)!!
|
||||
if(stNode.astNode.definingBlock()?.noSymbolPrefixing!=true) {
|
||||
val index = node.parent.children.indexOf(node)
|
||||
nodesToPrefix += node.parent to index
|
||||
}
|
||||
}
|
||||
is PtJump -> {
|
||||
if(node.identifier!=null) {
|
||||
val stNode = st.lookup(node.identifier!!.name)!!
|
||||
if(stNode.astNode.definingBlock()?.noSymbolPrefixing!=true) {
|
||||
val index = node.parent.children.indexOf(node)
|
||||
nodesToPrefix += node.parent to index
|
||||
}
|
||||
}
|
||||
else if(node.generatedLabel!=null) {
|
||||
val stNode = st.lookup(node.generatedLabel!!)!!
|
||||
if(stNode.astNode.definingBlock()?.noSymbolPrefixing!=true) {
|
||||
val index = node.parent.children.indexOf(node)
|
||||
nodesToPrefix += node.parent to index
|
||||
}
|
||||
}
|
||||
}
|
||||
is PtBlock -> prefixNamedNode(node)
|
||||
is PtConstant -> prefixNamedNode(node)
|
||||
is PtLabel -> prefixNamedNode(node)
|
||||
is PtMemMapped -> prefixNamedNode(node)
|
||||
is PtSubroutineParameter -> prefixNamedNode(node)
|
||||
is PtVariable -> {
|
||||
val index = node.parent.children.indexOf(node)
|
||||
nodesToPrefix += node.parent to index
|
||||
}
|
||||
else -> { }
|
||||
}
|
||||
node.children.forEach { prefixSymbols(it) }
|
||||
}
|
||||
|
||||
program.allBlocks().forEach { block ->
|
||||
if (!block.noSymbolPrefixing) {
|
||||
prefixSymbols(block)
|
||||
}
|
||||
}
|
||||
|
||||
nodesToPrefix.forEach { (parent, index) ->
|
||||
val node = parent.children[index]
|
||||
when(node) {
|
||||
is PtIdentifier -> parent.children[index] = node.prefix(parent, st)
|
||||
is PtFunctionCall -> throw AssemblyError("PtFunctionCall should be processed in their own list, last")
|
||||
is PtJump -> parent.children[index] = node.prefix(parent, st)
|
||||
is PtVariable -> parent.children[index] = node.prefix(st)
|
||||
else -> throw AssemblyError("weird node to prefix $node")
|
||||
}
|
||||
}
|
||||
|
||||
// reversed so inner calls (such as arguments to a function call) get processed before the actual function call itself
|
||||
functionCallsToPrefix.reversed().forEach { (parent, index) ->
|
||||
val node = parent.children[index]
|
||||
if(node is PtFunctionCall) {
|
||||
parent.children[index] = node.prefix(parent)
|
||||
} else {
|
||||
throw AssemblyError("expected PtFunctionCall")
|
||||
}
|
||||
}
|
||||
|
||||
return SymbolTableMaker(program, options).make()
|
||||
}
|
||||
}
|
||||
|
||||
private fun PtVariable.prefix(st: SymbolTable): PtVariable {
|
||||
name = name.split('.').map {"p8_$it" }.joinToString(".")
|
||||
if(value==null)
|
||||
return this
|
||||
|
||||
val arrayValue = value as? PtArray
|
||||
return if(arrayValue!=null && arrayValue.children.any { it !is PtNumber} ) {
|
||||
val newValue = PtArray(arrayValue.type, arrayValue.position)
|
||||
arrayValue.children.forEach { elt ->
|
||||
when(elt) {
|
||||
is PtIdentifier -> newValue.add(elt.prefix(arrayValue, st))
|
||||
is PtNumber -> newValue.add(elt)
|
||||
is PtAddressOf -> {
|
||||
if(elt.definingBlock()?.noSymbolPrefixing==true)
|
||||
newValue.add(elt)
|
||||
else {
|
||||
val newAddr = PtAddressOf(elt.position)
|
||||
newAddr.children.add(elt.identifier.prefix(newAddr, st))
|
||||
newAddr.parent = arrayValue
|
||||
newValue.add(newAddr)
|
||||
}
|
||||
}
|
||||
else -> throw AssemblyError("weird array value element $elt")
|
||||
}
|
||||
}
|
||||
PtVariable(name, type, zeropage, newValue, arraySize, position)
|
||||
}
|
||||
else this
|
||||
}
|
||||
|
||||
private fun PtJump.prefix(parent: PtNode, st: SymbolTable): PtJump {
|
||||
val jump = if(identifier!=null) {
|
||||
val prefixedIdent = identifier!!.prefix(this, st)
|
||||
PtJump(prefixedIdent, address, generatedLabel, position)
|
||||
} else {
|
||||
val prefixedLabel = generatedLabel!!.split('.').map {"p8_$it" }.joinToString(".")
|
||||
PtJump(null, address, prefixedLabel, position)
|
||||
}
|
||||
jump.parent = parent
|
||||
return jump
|
||||
}
|
||||
|
||||
private fun PtFunctionCall.prefix(parent: PtNode): PtFunctionCall {
|
||||
val newName = name.split('.').map {"p8_$it" }.joinToString(".")
|
||||
val call = PtFunctionCall(newName, void, type, position)
|
||||
call.children.addAll(children)
|
||||
call.children.forEach { it.parent = call }
|
||||
call.parent = parent
|
||||
if(name.endsWith("concat_string"))
|
||||
println("CONCAT ${this.position}")
|
||||
return call
|
||||
}
|
||||
|
||||
private fun PtIdentifier.prefix(parent: PtNode, st: SymbolTable): PtIdentifier {
|
||||
val target = st.lookup(name)
|
||||
if(target?.astNode?.definingBlock()?.noSymbolPrefixing==true)
|
||||
return this
|
||||
|
||||
val newName = name.split('.').map { "p8_$it" }.joinToString(".")
|
||||
val node = PtIdentifier(newName, type, position)
|
||||
node.parent = parent
|
||||
return node
|
||||
}
|
||||
|
||||
|
||||
class AsmGen6502Internal (
|
||||
val program: PtProgram,
|
||||
internal val symbolTable: SymbolTable,
|
||||
@ -513,7 +676,6 @@ class AsmGen6502Internal (
|
||||
private fun translate(stmt: PtIfElse) {
|
||||
val condition = stmt.condition as? PtBinaryExpression
|
||||
if(condition!=null) {
|
||||
require(!options.useNewExprCode)
|
||||
requireComparisonExpression(condition) // IfStatement: condition must be of form 'x <comparison> <value>'
|
||||
if (stmt.elseScope.children.isEmpty()) {
|
||||
val jump = stmt.ifScope.children.singleOrNull()
|
||||
@ -973,18 +1135,10 @@ $repeatLabel""")
|
||||
}
|
||||
|
||||
internal fun pointerViaIndexRegisterPossible(pointerOffsetExpr: PtExpression): Pair<PtExpression, PtExpression>? {
|
||||
val left: PtExpression
|
||||
val right: PtExpression
|
||||
val operator: String
|
||||
|
||||
if (pointerOffsetExpr is PtBinaryExpression) {
|
||||
require(!options.useNewExprCode)
|
||||
operator = pointerOffsetExpr.operator
|
||||
left = pointerOffsetExpr.left
|
||||
right = pointerOffsetExpr.right
|
||||
}
|
||||
else return null
|
||||
|
||||
if (pointerOffsetExpr !is PtBinaryExpression) return null
|
||||
val operator = pointerOffsetExpr.operator
|
||||
val left = pointerOffsetExpr.left
|
||||
val right = pointerOffsetExpr.right
|
||||
if (operator != "+") return null
|
||||
val leftDt = left.type
|
||||
val rightDt = right.type
|
||||
@ -1096,10 +1250,7 @@ $repeatLabel""")
|
||||
}
|
||||
|
||||
internal fun findSubroutineParameter(name: String, asmgen: AsmGen6502Internal): PtSubroutineParameter? {
|
||||
val stScope = asmgen.symbolTable.lookup(name)
|
||||
require(stScope!=null) {
|
||||
"invalid name lookup $name"
|
||||
}
|
||||
val stScope = asmgen.symbolTable.lookup(name) ?: return null
|
||||
val node = stScope.astNode
|
||||
if(node is PtSubroutineParameter)
|
||||
return node
|
||||
@ -2747,7 +2898,6 @@ $repeatLabel""")
|
||||
out(" sta P8ESTACK_LO,x | dex")
|
||||
}
|
||||
is PtBinaryExpression -> {
|
||||
require(!options.useNewExprCode)
|
||||
val addrExpr = expr.address as PtBinaryExpression
|
||||
if(tryOptimizedPointerAccessWithA(addrExpr, addrExpr.operator, false)) {
|
||||
if(pushResultOnEstack)
|
||||
|
@ -751,7 +751,6 @@ internal class BuiltinFunctionsAsmGen(private val program: PtProgram,
|
||||
}
|
||||
}
|
||||
is PtBinaryExpression -> {
|
||||
require(!asmgen.options.useNewExprCode)
|
||||
val result = asmgen.pointerViaIndexRegisterPossible(addrExpr)
|
||||
val pointer = result?.first as? PtIdentifier
|
||||
if(result!=null && pointer!=null && asmgen.isZpVar(pointer)) {
|
||||
@ -813,7 +812,6 @@ internal class BuiltinFunctionsAsmGen(private val program: PtProgram,
|
||||
} else fallback()
|
||||
}
|
||||
is PtBinaryExpression -> {
|
||||
require(!asmgen.options.useNewExprCode)
|
||||
val result = asmgen.pointerViaIndexRegisterPossible(addrExpr)
|
||||
val pointer = result?.first as? PtIdentifier
|
||||
if(result!=null && pointer!=null && asmgen.isZpVar(pointer)) {
|
||||
|
@ -248,8 +248,6 @@ internal class ExpressionsAsmGen(private val program: PtProgram,
|
||||
}
|
||||
|
||||
private fun translateExpression(expr: PtBinaryExpression) {
|
||||
require(!asmgen.options.useNewExprCode)
|
||||
|
||||
// Uses evalstack to evaluate the given expression. THIS IS SLOW AND SHOULD BE AVOIDED!
|
||||
if(translateSomewhatOptimized(expr.left, expr.operator, expr.right))
|
||||
return
|
||||
|
@ -33,8 +33,9 @@ internal class ProgramAndVarsGen(
|
||||
internal fun generate() {
|
||||
header()
|
||||
val allBlocks = program.allBlocks()
|
||||
if(allBlocks.first().name != "main")
|
||||
throw AssemblyError("first block should be 'main'")
|
||||
|
||||
if(allBlocks.first().name != "p8_main" && allBlocks.first().name != "main")
|
||||
throw AssemblyError("first block should be 'main' or 'p8_main'")
|
||||
|
||||
if(errors.noErrors()) {
|
||||
program.allBlocks().forEach { block2asm(it) }
|
||||
@ -139,24 +140,24 @@ internal class ProgramAndVarsGen(
|
||||
"cx16" -> {
|
||||
if(options.floats)
|
||||
asmgen.out(" lda #4 | sta $01") // to use floats, make sure Basic rom is banked in
|
||||
asmgen.out(" jsr main.start")
|
||||
asmgen.out(" jsr p8_main.p8_start")
|
||||
asmgen.out(" jmp sys.cleanup_at_exit")
|
||||
}
|
||||
"c64" -> {
|
||||
asmgen.out(" jsr main.start | lda #31 | sta $01")
|
||||
asmgen.out(" jsr p8_main.p8_start | lda #31 | sta $01")
|
||||
if(!options.noSysInit)
|
||||
asmgen.out(" jmp sys.cleanup_at_exit")
|
||||
else
|
||||
asmgen.out(" rts")
|
||||
}
|
||||
"c128" -> {
|
||||
asmgen.out(" jsr main.start | lda #0 | sta ${"$"}ff00")
|
||||
asmgen.out(" jsr p8_main.p8_start | lda #0 | sta ${"$"}ff00")
|
||||
if(!options.noSysInit)
|
||||
asmgen.out(" jmp sys.cleanup_at_exit")
|
||||
else
|
||||
asmgen.out(" rts")
|
||||
}
|
||||
else -> asmgen.jmp("main.start")
|
||||
else -> asmgen.jmp("p8_main.p8_start")
|
||||
}
|
||||
}
|
||||
|
||||
@ -312,7 +313,9 @@ internal class ProgramAndVarsGen(
|
||||
|
||||
asmgen.out("${sub.name}\t$asmStartScope")
|
||||
|
||||
val scope = symboltable.lookupOrElse(sub.scopedName) { throw AssemblyError("lookup") }
|
||||
val scope = symboltable.lookupOrElse(sub.scopedName) {
|
||||
throw AssemblyError("lookup ${sub.scopedName}")
|
||||
}
|
||||
require(scope.type==StNodeType.SUBROUTINE)
|
||||
val varsInSubroutine = getVars(scope)
|
||||
|
||||
@ -332,7 +335,7 @@ internal class ProgramAndVarsGen(
|
||||
asmsubs2asm(sub.children)
|
||||
|
||||
// the main.start subroutine is the program's entrypoint and should perform some initialization logic
|
||||
if(sub.name=="start" && sub.definingBlock()!!.name=="main")
|
||||
if((sub.name=="start" || sub.name=="p8_start") && (sub.definingBlock()!!.name=="main" || sub.definingBlock()!!.name=="p8_main"))
|
||||
entrypointInitialization()
|
||||
|
||||
if(functioncallAsmGen.optimizeIntArgsViaRegisters(sub)) {
|
||||
|
@ -179,6 +179,8 @@ internal class AsmAssignSource(val kind: SourceStorageKind,
|
||||
}
|
||||
is PtFunctionCall -> {
|
||||
val symbol = asmgen.symbolTable.lookup(value.name)
|
||||
if(symbol==null)
|
||||
TODO("${value.name}")
|
||||
val sub = symbol!!.astNode as IPtSubroutine
|
||||
val returnType = sub.returnsWhatWhere().firstOrNull { rr -> rr.first.registerOrPair != null || rr.first.statusflag!=null }?.second
|
||||
?: throw AssemblyError("can't translate zero return values in assignment")
|
||||
|
@ -158,7 +158,6 @@ internal class AssignmentAsmGen(private val program: PtProgram,
|
||||
assignMemoryByte(assign.target, null, value.address as PtIdentifier)
|
||||
}
|
||||
is PtBinaryExpression -> {
|
||||
require(!asmgen.options.useNewExprCode)
|
||||
val addrExpr = value.address as PtBinaryExpression
|
||||
if(asmgen.tryOptimizedPointerAccessWithA(addrExpr, addrExpr.operator, false)) {
|
||||
assignRegisterByte(assign.target, CpuRegister.A, false)
|
||||
@ -313,7 +312,6 @@ internal class AssignmentAsmGen(private val program: PtProgram,
|
||||
assignRegisterByte(assign.target, CpuRegister.A, false)
|
||||
}
|
||||
is PtBinaryExpression -> {
|
||||
require(!asmgen.options.useNewExprCode)
|
||||
if(!attemptAssignOptimizedBinexpr(value, assign)) {
|
||||
// All remaining binary expressions just evaluate via the stack for now.
|
||||
// (we can't use the assignment helper functions (assignExpressionTo...) to do it via registers here,
|
||||
@ -359,7 +357,6 @@ internal class AssignmentAsmGen(private val program: PtProgram,
|
||||
}
|
||||
|
||||
private fun attemptAssignOptimizedBinexpr(expr: PtBinaryExpression, assign: AsmAssignment): Boolean {
|
||||
require(!asmgen.options.useNewExprCode)
|
||||
if(expr.operator in ComparisonOperators) {
|
||||
if(expr.right.asConstInteger() == 0) {
|
||||
if(expr.operator == "==" || expr.operator=="!=") {
|
||||
@ -1155,7 +1152,6 @@ internal class AssignmentAsmGen(private val program: PtProgram,
|
||||
}
|
||||
|
||||
private fun attemptAssignToByteCompareZero(expr: PtBinaryExpression, assign: AsmAssignment): Boolean {
|
||||
require(!asmgen.options.useNewExprCode)
|
||||
when (expr.operator) {
|
||||
"==" -> {
|
||||
when(val dt = expr.left.type) {
|
||||
@ -1335,7 +1331,6 @@ internal class AssignmentAsmGen(private val program: PtProgram,
|
||||
assignMemoryByteIntoWord(target, null, value.address as PtIdentifier)
|
||||
}
|
||||
is PtBinaryExpression -> {
|
||||
require(!asmgen.options.useNewExprCode)
|
||||
val addrExpr = value.address as PtBinaryExpression
|
||||
if(asmgen.tryOptimizedPointerAccessWithA(addrExpr, addrExpr.operator, false)) {
|
||||
asmgen.out(" ldy #0")
|
||||
@ -3487,7 +3482,6 @@ internal class AssignmentAsmGen(private val program: PtProgram,
|
||||
asmgen.storeAIntoPointerVar(addressExpr)
|
||||
}
|
||||
addressExpr is PtBinaryExpression -> {
|
||||
require(!asmgen.options.useNewExprCode)
|
||||
if(!asmgen.tryOptimizedPointerAccessWithA(addressExpr, addressExpr.operator, true))
|
||||
storeViaExprEval()
|
||||
}
|
||||
|
@ -40,9 +40,9 @@ class TestCodegen: FunSpec({
|
||||
// xx += cx16.r0
|
||||
// }
|
||||
//}
|
||||
val codegen = AsmGen6502()
|
||||
val codegen = AsmGen6502(prefixSymbols = false)
|
||||
val program = PtProgram("test", DummyMemsizer, DummyStringEncoder)
|
||||
val block = PtBlock("main", null, false, false, PtBlock.BlockAlignment.NONE, SourceCode.Generated("test"), Position.DUMMY)
|
||||
val block = PtBlock("main", null, false, false, false, PtBlock.BlockAlignment.NONE, SourceCode.Generated("test"), Position.DUMMY)
|
||||
val sub = PtSub("start", emptyList(), null, Position.DUMMY)
|
||||
sub.add(PtVariable("pi", DataType.UBYTE, ZeropageWish.DONTCARE, PtNumber(DataType.UBYTE, 0.0, Position.DUMMY), null, Position.DUMMY))
|
||||
sub.add(PtVariable("particleX", DataType.ARRAY_UB, ZeropageWish.DONTCARE, null, 3u, Position.DUMMY))
|
||||
@ -92,7 +92,7 @@ class TestCodegen: FunSpec({
|
||||
program.add(block)
|
||||
|
||||
// define the "cx16.r0" virtual register
|
||||
val cx16block = PtBlock("cx16", null, false, false, PtBlock.BlockAlignment.NONE, SourceCode.Generated("test"), Position.DUMMY)
|
||||
val cx16block = PtBlock("cx16", null, false, false, false, PtBlock.BlockAlignment.NONE, SourceCode.Generated("test"), Position.DUMMY)
|
||||
cx16block.add(PtMemMapped("r0", DataType.UWORD, 100u, null, Position.DUMMY))
|
||||
program.add(cx16block)
|
||||
|
||||
|
@ -105,27 +105,10 @@ internal class AssignmentGen(private val codeGen: IRCodeGen, private val express
|
||||
value.add(origAssign.value)
|
||||
} else {
|
||||
require(origAssign.operator.endsWith('='))
|
||||
if(codeGen.options.useNewExprCode) {
|
||||
// X += Y -> temp = X, temp += Y, X = temp
|
||||
val tempvar = codeGen.getReusableTempvar(origAssign.definingSub()!!, origAssign.target.type)
|
||||
val assign = PtAssignment(origAssign.position)
|
||||
val target = PtAssignTarget(origAssign.position)
|
||||
target.add(tempvar)
|
||||
assign.add(target)
|
||||
assign.add(origAssign.target.children.single())
|
||||
val augAssign = PtAugmentedAssign(origAssign.operator, origAssign.position)
|
||||
augAssign.add(target)
|
||||
augAssign.add(origAssign.value)
|
||||
val assignBack = PtAssignment(origAssign.position)
|
||||
assignBack.add(origAssign.target)
|
||||
assignBack.add(tempvar)
|
||||
return translateRegularAssign(assign) + translate(augAssign) + translateRegularAssign(assignBack)
|
||||
} else {
|
||||
value = PtBinaryExpression(origAssign.operator.dropLast(1), origAssign.value.type, origAssign.value.position)
|
||||
val left: PtExpression = origAssign.target.children.single() as PtExpression
|
||||
value.add(left)
|
||||
value.add(origAssign.value)
|
||||
}
|
||||
value = PtBinaryExpression(origAssign.operator.dropLast(1), origAssign.value.type, origAssign.value.position)
|
||||
val left: PtExpression = origAssign.target.children.single() as PtExpression
|
||||
value.add(left)
|
||||
value.add(origAssign.value)
|
||||
}
|
||||
val normalAssign = PtAssignment(origAssign.position)
|
||||
normalAssign.add(origAssign.target)
|
||||
@ -347,19 +330,12 @@ internal class AssignmentGen(private val codeGen: IRCodeGen, private val express
|
||||
return Pair(result, tr.resultReg)
|
||||
}
|
||||
|
||||
if(codeGen.options.useNewExprCode) {
|
||||
val tr = expressionEval.translateExpression(array.index)
|
||||
result += tr.chunks
|
||||
addInstr(result, IRInstruction(Opcode.MUL, tr.dt, reg1=tr.resultReg, immediate = itemsize), null)
|
||||
return Pair(result, tr.resultReg)
|
||||
} else {
|
||||
val mult: PtExpression
|
||||
mult = PtBinaryExpression("*", DataType.UBYTE, array.position)
|
||||
mult.children += array.index
|
||||
mult.children += PtNumber(DataType.UBYTE, itemsize.toDouble(), array.position)
|
||||
val tr = expressionEval.translateExpression(mult)
|
||||
addToResult(result, tr, tr.resultReg, -1)
|
||||
return Pair(result, tr.resultReg)
|
||||
}
|
||||
val mult: PtExpression
|
||||
mult = PtBinaryExpression("*", DataType.UBYTE, array.position)
|
||||
mult.children += array.index
|
||||
mult.children += PtNumber(DataType.UBYTE, itemsize.toDouble(), array.position)
|
||||
val tr = expressionEval.translateExpression(mult)
|
||||
addToResult(result, tr, tr.resultReg, -1)
|
||||
return Pair(result, tr.resultReg)
|
||||
}
|
||||
}
|
@ -340,7 +340,6 @@ internal class ExpressionGen(private val codeGen: IRCodeGen) {
|
||||
}
|
||||
|
||||
private fun translate(binExpr: PtBinaryExpression): ExpressionCodeResult {
|
||||
require(!codeGen.options.useNewExprCode)
|
||||
val vmDt = irType(binExpr.left.type)
|
||||
val signed = binExpr.left.type in SignedDatatypes
|
||||
return when(binExpr.operator) {
|
||||
|
@ -905,7 +905,6 @@ class IRCodeGen(
|
||||
val goto = ifElse.ifScope.children.firstOrNull() as? PtJump
|
||||
when (condition) {
|
||||
is PtBinaryExpression -> {
|
||||
require(!options.useNewExprCode)
|
||||
if(condition.operator !in ComparisonOperators)
|
||||
throw AssemblyError("if condition should only be a binary comparison expression")
|
||||
|
||||
@ -919,7 +918,6 @@ class IRCodeGen(
|
||||
}
|
||||
else -> {
|
||||
// if X --> meaning: if X!=0
|
||||
require(options.useNewExprCode)
|
||||
val irDt = irType(condition.type)
|
||||
val signed = condition.type in SignedDatatypes
|
||||
return if(goto!=null && ifElse.elseScope.children.isEmpty()) {
|
||||
|
@ -135,7 +135,8 @@ class IRUnusedCodeRemover(
|
||||
}
|
||||
|
||||
private fun removeUnreachable(allLabeledChunks: MutableMap<String, IRCodeChunkBase>): Int {
|
||||
val entrypointSub = irprog.blocks.single { it.label=="main" }.children.single { it is IRSubroutine && it.label=="main.start" }
|
||||
val entrypointSub = irprog.blocks.single { it.label=="main" }
|
||||
.children.single { it is IRSubroutine && it.label=="main.start" }
|
||||
val reachable = mutableSetOf((entrypointSub as IRSubroutine).chunks.first())
|
||||
|
||||
fun grow() {
|
||||
|
@ -41,7 +41,7 @@ class TestVmCodeGen: FunSpec({
|
||||
//}
|
||||
val codegen = VmCodeGen()
|
||||
val program = PtProgram("test", DummyMemsizer, DummyStringEncoder)
|
||||
val block = PtBlock("main", null, false, false, PtBlock.BlockAlignment.NONE, SourceCode.Generated("test"), Position.DUMMY)
|
||||
val block = PtBlock("main", null, false, false, false, PtBlock.BlockAlignment.NONE, SourceCode.Generated("test"), Position.DUMMY)
|
||||
val sub = PtSub("start", emptyList(), null, Position.DUMMY)
|
||||
sub.add(PtVariable("pi", DataType.UBYTE, ZeropageWish.DONTCARE, PtNumber(DataType.UBYTE, 0.0, Position.DUMMY), null, Position.DUMMY))
|
||||
sub.add(PtVariable("particleX", DataType.ARRAY_UB, ZeropageWish.DONTCARE, null, 3u, Position.DUMMY))
|
||||
@ -91,7 +91,7 @@ class TestVmCodeGen: FunSpec({
|
||||
program.add(block)
|
||||
|
||||
// define the "cx16.r0" virtual register
|
||||
val cx16block = PtBlock("cx16", null, false, false, PtBlock.BlockAlignment.NONE, SourceCode.Generated("test"), Position.DUMMY)
|
||||
val cx16block = PtBlock("cx16", null, false, false, false, PtBlock.BlockAlignment.NONE, SourceCode.Generated("test"), Position.DUMMY)
|
||||
cx16block.add(PtMemMapped("r0", DataType.UWORD, 100u, null, Position.DUMMY))
|
||||
program.add(cx16block)
|
||||
|
||||
@ -120,7 +120,7 @@ class TestVmCodeGen: FunSpec({
|
||||
//}
|
||||
val codegen = VmCodeGen()
|
||||
val program = PtProgram("test", DummyMemsizer, DummyStringEncoder)
|
||||
val block = PtBlock("main", null, false, false, PtBlock.BlockAlignment.NONE, SourceCode.Generated("test"), Position.DUMMY)
|
||||
val block = PtBlock("main", null, false, false, false, PtBlock.BlockAlignment.NONE, SourceCode.Generated("test"), Position.DUMMY)
|
||||
val sub = PtSub("start", emptyList(), null, Position.DUMMY)
|
||||
sub.add(PtVariable("f1", DataType.FLOAT, ZeropageWish.DONTCARE, null, null, Position.DUMMY))
|
||||
val if1 = PtIfElse(Position.DUMMY)
|
||||
@ -183,7 +183,7 @@ class TestVmCodeGen: FunSpec({
|
||||
//}
|
||||
val codegen = VmCodeGen()
|
||||
val program = PtProgram("test", DummyMemsizer, DummyStringEncoder)
|
||||
val block = PtBlock("main", null, false, false, PtBlock.BlockAlignment.NONE, SourceCode.Generated("test"), Position.DUMMY)
|
||||
val block = PtBlock("main", null, false, false, false, PtBlock.BlockAlignment.NONE, SourceCode.Generated("test"), Position.DUMMY)
|
||||
val sub = PtSub("start", emptyList(), null, Position.DUMMY)
|
||||
sub.add(PtVariable("f1", DataType.FLOAT, ZeropageWish.DONTCARE, null, null, Position.DUMMY))
|
||||
val if1 = PtIfElse(Position.DUMMY)
|
||||
@ -242,7 +242,7 @@ class TestVmCodeGen: FunSpec({
|
||||
//}
|
||||
val codegen = VmCodeGen()
|
||||
val program = PtProgram("test", DummyMemsizer, DummyStringEncoder)
|
||||
val block = PtBlock("main", null, false, false, PtBlock.BlockAlignment.NONE, SourceCode.Generated("test"), Position.DUMMY)
|
||||
val block = PtBlock("main", null, false, false, false, PtBlock.BlockAlignment.NONE, SourceCode.Generated("test"), Position.DUMMY)
|
||||
val sub = PtSub("start", emptyList(), null, Position.DUMMY)
|
||||
sub.add(PtVariable("f1", DataType.FLOAT, ZeropageWish.DONTCARE, null, null, Position.DUMMY))
|
||||
val if1 = PtIfElse(Position.DUMMY)
|
||||
@ -289,7 +289,7 @@ class TestVmCodeGen: FunSpec({
|
||||
//}
|
||||
val codegen = VmCodeGen()
|
||||
val program = PtProgram("test", DummyMemsizer, DummyStringEncoder)
|
||||
val block = PtBlock("main", null, false, false, PtBlock.BlockAlignment.NONE, SourceCode.Generated("test"), Position.DUMMY)
|
||||
val block = PtBlock("main", null, false, false, false, PtBlock.BlockAlignment.NONE, SourceCode.Generated("test"), Position.DUMMY)
|
||||
val sub = PtSub("start", emptyList(), null, Position.DUMMY)
|
||||
sub.add(PtVariable("sb1", DataType.BYTE, ZeropageWish.DONTCARE, null, null, Position.DUMMY))
|
||||
val if1 = PtIfElse(Position.DUMMY)
|
||||
@ -352,7 +352,7 @@ class TestVmCodeGen: FunSpec({
|
||||
//}
|
||||
val codegen = VmCodeGen()
|
||||
val program = PtProgram("test", DummyMemsizer, DummyStringEncoder)
|
||||
val block = PtBlock("main", null, false, false, PtBlock.BlockAlignment.NONE, SourceCode.Generated("test"), Position.DUMMY)
|
||||
val block = PtBlock("main", null, false, false, false, PtBlock.BlockAlignment.NONE, SourceCode.Generated("test"), Position.DUMMY)
|
||||
val sub = PtSub("start", emptyList(), null, Position.DUMMY)
|
||||
sub.add(PtVariable("sb1", DataType.BYTE, ZeropageWish.DONTCARE, null, null, Position.DUMMY))
|
||||
val if1 = PtIfElse(Position.DUMMY)
|
||||
@ -411,7 +411,7 @@ class TestVmCodeGen: FunSpec({
|
||||
//}
|
||||
val codegen = VmCodeGen()
|
||||
val program = PtProgram("test", DummyMemsizer, DummyStringEncoder)
|
||||
val block = PtBlock("main", null, false, false, PtBlock.BlockAlignment.NONE, SourceCode.Generated("test"), Position.DUMMY)
|
||||
val block = PtBlock("main", null, false, false, false, PtBlock.BlockAlignment.NONE, SourceCode.Generated("test"), Position.DUMMY)
|
||||
val sub = PtSub("start", emptyList(), null, Position.DUMMY)
|
||||
sub.add(PtVariable("ub1", DataType.UBYTE, ZeropageWish.DONTCARE, null, null, Position.DUMMY))
|
||||
val if1 = PtIfElse(Position.DUMMY)
|
||||
@ -451,7 +451,7 @@ class TestVmCodeGen: FunSpec({
|
||||
//}
|
||||
val codegen = VmCodeGen()
|
||||
val program = PtProgram("test", DummyMemsizer, DummyStringEncoder)
|
||||
val block = PtBlock("main", null, false, false, PtBlock.BlockAlignment.NONE, SourceCode.Generated("test"), Position.DUMMY)
|
||||
val block = PtBlock("main", null, false, false, false, PtBlock.BlockAlignment.NONE, SourceCode.Generated("test"), Position.DUMMY)
|
||||
val romsub = PtAsmSub("routine", 0x5000u, setOf(CpuRegister.Y), emptyList(), emptyList(), false, Position.DUMMY)
|
||||
block.add(romsub)
|
||||
val sub = PtSub("start", emptyList(), null, Position.DUMMY)
|
||||
|
@ -2,6 +2,7 @@
|
||||
; Including memory registers, I/O registers, Basic and Kernal subroutines.
|
||||
|
||||
atari {
|
||||
%option no_symbol_prefixing
|
||||
|
||||
&uword NMI_VEC = $FFFA ; 6502 nmi vector, determined by the kernal if banked in
|
||||
&uword RESET_VEC = $FFFC ; 6502 reset vector, determined by the kernal if banked in
|
||||
@ -9,10 +10,11 @@ atari {
|
||||
|
||||
}
|
||||
|
||||
|
||||
sys {
|
||||
; ------- lowlevel system routines --------
|
||||
|
||||
%option no_symbol_prefixing
|
||||
|
||||
const ubyte target = 8 ; compilation target specifier. 64 = C64, 128 = C128, 16 = CommanderX16, 8 = atari800XL
|
||||
|
||||
asmsub init_system() {
|
||||
@ -216,6 +218,7 @@ _longcopy
|
||||
}
|
||||
|
||||
cx16 {
|
||||
%option no_symbol_prefixing
|
||||
|
||||
; the sixteen virtual 16-bit registers that the CX16 has defined in the zeropage
|
||||
; they are simulated on the Atari as well but their location in memory is different
|
||||
|
@ -6,6 +6,8 @@
|
||||
|
||||
txt {
|
||||
|
||||
%option no_symbol_prefixing
|
||||
|
||||
const ubyte DEFAULT_WIDTH = 40
|
||||
const ubyte DEFAULT_HEIGHT = 24
|
||||
|
||||
|
@ -6,6 +6,8 @@
|
||||
; TODO c128 actually implement the graphics routines. Ideally a way to 'borrow' the code form the C64 version without just copy-pasting that here?
|
||||
|
||||
graphics {
|
||||
%option no_symbol_prefixing
|
||||
|
||||
const uword WIDTH = 320
|
||||
const ubyte HEIGHT = 200
|
||||
|
||||
|
@ -3,6 +3,7 @@
|
||||
|
||||
cbm {
|
||||
; Commodore (CBM) common variables, vectors and kernal routines
|
||||
%option no_symbol_prefixing
|
||||
|
||||
&ubyte TIME_HI = $a0 ; software jiffy clock, hi byte
|
||||
&ubyte TIME_MID = $a1 ; .. mid byte
|
||||
@ -140,6 +141,7 @@ asmsub RDTIM16() -> uword @AY {
|
||||
|
||||
c64 {
|
||||
; C64 I/O registers (VIC, SID, CIA)
|
||||
%option no_symbol_prefixing
|
||||
|
||||
; the default locations of the 8 sprite pointers (store address of sprite / 64)
|
||||
&ubyte SPRPTR0 = 2040
|
||||
@ -294,6 +296,7 @@ c64 {
|
||||
|
||||
c128 {
|
||||
; ---- C128 specific registers ----
|
||||
%option no_symbol_prefixing
|
||||
|
||||
&ubyte VM1 = $0A2C ; shadow for VUC $d018 in text mode
|
||||
&ubyte VM2 = $0A2D ; shadow for VIC $d018 in bitmap screen mode
|
||||
@ -330,6 +333,7 @@ asmsub disable_basic() clobbers(A) {
|
||||
|
||||
sys {
|
||||
; ------- lowlevel system routines --------
|
||||
%option no_symbol_prefixing
|
||||
|
||||
const ubyte target = 128 ; compilation target specifier. 64 = C64, 128 = C128, 16 = CommanderX16.
|
||||
|
||||
@ -765,6 +769,7 @@ _longcopy
|
||||
}
|
||||
|
||||
cx16 {
|
||||
%option no_symbol_prefixing
|
||||
|
||||
; the sixteen virtual 16-bit registers that the CX16 has defined in the zeropage
|
||||
; they are simulated on the C128 as well but their location in memory is different
|
||||
|
@ -5,6 +5,7 @@
|
||||
|
||||
|
||||
txt {
|
||||
%option no_symbol_prefixing
|
||||
|
||||
const ubyte DEFAULT_WIDTH = 40
|
||||
const ubyte DEFAULT_HEIGHT = 25
|
||||
|
@ -5,6 +5,7 @@
|
||||
|
||||
floats {
|
||||
; ---- this block contains C-64 floating point related functions ----
|
||||
%option no_symbol_prefixing
|
||||
|
||||
const float PI = 3.141592653589793
|
||||
const float TWOPI = 6.283185307179586
|
||||
|
@ -5,6 +5,8 @@
|
||||
; assumes bitmap screen memory is $2000-$3fff
|
||||
|
||||
graphics {
|
||||
%option no_symbol_prefixing
|
||||
|
||||
const uword BITMAP_ADDRESS = $2000
|
||||
const uword WIDTH = 320
|
||||
const ubyte HEIGHT = 200
|
||||
|
@ -6,6 +6,8 @@ cbm {
|
||||
|
||||
; Commodore (CBM) common variables, vectors and kernal routines
|
||||
|
||||
%option no_symbol_prefixing
|
||||
|
||||
&ubyte TIME_HI = $a0 ; software jiffy clock, hi byte
|
||||
&ubyte TIME_MID = $a1 ; .. mid byte
|
||||
&ubyte TIME_LO = $a2 ; .. lo byte. Updated by IRQ every 1/60 sec
|
||||
@ -139,6 +141,8 @@ asmsub RDTIM16() -> uword @AY {
|
||||
c64 {
|
||||
; C64 I/O registers (VIC, SID, CIA)
|
||||
|
||||
%option no_symbol_prefixing
|
||||
|
||||
; the default locations of the 8 sprite pointers (store address of sprite / 64)
|
||||
&ubyte SPRPTR0 = 2040
|
||||
&ubyte SPRPTR1 = 2041
|
||||
@ -293,6 +297,8 @@ c64 {
|
||||
sys {
|
||||
; ------- lowlevel system routines --------
|
||||
|
||||
%option no_symbol_prefixing
|
||||
|
||||
const ubyte target = 64 ; compilation target specifier. 64 = C64, 128 = C128, 16 = CommanderX16.
|
||||
|
||||
|
||||
@ -732,6 +738,8 @@ _longcopy
|
||||
|
||||
cx16 {
|
||||
|
||||
%option no_symbol_prefixing
|
||||
|
||||
; the sixteen virtual 16-bit registers that the CX16 has defined in the zeropage
|
||||
; they are simulated on the C64 as well but their location in memory is different
|
||||
; (because there's no room for them in the zeropage)
|
||||
|
@ -6,6 +6,8 @@
|
||||
|
||||
txt {
|
||||
|
||||
%option no_symbol_prefixing
|
||||
|
||||
const ubyte DEFAULT_WIDTH = 40
|
||||
const ubyte DEFAULT_HEIGHT = 25
|
||||
|
||||
|
@ -2,6 +2,8 @@
|
||||
|
||||
conv {
|
||||
|
||||
%option no_symbol_prefixing
|
||||
|
||||
; ----- number conversions to decimal strings ----
|
||||
|
||||
str @shared string_out = "????????????????" ; result buffer for the string conversion routines
|
||||
|
@ -6,6 +6,7 @@
|
||||
%import syslib
|
||||
|
||||
diskio {
|
||||
%option no_symbol_prefixing
|
||||
|
||||
ubyte drivenumber = 8
|
||||
|
||||
|
@ -6,6 +6,8 @@
|
||||
floats {
|
||||
; ---- this block contains C-64 compatible floating point related functions ----
|
||||
|
||||
%option no_symbol_prefixing
|
||||
|
||||
const float PI = 3.141592653589793
|
||||
const float TWOPI = 6.283185307179586
|
||||
|
||||
|
@ -23,6 +23,8 @@
|
||||
|
||||
gfx2 {
|
||||
|
||||
%option no_symbol_prefixing
|
||||
|
||||
; read-only control variables:
|
||||
ubyte active_mode = 0
|
||||
uword width = 0
|
||||
|
@ -10,6 +10,8 @@
|
||||
|
||||
|
||||
graphics {
|
||||
%option no_symbol_prefixing
|
||||
|
||||
const uword WIDTH = 320
|
||||
const ubyte HEIGHT = 240
|
||||
|
||||
|
@ -2,9 +2,10 @@
|
||||
; Should you want to restore the default palette, you have to reinitialize the Vera yourself.
|
||||
|
||||
palette {
|
||||
%option no_symbol_prefixing
|
||||
|
||||
uword vera_palette_ptr
|
||||
ubyte c
|
||||
ubyte cc
|
||||
|
||||
sub set_color(ubyte index, uword color) {
|
||||
vera_palette_ptr = $fa00+(index as uword * 2)
|
||||
@ -79,13 +80,13 @@ palette {
|
||||
sub set_grayscale() {
|
||||
vera_palette_ptr = $fa00
|
||||
repeat 16 {
|
||||
c=0
|
||||
cc=0
|
||||
repeat 16 {
|
||||
cx16.vpoke(1, vera_palette_ptr, c)
|
||||
cx16.vpoke(1, vera_palette_ptr, cc)
|
||||
vera_palette_ptr++
|
||||
cx16.vpoke(1, vera_palette_ptr, c)
|
||||
cx16.vpoke(1, vera_palette_ptr, cc)
|
||||
vera_palette_ptr++
|
||||
c += $11
|
||||
cc += $11
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -150,11 +151,11 @@ palette {
|
||||
sub set_c64pepto() {
|
||||
vera_palette_ptr = $fa00
|
||||
repeat 16 {
|
||||
for c in 0 to 15 {
|
||||
uword cc = C64_colorpalette_pepto[c]
|
||||
cx16.vpoke(1, vera_palette_ptr, lsb(cc)) ; G, B
|
||||
for cc in 0 to 15 {
|
||||
uword ccp = C64_colorpalette_pepto[cc]
|
||||
cx16.vpoke(1, vera_palette_ptr, lsb(ccp)) ; G, B
|
||||
vera_palette_ptr++
|
||||
cx16.vpoke(1, vera_palette_ptr, msb(cc)) ; R
|
||||
cx16.vpoke(1, vera_palette_ptr, msb(ccp)) ; R
|
||||
vera_palette_ptr++
|
||||
}
|
||||
}
|
||||
@ -163,11 +164,11 @@ palette {
|
||||
sub set_c64light() {
|
||||
vera_palette_ptr = $fa00
|
||||
repeat 16 {
|
||||
for c in 0 to 15 {
|
||||
uword cc = C64_colorpalette_light[c]
|
||||
cx16.vpoke(1, vera_palette_ptr, lsb(cc)) ; G, B
|
||||
for cc in 0 to 15 {
|
||||
uword ccp = C64_colorpalette_light[cc]
|
||||
cx16.vpoke(1, vera_palette_ptr, lsb(ccp)) ; G, B
|
||||
vera_palette_ptr++
|
||||
cx16.vpoke(1, vera_palette_ptr, msb(cc)) ; R
|
||||
cx16.vpoke(1, vera_palette_ptr, msb(ccp)) ; R
|
||||
vera_palette_ptr++
|
||||
}
|
||||
}
|
||||
@ -176,11 +177,11 @@ palette {
|
||||
sub set_c64dark() {
|
||||
vera_palette_ptr = $fa00
|
||||
repeat 16 {
|
||||
for c in 0 to 15 {
|
||||
uword cc = C64_colorpalette_dark[c]
|
||||
cx16.vpoke(1, vera_palette_ptr, lsb(cc)) ; G, B
|
||||
for cc in 0 to 15 {
|
||||
uword ccp = C64_colorpalette_dark[cc]
|
||||
cx16.vpoke(1, vera_palette_ptr, lsb(ccp)) ; G, B
|
||||
vera_palette_ptr++
|
||||
cx16.vpoke(1, vera_palette_ptr, msb(cc)) ; R
|
||||
cx16.vpoke(1, vera_palette_ptr, msb(ccp)) ; R
|
||||
vera_palette_ptr++
|
||||
}
|
||||
}
|
||||
|
@ -1,6 +1,8 @@
|
||||
%import syslib
|
||||
|
||||
psg {
|
||||
%option no_symbol_prefixing
|
||||
|
||||
; $1F9C0 - $1F9FF 16 blocks of 4 PSG registers (16 voices)
|
||||
; 00 frequency word LSB
|
||||
; 01 frequency word MSB. freqword = HERZ / 0.3725290298461914
|
||||
|
@ -5,6 +5,8 @@ cbm {
|
||||
|
||||
; Commodore (CBM) common variables, vectors and kernal routines
|
||||
|
||||
%option no_symbol_prefixing
|
||||
|
||||
; STROUT --> use txt.print
|
||||
; CLEARSCR -> use txt.clear_screen
|
||||
; HOMECRSR -> use txt.home or txt.plot
|
||||
@ -88,6 +90,8 @@ asmsub RDTIM16() -> uword @AY {
|
||||
|
||||
cx16 {
|
||||
|
||||
%option no_symbol_prefixing
|
||||
|
||||
; irq, system and hardware vectors:
|
||||
&uword IERROR = $0300
|
||||
&uword IMAIN = $0302
|
||||
@ -710,6 +714,8 @@ asmsub restore_vera_context() clobbers(A) {
|
||||
sys {
|
||||
; ------- lowlevel system routines --------
|
||||
|
||||
%option no_symbol_prefixing
|
||||
|
||||
const ubyte target = 16 ; compilation target specifier. 64 = C64, 128 = C128, 16 = CommanderX16.
|
||||
|
||||
asmsub init_system() {
|
||||
|
@ -6,6 +6,8 @@
|
||||
|
||||
txt {
|
||||
|
||||
%option no_symbol_prefixing
|
||||
|
||||
const ubyte DEFAULT_WIDTH = 80
|
||||
const ubyte DEFAULT_HEIGHT = 60
|
||||
|
||||
|
@ -3,6 +3,8 @@
|
||||
%import textio
|
||||
|
||||
cx16logo {
|
||||
%option no_symbol_prefixing
|
||||
|
||||
sub logo_at(ubyte column, ubyte row) {
|
||||
uword strptr
|
||||
for strptr in logo_lines {
|
||||
|
@ -5,6 +5,7 @@
|
||||
%import syslib
|
||||
|
||||
diskio {
|
||||
%option no_symbol_prefixing
|
||||
|
||||
ubyte drivenumber = 8
|
||||
|
||||
|
@ -1,6 +1,6 @@
|
||||
floats {
|
||||
; the floating point functions shared across compiler targets
|
||||
%option merge
|
||||
%option merge, no_symbol_prefixing
|
||||
|
||||
sub print_f(float value) {
|
||||
; ---- prints the floating point value (without a newline).
|
||||
|
@ -1,6 +1,8 @@
|
||||
; Internal Math library routines - always included by the compiler
|
||||
|
||||
math {
|
||||
%option no_symbol_prefixing
|
||||
|
||||
%asminclude "library:math.asm"
|
||||
|
||||
asmsub sin8u(ubyte angle @A) clobbers(Y) -> ubyte @A {
|
||||
|
@ -1,6 +1,8 @@
|
||||
; Internal library routines - always included by the compiler
|
||||
|
||||
prog8_lib {
|
||||
%option no_symbol_prefixing
|
||||
|
||||
%asminclude "library:prog8_lib.asm"
|
||||
%asminclude "library:prog8_funcs.asm"
|
||||
}
|
||||
|
@ -1,6 +1,7 @@
|
||||
; 0-terminated string manipulation routines.
|
||||
|
||||
string {
|
||||
%option no_symbol_prefixing
|
||||
|
||||
asmsub length(uword string @AY) clobbers(A) -> ubyte @Y {
|
||||
; Returns the number of bytes in the string.
|
||||
|
@ -3,6 +3,7 @@
|
||||
%import textio
|
||||
|
||||
test_stack {
|
||||
%option no_symbol_prefixing
|
||||
|
||||
asmsub test() {
|
||||
%asm {{
|
||||
|
@ -54,7 +54,6 @@ private fun compileMain(args: Array<String>): Boolean {
|
||||
val startVm by cli.option(ArgType.Boolean, fullName = "vm", description = "load and run a .p8ir IR source file in the VM")
|
||||
val watchMode by cli.option(ArgType.Boolean, fullName = "watch", description = "continuous compilation mode (watch for file changes)")
|
||||
val varsHighBank by cli.option(ArgType.Int, fullName = "varshigh", description = "put uninitialized variables in high memory area instead of at the end of the program. On the cx16 target the value specifies the HiRAM bank (0=keep active), on other systems it is ignored.")
|
||||
val useNewExprCode by cli.option(ArgType.Boolean, fullName = "newexpr", description = "use new expression code-gen (experimental)")
|
||||
val splitWordArrays by cli.option(ArgType.Boolean, fullName = "splitarrays", description = "treat all word arrays as tagged with @split to make them lsb/msb split in memory")
|
||||
val moduleFiles by cli.argument(ArgType.String, fullName = "modules", description = "main module file(s) to compile").multiple(999)
|
||||
|
||||
@ -135,7 +134,6 @@ private fun compileMain(args: Array<String>): Boolean {
|
||||
asmListfile == true,
|
||||
experimentalCodegen == true,
|
||||
varsHighBank,
|
||||
useNewExprCode == true,
|
||||
compilationTarget,
|
||||
evalStackAddr,
|
||||
splitWordArrays == true,
|
||||
@ -205,7 +203,6 @@ private fun compileMain(args: Array<String>): Boolean {
|
||||
asmListfile == true,
|
||||
experimentalCodegen == true,
|
||||
varsHighBank,
|
||||
useNewExprCode == true,
|
||||
compilationTarget,
|
||||
evalStackAddr,
|
||||
splitWordArrays == true,
|
||||
|
@ -6,10 +6,10 @@ package prog8.buildversion
|
||||
const val MAVEN_GROUP = "prog8"
|
||||
const val MAVEN_NAME = "compiler"
|
||||
const val VERSION = "9.1-SNAPSHOT"
|
||||
const val GIT_REVISION = 3907
|
||||
const val GIT_SHA = "c9ef777e0f15922c06921c16e794576d3146b1c0"
|
||||
const val GIT_DATE = "2023-06-28T21:24:48Z"
|
||||
const val GIT_BRANCH = "master"
|
||||
const val BUILD_DATE = "2023-06-29T18:58:57Z"
|
||||
const val BUILD_UNIX_TIME = 1688065137839L
|
||||
const val GIT_REVISION = 3915
|
||||
const val GIT_SHA = "bdf8aa9168e16baa29543de041c90ad8f47bba3b"
|
||||
const val GIT_DATE = "2023-07-02T13:26:04Z"
|
||||
const val GIT_BRANCH = "prefixing"
|
||||
const val BUILD_DATE = "2023-07-02T17:14:33Z"
|
||||
const val BUILD_UNIX_TIME = 1688318073184L
|
||||
const val DIRTY = 1
|
||||
|
@ -4,12 +4,11 @@ import com.github.michaelbull.result.onFailure
|
||||
import prog8.ast.IBuiltinFunctions
|
||||
import prog8.ast.Program
|
||||
import prog8.ast.base.AstException
|
||||
import prog8.ast.base.FatalAstException
|
||||
import prog8.ast.expressions.Expression
|
||||
import prog8.ast.expressions.NumericLiteral
|
||||
import prog8.ast.statements.Directive
|
||||
import prog8.code.SymbolTableMaker
|
||||
import prog8.code.ast.*
|
||||
import prog8.code.ast.PtProgram
|
||||
import prog8.code.core.*
|
||||
import prog8.code.target.*
|
||||
import prog8.codegen.vm.VmCodeGen
|
||||
@ -37,7 +36,6 @@ class CompilerArguments(val filepath: Path,
|
||||
val asmListfile: Boolean,
|
||||
val experimentalCodegen: Boolean,
|
||||
val varsHighBank: Int?,
|
||||
val useNewExprCode: Boolean,
|
||||
val compilationTarget: String,
|
||||
val evalStackBaseAddress: UInt?,
|
||||
val splitWordArrays: Boolean,
|
||||
@ -79,7 +77,6 @@ fun compileProgram(args: CompilerArguments): CompilationResult? {
|
||||
asmListfile = args.asmListfile
|
||||
experimentalCodegen = args.experimentalCodegen
|
||||
varsHighBank = args.varsHighBank
|
||||
useNewExprCode = args.useNewExprCode
|
||||
evalStackBaseAddress = args.evalStackBaseAddress
|
||||
splitWordArrays = args.splitWordArrays
|
||||
outputDir = args.outputDir.normalize()
|
||||
@ -406,23 +403,12 @@ private fun createAssemblyAndAssemble(program: PtProgram,
|
||||
val asmgen = if(compilerOptions.experimentalCodegen)
|
||||
prog8.codegen.experimental.ExperiCodeGen()
|
||||
else if (compilerOptions.compTarget.machine.cpu in arrayOf(CpuType.CPU6502, CpuType.CPU65c02))
|
||||
prog8.codegen.cpu6502.AsmGen6502()
|
||||
prog8.codegen.cpu6502.AsmGen6502(prefixSymbols = true)
|
||||
else if (compilerOptions.compTarget.name == VMTarget.NAME)
|
||||
VmCodeGen()
|
||||
else
|
||||
throw NotImplementedError("no code generator for cpu ${compilerOptions.compTarget.machine.cpu}")
|
||||
|
||||
if(compilerOptions.useNewExprCode) {
|
||||
if(compilerOptions.compTarget.machine.cpu !in arrayOf(CpuType.CPU6502, CpuType.CPU65c02)) {
|
||||
// the IR code gen backend has its own, better, version of dealing with binary expressions.
|
||||
throw IllegalArgumentException("'newexpr' expression rewrite should not be used with compilation target ${compilerOptions.compTarget.name}")
|
||||
}
|
||||
|
||||
transformNewExpressions(program)
|
||||
}
|
||||
|
||||
// printAst(program, true) { println(it) }
|
||||
|
||||
val stMaker = SymbolTableMaker(program, compilerOptions)
|
||||
val symbolTable = stMaker.make()
|
||||
val assembly = asmgen.generate(program, symbolTable, compilerOptions, errors)
|
||||
@ -434,188 +420,3 @@ private fun createAssemblyAndAssemble(program: PtProgram,
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
private fun transformNewExpressions(program: PtProgram) {
|
||||
val newVariables = mutableMapOf<PtSub, MutableList<PtVariable>>()
|
||||
var countByteVars = 0
|
||||
var countWordVars = 0
|
||||
var countFloatVars = 0
|
||||
// TODO: find a reliable way to reuse more temp vars across expressions
|
||||
|
||||
fun getExprVar(type: DataType, pos: Position, scope: PtSub): PtIdentifier {
|
||||
val count = when(type) {
|
||||
in ByteDatatypes -> {
|
||||
countByteVars++
|
||||
countByteVars
|
||||
}
|
||||
in WordDatatypes -> {
|
||||
countWordVars++
|
||||
countWordVars
|
||||
}
|
||||
DataType.FLOAT -> {
|
||||
countFloatVars++
|
||||
countFloatVars
|
||||
}
|
||||
else -> throw FatalAstException("weird dt")
|
||||
}
|
||||
val name = "p8p_exprvar_${count}_${type.toString().lowercase()}"
|
||||
var subVars = newVariables[scope]
|
||||
if(subVars==null) {
|
||||
subVars = mutableListOf()
|
||||
newVariables[scope] = subVars
|
||||
}
|
||||
if(subVars.all { it.name!=name }) {
|
||||
subVars.add(PtVariable(name, type, ZeropageWish.DONTCARE, null, null, pos))
|
||||
}
|
||||
return PtIdentifier("${scope.scopedName}.$name", type, pos)
|
||||
}
|
||||
|
||||
fun transformExpr(expr: PtBinaryExpression): Pair<PtExpression, List<IPtAssignment>> {
|
||||
// depth first process the expression tree
|
||||
val scope = expr.definingSub()!!
|
||||
val assignments = mutableListOf<IPtAssignment>()
|
||||
|
||||
fun transformOperand(node: PtExpression): PtNode {
|
||||
return when(node) {
|
||||
is PtNumber, is PtIdentifier, is PtArray, is PtString, is PtMachineRegister -> node
|
||||
is PtBinaryExpression -> {
|
||||
val (replacement, subAssigns) = transformExpr(node)
|
||||
assignments.addAll(subAssigns)
|
||||
replacement
|
||||
}
|
||||
else -> {
|
||||
val variable = getExprVar(node.type, node.position, scope)
|
||||
val assign = PtAssignment(node.position)
|
||||
val target = PtAssignTarget(variable.position)
|
||||
target.add(variable)
|
||||
assign.add(target)
|
||||
assign.add(node)
|
||||
assignments.add(assign)
|
||||
variable
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
val newLeft = transformOperand(expr.left)
|
||||
val newRight = transformOperand(expr.right)
|
||||
|
||||
// process the binexpr
|
||||
|
||||
val resultVar =
|
||||
if(expr.type == expr.left.type) {
|
||||
getExprVar(expr.type, expr.position, scope)
|
||||
} else {
|
||||
if(expr.operator in ComparisonOperators && expr.type in ByteDatatypes) {
|
||||
// this is very common and should be dealth with correctly; byte==0, word>42
|
||||
val varType = if(expr.left.type in PassByReferenceDatatypes) DataType.UWORD else expr.left.type
|
||||
getExprVar(varType, expr.position, scope)
|
||||
}
|
||||
else if(expr.left.type in PassByReferenceDatatypes && expr.type==DataType.UBYTE) {
|
||||
// this is common and should be dealth with correctly; for instance "name"=="john"
|
||||
val varType = if (expr.left.type in PassByReferenceDatatypes) DataType.UWORD else expr.left.type
|
||||
getExprVar(varType, expr.position, scope)
|
||||
} else if(expr.left.type equalsSize expr.type) {
|
||||
getExprVar(expr.type, expr.position, scope)
|
||||
} else {
|
||||
TODO("expression type differs from left operand type! got ${expr.left.type} expected ${expr.type} ${expr.position}")
|
||||
}
|
||||
}
|
||||
|
||||
if(resultVar.name!=(newLeft as? PtIdentifier)?.name) {
|
||||
// resultvar = left
|
||||
val assign1 = PtAssignment(newLeft.position)
|
||||
val target1 = PtAssignTarget(resultVar.position)
|
||||
target1.add(resultVar)
|
||||
assign1.add(target1)
|
||||
assign1.add(newLeft)
|
||||
assignments.add(assign1)
|
||||
}
|
||||
// resultvar {oper}= right
|
||||
val operator = if(expr.operator in ComparisonOperators) expr.operator else expr.operator+'='
|
||||
val assign2 = PtAugmentedAssign(operator, newRight.position)
|
||||
val target2 = PtAssignTarget(resultVar.position)
|
||||
target2.add(resultVar.copy())
|
||||
assign2.add(target2)
|
||||
assign2.add(newRight)
|
||||
assignments.add(assign2)
|
||||
return Pair(resultVar, assignments)
|
||||
}
|
||||
|
||||
fun isProperStatement(node: PtNode): Boolean {
|
||||
return when(node) {
|
||||
is PtAssignment -> true
|
||||
is PtAugmentedAssign -> true
|
||||
is PtBreakpoint -> true
|
||||
is PtConditionalBranch -> true
|
||||
is PtForLoop -> true
|
||||
is PtIfElse -> true
|
||||
is PtIncludeBinary -> true
|
||||
is PtInlineAssembly -> true
|
||||
is PtJump -> true
|
||||
is PtAsmSub -> true
|
||||
is PtLabel -> true
|
||||
is PtSub -> true
|
||||
is PtVariable -> true
|
||||
is PtNop -> true
|
||||
is PtPostIncrDecr -> true
|
||||
is PtRepeatLoop -> true
|
||||
is PtReturn -> true
|
||||
is PtWhen -> true
|
||||
is PtBuiltinFunctionCall -> node.void
|
||||
is PtFunctionCall -> node.void
|
||||
else -> false
|
||||
}
|
||||
}
|
||||
|
||||
fun transform(node: PtNode, parent: PtNode) {
|
||||
if(node is PtBinaryExpression) {
|
||||
node.children.toTypedArray().forEach {
|
||||
transform(it, node)
|
||||
}
|
||||
val (rep, assignments) = transformExpr(node)
|
||||
var replacement = rep
|
||||
if(!(rep.type equalsSize node.type)) {
|
||||
if(rep.type in NumericDatatypes && node.type in ByteDatatypes) {
|
||||
replacement = PtTypeCast(node.type, node.position)
|
||||
replacement.add(rep)
|
||||
} else
|
||||
TODO("cast replacement type ${rep.type} -> ${node.type}")
|
||||
}
|
||||
var idx = parent.children.indexOf(node)
|
||||
parent.children[idx] = replacement
|
||||
replacement.parent = parent
|
||||
// find the statement above which we should insert the assignments
|
||||
var stmt = node
|
||||
while(!isProperStatement(stmt))
|
||||
stmt = stmt.parent
|
||||
idx = stmt.parent.children.indexOf(stmt)
|
||||
assignments.reversed().forEach {
|
||||
stmt.parent.add(idx, it as PtNode)
|
||||
}
|
||||
} else {
|
||||
node.children.toTypedArray().forEach { child -> transform(child, node) }
|
||||
}
|
||||
}
|
||||
|
||||
program.allBlocks().forEach { block ->
|
||||
block.children.toTypedArray().forEach {
|
||||
transform(it, block)
|
||||
}
|
||||
}
|
||||
|
||||
// add the new variables
|
||||
newVariables.forEach { (sub, vars) ->
|
||||
vars.forEach {
|
||||
sub.add(0, it)
|
||||
}
|
||||
}
|
||||
|
||||
// extra check to see that all PtBinaryExpressions have been transformed
|
||||
fun binExprCheck(node: PtNode) {
|
||||
if(node is PtBinaryExpression)
|
||||
throw IllegalArgumentException("still got binexpr $node ${node.position}")
|
||||
node.children.forEach { binExprCheck(it) }
|
||||
}
|
||||
binExprCheck(program)
|
||||
}
|
||||
|
||||
|
@ -1,49 +0,0 @@
|
||||
package prog8.compiler.astprocessing
|
||||
|
||||
import prog8.ast.statements.Block
|
||||
import prog8.ast.statements.Label
|
||||
import prog8.ast.statements.Subroutine
|
||||
import prog8.ast.statements.VarDecl
|
||||
import prog8.ast.walk.IAstVisitor
|
||||
import prog8.code.core.ICompilationTarget
|
||||
import prog8.code.target.VMTarget
|
||||
|
||||
class AsmInstructionNamesFinder(val target: ICompilationTarget): IAstVisitor {
|
||||
|
||||
val blocks = mutableSetOf<Block>()
|
||||
val variables = mutableSetOf<VarDecl>()
|
||||
val labels = mutableSetOf<Label>()
|
||||
val subroutines = mutableSetOf<Subroutine>()
|
||||
|
||||
private fun isPossibleConfusingAsmName(name: String) = (name.length==3 || name.length==1) && name.all { it.isLetter() }
|
||||
|
||||
fun foundAny(): Boolean = blocks.isNotEmpty() || variables.isNotEmpty() || subroutines.isNotEmpty() || labels.isNotEmpty()
|
||||
|
||||
override fun visit(block: Block) {
|
||||
if(target.name!=VMTarget.NAME && !block.isInLibrary && isPossibleConfusingAsmName(block.name)) {
|
||||
blocks += block
|
||||
}
|
||||
super.visit(block)
|
||||
}
|
||||
|
||||
override fun visit(decl: VarDecl) {
|
||||
if(target.name!=VMTarget.NAME && !decl.definingModule.isLibrary && isPossibleConfusingAsmName(decl.name)) {
|
||||
variables += decl
|
||||
}
|
||||
super.visit(decl)
|
||||
}
|
||||
|
||||
override fun visit(label: Label) {
|
||||
if(target.name!=VMTarget.NAME && !label.definingModule.isLibrary && isPossibleConfusingAsmName(label.name)) {
|
||||
labels += label
|
||||
}
|
||||
super.visit(label)
|
||||
}
|
||||
|
||||
override fun visit(subroutine: Subroutine) {
|
||||
if(target.name!=VMTarget.NAME && !subroutine.definingModule.isLibrary && isPossibleConfusingAsmName(subroutine.name)) {
|
||||
subroutines += subroutine
|
||||
}
|
||||
super.visit(subroutine)
|
||||
}
|
||||
}
|
@ -1,109 +0,0 @@
|
||||
package prog8.compiler.astprocessing
|
||||
|
||||
import prog8.ast.Node
|
||||
import prog8.ast.Program
|
||||
import prog8.ast.expressions.IdentifierReference
|
||||
import prog8.ast.statements.*
|
||||
import prog8.ast.walk.AstWalker
|
||||
import prog8.ast.walk.IAstModification
|
||||
|
||||
class AsmInstructionNamesReplacer(
|
||||
val program: Program,
|
||||
val blocks: Set<Block>,
|
||||
val subroutines: Set<Subroutine>,
|
||||
val variables: Set<VarDecl>,
|
||||
val labels: Set<Label>): AstWalker() {
|
||||
|
||||
override fun after(identifier: IdentifierReference, parent: Node): Iterable<IAstModification> {
|
||||
if(identifier.nameInSource.size>1) {
|
||||
val tgt = identifier.targetStatement(program)
|
||||
if(tgt==null || tgt.definingModule.isLibrary)
|
||||
return noModifications
|
||||
}
|
||||
|
||||
val newName = identifier.nameInSource.map { ident ->
|
||||
if((ident.length==3 || ident.length==1) && !identifier.definingModule.isLibrary) {
|
||||
val blockTarget = blocks.firstOrNull { it.name==ident }
|
||||
val subTarget = subroutines.firstOrNull {it.name==ident }
|
||||
val varTarget = variables.firstOrNull { it.name==ident }
|
||||
val labelTarget = labels.firstOrNull { it.name==ident}
|
||||
|
||||
if(blockTarget!=null || subTarget!=null || varTarget!=null || labelTarget!=null) {
|
||||
"p8p_$ident"
|
||||
} else
|
||||
ident
|
||||
} else
|
||||
ident
|
||||
}
|
||||
|
||||
return if(newName!=identifier.nameInSource)
|
||||
listOf(IAstModification.ReplaceNode(identifier, IdentifierReference(newName, identifier.position), parent))
|
||||
else
|
||||
noModifications
|
||||
}
|
||||
|
||||
override fun after(label: Label, parent: Node): Iterable<IAstModification> {
|
||||
return if(label in labels)
|
||||
listOf(IAstModification.ReplaceNode(label, Label("p8p_${label.name}", label.position), parent))
|
||||
else
|
||||
noModifications
|
||||
}
|
||||
|
||||
override fun after(block: Block, parent: Node): Iterable<IAstModification> {
|
||||
return if(block in blocks)
|
||||
listOf(IAstModification.ReplaceNode(block, Block("p8p_${block.name}", block.address, block.statements, block.isInLibrary, block.position), parent))
|
||||
else
|
||||
noModifications
|
||||
}
|
||||
|
||||
override fun after(decl: VarDecl, parent: Node): Iterable<IAstModification> {
|
||||
return if(decl in variables)
|
||||
listOf(IAstModification.ReplaceNode(decl, decl.renamed("p8p_${decl.name}"), parent))
|
||||
else
|
||||
noModifications
|
||||
}
|
||||
|
||||
private val subsWithParamRefsToFix = mutableListOf<Subroutine>()
|
||||
|
||||
override fun applyModifications(): Int {
|
||||
var count = super.applyModifications()
|
||||
subsWithParamRefsToFix.forEach { subroutine ->
|
||||
subroutine.statements.withIndex().reversed().forEach { (index,stmt) ->
|
||||
if(stmt is VarDecl && stmt.origin==VarDeclOrigin.SUBROUTINEPARAM) {
|
||||
val param = subroutine.parameters.single { it.name == stmt.name}
|
||||
val decl = VarDecl.fromParameter(param)
|
||||
subroutine.statements[index] = decl
|
||||
decl.linkParents(subroutine)
|
||||
count++
|
||||
}
|
||||
}
|
||||
}
|
||||
return count
|
||||
}
|
||||
|
||||
override fun after(subroutine: Subroutine, parent: Node): Iterable<IAstModification> {
|
||||
val changedParams = mutableListOf<Pair<Int, SubroutineParameter>>()
|
||||
subroutine.parameters.withIndex().forEach { (index, param) ->
|
||||
if((param.name.length==3 || param.name.length==1) && param.name.all { it.isLetter() } && !param.definingModule.isLibrary) {
|
||||
changedParams.add(index to SubroutineParameter("p8p_${param.name}", param.type, param.position))
|
||||
}
|
||||
}
|
||||
|
||||
changedParams.forEach { (index, newParam) -> subroutine.parameters[index] = newParam }
|
||||
val newName = if(subroutine in subroutines) "p8p_${subroutine.name}" else subroutine.name
|
||||
|
||||
return if(newName!=subroutine.name || changedParams.isNotEmpty()) {
|
||||
val newSub = Subroutine(newName, subroutine.parameters, subroutine.returntypes,
|
||||
subroutine.asmParameterRegisters, subroutine.asmReturnvaluesRegisters, subroutine.asmClobbers, subroutine.asmAddress, subroutine.isAsmSubroutine,
|
||||
subroutine.inline, false, subroutine.statements, subroutine.position)
|
||||
if(changedParams.isNotEmpty())
|
||||
subsWithParamRefsToFix += newSub
|
||||
listOf(IAstModification.ReplaceNode(subroutine, newSub, parent))
|
||||
} else {
|
||||
if(changedParams.isNotEmpty())
|
||||
subsWithParamRefsToFix += subroutine
|
||||
noModifications
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -812,7 +812,7 @@ internal class AstChecker(private val program: Program,
|
||||
err("this directive may only occur in a block or at module level")
|
||||
if(directive.args.isEmpty())
|
||||
err("missing option directive argument(s)")
|
||||
else if(directive.args.map{it.name in arrayOf("enable_floats", "force_output", "no_sysinit", "align_word", "align_page", "merge", "splitarrays")}.any { !it })
|
||||
else if(directive.args.map{it.name in arrayOf("enable_floats", "force_output", "no_sysinit", "align_word", "align_page", "merge", "splitarrays", "no_symbol_prefixing")}.any { !it })
|
||||
err("invalid option directive argument(s)")
|
||||
}
|
||||
else -> throw SyntaxError("invalid directive ${directive.directive}", directive.position)
|
||||
|
@ -12,7 +12,6 @@ import prog8.ast.statements.VarDeclOrigin
|
||||
import prog8.ast.walk.AstWalker
|
||||
import prog8.ast.walk.IAstModification
|
||||
import prog8.code.core.*
|
||||
import prog8.code.target.VMTarget
|
||||
|
||||
|
||||
internal fun Program.checkValid(errors: IErrorReporter, compilerOptions: CompilationOptions) {
|
||||
@ -28,21 +27,6 @@ internal fun Program.processAstBeforeAsmGeneration(compilerOptions: CompilationO
|
||||
boolRemover.visit(this)
|
||||
boolRemover.applyModifications()
|
||||
|
||||
if(compilerOptions.compTarget.name!=VMTarget.NAME) {
|
||||
val finder = AsmInstructionNamesFinder(compilerOptions.compTarget)
|
||||
finder.visit(this)
|
||||
if(finder.foundAny()) {
|
||||
val replacer = AsmInstructionNamesReplacer(
|
||||
this,
|
||||
finder.blocks,
|
||||
finder.subroutines,
|
||||
finder.variables,
|
||||
finder.labels)
|
||||
replacer.visit(this)
|
||||
replacer.applyModifications()
|
||||
}
|
||||
}
|
||||
|
||||
val fixer = BeforeAsmAstChanger(this, compilerOptions, errors)
|
||||
fixer.visit(this)
|
||||
while (errors.noErrors() && fixer.applyModifications() > 0) {
|
||||
|
@ -161,21 +161,23 @@ class IntermediateAstMaker(private val program: Program, private val options: Co
|
||||
private fun transform(srcBlock: Block): PtBlock {
|
||||
var alignment = PtBlock.BlockAlignment.NONE
|
||||
var forceOutput = false
|
||||
var noSymbolPrefixing = false
|
||||
val directives = srcBlock.statements.filterIsInstance<Directive>()
|
||||
for (directive in directives.filter { it.directive == "%option" }) {
|
||||
for (arg in directive.args) {
|
||||
when (arg.name) {
|
||||
"align_word" -> alignment = PtBlock.BlockAlignment.WORD
|
||||
"align_page" -> alignment = PtBlock.BlockAlignment.PAGE
|
||||
"no_symbol_prefixing" -> noSymbolPrefixing = true
|
||||
"force_output" -> forceOutput=true
|
||||
"merge", "splitarrays" -> { /* ignore this one */ }
|
||||
"merge", "splitarrays" -> { /* ignore this one */ }
|
||||
else -> throw FatalAstException("weird directive option: ${arg.name}")
|
||||
}
|
||||
}
|
||||
}
|
||||
val (vardecls, statements) = srcBlock.statements.partition { it is VarDecl }
|
||||
val src = srcBlock.definingModule.source
|
||||
val block = PtBlock(srcBlock.name, srcBlock.address, srcBlock.isInLibrary, forceOutput, alignment, src, srcBlock.position)
|
||||
val block = PtBlock(srcBlock.name, srcBlock.address, srcBlock.isInLibrary, forceOutput, noSymbolPrefixing, alignment, src, srcBlock.position)
|
||||
makeScopeVarsDecls(vardecls).forEach { block.add(it) }
|
||||
for (stmt in statements)
|
||||
block.add(transformStatement(stmt))
|
||||
@ -434,11 +436,10 @@ class IntermediateAstMaker(private val program: Program, private val options: Co
|
||||
private fun transform(src: AddressOf): PtAddressOf {
|
||||
val addr = PtAddressOf(src.position)
|
||||
val (name, dt) = src.identifier.targetNameAndType(program)
|
||||
if(dt in SplitWordArrayTypes) {
|
||||
addr.add(PtIdentifier(name+"_lsb", dt, src.identifier.position))
|
||||
} else {
|
||||
if(dt in SplitWordArrayTypes)
|
||||
addr.add(PtIdentifier(name+"_lsb", dt, src.identifier.position)) // NOTE: assumes _lsb is first in memory! (immediately followed by _msb)
|
||||
else
|
||||
addr.add(transform(src.identifier))
|
||||
}
|
||||
return addr
|
||||
}
|
||||
|
||||
|
@ -33,7 +33,6 @@ private fun compileTheThing(filepath: Path, optimize: Boolean, target: ICompilat
|
||||
asmListfile = false,
|
||||
experimentalCodegen = false,
|
||||
varsHighBank = null,
|
||||
useNewExprCode = false,
|
||||
compilationTarget = target.name,
|
||||
evalStackBaseAddress = null,
|
||||
splitWordArrays = false,
|
||||
|
@ -50,7 +50,6 @@ class TestCompilerOptionSourcedirs: FunSpec({
|
||||
asmListfile = false,
|
||||
experimentalCodegen = false,
|
||||
varsHighBank = null,
|
||||
useNewExprCode = false,
|
||||
compilationTarget = Cx16Target.NAME,
|
||||
evalStackBaseAddress = null,
|
||||
splitWordArrays = false,
|
||||
|
@ -90,7 +90,7 @@ private fun makeSt(): SymbolTable {
|
||||
|
||||
// first build the AST
|
||||
val astProgram = PtProgram("test", DummyMemsizer, DummyStringEncoder)
|
||||
val astBlock1 = PtBlock("block1", null, false, false, PtBlock.BlockAlignment.NONE, SourceCode.Generated("block1"), Position.DUMMY)
|
||||
val astBlock1 = PtBlock("block1", null, false, false, false, PtBlock.BlockAlignment.NONE, SourceCode.Generated("block1"), Position.DUMMY)
|
||||
val astConstant1 = PtConstant("c1", DataType.UWORD, 12345.0, Position.DUMMY)
|
||||
val astConstant2 = PtConstant("blockc", DataType.UWORD, 999.0, Position.DUMMY)
|
||||
astBlock1.add(astConstant1)
|
||||
@ -113,7 +113,7 @@ private fun makeSt(): SymbolTable {
|
||||
astBlock1.add(astSub2)
|
||||
val astBfunc = PtIdentifier("msb", DataType.UBYTE, Position.DUMMY)
|
||||
astBlock1.add(astBfunc)
|
||||
val astBlock2 = PtBlock("block2", null, false, false, PtBlock.BlockAlignment.NONE, SourceCode.Generated("block2"), Position.DUMMY)
|
||||
val astBlock2 = PtBlock("block2", null, false, false, false, PtBlock.BlockAlignment.NONE, SourceCode.Generated("block2"), Position.DUMMY)
|
||||
val astSub21 = PtSub("sub1", emptyList(), null, Position.DUMMY)
|
||||
val astSub22 = PtSub("sub2", emptyList(), null, Position.DUMMY)
|
||||
val astSub221 = PtSub("subsub", emptyList(), null, Position.DUMMY)
|
||||
|
@ -66,7 +66,6 @@ class TestIntermediateAst: FunSpec({
|
||||
val fcall = (entry.children[4] as PtAssignment).value as PtFunctionCall
|
||||
fcall.void shouldBe false
|
||||
fcall.type shouldBe DataType.UBYTE
|
||||
printAst(ast, false, ::println)
|
||||
}
|
||||
|
||||
})
|
@ -121,11 +121,11 @@ main {
|
||||
|
||||
sub start() {
|
||||
%asm {{
|
||||
lda normal
|
||||
lda uw_lsb
|
||||
lda uw_msb
|
||||
lda sw_lsb
|
||||
lda sw_msb
|
||||
lda p8_normal
|
||||
lda p8_uw_lsb
|
||||
lda p8_uw_msb
|
||||
lda p8_sw_lsb
|
||||
lda p8_sw_msb
|
||||
}}
|
||||
}
|
||||
}"""
|
||||
|
@ -17,9 +17,9 @@ class TestVariables: FunSpec({
|
||||
ubyte @shared bytevar = 0
|
||||
|
||||
%asm {{
|
||||
lda arrayvar
|
||||
lda stringvar
|
||||
lda bytevar
|
||||
lda p8_arrayvar
|
||||
lda p8_stringvar
|
||||
lda p8_bytevar
|
||||
}}
|
||||
}
|
||||
}
|
||||
|
@ -12,6 +12,7 @@ import prog8.code.ast.PtAssignment
|
||||
import prog8.code.ast.PtVariable
|
||||
import prog8.code.core.DataType
|
||||
import prog8.code.target.C64Target
|
||||
import prog8.code.target.Cx16Target
|
||||
import prog8.code.target.VMTarget
|
||||
import prog8tests.helpers.ErrorReporterForTests
|
||||
import prog8tests.helpers.compileText
|
||||
@ -84,10 +85,10 @@ main {
|
||||
result.codegenAst!!.name shouldBe result.compilerAst.name
|
||||
result.codegenAst!!.children.size shouldBeGreaterThan 2
|
||||
val start = result.codegenAst!!.entrypoint()!!
|
||||
start.name shouldBe "start"
|
||||
start.name shouldBe "p8_start"
|
||||
start.children.size shouldBeGreaterThan 2
|
||||
val seed = start.children[0] as PtVariable
|
||||
seed.name shouldBe "seed"
|
||||
seed.name shouldBe "p8_seed"
|
||||
seed.value shouldBe null
|
||||
seed.type shouldBe DataType.ARRAY_UW
|
||||
val assign = start.children[1] as PtAssignment
|
||||
@ -160,10 +161,8 @@ main {
|
||||
qq = 16000 + c*${'$'}0008
|
||||
}
|
||||
}"""
|
||||
compileText(C64Target(), true, text, writeAssembly = true, useNewExprCode = false) shouldNotBe null
|
||||
compileText(VMTarget(), true, text, writeAssembly = true, useNewExprCode = false) shouldNotBe null
|
||||
compileText(C64Target(), true, text, writeAssembly = true, useNewExprCode = true) shouldNotBe null
|
||||
// no newexpr for IR targets: compileText(VMTarget(), true, text, writeAssembly = true, useNewExprCode = true) shouldNotBe null
|
||||
compileText(C64Target(), true, text, writeAssembly = true) shouldNotBe null
|
||||
compileText(VMTarget(), true, text, writeAssembly = true) shouldNotBe null
|
||||
}
|
||||
|
||||
test("builtin func in float expression") {
|
||||
@ -202,4 +201,60 @@ block2 {
|
||||
compileText(C64Target(), true, src, writeAssembly = true) shouldNotBe null
|
||||
compileText(VMTarget(), true, src, writeAssembly = true) shouldNotBe null
|
||||
}
|
||||
|
||||
test("array with pointers") {
|
||||
val src = """
|
||||
main {
|
||||
sub start() {
|
||||
str localstr = "hello"
|
||||
ubyte[] otherarray = [1,2,3]
|
||||
uword[] words = [1111,2222,"three",&localstr,&otherarray]
|
||||
uword @shared zz = &words
|
||||
ubyte result = 2222 in words
|
||||
zz = words[2]
|
||||
zz++
|
||||
zz = words[3]
|
||||
}
|
||||
}"""
|
||||
val othertarget = Cx16Target()
|
||||
compileText(othertarget, true, src, writeAssembly = true) shouldNotBe null
|
||||
}
|
||||
|
||||
test("case sensitive symbols") {
|
||||
val src = """
|
||||
main {
|
||||
sub start() {
|
||||
ubyte bytevar = 11 ; var at 0
|
||||
ubyte byteVAR = 22 ; var at 1
|
||||
ubyte ByteVar = 33 ; var at 2
|
||||
ubyte @shared total = bytevar+byteVAR+ByteVar ; var at 3
|
||||
goto skipLABEL
|
||||
SkipLabel:
|
||||
return
|
||||
skipLABEL:
|
||||
bytevar = 42
|
||||
}
|
||||
}"""
|
||||
val target = Cx16Target()
|
||||
compileText(target, true, src, writeAssembly = true) shouldNotBe null
|
||||
}
|
||||
|
||||
test("addresses from labels/subroutines") {
|
||||
val src = """
|
||||
main {
|
||||
sub start() {
|
||||
|
||||
mylabel:
|
||||
ubyte variable
|
||||
uword @shared pointer1 = &main.start
|
||||
uword @shared pointer2 = &start
|
||||
uword @shared pointer3 = &main.start.mylabel
|
||||
uword @shared pointer4 = &mylabel
|
||||
uword[] @shared ptrs = [&variable, &start, &main.start, &mylabel, &main.start.mylabel]
|
||||
}
|
||||
}
|
||||
|
||||
"""
|
||||
compileText(Cx16Target(), true, src, writeAssembly = true) shouldNotBe null
|
||||
}
|
||||
})
|
@ -18,7 +18,6 @@ internal fun compileFile(
|
||||
errors: IErrorReporter? = null,
|
||||
writeAssembly: Boolean = true,
|
||||
optFloatExpr: Boolean = true,
|
||||
useNewExprCode: Boolean = false
|
||||
) : CompilationResult? {
|
||||
val filepath = fileDir.resolve(fileName)
|
||||
assumeReadableFile(filepath)
|
||||
@ -32,7 +31,6 @@ internal fun compileFile(
|
||||
asmListfile = false,
|
||||
experimentalCodegen = false,
|
||||
varsHighBank = null,
|
||||
useNewExprCode = useNewExprCode,
|
||||
platform.name,
|
||||
evalStackBaseAddress = null,
|
||||
symbolDefs = emptyMap(),
|
||||
@ -55,11 +53,10 @@ internal fun compileText(
|
||||
errors: IErrorReporter? = null,
|
||||
writeAssembly: Boolean = true,
|
||||
optFloatExpr: Boolean = true,
|
||||
useNewExprCode: Boolean = false
|
||||
) : CompilationResult? {
|
||||
val filePath = outputDir.resolve("on_the_fly_test_" + sourceText.hashCode().toUInt().toString(16) + ".p8")
|
||||
// we don't assumeNotExists(filePath) - should be ok to just overwrite it
|
||||
filePath.toFile().writeText(sourceText)
|
||||
return compileFile(platform, optimize, filePath.parent, filePath.name,
|
||||
errors=errors, writeAssembly=writeAssembly, optFloatExpr = optFloatExpr, useNewExprCode=useNewExprCode)
|
||||
errors=errors, writeAssembly=writeAssembly, optFloatExpr = optFloatExpr)
|
||||
}
|
||||
|
@ -53,8 +53,6 @@ main {
|
||||
zz = words[3]
|
||||
}
|
||||
}"""
|
||||
val othertarget = Cx16Target()
|
||||
compileText(othertarget, true, src, writeAssembly = true) shouldNotBe null
|
||||
val target = VMTarget()
|
||||
val result = compileText(target, true, src, writeAssembly = true)!!
|
||||
val virtfile = result.compilationOptions.outputDir.resolve(result.compilerAst.name + ".p8ir")
|
||||
@ -165,10 +163,7 @@ skipLABEL:
|
||||
bytevar = 42
|
||||
}
|
||||
}"""
|
||||
val othertarget = Cx16Target()
|
||||
compileText(othertarget, true, src, writeAssembly = true) shouldNotBe null
|
||||
val target = VMTarget()
|
||||
val result = compileText(target, true, src, writeAssembly = true)!!
|
||||
val result = compileText(VMTarget(), true, src, writeAssembly = true)!!
|
||||
val virtfile = result.compilationOptions.outputDir.resolve(result.compilerAst.name + ".p8ir")
|
||||
VmRunner().runAndTestProgram(virtfile.readText()) { vm ->
|
||||
vm.memory.getUB(0) shouldBe 42u
|
||||
@ -283,11 +278,7 @@ mylabel:
|
||||
}
|
||||
|
||||
"""
|
||||
val othertarget = Cx16Target()
|
||||
compileText(othertarget, true, src, writeAssembly = true) shouldNotBe null
|
||||
|
||||
val target = VMTarget()
|
||||
val result = compileText(target, false, src, writeAssembly = true)!!
|
||||
val result = compileText(VMTarget(), false, src, writeAssembly = true)!!
|
||||
val virtfile = result.compilationOptions.outputDir.resolve(result.compilerAst.name + ".p8ir")
|
||||
val exc = shouldThrow<Exception> {
|
||||
VmRunner().runProgram(virtfile.readText())
|
||||
|
@ -24,6 +24,8 @@ class Program(val name: String,
|
||||
val internedStringsModule =
|
||||
Module(mutableListOf(), Position.DUMMY, SourceCode.Generated(internedStringsModuleName))
|
||||
val block = Block(internedStringsModuleName, null, mutableListOf(), true, Position.DUMMY)
|
||||
val directive = Directive("%option", listOf(DirectiveArg(null,"no_symbol_prefixing", null, Position.DUMMY)), Position.DUMMY)
|
||||
block.statements.add(directive)
|
||||
internedStringsModule.statements.add(block)
|
||||
|
||||
_modules.add(0, internedStringsModule)
|
||||
@ -55,7 +57,7 @@ class Program(val name: String,
|
||||
|
||||
val entrypoint: Subroutine
|
||||
get() {
|
||||
val mainBlocks = allBlocks.filter { it.name == "main" }
|
||||
val mainBlocks = allBlocks.filter { it.name=="main" }
|
||||
return when (mainBlocks.size) {
|
||||
0 -> throw FatalAstException("no 'main' block")
|
||||
1 -> mainBlocks[0].subScope("start") as Subroutine
|
||||
@ -92,12 +94,11 @@ class Program(val name: String,
|
||||
return Pair(listOf(internedStringsModuleName, decl.name), decl)
|
||||
}
|
||||
|
||||
val existingDecl = internedStringsBlock.statements.singleOrNull {
|
||||
val declString = (it as VarDecl).value as StringLiteral
|
||||
val existingDecl = internedStringsBlock.statements.filterIsInstance<VarDecl>().singleOrNull {
|
||||
val declString = it.value as StringLiteral
|
||||
declString.encoding == string.encoding && declString.value == string.value
|
||||
}
|
||||
return if (existingDecl != null) {
|
||||
existingDecl as VarDecl
|
||||
internedStringsReferenceCounts[existingDecl] = internedStringsReferenceCounts.getValue(existingDecl)+1
|
||||
existingDecl.scopedName
|
||||
}
|
||||
@ -133,7 +134,7 @@ class Program(val name: String,
|
||||
.first { it.name == internedStringsModuleName }.statements
|
||||
.first { it is Block && it.name == internedStringsModuleName } as Block
|
||||
removals.forEach { scopedname ->
|
||||
val decl = internedStringsBlock.statements.single { decl -> (decl as VarDecl).scopedName == scopedname } as VarDecl
|
||||
val decl = internedStringsBlock.statements.filterIsInstance<VarDecl>().single { decl -> decl.scopedName == scopedname } as VarDecl
|
||||
val numRefs = program.internedStringsReferenceCounts.getValue(decl) - 1
|
||||
program.internedStringsReferenceCounts[decl] = numRefs
|
||||
if(numRefs==0)
|
||||
|
@ -932,7 +932,7 @@ data class IdentifierReference(val nameInSource: List<String>, override val posi
|
||||
fun targetSubroutine(program: Program): Subroutine? = targetStatement(program) as? Subroutine
|
||||
|
||||
fun targetNameAndType(program: Program): Pair<String, DataType> {
|
||||
val target=targetStatement(program)!! as INamedStatement
|
||||
val target = targetStatement(program) as? INamedStatement ?: throw FatalAstException("can't find target for $nameInSource")
|
||||
val targetname: String = if(target.name in program.builtinFunctions.names)
|
||||
"<builtin>.${target.name}"
|
||||
else
|
||||
@ -985,6 +985,8 @@ data class IdentifierReference(val nameInSource: List<String>, override val posi
|
||||
val scope=decl.definingModule
|
||||
return scope.name==internedStringsModuleName
|
||||
}
|
||||
|
||||
fun renamed(newName: List<String>): IdentifierReference = IdentifierReference(newName, position)
|
||||
}
|
||||
|
||||
class FunctionCallExpression(override var target: IdentifierReference,
|
||||
|
@ -94,6 +94,7 @@ class Block(override val name: String,
|
||||
override fun referencesIdentifier(nameInSource: List<String>): Boolean = statements.any { it.referencesIdentifier(nameInSource) }
|
||||
|
||||
fun options() = statements.filter { it is Directive && it.directive == "%option" }.flatMap { (it as Directive).args }.map {it.name!!}.toSet()
|
||||
fun renamed(newName: String): Block = Block(newName, address, statements, isInLibrary, position)
|
||||
}
|
||||
|
||||
data class Directive(val directive: String, val args: List<DirectiveArg>, override val position: Position) : Statement() {
|
||||
@ -135,6 +136,7 @@ data class Label(override val name: String, override val position: Position) : S
|
||||
override fun accept(visitor: IAstVisitor) = visitor.visit(this)
|
||||
override fun accept(visitor: AstWalker, parent: Node) = visitor.visit(this, parent)
|
||||
override fun toString()= "Label(name=$name, pos=$position)"
|
||||
fun renamed(newName: String): Label = Label(newName, position)
|
||||
}
|
||||
|
||||
class Return(var value: Expression?, override val position: Position) : Statement() {
|
||||
|
@ -131,6 +131,8 @@ Directives
|
||||
- ``align_page`` (in a block) will make the assembler align the start address of this block on a page boundary in memory (so, the LSB of the address is 0).
|
||||
- ``merge`` (in a block) will merge this block's contents into an already existing block with the same name. Useful in library scenarios.
|
||||
- ``splitarrays`` (block or module) makes all word-arrays in this scope lsb/msb split arrays (as if they all have the @split tag). See Arrays.
|
||||
- ``no_symbol_prefixing`` (block) makes the compiler *not* use symbol-prefixing when translating prog8 code into assembly.
|
||||
Only use this if you know what you're doing because it could result in invalid assembly code being generated.
|
||||
|
||||
|
||||
.. data:: %asmbinary "<filename>" [, <offset>[, <length>]]
|
||||
@ -210,7 +212,7 @@ Directives
|
||||
If you use the correct scoping rules you can access symbols from the prog8 program from inside
|
||||
the assembly code. Sometimes you'll have to declare a variable in prog8 with `@shared` if it
|
||||
is only used in such assembly code. For symbols just consisting of 3 letters, prog8 will
|
||||
add a special prefix to them, read more about this in :ref:`three-letter-prefixing`.
|
||||
add a special prefix to them, read more about this in :ref:`symbol-prefixing`.
|
||||
|
||||
|
||||
Identifiers
|
||||
|
@ -22,20 +22,26 @@ It is possible to relocate the BSS section using a compiler option
|
||||
so that more system ram is available for the program code itself.
|
||||
|
||||
|
||||
.. _three-letter-prefixing:
|
||||
.. _symbol-prefixing:
|
||||
|
||||
Three-letter symbols prefixing in Assembly
|
||||
------------------------------------------
|
||||
Symbol prefixing in generated Assembly code
|
||||
-------------------------------------------
|
||||
|
||||
Symbols consisting of three letters such as "brk" or "tax", or variables named "a", "x" or "y" could
|
||||
confuse the assembler to think these are cpu instructions or registers.
|
||||
It will likely fail to assemble the program correctly.
|
||||
Because of this, prog8 will prefix every 1- and 3-letter symbol with "``p8p_``" automatically during compilation.
|
||||
So "tax" will become "p8p_tax", "a" will become "p8p_a" in the resulting assembly code.
|
||||
*All* symbols in the prog8 program will be prefixed with ``p8_`` in the generated assembly code.
|
||||
This is to avoid naming conflicts with CPU registers, assembly instructions, etc.
|
||||
So if you're referencing symbols from the prog8 program in inlined assembly code, you have to take
|
||||
this into account. Stick a ``p8_`` in front of everything that you want to reference that is coming
|
||||
from a prog8 source file.
|
||||
All elements in scoped names such as ``main.routine.var1`` are prefixed so this becomes ``p8_main.p8_routine.p8_var1``.
|
||||
|
||||
If you're referencing symbols from the prog8 program in hand-written assembly code, you have to take
|
||||
this into account. Either prefix the 1- and 3-letter symbols in the assembly with "``p8p_``" as well, or just
|
||||
choose a symbol name of a different length in the first place.
|
||||
.. attention::
|
||||
Symbols from library modules are *not* prefixed and can be used
|
||||
in assembly code as-is. So you can write::
|
||||
|
||||
%asm {{
|
||||
lda #'a'
|
||||
jsr cbm.CHROUT
|
||||
}}
|
||||
|
||||
|
||||
Software stack for expression evaluation
|
||||
|
@ -1,9 +1,7 @@
|
||||
TODO
|
||||
====
|
||||
|
||||
- prog8->asm symbol name prefixing: prefix ALL symbols with p8_ Also update manual.
|
||||
EXCEPTION: library symbols such as cbm.CHROUT, cx16.r0 etc. should NOT be prefixed.
|
||||
Solution: add %option no_symbol_prefix to those blocks?
|
||||
- fix type error with returning an array literal from a subroutine returning uword
|
||||
|
||||
...
|
||||
|
||||
|
@ -1,104 +0,0 @@
|
||||
%import textio
|
||||
%import floats
|
||||
|
||||
main {
|
||||
sub start() {
|
||||
|
||||
test_val()
|
||||
|
||||
repeat {
|
||||
}
|
||||
}
|
||||
|
||||
sub test_val() {
|
||||
|
||||
; TODO c128 how do I set this in "bank 1" ? VAL() needs that...
|
||||
|
||||
str @shared value = "-1.23456"
|
||||
uword @shared result
|
||||
%asm {{
|
||||
stx P8ZP_SCRATCH_B1
|
||||
lda #<value
|
||||
sta $24
|
||||
lda #>value
|
||||
sta $25
|
||||
lda #8
|
||||
jsr floats.VAL
|
||||
jsr floats.FOUT
|
||||
sta result
|
||||
sty result+1
|
||||
ldx P8ZP_SCRATCH_B1
|
||||
}}
|
||||
txt.print_uwhex(result, true)
|
||||
txt.nl()
|
||||
txt.print(result)
|
||||
txt.nl()
|
||||
txt.print($0100)
|
||||
txt.nl()
|
||||
}
|
||||
|
||||
sub test_freadsa() {
|
||||
uword @shared result
|
||||
%asm {{
|
||||
stx P8ZP_SCRATCH_B1
|
||||
;lda #-123
|
||||
;jsr floats.FREADSA
|
||||
lda #<55444
|
||||
ldy #>55444
|
||||
jsr floats.GIVUAYFAY
|
||||
jsr floats.FOUT
|
||||
sta result
|
||||
sty result+1
|
||||
ldx P8ZP_SCRATCH_B1
|
||||
}}
|
||||
txt.print_uwhex(result, true)
|
||||
txt.nl()
|
||||
txt.print(result)
|
||||
txt.nl()
|
||||
txt.print($0100)
|
||||
txt.nl()
|
||||
}
|
||||
|
||||
sub test_getadr() {
|
||||
uword @shared value
|
||||
%asm {{
|
||||
stx P8ZP_SCRATCH_B1
|
||||
lda #<23456
|
||||
ldy #>23456
|
||||
jsr floats.GIVAYFAY
|
||||
jsr floats.GETADRAY
|
||||
sta value
|
||||
sty value+1
|
||||
ldx P8ZP_SCRATCH_B1
|
||||
}}
|
||||
txt.print_uw(value)
|
||||
txt.nl()
|
||||
}
|
||||
|
||||
sub test_ayint() {
|
||||
%asm {{
|
||||
stx P8ZP_SCRATCH_B1
|
||||
lda #<-23456
|
||||
ldy #>-23456
|
||||
jsr floats.GIVAYFAY
|
||||
jsr floats.AYINT
|
||||
ldx P8ZP_SCRATCH_B1
|
||||
}}
|
||||
word value = mkword(@($66), @($67)) as word
|
||||
txt.print_w(value)
|
||||
txt.nl()
|
||||
}
|
||||
|
||||
sub test_printf() {
|
||||
floats.print_f(0)
|
||||
txt.nl()
|
||||
floats.print_f(1)
|
||||
txt.nl()
|
||||
floats.print_f(-1)
|
||||
txt.nl()
|
||||
floats.print_f(floats.PI)
|
||||
txt.nl()
|
||||
floats.print_f(floats.TWOPI)
|
||||
txt.nl()
|
||||
}
|
||||
}
|
@ -87,14 +87,14 @@ irq {
|
||||
asmsub set_scanline_color(ubyte color_ix @Y) {
|
||||
; uword color = mkword(reds[ix], (greens[ix] << 4) | blues[ix] )
|
||||
%asm {{
|
||||
lda blinds_lines_reds,y
|
||||
lda p8_blinds_lines_reds,y
|
||||
pha
|
||||
lda blinds_lines_greens,y
|
||||
lda p8_blinds_lines_greens,y
|
||||
asl a
|
||||
asl a
|
||||
asl a
|
||||
asl a
|
||||
ora blinds_lines_blues,y
|
||||
ora p8_blinds_lines_blues,y
|
||||
tay
|
||||
|
||||
stz cx16.VERA_CTRL
|
||||
|
@ -66,12 +66,12 @@ main {
|
||||
|
||||
%asm {{
|
||||
pha
|
||||
sta keyhdl_scancode
|
||||
sta p8_keyhdl_scancode
|
||||
lda #1
|
||||
sta keyhdl_event
|
||||
sta p8_keyhdl_event
|
||||
pla
|
||||
|
||||
lda #0 ; By setting A=0 we will eat this key event. leave A unchanged to pass it through.
|
||||
lda #0 ; By setting A=0 we will eat this key event. leave A unchanged to pass it through.
|
||||
rts
|
||||
}}
|
||||
}
|
||||
|
@ -148,9 +148,9 @@ interrupt {
|
||||
asmsub wait_and_clear_aflow_semaphore() {
|
||||
%asm {{
|
||||
- wai
|
||||
lda aflow_semaphore
|
||||
lda p8_aflow_semaphore
|
||||
bne -
|
||||
inc aflow_semaphore
|
||||
inc p8_aflow_semaphore
|
||||
rts
|
||||
}}
|
||||
}
|
||||
@ -182,9 +182,9 @@ interrupt {
|
||||
; optimized loop to put 1024 bytes of data into the fifo as fast as possible
|
||||
; converting unsigned wav 8 bit samples to signed 8 bit on the fly
|
||||
%asm {{
|
||||
lda main.start.buffer
|
||||
lda p8_main.p8_start.p8_buffer
|
||||
sta cx16.r0L
|
||||
lda main.start.buffer+1
|
||||
lda p8_main.p8_start.p8_buffer+1
|
||||
sta cx16.r0H
|
||||
ldx #4
|
||||
- ldy #0
|
||||
@ -212,9 +212,9 @@ interrupt {
|
||||
asmsub uncompressed_block_16() {
|
||||
; optimized loop to put 1024 bytes of data into the fifo as fast as possible
|
||||
%asm {{
|
||||
lda main.start.buffer
|
||||
lda p8_main.p8_start.p8_buffer
|
||||
sta cx16.r0L
|
||||
lda main.start.buffer+1
|
||||
lda p8_main.p8_start.p8_buffer+1
|
||||
sta cx16.r0H
|
||||
ldx #4
|
||||
- ldy #0
|
||||
|
@ -110,6 +110,7 @@ char_loop:
|
||||
|
||||
vtui $1000 {
|
||||
|
||||
%option no_symbol_prefixing
|
||||
%asmbinary "VTUI1.0.BIN", 2 ; skip the 2 dummy load address bytes
|
||||
|
||||
; NOTE: base address $1000 here must be the same as the block's memory address, for obvious reasons!
|
||||
|
@ -2,79 +2,10 @@
|
||||
%zeropage basicsafe
|
||||
|
||||
main {
|
||||
sub start() {
|
||||
uword count = 255
|
||||
cx16.r0 = 0
|
||||
repeat count {
|
||||
cx16.r0++
|
||||
}
|
||||
txt.print_uw(255)
|
||||
txt.spc()
|
||||
txt.print_uw(cx16.r0)
|
||||
txt.nl()
|
||||
|
||||
count=256
|
||||
repeat count {
|
||||
cx16.r0++
|
||||
}
|
||||
txt.print_uw(255+256)
|
||||
txt.spc()
|
||||
txt.print_uw(cx16.r0)
|
||||
txt.nl()
|
||||
count = 257
|
||||
repeat count {
|
||||
cx16.r0++
|
||||
}
|
||||
txt.print_uw(255+256+257)
|
||||
txt.spc()
|
||||
txt.print_uw(cx16.r0)
|
||||
txt.nl()
|
||||
count=1023
|
||||
repeat count {
|
||||
cx16.r0++
|
||||
}
|
||||
txt.print_uw(255+256+257+1023)
|
||||
txt.spc()
|
||||
txt.print_uw(cx16.r0)
|
||||
txt.nl()
|
||||
count=1024
|
||||
repeat count {
|
||||
cx16.r0++
|
||||
}
|
||||
txt.print_uw(255+256+257+1023+1024)
|
||||
txt.spc()
|
||||
txt.print_uw(cx16.r0)
|
||||
txt.nl()
|
||||
count = 1025
|
||||
repeat count {
|
||||
cx16.r0++
|
||||
}
|
||||
txt.print_uw(255+256+257+1023+1024+1025)
|
||||
txt.spc()
|
||||
txt.print_uw(cx16.r0)
|
||||
txt.nl()
|
||||
count = 65534
|
||||
repeat count {
|
||||
cx16.r0++
|
||||
}
|
||||
txt.print_uw(3838)
|
||||
txt.spc()
|
||||
txt.print_uw(cx16.r0)
|
||||
txt.nl()
|
||||
count = 65535
|
||||
repeat count {
|
||||
cx16.r0++
|
||||
}
|
||||
count=0
|
||||
repeat count {
|
||||
cx16.r0++
|
||||
}
|
||||
repeat 0 {
|
||||
cx16.r0++
|
||||
}
|
||||
txt.print_uw(3837)
|
||||
txt.spc()
|
||||
txt.print_uw(cx16.r0)
|
||||
txt.nl()
|
||||
romsub $FFD2 = chrout(ubyte ch @ A)
|
||||
sub start() {
|
||||
ubyte ch = '\n'
|
||||
chrout(ch)
|
||||
}
|
||||
}
|
||||
|
@ -990,9 +990,9 @@ planet {
|
||||
sbc #$81
|
||||
asl a
|
||||
tay
|
||||
lda wordlists,y
|
||||
lda p8_wordlists,y
|
||||
sta P8ZP_SCRATCH_W1
|
||||
lda wordlists+1,y
|
||||
lda p8_wordlists+1,y
|
||||
sta P8ZP_SCRATCH_W1+1
|
||||
lda P8ZP_SCRATCH_REG
|
||||
asl a
|
||||
|
@ -44,7 +44,6 @@ class RequestParser : Take {
|
||||
experimentalCodegen = false,
|
||||
splitWordArrays = false,
|
||||
varsHighBank = null,
|
||||
useNewExprCode = false
|
||||
)
|
||||
val compilationResult = compileProgram(args)
|
||||
return RsJson(Jsonding())
|
||||
|
Loading…
x
Reference in New Issue
Block a user