2019-01-07 18:19:37 +00:00
|
|
|
package com.smallhacker.disbrowser.asm
|
|
|
|
|
|
|
|
import com.smallhacker.disbrowser.ImmStack
|
|
|
|
import com.smallhacker.disbrowser.immStack
|
2019-01-11 16:35:35 +00:00
|
|
|
import com.smallhacker.disbrowser.util.toUInt24
|
2019-01-07 18:19:37 +00:00
|
|
|
|
2019-01-12 02:16:50 +00:00
|
|
|
data class State(val origin: Instruction? = null, val memory: SnesMapper, val address: SnesAddress, 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-11 16:35:35 +00:00
|
|
|
val db: UByte? get() = pb // TODO
|
|
|
|
val dp: UShort? get() = 0x7e00u // TODO
|
|
|
|
val pb: UByte get() = (address.value shr 16).toUByte()
|
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)
|
|
|
|
|
2019-01-11 16:35:35 +00:00
|
|
|
fun mutateAddress(mutator: (SnesAddress) -> SnesAddress) = copy(address = mutator(address))
|
2019-01-07 18:19:37 +00:00
|
|
|
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()
|
|
|
|
}
|
|
|
|
|
2019-01-12 02:16:50 +00:00
|
|
|
fun resolveDirectPage(directPage: UByte) = dp?.let { dp ->
|
2019-01-11 16:35:35 +00:00
|
|
|
val ptr = (dp.toUInt24() shl 8) or (directPage.toUInt24())
|
|
|
|
SnesAddress(ptr)
|
|
|
|
}
|
|
|
|
|
2019-01-12 02:16:50 +00:00
|
|
|
fun resolveAbsoluteData(absolute: UShort) = db?.let { db ->
|
2019-01-11 16:35:35 +00:00
|
|
|
val ptr = (db.toUInt24() shl 16) or (absolute.toUInt24())
|
|
|
|
SnesAddress(ptr)
|
|
|
|
}
|
|
|
|
|
2019-01-12 02:16:50 +00:00
|
|
|
fun resolveAbsoluteCode(absolute: UShort): SnesAddress {
|
|
|
|
val ptr = (pb.toUInt24() shl 16) or (absolute.toUInt24())
|
|
|
|
return SnesAddress(ptr)
|
|
|
|
}
|
|
|
|
|
2019-01-07 18:19:37 +00:00
|
|
|
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)
|
|
|
|
}
|