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

107 lines
2.9 KiB
Kotlin

package com.smallhacker.disbrowser.asm
import com.smallhacker.disbrowser.util.*
class Instruction(val bytes: RomData, val opcode: Opcode, val preState: State) {
val address: Address
get() = preState.address
val postState = opcode.mutate(this)
.mutateAddress { it + bytes.size }
.withOrigin(this)
val linkedState = link()?.let { link ->
opcode.mutate(this)
.mutateAddress { link }
.withOrigin(this)
}
operator fun get(index: Int): UByte {
return bytes[index]
}
val signedByte: Int
get() = byte.value.toByte().toInt()
val signedWord: Int
get() = word.value.toShort().toInt()
val byte: UByte
get() = get(1)
val byte2: UByte
get() = get(2)
val dataByte: UByte
get() = get(0)
val word: UWord
get() = (get(2).toWord() left 8) or get(1).toWord()
val dataWord: UWord
get() = (get(1).toWord() left 8) or get(0).toWord()
val long: ULong
get() = (get(3).toLong() left 16) or (get(2).toLong() left 8) or get(1).toLong()
val dataLong: ULong
get() = (get(2).toLong() left 16) or (get(1).toLong() left 8) or get(0).toLong()
fun bytesToString(): String {
return bytes.asSequence().map { it.toHex() }.joinToString(" ").padEnd(11, ' ')
}
//val value: ULong
// get() {
// val len = operandLength
// val start = opcode.operandIndex
//}
//fun getOperand(index: Int, length: Int) {
// val v = uLong(0)
// for (i in (index + length) downTo index)
//}
val lengthSuffix: String
get() {
return when (opcode.mode) {
Mode.IMPLIED -> ""
Mode.IMMEDIATE_8 -> ""
Mode.IMMEDIATE_16 -> ""
Mode.RELATIVE -> ""
Mode.RELATIVE_LONG -> ""
Mode.BLOCK_MOVE -> ""
else -> when (operandLength) {
null -> ".?"
1 -> ".b"
2 -> ".w"
3 -> ".l"
else -> ""
}
}
}
private val operandLength
get() = opcode.mode.operandLength(preState)
private fun link(): Address? {
if (!opcode.link) {
return null
}
return when (opcode.mode) {
Mode.ABSOLUTE -> address.withinBank(word.value)
Mode.ABSOLUTE_LONG -> Address(long.value)
Mode.RELATIVE -> address + 2 + signedByte
Mode.RELATIVE_LONG -> address + 3 + signedWord
Mode.DATA_WORD -> address.withinBank(dataWord.value)
Mode.DATA_LONG -> Address(dataLong.value)
else -> null
}
}
override fun toString(): String {
return "$address ${bytesToString()} ${opcode.mnemonic} ${opcode.mode.print(this).padEnd(100, ' ')} ($preState -> $postState)"
}
}