diff --git a/codeGeneration/src/prog8/codegen/target/cpu6502/codegen/AsmGen.kt b/codeGeneration/src/prog8/codegen/target/cpu6502/codegen/AsmGen.kt index 639465524..a1deb9d9d 100644 --- a/codeGeneration/src/prog8/codegen/target/cpu6502/codegen/AsmGen.kt +++ b/codeGeneration/src/prog8/codegen/target/cpu6502/codegen/AsmGen.kt @@ -67,7 +67,6 @@ class AsmGen(private val program: Program, throw AssemblyError("first block should be 'main'") for(b in program.allBlocks) { - b.statements.removeAll(blockVariableInitializers.getValue(b)) // no longer output the initialization assignments as regular statements in the block! block2asm(b) } @@ -216,10 +215,30 @@ class AsmGen(private val program: Program, out("${block.name}\t" + (if("force_output" in block.options()) ".block\n" else ".proc\n")) + if(options.dontReinitGlobals) { + block.statements.filterIsInstance().forEach { + it.zeropage = ZeropageWish.NOT_IN_ZEROPAGE + val init = it.nextSibling() as? Assignment + if(init?.target?.identifier?.targetVarDecl(program) === it) { + // put the init value back into the vardecl + it.value = init.value + } + } + } + + // no longer output the initialization assignments as regular statements in the block! + block.statements.removeAll(blockVariableInitializers.getValue(block)) + outputSourceLine(block) zeropagevars2asm(block.statements, block) memdefs2asm(block.statements, block) vardecls2asm(block.statements, block) + + block.statements.filterIsInstance().forEach { + if(it.type==VarDeclType.VAR && it.datatype in NumericDatatypes) + it.value=null + } + out("\n; subroutines in this block") // first translate regular statements, and then put the subroutines at the end. @@ -227,12 +246,14 @@ class AsmGen(private val program: Program, stmts.forEach { translate(it) } subroutine.forEach { translateSubroutine(it as Subroutine) } - // generate subroutine to initialize block-level variables - val initializers = blockVariableInitializers.getValue(block) - if(initializers.isNotEmpty()) { - out("prog8_init_vars\t.proc\n") - initializers.forEach { assign -> translate(assign) } - out(" rts\n .pend") + if(!options.dontReinitGlobals) { + // generate subroutine to initialize block-level (global) variables + val initializers = blockVariableInitializers.getValue(block) + if (initializers.isNotEmpty()) { + out("prog8_init_vars\t.proc\n") + initializers.forEach { assign -> translate(assign) } + out(" rts\n .pend") + } } out(if("force_output" in block.options()) "\n\t.bend\n" else "\n\t.pend\n") @@ -291,12 +312,34 @@ class AsmGen(private val program: Program, private fun vardecl2asm(decl: VarDecl) { val name = decl.name + val value = decl.value + val staticValue: Number = + if(value!=null) { + if(value is NumericLiteralValue) { + if(value.type==DataType.FLOAT) + value.number + else + value.number.toInt() + } else { + if(decl.datatype in NumericDatatypes) + throw AssemblyError("can only deal with constant numeric values for global vars $value at ${decl.position}") + else 0 + } + } else 0 + when (decl.datatype) { - DataType.UBYTE -> out("$name\t.byte 0") - DataType.BYTE -> out("$name\t.char 0") - DataType.UWORD -> out("$name\t.word 0") - DataType.WORD -> out("$name\t.sint 0") - DataType.FLOAT -> out("$name\t.byte 0,0,0,0,0 ; float") + DataType.UBYTE -> out("$name\t.byte ${staticValue.toHex()}") + DataType.BYTE -> out("$name\t.char $staticValue") + DataType.UWORD -> out("$name\t.word ${staticValue.toHex()}") + DataType.WORD -> out("$name\t.sint $staticValue") + DataType.FLOAT -> { + if(staticValue==0) { + out("$name\t.byte 0,0,0,0,0 ; float") + } else { + val floatFill = compTarget.machine.getFloat(staticValue).makeFloatFillAsm() + out("$name\t.byte $floatFill ; float $staticValue") + } + } DataType.STR -> { val str = decl.value as StringLiteralValue outputStringvar(decl, compTarget.encodeString(str.value, str.altEncoding).plus(0.toUByte())) @@ -1001,9 +1044,11 @@ class AsmGen(private val program: Program, if(sub.name=="start" && sub.definingBlock.name=="main") { out("; program startup initialization") out(" cld") - blockVariableInitializers.forEach { - if(it.value.isNotEmpty()) - out(" jsr ${it.key.name}.prog8_init_vars") + if(!options.dontReinitGlobals) { + blockVariableInitializers.forEach { + if (it.value.isNotEmpty()) + out(" jsr ${it.key.name}.prog8_init_vars") + } } out(""" tsx diff --git a/compiler/src/prog8/CompilerMain.kt b/compiler/src/prog8/CompilerMain.kt index d26729487..19bc82873 100644 --- a/compiler/src/prog8/CompilerMain.kt +++ b/compiler/src/prog8/CompilerMain.kt @@ -37,6 +37,7 @@ private fun compileMain(args: Array): Boolean { val outputDir by cli.option(ArgType.String, fullName = "out", description = "directory for output files instead of current directory").default(".") val dontWriteAssembly by cli.option(ArgType.Boolean, fullName = "noasm", description="don't create assembly code") val dontOptimize by cli.option(ArgType.Boolean, fullName = "noopt", description = "don't perform any optimizations") + val dontReinitGlobals by cli.option(ArgType.Boolean, fullName = "noreinit", description = "don't create code to reinitialize globals on multiple runs of the program (experimental!)") val optimizeFloatExpressions by cli.option(ArgType.Boolean, fullName = "optfloatx", description = "optimize float expressions (warning: can increase program size)") val watchMode by cli.option(ArgType.Boolean, fullName = "watch", description = "continuous compilation mode (watches for file changes), greatly increases compilation speed") val slowCodegenWarnings by cli.option(ArgType.Boolean, fullName = "slowwarn", description="show debug warnings about slow/problematic assembly code generation") @@ -87,6 +88,7 @@ private fun compileMain(args: Array): Boolean { filepath, dontOptimize != true, optimizeFloatExpressions == true, + dontReinitGlobals == true, dontWriteAssembly != true, slowCodegenWarnings == true, quietAssembler == true, @@ -136,6 +138,7 @@ private fun compileMain(args: Array): Boolean { filepath, dontOptimize != true, optimizeFloatExpressions == true, + dontReinitGlobals == true, dontWriteAssembly != true, slowCodegenWarnings == true, quietAssembler == true, diff --git a/compiler/src/prog8/compiler/Compiler.kt b/compiler/src/prog8/compiler/Compiler.kt index 7986cd900..74ac00ebb 100644 --- a/compiler/src/prog8/compiler/Compiler.kt +++ b/compiler/src/prog8/compiler/Compiler.kt @@ -32,6 +32,7 @@ class CompilationResult(val success: Boolean, class CompilerArguments(val filepath: Path, val optimize: Boolean, val optimizeFloatExpressions: Boolean, + val dontReinitGlobals: Boolean, val writeAssembly: Boolean, val slowCodegenWarnings: Boolean, val quietAssembler: Boolean, @@ -65,6 +66,7 @@ fun compileProgram(args: CompilerArguments): CompilationResult { slowCodegenWarnings = args.slowCodegenWarnings optimize = args.optimize optimizeFloatExpressions = optimizeFloatExpr + dontReinitGlobals = args.dontReinitGlobals asmQuiet = args.quietAssembler asmListfile = args.asmListfile } diff --git a/compiler/test/TestCompilerOnExamples.kt b/compiler/test/TestCompilerOnExamples.kt index 3c5b1f66b..23f47d1d7 100644 --- a/compiler/test/TestCompilerOnExamples.kt +++ b/compiler/test/TestCompilerOnExamples.kt @@ -27,6 +27,7 @@ private fun compileTheThing(filepath: Path, optimize: Boolean, target: ICompilat filepath, optimize, optimizeFloatExpressions = true, + dontReinitGlobals = false, writeAssembly = true, slowCodegenWarnings = false, quietAssembler = true, diff --git a/compiler/test/TestCompilerOptionLibdirs.kt b/compiler/test/TestCompilerOptionLibdirs.kt index 22dcba967..d11d29575 100644 --- a/compiler/test/TestCompilerOptionLibdirs.kt +++ b/compiler/test/TestCompilerOptionLibdirs.kt @@ -41,6 +41,7 @@ class TestCompilerOptionSourcedirs: FunSpec({ filepath = filePath, optimize = false, optimizeFloatExpressions = false, + dontReinitGlobals = false, writeAssembly = true, slowCodegenWarnings = false, quietAssembler = true, diff --git a/compiler/test/helpers/compileXyz.kt b/compiler/test/helpers/compileXyz.kt index 37fd2abf9..aaf369e44 100644 --- a/compiler/test/helpers/compileXyz.kt +++ b/compiler/test/helpers/compileXyz.kt @@ -48,6 +48,7 @@ internal fun compileFile( filepath, optimize, optimizeFloatExpressions = optFloatExpr, + dontReinitGlobals = false, writeAssembly = writeAssembly, slowCodegenWarnings = false, quietAssembler = true, diff --git a/compilerAst/src/prog8/ast/statements/AstStatements.kt b/compilerAst/src/prog8/ast/statements/AstStatements.kt index 8e62da38f..c6b0bae3d 100644 --- a/compilerAst/src/prog8/ast/statements/AstStatements.kt +++ b/compilerAst/src/prog8/ast/statements/AstStatements.kt @@ -173,7 +173,7 @@ enum class ZeropageWish { class VarDecl(val type: VarDeclType, private val declaredDatatype: DataType, - val zeropage: ZeropageWish, + var zeropage: ZeropageWish, var arraysize: ArrayIndex?, override val name: String, var value: Expression?, diff --git a/compilerInterfaces/src/prog8/compilerinterface/CompilationOptions.kt b/compilerInterfaces/src/prog8/compilerinterface/CompilationOptions.kt index c8ea565f2..a7b1bf5f8 100644 --- a/compilerInterfaces/src/prog8/compilerinterface/CompilationOptions.kt +++ b/compilerInterfaces/src/prog8/compilerinterface/CompilationOptions.kt @@ -29,6 +29,7 @@ class CompilationOptions(val output: OutputType, var slowCodegenWarnings: Boolean = false, var optimize: Boolean = false, var optimizeFloatExpressions: Boolean = false, + var dontReinitGlobals: Boolean = false, var asmQuiet: Boolean = false, var asmListfile: Boolean = false ) diff --git a/docs/source/building.rst b/docs/source/building.rst index 9145df64d..d4ba9cdf4 100644 --- a/docs/source/building.rst +++ b/docs/source/building.rst @@ -124,6 +124,13 @@ One or more .p8 module files Don't perform any code optimizations. Useful for debugging or faster compilation cycles. +``-noreinit`` + Don't create code to reinitialize the global (block level) variables on every run of the program. + Also means that all such variables are no longer placed in the zero page. + Sometimes the program will be a lot shorter when using this, but sometimes the opposite happens. + When using this option, it is no longer be possible to run the program correctly more than once! + *Experimental feature*: still has some problems! + ``-optfloatx`` Also optimize float expressions if optimizations are enabled. Warning: can increase program size significantly if a lot of floating point expressions are used. diff --git a/docs/source/todo.rst b/docs/source/todo.rst index 369bb49cc..706b26579 100644 --- a/docs/source/todo.rst +++ b/docs/source/todo.rst @@ -31,7 +31,6 @@ Future - use more of Result<> and Either<> to handle errors/ nulls better - rethink the whole "isAugmentable" business. Because the way this is determined, should always also be exactly mirrorred in the AugmentableAssignmentAsmGen or you'll get a crash at code gen time. - can we get rid of pieces of asmgen.AssignmentAsmGen by just reusing the AugmentableAssignment ? generated code should not suffer -- add a switch to not create the globals-initialization logic, but instead create a smaller program (that can only run once though) - c64: make the graphics.BITMAP_ADDRESS configurable (VIC banking) - optimize several inner loops in gfx2 even further? - add modes 2 and 3 to gfx2 (lowres 4 color and 16 color)? diff --git a/examples/c128/fpval.p8 b/examples/c128/fpval.p8 new file mode 100644 index 000000000..75c94e97a --- /dev/null +++ b/examples/c128/fpval.p8 @@ -0,0 +1,104 @@ +%import textio +%import floats + +main { + sub start() { + + test_val() + + repeat { + } + } + + sub test_val() { + + ; TODO c128 how do I set this in "bank 1" ? VAL() needs that... + + str @shared value = "-1.23456" + uword @shared result + %asm {{ + stx P8ZP_SCRATCH_B1 + lda #value + sta $25 + lda #8 + jsr floats.VAL + jsr floats.FOUT + sta result + sty result+1 + ldx P8ZP_SCRATCH_B1 + }} + txt.print_uwhex(result, true) + txt.nl() + txt.print(result) + txt.nl() + txt.print($0100) + txt.nl() + } + + sub test_freadsa() { + uword @shared result + %asm {{ + stx P8ZP_SCRATCH_B1 + ;lda #-123 + ;jsr floats.FREADSA + lda #<55444 + ldy #>55444 + jsr floats.GIVUAYFAY + jsr floats.FOUT + sta result + sty result+1 + ldx P8ZP_SCRATCH_B1 + }} + txt.print_uwhex(result, true) + txt.nl() + txt.print(result) + txt.nl() + txt.print($0100) + txt.nl() + } + + sub test_getadr() { + uword @shared value + %asm {{ + stx P8ZP_SCRATCH_B1 + lda #<23456 + ldy #>23456 + jsr floats.GIVAYFAY + jsr floats.GETADRAY + sta value + sty value+1 + ldx P8ZP_SCRATCH_B1 + }} + txt.print_uw(value) + txt.nl() + } + + sub test_ayint() { + %asm {{ + stx P8ZP_SCRATCH_B1 + lda #<-23456 + ldy #>-23456 + jsr floats.GIVAYFAY + jsr floats.AYINT + ldx P8ZP_SCRATCH_B1 + }} + word value = mkword(@($66), @($67)) as word + txt.print_w(value) + txt.nl() + } + + sub test_printf() { + floats.print_f(0) + txt.nl() + floats.print_f(1) + txt.nl() + floats.print_f(-1) + txt.nl() + floats.print_f(floats.PI) + txt.nl() + floats.print_f(floats.TWOPI) + txt.nl() + } +} diff --git a/examples/test.p8 b/examples/test.p8 index 75c94e97a..26238b318 100644 --- a/examples/test.p8 +++ b/examples/test.p8 @@ -1,104 +1,57 @@ %import textio %import floats +%zeropage basicsafe +%option no_sysinit main { + ubyte bb = 1 + uword ww = 1 + float ff = 1.111 + str derp = "zzzz" + sub start() { - - test_val() - - repeat { - } + func() + txt.print(derp) } - sub test_val() { + sub func() { + ubyte fbb = 1 + uword fww = 1 + float fff = 1.111 - ; TODO c128 how do I set this in "bank 1" ? VAL() needs that... + txt.print_ub(fbb) + txt.spc() + txt.print_uw(fww) + txt.spc() + floats.print_f(fff) + txt.nl() + txt.print_ub(bb) + txt.spc() + txt.print_uw(ww) + txt.spc() + floats.print_f(ff) + txt.nl() + txt.print_ub(block2.bb) + txt.spc() + txt.print_uw(block2.ww) + txt.spc() + floats.print_f(block2.ff) + txt.nl() - str @shared value = "-1.23456" - uword @shared result - %asm {{ - stx P8ZP_SCRATCH_B1 - lda #value - sta $25 - lda #8 - jsr floats.VAL - jsr floats.FOUT - sta result - sty result+1 - ldx P8ZP_SCRATCH_B1 - }} - txt.print_uwhex(result, true) - txt.nl() - txt.print(result) - txt.nl() - txt.print($0100) - txt.nl() - } - - sub test_freadsa() { - uword @shared result - %asm {{ - stx P8ZP_SCRATCH_B1 - ;lda #-123 - ;jsr floats.FREADSA - lda #<55444 - ldy #>55444 - jsr floats.GIVUAYFAY - jsr floats.FOUT - sta result - sty result+1 - ldx P8ZP_SCRATCH_B1 - }} - txt.print_uwhex(result, true) - txt.nl() - txt.print(result) - txt.nl() - txt.print($0100) - txt.nl() - } - - sub test_getadr() { - uword @shared value - %asm {{ - stx P8ZP_SCRATCH_B1 - lda #<23456 - ldy #>23456 - jsr floats.GIVAYFAY - jsr floats.GETADRAY - sta value - sty value+1 - ldx P8ZP_SCRATCH_B1 - }} - txt.print_uw(value) - txt.nl() - } - - sub test_ayint() { - %asm {{ - stx P8ZP_SCRATCH_B1 - lda #<-23456 - ldy #>-23456 - jsr floats.GIVAYFAY - jsr floats.AYINT - ldx P8ZP_SCRATCH_B1 - }} - word value = mkword(@($66), @($67)) as word - txt.print_w(value) - txt.nl() - } - - sub test_printf() { - floats.print_f(0) - txt.nl() - floats.print_f(1) - txt.nl() - floats.print_f(-1) - txt.nl() - floats.print_f(floats.PI) - txt.nl() - floats.print_f(floats.TWOPI) - txt.nl() + fbb++ + fww++ + fff += 1.1 + bb++ + ww++ + ff += 1.1 + block2.bb++ + block2.ww++ + block2.ff += 1.1 } } + +block2 { + ubyte bb = 1 + uword ww = 1 + float ff = 1.111 +} diff --git a/httpCompilerService/src/prog8/http/TestHttp.kt b/httpCompilerService/src/prog8/http/TestHttp.kt index e0e28ae95..167c45ebf 100644 --- a/httpCompilerService/src/prog8/http/TestHttp.kt +++ b/httpCompilerService/src/prog8/http/TestHttp.kt @@ -34,6 +34,7 @@ class RequestParser : Take { Path.of(a), optimize = true, optimizeFloatExpressions = false, + dontReinitGlobals = false, writeAssembly = true, slowCodegenWarnings = true, compilationTarget = "c64",