Disassembler: Fixes for r15 architecture
[b43-tools.git] / disassembler / main.c
1 /*
2  *   Copyright (C) 2006  Michael Buesch <mb@bu3sch.de>
3  *
4  *   This program is free software; you can redistribute it and/or modify
5  *   it under the terms of the GNU General Public License version 2
6  *   as published by the Free Software Foundation.
7  *
8  *   This program is distributed in the hope that it will be useful,
9  *   but WITHOUT ANY WARRANTY; without even the implied warranty of
10  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11  *   GNU General Public License for more details.
12  */
13
14 #include "main.h"
15 #include "list.h"
16 #include "util.h"
17 #include "args.h"
18
19 #include <stdio.h>
20 #include <stdint.h>
21 #include <stdlib.h>
22 #include <string.h>
23
24
25 struct bin_instruction {
26         unsigned int opcode;
27         unsigned int operands[3];
28 };
29
30 struct statement {
31         enum {
32                 STMT_INSN,
33                 STMT_LABEL,
34         } type;
35
36         union {
37                 struct {
38                         struct bin_instruction *bin;
39                         const char *name;
40                         const char *operands[5];
41
42                         int is_labelref;
43                         unsigned int labeladdr;
44                         struct statement *labelref;
45                 } insn;
46                 struct {
47                         char *name;
48                 } label;
49         } u;
50
51         struct list_head list;
52 };
53
54 struct disassembler_context {
55         /* The architecture of the input file. */
56         unsigned int arch;
57
58         struct bin_instruction *code;
59         size_t nr_insns;
60
61         struct list_head stmt_list;
62 };
63
64
65 FILE *infile;
66 FILE *outfile;
67 const char *infile_name;
68 const char *outfile_name;
69
70
71 static const char * gen_raw_code(unsigned int operand)
72 {
73         char *ret;
74
75         ret = xmalloc(5);
76         snprintf(ret, 5, "@%03X", operand);
77
78         return ret;
79 }
80
81 static const char * disasm_mem_operand(unsigned int operand)
82 {
83         char *ret;
84
85         ret = xmalloc(9);
86         snprintf(ret, 9, "[0x%X]", operand);
87
88         return ret;
89 }
90
91 static const char * disasm_indirect_mem_operand(unsigned int operand)
92 {
93         char *ret;
94
95         ret = xmalloc(12);
96         snprintf(ret, 12, "[0x%02X,off%u]",
97                  (operand & 0x3F), ((operand >> 6) & 0x7));
98
99         return ret;
100 }
101
102 static const char * disasm_imm_operand(unsigned int operand)
103 {
104         char *ret;
105         unsigned int signmask;
106         unsigned int mask;
107
108         switch (cmdargs.arch) {
109         case 5:
110                 signmask = (1 << 9);
111                 mask = 0x3FF;
112                 break;
113         case 15:
114                 signmask = (1 << 10);
115                 mask = 0x7FF;
116                 break;
117         default:
118                 fprintf(stderr, "Internal error: disasm_imm_operand invalid arch\n");
119                 exit(1);
120         }
121
122         operand &= mask;
123
124         ret = xmalloc(7);
125         if (operand & signmask)
126                 operand = (operand | (~mask & 0xFFFF));
127         snprintf(ret, 7, "0x%X", operand);
128
129         return ret;
130 }
131
132 static const char * disasm_spr_operand(unsigned int operand)
133 {
134         char *ret;
135         unsigned int mask;
136
137         switch (cmdargs.arch) {
138         case 5:
139                 mask = 0x1FF;
140                 break;
141         case 15:
142                 mask = 0x7FF;
143                 break;
144         default:
145                 fprintf(stderr, "Internal error: disasm_spr_operand invalid arch\n");
146                 exit(1);
147         }
148
149         ret = xmalloc(8);
150         snprintf(ret, 8, "spr%X", (operand & mask));
151
152         return ret;
153 }
154
155 static const char * disasm_gpr_operand(unsigned int operand)
156 {
157         char *ret;
158         unsigned int mask;
159
160         switch (cmdargs.arch) {
161         case 5:
162                 mask = 0x3F;
163                 break;
164         case 15:
165                 mask = 0x7F;
166                 break;
167         default:
168                 fprintf(stderr, "Internal error: disasm_gpr_operand invalid arch\n");
169                 exit(1);
170         }
171
172         ret = xmalloc(5);
173         snprintf(ret, 5, "r%u", (operand & mask));
174
175         return ret;
176 }
177
178 static void disasm_std_operand(struct statement *stmt,
179                                int oper_idx,
180                                int out_idx,
181                                int forceraw)
182 {
183         unsigned int operand = stmt->u.insn.bin->operands[oper_idx];
184
185         if (forceraw)
186                 goto raw;
187
188         switch (cmdargs.arch) {
189         case 5:
190                 if (!(operand & 0x800)) {
191                         stmt->u.insn.operands[out_idx] = disasm_mem_operand(operand);
192                         return;
193                 } else if ((operand & 0xC00) == 0xC00) { 
194                         stmt->u.insn.operands[out_idx] = disasm_imm_operand(operand);
195                         return;
196                 } else if ((operand & 0xFC0) == 0xBC0) {
197                         stmt->u.insn.operands[out_idx] = disasm_gpr_operand(operand);
198                         return;
199                 } else if ((operand & 0xE00) == 0x800) {
200                         stmt->u.insn.operands[out_idx] = disasm_spr_operand(operand);
201                         return;
202                 } else if ((operand & 0xE00) == 0xA00) {
203                         stmt->u.insn.operands[out_idx] = disasm_indirect_mem_operand(operand);
204                         return;
205                 }
206                 break;
207         case 15:
208                 if (!(operand & 0x1000)) {
209                         stmt->u.insn.operands[out_idx] = disasm_mem_operand(operand);
210                         return;
211                 } else if ((operand & 0x1800) == 0x1800) { 
212                         stmt->u.insn.operands[out_idx] = disasm_imm_operand(operand);
213                         return;
214                 } else if ((operand & 0x1F80) == 0x1780) {
215                         stmt->u.insn.operands[out_idx] = disasm_gpr_operand(operand);
216                         return;
217                 } else if ((operand & 0x1C00) == 0x1000) {
218                         stmt->u.insn.operands[out_idx] = disasm_spr_operand(operand);
219                         return;
220                 } else if ((operand & 0x1C00) == 0x1400) {
221                         stmt->u.insn.operands[out_idx] = disasm_indirect_mem_operand(operand);
222                         return;
223                 }
224                 break;
225         default:
226                 fprintf(stderr, "Internal error: disasm_std_operand invalid arch\n");
227                 exit(1);
228         }
229 raw:
230         stmt->u.insn.operands[out_idx] = gen_raw_code(operand);
231 }
232
233 static void disasm_constant_opcodes(struct disassembler_context *ctx,
234                                     struct statement *stmt)
235 {
236         struct bin_instruction *bin = stmt->u.insn.bin;
237
238         switch (bin->opcode) {
239         case 0x1C0:
240                 stmt->u.insn.name = "add";
241                 disasm_std_operand(stmt, 0, 0, 0);
242                 disasm_std_operand(stmt, 1, 1, 0);
243                 disasm_std_operand(stmt, 2, 2, 0);
244                 break;
245         case 0x1C2:
246                 stmt->u.insn.name = "add.";
247                 disasm_std_operand(stmt, 0, 0, 0);
248                 disasm_std_operand(stmt, 1, 1, 0);
249                 disasm_std_operand(stmt, 2, 2, 0);
250                 break;
251         case 0x1C1:
252                 stmt->u.insn.name = "addc";
253                 disasm_std_operand(stmt, 0, 0, 0);
254                 disasm_std_operand(stmt, 1, 1, 0);
255                 disasm_std_operand(stmt, 2, 2, 0);
256                 break;
257         case 0x1C3:
258                 stmt->u.insn.name = "addc.";
259                 disasm_std_operand(stmt, 0, 0, 0);
260                 disasm_std_operand(stmt, 1, 1, 0);
261                 disasm_std_operand(stmt, 2, 2, 0);
262                 break;
263         case 0x1D0:
264                 stmt->u.insn.name = "sub";
265                 disasm_std_operand(stmt, 0, 0, 0);
266                 disasm_std_operand(stmt, 1, 1, 0);
267                 disasm_std_operand(stmt, 2, 2, 0);
268                 break;
269         case 0x1D2:
270                 stmt->u.insn.name = "sub.";
271                 disasm_std_operand(stmt, 0, 0, 0);
272                 disasm_std_operand(stmt, 1, 1, 0);
273                 disasm_std_operand(stmt, 2, 2, 0);
274                 break;
275         case 0x1D1:
276                 stmt->u.insn.name = "subc";
277                 disasm_std_operand(stmt, 0, 0, 0);
278                 disasm_std_operand(stmt, 1, 1, 0);
279                 disasm_std_operand(stmt, 2, 2, 0);
280                 break;
281         case 0x1D3:
282                 stmt->u.insn.name = "subc.";
283                 disasm_std_operand(stmt, 0, 0, 0);
284                 disasm_std_operand(stmt, 1, 1, 0);
285                 disasm_std_operand(stmt, 2, 2, 0);
286                 break;
287         case 0x130:
288                 stmt->u.insn.name = "sra";
289                 disasm_std_operand(stmt, 0, 0, 0);
290                 disasm_std_operand(stmt, 1, 1, 0);
291                 disasm_std_operand(stmt, 2, 2, 0);
292                 break;
293         case 0x160:
294                 stmt->u.insn.name = "or";
295                 disasm_std_operand(stmt, 0, 0, 0);
296                 disasm_std_operand(stmt, 1, 1, 0);
297                 disasm_std_operand(stmt, 2, 2, 0);
298                 break;
299         case 0x140:
300                 stmt->u.insn.name = "and";
301                 disasm_std_operand(stmt, 0, 0, 0);
302                 disasm_std_operand(stmt, 1, 1, 0);
303                 disasm_std_operand(stmt, 2, 2, 0);
304                 break;
305         case 0x170:
306                 stmt->u.insn.name = "xor";
307                 disasm_std_operand(stmt, 0, 0, 0);
308                 disasm_std_operand(stmt, 1, 1, 0);
309                 disasm_std_operand(stmt, 2, 2, 0);
310                 break;
311         case 0x120:
312                 stmt->u.insn.name = "sr";
313                 disasm_std_operand(stmt, 0, 0, 0);
314                 disasm_std_operand(stmt, 1, 1, 0);
315                 disasm_std_operand(stmt, 2, 2, 0);
316                 break;
317         case 0x110:
318                 stmt->u.insn.name = "sl";
319                 disasm_std_operand(stmt, 0, 0, 0);
320                 disasm_std_operand(stmt, 1, 1, 0);
321                 disasm_std_operand(stmt, 2, 2, 0);
322                 break;
323         case 0x1A0:
324                 stmt->u.insn.name = "rl";
325                 disasm_std_operand(stmt, 0, 0, 0);
326                 disasm_std_operand(stmt, 1, 1, 0);
327                 disasm_std_operand(stmt, 2, 2, 0);
328                 break;
329         case 0x1B0:
330                 stmt->u.insn.name = "rr";
331                 disasm_std_operand(stmt, 0, 0, 0);
332                 disasm_std_operand(stmt, 1, 1, 0);
333                 disasm_std_operand(stmt, 2, 2, 0);
334                 break;
335         case 0x150:
336                 stmt->u.insn.name = "nand";
337                 disasm_std_operand(stmt, 0, 0, 0);
338                 disasm_std_operand(stmt, 1, 1, 0);
339                 disasm_std_operand(stmt, 2, 2, 0);
340                 break;
341         case 0x040:
342                 stmt->u.insn.name = "jand";
343                 stmt->u.insn.is_labelref = 2;
344                 stmt->u.insn.labeladdr = stmt->u.insn.bin->operands[2];
345                 disasm_std_operand(stmt, 0, 0, 0);
346                 disasm_std_operand(stmt, 1, 1, 0);
347                 break;
348         case (0x040 | 0x1):
349                 stmt->u.insn.name = "jnand";
350                 stmt->u.insn.is_labelref = 2;
351                 stmt->u.insn.labeladdr = stmt->u.insn.bin->operands[2];
352                 disasm_std_operand(stmt, 0, 0, 0);
353                 disasm_std_operand(stmt, 1, 1, 0);
354                 break;
355         case 0x050:
356                 stmt->u.insn.name = "js";
357                 stmt->u.insn.is_labelref = 2;
358                 stmt->u.insn.labeladdr = stmt->u.insn.bin->operands[2];
359                 disasm_std_operand(stmt, 0, 0, 0);
360                 disasm_std_operand(stmt, 1, 1, 0);
361                 break;
362         case (0x050 | 0x1):
363                 stmt->u.insn.name = "jns";
364                 stmt->u.insn.is_labelref = 2;
365                 stmt->u.insn.labeladdr = stmt->u.insn.bin->operands[2];
366                 disasm_std_operand(stmt, 0, 0, 0);
367                 disasm_std_operand(stmt, 1, 1, 0);
368                 break;
369         case 0x0D0:
370                 stmt->u.insn.name = "je";
371                 stmt->u.insn.is_labelref = 2;
372                 stmt->u.insn.labeladdr = stmt->u.insn.bin->operands[2];
373                 disasm_std_operand(stmt, 0, 0, 0);
374                 disasm_std_operand(stmt, 1, 1, 0);
375                 break;
376         case (0x0D0 | 0x1):
377                 stmt->u.insn.name = "jne";
378                 stmt->u.insn.is_labelref = 2;
379                 stmt->u.insn.labeladdr = stmt->u.insn.bin->operands[2];
380                 disasm_std_operand(stmt, 0, 0, 0);
381                 disasm_std_operand(stmt, 1, 1, 0);
382                 break;
383         case 0x0D2:
384                 stmt->u.insn.name = "jls";
385                 stmt->u.insn.is_labelref = 2;
386                 stmt->u.insn.labeladdr = stmt->u.insn.bin->operands[2];
387                 disasm_std_operand(stmt, 0, 0, 0);
388                 disasm_std_operand(stmt, 1, 1, 0);
389                 break;
390         case (0x0D2 | 0x1):
391                 stmt->u.insn.name = "jges";
392                 stmt->u.insn.is_labelref = 2;
393                 stmt->u.insn.labeladdr = stmt->u.insn.bin->operands[2];
394                 disasm_std_operand(stmt, 0, 0, 0);
395                 disasm_std_operand(stmt, 1, 1, 0);
396                 break;
397         case 0x0D4:
398                 stmt->u.insn.name = "jgs";
399                 stmt->u.insn.is_labelref = 2;
400                 stmt->u.insn.labeladdr = stmt->u.insn.bin->operands[2];
401                 disasm_std_operand(stmt, 0, 0, 0);
402                 disasm_std_operand(stmt, 1, 1, 0);
403                 break;
404         case (0x0D4 | 0x1):
405                 stmt->u.insn.name = "jles";
406                 stmt->u.insn.is_labelref = 2;
407                 stmt->u.insn.labeladdr = stmt->u.insn.bin->operands[2];
408                 disasm_std_operand(stmt, 0, 0, 0);
409                 disasm_std_operand(stmt, 1, 1, 0);
410                 break;
411         case 0x0DA:
412                 stmt->u.insn.name = "jl";
413                 stmt->u.insn.is_labelref = 2;
414                 stmt->u.insn.labeladdr = stmt->u.insn.bin->operands[2];
415                 disasm_std_operand(stmt, 0, 0, 0);
416                 disasm_std_operand(stmt, 1, 1, 0);
417                 break;
418         case (0x0DA | 0x1):
419                 stmt->u.insn.name = "jge";
420                 stmt->u.insn.is_labelref = 2;
421                 stmt->u.insn.labeladdr = stmt->u.insn.bin->operands[2];
422                 disasm_std_operand(stmt, 0, 0, 0);
423                 disasm_std_operand(stmt, 1, 1, 0);
424                 break;
425         case 0x0DC:
426                 stmt->u.insn.name = "jg";
427                 stmt->u.insn.is_labelref = 2;
428                 stmt->u.insn.labeladdr = stmt->u.insn.bin->operands[2];
429                 disasm_std_operand(stmt, 0, 0, 0);
430                 disasm_std_operand(stmt, 1, 1, 0);
431                 break;
432         case (0x0DC | 0x1):
433                 stmt->u.insn.name = "jle";
434                 stmt->u.insn.is_labelref = 2;
435                 stmt->u.insn.labeladdr = stmt->u.insn.bin->operands[2];
436                 disasm_std_operand(stmt, 0, 0, 0);
437                 disasm_std_operand(stmt, 1, 1, 0);
438                 break;
439         case 0x002: {
440                 char *str;
441
442                 //FIXME: Broken for r15
443                 stmt->u.insn.name = "call";
444                 stmt->u.insn.is_labelref = 1;
445 //printf("CALL 0x%X 0x%X 0x%X\n", stmt->u.insn.bin->operands[0], stmt->u.insn.bin->operands[1], stmt->u.insn.bin->operands[2]);
446                 stmt->u.insn.labeladdr = stmt->u.insn.bin->operands[2];
447                 str = xmalloc(4);
448                 snprintf(str, 4, "lr%u", stmt->u.insn.bin->operands[0]);
449                 stmt->u.insn.operands[0] = str;
450                 break;
451         }
452         case 0x003: {
453                 char *str;
454
455                 stmt->u.insn.name = "ret";
456                 str = xmalloc(4);
457                 snprintf(str, 4, "lr%u", stmt->u.insn.bin->operands[0]);
458                 stmt->u.insn.operands[0] = str;
459                 str = xmalloc(4);
460                 snprintf(str, 4, "lr%u", stmt->u.insn.bin->operands[2]);
461                 stmt->u.insn.operands[2] = str;
462                 break;
463         }
464         case 0x1E0: {
465                 unsigned int flags, mask;
466
467                 switch (cmdargs.arch) {
468                 case 5:
469                         mask = 0x3FF;
470                         break;
471                 case 15:
472                         mask = 0x7FF;
473                         break;
474                 default:
475                         fprintf(stderr, "Internal error: TKIP invalid arch\n");
476                         exit(1);
477                 }
478
479                 flags = stmt->u.insn.bin->operands[1];
480                 switch (flags & mask) {
481                 case 0x1:
482                         stmt->u.insn.name = "tkiph";
483                         break;
484                 case (0x1 | 0x2):
485                         stmt->u.insn.name = "tkiphs";
486                         break;
487                 case 0x0:
488                         stmt->u.insn.name = "tkipl";
489                         break;
490                 case (0x0 | 0x2):
491                         stmt->u.insn.name = "tkipls";
492                         break;
493                 default:
494                         fprintf(stderr, "Invalid TKIP flags %X\n",
495                                 flags);
496                         exit(1);
497                 }
498                 disasm_std_operand(stmt, 0, 0, 0);
499                 disasm_std_operand(stmt, 2, 2, 0);
500                 break;
501         }
502         case 0x001: {
503                 unsigned int mask;
504
505                 stmt->u.insn.name = "nap";
506                 switch (cmdargs.arch) {
507                 case 5:
508                         mask = 0xBC0;
509                         break;
510                 case 15:
511                         mask = 0x1780;
512                         break;
513                 default:
514                         fprintf(stderr, "Internal error: NAP invalid arch\n");
515                         exit(1);
516                 }
517                 if (stmt->u.insn.bin->operands[0] != mask) {
518                         fprintf(stderr, "NAP: invalid first argument 0x%04X\n",
519                                 stmt->u.insn.bin->operands[0]);
520                 }
521                 if (stmt->u.insn.bin->operands[1] != mask) {
522                         fprintf(stderr, "NAP: invalid second argument 0x%04X\n",
523                                 stmt->u.insn.bin->operands[1]);
524                 }
525                 if (stmt->u.insn.bin->operands[2] != 0) {
526                         fprintf(stderr, "NAP: invalid third argument 0x%04X\n",
527                                 stmt->u.insn.bin->operands[2]);
528                 }
529                 break;
530         }
531         default:
532                 stmt->u.insn.name = gen_raw_code(bin->opcode);
533                 disasm_std_operand(stmt, 0, 0, 1);
534                 disasm_std_operand(stmt, 1, 1, 1);
535                 disasm_std_operand(stmt, 2, 2, 1);
536                 break;
537         }
538 }
539
540 static void disasm_opcodes(struct disassembler_context *ctx)
541 {
542         struct bin_instruction *bin;
543         size_t i;
544         struct statement *stmt;
545         char *str;
546
547         for (i = 0; i < ctx->nr_insns; i++) {
548                 bin = &(ctx->code[i]);
549
550                 stmt = xmalloc(sizeof(struct statement));
551                 stmt->type = STMT_INSN;
552                 INIT_LIST_HEAD(&stmt->list);
553                 stmt->u.insn.bin = bin;
554                 stmt->u.insn.is_labelref = -1;
555
556                 switch (bin->opcode & 0xF00) {
557                 case 0x200:
558                         stmt->u.insn.name = "srx";
559
560                         str = xmalloc(3);
561                         snprintf(str, 3, "%d", (bin->opcode & 0x0F0) >> 4);
562                         stmt->u.insn.operands[0] = str;
563                         str = xmalloc(3);
564                         snprintf(str, 3, "%d", (bin->opcode & 0x00F));
565                         stmt->u.insn.operands[1] = str;
566
567                         disasm_std_operand(stmt, 0, 2, 0);
568                         disasm_std_operand(stmt, 1, 3, 0);
569                         disasm_std_operand(stmt, 2, 4, 0);
570                         break;
571                 case 0x300:
572                         stmt->u.insn.name = "orx";
573
574                         str = xmalloc(3);
575                         snprintf(str, 3, "%d", (bin->opcode & 0x0F0) >> 4);
576                         stmt->u.insn.operands[0] = str;
577                         str = xmalloc(3);
578                         snprintf(str, 3, "%d", (bin->opcode & 0x00F));
579                         stmt->u.insn.operands[1] = str;
580
581                         disasm_std_operand(stmt, 0, 2, 0);
582                         disasm_std_operand(stmt, 1, 3, 0);
583                         disasm_std_operand(stmt, 2, 4, 0);
584                         break;
585                 case 0x400:
586                         stmt->u.insn.name = "jzx";
587
588                         str = xmalloc(3);
589                         snprintf(str, 3, "%d", (bin->opcode & 0x0F0) >> 4);
590                         stmt->u.insn.operands[0] = str;
591                         str = xmalloc(3);
592                         snprintf(str, 3, "%d", (bin->opcode & 0x00F));
593                         stmt->u.insn.operands[1] = str;
594
595                         disasm_std_operand(stmt, 0, 2, 0);
596                         disasm_std_operand(stmt, 1, 3, 0);
597                         stmt->u.insn.is_labelref = 4;
598                         stmt->u.insn.labeladdr = stmt->u.insn.bin->operands[2];
599                         break;
600                 case 0x500:
601                         stmt->u.insn.name = "jnzx";
602
603                         str = xmalloc(3);
604                         snprintf(str, 3, "%d", (bin->opcode & 0x0F0) >> 4);
605                         stmt->u.insn.operands[0] = str;
606                         str = xmalloc(3);
607                         snprintf(str, 3, "%d", (bin->opcode & 0x00F));
608                         stmt->u.insn.operands[1] = str;
609
610                         disasm_std_operand(stmt, 0, 2, 0);
611                         disasm_std_operand(stmt, 1, 3, 0);
612                         stmt->u.insn.is_labelref = 4;
613                         stmt->u.insn.labeladdr = stmt->u.insn.bin->operands[2];
614                         break;
615                 case 0x600:
616                         stmt->u.insn.name = "jnext";
617
618                         str = xmalloc(5);
619                         snprintf(str, 5, "0x%02X", (bin->opcode & 0x0FF));
620                         stmt->u.insn.operands[0] = str;
621
622                         /* We don't disassemble the first and second operand, as
623                          * that always is a dummy r0 operand.
624                          * disasm_std_operand(stmt, 0, 1, 0);
625                          * disasm_std_operand(stmt, 1, 2, 0);
626                          * stmt->u.insn.is_labelref = 3;
627                          */
628                         stmt->u.insn.is_labelref = 1;
629                         stmt->u.insn.labeladdr = stmt->u.insn.bin->operands[2];
630                         break;
631                 case 0x700:
632                         stmt->u.insn.name = "jext";
633
634                         str = xmalloc(5);
635                         snprintf(str, 5, "0x%02X", (bin->opcode & 0x0FF));
636                         stmt->u.insn.operands[0] = str;
637
638                         /* We don't disassemble the first and second operand, as
639                          * that always is a dummy r0 operand.
640                          * disasm_std_operand(stmt, 0, 1, 0);
641                          * disasm_std_operand(stmt, 1, 2, 0);
642                          * stmt->u.insn.is_labelref = 3;
643                          */
644                         stmt->u.insn.is_labelref = 1;
645                         stmt->u.insn.labeladdr = stmt->u.insn.bin->operands[2];
646                         break;
647                 default:
648                         disasm_constant_opcodes(ctx, stmt);
649                         break;
650                 }
651
652                 list_add_tail(&stmt->list, &ctx->stmt_list);
653         }
654 }
655
656 static struct statement * get_label_at(struct disassembler_context *ctx,
657                                        unsigned int addr)
658 {
659         unsigned int addrcnt = 0;
660         struct statement *stmt, *ret, *prev;
661
662         list_for_each_entry(stmt, &ctx->stmt_list, list) {
663                 if (stmt->type != STMT_INSN)
664                         continue;
665                 if (addrcnt == addr) {
666                         prev = list_entry(stmt->list.prev, struct statement, list);
667                         if (prev->type == STMT_LABEL)
668                                 return prev;
669                         ret = xmalloc(sizeof(struct statement));
670                         INIT_LIST_HEAD(&ret->list);
671                         ret->type = STMT_LABEL;
672                         list_add(&ret->list, &prev->list);
673
674                         return ret;
675                 }
676                 addrcnt++;
677         }
678
679         return NULL;
680 }
681
682 static void resolve_labels(struct disassembler_context *ctx)
683 {
684         struct statement *stmt;
685         struct statement *label;
686         struct statement *n;
687         unsigned int labeladdr;
688         unsigned int namecnt = 0;
689
690         /* Resolve label references */
691         list_for_each_entry_safe(stmt, n, &ctx->stmt_list, list) {
692                 if (stmt->type != STMT_INSN)
693                         continue;
694                 if (stmt->u.insn.is_labelref == -1)
695                         continue;
696                 labeladdr = stmt->u.insn.labeladdr;
697                 label = get_label_at(ctx, labeladdr);
698                 if (!label) {
699                         fprintf(stderr, "Labeladdress %X out of bounds\n",
700                                 labeladdr);
701                         exit(1);
702                 }
703                 stmt->u.insn.labelref = label;
704         }
705
706         /* Name the labels */
707         list_for_each_entry(stmt, &ctx->stmt_list, list) {
708                 if (stmt->type != STMT_LABEL)
709                         continue;
710                 stmt->u.label.name = xmalloc(20);
711                 snprintf(stmt->u.label.name, 20, "L%u", namecnt);
712                 namecnt++;
713         }
714 }
715
716 static void emit_asm(struct disassembler_context *ctx)
717 {
718         struct statement *stmt;
719         int first, i;
720         int err;
721         unsigned int addr = 0;
722
723         err = open_output_file();
724         if (err)
725                 exit(1);
726
727         fprintf(outfile, "%%arch %u\n\n", ctx->arch);
728         list_for_each_entry(stmt, &ctx->stmt_list, list) {
729                 switch (stmt->type) {
730                 case STMT_INSN:
731                         if (cmdargs.print_addresses)
732                                 fprintf(outfile, "/* %03X */", addr);
733                         fprintf(outfile, "\t%s", stmt->u.insn.name);
734                         first = 1;
735                         for (i = 0; i < ARRAY_SIZE(stmt->u.insn.operands); i++) {
736                                 if (stmt->u.insn.is_labelref == i) {
737                                         fprintf(outfile, ", %s",
738                                                 stmt->u.insn.labelref->u.label.name);
739                                 }
740                                 if (!stmt->u.insn.operands[i])
741                                         continue;
742                                 if (first)
743                                         fprintf(outfile, "\t");
744                                 if (!first)
745                                         fprintf(outfile, ", ");
746                                 first = 0;
747                                 fprintf(outfile, "%s",
748                                         stmt->u.insn.operands[i]);
749                         }
750                         fprintf(outfile, "\n");
751                         addr++;
752                         break;
753                 case STMT_LABEL:
754                         fprintf(outfile, "%s:\n", stmt->u.label.name);
755                         break;
756                 }
757         }
758
759         close_output_file();
760 }
761
762 static int read_input(struct disassembler_context *ctx)
763 {
764         size_t size = 0, pos = 0;
765         size_t ret;
766         struct bin_instruction *code = NULL;
767         unsigned char tmp[sizeof(uint64_t)];
768         uint64_t codeword;
769         struct fw_header hdr;
770         int err;
771
772         err = open_input_file();
773         if (err)
774                 goto error;
775
776         switch (cmdargs.informat) {
777         case FMT_RAW_LE32:
778         case FMT_RAW_BE32:
779                 /* Nothing */
780                 break;
781         case FMT_B43:
782                 ret = fread(&hdr, 1, sizeof(hdr), infile);
783                 if (ret != sizeof(hdr)) {
784                         fprintf(stderr, "Corrupt input file (not fwcutter output)\n");
785                         goto err_close;
786                 }
787                 if (hdr.type != FW_TYPE_UCODE) {
788                         fprintf(stderr, "Corrupt input file. Not a microcode image.\n");
789                         goto err_close;
790                 }
791                 if (hdr.ver != FW_HDR_VER) {
792                         fprintf(stderr, "Invalid input file header version.\n");
793                         goto err_close;
794                 }
795                 break;
796         }
797
798         while (1) {
799                 if (pos >= size) {
800                         size += 512;
801                         code = xrealloc(code, size * sizeof(struct bin_instruction));
802                 }
803                 ret = fread(tmp, 1, sizeof(uint64_t), infile);
804                 if (!ret)
805                         break;
806                 if (ret != sizeof(uint64_t)) {
807                         fprintf(stderr, "Corrupt input file (not 8 byte aligned)\n");
808                         goto err_free_code;
809                 }
810
811                 switch (cmdargs.informat) {
812                 case FMT_B43:
813                 case FMT_RAW_BE32:
814                         codeword = 0;
815                         codeword |= ((uint64_t)tmp[0]) << 56;
816                         codeword |= ((uint64_t)tmp[1]) << 48;
817                         codeword |= ((uint64_t)tmp[2]) << 40;
818                         codeword |= ((uint64_t)tmp[3]) << 32;
819                         codeword |= ((uint64_t)tmp[4]) << 24;
820                         codeword |= ((uint64_t)tmp[5]) << 16;
821                         codeword |= ((uint64_t)tmp[6]) << 8;
822                         codeword |= ((uint64_t)tmp[7]);
823                         codeword = ((codeword & (uint64_t)0xFFFFFFFF00000000ULL) >> 32) |
824                                    ((codeword & (uint64_t)0x00000000FFFFFFFFULL) << 32);
825                         break;
826                 case FMT_RAW_LE32:
827                         codeword = 0;
828                         codeword |= ((uint64_t)tmp[7]) << 56;
829                         codeword |= ((uint64_t)tmp[6]) << 48;
830                         codeword |= ((uint64_t)tmp[5]) << 40;
831                         codeword |= ((uint64_t)tmp[4]) << 32;
832                         codeword |= ((uint64_t)tmp[3]) << 24;
833                         codeword |= ((uint64_t)tmp[2]) << 16;
834                         codeword |= ((uint64_t)tmp[1]) << 8;
835                         codeword |= ((uint64_t)tmp[0]);
836                         break;
837                 }
838
839                 switch (cmdargs.arch) {
840                 case 5:
841                         if (codeword >> 48) {
842                                 fprintf(stderr, "Instruction format error at 0x%X (upper not clear). "
843                                         "Wrong input format or architecture?\n", (unsigned int)pos);
844                                 goto err_free_code;
845                         }
846                         code[pos].opcode = (codeword >> 36) & 0xFFF;
847                         code[pos].operands[2] = codeword & 0xFFF;
848                         code[pos].operands[1] = (codeword >> 12) & 0xFFF;
849                         code[pos].operands[0] = (codeword >> 24) & 0xFFF;
850                         break;
851                 case 15:
852                         if (codeword >> 51) {
853                                 fprintf(stderr, "Instruction format error at 0x%X (upper not clear). "
854                                         "Wrong input format or architecture?\n", (unsigned int)pos);
855                                 goto err_free_code;
856                         }
857                         code[pos].opcode = (codeword >> 39) & 0xFFF;
858                         code[pos].operands[2] = codeword & 0x1FFF;
859                         code[pos].operands[1] = (codeword >> 13) & 0x1FFF;
860                         code[pos].operands[0] = (codeword >> 26) & 0x1FFF;
861                         break;
862                 default:
863                         fprintf(stderr, "Internal error: read_input unknown arch %u\n",
864                                 cmdargs.arch);
865                         goto err_free_code;
866                 }
867
868                 pos++;
869         }
870
871         ctx->code = code;
872         ctx->nr_insns = pos;
873
874         close_input_file();
875
876         return 0;
877
878 err_free_code:
879         free(code);
880 err_close:
881         close_input_file();
882 error:
883         return -1;
884 }
885
886 static void disassemble(void)
887 {
888         struct disassembler_context ctx;
889         int err;
890
891         memset(&ctx, 0, sizeof(ctx));
892         INIT_LIST_HEAD(&ctx.stmt_list);
893         ctx.arch = cmdargs.arch;
894
895         err = read_input(&ctx);
896         if (err)
897                 exit(1);
898         disasm_opcodes(&ctx);
899         resolve_labels(&ctx);
900         emit_asm(&ctx);
901 }
902
903 int main(int argc, char **argv)
904 {
905         int err, res = 1;
906
907         err = parse_args(argc, argv);
908         if (err < 0)
909                 goto out;
910         if (err > 0) {
911                 res = 0;
912                 goto out;
913         }
914         disassemble();
915         res = 0;
916 out:
917         /* Lazyman simply leaks all allocated memory. */
918         return res;
919 }