mirror of
https://github.com/irmen/prog8.git
synced 2024-09-09 02:54:28 +00:00
IR support for instructions operating on cpu regs
This commit is contained in:
parent
2f3e7d1c27
commit
3091e3a1c8
@ -153,8 +153,11 @@ class CodeGen(internal val program: PtProgram,
|
|||||||
parent.children.remove(sub)
|
parent.children.remove(sub)
|
||||||
if (sub === entrypoint) {
|
if (sub === entrypoint) {
|
||||||
// entrypoint sub must be first sub
|
// entrypoint sub must be first sub
|
||||||
val firstsub = parent.children.withIndex().first { it.value is PtSub || it.value is PtAsmSub }
|
val firstsub = parent.children.withIndex().firstOrNull() { it.value is PtSub || it.value is PtAsmSub }
|
||||||
|
if(firstsub!=null)
|
||||||
parent.add(firstsub.index, renamedSub)
|
parent.add(firstsub.index, renamedSub)
|
||||||
|
else
|
||||||
|
parent.add(renamedSub)
|
||||||
} else {
|
} else {
|
||||||
parent.add(renamedSub)
|
parent.add(renamedSub)
|
||||||
}
|
}
|
||||||
|
@ -23,8 +23,7 @@ class VmAssemblyProgram(override val name: String, val irProgram: IRProgram): IA
|
|||||||
|
|
||||||
outfile.bufferedWriter().use { out ->
|
outfile.bufferedWriter().use { out ->
|
||||||
allocations.asVmMemory().forEach { (name, alloc) ->
|
allocations.asVmMemory().forEach { (name, alloc) ->
|
||||||
out.write("; ${name.joinToString(".")}\n")
|
out.write("var ${name.joinToString(".")} $alloc\n")
|
||||||
out.write(alloc + "\n")
|
|
||||||
}
|
}
|
||||||
|
|
||||||
out.write("------PROGRAM------\n")
|
out.write("------PROGRAM------\n")
|
||||||
|
@ -67,7 +67,7 @@ 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 $typeStr $value"))
|
||||||
}
|
}
|
||||||
return mm
|
return mm
|
||||||
}
|
}
|
||||||
|
@ -24,8 +24,7 @@ class AssemblyProgram(override val name: String, private val allocations: Variab
|
|||||||
println("write code to $outfile")
|
println("write code to $outfile")
|
||||||
outfile.bufferedWriter().use { out ->
|
outfile.bufferedWriter().use { out ->
|
||||||
allocations.asVmMemory().forEach { (name, alloc) ->
|
allocations.asVmMemory().forEach { (name, alloc) ->
|
||||||
out.write("; ${name.joinToString(".")}\n")
|
out.write("var ${name.joinToString(".")} $alloc\n")
|
||||||
out.write(alloc + "\n")
|
|
||||||
}
|
}
|
||||||
out.write("------PROGRAM------\n")
|
out.write("------PROGRAM------\n")
|
||||||
|
|
||||||
|
@ -81,7 +81,7 @@ class VariableAllocator(private val st: SymbolTable, private val program: PtProg
|
|||||||
}
|
}
|
||||||
else -> throw InternalCompilerException("weird dt")
|
else -> throw InternalCompilerException("weird dt")
|
||||||
}
|
}
|
||||||
mm.add(Pair(variable.scopedName, "$location $typeStr $value"))
|
mm.add(Pair(variable.scopedName, "@$location $typeStr $value"))
|
||||||
}
|
}
|
||||||
for (variable in st.allMemMappedVariables) {
|
for (variable in st.allMemMappedVariables) {
|
||||||
val location = allocations.getValue(variable.scopedName)
|
val location = allocations.getValue(variable.scopedName)
|
||||||
@ -100,7 +100,7 @@ class VariableAllocator(private val st: SymbolTable, private val program: PtProg
|
|||||||
in ArrayDatatypes -> (1..variable.length!!).joinToString(",") { "0" }
|
in ArrayDatatypes -> (1..variable.length!!).joinToString(",") { "0" }
|
||||||
else -> throw InternalCompilerException("weird dt for mem mapped var")
|
else -> throw InternalCompilerException("weird dt for mem mapped var")
|
||||||
}
|
}
|
||||||
mm.add(Pair(variable.scopedName, "$location $typeStr $value"))
|
mm.add(Pair(variable.scopedName, "@$location $typeStr $value"))
|
||||||
}
|
}
|
||||||
return mm
|
return mm
|
||||||
}
|
}
|
||||||
|
@ -399,8 +399,8 @@ private fun createAssemblyAndAssemble(program: Program,
|
|||||||
// to help clean up the code that still depends on them.
|
// to help clean up the code that still depends on them.
|
||||||
// removeAllVardeclsFromAst(program)
|
// removeAllVardeclsFromAst(program)
|
||||||
|
|
||||||
println("*********** AST RIGHT BEFORE ASM GENERATION *************")
|
// println("*********** AST RIGHT BEFORE ASM GENERATION *************")
|
||||||
printProgram(program)
|
// printProgram(program)
|
||||||
|
|
||||||
val assembly = asmGeneratorFor(program, errors, symbolTable, compilerOptions).compileToAssembly()
|
val assembly = asmGeneratorFor(program, errors, symbolTable, compilerOptions).compileToAssembly()
|
||||||
errors.report()
|
errors.report()
|
||||||
|
@ -3,10 +3,11 @@ TODO
|
|||||||
|
|
||||||
For next release
|
For next release
|
||||||
^^^^^^^^^^^^^^^^
|
^^^^^^^^^^^^^^^^
|
||||||
- VM Assembler: add support for translating symbols to address search for "TODO do we have to replace variable names by their allocated address" load.w r0,{_}txt.clear_screen.sequence
|
- IR/VM: add address calculation for simple addition: conv.string_out+42
|
||||||
- IR/VM: add proper memory mapped variables support - replace the symbol by the memory address in the IR code.
|
- 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: check that the above works ok now with the cx16 virtual registers.
|
||||||
- IR/VM: add proper memory slabs support
|
- IR/VM: add proper memory slabs support
|
||||||
|
- IR/VM: improve unit tests
|
||||||
|
|
||||||
...
|
...
|
||||||
|
|
||||||
|
@ -383,6 +383,12 @@ val OpcodesWithAddress = setOf(
|
|||||||
Opcode.ROXRM
|
Opcode.ROXRM
|
||||||
)
|
)
|
||||||
|
|
||||||
|
val OpcodesForCpuRegisters = setOf(
|
||||||
|
Opcode.LOADCPU,
|
||||||
|
Opcode.STORECPU,
|
||||||
|
Opcode.STOREZCPU
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
enum class VmDataType {
|
enum class VmDataType {
|
||||||
BYTE,
|
BYTE,
|
||||||
|
@ -15,7 +15,8 @@ class Assembler {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fun initializeMemory(memsrc: String, memory: Memory) {
|
fun initializeMemory(memsrc: String, memory: Memory) {
|
||||||
val instrPattern = Regex("""(.+?)\s+([a-z]+)\s+(.+)""", RegexOption.IGNORE_CASE)
|
labels.clear()
|
||||||
|
val instrPattern = Regex("""var (.+) @([0-9]+) ([a-z]+) (.+)""", 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
|
||||||
@ -23,9 +24,10 @@ class Assembler {
|
|||||||
if(match==null)
|
if(match==null)
|
||||||
throw IllegalArgumentException("invalid line $line")
|
throw IllegalArgumentException("invalid line $line")
|
||||||
else {
|
else {
|
||||||
val (_, addr, what, values) = match.groupValues
|
val (name, addrStr, datatype, values) = match.destructured
|
||||||
var address = parseValue(addr, 0).toInt()
|
var address = parseValue(Opcode.LOADCPU, addrStr, 0).toInt()
|
||||||
when(what) {
|
labels[name] = address
|
||||||
|
when(datatype) {
|
||||||
"str" -> {
|
"str" -> {
|
||||||
val string = values.trim('"').unescape()
|
val string = values.trim('"').unescape()
|
||||||
memory.setString(address, string, false)
|
memory.setString(address, string, false)
|
||||||
@ -35,14 +37,14 @@ class Assembler {
|
|||||||
memory.setString(address, string, true)
|
memory.setString(address, string, true)
|
||||||
}
|
}
|
||||||
"ubyte", "byte" -> {
|
"ubyte", "byte" -> {
|
||||||
val array = values.split(',').map { parseValue(it.trim(), 0).toInt() }
|
val array = values.split(',').map { parseValue(Opcode.LOADCPU, it.trim(), 0).toInt() }
|
||||||
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(it.trim(), 0).toInt() }
|
val array = values.split(',').map { parseValue(Opcode.LOADCPU, it.trim(), 0).toInt() }
|
||||||
for (value in array) {
|
for (value in array) {
|
||||||
memory.setUW(address, value.toUShort())
|
memory.setUW(address, value.toUShort())
|
||||||
address += 2
|
address += 2
|
||||||
@ -55,14 +57,13 @@ class Assembler {
|
|||||||
address += 4 // 32-bits floats
|
address += 4 // 32-bits floats
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else -> throw IllegalArgumentException("mem instr $what")
|
else -> throw IllegalArgumentException("invalid datatype $datatype")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun assembleProgram(source: CharSequence): List<Instruction> {
|
fun assembleProgram(source: CharSequence): List<Instruction> {
|
||||||
labels.clear()
|
|
||||||
placeholders.clear()
|
placeholders.clear()
|
||||||
val program = mutableListOf<Instruction>()
|
val program = mutableListOf<Instruction>()
|
||||||
val instructionPattern = Regex("""([a-z]+)(\.b|\.w|\.f)?(.*)""", RegexOption.IGNORE_CASE)
|
val instructionPattern = Regex("""([a-z]+)(\.b|\.w|\.f)?(.*)""", RegexOption.IGNORE_CASE)
|
||||||
@ -134,9 +135,9 @@ class Assembler {
|
|||||||
value = if(operand.startsWith('_')) {
|
value = if(operand.startsWith('_')) {
|
||||||
// it's a label, keep the original case!
|
// it's a label, keep the original case!
|
||||||
val labelname = rest.split(",").first().trim()
|
val labelname = rest.split(",").first().trim()
|
||||||
parseValue(labelname, program.size)
|
parseValue(opcode, labelname, program.size)
|
||||||
} else {
|
} else {
|
||||||
parseValue(operand, program.size)
|
parseValue(opcode, operand, program.size)
|
||||||
}
|
}
|
||||||
operands.clear()
|
operands.clear()
|
||||||
}
|
}
|
||||||
@ -147,7 +148,7 @@ class Assembler {
|
|||||||
else if(operand[0]=='f' && operand[1]=='r')
|
else if(operand[0]=='f' && operand[1]=='r')
|
||||||
fpReg2 = operand.substring(2).toInt()
|
fpReg2 = operand.substring(2).toInt()
|
||||||
else {
|
else {
|
||||||
value = parseValue(operand, program.size)
|
value = parseValue(opcode, operand, program.size)
|
||||||
operands.clear()
|
operands.clear()
|
||||||
}
|
}
|
||||||
if(operands.isNotEmpty()) {
|
if(operands.isNotEmpty()) {
|
||||||
@ -157,12 +158,13 @@ class Assembler {
|
|||||||
else if(operand[0]=='f' && operand[1]=='r')
|
else if(operand[0]=='f' && operand[1]=='r')
|
||||||
fpReg3 = operand.substring(2).toInt()
|
fpReg3 = operand.substring(2).toInt()
|
||||||
else {
|
else {
|
||||||
value = parseValue(operand, program.size)
|
val symbol=rest.split(',').last()
|
||||||
|
value = parseValue(opcode, symbol, program.size)
|
||||||
operands.clear()
|
operands.clear()
|
||||||
}
|
}
|
||||||
if(operands.isNotEmpty()) {
|
if(operands.isNotEmpty()) {
|
||||||
operand = operands.removeFirst().trim()
|
val symbol=rest.split(',').last()
|
||||||
value = parseValue(operand, program.size)
|
value = parseValue(opcode, symbol, program.size)
|
||||||
operands.clear()
|
operands.clear()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -219,9 +221,23 @@ class Assembler {
|
|||||||
if(format.fpValue)
|
if(format.fpValue)
|
||||||
floatValue = value!!
|
floatValue = value!!
|
||||||
|
|
||||||
|
if(opcode in OpcodesForCpuRegisters) {
|
||||||
|
val reg=rest.split(',').last().lowercase()
|
||||||
|
if(reg !in setOf(
|
||||||
|
"_a", "_x", "_y",
|
||||||
|
"_ax", "_ay", "_xy",
|
||||||
|
"_r0", "_r1", "_r2", "_r3",
|
||||||
|
"_r4", "_r5", "_r6", "_r7",
|
||||||
|
"_r8", "_r9", "_r10","_r11",
|
||||||
|
"_r12", "_r13", "_r14", "_r15",
|
||||||
|
"_pc", "_pz", "_pv","_pn"))
|
||||||
|
throw IllegalArgumentException("invalid cpu reg: $reg")
|
||||||
|
program.add(Instruction(opcode, type, reg1, labelSymbol = listOf(reg.substring(1))))
|
||||||
|
} else {
|
||||||
program.add(Instruction(opcode, type, reg1, reg2, fpReg1, fpReg2, intValue, floatValue))
|
program.add(Instruction(opcode, type, reg1, reg2, fpReg1, fpReg2, intValue, floatValue))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pass2replaceLabels(program)
|
pass2replaceLabels(program)
|
||||||
return program
|
return program
|
||||||
@ -229,14 +245,18 @@ 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.getValue(label)
|
val replacement = labels[label]
|
||||||
|
if(replacement==null) {
|
||||||
|
println("TODO: find address of symbol $label") // TODO
|
||||||
|
} else {
|
||||||
program[line] = program[line].copy(value = replacement)
|
program[line] = program[line].copy(value = replacement)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private fun parseValue(value: String, pc: Int): Float {
|
private fun parseValue(opcode: Opcode, value: String, pc: Int): Float {
|
||||||
if(value.startsWith("-")) {
|
if(value.startsWith("-")) {
|
||||||
return -parseValue(value.substring(1), pc)
|
return -parseValue(opcode, value.substring(1), pc)
|
||||||
}
|
}
|
||||||
if(value.startsWith('$'))
|
if(value.startsWith('$'))
|
||||||
return value.substring(1).toInt(16).toFloat()
|
return value.substring(1).toInt(16).toFloat()
|
||||||
@ -245,9 +265,15 @@ class Assembler {
|
|||||||
if(value.startsWith("0x"))
|
if(value.startsWith("0x"))
|
||||||
return value.substring(2).toInt(16).toFloat()
|
return value.substring(2).toInt(16).toFloat()
|
||||||
if(value.startsWith('_')) {
|
if(value.startsWith('_')) {
|
||||||
|
if(opcode !in OpcodesForCpuRegisters)
|
||||||
placeholders[pc] = value.substring(1)
|
placeholders[pc] = value.substring(1)
|
||||||
return 0f
|
return 0f
|
||||||
}
|
}
|
||||||
|
if(value[0].isLetter()) {
|
||||||
|
if(opcode !in OpcodesForCpuRegisters)
|
||||||
|
placeholders[pc] = value
|
||||||
|
return 0f
|
||||||
|
}
|
||||||
return value.toFloat()
|
return value.toFloat()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -218,6 +218,9 @@ class VirtualMachine(val memory: Memory, program: List<Instruction>) {
|
|||||||
Opcode.CLC -> { statusCarry = false; pc++ }
|
Opcode.CLC -> { statusCarry = false; pc++ }
|
||||||
Opcode.SEC -> { statusCarry = true; pc++ }
|
Opcode.SEC -> { statusCarry = true; pc++ }
|
||||||
Opcode.BINARYDATA -> TODO("BINARYDATA not yet supported in VM")
|
Opcode.BINARYDATA -> TODO("BINARYDATA not yet supported in VM")
|
||||||
|
Opcode.LOADCPU -> InsLOADCPU(ins)
|
||||||
|
Opcode.STORECPU -> InsSTORECPU(ins)
|
||||||
|
Opcode.STOREZCPU -> InsSTOREZCPU(ins)
|
||||||
|
|
||||||
Opcode.FFROMUB -> InsFFROMUB(ins)
|
Opcode.FFROMUB -> InsFFROMUB(ins)
|
||||||
Opcode.FFROMSB -> InsFFROMSB(ins)
|
Opcode.FFROMSB -> InsFFROMSB(ins)
|
||||||
@ -301,6 +304,30 @@ class VirtualMachine(val memory: Memory, program: List<Instruction>) {
|
|||||||
throw BreakpointException(pc)
|
throw BreakpointException(pc)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun InsLOADCPU(i: Instruction) {
|
||||||
|
println("VM:TODO: load reg ${i.reg1} from cpu register ${i.labelSymbol}") // TODO
|
||||||
|
pc++
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun InsSTORECPU(i: Instruction) {
|
||||||
|
val value: UShort = when(i.type!!) {
|
||||||
|
VmDataType.BYTE -> registers.getUB(i.reg1!!).toUShort()
|
||||||
|
VmDataType.WORD -> registers.getUW(i.reg1!!)
|
||||||
|
VmDataType.FLOAT -> throw IllegalArgumentException("there are no float cpu registers")
|
||||||
|
}
|
||||||
|
StoreCPU(value, i.type!!, i.labelSymbol!!.single())
|
||||||
|
pc++
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun InsSTOREZCPU(i: Instruction) {
|
||||||
|
StoreCPU(0u, i.type!!, i.labelSymbol!!.single())
|
||||||
|
pc++
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun StoreCPU(value: UShort, dt: VmDataType, regStr: String) {
|
||||||
|
println("VM:TODO: store a value into cpu register $regStr") // TODO
|
||||||
|
}
|
||||||
|
|
||||||
private fun InsLOAD(i: Instruction) {
|
private fun InsLOAD(i: Instruction) {
|
||||||
if(i.type==VmDataType.FLOAT)
|
if(i.type==VmDataType.FLOAT)
|
||||||
registers.setFloat(i.fpReg1!!, i.fpValue!!)
|
registers.setFloat(i.fpReg1!!, i.fpValue!!)
|
||||||
|
Loading…
Reference in New Issue
Block a user