diff --git a/compiler/res/prog8lib/c64utils.p8 b/compiler/res/prog8lib/c64utils.p8 index a27d7bbd3..3908ed4ad 100644 --- a/compiler/res/prog8lib/c64utils.p8 +++ b/compiler/res/prog8lib/c64utils.p8 @@ -13,15 +13,15 @@ const uword ESTACK_LO = $ce00 const uword ESTACK_HI = $cf00 - - + + ; ----- utility functions ---- asmsub init_system () -> clobbers(A,X,Y) -> () { ; ---- initializes the machine to a sane starting state ; This means that the BASIC, KERNAL and CHARGEN ROMs are banked in, ; the VIC, SID and CIA chips are reset, screen is cleared, and the default IRQ is set. - ; Also a different color scheme is chosen to identify ourselves a little. + ; Also a different color scheme is chosen to identify ourselves a little. ; Uppercase charset is activated, and all three registers set to 0, status flags cleared. %asm {{ sei @@ -186,7 +186,7 @@ asmsub uword2decimal (uword value @ AY) -> clobbers(A,X,Y) -> () { iny rts }} - + } @@ -268,7 +268,7 @@ asmsub str2word(str string @ AY) -> clobbers() -> (word @ AY) { rts }} } - + asmsub str2ubyte(str string @ AY) -> clobbers(Y) -> (ubyte @ A) { %asm {{ ;-- convert string (address in A/Y) to ubyte number in A @@ -276,13 +276,13 @@ asmsub str2ubyte(str string @ AY) -> clobbers(Y) -> (ubyte @ A) { jmp str2uword }} } - + asmsub str2byte(str string @ AY) -> clobbers(Y) -> (byte @ A) { %asm {{ ;-- convert string (address in A/Y) to byte number in A ; @todo don't use the (slow) kernel floating point conversion jmp str2word - }} + }} } @@ -413,10 +413,10 @@ _mod2b lda #0 ; self-modified bne - _done rts .pend - -}} - - + +}} + + asmsub set_irqvec_excl() -> clobbers(A) -> () { %asm {{ sei @@ -445,11 +445,11 @@ asmsub set_irqvec() -> clobbers(A) -> () { rts _irq_handler jsr irq.irq jmp c64.IRQDFRT ; continue with normal kernel irq routine - + }} } - - + + asmsub restore_irqvec() -> clobbers() -> () { %asm {{ sei @@ -517,7 +517,7 @@ asmsub set_rasterirq_excl(uword rasterpos @ AY) -> clobbers(A) -> () { cli rts -_raster_irq_handler +_raster_irq_handler jsr irq.irq lda #$ff sta c64.VICIRQ ; acknowledge raster irq @@ -812,7 +812,7 @@ asmsub print (str text @ AY) -> clobbers(A,Y) -> () { ; ---- print null terminated string from A/Y ; note: the compiler contains an optimization that will replace ; a call to this subroutine with a string argument of just one char, - ; by just one call to c64.CHROUT of that single char. @todo do this + ; by just one call to c64.CHROUT of that single char. %asm {{ sta c64.SCRATCH_ZPB1 sty c64.SCRATCH_ZPREG @@ -881,7 +881,7 @@ _print_tens txa jmp c64.CHROUT }} } - + asmsub print_b (byte value @ A) -> clobbers(A,X,Y) -> () { ; ---- print the byte in A in decimal form, without left padding 0s %asm {{ @@ -1066,7 +1066,7 @@ asmsub setchr (ubyte col @Y, ubyte row @A) -> clobbers(A) -> () { + lda c64.SCRATCH_ZPB1 _mod sta $ffff ; modified rts - + _screenrows .word $0400 + range(0, 1000, 40) }} } @@ -1088,12 +1088,12 @@ asmsub setclr (ubyte col @Y, ubyte row @A) -> clobbers(A) -> () { + lda c64.SCRATCH_ZPB1 _mod sta $ffff ; modified rts - + _colorrows .word $d800 + range(0, 1000, 40) }} } - + sub setcc (ubyte column, ubyte row, ubyte char, ubyte color) { ; ---- set char+color at the given position on the screen %asm {{ @@ -1117,7 +1117,7 @@ _charmod sta $ffff ; modified lda setcc_color _colormod sta $ffff ; modified rts - }} + }} } asmsub PLOT (ubyte col @ Y, ubyte row @ A) -> clobbers(A) -> () { diff --git a/compiler/src/prog8/CompilerMain.kt b/compiler/src/prog8/CompilerMain.kt index 0c6f4f8c3..dbf5b8e91 100644 --- a/compiler/src/prog8/CompilerMain.kt +++ b/compiler/src/prog8/CompilerMain.kt @@ -102,7 +102,7 @@ private fun compileMain(args: Array) { } //println(" time1: $time1") val time2 = measureTimeMillis { - // @todo this is slow! + // @todo this call below is relatively slow moduleAst.constantFold(namespace, heap) } //println(" time2: $time2") @@ -111,7 +111,7 @@ private fun compileMain(args: Array) { } //println(" time3: $time3") val time4 = measureTimeMillis { - // @todo this is slow! + // @todo this call below is relatively slow moduleAst.checkValid(namespace, compilerOptions, heap) // check if tree is valid } //println(" time4: $time4") diff --git a/compiler/src/prog8/ast/AST.kt b/compiler/src/prog8/ast/AST.kt index ee5427215..05a698922 100644 --- a/compiler/src/prog8/ast/AST.kt +++ b/compiler/src/prog8/ast/AST.kt @@ -1429,6 +1429,11 @@ data class IdentifierReference(val nameInSource: List, override val posi } override fun isIterable(namespace: INameScope, heap: HeapValues): Boolean = resultingDatatype(namespace, heap) in IterableDatatypes + + fun heapId(namespace: INameScope): Int { + val node = namespace.lookup(nameInSource, this) ?: throw UndefinedSymbolError(this) + return ((node as? VarDecl)?.value as? LiteralValue)?.heapId ?: throw FatalAstException("identifier is not on the heap") + } } diff --git a/compiler/src/prog8/ast/AstIdentifiersChecker.kt b/compiler/src/prog8/ast/AstIdentifiersChecker.kt index 55fa1d5ba..33ab76a13 100644 --- a/compiler/src/prog8/ast/AstIdentifiersChecker.kt +++ b/compiler/src/prog8/ast/AstIdentifiersChecker.kt @@ -21,11 +21,15 @@ fun Module.checkIdentifiers(heap: HeapValues): MutableMap { val parent = variable.first.parent when { parent is Assignment && parent.value === variable.first -> { - parent.value = IdentifierReference(listOf("auto_heap_value_${variable.first.heapId}"), variable.first.position) + val idref = IdentifierReference(listOf("auto_heap_value_${variable.first.heapId}"), variable.first.position) + idref.linkParents(parent) + parent.value = idref } parent is IFunctionCall -> { val parameterPos = parent.arglist.indexOf(variable.first) - parent.arglist[parameterPos] = IdentifierReference(listOf("auto_heap_value_${variable.first.heapId}"), variable.first.position) + val idref = IdentifierReference(listOf("auto_heap_value_${variable.first.heapId}"), variable.first.position) + idref.linkParents(parent) + parent.arglist[parameterPos] = idref } else -> TODO("replace literalvalue by identifierref: $variable (in $parent)") } diff --git a/compiler/src/prog8/compiler/Compiler.kt b/compiler/src/prog8/compiler/Compiler.kt index 473a47bd3..33ed0aa7b 100644 --- a/compiler/src/prog8/compiler/Compiler.kt +++ b/compiler/src/prog8/compiler/Compiler.kt @@ -99,6 +99,8 @@ class HeapValues { fun get(heapId: Int): HeapValue = heap[heapId] + // TODO remove function + fun allEntries() = heap.withIndex().toList() } @@ -2049,37 +2051,34 @@ private class StatementTranslator(private val prog: IntermediateProgram, } // todo deal with target.arrayindexed? + fun createLoopCode(step: Int) { + if(step!=1 && step !=-1) + TODO("can't generate code for step other than 1 or -1 right now") + + // LV++ / LV-- + val postIncr = PostIncrDecr(lvTarget, if(step==1) "++" else "--", range.position) + postIncr.linkParents(body) + translate(postIncr) + if(lvTarget.register!=null) + prog.instr(Opcode.PUSH_VAR_BYTE, callLabel =lvTarget.register.toString()) + else { + val opcode = opcodePushvar(targetStatement!!.datatype) + prog.instr(opcode, callLabel = targetStatement.scopedname) + } + val branch = BranchStatement( + BranchCondition.NZ, + AnonymousScope(mutableListOf(Jump(null, null, loopLabel, range.position)), range.position), + AnonymousScope(mutableListOf(), range.position), + range.position) + branch.linkParents(body) + translate(branch) + } when (literalStepValue) { - 1 -> { - // LV++ - val postIncr = PostIncrDecr(lvTarget, "++", range.position) - postIncr.linkParents(body) - translate(postIncr) - if(lvTarget.register!=null) - prog.instr(Opcode.PUSH_VAR_BYTE, callLabel =lvTarget.register.toString()) - else { - val opcode = opcodePushvar(targetStatement!!.datatype) - prog.instr(opcode, callLabel = targetStatement.scopedname) - } - val branch = BranchStatement( - BranchCondition.NZ, - AnonymousScope(mutableListOf(Jump(null, null, loopLabel, range.position)), range.position), - AnonymousScope(mutableListOf(), range.position), - range.position) - branch.linkParents(body) - translate(branch) - } - -1 -> { - // LV-- - val postIncr = PostIncrDecr(makeAssignmentTarget(), "--", range.position) - postIncr.linkParents(body) - translate(postIncr) - TODO("signed numbers and/or special condition are needed for decreasing for loop. Try an increasing loop and/or constant loop values instead? At: ${range.position}") // fix with signed numbers - } - else -> { - TODO("non-literal-const or other-than-one step increment code At: ${range.position}") - } + 1 -> createLoopCode(1) + -1 -> createLoopCode(-1) + null -> TODO("variable range forloop non-literal-const step increment, At: ${range.position}") + else -> TODO("variable range forloop step increment not 1 or -1, At: ${range.position}") } prog.label(breakLabel) diff --git a/compiler/src/prog8/optimizing/StatementOptimizer.kt b/compiler/src/prog8/optimizing/StatementOptimizer.kt index f2e6250d1..e557ef5b0 100644 --- a/compiler/src/prog8/optimizing/StatementOptimizer.kt +++ b/compiler/src/prog8/optimizing/StatementOptimizer.kt @@ -2,6 +2,7 @@ package prog8.optimizing import prog8.ast.* import prog8.compiler.HeapValues +import prog8.compiler.target.c64.Petscii import prog8.functions.BuiltinFunctions import kotlin.math.floor @@ -37,6 +38,37 @@ class StatementOptimizer(private val namespace: INameScope, private val heap: He if (functionName in pureBuiltinFunctions) { printWarning("statement has no effect (function return value is discarded)", functionCall.position) statementsToRemove.add(functionCall) + return functionCall + } + } + + if(functionCall.target.nameInSource==listOf("c64scr", "print") || + functionCall.target.nameInSource==listOf("c64scr", "print_p")) { + // printing a literal string of just 2 or 1 characters is replaced by directly outputting those characters + if(functionCall.arglist.single() is LiteralValue) + throw AstException("string argument should be on heap already") + val stringVar = functionCall.arglist.single() as? IdentifierReference + if(stringVar!=null) { + val heapId = stringVar.heapId(namespace) + val string = heap.get(heapId).str!! + // TODO heap.remove(heapId) + if(string.length==1) { + val petscii = Petscii.encodePetscii(string, true)[0] + functionCall.arglist.clear() + functionCall.arglist.add(LiteralValue.optimalInteger(petscii, functionCall.position)) + functionCall.target = IdentifierReference(listOf("c64", "CHROUT"), functionCall.target.position) + optimizationsDone++ + return functionCall + } else if(string.length==2) { + val petscii = Petscii.encodePetscii(string, true) + val scope = AnonymousScope(mutableListOf(), functionCall.position) + scope.statements.add(FunctionCallStatement(IdentifierReference(listOf("c64", "CHROUT"), functionCall.target.position), + mutableListOf(LiteralValue.optimalInteger(petscii[0], functionCall.position)), functionCall.position)) + scope.statements.add(FunctionCallStatement(IdentifierReference(listOf("c64", "CHROUT"), functionCall.target.position), + mutableListOf(LiteralValue.optimalInteger(petscii[1], functionCall.position)), functionCall.position)) + optimizationsDone++ + return scope + } } } diff --git a/examples/test.p8 b/examples/test.p8 index f2ab5f2ec..6fcffbcbf 100644 --- a/examples/test.p8 +++ b/examples/test.p8 @@ -1,48 +1,13 @@ %import c64utils -%import c64flt ~ main { sub start() { - uword[4] uwa = 5 - ubyte[4] uba = 5 - word[4] wa = 5 - byte[4] ba = 5 - float[4] fa = 5.123 - str naam = "irmen" - float ff = 3.4444 - - uword addr - - addr = naam - addr = uwa - addr = fa - - pairAX(naam) - pairAX("hello") - pairAX("hello2") - pairAX("hello2") - pairAX("hello2") - pairAY("hello2") - pairAY("hello2") - pairXY("hello2") - pairXY("hello2") - pairAX(uwa) - pairAX(fa) - pairAY(naam) - pairAY(uwa) - pairAY(fa) - pairXY(naam) - pairXY(uwa) - pairXY(fa) - - } - - asmsub pairAX(uword address @ AX) -> clobbers() -> () { - } - asmsub pairAY(uword address @ AY) -> clobbers() -> () { - } - asmsub pairXY(uword address @ XY) -> clobbers() -> () { + c64scr.print("hoi") + c64scr.print("ho") ; @todo 2x CHROUT + c64scr.print("h") ; @todo 1x CHROUT + c64scr.print("h") ; @todo 1x CHROUT + c64scr.print("\n") ; @todo 1x CHROUT } }