mirror of
https://github.com/irmen/prog8.git
synced 2024-12-27 05:29:38 +00:00
VM: support cpu registers
This commit is contained in:
parent
627ed51a1b
commit
11d87e4725
@ -3,7 +3,7 @@ TODO
|
||||
|
||||
For next release
|
||||
^^^^^^^^^^^^^^^^
|
||||
- IR/VM: actually support the physical cpu registers and status flags in the STORECPU and LOADCPU opcodes.
|
||||
- Join codeAst and codeCore modules?
|
||||
- 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
|
||||
|
@ -3,19 +3,31 @@ main {
|
||||
|
||||
sub start() {
|
||||
|
||||
uword @shared slab1 = memory("slab 1", 2000, 0)
|
||||
uword @shared slab2 = memory("slab 1", 2000, 0)
|
||||
uword @shared slab3 = memory("other # slab", 2000, 64)
|
||||
%asm {{
|
||||
loadcpu.b r1,_a
|
||||
loadcpu.b r1,_x
|
||||
loadcpu.b r1,_y
|
||||
loadcpu.w r1,_ax
|
||||
loadcpu.w r1,_ay
|
||||
loadcpu.w r1,_xy
|
||||
loadcpu.b r1,_pc
|
||||
loadcpu.b r1,_pn
|
||||
loadcpu.b r1,_pz
|
||||
loadcpu.w r1,_r0
|
||||
loadcpu.w r1,_r15
|
||||
|
||||
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()
|
||||
storezcpu.b _a
|
||||
storezcpu.b _x
|
||||
storezcpu.b _y
|
||||
storezcpu.w _ax
|
||||
storezcpu.w _ay
|
||||
storezcpu.w _xy
|
||||
storezcpu.b _pc
|
||||
storezcpu.b _pn
|
||||
storezcpu.b _pz
|
||||
storezcpu.b _r0
|
||||
storezcpu.w _r15
|
||||
}}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -7,6 +7,7 @@ import prog8.intermediate.*
|
||||
class Assembler {
|
||||
private val symbolAddresses = mutableMapOf<String, Int>()
|
||||
private val placeholders = mutableMapOf<Int, String>()
|
||||
var cx16virtualregBaseAdress = 0xff02
|
||||
|
||||
init {
|
||||
require(instructionFormats.size== Opcode.values().size) {
|
||||
@ -25,6 +26,9 @@ class Assembler {
|
||||
throw IllegalArgumentException("invalid line $line")
|
||||
else {
|
||||
val (name, addrStr, datatype, arrayspec, values) = match.destructured
|
||||
if(name=="cx16.r0") {
|
||||
cx16virtualregBaseAdress = addrStr.toInt()
|
||||
}
|
||||
val numArrayElts = if(arrayspec.isBlank()) 1 else arrayspec.substring(1, arrayspec.length-1).toInt()
|
||||
var address = parseValue(Opcode.LOADCPU, addrStr, 0).toInt()
|
||||
symbolAddresses[name] = address
|
||||
@ -250,17 +254,18 @@ class Assembler {
|
||||
floatValue = value!!
|
||||
|
||||
if(opcode in OpcodesForCpuRegisters) {
|
||||
val reg=rest.split(',').last().lowercase()
|
||||
val regStr = rest.split(',').last().lowercase().trim()
|
||||
val reg = if(regStr.startsWith('_')) regStr.substring(1) else regStr
|
||||
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"))
|
||||
"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))))
|
||||
program.add(Instruction(opcode, type, reg1, labelSymbol = listOf(reg)))
|
||||
} else {
|
||||
program.add(Instruction(opcode, type, reg1, reg2, fpReg1, fpReg2, intValue, floatValue))
|
||||
}
|
||||
|
@ -38,6 +38,6 @@ return"""
|
||||
assembler.initializeMemory(memsrc, memory)
|
||||
val program = assembler.assembleProgram(src)
|
||||
|
||||
val vm = VirtualMachine(memory, program)
|
||||
val vm = VirtualMachine(memory, program, assembler.cx16virtualregBaseAdress)
|
||||
vm.run()
|
||||
}
|
||||
|
@ -3,14 +3,21 @@ package prog8.vm
|
||||
/**
|
||||
* 65536 virtual integer registers of 16 bits wide.
|
||||
* 65536 virtual float registers of 32 bits wide.
|
||||
* A,X and Y "physical" 6502 registers.
|
||||
*/
|
||||
class Registers {
|
||||
private val registers = Array<UShort>(65536) { 0u }
|
||||
private val floatRegisters = Array(65535) { 0f }
|
||||
var cpuA: UByte = 0u
|
||||
var cpuX: UByte = 0u
|
||||
var cpuY: UByte = 0u
|
||||
|
||||
fun reset() {
|
||||
registers.fill(0u)
|
||||
floatRegisters.fill(0f)
|
||||
cpuA = 0u
|
||||
cpuX = 0u
|
||||
cpuY = 0u
|
||||
}
|
||||
|
||||
fun setUB(reg: Int, value: UByte) {
|
||||
|
@ -31,7 +31,7 @@ class BreakpointException(val pc: Int): Exception()
|
||||
|
||||
|
||||
@Suppress("FunctionName")
|
||||
class VirtualMachine(val memory: Memory, program: List<Instruction>) {
|
||||
class VirtualMachine(val memory: Memory, program: List<Instruction>, val cx16virtualregsBaseAddress: Int) {
|
||||
val registers = Registers()
|
||||
val program: Array<Instruction> = program.toTypedArray()
|
||||
val callStack = Stack<Int>()
|
||||
@ -305,14 +305,39 @@ class VirtualMachine(val memory: Memory, program: List<Instruction>) {
|
||||
}
|
||||
|
||||
private fun InsLOADCPU(i: Instruction) {
|
||||
println("VM:TODO: load reg ${i.reg1} from cpu register ${i.labelSymbol}") // TODO
|
||||
val reg = i.labelSymbol!!.single()
|
||||
val value: UInt
|
||||
if(reg.startsWith('r')) {
|
||||
val regnum = reg.substring(1).toInt()
|
||||
val regAddr = cx16virtualregsBaseAddress + regnum*2
|
||||
value = memory.getUW(regAddr).toUInt()
|
||||
} else {
|
||||
value = when(reg) {
|
||||
"a" -> registers.cpuA.toUInt()
|
||||
"x" -> registers.cpuX.toUInt()
|
||||
"y" -> registers.cpuY.toUInt()
|
||||
"ax" -> (registers.cpuA.toUInt() shl 8) or registers.cpuX.toUInt()
|
||||
"ay" -> (registers.cpuA.toUInt() shl 8) or registers.cpuY.toUInt()
|
||||
"xy" -> (registers.cpuX.toUInt() shl 8) or registers.cpuY.toUInt()
|
||||
"pc" -> if(statusCarry) 1u else 0u
|
||||
"pz" -> if(statusZero) 1u else 0u
|
||||
"pn" -> if(statusNegative) 1u else 0u
|
||||
"pv" -> throw IllegalArgumentException("overflow status register not supported in VM")
|
||||
else -> throw IllegalArgumentException("invalid cpu reg")
|
||||
}
|
||||
}
|
||||
when(i.type!!) {
|
||||
VmDataType.BYTE -> registers.setUB(i.reg1!!, value.toUByte())
|
||||
VmDataType.WORD -> registers.setUW(i.reg1!!, value.toUShort())
|
||||
else -> throw java.lang.IllegalArgumentException("invalid cpu reg type")
|
||||
}
|
||||
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!!)
|
||||
val value: UInt = when(i.type!!) {
|
||||
VmDataType.BYTE -> registers.getUB(i.reg1!!).toUInt()
|
||||
VmDataType.WORD -> registers.getUW(i.reg1!!).toUInt()
|
||||
VmDataType.FLOAT -> throw IllegalArgumentException("there are no float cpu registers")
|
||||
}
|
||||
StoreCPU(value, i.type!!, i.labelSymbol!!.single())
|
||||
@ -324,8 +349,39 @@ class VirtualMachine(val memory: Memory, program: List<Instruction>) {
|
||||
pc++
|
||||
}
|
||||
|
||||
private fun StoreCPU(value: UShort, dt: VmDataType, regStr: String) {
|
||||
println("VM:TODO: store a value into cpu register $regStr") // TODO
|
||||
private fun StoreCPU(value: UInt, dt: VmDataType, regStr: String) {
|
||||
if(regStr.startsWith('r')) {
|
||||
val regnum = regStr.substring(1).toInt()
|
||||
val regAddr = cx16virtualregsBaseAddress + regnum*2
|
||||
when(dt) {
|
||||
VmDataType.BYTE -> memory.setUB(regAddr, value.toUByte())
|
||||
VmDataType.WORD -> memory.setUW(regAddr, value.toUShort())
|
||||
else -> throw IllegalArgumentException("invalid reg dt")
|
||||
}
|
||||
} else {
|
||||
when (regStr) {
|
||||
"a" -> registers.cpuA = value.toUByte()
|
||||
"x" -> registers.cpuX = value.toUByte()
|
||||
"y" -> registers.cpuY = value.toUByte()
|
||||
"ax" -> {
|
||||
registers.cpuA = (value and 255u).toUByte()
|
||||
registers.cpuX = (value shr 8).toUByte()
|
||||
}
|
||||
"ay" -> {
|
||||
registers.cpuA = (value and 255u).toUByte()
|
||||
registers.cpuY = (value shr 8).toUByte()
|
||||
}
|
||||
"xy" -> {
|
||||
registers.cpuX = (value and 255u).toUByte()
|
||||
registers.cpuY = (value shr 8).toUByte()
|
||||
}
|
||||
"pc" -> statusCarry = value == 1u
|
||||
"pz" -> statusZero = value == 1u
|
||||
"pn" -> statusNegative = value == 1u
|
||||
"pv" -> throw IllegalArgumentException("overflow status register not supported in VM")
|
||||
else -> throw IllegalArgumentException("invalid cpu reg")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun InsLOAD(i: Instruction) {
|
||||
@ -2055,7 +2111,7 @@ class VmRunner: IVirtualMachineRunner {
|
||||
val assembler = Assembler()
|
||||
assembler.initializeMemory(memsrc, memory)
|
||||
val program = assembler.assembleProgram(programsrc)
|
||||
val vm = VirtualMachine(memory, program)
|
||||
val vm = VirtualMachine(memory, program, assembler.cx16virtualregBaseAdress)
|
||||
vm.run(throttle = true)
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user