mirror of
https://github.com/irmen/prog8.git
synced 2024-12-27 20:33:39 +00:00
IR support for storing incbins and romsubs
This commit is contained in:
parent
0e831d4b92
commit
2f3e7d1c27
@ -238,7 +238,11 @@ class StSub(name: String, val parameters: List<StSubroutineParameter>, val retur
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
class StRomSub(name: String, val address: UInt, val parameters: List<StSubroutineParameter>, val returnTypes: List<DataType>, position: Position) :
|
class StRomSub(name: String,
|
||||||
|
val address: UInt,
|
||||||
|
val parameters: List<StRomSubParameter>,
|
||||||
|
val returns: List<RegisterOrStatusflag>,
|
||||||
|
position: Position) :
|
||||||
StNode(name, StNodeType.ROMSUB, position) {
|
StNode(name, StNodeType.ROMSUB, position) {
|
||||||
override fun printProperties() {
|
override fun printProperties() {
|
||||||
print("$name address=${address.toHex()}")
|
print("$name address=${address.toHex()}")
|
||||||
@ -247,6 +251,7 @@ class StRomSub(name: String, val address: UInt, val parameters: List<StSubroutin
|
|||||||
|
|
||||||
|
|
||||||
class StSubroutineParameter(val name: String, val type: DataType)
|
class StSubroutineParameter(val name: String, val type: DataType)
|
||||||
|
class StRomSubParameter(val register: RegisterOrStatusflag, val type: DataType)
|
||||||
class StArrayElement(val number: Double?, val addressOf: List<String>?)
|
class StArrayElement(val number: Double?, val addressOf: List<String>?)
|
||||||
|
|
||||||
typealias StString = Pair<String, Encoding>
|
typealias StString = Pair<String, Encoding>
|
||||||
|
@ -913,7 +913,31 @@ internal class ExpressionGen(private val codeGen: CodeGen) {
|
|||||||
return code
|
return code
|
||||||
}
|
}
|
||||||
is StRomSub -> {
|
is StRomSub -> {
|
||||||
throw AssemblyError("virtual machine doesn't yet support calling romsub $fcall")
|
val code = IRCodeChunk(fcall.position)
|
||||||
|
for ((arg, parameter) in fcall.args.zip(callTarget.parameters)) {
|
||||||
|
val paramDt = codeGen.vmType(parameter.type)
|
||||||
|
val paramRegStr = if(parameter.register.registerOrPair!=null) parameter.register.registerOrPair.toString() else parameter.register.statusflag.toString()
|
||||||
|
if(codeGen.isZero(arg)) {
|
||||||
|
code += IRCodeInstruction(Opcode.STOREZCPU, paramDt, labelSymbol = paramRegStr)
|
||||||
|
} else {
|
||||||
|
if (paramDt == VmDataType.FLOAT)
|
||||||
|
throw AssemblyError("doesn't support float register argument in asm romsub")
|
||||||
|
val argReg = codeGen.vmRegisters.nextFree()
|
||||||
|
code += translateExpression(arg, argReg, -1)
|
||||||
|
code += IRCodeInstruction(Opcode.STORECPU, paramDt, reg1 = argReg, labelSymbol = paramRegStr)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
code += IRCodeInstruction(Opcode.CALL, value=callTarget.address.toInt())
|
||||||
|
if(!fcall.void) {
|
||||||
|
if(callTarget.returns.size!=1)
|
||||||
|
throw AssemblyError("expect precisely 1 return value")
|
||||||
|
if(fcall.type==DataType.FLOAT)
|
||||||
|
throw AssemblyError("doesn't support float register result in asm romsub")
|
||||||
|
val returns = callTarget.returns.single()
|
||||||
|
val regStr = if(returns.registerOrPair!=null) returns.registerOrPair.toString() else returns.statusflag.toString()
|
||||||
|
code += IRCodeInstruction(Opcode.LOADCPU, codeGen.vmType(fcall.type), reg1=resultRegister, labelSymbol = regStr)
|
||||||
|
}
|
||||||
|
return code
|
||||||
}
|
}
|
||||||
else -> throw AssemblyError("invalid node type")
|
else -> throw AssemblyError("invalid node type")
|
||||||
}
|
}
|
||||||
|
@ -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()
|
||||||
|
@ -230,7 +230,8 @@ class IntermediateAstMaker(val program: Program) {
|
|||||||
val type = srcCall.inferType(program).getOrElse {
|
val type = srcCall.inferType(program).getOrElse {
|
||||||
throw FatalAstException("unknown dt $srcCall")
|
throw FatalAstException("unknown dt $srcCall")
|
||||||
}
|
}
|
||||||
val call = PtFunctionCall(target, type==DataType.UNDEFINED, type, srcCall.position)
|
val isVoid = type==DataType.UNDEFINED
|
||||||
|
val call = PtFunctionCall(target, isVoid, type, srcCall.position)
|
||||||
for (arg in srcCall.args)
|
for (arg in srcCall.args)
|
||||||
call.add(transformExpression(arg))
|
call.add(transformExpression(arg))
|
||||||
return call
|
return call
|
||||||
|
@ -36,12 +36,13 @@ internal class SymbolTableMaker: IAstVisitor {
|
|||||||
}
|
}
|
||||||
|
|
||||||
override fun visit(subroutine: Subroutine) {
|
override fun visit(subroutine: Subroutine) {
|
||||||
val parameters = subroutine.parameters.map { StSubroutineParameter(it.name, it.type) }
|
|
||||||
if(subroutine.asmAddress!=null) {
|
if(subroutine.asmAddress!=null) {
|
||||||
val node = StRomSub(subroutine.name, subroutine.asmAddress!!, parameters, subroutine.returntypes, subroutine.position)
|
val parameters = subroutine.parameters.zip(subroutine.asmParameterRegisters).map { StRomSubParameter(it.second, it.first.type) }
|
||||||
|
val node = StRomSub(subroutine.name, subroutine.asmAddress!!, parameters, subroutine.asmParameterRegisters, subroutine.position)
|
||||||
scopestack.peek().add(node)
|
scopestack.peek().add(node)
|
||||||
// st.origAstLinks[subroutine] = node
|
// st.origAstLinks[subroutine] = node
|
||||||
} else {
|
} else {
|
||||||
|
val parameters = subroutine.parameters.map { StSubroutineParameter(it.name, it.type) }
|
||||||
val returnType = if(subroutine.returntypes.isEmpty()) null else subroutine.returntypes.first()
|
val returnType = if(subroutine.returntypes.isEmpty()) null else subroutine.returntypes.first()
|
||||||
val node = StSub(subroutine.name, parameters, returnType, subroutine.position)
|
val node = StSub(subroutine.name, parameters, returnType, subroutine.position)
|
||||||
scopestack.peek().add(node)
|
scopestack.peek().add(node)
|
||||||
|
@ -3,8 +3,9 @@ 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
|
- 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 support for incbin (!binary)
|
- 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: add proper memory slabs support
|
- IR/VM: add proper memory slabs support
|
||||||
|
|
||||||
...
|
...
|
||||||
@ -21,9 +22,6 @@ Future Things and Ideas
|
|||||||
^^^^^^^^^^^^^^^^^^^^^^^
|
^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
Compiler:
|
Compiler:
|
||||||
- vm: implement remaining sin/cos functions in math.p8 and merge tables
|
- vm: implement remaining sin/cos functions in math.p8 and merge tables
|
||||||
- vm: implement memory mapped variables properly in VariableAllocator
|
|
||||||
- vm: find a solution for the cx16.r0..r15 that "overlap" (r0, r0L, r0H etc) but in the vm each get their own separate variable location now. Maybe this gets solved by the previous item?
|
|
||||||
- vm: encode romsub & romsub call in VM IR (can just crash in virtualmachine itself because program is not in the simulated memory) ExpressionGen.kt
|
|
||||||
- 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: 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
|
- vm: add more optimizations in VmPeepholeOptimizer
|
||||||
|
@ -12,6 +12,9 @@ main {
|
|||||||
return
|
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 {
|
asmsub testasmsub(ubyte arg1 @A) clobbers(Y) -> uword @AX {
|
||||||
%asm {{
|
%asm {{
|
||||||
nop
|
nop
|
||||||
@ -20,6 +23,8 @@ main {
|
|||||||
}
|
}
|
||||||
|
|
||||||
sub start() {
|
sub start() {
|
||||||
|
void myromsubmulti(44)
|
||||||
|
global1 = myromsub(44)
|
||||||
sys.wait(1)
|
sys.wait(1)
|
||||||
|
|
||||||
%asm {{
|
%asm {{
|
||||||
|
@ -240,7 +240,7 @@ class IRFileReader(outputDir: Path, programName: String) {
|
|||||||
|
|
||||||
private val blockPattern = Regex("<BLOCK NAME=(.+) ADDRESS=(.+) ALIGN=(.+) POS=(.+)>")
|
private val blockPattern = Regex("<BLOCK NAME=(.+) ADDRESS=(.+) ALIGN=(.+) POS=(.+)>")
|
||||||
private val inlineAsmPattern = Regex("<INLINEASM POS=(.+)>")
|
private val inlineAsmPattern = Regex("<INLINEASM POS=(.+)>")
|
||||||
private val asmsubPattern = Regex("<ASMSUB NAME=(.+) ADDRESS=(.+) CLOBBERS=(.+) RETURNS=(.+) POS=(.+)>")
|
private val asmsubPattern = Regex("<ASMSUB NAME=(.+) ADDRESS=(.+) CLOBBERS=(.*) RETURNS=(.*) POS=(.+)>")
|
||||||
private val subPattern = Regex("<SUB NAME=(.+) RETURNTYPE=(.+) POS=(.+)>")
|
private val subPattern = Regex("<SUB NAME=(.+) RETURNTYPE=(.+) POS=(.+)>")
|
||||||
private val posPattern = Regex("\\[(.+): line (.+) col (.+)-(.+)\\]")
|
private val posPattern = Regex("\\[(.+): line (.+) col (.+)-(.+)\\]")
|
||||||
private val instructionPattern = Regex("""([a-z]+)(\.b|\.w|\.f)?(.*)""", RegexOption.IGNORE_CASE)
|
private val instructionPattern = Regex("""([a-z]+)(\.b|\.w|\.f)?(.*)""", RegexOption.IGNORE_CASE)
|
||||||
@ -309,7 +309,7 @@ class IRFileReader(outputDir: Path, programName: String) {
|
|||||||
val asm = parseInlineAssembly(line, lines)
|
val asm = parseInlineAssembly(line, lines)
|
||||||
while(line!="</ASMSUB>")
|
while(line!="</ASMSUB>")
|
||||||
line = lines.next()
|
line = lines.next()
|
||||||
val clobberRegs = clobbers.split(',').map { CpuRegister.valueOf(it) }
|
val clobberRegs = if(clobbers.isBlank()) emptyList() else clobbers.split(',').map { CpuRegister.valueOf(it) }
|
||||||
val returns = mutableListOf<Pair<DataType, RegisterOrStatusflag>>()
|
val returns = mutableListOf<Pair<DataType, RegisterOrStatusflag>>()
|
||||||
returnSpec.split(',').forEach{ rs ->
|
returnSpec.split(',').forEach{ rs ->
|
||||||
val (regstr, dtstr) = rs.split(':')
|
val (regstr, dtstr) = rs.split(':')
|
||||||
|
@ -29,12 +29,15 @@ loadi reg1, reg2 - load reg1 with value at memory indirect,
|
|||||||
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
|
||||||
loadix reg1, reg2, pointeraddr - load reg1 with value at memory indirect, pointed to by pointeraddr indexed by value in 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
|
loadr reg1, reg2 - load reg1 with value in register reg2
|
||||||
|
loadcpu reg1, cpureg - load reg1 with value from cpu register (register/registerpair/statusflag)
|
||||||
|
|
||||||
storem reg1, address - store reg1 at memory address
|
storem reg1, address - store reg1 at memory address
|
||||||
|
storecpu reg1, cpureg - store reg1 in cpu register (register/registerpair/statusflag)
|
||||||
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
|
||||||
storex reg1, reg2, address - store reg1 at memory address, indexed by value in reg2
|
storex reg1, reg2, address - store reg1 at memory address, indexed by value in reg2
|
||||||
storeix reg1, reg2, pointeraddr - store reg1 at memory indirect, pointed to by pointeraddr indexed by value in reg2
|
storeix reg1, reg2, pointeraddr - store reg1 at memory indirect, pointed to by pointeraddr indexed by value in reg2
|
||||||
storezm address - store zero at memory address
|
storezm address - store zero at memory address
|
||||||
|
storezcpu cpureg - store zero in cpu register (register/registerpair/statusflag)
|
||||||
storezi reg1 - store zero at memory pointed to by reg1
|
storezi reg1 - store zero at memory pointed to by reg1
|
||||||
storezx reg1, address - store zero at memory address, indexed by value in reg
|
storezx reg1, address - store zero at memory address, indexed by value in reg
|
||||||
|
|
||||||
@ -196,7 +199,7 @@ msig [b, w] reg1, reg2 - reg1 becomes the most significant by
|
|||||||
concat [b, w] reg1, reg2 - reg1 = concatenated lsb/lsw of reg1 (as lsb) and lsb/lsw of reg2 (as msb) into word or int (int not yet implemented; requires 32bits regs)
|
concat [b, w] reg1, reg2 - reg1 = concatenated lsb/lsw of reg1 (as lsb) and lsb/lsw of reg2 (as msb) into word or int (int not yet implemented; requires 32bits regs)
|
||||||
push [b, w] reg1 - push value in reg1 on the stack
|
push [b, w] reg1 - push value in reg1 on the stack
|
||||||
pop [b, w] reg1 - pop value from stack into reg1
|
pop [b, w] reg1 - pop value from stack into reg1
|
||||||
|
binarydata - 'instruction' to hold inlined binary data bytes
|
||||||
*/
|
*/
|
||||||
|
|
||||||
enum class Opcode {
|
enum class Opcode {
|
||||||
@ -207,11 +210,14 @@ enum class Opcode {
|
|||||||
LOADX,
|
LOADX,
|
||||||
LOADIX,
|
LOADIX,
|
||||||
LOADR,
|
LOADR,
|
||||||
|
LOADCPU,
|
||||||
STOREM,
|
STOREM,
|
||||||
|
STORECPU,
|
||||||
STOREI,
|
STOREI,
|
||||||
STOREX,
|
STOREX,
|
||||||
STOREIX,
|
STOREIX,
|
||||||
STOREZM,
|
STOREZM,
|
||||||
|
STOREZCPU,
|
||||||
STOREZI,
|
STOREZI,
|
||||||
STOREZX,
|
STOREZX,
|
||||||
|
|
||||||
@ -338,7 +344,8 @@ enum class Opcode {
|
|||||||
POP,
|
POP,
|
||||||
MSIG,
|
MSIG,
|
||||||
CONCAT,
|
CONCAT,
|
||||||
BREAKPOINT
|
BREAKPOINT,
|
||||||
|
BINARYDATA
|
||||||
}
|
}
|
||||||
|
|
||||||
val OpcodesWithAddress = setOf(
|
val OpcodesWithAddress = setOf(
|
||||||
@ -393,7 +400,8 @@ data class Instruction(
|
|||||||
val fpReg2: Int?=null, // 0-$ffff
|
val fpReg2: Int?=null, // 0-$ffff
|
||||||
val value: Int?=null, // 0-$ffff
|
val value: Int?=null, // 0-$ffff
|
||||||
val fpValue: Float?=null,
|
val fpValue: Float?=null,
|
||||||
val labelSymbol: List<String>?=null // symbolic label name as alternative to value (so only for Branch/jump/call Instructions!)
|
val labelSymbol: List<String>?=null, // symbolic label name as alternative to value (so only for Branch/jump/call Instructions!)
|
||||||
|
val binaryData: ByteArray?=null
|
||||||
) {
|
) {
|
||||||
// reg1 and fpreg1 can be IN/OUT/INOUT (all others are readonly INPUT)
|
// reg1 and fpreg1 can be IN/OUT/INOUT (all others are readonly INPUT)
|
||||||
// This knowledge is useful in IL assembly optimizers to see how registers are used.
|
// This knowledge is useful in IL assembly optimizers to see how registers are used.
|
||||||
@ -401,6 +409,9 @@ data class Instruction(
|
|||||||
val fpReg1direction: OperandDirection
|
val fpReg1direction: OperandDirection
|
||||||
|
|
||||||
init {
|
init {
|
||||||
|
if(opcode==Opcode.BINARYDATA && binaryData==null || binaryData!=null && opcode!=Opcode.BINARYDATA)
|
||||||
|
throw IllegalArgumentException("binarydata inconsistency")
|
||||||
|
|
||||||
val formats = instructionFormats.getValue(opcode)
|
val formats = instructionFormats.getValue(opcode)
|
||||||
if(type==null && !formats.containsKey(null))
|
if(type==null && !formats.containsKey(null))
|
||||||
throw IllegalArgumentException("missing type")
|
throw IllegalArgumentException("missing type")
|
||||||
@ -560,11 +571,14 @@ val instructionFormats = mutableMapOf(
|
|||||||
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.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.LOADCPU to InstructionFormat.from("BW,>r1"),
|
||||||
Opcode.STOREM to InstructionFormat.from("BW,<r1,<v | F,<fr1,<v"),
|
Opcode.STOREM to InstructionFormat.from("BW,<r1,<v | F,<fr1,<v"),
|
||||||
|
Opcode.STORECPU to InstructionFormat.from("BW,<r1"),
|
||||||
Opcode.STOREI to InstructionFormat.from("BW,<r1,<r2 | F,<fr1,<r1"),
|
Opcode.STOREI to InstructionFormat.from("BW,<r1,<r2 | F,<fr1,<r1"),
|
||||||
Opcode.STOREX to InstructionFormat.from("BW,<r1,<r2,<v | F,<fr1,<r1,<v"),
|
Opcode.STOREX to InstructionFormat.from("BW,<r1,<r2,<v | F,<fr1,<r1,<v"),
|
||||||
Opcode.STOREIX to InstructionFormat.from("BW,<r1,<r2,<v | F,<fr1,<r1,<v"),
|
Opcode.STOREIX to InstructionFormat.from("BW,<r1,<r2,<v | F,<fr1,<r1,<v"),
|
||||||
Opcode.STOREZM to InstructionFormat.from("BW,<v | F,<v"),
|
Opcode.STOREZM to InstructionFormat.from("BW,<v | F,<v"),
|
||||||
|
Opcode.STOREZCPU to InstructionFormat.from("BW"),
|
||||||
Opcode.STOREZI to InstructionFormat.from("BW,<r1 | F,<r1"),
|
Opcode.STOREZI to InstructionFormat.from("BW,<r1 | F,<r1"),
|
||||||
Opcode.STOREZX to InstructionFormat.from("BW,<r1,<v | F,<r1,<v"),
|
Opcode.STOREZX to InstructionFormat.from("BW,<r1,<v | F,<r1,<v"),
|
||||||
Opcode.JUMP to InstructionFormat.from("N,<v"),
|
Opcode.JUMP to InstructionFormat.from("N,<v"),
|
||||||
@ -688,4 +702,5 @@ val instructionFormats = mutableMapOf(
|
|||||||
Opcode.CLC to InstructionFormat.from("N"),
|
Opcode.CLC to InstructionFormat.from("N"),
|
||||||
Opcode.SEC to InstructionFormat.from("N"),
|
Opcode.SEC to InstructionFormat.from("N"),
|
||||||
Opcode.BREAKPOINT to InstructionFormat.from("N"),
|
Opcode.BREAKPOINT to InstructionFormat.from("N"),
|
||||||
|
Opcode.BINARYDATA to InstructionFormat.from("N"),
|
||||||
)
|
)
|
||||||
|
@ -76,7 +76,10 @@ class Assembler {
|
|||||||
val binarymatch = binaryPattern.matchEntire(line.trim())
|
val binarymatch = binaryPattern.matchEntire(line.trim())
|
||||||
if(binarymatch!=null) {
|
if(binarymatch!=null) {
|
||||||
val hex = binarymatch.groups[1]!!.value
|
val hex = binarymatch.groups[1]!!.value
|
||||||
TODO("binary ${hex}")
|
val binary = hex.windowed(size=2, step=2).map {
|
||||||
|
it.toString().toByte(16)
|
||||||
|
}.toByteArray()
|
||||||
|
program.add(Instruction(Opcode.BINARYDATA, binaryData = binary))
|
||||||
} else {
|
} else {
|
||||||
val labelmatch = labelPattern.matchEntire(line.trim())
|
val labelmatch = labelPattern.matchEntire(line.trim())
|
||||||
if (labelmatch == null)
|
if (labelmatch == null)
|
||||||
|
@ -217,6 +217,7 @@ class VirtualMachine(val memory: Memory, program: List<Instruction>) {
|
|||||||
Opcode.BREAKPOINT -> InsBREAKPOINT()
|
Opcode.BREAKPOINT -> InsBREAKPOINT()
|
||||||
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.FFROMUB -> InsFFROMUB(ins)
|
Opcode.FFROMUB -> InsFFROMUB(ins)
|
||||||
Opcode.FFROMSB -> InsFFROMSB(ins)
|
Opcode.FFROMSB -> InsFFROMSB(ins)
|
||||||
|
Loading…
Reference in New Issue
Block a user