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