128 lines
3.8 KiB
Kotlin
128 lines
3.8 KiB
Kotlin
package com.smallhacker.disbrowser.asm
|
|
|
|
import com.smallhacker.disbrowser.util.*
|
|
|
|
interface CodeUnit {
|
|
val address: Address?
|
|
val relativeAddress: Address
|
|
val presentedAddress: Address
|
|
val nextPresentedAddress: Address
|
|
|
|
val linkedState: State?
|
|
val preState: State?
|
|
val postState: State?
|
|
|
|
val bytes: RomData
|
|
val opcode: Opcode
|
|
val lengthSuffix: String?
|
|
|
|
fun operandByte(index: UInt): UByte = bytes[opcode.operandIndex + index]
|
|
fun printOpcodeAndSuffix(): String {
|
|
val mnemonic = opcode.mnemonic.displayName
|
|
val suffix = lengthSuffix ?: ""
|
|
return "$mnemonic$suffix"
|
|
}
|
|
fun printOperands() = opcode.mode.print(this)
|
|
|
|
fun bytesToString(): String {
|
|
return bytes.asSequence()
|
|
.map { toHex(it.toUInt(), 1u) }
|
|
.joinToString(" ")
|
|
.padEnd(11, ' ')
|
|
}
|
|
|
|
val operandLength: UInt?
|
|
|
|
val signedByte get() = byte.toByte()
|
|
|
|
val signedWord get() = word.toShort()
|
|
|
|
val byte get() = operandByte(0u)
|
|
|
|
val byte2 get() = operandByte(1u)
|
|
|
|
val word get() = joinBytes(operandByte(0u), operandByte(1u)).toUShort()
|
|
|
|
val long get() = joinBytes(operandByte(0u), operandByte(1u), operandByte(2u)).toUInt24()
|
|
|
|
val value
|
|
get() = when (operandLength?.toInt()) {
|
|
0 -> 0u
|
|
1 -> byte.toUInt()
|
|
2 -> word.toUInt()
|
|
3 -> long.toUInt()
|
|
else -> null
|
|
}
|
|
}
|
|
|
|
class DataBlock(
|
|
override val opcode: Opcode,
|
|
override val bytes: RomData,
|
|
override val presentedAddress: Address,
|
|
override val relativeAddress: Address,
|
|
override val linkedState: State?
|
|
) : CodeUnit {
|
|
override val nextPresentedAddress: Address
|
|
get() = presentedAddress + operandLength.toInt()
|
|
override val operandLength get() = bytes.size
|
|
|
|
override val address: Address? = null
|
|
override val preState: State? = null
|
|
override val postState: State? = null
|
|
override val lengthSuffix: String? = null
|
|
}
|
|
|
|
class Instruction(override val bytes: RomData, override val opcode: Opcode, override val preState: State) : CodeUnit {
|
|
override val address: Address get() = preState.address
|
|
override val relativeAddress get() = address
|
|
override val presentedAddress get() = address
|
|
override val nextPresentedAddress get() = postState.address
|
|
|
|
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)
|
|
}
|
|
|
|
override val lengthSuffix: String?
|
|
get() {
|
|
if (!opcode.mode.showLengthSuffix) {
|
|
return null
|
|
}
|
|
|
|
return when (operandLength?.toInt()) {
|
|
null -> ".?"
|
|
1 -> ".b"
|
|
2 -> ".w"
|
|
3 -> ".l"
|
|
else -> null
|
|
}
|
|
}
|
|
|
|
override val operandLength
|
|
get() = opcode.mode.operandLength(preState)
|
|
|
|
private fun link(): Address? {
|
|
if (!opcode.link) {
|
|
return null
|
|
}
|
|
|
|
return when (opcode.mode) {
|
|
Mode.ABSOLUTE -> relativeAddress.withinBank(word)
|
|
Mode.ABSOLUTE_LONG -> Address(long)
|
|
Mode.RELATIVE -> relativeAddress + 2 + signedByte.toInt()
|
|
Mode.RELATIVE_LONG -> relativeAddress + 3 + signedWord.toInt()
|
|
Mode.DATA_WORD -> relativeAddress.withinBank(word)
|
|
Mode.DATA_LONG -> Address(long)
|
|
else -> null
|
|
}
|
|
}
|
|
|
|
override fun toString(): String {
|
|
return "$address ${bytesToString()} ${opcode.mnemonic.displayName} ${opcode.mode.print(this).padEnd(100, ' ')} ($preState -> $postState)"
|
|
}
|
|
}
|