summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authoriximeow <me@iximeow.net>2015-03-11 18:23:21 -0700
committeriximeow <me@iximeow.net>2015-03-11 18:23:21 -0700
commit7cb66c7880d4841fb8cf38ce50a41f4f10700ddf (patch)
tree646052891f9cd38f6ccea3a654f39f33cb1e4e73
parent83366e673d87ef9bc0bf6d4bd2a1023bb8b1185e (diff)
Extract addressing modes + opcodes
-rw-r--r--src/AddressingModes.scala112
-rw-r--r--src/Opcodes.scala87
2 files changed, 199 insertions, 0 deletions
diff --git a/src/AddressingModes.scala b/src/AddressingModes.scala
new file mode 100644
index 0000000..e37bbe2
--- /dev/null
+++ b/src/AddressingModes.scala
@@ -0,0 +1,112 @@
+package ixee.re.disasm
+
+import ixee.cryptopals.utils.ByteUtils._
+import ixee.cryptopals.utils.FunctionUtils._
+
+import scala.collection.mutable.Map
+
+sealed trait AddressingMode {
+ def modeName: String
+ override def toString: String = modeName
+ def nameifyRegister(reg: Int): String = reg match {
+ case 0 => "pc"
+ case 1 => "sp"
+ case 2 => "sr"
+ case 3 => "cg"
+ case num @ _ => s"r$num"
+ }
+ def stringifyWith(reg: Int): String
+}
+
+sealed trait OneOpAddressing extends AddressingMode
+sealed trait TwoOpAddressing extends AddressingMode
+sealed trait TwoOpSourceAddressing extends TwoOpAddressing
+sealed trait TwoOpDestAddressing extends TwoOpAddressing
+
+object TwoOpSourceAddressingModes {
+ // just alias the apply over to make names look right at call sites.
+ // think hard about refactoring this
+ def apply(register: Int, mode: Int): Option[TwoOpSourceAddressing] = OneOpAddressingModes(register, mode)
+}
+
+object OneOpAddressingModes {
+ case class AddressingMode(as: Int, name: String, stringifier: String => String) extends OneOpAddressing with TwoOpSourceAddressing {
+ def modeName = name
+ def stringifyWith(reg: Int): String = stringifier(nameifyRegister(reg))
+ }
+
+ def apply(register: Int, mode: Int): Option[AddressingMode] = register match {
+ case 0 => PCModes(mode) orElse General(mode)
+ case 2 => SRModes(mode) orElse General(mode)
+ case 3 => CGModes(mode) orElse General(mode)
+ case _ => General(mode)
+ }
+
+ trait Modes {
+ private val modeMap: Map[Int, AddressingMode] = Map()
+ def Mode(as: Int, name: String, stringifier: String => String) = AddressingMode(as, name, stringifier).tap(modeMap += as -> _)
+
+ def apply(x: Int): Option[AddressingMode] = modeMap.get(x)
+ }
+
+ object PCModes extends Modes {
+ Mode(3, "NextWord", reg => s"@$reg+ (next word)")
+ }
+ object SRModes extends Modes {
+ Mode(2, "Const4", reg => "#4")
+ Mode(3, "Const8", reg => "#8")
+ }
+ object CGModes extends Modes {
+ Mode(0, "Const0", reg => "#0")
+ Mode(1, "Const1", reg => "#1")
+ Mode(2, "Const2", reg => "#2")
+ Mode(3, "ConstNeg1", reg => "#-1")
+ }
+ object General extends Modes {
+ Mode(0, "RegisterDirect", ident)
+ Mode(1, "Indexed", reg => s"@PC+($reg)")
+ Mode(2, "RegisterIndirect", reg => s"@$reg")
+ Mode(3, "IndirectAutoInc", reg => s"@$reg+")
+ }
+
+ PCModes
+ SRModes
+ CGModes
+ General
+}
+
+
+object TwoOpDestAddressingModes {
+ case class AddressingMode(as: Int, name: String, stringifier: String => String) extends TwoOpDestAddressing {
+ def modeName = name
+ def stringifyWith(reg: Int): String = stringifier(nameifyRegister(reg))
+ }
+
+ def apply(register: Int, mode: Int): Option[AddressingMode] = register match {
+ case 0 => PCModes(mode) orElse General(mode)
+ case 2 => SRModes(mode) orElse General(mode)
+ case _ => General(mode)
+ }
+
+ trait Modes {
+ private val modeMap: Map[Int, AddressingMode] = Map()
+ def Mode(as: Int, name: String, stringifier: String => String) = AddressingMode(as, name, stringifier).tap(modeMap += as -> _)
+
+ def apply(x: Int): Option[AddressingMode] = modeMap.get(x)
+ }
+
+ object PCModes extends Modes {
+ Mode(1, "Symbolic", reg => s"<??> (symbolic? x(PC)?")
+ }
+ object SRModes extends Modes {
+ Mode(1, "Absolute", reg => s"&@PC+ (value at nextWord)")
+ }
+ object General extends Modes {
+ Mode(0, "RegisterDirect", reg => s"$reg")
+ Mode(1, "Indexed", reg => s"@PC+($reg)")
+ }
+
+ PCModes
+ SRModes
+ General
+}
diff --git a/src/Opcodes.scala b/src/Opcodes.scala
new file mode 100644
index 0000000..7207f48
--- /dev/null
+++ b/src/Opcodes.scala
@@ -0,0 +1,87 @@
+package ixee.re.disasm
+
+import ixee.cryptopals.utils.ByteUtils._
+import ixee.cryptopals.utils.FunctionUtils._
+
+import scala.collection.mutable.Map
+
+sealed trait OpCode {
+ def instrName: String
+ override def toString: String = instrName
+}
+
+sealed trait NoOpCode extends OpCode
+sealed trait OneOpCode extends OpCode
+sealed trait TwoOpCode extends OpCode
+
+object Opcodes {
+ def opcodes: Map[Int, OpCode] = noOpCodes ++ oneOpCodes ++ twoOpCodes
+ val noOpCodes: Map[Int, NoOpCode] = Map()
+ val oneOpCodes: Map[Int, OneOpCode] = Map()
+ val twoOpCodes: Map[Int, TwoOpCode] = Map()
+
+ def apply(value: Int) = opcodes.get(value)
+ def noOp(value: Int) = noOpCodes.get(value)
+ def oneOp(value: Int) = oneOpCodes.get(value)
+ def twoOp(value: Int) = twoOpCodes.get(value)
+
+ object NoOpCodes {
+ val Prefix = 0x01
+ case class Code(value: Byte, name: String) extends NoOpCode { def instrName = name }
+ object Code {
+ def apply(value: Int, name: String) = new Code(value.toByte, name).tap(code => noOpCodes += ((((Prefix << 3) + value) << 10) -> code))
+ }
+
+ Code(0x00, "JNE")
+ Code(0x01, "JEQ")
+ Code(0x02, "JNC")
+ Code(0x03, "JC ")
+ Code(0x04, "JN ")
+ Code(0x05, "JGE")
+ Code(0x06, "JL ")
+ Code(0x07, "JMP")
+ }
+
+ object OneOpCodes {
+ val Prefix = 0x04
+ case class Code(value: Byte, name: String) extends OneOpCode { def instrName = name }
+ object Code {
+ def apply(value: Int, name: String) = new Code(value.toByte, name).tap(code => oneOpCodes += ((((Prefix << 3) + value) << 7) -> code))
+ }
+
+ Code(0x00, "RRC")
+ Code(0x01, "SWPB")
+ Code(0x02, "RRA")
+ Code(0x03, "SXT")
+ Code(0x04, "PUSH")
+ Code(0x05, "CALL")
+ Code(0x06, "RETI")
+// Code(0x07, "NotImplemented")
+ }
+
+ object TwoOpCodes {
+ val Prefix = 0x1
+ case class Code(value: Byte, name: String) extends TwoOpCode { def instrName = name }
+ object Code {
+ def apply(value: Int, name: String) = new Code(value.toByte, name).tap(code => twoOpCodes += ((value @<< 12) -> code))
+ }
+
+ Code(0x04, "MOV")
+ Code(0x05, "ADD")
+ Code(0x06, "ADDC")
+ Code(0x07, "SUBC")
+ Code(0x08, "SUB")
+ Code(0x09, "CMP")
+ Code(0x0a, "DADD")
+ Code(0x0b, "BIT")
+ Code(0x0c, "BIC")
+ Code(0x0d, "BIS")
+ Code(0x0e, "XOR")
+ Code(0x0f, "AND")
+ }
+
+ // forces the various opcode bodies to be evaluated. kinda weird, but it works so welp.
+ NoOpCodes
+ OneOpCodes
+ TwoOpCodes
+}