added direct memory access ("poke"/"peek")

This commit is contained in:
Irmen de Jong 2018-12-30 21:40:27 +01:00
parent 75a57da44d
commit 500777bf78
18 changed files with 1119 additions and 963 deletions

View File

@ -120,6 +120,7 @@ assign_target:
| identifier | identifier
| scoped_identifier | scoped_identifier
| arrayindexed | arrayindexed
| directmemory
; ;
postincrdecr : assign_target operator = ('++' | '--') ; postincrdecr : assign_target operator = ('++' | '--') ;
@ -146,6 +147,7 @@ expression :
| identifier | identifier
| scoped_identifier | scoped_identifier
| arrayindexed | arrayindexed
| directmemory
| expression typecast | expression typecast
; ;
@ -157,6 +159,8 @@ arrayindexed :
(identifier | scoped_identifier ) arrayspec (identifier | scoped_identifier ) arrayspec
; ;
directmemory : '@' expression ;
functioncall : functioncall :
(identifier | scoped_identifier) '(' expression_list? ')' (identifier | scoped_identifier) '(' expression_list? ')'

View File

@ -0,0 +1,21 @@
%import c64lib
%import c64utils
~ main {
sub start() {
c64.STROUT("balloon sprites!\n")
const uword SP0X = $d000 ; @todo "address-of" operator '&' so we can write &c64.SP0X
const uword SP0Y = $d001 ; @todo "address-of" operator '&' so we can write &c64.SP0Y
for ubyte i in 0 to 7 {
@(SP0X+i*2) = 30+i*30
@(SP0Y+i*2) = 100+i*10
}
c64.SPENA = 255 ; enable all sprites
}
}

View File

@ -1,95 +1,17 @@
%import c64utils %import c64utils
%option enable_floats
~ main { ~ main {
float[10] xcoor = [1,2,3,4,5,6,7,8,9.9,11.11 ]
float[10] ycoor = [11,22,33,44,55,66,77,88,99.9,111.11 ]
float[10] zcoor = [111,222,333,444,555,666,777,888,999.9,1001.11 ]
sub start() { sub start() {
c64scr.print("\nxcoor:\n")
for float f1 in xcoor {
c64flt.print_f(f1)
c64.CHROUT(',')
}
c64.CHROUT('\n') uword vic = $d000
c64scr.print("ycoor:\n") const uword cvic = $d000
for float f2 in ycoor {
c64flt.print_f(f2)
c64.CHROUT(',')
}
c64.CHROUT('\n')
c64scr.print("zcoor:\n")
for float f3 in zcoor {
c64flt.print_f(f3)
c64.CHROUT(',')
}
c64.CHROUT('\n')
c64.CHROUT('X') @(cvic+$20) = 7
c64scr.print_ub(X) @(cvic+$21) = @(cvic+$20)
c64.CHROUT('\n')
float avgfx = avg(xcoor)
float avgfy = avg(ycoor)
float avgfz = avg(zcoor)
c64.CHROUT('X')
c64scr.print_ub(X)
c64.CHROUT('\n')
c64scr.print("avgfx=") @(vic+$20) = 5
c64flt.print_f(avgfx) @(vic+$21) = @(vic+$20)
c64.CHROUT('\n')
c64scr.print("avgfy=")
c64flt.print_f(avgfy)
c64.CHROUT('\n')
c64scr.print("avgfz=")
c64flt.print_f(avgfz)
c64.CHROUT('\n')
separated2:
c64scr.print("\nseparated i=2\n")
c64scr.print(" x[2]=")
ubyte ii=2
c64flt.print_f(xcoor[ii])
c64scr.print(" y[2]=")
c64flt.print_f(ycoor[ii])
c64scr.print(" z[2]=")
c64flt.print_f(zcoor[ii])
separated3:
c64scr.print("\nseparated i=3\n")
ii=3
c64scr.print(" x[3]=")
c64flt.print_f(xcoor[ii])
c64scr.print(" y[3]=")
c64flt.print_f(ycoor[ii])
c64scr.print(" z[3]=")
c64flt.print_f(zcoor[ii])
c64.CHROUT('\n')
c64.CHROUT('X')
c64scr.print_ub(X)
c64.CHROUT('\n')
avgfx = avg(xcoor)
avgfy = avg(ycoor)
avgfz = avg(zcoor)
c64.CHROUT('X')
c64scr.print_ub(X)
c64.CHROUT('\n')
c64scr.print("avgfx=")
c64flt.print_f(avgfx)
c64.CHROUT('\n')
c64scr.print("avgfy=")
c64flt.print_f(avgfy)
c64.CHROUT('\n')
c64scr.print("avgfz=")
c64flt.print_f(avgfz)
c64.CHROUT('\n')
} }
} }

View File

@ -261,6 +261,7 @@ interface IAstProcessor {
fun process(assignTarget: AssignTarget): AssignTarget { fun process(assignTarget: AssignTarget): AssignTarget {
assignTarget.arrayindexed?.process(this) assignTarget.arrayindexed?.process(this)
assignTarget.identifier?.process(this) assignTarget.identifier?.process(this)
assignTarget.memAddressExpression = assignTarget.memAddressExpression?.process(this)
return assignTarget return assignTarget
} }
@ -273,6 +274,11 @@ interface IAstProcessor {
typecastExpression.expression = typecastExpression.expression.process(this) typecastExpression.expression = typecastExpression.expression.process(this)
return typecastExpression return typecastExpression
} }
fun process(directmemoryExpression: DirectMemoryExpression): IExpression {
directmemoryExpression.addressExpression = directmemoryExpression.addressExpression.process(this)
return directmemoryExpression
}
} }
@ -725,6 +731,7 @@ class VariableInitializationAssignment(target: AssignTarget, aug_op: String?, va
data class AssignTarget(val register: Register?, data class AssignTarget(val register: Register?,
val identifier: IdentifierReference?, val identifier: IdentifierReference?,
val arrayindexed: ArrayIndexedExpression?, val arrayindexed: ArrayIndexedExpression?,
var memAddressExpression: IExpression?,
override val position: Position) : Node { override val position: Position) : Node {
override lateinit var parent: Node override lateinit var parent: Node
@ -732,6 +739,7 @@ data class AssignTarget(val register: Register?,
this.parent = parent this.parent = parent
identifier?.linkParents(this) identifier?.linkParents(this)
arrayindexed?.linkParents(this) arrayindexed?.linkParents(this)
memAddressExpression?.linkParents(this)
} }
fun process(processor: IAstProcessor) = processor.process(this) fun process(processor: IAstProcessor) = processor.process(this)
@ -739,9 +747,10 @@ data class AssignTarget(val register: Register?,
companion object { companion object {
fun fromExpr(expr: IExpression): AssignTarget { fun fromExpr(expr: IExpression): AssignTarget {
return when (expr) { return when (expr) {
is RegisterExpr -> AssignTarget(expr.register, null, null, expr.position) is RegisterExpr -> AssignTarget(expr.register, null, null, null, expr.position)
is IdentifierReference -> AssignTarget(null, expr, null, expr.position) is IdentifierReference -> AssignTarget(null, expr, null, null, expr.position)
is ArrayIndexedExpression -> AssignTarget(null, null, expr, expr.position) is ArrayIndexedExpression -> AssignTarget(null, null, expr, null, expr.position)
is DirectMemoryExpression -> AssignTarget(null, null, null, expr, expr.position)
else -> throw FatalAstException("invalid expression object $expr") else -> throw FatalAstException("invalid expression object $expr")
} }
} }
@ -761,6 +770,10 @@ data class AssignTarget(val register: Register?,
if(dt!=null) if(dt!=null)
return dt return dt
} }
if(memAddressExpression!=null)
return DataType.UBYTE
return null return null
} }
@ -771,6 +784,8 @@ data class AssignTarget(val register: Register?,
return identifier.nameInSource.last() return identifier.nameInSource.last()
if(arrayindexed!=null) if(arrayindexed!=null)
return arrayindexed.identifier!!.nameInSource.last() return arrayindexed.identifier!!.nameInSource.last()
if(memAddressExpression is LiteralValue)
return (memAddressExpression as LiteralValue).asIntegerValue.toString()
return "???" return "???"
} }
} }
@ -1012,6 +1027,24 @@ class TypecastExpression(var expression: IExpression, var type: DataType, overri
} }
class DirectMemoryExpression(var addressExpression: IExpression, override val position: Position) : IExpression {
override lateinit var parent: Node
override fun linkParents(parent: Node) {
this.parent = parent
this.addressExpression.linkParents(this)
}
override fun process(processor: IAstProcessor) = processor.process(this)
override fun referencesIdentifier(name: String) = false
override fun resultingDatatype(namespace: INameScope, heap: HeapValues): DataType? = DataType.UBYTE
override fun isIterable(namespace: INameScope, heap: HeapValues) = false
override fun constValue(namespace: INameScope, heap: HeapValues) = null
override fun toString(): String {
return "DirectMemory($addressExpression)"
}
}
private data class NumericLiteral(val number: Number, val datatype: DataType) private data class NumericLiteral(val number: Number, val datatype: DataType)
@ -1942,14 +1975,14 @@ private fun prog8Parser.Assign_targetContext.toAst() : AssignTarget {
val register = register()?.toAst() val register = register()?.toAst()
val identifier = identifier() val identifier = identifier()
return when { return when {
register!=null -> AssignTarget(register, null, null, toPosition()) register!=null -> AssignTarget(register, null, null, null, toPosition())
identifier!=null -> AssignTarget(null, identifier.toAst(), null, toPosition()) identifier!=null -> AssignTarget(null, identifier.toAst(), null, null, toPosition())
arrayindexed()!=null -> AssignTarget(null, null, arrayindexed().toAst(), toPosition()) arrayindexed()!=null -> AssignTarget(null, null, arrayindexed().toAst(), null, toPosition())
else -> AssignTarget(null, scoped_identifier()?.toAst(), null, toPosition()) directmemory()!=null -> AssignTarget(null, null, null, directmemory().expression().toAst(), toPosition())
else -> AssignTarget(null, scoped_identifier()?.toAst(), null, null, toPosition())
} }
} }
private fun prog8Parser.RegisterContext.toAst() = Register.valueOf(text.toUpperCase()) private fun prog8Parser.RegisterContext.toAst() = Register.valueOf(text.toUpperCase())
private fun prog8Parser.DatatypeContext.toAst() = DataType.valueOf(text.toUpperCase()) private fun prog8Parser.DatatypeContext.toAst() = DataType.valueOf(text.toUpperCase())
@ -2074,6 +2107,9 @@ private fun prog8Parser.ExpressionContext.toAst() : IExpression {
if(typecast()!=null) if(typecast()!=null)
return TypecastExpression(expression(0).toAst(), typecast().datatype().toAst(), toPosition()) return TypecastExpression(expression(0).toAst(), typecast().datatype().toAst(), toPosition())
if(directmemory()!=null)
return DirectMemoryExpression(directmemory().expression().toAst(), toPosition())
throw FatalAstException(text) throw FatalAstException(text)
} }

