disbrowser/src/jvmMain/kotlin/com/smallhacker/disbrowser/asm/Mode.kt

233 lines
9.3 KiB
Kotlin

package com.smallhacker.disbrowser.asm
import com.smallhacker.disbrowser.memory.SnesAddress
import com.smallhacker.disbrowser.memory.SnesMemory
import com.smallhacker.util.UInt24
import com.smallhacker.util.toHex
interface Mode {
val dataMode get() = false
val showLengthSuffix get() = true
val canHaveLabel: Boolean
fun operandLength(state: State): UInt?
fun printWithLabel(ins: CodeUnit, label: String?): String? = 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, label: String?): String? = null
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, label: String?): String? = parent.printWithLabel(ins, label)?.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, label: String?): String? = get(ins.preState) { printWithLabel(ins, label) }
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: SnesMemory): SnesAddress?
fun resolve(word: UShort, state: State?, memory: SnesMemory): SnesAddress?
fun resolve(long: UInt24, state: State?, memory: SnesMemory): 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: SnesMemory): SnesAddress? = null
override fun resolve(word: UShort, state: State?, memory: SnesMemory): SnesAddress? = null
override fun resolve(long: UInt24, state: State?, memory: SnesMemory): SnesAddress? = null
}
object DataPointer : DataValueType {
override val canHaveLabel = true
override fun resolve(byte: UByte, state: State?, memory: SnesMemory) = state?.resolveDirectPage(byte)
override fun resolve(word: UShort, state: State?, memory: SnesMemory) = state?.resolveAbsoluteData(word)
override fun resolve(long: UInt24, state: State?, memory: SnesMemory) = memory.toCanonical(SnesAddress(long))
}
object CodePointer : DataValueType {
override val canHaveLabel = true
override fun resolve(byte: UByte, state: State?, memory: SnesMemory) = state?.resolveDirectPage(byte)
override fun resolve(word: UShort, state: State?, memory: SnesMemory) = state?.resolveAbsoluteCode(word)
override fun resolve(long: UInt24, state: State?, memory: SnesMemory) = 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) = "$" + ins.byte.toHex()
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) = "$" + ins.word.toHex()
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) = "$" + ins.long.toHex()
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) = "#$" + ins.byte.toHex()
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) = "#$" + ins.word.toHex()
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) = "$" + ins.byte.toHex()
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) = "$" + ins.word.toHex()
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) = "$" + ins.word.toHex()
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) = "$" + ins.long.toHex()
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, "[", "]")