2019-01-07 18:19:37 +00:00
|
|
|
package com.smallhacker.disbrowser.asm
|
|
|
|
|
|
|
|
import com.smallhacker.disbrowser.util.*
|
|
|
|
|
2019-01-11 03:19:08 +00:00
|
|
|
private val ZEROES = Regex("[0]+")
|
|
|
|
private fun countBytes(format: String) = (ZEROES.find(format)?.groupValues?.firstOrNull()?.length?.toUInt() ?: 0u) / 2u
|
|
|
|
|
|
|
|
private const val ACCUMULATOR_SIZE = -1
|
|
|
|
private const val INDEX_SIZE = -2
|
|
|
|
|
|
|
|
fun format(format: String, value: UInt, operandBytes: UInt = countBytes(format)) =
|
|
|
|
format.replace(ZEROES, toHex(value, operandBytes))
|
2019-01-07 18:19:37 +00:00
|
|
|
|
|
|
|
enum class Mode {
|
2019-01-11 03:19:08 +00:00
|
|
|
DATA_BYTE("$00", dataMode = true, showLengthSuffix = false),
|
|
|
|
DATA_WORD("$0000", dataMode = true, showLengthSuffix = false),
|
|
|
|
DATA_LONG("$000000", dataMode = true, showLengthSuffix = false),
|
2019-01-07 18:19:37 +00:00
|
|
|
|
2019-01-11 03:19:08 +00:00
|
|
|
IMPLIED("", showLengthSuffix = false),
|
|
|
|
IMMEDIATE_8("#$00", showLengthSuffix = false),
|
|
|
|
IMMEDIATE_16("#$0000", showLengthSuffix = false),
|
|
|
|
ABSOLUTE("$0000"),
|
|
|
|
ABSOLUTE_X("$0000,x"),
|
|
|
|
ABSOLUTE_Y("$0000,y"),
|
|
|
|
ABSOLUTE_LONG("$000000"),
|
|
|
|
ABSOLUTE_LONG_X("$000000,x"),
|
|
|
|
ABSOLUTE_INDIRECT("($0000)"),
|
|
|
|
ABSOLUTE_INDIRECT_LONG("[$0000]"),
|
|
|
|
ABSOLUTE_X_INDIRECT("($0000,x)"),
|
|
|
|
DIRECT("$00"),
|
|
|
|
DIRECT_X("$00,x"),
|
|
|
|
DIRECT_Y("$00,y"),
|
|
|
|
DIRECT_S("$00,s"),
|
|
|
|
DIRECT_INDIRECT("($00)"),
|
|
|
|
DIRECT_INDIRECT_Y("($00),y"),
|
|
|
|
DIRECT_X_INDIRECT("($00,x)"),
|
|
|
|
DIRECT_S_INDIRECT_Y("($00,s),y"),
|
|
|
|
DIRECT_INDIRECT_LONG("[$00]"),
|
|
|
|
DIRECT_INDIRECT_LONG_Y("[$00],y"),
|
|
|
|
|
|
|
|
IMMEDIATE_M(
|
|
|
|
operandLength = ACCUMULATOR_SIZE,
|
|
|
|
print = {
|
|
|
|
when (preState?.m) {
|
|
|
|
null -> "????"
|
|
|
|
true -> format("#$00", byte.toUInt())
|
|
|
|
false -> format("#$0000", word.toUInt())
|
|
|
|
}
|
|
|
|
}
|
|
|
|
),
|
|
|
|
IMMEDIATE_X(
|
|
|
|
operandLength = INDEX_SIZE,
|
|
|
|
print = {
|
|
|
|
when (preState?.x) {
|
|
|
|
null -> "???"
|
|
|
|
true -> format("#$00", byte.toUInt())
|
|
|
|
false -> format("#$0000", word.toUInt())
|
|
|
|
}
|
|
|
|
}
|
|
|
|
),
|
|
|
|
|
|
|
|
RELATIVE(
|
|
|
|
format = "$000000",
|
|
|
|
operandLength = 1u,
|
|
|
|
valueGetter = {
|
|
|
|
val rel = signedByte.toInt() + 2
|
|
|
|
(relativeAddress + rel).value.toUInt()
|
|
|
|
},
|
|
|
|
showLengthSuffix = false
|
|
|
|
),
|
|
|
|
RELATIVE_LONG(
|
|
|
|
format = "$000000",
|
|
|
|
operandLength = 2u,
|
|
|
|
valueGetter = {
|
|
|
|
val rel = signedWord.toInt() + 3
|
|
|
|
(relativeAddress + rel).value.toUInt()
|
|
|
|
},
|
|
|
|
showLengthSuffix = false
|
|
|
|
),
|
|
|
|
BLOCK_MOVE(
|
|
|
|
operandLength = 2,
|
|
|
|
print = { String.format("#$%02x,#$%02x", byte.toInt(), byte2.toInt()) },
|
|
|
|
showLengthSuffix = false
|
|
|
|
)
|
2019-01-07 18:19:37 +00:00
|
|
|
;
|
|
|
|
|
2019-01-11 03:19:08 +00:00
|
|
|
private val operandLength: Int
|
|
|
|
val print: CodeUnit.() -> String
|
2019-01-07 18:19:37 +00:00
|
|
|
val dataMode: Boolean
|
2019-01-11 03:19:08 +00:00
|
|
|
val showLengthSuffix: Boolean
|
2019-01-07 18:19:37 +00:00
|
|
|
|
2019-01-11 03:19:08 +00:00
|
|
|
constructor(operandLength: Int, print: CodeUnit.() -> String, showLengthSuffix: Boolean = true) {
|
|
|
|
this.operandLength = operandLength
|
2019-01-07 18:19:37 +00:00
|
|
|
this.print = print
|
|
|
|
this.dataMode = false
|
2019-01-11 03:19:08 +00:00
|
|
|
this.showLengthSuffix = showLengthSuffix
|
2019-01-07 18:19:37 +00:00
|
|
|
}
|
|
|
|
|
2019-01-11 03:19:08 +00:00
|
|
|
constructor(
|
|
|
|
format: String,
|
|
|
|
printedLength: UInt = countBytes(format),
|
|
|
|
operandLength: UInt = printedLength,
|
|
|
|
valueGetter: CodeUnit.() -> UInt = { value!! },
|
|
|
|
dataMode: Boolean = false,
|
|
|
|
showLengthSuffix: Boolean = true
|
|
|
|
) {
|
|
|
|
this.operandLength = operandLength.toInt()
|
|
|
|
this.print = { format(format, valueGetter(this), printedLength) }
|
2019-01-07 18:19:37 +00:00
|
|
|
this.dataMode = dataMode
|
2019-01-11 03:19:08 +00:00
|
|
|
this.showLengthSuffix = showLengthSuffix
|
2019-01-07 18:19:37 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Returns the total length, in bytes, of an instruction of this mode and its operands.
|
|
|
|
*
|
|
|
|
* This is usually one greater than [operandLength], except in the cases when the instruction is just pure data
|
|
|
|
* without an opcode (in which case the two are equal).
|
|
|
|
*
|
|
|
|
* If the length cannot be determined based on the current [State], `null` is returned.
|
|
|
|
*/
|
2019-01-11 03:19:08 +00:00
|
|
|
fun instructionLength(state: State): UInt? {
|
|
|
|
val operatorLength = if (this.dataMode) 0u else 1u
|
|
|
|
return operandLength(state)
|
|
|
|
?.plus(operatorLength)
|
2019-01-07 18:19:37 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Returns the length, in bytes, of the operands of an instruction of this mode.
|
|
|
|
*
|
|
|
|
* This is usually one less than [operandLength], except in the cases when the instruction is just pure data
|
|
|
|
* without an opcode (in which case the two are equal).
|
|
|
|
*
|
|
|
|
* If the length cannot be determined based on the current [State], `null` is returned.
|
|
|
|
*/
|
2019-01-11 03:19:08 +00:00
|
|
|
fun operandLength(state: State): UInt? {
|
|
|
|
return when (operandLength) {
|
|
|
|
ACCUMULATOR_SIZE -> state.mWidth
|
|
|
|
INDEX_SIZE -> state.xWidth
|
|
|
|
else -> operandLength.toUInt()
|
2019-01-07 18:19:37 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|