Permalink
Switch branches/tags
Nothing to show
Find file Copy path
Fetching contributors…
Cannot retrieve contributors at this time
1526 lines (1350 sloc) 37.1 KB

Mipsgen C code generator

The mipsgen C code generator generates the core routines for a C-based MIPS disassembler. The code for that disassembler is located in c_disasm/mipsdis.c.

The bulk of the work done by the code generator is generating dispatch and decoder functions.

An example of a generated dispatch function:

void decode_OPCODE(MipsEmu* emu, uint32_t op)
{
    switch (getopcode(op))
    {
        case 0:
            decode_SPC1(emu, op);
            break;
        case 1:
            decode_R(emu, op);
            break;
        case 2:
            decode_j(emu, op);
            break;
        case 3:
            decode_jal(emu, op);
            break;

    // ...
    }
}

An example of a generated decoder:

static void decode_jal(MipsEmu* emu, uint32_t op)
{
    if (!(check_opcode(op, 0xfc000000, 0x0c000000)))
    {
        decode_illegal(outbuf, n, pc, op);
        return;
    }

    snprintf(output,n,"jal 0x%x",gettarget(pc,op));
}

The generated code expects the host code to implement the following utility routines:

// error checking routines:

static int check_opcode(uint32_t op, uint32_t mask, uint32_t value);
static int check_cl(uint32_t rt, uint32_t rd);
static int check_jalr(uint32_t rs, uint32_t rd);

// exception handling routines:

static void decode_illegal(char* outbuf, size_t n, uint32_t addr, 
  uint32_t opcode);

static void decode_reserved(char* outbuf, size_t n, uint32_t addr, 
  uint32_t opcode);

// packed field extraction routines:

static uint32_t getopcode(uint32_t op);
static uint32_t getfunction(uint32_t op);
static uint32_t getrt(uint32_t op);
static uint32_t getrs(uint32_t op);
static uint32_t getrd(uint32_t op);
static uint32_t gettarget(uint32_t pc, uint32_t op);
static uint32_t getbroff(uint32_t pc, uint32_t op);
static int32_t getsimm(uint32_t op);
static uint32_t getimm(uint32_t op);
static int32_t getoffset(uint32_t op);
static uint32_t getbase(uint32_t op);
static uint32_t getcacheop(uint32_t op);
static uint32_t getprefhint(uint32_t op);
static uint32_t getsa(uint32_t op);
static uint32_t getsyscode(uint32_t op);
static uint32_t getstype(uint32_t op);
static uint32_t gettrapcode(uint32_t op);
static uint32_t getsel(uint32_t op);
static uint32_t getwaitcode(uint32_t op);

A full copy of the generated C code is included below, so that people browsing the project, or having trouble with the autogen can see what it looks like.

/*
 * This file contains autogenerated routines for dispatching and disassembling
 * MIPS opcodes.
 *
 * The code has been generated by mipsgen.
 *
 * See scripts/mipsgen.rb for the code generator framework.
 * See codegen/cgen.rb for C specific information.
 */

static void decode_j(char *outbuf, size_t n, uint32_t pc, uint32_t op)
{
    snprintf(outbuf,n,"j 0x%x",gettarget(pc,op));
}

static void decode_jal(char *outbuf, size_t n, uint32_t pc, uint32_t op)
{
    snprintf(outbuf,n,"jal 0x%x",gettarget(pc,op));
}

static void decode_beq(char *outbuf, size_t n, uint32_t pc, uint32_t op)
{
    snprintf(outbuf,n,"beq $%d,$%d,0x%x",getrs(op),getrt(op),getbroff(pc,op));
}

static void decode_bne(char *outbuf, size_t n, uint32_t pc, uint32_t op)
{
    snprintf(outbuf,n,"bne $%d,$%d,0x%x",getrs(op),getrt(op),getbroff(pc,op));
}

static void decode_blez(char *outbuf, size_t n, uint32_t pc, uint32_t op)
{
    if (!(check_opcode(op, 0xfc1f0000, 0x18000000)))
    {
        decode_illegal(outbuf, n, pc, op);
        return;
    }

    snprintf(outbuf,n,"blez $%d,0x%x",getrs(op),getbroff(pc,op));
}

static void decode_bgtz(char *outbuf, size_t n, uint32_t pc, uint32_t op)
{
    if (!(check_opcode(op, 0xfc1f0000, 0x1c000000)))
    {
        decode_illegal(outbuf, n, pc, op);
        return;
    }

    snprintf(outbuf,n,"bgtz $%d,0x%x",getrs(op),getbroff(pc,op));
}

static void decode_addi(char *outbuf, size_t n, uint32_t pc, uint32_t op)
{
    snprintf(outbuf,n,"addi $%d,$%d,%d",getrt(op),getrs(op),getsimm(op));
}

static void decode_addiu(char *outbuf, size_t n, uint32_t pc, uint32_t op)
{
    snprintf(outbuf,n,"addiu $%d,$%d,%d",getrt(op),getrs(op),getsimm(op));
}

static void decode_slti(char *outbuf, size_t n, uint32_t pc, uint32_t op)
{
    snprintf(outbuf,n,"slti $%d,$%d,%d",getrt(op),getrs(op),getsimm(op));
}

static void decode_sltiu(char *outbuf, size_t n, uint32_t pc, uint32_t op)
{
    snprintf(outbuf,n,"sltiu $%d,$%d,%d",getrt(op),getrs(op),getsimm(op));
}

static void decode_andi(char *outbuf, size_t n, uint32_t pc, uint32_t op)
{
    snprintf(outbuf,n,"andi $%d,$%d,0x%x",getrt(op),getrs(op),getimm(op));
}

