1
0
mirror of https://github.com/irmen/ksim65.git synced 2024-06-01 21:41:31 +00:00

fixed cycle times, implemented various illegal opcodes. NesTest now runs flawlessly

This commit is contained in:
Irmen de Jong 2020-02-20 02:59:03 +01:00
parent 35cbe4e3ca
commit 5667c00d85
6 changed files with 545 additions and 285 deletions

View File

@ -7,11 +7,10 @@ import razorvine.ksim65.components.UByte
/** /**
* 6502 cpu simulation (the NMOS version) including the 'illegal' opcodes. * 6502 cpu simulation (the NMOS version) including the 'illegal' opcodes.
* TODO: actually implement the illegal opcodes, see http://www.ffd2.com/fridge/docs/6502-NMOS.extra.opcodes or https://sourceforge.net/p/moarnes/code/ci/master/tree/src/6502.c
*/ */
open class Cpu6502 : BusComponent() { open class Cpu6502 : BusComponent() {
open val name = "6502" open val name = "6502"
var tracing: ((state: String) -> Unit)? = null var tracing: ((state: State) -> Unit)? = null
var totalCycles = 0L var totalCycles = 0L
protected set protected set
private var resetTime = System.nanoTime() private var resetTime = System.nanoTime()
@ -165,6 +164,9 @@ open class Cpu6502 : BusComponent() {
*/ */
override fun clock() { override fun clock() {
if (instrCycles == 0) { if (instrCycles == 0) {
tracing?.invoke(snapshot())
if(nmiAsserted || (irqAsserted && !regP.I)) { if(nmiAsserted || (irqAsserted && !regP.I)) {
handleInterrupt() handleInterrupt()
return return
@ -176,8 +178,6 @@ open class Cpu6502 : BusComponent() {
currentOpcode = read(regPC) currentOpcode = read(regPC)
currentInstruction = instructions[currentOpcode] currentInstruction = instructions[currentOpcode]
// tracing and breakpoint handling
tracing?.invoke(snapshot().toString())
breakpoints[regPC]?.let { breakpoints[regPC]?.let {
if (breakpoint(it)) return if (breakpoint(it)) return
} }
@ -557,7 +557,9 @@ open class Cpu6502 : BusComponent() {
val relative = readPc() val relative = readPc()
fetchedAddress = if (relative >= 0x80) { fetchedAddress = if (relative >= 0x80) {
regPC-(256-relative) and 0xffff regPC-(256-relative) and 0xffff
} else regPC+relative and 0xffff } else {
regPC+relative and 0xffff
}
false false
} }
AddrMode.Abs -> { AddrMode.Abs -> {
@ -581,6 +583,7 @@ open class Cpu6502 : BusComponent() {
(fetchedAddress and 0xff00) != hi shl 8 (fetchedAddress and 0xff00) != hi shl 8
} }
AddrMode.Ind -> { AddrMode.Ind -> {
val extraCycle: Boolean
var lo = readPc() var lo = readPc()
var hi = readPc() var hi = readPc()
fetchedAddress = lo or (hi shl 8) fetchedAddress = lo or (hi shl 8)
@ -589,13 +592,15 @@ open class Cpu6502 : BusComponent() {
// not able to fetch an address which crosses the page boundary. // not able to fetch an address which crosses the page boundary.
lo = read(fetchedAddress) lo = read(fetchedAddress)
hi = read(fetchedAddress and 0xff00) hi = read(fetchedAddress and 0xff00)
extraCycle = true
} else { } else {
// normal behavior // normal behavior
lo = read(fetchedAddress) lo = read(fetchedAddress)
hi = read(fetchedAddress+1) hi = read(fetchedAddress+1)
extraCycle = false
} }
fetchedAddress = lo or (hi shl 8) fetchedAddress = lo or (hi shl 8)
false extraCycle
} }
AddrMode.IzX -> { AddrMode.IzX -> {
// note: not able to fetch an address which crosses the (zero)page boundary // note: not able to fetch an address which crosses the (zero)page boundary
@ -603,15 +608,17 @@ open class Cpu6502 : BusComponent() {
val lo = read((fetchedAddress+regX) and 0xff) val lo = read((fetchedAddress+regX) and 0xff)
val hi = read((fetchedAddress+regX+1) and 0xff) val hi = read((fetchedAddress+regX+1) and 0xff)
fetchedAddress = lo or (hi shl 8) fetchedAddress = lo or (hi shl 8)
false // if this address is a different page, extra clock cycle:
(fetchedAddress and 0xff00) != hi shl 8
} }
AddrMode.IzY -> { AddrMode.IzY -> {
// note: not able to fetch an address which crosses the (zero)page boundary // note: not able to fetch an address which crosses the (zero)page boundary
fetchedAddress = readPc() val fetchedAddress1 = readPc()
val lo = read(fetchedAddress) val lo = read(fetchedAddress1)
val hi = read((fetchedAddress+1) and 0xff) val hi = read((fetchedAddress1+1) and 0xff)
fetchedAddress = regY+(lo or (hi shl 8)) and 0xffff fetchedAddress = regY+(lo or (hi shl 8)) and 0xffff
false // if this address is a different page, extra clock cycle:
(fetchedAddress and 0xff00) != hi shl 8
} }
AddrMode.Zpr, AddrMode.Izp, AddrMode.IaX -> { AddrMode.Zpr, AddrMode.Izp, AddrMode.IaX -> {
// addressing mode used by the 65C02 only // addressing mode used by the 65C02 only
@ -621,7 +628,7 @@ open class Cpu6502 : BusComponent() {
} }
protected open fun dispatchOpcode(opcode: Int): Boolean { protected open fun dispatchOpcode(opcode: Int): Boolean {
when (opcode) { return when (opcode) {
0x00 -> iBrk() 0x00 -> iBrk()
0x01 -> iOra() 0x01 -> iOra()
0x02 -> iInvalid() 0x02 -> iInvalid()
@ -878,15 +885,14 @@ open class Cpu6502 : BusComponent() {
0xfd -> iSbc() 0xfd -> iSbc()
0xfe -> iInc() 0xfe -> iInc()
0xff -> iIsc() 0xff -> iIsc()
else -> { /* can't occur */ } else -> false /* can't occur */
} }
return false // TODO determine if instructions can cause extra clock cycle
} }
// official instructions // official instructions
protected open fun iAdc() { protected open fun iAdc(): Boolean {
val operand = getFetched() val operand = getFetched()
if (regP.D) { if (regP.D) {
// BCD add // BCD add
@ -916,15 +922,18 @@ open class Cpu6502 : BusComponent() {
regP.C = tmp > 0xff regP.C = tmp > 0xff
regA = tmp and 0xff regA = tmp and 0xff
} }
return true
} }
protected fun iAnd() { protected fun iAnd(): Boolean {
regA = regA and getFetched() regA = regA and getFetched()
regP.Z = regA == 0 regP.Z = regA == 0
regP.N = (regA and 0b10000000) != 0 regP.N = (regA and 0b10000000) != 0
return true
} }
protected fun iAsl() { protected fun iAsl(): Boolean {
if (currentInstruction.mode == AddrMode.Acc) { if (currentInstruction.mode == AddrMode.Acc) {
regP.C = (regA and 0b10000000) != 0 regP.C = (regA and 0b10000000) != 0
regA = (regA shl 1) and 0xff regA = (regA shl 1) and 0xff
@ -938,44 +947,82 @@ open class Cpu6502 : BusComponent() {
regP.Z = shifted == 0 regP.Z = shifted == 0
regP.N = (shifted and 0b10000000) != 0 regP.N = (shifted and 0b10000000) != 0
} }
return false
} }
protected fun iBcc() { protected fun iBcc(): Boolean {
if (!regP.C) regPC = fetchedAddress if (!regP.C) {
if(fetchedAddress and 0xff00 != regPC and 0xff00)
instrCycles++
regPC = fetchedAddress
instrCycles++
}
return false
} }
protected fun iBcs() { protected fun iBcs(): Boolean {
if (regP.C) regPC = fetchedAddress if (regP.C) {
if(fetchedAddress and 0xff00 != regPC and 0xff00)
instrCycles++
regPC = fetchedAddress
instrCycles++
}
return false
} }
protected fun iBeq() { protected fun iBeq(): Boolean {
if (regP.Z) regPC = fetchedAddress if (regP.Z) {
if(fetchedAddress and 0xff00 != regPC and 0xff00)
instrCycles++
regPC = fetchedAddress
instrCycles++
}
return false
} }
protected open fun iBit() { protected open fun iBit(): Boolean {
val operand = getFetched() val operand = getFetched()
regP.Z = (regA and operand) == 0 regP.Z = (regA and operand) == 0
regP.V = (operand and 0b01000000) != 0 regP.V = (operand and 0b01000000) != 0
regP.N = (operand and 0b10000000) != 0 regP.N = (operand and 0b10000000) != 0
return false
} }
protected fun iBmi() { protected fun iBmi(): Boolean {
if (regP.N) regPC = fetchedAddress if (regP.N) {
if(fetchedAddress and 0xff00 != regPC and 0xff00)
instrCycles++
regPC = fetchedAddress
instrCycles++
}
return false
} }
protected fun iBne() { protected fun iBne(): Boolean {
if (!regP.Z) regPC = fetchedAddress if (!regP.Z) {
if(fetchedAddress and 0xff00 != regPC and 0xff00)
instrCycles++
regPC = fetchedAddress
instrCycles++
}
return false
} }
protected fun iBpl() { protected fun iBpl(): Boolean {
if (!regP.N) regPC = fetchedAddress if (!regP.N) {
if(fetchedAddress and 0xff00 != regPC and 0xff00)
instrCycles++
regPC = fetchedAddress
instrCycles++
}
return false
} }
protected open fun iBrk() { protected open fun iBrk(): Boolean {
// handle BRK ('software interrupt') // handle BRK ('software interrupt')
regPC++ regPC++
if(nmiAsserted) if(nmiAsserted)
return // if an NMI occurs during BRK, the BRK won't get executed on 6502 (65C02 fixes this) return false // if an NMI occurs during BRK, the BRK won't get executed on 6502 (65C02 fixes this)
pushStackAddr(regPC) pushStackAddr(regPC)
regP.B = true regP.B = true
pushStack(regP) pushStack(regP)
@ -984,6 +1031,7 @@ open class Cpu6502 : BusComponent() {
regPC = readWord(IRQ_vector) regPC = readWord(IRQ_vector)
// TODO prevent NMI from triggering immediately after IRQ/BRK... how does that work exactly? // TODO prevent NMI from triggering immediately after IRQ/BRK... how does that work exactly?
return false
} }
protected open fun handleInterrupt() { protected open fun handleInterrupt() {
@ -1008,123 +1056,154 @@ open class Cpu6502 : BusComponent() {
// TODO prevent NMI from triggering immediately after IRQ/BRK... how does that work exactly? // TODO prevent NMI from triggering immediately after IRQ/BRK... how does that work exactly?
} }
protected fun iBvc() { protected fun iBvc(): Boolean {
if (!regP.V) regPC = fetchedAddress if (!regP.V) {
if(fetchedAddress and 0xff00 != regPC and 0xff00)
instrCycles++
regPC = fetchedAddress
instrCycles++
}
return false
} }
protected fun iBvs() { protected fun iBvs(): Boolean {
if (regP.V) regPC = fetchedAddress if (regP.V) {
if(fetchedAddress and 0xff00 != regPC and 0xff00)
instrCycles++
regPC = fetchedAddress
instrCycles++
}
return false
} }
protected fun iClc() { protected fun iClc(): Boolean {
regP.C = false regP.C = false
return false
} }
protected fun iCld() { protected fun iCld(): Boolean {
regP.D = false regP.D = false
return false
} }
protected fun iCli() { protected fun iCli(): Boolean {
regP.I = false regP.I = false
return false
} }
protected fun iClv() { protected fun iClv(): Boolean {
regP.V = false regP.V = false
return false
} }
protected fun iCmp() { protected fun iCmp(operandOverride: Int? = null): Boolean {
val fetched = getFetched() val fetched = operandOverride ?: getFetched()
regP.C = regA >= fetched regP.C = regA >= fetched
regP.Z = regA == fetched regP.Z = regA == fetched
regP.N = ((regA-fetched) and 0b10000000) != 0 regP.N = ((regA-fetched) and 0b10000000) != 0
return true
} }
protected fun iCpx() { protected fun iCpx(): Boolean {
val fetched = getFetched() val fetched = getFetched()
regP.C = regX >= fetched regP.C = regX >= fetched
regP.Z = regX == fetched regP.Z = regX == fetched
regP.N = ((regX-fetched) and 0b10000000) != 0 regP.N = ((regX-fetched) and 0b10000000) != 0
return false
} }
protected fun iCpy() { protected fun iCpy(): Boolean {
val fetched = getFetched() val fetched = getFetched()
regP.C = regY >= fetched regP.C = regY >= fetched
regP.Z = regY == fetched regP.Z = regY == fetched
regP.N = ((regY-fetched) and 0b10000000) != 0 regP.N = ((regY-fetched) and 0b10000000) != 0
return false
} }
protected open fun iDec() { protected open fun iDec(): Boolean {
val data = (read(fetchedAddress)-1) and 0xff val data = (read(fetchedAddress)-1) and 0xff
write(fetchedAddress, data) write(fetchedAddress, data)
regP.Z = data == 0 regP.Z = data == 0
regP.N = (data and 0b10000000) != 0 regP.N = (data and 0b10000000) != 0
return false
} }
protected fun iDex() { protected fun iDex(): Boolean {
regX = (regX-1) and 0xff regX = (regX-1) and 0xff
regP.Z = regX == 0 regP.Z = regX == 0
regP.N = (regX and 0b10000000) != 0 regP.N = (regX and 0b10000000) != 0
return false
} }
protected fun iDey() { protected fun iDey(): Boolean {
regY = (regY-1) and 0xff regY = (regY-1) and 0xff
regP.Z = regY == 0 regP.Z = regY == 0
regP.N = (regY and 0b10000000) != 0 regP.N = (regY and 0b10000000) != 0
return false
} }
protected fun iEor() { protected fun iEor(): Boolean {
regA = regA xor getFetched() regA = regA xor getFetched()
regP.Z = regA == 0 regP.Z = regA == 0
regP.N = (regA and 0b10000000) != 0 regP.N = (regA and 0b10000000) != 0
return true
} }
protected open fun iInc() { protected open fun iInc(): Boolean {
val data = (read(fetchedAddress)+1) and 0xff val data = (read(fetchedAddress)+1) and 0xff
write(fetchedAddress, data) write(fetchedAddress, data)
regP.Z = data == 0 regP.Z = data == 0
regP.N = (data and 0b10000000) != 0 regP.N = (data and 0b10000000) != 0
return false
} }
protected fun iInx() { protected fun iInx(): Boolean {
regX = (regX+1) and 0xff regX = (regX+1) and 0xff
regP.Z = regX == 0 regP.Z = regX == 0
regP.N = (regX and 0b10000000) != 0 regP.N = (regX and 0b10000000) != 0
return false
} }
protected fun iIny() { protected fun iIny(): Boolean {
regY = (regY+1) and 0xff regY = (regY+1) and 0xff
regP.Z = regY == 0 regP.Z = regY == 0
regP.N = (regY and 0b10000000) != 0 regP.N = (regY and 0b10000000) != 0
return false
} }
protected fun iJmp() { protected fun iJmp(): Boolean {
regPC = fetchedAddress regPC = fetchedAddress
return false
} }
protected fun iJsr() { protected fun iJsr(): Boolean {
pushStackAddr(regPC-1) pushStackAddr(regPC-1)
regPC = fetchedAddress regPC = fetchedAddress
return false
} }
protected fun iLda() { protected fun iLda(): Boolean {
regA = getFetched() regA = getFetched()
regP.Z = regA == 0 regP.Z = regA == 0
regP.N = (regA and 0b10000000) != 0 regP.N = (regA and 0b10000000) != 0
return true
} }
protected fun iLdx() { protected fun iLdx(): Boolean {
regX = getFetched() regX = getFetched()
regP.Z = regX == 0 regP.Z = regX == 0
regP.N = (regX and 0b10000000) != 0 regP.N = (regX and 0b10000000) != 0
return true
} }
protected fun iLdy() { protected fun iLdy(): Boolean {
regY = getFetched() regY = getFetched()
regP.Z = regY == 0 regP.Z = regY == 0
regP.N = (regY and 0b10000000) != 0 regP.N = (regY and 0b10000000) != 0
return true
} }
protected fun iLsr() { protected fun iLsr(): Boolean {
if (currentInstruction.mode == AddrMode.Acc) { if (currentInstruction.mode == AddrMode.Acc) {
regP.C = (regA and 1) == 1 regP.C = (regA and 1) == 1
regA = regA ushr 1 regA = regA ushr 1
@ -1138,39 +1217,47 @@ open class Cpu6502 : BusComponent() {
regP.Z = shifted == 0 regP.Z = shifted == 0
regP.N = (shifted and 0b10000000) != 0 regP.N = (shifted and 0b10000000) != 0
} }
return false
} }
protected fun iNop() {} protected fun iNop(): Boolean {
return currentOpcode in listOf(0x1c, 0x3c, 0x5c, 0x7c, 0xdc, 0xfc)
}
protected fun iOra() { protected fun iOra(): Boolean {
regA = regA or getFetched() regA = regA or getFetched()
regP.Z = regA == 0 regP.Z = regA == 0
regP.N = (regA and 0b10000000) != 0 regP.N = (regA and 0b10000000) != 0
return true
} }
protected fun iPha() { protected fun iPha(): Boolean {
pushStack(regA) pushStack(regA)
return false
} }
protected fun iPhp() { protected fun iPhp(): Boolean {
val origBreakflag = regP.B val origBreakflag = regP.B
regP.B = true regP.B = true
pushStack(regP) pushStack(regP)
regP.B = origBreakflag regP.B = origBreakflag
return false
} }
protected fun iPla() { protected fun iPla(): Boolean {
regA = popStack() regA = popStack()
regP.Z = regA == 0 regP.Z = regA == 0
regP.N = (regA and 0b10000000) != 0 regP.N = (regA and 0b10000000) != 0
return false
} }
protected fun iPlp() { protected fun iPlp(): Boolean {
regP.fromInt(popStack()) regP.fromInt(popStack())
regP.B = true // break is always 1 except when pushing on stack regP.B = false
return false
} }
protected fun iRol() { protected fun iRol(): Boolean {
val oldCarry = regP.C val oldCarry = regP.C
if (currentInstruction.mode == AddrMode.Acc) { if (currentInstruction.mode == AddrMode.Acc) {
regP.C = (regA and 0b10000000) != 0 regP.C = (regA and 0b10000000) != 0
@ -1185,9 +1272,10 @@ open class Cpu6502 : BusComponent() {
regP.Z = shifted == 0 regP.Z = shifted == 0
regP.N = (shifted and 0b10000000) != 0 regP.N = (shifted and 0b10000000) != 0
} }
return false
} }
protected fun iRor() { protected fun iRor(): Boolean {
val oldCarry = regP.C val oldCarry = regP.C
if (currentInstruction.mode == AddrMode.Acc) { if (currentInstruction.mode == AddrMode.Acc) {
regP.C = (regA and 1) == 1 regP.C = (regA and 1) == 1
@ -1202,21 +1290,24 @@ open class Cpu6502 : BusComponent() {
regP.Z = shifted == 0 regP.Z = shifted == 0
regP.N = (shifted and 0b10000000) != 0 regP.N = (shifted and 0b10000000) != 0
} }
return false
} }
protected fun iRti() { protected fun iRti(): Boolean {
regP.fromInt(popStack()) regP.fromInt(popStack())
regP.B = true // break is always 1 except when pushing on stack regP.B = false
regPC = popStackAddr() regPC = popStackAddr()
return false
} }
protected fun iRts() { protected fun iRts(): Boolean {
regPC = popStackAddr() regPC = popStackAddr()
regPC = (regPC+1) and 0xffff regPC = (regPC+1) and 0xffff
return false
} }
protected open fun iSbc() { protected open fun iSbc(operandOverride: Int? = null): Boolean {
val operand = getFetched() val operand = operandOverride ?: getFetched()
val tmp = (regA-operand-if (regP.C) 0 else 1) and 0xffff val tmp = (regA-operand-if (regP.C) 0 else 1) and 0xffff
regP.V = (regA xor operand) and (regA xor tmp) and 0b10000000 != 0 regP.V = (regA xor operand) and (regA xor tmp) and 0b10000000 != 0
if (regP.D) { if (regP.D) {
@ -1240,142 +1331,205 @@ open class Cpu6502 : BusComponent() {
regP.C = tmp < 0x100 regP.C = tmp < 0x100
regP.Z = (tmp and 0xff) == 0 regP.Z = (tmp and 0xff) == 0
regP.N = (tmp and 0b10000000) != 0 regP.N = (tmp and 0b10000000) != 0
return true
} }
protected fun iSec() { protected fun iSec(): Boolean {
regP.C = true regP.C = true
return false
} }
protected fun iSed() { protected fun iSed(): Boolean {
regP.D = true regP.D = true
return false
} }
protected fun iSei() { protected fun iSei(): Boolean {
regP.I = true regP.I = true
return false
} }
protected fun iSta() { protected fun iSta(): Boolean {
write(fetchedAddress, regA) write(fetchedAddress, regA)
return false
} }
protected fun iStx() { protected fun iStx(): Boolean {
write(fetchedAddress, regX) write(fetchedAddress, regX)
return false
} }
protected fun iSty() { protected fun iSty(): Boolean {
write(fetchedAddress, regY) write(fetchedAddress, regY)
return false
} }
protected fun iTax() { protected fun iTax(): Boolean {
regX = regA regX = regA
regP.Z = regX == 0 regP.Z = regX == 0
regP.N = (regX and 0b10000000) != 0 regP.N = (regX and 0b10000000) != 0
return false
} }
protected fun iTay() { protected fun iTay(): Boolean {
regY = regA regY = regA
regP.Z = regY == 0 regP.Z = regY == 0
regP.N = (regY and 0b10000000) != 0 regP.N = (regY and 0b10000000) != 0
return false
} }
protected fun iTsx() { protected fun iTsx(): Boolean {
regX = regSP regX = regSP
regP.Z = regX == 0 regP.Z = regX == 0
regP.N = (regX and 0b10000000) != 0 regP.N = (regX and 0b10000000) != 0
return false
} }
protected fun iTxa() { protected fun iTxa(): Boolean {
regA = regX regA = regX
regP.Z = regA == 0 regP.Z = regA == 0
regP.N = (regA and 0b10000000) != 0 regP.N = (regA and 0b10000000) != 0
return false
} }
protected fun iTxs() { protected fun iTxs(): Boolean {
regSP = regX regSP = regX
return false
} }
protected fun iTya() { protected fun iTya(): Boolean {
regA = regY regA = regY
regP.Z = regA == 0 regP.Z = regA == 0
regP.N = (regA and 0b10000000) != 0 regP.N = (regA and 0b10000000) != 0
return false
} }
// unofficial/illegal 6502 instructions // unofficial/illegal 6502 instructions
// see http://www.ffd2.com/fridge/docs/6502-NMOS.extra.opcodes
// or https://github.com/quietust/nintendulator/blob/master/src/CPU.cpp (search for LogBadOps)
// TODO: actually implement the illegal opcodes
private fun iAhx() {
TODO("\$${hexB(currentOpcode)} - ahx - ('illegal' instruction) @ \$${hexW(currentOpcodeAddress)}") private fun iAhx(): Boolean {
val addrHi = 0xff // TODO get the correct byte from the instruction (=last byte read)
val value = regA and regX and (addrHi+1)
write(fetchedAddress, value)
return false
} }
private fun iAlr() { private fun iAlr(): Boolean {
TODO("\$${hexB(currentOpcode)} - alr=asr - ('illegal' instruction) @ \$${hexW(currentOpcodeAddress)}") iAnd()
iLsr()
return false
} }
private fun iAnc() { private fun iAnc(): Boolean {
TODO("\$${hexB(currentOpcode)} - anc - ('illegal' instruction) @ \$${hexW(currentOpcodeAddress)}") iAnd()
regP.C = regP.N
return false
} }
private fun iArr() { private fun iArr(): Boolean {
TODO("\$${hexB(currentOpcode)} - arr - ('illegal' instruction) @ \$${hexW(currentOpcodeAddress)}") iAnd()
iRor()
return false
} }
private fun iAxs() { private fun iAxs(): Boolean {
TODO("\$${hexB(currentOpcode)} - axs - ('illegal' instruction) @ \$${hexW(currentOpcodeAddress)}") val oldA = regA
regA = regA and regX
regP.C = false
iSbc()
regX = regA
regA = oldA
return false
} }
private fun iDcp() { private fun iDcp(): Boolean {
TODO("\$${hexB(currentOpcode)} - dcp - ('illegal' instruction) @ \$${hexW(currentOpcodeAddress)}") val data = (read(fetchedAddress)-1) and 0xff
write(fetchedAddress, data)
iCmp(data)
return false
} }
private fun iIsc() { private fun iIsc(): Boolean {
TODO("\$${hexB(currentOpcode)} - isc=isb - ('illegal' instruction) @ \$${hexW(currentOpcodeAddress)}") val data = (read(fetchedAddress)+1) and 0xff
write(fetchedAddress, data)
iSbc(data)
return false
} }
private fun iLas() { private fun iLas(): Boolean {
TODO("\$${hexB(currentOpcode)} - las=lar - ('illegal' instruction) @ \$${hexW(currentOpcodeAddress)}") regA = regSP and getFetched()
regX = regA
regSP = regA
regP.Z = regA == 0
regP.N = (regA and 0b10000000) != 0
return false
} }
private fun iLax() { private fun iLax(): Boolean {
TODO("\$${hexB(currentOpcode)} - lax - ('illegal' instruction) @ \$${hexW(currentOpcodeAddress)}") iLda()
regX = regA
return true
} }
private fun iRla() { private fun iRla(): Boolean {
TODO("\$${hexB(currentOpcode)} - rla - ('illegal' instruction) @ \$${hexW(currentOpcodeAddress)}") iRol()
iAnd()
return false
} }
private fun iRra() { private fun iRra(): Boolean {
TODO("\$${hexB(currentOpcode)} - rra - ('illegal' instruction) @ \$${hexW(currentOpcodeAddress)}") iRor()
iAdc()
return false
} }
private fun iSax() { private fun iSax(): Boolean {
TODO("\$${hexB(currentOpcode)} - sax - ('illegal' instruction) @ \$${hexW(currentOpcodeAddress)}") write(fetchedAddress, regA and regX)
return false
} }
private fun iShx() { private fun iShx(): Boolean {
TODO("\$${hexB(currentOpcode)} - shx - ('illegal' instruction) @ \$${hexW(currentOpcodeAddress)}") val addrHi = 0xff // TODO get the correct byte from the instruction (=last byte read)
write(fetchedAddress, regX and (addrHi+1))
return false
} }
private fun iShy() { private fun iShy(): Boolean {
TODO("\$${hexB(currentOpcode)} - shy - ('illegal' instruction) @ \$${hexW(currentOpcodeAddress)}") val addrHi = 0xff // TODO get the correct byte from the instruction (=last byte read)
write(fetchedAddress, regY and (addrHi+1))
return false
} }
private fun iSlo() { private fun iSlo(): Boolean {
TODO("\$${hexB(currentOpcode)} - slo=aso - ('illegal' instruction) @ \$${hexW(currentOpcodeAddress)}") iAsl()
iOra()
return false
} }
private fun iSre() { private fun iSre(): Boolean {
TODO("\$${hexB(currentOpcode)} - sre=lse - ('illegal' instruction) @ \$${hexW(currentOpcodeAddress)}") iLsr()
iEor()
return false
} }
private fun iTas() { private fun iTas(): Boolean {
TODO("\$${hexB(currentOpcode)} - tas - ('illegal' instruction) @ \$${hexW(currentOpcodeAddress)}") regSP = regA and regX
val addrHi = 0xff // TODO get the correct byte from the instruction (=last byte read)
write(fetchedAddress, regSP and addrHi)
return false
} }
private fun iXaa() { private fun iXaa(): Boolean {
TODO("\$${hexB(currentOpcode)} - xaa - ('illegal' instruction) @ \$${hexW(currentOpcodeAddress)}") regA = (regX and fetchedData)
return false
} }
// invalid instruction (JAM / KIL / HLT) // invalid instruction (JAM / KIL / HLT)
private fun iInvalid() { private fun iInvalid(): Boolean {
throw InstructionError("invalid instruction encountered: opcode=${hexB(currentOpcode)} instr=${currentInstruction.mnemonic} @ ${hexW(currentOpcodeAddress)}") throw InstructionError("invalid instruction encountered: opcode=${hexB(currentOpcode)} instr=${currentInstruction.mnemonic} @ ${hexW(currentOpcodeAddress)}")
} }
} }

View File

@ -103,7 +103,7 @@ class Cpu65C02 : Cpu6502() {
} }
override fun dispatchOpcode(opcode: Int): Boolean { override fun dispatchOpcode(opcode: Int): Boolean {
when (opcode) { return when (opcode) {
0x00 -> iBrk() 0x00 -> iBrk()
0x01 -> iOra() 0x01 -> iOra()
0x02 -> iNop() 0x02 -> iNop()
@ -360,9 +360,8 @@ class Cpu65C02 : Cpu6502() {
0xfd -> iSbc() 0xfd -> iSbc()
0xfe -> iInc() 0xfe -> iInc()
0xff -> iBbs7() 0xff -> iBbs7()
else -> { /* can't occur */ } else -> false /* can't occur */
} }
return false // TODO determine if instructions can cause extra clock cycle
} }
// opcode list: http://www.oxyron.de/html/opcodesc02.html // opcode list: http://www.oxyron.de/html/opcodesc02.html
@ -624,7 +623,7 @@ class Cpu65C02 : Cpu6502() {
/* fe */ Instruction("inc", AddrMode.AbsX, 7), /* fe */ Instruction("inc", AddrMode.AbsX, 7),
/* ff */ Instruction("bbs7", AddrMode.Zpr, 5)).toTypedArray() /* ff */ Instruction("bbs7", AddrMode.Zpr, 5)).toTypedArray()
override fun iBrk() { override fun iBrk(): Boolean {
// handle BRK ('software interrupt') // handle BRK ('software interrupt')
regPC++ regPC++
pushStackAddr(regPC) pushStackAddr(regPC)
@ -635,6 +634,7 @@ class Cpu65C02 : Cpu6502() {
regPC = readWord(IRQ_vector) regPC = readWord(IRQ_vector)
// TODO prevent NMI from triggering immediately after IRQ/BRK... how does that work exactly? // TODO prevent NMI from triggering immediately after IRQ/BRK... how does that work exactly?
return false
} }
override fun handleInterrupt() { override fun handleInterrupt() {
@ -642,16 +642,17 @@ class Cpu65C02 : Cpu6502() {
regP.D = false // this is different from NMOS 6502 regP.D = false // this is different from NMOS 6502
} }
override fun iBit() { override fun iBit(): Boolean {
val data = getFetched() val data = getFetched()
regP.Z = (regA and data) == 0 regP.Z = (regA and data) == 0
if (currentInstruction.mode != AddrMode.Imm) { if (currentInstruction.mode != AddrMode.Imm) {
regP.V = (data and 0b01000000) != 0 regP.V = (data and 0b01000000) != 0
regP.N = (data and 0b10000000) != 0 regP.N = (data and 0b10000000) != 0
} }
return false
} }
override fun iAdc() { override fun iAdc(): Boolean {
val value = getFetched() val value = getFetched()
if (regP.D) { if (regP.D) {
// BCD add // BCD add
@ -680,13 +681,14 @@ class Cpu65C02 : Cpu6502() {
regP.C = tmp > 0xff regP.C = tmp > 0xff
regA = tmp and 0xff regA = tmp and 0xff
} }
return false
} }
override fun iSbc() { override fun iSbc(operandOverride: Int?): Boolean {
// see http://www.6502.org/tutorials/decimal_mode.html // see http://www.6502.org/tutorials/decimal_mode.html
// and https://sourceforge.net/p/vice-emu/code/HEAD/tree/trunk/vice/src/65c02core.c#l1205 // and https://sourceforge.net/p/vice-emu/code/HEAD/tree/trunk/vice/src/65c02core.c#l1205
// (the implementation below is based on the code used by Vice) // (the implementation below is based on the code used by Vice)
val value = getFetched() val value = operandOverride ?: getFetched()
var tmp = (regA-value-if (regP.C) 0 else 1) and 0xffff var tmp = (regA-value-if (regP.C) 0 else 1) and 0xffff
regP.V = (regA xor tmp) and (regA xor value) and 0b10000000 != 0 regP.V = (regA xor tmp) and (regA xor value) and 0b10000000 != 0
if (regP.D) { if (regP.D) {
@ -698,230 +700,323 @@ class Cpu65C02 : Cpu6502() {
regP.Z = (tmp and 0xff) == 0 regP.Z = (tmp and 0xff) == 0
regP.N = (tmp and 0b10000000) != 0 regP.N = (tmp and 0b10000000) != 0
regA = tmp and 0xff regA = tmp and 0xff
return false
} }
override fun iDec() { override fun iDec(): Boolean {
if (currentInstruction.mode == AddrMode.Acc) { return if (currentInstruction.mode == AddrMode.Acc) {
regA = (regA-1) and 0xff regA = (regA-1) and 0xff
regP.Z = regA == 0 regP.Z = regA == 0
regP.N = (regA and 0b10000000) != 0 regP.N = (regA and 0b10000000) != 0
false
} else super.iDec() } else super.iDec()
} }
override fun iInc() { override fun iInc(): Boolean {
if (currentInstruction.mode == AddrMode.Acc) { return if (currentInstruction.mode == AddrMode.Acc) {
regA = (regA+1) and 0xff regA = (regA+1) and 0xff
regP.Z = regA == 0 regP.Z = regA == 0
regP.N = (regA and 0b10000000) != 0 regP.N = (regA and 0b10000000) != 0
false
} else super.iInc() } else super.iInc()
} }
private fun iBra() { private fun iBra(): Boolean {
// unconditional branch // unconditional branch
regPC = fetchedAddress regPC = fetchedAddress
return false
} }
private fun iTrb() { private fun iTrb(): Boolean {
val data = getFetched() val data = getFetched()
regP.Z = data and regA == 0 regP.Z = data and regA == 0
write(fetchedAddress, data and regA.inv()) write(fetchedAddress, data and regA.inv())
return false
} }
private fun iTsb() { private fun iTsb(): Boolean {
val data = getFetched() val data = getFetched()
regP.Z = data and regA == 0 regP.Z = data and regA == 0
write(fetchedAddress, data or regA) write(fetchedAddress, data or regA)
return false
} }
private fun iStz() { private fun iStz(): Boolean {
write(fetchedAddress, 0) write(fetchedAddress, 0)
return false
} }
private fun iWai() { private fun iWai(): Boolean {
waiting = Wait.Waiting waiting = Wait.Waiting
return false
} }
private fun iStp() { private fun iStp(): Boolean {
waiting = Wait.Stopped waiting = Wait.Stopped
return false
} }
private fun iPhx() { private fun iPhx(): Boolean {
pushStack(regX) pushStack(regX)
return false
} }
private fun iPlx() { private fun iPlx(): Boolean {
regX = popStack() regX = popStack()
regP.Z = regX == 0 regP.Z = regX == 0
regP.N = (regX and 0b10000000) != 0 regP.N = (regX and 0b10000000) != 0
return false
} }
private fun iPhy() { private fun iPhy(): Boolean {
pushStack(regY) pushStack(regY)
return false
} }
private fun iPly() { private fun iPly(): Boolean {
regY = popStack() regY = popStack()
regP.Z = regY == 0 regP.Z = regY == 0
regP.N = (regY and 0b10000000) != 0 regP.N = (regY and 0b10000000) != 0
return false
} }
private fun iBbr0() { private fun iBbr0(): Boolean {
val data = getFetched() val data = getFetched()
if (data and 1 == 0) regPC = fetchedAddressZpr if (data and 1 == 0) {
regPC = fetchedAddressZpr
instrCycles++
}
return false
} }
private fun iBbr1() { private fun iBbr1(): Boolean {
val data = getFetched() val data = getFetched()
if (data and 2 == 0) regPC = fetchedAddressZpr if (data and 2 == 0) {
regPC = fetchedAddressZpr
instrCycles++
}
return false
} }
private fun iBbr2() { private fun iBbr2(): Boolean {
val data = getFetched() val data = getFetched()
if (data and 4 == 0) regPC = fetchedAddressZpr if (data and 4 == 0) {
regPC = fetchedAddressZpr
instrCycles++
}
return false
} }
private fun iBbr3() { private fun iBbr3(): Boolean {
val data = getFetched() val data = getFetched()
if (data and 8 == 0) regPC = fetchedAddressZpr if (data and 8 == 0) {
regPC = fetchedAddressZpr
instrCycles++
}
return false
} }
private fun iBbr4() { private fun iBbr4(): Boolean {
val data = getFetched() val data = getFetched()
if (data and 16 == 0) regPC = fetchedAddressZpr if (data and 16 == 0) {
regPC = fetchedAddressZpr
instrCycles++
}
return false
} }
private fun iBbr5() { private fun iBbr5(): Boolean {
val data = getFetched() val data = getFetched()
if (data and 32 == 0) regPC = fetchedAddressZpr if (data and 32 == 0) {
regPC = fetchedAddressZpr
instrCycles++
}
return false
} }
private fun iBbr6() { private fun iBbr6(): Boolean {
val data = getFetched() val data = getFetched()
if (data and 64 == 0) regPC = fetchedAddressZpr if (data and 64 == 0) {
regPC = fetchedAddressZpr
instrCycles++
}
return false
} }
private fun iBbr7() { private fun iBbr7(): Boolean {
val data = getFetched() val data = getFetched()
if (data and 128 == 0) regPC = fetchedAddressZpr if (data and 128 == 0) {
regPC = fetchedAddressZpr
instrCycles++
}
return false
} }
private fun iBbs0() { private fun iBbs0(): Boolean {
val data = getFetched() val data = getFetched()
if (data and 1 != 0) regPC = fetchedAddressZpr if (data and 1 != 0) {
regPC = fetchedAddressZpr
instrCycles++
}
return false
} }
private fun iBbs1() { private fun iBbs1(): Boolean {
val data = getFetched() val data = getFetched()
if (data and 2 != 0) regPC = fetchedAddressZpr if (data and 2 != 0) {
regPC = fetchedAddressZpr
instrCycles++
}
return false
} }
private fun iBbs2() { private fun iBbs2(): Boolean {
val data = getFetched() val data = getFetched()
if (data and 4 != 0) regPC = fetchedAddressZpr if (data and 4 != 0) {
regPC = fetchedAddressZpr
instrCycles++
}
return false
} }
private fun iBbs3() { private fun iBbs3(): Boolean {
val data = getFetched() val data = getFetched()
if (data and 8 != 0) regPC = fetchedAddressZpr if (data and 8 != 0) {
regPC = fetchedAddressZpr
instrCycles++
}
return false
} }
private fun iBbs4() { private fun iBbs4(): Boolean {
val data = getFetched() val data = getFetched()
if (data and 16 != 0) regPC = fetchedAddressZpr if (data and 16 != 0) {
regPC = fetchedAddressZpr
instrCycles++
}
return false
} }
private fun iBbs5() { private fun iBbs5(): Boolean {
val data = getFetched() val data = getFetched()
if (data and 32 != 0) regPC = fetchedAddressZpr if (data and 32 != 0) {
regPC = fetchedAddressZpr
instrCycles++
}
return false
} }
private fun iBbs6() { private fun iBbs6(): Boolean {
val data = getFetched() val data = getFetched()
if (data and 64 != 0) regPC = fetchedAddressZpr if (data and 64 != 0) {
regPC = fetchedAddressZpr
instrCycles++
}
return false
} }
private fun iBbs7() { private fun iBbs7(): Boolean {
val data = getFetched() val data = getFetched()
if (data and 128 != 0) regPC = fetchedAddressZpr if (data and 128 != 0) {
regPC = fetchedAddressZpr
instrCycles++
}
return false
} }
private fun iSmb0() { private fun iSmb0(): Boolean {
val data = getFetched() val data = getFetched()
write(fetchedAddress, data or 1) write(fetchedAddress, data or 1)
return false
} }
private fun iSmb1() { private fun iSmb1(): Boolean {
val data = getFetched() val data = getFetched()
write(fetchedAddress, data or 2) write(fetchedAddress, data or 2)
return false
} }
private fun iSmb2() { private fun iSmb2(): Boolean {
val data = getFetched() val data = getFetched()
write(fetchedAddress, data or 4) write(fetchedAddress, data or 4)
return false
} }
private fun iSmb3() { private fun iSmb3(): Boolean {
val data = getFetched() val data = getFetched()
write(fetchedAddress, data or 8) write(fetchedAddress, data or 8)
return false
} }
private fun iSmb4() { private fun iSmb4(): Boolean {
val data = getFetched() val data = getFetched()
write(fetchedAddress, data or 16) write(fetchedAddress, data or 16)
return false
} }
private fun iSmb5() { private fun iSmb5(): Boolean {
val data = getFetched() val data = getFetched()
write(fetchedAddress, data or 32) write(fetchedAddress, data or 32)
return false
} }
private fun iSmb6() { private fun iSmb6(): Boolean {
val data = getFetched() val data = getFetched()
write(fetchedAddress, data or 64) write(fetchedAddress, data or 64)
return false
} }
private fun iSmb7() { private fun iSmb7(): Boolean {
val data = getFetched() val data = getFetched()
write(fetchedAddress, data or 128) write(fetchedAddress, data or 128)
return false
} }
private fun iRmb0() { private fun iRmb0(): Boolean {
val data = getFetched() val data = getFetched()
write(fetchedAddress, data and 0b11111110) write(fetchedAddress, data and 0b11111110)
return false
} }
private fun iRmb1() { private fun iRmb1(): Boolean {
val data = getFetched() val data = getFetched()
write(fetchedAddress, data and 0b11111101) write(fetchedAddress, data and 0b11111101)
return false
} }
private fun iRmb2() { private fun iRmb2(): Boolean {
val data = getFetched() val data = getFetched()
write(fetchedAddress, data and 0b11111011) write(fetchedAddress, data and 0b11111011)
return false
} }
private fun iRmb3() { private fun iRmb3(): Boolean {
val data = getFetched() val data = getFetched()
write(fetchedAddress, data and 0b11110111) write(fetchedAddress, data and 0b11110111)
return false
} }
private fun iRmb4() { private fun iRmb4(): Boolean {
val data = getFetched() val data = getFetched()
write(fetchedAddress, data and 0b11101111) write(fetchedAddress, data and 0b11101111)
return false
} }
private fun iRmb5() { private fun iRmb5(): Boolean {
val data = getFetched() val data = getFetched()
write(fetchedAddress, data and 0b11011111) write(fetchedAddress, data and 0b11011111)
return false
} }
private fun iRmb6() { private fun iRmb6(): Boolean {
val data = getFetched() val data = getFetched()
write(fetchedAddress, data and 0b10111111) write(fetchedAddress, data and 0b10111111)
return false
} }
private fun iRmb7() { private fun iRmb7(): Boolean {
val data = getFetched() val data = getFetched()
write(fetchedAddress, data and 0b01111111) write(fetchedAddress, data and 0b01111111)
return false
} }
} }

View File

@ -72,13 +72,4 @@ abstract class FunctionalTestsBase {
} }
fail("test failed") fail("test failed")
} }
protected fun runTestExpectNotImplemented(testprogram: String) {
try {
runTest(testprogram)
fail("expected to crash with NotImplementedError")
} catch(nx: NotImplementedError) {
// okay!
}
}
} }

View File

@ -230,6 +230,24 @@ class Test6502CpuBasics {
totalCycles = cycles totalCycles = cycles
instrCycles = 0 instrCycles = 0
} }
override fun iAdc(): Boolean {
// NES cpu doesn't have BCD mode
val decimal = regP.D
regP.D = false
val result = super.iAdc()
regP.D = decimal
return result
}
override fun iSbc(operandOverride: Int?): Boolean {
// NES cpu doesn't have BCD mode
val decimal = regP.D
regP.D = false
val result = super.iSbc(operandOverride)
regP.D = decimal
return result
}
} }
val cpu = NesCpu() val cpu = NesCpu()
@ -245,21 +263,23 @@ class Test6502CpuBasics {
bus.reset() bus.reset()
cpu.resetTotalCycles(7) // that is what the nes rom starts with cpu.resetTotalCycles(7) // that is what the nes rom starts with
cpu.regPC = 0xc000 cpu.regPC = 0xc000
var tracingSnapshot = cpu.snapshot()
cpu.tracing = { tracingSnapshot=it }
val neslog = javaClass.getResource("nestest.log").readText().lineSequence() val neslog = javaClass.getResource("nestest.log").readText().lineSequence()
for(logline in neslog) { for(logline in neslog) {
val s = cpu.snapshot() // TODO use cpu.tracing instead if(logline.isEmpty())
break
cpu.step()
val nesAddressHex = logline.substring(0, 4).toInt(16) val nesAddressHex = logline.substring(0, 4).toInt(16)
assertEquals(nesAddressHex, s.PC) assertEquals(nesAddressHex, tracingSnapshot.PC)
println("NES: $logline") // println("NES: $logline")
val disassem = disassembler.disassembleOneInstruction(ram.data, s.PC, 0).first.substring(1) // val disassem = disassembler.disassembleOneInstruction(ram.data, tracingSnapshot.PC, 0).first.substring(1)
val spaces = " ".substring(disassem.length-1) // val spaces = " ".substring(disassem.length-1)
println("EMU: $disassem $spaces A:${hexB(s.A)} X:${hexB(s.X)} Y:${hexB(s.Y)} P:${hexB(s.P.asInt())} SP:${hexB(s.SP)} PPU: 0, 0 CYC:${s.cycles}") // println("EMU: $disassem $spaces A:${hexB(tracingSnapshot.A)} X:${hexB(tracingSnapshot.X)} Y:${hexB(tracingSnapshot.Y)} P:${hexB(tracingSnapshot.P.asInt())} SP:${hexB(tracingSnapshot.SP)} PPU: 0, 0 CYC:${tracingSnapshot.cycles}")
// TODO use cpu.tracing, as per https://forums.nesdev.com/viewtopic.php?t=19117 (i.e. BEFORE instruction gets executed):
// "before fetching the first operation code byte, make an internal record of the program counter and other registers;
// after reading the final operand byte, log all the values you stored back in step (1) plus the full instruction and its disassembly."
val nesRegsLog = logline.substring(48).split(':') val nesRegsLog = logline.substring(48).split(':')
val nesA = nesRegsLog[1].substring(0, 2).toShort(16) val nesA = nesRegsLog[1].substring(0, 2).toShort(16)
@ -268,17 +288,16 @@ class Test6502CpuBasics {
val nesP = nesRegsLog[4].substring(0, 2).toInt(16) val nesP = nesRegsLog[4].substring(0, 2).toInt(16)
val nesSP = nesRegsLog[5].substring(0, 2).toInt(16) val nesSP = nesRegsLog[5].substring(0, 2).toInt(16)
val nesCycles = nesRegsLog[7].toLong() val nesCycles = nesRegsLog[7].toLong()
assertEquals(nesA, s.A) assertEquals(nesA, tracingSnapshot.A)
assertEquals(nesX, s.X) assertEquals(nesX, tracingSnapshot.X)
assertEquals(nesY, s.Y) assertEquals(nesY, tracingSnapshot.Y)
assertEquals(nesP, s.P.asInt()) assertEquals(nesP, tracingSnapshot.P.asInt())
assertEquals(nesSP, s.SP) assertEquals(nesSP, tracingSnapshot.SP)
assertEquals(nesCycles, s.cycles) assertEquals(nesCycles, tracingSnapshot.cycles)
cpu.step()
} }
// TODO test $02 and $03 for test results see http://www.qmtpro.com/~nes/misc/nestest.txt val two = ram[0x02]
val three = ram[0x03]
fail("todo: test success condition") assertEquals(0, two, "test failed, code ${hexB(two)} ${hexB(three)}")
} }
} }

View File

@ -182,10 +182,11 @@ class Test6502TestSuiteC64Specific {
runTest("cnto2") runTest("cnto2")
} }
@Test @Test
@Disabled("tests c64 specific hardware") @Disabled("tests c64 specific hardware")
fun testCputiming() { fun testCputiming() {
runTest("cputiming") // TODO fix this test once the cycle times are correct? runTest("cputiming")
} }
@Test @Test

View File

@ -2,328 +2,328 @@ import org.junit.jupiter.api.parallel.Execution
import org.junit.jupiter.api.parallel.ExecutionMode import org.junit.jupiter.api.parallel.ExecutionMode
import kotlin.test.* import kotlin.test.*
// TODO: implement the illegal instructions and replace these tests with the 'real' runTest // TODO: implement the still missing illegal instructions and replace these tests with the 'real' runTest
@Execution(ExecutionMode.CONCURRENT) @Execution(ExecutionMode.CONCURRENT)
class Test6502TestSuiteIllegalInstructions: FunctionalTestsBase() { class Test6502TestSuiteIllegalInstructions: FunctionalTestsBase() {
@Test @Test
fun testAlrb() { fun testAlrb() {
runTestExpectNotImplemented("alrb") runTest("alrb") // TODO fix?
} }
@Test @Test
fun testAncb() { fun testAncb() {
runTestExpectNotImplemented("ancb") runTest("ancb")
} }
@Test @Test
fun testAneb() { fun testAneb() {
runTestExpectNotImplemented("aneb") runTest("aneb") // TODO fix?
} }
@Test @Test
fun testArrb() { fun testArrb() {
runTestExpectNotImplemented("arrb") runTest("arrb") // TODO fix?
} }
@Test @Test
fun testAsoa() { fun testAsoa() {
runTestExpectNotImplemented("asoa") runTest("asoa")
} }
@Test @Test
fun testAsoax() { fun testAsoax() {
runTestExpectNotImplemented("asoax") runTest("asoax")
} }
@Test @Test
fun testAsoay() { fun testAsoay() {
runTestExpectNotImplemented("asoay") runTest("asoay")
} }
@Test @Test
fun testAsoix() { fun testAsoix() {
runTestExpectNotImplemented("asoix") runTest("asoix")
} }
@Test @Test
fun testAsoiy() { fun testAsoiy() {
runTestExpectNotImplemented("asoiy") runTest("asoiy")
} }
@Test @Test
fun testAsoz() { fun testAsoz() {
runTestExpectNotImplemented("asoz") runTest("asoz")
} }
@Test @Test
fun testAsozx() { fun testAsozx() {
runTestExpectNotImplemented("asozx") runTest("asozx")
} }
@Test @Test
fun testAxsa() { fun testAxsa() {
runTestExpectNotImplemented("axsa") runTest("axsa")
} }
@Test @Test
fun testAxsix() { fun testAxsix() {
runTestExpectNotImplemented("axsix") runTest("axsix")
} }
@Test @Test
fun testAxsz() { fun testAxsz() {
runTestExpectNotImplemented("axsz") runTest("axsz")
} }
@Test @Test
fun testAxszy() { fun testAxszy() {
runTestExpectNotImplemented("axszy") runTest("axszy")
} }
@Test @Test
fun testDcma() { fun testDcma() {
runTestExpectNotImplemented("dcma") runTest("dcma")
} }
@Test @Test
fun testDcmax() { fun testDcmax() {
runTestExpectNotImplemented("dcmax") runTest("dcmax")
} }
@Test @Test
fun testDcmay() { fun testDcmay() {
runTestExpectNotImplemented("dcmay") runTest("dcmay")
} }
@Test @Test
fun testDcmix() { fun testDcmix() {
runTestExpectNotImplemented("dcmix") runTest("dcmix")
} }
@Test @Test
fun testDcmiy() { fun testDcmiy() {
runTestExpectNotImplemented("dcmiy") runTest("dcmiy")
} }
@Test @Test
fun testDcmz() { fun testDcmz() {
runTestExpectNotImplemented("dcmz") runTest("dcmz")
} }
@Test @Test
fun testDcmzx() { fun testDcmzx() {
runTestExpectNotImplemented("dcmzx") runTest("dcmzx")
} }
@Test @Test
fun testInsa() { fun testInsa() {
runTestExpectNotImplemented("insa") runTest("insa")
} }
@Test @Test
fun testInsax() { fun testInsax() {
runTestExpectNotImplemented("insax") runTest("insax")
} }
@Test @Test
fun testInsay() { fun testInsay() {
runTestExpectNotImplemented("insay") runTest("insay")
} }
@Test @Test
fun testInsix() { fun testInsix() {
runTestExpectNotImplemented("insix") runTest("insix")
} }
@Test @Test
fun testInsiy() { fun testInsiy() {
runTestExpectNotImplemented("insiy") runTest("insiy")
} }
@Test @Test
fun testInsz() { fun testInsz() {
runTestExpectNotImplemented("insz") runTest("insz")
} }
@Test @Test
fun testInszx() { fun testInszx() {
runTestExpectNotImplemented("inszx") runTest("inszx")
} }
@Test @Test
fun testLasay() { fun testLasay() {
runTestExpectNotImplemented("lasay") runTest("lasay")
} }
@Test @Test
fun testLaxa() { fun testLaxa() {
runTestExpectNotImplemented("laxa") runTest("laxa")
} }
@Test @Test
fun testLaxay() { fun testLaxay() {
runTestExpectNotImplemented("laxay") runTest("laxay")
} }
@Test @Test
fun testLaxix() { fun testLaxix() {
runTestExpectNotImplemented("laxix") runTest("laxix")
} }
@Test @Test
fun testLaxiy() { fun testLaxiy() {
runTestExpectNotImplemented("laxiy") runTest("laxiy")
} }
@Test @Test
fun testLaxz() { fun testLaxz() {
runTestExpectNotImplemented("laxz") runTest("laxz")
} }
@Test @Test
fun testLaxzy() { fun testLaxzy() {
runTestExpectNotImplemented("laxzy") runTest("laxzy")
} }
@Test @Test
fun testLsea() { fun testLsea() {
runTestExpectNotImplemented("lsea") runTest("lsea")
} }
@Test @Test
fun testLseax() { fun testLseax() {
runTestExpectNotImplemented("lseax") runTest("lseax")
} }
@Test @Test
fun testLseay() { fun testLseay() {
runTestExpectNotImplemented("lseay") runTest("lseay")
} }
@Test @Test
fun testLseix() { fun testLseix() {
runTestExpectNotImplemented("lseix") runTest("lseix")
} }
@Test @Test
fun testLseiy() { fun testLseiy() {
runTestExpectNotImplemented("lseiy") runTest("lseiy")
} }
@Test @Test
fun testLsez() { fun testLsez() {
runTestExpectNotImplemented("lsez") runTest("lsez")
} }
@Test @Test
fun testLsezx() { fun testLsezx() {
runTestExpectNotImplemented("lsezx") runTest("lsezx")
} }
@Test @Test
fun testLxab() { fun testLxab() {
runTestExpectNotImplemented("lxab") runTest("lxab") // TODO fix something?
} }
@Test @Test
fun testRlaa() { fun testRlaa() {
runTestExpectNotImplemented("rlaa") runTest("rlaa")
} }
@Test @Test
fun testRlaax() { fun testRlaax() {
runTestExpectNotImplemented("rlaax") runTest("rlaax")
} }
@Test @Test
fun testRlaay() { fun testRlaay() {
runTestExpectNotImplemented("rlaay") runTest("rlaay")
} }
@Test @Test
fun testRlaix() { fun testRlaix() {
runTestExpectNotImplemented("rlaix") runTest("rlaix")
} }
@Test @Test
fun testRlaiy() { fun testRlaiy() {
runTestExpectNotImplemented("rlaiy") runTest("rlaiy")
} }
@Test @Test
fun testRlaz() { fun testRlaz() {
runTestExpectNotImplemented("rlaz") runTest("rlaz")
} }
@Test @Test
fun testRlazx() { fun testRlazx() {
runTestExpectNotImplemented("rlazx") runTest("rlazx")
} }
@Test @Test
fun testRraa() { fun testRraa() {
runTestExpectNotImplemented("rraa") runTest("rraa")
} }
@Test @Test
fun testRraax() { fun testRraax() {
runTestExpectNotImplemented("rraax") runTest("rraax")
} }
@Test @Test
fun testRraay() { fun testRraay() {
runTestExpectNotImplemented("rraay") runTest("rraay")
} }
@Test @Test
fun testRraix() { fun testRraix() {
runTestExpectNotImplemented("rraix") runTest("rraix")
} }
@Test @Test
fun testRraiy() { fun testRraiy() {
runTestExpectNotImplemented("rraiy") runTest("rraiy")
} }
@Test @Test
fun testRraz() { fun testRraz() {
runTestExpectNotImplemented("rraz") runTest("rraz")
} }
@Test @Test
fun testRrazx() { fun testRrazx() {
runTestExpectNotImplemented("rrazx") runTest("rrazx")
} }
@Test @Test
fun testSbxb() { fun testSbxb() {
runTestExpectNotImplemented("sbxb") runTest("sbxb") // TODO fix?
} }
@Test @Test
fun testShaay() { fun testShaay() {
runTestExpectNotImplemented("shaay") runTest("shaay") // TODO fix?
} }
@Test @Test
fun testShaiy() { fun testShaiy() {
runTestExpectNotImplemented("shaiy") runTest("shaiy") // TODO fix?
} }
@Test @Test
fun testShsay() { fun testShsay() {
runTestExpectNotImplemented("shsay") runTest("shsay") // TODO fix?
} }
@Test @Test
fun testShxay() { fun testShxay() {
runTestExpectNotImplemented("shxay") runTest("shxay") // TODO fix?
} }
@Test @Test
fun testShyax() { fun testShyax() {
runTestExpectNotImplemented("shyax") runTest("shyax") // TODO fix?
} }
} }