mirror of
https://github.com/irmen/prog8.git
synced 2025-02-20 03:29:01 +00:00
fixed register reuse and types on syscall interface
This commit is contained in:
parent
ee521793f8
commit
76b29aa629
@ -285,9 +285,10 @@ internal class ExpressionGen(private val codeGen: IRCodeGen) {
|
||||
addToResult(result, elementTr, elementTr.resultReg, -1)
|
||||
val iterableTr = translateExpression(haystackVar)
|
||||
addToResult(result, iterableTr, iterableTr.resultReg, -1)
|
||||
result += codeGen.makeSyscall(IMSyscall.STRING_CONTAINS, listOf(IRDataType.BYTE to elementTr.resultReg, IRDataType.WORD to iterableTr.resultReg), IRDataType.BYTE to elementTr.resultReg)
|
||||
addInstr(result, IRInstruction(Opcode.CMPI, IRDataType.BYTE, reg1=elementTr.resultReg, immediate = 0), null)
|
||||
return ExpressionCodeResult(result, IRDataType.BYTE, elementTr.resultReg, -1)
|
||||
val resultReg = codeGen.registers.nextFree()
|
||||
result += codeGen.makeSyscall(IMSyscall.STRING_CONTAINS, listOf(IRDataType.BYTE to elementTr.resultReg, IRDataType.WORD to iterableTr.resultReg), IRDataType.BYTE to resultReg)
|
||||
addInstr(result, IRInstruction(Opcode.CMPI, IRDataType.BYTE, reg1=resultReg, immediate = 0), null)
|
||||
return ExpressionCodeResult(result, IRDataType.BYTE, resultReg, -1)
|
||||
}
|
||||
haystackVar.type.isByteArray -> {
|
||||
addInstr(result, IRInstruction(Opcode.PREPARECALL, immediate = 3), null)
|
||||
@ -298,9 +299,10 @@ internal class ExpressionGen(private val codeGen: IRCodeGen) {
|
||||
val lengthReg = codeGen.registers.nextFree()
|
||||
val iterableLength = codeGen.symbolTable.getLength(haystackVar.name)
|
||||
addInstr(result, IRInstruction(Opcode.LOAD, IRDataType.BYTE, reg1=lengthReg, immediate = iterableLength!!), null)
|
||||
result += codeGen.makeSyscall(IMSyscall.BYTEARRAY_CONTAINS, listOf(IRDataType.BYTE to elementTr.resultReg, IRDataType.WORD to iterableTr.resultReg, IRDataType.BYTE to lengthReg), IRDataType.BYTE to elementTr.resultReg)
|
||||
addInstr(result, IRInstruction(Opcode.CMPI, IRDataType.BYTE, reg1=elementTr.resultReg, immediate = 0), null)
|
||||
return ExpressionCodeResult(result, IRDataType.BYTE, elementTr.resultReg, -1)
|
||||
val resultReg = codeGen.registers.nextFree()
|
||||
result += codeGen.makeSyscall(IMSyscall.BYTEARRAY_CONTAINS, listOf(IRDataType.BYTE to elementTr.resultReg, IRDataType.WORD to iterableTr.resultReg, IRDataType.BYTE to lengthReg), IRDataType.BYTE to resultReg)
|
||||
addInstr(result, IRInstruction(Opcode.CMPI, IRDataType.BYTE, reg1=resultReg, immediate = 0), null)
|
||||
return ExpressionCodeResult(result, IRDataType.BYTE, resultReg, -1)
|
||||
}
|
||||
haystackVar.type.isWordArray -> {
|
||||
addInstr(result, IRInstruction(Opcode.PREPARECALL, immediate = 3), null)
|
||||
@ -311,9 +313,10 @@ internal class ExpressionGen(private val codeGen: IRCodeGen) {
|
||||
val lengthReg = codeGen.registers.nextFree()
|
||||
val iterableLength = codeGen.symbolTable.getLength(haystackVar.name)
|
||||
addInstr(result, IRInstruction(Opcode.LOAD, IRDataType.BYTE, reg1=lengthReg, immediate = iterableLength!!), null)
|
||||
result += codeGen.makeSyscall(IMSyscall.WORDARRAY_CONTAINS, listOf(IRDataType.WORD to elementTr.resultReg, IRDataType.WORD to iterableTr.resultReg, IRDataType.BYTE to lengthReg), IRDataType.BYTE to elementTr.resultReg)
|
||||
addInstr(result, IRInstruction(Opcode.CMPI, IRDataType.BYTE, reg1=elementTr.resultReg, immediate = 0), null)
|
||||
return ExpressionCodeResult(result, IRDataType.BYTE, elementTr.resultReg, -1)
|
||||
val resultReg = codeGen.registers.nextFree()
|
||||
result += codeGen.makeSyscall(IMSyscall.WORDARRAY_CONTAINS, listOf(IRDataType.WORD to elementTr.resultReg, IRDataType.WORD to iterableTr.resultReg, IRDataType.BYTE to lengthReg), IRDataType.BYTE to resultReg)
|
||||
addInstr(result, IRInstruction(Opcode.CMPI, IRDataType.BYTE, reg1=resultReg, immediate = 0), null)
|
||||
return ExpressionCodeResult(result, IRDataType.BYTE, resultReg, -1)
|
||||
}
|
||||
haystackVar.type.isFloatArray -> {
|
||||
addInstr(result, IRInstruction(Opcode.PREPARECALL, immediate = 3), null)
|
||||
@ -1071,6 +1074,7 @@ internal class ExpressionGen(private val codeGen: IRCodeGen) {
|
||||
val leftTr = translateExpression(binExpr.left)
|
||||
addToResult(result, leftTr, leftTr.resultReg, -1)
|
||||
val rightTr = translateExpression(binExpr.right)
|
||||
require(rightTr.dt== IRDataType.BYTE) { "can only shift by 0-255" }
|
||||
addToResult(result, rightTr, rightTr.resultReg, -1)
|
||||
val opc = if (signed) Opcode.ASRN else Opcode.LSRN
|
||||
addInstr(result, IRInstruction(opc, vmDt, reg1 = leftTr.resultReg, reg2 = rightTr.resultReg), null)
|
||||
@ -1089,6 +1093,7 @@ internal class ExpressionGen(private val codeGen: IRCodeGen) {
|
||||
val leftTr = translateExpression(binExpr.left)
|
||||
addToResult(result, leftTr, leftTr.resultReg, -1)
|
||||
val rightTr = translateExpression(binExpr.right)
|
||||
require(rightTr.dt== IRDataType.BYTE) { "can only shift by 0-255" }
|
||||
addToResult(result, rightTr, rightTr.resultReg, -1)
|
||||
addInstr(result, IRInstruction(Opcode.LSLN, vmDt, reg1=leftTr.resultReg, rightTr.resultReg), null)
|
||||
ExpressionCodeResult(result, vmDt, leftTr.resultReg, -1)
|
||||
|
@ -808,7 +808,7 @@ class IRCodeGen(
|
||||
else if(pow2>=1) {
|
||||
// just shift multiple bits
|
||||
val pow2reg = registers.nextFree()
|
||||
code += IRInstruction(Opcode.LOAD, dt, reg1=pow2reg, immediate = pow2)
|
||||
code += IRInstruction(Opcode.LOAD, IRDataType.BYTE, reg1=pow2reg, immediate = pow2)
|
||||
code += IRInstruction(Opcode.LSLN, dt, reg1=reg, reg2=pow2reg)
|
||||
} else {
|
||||
code += if (factor == 0) {
|
||||
@ -906,7 +906,7 @@ class IRCodeGen(
|
||||
} else {
|
||||
// just shift multiple bits (signed)
|
||||
val pow2reg = registers.nextFree()
|
||||
code += IRInstruction(Opcode.LOAD, dt, reg1=pow2reg, immediate = pow2)
|
||||
code += IRInstruction(Opcode.LOAD, IRDataType.BYTE, reg1=pow2reg, immediate = pow2)
|
||||
code += IRInstruction(Opcode.ASRN, dt, reg1=reg, reg2=pow2reg)
|
||||
}
|
||||
} else {
|
||||
@ -916,7 +916,7 @@ class IRCodeGen(
|
||||
} else {
|
||||
// just shift multiple bits (unsigned)
|
||||
val pow2reg = registers.nextFree()
|
||||
code += IRInstruction(Opcode.LOAD, dt, reg1 = pow2reg, immediate = pow2)
|
||||
code += IRInstruction(Opcode.LOAD, IRDataType.BYTE, reg1 = pow2reg, immediate = pow2)
|
||||
code += IRInstruction(Opcode.LSRN, dt, reg1 = reg, reg2 = pow2reg)
|
||||
}
|
||||
}
|
||||
|
@ -1,20 +1,29 @@
|
||||
package prog8.codegen.intermediate
|
||||
|
||||
import prog8.code.core.AssemblyError
|
||||
|
||||
internal class RegisterPool {
|
||||
// reserve 0,1,2 for return values of subroutine calls and syscalls in IR assembly code
|
||||
// reserve first 3 registers a subroutine return registers TODO is this still needed? how does returning values go in IR? Double types?
|
||||
private var firstFree: Int=3
|
||||
private var firstFreeFloat: Int=3
|
||||
|
||||
fun peekNext() = firstFree
|
||||
fun peekNextFloat() = firstFreeFloat
|
||||
|
||||
// everything from 99000 onwards is reserved for special purposes:
|
||||
// 99000 - 99099 : WORD registers for syscall arguments and response value(s)
|
||||
// 99100 - 99199 : BYTE registers for syscall arguments and response value(s)
|
||||
|
||||
|
||||
fun nextFree(): Int {
|
||||
if(firstFree>=99000)
|
||||
throw AssemblyError("register pool depleted")
|
||||
val result = firstFree
|
||||
firstFree++
|
||||
return result
|
||||
}
|
||||
|
||||
fun nextFreeFloat(): Int {
|
||||
if(firstFreeFloat>=99000)
|
||||
throw AssemblyError("float register pool depleted")
|
||||
val result = firstFreeFloat
|
||||
firstFreeFloat++
|
||||
return result
|
||||
|
@ -212,9 +212,9 @@ sub str2uword(str string) -> uword {
|
||||
; the number may NOT be preceded by a + sign and may NOT contain spaces
|
||||
; (any non-digit character will terminate the number string that is parsed)
|
||||
%ir {{
|
||||
loadm.w r65535,conv.str2uword.string
|
||||
syscall 11 (r65535.w) : r0.w
|
||||
returnr.w r0
|
||||
loadm.w r99000,conv.str2uword.string
|
||||
syscall 11 (r99000.w) : r99000.w
|
||||
returnr.w r99000
|
||||
}}
|
||||
}
|
||||
|
||||
@ -223,9 +223,9 @@ sub str2word(str string) -> word {
|
||||
; the number may be preceded by a + or - sign but may NOT contain spaces
|
||||
; (any non-digit character will terminate the number string that is parsed)
|
||||
%ir {{
|
||||
loadm.w r65535,conv.str2word.string
|
||||
syscall 12 (r65535.w) : r0.w
|
||||
returnr.w r0
|
||||
loadm.w r99000,conv.str2word.string
|
||||
syscall 12 (r99000.w) : r99000.w
|
||||
returnr.w r99000
|
||||
}}
|
||||
}
|
||||
|
||||
|
@ -13,10 +13,8 @@ diskio {
|
||||
sub directory() -> bool {
|
||||
; -- Prints the directory contents to the screen. Returns success.
|
||||
%ir {{
|
||||
loadm.w r65534,diskio.load.filenameptr
|
||||
loadm.w r65535,diskio.load.address_override
|
||||
syscall 45 (): r0.b
|
||||
returnr.b r0
|
||||
syscall 45 (): r99100.b
|
||||
returnr.b r99100
|
||||
}}
|
||||
}
|
||||
|
||||
@ -64,9 +62,9 @@ diskio {
|
||||
; if you're going to read from it yourself instead of using f_read()!
|
||||
|
||||
%ir {{
|
||||
loadm.w r65535,diskio.f_open.filenameptr
|
||||
syscall 52 (r65535.w): r0.b
|
||||
returnr.b r0
|
||||
loadm.w r99000,diskio.f_open.filenameptr
|
||||
syscall 52 (r99000.w): r99100.b
|
||||
returnr.b r99100
|
||||
}}
|
||||
}
|
||||
|
||||
@ -76,8 +74,8 @@ diskio {
|
||||
uword actual
|
||||
repeat num_bytes {
|
||||
%ir {{
|
||||
syscall 54 (): r0.w
|
||||
storem.w r0,$ff02
|
||||
syscall 54 (): r99000.w
|
||||
storem.w r99000,$ff02
|
||||
}}
|
||||
if cx16.r0H==0
|
||||
return actual
|
||||
@ -94,8 +92,8 @@ diskio {
|
||||
uword actual
|
||||
repeat {
|
||||
%ir {{
|
||||
syscall 54 (): r0.w
|
||||
storem.w r0,$ff02
|
||||
syscall 54 (): r99000.w
|
||||
storem.w r99000,$ff02
|
||||
}}
|
||||
if cx16.r0H==0
|
||||
return actual
|
||||
@ -114,8 +112,8 @@ diskio {
|
||||
ubyte size
|
||||
repeat {
|
||||
%ir {{
|
||||
syscall 54 (): r0.w
|
||||
storem.w r0,$ff02
|
||||
syscall 54 (): r99000.w
|
||||
storem.w r99000,$ff02
|
||||
}}
|
||||
|
||||
if cx16.r0H==0 {
|
||||
@ -157,9 +155,9 @@ diskio {
|
||||
; To be 100% sure if this call was successful, you have to use status()
|
||||
; and check the drive's status message!
|
||||
%ir {{
|
||||
loadm.w r65535,diskio.f_open_w.filenameptr
|
||||
syscall 53 (r65535.w): r0.b
|
||||
returnr.b r0
|
||||
loadm.w r99000,diskio.f_open_w.filenameptr
|
||||
syscall 53 (r99000.w): r99100.b
|
||||
returnr.b r99100
|
||||
}}
|
||||
}
|
||||
|
||||
@ -169,9 +167,9 @@ diskio {
|
||||
repeat num_bytes {
|
||||
%ir {{
|
||||
loadm.w r0,diskio.f_write.bufferpointer
|
||||
loadi.b r1,r0
|
||||
syscall 55 (r1.b): r0.b
|
||||
storem.b r0,$ff02
|
||||
loadi.b r99100,r0
|
||||
syscall 55 (r99100.b): r99100.b
|
||||
storem.b r99100,$ff02
|
||||
}}
|
||||
if cx16.r0L==0
|
||||
return false
|
||||
@ -194,32 +192,32 @@ diskio {
|
||||
sub chdir(str path) {
|
||||
; -- change current directory.
|
||||
%ir {{
|
||||
loadm.w r65535,diskio.chdir.path
|
||||
syscall 50 (r65535.w)
|
||||
loadm.w r99000,diskio.chdir.path
|
||||
syscall 50 (r99000.w)
|
||||
}}
|
||||
}
|
||||
|
||||
sub mkdir(str name) {
|
||||
; -- make a new subdirectory.
|
||||
%ir {{
|
||||
loadm.w r65535,diskio.mkdir.name
|
||||
syscall 49 (r65535.w)
|
||||
loadm.w r99000,diskio.mkdir.name
|
||||
syscall 49 (r99000.w)
|
||||
}}
|
||||
}
|
||||
|
||||
sub rmdir(str name) {
|
||||
; -- remove a subdirectory.
|
||||
%ir {{
|
||||
loadm.w r65535,diskio.rmdir.name
|
||||
syscall 51 (r65535.w)
|
||||
loadm.w r99000,diskio.rmdir.name
|
||||
syscall 51 (r99000.w)
|
||||
}}
|
||||
}
|
||||
|
||||
sub curdir() -> uword {
|
||||
; return current directory name or 0 if error
|
||||
%ir {{
|
||||
syscall 48 (): r0.w
|
||||
returnr.w r0
|
||||
syscall 48 (): r99000.w
|
||||
returnr.w r99000
|
||||
}}
|
||||
}
|
||||
|
||||
@ -236,24 +234,24 @@ diskio {
|
||||
|
||||
sub save(uword filenameptr, uword start_address, uword savesize) -> bool {
|
||||
%ir {{
|
||||
load.b r65532,0
|
||||
loadm.w r65533,diskio.save.filenameptr
|
||||
loadm.w r65534,diskio.save.start_address
|
||||
loadm.w r65535,diskio.save.savesize
|
||||
syscall 42 (r65532.b, r65533.w, r65534.w, r65535.w): r0.b
|
||||
returnr.b r0
|
||||
load.b r99100,0
|
||||
loadm.w r99000,diskio.save.filenameptr
|
||||
loadm.w r99001,diskio.save.start_address
|
||||
loadm.w r99002,diskio.save.savesize
|
||||
syscall 42 (r99100.b, r99000.w, r99001.w, r99002.w): r99100.b
|
||||
returnr.b r99100
|
||||
}}
|
||||
}
|
||||
|
||||
; like save() but omits the 2 byte prg header.
|
||||
sub save_raw(uword filenameptr, uword startaddress, uword savesize) -> bool {
|
||||
%ir {{
|
||||
load.b r65532,1
|
||||
loadm.w r65533,diskio.save.filenameptr
|
||||
loadm.w r65534,diskio.save.start_address
|
||||
loadm.w r65535,diskio.save.savesize
|
||||
syscall 42 (r65532.b, r65533.w, r65534.w, r65535.w): r0.b
|
||||
returnr.b r0
|
||||
load.b r99100,1
|
||||
loadm.w r99000,diskio.save.filenameptr
|
||||
loadm.w r99001,diskio.save.start_address
|
||||
loadm.w r99002,diskio.save.savesize
|
||||
syscall 42 (r99100.b, r99000.w, r99001.w, r99002.w): r99100.b
|
||||
returnr.b r99100
|
||||
}}
|
||||
}
|
||||
|
||||
@ -265,10 +263,10 @@ diskio {
|
||||
; Returns the end load address+1 if successful or 0 if a load error occurred.
|
||||
sub load(uword filenameptr, uword address_override) -> uword {
|
||||
%ir {{
|
||||
loadm.w r65534,diskio.load.filenameptr
|
||||
loadm.w r65535,diskio.load.address_override
|
||||
syscall 40 (r65534.w, r65535.w): r0.w
|
||||
returnr.w r0
|
||||
loadm.w r99000,diskio.load.filenameptr
|
||||
loadm.w r99001,diskio.load.address_override
|
||||
syscall 40 (r99000.w, r99001.w): r99002.w
|
||||
returnr.w r99002
|
||||
}}
|
||||
}
|
||||
|
||||
@ -277,27 +275,27 @@ diskio {
|
||||
; See comments on load() for more details.
|
||||
sub load_raw(uword filenameptr, uword start_address) -> uword {
|
||||
%ir {{
|
||||
loadm.w r65534,diskio.load_raw.filenameptr
|
||||
loadm.w r65535,diskio.load_raw.start_address
|
||||
syscall 41 (r65534.w, r65535.w): r0.w
|
||||
returnr.w r0
|
||||
loadm.w r99000,diskio.load_raw.filenameptr
|
||||
loadm.w r99001,diskio.load_raw.start_address
|
||||
syscall 41 (r99000.w, r99001.w): r99002.w
|
||||
returnr.w r99002
|
||||
}}
|
||||
}
|
||||
|
||||
sub delete(uword filenameptr) {
|
||||
; -- delete a file on the drive
|
||||
%ir {{
|
||||
loadm.w r65535,diskio.delete.filenameptr
|
||||
syscall 43 (r65535.w)
|
||||
loadm.w r99000,diskio.delete.filenameptr
|
||||
syscall 43 (r99000.w)
|
||||
}}
|
||||
}
|
||||
|
||||
sub rename(uword oldfileptr, uword newfileptr) {
|
||||
; -- rename a file on the drive
|
||||
%ir {{
|
||||
loadm.w r65534,diskio.rename.oldfileptr
|
||||
loadm.w r65535,diskio.rename.newfileptr
|
||||
syscall 44 (r65534.w, r65535.w)
|
||||
loadm.w r99000,diskio.rename.oldfileptr
|
||||
loadm.w r99001,diskio.rename.newfileptr
|
||||
syscall 44 (r99000.w, r99001.w)
|
||||
}}
|
||||
}
|
||||
|
||||
|
@ -35,8 +35,8 @@ floats {
|
||||
sub print(float value) {
|
||||
; ---- prints the floating point value (without a newline and no leading spaces).
|
||||
%ir {{
|
||||
loadm.f fr65535,floats.print.value
|
||||
syscall 15 (fr65535.f)
|
||||
loadm.f fr99000,floats.print.value
|
||||
syscall 15 (fr99000.f)
|
||||
return
|
||||
}}
|
||||
}
|
||||
@ -45,9 +45,9 @@ sub tostr(float value) -> str {
|
||||
; ---- converts the floating point value to a string (no leading spaces)
|
||||
str @shared buffer=" "*20
|
||||
%ir {{
|
||||
load.w r65535,floats.tostr.buffer
|
||||
loadm.f fr65535,floats.tostr.value
|
||||
syscall 34 (r65535.w, fr65535.f)
|
||||
load.w r99000,floats.tostr.buffer
|
||||
loadm.f fr99000,floats.tostr.value
|
||||
syscall 34 (r99000.w, fr99000.f)
|
||||
load.w r0,floats.tostr.buffer
|
||||
returnr.w r0
|
||||
}}
|
||||
@ -56,9 +56,9 @@ sub tostr(float value) -> str {
|
||||
sub parse(str value) -> float {
|
||||
; -- parse a string value of a number to float
|
||||
%ir {{
|
||||
loadm.w r65535,floats.parse.value
|
||||
syscall 32 (r65535.w): fr0.f
|
||||
returnr.f fr0
|
||||
loadm.w r99000,floats.parse.value
|
||||
syscall 32 (r99000.w): fr99000.f
|
||||
returnr.f fr99000
|
||||
}}
|
||||
}
|
||||
|
||||
@ -170,15 +170,15 @@ sub ceil(float value) -> float {
|
||||
|
||||
sub rnd() -> float {
|
||||
%ir {{
|
||||
syscall 22 () : fr0.f
|
||||
returnr.f fr0
|
||||
syscall 22 () : fr99000.f
|
||||
returnr.f fr99000
|
||||
}}
|
||||
}
|
||||
|
||||
sub rndseed(float seed) {
|
||||
%ir {{
|
||||
loadm.f fr65535,floats.rndseed.seed
|
||||
syscall 19 (fr65535.f)
|
||||
loadm.f fr99000,floats.rndseed.seed
|
||||
syscall 19 (fr99000.f)
|
||||
return
|
||||
}}
|
||||
}
|
||||
@ -213,16 +213,16 @@ sub normalize(float value) -> float {
|
||||
sub push(float value) {
|
||||
; note: this *should* be inlined, however since the VM has separate program counter and value stacks, this also works
|
||||
%ir {{
|
||||
loadm.f fr65535,floats.push.value
|
||||
push.f fr65535
|
||||
loadm.f fr99000,floats.push.value
|
||||
push.f fr99000
|
||||
}}
|
||||
}
|
||||
|
||||
sub pop() -> float {
|
||||
; note: this *should* be inlined, however since the VM has separate program counter and value stacks, this also works
|
||||
%ir {{
|
||||
pop.f fr65535
|
||||
returnr.f fr65535
|
||||
pop.f fr99000
|
||||
returnr.f fr99000
|
||||
}}
|
||||
}
|
||||
|
||||
|
@ -164,15 +164,15 @@ math {
|
||||
|
||||
sub rnd() -> ubyte {
|
||||
%ir {{
|
||||
syscall 20 (): r0.b
|
||||
returnr.b r0
|
||||
syscall 20 (): r99100.b
|
||||
returnr.b r99100
|
||||
}}
|
||||
}
|
||||
|
||||
sub rndw() -> uword {
|
||||
%ir {{
|
||||
syscall 21 (): r0.w
|
||||
returnr.w r0
|
||||
syscall 21 (): r99000.w
|
||||
returnr.w r99000
|
||||
}}
|
||||
}
|
||||
|
||||
@ -197,9 +197,9 @@ math {
|
||||
sub rndseed(uword seed1, uword seed2) {
|
||||
; -- reset the pseudo RNG's seed values. Defaults are: $a55a, $7653.
|
||||
%ir {{
|
||||
loadm.w r65534,math.rndseed.seed1
|
||||
loadm.w r65535,math.rndseed.seed2
|
||||
syscall 18 (r65534.w, r65535.w)
|
||||
loadm.w r99000,math.rndseed.seed1
|
||||
loadm.w r99001,math.rndseed.seed2
|
||||
syscall 18 (r99000.w, r99001.w)
|
||||
return
|
||||
}}
|
||||
}
|
||||
@ -276,12 +276,12 @@ math {
|
||||
;; Calculate the angle, in a 256-degree circle, between two points into A.
|
||||
;; The points (x1, y1) and (x2, y2) have to use *unsigned coordinates only* from the positive quadrant in the carthesian plane!
|
||||
%ir {{
|
||||
loadm.b r65532,math.atan2.x1
|
||||
loadm.b r65533,math.atan2.y1
|
||||
loadm.b r65534,math.atan2.x2
|
||||
loadm.b r65535,math.atan2.y2
|
||||
syscall 31 (r65532.b, r65533.b, r65534.b, r65535.b): r0.b
|
||||
returnr.b r0
|
||||
loadm.b r99100,math.atan2.x1
|
||||
loadm.b r99101,math.atan2.y1
|
||||
loadm.b r99102,math.atan2.x2
|
||||
loadm.b r99103,math.atan2.y2
|
||||
syscall 31 (r99100.b, r99101.b, r99102.b, r99103.b): r99100.b
|
||||
returnr.b r99100
|
||||
}}
|
||||
}
|
||||
|
||||
@ -296,8 +296,8 @@ math {
|
||||
; - THE RESULT IS ONLY VALID IF THE MULTIPLICATION WAS DONE WITH UWORD ARGUMENTS (or two positive WORD arguments)
|
||||
; as soon as a negative word value (or 2) was used in the multiplication, these upper 16 bits are not valid!!
|
||||
%ir {{
|
||||
syscall 33 (): r0.w
|
||||
returnr.w r0
|
||||
syscall 33 (): r99000.w
|
||||
returnr.w r99000
|
||||
}}
|
||||
}
|
||||
|
||||
|
@ -96,10 +96,10 @@ strings {
|
||||
; Often you don’t have to call this explicitly and can just write string1 = string2
|
||||
; but this function is useful if you’re dealing with addresses for instance.
|
||||
%ir {{
|
||||
loadm.w r65534,strings.copy.source
|
||||
loadm.w r65535,strings.copy.target
|
||||
syscall 39 (r65534.w, r65535.w): r0.b
|
||||
returnr.b r0
|
||||
loadm.w r99000,strings.copy.source
|
||||
loadm.w r99001,strings.copy.target
|
||||
syscall 39 (r99000.w, r99001.w): r99100.b
|
||||
returnr.b r99100
|
||||
}}
|
||||
}
|
||||
|
||||
@ -116,10 +116,10 @@ strings {
|
||||
; Note that you can also directly compare strings and string values with eachother using
|
||||
; comparison operators ==, < etcetera (this will use strcmp automatically).
|
||||
%ir {{
|
||||
loadm.w r65534,strings.compare.st1
|
||||
loadm.w r65535,strings.compare.st2
|
||||
syscall 16 (r65534.w, r65535.w) : r0.b
|
||||
returnr.b r0
|
||||
loadm.w r99000,strings.compare.st1
|
||||
loadm.w r99001,strings.compare.st2
|
||||
syscall 16 (r99000.w, r99001.w) : r99100.b
|
||||
returnr.b r99100
|
||||
}}
|
||||
}
|
||||
|
||||
|
@ -34,8 +34,8 @@ sys {
|
||||
sub wait(uword jiffies) {
|
||||
; --- wait approximately the given number of jiffies (1/60th seconds)
|
||||
%ir {{
|
||||
loadm.w r65535,sys.wait.jiffies
|
||||
syscall 13 (r65535.w)
|
||||
loadm.w r99000,sys.wait.jiffies
|
||||
syscall 13 (r99000.w)
|
||||
}}
|
||||
}
|
||||
|
||||
@ -49,36 +49,36 @@ sys {
|
||||
sub internal_stringcopy(uword source, uword tgt) {
|
||||
; Called when the compiler wants to assign a string value to another string.
|
||||
%ir {{
|
||||
loadm.w r65534,sys.internal_stringcopy.source
|
||||
loadm.w r65535,sys.internal_stringcopy.tgt
|
||||
syscall 39 (r65534.w, r65535.w): r0.b
|
||||
loadm.w r99000,sys.internal_stringcopy.source
|
||||
loadm.w r99001,sys.internal_stringcopy.tgt
|
||||
syscall 39 (r99000.w, r99001.w): r99100.b
|
||||
}}
|
||||
}
|
||||
|
||||
sub memcopy(uword source, uword tgt, uword count) {
|
||||
%ir {{
|
||||
loadm.w r65533,sys.memcopy.source
|
||||
loadm.w r65534,sys.memcopy.tgt
|
||||
loadm.w r65535,sys.memcopy.count
|
||||
syscall 36 (r65533.w, r65534.w, r65535.w)
|
||||
loadm.w r99000,sys.memcopy.source
|
||||
loadm.w r99001,sys.memcopy.tgt
|
||||
loadm.w r99002,sys.memcopy.count
|
||||
syscall 36 (r99000.w, r99001.w, r99002.w)
|
||||
}}
|
||||
}
|
||||
|
||||
sub memset(uword mem, uword numbytes, ubyte value) {
|
||||
%ir {{
|
||||
loadm.w r65533,sys.memset.mem
|
||||
loadm.w r65534,sys.memset.numbytes
|
||||
loadm.b r65535,sys.memset.value
|
||||
syscall 37 (r65533.w, r65534.w, r65535.b)
|
||||
loadm.w r99000,sys.memset.mem
|
||||
loadm.w r99001,sys.memset.numbytes
|
||||
loadm.b r99100,sys.memset.value
|
||||
syscall 37 (r99000.w, r99001.w, r99100.b)
|
||||
}}
|
||||
}
|
||||
|
||||
sub memsetw(uword mem, uword numwords, uword value) {
|
||||
%ir {{
|
||||
loadm.w r65533,sys.memsetw.mem
|
||||
loadm.w r65534,sys.memsetw.numwords
|
||||
loadm.w r65535,sys.memsetw.value
|
||||
syscall 38 (r65533.w, r65534.w, r65535.w)
|
||||
loadm.w r99000,sys.memsetw.mem
|
||||
loadm.w r99001,sys.memsetw.numwords
|
||||
loadm.w r99002,sys.memsetw.value
|
||||
syscall 38 (r99000.w, r99001.w, r99002.w)
|
||||
}}
|
||||
}
|
||||
|
||||
@ -86,19 +86,19 @@ sys {
|
||||
; Compares two blocks of memory of up to 65535 bytes in size
|
||||
; Returns -1 (255), 0 or 1, meaning: block 1 sorts before, equal or after block 2.
|
||||
%ir {{
|
||||
loadm.w r65533,sys.memcmp.address1
|
||||
loadm.w r65534,sys.memcmp.address2
|
||||
loadm.w r65535,sys.memcmp.size
|
||||
syscall 47 (r65533.w, r65534.w, r65535.w) : r0.b
|
||||
returnr.b r0
|
||||
loadm.w r99000,sys.memcmp.address1
|
||||
loadm.w r99001,sys.memcmp.address2
|
||||
loadm.w r99002,sys.memcmp.size
|
||||
syscall 47 (r99000.w, r99001.w, r99002.w) : r99100.b
|
||||
returnr.b r99100
|
||||
}}
|
||||
}
|
||||
|
||||
sub exit(ubyte returnvalue) {
|
||||
; -- immediately exit the program with a return code in the A register
|
||||
%ir {{
|
||||
loadm.b r65535,sys.exit.returnvalue
|
||||
syscall 1 (r65535.b)
|
||||
loadm.b r99100,sys.exit.returnvalue
|
||||
syscall 1 (r99100.b)
|
||||
}}
|
||||
}
|
||||
|
||||
@ -144,73 +144,73 @@ sys {
|
||||
|
||||
sub gfx_enable(ubyte mode) {
|
||||
%ir {{
|
||||
loadm.b r65535,sys.gfx_enable.mode
|
||||
syscall 8 (r65535.b)
|
||||
loadm.b r99100,sys.gfx_enable.mode
|
||||
syscall 8 (r99100.b)
|
||||
}}
|
||||
}
|
||||
|
||||
sub gfx_clear(ubyte color) {
|
||||
%ir {{
|
||||
loadm.b r65535,sys.gfx_clear.color
|
||||
syscall 9 (r65535.b)
|
||||
loadm.b r99100,sys.gfx_clear.color
|
||||
syscall 9 (r99100.b)
|
||||
}}
|
||||
}
|
||||
|
||||
sub gfx_plot(uword xx, uword yy, ubyte color) {
|
||||
%ir {{
|
||||
loadm.w r65533,sys.gfx_plot.xx
|
||||
loadm.w r65534,sys.gfx_plot.yy
|
||||
loadm.b r65535,sys.gfx_plot.color
|
||||
syscall 10 (r65533.w, r65534.w, r65535.b)
|
||||
loadm.w r99000,sys.gfx_plot.xx
|
||||
loadm.w r99001,sys.gfx_plot.yy
|
||||
loadm.b r99100,sys.gfx_plot.color
|
||||
syscall 10 (r99000.w, r99001.w, r99100.b)
|
||||
}}
|
||||
}
|
||||
|
||||
sub gfx_getpixel(uword xx, uword yy) -> ubyte {
|
||||
%ir {{
|
||||
loadm.w r65534,sys.gfx_getpixel.xx
|
||||
loadm.w r65535,sys.gfx_getpixel.yy
|
||||
syscall 17 (r65534.w, r65535.w): r0.b
|
||||
returnr.b r0
|
||||
loadm.w r99000,sys.gfx_getpixel.xx
|
||||
loadm.w r99001,sys.gfx_getpixel.yy
|
||||
syscall 17 (r99000.w, r99001.w): r99100.b
|
||||
returnr.b r99100
|
||||
}}
|
||||
}
|
||||
|
||||
sub push(ubyte b) {
|
||||
; note: this *should* be inlined, however since the VM has separate program counter and value stacks, this also works
|
||||
%ir {{
|
||||
loadm.b r65535,sys.push.b
|
||||
push.b r65535
|
||||
loadm.b r99100,sys.push.b
|
||||
push.b r99100
|
||||
}}
|
||||
}
|
||||
|
||||
sub pushw(uword w) {
|
||||
; note: this *should* be inlined, however since the VM has separate program counter and value stacks, this also works
|
||||
%ir {{
|
||||
loadm.w r65535,sys.pushw.w
|
||||
push.w r65535
|
||||
loadm.w r99000,sys.pushw.w
|
||||
push.w r99000
|
||||
}}
|
||||
}
|
||||
|
||||
sub push_returnaddress(uword w) {
|
||||
; note: this actually doesn't do anything useful on the VM because the code execution doesn't use the simulated cpu stack
|
||||
%ir {{
|
||||
loadm.w r65535,sys.pushw.w
|
||||
push.w r65535
|
||||
loadm.w r99000,sys.pushw.w
|
||||
push.w r99000
|
||||
}}
|
||||
}
|
||||
|
||||
sub pop() -> ubyte {
|
||||
; note: this *should* be inlined, however since the VM has separate program counter and value stacks, this also works
|
||||
%ir {{
|
||||
pop.b r65535
|
||||
returnr.b r65535
|
||||
pop.b r99100
|
||||
returnr.b r99100
|
||||
}}
|
||||
}
|
||||
|
||||
sub popw() -> uword {
|
||||
; note: this *should* be inlined, however since the VM has separate program counter and value stacks, this also works
|
||||
%ir {{
|
||||
pop.w r65535
|
||||
returnr.w r65535
|
||||
pop.w r99000
|
||||
returnr.w r99000
|
||||
}}
|
||||
}
|
||||
|
||||
|
@ -7,24 +7,25 @@ txt {
|
||||
|
||||
sub width() -> ubyte {
|
||||
%ir {{
|
||||
syscall 46 (): r0.w
|
||||
returnr.b r0
|
||||
syscall 46 (): r99000.w
|
||||
lsig.b r99100,r99000
|
||||
returnr.b r99100
|
||||
}}
|
||||
}
|
||||
|
||||
sub height() -> ubyte {
|
||||
%ir {{
|
||||
syscall 46 (): r0.w
|
||||
msig.b r1,r0
|
||||
returnr.b r1
|
||||
syscall 46 (): r99000.w
|
||||
msig.b r99100,r99000
|
||||
returnr.b r99100
|
||||
}}
|
||||
}
|
||||
|
||||
sub clear_screen() {
|
||||
str @shared sequence = "\x1b[2J\x1B[H"
|
||||
%ir {{
|
||||
load.w r65535,txt.clear_screen.sequence
|
||||
syscall 3 (r65535.w)
|
||||
load.w r99000,txt.clear_screen.sequence
|
||||
syscall 3 (r99000.w)
|
||||
}}
|
||||
}
|
||||
|
||||
@ -54,8 +55,8 @@ sub uppercase() {
|
||||
|
||||
sub chrout(ubyte char) {
|
||||
%ir {{
|
||||
loadm.b r65535,txt.chrout.char
|
||||
syscall 2 (r65535.b)
|
||||
loadm.b r99100,txt.chrout.char
|
||||
syscall 2 (r99100.b)
|
||||
}}
|
||||
}
|
||||
|
||||
@ -65,8 +66,8 @@ sub bell() {
|
||||
|
||||
sub print (str text) {
|
||||
%ir {{
|
||||
loadm.w r65535,txt.print.text
|
||||
syscall 3 (r65535.w)
|
||||
loadm.w r99000,txt.print.text
|
||||
syscall 3 (r99000.w)
|
||||
}}
|
||||
}
|
||||
|
||||
@ -139,10 +140,10 @@ sub input_chars (uword buffer) -> ubyte {
|
||||
; ---- Input a string (max. 80 chars) from the keyboard. Returns length of input. (string is terminated with a 0 byte as well)
|
||||
; It assumes the keyboard is selected as I/O channel!
|
||||
%ir {{
|
||||
loadm.w r65534,txt.input_chars.buffer
|
||||
load.b r65535,80
|
||||
syscall 6 (r65534.w, r65535.b): r0.b
|
||||
returnr.b r0
|
||||
loadm.w r99000,txt.input_chars.buffer
|
||||
load.b r99100,80
|
||||
syscall 6 (r99000.w, r99100.b): r99100.b
|
||||
returnr.b r99100
|
||||
}}
|
||||
}
|
||||
|
||||
|
@ -1,8 +1,6 @@
|
||||
TODO
|
||||
====
|
||||
|
||||
- addUsedRegistersCounts() doesn't always determine the datatype correctly. --> GET RID OF THE Sxxx OPCODES FOR NOW?
|
||||
|
||||
- add paypal donation button as well?
|
||||
- announce prog8 on the 6502.org site?
|
||||
|
||||
@ -56,8 +54,8 @@ Future Things and Ideas
|
||||
|
||||
IR/VM
|
||||
-----
|
||||
- fix the syscall interface. It should not use r0 as return reg, but something in the 65000 range. Also, separete input regs for byte or word types.
|
||||
- getting it in shape for code generation...: the IR file should be able to encode every detail about a prog8 program (the VM doesn't have to actually be able to run all of it though!)
|
||||
- registerPool should have separate pools, one for byte and word registers each (and 1 for floats)?
|
||||
- add BZ and BNZ instructions? To replace CMPI #0 + Branch?
|
||||
- fix TODO("IR rol/ror on split words array")
|
||||
- fix "<< in array" / ">> in array"
|
||||
|
@ -1,14 +1,8 @@
|
||||
%zeropage basicsafe
|
||||
%option no_sysinit
|
||||
|
||||
main {
|
||||
ubyte @shared width
|
||||
|
||||
sub start() {
|
||||
if width==22 or width==33 {
|
||||
cx16.r1++
|
||||
}
|
||||
str localstr = "hello"
|
||||
uword[] words = [1111,2222,"three"]
|
||||
bool r1 = 'z' in localstr
|
||||
bool result = 2222 in words
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
@ -1,5 +1,6 @@
|
||||
package prog8.intermediate
|
||||
|
||||
import prog8.code.core.AssemblyError
|
||||
import prog8.code.core.RegisterOrStatusflag
|
||||
import prog8.code.core.toHex
|
||||
|
||||
@ -795,11 +796,11 @@ data class IRInstruction(
|
||||
}
|
||||
}
|
||||
if(labelSymbolOffset!=null) require(labelSymbolOffset>0 && labelSymbol!=null) {"labelsymbol offset inconsistency"}
|
||||
require(reg1==null || reg1 in 0..65536) {"reg1 out of bounds"}
|
||||
require(reg2==null || reg2 in 0..65536) {"reg2 out of bounds"}
|
||||
require(reg3==null || reg3 in 0..65536) {"reg3 out of bounds"}
|
||||
require(fpReg1==null || fpReg1 in 0..65536) {"fpReg1 out of bounds"}
|
||||
require(fpReg2==null || fpReg2 in 0..65536) {"fpReg2 out of bounds"}
|
||||
require(reg1==null || reg1 in 0..99999) {"reg1 out of bounds"}
|
||||
require(reg2==null || reg2 in 0..99999) {"reg2 out of bounds"}
|
||||
require(reg3==null || reg3 in 0..99999) {"reg3 out of bounds"}
|
||||
require(fpReg1==null || fpReg1 in 0..99999) {"fpReg1 out of bounds"}
|
||||
require(fpReg2==null || fpReg2 in 0..99999) {"fpReg2 out of bounds"}
|
||||
if(reg1!=null && reg2!=null) require(reg1!=reg2) {"reg1 must not be same as reg2"} // note: this is ok for fpRegs as these are always the same type
|
||||
if(reg1!=null && reg3!=null) require(reg1!=reg3) {"reg1 must not be same as reg3"} // note: this is ok for fpRegs as these are always the same type
|
||||
if(reg2!=null && reg3!=null) require(reg2!=reg3) {"reg2 must not be same as reg3"} // note: this is ok for fpRegs as these are always the same type
|
||||
@ -855,6 +856,20 @@ data class IRInstruction(
|
||||
|
||||
if(opcode==Opcode.SYSCALL) {
|
||||
requireNotNull(immediate) { "syscall needs immediate integer for the syscall number" }
|
||||
val callRegisters = fcallArgs?.arguments?.map { it.reg.registerNum } ?: emptyList()
|
||||
val returnRegisters = fcallArgs?.returns?.map { it.registerNum } ?: emptyList()
|
||||
|
||||
val reused = callRegisters.intersect(returnRegisters)
|
||||
if(reused.isNotEmpty()) {
|
||||
for(r in reused) {
|
||||
val argType = fcallArgs!!.arguments.single { it.reg.registerNum==r }.reg.dt
|
||||
val returnType = fcallArgs.returns.single { it.registerNum==r }.dt
|
||||
if (argType!=IRDataType.FLOAT && returnType!=IRDataType.FLOAT) {
|
||||
if(argType!=returnType)
|
||||
throw AssemblyError("syscall cannot reuse argument register as return register with different type $this")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -863,7 +878,8 @@ data class IRInstruction(
|
||||
writeRegsCounts: MutableMap<Int, Int>,
|
||||
readFpRegsCounts: MutableMap<Int, Int>,
|
||||
writeFpRegsCounts: MutableMap<Int, Int>,
|
||||
regsTypes: MutableMap<Int, IRDataType>
|
||||
regsTypes: MutableMap<Int, IRDataType>,
|
||||
chunk: IRCodeChunk?
|
||||
) {
|
||||
when (this.reg1direction) {
|
||||
OperandDirection.UNUSED -> {}
|
||||
@ -874,7 +890,7 @@ data class IRInstruction(
|
||||
val existingType = regsTypes[reg1]
|
||||
if (existingType!=null) {
|
||||
if (existingType != actualtype)
|
||||
throw IllegalArgumentException("register $reg1 assigned multiple types! $existingType and $actualtype")
|
||||
throw IllegalArgumentException("register $reg1 assigned multiple types! $existingType and $actualtype in label ${chunk?.label} chunk $chunk")
|
||||
} else
|
||||
regsTypes[reg1] = actualtype
|
||||
}
|
||||
@ -886,7 +902,7 @@ data class IRInstruction(
|
||||
val existingType = regsTypes[reg1]
|
||||
if (existingType!=null) {
|
||||
if (existingType != actualtype)
|
||||
throw IllegalArgumentException("register $reg1 assigned multiple types! $existingType and $actualtype")
|
||||
throw IllegalArgumentException("register $reg1 assigned multiple types! $existingType and $actualtype in label ${chunk?.label} chunk $chunk")
|
||||
} else
|
||||
regsTypes[reg1] = actualtype
|
||||
|
||||
@ -900,7 +916,7 @@ data class IRInstruction(
|
||||
val existingType = regsTypes[reg1]
|
||||
if (existingType!=null) {
|
||||
if (existingType != actualtype)
|
||||
throw IllegalArgumentException("register $reg1 assigned multiple types! $existingType and $actualtype")
|
||||
throw IllegalArgumentException("register $reg1 assigned multiple types! $existingType and $actualtype in label ${chunk?.label} chunk $chunk")
|
||||
} else
|
||||
regsTypes[reg1] = actualtype
|
||||
|
||||
@ -916,7 +932,7 @@ data class IRInstruction(
|
||||
val existingType = regsTypes[reg2]
|
||||
if (existingType!=null) {
|
||||
if (existingType != actualtype)
|
||||
throw IllegalArgumentException("register $reg2 assigned multiple types! $existingType and $actualtype")
|
||||
throw IllegalArgumentException("register $reg2 assigned multiple types! $existingType and $actualtype in label ${chunk?.label} chunk $chunk")
|
||||
} else
|
||||
regsTypes[reg2] = actualtype
|
||||
}
|
||||
@ -932,7 +948,7 @@ data class IRInstruction(
|
||||
val existingType = regsTypes[reg3]
|
||||
if (existingType!=null) {
|
||||
if (existingType != actualtype)
|
||||
throw IllegalArgumentException("register $reg3 assigned multiple types! $existingType and $actualtype")
|
||||
throw IllegalArgumentException("register $reg3 assigned multiple types! $existingType and $actualtype in label ${chunk?.label} chunk $chunk")
|
||||
} else
|
||||
regsTypes[reg3] = actualtype
|
||||
}
|
||||
@ -965,7 +981,7 @@ data class IRInstruction(
|
||||
val existingType = regsTypes[it.registerNum]
|
||||
if (existingType!=null) {
|
||||
if (existingType != it.dt)
|
||||
throw IllegalArgumentException("register ${it.registerNum} assigned multiple types! $existingType and ${it.dt}")
|
||||
throw IllegalArgumentException("register ${it.registerNum} assigned multiple types! $existingType and ${it.dt} in label ${chunk?.label} chunk $chunk")
|
||||
} else
|
||||
regsTypes[it.registerNum] = it.dt
|
||||
}
|
||||
@ -978,7 +994,7 @@ data class IRInstruction(
|
||||
val existingType = regsTypes[it.reg.registerNum]
|
||||
if (existingType!=null) {
|
||||
if (existingType != it.reg.dt)
|
||||
throw IllegalArgumentException("register ${it.reg.registerNum} assigned multiple types! $existingType and ${it.reg.dt}")
|
||||
throw IllegalArgumentException("register ${it.reg.registerNum} assigned multiple types! $existingType and ${it.reg.dt} in label ${chunk?.label} chunk $chunk")
|
||||
} else
|
||||
regsTypes[it.reg.registerNum] = it.reg.dt
|
||||
}
|
||||
|
@ -286,7 +286,14 @@ class IRProgram(val name: String,
|
||||
}
|
||||
|
||||
globalInits.instructions.forEach {
|
||||
it.addUsedRegistersCounts(readRegsCounts, writeRegsCounts, readFpRegsCounts, writeFpRegsCounts, regsTypes)
|
||||
it.addUsedRegistersCounts(
|
||||
readRegsCounts,
|
||||
writeRegsCounts,
|
||||
readFpRegsCounts,
|
||||
writeFpRegsCounts,
|
||||
regsTypes,
|
||||
globalInits
|
||||
)
|
||||
}
|
||||
|
||||
blocks.forEach {block ->
|
||||
@ -474,7 +481,7 @@ class IRCodeChunk(label: String?, next: IRCodeChunkBase?): IRCodeChunkBase(label
|
||||
val readFpRegsCounts = mutableMapOf<Int, Int>().withDefault { 0 }
|
||||
val writeRegsCounts = mutableMapOf<Int, Int>().withDefault { 0 }
|
||||
val writeFpRegsCounts = mutableMapOf<Int, Int>().withDefault { 0 }
|
||||
instructions.forEach { it.addUsedRegistersCounts(readRegsCounts, writeRegsCounts, readFpRegsCounts, writeFpRegsCounts, regsTypes) }
|
||||
instructions.forEach { it.addUsedRegistersCounts(readRegsCounts, writeRegsCounts, readFpRegsCounts, writeFpRegsCounts, regsTypes, this) }
|
||||
return RegistersUsed(readRegsCounts, writeRegsCounts, readFpRegsCounts, writeFpRegsCounts, regsTypes)
|
||||
}
|
||||
|
||||
@ -559,7 +566,14 @@ private fun registersUsedInAssembly(isIR: Boolean, assembly: String): RegistersU
|
||||
if(t.isNotEmpty()) {
|
||||
val result = parseIRCodeLine(t)
|
||||
result.fold(
|
||||
ifLeft = { it.addUsedRegistersCounts(readRegsCounts, writeRegsCounts,readFpRegsCounts, writeFpRegsCounts, regsTypes) },
|
||||
ifLeft = { it.addUsedRegistersCounts(
|
||||
readRegsCounts,
|
||||
writeRegsCounts,
|
||||
readFpRegsCounts,
|
||||
writeFpRegsCounts,
|
||||
regsTypes,
|
||||
null
|
||||
) },
|
||||
ifRight = { /* labels can be skipped */ }
|
||||
)
|
||||
}
|
||||
|
@ -6,8 +6,8 @@ package prog8.vm
|
||||
* A,X and Y "physical" 6502 registers.
|
||||
*/
|
||||
class Registers {
|
||||
private val registers = Array<UShort>(65536) { 0u }
|
||||
private val floatRegisters = Array(65536) { 0.0 }
|
||||
private val registers = Array<UShort>(99999) { 0u }
|
||||
private val floatRegisters = Array(99999) { 0.0 }
|
||||
var cpuA: UByte = 0u
|
||||
var cpuX: UByte = 0u
|
||||
var cpuY: UByte = 0u
|
||||
|
Loading…
x
Reference in New Issue
Block a user