mirror of
https://github.com/irmen/prog8.git
synced 2024-09-07 03:54:27 +00:00
vm: memory is randomized on start instead of 0. P8ir file now has BSS segment. Vm clears BSS vars to 0.
This commit is contained in:
parent
4831fad27a
commit
17bedac96c
@ -8,10 +8,6 @@ import prog8.code.core.*
|
|||||||
* (blocks, subroutines, variables (all types), memoryslabs, and labels).
|
* (blocks, subroutines, variables (all types), memoryslabs, and labels).
|
||||||
*/
|
*/
|
||||||
class SymbolTable : StNode("", StNodeType.GLOBAL, Position.DUMMY) {
|
class SymbolTable : StNode("", StNodeType.GLOBAL, Position.DUMMY) {
|
||||||
fun print() = printIndented(0)
|
|
||||||
|
|
||||||
override fun printProperties() { }
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The table as a flat mapping of scoped names to the StNode.
|
* The table as a flat mapping of scoped names to the StNode.
|
||||||
* This gives the fastest lookup possible (no need to traverse tree nodes)
|
* This gives the fastest lookup possible (no need to traverse tree nodes)
|
||||||
@ -138,29 +134,6 @@ open class StNode(val name: String,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun printIndented(indent: Int) {
|
|
||||||
print(" ".repeat(indent))
|
|
||||||
when(type) {
|
|
||||||
StNodeType.GLOBAL -> print("SYMBOL-TABLE:")
|
|
||||||
StNodeType.BLOCK -> print("(B) ")
|
|
||||||
StNodeType.SUBROUTINE -> print("(S) ")
|
|
||||||
StNodeType.LABEL -> print("(L) ")
|
|
||||||
StNodeType.STATICVAR -> print("(V) ")
|
|
||||||
StNodeType.MEMVAR -> print("(M) ")
|
|
||||||
StNodeType.MEMORYSLAB -> print("(MS) ")
|
|
||||||
StNodeType.CONSTANT -> print("(C) ")
|
|
||||||
StNodeType.BUILTINFUNC -> print("(F) ")
|
|
||||||
StNodeType.ROMSUB -> print("(R) ")
|
|
||||||
}
|
|
||||||
printProperties()
|
|
||||||
println()
|
|
||||||
children.forEach { (_, node) -> node.printIndented(indent+1) }
|
|
||||||
}
|
|
||||||
|
|
||||||
open fun printProperties() {
|
|
||||||
print("$name ")
|
|
||||||
}
|
|
||||||
|
|
||||||
fun add(child: StNode) {
|
fun add(child: StNode) {
|
||||||
children[child.name] = child
|
children[child.name] = child
|
||||||
child.parent = this
|
child.parent = this
|
||||||
@ -201,18 +174,11 @@ class StStaticVariable(name: String,
|
|||||||
require(length == onetimeInitializationStringValue.first.length+1)
|
require(length == onetimeInitializationStringValue.first.length+1)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun printProperties() {
|
|
||||||
print("$name dt=$dt zpw=$zpwish bss=$bss")
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
class StConstant(name: String, val dt: DataType, val value: Double, position: Position) :
|
class StConstant(name: String, val dt: DataType, val value: Double, position: Position) :
|
||||||
StNode(name, StNodeType.CONSTANT, position) {
|
StNode(name, StNodeType.CONSTANT, position) {
|
||||||
override fun printProperties() {
|
|
||||||
print("$name dt=$dt value=$value")
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -222,9 +188,6 @@ class StMemVar(name: String,
|
|||||||
val length: Int?, // for arrays: the number of elements, for strings: number of characters *including* the terminating 0-byte
|
val length: Int?, // for arrays: the number of elements, for strings: number of characters *including* the terminating 0-byte
|
||||||
position: Position) :
|
position: Position) :
|
||||||
StNode(name, StNodeType.MEMVAR, position) {
|
StNode(name, StNodeType.MEMVAR, position) {
|
||||||
override fun printProperties() {
|
|
||||||
print("$name dt=$dt address=${address.toHex()}")
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
class StMemorySlab(
|
class StMemorySlab(
|
||||||
@ -234,16 +197,10 @@ class StMemorySlab(
|
|||||||
position: Position
|
position: Position
|
||||||
):
|
):
|
||||||
StNode(name, StNodeType.MEMORYSLAB, position) {
|
StNode(name, StNodeType.MEMORYSLAB, position) {
|
||||||
override fun printProperties() {
|
|
||||||
print("$name size=$size align=$align")
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
class StSub(name: String, val parameters: List<StSubroutineParameter>, val returnType: DataType?, position: Position) :
|
class StSub(name: String, val parameters: List<StSubroutineParameter>, val returnType: DataType?, position: Position) :
|
||||||
StNode(name, StNodeType.SUBROUTINE, position) {
|
StNode(name, StNodeType.SUBROUTINE, position) {
|
||||||
override fun printProperties() {
|
|
||||||
print(name)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -253,9 +210,6 @@ class StRomSub(name: String,
|
|||||||
val returns: List<RegisterOrStatusflag>,
|
val returns: List<RegisterOrStatusflag>,
|
||||||
position: Position) :
|
position: Position) :
|
||||||
StNode(name, StNodeType.ROMSUB, position) {
|
StNode(name, StNodeType.ROMSUB, position) {
|
||||||
override fun printProperties() {
|
|
||||||
print("$name address=${address.toHex()}")
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -19,6 +19,8 @@ class TestLaunchEmu: FunSpec({
|
|||||||
<ASMSYMBOLS>
|
<ASMSYMBOLS>
|
||||||
</ASMSYMBOLS>
|
</ASMSYMBOLS>
|
||||||
|
|
||||||
|
<BSS>
|
||||||
|
</BSS>
|
||||||
<VARIABLES>
|
<VARIABLES>
|
||||||
</VARIABLES>
|
</VARIABLES>
|
||||||
|
|
||||||
|
@ -3,15 +3,10 @@ TODO
|
|||||||
|
|
||||||
For next release
|
For next release
|
||||||
^^^^^^^^^^^^^^^^
|
^^^^^^^^^^^^^^^^
|
||||||
- Think this through/ ask opinions: add a mechanism to allocate variables into golden ram (see GoldenRam class)
|
- add more descriptions to require() calls (at least line number?)
|
||||||
- block "golden" treated specially: every var in here will be allocated in the Golden ram area
|
- 6502 codegen: create BSS section in output assembly code and put StStaticVariables in there with bss=true.
|
||||||
- that block can only contain variables.
|
Don't forget to add init code to zero out everything that was put in bss. If array in bss->only zero ONCE if possible.
|
||||||
- the variables can NOT have initialization values, they will all be set to zero on startup (simple memset)
|
Note that bss can still contain variables that have @zp tag and those are already dealt with differently
|
||||||
- just initialize them yourself in start() if you need a non-zero value
|
|
||||||
- OR.... do all this automatically if 'golden' is enabled as a compiler option? So compiler allocates in ZP first, then Golden Ram, then regular ram
|
|
||||||
- (need separate step in codegen and IR to write the "golden" variables)
|
|
||||||
|
|
||||||
|
|
||||||
- regression test the various projects before release
|
- regression test the various projects before release
|
||||||
|
|
||||||
...
|
...
|
||||||
@ -28,7 +23,6 @@ Future Things and Ideas
|
|||||||
^^^^^^^^^^^^^^^^^^^^^^^
|
^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
Compiler:
|
Compiler:
|
||||||
|
|
||||||
- create BSS section in output program and put StStaticVariables in there with bss=true. Don't forget to add init code to zero out everything that was put in bss. If array in bss->only zero ONCE! So requires self-modifying code
|
|
||||||
- ir: mechanism to determine for chunks which registers are getting input values from "outside"
|
- ir: mechanism to determine for chunks which registers are getting input values from "outside"
|
||||||
- ir: mechanism to determine for chunks which registers are passing values out? (i.e. are used again in another chunk)
|
- ir: mechanism to determine for chunks which registers are passing values out? (i.e. are used again in another chunk)
|
||||||
- ir: peephole opt: renumber registers in chunks to start with 1 again every time (but keep entry values in mind!)
|
- ir: peephole opt: renumber registers in chunks to start with 1 again every time (but keep entry values in mind!)
|
||||||
@ -48,6 +42,14 @@ Compiler:
|
|||||||
Once new codegen is written that is based on the IR, this point is moot anyway as that will have its own dead code removal.
|
Once new codegen is written that is based on the IR, this point is moot anyway as that will have its own dead code removal.
|
||||||
- Zig-like try-based error handling where the V flag could indicate error condition? and/or BRK to jump into monitor on failure? (has to set BRK vector for that)
|
- Zig-like try-based error handling where the V flag could indicate error condition? and/or BRK to jump into monitor on failure? (has to set BRK vector for that)
|
||||||
- add special (u)word array type (or modifier?) that puts the array into memory as 2 separate byte-arrays 1 for LSB 1 for MSB -> allows for word arrays of length 256 and faster indexing
|
- add special (u)word array type (or modifier?) that puts the array into memory as 2 separate byte-arrays 1 for LSB 1 for MSB -> allows for word arrays of length 256 and faster indexing
|
||||||
|
- Add a mechanism to allocate variables into golden ram (or segments really) (see GoldenRam class)
|
||||||
|
- block "golden" treated specially: every var in here will be allocated in the Golden ram area
|
||||||
|
- that block can only contain variables.
|
||||||
|
- the variables can NOT have initialization values, they will all be set to zero on startup (simple memset)
|
||||||
|
- just initialize them yourself in start() if you need a non-zero value
|
||||||
|
- OR.... do all this automatically if 'golden' is enabled as a compiler option? So compiler allocates in ZP first, then Golden Ram, then regular ram
|
||||||
|
- OR.... make all this more generic and use some %segment option to create real segments for 64tass?
|
||||||
|
- (need separate step in codegen and IR to write the "golden" variables)
|
||||||
|
|
||||||
Libraries:
|
Libraries:
|
||||||
|
|
||||||
|
@ -1,37 +1,54 @@
|
|||||||
%import textio
|
%import textio
|
||||||
%import cx16logo
|
%zeropage basicsafe
|
||||||
|
%option no_sysinit
|
||||||
nop {
|
|
||||||
sub lda(ubyte sec) -> ubyte {
|
|
||||||
asl:
|
|
||||||
ubyte brk = sec
|
|
||||||
sec++
|
|
||||||
brk += sec
|
|
||||||
return brk
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
main {
|
main {
|
||||||
|
|
||||||
sub ffalse(ubyte arg) -> ubyte {
|
|
||||||
arg++
|
|
||||||
return 0
|
|
||||||
}
|
|
||||||
sub ftrue(ubyte arg) -> ubyte {
|
|
||||||
arg++
|
|
||||||
return 128
|
|
||||||
}
|
|
||||||
|
|
||||||
sub start() {
|
sub start() {
|
||||||
ubyte col = 10
|
; TODO ALSO TEST AS GLOBALS
|
||||||
ubyte row = 20
|
ubyte @requirezp zpvar = 10
|
||||||
cx16logo.logo_at(col, row)
|
ubyte @zp zpvar2 = 20
|
||||||
txt.setcc(10, 10, 2, 3)
|
uword empty
|
||||||
txt.print_ub(nop.lda(42))
|
ubyte[10] bssarray
|
||||||
txt.nl()
|
uword[10] bsswordarray
|
||||||
txt.print_uw(nop.lda.asl)
|
ubyte[10] nonbssarray = 99
|
||||||
|
str name="irmen"
|
||||||
|
|
||||||
void ffalse(99)
|
txt.print("10 ")
|
||||||
void ftrue(99)
|
txt.print_ub(zpvar)
|
||||||
|
txt.nl()
|
||||||
|
zpvar++
|
||||||
|
|
||||||
|
txt.print("20 ")
|
||||||
|
txt.print_ub(zpvar2)
|
||||||
|
txt.nl()
|
||||||
|
zpvar2++
|
||||||
|
|
||||||
|
txt.print("0 ")
|
||||||
|
txt.print_uw(empty)
|
||||||
|
txt.nl()
|
||||||
|
empty++
|
||||||
|
|
||||||
|
txt.print("0 ")
|
||||||
|
txt.print_ub(bssarray[1])
|
||||||
|
txt.nl()
|
||||||
|
bssarray[1]++
|
||||||
|
|
||||||
|
txt.print("0 ")
|
||||||
|
txt.print_uw(bsswordarray[1])
|
||||||
|
txt.nl()
|
||||||
|
bsswordarray[1]++
|
||||||
|
|
||||||
|
txt.print("99 ")
|
||||||
|
txt.print_ub(nonbssarray[1])
|
||||||
|
txt.nl()
|
||||||
|
nonbssarray[1]++
|
||||||
|
|
||||||
|
txt.print("r ")
|
||||||
|
txt.chrout(name[1])
|
||||||
|
txt.nl()
|
||||||
|
name[1] = (name[1] as ubyte +1)
|
||||||
|
|
||||||
|
txt.print("try running again.\n")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -44,6 +44,7 @@ class IRFileReader {
|
|||||||
val programName = start.attributes.asSequence().single { it.name.localPart == "NAME" }.value
|
val programName = start.attributes.asSequence().single { it.name.localPart == "NAME" }.value
|
||||||
val options = parseOptions(reader)
|
val options = parseOptions(reader)
|
||||||
val asmsymbols = parseAsmSymbols(reader)
|
val asmsymbols = parseAsmSymbols(reader)
|
||||||
|
val bss = parseBss(reader)
|
||||||
val variables = parseVariables(reader, options.dontReinitGlobals)
|
val variables = parseVariables(reader, options.dontReinitGlobals)
|
||||||
val memorymapped = parseMemMapped(reader)
|
val memorymapped = parseMemMapped(reader)
|
||||||
val slabs = parseSlabs(reader)
|
val slabs = parseSlabs(reader)
|
||||||
@ -52,6 +53,7 @@ class IRFileReader {
|
|||||||
|
|
||||||
val st = IRSymbolTable(null)
|
val st = IRSymbolTable(null)
|
||||||
asmsymbols.forEach { (name, value) -> st.addAsmSymbol(name, value)}
|
asmsymbols.forEach { (name, value) -> st.addAsmSymbol(name, value)}
|
||||||
|
bss.forEach { st.add(it) }
|
||||||
variables.forEach { st.add(it) }
|
variables.forEach { st.add(it) }
|
||||||
memorymapped.forEach { st.add(it) }
|
memorymapped.forEach { st.add(it) }
|
||||||
slabs.forEach { st.add(it) }
|
slabs.forEach { st.add(it) }
|
||||||
@ -147,6 +149,33 @@ class IRFileReader {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun parseBss(reader: XMLEventReader): List<StStaticVariable> {
|
||||||
|
skipText(reader)
|
||||||
|
val start = reader.nextEvent().asStartElement()
|
||||||
|
require(start.name.localPart=="BSS") { "missing BSS" }
|
||||||
|
val text = readText(reader).trim()
|
||||||
|
require(reader.nextEvent().isEndElement)
|
||||||
|
|
||||||
|
return if(text.isBlank())
|
||||||
|
emptyList()
|
||||||
|
else {
|
||||||
|
val varPattern = Regex("(.+?)(\\[.+?\\])? (.+) (zp=(.+))?")
|
||||||
|
val bssVariables = mutableListOf<StStaticVariable>()
|
||||||
|
text.lineSequence().forEach { line ->
|
||||||
|
// example: uword main.start.qq2 zp=DONTCARE
|
||||||
|
val match = varPattern.matchEntire(line) ?: throw IRParseException("invalid BSS $line")
|
||||||
|
val (type, arrayspec, name, _, zpwish) = match.destructured
|
||||||
|
if('.' !in name)
|
||||||
|
throw IRParseException("unscoped varname: $name")
|
||||||
|
val arraysize = if(arrayspec.isNotBlank()) arrayspec.substring(1, arrayspec.length-1).toInt() else null
|
||||||
|
val dt: DataType = parseDatatype(type, arraysize!=null)
|
||||||
|
val zp = if(zpwish.isBlank()) ZeropageWish.DONTCARE else ZeropageWish.valueOf(zpwish)
|
||||||
|
bssVariables.add(StStaticVariable(name, dt, true, null, null, null, arraysize, zp, Position.DUMMY))
|
||||||
|
}
|
||||||
|
return bssVariables
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private fun parseVariables(reader: XMLEventReader, dontReinitGlobals: Boolean): List<StStaticVariable> {
|
private fun parseVariables(reader: XMLEventReader, dontReinitGlobals: Boolean): List<StStaticVariable> {
|
||||||
skipText(reader)
|
skipText(reader)
|
||||||
val start = reader.nextEvent().asStartElement()
|
val start = reader.nextEvent().asStartElement()
|
||||||
@ -165,6 +194,8 @@ class IRFileReader {
|
|||||||
// ubyte[6] main.start.namestring=105,114,109,101,110,0
|
// ubyte[6] main.start.namestring=105,114,109,101,110,0
|
||||||
val match = varPattern.matchEntire(line) ?: throw IRParseException("invalid VARIABLE $line")
|
val match = varPattern.matchEntire(line) ?: throw IRParseException("invalid VARIABLE $line")
|
||||||
val (type, arrayspec, name, value, _, zpwish) = match.destructured
|
val (type, arrayspec, name, value, _, zpwish) = match.destructured
|
||||||
|
if('.' !in name)
|
||||||
|
throw IRParseException("unscoped varname: $name")
|
||||||
val arraysize = if(arrayspec.isNotBlank()) arrayspec.substring(1, arrayspec.length-1).toInt() else null
|
val arraysize = if(arrayspec.isNotBlank()) arrayspec.substring(1, arrayspec.length-1).toInt() else null
|
||||||
val dt: DataType = parseDatatype(type, arraysize!=null)
|
val dt: DataType = parseDatatype(type, arraysize!=null)
|
||||||
val zp = if(zpwish.isBlank()) ZeropageWish.DONTCARE else ZeropageWish.valueOf(zpwish)
|
val zp = if(zpwish.isBlank()) ZeropageWish.DONTCARE else ZeropageWish.valueOf(zpwish)
|
||||||
@ -199,7 +230,7 @@ class IRFileReader {
|
|||||||
DataType.STR -> throw IRParseException("STR should have been converted to byte array")
|
DataType.STR -> throw IRParseException("STR should have been converted to byte array")
|
||||||
else -> throw IRParseException("weird dt")
|
else -> throw IRParseException("weird dt")
|
||||||
}
|
}
|
||||||
|
require(!bss) { "bss var should be in BSS section" }
|
||||||
variables.add(StStaticVariable(name, dt, bss, initNumeric, null, initArray, arraysize, zp, Position.DUMMY))
|
variables.add(StStaticVariable(name, dt, bss, initNumeric, null, initArray, arraysize, zp, Position.DUMMY))
|
||||||
}
|
}
|
||||||
return variables
|
return variables
|
||||||
|
@ -19,7 +19,7 @@ class IRFileWriter(private val irProgram: IRProgram, outfileOverride: Path?) {
|
|||||||
out.write("<PROGRAM NAME=\"${irProgram.name}\">\n")
|
out.write("<PROGRAM NAME=\"${irProgram.name}\">\n")
|
||||||
writeOptions()
|
writeOptions()
|
||||||
writeAsmSymbols()
|
writeAsmSymbols()
|
||||||
writeVariableAllocations()
|
writeVariables()
|
||||||
|
|
||||||
out.write("\n<INITGLOBALS>\n")
|
out.write("\n<INITGLOBALS>\n")
|
||||||
if(!irProgram.options.dontReinitGlobals) {
|
if(!irProgram.options.dontReinitGlobals) {
|
||||||
@ -137,10 +137,17 @@ class IRFileWriter(private val irProgram: IRProgram, outfileOverride: Path?) {
|
|||||||
out.write("</OPTIONS>\n")
|
out.write("</OPTIONS>\n")
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun writeVariableAllocations() {
|
private fun writeVariables() {
|
||||||
|
|
||||||
out.write("\n<VARIABLES>\n")
|
out.write("\n<BSS>\n")
|
||||||
for (variable in irProgram.st.allVariables()) {
|
for (variable in irProgram.st.allVariables().filter { it.bss }) {
|
||||||
|
val typeStr = getTypeString(variable)
|
||||||
|
// bss variables have no initialization value
|
||||||
|
out.write("$typeStr ${variable.name} zp=${variable.zpwish}\n")
|
||||||
|
}
|
||||||
|
|
||||||
|
out.write("</BSS>\n<VARIABLES>\n")
|
||||||
|
for (variable in irProgram.st.allVariables().filter { !it.bss }) {
|
||||||
val typeStr = getTypeString(variable)
|
val typeStr = getTypeString(variable)
|
||||||
val value: String = when(variable.dt) {
|
val value: String = when(variable.dt) {
|
||||||
DataType.FLOAT -> (variable.onetimeInitializationNumericValue ?: "").toString()
|
DataType.FLOAT -> (variable.onetimeInitializationNumericValue ?: "").toString()
|
||||||
|
@ -49,15 +49,18 @@ output=PRG
|
|||||||
launcher=BASIC
|
launcher=BASIC
|
||||||
zeropage=KERNALSAFE
|
zeropage=KERNALSAFE
|
||||||
loadAddress=0
|
loadAddress=0
|
||||||
dontReinitGlobals=false
|
dontReinitGlobals=true
|
||||||
evalStackBaseAddress=null
|
evalStackBaseAddress=null
|
||||||
</OPTIONS>
|
</OPTIONS>
|
||||||
|
|
||||||
<ASMSYMBOLS>
|
<ASMSYMBOLS>
|
||||||
</ASMSYMBOLS>
|
</ASMSYMBOLS>
|
||||||
|
|
||||||
|
<BSS>
|
||||||
|
uword sys.bssvar zp=DONTCARE
|
||||||
|
</BSS>
|
||||||
<VARIABLES>
|
<VARIABLES>
|
||||||
uword sys.wait.jiffies= zp=DONTCARE
|
uword sys.wait.jiffies=10 zp=DONTCARE
|
||||||
</VARIABLES>
|
</VARIABLES>
|
||||||
|
|
||||||
<MEMORYMAPPEDVARIABLES>
|
<MEMORYMAPPEDVARIABLES>
|
||||||
@ -105,7 +108,10 @@ return
|
|||||||
tempfile.deleteExisting()
|
tempfile.deleteExisting()
|
||||||
program.name shouldBe "test-ir-reader"
|
program.name shouldBe "test-ir-reader"
|
||||||
program.blocks.size shouldBe 2
|
program.blocks.size shouldBe 2
|
||||||
program.st.allVariables().count() shouldBe 1
|
program.st.allVariables().count() shouldBe 2
|
||||||
program.st.lookup("sys.wait.jiffies") shouldBe instanceOf<StStaticVariable>()
|
val var1 = program.st.lookup("sys.wait.jiffies") as StStaticVariable
|
||||||
|
val var2 = program.st.lookup("sys.bssvar") as StStaticVariable
|
||||||
|
var1.bss shouldBe false
|
||||||
|
var2.bss shouldBe true
|
||||||
}
|
}
|
||||||
})
|
})
|
@ -1,10 +1,12 @@
|
|||||||
package prog8.vm
|
package prog8.vm
|
||||||
|
|
||||||
|
import kotlin.random.Random
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 64 Kb of random access memory.
|
* 64 Kb of random access memory. Initialized to random values.
|
||||||
*/
|
*/
|
||||||
class Memory {
|
class Memory {
|
||||||
private val mem = Array<UByte>(64 * 1024) { 0u }
|
private val mem = Array<UByte>(64 * 1024) { Random.nextInt().toUByte() }
|
||||||
|
|
||||||
fun reset() {
|
fun reset() {
|
||||||
mem.fill(0u)
|
mem.fill(0u)
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
package prog8.vm
|
package prog8.vm
|
||||||
|
|
||||||
|
import prog8.code.core.ArrayDatatypes
|
||||||
import prog8.code.core.AssemblyError
|
import prog8.code.core.AssemblyError
|
||||||
import prog8.code.core.DataType
|
import prog8.code.core.DataType
|
||||||
import prog8.intermediate.*
|
import prog8.intermediate.*
|
||||||
@ -183,6 +184,29 @@ class VmProgramLoader {
|
|||||||
) {
|
) {
|
||||||
program.st.allVariables().forEach { variable ->
|
program.st.allVariables().forEach { variable ->
|
||||||
var addr = allocations.allocations.getValue(variable.name)
|
var addr = allocations.allocations.getValue(variable.name)
|
||||||
|
|
||||||
|
if(variable.bss && variable.dt in ArrayDatatypes) {
|
||||||
|
// zero out the array bss variable.
|
||||||
|
// non-array variables are reset using explicit assignment instructions.
|
||||||
|
repeat(variable.length!!) {
|
||||||
|
when(variable.dt) {
|
||||||
|
DataType.STR, DataType.ARRAY_UB, DataType.ARRAY_B, DataType.ARRAY_BOOL -> {
|
||||||
|
memory.setUB(addr, 0u)
|
||||||
|
addr++
|
||||||
|
}
|
||||||
|
DataType.ARRAY_UW, DataType.ARRAY_W -> {
|
||||||
|
memory.setUW(addr, 0u)
|
||||||
|
addr += 2
|
||||||
|
}
|
||||||
|
DataType.ARRAY_F -> {
|
||||||
|
memory.setFloat(addr, 0.0f)
|
||||||
|
addr += program.options.compTarget.machine.FLOAT_MEM_SIZE
|
||||||
|
}
|
||||||
|
else -> throw IRParseException("invalid dt")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
variable.onetimeInitializationNumericValue?.let {
|
variable.onetimeInitializationNumericValue?.let {
|
||||||
when(variable.dt) {
|
when(variable.dt) {
|
||||||
DataType.UBYTE -> memory.setUB(addr, it.toInt().toUByte())
|
DataType.UBYTE -> memory.setUB(addr, it.toInt().toUByte())
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
import io.kotest.assertions.throwables.shouldThrow
|
import io.kotest.assertions.throwables.shouldThrow
|
||||||
import io.kotest.core.spec.style.FunSpec
|
import io.kotest.core.spec.style.FunSpec
|
||||||
import io.kotest.matchers.shouldBe
|
import io.kotest.matchers.shouldBe
|
||||||
|
import io.kotest.matchers.shouldNotBe
|
||||||
import prog8.vm.Memory
|
import prog8.vm.Memory
|
||||||
|
|
||||||
|
|
||||||
@ -46,7 +47,9 @@ class TestMemory: FunSpec({
|
|||||||
|
|
||||||
test("32 bits float access") {
|
test("32 bits float access") {
|
||||||
val mem = Memory()
|
val mem = Memory()
|
||||||
mem.getFloat(1000) shouldBe 0.0
|
mem.getFloat(1000) shouldNotBe 0.0
|
||||||
|
mem.setFloat(1000, 0.0f)
|
||||||
|
mem.getFloat(1000) shouldBe 0.0f
|
||||||
mem.setFloat(1000, -9.876543f)
|
mem.setFloat(1000, -9.876543f)
|
||||||
mem.getFloat(1000) shouldBe -9.876543f
|
mem.getFloat(1000) shouldBe -9.876543f
|
||||||
}
|
}
|
||||||
|
@ -2,6 +2,7 @@ import io.kotest.assertions.throwables.shouldThrowWithMessage
|
|||||||
import io.kotest.core.spec.style.FunSpec
|
import io.kotest.core.spec.style.FunSpec
|
||||||
import io.kotest.matchers.collections.shouldBeEmpty
|
import io.kotest.matchers.collections.shouldBeEmpty
|
||||||
import io.kotest.matchers.shouldBe
|
import io.kotest.matchers.shouldBe
|
||||||
|
import io.kotest.matchers.shouldNotBe
|
||||||
import prog8.code.core.*
|
import prog8.code.core.*
|
||||||
import prog8.code.target.VMTarget
|
import prog8.code.target.VMTarget
|
||||||
import prog8.intermediate.*
|
import prog8.intermediate.*
|
||||||
@ -51,6 +52,7 @@ class TestVm: FunSpec( {
|
|||||||
block += startSub
|
block += startSub
|
||||||
program.addBlock(block)
|
program.addBlock(block)
|
||||||
val vm = VirtualMachine(program)
|
val vm = VirtualMachine(program)
|
||||||
|
vm.memory.setUW(1000, 0u)
|
||||||
|
|
||||||
vm.memory.getUW(1000) shouldBe 0u
|
vm.memory.getUW(1000) shouldBe 0u
|
||||||
vm.callStack.shouldBeEmpty()
|
vm.callStack.shouldBeEmpty()
|
||||||
@ -128,6 +130,8 @@ class TestVm: FunSpec( {
|
|||||||
<ASMSYMBOLS>
|
<ASMSYMBOLS>
|
||||||
</ASMSYMBOLS>
|
</ASMSYMBOLS>
|
||||||
|
|
||||||
|
<BSS>
|
||||||
|
</BSS>
|
||||||
<VARIABLES>
|
<VARIABLES>
|
||||||
</VARIABLES>
|
</VARIABLES>
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user