static void decode_ori(char *outbuf, size_t n, uint32_t pc, uint32_t op)
{
    snprintf(outbuf,n,"ori $%d,$%d,0x%x",getrt(op),getrs(op),getimm(op));
}

static void decode_xori(char *outbuf, size_t n, uint32_t pc, uint32_t op)
{
    snprintf(outbuf,n,"xori $%d,$%d,0x%x",getrt(op),getrs(op),getimm(op));
}

static void decode_lui(char *outbuf, size_t n, uint32_t pc, uint32_t op)
{
    if (!(check_opcode(op, 0xffe00000, 0x3c000000)))
    {
        decode_illegal(outbuf, n, pc, op);
        return;
    }

    snprintf(outbuf,n,"lui $%d,0x%x",getrt(op),getimm(op));
}

static void decode_beql(char *outbuf, size_t n, uint32_t pc, uint32_t op)
{
    snprintf(outbuf,n,"beql $%d,$%d,0x%x",getrs(op),getrt(op),getbroff(pc,op));
}

static void decode_bnel(char *outbuf, size_t n, uint32_t pc, uint32_t op)
{
    snprintf(outbuf,n,"bnel $%d,$%d,0x%x",getrs(op),getrt(op),getbroff(pc,op));
}

static void decode_blezl(char *outbuf, size_t n, uint32_t pc, uint32_t op)
{
    if (!(check_opcode(op, 0xfc1f0000, 0x58000000)))
    {
        decode_illegal(outbuf, n, pc, op);
        return;
    }

    snprintf(outbuf,n,"blezl $%d,0x%x",getrs(op),getbroff(pc,op));
}

static void decode_bgtzl(char *outbuf, size_t n, uint32_t pc, uint32_t op)
{
    if (!(check_opcode(op, 0xfc1f0000, 0x5c000000)))
    {
        decode_illegal(outbuf, n, pc, op);
        return;
    }

    snprintf(outbuf,n,"bgtzl $%d,0x%x",getrs(op),getbroff(pc,op));
}

static void decode_lb(char *outbuf, size_t n, uint32_t pc, uint32_t op)
{
    snprintf(outbuf,n,"lb $%d,%d($%d)",getrt(op),getoffset(op),getbase(op));
}

static void decode_lh(char *outbuf, size_t n, uint32_t pc, uint32_t op)
{
    snprintf(outbuf,n,"lh $%d,%d($%d)",getrt(op),getoffset(op),getbase(op));
}

static void decode_lwl(char *outbuf, size_t n, uint32_t pc, uint32_t op)
{
    snprintf(outbuf,n,"lwl $%d,%d($%d)",getrt(op),getoffset(op),getbase(op));
}

static void decode_lw(char *outbuf, size_t n, uint32_t pc, uint32_t op)
{
    snprintf(outbuf,n,"lw $%d,%d($%d)",getrt(op),getoffset(op),getbase(op));
}

static void decode_lbu(char *outbuf, size_t n, uint32_t pc, uint32_t op)
{
    snprintf(outbuf,n,"lbu $%d,%d($%d)",getrt(op),getoffset(op),getbase(op));
}

static void decode_lhu(char *outbuf, size_t n, uint32_t pc, uint32_t op)
{
    snprintf(outbuf,n,"lhu $%d,%d($%d)",getrt(op),getoffset(op),getbase(op));
}

static void decode_lwr(char *outbuf, size_t n, uint32_t pc, uint32_t op)
{
    snprintf(outbuf,n,"lwr $%d,%d($%d)",getrt(op),getoffset(op),getbase(op));
}

static void decode_sb(char *outbuf, size_t n, uint32_t pc, uint32_t op)
{
    snprintf(outbuf,n,"sb $%d,%d($%d)",getrt(op),getoffset(op),getbase(op));
}

static void decode_sh(char *outbuf, size_t n, uint32_t pc, uint32_t op)
{
    snprintf(outbuf,n,"sh $%d,%d($%d)",getrt(op),getoffset(op),getbase(op));
}

static void decode_swl(char *outbuf, size_t n, uint32_t pc, uint32_t op)
{
    snprintf(outbuf,n,"swl $%d,%d($%d)",getrt(op),getoffset(op),getbase(op));
}

static void decode_sw(char *outbuf, size_t n, uint32_t pc, uint32_t op)
{
    snprintf(outbuf,n,"sw $%d,%d($%d)",getrt(op),getoffset(op),getbase(op));
}

static void decode_swr(char *outbuf, size_t n, uint32_t pc, uint32_t op)
{
    snprintf(outbuf,n,"swr $%d,%d($%d)",getrt(op),getoffset(op),getbase(op));
}

static void decode_cache(char *outbuf, size_t n, uint32_t pc, uint32_t op)
{
    snprintf(outbuf,n,"cache 0x%x,%d($%d)",getcacheop(op),getoffset(op),getbase(op));
}

static void decode_ll(char *outbuf, size_t n, uint32_t pc, uint32_t op)
{
    snprintf(outbuf,n,"ll $%d,%d($%d)",getrt(op),getoffset(op),getbase(op));
}

static void decode_pref(char *outbuf, size_t n, uint32_t pc, uint32_t op)
{
    snprintf(outbuf,n,"pref 0x%x,%d($%d)",getprefhint(op),getoffset(op),getbase(op));
}

static void decode_sc(char *outbuf, size_t n, uint32_t pc, uint32_t op)
{
    snprintf(outbuf,n,"sc $%d,%d($%d)",getrt(op),getoffset(op),getbase(op));
}

static void decode_sll(char *outbuf, size_t n, uint32_t pc, uint32_t op)
{
    if (!(check_opcode(op, 0xffe0003f, 0x00000000)))
    {
        decode_illegal(outbuf, n, pc, op);
        return;
    }

    snprintf(outbuf,n,"sll $%d,$%d,0x%x",getrd(op),getrt(op),getsa(op));
}

