1structure arm_disassemblerLib :> arm_disassemblerLib =
2struct
3
4(* interactive use:
5  app load ["arm_parserLib", "arm_encoderLib"];
6*)
7
8open HolKernel boolLib bossLib;
9open armSyntax arm_astSyntax;
10
11(* ------------------------------------------------------------------------- *)
12
13val _ = numLib.prefer_num();
14val _ = wordsLib.prefer_word();
15
16val ERR = Feedback.mk_HOL_ERR "arm_disassemblerLib";
17
18(* ------------------------------------------------------------------------- *)
19
20val eval = boolSyntax.rhs o Thm.concl o bossLib.EVAL;
21
22val uint_of_word = wordsSyntax.uint_of_word;
23val sint_of_term = Arbint.toInt o intSyntax.int_of_term;
24val hex_of_word = Int.fmt StringCvt.HEX o uint_of_word;
25
26fun mk_word2 i = wordsSyntax.mk_wordii (i,2);
27fun mk_word4 i = wordsSyntax.mk_wordii (i,4);
28
29val SP = mk_word4 13;
30val AL = mk_word4 14;
31val PC = mk_word4 15;
32
33val is_T  = Term.term_eq T;
34val is_F  = Term.term_eq F;
35val is_SP = Term.term_eq SP;
36val is_AL = Term.term_eq AL;
37val is_PC = Term.term_eq PC;
38
39fun is_0 tm = uint_of_word tm = 0;
40
41val dest_strip = armSyntax.dest_strip;
42
43fun i2l i =
44let fun recurse n l =
45          if n = 0 then List.rev l
46                   else recurse (n div 2) ((n mod 2 = 1)::l)
47in
48  if i < 0 then
49    raise ERR "i2l" "negative"
50  else if i = 0 then
51    [false]
52  else
53    recurse i []
54end;
55
56(* ------------------------------------------------------------------------- *)
57
58val comma     = ", ";
59val uppercase = String.map Char.toUpper;
60val commy     = String.concat o Lib.separate comma;
61fun square s  = String.concat ["[",s,"]"];
62fun curly s   = String.concat ["{",s,"}"];
63val scommy    = square o commy;
64fun opt b c x = if b then x ^ c else x
65
66fun code_line s1 s2 = (s1,s2) : string * string;
67fun directive_line s1 s2 = code_line (uppercase s1) s2;
68
69fun disassemble_ascii s = directive_line "ascii" (Lib.quote s);
70
71local
72  val tm_g = Parse.term_grammar ()
73  val ty_g = Parse.type_grammar ()
74in
75  val term_to_string =
76        PP.pp_to_string 70
77          (Parse.mlower o term_pp.pp_term tm_g ty_g PPBackEnd.raw_terminal)
78end
79
80fun disassemble_byte l =
81  l |> List.map term_to_string |> commy |> directive_line "byte"
82
83fun disassemble_short l =
84  l |> List.map term_to_string |> commy |> directive_line "short"
85
86fun disassemble_word l =
87  l |> List.map term_to_string |> commy |> directive_line "word"
88
89(* ------------------------------------------------------------------------- *)
90
91fun number tm =
92let val s = term_to_string tm in
93  if s = "ARB" then
94    "UNPREDICTABLE"
95  else
96    String.extract(s,0,SOME (String.size s - 1))
97end;
98
99fun constant tm = "#" ^ number tm;
100fun sign_constant (u,tm) = (if is_T u then "#" else "#-") ^ number tm;
101
102fun offset tm =
103let val s = tm |> integer_wordSyntax.mk_w2i |> eval |> term_to_string in
104  if String.sub (s,0) = #"-" then
105    "-#" ^ String.extract(s,1,SOME (String.size s - 1))
106  else
107    "+#" ^ s
108end;
109
110fun char_word4 c n =
111let val _ = 0 <= n andalso n <= 15 orelse raise ERR "char_word4" "" in
112  String.str c ^ Int.toString n
113end;
114
115fun reg 13 = "sp"
116  | reg 14 = "lr"
117  | reg 15 = "pc"
118  | reg n = char_word4 #"r" n;
119
120val register = reg o uint_of_word;
121val cregister = (char_word4 #"c") o uint_of_word;
122val coprocessor = (char_word4 #"p") o uint_of_word;
123val rcommy = commy o List.map register;
124
125local
126  fun mk_blocks l =
127  let
128    fun blocks [] i ys = ys
129      | blocks [false] i ys = ys
130      | blocks [true] i [] = [(i,i)]
131      | blocks [true] i (h::t) = ((fst h,i)::t)
132      | blocks (false::false::xs) i ys = blocks (false::xs) (i + 1) ys
133      | blocks (true::true::xs) i ys = blocks (true::xs) (i + 1) ys
134      | blocks (false::true::xs) i ys =
135          blocks (true::xs) (i + 1) ((i + 1,~1)::ys)
136      | blocks (true::false::xs) i [] =
137          blocks (false::xs) (i + 1) [(i,i)]
138      | blocks (true::false::xs) i (h::t) =
139          blocks (false::xs) (i + 1) ((fst h,i)::t)
140  in
141    List.rev (blocks l 0 (if hd l then [(0,~1)] else []))
142  end
143
144  fun reg_list s [] = s ^ "}"
145    | reg_list s ((i,j)::xs) =
146        reg_list (s ^ reg i ^
147          (if i = j then
148            ""
149           else if i + 1 = j then
150            comma ^ reg j
151           else
152            "-" ^ reg j) ^
153          (if xs = [] then "" else comma)) xs
154in
155  val register_list =
156        (reg_list "{") o mk_blocks o i2l o
157        (fn i => i mod 0x10000) o uint_of_word
158end;
159
160fun full_condition tm =
161  case uint_of_word tm
162  of 0  => "eq"
163   | 1  => "ne"
164   | 2  => "cs"
165   | 3  => "cc"
166   | 4  => "mi"
167   | 5  => "pl"
168   | 6  => "vs"
169   | 7  => "vc"
170   | 8  => "hi"
171   | 9  => "ls"
172   | 10 => "ge"
173   | 11 => "lt"
174   | 12 => "gt"
175   | 13 => "le"
176   | 14 => "al"
177   | _  => raise ERR "full_condition" "unexpected value";
178
179fun condition tm =
180  if Term.is_var tm then
181    fst (Term.dest_var tm)
182  else if is_AL tm orelse is_PC tm then
183    ""
184  else
185    full_condition tm;
186
187fun mnemonic (enc,cond,tm) s1 s2 =
188let
189  val q = if enc = Encoding_Thumb2_tm andalso
190             can arm_encoderLib.arm_encode
191                 (arm_parserLib.Instruction (Encoding_Thumb_tm,cond,tm))
192          then
193            ".w"
194          else
195            ""
196in
197  code_line (s1 ^ condition cond ^ q) s2
198end;
199
200fun arm_expand_imm tm =
201  ``(((7 >< 0) ^tm) #>> (2 * (w2n ((11 -- 8) ^tm)))) : word32``
202    |> eval;
203
204fun thumb_expand_imm tm =
205  ``if (11 -- 10) ^tm = 0b00w then
206      let imm8 = (7 >< 0) ^tm : word8 in
207        case (9 >< 8) ^tm : word2
208        of 0b00w => w2w imm8
209         | 0b01w => if imm8 = 0w then ARB else
210                      word32 [imm8; 0b00000000w; imm8; 0b00000000w]
211         | 0b10w => if imm8 = 0w then ARB else
212                      word32 [0b00000000w; imm8; 0b00000000w; imm8]
213         | 0b11w => if imm8 = 0w then ARB else
214                      word32 [imm8; imm8; imm8; imm8]
215    else
216      let unrotated_value = (7 :+ T) ((6 >< 0) ^tm) in
217        (unrotated_value #>> w2n ((11 -- 7) ^tm))``
218      |> eval;
219
220fun shift tm =
221  comma ^
222  (case uint_of_word tm
223   of 0 => "lsl "
224    | 1 => "lsr "
225    | 2 => "asr "
226    | 3 => "ror "
227    | _ => raise ERR "shift" "unexpected value");
228
229fun disassemble_imm_shift (imm5,typ,rm) =
230  case uint_of_word typ
231  of 0 => if is_0 imm5 then
232            register rm
233          else
234            register rm ^ shift typ ^ constant imm5
235   | 1 => register rm ^ shift typ ^
236            (if is_0 imm5 then "#32" else constant imm5)
237   | 2 => register rm ^ shift typ ^
238            (if is_0 imm5 then "#32" else constant imm5)
239   | 3 => if is_0 imm5 then
240            register rm ^ comma ^ "rrx"
241          else
242            register rm ^ shift typ ^ constant imm5
243   | _ => raise ERR "disassemble_imm_shift" "unexpected value";
244
245fun disassemble_mode1 thumb2 tm =
246  case dest_strip tm
247  of ("Mode1_immediate", [imm12]) =>
248        imm12 |> (if thumb2 then thumb_expand_imm else arm_expand_imm)
249              |> constant
250   | ("Mode1_register", [imm5,typ,rm]) =>
251        disassemble_imm_shift (imm5,typ,rm)
252   | ("Mode1_register_shifted_register", [rs,typ,rm]) =>
253       register rm ^ shift typ ^ register rs
254   | _ => raise ERR "disassemble_mode1" "";
255
256fun disassemble_mode2 (u,tm) =
257  case dest_strip tm
258  of ("Mode2_immediate", [imm12]) =>
259         if is_T u andalso is_0 imm12 then
260           ""
261         else
262           comma ^ sign_constant (u,imm12)
263   | ("Mode2_register", [imm5,typ,rm]) =>
264         comma ^ (if is_F u then "-" else "") ^
265         disassemble_imm_shift (imm5,typ,rm)
266   | _ => raise ERR "disassemble_mode2" "";
267
268fun disassemble_mode3 (u,tm) =
269  case dest_strip tm
270  of ("Mode3_immediate", [imm12]) =>
271         if is_T u andalso is_0 imm12 then
272           ""
273         else
274           comma ^ sign_constant (u,imm12)
275   | ("Mode3_register", [imm2,rm]) =>
276        comma ^ (if is_F u then "-" else "") ^
277        disassemble_imm_shift (imm2,``0w:word2``,rm)
278   | _ => raise ERR "disassemble_mode3" "";
279
280fun disassemble_mode5 (rn,p,u,w,imm8) =
281let val imm32 = ``((w2w ^imm8) << 2) : word32`` |> eval in
282  if is_T p then
283    opt (is_T w) "!" (square
284      (if is_0 imm32 then
285         register rn
286       else
287         commy [register rn, sign_constant (u,imm32)]))
288  else if is_T w then
289    commy [square (register rn), sign_constant (u,imm32)]
290  else if is_T u then
291    commy [square (register rn), curly (number imm8)]
292  else
293    raise ERR "disassemble_mode5" "unexpected mode"
294end;
295
296fun rotation (n,rot) =
297  case uint_of_word rot
298  of 0 => register n
299   | 1 => commy [register n, "ror #8"]
300   | 2 => commy [register n, "ror #16"]
301   | 3 => commy [register n, "ror #24"]
302   | _ => raise ERR "rotation" "unexpected value";
303
304fun data_processing
305      (f : string -> string -> string * string) enc (opc,s,n,d,mode1) =
306let
307  val m1 = disassemble_mode1 (enc = Encoding_Thumb2_tm) mode1
308  val sflag = opt (is_T s) "s"
309  fun arith x = f (sflag x) (commy [register d, register n, m1])
310  fun move x = f (sflag x) (commy [register d, m1])
311  fun test x = f x (commy [register n, m1])
312in
313  case uint_of_word opc
314  of 0  => arith "and"
315   | 1  => arith "eor"
316   | 2  => arith "sub"
317   | 3  => arith "rsb"
318   | 4  => arith "add"
319   | 5  => arith "adc"
320   | 6  => arith "sbc"
321   | 7  => arith "rsc"
322   | 8  => test  "tst"
323   | 9  => test  "teq"
324   | 10 => test  "cmp"
325   | 11 => test  "cmn"
326   | 12 => arith "orr"
327   | 13 => move  "mov"
328   | 14 => arith "bic"
329   | 15 => if enc = Encoding_Thumb2_tm andalso not (is_PC n) then
330             arith "orn"
331           else
332             move "mvn"
333   | _  => raise ERR "register" "unexpected value"
334end;
335
336fun signed_halfword_multiply
337      (f : string -> string -> string * string) (opc,M,N,d,a,m,n) =
338  case (uint_of_word opc,is_T M,is_T N)
339  of (0,false,false) => f "smlabb" (rcommy [d,n,m,a])
340   | (0,false,true ) => f "smlatb" (rcommy [d,n,m,a])
341   | (0,true, false) => f "smlabt" (rcommy [d,n,m,a])
342   | (0,true, true ) => f "smlatt" (rcommy [d,n,m,a])
343   | (1,false,false) => f "smlawb" (rcommy [d,n,m,a])
344   | (1,false,true)  => f "smulwb" (rcommy [d,n,m])
345   | (1,true, false) => f "smlawt" (rcommy [d,n,m,a])
346   | (1,true, true)  => f "smulwt" (rcommy [d,n,m])
347   | (2,false,false) => f "smlalbb" (rcommy [d,n,m,a])
348   | (2,false,true ) => f "smlaltb" (rcommy [d,n,m,a])
349   | (2,true, false) => f "smlalbt" (rcommy [d,n,m,a])
350   | (2,true, true ) => f "smlaltt" (rcommy [d,n,m,a])
351   | (3,false,false) => f "smulbb" (rcommy [d,n,m])
352   | (3,false,true ) => f "smultb" (rcommy [d,n,m])
353   | (3,true, false) => f "smulbt" (rcommy [d,n,m])
354   | (3,true, true ) => f "smultt" (rcommy [d,n,m])
355   | _ => raise ERR "signed_halfword_multiply" "unexpected value";
356
357fun parallel_add_subtract (u,(opc1,opc2)) =
358  case (is_T u,fst (dest_const opc1),fst (dest_const opc2))
359  of (false,"Parallel_normal", "Parallel_add_16")               => "sadd16"
360   | (false,"Parallel_normal", "Parallel_add_sub_exchange")     => "sasx"
361   | (false,"Parallel_normal", "Parallel_sub_add_exchange")     => "ssax"
362   | (false,"Parallel_normal", "Parallel_sub_16")               => "ssub16"
363   | (false,"Parallel_normal", "Parallel_add_8")                => "sadd8"
364   | (false,"Parallel_normal", "Parallel_sub_8")                => "ssub8"
365   | (false,"Parallel_saturating", "Parallel_add_16")           => "qadd16"
366   | (false,"Parallel_saturating", "Parallel_add_sub_exchange") => "qasx"
367   | (false,"Parallel_saturating", "Parallel_sub_add_exchange") => "qsax"
368   | (false,"Parallel_saturating", "Parallel_sub_16")           => "qsub16"
369   | (false,"Parallel_saturating", "Parallel_add_8")            => "qadd8"
370   | (false,"Parallel_saturating", "Parallel_sub_8")            => "qsub8"
371   | (false,"Parallel_halving", "Parallel_add_16")              => "shadd16"
372   | (false,"Parallel_halving", "Parallel_add_sub_exchange")    => "shasx"
373   | (false,"Parallel_halving", "Parallel_sub_add_exchange")    => "shsax"
374   | (false,"Parallel_halving", "Parallel_sub_16")              => "shsub16"
375   | (false,"Parallel_halving", "Parallel_add_8")               => "shadd8"
376   | (false,"Parallel_halving", "Parallel_sub_8")               => "shsub8"
377   | (true, "Parallel_normal", "Parallel_add_16")               => "uadd16"
378   | (true, "Parallel_normal", "Parallel_add_sub_exchange")     => "uasx"
379   | (true, "Parallel_normal", "Parallel_sub_add_exchange")     => "usax"
380   | (true, "Parallel_normal", "Parallel_sub_16")               => "usub16"
381   | (true, "Parallel_normal", "Parallel_add_8")                => "uadd8"
382   | (true, "Parallel_normal", "Parallel_sub_8")                => "usub8"
383   | (true, "Parallel_saturating", "Parallel_add_16")           => "uqadd16"
384   | (true, "Parallel_saturating", "Parallel_add_sub_exchange") => "uqasx"
385   | (true, "Parallel_saturating", "Parallel_sub_add_exchange") => "uqsax"
386   | (true, "Parallel_saturating", "Parallel_sub_16")           => "uqsub16"
387   | (true, "Parallel_saturating", "Parallel_add_8")            => "uqadd8"
388   | (true, "Parallel_saturating", "Parallel_sub_8")            => "uqsub8"
389   | (true, "Parallel_halving", "Parallel_add_16")              => "uhadd16"
390   | (true, "Parallel_halving", "Parallel_add_sub_exchange")    => "uhasx"
391   | (true, "Parallel_halving", "Parallel_sub_add_exchange")    => "uhsax"
392   | (true, "Parallel_halving", "Parallel_sub_16")              => "uhsub16"
393   | (true, "Parallel_halving", "Parallel_add_8")               => "uhadd8"
394   | (true, "Parallel_halving", "Parallel_sub_8")               => "uhsub8"
395   | _ => raise ERR "parallel_add_subtract" "unexpected value";
396
397fun msr_mask (r,mask) =
398let fun odd n = n mod 2 = 1
399    fun divodd n = (n div 2, odd n)
400    val n = uint_of_word mask
401    val (n,b0) = divodd n
402    val (n,b1) = divodd n
403    val (n,b2) = divodd n
404    val b3 = odd n
405in
406  String.concat ((if is_T r then "spsr_" else "cpsr_")::
407    (List.map (fn (b,c) => opt b c "") [(b3,"f"),(b2,"s"),(b1,"x"),(b0,"c")]))
408end;
409
410fun it_mask c0 mask =
411let val n = uint_of_word mask in
412  if c0 then
413    case n
414    of 8  => ""
415     | 12 => "t"
416     | 4  => "e"
417     | 14 => "tt"
418     | 6  => "et"
419     | 10 => "te"
420     | 2  => "ee"
421     | 15 => "ttt"
422     | 7  => "ett"
423     | 11 => "tet"
424     | 3  => "eet"
425     | 13 => "tte"
426     | 5  => "ete"
427     | 9  => "tee"
428     | 1  => "eee"
429     | _ => raise ERR "it_mask" ""
430  else
431    case n
432    of 8  => ""
433     | 4  => "t"
434     | 12 => "e"
435     | 2  => "tt"
436     | 10 => "et"
437     | 6  => "te"
438     | 14 => "ee"
439     | 1  => "ttt"
440     | 9  => "ett"
441     | 5  => "tet"
442     | 13 => "eet"
443     | 3  => "tte"
444     | 11 => "ete"
445     | 7  => "tee"
446     | 15 => "eee"
447     | _ => raise ERR "it_mask" ""
448end;
449
450fun address f (p,u:term,w,n,t,mode:term) =
451  opt (is_T w andalso is_T p) "!"
452    (commy [register t,
453      (if is_T p then
454         [register n, f (u,mode)] |> String.concat |> square
455       else
456         String.concat [square (register n), f (u,mode)])]);
457
458fun indexing (p,u) =
459  (if is_T u then "i" else "d") ^
460  (if is_T p then "b" else "a");
461
462fun exclusive (n,imm8) =
463  square
464    (if is_0 imm8 then
465       register n
466     else
467       commy [register n, ``(w2w ^imm8 << 2) : word32`` |> eval |> constant]);
468
469fun hint (f : string -> string -> string * string) tm =
470  case dest_strip tm
471  of ("Hint_nop", [])                => f "nop" ""
472   | ("Hint_yield", [])              => f "yield" ""
473   | ("Hint_wait_for_event", [])     => f "wfe" ""
474   | ("Hint_wait_for_interrupt", []) => f "wfi" ""
475   | ("Hint_send_event", [])         => f "sev" ""
476   | ("Hint_debug", [opt])           => f "dbg" (constant opt)
477   | _ => raise ERR "hint" "";
478
479fun barrier_option tm =
480  case uint_of_word tm
481  of 2  => "oshst"
482   | 3  => "osh"
483   | 6  => "nshst"
484   | 7  => "nsh"
485   | 10 => "ishst"
486   | 11 => "ish"
487   | 14 => "st"
488   | _  => "sy";
489
490(* ------------------------------------------------------------------------- *)
491
492fun disassemble_branch (instr as (enc,_,tm)) =
493let val f = mnemonic instr in
494  case dest_strip (dest_Branch tm)
495  of ("Branch_Target", [imm24]) =>
496       f "b" (``if ^enc = Encoding_ARM then
497                  sw2sw ^imm24 << 2 + 8w : word32
498                else
499                  sw2sw ^imm24 << 1 + 4w`` |> offset)
500   | ("Branch_Exchange", [m]) =>
501       f "bx" (register m)
502   | ("Branch_Link_Exchange_Immediate", [h,toarm,imm24]) =>
503       f (if (enc = Encoding_ARM_tm) = is_F toarm then "blx" else "bl")
504         (``let imm32 = (sw2sw ^imm24 << 2) +
505                        (if ^enc = Encoding_ARM then 8w else 4w:word32) in
506              if ^toarm then imm32 else (1 :+ ^h) imm32`` |> offset)
507   | ("Branch_Link_Exchange_Register", [m]) =>
508       f "blx" (register m)
509   | ("Compare_Branch", [nzero,imm6,n]) =>
510       f (if is_T nzero then "cbnz" else "cbz")
511         (commy [register n, ``(w2w ^imm6 << 1) + 4w : word32`` |> offset])
512   | ("Table_Branch_Byte", [n,h,m]) =>
513       if is_T h then
514         f "tbh" (scommy [register n, register m, "lsl #1"])
515       else
516         f "tbb" (scommy [register n, register m])
517   | ("Check_Array", [n,m]) =>
518       f "chka" (commy [register n,register m])
519   | ("Handler_Branch_Link", [l,handler]) =>
520       f (if is_T l then "hbl" else "hb") (constant handler)
521   | ("Handler_Branch_Link_Parameter", [imm5,handler]) =>
522       f "hblp" (commy [constant imm5, constant handler])
523   | ("Handler_Branch_Parameter", [imm3,handler]) =>
524       f "hbp" (commy [constant imm3, constant handler])
525   | _ => raise ERR "disassemble_branch"
526            ("cannot disassemble: " ^ term_to_string tm)
527end;
528
529fun disassemble_data_processing (instr as (enc,_,tm)) =
530let val f = mnemonic instr
531    fun ocommy b l x = rcommy (if b then l @ [x] else l)
532in
533  case dest_strip (dest_DataProcessing tm)
534  of ("Data_Processing", [opc,s,n,d,mode1]) =>
535        data_processing f enc (opc,s,n,d,mode1)
536   | ("Move_Halfword", [h,d,imm16]) =>
537        f (if is_T h then "movt" else "movw")
538          (commy [register d, constant imm16])
539   | ("Add_Sub", [a,n,d,imm12]) =>
540        if enc = Encoding_ARM_tm then
541          f (if is_T a then "add" else "sub")
542            (commy [register d, register n,
543                    disassemble_mode1 false (mk_Mode1_immediate imm12)])
544        else
545          f (if enc = Encoding_Thumb_tm then "add" else
546               if is_T a then "addw" else "subw")
547            (commy [register d, register n, constant imm12])
548   | ("Multiply", [acc,s,d,a,m,n]) =>
549        f ((if is_T acc then "mla" else "mul") ^ (if is_T s then "s" else ""))
550          (ocommy (is_T acc) [d,n,m] a)
551   | ("Multiply_Subtract", [d,a,m,n]) =>
552        f "mls" (rcommy [d,n,m,a])
553   | ("Signed_Halfword_Multiply", [opc,M,N,d,a,m,n]) =>
554        signed_halfword_multiply f (opc,M,N,d,a,m,n)
555   | ("Signed_Multiply_Dual", [d,a,m,M,N,n]) =>
556        f ((if is_T M
557            then if is_PC a then "smusd" else "smlsd"
558            else if is_PC a then "smuad" else "smlad") ^
559           (if is_T N then "x" else "")) (ocommy (not (is_PC a)) [d,n,m] a)
560   | ("Signed_Multiply_Long_Dual", [dhi,dlo,m,M,N,n]) =>
561        f ((if is_T M then "smlsld" else "smlald") ^
562           (if is_T N then "x" else "")) (rcommy [dlo,dhi,n,m])
563   | ("Signed_Most_Significant_Multiply", [d,a,m,r,n]) =>
564        f ((if is_PC a then "smmul" else "smmla") ^
565           (if is_T r then "r" else "")) (ocommy (not (is_PC a)) [d,n,m] a)
566   | ("Signed_Most_Significant_Multiply_Subtract", [d,a,m,r,n]) =>
567        f (if is_T r then "smmlsr" else "smmls") (rcommy [d,n,m,a])
568   | ("Multiply_Long", [sgnd,a,s,dhi,dlo,m,n]) =>
569        f ((if is_T sgnd then "s" else "u") ^
570           (if is_T a then "mlal" else "mull") ^
571           (if is_T s then "s" else "")) (rcommy [dlo,dhi,n,m])
572   | ("Multiply_Accumulate_Accumulate", [dhi,dlo,m,n]) =>
573        f "umaal" (rcommy [dlo,dhi,n,m])
574   | ("Saturate", [u,sat,d,imm5,sh,n]) =>
575        let
576           val imm = constant (``if ^u then ^sat else ^sat + 1w`` |> eval)
577           val imm = if is_T u then imm else if imm = "#0" then "#32" else imm
578        in
579           f (if is_T u then "usat" else "ssat")
580             (commy [register d, imm,
581               disassemble_imm_shift
582                  (imm5,mk_word2 (if is_T sh then 2 else 0),n)])
583        end
584   | ("Saturate_16", [u,imm4,d,n]) =>
585        let
586           val imm = constant (``if ^u then ^imm4 else ^imm4 + 1w`` |> eval)
587           val imm = if is_T u then imm else if imm = "#0" then "#16" else imm
588        in
589           f (if is_T u then "usat16" else "ssat16")
590             (commy [register d, imm, register n])
591        end
592   | ("Saturating_Add_Subtract", [opc,n,d,m]) =>
593        f (case uint_of_word opc
594           of 0 => "qadd" | 1 => "qsub" | 2 => "qdadd" | 3 => "qdsub"
595            | _ => raise ERR "disassemble_data_processing" "unexpected value")
596          (rcommy [d,m,n])
597   | ("Pack_Halfword", [n,d,imm5,t,m]) =>
598        f (if is_T t then "pkhtb" else "pkhbt")
599          (commy [register d, register n,
600            disassemble_imm_shift (imm5,mk_word2 (if is_T t then 2 else 0),m)])
601   | ("Extend_Byte", [u,n,d,rot,m]) =>
602        f ((if is_T u then "u" else "s") ^
603           (if is_PC n then "xtb" else "xtab"))
604          (if is_PC n then
605             commy [register d, rotation (m,rot)]
606           else
607             commy [register d, register n, rotation (m,rot)])
608   | ("Extend_Byte_16", [u,n,d,rot,m]) =>
609        f ((if is_T u then "u" else "s") ^
610           (if is_PC n then "xtb16" else "xtab16"))
611          (if is_PC n then
612             commy [register d, rotation (m,rot)]
613           else
614             commy [register d, register n, rotation (m,rot)])
615   | ("Extend_Halfword", [u,n,d,rot,m]) =>
616        f ((if is_T u then "u" else "s") ^
617           (if is_PC n then "xth" else "xtah"))
618          (if is_PC n then
619             commy [register d, rotation (m,rot)]
620           else
621             commy [register d, register n, rotation (m,rot)])
622   | ("Bit_Field_Clear_Insert", [msb,d,lsb,n]) =>
623        let
624           val width = constant (``^msb - ^lsb + 1w`` |> eval)
625           val width = if width = "#0" then "#32" else width
626        in
627          if is_PC n then
628            f "bfc" (commy [register d, constant lsb, width])
629          else
630            f "bfi"
631              (commy [register d, register n, constant lsb, width])
632        end
633   | ("Count_Leading_Zeroes", [d,m]) =>
634        f "clz" (rcommy [d,m])
635   | ("Reverse_Bits", [d,m]) =>
636        f "rbit" (rcommy [d,m])
637   | ("Byte_Reverse_Word", [d,m]) =>
638        f "rev" (rcommy [d,m])
639   | ("Byte_Reverse_Packed_Halfword", [d,m]) =>
640        f "rev16" (rcommy [d,m])
641   | ("Byte_Reverse_Signed_Halfword", [d,m]) =>
642        f "revsh" (rcommy [d,m])
643   | ("Bit_Field_Extract", [u,w,d,lsb,n]) =>
644        let val width = ``^w + 1w`` |> eval in
645          f (if is_T u then "ubfx" else "sbfx")
646            (commy [register d, register n, constant lsb, constant width])
647        end
648   | ("Select_Bytes", [n,d,m]) =>
649        f "sel" (rcommy [d,n,m])
650   | ("Unsigned_Sum_Absolute_Differences", [d,a,m,n]) =>
651        f (if is_PC a then "usad8" else "usada8")
652          (ocommy (not (is_PC a)) [d,n,m] a)
653   | ("Parallel_Add_Subtract", [u,opc,n,d,m]) =>
654        f (parallel_add_subtract (u,pairTheory.dest_pair opc)) (rcommy [d,n,m])
655   | ("Divide", [u,n,d,m]) =>
656        f (if is_T u then "udiv" else "sdiv") (rcommy [d,n,m])
657   | _ => raise ERR "disassemble_data_processing"
658            ("cannot disassemble: " ^ term_to_string tm)
659end;
660
661fun disassemble_status_access (instr as (enc,_,tm)) =
662let val f = mnemonic instr in
663  case dest_strip (dest_StatusAccess tm)
664  of ("Status_to_Register", [r,d]) =>
665        f "mrs" (commy [register d, if is_T r then "spsr" else "cpsr"])
666   | ("Immediate_to_Status", [r,mask,imm12]) =>
667        f "msr" (commy [msr_mask (r,mask), imm12 |> arm_expand_imm |> constant])
668   | ("Register_to_Status", [r,mask,n]) =>
669        f "msr" (commy [msr_mask (r,mask), register n])
670   | ("Change_Processor_State", [imod,A,I,F,mode]) =>
671        let val effect = case uint_of_word imod
672                         of 0 => ""
673                          | 2 => "ie"
674                          | 3 => "id"
675                          | _ => raise ERR "disassemble_status_access"
676                                   "unexpected value"
677            fun optc x c = opt (is_T x) c ""
678            val iflags = String.concat [optc A "a",optc I "i",optc F "f"]
679        in
680          f ("cps" ^ effect)
681            (if effect = "" then
682               constant (optionSyntax.dest_some mode)
683             else if optionSyntax.is_some mode then
684               commy [iflags, constant (optionSyntax.dest_some mode)]
685             else
686               iflags)
687        end
688   | ("Set_Endianness", [e]) =>
689        f "setend" (if is_T e then "be" else "le")
690   | _ => raise ERR "disassemble_status_access"
691            ("cannot disassemble: " ^ term_to_string tm)
692end;
693
694fun disassemble_load_store (instr as (enc,_,tm)) =
695let val f = mnemonic instr in
696  case dest_strip (dest_LoadStore tm)
697  of ("Load", [p,u,b,w,unpriv,n,t,mode2]) =>
698       f (opt (is_T unpriv) "t" (if is_T b then "ldrb" else "ldr"))
699         (address disassemble_mode2 (p,u,w,n,t,mode2))
700   | ("Store", [p,u,b,w,unpriv,n,t,mode2]) =>
701       f (opt (is_T unpriv) "t" (if is_T b then "strb" else "str"))
702         (address disassemble_mode2 (p,u,w,n,t,mode2))
703   | ("Load_Halfword", [p,u,w,s,h,unpriv,n,t,mode3]) =>
704       f (opt (is_T unpriv) "t"
705           (case (is_T s,is_T h)
706            of (false, true ) => "ldrh"
707             | (true,  false) => "ldrsb"
708             | (true,  true ) => "ldrsh"
709             | _ => raise ERR "disassemble_load_store" "unexpected value"))
710         (address disassemble_mode3 (p,u,w,n,t,mode3))
711   | ("Store_Halfword", [p,u,w,unpriv,n,t,mode3]) =>
712       f (if is_T unpriv then "strht" else "strh")
713         (address disassemble_mode3 (p,u,w,n,t,mode3))
714   | ("Load_Dual", [p,u,w,n,t,t2,mode3]) =>
715       f "ldrd"
716         (commy [register t, address disassemble_mode3 (p,u,w,n,t2,mode3)])
717   | ("Store_Dual", [p,u,w,n,t,t2,mode3]) =>
718       f "strd"
719         (commy [register t, address disassemble_mode3 (p,u,w,n,t2,mode3)])
720   | ("Load_Multiple", [p,u,s,w,n,registers]) =>
721       if is_F p andalso is_T u andalso is_T w andalso is_F s andalso is_SP n
722       then
723         f "pop" (register_list registers)
724       else
725         f ("ldm" ^ indexing (p,u))
726           (commy [opt (is_T w) "!" (register n),
727                   opt (is_T s) "^" (register_list registers)])
728   | ("Store_Multiple", [p,u,s,w,n,registers]) =>
729       if is_T p andalso is_F u andalso is_T w andalso is_F s andalso is_SP n
730       then
731         f "push" (register_list registers)
732       else
733         f ("stm" ^ indexing (p,u))
734           (commy [opt (is_T w) "!" (register n),
735                   opt (is_T s) "^" (register_list registers)])
736   | ("Load_Exclusive", [n,t,imm8]) =>
737       f "ldrex" (commy [register t, exclusive (n,imm8)])
738   | ("Store_Exclusive", [n,d,t,imm8]) =>
739       f "strex" (commy [register d, register t, exclusive (n,imm8)])
740   | ("Load_Exclusive_Doubleword", [n,t,t2]) =>
741       f "ldrexd" (commy [register t, register t2, square (register n)])
742   | ("Store_Exclusive_Doubleword", [n,d,t,t2]) =>
743       f "strexd"
744         (commy [register d, register t, register t2, square (register n)])
745   | ("Load_Exclusive_Halfword", [n,t]) =>
746       f "ldrexh" (commy [register t, square (register n)])
747   | ("Store_Exclusive_Halfword", [n,d,t]) =>
748       f "strexh" (commy [register d, register t, square (register n)])
749   | ("Load_Exclusive_Byte", [n,t]) =>
750       f "ldrexb" (commy [register t, square (register n)])
751   | ("Store_Exclusive_Byte", [n,d,t]) =>
752       f "strexb" (commy [register d, register t, square (register n)])
753   | ("Store_Return_State", [p,u,w,mode]) =>
754       f ("srs" ^ indexing (p,u))
755         (commy [opt (is_T w) "!" (register SP), constant mode])
756   | ("Return_From_Exception", [p,u,w,n]) =>
757       f ("rfe" ^ indexing (p,u)) (opt (is_T w) "!" (register n))
758   | _ => raise ERR "disassemble_load_store"
759            ("cannot disassemble: " ^ term_to_string tm)
760end;
761
762fun disassemble_miscellaneous (instr as (enc,_,tm)) =
763let val f = mnemonic instr in
764  case dest_strip (dest_Miscellaneous tm)
765  of ("Hint", [h]) =>
766        hint f h
767   | ("Breakpoint", [imm16]) =>
768        f "bkpt" (constant imm16)
769   | ("Data_Memory_Barrier", [opt]) =>
770        f "dmb" (barrier_option opt)
771   | ("Data_Synchronization_Barrier", [opt]) =>
772        f "dsb" (barrier_option opt)
773   | ("Instruction_Synchronization_Barrier", [opt]) =>
774        f "isb" "sy"
775   | ("Swap", [b,n,t,t2]) =>
776       f (opt (is_T b) "b" "swp")
777         (commy [register t, register t2, square (register n)])
778   | ("Preload_Data", [u,r,n,mode2]) =>
779       f (opt (is_T r) "w" "pld")
780         ([register n, disassemble_mode2 (u,mode2)] |> String.concat |> square)
781   | ("Preload_Instruction", [u,n,mode2]) =>
782       f "pli"
783         ([register n, disassemble_mode2 (u,mode2)] |> String.concat |> square)
784   | ("Supervisor_Call", [imm24]) =>
785       f "svc" (constant imm24)
786   | ("Secure_Monitor_Call", [imm4]) =>
787       f "smc" (constant imm4)
788   | ("Enterx_Leavex", [is_enterx]) =>
789       f (if is_T is_enterx then "enterx" else "leavex") ""
790   | ("Clear_Exclusive", []) =>
791       f "clrex" ""
792   | ("If_Then", [firstcond,mask]) =>
793       f ("it" ^ it_mask ((uint_of_word firstcond) mod 2 = 1) mask)
794         (full_condition firstcond)
795   | _ => raise ERR "disassemble_miscellaneous"
796            ("cannot encode: " ^ term_to_string tm)
797end;
798
799fun disassemble_coprocessor (instr as (enc,cond,tm)) =
800let val f = mnemonic instr
801    val v2 = opt (is_var cond orelse is_PC cond) "2"
802    fun ocommy b l x = commy (if b then l @ [x] else l)
803in
804  case dest_strip (dest_Coprocessor tm)
805  of ("Coprocessor_Load", [p,u,d,w,n,cd,coproc,imm8]) =>
806        f (opt (is_T d) "l" (v2 "ldc"))
807          (commy [coprocessor coproc, cregister cd,
808                  disassemble_mode5 (n,p,u,w,imm8)])
809   | ("Coprocessor_Store", [p,u,d,w,n,cd,coproc,imm8]) =>
810        f (opt (is_T d) "l" (v2 "stc"))
811          (commy [coprocessor coproc, cregister cd,
812                  disassemble_mode5 (n,p,u,w,imm8)])
813   | ("Coprocessor_Data_Processing", [opc1,n,d,coproc,opc2,m]) =>
814        f (v2 "cdp")
815          (ocommy (not (is_0 opc2))
816            [coprocessor coproc, constant opc1, cregister d,
817             cregister n, cregister m] (constant opc2))
818   | ("Coprocessor_Transfer", [opc1,mrc,n,t,coproc,opc2,m]) =>
819        f (v2 (if is_T mrc then "mrc" else "mcr"))
820          (ocommy (not (is_0 opc2))
821            [coprocessor coproc, constant opc1, register t,
822             cregister n, cregister m] (constant opc2))
823   | ("Coprocessor_Transfer_Two", [mrrc,t2,t,coproc,opc,m]) =>
824        f (v2 (if is_T mrrc then "mrrc" else "mcrr"))
825          (commy [coprocessor coproc, constant opc, register t,
826                  register t2, cregister m])
827   | _ => raise ERR "disassemble_coprocessor"
828            ("cannot disassemble: " ^ term_to_string tm)
829end;
830
831(* ------------------------------------------------------------------------- *)
832
833fun disassemble_instruction (instr as (enc,cond,tm)) =
834  case dest_strip tm
835  of ("Branch", [i]) =>
836         disassemble_branch instr
837   | ("DataProcessing", [i]) =>
838         disassemble_data_processing instr
839   | ("StatusAccess", [i]) =>
840         disassemble_status_access instr
841   | ("LoadStore", [i]) =>
842         disassemble_load_store instr
843   | ("Miscellaneous", [i]) =>
844         disassemble_miscellaneous instr
845   | ("Coprocessor", [i]) =>
846         disassemble_coprocessor instr
847   | ("Undefined", []) =>
848        (case fst (dest_const enc)
849         of "Encoding_ARM"    => let val c = hex_of_word cond in
850                                   directive_line "word"  ("0x" ^ c ^ "6000010")
851                                 end
852          | "Encoding_Thumb"  => directive_line "short" "0xDE00"
853          | "Encoding_Thumb2" => directive_line "word"  "0xF7F0A000"
854          | _ => raise ERR "" "unexpected value")
855   | _ => raise ERR "disassemble_instruction" ("cannot disassemble: " ^
856            term_to_string (pairSyntax.mk_pair (enc,tm)));
857
858(* ------------------------------------------------------------------------- *)
859
860fun arm_disassemble (arm_parserLib.Ascii s)       = disassemble_ascii s
861  | arm_disassemble (arm_parserLib.Byte l)        = disassemble_byte l
862  | arm_disassemble (arm_parserLib.Short l)       = disassemble_short l
863  | arm_disassemble (arm_parserLib.Word l)        = disassemble_word l
864  | arm_disassemble (arm_parserLib.Instruction i) = disassemble_instruction i;
865
866(*
867val arm_disassemble_parse =
868  List.map (arm_disassemble o
869       (snd : Arbnum.num * arm_parserLib.arm_code -> arm_parserLib.arm_code));
870
871val arm_disassemble_from_quote =
872  arm_disassemble_parse o fst o arm_parserLib.arm_parse_from_quote;
873
874val arm_disassemble_from_string =
875  arm_disassemble_parse o fst o arm_parserLib.arm_parse_from_string;
876
877val arm_disassemble_from_file =
878  arm_disassemble_parse o fst o arm_parserLib.arm_parse_from_file;
879*)
880
881end
882