mirror of
https://github.com/irmen/prog8.git
synced 2025-02-16 22:30:46 +00:00
vm: loadix instruction added for indirect addressing via pointer
This commit is contained in:
parent
2002412026
commit
3c8c44155d
@ -78,6 +78,8 @@ internal class AssignmentAsmGen(private val program: Program,
|
|||||||
// indexing a pointer var instead of a real array or string
|
// indexing a pointer var instead of a real array or string
|
||||||
if(elementDt !in ByteDatatypes)
|
if(elementDt !in ByteDatatypes)
|
||||||
throw AssemblyError("non-array var indexing requires bytes dt")
|
throw AssemblyError("non-array var indexing requires bytes dt")
|
||||||
|
if(value.inferType(program) isnot DataType.UBYTE)
|
||||||
|
throw AssemblyError("non-array var indexing requires bytes index")
|
||||||
asmgen.loadScaledArrayIndexIntoRegister(value, elementDt, CpuRegister.Y)
|
asmgen.loadScaledArrayIndexIntoRegister(value, elementDt, CpuRegister.Y)
|
||||||
if(asmgen.isZpVar(value.arrayvar)) {
|
if(asmgen.isZpVar(value.arrayvar)) {
|
||||||
asmgen.out(" lda ($arrayVarName),y")
|
asmgen.out(" lda ($arrayVarName),y")
|
||||||
|
@ -82,34 +82,34 @@ internal class VmCodeInstruction(
|
|||||||
value: Int?=null, // 0-$ffff
|
value: Int?=null, // 0-$ffff
|
||||||
fpValue: Float?=null,
|
fpValue: Float?=null,
|
||||||
labelSymbol: List<String>?=null // alternative to value for branch/call/jump labels
|
labelSymbol: List<String>?=null // alternative to value for branch/call/jump labels
|
||||||
): VmCodeLine() {
|
): VmCodeLine() {
|
||||||
val ins = Instruction(opcode, type, reg1, reg2, fpReg1, fpReg2, value, fpValue, labelSymbol)
|
val ins = Instruction(opcode, type, reg1, reg2, fpReg1, fpReg2, value, fpValue, labelSymbol)
|
||||||
|
|
||||||
init {
|
init {
|
||||||
if(reg1!=null && (reg1<0 || reg1>65536))
|
if(reg1!=null && (reg1<0 || reg1>65536))
|
||||||
throw IllegalArgumentException("reg1 out of bounds")
|
throw IllegalArgumentException("reg1 out of bounds")
|
||||||
if(reg2!=null && (reg2<0 || reg2>65536))
|
if(reg2!=null && (reg2<0 || reg2>65536))
|
||||||
throw IllegalArgumentException("reg2 out of bounds")
|
throw IllegalArgumentException("reg2 out of bounds")
|
||||||
if(fpReg1!=null && (fpReg1<0 || fpReg1>65536))
|
if(fpReg1!=null && (fpReg1<0 || fpReg1>65536))
|
||||||
throw IllegalArgumentException("fpReg1 out of bounds")
|
throw IllegalArgumentException("fpReg1 out of bounds")
|
||||||
if(fpReg2!=null && (fpReg2<0 || fpReg2>65536))
|
if(fpReg2!=null && (fpReg2<0 || fpReg2>65536))
|
||||||
throw IllegalArgumentException("fpReg2 out of bounds")
|
throw IllegalArgumentException("fpReg2 out of bounds")
|
||||||
|
|
||||||
if(value!=null && opcode !in OpcodesWithAddress) {
|
if(value!=null && opcode !in OpcodesWithAddress) {
|
||||||
when (type) {
|
when (type) {
|
||||||
VmDataType.BYTE -> {
|
VmDataType.BYTE -> {
|
||||||
if (value < -128 || value > 255)
|
if (value < -128 || value > 255)
|
||||||
throw IllegalArgumentException("value out of range for byte: $value")
|
throw IllegalArgumentException("value out of range for byte: $value")
|
||||||
}
|
|
||||||
VmDataType.WORD -> {
|
|
||||||
if (value < -32768 || value > 65535)
|
|
||||||
throw IllegalArgumentException("value out of range for word: $value")
|
|
||||||
}
|
|
||||||
VmDataType.FLOAT, null -> {}
|
|
||||||
}
|
}
|
||||||
|
VmDataType.WORD -> {
|
||||||
|
if (value < -32768 || value > 65535)
|
||||||
|
throw IllegalArgumentException("value out of range for word: $value")
|
||||||
|
}
|
||||||
|
VmDataType.FLOAT, null -> {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
internal class VmCodeLabel(val name: List<String>): VmCodeLine()
|
internal class VmCodeLabel(val name: List<String>): VmCodeLine()
|
||||||
internal class VmCodeComment(val comment: String): VmCodeLine()
|
internal class VmCodeComment(val comment: String): VmCodeLine()
|
||||||
|
@ -154,12 +154,8 @@ internal class ExpressionGen(private val codeGen: CodeGen) {
|
|||||||
// indexing a pointer var instead of a real array or string
|
// indexing a pointer var instead of a real array or string
|
||||||
if(eltSize!=1)
|
if(eltSize!=1)
|
||||||
throw AssemblyError("non-array var indexing requires bytes dt")
|
throw AssemblyError("non-array var indexing requires bytes dt")
|
||||||
val pointerReg = codeGen.vmRegisters.nextFree()
|
|
||||||
code += translateExpression(arrayIx.index, idxReg, -1)
|
code += translateExpression(arrayIx.index, idxReg, -1)
|
||||||
// TODO introduce LOADIX instruction to skip the ADD (requires 3 registers)
|
code += VmCodeInstruction(Opcode.LOADIX, vmDt, reg1=resultRegister, reg2=idxReg, value = arrayLocation)
|
||||||
code += VmCodeInstruction(Opcode.LOADM, VmDataType.WORD, reg1=pointerReg, value=arrayLocation)
|
|
||||||
code += VmCodeInstruction(Opcode.ADD, VmDataType.WORD, reg1=pointerReg, reg2=idxReg)
|
|
||||||
code += VmCodeInstruction(Opcode.LOADI, vmDt, reg1=resultRegister, reg2=pointerReg)
|
|
||||||
return code
|
return code
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3,9 +3,8 @@ TODO
|
|||||||
|
|
||||||
For next release
|
For next release
|
||||||
^^^^^^^^^^^^^^^^
|
^^^^^^^^^^^^^^^^
|
||||||
- optimize pointervar indexing codegen: reading (expressions) via optimized codegen instead of @(pointer+idx)
|
- fix pointervar indexing 6502 codegen (AssignmentAsmGen translateNormalAssignment) -> gridcommander worm doesn't move
|
||||||
- optimize pointervar indexing codegen: writing (all sorts of things)
|
- is this code still so much larger:
|
||||||
- why is this code so much larger:
|
|
||||||
uword xx
|
uword xx
|
||||||
for xx in 0 to size-1 {
|
for xx in 0 to size-1 {
|
||||||
gfx2.next_pixel(bitmapbuf[xx])
|
gfx2.next_pixel(bitmapbuf[xx])
|
||||||
@ -16,8 +15,8 @@ For next release
|
|||||||
gfx2.next_pixel(@(srcptr))
|
gfx2.next_pixel(@(srcptr))
|
||||||
srcptr++
|
srcptr++
|
||||||
}
|
}
|
||||||
any difference between 6502 codegen and vm codegen?
|
|
||||||
|
|
||||||
|
- optimize pointervar indexing codegen: writing (all sorts of things)
|
||||||
- pipe operator: (targets other than 'Virtual'): allow non-unary function calls in the pipe that specify the other argument(s) in the calls. Already working for VM target.
|
- pipe operator: (targets other than 'Virtual'): allow non-unary function calls in the pipe that specify the other argument(s) in the calls. Already working for VM target.
|
||||||
- add McCarthy evaluation to shortcircuit and/or expressions. First do ifs by splitting them up? Then do expressions that compute a value?
|
- add McCarthy evaluation to shortcircuit and/or expressions. First do ifs by splitting them up? Then do expressions that compute a value?
|
||||||
- Inliner: also inline function call expressions, and remove it from the StatementOptimizer
|
- Inliner: also inline function call expressions, and remove it from the StatementOptimizer
|
||||||
|
@ -24,8 +24,9 @@ All have type b or w or f.
|
|||||||
load reg1, value - load immediate value into register
|
load reg1, value - load immediate value into register
|
||||||
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
|
||||||
loadr reg1, reg2 - load reg1 with value at register reg2
|
loadix reg1, reg2, pointeraddr - load reg1 with value at memory indirect, pointed to by pointeraddr indexed by value in reg2
|
||||||
|
loadr reg1, reg2 - load reg1 with value in register reg2
|
||||||
|
|
||||||
storem reg1, address - store reg1 at memory address
|
storem reg1, address - store reg1 at memory address
|
||||||
storei reg1, reg2 - store reg1 at memory indirect, memory pointed to by reg2
|
storei reg1, reg2 - store reg1 at memory indirect, memory pointed to by reg2
|
||||||
@ -184,6 +185,7 @@ enum class Opcode {
|
|||||||
LOADM,
|
LOADM,
|
||||||
LOADI,
|
LOADI,
|
||||||
LOADX,
|
LOADX,
|
||||||
|
LOADIX,
|
||||||
LOADR,
|
LOADR,
|
||||||
STOREM,
|
STOREM,
|
||||||
STOREI,
|
STOREI,
|
||||||
@ -313,6 +315,7 @@ enum class Opcode {
|
|||||||
val OpcodesWithAddress = setOf(
|
val OpcodesWithAddress = setOf(
|
||||||
Opcode.LOADM,
|
Opcode.LOADM,
|
||||||
Opcode.LOADX,
|
Opcode.LOADX,
|
||||||
|
Opcode.LOADIX,
|
||||||
Opcode.STOREM,
|
Opcode.STOREM,
|
||||||
Opcode.STOREX,
|
Opcode.STOREX,
|
||||||
Opcode.STOREZM,
|
Opcode.STOREZM,
|
||||||
@ -481,6 +484,7 @@ val instructionFormats = mutableMapOf(
|
|||||||
Opcode.LOADM to InstructionFormat.from("BW,r1,v | F,fr1,v"),
|
Opcode.LOADM to InstructionFormat.from("BW,r1,v | F,fr1,v"),
|
||||||
Opcode.LOADI to InstructionFormat.from("BW,r1,r2 | F,fr1,r1"),
|
Opcode.LOADI to InstructionFormat.from("BW,r1,r2 | F,fr1,r1"),
|
||||||
Opcode.LOADX to InstructionFormat.from("BW,r1,r2,v | F,fr1,r1,v"),
|
Opcode.LOADX to InstructionFormat.from("BW,r1,r2,v | F,fr1,r1,v"),
|
||||||
|
Opcode.LOADIX to InstructionFormat.from("BW,r1,r2,v | F,fr1,r1,v"),
|
||||||
Opcode.LOADR to InstructionFormat.from("BW,r1,r2 | F,fr1,fr2"),
|
Opcode.LOADR to InstructionFormat.from("BW,r1,r2 | F,fr1,fr2"),
|
||||||
Opcode.STOREM to InstructionFormat.from("BW,r1,v | F,fr1,v"),
|
Opcode.STOREM to InstructionFormat.from("BW,r1,v | F,fr1,v"),
|
||||||
Opcode.STOREI to InstructionFormat.from("BW,r1,r2 | F,fr1,r1"),
|
Opcode.STOREI to InstructionFormat.from("BW,r1,r2 | F,fr1,r1"),
|
||||||
|
@ -91,6 +91,7 @@ class VirtualMachine(val memory: Memory, program: List<Instruction>) {
|
|||||||
Opcode.LOADM -> InsLOADM(ins)
|
Opcode.LOADM -> InsLOADM(ins)
|
||||||
Opcode.LOADX -> InsLOADX(ins)
|
Opcode.LOADX -> InsLOADX(ins)
|
||||||
Opcode.LOADI -> InsLOADI(ins)
|
Opcode.LOADI -> InsLOADI(ins)
|
||||||
|
Opcode.LOADIX -> InsLOADIX(ins)
|
||||||
Opcode.LOADR -> InsLOADR(ins)
|
Opcode.LOADR -> InsLOADR(ins)
|
||||||
Opcode.STOREM -> InsSTOREM(ins)
|
Opcode.STOREM -> InsSTOREM(ins)
|
||||||
Opcode.STOREX -> InsSTOREX(ins)
|
Opcode.STOREX -> InsSTOREX(ins)
|
||||||
@ -308,6 +309,24 @@ class VirtualMachine(val memory: Memory, program: List<Instruction>) {
|
|||||||
pc++
|
pc++
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun InsLOADIX(i: Instruction) {
|
||||||
|
when (i.type!!) {
|
||||||
|
VmDataType.BYTE -> {
|
||||||
|
val pointer = memory.getUW(i.value!!) + registers.getUB(i.reg2!!)
|
||||||
|
registers.setUB(i.reg1!!, memory.getUB(pointer.toInt()))
|
||||||
|
}
|
||||||
|
VmDataType.WORD -> {
|
||||||
|
val pointer = memory.getUW(i.value!!) + registers.getUB(i.reg2!!)
|
||||||
|
registers.setUW(i.reg1!!, memory.getUW(pointer.toInt()))
|
||||||
|
}
|
||||||
|
VmDataType.FLOAT -> {
|
||||||
|
val pointer = memory.getUW(i.value!!) + registers.getUB(i.reg1!!)
|
||||||
|
registers.setFloat(i.fpReg1!!, memory.getFloat(pointer.toInt()))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
pc++
|
||||||
|
}
|
||||||
|
|
||||||
private fun InsLOADR(i: Instruction) {
|
private fun InsLOADR(i: Instruction) {
|
||||||
when(i.type!!) {
|
when(i.type!!) {
|
||||||
VmDataType.BYTE -> registers.setUB(i.reg1!!, registers.getUB(i.reg2!!))
|
VmDataType.BYTE -> registers.setUB(i.reg1!!, registers.getUB(i.reg2!!))
|
||||||
|
Loading…
x
Reference in New Issue
Block a user