static void decode_srl(char *outbuf, size_t n, uint32_t pc, uint32_t op)
{
    if (!(check_opcode(op, 0xffe0003f, 0x00000002)))
    {
        decode_illegal(outbuf, n, pc, op);
        return;
    }

    snprintf(outbuf,n,"srl $%d,$%d,0x%x",getrd(op),getrt(op),getsa(op));
}

static void decode_sra(char *outbuf, size_t n, uint32_t pc, uint32_t op)
{
    if (!(check_opcode(op, 0xffe0003f, 0x00000003)))
    {
        decode_illegal(outbuf, n, pc, op);
        return;
    }

    snprintf(outbuf,n,"sra $%d,$%d,0x%x",getrd(op),getrt(op),getsa(op));
}

static void decode_sllv(char *outbuf, size_t n, uint32_t pc, uint32_t op)
{
    if (!(check_opcode(op, 0xfc0007ff, 0x00000004)))
    {
        decode_illegal(outbuf, n, pc, op);
        return;
    }

    snprintf(outbuf,n,"sllv $%d,$%d,$%d",getrd(op),getrt(op),getrs(op));
}

static void decode_srlv(char *outbuf, size_t n, uint32_t pc, uint32_t op)
{
    if (!(check_opcode(op, 0xfc0007ff, 0x00000006)))
    {
        decode_illegal(outbuf, n, pc, op);
        return;
    }

    snprintf(outbuf,n,"srlv $%d,$%d,$%d",getrd(op),getrt(op),getrs(op));
}

static void decode_srav(char *outbuf, size_t n, uint32_t pc, uint32_t op)
{
    if (!(check_opcode(op, 0xfc0007ff, 0x00000007)))
    {
        decode_illegal(outbuf, n, pc, op);
        return;
    }

    snprintf(outbuf,n,"srav $%d,$%d,$%d",getrd(op),getrt(op),getrs(op));
}

static void decode_jr(char *outbuf, size_t n, uint32_t pc, uint32_t op)
{
    if (!(check_opcode(op, 0xfc1fffff, 0x00000008)))
    {
        decode_illegal(outbuf, n, pc, op);
        return;
    }

    snprintf(outbuf,n,"jr $%d",getrs(op));
}

static void decode_jalr(char *outbuf, size_t n, uint32_t pc, uint32_t op)
{
    if (!(check_opcode(op, 0xfc1f07ff, 0x00000009)&&check_jalr(getrs(op), getrd(op))))
    {
        decode_illegal(outbuf, n, pc, op);
        return;
    }

    snprintf(outbuf,n,"jalr $%d,$%d",getrd(op),getrs(op));
}

static void decode_movz(char *outbuf, size_t n, uint32_t pc, uint32_t op)
{
    if (!(check_opcode(op, 0xfc0007ff, 0x0000000a)))
    {
        decode_illegal(outbuf, n, pc, op);
        return;
    }

    snprintf(outbuf,n,"movz $%d,$%d,$%d",getrd(op),getrs(op),getrt(op));
}

static void decode_movn(char *outbuf, size_t n, uint32_t pc, uint32_t op)
{
    if (!(check_opcode(op, 0xfc0007ff, 0x0000000b)))
    {
        decode_illegal(outbuf, n, pc, op);
        return;
    }

    snprintf(outbuf,n,"movn $%d,$%d,$%d",getrd(op),getrs(op),getrt(op));
}

static void decode_syscall(char *outbuf, size_t n, uint32_t pc, uint32_t op)
{
    snprintf(outbuf,n,"syscall 0x%x",getsyscode(op));
}

static void decode_break(char *outbuf, size_t n, uint32_t pc, uint32_t op)
{
    snprintf(outbuf,n,"break 0x%x,0x%x",getbc1(op),getbc2(op));
}

static void decode_sync(char *outbuf, size_t n, uint32_t pc, uint32_t op)
{
    if (!(check_opcode(op, 0xfffff83f, 0x0000000f)))
    {
        decode_illegal(outbuf, n, pc, op);
        return;
    }

    snprintf(outbuf,n,"sync 0x%x",getstype(op));
}

static void decode_mfhi(char *outbuf, size_t n, uint32_t pc, uint32_t op)
{
    if (!(check_opcode(op, 0xffff07ff, 0x00000010)))
    {
        decode_illegal(outbuf, n, pc, op);
        return;
    }

    snprintf(outbuf,n,"mfhi $%d",getrd(op));
}

static void decode_mthi(char *outbuf, size_t n, uint32_t pc, uint32_t op)
{
    if (!(check_opcode(op, 0xfc1fffff, 0x00000011)))
    {
        decode_illegal(outbuf, n, pc, op);
        return;
    }

    snprintf(outbuf,n,"mthi $%d",getrs(op));
}

static void decode_mflo(char *outbuf, size_t n, uint32_t pc, uint32_t op)
{
    if (!(check_opcode(op, 0xffff07ff, 0x00000012)))
    {
        decode_illegal(outbuf, n, pc, op);
        return;
    }

    snprintf(outbuf,n,"mflo $%d",getrd(op));
}

static void decode_mtlo(char *outbuf, size_t n, uint32_t pc, uint32_t op)
{
    if (!(check_opcode(op, 0xfc1fffff, 0x00000013)))
    {
        decode_illegal(outbuf, n, pc, op);
        return;
    }

    snprintf(outbuf,n,"mtlo $%d",getrs(op));
}

