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