mirror of
https://github.com/Smallhacker/disbrowser.git
synced 2025-04-06 16:37:30 +00:00
Working ROM/RAM labeling, vector table
This commit is contained in:
parent
e6445575d7
commit
5afdf84c1e
@ -1,9 +1,23 @@
|
||||
{
|
||||
"code" : {
|
||||
"002140" : {
|
||||
"label" : "apuIo0"
|
||||
},
|
||||
"002141" : {
|
||||
"label" : "apuIo1"
|
||||
},
|
||||
"002142" : {
|
||||
"label" : "apuIo2"
|
||||
},
|
||||
"002143" : {
|
||||
"label" : "apuIo3"
|
||||
},
|
||||
"00420c" : {
|
||||
"label" : "hdmaEnable"
|
||||
},
|
||||
"008000" : {
|
||||
"label" : "ResetVector"
|
||||
},
|
||||
"00800a" : { },
|
||||
"00801b" : {
|
||||
"comment" : "\\ Turn off emulation mode"
|
||||
},
|
||||
@ -58,9 +72,17 @@
|
||||
"entries" : 28
|
||||
} ]
|
||||
},
|
||||
"0080c9" : {
|
||||
"label" : "NmiVector"
|
||||
},
|
||||
"00822c" : {
|
||||
"label" : "UnusedVector"
|
||||
},
|
||||
"0082d8" : {
|
||||
"label" : "IrqVector"
|
||||
},
|
||||
"00841e" : {
|
||||
"label" : "ClearOam",
|
||||
"comment" : "Test3"
|
||||
"label" : "ClearOam"
|
||||
},
|
||||
"00879c" : {
|
||||
"comment" : "Preserve Y value for later",
|
||||
@ -137,6 +159,9 @@
|
||||
"00890b" : {
|
||||
"comment" : "/"
|
||||
},
|
||||
"00ffff" : {
|
||||
"label" : "CrashVector"
|
||||
},
|
||||
"0287d0" : {
|
||||
"flags" : [ {
|
||||
"flagType" : "JslTableRoutine",
|
||||
@ -151,6 +176,15 @@
|
||||
"flagType" : "JslTableRoutine",
|
||||
"entries" : 12
|
||||
} ]
|
||||
},
|
||||
"7e0010" : {
|
||||
"label" : "gameMode"
|
||||
},
|
||||
"7e0011" : {
|
||||
"label" : "subGameMode"
|
||||
},
|
||||
"7e0012" : {
|
||||
"label" : "nmiExecuted"
|
||||
}
|
||||
}
|
||||
}
|
@ -60,9 +60,6 @@ class Grid {
|
||||
}
|
||||
|
||||
fun add(ins: CodeUnit, metadata: Metadata, disassembly: Disassembly) {
|
||||
val insMetadata = ins.address?.let { metadata[it] }
|
||||
|
||||
val actualAddress = ins.address
|
||||
val presentedAddress = ins.presentedAddress
|
||||
|
||||
if (nextAddress != null) {
|
||||
@ -75,18 +72,31 @@ class Grid {
|
||||
val y = (height++)
|
||||
addresses[presentedAddress] = y
|
||||
|
||||
add(y, ins.address,
|
||||
text(actualAddress?.toFormattedString() ?: ""),
|
||||
text(ins.bytesToString()),
|
||||
editableField(presentedAddress, "label", insMetadata?.label),
|
||||
fragment {
|
||||
opcodeNode(ins)
|
||||
text(" ")
|
||||
var operands = ins.printOperands()
|
||||
val (address, bytes, label, primaryMnemonic, secondaryMnemonic, suffix, operands, state, comment, labelAddress)
|
||||
= ins.print(metadata)
|
||||
|
||||
add(y, ins.address,
|
||||
text(address ?: ""),
|
||||
text(bytes),
|
||||
editableField(presentedAddress, "label", label),
|
||||
fragment {
|
||||
if (secondaryMnemonic == null) {
|
||||
text(primaryMnemonic)
|
||||
} else {
|
||||
span {
|
||||
text(primaryMnemonic)
|
||||
}.attr("title", secondaryMnemonic).addClass("opcode-info")
|
||||
}
|
||||
text(suffix ?: "")
|
||||
text(" ")
|
||||
val link = ins.linkedState
|
||||
if (link == null) {
|
||||
text(operands)
|
||||
if (labelAddress == null) {
|
||||
text(operands ?: "")
|
||||
} else {
|
||||
val currentLabel = metadata[labelAddress]?.label
|
||||
editablePopupField(labelAddress, "label", operands, currentLabel)
|
||||
}
|
||||
} else {
|
||||
val local = link.address in disassembly
|
||||
|
||||
@ -95,15 +105,15 @@ class Grid {
|
||||
else -> "/${link.address.toSimpleString()}/${link.urlString}"
|
||||
}
|
||||
|
||||
operands = metadata[link.address]?.label ?: operands
|
||||
//operands = metadata[link.address]?.label ?: operands
|
||||
|
||||
a {
|
||||
text(operands)
|
||||
text(operands ?: "")
|
||||
}.attr("href", url)
|
||||
}
|
||||
},
|
||||
text(ins.postState?.toString() ?: ""),
|
||||
editableField(presentedAddress, "comment", insMetadata?.comment)
|
||||
text(state ?: ""),
|
||||
editableField(presentedAddress, "comment", comment)
|
||||
)
|
||||
|
||||
if (ins.opcode.continuation == Continuation.NO) {
|
||||
@ -111,18 +121,6 @@ class Grid {
|
||||
}
|
||||
}
|
||||
|
||||
private fun HtmlArea.opcodeNode(ins: CodeUnit) {
|
||||
val alt = ins.printAlternativeOpcodeAndSuffix()
|
||||
if (alt == null) {
|
||||
text(ins.printOpcodeAndSuffix())
|
||||
} else {
|
||||
span {
|
||||
text(ins.printOpcodeAndSuffix())
|
||||
}.attr("title", alt).addClass("opcode-info")
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private fun editableField(address: SnesAddress, type: String, value: String?): HtmlNode {
|
||||
return input(value = value ?: "")
|
||||
.addClass("field-$type")
|
||||
@ -131,6 +129,18 @@ class Grid {
|
||||
.attr("data-address", address.toSimpleString())
|
||||
}
|
||||
|
||||
private fun HtmlArea.editablePopupField(address: SnesAddress, type: String, displayValue: String?, editValue: String?) {
|
||||
span {
|
||||
text(displayValue ?: "")
|
||||
span {}.addClass("field-editable-popup-icon")
|
||||
}
|
||||
.addClass("field-$type")
|
||||
.addClass("field-editable-popup")
|
||||
.attr("data-field", type)
|
||||
.attr("data-value", editValue ?: "")
|
||||
.attr("data-address", address.toSimpleString())
|
||||
}
|
||||
|
||||
private fun addDummy() {
|
||||
val y = (height++)
|
||||
add(y, null, null, null, null, text("..."), null, null)
|
||||
|
@ -9,6 +9,21 @@ import kotlin.reflect.KMutableProperty1
|
||||
|
||||
private val RESET_VECTOR_LOCATION = address(0x00_FFFC)
|
||||
|
||||
private val VECTORS = listOf(
|
||||
address(0x00_FFE4) to "COP",
|
||||
address(0x00_FFE6) to "BRK",
|
||||
address(0x00_FFE8) to "ABORT",
|
||||
address(0x00_FFEA) to "NMI",
|
||||
address(0x00_FFEC) to "RESET",
|
||||
address(0x00_FFEE) to "IRQ",
|
||||
address(0x00_FFF4) to "COP (e)",
|
||||
address(0x00_FFF6) to "BRK (e)",
|
||||
address(0x00_FFF8) to "ABORT (e)",
|
||||
address(0x00_FFFA) to "NMI (e)",
|
||||
address(0x00_FFFC) to "RES (e)",
|
||||
address(0x00_FFFE) to "IRQBRK (e)"
|
||||
)
|
||||
|
||||
object Service {
|
||||
private const val romName = "Zelda no Densetsu - Kamigami no Triforce (Japan)"
|
||||
private val romDir = Paths.get("""P:\Emulation\ROMs\SNES""")
|
||||
@ -30,7 +45,7 @@ object Service {
|
||||
}
|
||||
|
||||
fun showDisassembly(initialAddress: SnesAddress, flags: VagueNumber): HtmlNode? {
|
||||
val initialState = State(memory = snesMemory, address = initialAddress, flags = flags)
|
||||
val initialState = State(memory = snesMemory, address = initialAddress, flags = flags, metadata = metadata)
|
||||
val disassembly = Disassembler.disassemble(initialState, metadata, false)
|
||||
|
||||
return print(disassembly, metadata)
|
||||
@ -52,17 +67,7 @@ object Service {
|
||||
.sortedBy { it.first distanceTo it.second }
|
||||
.forEach { grid.arrow(it.first, it.second) }
|
||||
|
||||
return html {
|
||||
head {
|
||||
title { text("Disassembly Browser") }
|
||||
link {}.attr("rel", "stylesheet").attr("href", "/resources/style.css")
|
||||
meta {}.attr("charset", "UTF-8")
|
||||
}
|
||||
body {
|
||||
grid.output().appendTo(parent)
|
||||
script().attr("src", "/resources/disbrowser.js")
|
||||
}
|
||||
}
|
||||
return grid.output()
|
||||
}
|
||||
|
||||
fun updateMetadata(address: SnesAddress, field: KMutableProperty1<MetadataLine, String?>, value: String) {
|
||||
@ -79,11 +84,17 @@ object Service {
|
||||
val line = metadata.getOrCreate(address)
|
||||
field.set(line, value)
|
||||
|
||||
if (line.isEmpty()) {
|
||||
metadata[address] = null
|
||||
}
|
||||
|
||||
metadata.cleanUp()
|
||||
metaFile.save(metadata)
|
||||
}
|
||||
|
||||
fun getVectors() = VECTORS.asSequence()
|
||||
.map { (vectorLocation: SnesAddress, name: String ) ->
|
||||
val codeLocation = SnesAddress(snesMemory.getWord(vectorLocation)!!.toUInt24())
|
||||
val label = metadata[codeLocation]?.label
|
||||
?: codeLocation.toFormattedString()
|
||||
Vector(vectorLocation, codeLocation, name, label)
|
||||
}
|
||||
}
|
||||
|
||||
data class Vector(val vectorLocation: SnesAddress, val codeLocation: SnesAddress, val name: String, val label: String)
|
@ -16,18 +16,9 @@ interface CodeUnit {
|
||||
val opcode: Opcode
|
||||
val lengthSuffix: String?
|
||||
|
||||
val memory: SnesMapper
|
||||
|
||||
fun operandByte(index: UInt): UByte = bytes[opcode.operandIndex + index]
|
||||
fun printOpcodeAndSuffix(): String {
|
||||
val mnemonic = opcode.mnemonic.displayName
|
||||
val suffix = lengthSuffix ?: ""
|
||||
return "$mnemonic$suffix"
|
||||
}
|
||||
fun printAlternativeOpcodeAndSuffix(): String? {
|
||||
val mnemonic = opcode.mnemonic.alternativeName ?: return null
|
||||
val suffix = lengthSuffix ?: ""
|
||||
return "$mnemonic$suffix"
|
||||
}
|
||||
fun printOperands() = opcode.mode.print(this)
|
||||
|
||||
fun bytesToString(): String {
|
||||
return bytes.asSequence()
|
||||
@ -65,7 +56,8 @@ class DataBlock(
|
||||
override val bytes: ValidMemorySpace,
|
||||
override val presentedAddress: SnesAddress,
|
||||
override val relativeAddress: SnesAddress,
|
||||
override val linkedState: State?
|
||||
override val linkedState: State?,
|
||||
override val memory: SnesMapper
|
||||
) : CodeUnit {
|
||||
override val nextPresentedAddress: SnesAddress
|
||||
get() = presentedAddress + operandLength.toInt()
|
||||
@ -78,6 +70,7 @@ class DataBlock(
|
||||
}
|
||||
|
||||
class Instruction(override val bytes: ValidMemorySpace, override val opcode: Opcode, override val preState: State) : CodeUnit {
|
||||
override val memory = preState.memory
|
||||
override val address: SnesAddress get() = preState.address
|
||||
override val relativeAddress get() = address
|
||||
override val presentedAddress get() = address
|
||||
@ -92,9 +85,11 @@ class Instruction(override val bytes: ValidMemorySpace, override val opcode: Opc
|
||||
.withOrigin(this)
|
||||
}
|
||||
|
||||
private val showLengthSuffix get() = opcode.mode.showLengthSuffix and opcode.mnemonic.showLengthSuffix
|
||||
|
||||
override val lengthSuffix: String?
|
||||
get() {
|
||||
if (!opcode.mode.showLengthSuffix) {
|
||||
if (!showLengthSuffix) {
|
||||
return null
|
||||
}
|
||||
|
||||
@ -116,58 +111,55 @@ class Instruction(override val bytes: ValidMemorySpace, override val opcode: Opc
|
||||
}
|
||||
|
||||
return referencedAddress()
|
||||
|
||||
// return when (opcode.mode) {
|
||||
// Mode.ABSOLUTE_CODE -> preState.resolveAbsoluteCode(word)
|
||||
// Mode.ABSOLUTE_LONG -> SnesAddress(long)
|
||||
// Mode.RELATIVE -> relativeAddress + 2 + signedByte.toInt()
|
||||
// Mode.RELATIVE_LONG -> relativeAddress + 3 + signedWord.toInt()
|
||||
// Mode.CODE_WORD -> preState.resolveAbsoluteCode(word)
|
||||
// Mode.CODE_LONG -> SnesAddress(long)
|
||||
// Mode.DATA_WORD -> preState.resolveAbsoluteData(word)
|
||||
// Mode.DATA_LONG -> SnesAddress(long)
|
||||
// else -> null
|
||||
// }
|
||||
}
|
||||
|
||||
private fun referencedAddress(): SnesAddress? {
|
||||
return when (opcode.mode) {
|
||||
Mode.ABSOLUTE -> preState.resolveAbsoluteData(word)
|
||||
Mode.ABSOLUTE_CODE -> preState.resolveAbsoluteCode(word)
|
||||
Mode.ABSOLUTE_INDIRECT -> preState.resolveAbsoluteData(word)
|
||||
Mode.ABSOLUTE_INDIRECT_LONG -> preState.resolveAbsoluteData(word)
|
||||
Mode.ABSOLUTE_LONG -> SnesAddress(long)
|
||||
Mode.ABSOLUTE_LONG_X -> SnesAddress(long)
|
||||
Mode.ABSOLUTE_X -> preState.resolveAbsoluteData(word)
|
||||
Mode.ABSOLUTE_X_INDIRECT -> preState.resolveAbsoluteData(word)
|
||||
Mode.ABSOLUTE_Y -> preState.resolveAbsoluteData(word)
|
||||
Mode.BLOCK_MOVE -> null
|
||||
Mode.CODE_WORD -> preState.resolveAbsoluteCode(word)
|
||||
Mode.CODE_LONG -> SnesAddress(long)
|
||||
Mode.DATA_BYTE -> null
|
||||
Mode.DATA_WORD -> preState.resolveAbsoluteData(word)
|
||||
Mode.DATA_LONG -> SnesAddress(long)
|
||||
Mode.DIRECT -> preState.resolveDirectPage(byte)
|
||||
Mode.DIRECT_X -> preState.resolveDirectPage(byte)
|
||||
Mode.DIRECT_Y -> preState.resolveDirectPage(byte)
|
||||
Mode.DIRECT_S -> null
|
||||
Mode.DIRECT_INDIRECT -> preState.resolveDirectPage(byte)
|
||||
Mode.DIRECT_INDIRECT_Y -> preState.resolveDirectPage(byte)
|
||||
Mode.DIRECT_X_INDIRECT -> preState.resolveDirectPage(byte)
|
||||
Mode.DIRECT_S_INDIRECT_Y -> null
|
||||
Mode.DIRECT_INDIRECT_LONG -> preState.resolveDirectPage(byte)
|
||||
Mode.DIRECT_INDIRECT_LONG_Y -> preState.resolveDirectPage(byte)
|
||||
Mode.IMMEDIATE_8 -> null
|
||||
Mode.IMMEDIATE_16 -> null
|
||||
Mode.IMMEDIATE_M -> null
|
||||
Mode.IMMEDIATE_X -> null
|
||||
Mode.IMPLIED -> null
|
||||
Mode.RELATIVE -> relativeAddress + 2 + signedByte.toInt()
|
||||
Mode.RELATIVE_LONG -> relativeAddress + 3 + signedWord.toInt()
|
||||
}
|
||||
}
|
||||
private fun referencedAddress() = opcode.mode.referencedAddress(this)
|
||||
|
||||
override fun toString(): String {
|
||||
return "$address ${bytesToString()} ${opcode.mnemonic.displayName} ${opcode.mode.print(this).padEnd(100, ' ')} ($preState -> $postState)"
|
||||
val (address, bytes, _, primaryMnemonic, _, suffix, operands, _, _) = print()
|
||||
return "${address ?: "\$xx:xxxx"} $bytes $primaryMnemonic${suffix ?: ""} ${operands?.padEnd(100, ' ')
|
||||
?: ""} ($preState -> $postState)"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun CodeUnit.print(metadata: Metadata? = null): PrintedCodeUnit {
|
||||
val mnemonic = opcode.mnemonic
|
||||
val primaryMnemonic = mnemonic.displayName
|
||||
val secondaryMnemonic = mnemonic.alternativeName
|
||||
|
||||
var suffix = lengthSuffix
|
||||
var operands = metadata?.let { opcode.mode.printWithLabel(this, it) }
|
||||
if (operands == null) {
|
||||
operands = opcode.mode.printRaw(this)
|
||||
suffix = null
|
||||
}
|
||||
|
||||
val state = postState?.toString()
|
||||
val label = address?.let { metadata?.get(it)?.label }
|
||||
val comment = address?.let { metadata?.get(it)?.comment }
|
||||
val formattedAddress = address?.toFormattedString()
|
||||
val bytes = bytesToString()
|
||||
|
||||
val labelAddress = if (opcode.mode.canHaveLabel) {
|
||||
opcode.mode.referencedAddress(this)?.let {
|
||||
memory.toCanonical(it)
|
||||
}
|
||||
} else {
|
||||
null
|
||||
}
|
||||
|
||||
return PrintedCodeUnit(formattedAddress, bytes, label, primaryMnemonic, secondaryMnemonic, suffix, operands, state, comment, labelAddress)
|
||||
}
|
||||
|
||||
data class PrintedCodeUnit(
|
||||
val address: String?,
|
||||
val bytes: String,
|
||||
val label: String?,
|
||||
val primaryMnemonic: String,
|
||||
val secondaryMnemonic: String?,
|
||||
val suffix: String?,
|
||||
val operands: String?,
|
||||
val state: String?,
|
||||
val comment: String?,
|
||||
val labelAddress: SnesAddress?
|
||||
)
|
@ -6,12 +6,13 @@ import com.fasterxml.jackson.annotation.JsonSubTypes
|
||||
import com.fasterxml.jackson.annotation.JsonSubTypes.Type
|
||||
import com.fasterxml.jackson.annotation.JsonTypeInfo
|
||||
import com.smallhacker.disbrowser.util.joinNullableBytes
|
||||
import com.smallhacker.disbrowser.util.removeIf
|
||||
import com.smallhacker.disbrowser.util.toUInt24
|
||||
import java.util.*
|
||||
|
||||
class Metadata {
|
||||
@JsonProperty
|
||||
private val code: TreeMap<SnesAddress, MetadataLine>
|
||||
private val code: MutableMap<SnesAddress, MetadataLine>
|
||||
|
||||
constructor() {
|
||||
this.code = TreeMap()
|
||||
@ -46,6 +47,10 @@ class Metadata {
|
||||
this[address] = newLine
|
||||
return newLine
|
||||
}
|
||||
|
||||
fun cleanUp() {
|
||||
code.removeIf { _, v -> v.isEmpty() }
|
||||
}
|
||||
}
|
||||
|
||||
@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, include = JsonTypeInfo.As.PROPERTY, property = "flagType")
|
||||
@ -88,13 +93,14 @@ class JmpIndirectLongInterleavedTable @JsonCreator constructor(
|
||||
val target = table.getLong(offset)
|
||||
|
||||
DataBlock(
|
||||
Opcode.POINTER_LONG,
|
||||
Opcode.CODE_POINTER_LONG,
|
||||
table.range(offset, 3u),
|
||||
jumpInstruction.postState.address + offset.toInt(),
|
||||
jumpInstruction.relativeAddress,
|
||||
jumpInstruction.opcode.mutate(jumpInstruction)
|
||||
.mutateAddress { SnesAddress(target) }
|
||||
.withOrigin(jumpInstruction)
|
||||
.withOrigin(jumpInstruction),
|
||||
jumpInstruction.memory
|
||||
)
|
||||
}
|
||||
}
|
||||
|
@ -12,5 +12,5 @@ data class MetadataLine(
|
||||
val flags: MutableList<InstructionFlag> = ArrayList()
|
||||
) {
|
||||
@JsonIgnore
|
||||
fun isEmpty() = (label == null) && (comment == null) && (preComment == null) && (length == 0) && (flags.isEmpty())
|
||||
fun isEmpty() = (label == null) && (comment == null) && (preComment == null) && (length == null) && (flags.isEmpty())
|
||||
}
|
||||
|
@ -1,10 +1,10 @@
|
||||
package com.smallhacker.disbrowser.asm
|
||||
|
||||
enum class Mnemonic(private val nameOverride: String? = null, val alternativeName: String? = null) {
|
||||
enum class Mnemonic(private val nameOverride: String? = null, val alternativeName: String? = null, val showLengthSuffix: Boolean = true) {
|
||||
ADC, AND, ASL, BCC(alternativeName = "BLT"), BCS(alternativeName = "BGE"), BEQ, BIT, BMI, BNE, BPL, BRA,
|
||||
BRK, BRL, BVC, BVS, CLC, CLD, CLI, CLV, CMP, COP, CPX,
|
||||
CPY, DEC, DEX, DEY, EOR, INC, INX, INY, JMP, JML, JSL,
|
||||
JSR, LDA, LDX, LDY, LSR, MVN, MVP, NOP, ORA, PEA, PEI,
|
||||
CPY, DEC, DEX, DEY, EOR, INC, INX, INY, JMP(showLengthSuffix = false), JML(showLengthSuffix = false), JSL(showLengthSuffix = false),
|
||||
JSR(showLengthSuffix = false), LDA, LDX, LDY, LSR, MVN, MVP, NOP, ORA, PEA, PEI,
|
||||
PER, PHA, PHB, PHD, PHK, PHP, PHX, PHY, PLA, PLB, PLD,
|
||||
PLP, PLX, PLY, REP, ROL, ROR, RTI, RTL, RTS, SBC, SEC,
|
||||
SED, SEI, SEP, STA, STP, STX, STY, STZ, TAX, TAY, TCD,
|
||||
|
@ -2,144 +2,228 @@ package com.smallhacker.disbrowser.asm
|
||||
|
||||
import com.smallhacker.disbrowser.util.*
|
||||
|
||||
private val ZEROES = Regex("[0]+")
|
||||
private fun countBytes(format: String) = (ZEROES.find(format)?.groupValues?.firstOrNull()?.length?.toUInt() ?: 0u) / 2u
|
||||
|
||||
private const val ACCUMULATOR_SIZE = -1
|
||||
private const val INDEX_SIZE = -2
|
||||
|
||||
fun format(format: String, value: UInt, operandBytes: UInt = countBytes(format)) =
|
||||
format.replace(ZEROES, toHex(value, operandBytes))
|
||||
|
||||
enum class Mode {
|
||||
DATA_BYTE("$00", dataMode = true, showLengthSuffix = false),
|
||||
DATA_WORD("$0000", dataMode = true, showLengthSuffix = false),
|
||||
DATA_LONG("$000000", dataMode = true, showLengthSuffix = false),
|
||||
CODE_WORD("$0000", dataMode = true, showLengthSuffix = false),
|
||||
CODE_LONG("$000000", dataMode = true, showLengthSuffix = false),
|
||||
|
||||
IMPLIED("", showLengthSuffix = false),
|
||||
IMMEDIATE_8("#$00", showLengthSuffix = false),
|
||||
IMMEDIATE_16("#$0000", showLengthSuffix = false),
|
||||
ABSOLUTE("$0000"),
|
||||
ABSOLUTE_CODE("$0000"),
|
||||
ABSOLUTE_X("$0000,x"),
|
||||
ABSOLUTE_Y("$0000,y"),
|
||||
ABSOLUTE_LONG("$000000"),
|
||||
ABSOLUTE_LONG_X("$000000,x"),
|
||||
ABSOLUTE_INDIRECT("($0000)"),
|
||||
ABSOLUTE_INDIRECT_LONG("[$0000]"),
|
||||
ABSOLUTE_X_INDIRECT("($0000,x)"),
|
||||
DIRECT("$00"),
|
||||
DIRECT_X("$00,x"),
|
||||
DIRECT_Y("$00,y"),
|
||||
DIRECT_S("$00,s"),
|
||||
DIRECT_INDIRECT("($00)"),
|
||||
DIRECT_INDIRECT_Y("($00),y"),
|
||||
DIRECT_X_INDIRECT("($00,x)"),
|
||||
DIRECT_S_INDIRECT_Y("($00,s),y"),
|
||||
DIRECT_INDIRECT_LONG("[$00]"),
|
||||
DIRECT_INDIRECT_LONG_Y("[$00],y"),
|
||||
|
||||
IMMEDIATE_M(
|
||||
operandLength = ACCUMULATOR_SIZE,
|
||||
print = {
|
||||
when (preState?.m) {
|
||||
null -> "????"
|
||||
true -> format("#$00", byte.toUInt())
|
||||
false -> format("#$0000", word.toUInt())
|
||||
}
|
||||
}
|
||||
),
|
||||
IMMEDIATE_X(
|
||||
operandLength = INDEX_SIZE,
|
||||
print = {
|
||||
when (preState?.x) {
|
||||
null -> "???"
|
||||
true -> format("#$00", byte.toUInt())
|
||||
false -> format("#$0000", word.toUInt())
|
||||
}
|
||||
}
|
||||
),
|
||||
|
||||
RELATIVE(
|
||||
format = "$000000",
|
||||
operandLength = 1u,
|
||||
valueGetter = {
|
||||
val rel = signedByte.toInt() + 2
|
||||
(relativeAddress + rel).value.toUInt()
|
||||
},
|
||||
showLengthSuffix = false
|
||||
),
|
||||
RELATIVE_LONG(
|
||||
format = "$000000",
|
||||
operandLength = 2u,
|
||||
valueGetter = {
|
||||
val rel = signedWord.toInt() + 3
|
||||
(relativeAddress + rel).value.toUInt()
|
||||
},
|
||||
showLengthSuffix = false
|
||||
),
|
||||
BLOCK_MOVE(
|
||||
operandLength = 2,
|
||||
print = { String.format("#$%02x,#$%02x", byte.toInt(), byte2.toInt()) },
|
||||
showLengthSuffix = false
|
||||
)
|
||||
;
|
||||
|
||||
private val operandLength: Int
|
||||
val print: CodeUnit.() -> String
|
||||
val dataMode: Boolean
|
||||
val showLengthSuffix: Boolean
|
||||
|
||||
constructor(operandLength: Int, print: CodeUnit.() -> String, showLengthSuffix: Boolean = true) {
|
||||
this.operandLength = operandLength
|
||||
this.print = print
|
||||
this.dataMode = false
|
||||
this.showLengthSuffix = showLengthSuffix
|
||||
}
|
||||
|
||||
constructor(
|
||||
format: String,
|
||||
printedLength: UInt = countBytes(format),
|
||||
operandLength: UInt = printedLength,
|
||||
valueGetter: CodeUnit.() -> UInt = { value!! },
|
||||
dataMode: Boolean = false,
|
||||
showLengthSuffix: Boolean = true
|
||||
) {
|
||||
this.operandLength = operandLength.toInt()
|
||||
this.print = { format(format, valueGetter(this), printedLength) }
|
||||
this.dataMode = dataMode
|
||||
this.showLengthSuffix = showLengthSuffix
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the total length, in bytes, of an instruction of this mode and its operands.
|
||||
*
|
||||
* This is usually one greater than [operandLength], except in the cases when the instruction is just pure data
|
||||
* without an opcode (in which case the two are equal).
|
||||
*
|
||||
* If the length cannot be determined based on the current [State], `null` is returned.
|
||||
*/
|
||||
fun instructionLength(state: State): UInt? {
|
||||
val operatorLength = if (this.dataMode) 0u else 1u
|
||||
return operandLength(state)
|
||||
?.plus(operatorLength)
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the length, in bytes, of the operands of an instruction of this mode.
|
||||
*
|
||||
* This is usually one less than [operandLength], except in the cases when the instruction is just pure data
|
||||
* without an opcode (in which case the two are equal).
|
||||
*
|
||||
* If the length cannot be determined based on the current [State], `null` is returned.
|
||||
*/
|
||||
fun operandLength(state: State): UInt? {
|
||||
return when (operandLength) {
|
||||
ACCUMULATOR_SIZE -> state.mWidth
|
||||
INDEX_SIZE -> state.xWidth
|
||||
else -> operandLength.toUInt()
|
||||
}
|
||||
}
|
||||
interface Mode {
|
||||
val dataMode get() = false
|
||||
val showLengthSuffix get() = true
|
||||
val canHaveLabel: Boolean
|
||||
fun operandLength(state: State): UInt?
|
||||
fun printWithLabel(ins: CodeUnit, metadata: Metadata): String? = referencedAddress(ins)?.let { metadata[it]?.label }
|
||||
fun printRaw(ins: CodeUnit): String
|
||||
fun referencedAddress(ins: CodeUnit): SnesAddress?
|
||||
}
|
||||
|
||||
fun Mode.instructionLength(state: State): UInt? {
|
||||
val operatorLength = if (this.dataMode) 0u else 1u
|
||||
return operandLength(state)
|
||||
?.plus(operatorLength)
|
||||
}
|
||||
|
||||
val Mode.x: Mode get() = IndexXMode(this)
|
||||
val Mode.y: Mode get() = IndexYMode(this)
|
||||
val Mode.s: Mode get() = IndexSMode(this)
|
||||
val Mode.indirect: Mode get() = IndirectMode(this)
|
||||
val Mode.indirectLong: Mode get() = IndirectLongMode(this)
|
||||
|
||||
private abstract class RawWrappedMode(
|
||||
private val parent: Mode,
|
||||
private val prefix: String = "",
|
||||
private val suffix: String = ""
|
||||
) : Mode by parent {
|
||||
override val canHaveLabel = false
|
||||
override fun printWithLabel(ins: CodeUnit, metadata: Metadata): String? = printRaw(ins)
|
||||
override fun printRaw(ins: CodeUnit) = prefix + parent.printRaw(ins) + suffix
|
||||
}
|
||||
|
||||
private abstract class WrappedMode(
|
||||
private val parent: Mode,
|
||||
private val prefix: String = "",
|
||||
private val suffix: String = ""
|
||||
) : Mode by parent {
|
||||
override fun printWithLabel(ins: CodeUnit, metadata: Metadata): String? = parent.printWithLabel(ins, metadata)?.let { prefix + it + suffix }
|
||||
override fun printRaw(ins: CodeUnit) = prefix + parent.printRaw(ins) + suffix
|
||||
}
|
||||
|
||||
abstract class MultiMode(private val fallback: Mode, private vararg val options: Mode) : Mode {
|
||||
override val canHaveLabel = get{ canHaveLabel }
|
||||
override val dataMode = get { dataMode }
|
||||
override val showLengthSuffix = get { showLengthSuffix }
|
||||
|
||||
override fun operandLength(state: State) = get(state) { operandLength(state) }
|
||||
|
||||
override fun printWithLabel(ins: CodeUnit, metadata: Metadata): String? = get(ins.preState) { printWithLabel(ins, metadata) }
|
||||
|
||||
override fun printRaw(ins: CodeUnit) = get(ins.preState) { printRaw(ins) }
|
||||
|
||||
override fun referencedAddress(ins: CodeUnit): SnesAddress? = get(ins.preState) { referencedAddress(ins) }
|
||||
|
||||
protected abstract fun pickMode(state: State): UInt
|
||||
|
||||
private fun <T> get(state: State?, getter: Mode.() -> T): T {
|
||||
if (state != null) {
|
||||
val mode = pickMode(state)
|
||||
if (mode != 0u) {
|
||||
return getter(options[mode.toInt() - 1])
|
||||
}
|
||||
}
|
||||
|
||||
return getter(fallback)
|
||||
}
|
||||
|
||||
private fun <T : Any> get(getter: Mode.() -> T) = get(null, getter)
|
||||
}
|
||||
|
||||
private interface DataValueType {
|
||||
fun resolve(byte: UByte, state: State?, memory: SnesMapper): SnesAddress?
|
||||
fun resolve(word: UShort, state: State?, memory: SnesMapper): SnesAddress?
|
||||
fun resolve(long: UInt24, state: State?, memory: SnesMapper): SnesAddress?
|
||||
val canHaveLabel: Boolean
|
||||
|
||||
val byte: Mode get() = DataByteMode(this)
|
||||
val word: Mode get() = DataWordMode(this)
|
||||
val long: Mode get() = DataLongMode(this)
|
||||
}
|
||||
|
||||
object DirectData : DataValueType {
|
||||
override val canHaveLabel = false
|
||||
override fun resolve(byte: UByte, state: State?, memory: SnesMapper): SnesAddress? = null
|
||||
override fun resolve(word: UShort, state: State?, memory: SnesMapper): SnesAddress? = null
|
||||
override fun resolve(long: UInt24, state: State?, memory: SnesMapper): SnesAddress? = null
|
||||
}
|
||||
|
||||
object DataPointer : DataValueType {
|
||||
override val canHaveLabel = true
|
||||
override fun resolve(byte: UByte, state: State?, memory: SnesMapper) = state?.resolveDirectPage(byte)
|
||||
override fun resolve(word: UShort, state: State?, memory: SnesMapper) = state?.resolveAbsoluteData(word)
|
||||
override fun resolve(long: UInt24, state: State?, memory: SnesMapper) = memory.toCanonical(SnesAddress(long))
|
||||
}
|
||||
|
||||
object CodePointer : DataValueType {
|
||||
override val canHaveLabel = true
|
||||
override fun resolve(byte: UByte, state: State?, memory: SnesMapper) = state?.resolveDirectPage(byte)
|
||||
override fun resolve(word: UShort, state: State?, memory: SnesMapper) = state?.resolveAbsoluteCode(word)
|
||||
override fun resolve(long: UInt24, state: State?, memory: SnesMapper) = memory.toCanonical(SnesAddress(long))
|
||||
}
|
||||
|
||||
private abstract class DataValueMode(private val length: UInt, protected val type: DataValueType) : Mode {
|
||||
override val canHaveLabel = type.canHaveLabel
|
||||
override val dataMode = true
|
||||
override val showLengthSuffix = false
|
||||
override fun operandLength(state: State) = length
|
||||
}
|
||||
|
||||
private class DataByteMode(type: DataValueType) : DataValueMode(1u, type) {
|
||||
override fun printRaw(ins: CodeUnit) = "$" + toHex(ins.byte)
|
||||
override fun referencedAddress(ins: CodeUnit): SnesAddress? = type.resolve(ins.byte, ins.preState, ins.memory)
|
||||
}
|
||||
|
||||
private class DataWordMode(type: DataValueType) : DataValueMode(2u, type) {
|
||||
override fun printRaw(ins: CodeUnit) = "$" + toHex(ins.word)
|
||||
override fun referencedAddress(ins: CodeUnit): SnesAddress? = type.resolve(ins.word, ins.preState, ins.memory)
|
||||
}
|
||||
|
||||
private class DataLongMode(type: DataValueType) : DataValueMode(3u, type) {
|
||||
override fun printRaw(ins: CodeUnit) = "$" + toHex(ins.long)
|
||||
override fun referencedAddress(ins: CodeUnit): SnesAddress? = type.resolve(ins.long, ins.preState, ins.memory)
|
||||
}
|
||||
|
||||
object Implied : Mode {
|
||||
override val canHaveLabel = false
|
||||
override val showLengthSuffix = false
|
||||
override fun operandLength(state: State) = 0u
|
||||
override fun printRaw(ins: CodeUnit) = ""
|
||||
override fun referencedAddress(ins: CodeUnit): SnesAddress? = null
|
||||
}
|
||||
|
||||
object Immediate8 : Mode {
|
||||
override val canHaveLabel = false
|
||||
override val showLengthSuffix = false
|
||||
override fun operandLength(state: State) = 1u
|
||||
override fun printRaw(ins: CodeUnit) = "#$" + toHex(ins.byte)
|
||||
override fun referencedAddress(ins: CodeUnit): SnesAddress? = null
|
||||
}
|
||||
|
||||
object Immediate16 : Mode {
|
||||
override val canHaveLabel = false
|
||||
override val showLengthSuffix = false
|
||||
override fun operandLength(state: State) = 2u
|
||||
override fun printRaw(ins: CodeUnit) = "#$" + toHex(ins.word)
|
||||
override fun referencedAddress(ins: CodeUnit): SnesAddress? = null
|
||||
}
|
||||
|
||||
object Direct : Mode {
|
||||
override val canHaveLabel = true
|
||||
override fun operandLength(state: State) = 1u
|
||||
override fun printRaw(ins: CodeUnit) = "$" + toHex(ins.byte)
|
||||
override fun referencedAddress(ins: CodeUnit) = ins.preState?.resolveDirectPage(ins.byte)
|
||||
}
|
||||
|
||||
object Absolute : Mode {
|
||||
override val canHaveLabel = true
|
||||
override fun operandLength(state: State) = 2u
|
||||
override fun printRaw(ins: CodeUnit) = "$" + toHex(ins.word)
|
||||
override fun referencedAddress(ins: CodeUnit) = ins.preState?.resolveAbsoluteData(ins.word)
|
||||
}
|
||||
|
||||
object AbsoluteCode : Mode {
|
||||
override val canHaveLabel = true
|
||||
override fun operandLength(state: State) = 2u
|
||||
override fun printRaw(ins: CodeUnit) = "$" + toHex(ins.word)
|
||||
override fun referencedAddress(ins: CodeUnit) = ins.preState?.resolveAbsoluteCode(ins.word)
|
||||
}
|
||||
|
||||
object AbsoluteLong : Mode {
|
||||
override val canHaveLabel = true
|
||||
override fun operandLength(state: State) = 3u
|
||||
override fun printRaw(ins: CodeUnit) = "$" + toHex(ins.long)
|
||||
override fun referencedAddress(ins: CodeUnit) = ins.memory.toCanonical(SnesAddress(ins.long))
|
||||
}
|
||||
|
||||
private object ImmediateUnknownMode : Mode {
|
||||
override val canHaveLabel = false
|
||||
override fun operandLength(state: State): UInt? = null
|
||||
override fun printRaw(ins: CodeUnit) = "???"
|
||||
override fun referencedAddress(ins: CodeUnit): SnesAddress? = null
|
||||
}
|
||||
|
||||
object ImmediateM : MultiMode(ImmediateUnknownMode, Immediate8, Immediate16) {
|
||||
override fun pickMode(state: State) = state.mWidth ?: 0u
|
||||
}
|
||||
|
||||
object ImmediateX : MultiMode(ImmediateUnknownMode, Immediate8, Immediate16) {
|
||||
override fun pickMode(state: State) = state.xWidth ?: 0u
|
||||
}
|
||||
|
||||
abstract class BaseRelativeMode(private val length: UInt) : Mode {
|
||||
override val showLengthSuffix = false
|
||||
override fun operandLength(state: State) = length
|
||||
override fun printRaw(ins: CodeUnit) = "$" + referencedAddress(ins).toSimpleString()
|
||||
override fun referencedAddress(ins: CodeUnit) = ins.memory.toCanonical(ins.relativeAddress + (relativeOffset(ins) + 1 + length.toInt()))
|
||||
protected abstract fun relativeOffset(ins: CodeUnit): Int
|
||||
}
|
||||
|
||||
object Relative : BaseRelativeMode(1u) {
|
||||
override val canHaveLabel = true
|
||||
override fun relativeOffset(ins: CodeUnit) = ins.signedByte.toInt()
|
||||
}
|
||||
|
||||
object RelativeLong : BaseRelativeMode(2u) {
|
||||
override val canHaveLabel = true
|
||||
override fun relativeOffset(ins: CodeUnit) = ins.signedWord.toInt()
|
||||
}
|
||||
|
||||
object BlockMove : Mode {
|
||||
override val canHaveLabel = false
|
||||
override val showLengthSuffix = false
|
||||
|
||||
override fun operandLength(state: State) = 2u
|
||||
|
||||
override fun printRaw(ins: CodeUnit) = String.format("#$%02x,#$%02x", ins.byte.toInt(), ins.byte2.toInt())
|
||||
|
||||
override fun referencedAddress(ins: CodeUnit): SnesAddress? = null
|
||||
}
|
||||
|
||||
private class IndexXMode(parent: Mode) : WrappedMode(parent, suffix = ",x")
|
||||
private class IndexYMode(parent: Mode) : WrappedMode(parent, suffix = ",y")
|
||||
private class IndexSMode(parent: Mode) : RawWrappedMode(parent, suffix = ",s")
|
||||
private class IndirectMode(parent: Mode) : WrappedMode(parent, "(", ")")
|
||||
private class IndirectLongMode(parent: Mode) : WrappedMode(parent, "[", "]")
|
||||
|
@ -3,7 +3,6 @@ package com.smallhacker.disbrowser.asm
|
||||
import java.util.HashMap
|
||||
|
||||
import com.smallhacker.disbrowser.asm.Mnemonic.*
|
||||
import com.smallhacker.disbrowser.asm.Mode.*
|
||||
|
||||
typealias SegmentEnder = Instruction.() -> SegmentEnd?
|
||||
|
||||
@ -46,12 +45,13 @@ class Opcode private constructor(val mnemonic: Mnemonic, val mode: Mode, val end
|
||||
}
|
||||
|
||||
companion object {
|
||||
val DATA_BYTE = Opcode(Mnemonic.DB, Mode.DATA_BYTE, { null }, { it.preState })
|
||||
val DATA_WORD = Opcode(Mnemonic.DW, Mode.DATA_WORD, { null }, { it.preState })
|
||||
val DATA_LONG = Opcode(Mnemonic.DL, Mode.DATA_LONG, { null }, { it.preState })
|
||||
|
||||
val POINTER_WORD = Opcode(Mnemonic.DW, Mode.CODE_WORD, { null }, { it.preState }).linking()
|
||||
val POINTER_LONG = Opcode(Mnemonic.DL, Mode.CODE_LONG, { null }, { it.preState }).linking()
|
||||
val DATA_BYTE = Opcode(Mnemonic.DB, DirectData.byte, { null }, { it.preState })
|
||||
val DATA_WORD = Opcode(Mnemonic.DW, DirectData.word, { null }, { it.preState })
|
||||
val DATA_LONG = Opcode(Mnemonic.DL, DirectData.long, { null }, { it.preState })
|
||||
val DATA_POINTER_WORD = Opcode(Mnemonic.DW, DataPointer.word, { null }, { it.preState }).linking()
|
||||
val DATA_POINTER_LONG = Opcode(Mnemonic.DL, DataPointer.long, { null }, { it.preState }).linking()
|
||||
val CODE_POINTER_WORD = Opcode(Mnemonic.DW, CodePointer.word, { null }, { it.preState }).linking()
|
||||
val CODE_POINTER_LONG = Opcode(Mnemonic.DL, CodePointer.long, { null }, { it.preState }).linking()
|
||||
|
||||
val UNKNOWN_OPCODE: Opcode
|
||||
|
||||
@ -80,284 +80,284 @@ class Opcode private constructor(val mnemonic: Mnemonic, val mode: Mode, val end
|
||||
val dynamicSubJumping: SegmentEnder = { stoppingSegmentEnd(address) }
|
||||
val returning: SegmentEnder = { returnSegmentEnd(address) }
|
||||
|
||||
UNKNOWN_OPCODE = Opcode(UNKNOWN, IMPLIED, alwaysStop, Instruction::preState).stop()
|
||||
UNKNOWN_OPCODE = Opcode(UNKNOWN, Implied, alwaysStop, Instruction::preState).stop()
|
||||
|
||||
add(0x00, BRK, IMMEDIATE_8, alwaysStop).stop()
|
||||
add(0x02, COP, IMMEDIATE_8, alwaysStop).stop()
|
||||
add(0x42, WDM, IMMEDIATE_8, alwaysStop).stop()
|
||||
add(0x00, BRK, Immediate8, alwaysStop).stop()
|
||||
add(0x02, COP, Immediate8, alwaysStop).stop()
|
||||
add(0x42, WDM, Immediate8, alwaysStop).stop()
|
||||
|
||||
add(0xEA, NOP, IMPLIED, alwaysContinue)
|
||||
add(0xEA, NOP, Implied, alwaysContinue)
|
||||
|
||||
add(0xDB, STP, IMPLIED, alwaysStop).stop()
|
||||
add(0xCB, WAI, IMPLIED, alwaysContinue)
|
||||
add(0xDB, STP, Implied, alwaysStop).stop()
|
||||
add(0xCB, WAI, Implied, alwaysContinue)
|
||||
|
||||
add(0x10, BPL, RELATIVE, branching).branching()
|
||||
add(0x30, BMI, RELATIVE, branching).branching()
|
||||
add(0x50, BVC, RELATIVE, branching).branching()
|
||||
add(0x70, BVS, RELATIVE, branching).branching()
|
||||
add(0x80, BRA, RELATIVE, alwaysBranching).stop().branching()
|
||||
add(0x90, BCC, RELATIVE, branching).branching()
|
||||
add(0xB0, BCS, RELATIVE, branching).branching()
|
||||
add(0xD0, BNE, RELATIVE, branching).branching()
|
||||
add(0xF0, BEQ, RELATIVE, branching).branching()
|
||||
add(0x82, BRL, RELATIVE_LONG, alwaysBranching).stop().branching()
|
||||
add(0x10, BPL, Relative, branching).branching()
|
||||
add(0x30, BMI, Relative, branching).branching()
|
||||
add(0x50, BVC, Relative, branching).branching()
|
||||
add(0x70, BVS, Relative, branching).branching()
|
||||
add(0x80, BRA, Relative, alwaysBranching).stop().branching()
|
||||
add(0x90, BCC, Relative, branching).branching()
|
||||
add(0xB0, BCS, Relative, branching).branching()
|
||||
add(0xD0, BNE, Relative, branching).branching()
|
||||
add(0xF0, BEQ, Relative, branching).branching()
|
||||
add(0x82, BRL, RelativeLong, alwaysBranching).stop().branching()
|
||||
|
||||
add(0x4C, JMP, ABSOLUTE_CODE, jumping).linking().stop()
|
||||
add(0x5C, JML, ABSOLUTE_LONG, jumping).linking().stop()
|
||||
add(0x6C, JMP, ABSOLUTE_INDIRECT, dynamicJumping).stop()
|
||||
add(0x7C, JMP, ABSOLUTE_X_INDIRECT, dynamicJumping).stop()
|
||||
add(0xDC, JMP, ABSOLUTE_INDIRECT_LONG, dynamicJumping).stop()
|
||||
add(0x4C, JMP, AbsoluteCode, jumping).linking().stop()
|
||||
add(0x5C, JML, AbsoluteLong, jumping).linking().stop()
|
||||
add(0x6C, JMP, Absolute.indirect, dynamicJumping).stop()
|
||||
add(0x7C, JMP, Absolute.x.indirect, dynamicJumping).stop()
|
||||
add(0xDC, JMP, Absolute.indirectLong, dynamicJumping).stop()
|
||||
|
||||
add(0x22, JSL, ABSOLUTE_LONG, subJumping).linking().mayStop()
|
||||
add(0x20, JSR, ABSOLUTE_CODE, subJumping).linking().mayStop()
|
||||
add(0xFC, JSR, ABSOLUTE_X_INDIRECT, dynamicSubJumping).mayStop()
|
||||
add(0x22, JSL, AbsoluteLong, subJumping).linking().mayStop()
|
||||
add(0x20, JSR, AbsoluteCode, subJumping).linking().mayStop()
|
||||
add(0xFC, JSR, Absolute.x.indirect, dynamicSubJumping).mayStop()
|
||||
|
||||
add(0x60, RTS, IMPLIED, returning).stop()
|
||||
add(0x6B, RTL, IMPLIED, returning).stop()
|
||||
add(0x40, RTI, IMPLIED, returning).stop()
|
||||
add(0x60, RTS, Implied, returning).stop()
|
||||
add(0x6B, RTL, Implied, returning).stop()
|
||||
add(0x40, RTI, Implied, returning).stop()
|
||||
|
||||
add(0x1B, TCS, IMPLIED, alwaysContinue)
|
||||
add(0x3B, TSC, IMPLIED, alwaysContinue)
|
||||
add(0x5B, TCD, IMPLIED, alwaysContinue)
|
||||
add(0x7B, TDC, IMPLIED, alwaysContinue)
|
||||
add(0xAA, TAX, IMPLIED, alwaysContinue)
|
||||
add(0xA8, TAY, IMPLIED, alwaysContinue)
|
||||
add(0xBA, TSX, IMPLIED, alwaysContinue)
|
||||
add(0x8A, TXA, IMPLIED, alwaysContinue)
|
||||
add(0x9A, TXS, IMPLIED, alwaysContinue)
|
||||
add(0x9B, TXY, IMPLIED, alwaysContinue)
|
||||
add(0x98, TYA, IMPLIED, alwaysContinue)
|
||||
add(0xBB, TYX, IMPLIED, alwaysContinue)
|
||||
add(0xEB, XBA, IMPLIED, alwaysContinue)
|
||||
add(0x1B, TCS, Implied, alwaysContinue)
|
||||
add(0x3B, TSC, Implied, alwaysContinue)
|
||||
add(0x5B, TCD, Implied, alwaysContinue)
|
||||
add(0x7B, TDC, Implied, alwaysContinue)
|
||||
add(0xAA, TAX, Implied, alwaysContinue)
|
||||
add(0xA8, TAY, Implied, alwaysContinue)
|
||||
add(0xBA, TSX, Implied, alwaysContinue)
|
||||
add(0x8A, TXA, Implied, alwaysContinue)
|
||||
add(0x9A, TXS, Implied, alwaysContinue)
|
||||
add(0x9B, TXY, Implied, alwaysContinue)
|
||||
add(0x98, TYA, Implied, alwaysContinue)
|
||||
add(0xBB, TYX, Implied, alwaysContinue)
|
||||
add(0xEB, XBA, Implied, alwaysContinue)
|
||||
|
||||
add(0x18, CLC, IMPLIED, alwaysContinue)
|
||||
add(0x38, SEC, IMPLIED, alwaysContinue)
|
||||
add(0x58, CLI, IMPLIED, alwaysContinue)
|
||||
add(0x78, SEI, IMPLIED, alwaysContinue)
|
||||
add(0xF8, SED, IMPLIED, alwaysContinue)
|
||||
add(0xD8, CLD, IMPLIED, alwaysContinue)
|
||||
add(0xB8, CLV, IMPLIED, alwaysContinue)
|
||||
add(0xE2, SEP, IMMEDIATE_8, alwaysContinue) { it.preState.sep(it.bytes[1u]) }
|
||||
add(0xC2, REP, IMMEDIATE_8, alwaysContinue) { it.preState.rep(it.bytes[1u]) }
|
||||
add(0xFB, XCE, IMPLIED, alwaysContinue)
|
||||
add(0x18, CLC, Implied, alwaysContinue)
|
||||
add(0x38, SEC, Implied, alwaysContinue)
|
||||
add(0x58, CLI, Implied, alwaysContinue)
|
||||
add(0x78, SEI, Implied, alwaysContinue)
|
||||
add(0xF8, SED, Implied, alwaysContinue)
|
||||
add(0xD8, CLD, Implied, alwaysContinue)
|
||||
add(0xB8, CLV, Implied, alwaysContinue)
|
||||
add(0xE2, SEP, Immediate8, alwaysContinue) { it.preState.sep(it.bytes[1u]) }
|
||||
add(0xC2, REP, Immediate8, alwaysContinue) { it.preState.rep(it.bytes[1u]) }
|
||||
add(0xFB, XCE, Implied, alwaysContinue)
|
||||
|
||||
add(0xC1, CMP, DIRECT_X_INDIRECT, alwaysContinue)
|
||||
add(0xC3, CMP, DIRECT_S, alwaysContinue)
|
||||
add(0xC5, CMP, DIRECT, alwaysContinue)
|
||||
add(0xC7, CMP, DIRECT_INDIRECT_LONG, alwaysContinue)
|
||||
add(0xC9, CMP, IMMEDIATE_M, alwaysContinue)
|
||||
add(0xCD, CMP, ABSOLUTE, alwaysContinue)
|
||||
add(0xCF, CMP, ABSOLUTE_LONG, alwaysContinue)
|
||||
add(0xD1, CMP, DIRECT_INDIRECT_Y, alwaysContinue)
|
||||
add(0xD2, CMP, DIRECT_INDIRECT, alwaysContinue)
|
||||
add(0xD3, CMP, DIRECT_S_INDIRECT_Y, alwaysContinue)
|
||||
add(0xD5, CMP, DIRECT_X, alwaysContinue)
|
||||
add(0xD7, CMP, DIRECT_INDIRECT_LONG_Y, alwaysContinue)
|
||||
add(0xD9, CMP, ABSOLUTE_Y, alwaysContinue)
|
||||
add(0xDD, CMP, ABSOLUTE_X, alwaysContinue)
|
||||
add(0xDF, CMP, ABSOLUTE_LONG_X, alwaysContinue)
|
||||
add(0xE0, CPX, IMMEDIATE_X, alwaysContinue)
|
||||
add(0xE4, CPX, DIRECT, alwaysContinue)
|
||||
add(0xEC, CPX, ABSOLUTE, alwaysContinue)
|
||||
add(0xC0, CPY, IMMEDIATE_X, alwaysContinue)
|
||||
add(0xC4, CPY, DIRECT, alwaysContinue)
|
||||
add(0xCC, CPY, ABSOLUTE, alwaysContinue)
|
||||
add(0xC1, CMP, Direct.x.indirect, alwaysContinue)
|
||||
add(0xC3, CMP, Direct.s, alwaysContinue)
|
||||
add(0xC5, CMP, Direct, alwaysContinue)
|
||||
add(0xC7, CMP, Direct.indirectLong, alwaysContinue)
|
||||
add(0xC9, CMP, ImmediateM, alwaysContinue)
|
||||
add(0xCD, CMP, Absolute, alwaysContinue)
|
||||
add(0xCF, CMP, AbsoluteLong, alwaysContinue)
|
||||
add(0xD1, CMP, Direct.indirect.y, alwaysContinue)
|
||||
add(0xD2, CMP, Direct.indirect, alwaysContinue)
|
||||
add(0xD3, CMP, Direct.s.indirect.y, alwaysContinue)
|
||||
add(0xD5, CMP, Direct.x, alwaysContinue)
|
||||
add(0xD7, CMP, Direct.indirectLong.y, alwaysContinue)
|
||||
add(0xD9, CMP, Absolute.y, alwaysContinue)
|
||||
add(0xDD, CMP, Absolute.x, alwaysContinue)
|
||||
add(0xDF, CMP, AbsoluteLong.x, alwaysContinue)
|
||||
add(0xE0, CPX, ImmediateX, alwaysContinue)
|
||||
add(0xE4, CPX, Direct, alwaysContinue)
|
||||
add(0xEC, CPX, Absolute, alwaysContinue)
|
||||
add(0xC0, CPY, ImmediateX, alwaysContinue)
|
||||
add(0xC4, CPY, Direct, alwaysContinue)
|
||||
add(0xCC, CPY, Absolute, alwaysContinue)
|
||||
|
||||
add(0xA1, LDA, DIRECT_X_INDIRECT, alwaysContinue)
|
||||
add(0xA3, LDA, DIRECT_S, alwaysContinue)
|
||||
add(0xA5, LDA, DIRECT, alwaysContinue)
|
||||
add(0xA7, LDA, DIRECT_INDIRECT_LONG, alwaysContinue)
|
||||
add(0xA9, LDA, IMMEDIATE_M, alwaysContinue)
|
||||
add(0xAD, LDA, ABSOLUTE, alwaysContinue)
|
||||
add(0xAF, LDA, ABSOLUTE_LONG, alwaysContinue)
|
||||
add(0xB1, LDA, DIRECT_INDIRECT_Y, alwaysContinue)
|
||||
add(0xB2, LDA, DIRECT_INDIRECT, alwaysContinue)
|
||||
add(0xB3, LDA, DIRECT_S_INDIRECT_Y, alwaysContinue)
|
||||
add(0xB5, LDA, DIRECT_X, alwaysContinue)
|
||||
add(0xB7, LDA, DIRECT_INDIRECT_LONG_Y, alwaysContinue)
|
||||
add(0xB9, LDA, ABSOLUTE_Y, alwaysContinue)
|
||||
add(0xBD, LDA, ABSOLUTE_X, alwaysContinue)
|
||||
add(0xBF, LDA, ABSOLUTE_LONG_X, alwaysContinue)
|
||||
add(0xA2, LDX, IMMEDIATE_X, alwaysContinue)
|
||||
add(0xA6, LDX, DIRECT, alwaysContinue)
|
||||
add(0xAE, LDX, ABSOLUTE, alwaysContinue)
|
||||
add(0xB6, LDX, DIRECT_Y, alwaysContinue)
|
||||
add(0xBE, LDX, ABSOLUTE_Y, alwaysContinue)
|
||||
add(0xA0, LDY, IMMEDIATE_X, alwaysContinue)
|
||||
add(0xA4, LDY, DIRECT, alwaysContinue)
|
||||
add(0xAC, LDY, ABSOLUTE, alwaysContinue)
|
||||
add(0xB4, LDY, DIRECT_X, alwaysContinue)
|
||||
add(0xBC, LDY, ABSOLUTE_X, alwaysContinue)
|
||||
add(0x81, STA, DIRECT_X_INDIRECT, alwaysContinue)
|
||||
add(0x83, STA, DIRECT_S, alwaysContinue)
|
||||
add(0x85, STA, DIRECT, alwaysContinue)
|
||||
add(0x87, STA, DIRECT_INDIRECT_LONG, alwaysContinue)
|
||||
add(0x8D, STA, ABSOLUTE, alwaysContinue)
|
||||
add(0x8F, STA, ABSOLUTE_LONG, alwaysContinue)
|
||||
add(0x91, STA, DIRECT_INDIRECT_Y, alwaysContinue)
|
||||
add(0x92, STA, DIRECT_INDIRECT, alwaysContinue)
|
||||
add(0x93, STA, DIRECT_S_INDIRECT_Y, alwaysContinue)
|
||||
add(0x95, STA, DIRECT_X, alwaysContinue)
|
||||
add(0x97, STA, DIRECT_INDIRECT_LONG_Y, alwaysContinue)
|
||||
add(0x99, STA, ABSOLUTE_Y, alwaysContinue)
|
||||
add(0x9D, STA, ABSOLUTE_X, alwaysContinue)
|
||||
add(0x9F, STA, ABSOLUTE_LONG_X, alwaysContinue)
|
||||
add(0x86, STX, DIRECT, alwaysContinue)
|
||||
add(0x8E, STX, ABSOLUTE, alwaysContinue)
|
||||
add(0x96, STX, DIRECT_Y, alwaysContinue)
|
||||
add(0x84, STY, DIRECT, alwaysContinue)
|
||||
add(0x8C, STY, ABSOLUTE, alwaysContinue)
|
||||
add(0x94, STY, DIRECT_X, alwaysContinue)
|
||||
add(0x64, STZ, DIRECT, alwaysContinue)
|
||||
add(0x74, STZ, DIRECT_X, alwaysContinue)
|
||||
add(0x9C, STZ, ABSOLUTE, alwaysContinue)
|
||||
add(0x9E, STZ, ABSOLUTE_X, alwaysContinue)
|
||||
add(0xA1, LDA, Direct.x.indirect, alwaysContinue)
|
||||
add(0xA3, LDA, Direct.s, alwaysContinue)
|
||||
add(0xA5, LDA, Direct, alwaysContinue)
|
||||
add(0xA7, LDA, Direct.indirectLong, alwaysContinue)
|
||||
add(0xA9, LDA, ImmediateM, alwaysContinue)
|
||||
add(0xAD, LDA, Absolute, alwaysContinue)
|
||||
add(0xAF, LDA, AbsoluteLong, alwaysContinue)
|
||||
add(0xB1, LDA, Direct.indirect.y, alwaysContinue)
|
||||
add(0xB2, LDA, Direct.indirect, alwaysContinue)
|
||||
add(0xB3, LDA, Direct.s.indirect.y, alwaysContinue)
|
||||
add(0xB5, LDA, Direct.x, alwaysContinue)
|
||||
add(0xB7, LDA, Direct.indirectLong.y, alwaysContinue)
|
||||
add(0xB9, LDA, Absolute.y, alwaysContinue)
|
||||
add(0xBD, LDA, Absolute.x, alwaysContinue)
|
||||
add(0xBF, LDA, AbsoluteLong.x, alwaysContinue)
|
||||
add(0xA2, LDX, ImmediateX, alwaysContinue)
|
||||
add(0xA6, LDX, Direct, alwaysContinue)
|
||||
add(0xAE, LDX, Absolute, alwaysContinue)
|
||||
add(0xB6, LDX, Direct.y, alwaysContinue)
|
||||
add(0xBE, LDX, Absolute.y, alwaysContinue)
|
||||
add(0xA0, LDY, ImmediateX, alwaysContinue)
|
||||
add(0xA4, LDY, Direct, alwaysContinue)
|
||||
add(0xAC, LDY, Absolute, alwaysContinue)
|
||||
add(0xB4, LDY, Direct.x, alwaysContinue)
|
||||
add(0xBC, LDY, Absolute.x, alwaysContinue)
|
||||
add(0x81, STA, Direct.x.indirect, alwaysContinue)
|
||||
add(0x83, STA, Direct.s, alwaysContinue)
|
||||
add(0x85, STA, Direct, alwaysContinue)
|
||||
add(0x87, STA, Direct.indirectLong, alwaysContinue)
|
||||
add(0x8D, STA, Absolute, alwaysContinue)
|
||||
add(0x8F, STA, AbsoluteLong, alwaysContinue)
|
||||
add(0x91, STA, Direct.indirect.y, alwaysContinue)
|
||||
add(0x92, STA, Direct.indirect, alwaysContinue)
|
||||
add(0x93, STA, Direct.s.indirect.y, alwaysContinue)
|
||||
add(0x95, STA, Direct.x, alwaysContinue)
|
||||
add(0x97, STA, Direct.indirectLong.y, alwaysContinue)
|
||||
add(0x99, STA, Absolute.y, alwaysContinue)
|
||||
add(0x9D, STA, Absolute.x, alwaysContinue)
|
||||
add(0x9F, STA, AbsoluteLong.x, alwaysContinue)
|
||||
add(0x86, STX, Direct, alwaysContinue)
|
||||
add(0x8E, STX, Absolute, alwaysContinue)
|
||||
add(0x96, STX, Direct.y, alwaysContinue)
|
||||
add(0x84, STY, Direct, alwaysContinue)
|
||||
add(0x8C, STY, Absolute, alwaysContinue)
|
||||
add(0x94, STY, Direct.x, alwaysContinue)
|
||||
add(0x64, STZ, Direct, alwaysContinue)
|
||||
add(0x74, STZ, Direct.x, alwaysContinue)
|
||||
add(0x9C, STZ, Absolute, alwaysContinue)
|
||||
add(0x9E, STZ, Absolute.x, alwaysContinue)
|
||||
|
||||
add(0x48, PHA, IMPLIED, alwaysContinue) { it.preState.pushUnknown(it.preState.mWidth) }
|
||||
add(0xDA, PHX, IMPLIED, alwaysContinue) { it.preState.pushUnknown(it.preState.xWidth) }
|
||||
add(0x5A, PHY, IMPLIED, alwaysContinue) { it.preState.pushUnknown(it.preState.xWidth) }
|
||||
add(0x68, PLA, IMPLIED, alwaysContinue) { it.preState.pull(it.preState.mWidth) }
|
||||
add(0xFA, PLX, IMPLIED, alwaysContinue) { it.preState.pull(it.preState.xWidth) }
|
||||
add(0x7A, PLY, IMPLIED, alwaysContinue) { it.preState.pull(it.preState.xWidth) }
|
||||
add(0x48, PHA, Implied, alwaysContinue) { it.preState.pushUnknown(it.preState.mWidth) }
|
||||
add(0xDA, PHX, Implied, alwaysContinue) { it.preState.pushUnknown(it.preState.xWidth) }
|
||||
add(0x5A, PHY, Implied, alwaysContinue) { it.preState.pushUnknown(it.preState.xWidth) }
|
||||
add(0x68, PLA, Implied, alwaysContinue) { it.preState.pull(it.preState.mWidth) }
|
||||
add(0xFA, PLX, Implied, alwaysContinue) { it.preState.pull(it.preState.xWidth) }
|
||||
add(0x7A, PLY, Implied, alwaysContinue) { it.preState.pull(it.preState.xWidth) }
|
||||
|
||||
add(0x8B, PHB, IMPLIED, alwaysContinue) { it.preState.pushUnknown(1u) }
|
||||
add(0xAB, PLB, IMPLIED, alwaysContinue) { it.preState.pull(1u) }
|
||||
add(0x0B, PHD, IMPLIED, alwaysContinue) { it.preState.pushUnknown(1u) }
|
||||
add(0x2B, PLD, IMPLIED, alwaysContinue) { it.preState.pull(1u) }
|
||||
add(0x4B, PHK, IMPLIED, alwaysContinue) { it.preState.push((it.address.value shr 16).toUInt()) }
|
||||
add(0x08, PHP, IMPLIED, alwaysContinue) { it.preState.push(it.preState.flags) }
|
||||
add(0x28, PLP, IMPLIED, alwaysContinue) { it.preState.pull { copy(flags = it) } }
|
||||
add(0x8B, PHB, Implied, alwaysContinue) { it.preState.pushUnknown(1u) }
|
||||
add(0xAB, PLB, Implied, alwaysContinue) { it.preState.pull(1u) }
|
||||
add(0x0B, PHD, Implied, alwaysContinue) { it.preState.pushUnknown(1u) }
|
||||
add(0x2B, PLD, Implied, alwaysContinue) { it.preState.pull(1u) }
|
||||
add(0x4B, PHK, Implied, alwaysContinue) { it.preState.push((it.address.value shr 16).toUInt()) }
|
||||
add(0x08, PHP, Implied, alwaysContinue) { it.preState.push(it.preState.flags) }
|
||||
add(0x28, PLP, Implied, alwaysContinue) { it.preState.pull { copy(flags = it) } }
|
||||
|
||||
add(0x3A, DEC, IMPLIED, alwaysContinue)
|
||||
add(0xC6, DEC, DIRECT, alwaysContinue)
|
||||
add(0xCE, DEC, ABSOLUTE, alwaysContinue)
|
||||
add(0xD6, DEC, DIRECT_X, alwaysContinue)
|
||||
add(0xDE, DEC, ABSOLUTE_X, alwaysContinue)
|
||||
add(0xCA, DEX, IMPLIED, alwaysContinue)
|
||||
add(0x88, DEY, IMPLIED, alwaysContinue)
|
||||
add(0x1A, INC, IMPLIED, alwaysContinue)
|
||||
add(0xE6, INC, DIRECT, alwaysContinue)
|
||||
add(0xEE, INC, ABSOLUTE, alwaysContinue)
|
||||
add(0xF6, INC, DIRECT_X, alwaysContinue)
|
||||
add(0xFE, INC, ABSOLUTE_X, alwaysContinue)
|
||||
add(0xE8, INX, IMPLIED, alwaysContinue)
|
||||
add(0xC8, INY, IMPLIED, alwaysContinue)
|
||||
add(0x3A, DEC, Implied, alwaysContinue)
|
||||
add(0xC6, DEC, Direct, alwaysContinue)
|
||||
add(0xCE, DEC, Absolute, alwaysContinue)
|
||||
add(0xD6, DEC, Direct.x, alwaysContinue)
|
||||
add(0xDE, DEC, Absolute.x, alwaysContinue)
|
||||
add(0xCA, DEX, Implied, alwaysContinue)
|
||||
add(0x88, DEY, Implied, alwaysContinue)
|
||||
add(0x1A, INC, Implied, alwaysContinue)
|
||||
add(0xE6, INC, Direct, alwaysContinue)
|
||||
add(0xEE, INC, Absolute, alwaysContinue)
|
||||
add(0xF6, INC, Direct.x, alwaysContinue)
|
||||
add(0xFE, INC, Absolute.x, alwaysContinue)
|
||||
add(0xE8, INX, Implied, alwaysContinue)
|
||||
add(0xC8, INY, Implied, alwaysContinue)
|
||||
|
||||
add(0x06, ASL, DIRECT, alwaysContinue)
|
||||
add(0x0A, ASL, IMPLIED, alwaysContinue)
|
||||
add(0x0E, ASL, ABSOLUTE, alwaysContinue)
|
||||
add(0x16, ASL, DIRECT_X, alwaysContinue)
|
||||
add(0x1E, ASL, ABSOLUTE_X, alwaysContinue)
|
||||
add(0x46, LSR, DIRECT, alwaysContinue)
|
||||
add(0x4A, LSR, IMPLIED, alwaysContinue)
|
||||
add(0x4E, LSR, ABSOLUTE, alwaysContinue)
|
||||
add(0x56, LSR, DIRECT_X, alwaysContinue)
|
||||
add(0x5E, LSR, ABSOLUTE_X, alwaysContinue)
|
||||
add(0x26, ROL, DIRECT, alwaysContinue)
|
||||
add(0x2A, ROL, IMPLIED, alwaysContinue)
|
||||
add(0x2E, ROL, ABSOLUTE, alwaysContinue)
|
||||
add(0x36, ROL, DIRECT_X, alwaysContinue)
|
||||
add(0x3E, ROL, ABSOLUTE_X, alwaysContinue)
|
||||
add(0x66, ROR, DIRECT, alwaysContinue)
|
||||
add(0x6A, ROR, IMPLIED, alwaysContinue)
|
||||
add(0x6E, ROR, ABSOLUTE, alwaysContinue)
|
||||
add(0x76, ROR, DIRECT_X, alwaysContinue)
|
||||
add(0x7E, ROR, ABSOLUTE_X, alwaysContinue)
|
||||
add(0x06, ASL, Direct, alwaysContinue)
|
||||
add(0x0A, ASL, Implied, alwaysContinue)
|
||||
add(0x0E, ASL, Absolute, alwaysContinue)
|
||||
add(0x16, ASL, Direct.x, alwaysContinue)
|
||||
add(0x1E, ASL, Absolute.x, alwaysContinue)
|
||||
add(0x46, LSR, Direct, alwaysContinue)
|
||||
add(0x4A, LSR, Implied, alwaysContinue)
|
||||
add(0x4E, LSR, Absolute, alwaysContinue)
|
||||
add(0x56, LSR, Direct.x, alwaysContinue)
|
||||
add(0x5E, LSR, Absolute.x, alwaysContinue)
|
||||
add(0x26, ROL, Direct, alwaysContinue)
|
||||
add(0x2A, ROL, Implied, alwaysContinue)
|
||||
add(0x2E, ROL, Absolute, alwaysContinue)
|
||||
add(0x36, ROL, Direct.x, alwaysContinue)
|
||||
add(0x3E, ROL, Absolute.x, alwaysContinue)
|
||||
add(0x66, ROR, Direct, alwaysContinue)
|
||||
add(0x6A, ROR, Implied, alwaysContinue)
|
||||
add(0x6E, ROR, Absolute, alwaysContinue)
|
||||
add(0x76, ROR, Direct.x, alwaysContinue)
|
||||
add(0x7E, ROR, Absolute.x, alwaysContinue)
|
||||
|
||||
add(0x61, ADC, DIRECT_X_INDIRECT, alwaysContinue)
|
||||
add(0x63, ADC, DIRECT_S, alwaysContinue)
|
||||
add(0x65, ADC, DIRECT, alwaysContinue)
|
||||
add(0x67, ADC, DIRECT_INDIRECT_LONG, alwaysContinue)
|
||||
add(0x69, ADC, IMMEDIATE_M, alwaysContinue)
|
||||
add(0x6D, ADC, ABSOLUTE, alwaysContinue)
|
||||
add(0x6F, ADC, ABSOLUTE_LONG, alwaysContinue)
|
||||
add(0x71, ADC, DIRECT_INDIRECT_Y, alwaysContinue)
|
||||
add(0x72, ADC, DIRECT_INDIRECT, alwaysContinue)
|
||||
add(0x73, ADC, DIRECT_S_INDIRECT_Y, alwaysContinue)
|
||||
add(0x75, ADC, DIRECT_X, alwaysContinue)
|
||||
add(0x77, ADC, DIRECT_INDIRECT_LONG_Y, alwaysContinue)
|
||||
add(0x79, ADC, ABSOLUTE_Y, alwaysContinue)
|
||||
add(0x7D, ADC, ABSOLUTE_X, alwaysContinue)
|
||||
add(0x7F, ADC, ABSOLUTE_LONG_X, alwaysContinue)
|
||||
add(0xE1, SBC, DIRECT_X_INDIRECT, alwaysContinue)
|
||||
add(0xE3, SBC, DIRECT_S, alwaysContinue)
|
||||
add(0xE5, SBC, DIRECT, alwaysContinue)
|
||||
add(0xE7, SBC, DIRECT_INDIRECT_LONG, alwaysContinue)
|
||||
add(0xE9, SBC, IMMEDIATE_M, alwaysContinue)
|
||||
add(0xED, SBC, ABSOLUTE, alwaysContinue)
|
||||
add(0xEF, SBC, ABSOLUTE_LONG, alwaysContinue)
|
||||
add(0xF1, SBC, DIRECT_INDIRECT_Y, alwaysContinue)
|
||||
add(0xF2, SBC, DIRECT_INDIRECT, alwaysContinue)
|
||||
add(0xF3, SBC, DIRECT_S_INDIRECT_Y, alwaysContinue)
|
||||
add(0xF5, SBC, DIRECT_X, alwaysContinue)
|
||||
add(0xF7, SBC, DIRECT_INDIRECT_LONG_Y, alwaysContinue)
|
||||
add(0xF9, SBC, ABSOLUTE_Y, alwaysContinue)
|
||||
add(0xFD, SBC, ABSOLUTE_X, alwaysContinue)
|
||||
add(0xFF, SBC, ABSOLUTE_LONG_X, alwaysContinue)
|
||||
add(0x61, ADC, Direct.x.indirect, alwaysContinue)
|
||||
add(0x63, ADC, Direct.s, alwaysContinue)
|
||||
add(0x65, ADC, Direct, alwaysContinue)
|
||||
add(0x67, ADC, Direct.indirectLong, alwaysContinue)
|
||||
add(0x69, ADC, ImmediateM, alwaysContinue)
|
||||
add(0x6D, ADC, Absolute, alwaysContinue)
|
||||
add(0x6F, ADC, AbsoluteLong, alwaysContinue)
|
||||
add(0x71, ADC, Direct.indirect.y, alwaysContinue)
|
||||
add(0x72, ADC, Direct.indirect, alwaysContinue)
|
||||
add(0x73, ADC, Direct.s.indirect.y, alwaysContinue)
|
||||
add(0x75, ADC, Direct.x, alwaysContinue)
|
||||
add(0x77, ADC, Direct.indirectLong.y, alwaysContinue)
|
||||
add(0x79, ADC, Absolute.y, alwaysContinue)
|
||||
add(0x7D, ADC, Absolute.x, alwaysContinue)
|
||||
add(0x7F, ADC, AbsoluteLong.x, alwaysContinue)
|
||||
add(0xE1, SBC, Direct.x.indirect, alwaysContinue)
|
||||
add(0xE3, SBC, Direct.s, alwaysContinue)
|
||||
add(0xE5, SBC, Direct, alwaysContinue)
|
||||
add(0xE7, SBC, Direct.indirectLong, alwaysContinue)
|
||||
add(0xE9, SBC, ImmediateM, alwaysContinue)
|
||||
add(0xED, SBC, Absolute, alwaysContinue)
|
||||
add(0xEF, SBC, AbsoluteLong, alwaysContinue)
|
||||
add(0xF1, SBC, Direct.indirect.y, alwaysContinue)
|
||||
add(0xF2, SBC, Direct.indirect, alwaysContinue)
|
||||
add(0xF3, SBC, Direct.s.indirect.y, alwaysContinue)
|
||||
add(0xF5, SBC, Direct.x, alwaysContinue)
|
||||
add(0xF7, SBC, Direct.indirectLong.y, alwaysContinue)
|
||||
add(0xF9, SBC, Absolute.y, alwaysContinue)
|
||||
add(0xFD, SBC, Absolute.x, alwaysContinue)
|
||||
add(0xFF, SBC, AbsoluteLong.x, alwaysContinue)
|
||||
|
||||
add(0x21, AND, DIRECT_X_INDIRECT, alwaysContinue)
|
||||
add(0x23, AND, DIRECT_S, alwaysContinue)
|
||||
add(0x25, AND, DIRECT, alwaysContinue)
|
||||
add(0x27, AND, DIRECT_INDIRECT_LONG, alwaysContinue)
|
||||
add(0x29, AND, IMMEDIATE_M, alwaysContinue)
|
||||
add(0x2D, AND, ABSOLUTE, alwaysContinue)
|
||||
add(0x2F, AND, ABSOLUTE_LONG, alwaysContinue)
|
||||
add(0x31, AND, DIRECT_INDIRECT_Y, alwaysContinue)
|
||||
add(0x32, AND, DIRECT_INDIRECT, alwaysContinue)
|
||||
add(0x33, AND, DIRECT_S_INDIRECT_Y, alwaysContinue)
|
||||
add(0x35, AND, DIRECT_X, alwaysContinue)
|
||||
add(0x37, AND, DIRECT_INDIRECT_LONG_Y, alwaysContinue)
|
||||
add(0x39, AND, ABSOLUTE_Y, alwaysContinue)
|
||||
add(0x3D, AND, ABSOLUTE_X, alwaysContinue)
|
||||
add(0x3F, AND, ABSOLUTE_LONG_X, alwaysContinue)
|
||||
add(0x41, EOR, DIRECT_X_INDIRECT, alwaysContinue)
|
||||
add(0x43, EOR, DIRECT_S, alwaysContinue)
|
||||
add(0x45, EOR, DIRECT, alwaysContinue)
|
||||
add(0x47, EOR, DIRECT_INDIRECT_LONG, alwaysContinue)
|
||||
add(0x49, EOR, IMMEDIATE_M, alwaysContinue)
|
||||
add(0x4D, EOR, ABSOLUTE, alwaysContinue)
|
||||
add(0x4F, EOR, ABSOLUTE_LONG, alwaysContinue)
|
||||
add(0x51, EOR, DIRECT_INDIRECT_Y, alwaysContinue)
|
||||
add(0x52, EOR, DIRECT_INDIRECT, alwaysContinue)
|
||||
add(0x53, EOR, DIRECT_S_INDIRECT_Y, alwaysContinue)
|
||||
add(0x55, EOR, DIRECT_X, alwaysContinue)
|
||||
add(0x57, EOR, DIRECT_INDIRECT_LONG_Y, alwaysContinue)
|
||||
add(0x59, EOR, ABSOLUTE_Y, alwaysContinue)
|
||||
add(0x5D, EOR, ABSOLUTE_X, alwaysContinue)
|
||||
add(0x5F, EOR, ABSOLUTE_LONG_X, alwaysContinue)
|
||||
add(0x01, ORA, DIRECT_X_INDIRECT, alwaysContinue)
|
||||
add(0x03, ORA, DIRECT_S, alwaysContinue)
|
||||
add(0x05, ORA, DIRECT, alwaysContinue)
|
||||
add(0x07, ORA, DIRECT_INDIRECT_LONG, alwaysContinue)
|
||||
add(0x09, ORA, IMMEDIATE_M, alwaysContinue)
|
||||
add(0x0D, ORA, ABSOLUTE, alwaysContinue)
|
||||
add(0x0F, ORA, ABSOLUTE_LONG, alwaysContinue)
|
||||
add(0x11, ORA, DIRECT_INDIRECT_Y, alwaysContinue)
|
||||
add(0x12, ORA, DIRECT_INDIRECT, alwaysContinue)
|
||||
add(0x13, ORA, DIRECT_S_INDIRECT_Y, alwaysContinue)
|
||||
add(0x15, ORA, DIRECT_X, alwaysContinue)
|
||||
add(0x17, ORA, DIRECT_INDIRECT_LONG_Y, alwaysContinue)
|
||||
add(0x19, ORA, ABSOLUTE_Y, alwaysContinue)
|
||||
add(0x1D, ORA, ABSOLUTE_X, alwaysContinue)
|
||||
add(0x1F, ORA, ABSOLUTE_LONG_X, alwaysContinue)
|
||||
add(0x21, AND, Direct.x.indirect, alwaysContinue)
|
||||
add(0x23, AND, Direct.s, alwaysContinue)
|
||||
add(0x25, AND, Direct, alwaysContinue)
|
||||
add(0x27, AND, Direct.indirectLong, alwaysContinue)
|
||||
add(0x29, AND, ImmediateM, alwaysContinue)
|
||||
add(0x2D, AND, Absolute, alwaysContinue)
|
||||
add(0x2F, AND, AbsoluteLong, alwaysContinue)
|
||||
add(0x31, AND, Direct.indirect.y, alwaysContinue)
|
||||
add(0x32, AND, Direct.indirect, alwaysContinue)
|
||||
add(0x33, AND, Direct.s.indirect.y, alwaysContinue)
|
||||
add(0x35, AND, Direct.x, alwaysContinue)
|
||||
add(0x37, AND, Direct.indirectLong.y, alwaysContinue)
|
||||
add(0x39, AND, Absolute.y, alwaysContinue)
|
||||
add(0x3D, AND, Absolute.x, alwaysContinue)
|
||||
add(0x3F, AND, AbsoluteLong.x, alwaysContinue)
|
||||
add(0x41, EOR, Direct.x.indirect, alwaysContinue)
|
||||
add(0x43, EOR, Direct.s, alwaysContinue)
|
||||
add(0x45, EOR, Direct, alwaysContinue)
|
||||
add(0x47, EOR, Direct.indirectLong, alwaysContinue)
|
||||
add(0x49, EOR, ImmediateM, alwaysContinue)
|
||||
add(0x4D, EOR, Absolute, alwaysContinue)
|
||||
add(0x4F, EOR, AbsoluteLong, alwaysContinue)
|
||||
add(0x51, EOR, Direct.indirect.y, alwaysContinue)
|
||||
add(0x52, EOR, Direct.indirect, alwaysContinue)
|
||||
add(0x53, EOR, Direct.s.indirect.y, alwaysContinue)
|
||||
add(0x55, EOR, Direct.x, alwaysContinue)
|
||||
add(0x57, EOR, Direct.indirectLong.y, alwaysContinue)
|
||||
add(0x59, EOR, Absolute.y, alwaysContinue)
|
||||
add(0x5D, EOR, Absolute.x, alwaysContinue)
|
||||
add(0x5F, EOR, AbsoluteLong.x, alwaysContinue)
|
||||
add(0x01, ORA, Direct.x.indirect, alwaysContinue)
|
||||
add(0x03, ORA, Direct.s, alwaysContinue)
|
||||
add(0x05, ORA, Direct, alwaysContinue)
|
||||
add(0x07, ORA, Direct.indirectLong, alwaysContinue)
|
||||
add(0x09, ORA, ImmediateM, alwaysContinue)
|
||||
add(0x0D, ORA, Absolute, alwaysContinue)
|
||||
add(0x0F, ORA, AbsoluteLong, alwaysContinue)
|
||||
add(0x11, ORA, Direct.indirect.y, alwaysContinue)
|
||||
add(0x12, ORA, Direct.indirect, alwaysContinue)
|
||||
add(0x13, ORA, Direct.s.indirect.y, alwaysContinue)
|
||||
add(0x15, ORA, Direct.x, alwaysContinue)
|
||||
add(0x17, ORA, Direct.indirectLong.y, alwaysContinue)
|
||||
add(0x19, ORA, Absolute.y, alwaysContinue)
|
||||
add(0x1D, ORA, Absolute.x, alwaysContinue)
|
||||
add(0x1F, ORA, AbsoluteLong.x, alwaysContinue)
|
||||
|
||||
add(0x14, TRB, DIRECT, alwaysContinue)
|
||||
add(0x1C, TRB, ABSOLUTE, alwaysContinue)
|
||||
add(0x04, TSB, DIRECT, alwaysContinue)
|
||||
add(0x0C, TSB, ABSOLUTE, alwaysContinue)
|
||||
add(0x14, TRB, Direct, alwaysContinue)
|
||||
add(0x1C, TRB, Absolute, alwaysContinue)
|
||||
add(0x04, TSB, Direct, alwaysContinue)
|
||||
add(0x0C, TSB, Absolute, alwaysContinue)
|
||||
|
||||
add(0x24, BIT, DIRECT, alwaysContinue)
|
||||
add(0x2C, BIT, ABSOLUTE, alwaysContinue)
|
||||
add(0x34, BIT, DIRECT_X, alwaysContinue)
|
||||
add(0x3C, BIT, ABSOLUTE_X, alwaysContinue)
|
||||
add(0x89, BIT, IMMEDIATE_M, alwaysContinue)
|
||||
add(0x24, BIT, Direct, alwaysContinue)
|
||||
add(0x2C, BIT, Absolute, alwaysContinue)
|
||||
add(0x34, BIT, Direct.x, alwaysContinue)
|
||||
add(0x3C, BIT, Absolute.x, alwaysContinue)
|
||||
add(0x89, BIT, ImmediateM, alwaysContinue)
|
||||
|
||||
add(0x54, MVN, BLOCK_MOVE, alwaysContinue)
|
||||
add(0x44, MVP, BLOCK_MOVE, alwaysContinue)
|
||||
add(0x54, MVN, BlockMove, alwaysContinue)
|
||||
add(0x44, MVP, BlockMove, alwaysContinue)
|
||||
|
||||
add(0xF4, PEA, IMMEDIATE_16, alwaysContinue)
|
||||
add(0xD4, PEI, DIRECT, alwaysContinue)
|
||||
add(0x62, PER, RELATIVE_LONG, alwaysContinue)
|
||||
add(0xF4, PEA, Immediate16, alwaysContinue)
|
||||
add(0xD4, PEI, Direct, alwaysContinue)
|
||||
add(0x62, PER, RelativeLong, alwaysContinue)
|
||||
|
||||
OPCODES = Array(256) { ocs[it]!! }
|
||||
}
|
||||
|
@ -19,8 +19,8 @@ abstract class SnesMapper: MemorySpace {
|
||||
return entry.space[offset]
|
||||
}
|
||||
|
||||
fun toCanonical(address: SnesAddress): SnesAddress? {
|
||||
val entry = areas[address.value.toUInt()] ?: return null
|
||||
fun toCanonical(address: SnesAddress): SnesAddress {
|
||||
val entry = areas[address.value.toUInt()] ?: return address
|
||||
val offset = address.value - entry.start
|
||||
return entry.canonicalStart + offset.toInt()
|
||||
}
|
||||
|
@ -4,7 +4,7 @@ import com.smallhacker.disbrowser.ImmStack
|
||||
import com.smallhacker.disbrowser.immStack
|
||||
import com.smallhacker.disbrowser.util.toUInt24
|
||||
|
||||
data class State(val origin: Instruction? = null, val memory: SnesMapper, val address: SnesAddress, val flags: VagueNumber = VagueNumber(), val stack: ImmStack<VagueNumber> = immStack()) {
|
||||
data class State(val origin: Instruction? = null, val memory: SnesMapper, val address: SnesAddress, val flags: VagueNumber = VagueNumber(), val stack: ImmStack<VagueNumber> = immStack(), val metadata: Metadata) {
|
||||
val m: Boolean? get() = flags.getBoolean(0x20u)
|
||||
val x: Boolean? get() = flags.getBoolean(0x10u)
|
||||
val db: UByte? get() = pb // TODO
|
||||
@ -58,17 +58,18 @@ data class State(val origin: Instruction? = null, val memory: SnesMapper, val ad
|
||||
|
||||
fun resolveDirectPage(directPage: UByte) = dp?.let { dp ->
|
||||
val ptr = (dp.toUInt24() shl 8) or (directPage.toUInt24())
|
||||
SnesAddress(ptr)
|
||||
memory.toCanonical(SnesAddress(ptr))
|
||||
}
|
||||
|
||||
fun resolveAbsoluteData(absolute: UShort) = db?.let { db ->
|
||||
val ptr = (db.toUInt24() shl 16) or (absolute.toUInt24())
|
||||
SnesAddress(ptr)
|
||||
memory.toCanonical(SnesAddress(ptr))
|
||||
}
|
||||
|
||||
fun resolveAbsoluteCode(absolute: UShort): SnesAddress {
|
||||
fun resolveAbsoluteCode(absolute: UShort): SnesAddress? {
|
||||
val ptr = (pb.toUInt24() shl 16) or (absolute.toUInt24())
|
||||
return SnesAddress(ptr)
|
||||
val address = SnesAddress(ptr)
|
||||
return memory.toCanonical(address)
|
||||
}
|
||||
|
||||
private fun stackToString(): String {
|
||||
|
@ -1,7 +1,6 @@
|
||||
package com.smallhacker.disbrowser.resource
|
||||
|
||||
import com.smallhacker.disbrowser.HtmlNode
|
||||
import com.smallhacker.disbrowser.Service
|
||||
import com.smallhacker.disbrowser.*
|
||||
import com.smallhacker.disbrowser.asm.SnesAddress
|
||||
import com.smallhacker.disbrowser.asm.VagueNumber
|
||||
import java.nio.charset.StandardCharsets
|
||||
@ -17,7 +16,21 @@ class DisassemblyResource {
|
||||
@GET
|
||||
@Produces(MediaType.TEXT_HTML)
|
||||
fun getIt() = handle {
|
||||
Service.showDisassemblyFromReset()
|
||||
//Service.showDisassemblyFromReset()
|
||||
table {
|
||||
Service.getVectors().forEach {
|
||||
tr {
|
||||
td { text(it.name) }
|
||||
td { text("(" + it.vectorLocation.toFormattedString() + ")") }
|
||||
td {
|
||||
a {
|
||||
text(it.label)
|
||||
}.attr("href", "/${it.codeLocation.toSimpleString()}/mx")
|
||||
}
|
||||
td { text("(" + it.codeLocation.toFormattedString() + ")") }
|
||||
}
|
||||
}
|
||||
}.addClass("vector-table")
|
||||
}
|
||||
|
||||
@GET
|
||||
@ -39,14 +52,24 @@ class DisassemblyResource {
|
||||
|
||||
private fun handle(runner: () -> HtmlNode?): Response {
|
||||
try {
|
||||
val disassembly = runner()
|
||||
val output = runner()
|
||||
?: return Response.status(404).build()
|
||||
|
||||
return if (disassembly == null)
|
||||
Response.status(404).build()
|
||||
else
|
||||
Response.ok(disassembly.toString().toByteArray(StandardCharsets.UTF_8))
|
||||
.encoding("UTF-8")
|
||||
.build()
|
||||
val html = html {
|
||||
head {
|
||||
title { text("Disassembly Browser") }
|
||||
link {}.attr("rel", "stylesheet").attr("href", "/resources/style.css")
|
||||
meta {}.attr("charset", "UTF-8")
|
||||
}
|
||||
body {
|
||||
output.appendTo(parent)
|
||||
script().attr("src", "/resources/disbrowser.js")
|
||||
}
|
||||
}
|
||||
|
||||
return Response.ok(html.toString().toByteArray(StandardCharsets.UTF_8))
|
||||
.encoding("UTF-8")
|
||||
.build()
|
||||
} catch (e: Exception) {
|
||||
e.printStackTrace()
|
||||
throw e
|
||||
|
@ -25,6 +25,10 @@ fun toHex(value: UInt, bytes: UInt): String {
|
||||
return String.format(pattern, value.toInt())
|
||||
}
|
||||
|
||||
fun toHex(value: UInt24) = toHex(value.toUInt(), 3u)
|
||||
fun toHex(value: UShort) = toHex(value.toUInt(), 2u)
|
||||
fun toHex(value: UByte) = toHex(value.toUInt(), 1u)
|
||||
|
||||
fun joinBytes(vararg bytes: UByte) = bytes
|
||||
.asSequence()
|
||||
.mapIndexed { index, v -> v.toUInt() shl (index * 8) }
|
||||
@ -74,4 +78,12 @@ fun Short.toUInt24() = this.toUInt().toUInt24()
|
||||
fun Byte.toUInt24() = this.toUInt().toUInt24()
|
||||
|
||||
fun <T> List<T>.asReverseSequence(): Sequence<T> =
|
||||
((size - 1) downTo 0).asSequence().map { this[it] }
|
||||
((size - 1) downTo 0).asSequence().map { this[it] }
|
||||
|
||||
fun <K, V> MutableMap<K, V>.removeIf(condition: (K, V) -> Boolean) {
|
||||
this.asSequence()
|
||||
.filter { condition(it.key, it.value) }
|
||||
.map { it.key }
|
||||
.toList()
|
||||
.forEach { remove(it) }
|
||||
}
|
@ -107,4 +107,24 @@ tr.line-active {
|
||||
|
||||
.opcode-info{
|
||||
text-decoration: green underline dotted;
|
||||
}
|
||||
|
||||
.field-editable-popup-icon {
|
||||
cursor: pointer;
|
||||
text-align: center;
|
||||
padding: 0 5px;
|
||||
opacity: 0;
|
||||
}
|
||||
|
||||
|
||||
.field-editable-popup-icon:hover,
|
||||
.field-editable-popup:hover > .field-editable-popup-icon {
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
.field-editable-popup-icon:hover {
|
||||
font-weight: bold;
|
||||
}
|
||||
.field-editable-popup-icon::before {
|
||||
content: "[e]"
|
||||
}
|
@ -67,10 +67,10 @@ window.addEventListener("hashchange", function () {
|
||||
highlight(fromHash())
|
||||
}, false);
|
||||
|
||||
let comments = document.getElementsByClassName("field-editable");
|
||||
for (let i = 0; i < comments.length; i++) {
|
||||
let comment = comments[i];
|
||||
comment.addEventListener("change", e => {
|
||||
let editables = document.getElementsByClassName("field-editable");
|
||||
for (let i = 0; i < editables.length; i++) {
|
||||
let editable = editables[i];
|
||||
editable.addEventListener("change", e => {
|
||||
let target = <HTMLInputElement>(e.target);
|
||||
let field = target.dataset.field || "";
|
||||
let address = target.dataset.address;
|
||||
@ -79,6 +79,30 @@ for (let i = 0; i < comments.length; i++) {
|
||||
xhr(`/rest/${address}/${field}`, "POST", value)
|
||||
.catch((xhr: XMLHttpRequest) => alert("Error: HTTP " + xhr.status));
|
||||
|
||||
return false;
|
||||
});
|
||||
}
|
||||
|
||||
let popupEditables = document.getElementsByClassName("field-editable-popup");
|
||||
for (let i = 0; i < popupEditables.length; i++) {
|
||||
let editable = <HTMLSpanElement>(popupEditables[i]);
|
||||
let first = editable.getElementsByClassName("field-editable-popup-icon")[0];
|
||||
if (!first) {
|
||||
continue;
|
||||
}
|
||||
first.addEventListener("click", e => {
|
||||
let field = editable.dataset.field || "";
|
||||
let address = editable.dataset.address;
|
||||
let value = editable.dataset.value;
|
||||
let newValue = prompt("Label for $" + address, value);
|
||||
if (newValue === null || newValue == value) {
|
||||
return false;
|
||||
}
|
||||
|
||||
xhr(`/rest/${address}/${field}`, "POST", newValue)
|
||||
.then(() => location.reload())
|
||||
.catch((xhr: XMLHttpRequest) => alert("Error: HTTP " + xhr.status));
|
||||
|
||||
return false;
|
||||
});
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user