static void decode_mult(char *outbuf, size_t n, uint32_t pc, uint32_t op)
{
    if (!(check_opcode(op, 0xfc00ffff, 0x00000018)))
    {
        decode_illegal(outbuf, n, pc, op);
        return;
    }

    snprintf(outbuf,n,"mult $%d,$%d",getrs(op),getrt(op));
}

static void decode_multu(char *outbuf, size_t n, uint32_t pc, uint32_t op)
{
    if (!(check_opcode(op, 0xfc00ffff, 0x00000019)))
    {
        decode_illegal(outbuf, n, pc, op);
        return;
    }

    snprintf(outbuf,n,"multu $%d,$%d",getrs(op),getrt(op));
}

static void decode_div(char *outbuf, size_t n, uint32_t pc, uint32_t op)
{
    if (!(check_opcode(op, 0xfc00ffff, 0x0000001a)))
    {
        decode_illegal(outbuf, n, pc, op);
        return;
    }

    snprintf(outbuf,n,"div $%d,$%d",getrs(op),getrt(op));
}

static void decode_divu(char *outbuf, size_t n, uint32_t pc, uint32_t op)
{
    if (!(check_opcode(op, 0xfc00ffff, 0x0000001b)))
    {
        decode_illegal(outbuf, n, pc, op);
        return;
    }

    snprintf(outbuf,n,"divu $%d,$%d",getrs(op),getrt(op));
}

static void decode_add(char *outbuf, size_t n, uint32_t pc, uint32_t op)
{
    if (!(check_opcode(op, 0xfc0007ff, 0x00000020)))
    {
        decode_illegal(outbuf, n, pc, op);
        return;
    }

    snprintf(outbuf,n,"add $%d,$%d,$%d",getrd(op),getrs(op),getrt(op));
}

static void decode_addu(char *outbuf, size_t n, uint32_t pc, uint32_t op)
{
    if (!(check_opcode(op, 0xfc0007ff, 0x00000021)))
    {
        decode_illegal(outbuf, n, pc, op);
        return;
    }

    snprintf(outbuf,n,"addu $%d,$%d,$%d",getrd(op),getrs(op),getrt(op));
}

static void decode_sub(char *outbuf, size_t n, uint32_t pc, uint32_t op)
{
    if (!(check_opcode(op, 0xfc0007ff, 0x00000022)))
    {
        decode_illegal(outbuf, n, pc, op);
        return;
    }

    snprintf(outbuf,n,"sub $%d,$%d,$%d",getrd(op),getrs(op),getrt(op));
}

static void decode_subu(char *outbuf, size_t n, uint32_t pc, uint32_t op)
{
    if (!(check_opcode(op, 0xfc0007ff, 0x00000023)))
    {
        decode_illegal(outbuf, n, pc, op);
        return;
    }

    snprintf(outbuf,n,"subu $%d,$%d,$%d",getrd(op),getrs(op),getrt(op));
}

static void decode_and(char *outbuf, size_t n, uint32_t pc, uint32_t op)
{
    if (!(check_opcode(op, 0xfc0007ff, 0x00000024)))
    {
        decode_illegal(outbuf, n, pc, op);
        return;
    }

    snprintf(outbuf,n,"and $%d,$%d,$%d",getrd(op),getrs(op),getrt(op));
}

static void decode_or(char *outbuf, size_t n, uint32_t pc, uint32_t op)
{
    if (!(check_opcode(op, 0xfc0007ff, 0x00000025)))
    {
        decode_illegal(outbuf, n, pc, op);
        return;
    }

    snprintf(outbuf,n,"or $%d,$%d,$%d",getrd(op),getrs(op),getrt(op));
}

static void decode_xor(char *outbuf, size_t n, uint32_t pc, uint32_t op)
{
    if (!(check_opcode(op, 0xfc0007ff, 0x00000026)))
    {
        decode_illegal(outbuf, n, pc, op);
        return;
    }

    snprintf(outbuf,n,"xor $%d,$%d,$%d",getrd(op),getrs(op),getrt(op));
}

static void decode_nor(char *outbuf, size_t n, uint32_t pc, uint32_t op)
{
    if (!(check_opcode(op, 0xfc0007ff, 0x00000027)))
    {
        decode_illegal(outbuf, n, pc, op);
        return;
    }

    snprintf(outbuf,n,"nor $%d,$%d,$%d",getrd(op),getrs(op),getrt(op));
}

static void decode_slt(char *outbuf, size_t n, uint32_t pc, uint32_t op)
{
    if (!(check_opcode(op, 0xfc0007ff, 0x0000002a)))
    {
        decode_illegal(outbuf, n, pc, op);
        return;
    }

    snprintf(outbuf,n,"slt $%d,$%d,$%d",getrd(op),getrs(op),getrt(op));
}

static void decode_sltu(char *outbuf, size_t n, uint32_t pc, uint32_t op)
{
    if (!(check_opcode(op, 0xfc0007ff, 0x0000002b)))
    {
        decode_illegal(outbuf, n, pc, op);
        return;
    }

    snprintf(outbuf,n,"sltu $%d,$%d,$%d",getrd(op),getrs(op),getrt(op));
}

static void decode_tge(char *outbuf, size_t n, uint32_t pc, uint32_t op)
{
    snprintf(outbuf,n,"tge $%d,$%d,0x%x",getrs(op),getrt(op),gettrapcode(op));
}

static void decode_tgeu(char *outbuf, size_t n, uint32_t pc, uint32_t op)
{
    snprintf(outbuf,n,"tgeu $%d,$%d,0x%x",getrs(op),getrt(op),gettrapcode(op));
}

static void decode_tlt(char *outbuf, size_t n, uint32_t pc, uint32_t op)
{
    snprintf(outbuf,n,"tlt $%d,$%d,0x%x",getrs(op),getrt(op),gettrapcode(op));
}

