module Arm.Encoder
( encode )
where
import Data.Bits
import Data.Int
import Data.Word
import Data.Array
import Arm.Instruction
import Arm.Operand
import Arm.RegisterName
condEq :: (Int, Int, Word32)
condNe :: (Int, Int, Word32)
condCs :: (Int, Int, Word32)
condHs :: (Int, Int, Word32)
condCc :: (Int, Int, Word32)
condLo :: (Int, Int, Word32)
condMi :: (Int, Int, Word32)
condPl :: (Int, Int, Word32)
condVs :: (Int, Int, Word32)
condVc :: (Int, Int, Word32)
condHi :: (Int, Int, Word32)
condLs :: (Int, Int, Word32)
condGe :: (Int, Int, Word32)
condLt :: (Int, Int, Word32)
condGt :: (Int, Int, Word32)
condLe :: (Int, Int, Word32)
condAl :: (Int, Int, Word32)
condNv :: (Int, Int, Word32)
condEq = (31, 28, 0x0)
condNe = (31, 28, 0x1)
condCs = (31, 28, 0x2)
condHs = (31, 28, 0x2)
condCc = (31, 28, 0x3)
condLo = (31, 28, 0x3)
condMi = (31, 28, 0x4)
condPl = (31, 28, 0x5)
condVs = (31, 28, 0x6)
condVc = (31, 28, 0x7)
condHi = (31, 28, 0x8)
condLs = (31, 28, 0x9)
condGe = (31, 28, 0xA)
condLt = (31, 28, 0xB)
condGt = (31, 28, 0xC)
condLe = (31, 28, 0xD)
condAl = (31, 28, 0xE)
condNv = (31, 28, 0xF)
encode
:: Instruction
-> Word32
encode (Add (Reg r1) (Reg r2) op2)
= let w1 = concatFields 0
[ condAl
, (24, 21, 0x04)
, (19, 16, regIndex r2)
, (15, 12, regIndex r1)
]
w2 = concatFields 0
(case op2 of
Reg r3
-> [(25, 25, 0), (3, 0, regIndex r3)]
Con c1
-> [(25, 25, 1), (7, 0, c1)]
)
in w1 .|. w2
encode (And (Reg r1) (Reg r2) op2)
= let w1 = concatFields 0
[ condAl
, (24, 21, 0x00)
, (19, 16, regIndex r2)
, (15, 12, regIndex r1)
]
w2 = concatFields 0
(case op2 of
Reg r3
-> [(3, 0, regIndex r3)]
Con c1
-> [(7, 0, c1)]
)
in w1 .|. w2
encode (B (Rel rel))
= encodeBranch condAl rel
encode (Beq (Rel rel))
= encodeBranch condEq rel
encode (Bgt (Rel rel))
= encodeBranch condGt rel
encode (Bic (Reg r1) (Reg r2) op2)
= let w1 = concatFields 0
[ condAl
, (24, 21, 0x0E)
, (19, 16, regIndex r2)
, (15, 12, regIndex r1)
]
w2 = concatFields 0
(case op2 of
Reg r3
-> [(3, 0, regIndex r3)]
Con c1
-> [(7, 0, c1)]
)
in w1 .|. w2
encode (Bl (Rel rel))
= encodeBranch condAl rel .|. concatFields 0 [(24, 24, 1)]
encode (Blt (Rel rel))
= encodeBranch condLt rel
encode (Bne (Rel rel))
= encodeBranch condNe rel
encode (Cmp (Reg r1) op2)
= let w1 = concatFields 0
[ condAl
, (24, 21, 0x0A)
, (15, 12, regIndex r1)
]
w2 = encodeOp2 op2
in w1 .|. w2
encode (Eor (Reg r1) (Reg r2) op2)
= let w1 = concatFields 0
[ condAl
, (24, 21, 0x01)
, (19, 16, regIndex r2)
, (15, 12, regIndex r1)
]
w2 = concatFields 0
(case op2 of
Reg r3
-> [(3, 0, regIndex r3)]
Con c1
-> [(7, 0, c1)]
)
in w1 .|. w2
encode (Ldmea op1 (Mrg regs))
= encodeMReg 0x0 op1 regs
encode (Ldr (Reg r1) op2)
= encodeLdrStr 0x0 0x1 r1 op2
encode (Ldrb (Reg r1) op2)
= encodeLdrStr 0x0 0x0 r1 op2
encode (Mov (Reg r1) op2)
= let w1 = concatFields 0
[ condAl
, (24, 21, 0x0D)
, (15, 12, regIndex r1)
]
w2 = encodeOp2 op2
in w1 .|. w2
encode (Mul (Reg r1) (Reg r2) (Reg r3))
= concatFields 0
[ condAl
, (19, 16, regIndex r1)
, (11, 8, regIndex r3)
, ( 7, 4, 0x09)
, ( 3, 0, regIndex r2)
]
encode (Orr (Reg r1) (Reg r2) op2)
= let w1 = concatFields 0
[ condAl
, (24, 21, 0x0C)
, (19, 16, regIndex r2)
, (15, 12, regIndex r1)
]
w2 = concatFields 0
(case op2 of
Reg r3
-> [(3, 0, regIndex r3)]
Con c1
-> [(7, 0, c1)]
)
in w1 .|. w2
encode (Stmea op1 (Mrg regs))
= encodeMReg 0x1 op1 regs
encode (Str (Reg r1) op2)
= encodeLdrStr 0x1 0x1 r1 op2
encode (Strb (Reg r1) op2)
= encodeLdrStr 0x1 0x0 r1 op2
encode (Sub (Reg r1) (Reg r2) op2)
= let w1 = concatFields 0
[ condAl
, (24, 21, 0x02)
, (19, 16, regIndex r2)
, (15, 12, regIndex r1)
]
w2 = concatFields 0
(case op2 of
Reg r3
-> [(3, 0, regIndex r3)]
Con c1
-> [(7, 0, c1)]
)
in w1 .|. w2
encode (Swi (Con c))
= concatFields 0 [ condAl
, (27, 24, 0xF)
] .|. c
encodeBranch cond rel
= concatFields 0 [ cond,
(27, 25, 0x5)
] .|. (to16to32 rel)
to16to32 n = (fromIntegral (fromIntegral n :: Word16) :: Word32)
encodeOp2 op
= concatFields 0
(case op of
Reg r2
-> [(3, 0, regIndex r2)]
Con c1
-> [ (25, 25, 0x01)
, (7, 0, c1)
])
encodeMReg ls op1 regs
= let w1 = concatFields 0
[ condAl
, (27, 25, 0x04)
, (23, 23, 0x01)
, (20, 20, ls)
]
w2 = concatFields 0
(case op1 of
Aut (Reg reg)
-> [ (21, 21, 0x01)
, (19, 16, regIndex reg)
]
Reg reg
-> [ (19, 16, regIndex reg)
]
)
w3 = concatFields 0
(map (\reg -> let i = fromIntegral (regIndex reg) in (i, i, 1)) regs)
in w1 .|. w2 .|. w3
encodeLdrStr ls bw r1 op2
= let w1 = concatFields 0
[ condAl
, (27, 26, 0x01)
, (22, 22, bw)
, (20, 20, ls)
, (15, 12, regIndex r1)
]
w2 = concatFields 0
(case op2 of
Ind r2
-> [
(19, 16, regIndex r2)
]
Bas r2 offset
-> [
(19, 16, regIndex r2)
, (11, 0, offset)
]
Aut (Bas r2 offset)
-> [
(21, 21, 0x01)
, (19, 16, regIndex r2)
, (11, 0, offset)
]
Pos (Ind r2) const
-> [ (24, 24, 0x01)
, (21, 21, 0x01)
, (19, 16, regIndex r2)
, (11, 0, const)
]
)
in w1 .|. w2
concatFields
:: Word32
-> [(Int, Int, Word32)]
-> Word32
concatFields word [] = word
concatFields word ((hi, lo, val) : fields)
= let mask = fromIntegral (2 ^ (hi lo + 1) 1)
val' = val .&. mask
in concatFields (word .|. (val' `shiftL` lo)) fields
regIndex
:: RegisterName
-> Word32
regIndex = fromIntegral . (index (R0, CPSR))