View File

@ -387,6 +387,13 @@ class AstChecker(private val namespace: INameScope,
} }
private fun processAssignmentTarget(assignment: Assignment, target: AssignTarget): Assignment { private fun processAssignmentTarget(assignment: Assignment, target: AssignTarget): Assignment {
val memAddr = target.memAddressExpression?.constValue(namespace, heap)?.asIntegerValue
if(memAddr!=null) {
if(memAddr<0 || memAddr>=65536)
checkResult.add(ExpressionError("address out of range", target.position))
return assignment
}
if(target.identifier!=null) { if(target.identifier!=null) {
val targetName = target.identifier.nameInSource val targetName = target.identifier.nameInSource
val targetSymbol = namespace.lookup(targetName, assignment) val targetSymbol = namespace.lookup(targetName, assignment)

View File

@ -121,7 +121,7 @@ class StatementReorderer(private val namespace: INameScope, private val heap: He
else else
declvalue declvalue
return VariableInitializationAssignment( return VariableInitializationAssignment(
AssignTarget(null, IdentifierReference(decl.scopedname.split("."), decl.position), null, decl.position), AssignTarget(null, IdentifierReference(decl.scopedname.split("."), decl.position), null, null, decl.position),
null, null,
value, value,
decl.position decl.position

View File

@ -580,6 +580,7 @@ private class StatementTranslator(private val prog: IntermediateProgram,
is ArrayIndexedExpression -> translate(expr, false) is ArrayIndexedExpression -> translate(expr, false)
is RangeExpr -> throw CompilerException("it's not possible to just have a range expression that has to be translated") is RangeExpr -> throw CompilerException("it's not possible to just have a range expression that has to be translated")
is TypecastExpression -> translate(expr) is TypecastExpression -> translate(expr)
is DirectMemoryExpression -> translate(expr)
else -> { else -> {
val lv = expr.constValue(namespace, heap) ?: throw CompilerException("constant expression required, not $expr") val lv = expr.constValue(namespace, heap) ?: throw CompilerException("constant expression required, not $expr")
when(lv.type) { when(lv.type) {
@ -876,7 +877,7 @@ private class StatementTranslator(private val prog: IntermediateProgram,
} else { } else {
when (arg.second.registerOrPair!!) { when (arg.second.registerOrPair!!) {
A -> { A -> {
val assign = Assignment(listOf(AssignTarget(Register.A, null, null, callPosition)), null, arg.first, callPosition) val assign = Assignment(listOf(AssignTarget(Register.A, null, null, null, callPosition)), null, arg.first, callPosition)
assign.linkParents(arguments[0].parent) assign.linkParents(arguments[0].parent)
translate(assign) translate(assign)
} }
@ -885,12 +886,12 @@ private class StatementTranslator(private val prog: IntermediateProgram,
prog.instr(Opcode.RSAVEX) prog.instr(Opcode.RSAVEX)
restoreX = true restoreX = true
} }
val assign = Assignment(listOf(AssignTarget(Register.X, null, null, callPosition)), null, arg.first, callPosition) val assign = Assignment(listOf(AssignTarget(Register.X, null, null, null, callPosition)), null, arg.first, callPosition)
assign.linkParents(arguments[0].parent) assign.linkParents(arguments[0].parent)
translate(assign) translate(assign)
} }
Y -> { Y -> {
val assign = Assignment(listOf(AssignTarget(Register.Y, null, null, callPosition)), null, arg.first, callPosition) val assign = Assignment(listOf(AssignTarget(Register.Y, null, null, null, callPosition)), null, arg.first, callPosition)
assign.linkParents(arguments[0].parent) assign.linkParents(arguments[0].parent)
translate(assign) translate(assign)
} }
@ -906,8 +907,8 @@ private class StatementTranslator(private val prog: IntermediateProgram,
DataType.UBYTE -> { DataType.UBYTE -> {
valueA=arg.first valueA=arg.first
valueX=LiteralValue.optimalInteger(0, callPosition) valueX=LiteralValue.optimalInteger(0, callPosition)
val assignA = Assignment(listOf(AssignTarget(Register.A, null, null, callPosition)), null, valueA, callPosition) val assignA = Assignment(listOf(AssignTarget(Register.A, null, null, null, callPosition)), null, valueA, callPosition)
val assignX = Assignment(listOf(AssignTarget(Register.X, null, null, callPosition)), null, valueX, callPosition) val assignX = Assignment(listOf(AssignTarget(Register.X, null, null, null, callPosition)), null, valueX, callPosition)
assignA.linkParents(arguments[0].parent) assignA.linkParents(arguments[0].parent)
assignX.linkParents(arguments[0].parent) assignX.linkParents(arguments[0].parent)
translate(assignA) translate(assignA)
@ -932,8 +933,8 @@ private class StatementTranslator(private val prog: IntermediateProgram,
DataType.UBYTE -> { DataType.UBYTE -> {
valueA=arg.first valueA=arg.first
valueY=LiteralValue.optimalInteger(0, callPosition) valueY=LiteralValue.optimalInteger(0, callPosition)
val assignA = Assignment(listOf(AssignTarget(Register.A, null, null, callPosition)), null, valueA, callPosition) val assignA = Assignment(listOf(AssignTarget(Register.A, null, null, null, callPosition)), null, valueA, callPosition)
val assignY = Assignment(listOf(AssignTarget(Register.Y, null, null, callPosition)), null, valueY, callPosition) val assignY = Assignment(listOf(AssignTarget(Register.Y, null, null, null, callPosition)), null, valueY, callPosition)
assignA.linkParents(arguments[0].parent) assignA.linkParents(arguments[0].parent)
assignY.linkParents(arguments[0].parent) assignY.linkParents(arguments[0].parent)
translate(assignA) translate(assignA)
@ -962,8 +963,8 @@ private class StatementTranslator(private val prog: IntermediateProgram,
DataType.UBYTE -> { DataType.UBYTE -> {
valueX=arg.first valueX=arg.first
valueY=LiteralValue.optimalInteger(0, callPosition) valueY=LiteralValue.optimalInteger(0, callPosition)
val assignX = Assignment(listOf(AssignTarget(Register.X, null, null, callPosition)), null, valueX, callPosition) val assignX = Assignment(listOf(AssignTarget(Register.X, null, null, null, callPosition)), null, valueX, callPosition)
val assignY = Assignment(listOf(AssignTarget(Register.Y, null, null, callPosition)), null, valueY, callPosition) val assignY = Assignment(listOf(AssignTarget(Register.Y, null, null, null, callPosition)), null, valueY, callPosition)
assignX.linkParents(arguments[0].parent) assignX.linkParents(arguments[0].parent)
assignY.linkParents(arguments[0].parent) assignY.linkParents(arguments[0].parent)
translate(assignX) translate(assignX)
@ -1481,6 +1482,17 @@ private class StatementTranslator(private val prog: IntermediateProgram,
} }
assignTarget.register != null -> prog.instr(Opcode.POP_VAR_BYTE, callLabel = assignTarget.register.toString()) assignTarget.register != null -> prog.instr(Opcode.POP_VAR_BYTE, callLabel = assignTarget.register.toString())
assignTarget.arrayindexed != null -> translate(assignTarget.arrayindexed, true) // write value to it assignTarget.arrayindexed != null -> translate(assignTarget.arrayindexed, true) // write value to it
assignTarget.memAddressExpression != null -> {
val address = assignTarget.memAddressExpression?.constValue(namespace, heap)?.asIntegerValue
if(address!=null) {
// const integer address given
prog.instr(Opcode.POP_MEM_BYTE, arg=Value(DataType.UWORD, address))
} else {
translate(assignTarget.memAddressExpression!!)
prog.instr(Opcode.POP_MEMWRITE)
}
}
else -> throw CompilerException("corrupt assigntarget $assignTarget")
} }
} }
@ -1710,9 +1722,9 @@ private class StatementTranslator(private val prog: IntermediateProgram,
// loop starts here // loop starts here
prog.label(loopLabel) prog.label(loopLabel)
val assignTarget = if(loop.loopRegister!=null) val assignTarget = if(loop.loopRegister!=null)
AssignTarget(loop.loopRegister, null, null, loop.position) AssignTarget(loop.loopRegister, null, null, null, loop.position)
else else
AssignTarget(null, loop.loopVar!!.copy(), null, loop.position) AssignTarget(null, loop.loopVar!!.copy(), null, null, loop.position)
val arrayspec = ArraySpec(IdentifierReference(listOf(ForLoop.iteratorLoopcounterVarname), loop.position), loop.position) val arrayspec = ArraySpec(IdentifierReference(listOf(ForLoop.iteratorLoopcounterVarname), loop.position), loop.position)
val assignLv = Assignment( val assignLv = Assignment(
listOf(assignTarget), null, listOf(assignTarget), null,
@ -1843,9 +1855,9 @@ private class StatementTranslator(private val prog: IntermediateProgram,
*/ */
fun makeAssignmentTarget(): AssignTarget { fun makeAssignmentTarget(): AssignTarget {
return if(varname!=null) return if(varname!=null)
AssignTarget(null, IdentifierReference(varname, range.position), null, range.position) AssignTarget(null, IdentifierReference(varname, range.position), null, null, range.position)
else else
AssignTarget(register, null, null, range.position) AssignTarget(register, null, null, null, range.position)
} }
val startAssignment = Assignment(listOf(makeAssignmentTarget()), null, range.from, range.position) val startAssignment = Assignment(listOf(makeAssignmentTarget()), null, range.from, range.position)
@ -2071,4 +2083,15 @@ private class StatementTranslator(private val prog: IntermediateProgram,
} }
} }
private fun translate(expr: DirectMemoryExpression) {
// for now, only a single memory location (ubyte) is read at a time.
val address = expr.addressExpression.constValue(namespace, heap)?.asIntegerValue
if(address!=null) {
prog.instr(Opcode.PUSH_MEM_UB, arg = Value(DataType.UWORD, address))
} else {
translate(expr.addressExpression)
prog.instr(Opcode.PUSH_MEMREAD)
}
}
} }

View File

@ -11,6 +11,7 @@ enum class Opcode {
PUSH_MEM_W, // push word value from memory to stack PUSH_MEM_W, // push word value from memory to stack
PUSH_MEM_UW, // push unsigned word value from memory to stack PUSH_MEM_UW, // push unsigned word value from memory to stack
PUSH_MEM_FLOAT, // push float value from memory to stack PUSH_MEM_FLOAT, // push float value from memory to stack
PUSH_MEMREAD, // push memory value from address that's on the stack
PUSH_VAR_BYTE, // push byte variable (ubyte, byte) PUSH_VAR_BYTE, // push byte variable (ubyte, byte)
PUSH_VAR_WORD, // push word variable (uword, word) PUSH_VAR_WORD, // push word variable (uword, word)
PUSH_VAR_FLOAT, // push float variable PUSH_VAR_FLOAT, // push float variable
@ -27,6 +28,7 @@ enum class Opcode {
POP_MEM_BYTE, // pop (u)byte value into destination memory address POP_MEM_BYTE, // pop (u)byte value into destination memory address
POP_MEM_WORD, // pop (u)word value into destination memory address POP_MEM_WORD, // pop (u)word value into destination memory address
POP_MEM_FLOAT, // pop float value into destination memory address POP_MEM_FLOAT, // pop float value into destination memory address
POP_MEMWRITE, // pop address and byte stack and write the byte to the memory address
POP_VAR_BYTE, // pop (u)byte value into variable POP_VAR_BYTE, // pop (u)byte value into variable
POP_VAR_WORD, // pop (u)word value into variable POP_VAR_WORD, // pop (u)word value into variable
POP_VAR_FLOAT, // pop float value into variable POP_VAR_FLOAT, // pop float value into variable

View File

@ -493,6 +493,17 @@ class AsmGen(val options: CompilationOptions, val program: IntermediateProgram,
Opcode.PUSH_MEM_FLOAT -> { Opcode.PUSH_MEM_FLOAT -> {
" lda #<${hexVal(ins)} | ldy #>${hexVal(ins)}| jsr prog8_lib.push_float" " lda #<${hexVal(ins)} | ldy #>${hexVal(ins)}| jsr prog8_lib.push_float"
} }
Opcode.PUSH_MEMREAD -> {
"""
lda ${(ESTACK_LO+1).toHex()},x
sta ${C64Zeropage.SCRATCH_W1}
lda ${(ESTACK_HI+1).toHex()},x
sta ${C64Zeropage.SCRATCH_W1+1}
ldy #0
lda (${C64Zeropage.SCRATCH_W1}),y
sta ${(ESTACK_LO+1).toHex()},x
"""
}
Opcode.PUSH_REGAY_WORD -> { Opcode.PUSH_REGAY_WORD -> {
" sta ${ESTACK_LO.toHex()},x | tya | sta ${ESTACK_HI.toHex()},x | dex " " sta ${ESTACK_LO.toHex()},x | tya | sta ${ESTACK_HI.toHex()},x | dex "
@ -579,6 +590,20 @@ class AsmGen(val options: CompilationOptions, val program: IntermediateProgram,
Opcode.POP_MEM_FLOAT -> { Opcode.POP_MEM_FLOAT -> {
" lda ${hexVal(ins)} | ldy ${hexValPlusOne(ins)} | jsr prog8_lib.pop_float" " lda ${hexVal(ins)} | ldy ${hexValPlusOne(ins)} | jsr prog8_lib.pop_float"
} }
Opcode.POP_MEMWRITE -> {
"""
inx
lda ${ESTACK_LO.toHex()},x
sta ${C64Zeropage.SCRATCH_W1}
lda ${ESTACK_HI.toHex()},x
sta ${C64Zeropage.SCRATCH_W1+1}
inx
lda ${ESTACK_LO.toHex()},x
ldy #0
sta (${C64Zeropage.SCRATCH_W1}),y
"""
}
Opcode.POP_VAR_BYTE -> { Opcode.POP_VAR_BYTE -> {
when (ins.callLabel) { when (ins.callLabel) {
"X" -> throw CompilerException("makes no sense to pop X, it's used as a stack pointer itself") "X" -> throw CompilerException("makes no sense to pop X, it's used as a stack pointer itself")
@ -702,8 +727,8 @@ class AsmGen(val options: CompilationOptions, val program: IntermediateProgram,
Opcode.CAST_F_TO_B -> " jsr prog8_lib.stack_float2w" Opcode.CAST_F_TO_B -> " jsr prog8_lib.stack_float2w"
Opcode.CAST_F_TO_UW -> " jsr prog8_lib.stack_float2uw" Opcode.CAST_F_TO_UW -> " jsr prog8_lib.stack_float2uw"
Opcode.CAST_F_TO_W -> " jsr prog8_lib.stack_float2w" Opcode.CAST_F_TO_W -> " jsr prog8_lib.stack_float2w"
Opcode.CAST_UB_TO_UW, Opcode.CAST_UB_TO_W -> " lda #0 | sta ${ESTACK_HI+1},x" // clear the msb Opcode.CAST_UB_TO_UW, Opcode.CAST_UB_TO_W -> " lda #0 | sta ${(ESTACK_HI+1).toHex()},x" // clear the msb
Opcode.CAST_B_TO_UW, Opcode.CAST_B_TO_W -> " ${signExtendA("${ESTACK_HI+1},x")}" // sign extend the lsb @todo missing an lda??? Opcode.CAST_B_TO_UW, Opcode.CAST_B_TO_W -> " lda ${(ESTACK_LO+1)},x | ${signExtendA("${(ESTACK_HI+1).toHex()},x")}" // sign extend the lsb
Opcode.MSB -> " lda ${(ESTACK_HI+1).toHex()},x | sta ${(ESTACK_LO+1).toHex()},x" Opcode.MSB -> " lda ${(ESTACK_HI+1).toHex()},x | sta ${(ESTACK_LO+1).toHex()},x"
Opcode.ADD_UB, Opcode.ADD_B -> { Opcode.ADD_UB, Opcode.ADD_B -> {

View File

@ -93,7 +93,7 @@ class StatementOptimizer(private val namespace: INameScope, private val heap: He
if(range.size(heap)==1) { if(range.size(heap)==1) {
// for loop over a (constant) range of just a single value-- optimize the loop away // for loop over a (constant) range of just a single value-- optimize the loop away
// loopvar/reg = range value , follow by block // loopvar/reg = range value , follow by block
val assignment = Assignment(listOf(AssignTarget(forLoop.loopRegister, forLoop.loopVar, null, forLoop.position)), null, range.from, forLoop.position) val assignment = Assignment(listOf(AssignTarget(forLoop.loopRegister, forLoop.loopVar, null, null, forLoop.position)), null, range.from, forLoop.position)
forLoop.body.statements.add(0, assignment) forLoop.body.statements.add(0, assignment)
optimizationsDone++ optimizationsDone++
return forLoop.body return forLoop.body

View File

@ -1,4 +1,4 @@
// Generated from ../antlr/prog8.g4 by ANTLR 4.7.2 // Generated from /home/irmen/Projects/prog8/compiler/antlr/prog8.g4 by ANTLR 4.7.2
package prog8.parser; package prog8.parser;
import org.antlr.v4.runtime.Lexer; import org.antlr.v4.runtime.Lexer;
import org.antlr.v4.runtime.CharStream; import org.antlr.v4.runtime.CharStream;
@ -75,13 +75,13 @@ public class prog8Lexer extends Lexer {
"'&='", "'|='", "'^='", "'%='", "'++'", "'--'", "'('", "')'", "'+'", "'&='", "'|='", "'^='", "'%='", "'++'", "'--'", "'('", "')'", "'+'",
"'-'", "'**'", "'*'", "'/'", "'//'", "'%'", "'<'", "'>'", "'<='", "'>='", "'-'", "'**'", "'*'", "'/'", "'//'", "'%'", "'<'", "'>'", "'<='", "'>='",
"'=='", "'!='", "'&'", "'^'", "'|'", "'to'", "'step'", "'and'", "'or'", "'=='", "'!='", "'&'", "'^'", "'|'", "'to'", "'step'", "'and'", "'or'",
"'xor'", "'not'", "'as'", "'return'", "'break'", "'continue'", "'.'", "'xor'", "'not'", "'as'", "'@'", "'return'", "'break'", "'continue'",
"'A'", "'X'", "'Y'", "'AX'", "'AY'", "'XY'", "'Pc'", "'Pz'", "'Pn'", "'.'", "'A'", "'X'", "'Y'", "'AX'", "'AY'", "'XY'", "'Pc'", "'Pz'", "'Pn'",
"'Pv'", "'.w'", "'true'", "'false'", "'%asm'", "'sub'", "'->'", "'{'", "'Pv'", "'.w'", "'true'", "'false'", "'%asm'", "'sub'", "'->'", "'{'",
"'}'", "'asmsub'", "'clobbers'", "'@'", "'if'", "'else'", "'if_cs'", "'}'", "'asmsub'", "'clobbers'", "'if'", "'else'", "'if_cs'", "'if_cc'",
"'if_cc'", "'if_eq'", "'if_z'", "'if_ne'", "'if_nz'", "'if_pl'", "'if_pos'", "'if_eq'", "'if_z'", "'if_ne'", "'if_nz'", "'if_pl'", "'if_pos'", "'if_mi'",
"'if_mi'", "'if_neg'", "'if_vs'", "'if_vc'", "'for'", "'in'", "'while'", "'if_neg'", "'if_vs'", "'if_vc'", "'for'", "'in'", "'while'", "'repeat'",
"'repeat'", "'until'" "'until'"
}; };
} }
private static final String[] _LITERAL_NAMES = makeLiteralNames(); private static final String[] _LITERAL_NAMES = makeLiteralNames();
@ -238,11 +238,11 @@ public class prog8Lexer extends Lexer {
")\3)\3*\3*\3+\3+\3,\3,\3-\3-\3.\3.\3.\3/\3/\3\60\3\60\3\61\3\61\3\61\3"+ ")\3)\3*\3*\3+\3+\3,\3,\3-\3-\3.\3.\3.\3/\3/\3\60\3\60\3\61\3\61\3\61\3"+
"\62\3\62\3\63\3\63\3\64\3\64\3\65\3\65\3\65\3\66\3\66\3\66\3\67\3\67\3"+ "\62\3\62\3\63\3\63\3\64\3\64\3\65\3\65\3\65\3\66\3\66\3\66\3\67\3\67\3"+
"\67\38\38\38\39\39\3:\3:\3;\3;\3<\3<\3<\3=\3=\3=\3=\3=\3>\3>\3>\3>\3?"+ "\67\38\38\38\39\39\3:\3:\3;\3;\3<\3<\3<\3=\3=\3=\3=\3=\3>\3>\3>\3>\3?"+
"\3?\3?\3@\3@\3@\3@\3A\3A\3A\3A\3B\3B\3B\3C\3C\3C\3C\3C\3C\3C\3D\3D\3D"+ "\3?\3?\3@\3@\3@\3@\3A\3A\3A\3A\3B\3B\3B\3C\3C\3D\3D\3D\3D\3D\3D\3D\3E"+
"\3D\3D\3D\3E\3E\3E\3E\3E\3E\3E\3E\3E\3F\3F\3G\3G\3H\3H\3I\3I\3J\3J\3J"+ "\3E\3E\3E\3E\3E\3F\3F\3F\3F\3F\3F\3F\3F\3F\3G\3G\3H\3H\3I\3I\3J\3J\3K"+
"\3K\3K\3K\3L\3L\3L\3M\3M\3M\3N\3N\3N\3O\3O\3O\3P\3P\3P\3Q\3Q\3Q\3R\3R"+ "\3K\3K\3L\3L\3L\3M\3M\3M\3N\3N\3N\3O\3O\3O\3P\3P\3P\3Q\3Q\3Q\3R\3R\3R"+
"\3R\3R\3R\3S\3S\3S\3S\3S\3S\3T\3T\3T\3T\3T\3U\3U\3U\3U\3V\3V\3V\3W\3W"+ "\3S\3S\3S\3S\3S\3T\3T\3T\3T\3T\3T\3U\3U\3U\3U\3U\3V\3V\3V\3V\3W\3W\3W"+
"\3X\3X\3Y\3Y\3Y\3Y\3Y\3Y\3Y\3Z\3Z\3Z\3Z\3Z\3Z\3Z\3Z\3Z\3[\3[\3\\\3\\\3"+ "\3X\3X\3Y\3Y\3Z\3Z\3Z\3Z\3Z\3Z\3Z\3[\3[\3[\3[\3[\3[\3[\3[\3[\3\\\3\\\3"+
"\\\3]\3]\3]\3]\3]\3^\3^\3^\3^\3^\3^\3_\3_\3_\3_\3_\3_\3`\3`\3`\3`\3`\3"+ "\\\3]\3]\3]\3]\3]\3^\3^\3^\3^\3^\3^\3_\3_\3_\3_\3_\3_\3`\3`\3`\3`\3`\3"+
"`\3a\3a\3a\3a\3a\3b\3b\3b\3b\3b\3b\3c\3c\3c\3c\3c\3c\3d\3d\3d\3d\3d\3"+ "`\3a\3a\3a\3a\3a\3b\3b\3b\3b\3b\3b\3c\3c\3c\3c\3c\3c\3d\3d\3d\3d\3d\3"+
"d\3e\3e\3e\3e\3e\3e\3e\3f\3f\3f\3f\3f\3f\3g\3g\3g\3g\3g\3g\3g\3h\3h\3"+ "d\3e\3e\3e\3e\3e\3e\3e\3f\3f\3f\3f\3f\3f\3g\3g\3g\3g\3g\3g\3g\3h\3h\3"+
@ -304,13 +304,13 @@ public class prog8Lexer extends Lexer {
"\2\2k\u01ef\3\2\2\2m\u01f2\3\2\2\2o\u01f5\3\2\2\2q\u01f8\3\2\2\2s\u01fa"+ "\2\2k\u01ef\3\2\2\2m\u01f2\3\2\2\2o\u01f5\3\2\2\2q\u01f8\3\2\2\2s\u01fa"+
"\3\2\2\2u\u01fc\3\2\2\2w\u01fe\3\2\2\2y\u0201\3\2\2\2{\u0206\3\2\2\2}"+ "\3\2\2\2u\u01fc\3\2\2\2w\u01fe\3\2\2\2y\u0201\3\2\2\2{\u0206\3\2\2\2}"+
"\u020a\3\2\2\2\177\u020d\3\2\2\2\u0081\u0211\3\2\2\2\u0083\u0215\3\2\2"+ "\u020a\3\2\2\2\177\u020d\3\2\2\2\u0081\u0211\3\2\2\2\u0083\u0215\3\2\2"+
"\2\u0085\u0218\3\2\2\2\u0087\u021f\3\2\2\2\u0089\u0225\3\2\2\2\u008b\u022e"+ "\2\u0085\u0218\3\2\2\2\u0087\u021a\3\2\2\2\u0089\u0221\3\2\2\2\u008b\u0227"+
"\3\2\2\2\u008d\u0230\3\2\2\2\u008f\u0232\3\2\2\2\u0091\u0234\3\2\2\2\u0093"+ "\3\2\2\2\u008d\u0230\3\2\2\2\u008f\u0232\3\2\2\2\u0091\u0234\3\2\2\2\u0093"+
"\u0236\3\2\2\2\u0095\u0239\3\2\2\2\u0097\u023c\3\2\2\2\u0099\u023f\3\2"+ "\u0236\3\2\2\2\u0095\u0238\3\2\2\2\u0097\u023b\3\2\2\2\u0099\u023e\3\2"+
"\2\2\u009b\u0242\3\2\2\2\u009d\u0245\3\2\2\2\u009f\u0248\3\2\2\2\u00a1"+ "\2\2\u009b\u0241\3\2\2\2\u009d\u0244\3\2\2\2\u009f\u0247\3\2\2\2\u00a1"+
"\u024b\3\2\2\2\u00a3\u024e\3\2\2\2\u00a5\u0253\3\2\2\2\u00a7\u0259\3\2"+ "\u024a\3\2\2\2\u00a3\u024d\3\2\2\2\u00a5\u0250\3\2\2\2\u00a7\u0255\3\2"+
"\2\2\u00a9\u025e\3\2\2\2\u00ab\u0262\3\2\2\2\u00ad\u0265\3\2\2\2\u00af"+ "\2\2\u00a9\u025b\3\2\2\2\u00ab\u0260\3\2\2\2\u00ad\u0264\3\2\2\2\u00af"+
"\u0267\3\2\2\2\u00b1\u0269\3\2\2\2\u00b3\u0270\3\2\2\2\u00b5\u0279\3\2"+ "\u0267\3\2\2\2\u00b1\u0269\3\2\2\2\u00b3\u026b\3\2\2\2\u00b5\u0272\3\2"+
"\2\2\u00b7\u027b\3\2\2\2\u00b9\u027e\3\2\2\2\u00bb\u0283\3\2\2\2\u00bd"+ "\2\2\u00b7\u027b\3\2\2\2\u00b9\u027e\3\2\2\2\u00bb\u0283\3\2\2\2\u00bd"+
"\u0289\3\2\2\2\u00bf\u028f\3\2\2\2\u00c1\u0295\3\2\2\2\u00c3\u029a\3\2"+ "\u0289\3\2\2\2\u00bf\u028f\3\2\2\2\u00c1\u0295\3\2\2\2\u00c3\u029a\3\2"+
"\2\2\u00c5\u02a0\3\2\2\2\u00c7\u02a6\3\2\2\2\u00c9\u02ac\3\2\2\2\u00cb"+ "\2\2\u00c5\u02a0\3\2\2\2\u00c7\u02a6\3\2\2\2\u00c9\u02ac\3\2\2\2\u00cb"+
@ -395,68 +395,68 @@ public class prog8Lexer extends Lexer {
"\7z\2\2\u020e\u020f\7q\2\2\u020f\u0210\7t\2\2\u0210\u0080\3\2\2\2\u0211"+ "\7z\2\2\u020e\u020f\7q\2\2\u020f\u0210\7t\2\2\u0210\u0080\3\2\2\2\u0211"+
"\u0212\7p\2\2\u0212\u0213\7q\2\2\u0213\u0214\7v\2\2\u0214\u0082\3\2\2"+ "\u0212\7p\2\2\u0212\u0213\7q\2\2\u0213\u0214\7v\2\2\u0214\u0082\3\2\2"+
"\2\u0215\u0216\7c\2\2\u0216\u0217\7u\2\2\u0217\u0084\3\2\2\2\u0218\u0219"+ "\2\u0215\u0216\7c\2\2\u0216\u0217\7u\2\2\u0217\u0084\3\2\2\2\u0218\u0219"+
"\7t\2\2\u0219\u021a\7g\2\2\u021a\u021b\7v\2\2\u021b\u021c\7w\2\2\u021c"+ "\7B\2\2\u0219\u0086\3\2\2\2\u021a\u021b\7t\2\2\u021b\u021c\7g\2\2\u021c"+
"\u021d\7t\2\2\u021d\u021e\7p\2\2\u021e\u0086\3\2\2\2\u021f\u0220\7d\2"+ "\u021d\7v\2\2\u021d\u021e\7w\2\2\u021e\u021f\7t\2\2\u021f\u0220\7p\2\2"+
"\2\u0220\u0221\7t\2\2\u0221\u0222\7g\2\2\u0222\u0223\7c\2\2\u0223\u0224"+ "\u0220\u0088\3\2\2\2\u0221\u0222\7d\2\2\u0222\u0223\7t\2\2\u0223\u0224"+
"\7m\2\2\u0224\u0088\3\2\2\2\u0225\u0226\7e\2\2\u0226\u0227\7q\2\2\u0227"+ "\7g\2\2\u0224\u0225\7c\2\2\u0225\u0226\7m\2\2\u0226\u008a\3\2\2\2\u0227"+
"\u0228\7p\2\2\u0228\u0229\7v\2\2\u0229\u022a\7k\2\2\u022a\u022b\7p\2\2"+ "\u0228\7e\2\2\u0228\u0229\7q\2\2\u0229\u022a\7p\2\2\u022a\u022b\7v\2\2"+
"\u022b\u022c\7w\2\2\u022c\u022d\7g\2\2\u022d\u008a\3\2\2\2\u022e\u022f"+ "\u022b\u022c\7k\2\2\u022c\u022d\7p\2\2\u022d\u022e\7w\2\2\u022e\u022f"+
"\7\60\2\2\u022f\u008c\3\2\2\2\u0230\u0231\7C\2\2\u0231\u008e\3\2\2\2\u0232"+ "\7g\2\2\u022f\u008c\3\2\2\2\u0230\u0231\7\60\2\2\u0231\u008e\3\2\2\2\u0232"+
"\u0233\7Z\2\2\u0233\u0090\3\2\2\2\u0234\u0235\7[\2\2\u0235\u0092\3\2\2"+ "\u0233\7C\2\2\u0233\u0090\3\2\2\2\u0234\u0235\7Z\2\2\u0235\u0092\3\2\2"+
"\2\u0236\u0237\7C\2\2\u0237\u0238\7Z\2\2\u0238\u0094\3\2\2\2\u0239\u023a"+ "\2\u0236\u0237\7[\2\2\u0237\u0094\3\2\2\2\u0238\u0239\7C\2\2\u0239\u023a"+
"\7C\2\2\u023a\u023b\7[\2\2\u023b\u0096\3\2\2\2\u023c\u023d\7Z\2\2\u023d"+ "\7Z\2\2\u023a\u0096\3\2\2\2\u023b\u023c\7C\2\2\u023c\u023d\7[\2\2\u023d"+
"\u023e\7[\2\2\u023e\u0098\3\2\2\2\u023f\u0240\7R\2\2\u0240\u0241\7e\2"+ "\u0098\3\2\2\2\u023e\u023f\7Z\2\2\u023f\u0240\7[\2\2\u0240\u009a\3\2\2"+
"\2\u0241\u009a\3\2\2\2\u0242\u0243\7R\2\2\u0243\u0244\7|\2\2\u0244\u009c"+ "\2\u0241\u0242\7R\2\2\u0242\u0243\7e\2\2\u0243\u009c\3\2\2\2\u0244\u0245"+
"\3\2\2\2\u0245\u0246\7R\2\2\u0246\u0247\7p\2\2\u0247\u009e\3\2\2\2\u0248"+ "\7R\2\2\u0245\u0246\7|\2\2\u0246\u009e\3\2\2\2\u0247\u0248\7R\2\2\u0248"+
"\u0249\7R\2\2\u0249\u024a\7x\2\2\u024a\u00a0\3\2\2\2\u024b\u024c\7\60"+ "\u0249\7p\2\2\u0249\u00a0\3\2\2\2\u024a\u024b\7R\2\2\u024b\u024c\7x\2"+
"\2\2\u024c\u024d\7y\2\2\u024d\u00a2\3\2\2\2\u024e\u024f\7v\2\2\u024f\u0250"+ "\2\u024c\u00a2\3\2\2\2\u024d\u024e\7\60\2\2\u024e\u024f\7y\2\2\u024f\u00a4"+
"\7t\2\2\u0250\u0251\7w\2\2\u0251\u0252\7g\2\2\u0252\u00a4\3\2\2\2\u0253"+ "\3\2\2\2\u0250\u0251\7v\2\2\u0251\u0252\7t\2\2\u0252\u0253\7w\2\2\u0253"+
"\u0254\7h\2\2\u0254\u0255\7c\2\2\u0255\u0256\7n\2\2\u0256\u0257\7u\2\2"+ "\u0254\7g\2\2\u0254\u00a6\3\2\2\2\u0255\u0256\7h\2\2\u0256\u0257\7c\2"+
"\u0257\u0258\7g\2\2\u0258\u00a6\3\2\2\2\u0259\u025a\7\'\2\2\u025a\u025b"+ "\2\u0257\u0258\7n\2\2\u0258\u0259\7u\2\2\u0259\u025a\7g\2\2\u025a\u00a8"+
"\7c\2\2\u025b\u025c\7u\2\2\u025c\u025d\7o\2\2\u025d\u00a8\3\2\2\2\u025e"+ "\3\2\2\2\u025b\u025c\7\'\2\2\u025c\u025d\7c\2\2\u025d\u025e\7u\2\2\u025e"+
"\u025f\7u\2\2\u025f\u0260\7w\2\2\u0260\u0261\7d\2\2\u0261\u00aa\3\2\2"+ "\u025f\7o\2\2\u025f\u00aa\3\2\2\2\u0260\u0261\7u\2\2\u0261\u0262\7w\2"+
"\2\u0262\u0263\7/\2\2\u0263\u0264\7@\2\2\u0264\u00ac\3\2\2\2\u0265\u0266"+ "\2\u0262\u0263\7d\2\2\u0263\u00ac\3\2\2\2\u0264\u0265\7/\2\2\u0265\u0266"+
"\7}\2\2\u0266\u00ae\3\2\2\2\u0267\u0268\7\177\2\2\u0268\u00b0\3\2\2\2"+ "\7@\2\2\u0266\u00ae\3\2\2\2\u0267\u0268\7}\2\2\u0268\u00b0\3\2\2\2\u0269"+
"\u0269\u026a\7c\2\2\u026a\u026b\7u\2\2\u026b\u026c\7o\2\2\u026c\u026d"+ "\u026a\7\177\2\2\u026a\u00b2\3\2\2\2\u026b\u026c\7c\2\2\u026c\u026d\7"+
"\7u\2\2\u026d\u026e\7w\2\2\u026e\u026f\7d\2\2\u026f\u00b2\3\2\2\2\u0270"+ "u\2\2\u026d\u026e\7o\2\2\u026e\u026f\7u\2\2\u026f\u0270\7w\2\2\u0270\u0271"+
"\u0271\7e\2\2\u0271\u0272\7n\2\2\u0272\u0273\7q\2\2\u0273\u0274\7d\2\2"+ "\7d\2\2\u0271\u00b4\3\2\2\2\u0272\u0273\7e\2\2\u0273\u0274\7n\2\2\u0274"+
"\u0274\u0275\7d\2\2\u0275\u0276\7g\2\2\u0276\u0277\7t\2\2\u0277\u0278"+ "\u0275\7q\2\2\u0275\u0276\7d\2\2\u0276\u0277\7d\2\2\u0277\u0278\7g\2\2"+
"\7u\2\2\u0278\u00b4\3\2\2\2\u0279\u027a\7B\2\2\u027a\u00b6\3\2\2\2\u027b"+ "\u0278\u0279\7t\2\2\u0279\u027a\7u\2\2\u027a\u00b6\3\2\2\2\u027b\u027c"+
"\u027c\7k\2\2\u027c\u027d\7h\2\2\u027d\u00b8\3\2\2\2\u027e\u027f\7g\2"+ "\7k\2\2\u027c\u027d\7h\2\2\u027d\u00b8\3\2\2\2\u027e\u027f\7g\2\2\u027f"+
"\2\u027f\u0280\7n\2\2\u0280\u0281\7u\2\2\u0281\u0282\7g\2\2\u0282\u00ba"+ "\u0280\7n\2\2\u0280\u0281\7u\2\2\u0281\u0282\7g\2\2\u0282\u00ba\3\2\2"+
"\3\2\2\2\u0283\u0284\7k\2\2\u0284\u0285\7h\2\2\u0285\u0286\7a\2\2\u0286"+ "\2\u0283\u0284\7k\2\2\u0284\u0285\7h\2\2\u0285\u0286\7a\2\2\u0286\u0287"+
"\u0287\7e\2\2\u0287\u0288\7u\2\2\u0288\u00bc\3\2\2\2\u0289\u028a\7k\2"+ "\7e\2\2\u0287\u0288\7u\2\2\u0288\u00bc\3\2\2\2\u0289\u028a\7k\2\2\u028a"+
"\2\u028a\u028b\7h\2\2\u028b\u028c\7a\2\2\u028c\u028d\7e\2\2\u028d\u028e"+ "\u028b\7h\2\2\u028b\u028c\7a\2\2\u028c\u028d\7e\2\2\u028d\u028e\7e\2\2"+
"\7e\2\2\u028e\u00be\3\2\2\2\u028f\u0290\7k\2\2\u0290\u0291\7h\2\2\u0291"+ "\u028e\u00be\3\2\2\2\u028f\u0290\7k\2\2\u0290\u0291\7h\2\2\u0291\u0292"+
"\u0292\7a\2\2\u0292\u0293\7g\2\2\u0293\u0294\7s\2\2\u0294\u00c0\3\2\2"+ "\7a\2\2\u0292\u0293\7g\2\2\u0293\u0294\7s\2\2\u0294\u00c0\3\2\2\2\u0295"+
"\2\u0295\u0296\7k\2\2\u0296\u0297\7h\2\2\u0297\u0298\7a\2\2\u0298\u0299"+ "\u0296\7k\2\2\u0296\u0297\7h\2\2\u0297\u0298\7a\2\2\u0298\u0299\7|\2\2"+
"\7|\2\2\u0299\u00c2\3\2\2\2\u029a\u029b\7k\2\2\u029b\u029c\7h\2\2\u029c"+ "\u0299\u00c2\3\2\2\2\u029a\u029b\7k\2\2\u029b\u029c\7h\2\2\u029c\u029d"+
"\u029d\7a\2\2\u029d\u029e\7p\2\2\u029e\u029f\7g\2\2\u029f\u00c4\3\2\2"+ "\7a\2\2\u029d\u029e\7p\2\2\u029e\u029f\7g\2\2\u029f\u00c4\3\2\2\2\u02a0"+
"\2\u02a0\u02a1\7k\2\2\u02a1\u02a2\7h\2\2\u02a2\u02a3\7a\2\2\u02a3\u02a4"+ "\u02a1\7k\2\2\u02a1\u02a2\7h\2\2\u02a2\u02a3\7a\2\2\u02a3\u02a4\7p\2\2"+
"\7p\2\2\u02a4\u02a5\7|\2\2\u02a5\u00c6\3\2\2\2\u02a6\u02a7\7k\2\2\u02a7"+ "\u02a4\u02a5\7|\2\2\u02a5\u00c6\3\2\2\2\u02a6\u02a7\7k\2\2\u02a7\u02a8"+
"\u02a8\7h\2\2\u02a8\u02a9\7a\2\2\u02a9\u02aa\7r\2\2\u02aa\u02ab\7n\2\2"+ "\7h\2\2\u02a8\u02a9\7a\2\2\u02a9\u02aa\7r\2\2\u02aa\u02ab\7n\2\2\u02ab"+
"\u02ab\u00c8\3\2\2\2\u02ac\u02ad\7k\2\2\u02ad\u02ae\7h\2\2\u02ae\u02af"+ "\u00c8\3\2\2\2\u02ac\u02ad\7k\2\2\u02ad\u02ae\7h\2\2\u02ae\u02af\7a\2"+
"\7a\2\2\u02af\u02b0\7r\2\2\u02b0\u02b1\7q\2\2\u02b1\u02b2\7u\2\2\u02b2"+ "\2\u02af\u02b0\7r\2\2\u02b0\u02b1\7q\2\2\u02b1\u02b2\7u\2\2\u02b2\u00ca"+
"\u00ca\3\2\2\2\u02b3\u02b4\7k\2\2\u02b4\u02b5\7h\2\2\u02b5\u02b6\7a\2"+ "\3\2\2\2\u02b3\u02b4\7k\2\2\u02b4\u02b5\7h\2\2\u02b5\u02b6\7a\2\2\u02b6"+
"\2\u02b6\u02b7\7o\2\2\u02b7\u02b8\7k\2\2\u02b8\u00cc\3\2\2\2\u02b9\u02ba"+ "\u02b7\7o\2\2\u02b7\u02b8\7k\2\2\u02b8\u00cc\3\2\2\2\u02b9\u02ba\7k\2"+
"\7k\2\2\u02ba\u02bb\7h\2\2\u02bb\u02bc\7a\2\2\u02bc\u02bd\7p\2\2\u02bd"+ "\2\u02ba\u02bb\7h\2\2\u02bb\u02bc\7a\2\2\u02bc\u02bd\7p\2\2\u02bd\u02be"+
"\u02be\7g\2\2\u02be\u02bf\7i\2\2\u02bf\u00ce\3\2\2\2\u02c0\u02c1\7k\2"+ "\7g\2\2\u02be\u02bf\7i\2\2\u02bf\u00ce\3\2\2\2\u02c0\u02c1\7k\2\2\u02c1"+
"\2\u02c1\u02c2\7h\2\2\u02c2\u02c3\7a\2\2\u02c3\u02c4\7x\2\2\u02c4\u02c5"+ "\u02c2\7h\2\2\u02c2\u02c3\7a\2\2\u02c3\u02c4\7x\2\2\u02c4\u02c5\7u\2\2"+
"\7u\2\2\u02c5\u00d0\3\2\2\2\u02c6\u02c7\7k\2\2\u02c7\u02c8\7h\2\2\u02c8"+ "\u02c5\u00d0\3\2\2\2\u02c6\u02c7\7k\2\2\u02c7\u02c8\7h\2\2\u02c8\u02c9"+
"\u02c9\7a\2\2\u02c9\u02ca\7x\2\2\u02ca\u02cb\7e\2\2\u02cb\u00d2\3\2\2"+ "\7a\2\2\u02c9\u02ca\7x\2\2\u02ca\u02cb\7e\2\2\u02cb\u00d2\3\2\2\2\u02cc"+
"\2\u02cc\u02cd\7h\2\2\u02cd\u02ce\7q\2\2\u02ce\u02cf\7t\2\2\u02cf\u00d4"+ "\u02cd\7h\2\2\u02cd\u02ce\7q\2\2\u02ce\u02cf\7t\2\2\u02cf\u00d4\3\2\2"+
"\3\2\2\2\u02d0\u02d1\7k\2\2\u02d1\u02d2\7p\2\2\u02d2\u00d6\3\2\2\2\u02d3"+ "\2\u02d0\u02d1\7k\2\2\u02d1\u02d2\7p\2\2\u02d2\u00d6\3\2\2\2\u02d3\u02d4"+
"\u02d4\7y\2\2\u02d4\u02d5\7j\2\2\u02d5\u02d6\7k\2\2\u02d6\u02d7\7n\2\2"+ "\7y\2\2\u02d4\u02d5\7j\2\2\u02d5\u02d6\7k\2\2\u02d6\u02d7\7n\2\2\u02d7"+
"\u02d7\u02d8\7g\2\2\u02d8\u00d8\3\2\2\2\u02d9\u02da\7t\2\2\u02da\u02db"+ "\u02d8\7g\2\2\u02d8\u00d8\3\2\2\2\u02d9\u02da\7t\2\2\u02da\u02db\7g\2"+
"\7g\2\2\u02db\u02dc\7r\2\2\u02dc\u02dd\7g\2\2\u02dd\u02de\7c\2\2\u02de"+ "\2\u02db\u02dc\7r\2\2\u02dc\u02dd\7g\2\2\u02dd\u02de\7c\2\2\u02de\u02df"+
"\u02df\7v\2\2\u02df\u00da\3\2\2\2\u02e0\u02e1\7w\2\2\u02e1\u02e2\7p\2"+ "\7v\2\2\u02df\u00da\3\2\2\2\u02e0\u02e1\7w\2\2\u02e1\u02e2\7p\2\2\u02e2"+
"\2\u02e2\u02e3\7v\2\2\u02e3\u02e4\7k\2\2\u02e4\u02e5\7n\2\2\u02e5\u00dc"+ "\u02e3\7v\2\2\u02e3\u02e4\7k\2\2\u02e4\u02e5\7n\2\2\u02e5\u00dc\3\2\2"+
"\3\2\2\2\u02e6\u02ea\t\2\2\2\u02e7\u02e9\t\3\2\2\u02e8\u02e7\3\2\2\2\u02e9"+ "\2\u02e6\u02ea\t\2\2\2\u02e7\u02e9\t\3\2\2\u02e8\u02e7\3\2\2\2\u02e9\u02ec"+
"\u02ec\3\2\2\2\u02ea\u02e8\3\2\2\2\u02ea\u02eb\3\2\2\2\u02eb\u02ed\3\2"+ "\3\2\2\2\u02ea\u02e8\3\2\2\2\u02ea\u02eb\3\2\2\2\u02eb\u02ed\3\2\2\2\u02ec"+
"\2\2\u02ec\u02ea\3\2\2\2\u02ed\u02ee\5\u00dfp\2\u02ee\u02ef\3\2\2\2\u02ef"+ "\u02ea\3\2\2\2\u02ed\u02ee\5\u00dfp\2\u02ee\u02ef\3\2\2\2\u02ef\u02f0"+
"\u02f0\bo\2\2\u02f0\u00de\3\2\2\2\u02f1\u02f5\7=\2\2\u02f2\u02f4\n\2\2"+ "\bo\2\2\u02f0\u00de\3\2\2\2\u02f1\u02f5\7=\2\2\u02f2\u02f4\n\2\2\2\u02f3"+
"\2\u02f3\u02f2\3\2\2\2\u02f4\u02f7\3\2\2\2\u02f5\u02f3\3\2\2\2\u02f5\u02f6"+ "\u02f2\3\2\2\2\u02f4\u02f7\3\2\2\2\u02f5\u02f3\3\2\2\2\u02f5\u02f6\3\2"+
"\3\2\2\2\u02f6\u02f8\3\2\2\2\u02f7\u02f5\3\2\2\2\u02f8\u02f9\bp\2\2\u02f9"+ "\2\2\u02f6\u02f8\3\2\2\2\u02f7\u02f5\3\2\2\2\u02f8\u02f9\bp\2\2\u02f9"+
"\u00e0\3\2\2\2\u02fa\u02fb\t\3\2\2\u02fb\u02fc\3\2\2\2\u02fc\u02fd\bq"+ "\u00e0\3\2\2\2\u02fa\u02fb\t\3\2\2\u02fb\u02fc\3\2\2\2\u02fc\u02fd\bq"+
"\3\2\u02fd\u00e2\3\2\2\2\u02fe\u0300\t\2\2\2\u02ff\u02fe\3\2\2\2\u0300"+ "\3\2\u02fd\u00e2\3\2\2\2\u02fe\u0300\t\2\2\2\u02ff\u02fe\3\2\2\2\u0300"+
"\u0301\3\2\2\2\u0301\u02ff\3\2\2\2\u0301\u0302\3\2\2\2\u0302\u00e4\3\2"+ "\u0301\3\2\2\2\u0301\u02ff\3\2\2\2\u0301\u0302\3\2\2\2\u0302\u00e4\3\2"+

File diff suppressed because it is too large Load Diff

View File

@ -277,6 +277,11 @@ class StackVm(private var traceOutputFile: String?) {
val address = ins.arg!!.integerValue() val address = ins.arg!!.integerValue()
evalstack.push(Value(DataType.FLOAT, mem.getFloat(address))) evalstack.push(Value(DataType.FLOAT, mem.getFloat(address)))
} }
Opcode.PUSH_MEMREAD -> {
val address = evalstack.pop()
checkDt(address, DataType.UWORD)
TODO("push_memread from $address")
}
Opcode.DISCARD_BYTE -> { Opcode.DISCARD_BYTE -> {
val value = evalstack.pop() val value = evalstack.pop()
checkDt(value, DataType.UBYTE) checkDt(value, DataType.UBYTE)
@ -313,6 +318,13 @@ class StackVm(private var traceOutputFile: String?) {
val address = ins.arg!!.integerValue() val address = ins.arg!!.integerValue()
mem.setFloat(address, value.numericValue().toDouble()) mem.setFloat(address, value.numericValue().toDouble())
} }
Opcode.POP_MEMWRITE -> {
val address = evalstack.pop()
checkDt(address, DataType.UWORD)
val value = evalstack.pop()
checkDt(value, DataType.UBYTE)
TODO("pop_memwrite $value to $address")
}
Opcode.ADD_UB -> { Opcode.ADD_UB -> {
val (top, second) = evalstack.pop2() val (top, second) = evalstack.pop2()
checkDt(top, DataType.UBYTE) checkDt(top, DataType.UBYTE)

View File

@ -5,7 +5,7 @@
<content url="file://$MODULE_DIR$"> <content url="file://$MODULE_DIR$">
<excludeFolder url="file://$MODULE_DIR$/build" /> <excludeFolder url="file://$MODULE_DIR$/build" />
</content> </content>
<orderEntry type="inheritedJdk" /> <orderEntry type="jdk" jdkName="Python 3.7" jdkType="Python SDK" />
<orderEntry type="sourceFolder" forTests="false" /> <orderEntry type="sourceFolder" forTests="false" />
</component> </component>
</module> </module>

View File

@ -291,6 +291,24 @@ are banked in (and your code imports the ``c64lib.p8``)
The largest 5-byte MFLPT float that can be stored is: **1.7014118345e+38** (negative: **-1.7014118345e+38**) The largest 5-byte MFLPT float that can be stored is: **1.7014118345e+38** (negative: **-1.7014118345e+38**)
Converting types into other types
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Sometimes you need an unsigned word where you have an unsigned byte, or you need some other type conversion.
Many type conversions are possible by just writing ``as <type>`` at the end of an expression::
uword uw = $ea31
ubyte ub = uw as ubyte ; ub will be $31, identical to lsb(uw)
float f = uw as float ; f will be 59953, but this conversion can be omitted in this case
word w = uw as word ; w will be -5583 (simply reinterpret $ea31 as 2-complement negative number)
f = 56.777
ub = f as ubyte ; ub will be 56
Sometimes it is a straight 'type cast' where the value is simply interpreted as being of the other type,
sometimes an actual value conversion is done to convert it into the targe type.
Try to avoid type conversions as much as possible.
Initial values across multiple runs of the program Initial values across multiple runs of the program
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@ -305,21 +323,6 @@ expected when the program is restarted.
(This is an optimization choice to avoid having to store two copies of every string and array) (This is an optimization choice to avoid having to store two copies of every string and array)
Indirect addressing and address-of
----------------------------------
The ``#`` operator is used to take the address of the symbol following it.
It can be used for example to work with the *address* of a memory mapped variable rather than
the value it holds. You could take the address of a string as well, but that is redundant:
the compiler already treats those as a value that you manipulate via its address.
For most other types this prefix is not supported and will result in a compilation error.
The resulting value is simply a 16 bit word.
.. todo::
This is not yet implemented.
Indirect addressing, Indirect addressing in jumps (jmp/jsr indirect)
Loops Loops
----- -----
@ -411,6 +414,19 @@ a fixed amount of memory which will not change.
that there is a loss of precision. You can use builtin functions such as ``round`` and ``lsb`` to convert that there is a loss of precision. You can use builtin functions such as ``round`` and ``lsb`` to convert
to a smaller datatype, or revert to integer arithmetic. to a smaller datatype, or revert to integer arithmetic.
Direct access to memory locations
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Normally memory locations are accessed by a *memory mapped* name, such as ``c64.BGCOL0`` that is defined
as the memory mapped address $d021.
If you want to access a memory location directly (by using the address itself), without defining
a memory mapped location, you can do so by prefixing the address with ``@``::
A = @$d020 ; set the A register to the current c64 screen border color ("peek(53280)")
@$d020 = 0 ; set the c64 screen border to black ("poke 53280,0")
@(vic+$20) = 6 ; you can also use expressions to 'calculate' the address
Expressions Expressions
----------- -----------

View File

@ -280,6 +280,12 @@ of something with an operand starting with 1 or 0, you'll have to add a space in
**@todo pointers/addresses? (as opposed to normal WORDs)** **@todo pointers/addresses? (as opposed to normal WORDs)**
Data type conversion
^^^^^^^^^^^^^^^^^^^^
Many type conversions are possible by just writing ``as <type>`` at the end of an expression,
for example ``ubyte ub = floatvalue as ubyte`` will convert the floating point value to an unsigned byte.
Memory mapped variables Memory mapped variables
^^^^^^^^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^^^^^^^^^
@ -290,6 +296,16 @@ should be the *memory address* where the value is located::
memory byte BORDER = $d020 memory byte BORDER = $d020
Direct access to memory locations
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Instead of defining a memory mapped name for a specific memory location, you can also
directly access the memory. Prefix a numeric expression or literal by ``@`` to do that::
A = @$d020 ; set the A register to the current c64 screen border color ("peek(53280)")
@$d020 = 0 ; set the c64 screen border to black ("poke 53280,0")
@(vic+$20) = 6 ; a dynamic expression to 'calculate' the address
Constants Constants
^^^^^^^^^ ^^^^^^^^^

View File

@ -30,6 +30,15 @@
const uword Screen = $0400 ; default character screen matrix @todo matrix/array? needs to support array size > 255 const uword Screen = $0400 ; default character screen matrix @todo matrix/array? needs to support array size > 255
const uword Colors = $d800 ; character screen colors @todo matrix/array? needs to support array size > 255 const uword Colors = $d800 ; character screen colors @todo matrix/array? needs to support array size > 255
memory ubyte SPRPTR0 = 2040 ; default sprite pointers (store address of sprite / 64)
memory ubyte SPRPTR1 = 2041
memory ubyte SPRPTR2 = 2042
memory ubyte SPRPTR3 = 2043
memory ubyte SPRPTR4 = 2044
memory ubyte SPRPTR5 = 2045
memory ubyte SPRPTR6 = 2046
memory ubyte SPRPTR7 = 2047
; ---- VIC-II registers ---- ; ---- VIC-II registers ----

View File

@ -476,6 +476,7 @@ abs_f .proc
add_w .proc add_w .proc
; -- push word+word / uword+uword ; -- push word+word / uword+uword
; @todo INLINE THIS
inx inx
clc clc
lda ESTACK_LO,x lda ESTACK_LO,x
@ -489,6 +490,7 @@ add_w .proc
sub_w .proc sub_w .proc
; -- push word-word ; -- push word-word
; @todo INLINE THIS
inx inx
sec sec
lda ESTACK_LO+1,x lda ESTACK_LO+1,x