module Arm.Decoder
( decode )
where
import Data.Bits
import Data.Int
import Data.Maybe
import Debug.Trace
import Data.Word
import Arm.Instruction
import Arm.Operand
import Arm.RegisterName
decode
:: Word32
-> Maybe Instruction
decode word
= let bits = splitWord word
bit x = splitWord word (x, x)
destReg = nthReg (bits (15, 12))
firstOp = nthReg (bits (19, 16))
op2 = case (bit 25) of
0x0
-> Reg (nthReg (bits (3, 0)))
0x1
-> Con (bits (7, 0))
in case bits (27, 24) of
0xF -> Just (Swi (Con (bits (23, 0))))
_ -> case bits (27, 25) of
0x4 -> decodeMReg word firstOp
0x5 -> decodeBranch word
_ -> case (bits (27, 26)) of
0x0
-> decodeMulOrDp word destReg firstOp op2
0x1
-> decodeDataTrans word destReg
_ -> Nothing
decodeMulOrDp word destReg firstOp op2
= let bits = splitWord word
bit x = splitWord word (x, x)
in case (bits (27, 24), bit 7, bit 4) of
(0, 1, 1)
-> let rm = nthReg (bits (3, 0))
rd = nthReg (bits (19, 16))
rs = nthReg (bits (11, 8))
in Just (Mul (Reg rd) (Reg rm) (Reg rs))
_ -> decodeDataProc (bits (24, 21)) destReg firstOp op2
decodeBranch word
= let link = splitWord word (24, 24)
offset = fromIntegral (splitWord word (23, 0))
offset' = if offset > 32767
then offset 65536
else offset
cond = splitWord word (31, 28)
in case link of
0x0
-> case cond of
0x0 -> Just (Beq (Rel offset'))
0x1 -> Just (Bne (Rel offset'))
0xB -> Just (Blt (Rel offset'))
0xC -> Just (Bgt (Rel offset'))
0xE -> Just (B (Rel offset'))
_ -> Nothing
0x1
-> case cond of
0xE -> Just (Bl (Rel offset'))
_ -> Nothing
decodeDataProc opcode destReg firstOp op2
= case opcode of
0x00 -> Just (And (Reg destReg) (Reg firstOp) op2)
0x01 -> Just (Eor (Reg destReg) (Reg firstOp) op2)
0x02 -> Just (Sub (Reg destReg) (Reg firstOp) op2)
0x04 -> Just (Add (Reg destReg) (Reg firstOp) op2)
0x0A -> Just (Cmp (Reg destReg) op2)
0x0C -> Just (Orr (Reg destReg) (Reg firstOp) op2)
0x0D -> Just (Mov (Reg destReg) op2)
0x0E -> Just (Bic (Reg destReg) (Reg firstOp) op2)
_ -> Nothing
decodeMReg word firstOp
= let bits = splitWord word
bit x = splitWord word (x, x)
instr = case (bit 20) of
0x0 -> Ldmea
0x1 -> Stmea
rn = case (bit 21) of
0x0 -> Reg firstOp
0x1 -> (Aut (Reg firstOp))
regList 0 _ = []
regList n regNum
| odd n = (nthReg regNum) : (regList (n `div` 2) (regNum + 1))
| even n = regList (n `div` 2) (regNum + 1)
regs = regList (fromIntegral (bits (15, 0))) 0
in Just (instr rn (Mrg regs))
decodeDataTrans word destReg
= let bits = splitWord word
bit x = splitWord word (x, x)
instr = case (bit 22, bit 20) of
(0, 0) -> Ldrb
(0, 1) -> Strb
(1, 0) -> Ldr
(1, 1) -> Str
baseReg = nthReg (bits (19, 16))
offset = bits (11, 0)
addrMode = (bit 21) * 2 + bit 24
op2 = case addrMode of
0x0 -> if offset == 0
then Just (Ind baseReg)
else Just (Bas baseReg offset)
0x1 -> Nothing
0x2 -> Just (Aut (Bas baseReg offset))
0x3 -> Just (Pos (Ind baseReg) offset)
in op2 >>= (\op2' -> Just (instr (Reg destReg) op2'))
splitWord
:: Word32
-> (Int, Int)
-> Word32
splitWord word (hi, lo)
= let mask = (2 ^ (hi lo + 1) 1) `shiftL` lo
in (word .&. mask) `shiftR` lo