static void decode_tltu(char *outbuf, size_t n, uint32_t pc, uint32_t op)
{
    snprintf(outbuf,n,"tltu $%d,$%d,0x%x",getrs(op),getrt(op),gettrapcode(op));
}

static void decode_teq(char *outbuf, size_t n, uint32_t pc, uint32_t op)
{
    snprintf(outbuf,n,"teq $%d,$%d,0x%x",getrs(op),getrt(op),gettrapcode(op));
}

static void decode_tne(char *outbuf, size_t n, uint32_t pc, uint32_t op)
{
    snprintf(outbuf,n,"tne $%d,$%d,0x%x",getrs(op),getrt(op),gettrapcode(op));
}

static void decode_madd(char *outbuf, size_t n, uint32_t pc, uint32_t op)
{
    if (!(check_opcode(op, 0xfc00ffff, 0x70000000)))
    {
        decode_illegal(outbuf, n, pc, op);
        return;
    }

    snprintf(outbuf,n,"madd $%d,$%d",getrs(op),getrt(op));
}

static void decode_maddu(char *outbuf, size_t n, uint32_t pc, uint32_t op)
{
    if (!(check_opcode(op, 0xfc00ffff, 0x70000001)))
    {
        decode_illegal(outbuf, n, pc, op);
        return;
    }

    snprintf(outbuf,n,"maddu $%d,$%d",getrs(op),getrt(op));
}

static void decode_mul(char *outbuf, size_t n, uint32_t pc, uint32_t op)
{
    if (!(check_opcode(op, 0xfc0007ff, 0x70000002)))
    {
        decode_illegal(outbuf, n, pc, op);
        return;
    }

    snprintf(outbuf,n,"mul $%d,$%d,$%d",getrd(op),getrs(op),getrt(op));
}

static void decode_msub(char *outbuf, size_t n, uint32_t pc, uint32_t op)
{
    if (!(check_opcode(op, 0xfc00ffff, 0x70000004)))
    {
        decode_illegal(outbuf, n, pc, op);
        return;
    }

    snprintf(outbuf,n,"msub $%d,$%d",getrs(op),getrt(op));
}

static void decode_msubu(char *outbuf, size_t n, uint32_t pc, uint32_t op)
{
    if (!(check_opcode(op, 0xfc00ffff, 0x70000005)))
    {
        decode_illegal(outbuf, n, pc, op);
        return;
    }

    snprintf(outbuf,n,"msubu $%d,$%d",getrs(op),getrt(op));
}

static void decode_clz(char *outbuf, size_t n, uint32_t pc, uint32_t op)
{
    if (!(check_opcode(op, 0xfc0007ff, 0x70000020)&&check_cl(getrt(op), getrd(op))))
    {
        decode_illegal(outbuf, n, pc, op);
        return;
    }

    snprintf(outbuf,n,"clz $%d,$%d",getrd(op),getrs(op));
}

static void decode_clo(char *outbuf, size_t n, uint32_t pc, uint32_t op)
{
    if (!(check_opcode(op, 0xfc0007ff, 0x70000021)&&check_cl(getrt(op), getrd(op))))
    {
        decode_illegal(outbuf, n, pc, op);
        return;
    }

    snprintf(outbuf,n,"clo $%d,$%d",getrd(op),getrs(op));
}

static void decode_sdbbp(char *outbuf, size_t n, uint32_t pc, uint32_t op)
{
    snprintf(outbuf,n,"sdbbp 0x%x",getsyscode(op));
}

static void decode_bltz(char *outbuf, size_t n, uint32_t pc, uint32_t op)
{
    snprintf(outbuf,n,"bltz $%d,0x%x",getrs(op),getbroff(pc,op));
}

static void decode_bgez(char *outbuf, size_t n, uint32_t pc, uint32_t op)
{
    snprintf(outbuf,n,"bgez $%d,0x%x",getrs(op),getbroff(pc,op));
}

static void decode_bltzl(char *outbuf, size_t n, uint32_t pc, uint32_t op)
{
    snprintf(outbuf,n,"bltzl $%d,0x%x",getrs(op),getbroff(pc,op));
}

static void decode_bgezl(char *outbuf, size_t n, uint32_t pc, uint32_t op)
{
    snprintf(outbuf,n,"bgezl $%d,0x%x",getrs(op),getbroff(pc,op));
}

static void decode_tgei(char *outbuf, size_t n, uint32_t pc, uint32_t op)
{
    snprintf(outbuf,n,"tgei $%d,%d",getrs(op),getsimm(op));
}

static void decode_tgeiu(char *outbuf, size_t n, uint32_t pc, uint32_t op)
{
    snprintf(outbuf,n,"tgeiu $%d,%d",getrs(op),getsimm(op));
}

static void decode_tlti(char *outbuf, size_t n, uint32_t pc, uint32_t op)
{
    snprintf(outbuf,n,"tlti $%d,%d",getrs(op),getsimm(op));
}

static void decode_tltiu(char *outbuf, size_t n, uint32_t pc, uint32_t op)
{
    snprintf(outbuf,n,"tltiu $%d,%d",getrs(op),getsimm(op));
}

static void decode_teqi(char *outbuf, size_t n, uint32_t pc, uint32_t op)
{
    snprintf(outbuf,n,"teqi $%d,%d",getrs(op),getsimm(op));
}

static void decode_tnei(char *outbuf, size_t n, uint32_t pc, uint32_t op)
{
    snprintf(outbuf,n,"tnei $%d,%d",getrs(op),getsimm(op));
}

static void decode_bltzal(char *outbuf, size_t n, uint32_t pc, uint32_t op)
{
    snprintf(outbuf,n,"bltzal $%d,0x%x",getrs(op),getbroff(pc,op));
}

