disbrowser/src/jvmMain/kotlin/com/smallhacker/disbrowser/asm/State.kt

137 lines
4.3 KiB
Kotlin
Raw Normal View History

2019-01-07 18:19:37 +00:00
package com.smallhacker.disbrowser.asm
2019-01-20 10:11:30 +00:00
import com.smallhacker.util.ImmStack
import com.smallhacker.disbrowser.game.GameData
2019-01-20 10:11:30 +00:00
import com.smallhacker.util.immStack
import com.smallhacker.disbrowser.memory.SnesAddress
import com.smallhacker.disbrowser.memory.SnesMemory
import com.smallhacker.util.VagueNumber
import com.smallhacker.util.toUInt24
2019-01-07 18:19:37 +00:00
data class State(val origin: Instruction? = null, val memory: SnesMemory, val address: SnesAddress, val flags: VagueNumber = VagueNumber(), val stack: ImmStack<VagueNumber> = immStack(), val gameData: GameData) {
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())
2019-01-13 03:38:59 +00:00
memory.toCanonical(SnesAddress(ptr))
2019-01-11 16:35:35 +00:00
}
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())
2019-01-13 03:38:59 +00:00
memory.toCanonical(SnesAddress(ptr))
2019-01-11 16:35:35 +00:00
}
2019-01-13 03:38:59 +00:00
fun resolveAbsoluteCode(absolute: UShort): SnesAddress? {
2019-01-12 02:16:50 +00:00
val ptr = (pb.toUInt24() shl 16) or (absolute.toUInt24())
2019-01-13 03:38:59 +00:00
val address = SnesAddress(ptr)
return memory.toCanonical(address)
2019-01-12 02:16:50 +00:00
}
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)
}