diff --git a/.idea/compiler.xml b/.idea/compiler.xml new file mode 100644 index 000000000..a39e0f0fb --- /dev/null +++ b/.idea/compiler.xml @@ -0,0 +1,6 @@ + + + + + \ No newline at end of file diff --git a/compiler/src/prog8/compiler/Compiler.kt b/compiler/src/prog8/compiler/Compiler.kt index 0201bd107..759c067d6 100644 --- a/compiler/src/prog8/compiler/Compiler.kt +++ b/compiler/src/prog8/compiler/Compiler.kt @@ -96,7 +96,7 @@ fun compileProgram(filepath: Path, importedFiles = imported processAst(programAst, errors, compilationOptions) if (compilationOptions.optimize) - optimizeAst(programAst, errors, BuiltinFunctionsFacade(BuiltinFunctions), compTarget) + optimizeAst(programAst, errors, BuiltinFunctionsFacade(BuiltinFunctions), compTarget, compilationOptions) postprocessAst(programAst, errors, compilationOptions) // printAst(programAst) @@ -253,7 +253,7 @@ private fun processAst(programAst: Program, errors: IErrorReporter, compilerOpti errors.report() programAst.addTypecasts(errors) errors.report() - programAst.variousCleanups(programAst, errors, compilerOptions) + programAst.variousCleanups(errors) errors.report() programAst.checkValid(compilerOptions, errors, compilerOptions.compTarget) errors.report() @@ -261,7 +261,7 @@ private fun processAst(programAst: Program, errors: IErrorReporter, compilerOpti errors.report() } -private fun optimizeAst(programAst: Program, errors: IErrorReporter, functions: IBuiltinFunctions, compTarget: ICompilationTarget) { +private fun optimizeAst(programAst: Program, errors: IErrorReporter, functions: IBuiltinFunctions, compTarget: ICompilationTarget, options: CompilationOptions) { // optimize the parse tree println("Optimizing...") while (true) { @@ -275,16 +275,24 @@ private fun optimizeAst(programAst: Program, errors: IErrorReporter, functions: break } - val remover = UnusedCodeRemover(programAst, errors, compTarget, ::loadAsmIncludeFile) - remover.visit(programAst) - remover.applyModifications() + val inliner = SubroutineInliner(programAst, errors, options) + inliner.visit(programAst) + errors.report() + if(errors.noErrors()) { + inliner.applyModifications() + inliner.fixCallsToInlinedSubroutines() + val remover = UnusedCodeRemover(programAst, errors, compTarget, ::loadAsmIncludeFile) + remover.visit(programAst) + remover.applyModifications() + } + errors.report() } private fun postprocessAst(programAst: Program, errors: IErrorReporter, compilerOptions: CompilationOptions) { programAst.addTypecasts(errors) errors.report() - programAst.variousCleanups(programAst, errors, compilerOptions) + programAst.variousCleanups(errors) programAst.checkValid(compilerOptions, errors, compilerOptions.compTarget) // check if final tree is still valid errors.report() val callGraph = CallGraph(programAst, ::loadAsmIncludeFile) diff --git a/compiler/src/prog8/compiler/astprocessing/AstExtensions.kt b/compiler/src/prog8/compiler/astprocessing/AstExtensions.kt index 099e6e5d5..b8201b028 100644 --- a/compiler/src/prog8/compiler/astprocessing/AstExtensions.kt +++ b/compiler/src/prog8/compiler/astprocessing/AstExtensions.kt @@ -56,8 +56,8 @@ internal fun Program.checkIdentifiers(errors: IErrorReporter, compTarget: ICompi } } -internal fun Program.variousCleanups(program: Program, errors: IErrorReporter, options: CompilationOptions) { - val process = VariousCleanups(program, errors, options) +internal fun Program.variousCleanups(errors: IErrorReporter) { + val process = VariousCleanups(errors) process.visit(this) if(errors.noErrors()) process.applyModifications() diff --git a/compiler/src/prog8/compiler/astprocessing/VariousCleanups.kt b/compiler/src/prog8/compiler/astprocessing/VariousCleanups.kt index bb8abf760..1bcf1da09 100644 --- a/compiler/src/prog8/compiler/astprocessing/VariousCleanups.kt +++ b/compiler/src/prog8/compiler/astprocessing/VariousCleanups.kt @@ -3,19 +3,16 @@ package prog8.compiler.astprocessing import prog8.ast.IFunctionCall import prog8.ast.INameScope import prog8.ast.Node -import prog8.ast.Program import prog8.ast.base.FatalAstException import prog8.ast.base.Position import prog8.ast.expressions.* import prog8.ast.statements.* import prog8.ast.walk.AstWalker import prog8.ast.walk.IAstModification -import prog8.compiler.CompilationOptions import prog8.compiler.IErrorReporter -import prog8.optimizer.retvarName -internal class VariousCleanups(private val program: Program, val errors: IErrorReporter, private val compilerOptions: CompilationOptions): AstWalker() { +internal class VariousCleanups(val errors: IErrorReporter): AstWalker() { private val noModifications = emptyList() override fun before(nopStatement: NopStatement, parent: Node): Iterable { @@ -58,33 +55,24 @@ internal class VariousCleanups(private val program: Program, val errors: IErrorR } private fun before(functionCall: IFunctionCall, parent: Node, position: Position): Iterable { - - val modifications = mutableListOf() - - if(compilerOptions.optimize) { - val sub = functionCall.target.targetSubroutine(program) - if(sub!=null && sub.inline && !sub.isAsmSubroutine) { - val (annotations, intermediateReturnValueVar) = annotateInlinedSubroutineIdentifiers(sub) - modifications.addAll(annotations) - if(intermediateReturnValueVar!=null) { - val decl=intermediateReturnValueVar.copy() - modifications.add(IAstModification.InsertFirst(decl, parent.definingScope())) - } - } - } - if(functionCall.target.nameInSource==listOf("peek")) { // peek(a) is synonymous with @(a) val memread = DirectMemoryRead(functionCall.args.single(), position) - modifications.add(IAstModification.ReplaceNode(functionCall as Node, memread, parent)) + return listOf(IAstModification.ReplaceNode(functionCall as Node, memread, parent)) } if(functionCall.target.nameInSource==listOf("poke")) { // poke(a, v) is synonymous with @(a) = v val tgt = AssignTarget(null, null, DirectMemoryWrite(functionCall.args[0], position), position) val assign = Assignment(tgt, functionCall.args[1], position) - modifications.add(IAstModification.ReplaceNode(functionCall as Node, assign, parent)) + return listOf(IAstModification.ReplaceNode(functionCall as Node, assign, parent)) } - return modifications + return noModifications + } + + override fun after(subroutine: Subroutine, parent: Node): Iterable { + if(subroutine.parent!==parent) + throw FatalAstException("parent node mismatch at $subroutine") + return noModifications } override fun after(assignment: Assignment, parent: Node): Iterable { @@ -128,61 +116,4 @@ internal class VariousCleanups(private val program: Program, val errors: IErrorR throw FatalAstException("parent node mismatch at $identifier") return noModifications } - - private fun annotateInlinedSubroutineIdentifiers(sub: Subroutine): Pair, VarDecl?> { - // this adds full name prefixes to all identifiers used in the subroutine, - // so that the statements can be inlined (=copied) in the call site and still reference - // the correct symbols as seen from the scope of the subroutine. - - if(sub.containsDefinedVariables()) - errors.warn("inlining a subroutine with variables, this could result in large code/memory size", sub.position) - - var intermediateReturnVar: VarDecl? = null - - class Annotator: AstWalker() { - var numReturns=0 - - override fun before(identifier: IdentifierReference, parent: Node): Iterable { - val stmt = identifier.targetStatement(program)!! - val subroutine = identifier.definingSubroutine() - return if(stmt is VarDecl && stmt.parent === subroutine) { - val prefixed = stmt.makeScopedName(identifier.nameInSource.last()).replace('.','_') - val withPrefix = IdentifierReference(listOf(prefixed), identifier.position) - listOf(IAstModification.ReplaceNode(identifier, withPrefix, parent)) - } else { - val prefixed = stmt.makeScopedName(identifier.nameInSource.last()).split('.') - val withPrefix = IdentifierReference(prefixed, identifier.position) - listOf(IAstModification.ReplaceNode(identifier, withPrefix, parent)) - } - } - - override fun after(decl: VarDecl, parent: Node): Iterable { - val prefixed = decl.makeScopedName(decl.name).replace('.','_') - val newdecl = VarDecl(decl.type, decl.datatype, decl.zeropage, decl.arraysize, prefixed, decl.struct?.name, decl.value, decl.isArray, decl.autogeneratedDontRemove, decl.position) - if(decl.name == retvarName) - intermediateReturnVar = newdecl - return listOf(IAstModification.ReplaceNode(decl, newdecl, parent)) - } - - override fun before(returnStmt: Return, parent: Node): Iterable { - numReturns++ - if(parent !== sub || sub.indexOfChild(returnStmt) { - return this.modifications.map { it.first }.toList() - } - } - - val annotator = Annotator() - sub.accept(annotator, sub.parent) - if(annotator.numReturns>1) { - errors.err("inlined subroutine can only have one return statement", sub.position) - return Pair(noModifications, intermediateReturnVar) - } - return Pair(annotator.theModifications(), intermediateReturnVar) - } - } diff --git a/compiler/src/prog8/optimizer/SubroutineInliner.kt b/compiler/src/prog8/optimizer/SubroutineInliner.kt new file mode 100644 index 000000000..2dd4aab2b --- /dev/null +++ b/compiler/src/prog8/optimizer/SubroutineInliner.kt @@ -0,0 +1,109 @@ +package prog8.optimizer + +import prog8.ast.IFunctionCall +import prog8.ast.Node +import prog8.ast.Program +import prog8.ast.base.Position +import prog8.ast.expressions.* +import prog8.ast.statements.* +import prog8.ast.walk.AstWalker +import prog8.ast.walk.IAstModification +import prog8.compiler.CompilationOptions +import prog8.compiler.IErrorReporter + + +internal class SubroutineInliner(private val program: Program, val errors: IErrorReporter, private val compilerOptions: CompilationOptions): AstWalker() { + private val noModifications = emptyList() + private var callsToInlinedSubroutines = mutableListOf>() + + fun fixCallsToInlinedSubroutines() { + for((call, parent) in callsToInlinedSubroutines) { + val sub = call.target.targetSubroutine(program)!! + val intermediateReturnValueVar = sub.statements.filterIsInstance().singleOrNull { it.name.endsWith(retvarName) } + if(intermediateReturnValueVar!=null) { + val scope = parent.definingScope() + if(!scope.statements.filterIsInstance().any { it.name==intermediateReturnValueVar.name}) { + val decl = intermediateReturnValueVar.copy() + scope.statements.add(0, decl) + decl.linkParents(scope as Node) + } + } + } + } + + override fun after(subroutine: Subroutine, parent: Node): Iterable { + return if(compilerOptions.optimize && subroutine.inline && !subroutine.isAsmSubroutine) + annotateInlinedSubroutineIdentifiers(subroutine) + else + noModifications + } + + override fun after(functionCallStatement: FunctionCallStatement, parent: Node): Iterable { + return after(functionCallStatement as IFunctionCall, parent, functionCallStatement.position) + } + + override fun after(functionCall: FunctionCall, parent: Node): Iterable { + return after(functionCall as IFunctionCall, parent, functionCall.position) + } + + private fun after(functionCall: IFunctionCall, parent: Node, position: Position): Iterable { + val sub = functionCall.target.targetSubroutine(program) + if(sub != null && compilerOptions.optimize && sub.inline && !sub.isAsmSubroutine) + callsToInlinedSubroutines.add(Pair(functionCall, parent)) + + return noModifications + } + + private fun annotateInlinedSubroutineIdentifiers(sub: Subroutine): List { + // this adds full name prefixes to all identifiers used in the subroutine, + // so that the statements can be inlined (=copied) in the call site and still reference + // the correct symbols as seen from the scope of the subroutine. + + if(sub.containsDefinedVariables()) + errors.warn("inlining a subroutine with variables, this could result in large code/memory size", sub.position) + + class Annotator: AstWalker() { + var numReturns=0 + + override fun before(identifier: IdentifierReference, parent: Node): Iterable { + val stmt = identifier.targetStatement(program)!! + val subroutine = identifier.definingSubroutine() + return if(stmt is VarDecl && stmt.parent === subroutine) { + val prefixed = stmt.makeScopedName(identifier.nameInSource.last()).replace('.','_') + val withPrefix = IdentifierReference(listOf(prefixed), identifier.position) + listOf(IAstModification.ReplaceNode(identifier, withPrefix, parent)) + } else { + val prefixed = stmt.makeScopedName(identifier.nameInSource.last()).split('.') + val withPrefix = IdentifierReference(prefixed, identifier.position) + listOf(IAstModification.ReplaceNode(identifier, withPrefix, parent)) + } + } + + override fun after(decl: VarDecl, parent: Node): Iterable { + val prefixed = decl.makeScopedName(decl.name).replace('.','_') + val newdecl = VarDecl(decl.type, decl.datatype, decl.zeropage, decl.arraysize, prefixed, decl.struct?.name, decl.value, decl.isArray, decl.autogeneratedDontRemove, decl.position) + return listOf(IAstModification.ReplaceNode(decl, newdecl, parent)) + } + + override fun before(returnStmt: Return, parent: Node): Iterable { + numReturns++ + if(parent !== sub || sub.indexOfChild(returnStmt) { + return this.modifications.map { it.first }.toList() + } + } + + val annotator = Annotator() + sub.accept(annotator, sub.parent) + if(annotator.numReturns>1) { + errors.err("inlined subroutine can only have one return statement", sub.position) + return noModifications + } + return annotator.theModifications() + } + +} diff --git a/compilerAst/src/prog8/ast/statements/AstStatements.kt b/compilerAst/src/prog8/ast/statements/AstStatements.kt index 32bcf099c..c9fdd9cba 100644 --- a/compilerAst/src/prog8/ast/statements/AstStatements.kt +++ b/compilerAst/src/prog8/ast/statements/AstStatements.kt @@ -658,6 +658,7 @@ class Subroutine(override val name: String, override lateinit var parent: Node val asmGenInfo = AsmGenInfo() val scopedname: String by lazy { makeScopedName(name) } + var inlineAnnotated: Boolean = false override fun linkParents(parent: Node) { this.parent = parent diff --git a/docs/source/todo.rst b/docs/source/todo.rst index 9b08db37c..80b226d18 100644 --- a/docs/source/todo.rst +++ b/docs/source/todo.rst @@ -2,8 +2,6 @@ TODO ==== -- fix multiple cals to inlined subroutines - - allow inlining of subroutines with params - optimize several inner loops in gfx2 - hoist all variable declarations up to the subroutine scope *before* even the constant folding takes place (to avoid undefined symbol errors when referring to a variable from another nested scope in the subroutine) diff --git a/examples/cx16/multipalette.p8 b/examples/cx16/multipalette.p8 new file mode 100644 index 000000000..d09b202c0 --- /dev/null +++ b/examples/cx16/multipalette.p8 @@ -0,0 +1,415 @@ +%target cx16 +%import palette +%import gfx2 +%option no_sysinit + +main { + + sub start() { + ; palette.set_rgb(&colors, len(colors)) + void cx16.screen_set_mode(128) ; low-res bitmap 256 colors + + cx16.FB_init() + + cx16.VERA_DC_VIDEO = (cx16.VERA_DC_VIDEO & %11001111) | %00010000 ; enable only layer 0 + cx16.VERA_L0_CONFIG = %00000110 ; 4 bpp = 16 colors + ;cx16.VERA_L0_MAPBASE = 0 + ;cx16.VERA_L0_TILEBASE = 0 + + ubyte pix=0 + ubyte ypos + cx16.FB_cursor_position(0, 0) + for ypos in 0 to 199 { + repeat 320/2 { + cx16.FB_set_pixel((pix&15)<<4 | (pix&15)) + pix++ + } + pix=0 + } + + ; color index 0 can't be swapped - set it to black in both ranges + palette.set_color(0, 0) + palette.set_color(16, 0) + + cx16.set_rasterirq(&irq.irq, 0) + + repeat { + ; don't exit + } + } +} + + +irq { + ubyte phase = 0 + uword next_rasterline = 0 + const ubyte increment = 4 ; 4 scanlines = 2 lores pixels per color swap (2 scanlines is too tight) + + sub irq() { + if phase & 1 == 0 { + %asm {{ + lda #0 ; activate palette #0 (first set of colors) + sta cx16.VERA_L0_HSCROLL_H + + stz cx16.VERA_CTRL + lda #<$fa00+32+2 + sta cx16.VERA_ADDR_L + lda #>$fa00+32+2 + sta cx16.VERA_ADDR_M + lda #%00010001 + sta cx16.VERA_ADDR_H + + ; change 15 palette entries 1..15 (0 is fixed) + lda #<$e000 + sta $02 + lda #>$e000 + sta $02 + ldy #0 + lda (2),y + sta cx16.VERA_DATA0 + iny + lda (2),y + sta cx16.VERA_DATA0 + iny + lda (2),y + sta cx16.VERA_DATA0 + iny + lda (2),y + sta cx16.VERA_DATA0 + iny + lda (2),y + sta cx16.VERA_DATA0 + iny + lda (2),y + sta cx16.VERA_DATA0 + iny + lda (2),y + sta cx16.VERA_DATA0 + iny + lda (2),y + sta cx16.VERA_DATA0 + iny + lda (2),y + sta cx16.VERA_DATA0 + iny + lda (2),y + sta cx16.VERA_DATA0 + iny + lda (2),y + sta cx16.VERA_DATA0 + iny + lda (2),y + sta cx16.VERA_DATA0 + iny + lda (2),y + sta cx16.VERA_DATA0 + iny + lda (2),y + sta cx16.VERA_DATA0 + iny + lda (2),y + sta cx16.VERA_DATA0 + iny + lda (2),y + sta cx16.VERA_DATA0 + iny + lda (2),y + sta cx16.VERA_DATA0 + iny + lda (2),y + sta cx16.VERA_DATA0 + iny + lda (2),y + sta cx16.VERA_DATA0 + iny + lda (2),y + sta cx16.VERA_DATA0 + iny + lda (2),y + sta cx16.VERA_DATA0 + iny + lda (2),y + sta cx16.VERA_DATA0 + iny + lda (2),y + sta cx16.VERA_DATA0 + iny + lda (2),y + sta cx16.VERA_DATA0 + iny + lda (2),y + sta cx16.VERA_DATA0 + iny + lda (2),y + sta cx16.VERA_DATA0 + iny + lda (2),y + sta cx16.VERA_DATA0 + iny + lda (2),y + sta cx16.VERA_DATA0 + iny + lda (2),y + sta cx16.VERA_DATA0 + iny + lda (2),y + sta cx16.VERA_DATA0 + + + +; lda #$0f +; sta cx16.VERA_DATA0 +; lda #0 +; sta cx16.VERA_DATA0 +; lda #$0f +; sta cx16.VERA_DATA0 +; lda #0 +; sta cx16.VERA_DATA0 +; lda #$0f +; sta cx16.VERA_DATA0 +; lda #0 +; sta cx16.VERA_DATA0 +; lda #$0f +; sta cx16.VERA_DATA0 +; lda #0 +; sta cx16.VERA_DATA0 +; lda #$0f +; sta cx16.VERA_DATA0 +; lda #0 +; sta cx16.VERA_DATA0 +; lda #$0f +; sta cx16.VERA_DATA0 +; lda #0 +; sta cx16.VERA_DATA0 +; lda #$0f +; sta cx16.VERA_DATA0 +; lda #0 +; sta cx16.VERA_DATA0 +; lda #$0f +; sta cx16.VERA_DATA0 +; lda #0 +; sta cx16.VERA_DATA0 +; lda #$0f +; sta cx16.VERA_DATA0 +; lda #0 +; sta cx16.VERA_DATA0 +; lda #$0f +; sta cx16.VERA_DATA0 +; lda #0 +; sta cx16.VERA_DATA0 +; lda #$0f +; sta cx16.VERA_DATA0 +; lda #0 +; sta cx16.VERA_DATA0 +; lda #$0f +; sta cx16.VERA_DATA0 +; lda #0 +; sta cx16.VERA_DATA0 +; lda #$0f +; sta cx16.VERA_DATA0 +; lda #0 +; sta cx16.VERA_DATA0 +; lda #$0f +; sta cx16.VERA_DATA0 +; lda #0 +; sta cx16.VERA_DATA0 +; lda #$0f +; sta cx16.VERA_DATA0 +; lda #0 +; sta cx16.VERA_DATA0 + + }} + } + else { + %asm {{ + lda #1 ; activate palette #1 (second set of colors) + sta cx16.VERA_L0_HSCROLL_H + + stz cx16.VERA_CTRL + lda #<$fa00+2 + sta cx16.VERA_ADDR_L + lda #>$fa00+2 + sta cx16.VERA_ADDR_M + lda #%00010001 + sta cx16.VERA_ADDR_H + + ; change 15 palette entries 1..15 (0 is fixed) + + lda #<$f000 + sta $02 + lda #>$f000 + sta $02 + ldy #0 + lda (2),y + sta cx16.VERA_DATA0 + iny + lda (2),y + sta cx16.VERA_DATA0 + iny + lda (2),y + sta cx16.VERA_DATA0 + iny + lda (2),y + sta cx16.VERA_DATA0 + iny + lda (2),y + sta cx16.VERA_DATA0 + iny + lda (2),y + sta cx16.VERA_DATA0 + iny + lda (2),y + sta cx16.VERA_DATA0 + iny + lda (2),y + sta cx16.VERA_DATA0 + iny + lda (2),y + sta cx16.VERA_DATA0 + iny + lda (2),y + sta cx16.VERA_DATA0 + iny + lda (2),y + sta cx16.VERA_DATA0 + iny + lda (2),y + sta cx16.VERA_DATA0 + iny + lda (2),y + sta cx16.VERA_DATA0 + iny + lda (2),y + sta cx16.VERA_DATA0 + iny + lda (2),y + sta cx16.VERA_DATA0 + iny + lda (2),y + sta cx16.VERA_DATA0 + iny + lda (2),y + sta cx16.VERA_DATA0 + iny + lda (2),y + sta cx16.VERA_DATA0 + iny + lda (2),y + sta cx16.VERA_DATA0 + iny + lda (2),y + sta cx16.VERA_DATA0 + iny + lda (2),y + sta cx16.VERA_DATA0 + iny + lda (2),y + sta cx16.VERA_DATA0 + iny + lda (2),y + sta cx16.VERA_DATA0 + iny + lda (2),y + sta cx16.VERA_DATA0 + iny + lda (2),y + sta cx16.VERA_DATA0 + iny + lda (2),y + sta cx16.VERA_DATA0 + iny + lda (2),y + sta cx16.VERA_DATA0 + iny + lda (2),y + sta cx16.VERA_DATA0 + iny + lda (2),y + sta cx16.VERA_DATA0 + iny + lda (2),y + sta cx16.VERA_DATA0 + + +; lda #$ff +; sta cx16.VERA_DATA0 +; lda #0 +; sta cx16.VERA_DATA0 +; lda #$ff +; sta cx16.VERA_DATA0 +; lda #0 +; sta cx16.VERA_DATA0 +; lda #$ff +; sta cx16.VERA_DATA0 +; lda #0 +; sta cx16.VERA_DATA0 +; lda #$ff +; sta cx16.VERA_DATA0 +; lda #0 +; sta cx16.VERA_DATA0 +; lda #$ff +; sta cx16.VERA_DATA0 +; lda #0 +; sta cx16.VERA_DATA0 +; lda #$ff +; sta cx16.VERA_DATA0 +; lda #0 +; sta cx16.VERA_DATA0 +; lda #$ff +; sta cx16.VERA_DATA0 +; lda #0 +; sta cx16.VERA_DATA0 +; lda #$ff +; sta cx16.VERA_DATA0 +; lda #0 +; sta cx16.VERA_DATA0 +; lda #$ff +; sta cx16.VERA_DATA0 +; lda #0 +; sta cx16.VERA_DATA0 +; lda #$ff +; sta cx16.VERA_DATA0 +; lda #0 +; sta cx16.VERA_DATA0 +; lda #$ff +; sta cx16.VERA_DATA0 +; lda #0 +; sta cx16.VERA_DATA0 +; lda #$ff +; sta cx16.VERA_DATA0 +; lda #0 +; sta cx16.VERA_DATA0 +; lda #$ff +; sta cx16.VERA_DATA0 +; lda #0 +; sta cx16.VERA_DATA0 +; lda #$ff +; sta cx16.VERA_DATA0 +; lda #0 +; sta cx16.VERA_DATA0 +; lda #$ff +; sta cx16.VERA_DATA0 +; lda #0 +; sta cx16.VERA_DATA0 + + }} + } + + phase++ + next_rasterline += increment + + if next_rasterline > 400 { + next_rasterline = 0 + phase = 0 + } + + cx16.set_rasterline(next_rasterline) + +; +; uword[16] colors1 = 0 +; uword[16] colors2 = 200 +; +; palette.set_rgb(colors1, len(colors1)) +; palette.set_rgb(colors2, len(colors2)) + } +} diff --git a/examples/test.p8 b/examples/test.p8 index ecbc2c820..07f19c150 100644 --- a/examples/test.p8 +++ b/examples/test.p8 @@ -6,9 +6,14 @@ main { sub start() { ubyte thing = otherblock.othersub() - ;ubyte thing2 = otherblock.othersub() + thing = otherblock.othersub() + thing = otherblock.othersub() + thing = otherblock.othersub() + thing = otherblock.othersub() + thing = otherblock.othersub() + thing = otherblock.othersub() + thing = otherblock.othersub() txt.print_ub(thing) ; should print 41! - ;txt.print_ub(thing2) ; should print 41! ; str filename = "titlescreen.bin" ; ubyte success = cx16.vload(filename, 8, 0, $0000)