static void decode_bgezal(char *outbuf, size_t n, uint32_t pc, uint32_t op)
{
    snprintf(outbuf,n,"bgezal $%d,0x%x",getrs(op),getbroff(pc,op));
}

static void decode_bltzall(char *outbuf, size_t n, uint32_t pc, uint32_t op)
{
    snprintf(outbuf,n,"bltzall $%d,0x%x",getrs(op),getbroff(pc,op));
}

static void decode_bgezall(char *outbuf, size_t n, uint32_t pc, uint32_t op)
{
    snprintf(outbuf,n,"bgezall $%d,0x%x",getrs(op),getbroff(pc,op));
}

static void decode_mfc0(char *outbuf, size_t n, uint32_t pc, uint32_t op)
{
    if (!(check_opcode(op, 0xffe007f8, 0x40000000)))
    {
        decode_illegal(outbuf, n, pc, op);
        return;
    }

    snprintf(outbuf,n,"mfc0 $%d,$%d,%d",getrt(op),getrd(op),getsel(op));
}

static void decode_mtc0(char *outbuf, size_t n, uint32_t pc, uint32_t op)
{
    if (!(check_opcode(op, 0xffe007f8, 0x40800000)))
    {
        decode_illegal(outbuf, n, pc, op);
        return;
    }

    snprintf(outbuf,n,"mtc0 $%d,$%d,%d",getrt(op),getrd(op),getsel(op));
}

static void decode_tlbr(char *outbuf, size_t n, uint32_t pc, uint32_t op)
{
    if (!(check_opcode(op, 0xffffffff, 0x42000001)))
    {
        decode_illegal(outbuf, n, pc, op);
        return;
    }

    snprintf(outbuf,n,"tlbr");
}

static void decode_tlbwi(char *outbuf, size_t n, uint32_t pc, uint32_t op)
{
    if (!(check_opcode(op, 0xffffffff, 0x42000002)))
    {
        decode_illegal(outbuf, n, pc, op);
        return;
    }

    snprintf(outbuf,n,"tlbwi");
}

static void decode_tlbwr(char *outbuf, size_t n, uint32_t pc, uint32_t op)
{
    if (!(check_opcode(op, 0xffffffff, 0x42000006)))
    {
        decode_illegal(outbuf, n, pc, op);
        return;
    }

    snprintf(outbuf,n,"tlbwr");
}

static void decode_tlbp(char *outbuf, size_t n, uint32_t pc, uint32_t op)
{
    if (!(check_opcode(op, 0xffffffff, 0x42000008)))
    {
        decode_illegal(outbuf, n, pc, op);
        return;
    }

    snprintf(outbuf,n,"tlbp");
}

static void decode_eret(char *outbuf, size_t n, uint32_t pc, uint32_t op)
{
    if (!(check_opcode(op, 0xffffffff, 0x42000018)))
    {
        decode_illegal(outbuf, n, pc, op);
        return;
    }

    snprintf(outbuf,n,"eret");
}

static void decode_deret(char *outbuf, size_t n, uint32_t pc, uint32_t op)
{
    if (!(check_opcode(op, 0xffffffff, 0x4200001f)))
    {
        decode_illegal(outbuf, n, pc, op);
        return;
    }

    snprintf(outbuf,n,"deret");
}

static void decode_wait(char *outbuf, size_t n, uint32_t pc, uint32_t op)
{
    snprintf(outbuf,n,"wait 0x%x",getwaitcode(op));
}

static void decode_OPCODE(char *outbuf, size_t n, uint32_t pc, uint32_t op);
static void decode_SPC1(char *outbuf, size_t n, uint32_t pc, uint32_t op);
static void decode_SPC2(char *outbuf, size_t n, uint32_t pc, uint32_t op);
static void decode_R(char *outbuf, size_t n, uint32_t pc, uint32_t op);
static void decode_COP0(char *outbuf, size_t n, uint32_t pc, uint32_t op);
static void decode_CO(char *outbuf, size_t n, uint32_t pc, uint32_t op);
static void decode_OPCODE(char *outbuf, size_t n, uint32_t pc, uint32_t op)
{
    switch (getopcode(op))
    {
        case 0:
            decode_SPC1(outbuf, n, pc, op);
            break;
        case 1:
            decode_R(outbuf, n, pc, op);
            break;
        case 2:
            decode_j(outbuf, n, pc, op);
            break;
        case 3:
            decode_jal(outbuf, n, pc, op);
            break;
        case 4:
            decode_beq(outbuf, n, pc, op);
            break;
        case 5:
            decode_bne(outbuf, n, pc, op);
            break;
        case 6:
            decode_blez(outbuf, n, pc, op);
            break;
        case 7:
            decode_bgtz(outbuf, n, pc, op);
            break;
        case 8:
            decode_addi(outbuf, n, pc, op);
            break;
        case 9:
            decode_addiu(outbuf, n, pc, op);
            break;
        case 10:
            decode_slti(outbuf, n, pc, op);
            break;
        case 11:
            decode_sltiu(outbuf, n, pc, op);
            break;
        case 12:
            decode_andi(outbuf, n, pc, op);
            break;
        case 13:
            decode_ori(outbuf, n, pc, op);
            break;
        case 14:
            decode_xori(outbuf, n, pc, op);
            break;
        case 15:
            decode_lui(outbuf, n, pc, op);
            break;
        case 16:
            decode_COP0(outbuf, n, pc, op);
            break;
        case 17:
        case 18:
        case 19:
        case 49:
        case 50:
        case 53:
        case 54:
        case 57:
        case 58:
        case 61:
        case 62:
            decode_unusable(outbuf, n, pc, op);
            break;
        case 20:
            decode_beql(outbuf, n, pc, op);
            break;
        case 21:
            decode_bnel(outbuf, n, pc, op);
            break;
        case 22:
            decode_blezl(outbuf, n, pc, op);
            break;
        case 23:
            decode_bgtzl(outbuf, n, pc, op);
            break;
        case 24:
        case 25:
        case 26:
        case 27:
        case 29:
        case 30:
        case 31:
        case 39:
        case 44:
        case 45:
        case 52:
        case 55:
        case 59:
        case 60:
        case 63:
            decode_reserved(outbuf, n, pc, op);
            break;
        case 28:
            decode_SPC2(outbuf, n, pc, op);
            break;
        case 32:
            decode_lb(outbuf, n, pc, op);
            break;
        case 33:
            decode_lh(outbuf, n, pc, op);
            break;
        case 34:
            decode_lwl(outbuf, n, pc, op);
            break;
        case 35:
            decode_lw(outbuf, n, pc, op);
            break;
        case 36:
            decode_lbu(outbuf, n, pc, op);
            break;
        case 37:
            decode_lhu(outbuf, n, pc, op);
            break;
        case 38:
            decode_lwr(outbuf, n, pc, op);
            break;
        case 40:
            decode_sb(outbuf, n, pc, op);
            break;
        case 41:
            decode_sh(outbuf, n, pc, op);
            break;
        case 42:
            decode_swl(outbuf, n, pc, op);
            break;
        case 43:
            decode_sw(outbuf, n, pc, op);
            break;
        case 46:
            decode_swr(outbuf, n, pc, op);
            break;
        case 47:
            decode_cache(outbuf, n, pc, op);
            break;
        case 48:
            decode_ll(outbuf, n, pc, op);
            break;
        case 51:
            decode_pref(outbuf, n, pc, op);
            break;
        case 56:
            decode_sc(outbuf, n, pc, op);
            break;
        default:
            /* unreachable */
            abort();
    }
}

