summaryrefslogtreecommitdiff
path: root/src/Instruction.scala
blob: 8a4e0183002785067c07bc6713f013810e263274 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
package ixee.re.disasm

import ixee.cryptopals.utils.ByteUtils._
import ixee.cryptopals.utils.FunctionUtils._

import scala.collection.mutable.Map

sealed trait Instruction

case class NoOpInst(code: NoOpCode, offset: Int) extends Instruction {
  override def toString: String = {
    s"$code -> $offset"
  }
}
case class OneOpInst(code: OneOpCode, byte: Boolean, dest: Int, addressMode: OneOpAddressing) extends Instruction {
  override def toString: String = {
    val byteStr = if (byte) ".B" else "  "
    s"$code$byteStr ${addressMode.stringifyWith(dest)}"
  }
}
case class TwoOpInst(code: TwoOpCode, byte: Boolean, src: Int, srcMode: TwoOpSourceAddressing, dest: Int, dstMode: TwoOpDestAddressing) extends Instruction {
  override def toString: String = {
    val byteStr = if (byte) ".B" else "  "
    s"$code$byteStr ${srcMode.stringifyWith(src)}, ${dstMode.stringifyWith(dest)}"
  }
}

object NoOp {
  def info(bytes: (Byte, Byte)): (Int, Int) = {
    val op = (bytes._1 & 0xfc) >> 2
    val offset = ((bytes._1 & 0x03) << 8) | bytes._2
    (op, offset)
  }

  def apply(bytes: (Byte, Byte)): Option[NoOpInst] = {
    val (opVal, offset) = info(bytes)
    for {
      opcode <- Opcodes.noOp(opVal << 10)
    } yield NoOpInst(opcode, offset)
  }
}

object OneOp {
  def info(bytes: (Byte, Byte)): (Int, Int, Int, Int) = {
    val dest = (bytes._2 & 0x0f)
    val destMode = ((bytes._2 & 0x30) >> 4)
    val byteBit = ((bytes._2 & 0x40) >> 6)
    val opcode = ((bytes._1 & 0xff) << 1) | ((bytes._2 & 0x80) >> 7)
    (opcode, byteBit, dest, destMode)
  }

  def apply(bytes: (Byte, Byte)): Option[OneOpInst] = {
    val (opVal, byteInstr, dest, rawDestMode) = info(bytes)
    for {
      opcode <- Opcodes.oneOp(opVal << 7)
      isByteOp = if (byteInstr == 1) true else false
      destMode <- OneOpAddressingModes(dest, rawDestMode)
    } yield OneOpInst(opcode, isByteOp, dest, destMode)
  }
}

object TwoOp {
  def info(bytes: (Byte, Byte)): (Int, Int, Int, Int, Int, Int) = {
    val dest = (bytes._2 & 0x0f)
    val sourceMode = (bytes._2 & 0x30) >> 4
    val byteBit = (bytes._2 & 0x40) >> 6
    val destMode = (bytes._2 & 0x80) >> 7
    val source = (bytes._1 & 0x0f)
    val opcode = (bytes._1 & 0xf0) >> 4
    (opcode, byteBit, source, destMode, dest, sourceMode)
  }

  def apply(bytes: (Byte, Byte)): Option[TwoOpInst] = {
    val (opVal, byteInstr, source, rawDestMode, dest, rawSourceMode) = info(bytes)

    for {
      opcode <- Opcodes.twoOp(opVal << 12)
      isByteOp = if (byteInstr == 1) true else false
      destMode <- TwoOpDestAddressingModes(dest, rawDestMode)
      sourceMode <- TwoOpSourceAddressingModes(source, rawSourceMode)
    } yield TwoOpInst(opcode, isByteOp, source, sourceMode, dest, destMode)
  }
}

object Instruction {
  def apply(instruction: (Byte, Byte)): Option[Instruction] = NoOp(instruction) orElse OneOp(instruction) orElse TwoOp(instruction)
  def littleEndian(instruction: String): Option[Instruction] = {
    val instr = Integer.parseInt(instruction, 16)
    val hi = (instr & 0xff00) >> 8
    val lo = instr & 0x00ff
    apply((hi.toByte, lo.toByte))
  }
  def apply(instruction: String): Option[Instruction] = {
    val instr = Integer.parseInt(instruction, 16)
    val hi = (instr & 0xff00) >> 8
    val lo = instr & 0x00ff
    apply((lo.toByte, hi.toByte))
  }

  def noOp(instruction: (Byte, Byte)): Option[NoOpInst] = NoOp.apply(instruction)

  def oneOp(instruction: (Byte, Byte)): Option[OneOpInst] = OneOp.apply(instruction)

  def twoOp(instruction: (Byte, Byte)): Option[TwoOpInst] = TwoOp.apply(instruction)

  def isNoOp(instruction: (Byte ,Byte)) = noOp(instruction).isDefined

  def isOneOp(instruction: (Byte, Byte)) = oneOp(instruction).isDefined

  def isTwoOp(instruction: (Byte, Byte)) = twoOp(instruction).isDefined
}