From 7cb66c7880d4841fb8cf38ce50a41f4f10700ddf Mon Sep 17 00:00:00 2001
From: iximeow <me@iximeow.net>
Date: Wed, 11 Mar 2015 18:23:21 -0700
Subject: Extract addressing modes + opcodes

---
 src/AddressingModes.scala | 112 ++++++++++++++++++++++++++++++++++++++++++++++
 src/Opcodes.scala         |  87 +++++++++++++++++++++++++++++++++++
 2 files changed, 199 insertions(+)
 create mode 100644 src/AddressingModes.scala
 create mode 100644 src/Opcodes.scala

(limited to 'src')

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
+}
-- 
cgit v1.1