mirror of
https://github.com/irmen/prog8.git
synced 2025-11-01 06:16:15 +00:00
document romable option and that strings+initialized arrays become read-only
This commit is contained in:
@@ -111,6 +111,15 @@ fun compileProgram(args: CompilerArguments): CompilationResult? {
|
||||
resultingProgram = program
|
||||
importedFiles = imported
|
||||
|
||||
if(compilationOptions.romable) {
|
||||
if (!compilationOptions.varsGolden && compilationOptions.varsHighBank==null)
|
||||
args.errors.err("When ROMable code is selected, variables should be moved to a RAM memory region using either -varsgolden or -varshigh option", program.toplevelModule.position)
|
||||
if (!compilationOptions.slabsGolden && compilationOptions.slabsHighBank==null)
|
||||
args.errors.err("When ROMable code is selected, memory() blocks should be moved to a RAM memory region using either -slabsgolden or -slabshigh option", program.toplevelModule.position)
|
||||
args.errors.report()
|
||||
}
|
||||
|
||||
|
||||
processAst(program, args.errors, compilationOptions)
|
||||
// println("*********** COMPILER AST RIGHT BEFORE OPTIMIZING *************")
|
||||
// printProgram(program)
|
||||
@@ -246,7 +255,7 @@ fun compileProgram(args: CompilerArguments): CompilationResult? {
|
||||
|
||||
internal fun determineProgramLoadAddress(program: Program, options: CompilationOptions, errors: IErrorReporter) {
|
||||
val specifiedAddress = program.toplevelModule.loadAddress
|
||||
var loadAddress: UInt? = null
|
||||
var loadAddress: UInt?
|
||||
if(specifiedAddress!=null)
|
||||
loadAddress = specifiedAddress.first
|
||||
else
|
||||
@@ -360,7 +369,7 @@ internal fun determineCompilationOptions(program: Program, compTarget: ICompilat
|
||||
val allOptions = program.modules.flatMap { it.options() }.toSet()
|
||||
val floatsEnabled = "enable_floats" in allOptions
|
||||
var noSysInit = "no_sysinit" in allOptions
|
||||
var rombale = "romable" in allOptions
|
||||
val rombale = "romable" in allOptions
|
||||
var zpType: ZeropageType =
|
||||
if (zpoption == null)
|
||||
if (floatsEnabled) ZeropageType.FLOATSAFE else ZeropageType.KERNALSAFE
|
||||
@@ -490,7 +499,7 @@ private fun optimizeAst(program: Program, compilerOptions: CompilationOptions, e
|
||||
|
||||
if(errors.noErrors()) {
|
||||
// certain optimization steps could have introduced a "not" in an if statement, postprocess those again.
|
||||
var changer = NotExpressionAndIfComparisonExprChanger(program, errors, compilerOptions.compTarget)
|
||||
val changer = NotExpressionAndIfComparisonExprChanger(program, errors, compilerOptions.compTarget)
|
||||
changer.visit(program)
|
||||
if(errors.noErrors())
|
||||
changer.applyModifications()
|
||||
|
||||
@@ -694,7 +694,7 @@ internal class AstChecker(private val program: Program,
|
||||
val decl = idx.arrayvar.targetVarDecl(program)!!
|
||||
if(decl.type!=VarDeclType.MEMORY && decl.zeropage!=ZeropageWish.REQUIRE_ZEROPAGE) {
|
||||
// memory mapped arrays are assumed to be in RAM. If they're not.... well, POOF
|
||||
errors.err("cannot assign to an array or string that is located in ROM", assignTarget.position)
|
||||
errors.err("cannot assign to an array or string that is located in ROM (option romable is enabled)", assignTarget.position)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1898,7 +1898,7 @@ internal class AstChecker(private val program: Program,
|
||||
return err("invalid float array size, must be 1-51")
|
||||
|
||||
// check if the floating point values are all within range
|
||||
val doubles = value.value.map {it.constValue(program)?.number!!.toDouble()}.toDoubleArray()
|
||||
val doubles = value.value.map { it.constValue(program)?.number!! }.toDoubleArray()
|
||||
if(doubles.any { it < compilerOptions.compTarget.FLOAT_MAX_NEGATIVE || it > compilerOptions.compTarget.FLOAT_MAX_POSITIVE })
|
||||
return err("floating point value overflow")
|
||||
return true
|
||||
|
||||
@@ -430,7 +430,8 @@ Directives
|
||||
- ``ignore_unused`` (block or module) suppress warnings about unused variables and subroutines. Instead, these will be silently stripped.
|
||||
This option is useful in library modules that contain many more routines beside the ones that you actually use.
|
||||
- ``verafxmuls`` (block, cx16 target only) uses Vera FX hardware word multiplication on the CommanderX16 for all word multiplications in this block. Warning: this may interfere with IRQs and other Vera operations, so use this only when you know what you're doing. It's safer to explicitly use ``verafx.muls()``.
|
||||
- ``romable`` (module) *WORK-IN-PROGRESS/EXPERIMENTAL* make sure that the generated code is suitable for running in ROM (so no self-modifying code and such)
|
||||
- ``romable`` (module) *WORK-IN-PROGRESS/EXPERIMENTAL* make sure that the generated code is suitable for running in ROM (so no self-modifying code and such, which is normally used to generate smaller/more optimized code)
|
||||
See :ref:`romable` for more details.
|
||||
|
||||
|
||||
.. data:: %output <type>
|
||||
|
||||
@@ -301,3 +301,37 @@ The tool isn't powerful enough to see what routine the variables or instructions
|
||||
You can see in the example above that the variables that are among the most used are neatly placed in zeropage already.
|
||||
If you see for instance a variable that is heavily used and that is *not* in zeropage, you
|
||||
could consider adding ``@zp`` to that variable's declaration to prioritize it to be put into zeropage.
|
||||
|
||||
|
||||
.. _romable:
|
||||
|
||||
ROM-able programs
|
||||
-----------------
|
||||
|
||||
Normally Prog8 will use some tricks to generate the smallest and most optimized code it can.
|
||||
This includes the following techniques that by default prevent generated program code from running in ROM:
|
||||
|
||||
self-modifying code
|
||||
This is program code that actually modifies itself during program execution (instructions or operands are modified)
|
||||
When the program is in ROM, such modifications are impossible, so the program will not execute correctly.
|
||||
|
||||
inline variables
|
||||
These are variables that are located in the same memory region that the program code is in (or even interleaved within the program code).
|
||||
Again, writing to such variables will not work when it is in ROM, so the program will not execute correctly.
|
||||
|
||||
(Not all prog8 source code will end up using these techniques but you should not depend on it.)
|
||||
|
||||
The directive ``%option romable`` changes this behavior.
|
||||
It tells the compiler to no longer generate code using these two tricks, and instead revert to slightly slower running code (or needing more instructions)
|
||||
but which *is* able to run from ROM.
|
||||
There are a few things to note:
|
||||
|
||||
- string variables and array variables that are initialized with something other than just zeros, *are no longer mutable*.
|
||||
This is because both of these will still end up as part of the same memory region the program code is in (which will be ROM).
|
||||
The compiler will try to detect writes to them and give an error if these occur. However it cannot detect all such writes, so beware.
|
||||
- arrays without an initialization literal will be placed into the memory region for variables instead which can and should be placed in RAM,
|
||||
so those arrays *are* mutable as usual.
|
||||
- the same holds for memory blocks allocated using the ``memory`` function; nothing changes for them.
|
||||
- the memory region for variables and memory blocks (BSS sections) should be explicitly placed in RAM memory.
|
||||
You can do this with the ``-varsgolden`` or ``-varshigh``, and ``-slabsgolden`` or ``-slabshigh`` command line options.
|
||||
TODO: maybe in the future an option will be added to choose a memory address for those manually.
|
||||
|
||||
@@ -1,11 +1,6 @@
|
||||
TODO
|
||||
====
|
||||
|
||||
document romable option and that strings+initialized arrays become read-only
|
||||
|
||||
also support 'heavy' version of the unicode box characters like https://www.compart.com/en/unicode/U+250F as characters in strings
|
||||
|
||||
|
||||
...
|
||||
|
||||
|
||||
|
||||
@@ -1,12 +1,38 @@
|
||||
%import graphics
|
||||
%import textio
|
||||
%zeropage basicsafe
|
||||
%option no_sysinit
|
||||
%option no_sysinit, romable
|
||||
|
||||
main {
|
||||
main $9000 {
|
||||
sub start() {
|
||||
graphics.enable_bitmap_mode()
|
||||
for cx16.r11L in 0 to 110 {
|
||||
graphics.horizontal_line(cx16.r11L+10, cx16.r11L+20, cx16.r11L+5)
|
||||
}
|
||||
ubyte[] filled_array = [11,22,33,44]
|
||||
ubyte[10] empty_array
|
||||
|
||||
uword block = memory("block", 100, 0)
|
||||
sys.memset(block, 100, 0)
|
||||
str name = "irmen"
|
||||
ubyte @shared number
|
||||
txt.print(name)
|
||||
txt.spc()
|
||||
number++
|
||||
txt.print_ub(number)
|
||||
txt.spc()
|
||||
number++
|
||||
txt.print_ub(number)
|
||||
txt.nl()
|
||||
txt.print_ub(block[10])
|
||||
txt.spc()
|
||||
block[10]++
|
||||
txt.print_ub(block[10])
|
||||
txt.nl()
|
||||
|
||||
txt.print_ub(filled_array[2])
|
||||
txt.spc()
|
||||
;;empty_array[2]=0 ; TODO should not give error!
|
||||
txt.print_ub(empty_array[2])
|
||||
txt.spc()
|
||||
;;empty_array[2]++ ; TODO should not give error!
|
||||
txt.print_ub(empty_array[2])
|
||||
txt.nl()
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user