assembler reserved symbols checked

This commit is contained in:
Irmen de Jong 2019-07-28 23:37:33 +02:00
parent 2c25df122a
commit b0dda08e74
5 changed files with 198 additions and 30 deletions

View File

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

View File

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

View File

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

View File

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

View File

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