summaryrefslogtreecommitdiff
path: root/SHARC/Instruction.hs
blob: 5c3b1bfadc1a316cec2b31aa73ccf8fbd1441ad7 (about) (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
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
{-
  This file is part of shark-disassembler.

  Copyright (C) 2014 Ricardo Wurmus

  This program is free software: you can redistribute it and/or modify
  it under the terms of the GNU General Public License as published by
  the Free Software Foundation, either version 3 of the License, or
  (at your option) any later version.

  This program is distributed in the hope that it will be useful,
  but WITHOUT ANY WARRANTY; without even the implied warranty of
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  GNU General Public License for more details.

  You should have received a copy of the GNU General Public License
  along with this program.  If not, see <http://www.gnu.org/licenses/>.
-}

{-# LANGUAGE QuasiQuotes #-}

module SHARC.Instruction where

import           SHARC.Types
import           SHARC.Word48
import           SHARC.ComputeField

import           Language.Literals.Binary
import           Data.Bits ((.&.), (.|.), xor, shift, shiftL, shiftR, testBit)
import           Data.Word
import           Data.List (intercalate)
import           Text.Printf (printf)
import           Data.Binary.Get


data Instruction = Type1 Word48
                 | Type2 Cond ComputeField
                 | Type3
                   Cond
                   ComputeField
                   Ireg
                   Mreg
                   Ureg
                   AccessType
                   Memory
                   WordAccess
                   Update
                 | Type4
                   Cond
                   ComputeField
                   Word8 {-6 bit data-}
                   Dreg
                   Ireg
                   AccessType
                   Memory
                   Update
                 | Type5Transfer
                   Cond
                   ComputeField
                   Ureg {-source register, 7 bit-}
                   Ureg {-destination register, 7 bit-}
                 | Type5Swap
                   Cond
                   ComputeField
                   Dreg {-x, 4 bit-}
                   Dreg {-y, 4 bit-}
                 | Type6WithDataAccess -- with data access
                   Cond
                   ImmediateShift
                   Dreg
                   Ireg
                   Mreg
                   AccessType
                   Memory
                 | Type6WithoutDataAccess -- without data access
                   Cond
                   ImmediateShift
                 | Type7 Word48
                 | Type8
                   BranchType
                   Cond
                   Address24
                   Bool {-loop abort-}
                   Bool {-branch delayed or not-}
                   Bool {-clear interrupt-}
                 | Type9 Word48
                 | Type10 Word48
                 | Type11
                   ReturnSource {- subroutine or interrupt -}
                   Cond
                   Bool {-return delayed or not-}
                   Bool {-else clause used or not-}
                   Bool {-loop reentry modifier specified or not-}
                   ComputeField
                 | Type12Ureg Ureg Address24
                 | Type12Immediate Word16 Address24
                 | Type13 TermCond Address24
                 | Type14 AccessType Memory WordAccess Ureg Address32
                 | Type15 Word48
                 | Type16 Word48
                 | Type17 Ureg Word32
                 | Type18 BitOp Sreg Word32
                 | Type19 Word48
                 | Type20
                   ([String], [String]) {-list of pushes and pops-}
                   Bool    {-cause a cash flush-}
                 | NOP  -- Type 21
                 | IDLE -- Type 22
                 | Type25 Word48
                 | UndefinedInstruction Word48
                 | InvalidInstruction Word48

instance Show Instruction where
  show NOP  = "NOP"
  show IDLE = "IDLE"
  show (UndefinedInstruction w) = "!! UNDEFINED: " ++ show w
  show (InvalidInstruction w)   = "!! INVALID: " ++ show w
  show t = let f = printf "%-46s; %s" in case t of
    Type1 w                  -> f (showType1 w) "type 1"
    Type2{}                  -> f (showType2 t) "type 2"
    Type3{}                  -> f (showType3 t) "type 3"
    Type4{}                  -> f (showType4 t) "type 4"
    Type5Transfer{}          -> f (showType5 t) "type 5 (transfer)"
    Type5Swap{}              -> f (showType5 t) "type 5 (swap)"
    Type6WithDataAccess{}    -> f (showType6 t) "type 6 (with data access)"
    Type6WithoutDataAccess{} -> f (showType6 t) "type 6 (without data access)"
    Type7 w                  -> f (showType7 w) "type 7"
    Type8{}                  -> f (showType8 t) "type 8"
    Type9 w                  -> f (showType9 w) "type 9"
    Type10 w                 -> f (showType10 w) "type 10"
    Type11{}                 -> f (showType11 t) "type 11"
    Type12Immediate{}        -> f (showType12 t) "type 12 (immediate)"
    Type12Ureg{}             -> f (showType12 t) "type 12 (from ureg)"
    Type13{}                 -> f (showType13 t) "type 13"
    Type14{}                 -> f (showType14 t) "type 14"
    Type15 w                 -> f (showType15 w) "type 15"
    Type16 w                 -> f (showType16 w) "type 16"
    Type17{}                 -> f (showType17 t) "type 17"
    Type18{}                 -> f (showType18 t) "type 18"
    Type19 w                 -> f (showType19 w) "type 19"
    Type20{}                 -> f (showType20 t) "type 20"
    Type25 w                 -> f (showType25 w) "type 25"


showType1 w = "  TODO: " ++ show w

showType2 (Type2 cond cf) = show cond ++ show cf

showType3 (Type3 cond compute ireg mreg ureg rw mem wa up) =
  show cond ++ show compute ++ assignment ++ flag
  where
    imOrder = case up of
               PreModify -> [show mreg, show ireg]
               PostModify -> [show ireg, show mreg]
    pair = "(" ++ intercalate ", " imOrder ++ ")"
    mem' = case mem of
      Prog -> "PM" ++ pair
      Data -> "DM" ++ pair
    assignment = case rw of
      Read  -> show ureg ++ "=" ++ mem'
      Write -> mem' ++ "=" ++ show ureg
    flag = case wa of
      LW -> " (LW)"
      _ -> ""

showType4 (Type4 cond compute dat dreg ireg rw mem up) =
  show cond ++ show compute ++ assignment
  where
    -- print 6 bit data as two's complement
    dat' = if dat `testBit` 5
           then '-' : show (dat `xor` 0x3F)
           else show dat
    order = case up of
      PreModify -> [dat', show ireg]
      PostModify -> [show ireg, dat']
    pair = "(" ++ intercalate ", " order ++ ")"
    mem' = case mem of
      Prog -> "PM" ++ pair
      Data -> "DM" ++ pair
    assignment = case rw of
      Read  -> show dreg ++ "=" ++ mem'
      Write -> mem' ++ "=" ++ show dreg

showType5 (Type5Transfer cond compute src dest) =
  optional ++ sep ++ show dest ++ "=" ++ show src
  where
    optional = show cond ++ show compute
    sep = if optional == "" then "" else ", "
showType5 (Type5Swap cond compute x y) =
  optional ++ sep ++ show x ++ "<->" ++ show y
  where
    optional = show cond ++ show compute
    sep = if optional == "" then "" else ", "

showType6 (Type6WithDataAccess cond shiftField dreg ireg mreg rw mem) =
  show cond ++ show shiftField ++ assignment
  where
    pair = "(" ++ intercalate ", " [show ireg, show mreg] ++ ")"
    mem' = case mem of
      Prog -> "PM" ++ pair
      Data -> "DM" ++ pair
    assignment = case rw of
      Read  -> show dreg ++ "=" ++ mem'
      Write -> mem' ++ "=" ++ show dreg

showType6 (Type6WithoutDataAccess cond shiftField) =
  show cond ++ show shiftField

showType7 w = "  TODO: " ++ show w

-- TODO: if Call, ignore LA and CI
-- TODO: flag handling is ugly
showType8 (Type8 t cond addr a d c) = show cond ++ t' ++ flags
  where
    t' = case t of
      Jump -> "JUMP " ++ show addr
      Call -> "CALL " ++ show addr
    a' = if a then "LA" else ""
    d' = if d then "DB" else ""
    c' = if c then "CI" else ""
    flags = if a || d || c
            then " (" ++ intercalate ", " (filter (/= "") [a', d', c']) ++ ")"
            else ""

showType9 w = "  TODO: " ++ show w

showType10 w = "  TODO: " ++ show w

showType11 (Type11 rs cond d e l cf) = show cond ++ rs' ++ flags ++ elseCompute
  where
    rs' = case rs of
      Subroutine -> "RTS"
      Interrupt  -> "RTI"
    -- TODO: this is ugly
    d' = if d then "DB" else ""
    l' = if l then "LR" else ""
    flags = if d || l
            then " (" ++ intercalate ", " (filter (/= "") [d', l']) ++ ")"
            else ""
    e' = if e then ", ELSE " else ", "
    -- do not print at all if opcode in compute field is empty
    -- TODO: can this be encoded in the type instead of doing an ugly string comparison?
    elseCompute = if show cf == "" then "" else e' ++ show cf

showType12 (Type12Immediate dat reladdr) =
  "LNCTR=" ++ show dat ++ ", DO " ++ show reladdr ++ " UNTIL LCE"
showType12 (Type12Ureg ureg reladdr) =
  "LNCTR=" ++ show ureg ++ ", DO " ++ show reladdr ++ " UNTIL LCE"

showType13 (Type13 term reladdr) =
  "DO " ++ show reladdr ++ " UNTIL " ++ show term

showType14 (Type14 rw mem wa ureg addr) = lhs ++ " = " ++ rhs ++ lwflag
  where
    lwflag = case wa of
              LW -> " (LW)"
              _ -> ""
    memloc = case mem of
              Data -> "DM(" ++ show addr ++ ")"
              Prog -> "PM(" ++ show addr ++ ")"
    lhs = case rw of
           Write -> memloc
           Read  -> show ureg
    rhs = case rw of
           Write -> show ureg
           Read  -> memloc

showType15 w = "  TODO: " ++ show w

showType16 w = "  TODO: " ++ show w

showType17 (Type17 ureg dat) = show ureg ++ " = " ++ printf "0x%08X" dat

showType18 (Type18 bop sreg w) =
  "BIT " ++ show bop ++ " " ++ show sreg ++ " " ++ printf "0x%08X" w

showType19 w = "  TODO: " ++ show w

showType20 (Type20 (pushes,pops) fc) = intercalate ", " (pu ++ po ++ [flush])
  where
    pu = map (\x -> "PUSH " ++ x) pushes
    po = map (\x -> "POP "  ++ x) pops
    flush = if fc then "FLUSH CACHE" else ""

showType25 w = "  TODO: " ++ show w



-- TODO
parseType1 = Type1

parseType2 w = Type2 cond (mkComputeField w)
  where
    cond = mkCond w

parseType3 w = Type3 cond compute ireg mreg ureg rw mem wa up
  where
    w64 = word48ToWord64 w
    cond = mkCond w
    compute = mkComputeField w
    ireg = mkIreg $ w64 `cutMask` [b| 000 0 111 000 00000 000 0000000 0000000 00000000 00000000 |]
    mreg = mkMreg $ w64 `cutMask` [b| 000 0 000 111 00000 000 0000000 0000000 00000000 00000000 |]
    ureg = mkUreg $ w64 `cutMask` [b| 000 0 000 000 00000 000 1111111 0000000 00000000 00000000 |]
    rw   = if w64 `testBit` 31 then Read else Write
    mem  = if w64 `testBit` 32 then Data else Prog
    wa   = if w64 `testBit` 30 then LW else NW
    up   = if w64 `testBit` 44 then PostModify else PreModify

parseType4 w = Type4 cond compute dat dreg ireg rw mem up
  where
    w64 = word48ToWord64 w
    cond = mkCond w
    compute = mkComputeField w
    dat  = w64 `cutMask` 0x0001F8000000
    dreg = mkDreg $ w64 `cutMask` 0x000007800000
    ireg = mkIreg $ w64 `cutMask` [b| 000 0 111 000 00000 000 0000000 0000000 00000000 00000000 |]
    rw   = if w64 `testBit` 39 then Read else Write
    mem  = if w64 `testBit` 40 then Data else Prog
    up   = if w64 `testBit` 38 then PostModify else PreModify

parseType5 w = if w64 `testBit` 43
               then let
                 x = mkDreg $ w64 `cutMask` 0x000007800000
                 y = mkDreg $ w64 `cutMask` 0x03C000000000
                 in Type5Swap cond compute x y
               else let
                 src  = mkUreg $ ((w64 `cutMask` 0x07C000000000) `shiftL` 2) .|. (w64 `cutMask` 0x000180000000)
                 dest = mkUreg $ w64 `cutMask` 0x00003F800000
                 in Type5Transfer cond compute src dest
  where
    w64 = word48ToWord64 w
    cond = mkCond w
    compute = mkComputeField w

parseType6 w = if w64 `testBit` 47
               then let -- with data access
                 dreg = mkDreg $ w64 `cutMask` [b| 0000 000 000 00000 00 0000 1111 0 000000 00000000 0000 0000 |]
                 ireg = mkIreg $ w64 `cutMask` [b| 0000 111 000 00000 00 0000 0000 0 000000 00000000 0000 0000 |]
                 mreg = mkMreg $ w64 `cutMask` [b| 0000 000 111 00000 00 0000 0000 0 000000 00000000 0000 0000 |]
                 rw   = if w64 `testBit` 31 then Read else Write
                 mem  = if w64 `testBit` 32 then Data else Prog
                 in
                  Type6WithDataAccess cond shiftField dreg ireg mreg rw mem
               else -- without data access
                 Type6WithoutDataAccess cond shiftField
  where
    w64 = word48ToWord64 w
    cond = mkCond w
    shiftField = ImmediateShift op dat rn rx
    op  = w64 `cutMask` 0x0000003F0000
    dat = (w64 `cutMask` 0x000078000000) `shiftL` 8 .|. (w64 `cutMask` 0x00000000FF00)
    rn = Dreg $ w64 `cutMask` 0xF0
    rx = Dreg $ w64 `cutMask` 0x0F

-- TODO
parseType7 = Type7

parseType8 :: (Word32 -> Address24) -> Word48 -> Instruction
parseType8 addressConstr w = Type8 t cond addr a d c
  where
    w64 = word48ToWord64 w
    t = if w64 `testBit` 39 then Jump else Call
    cond = mkCond w
    addr = addressConstr $ w64 `cutMask` 0x000000FFFFFF
    a = w64 `testBit` 38 -- loop abort
    d = w64 `testBit` 26 -- branch delayed or not
    c = w64 `testBit` 24 -- clear interrupt

-- TODO
parseType9 = Type9

-- TODO
parseType10 = Type10

parseType11 rs w = Type11 rs cond d e l cf where
    cond = mkCond w
    w64 = word48ToWord64 w
    d = w64 `testBit` 26 -- return delayed
    e = w64 `testBit` 25 -- else clause
    l = w64 `testBit` 24 -- loop reentry
    cf = mkComputeField w

parseType12 w = if w64 `testBit` 40
                then let -- loop counter load from a Ureg
                  ureg = mkUreg $ w64 `cutMask` 0x007F00000000
                  in Type12Ureg ureg reladdr
                else let -- immediate loop counter load
                  dat = w64 `cutMask` 0x00FFFF000000
                  in Type12Immediate dat reladdr
  where
    w64 = word48ToWord64 w
    reladdr = RelAddress24 $ w64 `cutMask` 0xFFFFFF -- lowest 24 bit

parseType13 w = Type13 term reladdr
  where
    w64 = word48ToWord64 w
    term = mkTermCond w
    reladdr = RelAddress24 $ w64 `cutMask` 0xFFFFFF -- lowest 24 bit

parseType14 w = Type14 rw mem wa ureg addr
  where
    w64 = word48ToWord64 w
    rw   = if w64 `testBit` 40 then Read else Write
    mem  = if w64 `testBit` 41 then Data else Prog
    wa   = if w64 `testBit` 39 then LW   else NW
    ureg = mkUreg $ w64 `cutMask` 0x00EF00000000
    addr = Address32 $ w64 `cutMask` 0x0000FFFFFFFF

-- TODO
parseType15 = Type15
parseType16 = Type16

parseType17 w = Type17 ureg dat
  where
    w64 = word48ToWord64 w
    dat = w64 `cutMask` 0x0000FFFFFFFF
    ureg = mkUreg $ w64 `cutMask` 0x00EF00000000

parseType18 w = Type18 bop sreg dat
  where
    w64 = word48ToWord64 w
    dat = w64 `cutMask` 0x0000FFFFFFFF
    bop = [ SET, CLR, TGL, TST, XOR ] !! (w64 `cutMask` 0x00E000000000)
    sreg = mkSreg $ w64 `cutMask` 0x00FF00000000

-- TODO
parseType19 = Type19

parseType20 w = Type20 (pushes, pops) fc
  where
    w64 = word48ToWord64 w
    lpu = if w64 `testBit` 39 then "LOOP"  else ""
    lpo = if w64 `testBit` 38 then "LOOP"  else ""
    spu = if w64 `testBit` 37 then "STS"   else ""
    spo = if w64 `testBit` 36 then "STS"   else ""
    ppu = if w64 `testBit` 35 then "PCSTK" else ""
    ppo = if w64 `testBit` 34 then "PCSTK" else ""
    pushes = filter (/= "") [lpu, spu, ppu]
    pops = filter (/= "") [lpo, spo, ppo]
    fc = w64 `testBit` 33

-- TODO
parseType25 = Type25


parseInstruction :: Word48 -> Instruction
parseInstruction word =
  let
    w64 = word48ToWord64 word
    b1 = (w64 `cutMask` 0xFF0000000000) :: Word8
    b2 = (w64 `cutMask` 0x00FF00000000) :: Word8
  in case fromIntegral b1 of
   [b| 0000 0000 |] -> if b2 `testBit` 7
                       then IDLE
                       else NOP
   [b| 0000 0001 |] -> parseType2 word
   [b| 0000 0010 |] -> parseType6 word
   [b| 0000 0011 |] -> UndefinedInstruction word
   [b| 0000 0100 |] -> parseType7 word
   [b| 0000 0101 |] -> UndefinedInstruction word
   [b| 0000 0110 |] -> parseType8 Address24 word
   [b| 0000 0111 |] -> parseType8 RelAddress24 word
   [b| 0000 1000 |] -> parseType9 word
   [b| 0000 1001 |] -> parseType9 word
   [b| 0000 1010 |] -> parseType11 Subroutine word
   [b| 0000 1011 |] -> parseType11 Interrupt word
   [b| 0000 1100 |] -> parseType12 word
   [b| 0000 1101 |] -> parseType12 word
   [b| 0000 1110 |] -> parseType13 word
   [b| 0000 1111 |] -> parseType17 word

   [b| 0001 0100 |] -> parseType18 word
   [b| 0001 0101 |] -> UndefinedInstruction word
   [b| 0001 0110 |] -> parseType19 word
   [b| 0001 0111 |] -> parseType20 word
   [b| 0001 1000 |] -> parseType25 word

   -- check six bit prefix
   _ -> case b1 .&. 0xFC of
     [b| 0001 0000 |] -> parseType14 word
     -- check four bit prefix
     _ -> case b1 .&. 0xF0 of
       [b| 0110 0000 |] -> parseType4 word
       [b| 0111 0000 |] -> parseType5 word
       [b| 1000 0000 |] -> parseType6 word
       [b| 1001 0000 |] -> parseType16 word
       -- check three bit prefix
       _ -> case b1 .&. 0xE0 of
         [b| 001 00000 |] -> parseType1 word
         [b| 010 00000 |] -> parseType3 word
         [b| 101 00000 |] -> parseType15 word
         [b| 110 00000 |] -> parseType10 word
         [b| 111 00000 |] -> parseType10 word
         _ -> InvalidInstruction word

getInstruction :: Get Instruction
getInstruction = fmap parseInstruction getPackedWord48

printInstructionWithAddr :: (Word64, Instruction) -> IO ()
printInstructionWithAddr (addr, instr) = printf "0x%05X: %s\n" addr (show instr)