static void decode_SPC1(char *outbuf, size_t n, uint32_t pc, uint32_t op)
{
    switch (getfunction(op))
    {
        case 0:
            decode_sll(outbuf, n, pc, op);
            break;
        case 1:
            decode_unusable(outbuf, n, pc, op);
            break;
        case 2:
            decode_srl(outbuf, n, pc, op);
            break;
        case 3:
            decode_sra(outbuf, n, pc, op);
            break;
        case 4:
            decode_sllv(outbuf, n, pc, op);
            break;
        case 5:
        case 14:
        case 20:
        case 21:
        case 22:
        case 23:
        case 28:
        case 29:
        case 30:
        case 31:
        case 40:
        case 41:
        case 44:
        case 45:
        case 46:
        case 47:
        case 53:
        case 55:
        case 56:
        case 57:
        case 58:
        case 59:
        case 60:
        case 61:
        case 62:
        case 63:
            decode_reserved(outbuf, n, pc, op);
            break;
        case 6:
            decode_srlv(outbuf, n, pc, op);
            break;
        case 7:
            decode_srav(outbuf, n, pc, op);
            break;
        case 8:
            decode_jr(outbuf, n, pc, op);
            break;
        case 9:
            decode_jalr(outbuf, n, pc, op);
            break;
        case 10:
            decode_movz(outbuf, n, pc, op);
            break;
        case 11:
            decode_movn(outbuf, n, pc, op);
            break;
        case 12:
            decode_syscall(outbuf, n, pc, op);
            break;
        case 13:
            decode_break(outbuf, n, pc, op);
            break;
        case 15:
            decode_sync(outbuf, n, pc, op);
            break;
        case 16:
            decode_mfhi(outbuf, n, pc, op);
            break;
        case 17:
            decode_mthi(outbuf, n, pc, op);
            break;
        case 18:
            decode_mflo(outbuf, n, pc, op);
            break;
        case 19:
            decode_mtlo(outbuf, n, pc, op);
            break;
        case 24:
            decode_mult(outbuf, n, pc, op);
            break;
        case 25:
            decode_multu(outbuf, n, pc, op);
            break;
        case 26:
            decode_div(outbuf, n, pc, op);
            break;
        case 27:
            decode_divu(outbuf, n, pc, op);
            break;
        case 32:
            decode_add(outbuf, n, pc, op);
            break;
        case 33:
            decode_addu(outbuf, n, pc, op);
            break;
        case 34:
            decode_sub(outbuf, n, pc, op);
            break;
        case 35:
            decode_subu(outbuf, n, pc, op);
            break;
        case 36:
            decode_and(outbuf, n, pc, op);
            break;
        case 37:
            decode_or(outbuf, n, pc, op);
            break;
        case 38:
            decode_xor(outbuf, n, pc, op);
            break;
        case 39:
            decode_nor(outbuf, n, pc, op);
            break;
        case 42:
            decode_slt(outbuf, n, pc, op);
            break;
        case 43:
            decode_sltu(outbuf, n, pc, op);
            break;
        case 48:
            decode_tge(outbuf, n, pc, op);
            break;
        case 49:
            decode_tgeu(outbuf, n, pc, op);
            break;
        case 50:
            decode_tlt(outbuf, n, pc, op);
            break;
        case 51:
            decode_tltu(outbuf, n, pc, op);
            break;
        case 52:
            decode_teq(outbuf, n, pc, op);
            break;
        case 54:
            decode_tne(outbuf, n, pc, op);
            break;
        default:
            /* unreachable */
            abort();
    }
}

