disbrowser/src/main/java/com/smallhacker/disbrowser/asm/Instruction.kt

211 lines
6.3 KiB
Kotlin
Raw Normal View History

2019-01-07 18:19:37 +00:00
package com.smallhacker.disbrowser.asm
import com.smallhacker.disbrowser.game.GameData
2019-01-07 18:19:37 +00:00
import com.smallhacker.disbrowser.util.*
2019-01-11 03:19:08 +00:00
interface CodeUnit {
2019-01-11 16:35:35 +00:00
val address: SnesAddress?
val relativeAddress: SnesAddress
2019-01-14 05:23:19 +00:00
val indicativeAddress: SnesAddress
val sortedAddress: SnesAddress
val nextSortedAddress: SnesAddress
2019-01-11 03:19:08 +00:00
val linkedState: State?
val preState: State?
val postState: State?
2019-01-12 02:16:50 +00:00
val bytes: ValidMemorySpace
2019-01-11 03:19:08 +00:00
val opcode: Opcode
val lengthSuffix: String?
val memory: SnesMemory
2019-01-15 05:54:54 +00:00
val certainty: Certainty
2019-01-13 03:38:59 +00:00
2019-01-11 03:19:08 +00:00
fun operandByte(index: UInt): UByte = bytes[opcode.operandIndex + index]
2019-01-07 18:19:37 +00:00
2019-01-11 03:19:08 +00:00
fun bytesToString(): String {
return bytes.asSequence()
.map { toHex(it.toUInt(), 1u) }
.joinToString(" ")
.padEnd(11, ' ')
2019-01-07 18:19:37 +00:00
}
2019-01-11 03:19:08 +00:00
val operandLength: UInt?
2019-01-07 18:19:37 +00:00
2019-01-11 03:19:08 +00:00
val signedByte get() = byte.toByte()
2019-01-07 18:19:37 +00:00
2019-01-11 03:19:08 +00:00
val signedWord get() = word.toShort()
2019-01-07 18:19:37 +00:00
2019-01-11 03:19:08 +00:00
val byte get() = operandByte(0u)
2019-01-07 18:19:37 +00:00
2019-01-11 03:19:08 +00:00
val byte2 get() = operandByte(1u)
2019-01-07 18:19:37 +00:00
2019-01-11 03:19:08 +00:00
val word get() = joinBytes(operandByte(0u), operandByte(1u)).toUShort()
2019-01-07 18:19:37 +00:00
2019-01-11 03:19:08 +00:00
val long get() = joinBytes(operandByte(0u), operandByte(1u), operandByte(2u)).toUInt24()
2019-01-07 18:19:37 +00:00
2019-01-11 03:19:08 +00:00
val value
get() = when (operandLength?.toInt()) {
0 -> 0u
1 -> byte.toUInt()
2 -> word.toUInt()
3 -> long.toUInt()
else -> null
}
}
2019-01-07 18:19:37 +00:00
2019-01-11 03:19:08 +00:00
class DataBlock(
override val opcode: Opcode,
2019-01-12 02:16:50 +00:00
override val bytes: ValidMemorySpace,
2019-01-15 05:54:54 +00:00
override val address: SnesAddress?,
2019-01-14 05:23:19 +00:00
override val indicativeAddress: SnesAddress,
override val sortedAddress: SnesAddress,
2019-01-11 16:35:35 +00:00
override val relativeAddress: SnesAddress,
2019-01-13 03:38:59 +00:00
override val linkedState: State?,
2019-01-15 05:54:54 +00:00
override val memory: SnesMemory,
override val certainty: Certainty
2019-01-11 03:19:08 +00:00
) : CodeUnit {
2019-01-15 05:54:54 +00:00
constructor(
opcode: Opcode,
bytes: ValidMemorySpace,
indicativeAddress: SnesAddress,
sortedAddress: SnesAddress,
relativeAddress: SnesAddress,
linkedState: State?,
memory: SnesMemory,
certainty: Certainty
) : this(opcode, bytes, null, indicativeAddress, sortedAddress, relativeAddress, linkedState, memory, certainty)
constructor(
opcode: Opcode,
bytes: ValidMemorySpace,
address: SnesAddress,
relativeAddress: SnesAddress,
linkedState: State?,
memory: SnesMemory,
certainty: Certainty
) : this(opcode, bytes, address, address, address, relativeAddress, linkedState, memory, certainty)
2019-01-14 05:23:19 +00:00
override val nextSortedAddress: SnesAddress
get() = sortedAddress + operandLength.toInt()
2019-01-11 03:19:08 +00:00
override val operandLength get() = bytes.size
override val preState: State? = null
override val postState: State? = null
override val lengthSuffix: String? = null
}
2019-01-07 18:19:37 +00:00
2019-01-15 05:54:54 +00:00
interface Instruction : CodeUnit {
override val preState: State
override val address: SnesAddress
override val postState: State
val continuation: Continuation
val showLengthSuffix: Boolean
fun link(): SnesAddress?
fun referencedAddress(): SnesAddress?
override fun toString(): String
}
class MutableInstruction(
override val bytes: ValidMemorySpace,
override val opcode: Opcode,
override val preState: State,
override var continuation: Continuation,
override var certainty: Certainty
) : Instruction {
2019-01-13 03:38:59 +00:00
override val memory = preState.memory
2019-01-11 16:35:35 +00:00
override val address: SnesAddress get() = preState.address
2019-01-14 05:23:19 +00:00
override val indicativeAddress get() = address
2019-01-11 03:19:08 +00:00
override val relativeAddress get() = address
2019-01-14 05:23:19 +00:00
override val sortedAddress get() = address
override val nextSortedAddress get() = postState.address
2019-01-07 18:19:37 +00:00
2019-01-11 03:19:08 +00:00
override val postState = opcode.mutate(this)
.mutateAddress { it + bytes.size.toInt() }
.withOrigin(this)
override val linkedState = link()?.let { link ->
opcode.mutate(this)
.mutateAddress { link }
.withOrigin(this)
}
2019-01-07 18:19:37 +00:00
2019-01-15 05:54:54 +00:00
override val showLengthSuffix get() = opcode.mode.showLengthSuffix and opcode.mnemonic.showLengthSuffix
2019-01-13 03:38:59 +00:00
2019-01-11 03:19:08 +00:00
override val lengthSuffix: String?
2019-01-07 18:19:37 +00:00
get() {
2019-01-13 03:38:59 +00:00
if (!showLengthSuffix) {
2019-01-11 03:19:08 +00:00
return null
}
return when (operandLength?.toInt()) {
null -> ".?"
1 -> ".b"
2 -> ".w"
3 -> ".l"
else -> null
2019-01-07 18:19:37 +00:00
}
}
2019-01-11 03:19:08 +00:00
override val operandLength
2019-01-07 18:19:37 +00:00
get() = opcode.mode.operandLength(preState)
2019-01-15 05:54:54 +00:00
override fun link(): SnesAddress? {
2019-01-07 18:19:37 +00:00
if (!opcode.link) {
return null
}
2019-01-12 02:16:50 +00:00
return referencedAddress()
2019-01-13 03:38:59 +00:00
}
2019-01-15 05:54:54 +00:00
override fun referencedAddress() = opcode.mode.referencedAddress(this)
2019-01-13 03:38:59 +00:00
override fun toString(): String {
val (address, bytes, _, primaryMnemonic, _, suffix, operands, _, _) = print()
return "${address ?: "\$xx:xxxx"} $bytes $primaryMnemonic${suffix ?: ""} ${operands?.padEnd(100, ' ')
?: ""} ($preState -> $postState)"
}
}
2019-01-12 02:16:50 +00:00
fun CodeUnit.print(gameData: GameData? = null): PrintedCodeUnit {
2019-01-13 03:38:59 +00:00
val mnemonic = opcode.mnemonic
val primaryMnemonic = mnemonic.displayName
val secondaryMnemonic = mnemonic.alternativeName
var suffix = lengthSuffix
var operands = gameData?.let { opcode.mode.printWithLabel(this, it) }
2019-01-13 03:38:59 +00:00
if (operands == null) {
operands = opcode.mode.printRaw(this)
suffix = null
2019-01-12 02:16:50 +00:00
}
2019-01-13 03:38:59 +00:00
val state = postState?.toString()
2019-01-14 05:23:19 +00:00
val label = gameData?.get(indicativeAddress)?.label
val comment = gameData?.get(indicativeAddress)?.comment
2019-01-13 03:38:59 +00:00
val formattedAddress = address?.toFormattedString()
val bytes = bytesToString()
val labelAddress = if (opcode.mode.canHaveLabel) {
opcode.mode.referencedAddress(this)?.let {
memory.toCanonical(it)
2019-01-07 18:19:37 +00:00
}
2019-01-13 03:38:59 +00:00
} else {
null
2019-01-07 18:19:37 +00:00
}
2019-01-13 03:38:59 +00:00
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?
)