mirror of
https://github.com/irmen/prog8.git
synced 2024-10-21 04:24:05 +00:00
IR: mem mapped vars and memory slabs
This commit is contained in:
parent
c8f3bfa726
commit
627ed51a1b
@ -1,5 +1,6 @@
|
|||||||
package prog8.codegen.experimental
|
package prog8.codegen.experimental
|
||||||
|
|
||||||
|
import prog8.code.StMemVar
|
||||||
import prog8.code.StMemorySlab
|
import prog8.code.StMemorySlab
|
||||||
import prog8.code.StStaticVariable
|
import prog8.code.StStaticVariable
|
||||||
import prog8.code.SymbolTable
|
import prog8.code.SymbolTable
|
||||||
@ -69,6 +70,8 @@ class CodeGen(internal val program: PtProgram,
|
|||||||
irProg.addBlock(translate(block))
|
irProg.addBlock(translate(block))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
replaceMemoryMappedVars(irProg)
|
||||||
|
|
||||||
if(options.optimize) {
|
if(options.optimize) {
|
||||||
val optimizer = IRPeepholeOptimizer(irProg)
|
val optimizer = IRPeepholeOptimizer(irProg)
|
||||||
optimizer.optimize()
|
optimizer.optimize()
|
||||||
@ -81,6 +84,51 @@ class CodeGen(internal val program: PtProgram,
|
|||||||
return VmAssemblyProgram(irProgFromDisk.name, irProgFromDisk)
|
return VmAssemblyProgram(irProgFromDisk.name, irProgFromDisk)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun replaceMemoryMappedVars(irProg: IRProgram) {
|
||||||
|
// replace memory mapped variable symbols with the memory address directly.
|
||||||
|
// note: we do still export the memory mapped symbols so a code generator can use those
|
||||||
|
// for instance when a piece of inlined assembly references them.
|
||||||
|
val replacements = mutableListOf<Triple<IRCodeChunkBase, Int, UInt>>()
|
||||||
|
irProg.blocks.asSequence().flatMap { it.subroutines }.flatMap { it.chunks }.forEach { chunk ->
|
||||||
|
chunk.lines.withIndex().forEach {
|
||||||
|
(lineIndex, line)-> if(line is IRCodeInstruction) {
|
||||||
|
val symbolExpr = line.ins.labelSymbol?.single()
|
||||||
|
if(symbolExpr!=null) {
|
||||||
|
val symbol: String
|
||||||
|
val index: UInt
|
||||||
|
if('+' in symbolExpr) {
|
||||||
|
val operands = symbolExpr.split('+', )
|
||||||
|
symbol = operands[0]
|
||||||
|
index = operands[1].toUInt()
|
||||||
|
} else {
|
||||||
|
symbol = symbolExpr
|
||||||
|
index = 0u
|
||||||
|
}
|
||||||
|
val target = symbolTable.flat[symbol.split('.')]
|
||||||
|
if (target is StMemVar) {
|
||||||
|
replacements.add(Triple(chunk, lineIndex, target.address+index))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
replacements.forEach {
|
||||||
|
val old = it.first.lines[it.second] as IRCodeInstruction
|
||||||
|
it.first.lines[it.second] = IRCodeInstruction(
|
||||||
|
old.ins.opcode,
|
||||||
|
old.ins.type,
|
||||||
|
old.ins.reg1,
|
||||||
|
old.ins.reg2,
|
||||||
|
old.ins.fpReg1,
|
||||||
|
old.ins.fpReg2,
|
||||||
|
it.third.toInt(),
|
||||||
|
null,
|
||||||
|
null
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private fun flattenNestedSubroutines() {
|
private fun flattenNestedSubroutines() {
|
||||||
// this moves all nested subroutines up to the block scope.
|
// this moves all nested subroutines up to the block scope.
|
||||||
// also changes the name to be the fully scoped one so it becomes unique at the top level.
|
// also changes the name to be the fully scoped one so it becomes unique at the top level.
|
||||||
|
@ -44,6 +44,7 @@ internal class ExpressionGen(private val codeGen: CodeGen) {
|
|||||||
is PtAddressOf -> {
|
is PtAddressOf -> {
|
||||||
val vmDt = codeGen.vmType(expr.type)
|
val vmDt = codeGen.vmType(expr.type)
|
||||||
val symbol = expr.identifier.targetName.joinToString(".")
|
val symbol = expr.identifier.targetName.joinToString(".")
|
||||||
|
// note: LOAD <symbol> gets you the address of the symbol, whereas LOADM <symbol> would get you the value stored at that location
|
||||||
code += IRCodeInstruction(Opcode.LOAD, vmDt, reg1=resultRegister, labelSymbol = symbol)
|
code += IRCodeInstruction(Opcode.LOAD, vmDt, reg1=resultRegister, labelSymbol = symbol)
|
||||||
}
|
}
|
||||||
is PtMemoryByte -> {
|
is PtMemoryByte -> {
|
||||||
|
@ -79,11 +79,6 @@ class VmAssemblyProgram(override val name: String, val irProgram: IRProgram): IA
|
|||||||
private fun processInlinedAsm(asm: String, allocations: VmVariableAllocator): String {
|
private fun processInlinedAsm(asm: String, allocations: VmVariableAllocator): String {
|
||||||
// TODO do we have to replace variable names by their allocated address???
|
// TODO do we have to replace variable names by their allocated address???
|
||||||
return asm
|
return asm
|
||||||
// // need to replace &X by address of X. TODO: this actually needs to be done by the vm assembler/loader. Then this can be omitted
|
|
||||||
// return asm.replace("""&[a-zA-Z\d_\.]+""".toRegex()) { matchResult ->
|
|
||||||
// // replace "&X" with the address of X
|
|
||||||
// val name = matchResult.value.substring(1, matchResult.value.length).split('.')
|
|
||||||
// allocations.get(name).toString() }
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2,6 +2,7 @@ package prog8.codegen.experimental
|
|||||||
|
|
||||||
import prog8.code.SymbolTable
|
import prog8.code.SymbolTable
|
||||||
import prog8.code.core.*
|
import prog8.code.core.*
|
||||||
|
import prog8.intermediate.getTypeString
|
||||||
|
|
||||||
class VmVariableAllocator(val st: SymbolTable, val encoding: IStringEncoding, memsizer: IMemSizer) {
|
class VmVariableAllocator(val st: SymbolTable, val encoding: IStringEncoding, memsizer: IMemSizer) {
|
||||||
|
|
||||||
@ -26,24 +27,21 @@ class VmVariableAllocator(val st: SymbolTable, val encoding: IStringEncoding, me
|
|||||||
allocations[variable.scopedName] = nextLocation
|
allocations[variable.scopedName] = nextLocation
|
||||||
nextLocation += memsize
|
nextLocation += memsize
|
||||||
}
|
}
|
||||||
|
for(slab in st.allMemorySlabs) {
|
||||||
|
// we ignore the alignment for the VM.
|
||||||
|
allocations[slab.scopedName] = nextLocation
|
||||||
|
nextLocation += slab.size.toInt()
|
||||||
|
}
|
||||||
|
|
||||||
freeMemoryStart = nextLocation
|
freeMemoryStart = nextLocation
|
||||||
}
|
}
|
||||||
|
|
||||||
fun get(name: List<String>) = allocations.getValue(name)
|
|
||||||
|
|
||||||
fun asVmMemory(): List<Pair<List<String>, String>> {
|
fun asVmMemory(): List<Pair<List<String>, String>> {
|
||||||
val mm = mutableListOf<Pair<List<String>, String>>()
|
val mm = mutableListOf<Pair<List<String>, String>>()
|
||||||
|
|
||||||
|
// normal variables
|
||||||
for (variable in st.allVariables) {
|
for (variable in st.allVariables) {
|
||||||
val location = allocations.getValue(variable.scopedName)
|
val location = allocations.getValue(variable.scopedName)
|
||||||
val typeStr = when(variable.dt) {
|
|
||||||
DataType.UBYTE, DataType.ARRAY_UB, DataType.STR -> "ubyte"
|
|
||||||
DataType.BYTE, DataType.ARRAY_B -> "byte"
|
|
||||||
DataType.UWORD, DataType.ARRAY_UW -> "uword"
|
|
||||||
DataType.WORD, DataType.ARRAY_W -> "word"
|
|
||||||
DataType.FLOAT, DataType.ARRAY_F -> "float"
|
|
||||||
else -> throw InternalCompilerException("weird dt")
|
|
||||||
}
|
|
||||||
val value = when(variable.dt) {
|
val value = when(variable.dt) {
|
||||||
DataType.FLOAT -> (variable.onetimeInitializationNumericValue ?: 0.0).toString()
|
DataType.FLOAT -> (variable.onetimeInitializationNumericValue ?: 0.0).toString()
|
||||||
in NumericDatatypes -> (variable.onetimeInitializationNumericValue ?: 0).toHex()
|
in NumericDatatypes -> (variable.onetimeInitializationNumericValue ?: 0).toHex()
|
||||||
@ -67,8 +65,27 @@ class VmVariableAllocator(val st: SymbolTable, val encoding: IStringEncoding, me
|
|||||||
}
|
}
|
||||||
else -> throw InternalCompilerException("weird dt")
|
else -> throw InternalCompilerException("weird dt")
|
||||||
}
|
}
|
||||||
mm.add(Pair(variable.scopedName, "@$location $typeStr $value"))
|
mm.add(Pair(variable.scopedName, "@$location ${getTypeString(variable)} $value"))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// memory mapped variables
|
||||||
|
for (variable in st.allMemMappedVariables) {
|
||||||
|
val value = when(variable.dt) {
|
||||||
|
DataType.FLOAT -> "0.0"
|
||||||
|
in NumericDatatypes -> "0"
|
||||||
|
DataType.ARRAY_F -> (1..variable.length!!).joinToString(",") { "0.0" }
|
||||||
|
in ArrayDatatypes -> (1..variable.length!!).joinToString(",") { "0" }
|
||||||
|
else -> throw InternalCompilerException("weird dt for mem mapped var")
|
||||||
|
}
|
||||||
|
mm.add(Pair(variable.scopedName, "@${variable.address} ${getTypeString(variable)} $value"))
|
||||||
|
}
|
||||||
|
|
||||||
|
// memory slabs.
|
||||||
|
for(slab in st.allMemorySlabs) {
|
||||||
|
val address = allocations.getValue(slab.scopedName)
|
||||||
|
mm.add(Pair(slab.scopedName, "@$address ubyte[${slab.size}] 0"))
|
||||||
|
}
|
||||||
|
|
||||||
return mm
|
return mm
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -48,12 +48,7 @@ class AssemblyProgram(override val name: String, private val allocations: Variab
|
|||||||
is VmCodeLabel -> write("_" + line.name.joinToString(".") + ":\n")
|
is VmCodeLabel -> write("_" + line.name.joinToString(".") + ":\n")
|
||||||
is VmCodeInlineAsm -> {
|
is VmCodeInlineAsm -> {
|
||||||
// TODO do we have to replace variable names by their allocated address???
|
// TODO do we have to replace variable names by their allocated address???
|
||||||
val asm = line.assembly
|
write(line.assembly+"\n")
|
||||||
// val asm = line.assembly.replace("""&[a-zA-Z\d_\.]+""".toRegex()) { matchResult ->
|
|
||||||
// // need to replace &X by address of X. TODO: this actually needs to be done by the vm assembler/loader. Then this can be omitted
|
|
||||||
// val name = matchResult.value.substring(1, matchResult.value.length).split('.')
|
|
||||||
// allocations.get(name).toString() }
|
|
||||||
write(asm+"\n")
|
|
||||||
}
|
}
|
||||||
is VmCodeInlineBinary -> {
|
is VmCodeInlineBinary -> {
|
||||||
write("incbin \"${line.file}\"")
|
write("incbin \"${line.file}\"")
|
||||||
|
@ -110,105 +110,105 @@ cx16 {
|
|||||||
|
|
||||||
; the sixteen virtual 16-bit registers that the CX16 has defined in the zeropage
|
; the sixteen virtual 16-bit registers that the CX16 has defined in the zeropage
|
||||||
; they are simulated on the VirtualMachine as well but their location in memory is different
|
; they are simulated on the VirtualMachine as well but their location in memory is different
|
||||||
&uword r0 = $0002
|
&uword r0 = $ff02
|
||||||
&uword r1 = $0004
|
&uword r1 = $ff04
|
||||||
&uword r2 = $0006
|
&uword r2 = $ff06
|
||||||
&uword r3 = $0008
|
&uword r3 = $ff08
|
||||||
&uword r4 = $000a
|
&uword r4 = $ff0a
|
||||||
&uword r5 = $000c
|
&uword r5 = $ff0c
|
||||||
&uword r6 = $000e
|
&uword r6 = $ff0e
|
||||||
&uword r7 = $0010
|
&uword r7 = $ff10
|
||||||
&uword r8 = $0012
|
&uword r8 = $ff12
|
||||||
&uword r9 = $0014
|
&uword r9 = $ff14
|
||||||
&uword r10 = $0016
|
&uword r10 = $ff16
|
||||||
&uword r11 = $0018
|
&uword r11 = $ff18
|
||||||
&uword r12 = $001a
|
&uword r12 = $ff1a
|
||||||
&uword r13 = $001c
|
&uword r13 = $ff1c
|
||||||
&uword r14 = $001e
|
&uword r14 = $ff1e
|
||||||
&uword r15 = $0020
|
&uword r15 = $ff20
|
||||||
|
|
||||||
&word r0s = $0002
|
&word r0s = $ff02
|
||||||
&word r1s = $0004
|
&word r1s = $ff04
|
||||||
&word r2s = $0006
|
&word r2s = $ff06
|
||||||
&word r3s = $0008
|
&word r3s = $ff08
|
||||||
&word r4s = $000a
|
&word r4s = $ff0a
|
||||||
&word r5s = $000c
|
&word r5s = $ff0c
|
||||||
&word r6s = $000e
|
&word r6s = $ff0e
|
||||||
&word r7s = $0010
|
&word r7s = $ff10
|
||||||
&word r8s = $0012
|
&word r8s = $ff12
|
||||||
&word r9s = $0014
|
&word r9s = $ff14
|
||||||
&word r10s = $0016
|
&word r10s = $ff16
|
||||||
&word r11s = $0018
|
&word r11s = $ff18
|
||||||
&word r12s = $001a
|
&word r12s = $ff1a
|
||||||
&word r13s = $001c
|
&word r13s = $ff1c
|
||||||
&word r14s = $001e
|
&word r14s = $ff1e
|
||||||
&word r15s = $0020
|
&word r15s = $ff20
|
||||||
|
|
||||||
&ubyte r0L = $0002
|
&ubyte r0L = $ff02
|
||||||
&ubyte r1L = $0004
|
&ubyte r1L = $ff04
|
||||||
&ubyte r2L = $0006
|
&ubyte r2L = $ff06
|
||||||
&ubyte r3L = $0008
|
&ubyte r3L = $ff08
|
||||||
&ubyte r4L = $000a
|
&ubyte r4L = $ff0a
|
||||||
&ubyte r5L = $000c
|
&ubyte r5L = $ff0c
|
||||||
&ubyte r6L = $000e
|
&ubyte r6L = $ff0e
|
||||||
&ubyte r7L = $0010
|
&ubyte r7L = $ff10
|
||||||
&ubyte r8L = $0012
|
&ubyte r8L = $ff12
|
||||||
&ubyte r9L = $0014
|
&ubyte r9L = $ff14
|
||||||
&ubyte r10L = $0016
|
&ubyte r10L = $ff16
|
||||||
&ubyte r11L = $0018
|
&ubyte r11L = $ff18
|
||||||
&ubyte r12L = $001a
|
&ubyte r12L = $ff1a
|
||||||
&ubyte r13L = $001c
|
&ubyte r13L = $ff1c
|
||||||
&ubyte r14L = $001e
|
&ubyte r14L = $ff1e
|
||||||
&ubyte r15L = $0020
|
&ubyte r15L = $ff20
|
||||||
|
|
||||||
&ubyte r0H = $0003
|
&ubyte r0H = $ff03
|
||||||
&ubyte r1H = $0005
|
&ubyte r1H = $ff05
|
||||||
&ubyte r2H = $0007
|
&ubyte r2H = $ff07
|
||||||
&ubyte r3H = $0009
|
&ubyte r3H = $ff09
|
||||||
&ubyte r4H = $000b
|
&ubyte r4H = $ff0b
|
||||||
&ubyte r5H = $000d
|
&ubyte r5H = $ff0d
|
||||||
&ubyte r6H = $000f
|
&ubyte r6H = $ff0f
|
||||||
&ubyte r7H = $0011
|
&ubyte r7H = $ff11
|
||||||
&ubyte r8H = $0013
|
&ubyte r8H = $ff13
|
||||||
&ubyte r9H = $0015
|
&ubyte r9H = $ff15
|
||||||
&ubyte r10H = $0017
|
&ubyte r10H = $ff17
|
||||||
&ubyte r11H = $0019
|
&ubyte r11H = $ff19
|
||||||
&ubyte r12H = $001b
|
&ubyte r12H = $ff1b
|
||||||
&ubyte r13H = $001d
|
&ubyte r13H = $ff1d
|
||||||
&ubyte r14H = $001f
|
&ubyte r14H = $ff1f
|
||||||
&ubyte r15H = $0021
|
&ubyte r15H = $ff21
|
||||||
|
|
||||||
&byte r0sL = $0002
|
&byte r0sL = $ff02
|
||||||
&byte r1sL = $0004
|
&byte r1sL = $ff04
|
||||||
&byte r2sL = $0006
|
&byte r2sL = $ff06
|
||||||
&byte r3sL = $0008
|
&byte r3sL = $ff08
|
||||||
&byte r4sL = $000a
|
&byte r4sL = $ff0a
|
||||||
&byte r5sL = $000c
|
&byte r5sL = $ff0c
|
||||||
&byte r6sL = $000e
|
&byte r6sL = $ff0e
|
||||||
&byte r7sL = $0010
|
&byte r7sL = $ff10
|
||||||
&byte r8sL = $0012
|
&byte r8sL = $ff12
|
||||||
&byte r9sL = $0014
|
&byte r9sL = $ff14
|
||||||
&byte r10sL = $0016
|
&byte r10sL = $ff16
|
||||||
&byte r11sL = $0018
|
&byte r11sL = $ff18
|
||||||
&byte r12sL = $001a
|
&byte r12sL = $ff1a
|
||||||
&byte r13sL = $001c
|
&byte r13sL = $ff1c
|
||||||
&byte r14sL = $001e
|
&byte r14sL = $ff1e
|
||||||
&byte r15sL = $0020
|
&byte r15sL = $ff20
|
||||||
|
|
||||||
&byte r0sH = $0003
|
&byte r0sH = $ff03
|
||||||
&byte r1sH = $0005
|
&byte r1sH = $ff05
|
||||||
&byte r2sH = $0007
|
&byte r2sH = $ff07
|
||||||
&byte r3sH = $0009
|
&byte r3sH = $ff09
|
||||||
&byte r4sH = $000b
|
&byte r4sH = $ff0b
|
||||||
&byte r5sH = $000d
|
&byte r5sH = $ff0d
|
||||||
&byte r6sH = $000f
|
&byte r6sH = $ff0f
|
||||||
&byte r7sH = $0011
|
&byte r7sH = $ff11
|
||||||
&byte r8sH = $0013
|
&byte r8sH = $ff13
|
||||||
&byte r9sH = $0015
|
&byte r9sH = $ff15
|
||||||
&byte r10sH = $0017
|
&byte r10sH = $ff17
|
||||||
&byte r11sH = $0019
|
&byte r11sH = $ff19
|
||||||
&byte r12sH = $001b
|
&byte r12sH = $ff1b
|
||||||
&byte r13sH = $001d
|
&byte r13sH = $ff1d
|
||||||
&byte r14sH = $001f
|
&byte r14sH = $ff1f
|
||||||
&byte r15sH = $0021
|
&byte r15sH = $ff21
|
||||||
}
|
}
|
||||||
|
@ -617,7 +617,7 @@ internal class AstChecker(private val program: Program,
|
|||||||
err("memory address must be valid integer 0..\$ffff")
|
err("memory address must be valid integer 0..\$ffff")
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
err("value of memory mapped variable can only be a fixed number, perhaps you meant to use an address pointer type instead?")
|
err("value of memory mapped variable can only be a constant, maybe use an address pointer type instead?")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -3,10 +3,11 @@ TODO
|
|||||||
|
|
||||||
For next release
|
For next release
|
||||||
^^^^^^^^^^^^^^^^
|
^^^^^^^^^^^^^^^^
|
||||||
- IR/VM: add proper memory mapped variables support - replace the symbol by the memory address in the IR code.
|
|
||||||
- IR/VM: check that the above works ok now with the cx16 virtual registers.
|
|
||||||
- IR/VM: actually support the physical cpu registers and status flags in the STORECPU and LOADCPU opcodes.
|
- IR/VM: actually support the physical cpu registers and status flags in the STORECPU and LOADCPU opcodes.
|
||||||
- IR/VM: add proper memory slabs support
|
- IR: option to save IR in file
|
||||||
|
- Replace existing vm codegen by expericodegen, expericodegen just stops at saving IR in file.
|
||||||
|
- vm: implement remaining sin/cos functions in virtual/math.p8 and merge tables
|
||||||
|
- write some documentation about the compiler architecture and where to plug a code generator onto.
|
||||||
- IR/VM: improve unit tests
|
- IR/VM: improve unit tests
|
||||||
|
|
||||||
...
|
...
|
||||||
@ -22,20 +23,17 @@ Need help with
|
|||||||
Future Things and Ideas
|
Future Things and Ideas
|
||||||
^^^^^^^^^^^^^^^^^^^^^^^
|
^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
Compiler:
|
Compiler:
|
||||||
- vm: implement remaining sin/cos functions in math.p8 and merge tables
|
- vm: Jumps go to a code block rather than a specific address(label) -> also helps future dead code elimination?
|
||||||
|
- vm: the above means that every label introduces a new code block. This eliminates the use of actual labels altogether.
|
||||||
|
- vm: add more optimizations in IRPeepholeOptimizer
|
||||||
- vm: how to remove all unused subroutines? (the 6502 assembly codegen relies on 64tass solve this for us)
|
- vm: how to remove all unused subroutines? (the 6502 assembly codegen relies on 64tass solve this for us)
|
||||||
- vm: rather than being able to jump to any 'address' (IPTR), use 'blocks' that have entry and exit points -> even better dead code elimination possible too
|
|
||||||
- vm: add more optimizations in VmPeepholeOptimizer
|
|
||||||
- see if we can let for loops skip the loop if end<start, like other programming languages. Without adding a lot of code size/duplicating the loop condition.
|
- see if we can let for loops skip the loop if end<start, like other programming languages. Without adding a lot of code size/duplicating the loop condition.
|
||||||
this is documented behavior to now loop around but it's too easy to forget about!
|
this is documented behavior to now loop around but it's too easy to forget about!
|
||||||
Lot of work because of so many special cases in ForLoopsAsmgen.....
|
Lot of work because of so many special cases in ForLoopsAsmgen.....
|
||||||
How is it for the vm target? -> just 2 special cases in CodeGen.
|
How is it for the vm target? -> just 2 special cases in CodeGen.
|
||||||
- when the vm is stable and *if* its language can get promoted to prog8 IL, the variable allocation should be changed.
|
|
||||||
It's now done before the vm code generation, but the IL should probably not depend on the allocations already performed.
|
|
||||||
So the CodeGen doesn't do VariableAlloc *before* the codegen, but as a last step instead.
|
|
||||||
- createAssemblyAndAssemble(): make it possible to actually get rid of the VarDecl nodes by fixing the rest of the code mentioned there.
|
- createAssemblyAndAssemble(): make it possible to actually get rid of the VarDecl nodes by fixing the rest of the code mentioned there.
|
||||||
but probably better to rewrite the 6502 codegen on top of the new Ast.
|
but probably better to rewrite the 6502 codegen on top of the new Ast.
|
||||||
- generate WASM from the new ast (or from vm code?) to eventually run prog8 on a browser canvas?
|
- generate WASM to eventually run prog8 on a browser canvas?
|
||||||
- make it possible to use cpu opcodes such as 'nop' as variable names by prefixing all asm vars with something such as ``p8v_``? Or not worth it (most 3 letter opcodes as variables are nonsensical anyway)
|
- make it possible to use cpu opcodes such as 'nop' as variable names by prefixing all asm vars with something such as ``p8v_``? Or not worth it (most 3 letter opcodes as variables are nonsensical anyway)
|
||||||
then we can get rid of the instruction lists in the machinedefinitions as well?
|
then we can get rid of the instruction lists in the machinedefinitions as well?
|
||||||
- [problematic due to using 64tass:] add a compiler option to not remove unused subroutines. this allows for building library programs. But this won't work with 64tass's .proc ...
|
- [problematic due to using 64tass:] add a compiler option to not remove unused subroutines. this allows for building library programs. But this won't work with 64tass's .proc ...
|
||||||
|
166
examples/test.p8
166
examples/test.p8
@ -1,83 +1,103 @@
|
|||||||
%zpreserved 10,20
|
|
||||||
%zpreserved 30,40
|
|
||||||
|
|
||||||
main {
|
main {
|
||||||
|
|
||||||
uword @shared global1 = 1234
|
|
||||||
str @shared globalstring = "irmen"
|
|
||||||
|
|
||||||
%asm {{
|
|
||||||
nop
|
|
||||||
nop
|
|
||||||
return
|
|
||||||
}}
|
|
||||||
|
|
||||||
romsub $ee33 = myromsub(ubyte arg1 @A) clobbers() -> ubyte @Y
|
|
||||||
romsub $ee44 = myromsubmulti(ubyte arg1 @A) clobbers() -> ubyte @Y, ubyte @X, ubyte @Pc
|
|
||||||
|
|
||||||
asmsub testasmsub(ubyte arg1 @A) clobbers(Y) -> uword @AX {
|
|
||||||
%asm {{
|
|
||||||
nop
|
|
||||||
return
|
|
||||||
}}
|
|
||||||
}
|
|
||||||
|
|
||||||
sub start() {
|
sub start() {
|
||||||
void myromsubmulti(44)
|
|
||||||
global1 = myromsub(44)
|
|
||||||
sys.wait(1)
|
|
||||||
|
|
||||||
%asm {{
|
uword @shared slab1 = memory("slab 1", 2000, 0)
|
||||||
nop
|
uword @shared slab2 = memory("slab 1", 2000, 0)
|
||||||
jump _a_label
|
uword @shared slab3 = memory("other # slab", 2000, 64)
|
||||||
}}
|
|
||||||
a_label:
|
|
||||||
|
|
||||||
%asmbinary "LICENSE", 200, 513
|
uword total = slab1+slab2+slab3
|
||||||
|
txt.print_uw(slab1)
|
||||||
|
txt.nl()
|
||||||
|
txt.print_uw(slab2)
|
||||||
|
txt.nl()
|
||||||
|
txt.print_uw(slab3)
|
||||||
|
txt.nl()
|
||||||
|
txt.print_uw(total)
|
||||||
|
txt.nl()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
; TODO add proper memory SLAB support to IR+VM
|
; uword @shared global1 = 1234
|
||||||
|
; str @shared globalstring = "irmen"
|
||||||
|
;
|
||||||
|
; %asm {{
|
||||||
|
; nop
|
||||||
|
; nop
|
||||||
|
; return
|
||||||
|
; }}
|
||||||
|
;
|
||||||
|
; romsub $ee33 = myromsub(ubyte arg1 @A) clobbers() -> ubyte @Y
|
||||||
|
; romsub $ee44 = myromsubmulti(ubyte arg1 @A) clobbers() -> ubyte @Y, ubyte @X, ubyte @Pc
|
||||||
|
;
|
||||||
|
; asmsub testasmsub(ubyte arg1 @A) clobbers(Y) -> uword @AX {
|
||||||
|
; %asm {{
|
||||||
|
; nop
|
||||||
|
; return
|
||||||
|
; }}
|
||||||
|
; }
|
||||||
|
;
|
||||||
|
; sub start() {
|
||||||
|
; void myromsubmulti(44)
|
||||||
|
; global1 = myromsub(44)
|
||||||
|
; sys.wait(1)
|
||||||
|
;
|
||||||
|
; cx16.r0 = 11111
|
||||||
|
; cx16.r0L = 22
|
||||||
|
; cx16.r0H = 33
|
||||||
|
;
|
||||||
|
; %asm {{
|
||||||
|
; nop
|
||||||
|
; jump main.start.a_label
|
||||||
|
; }}
|
||||||
|
;a_label:
|
||||||
|
;
|
||||||
|
; %asmbinary "LICENSE", 200, 513
|
||||||
|
;
|
||||||
|
;; TODO add proper memory SLAB support to IR+VM
|
||||||
; uword @shared slab1 = memory("slab 1", 2000, 0)
|
; uword @shared slab1 = memory("slab 1", 2000, 0)
|
||||||
; uword @shared slab2 = memory("slab 1", 2000, 0)
|
; uword @shared slab2 = memory("slab 1", 2000, 0)
|
||||||
; uword @shared slab3 = memory("other # slab", 2000, 64)
|
; uword @shared slab3 = memory("other # slab", 2000, 64)
|
||||||
|
;
|
||||||
&uword mapped = $c000
|
; &uword mapped = $c000
|
||||||
&ubyte[20] mappedarray = $c100
|
; &ubyte[20] mappedarray = $c100
|
||||||
|
;
|
||||||
uword @shared zz
|
; uword @shared zz
|
||||||
; TODO zz = slab1+slab2+slab3
|
; zz = slab1+slab2+slab3
|
||||||
|
;
|
||||||
uword @shared @zp qq = zz
|
; uword @shared @zp qq = zz
|
||||||
uword @shared @zp qq2 = &zz
|
; uword @shared @zp qq2 = &zz
|
||||||
|
;
|
||||||
str @shared namestring = "irmen"
|
; str @shared namestring = "irmen"
|
||||||
uword[] @shared wordarray1 = [1111,2222,3333,4444]
|
; uword[] @shared wordarray1 = [1111,2222,3333,4444]
|
||||||
uword[4] @shared wordarray2 = 12345
|
; uword[4] @shared wordarray2 = 12345
|
||||||
uword[4] @shared wordzeroarray
|
; uword[4] @shared wordzeroarray
|
||||||
|
;
|
||||||
qq=4242 ; TODO should generate symbol not allocated address
|
; qq=4242 ; TODO should generate symbol not allocated address????
|
||||||
mapped = 99 ; TODO wrong VMASM code generated... should generate mapped memory address
|
; mapped = 99 ; TODO wrong VMASM code generated... should generate mapped memory address?????
|
||||||
mappedarray[1]=99
|
; mappedarray[1]=99 ; TODO check code????
|
||||||
|
;
|
||||||
qq=global1
|
; qq=global1
|
||||||
qq=other.global2
|
; qq=other.global2
|
||||||
nested(11,22)
|
; nested(11,22)
|
||||||
main.start.nested.nested2()
|
; main.start.nested.nested2()
|
||||||
|
;
|
||||||
sub nested(ubyte a1, ubyte a2) {
|
; sub nested(ubyte a1, ubyte a2) {
|
||||||
qq++
|
; qq++
|
||||||
txt.print("zzz")
|
; txt.print("zzz")
|
||||||
nested2()
|
; nested2()
|
||||||
|
;
|
||||||
sub nested2() {
|
; sub nested2() {
|
||||||
txt.print("zzz2")
|
; txt.print("zzz2")
|
||||||
qq++
|
; qq++
|
||||||
}
|
; }
|
||||||
}
|
; }
|
||||||
}
|
; }
|
||||||
}
|
;}
|
||||||
|
;
|
||||||
other {
|
;other {
|
||||||
|
;
|
||||||
uword global2 = 9999
|
; uword global2 = 9999
|
||||||
|
;
|
||||||
}
|
;}
|
||||||
|
@ -446,7 +446,7 @@ class IRFileReader(outputDir: Path, programName: String) {
|
|||||||
fpReg1 = operand.substring(2).toInt()
|
fpReg1 = operand.substring(2).toInt()
|
||||||
else {
|
else {
|
||||||
if(operand.startsWith('_')) {
|
if(operand.startsWith('_')) {
|
||||||
// it's a label.
|
// it's a label
|
||||||
labelSymbol = rest.split(",")[0].trim().substring(1) // keep the original case
|
labelSymbol = rest.split(",")[0].trim().substring(1) // keep the original case
|
||||||
value = null
|
value = null
|
||||||
} else {
|
} else {
|
||||||
@ -462,7 +462,7 @@ class IRFileReader(outputDir: Path, programName: String) {
|
|||||||
fpReg2 = operand.substring(2).toInt()
|
fpReg2 = operand.substring(2).toInt()
|
||||||
else {
|
else {
|
||||||
if(operand.startsWith('_')) {
|
if(operand.startsWith('_')) {
|
||||||
// it's a label.
|
// it's a label
|
||||||
labelSymbol = rest.split(",")[1].trim().substring(1) // keep the original case
|
labelSymbol = rest.split(",")[1].trim().substring(1) // keep the original case
|
||||||
value = null
|
value = null
|
||||||
} else {
|
} else {
|
||||||
@ -478,7 +478,7 @@ class IRFileReader(outputDir: Path, programName: String) {
|
|||||||
fpReg3 = operand.substring(2).toInt()
|
fpReg3 = operand.substring(2).toInt()
|
||||||
else {
|
else {
|
||||||
if(operand.startsWith('_')) {
|
if(operand.startsWith('_')) {
|
||||||
// it's a label.
|
// it's a label
|
||||||
labelSymbol = rest.split(",")[2].trim().substring(1) // keep the original case
|
labelSymbol = rest.split(",")[2].trim().substring(1) // keep the original case
|
||||||
value = null
|
value = null
|
||||||
} else {
|
} else {
|
||||||
@ -489,7 +489,7 @@ class IRFileReader(outputDir: Path, programName: String) {
|
|||||||
if(operands.isNotEmpty()) {
|
if(operands.isNotEmpty()) {
|
||||||
operand = operands.removeFirst().trim()
|
operand = operands.removeFirst().trim()
|
||||||
if(operand.startsWith('_')) {
|
if(operand.startsWith('_')) {
|
||||||
// it's a label.
|
// it's a label
|
||||||
labelSymbol = rest.split(",")[3].trim().substring(1) // keep the original case
|
labelSymbol = rest.split(",")[3].trim().substring(1) // keep the original case
|
||||||
value = null
|
value = null
|
||||||
} else {
|
} else {
|
||||||
@ -573,7 +573,9 @@ class IRFileReader(outputDir: Path, programName: String) {
|
|||||||
else if(value.startsWith("0x"))
|
else if(value.startsWith("0x"))
|
||||||
value.substring(2).toInt(16).toFloat()
|
value.substring(2).toInt(16).toFloat()
|
||||||
else if(value.startsWith('_'))
|
else if(value.startsWith('_'))
|
||||||
throw IRParseException("attempt to parse a label as value")
|
throw IRParseException("attempt to parse a label as numeric value")
|
||||||
|
else if(value.startsWith('&'))
|
||||||
|
throw IRParseException("address-of should be done with normal LOAD <symbol>")
|
||||||
else
|
else
|
||||||
return value.toFloat()
|
return value.toFloat()
|
||||||
}
|
}
|
||||||
|
@ -1,7 +1,5 @@
|
|||||||
package prog8.intermediate
|
package prog8.intermediate
|
||||||
|
|
||||||
import prog8.code.StMemVar
|
|
||||||
import prog8.code.StStaticVariable
|
|
||||||
import prog8.code.core.*
|
import prog8.code.core.*
|
||||||
import java.io.BufferedWriter
|
import java.io.BufferedWriter
|
||||||
import kotlin.io.path.bufferedWriter
|
import kotlin.io.path.bufferedWriter
|
||||||
@ -139,58 +137,10 @@ class IRFileWriter(private val irProgram: IRProgram) {
|
|||||||
out.write("</MEMORYMAPPEDVARIABLES>\n")
|
out.write("</MEMORYMAPPEDVARIABLES>\n")
|
||||||
|
|
||||||
out.write("\n<MEMORYSLABS>\n")
|
out.write("\n<MEMORYSLABS>\n")
|
||||||
irProgram.st.allMemorySlabs.forEach{ slab -> out.write("SLAB _${slab.name} ${slab.size} ${slab.align}\n") }
|
irProgram.st.allMemorySlabs.forEach{ slab -> out.write("SLAB ${slab.name} ${slab.size} ${slab.align}\n") }
|
||||||
out.write("</MEMORYSLABS>\n")
|
out.write("</MEMORYSLABS>\n")
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun getTypeString(dt : DataType): String {
|
|
||||||
return when(dt) {
|
|
||||||
DataType.UBYTE -> "ubyte"
|
|
||||||
DataType.BYTE -> "byte"
|
|
||||||
DataType.UWORD -> "uword"
|
|
||||||
DataType.WORD -> "word"
|
|
||||||
DataType.FLOAT -> "float"
|
|
||||||
DataType.ARRAY_UB, DataType.STR -> "ubyte[]"
|
|
||||||
DataType.ARRAY_B -> "byte[]"
|
|
||||||
DataType.ARRAY_UW -> "uword[]"
|
|
||||||
DataType.ARRAY_W -> "word[]"
|
|
||||||
DataType.ARRAY_F -> "float[]"
|
|
||||||
else -> throw InternalCompilerException("weird dt")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun getTypeString(memvar: StMemVar): String {
|
|
||||||
return when(memvar.dt) {
|
|
||||||
DataType.UBYTE -> "ubyte"
|
|
||||||
DataType.BYTE -> "byte"
|
|
||||||
DataType.UWORD -> "uword"
|
|
||||||
DataType.WORD -> "word"
|
|
||||||
DataType.FLOAT -> "float"
|
|
||||||
DataType.ARRAY_UB, DataType.STR -> "ubyte[${memvar.length}]"
|
|
||||||
DataType.ARRAY_B -> "byte[${memvar.length}]"
|
|
||||||
DataType.ARRAY_UW -> "uword[${memvar.length}]"
|
|
||||||
DataType.ARRAY_W -> "word[${memvar.length}]"
|
|
||||||
DataType.ARRAY_F -> "float[${memvar.length}]"
|
|
||||||
else -> throw InternalCompilerException("weird dt")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun getTypeString(variable : StStaticVariable): String {
|
|
||||||
return when(variable.dt) {
|
|
||||||
DataType.UBYTE -> "ubyte"
|
|
||||||
DataType.BYTE -> "byte"
|
|
||||||
DataType.UWORD -> "uword"
|
|
||||||
DataType.WORD -> "word"
|
|
||||||
DataType.FLOAT -> "float"
|
|
||||||
DataType.ARRAY_UB, DataType.STR -> "ubyte[${variable.length}]"
|
|
||||||
DataType.ARRAY_B -> "byte[${variable.length}]"
|
|
||||||
DataType.ARRAY_UW -> "uword[${variable.length}]"
|
|
||||||
DataType.ARRAY_W -> "word[${variable.length}]"
|
|
||||||
DataType.ARRAY_F -> "float[${variable.length}]"
|
|
||||||
else -> throw InternalCompilerException("weird dt")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun BufferedWriter.writeLine(line: IRCodeLine) {
|
private fun BufferedWriter.writeLine(line: IRCodeLine) {
|
||||||
when(line) {
|
when(line) {
|
||||||
is IRCodeComment -> write("; ${line.comment}\n")
|
is IRCodeComment -> write("; ${line.comment}\n")
|
||||||
|
@ -23,7 +23,7 @@ LOAD/STORE
|
|||||||
----------
|
----------
|
||||||
All have type b or w or f.
|
All have type b or w or f.
|
||||||
|
|
||||||
load reg1, value - load immediate value into register
|
load reg1, value - load immediate value into register. If you supply a symbol, loads the address of the symbol.
|
||||||
loadm reg1, address - load reg1 with value at memory address
|
loadm reg1, address - load reg1 with value at memory address
|
||||||
loadi reg1, reg2 - load reg1 with value at memory indirect, memory pointed to by reg2
|
loadi reg1, reg2 - load reg1 with value at memory indirect, memory pointed to by reg2
|
||||||
loadx reg1, reg2, address - load reg1 with value at memory address indexed by value in reg2
|
loadx reg1, reg2, address - load reg1 with value at memory address indexed by value in reg2
|
||||||
@ -204,7 +204,7 @@ binarydata - 'instruction' to hold inlined binary
|
|||||||
|
|
||||||
enum class Opcode {
|
enum class Opcode {
|
||||||
NOP,
|
NOP,
|
||||||
LOAD,
|
LOAD, // note: LOAD <symbol> gets you the address of the symbol, whereas LOADM <symbol> would get you the value stored at that location
|
||||||
LOADM,
|
LOADM,
|
||||||
LOADI,
|
LOADI,
|
||||||
LOADX,
|
LOADX,
|
||||||
|
55
intermediate/src/prog8/intermediate/Utils.kt
Normal file
55
intermediate/src/prog8/intermediate/Utils.kt
Normal file
@ -0,0 +1,55 @@
|
|||||||
|
package prog8.intermediate
|
||||||
|
|
||||||
|
import prog8.code.StMemVar
|
||||||
|
import prog8.code.StStaticVariable
|
||||||
|
import prog8.code.core.DataType
|
||||||
|
import prog8.code.core.InternalCompilerException
|
||||||
|
|
||||||
|
|
||||||
|
public fun getTypeString(dt : DataType): String {
|
||||||
|
return when(dt) {
|
||||||
|
DataType.UBYTE -> "ubyte"
|
||||||
|
DataType.BYTE -> "byte"
|
||||||
|
DataType.UWORD -> "uword"
|
||||||
|
DataType.WORD -> "word"
|
||||||
|
DataType.FLOAT -> "float"
|
||||||
|
DataType.ARRAY_UB, DataType.STR -> "ubyte[]"
|
||||||
|
DataType.ARRAY_B -> "byte[]"
|
||||||
|
DataType.ARRAY_UW -> "uword[]"
|
||||||
|
DataType.ARRAY_W -> "word[]"
|
||||||
|
DataType.ARRAY_F -> "float[]"
|
||||||
|
else -> throw InternalCompilerException("weird dt")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public fun getTypeString(memvar: StMemVar): String {
|
||||||
|
return when(memvar.dt) {
|
||||||
|
DataType.UBYTE -> "ubyte"
|
||||||
|
DataType.BYTE -> "byte"
|
||||||
|
DataType.UWORD -> "uword"
|
||||||
|
DataType.WORD -> "word"
|
||||||
|
DataType.FLOAT -> "float"
|
||||||
|
DataType.ARRAY_UB, DataType.STR -> "ubyte[${memvar.length}]"
|
||||||
|
DataType.ARRAY_B -> "byte[${memvar.length}]"
|
||||||
|
DataType.ARRAY_UW -> "uword[${memvar.length}]"
|
||||||
|
DataType.ARRAY_W -> "word[${memvar.length}]"
|
||||||
|
DataType.ARRAY_F -> "float[${memvar.length}]"
|
||||||
|
else -> throw InternalCompilerException("weird dt")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public fun getTypeString(variable : StStaticVariable): String {
|
||||||
|
return when(variable.dt) {
|
||||||
|
DataType.UBYTE -> "ubyte"
|
||||||
|
DataType.BYTE -> "byte"
|
||||||
|
DataType.UWORD -> "uword"
|
||||||
|
DataType.WORD -> "word"
|
||||||
|
DataType.FLOAT -> "float"
|
||||||
|
DataType.ARRAY_UB, DataType.STR -> "ubyte[${variable.length}]"
|
||||||
|
DataType.ARRAY_B -> "byte[${variable.length}]"
|
||||||
|
DataType.ARRAY_UW -> "uword[${variable.length}]"
|
||||||
|
DataType.ARRAY_W -> "word[${variable.length}]"
|
||||||
|
DataType.ARRAY_F -> "float[${variable.length}]"
|
||||||
|
else -> throw InternalCompilerException("weird dt")
|
||||||
|
}
|
||||||
|
}
|
@ -5,7 +5,7 @@ import prog8.intermediate.*
|
|||||||
|
|
||||||
|
|
||||||
class Assembler {
|
class Assembler {
|
||||||
private val labels = mutableMapOf<String, Int>()
|
private val symbolAddresses = mutableMapOf<String, Int>()
|
||||||
private val placeholders = mutableMapOf<Int, String>()
|
private val placeholders = mutableMapOf<Int, String>()
|
||||||
|
|
||||||
init {
|
init {
|
||||||
@ -15,8 +15,8 @@ class Assembler {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fun initializeMemory(memsrc: String, memory: Memory) {
|
fun initializeMemory(memsrc: String, memory: Memory) {
|
||||||
labels.clear()
|
symbolAddresses.clear()
|
||||||
val instrPattern = Regex("""var (.+) @([0-9]+) ([a-z]+) (.+)""", RegexOption.IGNORE_CASE)
|
val instrPattern = Regex("""var (.+) @([0-9]+) ([a-z]+)(\[[0-9]+\])? (.+)""", RegexOption.IGNORE_CASE)
|
||||||
for(line in memsrc.lines()) {
|
for(line in memsrc.lines()) {
|
||||||
if(line.isBlank() || line.startsWith(';'))
|
if(line.isBlank() || line.startsWith(';'))
|
||||||
continue
|
continue
|
||||||
@ -24,9 +24,10 @@ class Assembler {
|
|||||||
if(match==null)
|
if(match==null)
|
||||||
throw IllegalArgumentException("invalid line $line")
|
throw IllegalArgumentException("invalid line $line")
|
||||||
else {
|
else {
|
||||||
val (name, addrStr, datatype, values) = match.destructured
|
val (name, addrStr, datatype, arrayspec, values) = match.destructured
|
||||||
|
val numArrayElts = if(arrayspec.isBlank()) 1 else arrayspec.substring(1, arrayspec.length-1).toInt()
|
||||||
var address = parseValue(Opcode.LOADCPU, addrStr, 0).toInt()
|
var address = parseValue(Opcode.LOADCPU, addrStr, 0).toInt()
|
||||||
labels[name] = address
|
symbolAddresses[name] = address
|
||||||
when(datatype) {
|
when(datatype) {
|
||||||
"str" -> {
|
"str" -> {
|
||||||
val string = values.trim('"').unescape()
|
val string = values.trim('"').unescape()
|
||||||
@ -38,25 +39,52 @@ class Assembler {
|
|||||||
}
|
}
|
||||||
"ubyte", "byte" -> {
|
"ubyte", "byte" -> {
|
||||||
val array = values.split(',').map { parseValue(Opcode.LOADCPU, it.trim(), 0).toInt() }
|
val array = values.split(',').map { parseValue(Opcode.LOADCPU, it.trim(), 0).toInt() }
|
||||||
|
require(array.size==numArrayElts || array.size==1)
|
||||||
|
if(numArrayElts > array.size) {
|
||||||
|
val value = array.single().toUByte()
|
||||||
|
repeat(numArrayElts) {
|
||||||
|
memory.setUB(address, value)
|
||||||
|
address++
|
||||||
|
}
|
||||||
|
} else {
|
||||||
for (value in array) {
|
for (value in array) {
|
||||||
memory.setUB(address, value.toUByte())
|
memory.setUB(address, value.toUByte())
|
||||||
address++
|
address++
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
"uword", "word" -> {
|
"uword", "word" -> {
|
||||||
val array = values.split(',').map { parseValue(Opcode.LOADCPU, it.trim(), 0).toInt() }
|
val array = values.split(',').map { parseValue(Opcode.LOADCPU, it.trim(), 0).toInt() }
|
||||||
|
require(array.size==numArrayElts || array.size==1)
|
||||||
|
if(numArrayElts>array.size) {
|
||||||
|
val value = array.single().toUShort()
|
||||||
|
repeat(numArrayElts) {
|
||||||
|
memory.setUW(address, value)
|
||||||
|
address += 2
|
||||||
|
}
|
||||||
|
} else {
|
||||||
for (value in array) {
|
for (value in array) {
|
||||||
memory.setUW(address, value.toUShort())
|
memory.setUW(address, value.toUShort())
|
||||||
address += 2
|
address += 2
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
"float" -> {
|
"float" -> {
|
||||||
val array = values.split(',').map { it.toFloat() }
|
val array = values.split(',').map { it.toFloat() }
|
||||||
|
require(array.size==numArrayElts || array.size==1)
|
||||||
|
if(numArrayElts>array.size) {
|
||||||
|
val value = array.single()
|
||||||
|
repeat(numArrayElts) {
|
||||||
|
memory.setFloat(address, value)
|
||||||
|
address += 4 // 32-bits floats
|
||||||
|
}
|
||||||
|
} else {
|
||||||
for (value in array) {
|
for (value in array) {
|
||||||
memory.setFloat(address, value)
|
memory.setFloat(address, value)
|
||||||
address += 4 // 32-bits floats
|
address += 4 // 32-bits floats
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
else -> throw IllegalArgumentException("invalid datatype $datatype")
|
else -> throw IllegalArgumentException("invalid datatype $datatype")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -87,9 +115,9 @@ class Assembler {
|
|||||||
throw IllegalArgumentException("invalid line $line at line ${program.size + 1}")
|
throw IllegalArgumentException("invalid line $line at line ${program.size + 1}")
|
||||||
else {
|
else {
|
||||||
val label = labelmatch.groupValues[1]
|
val label = labelmatch.groupValues[1]
|
||||||
if (label in labels)
|
if (label in symbolAddresses)
|
||||||
throw IllegalArgumentException("label redefined $label")
|
throw IllegalArgumentException("label redefined $label")
|
||||||
labels[label] = program.size
|
symbolAddresses[label] = program.size
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
@ -245,13 +273,13 @@ class Assembler {
|
|||||||
|
|
||||||
private fun pass2replaceLabels(program: MutableList<Instruction>) {
|
private fun pass2replaceLabels(program: MutableList<Instruction>) {
|
||||||
for((line, label) in placeholders) {
|
for((line, label) in placeholders) {
|
||||||
val replacement = labels[label]
|
val replacement = symbolAddresses[label]
|
||||||
if(replacement==null) {
|
if(replacement==null) {
|
||||||
// it could be an address + index: symbol+42
|
// it could be an address + index: symbol+42
|
||||||
if('+' in label) {
|
if('+' in label) {
|
||||||
val (symbol, indexStr) = label.split('+')
|
val (symbol, indexStr) = label.split('+')
|
||||||
val index = indexStr.toInt()
|
val index = indexStr.toInt()
|
||||||
val address = labels.getValue(symbol) + index
|
val address = symbolAddresses.getValue(symbol) + index
|
||||||
program[line] = program[line].copy(value = address)
|
program[line] = program[line].copy(value = address)
|
||||||
} else {
|
} else {
|
||||||
throw IllegalArgumentException("placeholder not found in labels: $label")
|
throw IllegalArgumentException("placeholder not found in labels: $label")
|
||||||
|
Loading…
Reference in New Issue
Block a user