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

113 lines
3.4 KiB
Kotlin
Raw Normal View History

2019-01-07 18:19:37 +00:00
package com.smallhacker.disbrowser.asm
import com.smallhacker.disbrowser.ImmStack
import com.smallhacker.disbrowser.immStack
data class State(val origin: Instruction? = null, val data: RomData, val address: Address, val flags: VagueNumber = VagueNumber(), val stack: ImmStack<VagueNumber> = immStack()) {
2019-01-11 03:19:08 +00:00
val m: Boolean? get() = flags.getBoolean(0x20u)
val x: Boolean? get() = flags.getBoolean(0x10u)
2019-01-07 18:19:37 +00:00
2019-01-11 03:19:08 +00:00
val mWidth: UInt? get() = toWidth(m)
val xWidth: UInt? get() = toWidth(x)
2019-01-07 18:19:37 +00:00
2019-01-11 03:19:08 +00:00
fun sep(i: UByte) = withFlags(flags.withBits(i.toUInt()))
fun rep(i: UByte) = withFlags(flags.withoutBits(i.toUInt()))
2019-01-07 18:19:37 +00:00
fun uncertain() = withFlags(VagueNumber())
private fun withFlags(flags: VagueNumber) = copy(flags = flags)
fun mutateAddress(mutator: (Address) -> Address) = copy(address = mutator(address))
fun withOrigin(instruction: Instruction?) = copy(origin = instruction)
2019-01-11 03:19:08 +00:00
fun push(value: UInt) = push(VagueNumber(value))
2019-01-07 18:19:37 +00:00
fun push(value: VagueNumber) = copy(stack = stack.push(value))
2019-01-11 03:19:08 +00:00
fun pushUnknown(count: UInt? = 1u): State {
2019-01-07 18:19:37 +00:00
if (count == null) {
return copy(stack = immStack())
}
var stack = this.stack
2019-01-11 03:19:08 +00:00
for (i in 1u..count) {
2019-01-07 18:19:37 +00:00
stack = stack.push(VagueNumber())
}
return copy(stack = stack)
}
fun pull() = (stack.top ?: VagueNumber()) to copy(stack = stack.pop())
2019-01-11 03:19:08 +00:00
fun pull(count: UInt?): State {
2019-01-07 18:19:37 +00:00
if (count == null) {
return copy(stack = immStack())
}
var stack = this.stack
2019-01-11 03:19:08 +00:00
for (i in 1u..count) {
2019-01-07 18:19:37 +00:00
stack = stack.pop()
}
return copy(stack = stack)
}
fun clearStack() = copy(stack = immStack())
override fun toString(): String {
return "A:${printSize(m)} XY:${printSize(x)} S:" + stackToString()
}
private fun stackToString(): String {
return stack.reversed().asSequence()
.map { stackByteToString(it) }
.joinToString(" ")
}
private fun stackByteToString(v: VagueNumber): String {
if (v.certain) {
2019-01-11 03:19:08 +00:00
return String.format("%02x", v.value.toInt())
2019-01-07 18:19:37 +00:00
}
2019-01-11 03:19:08 +00:00
if (v.certainty == 0u) {
2019-01-07 18:19:37 +00:00
return "??"
}
val c = v.certainty
2019-01-11 03:19:08 +00:00
val high = (c and 0xF0u) != 0u
val low = (c and 0x0Fu) != 0u
2019-01-07 18:19:37 +00:00
return StringBuilder()
2019-01-11 03:19:08 +00:00
.append(if (high) String.format("%x", ((v.value shr 4) and 0xFu).toInt()) else "?")
.append(if (low) String.format("%x", (v.value and 0xFu).toInt()) else "?")
2019-01-07 18:19:37 +00:00
.toString()
}
private fun printSize(flag: Boolean?): String = when (flag) {
null -> "??"
true -> " 8"
false -> "16"
}
val urlString: String
get() {
val out = StringBuilder()
out.append(when (x) {
null -> ""
true -> "X"
false -> "x"
})
out.append(when (m) {
null -> ""
true -> "M"
false -> "m"
})
return out.toString()
}
2019-01-11 03:19:08 +00:00
private fun toWidth(flag: Boolean?): UInt? = when (flag) {
2019-01-07 18:19:37 +00:00
null -> null
2019-01-11 03:19:08 +00:00
true -> 1u
false -> 2u
2019-01-07 18:19:37 +00:00
}
}
2019-01-11 03:19:08 +00:00
fun State.pushByte(value: Byte) = this.push(VagueNumber(value.toUInt()))
2019-01-07 18:19:37 +00:00
fun State.pull(consumer: State.(VagueNumber) -> State): State {
val (value, state) = this.pull()
return consumer(state, value)
}