mirror of
https://github.com/irmen/prog8.git
synced 2025-01-12 19:29:50 +00:00
assembler reserved symbols checked
This commit is contained in:
parent
2c25df122a
commit
b0dda08e74
@ -35,6 +35,17 @@ init_system .proc
|
||||
rts
|
||||
.pend
|
||||
|
||||
|
||||
read_byte_from_address .proc
|
||||
; -- read the byte from the memory address on the top of the stack, return in A (stack remains unchanged)
|
||||
lda c64.ESTACK_LO+1,x
|
||||
ldy c64.ESTACK_HI+1,x
|
||||
sta (+) +1
|
||||
sty (+) +2
|
||||
+ lda $ffff ; modified
|
||||
rts
|
||||
.pend
|
||||
|
||||
|
||||
add_a_to_zpword .proc
|
||||
; -- add ubyte in A to the uword in c64.SCRATCH_ZPWORD1
|
||||
|
@ -7,10 +7,12 @@ import prog8.ast.Program
|
||||
import prog8.ast.base.*
|
||||
import prog8.ast.expressions.*
|
||||
import prog8.ast.statements.*
|
||||
import prog8.compiler.target.c64.AssemblyProgram
|
||||
import prog8.functions.BuiltinFunctions
|
||||
|
||||
|
||||
internal class AstIdentifiersChecker(private val program: Program) : IAstModifyingVisitor {
|
||||
|
||||
private val checkResult: MutableList<AstException> = mutableListOf()
|
||||
|
||||
private var blocks = mutableMapOf<String, Block>()
|
||||
@ -64,6 +66,11 @@ internal class AstIdentifiersChecker(private val program: Program) : IAstModifyi
|
||||
// the builtin functions can't be redefined
|
||||
checkResult.add(NameError("builtin function cannot be redefined", decl.position))
|
||||
|
||||
if(decl.name in AssemblyProgram.reservedNames)
|
||||
checkResult.add(NameError("can't use a symbol name reserved by the assembler program", decl.position))
|
||||
if(decl.name in AssemblyProgram.opcodeNames)
|
||||
checkResult.add(NameError("can't use a cpu opcode name as a symbol", decl.position))
|
||||
|
||||
// is it a struct variable? then define all its struct members as mangled names,
|
||||
// and include the original decl as well.
|
||||
if(decl.datatype==DataType.STRUCT) {
|
||||
@ -102,8 +109,9 @@ internal class AstIdentifiersChecker(private val program: Program) : IAstModifyi
|
||||
// the builtin functions can't be redefined
|
||||
checkResult.add(NameError("builtin function cannot be redefined", subroutine.position))
|
||||
} else {
|
||||
if (subroutine.parameters.any { it.name in BuiltinFunctions })
|
||||
checkResult.add(NameError("builtin function name cannot be used as parameter", subroutine.position))
|
||||
// already reported elsewhere:
|
||||
// if (subroutine.parameters.any { it.name in BuiltinFunctions })
|
||||
// checkResult.add(NameError("builtin function name cannot be used as parameter", subroutine.position))
|
||||
|
||||
val existing = program.namespace.lookup(listOf(subroutine.name), subroutine)
|
||||
if (existing != null && existing !== subroutine)
|
||||
|
@ -9,6 +9,25 @@ class AssemblyProgram(val name: String) {
|
||||
private val assemblyFile = "$name.asm"
|
||||
private val viceMonListFile = "$name.vice-mon-list"
|
||||
|
||||
companion object {
|
||||
// reserved by the 64tass assembler (on top of prog8"s own reserved names)
|
||||
val reservedNames = setOf("bit", "bits", "bool", "bytes", "code", "dict", "gap", "int", "list", "tuple", "type",
|
||||
"trunc", " frac", "cbrt", "log10", "log", "exp", "pow", "asin", "sinh", "acos", "cosh", "tanh", "hypot",
|
||||
"atan2", "sign", "binary", "format", "random", "range", "repr", "size", "sort")
|
||||
|
||||
// 6502 opcodes (including aliases and illegal opcodes), these cannot be used as variable names either
|
||||
val opcodeNames = setOf("adc", "ahx", "alr", "anc", "and", "ane", "arr", "asl", "asr", "axs", "bcc", "bcs",
|
||||
"beq", "bge", "bit", "blt", "bmi", "bne", "bpl", "brk", "bvc", "bvs", "clc",
|
||||
"cld", "cli", "clv", "cmp", "cpx", "cpy", "dcm", "dcp", "dec", "dex", "dey",
|
||||
"eor", "gcc", "gcs", "geq", "gge", "glt", "gmi", "gne", "gpl", "gvc", "gvs",
|
||||
"inc", "ins", "inx", "iny", "isb", "isc", "jam", "jmp", "jsr", "lae", "las",
|
||||
"lax", "lda", "lds", "ldx", "ldy", "lsr", "lxa", "nop", "ora", "pha", "php",
|
||||
"pla", "plp", "rla", "rol", "ror", "rra", "rti", "rts", "sax", "sbc", "sbx",
|
||||
"sec", "sed", "sei", "sha", "shl", "shr", "shs", "shx", "shy", "slo", "sre",
|
||||
"sta", "stx", "sty", "tas", "tax", "tay", "tsx", "txa", "txs", "tya", "xaa")
|
||||
}
|
||||
|
||||
|
||||
fun assemble(options: CompilationOptions) {
|
||||
// add "-Wlong-branch" to see warnings about conversion of branch instructions to jumps
|
||||
val command = mutableListOf("64tass", "--ascii", "--case-sensitive", "--long-branch", "-Wall", "-Wno-strict-bool",
|
||||
@ -41,7 +60,7 @@ class AssemblyProgram(val name: String) {
|
||||
private fun generateBreakpointList() {
|
||||
// builds list of breakpoints, appends to monitor list file
|
||||
val breakpoints = mutableListOf<String>()
|
||||
val pattern = Regex("""al (\w+) \S+_prog8_breakpoint_\d+.?""") // gather breakpoints by the source label that's generated for them
|
||||
val pattern = Regex("""al (\w+) \S+_prog8_breakpoint_\d+.?""") // gather breakpoints by the source label that"s generated for them
|
||||
for(line in File(viceMonListFile).readLines()) {
|
||||
val match = pattern.matchEntire(line)
|
||||
if(match!=null)
|
||||
|
@ -644,19 +644,18 @@ internal class AsmGen2(val program: Program,
|
||||
val scopedParamVar = (sub.scopedname+"."+paramVar.name).split(".")
|
||||
val target = AssignTarget(null, IdentifierReference(scopedParamVar, sub.position), null, null, sub.position)
|
||||
target.linkParents(value.parent)
|
||||
val literal = value as? NumericLiteralValue
|
||||
when {
|
||||
literal!=null -> {
|
||||
when (value) {
|
||||
is NumericLiteralValue -> {
|
||||
// optimize when the argument is a constant literal
|
||||
when(arg.value.type) {
|
||||
in ByteDatatypes -> assignFromByteConstant(target, literal.number.toShort())
|
||||
in WordDatatypes -> assignFromWordConstant(target, literal.number.toInt())
|
||||
DataType.FLOAT -> assignFromFloatConstant(target, literal.number.toDouble())
|
||||
in ByteDatatypes -> assignFromByteConstant(target, value.number.toShort())
|
||||
in WordDatatypes -> assignFromWordConstant(target, value.number.toInt())
|
||||
DataType.FLOAT -> assignFromFloatConstant(target, value.number.toDouble())
|
||||
in PassByReferenceDatatypes -> throw AssemblyError("can't pass string/array as arguments?")
|
||||
else -> throw AssemblyError("weird arg datatype")
|
||||
}
|
||||
}
|
||||
value is IdentifierReference -> {
|
||||
is IdentifierReference -> {
|
||||
// optimize when the argument is a variable
|
||||
when (arg.value.type) {
|
||||
in ByteDatatypes -> assignFromByteVariable(target, value)
|
||||
@ -666,7 +665,29 @@ internal class AsmGen2(val program: Program,
|
||||
else -> throw AssemblyError("weird arg datatype")
|
||||
}
|
||||
}
|
||||
else -> TODO("non-constant sub arg $arg")
|
||||
is RegisterExpr -> {
|
||||
assignFromRegister(target, value.register)
|
||||
}
|
||||
is DirectMemoryRead -> {
|
||||
when(value.addressExpression) {
|
||||
is NumericLiteralValue -> {
|
||||
val address = (value.addressExpression as NumericLiteralValue).number.toInt()
|
||||
assignFromMemoryByte(target, address, null)
|
||||
}
|
||||
is IdentifierReference -> {
|
||||
assignFromMemoryByte(target, null, value.addressExpression as IdentifierReference)
|
||||
}
|
||||
else -> {
|
||||
translateExpression(value.addressExpression)
|
||||
out(" jsr prog8_lib.read_byte_from_address | inx")
|
||||
assignFromRegister(target, Register.A)
|
||||
}
|
||||
}
|
||||
}
|
||||
else -> {
|
||||
translateExpression(value)
|
||||
assignFromEvalResult(target)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// pass arg via a register parameter
|
||||
@ -1149,7 +1170,21 @@ internal class AsmGen2(val program: Program,
|
||||
}
|
||||
|
||||
private fun translateExpression(expr: DirectMemoryRead) {
|
||||
TODO("memread $expr")
|
||||
when(expr.addressExpression) {
|
||||
is NumericLiteralValue -> {
|
||||
val address = (expr.addressExpression as NumericLiteralValue).number.toInt()
|
||||
out(" lda ${address.toHex()} | sta $ESTACK_LO_HEX,x | dex")
|
||||
}
|
||||
is IdentifierReference -> {
|
||||
val sourceName = asmIdentifierName(expr.addressExpression as IdentifierReference)
|
||||
out(" lda $sourceName | sta $ESTACK_LO_HEX,x | dex")
|
||||
}
|
||||
else -> {
|
||||
translateExpression(expr.addressExpression)
|
||||
out(" jsr prog8_lib.read_byte_from_address")
|
||||
out(" sta $ESTACK_LO_PLUS1_HEX,x")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun translateExpression(expr: NumericLiteralValue) {
|
||||
@ -1514,9 +1549,9 @@ internal class AsmGen2(val program: Program,
|
||||
out("""
|
||||
inx
|
||||
lda $ESTACK_LO_HEX,x
|
||||
ldy $ESTACK_HI_HEX,x
|
||||
sta (+) +1
|
||||
lda $ESTACK_HI_HEX,x
|
||||
sta (+) +2
|
||||
sty (+) +2
|
||||
lda $sourceName
|
||||
+ sta ${65535.toHex()} ; modified
|
||||
""")
|
||||
@ -1554,7 +1589,97 @@ internal class AsmGen2(val program: Program,
|
||||
}
|
||||
}
|
||||
}
|
||||
else -> out("; TODO assign register $register to $target") // TODO
|
||||
target.memoryAddress!=null -> {
|
||||
val addressExpr = target.memoryAddress.addressExpression
|
||||
val addressLv = addressExpr as? NumericLiteralValue
|
||||
val registerName = register.name.toLowerCase()
|
||||
when {
|
||||
addressLv != null -> out(" st$registerName ${addressLv.number.toHex()}")
|
||||
addressExpr is IdentifierReference -> {
|
||||
val targetName = asmIdentifierName(addressExpr)
|
||||
out(" st$registerName $targetName")
|
||||
}
|
||||
else -> {
|
||||
translateExpression(addressExpr)
|
||||
when (register) {
|
||||
Register.A -> out(" tay")
|
||||
Register.X -> throw AssemblyError("can't use X register here")
|
||||
Register.Y -> {
|
||||
}
|
||||
}
|
||||
out("""
|
||||
inx
|
||||
lda $ESTACK_LO_HEX,x
|
||||
sta (+) +1
|
||||
lda $ESTACK_HI_HEX,x
|
||||
sta (+) +2
|
||||
+ sty ${65535.toHex()} ; modified
|
||||
""")
|
||||
}
|
||||
}
|
||||
}
|
||||
targetArrayIdx!=null -> {
|
||||
val index = targetArrayIdx.arrayspec.index
|
||||
val targetName = asmIdentifierName(targetArrayIdx.identifier)
|
||||
when (index) {
|
||||
is NumericLiteralValue -> {
|
||||
val memindex = index.number.toInt()
|
||||
when(register) {
|
||||
Register.A -> out(" sta $targetName+$memindex")
|
||||
Register.X -> out(" stx $targetName+$memindex")
|
||||
Register.Y -> out(" sty $targetName+$memindex")
|
||||
}
|
||||
}
|
||||
is RegisterExpr -> {
|
||||
when(register) {
|
||||
Register.A -> out(" sta ${C64Zeropage.SCRATCH_B1}")
|
||||
Register.X -> out(" stx ${C64Zeropage.SCRATCH_B1}")
|
||||
Register.Y -> out(" sty ${C64Zeropage.SCRATCH_B1}")
|
||||
}
|
||||
when(index.register) {
|
||||
Register.A -> {}
|
||||
Register.X -> out(" txa")
|
||||
Register.Y -> out(" tya")
|
||||
}
|
||||
out("""
|
||||
tay
|
||||
lda ${C64Zeropage.SCRATCH_B1}
|
||||
sta $targetName,y
|
||||
""")
|
||||
}
|
||||
is IdentifierReference -> {
|
||||
when(register) {
|
||||
Register.A -> out(" sta ${C64Zeropage.SCRATCH_B1}")
|
||||
Register.X -> out(" stx ${C64Zeropage.SCRATCH_B1}")
|
||||
Register.Y -> out(" sty ${C64Zeropage.SCRATCH_B1}")
|
||||
}
|
||||
out("""
|
||||
lda ${asmIdentifierName(index)}
|
||||
tay
|
||||
lda ${C64Zeropage.SCRATCH_B1}
|
||||
sta $targetName,y
|
||||
""")
|
||||
}
|
||||
else -> {
|
||||
saveRegister(register)
|
||||
translateExpression(index)
|
||||
restoreRegister(register)
|
||||
when(register) {
|
||||
Register.A -> out(" sta ${C64Zeropage.SCRATCH_B1}")
|
||||
Register.X -> out(" stx ${C64Zeropage.SCRATCH_B1}")
|
||||
Register.Y -> out(" sty ${C64Zeropage.SCRATCH_B1}")
|
||||
}
|
||||
out("""
|
||||
inx
|
||||
lda $ESTACK_LO_HEX,x
|
||||
tay
|
||||
lda ${C64Zeropage.SCRATCH_B1}
|
||||
sta $targetName,y
|
||||
""")
|
||||
}
|
||||
}
|
||||
}
|
||||
else -> TODO("assign register $register to $target")
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -6,22 +6,27 @@
|
||||
|
||||
sub start() {
|
||||
|
||||
str s1 = "hello"
|
||||
str s2 = "hello"
|
||||
str s3 = "hello"
|
||||
str s4 = "hello"
|
||||
carry(1)
|
||||
carry(0)
|
||||
; ubyte bb = @($d020)+4
|
||||
; ubyte bb2 = @($d020+A)+4
|
||||
;
|
||||
; subje(55)
|
||||
; subje(@($d020+bb))
|
||||
; subje(A)
|
||||
; subje(bb)
|
||||
; subje(bb+43)
|
||||
}
|
||||
|
||||
if true {
|
||||
c64scr.print("irmen")
|
||||
c64scr.print("hello")
|
||||
c64scr.print("hello2")
|
||||
}
|
||||
|
||||
if true {
|
||||
c64scr.print("irmen")
|
||||
c64scr.print("hello")
|
||||
c64scr.print("hello2")
|
||||
}
|
||||
sub carry(ubyte cc) {
|
||||
A=cc
|
||||
if A!=0
|
||||
c64scr.print("carry set\n")
|
||||
else
|
||||
c64scr.print("carry clear\n")
|
||||
}
|
||||
|
||||
sub subje(ubyte arg) {
|
||||
A=arg
|
||||
}
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user