Initial commit.
[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 "list.h"
15 #include "util.h"
16
17 #include <stdio.h>
18 #include <stdint.h>
19 #include <stdlib.h>
20 #include <string.h>
21
22 #define ARRAY_SIZE(x)   (sizeof(x)/sizeof(x[0]))
23
24 /* The header that fwcutter puts in to every .fw file */
25 struct fw_header {
26         /* Type of the firmware data */
27         uint8_t type;
28         /* Version number of the firmware data format */
29         uint8_t ver;
30         uint8_t __padding[2];
31         /* Size of the data. For ucode and PCM this is in bytes.
32          * For IV this is in number-of-ivs. */
33         uint32_t size;
34 } __attribute__ ((__packed__));
35
36
37 struct bin_instruction {
38         unsigned int opcode;
39         unsigned int operands[3];
40 };
41
42 struct statement {
43         enum {
44                 STMT_INSN,
45                 STMT_LABEL,
46         } type;
47
48         union {
49                 struct {
50                         struct bin_instruction *bin;
51                         const char *name;
52                         const char *operands[5];
53
54                         int is_labelref;
55                         unsigned int labeladdr;
56                         struct statement *labelref;
57                 } insn;
58                 struct {
59                         char *name;
60                 } label;
61         } u;
62
63         struct list_head list;
64 };
65
66 struct disassembler_context {
67         struct bin_instruction *code;
68         size_t nr_insns;
69
70         struct list_head stmt_list;
71 };
72
73
74 static FILE *infile;
75 const char *outfile_name;
76
77
78 static const char * gen_raw_code(unsigned int operand)
79 {
80         char *ret;
81
82         ret = xmalloc(5);
83         snprintf(ret, 5, "@%03X", operand);
84
85         return ret;
86 }
87
88 static const char * disasm_mem_operand(unsigned int operand)
89 {
90         char *ret;
91
92         ret = xmalloc(8);
93         snprintf(ret, 8, "[0x%03X]", operand);
94
95         return ret;
96 }
97
98 static const char * disasm_indirect_mem_operand(unsigned int operand)
99 {
100         char *ret;
101
102         ret = xmalloc(12);
103         snprintf(ret, 12, "[0x%02X,off%u]",
104                  (operand & 0x3F), ((operand >> 6) & 0x7));
105
106         return ret;
107 }
108
109 static const char * disasm_imm_operand(unsigned int operand)
110 {
111         char *ret;
112
113         operand &= ~0xC00;
114
115         ret = xmalloc(7);
116         if (operand & (1 << 9))
117                 snprintf(ret, 7, "0x%04X", (operand | 0xFC00));
118         else
119                 snprintf(ret, 7, "0x%03X", operand);
120
121         return ret;
122 }
123
124 static const char * disasm_spr_operand(unsigned int operand)
125 {
126         char *ret;
127
128         ret = xmalloc(7);
129         snprintf(ret, 7, "spr%03X", (operand & 0x1FF));
130
131         return ret;
132 }
133
134 static const char * disasm_gpr_operand(unsigned int operand)
135 {
136         char *ret;
137
138         ret = xmalloc(4);
139         snprintf(ret, 4, "r%u", (operand & 0x3F));
140
141         return ret;
142 }
143
144 static const char * disasm_offr_operand(unsigned int operand)
145 {
146         char *ret;
147
148         ret = xmalloc(5);
149         snprintf(ret, 5, "off%u", (operand & 0x7));
150
151         return ret;
152 }
153
154 static void disasm_std_operand(struct statement *stmt,
155                                int oper_idx,
156                                int out_idx,
157                                int forceraw)
158 {
159         unsigned int operand = stmt->u.insn.bin->operands[oper_idx];
160
161         if (forceraw)
162                 goto raw;
163
164         if (!(operand & 0x800)) {
165                 stmt->u.insn.operands[out_idx] = disasm_mem_operand(operand);
166                 return;
167         } else if ((operand & 0xC00) == 0xC00) { 
168                 stmt->u.insn.operands[out_idx] = disasm_imm_operand(operand);
169                 return;
170         } else if ((operand & 0xFC0) == 0xBC0) {
171                 stmt->u.insn.operands[out_idx] = disasm_gpr_operand(operand);
172                 return;
173         } else if ((operand & 0xE00) == 0x800) {
174                 stmt->u.insn.operands[out_idx] = disasm_spr_operand(operand);
175                 return;
176         } else if ((operand & 0xFF8) == 0x860) {
177                 stmt->u.insn.operands[out_idx] = disasm_offr_operand(operand);
178                 return;
179         } else if ((operand & 0xE00) == 0xA00) {
180                 stmt->u.insn.operands[out_idx] = disasm_indirect_mem_operand(operand);
181                 return;
182         }
183 raw:
184         stmt->u.insn.operands[out_idx] = gen_raw_code(operand);
185 }
186
187 static void disasm_constant_opcodes(struct disassembler_context *ctx,
188                                     struct statement *stmt)
189 {
190         struct bin_instruction *bin = stmt->u.insn.bin;
191
192         switch (bin->opcode) {
193         case 0x1C0:
194                 stmt->u.insn.name = "add";
195                 disasm_std_operand(stmt, 0, 0, 0);
196                 disasm_std_operand(stmt, 1, 1, 0);
197                 disasm_std_operand(stmt, 2, 2, 0);
198                 break;
199         case 0x1C2:
200                 stmt->u.insn.name = "add.";
201                 disasm_std_operand(stmt, 0, 0, 0);
202                 disasm_std_operand(stmt, 1, 1, 0);
203                 disasm_std_operand(stmt, 2, 2, 0);
204                 break;
205         case 0x1C1:
206                 stmt->u.insn.name = "addc";
207                 disasm_std_operand(stmt, 0, 0, 0);
208                 disasm_std_operand(stmt, 1, 1, 0);
209                 disasm_std_operand(stmt, 2, 2, 0);
210                 break;
211         case 0x1C3:
212                 stmt->u.insn.name = "addc.";
213                 disasm_std_operand(stmt, 0, 0, 0);
214                 disasm_std_operand(stmt, 1, 1, 0);
215                 disasm_std_operand(stmt, 2, 2, 0);
216                 break;
217         case 0x1D0:
218                 stmt->u.insn.name = "sub";
219                 disasm_std_operand(stmt, 0, 0, 0);
220                 disasm_std_operand(stmt, 1, 1, 0);
221                 disasm_std_operand(stmt, 2, 2, 0);
222                 break;
223         case 0x1D2:
224                 stmt->u.insn.name = "sub.";
225                 disasm_std_operand(stmt, 0, 0, 0);
226                 disasm_std_operand(stmt, 1, 1, 0);
227                 disasm_std_operand(stmt, 2, 2, 0);
228                 break;
229         case 0x1D1:
230                 stmt->u.insn.name = "subc";
231                 disasm_std_operand(stmt, 0, 0, 0);
232                 disasm_std_operand(stmt, 1, 1, 0);
233                 disasm_std_operand(stmt, 2, 2, 0);
234                 break;
235         case 0x1D3:
236                 stmt->u.insn.name = "subc.";
237                 disasm_std_operand(stmt, 0, 0, 0);
238                 disasm_std_operand(stmt, 1, 1, 0);
239                 disasm_std_operand(stmt, 2, 2, 0);
240                 break;
241         case 0x130:
242                 stmt->u.insn.name = "sra";
243                 disasm_std_operand(stmt, 0, 0, 0);
244                 disasm_std_operand(stmt, 1, 1, 0);
245                 disasm_std_operand(stmt, 2, 2, 0);
246                 break;
247         case 0x160:
248                 stmt->u.insn.name = "or";
249                 disasm_std_operand(stmt, 0, 0, 0);
250                 disasm_std_operand(stmt, 1, 1, 0);
251                 disasm_std_operand(stmt, 2, 2, 0);
252                 break;
253         case 0x140:
254                 stmt->u.insn.name = "and";
255                 disasm_std_operand(stmt, 0, 0, 0);
256                 disasm_std_operand(stmt, 1, 1, 0);
257                 disasm_std_operand(stmt, 2, 2, 0);
258                 break;
259         case 0x170:
260                 stmt->u.insn.name = "xor";
261                 disasm_std_operand(stmt, 0, 0, 0);
262                 disasm_std_operand(stmt, 1, 1, 0);
263                 disasm_std_operand(stmt, 2, 2, 0);
264                 break;
265         case 0x120:
266                 stmt->u.insn.name = "sr";
267                 disasm_std_operand(stmt, 0, 0, 0);
268                 disasm_std_operand(stmt, 1, 1, 0);
269                 disasm_std_operand(stmt, 2, 2, 0);
270                 break;
271         case 0x110:
272                 stmt->u.insn.name = "sl";
273                 disasm_std_operand(stmt, 0, 0, 0);
274                 disasm_std_operand(stmt, 1, 1, 0);
275                 disasm_std_operand(stmt, 2, 2, 0);
276                 break;
277         case 0x1A0:
278                 stmt->u.insn.name = "rl";
279                 disasm_std_operand(stmt, 0, 0, 0);
280                 disasm_std_operand(stmt, 1, 1, 0);
281                 disasm_std_operand(stmt, 2, 2, 0);
282                 break;
283         case 0x1B0:
284                 stmt->u.insn.name = "rr";
285                 disasm_std_operand(stmt, 0, 0, 0);
286                 disasm_std_operand(stmt, 1, 1, 0);
287                 disasm_std_operand(stmt, 2, 2, 0);
288                 break;
289         case 0x150:
290                 stmt->u.insn.name = "nand";
291                 disasm_std_operand(stmt, 0, 0, 0);
292                 disasm_std_operand(stmt, 1, 1, 0);
293                 disasm_std_operand(stmt, 2, 2, 0);
294                 break;
295         case 0x040:
296                 stmt->u.insn.name = "jand";
297                 stmt->u.insn.is_labelref = 2;
298                 stmt->u.insn.labeladdr = stmt->u.insn.bin->operands[2];
299                 disasm_std_operand(stmt, 0, 0, 0);
300                 disasm_std_operand(stmt, 1, 1, 0);
301                 break;
302         case (0x040 | 0x1):
303                 stmt->u.insn.name = "jnand";
304                 stmt->u.insn.is_labelref = 2;
305                 stmt->u.insn.labeladdr = stmt->u.insn.bin->operands[2];
306                 disasm_std_operand(stmt, 0, 0, 0);
307                 disasm_std_operand(stmt, 1, 1, 0);
308                 break;
309         case 0x050:
310                 stmt->u.insn.name = "js";
311                 stmt->u.insn.is_labelref = 2;
312                 stmt->u.insn.labeladdr = stmt->u.insn.bin->operands[2];
313                 disasm_std_operand(stmt, 0, 0, 0);
314                 disasm_std_operand(stmt, 1, 1, 0);
315                 break;
316         case (0x050 | 0x1):
317                 stmt->u.insn.name = "jns";
318                 stmt->u.insn.is_labelref = 2;
319                 stmt->u.insn.labeladdr = stmt->u.insn.bin->operands[2];
320                 disasm_std_operand(stmt, 0, 0, 0);
321                 disasm_std_operand(stmt, 1, 1, 0);
322                 break;
323         case 0x0D0:
324                 stmt->u.insn.name = "je";
325                 stmt->u.insn.is_labelref = 2;
326                 stmt->u.insn.labeladdr = stmt->u.insn.bin->operands[2];
327                 disasm_std_operand(stmt, 0, 0, 0);
328                 disasm_std_operand(stmt, 1, 1, 0);
329                 break;
330         case (0x0D0 | 0x1):
331                 stmt->u.insn.name = "jne";
332                 stmt->u.insn.is_labelref = 2;
333                 stmt->u.insn.labeladdr = stmt->u.insn.bin->operands[2];
334                 disasm_std_operand(stmt, 0, 0, 0);
335                 disasm_std_operand(stmt, 1, 1, 0);
336                 break;
337         case 0x0D2:
338                 stmt->u.insn.name = "jls";
339                 stmt->u.insn.is_labelref = 2;
340                 stmt->u.insn.labeladdr = stmt->u.insn.bin->operands[2];
341                 disasm_std_operand(stmt, 0, 0, 0);
342                 disasm_std_operand(stmt, 1, 1, 0);
343                 break;
344         case (0x0D2 | 0x1):
345                 stmt->u.insn.name = "jges";
346                 stmt->u.insn.is_labelref = 2;
347                 stmt->u.insn.labeladdr = stmt->u.insn.bin->operands[2];
348                 disasm_std_operand(stmt, 0, 0, 0);
349                 disasm_std_operand(stmt, 1, 1, 0);
350                 break;
351         case 0x0D4:
352                 stmt->u.insn.name = "jgs";
353                 stmt->u.insn.is_labelref = 2;
354                 stmt->u.insn.labeladdr = stmt->u.insn.bin->operands[2];
355                 disasm_std_operand(stmt, 0, 0, 0);
356                 disasm_std_operand(stmt, 1, 1, 0);
357                 break;
358         case (0x0D4 | 0x1):
359                 stmt->u.insn.name = "jles";
360                 stmt->u.insn.is_labelref = 2;
361                 stmt->u.insn.labeladdr = stmt->u.insn.bin->operands[2];
362                 disasm_std_operand(stmt, 0, 0, 0);
363                 disasm_std_operand(stmt, 1, 1, 0);
364                 break;
365         case 0x0DA:
366                 stmt->u.insn.name = "jl";
367                 stmt->u.insn.is_labelref = 2;
368                 stmt->u.insn.labeladdr = stmt->u.insn.bin->operands[2];
369                 disasm_std_operand(stmt, 0, 0, 0);
370                 disasm_std_operand(stmt, 1, 1, 0);
371                 break;
372         case (0x0DA | 0x1):
373                 stmt->u.insn.name = "jge";
374                 stmt->u.insn.is_labelref = 2;
375                 stmt->u.insn.labeladdr = stmt->u.insn.bin->operands[2];
376                 disasm_std_operand(stmt, 0, 0, 0);
377                 disasm_std_operand(stmt, 1, 1, 0);
378                 break;
379         case 0x0DC:
380                 stmt->u.insn.name = "jg";
381                 stmt->u.insn.is_labelref = 2;
382                 stmt->u.insn.labeladdr = stmt->u.insn.bin->operands[2];
383                 disasm_std_operand(stmt, 0, 0, 0);
384                 disasm_std_operand(stmt, 1, 1, 0);
385                 break;
386         case (0x0DC | 0x1):
387                 stmt->u.insn.name = "jle";
388                 stmt->u.insn.is_labelref = 2;
389                 stmt->u.insn.labeladdr = stmt->u.insn.bin->operands[2];
390                 disasm_std_operand(stmt, 0, 0, 0);
391                 disasm_std_operand(stmt, 1, 1, 0);
392                 break;
393         case 0x002: {
394                 char *str;
395
396                 stmt->u.insn.name = "call";
397                 stmt->u.insn.is_labelref = 1;
398                 stmt->u.insn.labeladdr = stmt->u.insn.bin->operands[2];
399                 str = xmalloc(4);
400                 snprintf(str, 4, "lr%u", stmt->u.insn.bin->operands[0]);
401                 stmt->u.insn.operands[0] = str;
402                 break;
403         }
404         case 0x003: {
405                 char *str;
406
407                 stmt->u.insn.name = "ret";
408                 str = xmalloc(4);
409                 snprintf(str, 4, "lr%u", stmt->u.insn.bin->operands[0]);
410                 stmt->u.insn.operands[0] = str;
411                 str = xmalloc(4);
412                 snprintf(str, 4, "lr%u", stmt->u.insn.bin->operands[2]);
413                 stmt->u.insn.operands[2] = str;
414                 break;
415         }
416         case 0x1E0: {
417                 unsigned int flags;
418
419                 flags = stmt->u.insn.bin->operands[1];
420                 switch (flags & ~0xC00) {
421                 case 0x1:
422                         stmt->u.insn.name = "tkiph";
423                         break;
424                 case (0x1 | 0x2):
425                         stmt->u.insn.name = "tkiphs";
426                         break;
427                 case 0x0:
428                         stmt->u.insn.name = "tkipl";
429                         break;
430                 case (0x0 | 0x2):
431                         stmt->u.insn.name = "tkipls";
432                         break;
433                 default:
434                         fprintf(stderr, "Invalid TKIP flags %X\n",
435                                 flags);
436                         exit(1);
437                 }
438                 disasm_std_operand(stmt, 0, 0, 0);
439                 disasm_std_operand(stmt, 2, 2, 0);
440                 break;
441         }
442         case 0x001: {
443                 stmt->u.insn.name = "nap";
444                 if (stmt->u.insn.bin->operands[0] != 0xBC0) {
445                         fprintf(stderr, "NAP: invalid first argument 0x%03X\n",
446                                 stmt->u.insn.bin->operands[0]);
447                 }
448                 if (stmt->u.insn.bin->operands[1] != 0xBC0) {
449                         fprintf(stderr, "NAP: invalid second argument 0x%03X\n",
450                                 stmt->u.insn.bin->operands[1]);
451                 }
452                 if (stmt->u.insn.bin->operands[2] != 0x000) {
453                         fprintf(stderr, "NAP: invalid third argument 0x%03X\n",
454                                 stmt->u.insn.bin->operands[2]);
455                 }
456                 break;
457         }
458         default:
459                 stmt->u.insn.name = gen_raw_code(bin->opcode);
460                 disasm_std_operand(stmt, 0, 0, 1);
461                 disasm_std_operand(stmt, 1, 1, 1);
462                 disasm_std_operand(stmt, 2, 2, 1);
463                 break;
464         }
465 }
466
467 static void disasm_opcodes(struct disassembler_context *ctx)
468 {
469         struct bin_instruction *bin;
470         size_t i;
471         struct statement *stmt;
472         char *str;
473
474         for (i = 0; i < ctx->nr_insns; i++) {
475                 bin = &(ctx->code[i]);
476
477                 stmt = xmalloc(sizeof(struct statement));
478                 stmt->type = STMT_INSN;
479                 INIT_LIST_HEAD(&stmt->list);
480                 stmt->u.insn.bin = bin;
481                 stmt->u.insn.is_labelref = -1;
482
483                 switch (bin->opcode & 0xF00) {
484                 case 0x200:
485                         stmt->u.insn.name = "srx";
486
487                         str = xmalloc(3);
488                         snprintf(str, 3, "%d", (bin->opcode & 0x0F0) >> 4);
489                         stmt->u.insn.operands[0] = str;
490                         str = xmalloc(3);
491                         snprintf(str, 3, "%d", (bin->opcode & 0x00F));
492                         stmt->u.insn.operands[1] = str;
493
494                         disasm_std_operand(stmt, 0, 2, 0);
495                         disasm_std_operand(stmt, 1, 3, 0);
496                         disasm_std_operand(stmt, 2, 4, 0);
497                         break;
498                 case 0x300:
499                         stmt->u.insn.name = "orx";
500
501                         str = xmalloc(3);
502                         snprintf(str, 3, "%d", (bin->opcode & 0x0F0) >> 4);
503                         stmt->u.insn.operands[0] = str;
504                         str = xmalloc(3);
505                         snprintf(str, 3, "%d", (bin->opcode & 0x00F));
506                         stmt->u.insn.operands[1] = str;
507
508                         disasm_std_operand(stmt, 0, 2, 0);
509                         disasm_std_operand(stmt, 1, 3, 0);
510                         disasm_std_operand(stmt, 2, 4, 0);
511                         break;
512                 case 0x400:
513                         stmt->u.insn.name = "jzx";
514
515                         str = xmalloc(3);
516                         snprintf(str, 3, "%d", (bin->opcode & 0x0F0) >> 4);
517                         stmt->u.insn.operands[0] = str;
518                         str = xmalloc(3);
519                         snprintf(str, 3, "%d", (bin->opcode & 0x00F));
520                         stmt->u.insn.operands[1] = str;
521
522                         disasm_std_operand(stmt, 0, 2, 0);
523                         disasm_std_operand(stmt, 1, 3, 0);
524                         stmt->u.insn.is_labelref = 4;
525                         stmt->u.insn.labeladdr = stmt->u.insn.bin->operands[2];
526                         break;
527                 case 0x500:
528                         stmt->u.insn.name = "jnzx";
529
530                         str = xmalloc(3);
531                         snprintf(str, 3, "%d", (bin->opcode & 0x0F0) >> 4);
532                         stmt->u.insn.operands[0] = str;
533                         str = xmalloc(3);
534                         snprintf(str, 3, "%d", (bin->opcode & 0x00F));
535                         stmt->u.insn.operands[1] = str;
536
537                         disasm_std_operand(stmt, 0, 2, 0);
538                         disasm_std_operand(stmt, 1, 3, 0);
539                         stmt->u.insn.is_labelref = 4;
540                         stmt->u.insn.labeladdr = stmt->u.insn.bin->operands[2];
541                         break;
542                 case 0x600:
543                         stmt->u.insn.name = "jnext";
544
545                         str = xmalloc(5);
546                         snprintf(str, 5, "0x%02X", (bin->opcode & 0x0FF));
547                         stmt->u.insn.operands[0] = str;
548
549                         disasm_std_operand(stmt, 0, 1, 0);
550                         disasm_std_operand(stmt, 1, 2, 0);
551                         stmt->u.insn.is_labelref = 3;
552                         stmt->u.insn.labeladdr = stmt->u.insn.bin->operands[2];
553                         break;
554                 case 0x700:
555                         stmt->u.insn.name = "jext";
556
557                         str = xmalloc(5);
558                         snprintf(str, 5, "0x%02X", (bin->opcode & 0x0FF));
559                         stmt->u.insn.operands[0] = str;
560
561                         disasm_std_operand(stmt, 0, 1, 0);
562                         disasm_std_operand(stmt, 1, 2, 0);
563                         stmt->u.insn.is_labelref = 3;
564                         stmt->u.insn.labeladdr = stmt->u.insn.bin->operands[2];
565                         break;
566                 default:
567                         disasm_constant_opcodes(ctx, stmt);
568                         break;
569                 }
570
571                 list_add_tail(&stmt->list, &ctx->stmt_list);
572         }
573 }
574
575 static struct statement * get_label_at(struct disassembler_context *ctx,
576                                        unsigned int addr)
577 {
578         unsigned int addrcnt = 0;
579         struct statement *stmt, *ret, *prev;
580
581         list_for_each_entry(stmt, &ctx->stmt_list, list) {
582                 if (stmt->type != STMT_INSN)
583                         continue;
584                 if (addrcnt == addr) {
585                         prev = list_entry(stmt->list.prev, struct statement, list);
586                         if (prev->type == STMT_LABEL)
587                                 return prev;
588                         ret = xmalloc(sizeof(struct statement));
589                         INIT_LIST_HEAD(&ret->list);
590                         ret->type = STMT_LABEL;
591                         list_add(&ret->list, &prev->list);
592
593                         return ret;
594                 }
595                 addrcnt++;
596         }
597
598         return NULL;
599 }
600
601 static void resolve_labels(struct disassembler_context *ctx)
602 {
603         struct statement *stmt;
604         struct statement *label;
605         struct statement *n;
606         unsigned int labeladdr;
607         unsigned int namecnt = 0;
608
609         /* Resolve label references */
610         list_for_each_entry_safe(stmt, n, &ctx->stmt_list, list) {
611                 if (stmt->type != STMT_INSN)
612                         continue;
613                 if (stmt->u.insn.is_labelref == -1)
614                         continue;
615                 labeladdr = stmt->u.insn.labeladdr;
616                 label = get_label_at(ctx, labeladdr);
617                 if (!label) {
618                         fprintf(stderr, "Labeladdress %X out of bounds\n",
619                                 labeladdr);
620                         exit(1);
621                 }
622                 stmt->u.insn.labelref = label;
623         }
624
625         /* Name the labels */
626         list_for_each_entry(stmt, &ctx->stmt_list, list) {
627                 if (stmt->type != STMT_LABEL)
628                         continue;
629                 stmt->u.label.name = xmalloc(20);
630                 snprintf(stmt->u.label.name, 20, "L%u", namecnt);
631                 namecnt++;
632         }
633 }
634
635 static void emit_asm(struct disassembler_context *ctx)
636 {
637         struct statement *stmt;
638         FILE *fd;
639         int first, i;
640
641         fd = fopen(outfile_name, "w+");
642         if (!fd) {
643                 fprintf(stderr, "Could not open output file \"%s\"\n",
644                         outfile_name);
645                 exit(1);
646         }
647         fprintf(fd, "%%arch bcm43xx_newworld\n\n");
648         list_for_each_entry(stmt, &ctx->stmt_list, list) {
649                 switch (stmt->type) {
650                 case STMT_INSN:
651                         fprintf(fd, "\t%s", stmt->u.insn.name);
652                         first = 1;
653                         for (i = 0; i < ARRAY_SIZE(stmt->u.insn.operands); i++) {
654                                 if (stmt->u.insn.is_labelref == i) {
655                                         fprintf(fd, ",%s",
656                                                 stmt->u.insn.labelref->u.label.name);
657                                 }
658                                 if (!stmt->u.insn.operands[i])
659                                         continue;
660                                 if (first)
661                                         fprintf(fd, "\t");
662                                 if (!first)
663                                         fprintf(fd, ",");
664                                 first = 0;
665                                 fprintf(fd, "%s",
666                                         stmt->u.insn.operands[i]);
667                         }
668                         fprintf(fd, "\n");
669                         break;
670                 case STMT_LABEL:
671                         fprintf(fd, "%s:\n", stmt->u.label.name);
672                         break;
673                 }
674         }
675         fclose(fd);
676 }
677
678 static void read_input(struct disassembler_context *ctx)
679 {
680         size_t size = 0, pos = 0;
681         size_t ret;
682         struct bin_instruction *code = NULL;
683         unsigned char tmp[sizeof(uint64_t)];
684         uint64_t codeword;
685         struct fw_header hdr;
686
687         ret = fread(&hdr, 1, sizeof(hdr), infile);
688         if (!ret || ret != sizeof(hdr)) {
689                 fprintf(stderr, "Corrupt input file (not fwcutter output)\n");
690                 exit(1);
691         }       
692
693         if (hdr.ver != 1) {
694                 fprintf(stderr, "Invalid fwcutter header version\n");
695                 exit(1);
696         }
697
698         if (hdr.type != 'u') {
699                 fprintf(stderr, "Not a microcode image\n");
700                 exit(1);
701         }
702
703         while (1) {
704                 if (pos >= size) {
705                         size += 512;
706                         code = xrealloc(code, size * sizeof(struct bin_instruction));
707                 }
708                 ret = fread(tmp, 1, sizeof(uint64_t), infile);
709                 if (!ret)
710                         break;
711                 if (ret != sizeof(uint64_t)) {
712                         fprintf(stderr, "Corrupt input file (not 8 byte aligned)\n");
713                         exit(1);
714                 }
715
716                 codeword = 0;
717                 codeword |= ((uint64_t)tmp[0]) << 56;
718                 codeword |= ((uint64_t)tmp[1]) << 48;
719                 codeword |= ((uint64_t)tmp[2]) << 40;
720                 codeword |= ((uint64_t)tmp[3]) << 32;
721                 codeword |= ((uint64_t)tmp[4]) << 24;
722                 codeword |= ((uint64_t)tmp[5]) << 16;
723                 codeword |= ((uint64_t)tmp[6]) << 8;
724                 codeword |= ((uint64_t)tmp[7]);
725
726                 code[pos].opcode = (codeword >> 4) & 0xFFF;
727                 code[pos].operands[0] = (codeword & 0xF) << 8;
728                 code[pos].operands[0] |= (codeword >> 56) & 0xFF;
729                 code[pos].operands[1] = (codeword >> 44) & 0xFFF;
730                 code[pos].operands[2] = (codeword >> 32) & 0xFFF;
731
732                 pos++;
733         }
734
735         ctx->code = code;
736         ctx->nr_insns = pos;
737 }
738
739 static void disassemble(void)
740 {
741         struct disassembler_context ctx;
742
743         memset(&ctx, 0, sizeof(ctx));
744         INIT_LIST_HEAD(&ctx.stmt_list);
745
746         read_input(&ctx);
747         disasm_opcodes(&ctx);
748         resolve_labels(&ctx);
749         emit_asm(&ctx);
750 }
751
752 static void usage(int argc, char **argv)
753 {
754         fprintf(stderr, "Usage: %s output_file\n", argv[0]);
755 }
756
757 static void parse_args(int argc, char **argv)
758 {
759         if (argc != 2) {
760                 usage(argc, argv);
761                 exit(1);
762         }
763         outfile_name = argv[1];
764 }
765
766 int main(int argc, char **argv)
767 {
768         infile = stdin;
769         parse_args(argc, argv);
770         disassemble();
771
772         /* Lazyman simply leaks all allocated memory. */
773         return 0;
774 }