static void decode_SPC2(char *outbuf, size_t n, uint32_t pc, uint32_t op)
{
    switch (getfunction(op))
    {
        case 0:
            decode_madd(outbuf, n, pc, op);
            break;
        case 1:
            decode_maddu(outbuf, n, pc, op);
            break;
        case 2:
            decode_mul(outbuf, n, pc, op);
            break;
        case 3:
        case 6:
        case 7:
        case 8:
        case 9:
        case 10:
        case 11:
        case 12:
        case 13:
        case 14:
        case 15:
        case 16:
        case 17:
        case 18:
        case 19:
        case 20:
        case 21:
        case 22:
        case 23:
        case 24:
        case 25:
        case 26:
        case 27:
        case 28:
        case 29:
        case 30:
        case 31:
        case 34:
        case 35:
        case 36:
        case 37:
        case 38:
        case 39:
        case 40:
        case 41:
        case 42:
        case 43:
        case 44:
        case 45:
        case 46:
        case 47:
        case 48:
        case 49:
        case 50:
        case 51:
        case 52:
        case 53:
        case 54:
        case 55:
        case 56:
        case 57:
        case 58:
        case 59:
        case 60:
        case 61:
        case 62:
            decode_reserved(outbuf, n, pc, op);
            break;
        case 4:
            decode_msub(outbuf, n, pc, op);
            break;
        case 5:
            decode_msubu(outbuf, n, pc, op);
            break;
        case 32:
            decode_clz(outbuf, n, pc, op);
            break;
        case 33:
            decode_clo(outbuf, n, pc, op);
            break;
        case 63:
            decode_sdbbp(outbuf, n, pc, op);
            break;
        default:
            /* unreachable */
            abort();
    }
}

static void decode_R(char *outbuf, size_t n, uint32_t pc, uint32_t op)
{
    switch (getrt(op))
    {
        case 0:
            decode_bltz(outbuf, n, pc, op);
            break;
        case 1:
            decode_bgez(outbuf, n, pc, op);
            break;
        case 2:
            decode_bltzl(outbuf, n, pc, op);
            break;
        case 3:
            decode_bgezl(outbuf, n, pc, op);
            break;
        case 4:
        case 5:
        case 6:
        case 7:
        case 13:
        case 15:
        case 20:
        case 21:
        case 22:
        case 23:
        case 24:
        case 25:
        case 26:
        case 27:
        case 28:
        case 29:
        case 30:
        case 31:
            decode_reserved(outbuf, n, pc, op);
            break;
        case 8:
            decode_tgei(outbuf, n, pc, op);
            break;
        case 9:
            decode_tgeiu(outbuf, n, pc, op);
            break;
        case 10:
            decode_tlti(outbuf, n, pc, op);
            break;
        case 11:
            decode_tltiu(outbuf, n, pc, op);
            break;
        case 12:
            decode_teqi(outbuf, n, pc, op);
            break;
        case 14:
            decode_tnei(outbuf, n, pc, op);
            break;
        case 16:
            decode_bltzal(outbuf, n, pc, op);
            break;
        case 17:
            decode_bgezal(outbuf, n, pc, op);
            break;
        case 18:
            decode_bltzall(outbuf, n, pc, op);
            break;
        case 19:
            decode_bgezall(outbuf, n, pc, op);
            break;
        default:
            /* unreachable */
            abort();
    }
}

static void decode_COP0(char *outbuf, size_t n, uint32_t pc, uint32_t op)
{
    switch (getrs(op))
    {
        case 0:
            decode_mfc0(outbuf, n, pc, op);
            break;
        case 1:
        case 2:
        case 3:
        case 5:
        case 6:
        case 7:
        case 8:
        case 9:
        case 10:
        case 11:
        case 12:
        case 13:
        case 14:
        case 15:
            decode_reserved(outbuf, n, pc, op);
            break;
        case 4:
            decode_mtc0(outbuf, n, pc, op);
            break;
        case 16:
        case 17:
        case 18:
        case 19:
        case 20:
        case 21:
        case 22:
        case 23:
        case 24:
        case 25:
        case 26:
        case 27:
        case 28:
        case 29:
        case 30:
        case 31:
            decode_CO(outbuf, n, pc, op);
            break;
        default:
            /* unreachable */
            abort();
    }
}

static void decode_CO(char *outbuf, size_t n, uint32_t pc, uint32_t op)
{
    switch (getfunction(op))
    {
        case 0:
        case 3:
        case 4:
        case 5:
        case 7:
        case 9:
        case 10:
        case 11:
        case 12:
        case 13:
        case 14:
        case 15:
        case 16:
        case 17:
        case 18:
        case 19:
        case 20:
        case 21:
        case 22:
        case 23:
        case 25:
        case 26:
        case 27:
        case 28:
        case 29:
        case 30:
        case 33:
        case 34:
        case 35:
        case 36:
        case 37:
        case 38:
        case 39:
        case 40:
        case 41:
        case 42:
        case 43:
        case 44:
        case 45:
        case 46:
        case 47:
        case 48:
        case 49:
        case 50:
        case 51:
        case 52:
        case 53:
        case 54:
        case 55:
        case 56:
        case 57:
        case 58:
        case 59:
        case 60:
        case 61:
        case 62:
        case 63:
            decode_reserved(outbuf, n, pc, op);
            break;
        case 1:
            decode_tlbr(outbuf, n, pc, op);
            break;
        case 2:
            decode_tlbwi(outbuf, n, pc, op);
            break;
        case 6:
            decode_tlbwr(outbuf, n, pc, op);
            break;
        case 8:
            decode_tlbp(outbuf, n, pc, op);
            break;
        case 24:
            decode_eret(outbuf, n, pc, op);
            break;
        case 31:
            decode_deret(outbuf, n, pc, op);
            break;
        case 32:
            decode_wait(outbuf, n, pc, op);
            break;
        default:
            /* unreachable */
            abort();
    }
}