fwcutter/make: Avoid _DEFAULT_SOURCE warning
[b43-tools.git] / disassembler / main.c
index 76295fd5eb2a836b91c1692827c7fb50405e8033..eecea39d70d2f1e33eb68a489303b5a7a75211ab 100644 (file)
@@ -1,5 +1,5 @@
 /*
- *   Copyright (C) 2006-2010  Michael Buesch <mb@bu3sch.de>
+ *   Copyright (C) 2006-2010  Michael Buesch <m@bues.ch>
  *
  *   This program is free software; you can redistribute it and/or modify
  *   it under the terms of the GNU General Public License version 2
@@ -39,7 +39,7 @@ struct statement {
                        const char *name;
                        const char *operands[5];
 
-                       int is_labelref;
+                       int labelref_operand;
                        unsigned int labeladdr;
                        struct statement *labelref;
                } insn;
@@ -68,6 +68,25 @@ const char *infile_name;
 const char *outfile_name;
 
 
+#define _msg_helper(type, msg, x...)   do {            \
+       fprintf(stderr, "Disassembler " type            \
+               ":\n  " msg "\n" ,##x);                 \
+                                       } while (0)
+
+#define dasm_error(msg, x...)  do {            \
+       _msg_helper("ERROR", msg ,##x);         \
+       exit(1);                                \
+                               } while (0)
+
+#define dasm_int_error(msg, x...) \
+       dasm_error("Internal error (bug): " msg ,##x)
+
+#define dasm_warn(msg, x...)   \
+       _msg_helper("warning", msg ,##x)
+
+#define asm_info(msg, x...)    \
+       _msg_helper("info", msg ,##x)
+
 static const char * gen_raw_code(unsigned int operand)
 {
        char *ret;
@@ -103,8 +122,7 @@ static const char * disasm_indirect_mem_operand(unsigned int operand)
                reg = ((operand >> 7) & 0x7);
                break;
        default:
-               fprintf(stderr, "Internal error: disasm_indirect_mem_operand invalid arch\n");
-               exit(1);
+               dasm_int_error("disasm_indirect_mem_operand invalid arch");
        }
        ret = xmalloc(12);
        snprintf(ret, 12, "[0x%02X,off%u]", offset, reg);
@@ -128,8 +146,7 @@ static const char * disasm_imm_operand(unsigned int operand)
                mask = 0x7FF;
                break;
        default:
-               fprintf(stderr, "Internal error: disasm_imm_operand invalid arch\n");
-               exit(1);
+               dasm_int_error("disasm_imm_operand invalid arch");
        }
 
        operand &= mask;
@@ -155,8 +172,7 @@ static const char * disasm_spr_operand(unsigned int operand)
                mask = 0x7FF;
                break;
        default:
-               fprintf(stderr, "Internal error: disasm_spr_operand invalid arch\n");
-               exit(1);
+               dasm_int_error("disasm_spr_operand invalid arch");
        }
 
        ret = xmalloc(8);
@@ -178,8 +194,7 @@ static const char * disasm_gpr_operand(unsigned int operand)
                mask = 0x7F;
                break;
        default:
-               fprintf(stderr, "Internal error: disasm_gpr_operand invalid arch\n");
-               exit(1);
+               dasm_int_error("disasm_gpr_operand invalid arch");
        }
 
        ret = xmalloc(5);
@@ -188,15 +203,20 @@ static const char * disasm_gpr_operand(unsigned int operand)
        return ret;
 }
 
-static void disasm_std_operand(struct statement *stmt,
+static void disasm_raw_operand(struct statement *stmt,
                               int oper_idx,
-                              int out_idx,
-                              int forceraw)
+                              int out_idx)
 {
        unsigned int operand = stmt->u.insn.bin->operands[oper_idx];
 
-       if (forceraw)
-               goto raw;
+       stmt->u.insn.operands[out_idx] = gen_raw_code(operand);
+}
+
+static void disasm_std_operand(struct statement *stmt,
+                              int oper_idx,
+                              int out_idx)
+{
+       unsigned int operand = stmt->u.insn.bin->operands[oper_idx];
 
        switch (cmdargs.arch) {
        case 5:
@@ -236,20 +256,26 @@ static void disasm_std_operand(struct statement *stmt,
                }
                break;
        default:
-               fprintf(stderr, "Internal error: disasm_std_operand invalid arch\n");
-               exit(1);
+               dasm_int_error("disasm_std_operand invalid arch");
        }
-raw:
-       stmt->u.insn.operands[out_idx] = gen_raw_code(operand);
+       /* No luck. Disassemble to raw operand. */
+       disasm_raw_operand(stmt, oper_idx, out_idx);
 }
 
 static void disasm_opcode_raw(struct disassembler_context *ctx,
-                             struct statement *stmt)
+                             struct statement *stmt,
+                             int raw_operands)
 {
        stmt->u.insn.name = gen_raw_code(stmt->u.insn.bin->opcode);
-       disasm_std_operand(stmt, 0, 0, 1);
-       disasm_std_operand(stmt, 1, 1, 1);
-       disasm_std_operand(stmt, 2, 2, 1);
+       if (raw_operands) {
+               disasm_raw_operand(stmt, 0, 0);
+               disasm_raw_operand(stmt, 1, 1);
+               disasm_raw_operand(stmt, 2, 2);
+       } else {
+               disasm_std_operand(stmt, 0, 0);
+               disasm_std_operand(stmt, 1, 1);
+               disasm_std_operand(stmt, 2, 2);
+       }
 }
 
 static void disasm_constant_opcodes(struct disassembler_context *ctx,
@@ -258,205 +284,239 @@ static void disasm_constant_opcodes(struct disassembler_context *ctx,
        struct bin_instruction *bin = stmt->u.insn.bin;
 
        switch (bin->opcode) {
+       case 0x101:
+               stmt->u.insn.name = "mul";
+               disasm_std_operand(stmt, 0, 0);
+               disasm_std_operand(stmt, 1, 1);
+               disasm_std_operand(stmt, 2, 2);
+               break;
        case 0x1C0:
                stmt->u.insn.name = "add";
-               disasm_std_operand(stmt, 0, 0, 0);
-               disasm_std_operand(stmt, 1, 1, 0);
-               disasm_std_operand(stmt, 2, 2, 0);
+               disasm_std_operand(stmt, 0, 0);
+               disasm_std_operand(stmt, 1, 1);
+               disasm_std_operand(stmt, 2, 2);
                break;
        case 0x1C2:
                stmt->u.insn.name = "add.";
-               disasm_std_operand(stmt, 0, 0, 0);
-               disasm_std_operand(stmt, 1, 1, 0);
-               disasm_std_operand(stmt, 2, 2, 0);
+               disasm_std_operand(stmt, 0, 0);
+               disasm_std_operand(stmt, 1, 1);
+               disasm_std_operand(stmt, 2, 2);
                break;
        case 0x1C1:
                stmt->u.insn.name = "addc";
-               disasm_std_operand(stmt, 0, 0, 0);
-               disasm_std_operand(stmt, 1, 1, 0);
-               disasm_std_operand(stmt, 2, 2, 0);
+               disasm_std_operand(stmt, 0, 0);
+               disasm_std_operand(stmt, 1, 1);
+               disasm_std_operand(stmt, 2, 2);
                break;
        case 0x1C3:
                stmt->u.insn.name = "addc.";
-               disasm_std_operand(stmt, 0, 0, 0);
-               disasm_std_operand(stmt, 1, 1, 0);
-               disasm_std_operand(stmt, 2, 2, 0);
+               disasm_std_operand(stmt, 0, 0);
+               disasm_std_operand(stmt, 1, 1);
+               disasm_std_operand(stmt, 2, 2);
                break;
        case 0x1D0:
                stmt->u.insn.name = "sub";
-               disasm_std_operand(stmt, 0, 0, 0);
-               disasm_std_operand(stmt, 1, 1, 0);
-               disasm_std_operand(stmt, 2, 2, 0);
+               disasm_std_operand(stmt, 0, 0);
+               disasm_std_operand(stmt, 1, 1);
+               disasm_std_operand(stmt, 2, 2);
                break;
        case 0x1D2:
                stmt->u.insn.name = "sub.";
-               disasm_std_operand(stmt, 0, 0, 0);
-               disasm_std_operand(stmt, 1, 1, 0);
-               disasm_std_operand(stmt, 2, 2, 0);
+               disasm_std_operand(stmt, 0, 0);
+               disasm_std_operand(stmt, 1, 1);
+               disasm_std_operand(stmt, 2, 2);
                break;
        case 0x1D1:
                stmt->u.insn.name = "subc";
-               disasm_std_operand(stmt, 0, 0, 0);
-               disasm_std_operand(stmt, 1, 1, 0);
-               disasm_std_operand(stmt, 2, 2, 0);
+               disasm_std_operand(stmt, 0, 0);
+               disasm_std_operand(stmt, 1, 1);
+               disasm_std_operand(stmt, 2, 2);
                break;
        case 0x1D3:
                stmt->u.insn.name = "subc.";
-               disasm_std_operand(stmt, 0, 0, 0);
-               disasm_std_operand(stmt, 1, 1, 0);
-               disasm_std_operand(stmt, 2, 2, 0);
+               disasm_std_operand(stmt, 0, 0);
+               disasm_std_operand(stmt, 1, 1);
+               disasm_std_operand(stmt, 2, 2);
                break;
        case 0x130:
                stmt->u.insn.name = "sra";
-               disasm_std_operand(stmt, 0, 0, 0);
-               disasm_std_operand(stmt, 1, 1, 0);
-               disasm_std_operand(stmt, 2, 2, 0);
+               disasm_std_operand(stmt, 0, 0);
+               disasm_std_operand(stmt, 1, 1);
+               disasm_std_operand(stmt, 2, 2);
                break;
        case 0x160:
                stmt->u.insn.name = "or";
-               disasm_std_operand(stmt, 0, 0, 0);
-               disasm_std_operand(stmt, 1, 1, 0);
-               disasm_std_operand(stmt, 2, 2, 0);
+               disasm_std_operand(stmt, 0, 0);
+               disasm_std_operand(stmt, 1, 1);
+               disasm_std_operand(stmt, 2, 2);
                break;
        case 0x140:
                stmt->u.insn.name = "and";
-               disasm_std_operand(stmt, 0, 0, 0);
-               disasm_std_operand(stmt, 1, 1, 0);
-               disasm_std_operand(stmt, 2, 2, 0);
+               disasm_std_operand(stmt, 0, 0);
+               disasm_std_operand(stmt, 1, 1);
+               disasm_std_operand(stmt, 2, 2);
                break;
        case 0x170:
                stmt->u.insn.name = "xor";
-               disasm_std_operand(stmt, 0, 0, 0);
-               disasm_std_operand(stmt, 1, 1, 0);
-               disasm_std_operand(stmt, 2, 2, 0);
+               disasm_std_operand(stmt, 0, 0);
+               disasm_std_operand(stmt, 1, 1);
+               disasm_std_operand(stmt, 2, 2);
                break;
        case 0x120:
                stmt->u.insn.name = "sr";
-               disasm_std_operand(stmt, 0, 0, 0);
-               disasm_std_operand(stmt, 1, 1, 0);
-               disasm_std_operand(stmt, 2, 2, 0);
+               disasm_std_operand(stmt, 0, 0);
+               disasm_std_operand(stmt, 1, 1);
+               disasm_std_operand(stmt, 2, 2);
                break;
        case 0x110:
                stmt->u.insn.name = "sl";
-               disasm_std_operand(stmt, 0, 0, 0);
-               disasm_std_operand(stmt, 1, 1, 0);
-               disasm_std_operand(stmt, 2, 2, 0);
+               disasm_std_operand(stmt, 0, 0);
+               disasm_std_operand(stmt, 1, 1);
+               disasm_std_operand(stmt, 2, 2);
                break;
        case 0x1A0:
                stmt->u.insn.name = "rl";
-               disasm_std_operand(stmt, 0, 0, 0);
-               disasm_std_operand(stmt, 1, 1, 0);
-               disasm_std_operand(stmt, 2, 2, 0);
+               disasm_std_operand(stmt, 0, 0);
+               disasm_std_operand(stmt, 1, 1);
+               disasm_std_operand(stmt, 2, 2);
                break;
        case 0x1B0:
                stmt->u.insn.name = "rr";
-               disasm_std_operand(stmt, 0, 0, 0);
-               disasm_std_operand(stmt, 1, 1, 0);
-               disasm_std_operand(stmt, 2, 2, 0);
+               disasm_std_operand(stmt, 0, 0);
+               disasm_std_operand(stmt, 1, 1);
+               disasm_std_operand(stmt, 2, 2);
                break;
        case 0x150:
                stmt->u.insn.name = "nand";
-               disasm_std_operand(stmt, 0, 0, 0);
-               disasm_std_operand(stmt, 1, 1, 0);
-               disasm_std_operand(stmt, 2, 2, 0);
+               disasm_std_operand(stmt, 0, 0);
+               disasm_std_operand(stmt, 1, 1);
+               disasm_std_operand(stmt, 2, 2);
                break;
        case 0x040:
                stmt->u.insn.name = "jand";
-               stmt->u.insn.is_labelref = 2;
+               stmt->u.insn.labelref_operand = 2;
                stmt->u.insn.labeladdr = stmt->u.insn.bin->operands[2];
-               disasm_std_operand(stmt, 0, 0, 0);
-               disasm_std_operand(stmt, 1, 1, 0);
+               disasm_std_operand(stmt, 0, 0);
+               disasm_std_operand(stmt, 1, 1);
                break;
        case (0x040 | 0x1):
                stmt->u.insn.name = "jnand";
-               stmt->u.insn.is_labelref = 2;
+               stmt->u.insn.labelref_operand = 2;
                stmt->u.insn.labeladdr = stmt->u.insn.bin->operands[2];
-               disasm_std_operand(stmt, 0, 0, 0);
-               disasm_std_operand(stmt, 1, 1, 0);
+               disasm_std_operand(stmt, 0, 0);
+               disasm_std_operand(stmt, 1, 1);
                break;
        case 0x050:
                stmt->u.insn.name = "js";
-               stmt->u.insn.is_labelref = 2;
+               stmt->u.insn.labelref_operand = 2;
                stmt->u.insn.labeladdr = stmt->u.insn.bin->operands[2];
-               disasm_std_operand(stmt, 0, 0, 0);
-               disasm_std_operand(stmt, 1, 1, 0);
+               disasm_std_operand(stmt, 0, 0);
+               disasm_std_operand(stmt, 1, 1);
                break;
        case (0x050 | 0x1):
                stmt->u.insn.name = "jns";
-               stmt->u.insn.is_labelref = 2;
+               stmt->u.insn.labelref_operand = 2;
                stmt->u.insn.labeladdr = stmt->u.insn.bin->operands[2];
-               disasm_std_operand(stmt, 0, 0, 0);
-               disasm_std_operand(stmt, 1, 1, 0);
+               disasm_std_operand(stmt, 0, 0);
+               disasm_std_operand(stmt, 1, 1);
                break;
        case 0x0D0:
                stmt->u.insn.name = "je";
-               stmt->u.insn.is_labelref = 2;
+               stmt->u.insn.labelref_operand = 2;
                stmt->u.insn.labeladdr = stmt->u.insn.bin->operands[2];
-               disasm_std_operand(stmt, 0, 0, 0);
-               disasm_std_operand(stmt, 1, 1, 0);
+               disasm_std_operand(stmt, 0, 0);
+               disasm_std_operand(stmt, 1, 1);
                break;
        case (0x0D0 | 0x1):
                stmt->u.insn.name = "jne";
-               stmt->u.insn.is_labelref = 2;
+               stmt->u.insn.labelref_operand = 2;
                stmt->u.insn.labeladdr = stmt->u.insn.bin->operands[2];
-               disasm_std_operand(stmt, 0, 0, 0);
-               disasm_std_operand(stmt, 1, 1, 0);
+               disasm_std_operand(stmt, 0, 0);
+               disasm_std_operand(stmt, 1, 1);
                break;
        case 0x0D2:
                stmt->u.insn.name = "jls";
-               stmt->u.insn.is_labelref = 2;
+               stmt->u.insn.labelref_operand = 2;
                stmt->u.insn.labeladdr = stmt->u.insn.bin->operands[2];
-               disasm_std_operand(stmt, 0, 0, 0);
-               disasm_std_operand(stmt, 1, 1, 0);
+               disasm_std_operand(stmt, 0, 0);
+               disasm_std_operand(stmt, 1, 1);
                break;
        case (0x0D2 | 0x1):
                stmt->u.insn.name = "jges";
-               stmt->u.insn.is_labelref = 2;
+               stmt->u.insn.labelref_operand = 2;
                stmt->u.insn.labeladdr = stmt->u.insn.bin->operands[2];
-               disasm_std_operand(stmt, 0, 0, 0);
-               disasm_std_operand(stmt, 1, 1, 0);
+               disasm_std_operand(stmt, 0, 0);
+               disasm_std_operand(stmt, 1, 1);
                break;
        case 0x0D4:
                stmt->u.insn.name = "jgs";
-               stmt->u.insn.is_labelref = 2;
+               stmt->u.insn.labelref_operand = 2;
                stmt->u.insn.labeladdr = stmt->u.insn.bin->operands[2];
-               disasm_std_operand(stmt, 0, 0, 0);
-               disasm_std_operand(stmt, 1, 1, 0);
+               disasm_std_operand(stmt, 0, 0);
+               disasm_std_operand(stmt, 1, 1);
                break;
        case (0x0D4 | 0x1):
                stmt->u.insn.name = "jles";
-               stmt->u.insn.is_labelref = 2;
+               stmt->u.insn.labelref_operand = 2;
                stmt->u.insn.labeladdr = stmt->u.insn.bin->operands[2];
-               disasm_std_operand(stmt, 0, 0, 0);
-               disasm_std_operand(stmt, 1, 1, 0);
+               disasm_std_operand(stmt, 0, 0);
+               disasm_std_operand(stmt, 1, 1);
+               break;
+       case 0x0D6:
+               stmt->u.insn.name = "jdn";
+               stmt->u.insn.labelref_operand = 2;
+               stmt->u.insn.labeladdr = stmt->u.insn.bin->operands[2];
+               disasm_std_operand(stmt, 0, 0);
+               disasm_std_operand(stmt, 1, 1);
+               break;
+       case (0x0D6 | 0x1):
+               stmt->u.insn.name = "jdpz";
+               stmt->u.insn.labelref_operand = 2;
+               stmt->u.insn.labeladdr = stmt->u.insn.bin->operands[2];
+               disasm_std_operand(stmt, 0, 0);
+               disasm_std_operand(stmt, 1, 1);
+               break;
+       case 0x0D8:
+               stmt->u.insn.name = "jdp";
+               stmt->u.insn.labelref_operand = 2;
+               stmt->u.insn.labeladdr = stmt->u.insn.bin->operands[2];
+               disasm_std_operand(stmt, 0, 0);
+               disasm_std_operand(stmt, 1, 1);
+               break;
+       case (0x0D8 | 0x1):
+               stmt->u.insn.name = "jdnz";
+               stmt->u.insn.labelref_operand = 2;
+               stmt->u.insn.labeladdr = stmt->u.insn.bin->operands[2];
+               disasm_std_operand(stmt, 0, 0);
+               disasm_std_operand(stmt, 1, 1);
                break;
        case 0x0DA:
                stmt->u.insn.name = "jl";
-               stmt->u.insn.is_labelref = 2;
+               stmt->u.insn.labelref_operand = 2;
                stmt->u.insn.labeladdr = stmt->u.insn.bin->operands[2];
-               disasm_std_operand(stmt, 0, 0, 0);
-               disasm_std_operand(stmt, 1, 1, 0);
+               disasm_std_operand(stmt, 0, 0);
+               disasm_std_operand(stmt, 1, 1);
                break;
        case (0x0DA | 0x1):
                stmt->u.insn.name = "jge";
-               stmt->u.insn.is_labelref = 2;
+               stmt->u.insn.labelref_operand = 2;
                stmt->u.insn.labeladdr = stmt->u.insn.bin->operands[2];
-               disasm_std_operand(stmt, 0, 0, 0);
-               disasm_std_operand(stmt, 1, 1, 0);
+               disasm_std_operand(stmt, 0, 0);
+               disasm_std_operand(stmt, 1, 1);
                break;
        case 0x0DC:
                stmt->u.insn.name = "jg";
-               stmt->u.insn.is_labelref = 2;
+               stmt->u.insn.labelref_operand = 2;
                stmt->u.insn.labeladdr = stmt->u.insn.bin->operands[2];
-               disasm_std_operand(stmt, 0, 0, 0);
-               disasm_std_operand(stmt, 1, 1, 0);
+               disasm_std_operand(stmt, 0, 0);
+               disasm_std_operand(stmt, 1, 1);
                break;
        case (0x0DC | 0x1):
                stmt->u.insn.name = "jle";
-               stmt->u.insn.is_labelref = 2;
+               stmt->u.insn.labelref_operand = 2;
                stmt->u.insn.labeladdr = stmt->u.insn.bin->operands[2];
-               disasm_std_operand(stmt, 0, 0, 0);
-               disasm_std_operand(stmt, 1, 1, 0);
+               disasm_std_operand(stmt, 0, 0);
+               disasm_std_operand(stmt, 1, 1);
                break;
        case 0x002: {
                char *str;
@@ -464,7 +524,7 @@ static void disasm_constant_opcodes(struct disassembler_context *ctx,
                switch (cmdargs.arch) {
                case 5:
                        stmt->u.insn.name = "call";
-                       stmt->u.insn.is_labelref = 1;
+                       stmt->u.insn.labelref_operand = 1;
                        stmt->u.insn.labeladdr = stmt->u.insn.bin->operands[2];
                        str = xmalloc(4);
                        snprintf(str, 4, "lr%u", stmt->u.insn.bin->operands[0]);
@@ -472,7 +532,7 @@ static void disasm_constant_opcodes(struct disassembler_context *ctx,
                        break;
                case 15:
                        //FIXME: This opcode is different on r15. Decode raw for now.
-                       disasm_opcode_raw(ctx, stmt);
+                       disasm_opcode_raw(ctx, stmt, 1);
                        break;
                }
                break;
@@ -489,6 +549,31 @@ static void disasm_constant_opcodes(struct disassembler_context *ctx,
                stmt->u.insn.operands[2] = str;
                break;
        }
+       case 0x004: {
+               if (cmdargs.arch != 15) {
+                       dasm_error("arch 15 'calls' instruction found in arch %d binary",
+                                  cmdargs.arch);
+               }
+               stmt->u.insn.name = "calls";
+               stmt->u.insn.labelref_operand = 0;
+               stmt->u.insn.labeladdr = stmt->u.insn.bin->operands[2];
+               if (stmt->u.insn.bin->operands[0] != 0x1780 ||
+                   stmt->u.insn.bin->operands[1] != 0x1780)
+                       dasm_warn("r15 calls: Invalid first or second argument");
+               break;
+       }
+       case 0x005: {
+               if (cmdargs.arch != 15) {
+                       dasm_error("arch 15 'rets' instruction found in arch %d binary",
+                                  cmdargs.arch);
+               }
+               stmt->u.insn.name = "rets";
+               if (stmt->u.insn.bin->operands[0] != 0x1780 ||
+                   stmt->u.insn.bin->operands[1] != 0x1780 ||
+                   stmt->u.insn.bin->operands[2] != 0)
+                       dasm_warn("r15 rets: Invalid argument(s)");
+               break;
+       }
        case 0x1E0: {
                unsigned int flags, mask;
 
@@ -500,8 +585,7 @@ static void disasm_constant_opcodes(struct disassembler_context *ctx,
                        mask = 0x7FF;
                        break;
                default:
-                       fprintf(stderr, "Internal error: TKIP invalid arch\n");
-                       exit(1);
+                       dasm_int_error("TKIP invalid arch");
                }
 
                flags = stmt->u.insn.bin->operands[1];
@@ -519,12 +603,10 @@ static void disasm_constant_opcodes(struct disassembler_context *ctx,
                        stmt->u.insn.name = "tkipls";
                        break;
                default:
-                       fprintf(stderr, "Invalid TKIP flags %X\n",
-                               flags);
-                       exit(1);
+                       dasm_error("Invalid TKIP flags %X", flags);
                }
-               disasm_std_operand(stmt, 0, 0, 0);
-               disasm_std_operand(stmt, 2, 2, 0);
+               disasm_std_operand(stmt, 0, 0);
+               disasm_std_operand(stmt, 2, 2);
                break;
        }
        case 0x001: {
@@ -539,25 +621,27 @@ static void disasm_constant_opcodes(struct disassembler_context *ctx,
                        mask = 0x1780;
                        break;
                default:
-                       fprintf(stderr, "Internal error: NAP invalid arch\n");
-                       exit(1);
+                       dasm_int_error("NAP invalid arch");
                }
                if (stmt->u.insn.bin->operands[0] != mask) {
-                       fprintf(stderr, "NAP: invalid first argument 0x%04X\n",
-                               stmt->u.insn.bin->operands[0]);
+                       dasm_warn("NAP: invalid first argument 0x%04X\n",
+                                 stmt->u.insn.bin->operands[0]);
                }
                if (stmt->u.insn.bin->operands[1] != mask) {
-                       fprintf(stderr, "NAP: invalid second argument 0x%04X\n",
-                               stmt->u.insn.bin->operands[1]);
+                       dasm_warn("NAP: invalid second argument 0x%04X\n",
+                                 stmt->u.insn.bin->operands[1]);
                }
                if (stmt->u.insn.bin->operands[2] != 0) {
-                       fprintf(stderr, "NAP: invalid third argument 0x%04X\n",
-                               stmt->u.insn.bin->operands[2]);
+                       dasm_warn("NAP: invalid third argument 0x%04X\n",
+                                 stmt->u.insn.bin->operands[2]);
                }
                break;
        }
+       case 0x000:
+               disasm_opcode_raw(ctx, stmt, 1);
+               break;
        default:
-               disasm_opcode_raw(ctx, stmt);
+               disasm_opcode_raw(ctx, stmt, (cmdargs.unknown_decode == 0));
                break;
        }
 }
@@ -576,7 +660,7 @@ static void disasm_opcodes(struct disassembler_context *ctx)
                stmt->type = STMT_INSN;
                INIT_LIST_HEAD(&stmt->list);
                stmt->u.insn.bin = bin;
-               stmt->u.insn.is_labelref = -1;
+               stmt->u.insn.labelref_operand = -1; /* none */
 
                switch (bin->opcode & 0xF00) {
                case 0x200:
@@ -589,9 +673,9 @@ static void disasm_opcodes(struct disassembler_context *ctx)
                        snprintf(str, 3, "%d", (bin->opcode & 0x00F));
                        stmt->u.insn.operands[1] = str;
 
-                       disasm_std_operand(stmt, 0, 2, 0);
-                       disasm_std_operand(stmt, 1, 3, 0);
-                       disasm_std_operand(stmt, 2, 4, 0);
+                       disasm_std_operand(stmt, 0, 2);
+                       disasm_std_operand(stmt, 1, 3);
+                       disasm_std_operand(stmt, 2, 4);
                        break;
                case 0x300:
                        stmt->u.insn.name = "orx";
@@ -603,9 +687,9 @@ static void disasm_opcodes(struct disassembler_context *ctx)
                        snprintf(str, 3, "%d", (bin->opcode & 0x00F));
                        stmt->u.insn.operands[1] = str;
 
-                       disasm_std_operand(stmt, 0, 2, 0);
-                       disasm_std_operand(stmt, 1, 3, 0);
-                       disasm_std_operand(stmt, 2, 4, 0);
+                       disasm_std_operand(stmt, 0, 2);
+                       disasm_std_operand(stmt, 1, 3);
+                       disasm_std_operand(stmt, 2, 4);
                        break;
                case 0x400:
                        stmt->u.insn.name = "jzx";
@@ -617,9 +701,9 @@ static void disasm_opcodes(struct disassembler_context *ctx)
                        snprintf(str, 3, "%d", (bin->opcode & 0x00F));
                        stmt->u.insn.operands[1] = str;
 
-                       disasm_std_operand(stmt, 0, 2, 0);
-                       disasm_std_operand(stmt, 1, 3, 0);
-                       stmt->u.insn.is_labelref = 4;
+                       disasm_std_operand(stmt, 0, 2);
+                       disasm_std_operand(stmt, 1, 3);
+                       stmt->u.insn.labelref_operand = 4;
                        stmt->u.insn.labeladdr = stmt->u.insn.bin->operands[2];
                        break;
                case 0x500:
@@ -632,9 +716,9 @@ static void disasm_opcodes(struct disassembler_context *ctx)
                        snprintf(str, 3, "%d", (bin->opcode & 0x00F));
                        stmt->u.insn.operands[1] = str;
 
-                       disasm_std_operand(stmt, 0, 2, 0);
-                       disasm_std_operand(stmt, 1, 3, 0);
-                       stmt->u.insn.is_labelref = 4;
+                       disasm_std_operand(stmt, 0, 2);
+                       disasm_std_operand(stmt, 1, 3);
+                       stmt->u.insn.labelref_operand = 4;
                        stmt->u.insn.labeladdr = stmt->u.insn.bin->operands[2];
                        break;
                case 0x600:
@@ -646,11 +730,11 @@ static void disasm_opcodes(struct disassembler_context *ctx)
 
                        /* We don't disassemble the first and second operand, as
                         * that always is a dummy r0 operand.
-                        * disasm_std_operand(stmt, 0, 1, 0);
-                        * disasm_std_operand(stmt, 1, 2, 0);
-                        * stmt->u.insn.is_labelref = 3;
+                        * disasm_std_operand(stmt, 0, 1);
+                        * disasm_std_operand(stmt, 1, 2);
+                        * stmt->u.insn.labelref_operand = 3;
                         */
-                       stmt->u.insn.is_labelref = 1;
+                       stmt->u.insn.labelref_operand = 1;
                        stmt->u.insn.labeladdr = stmt->u.insn.bin->operands[2];
                        break;
                case 0x700:
@@ -662,11 +746,11 @@ static void disasm_opcodes(struct disassembler_context *ctx)
 
                        /* We don't disassemble the first and second operand, as
                         * that always is a dummy r0 operand.
-                        * disasm_std_operand(stmt, 0, 1, 0);
-                        * disasm_std_operand(stmt, 1, 2, 0);
-                        * stmt->u.insn.is_labelref = 3;
+                        * disasm_std_operand(stmt, 0, 1);
+                        * disasm_std_operand(stmt, 1, 2);
+                        * stmt->u.insn.labelref_operand = 3;
                         */
-                       stmt->u.insn.is_labelref = 1;
+                       stmt->u.insn.labelref_operand = 1;
                        stmt->u.insn.labeladdr = stmt->u.insn.bin->operands[2];
                        break;
                default:
@@ -716,15 +800,12 @@ static void resolve_labels(struct disassembler_context *ctx)
        list_for_each_entry_safe(stmt, n, &ctx->stmt_list, list) {
                if (stmt->type != STMT_INSN)
                        continue;
-               if (stmt->u.insn.is_labelref == -1)
-                       continue;
+               if (stmt->u.insn.labelref_operand < 0)
+                       continue; /* Doesn't have label reference operand. */
                labeladdr = stmt->u.insn.labeladdr;
                label = get_label_at(ctx, labeladdr);
-               if (!label) {
-                       fprintf(stderr, "Labeladdress %X out of bounds\n",
-                               labeladdr);
-                       exit(1);
-               }
+               if (!label)
+                       dasm_error("Labeladdress %X out of bounds", labeladdr);
                stmt->u.insn.labelref = label;
        }
 
@@ -741,9 +822,9 @@ static void resolve_labels(struct disassembler_context *ctx)
 static void emit_asm(struct disassembler_context *ctx)
 {
        struct statement *stmt;
-       int first, i;
+       int first;
        int err;
-       unsigned int addr = 0;
+       unsigned int i, addr = 0;
 
        err = open_output_file();
        if (err)
@@ -756,23 +837,27 @@ static void emit_asm(struct disassembler_context *ctx)
                switch (stmt->type) {
                case STMT_INSN:
                        if (cmdargs.print_addresses)
-                               fprintf(outfile, "/* %03X */", addr);
+                               fprintf(outfile, "/* %04X */", addr);
                        fprintf(outfile, "\t%s", stmt->u.insn.name);
                        first = 1;
                        for (i = 0; i < ARRAY_SIZE(stmt->u.insn.operands); i++) {
-                               if (stmt->u.insn.is_labelref == i) {
-                                       fprintf(outfile, ", %s",
-                                               stmt->u.insn.labelref->u.label.name);
-                               }
-                               if (!stmt->u.insn.operands[i])
+                               if (!stmt->u.insn.operands[i] &&
+                                   (stmt->u.insn.labelref_operand < 0 ||
+                                    (unsigned int)stmt->u.insn.labelref_operand != i))
                                        continue;
                                if (first)
                                        fprintf(outfile, "\t");
                                if (!first)
                                        fprintf(outfile, ", ");
                                first = 0;
-                               fprintf(outfile, "%s",
-                                       stmt->u.insn.operands[i]);
+                               if (stmt->u.insn.labelref_operand >= 0 &&
+                                   (unsigned int)stmt->u.insn.labelref_operand == i) {
+                                       fprintf(outfile, "%s",
+                                               stmt->u.insn.labelref->u.label.name);
+                               } else {
+                                       fprintf(outfile, "%s",
+                                               stmt->u.insn.operands[i]);
+                               }
                        }
                        fprintf(outfile, "\n");
                        addr++;
@@ -792,7 +877,7 @@ static int read_input(struct disassembler_context *ctx)
        size_t ret;
        struct bin_instruction *code = NULL;
        unsigned char tmp[sizeof(uint64_t)];
-       uint64_t codeword;
+       uint64_t codeword = 0;
        struct fw_header hdr;
        int err;
 
@@ -808,11 +893,11 @@ static int read_input(struct disassembler_context *ctx)
        case FMT_B43:
                ret = fread(&hdr, 1, sizeof(hdr), infile);
                if (ret != sizeof(hdr)) {
-                       fprintf(stderr, "Corrupt input file (not fwcutter output)\n");
+                       fprintf(stderr, "Corrupt input file (no b43 header found)\n");
                        goto err_close;
                }
                if (hdr.type != FW_TYPE_UCODE) {
-                       fprintf(stderr, "Corrupt input file. Not a microcode image.\n");
+                       fprintf(stderr, "Corrupt input file. Not a b43 microcode image.\n");
                        goto err_close;
                }
                if (hdr.ver != FW_HDR_VER) {