Working ROM/RAM labeling, vector table

This commit is contained in:
Smallhacker 2019-01-12 22:38:59 -05:00
parent e6445575d7
commit 5afdf84c1e
15 changed files with 760 additions and 543 deletions

View File

@ -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"
}
}
}

View File

@ -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)

View File

@ -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)

View File

@ -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?
)

View File

@ -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
)
}
}

View File

@ -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())
}

View File

@ -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,

View File

@ -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, "[", "]")

View File

@ -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]!! }
}

View File

@ -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()
}

View File

@ -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 {

View File

@ -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

View File

@ -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) }
}

View File

@ -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]"
}

View File

@ -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;
});
}