mirror of
https://github.com/irmen/prog8.git
synced 2025-11-03 04:17:16 +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
|
resultingProgram = program
|
||||||
importedFiles = imported
|
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)
|
processAst(program, args.errors, compilationOptions)
|
||||||
// println("*********** COMPILER AST RIGHT BEFORE OPTIMIZING *************")
|
// println("*********** COMPILER AST RIGHT BEFORE OPTIMIZING *************")
|
||||||
// printProgram(program)
|
// printProgram(program)
|
||||||
@@ -246,7 +255,7 @@ fun compileProgram(args: CompilerArguments): CompilationResult? {
|
|||||||
|
|
||||||
internal fun determineProgramLoadAddress(program: Program, options: CompilationOptions, errors: IErrorReporter) {
|
internal fun determineProgramLoadAddress(program: Program, options: CompilationOptions, errors: IErrorReporter) {
|
||||||
val specifiedAddress = program.toplevelModule.loadAddress
|
val specifiedAddress = program.toplevelModule.loadAddress
|
||||||
var loadAddress: UInt? = null
|
var loadAddress: UInt?
|
||||||
if(specifiedAddress!=null)
|
if(specifiedAddress!=null)
|
||||||
loadAddress = specifiedAddress.first
|
loadAddress = specifiedAddress.first
|
||||||
else
|
else
|
||||||
@@ -360,7 +369,7 @@ internal fun determineCompilationOptions(program: Program, compTarget: ICompilat
|
|||||||
val allOptions = program.modules.flatMap { it.options() }.toSet()
|
val allOptions = program.modules.flatMap { it.options() }.toSet()
|
||||||
val floatsEnabled = "enable_floats" in allOptions
|
val floatsEnabled = "enable_floats" in allOptions
|
||||||
var noSysInit = "no_sysinit" in allOptions
|
var noSysInit = "no_sysinit" in allOptions
|
||||||
var rombale = "romable" in allOptions
|
val rombale = "romable" in allOptions
|
||||||
var zpType: ZeropageType =
|
var zpType: ZeropageType =
|
||||||
if (zpoption == null)
|
if (zpoption == null)
|
||||||
if (floatsEnabled) ZeropageType.FLOATSAFE else ZeropageType.KERNALSAFE
|
if (floatsEnabled) ZeropageType.FLOATSAFE else ZeropageType.KERNALSAFE
|
||||||
@@ -490,7 +499,7 @@ private fun optimizeAst(program: Program, compilerOptions: CompilationOptions, e
|
|||||||
|
|
||||||
if(errors.noErrors()) {
|
if(errors.noErrors()) {
|
||||||
// certain optimization steps could have introduced a "not" in an if statement, postprocess those again.
|
// 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)
|
changer.visit(program)
|
||||||
if(errors.noErrors())
|
if(errors.noErrors())
|
||||||
changer.applyModifications()
|
changer.applyModifications()
|
||||||
|
|||||||
@@ -694,7 +694,7 @@ internal class AstChecker(private val program: Program,
|
|||||||
val decl = idx.arrayvar.targetVarDecl(program)!!
|
val decl = idx.arrayvar.targetVarDecl(program)!!
|
||||||
if(decl.type!=VarDeclType.MEMORY && decl.zeropage!=ZeropageWish.REQUIRE_ZEROPAGE) {
|
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
|
// 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")
|
return err("invalid float array size, must be 1-51")
|
||||||
|
|
||||||
// check if the floating point values are all within range
|
// 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 })
|
if(doubles.any { it < compilerOptions.compTarget.FLOAT_MAX_NEGATIVE || it > compilerOptions.compTarget.FLOAT_MAX_POSITIVE })
|
||||||
return err("floating point value overflow")
|
return err("floating point value overflow")
|
||||||
return true
|
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.
|
- ``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.
|
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()``.
|
- ``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>
|
.. 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.
|
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
|
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.
|
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
|
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
|
%zeropage basicsafe
|
||||||
%option no_sysinit
|
%option no_sysinit, romable
|
||||||
|
|
||||||
main {
|
main $9000 {
|
||||||
sub start() {
|
sub start() {
|
||||||
graphics.enable_bitmap_mode()
|
ubyte[] filled_array = [11,22,33,44]
|
||||||
for cx16.r11L in 0 to 110 {
|
ubyte[10] empty_array
|
||||||
graphics.horizontal_line(cx16.r11L+10, cx16.r11L+20, cx16.r11L+5)
|
|
||||||
}
|
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