#include <u.h>
#include <libc.h>
#include <bio.h>
#include <ctype.h>
#include <mach.h>
#define Extern extern
#include "acid.h"

typedef struct
{
       uchar op;                       /* bits 31-26 */
       uchar rs;                       /* bits 25-21 */
       uchar rt;                       /* bits 20-16 */
       uchar rd;                       /* bits 15-11 */
       uchar sa;                       /* bits 10-6 */
       uchar function;                 /* bits 5-0 */
       long immediate;                 /* bits 15-0 */
       ulong cofun;                    /* bits 24-0 */
       ulong target;                   /* bits 25-0 */
       ulong w0;
       ulong w1;
} Instr;

static  char FRAMENAME[] = ".frame";
static  void format(char*, Instr*, char*);
static  int myisp;
static  Map *mymap;

static void
mkinstr(Instr *i)
{
       ulong w;
       Instr x;

       get4(mymap, dot, myisp, (long*)&w);

       i->op = (w >> 26) & 0x3F;
       i->rs = (w >> 21) & 0x1F;
       i->rt = (w >> 16) & 0x1F;
       i->rd = (w >> 11) & 0x1F;
       i->sa = (w >> 6) & 0x1F;
       i->function = w & 0x3F;
       i->immediate = w & 0x0000FFFF;
       if (i->immediate & 0x8000)
               i->immediate |= 0xFFFF0000;
       i->cofun = w & 0x01FFFFFF;
       i->target = w & 0x03FFFFFF;
       i->w0 = w;
       /*
        * if it's a LUI followed by an ORI,
        * it's an immediate load of a large constant.
        * fix the LUI immediate in any case.
        */
       if (i->op == 0x0F) {
               dot += 4;
               mkinstr(&x);
               dot -= 4;
               i->immediate <<= 16;
               if (x.op == 0x0D && x.rs == x.rt && x.rt == i->rt) {
                       i->immediate |= (x.immediate & 0xFFFF);
                       i->w1 = x.w0;
                       dotinc = 8;
                       return;
               }
       }
       /*
        * if it's a LWC1 followed by another LWC1
        * into an adjacent register, it's a load of
        * a floating point double.
        */
       else if (i->op == 0x31 && (i->rt & 0x01)) {
               dot += 4;
               mkinstr(&x);
               dot -= 4;
               if (x.op == 0x31 && x.rt == (i->rt - 1) && x.rs == i->rs) {
                       i->rt -= 1;
                       i->w1 = x.w0;
                       dotinc = 8;
                       return;
               }
       }
       /*
        * similarly for double stores
        */
       else if (i->op == 0x39 && (i->rt & 0x01)) {
               dot += 4;
               mkinstr(&x);
               dot -= 4;
               if (x.op == 0x39 && x.rt == (i->rt - 1) && x.rs == i->rs) {
                       i->rt -= 1;
                       i->w1 = x.w0;
                       dotinc = 8;
                       return;
               }
       }
       dotinc = 4;
}

typedef struct Opcode Opcode;
struct Opcode {
       char *mnemonic;
       void (*f)(Opcode *, Instr *);
       char *ken;
};


static void
branch(Opcode *o, Instr *i)
{
       if (i->rs == 0 && i->rt == 0)
               format("JMP", i, "%b");
       else if (i->rs == 0)
               format(o->mnemonic, i, "R%t,%b");
       else if (i->rt == 0)
               format(o->mnemonic, i, "R%s,%b");
       else
               format(o->mnemonic, i, "R%s,R%t,%b");
}

static void
addi(Opcode *o, Instr *i)
{
       if (i->rs == i->rt)
               format(o->mnemonic, i, "%i,R%t");
       else if (i->rs == 0)
               format("MOVW", i, "%i,R%t");
       else if (i->rs == 30) {
               dprint("MOVW\t$");
               psymoff(i->immediate+mach->sb, SEGDATA, "(SB),");
               dprint("R%d", i->rt);
       }
       else
               format(o->mnemonic, i, o->ken);
}

static void
andi(Opcode *o, Instr *i)
{
       if (i->rs == i->rt)
               format(o->mnemonic, i, "%i,R%t");
       else
               format(o->mnemonic, i, o->ken);
}

static void
lw(Opcode *o, Instr *i, char r)
{
       char *m;
       Symbol s;
       ulong l, h;
       int offset;

       if (r == 'F') {
               if (dotinc == 8)
                       m = "MOVD";
               else
                       m = "MOVF";
       }
       else
               m = o->mnemonic;
       if(i->rs == 29) {
               if (findsym(dot, CTEXT, &s) && findlocal(&s, FRAMENAME, &s)) {
                       offset = s.value-i->immediate;
                       if(offset > 0 && getauto(&s, offset, CAUTO, &s)){
                               dprint("%s\t%s-%d(SP),%c%d", m, s.name,
                                       offset, r, i->rt);
                               return;
                       }
                       else if (getauto(&s, (-offset)-4, CPARAM, &s)) {
                               dprint("%s\t%s+%d(FP),%c%d",
                                       m, s.name, -offset, r, i->rt);
                               return;
                       }
               }
       }
       if(i->rs == 30 && mach->sb) {
               dprint("%s\t", m);
               if (r == 'F') {
                       offset = i->immediate+mach->sb;
                       if (get1(symmap, offset, SEGDATA, (uchar*)&h, 4))
                       if (get1(symmap, offset+4, SEGDATA, (uchar*)&l, 4)) {
                               dprint("$%s,%c%d", ieeedtos("%g", h, l), r, i->rt);
                               return;
                       }
               }
               psymoff(i->immediate+mach->sb, SEGDATA, "(SB),");
               dprint("%c%d", r, i->rt);
               return;
       }
       if (r == 'F')
               format(m, i, "%l,F%t");
       else
               format(m, i, o->ken);
}

static void
load(Opcode *o, Instr *i)
{
       lw(o, i, 'R');
}

static void
lwc1(Opcode *o, Instr *i)
{
       lw(o, i, 'F');
}

static void
sw(Opcode *o, Instr *i, char r)
{
       int offset;
       char *m;
       Symbol s;

       if (r == 'F') {
               if (dotinc == 8)
                       m = "MOVD";
               else
                       m = "MOVF";
       }
       else
               m = o->mnemonic;

       if(i->rs == 29) {
               if (findsym(dot, CTEXT, &s) && findlocal(&s, FRAMENAME, &s)) {
                       offset = s.value-i->immediate;
                       if (offset > 0 && getauto(&s, offset, CAUTO, &s)) {
                               dprint("%s\t%c%d,%s-%d(SP)", m, r, i->rt,
                                       s.name, offset);
                               return;
                       }
               }
       }

       if(i->rs == 30 && mach->sb) {
               dprint("%s\t%c%d,", m, r, i->rt);
               psymoff(i->immediate+mach->sb, SEGDATA, "(SB)");
               return;
       }
       if (r == 'F')
               format(m, i, "F%t,%l");
       else
               format(m, i, o->ken);
}

static void
store(Opcode *o, Instr *i)
{
       sw(o, i, 'R');
}

static void
swc1(Opcode *o, Instr *i)
{
       sw(o, i, 'F');
}

static void
sll(Opcode *o, Instr *i)
{
       if (i->w0 == 0)
               dprint("NOOP");
       else if (i->rd == i->rt)
               format(o->mnemonic, i, "$%a,R%d");
       else
               format(o->mnemonic, i, o->ken);
}

static void
sllv(Opcode *o, Instr *i)
{
       if (i->rd == i->rt)
               format(o->mnemonic, i, "R%s,R%d");
       else
               format(o->mnemonic, i, o->ken);
}

static void
jal(Opcode *o, Instr *i)
{
       if (i->rd == 31)
               format("JAL", i, "(R%s)");
       else
               format(o->mnemonic, i, o->ken);
}

static void
add(Opcode *o, Instr *i)
{
       if (i->rd == i->rs)
               format(o->mnemonic, i, "R%t,R%d");
       else if (i->rd == i->rt)
               format(o->mnemonic, i, "R%s,R%d");
       else
               format(o->mnemonic, i, o->ken);
}

static void
sub(Opcode *o, Instr *i)
{
       if (i->rd == i->rs)
               format(o->mnemonic, i, "R%t,R%d");
       else
               format(o->mnemonic, i, o->ken);
}

static void
or(Opcode *o, Instr *i)
{
       if (i->rs == 0 && i->rt == 0)
               format("MOVW", i, "$0,R%d");
       else if (i->rs == 0)
               format("MOVW", i, "R%t,R%d");
       else if (i->rt == 0)
               format("MOVW", i, "R%s,R%d");
       else
               add(o, i);
}

static void
nor(Opcode *o, Instr *i)
{
       if (i->rs == 0 && i->rt == 0 && i->rd == 0)
               format("NOP", i, 0);
       else
               add(o, i);
}

static char mipscoload[] = "r%t,%l";
static char mipsload[] = "%l,R%t";
static char mipsstore[] = "R%t,%l";
static char mipsalui[] = "%i,R%s,R%t";
static char mipsalu3op[] = "R%t,R%s,R%d";
static char mipsrtrs[] = "R%t,R%s";
static char mipscorsrt[] = "r%s,r%t";
static char mipscorsi[] = "r%s,%i";
static char mipscoxxx[] = "%w";
static char mipscofp3[] = "f%a,f%d,f%t";        /* fd,fs,ft */
static char mipsfp3[] = "F%t,F%d,F%a";
static char mipscofp2[] = "f%a,f%d";            /* fd,fs */
static char mipsfp2[] = "F%d,F%a";
static char mipscofpc[] = "f%d,f%t";            /* fs,ft */
static char mipsfpc[] = "F%t,F%d";

static Opcode opcodes[64] =
{
       0,              0,      0,
       0,              0,      0,
       "JMP",          0,      "%j",
       "JAL",          0,      "%j",
       "BEQ",     branch,      0,
       "BNE",     branch,      0,
       "BLEZ",    branch,      0,
       "BGTZ",    branch,      0,
       "ADD",       addi,      mipsalui,
       "ADDU",      addi,      mipsalui,
       "SGT",          0,      mipsalui,
       "SGTU",         0,      mipsalui,
       "AND",       andi,      mipsalui,
       "OR",        andi,      mipsalui,
       "XOR",       andi,      mipsalui,
       "MOVW",         0,      "$%u,R%t",
       "cop0",         0,      0,
       "cop1",         0,      0,
       "cop2",         0,      0,
       "cop3",         0,      0,
       "BEQL",    branch,      0,
       "BNEL",    branch,      0,
       "BLEZL",   branch,      0,
       "BGTZL",   branch,      0,
       "instr18",      0,      mipscoxxx,
       "instr19",      0,      mipscoxxx,
       "instr1A",      0,      mipscoxxx,
       "instr1B",      0,      mipscoxxx,
       "instr1C",      0,      mipscoxxx,
       "instr1D",      0,      mipscoxxx,
       "instr1E",      0,      mipscoxxx,
       "instr1F",      0,      mipscoxxx,
       "MOVB",      load,      mipsload,
       "MOVH",      load,      mipsload,
       "lwl",          0,      mipscoload,
       "MOVW",      load,      mipsload,
       "MOVBU",     load,      mipsload,
       "MOVHU",     load,      mipsload,
       "lwr",          0,      mipscoload,
       "instr27",      0,      mipscoxxx,
       "MOVB",     store,      mipsstore,
       "MOVH",     store,      mipsstore,
       "swl",          0,      mipscoload,
       "MOVW",     store,      mipsstore,
       "instr2C",      0,      mipscoxxx,
       "instr2D",      0,      mipscoxxx,
       "swr",          0,      mipscoload,
       "CACHE",        0,      0,
       "ll",           0,      mipscoload,
       "MOVW",      lwc1,      mipscoload,
       "lwc2",         0,      mipscoload,
       "lwc3",         0,      mipscoload,
       "instr34",      0,      mipscoxxx,
       "ldc1",         0,      mipscoload,
       "ldc2",         0,      mipscoload,
       "ldc3",         0,      mipscoload,
       "sc",           0,      mipscoload,
       "swc1",      swc1,      mipscoload,
       "swc2",         0,      mipscoload,
       "swc3",         0,      mipscoload,
       "instr3C",      0,      mipscoxxx,
       "sdc1",         0,      mipscoload,
       "sdc2",         0,      mipscoload,
       "sdc3",         0,      mipscoload,
};

static Opcode sopcodes[64] =
{
       "SLL",        sll,      "$%a,R%t,R%d,",
       "special01",    0,      mipscoxxx,
       "SRL",        sll,      "$%a,R%t,R%d,",
       "SRA",        sll,      "$%a,R%t,R%d,",
       "SLL",       sllv,      "R%s,R%t,R%d",
       "special05",    0,      mipscoxxx,
       "SRL",       sllv,      "R%s,R%t,R%d",
       "SRA",       sllv,      "R%s,R%t,R%d",
       "JMP",          0,      "(R%s)",
       "jal",        jal,      "r%d,r%s",
       "special0A",    0,      mipscoxxx,
       "special0B",    0,      mipscoxxx,
       "SYSCALL",      0,      0,
       "BREAK",        0,      0,
       "special0E",    0,      mipscoxxx,
       "SYNC",         0,      0,
       "MOVW",         0,      "HI,R%d",
       "MOVW",         0,      "R%s,HI",
       "MOVW",         0,      "LO,R%d",
       "MOVW",         0,      "R%s,LO",
       "special14",    0,      mipscoxxx,
       "special15",    0,      mipscoxxx,
       "special16",    0,      mipscoxxx,
       "special17",    0,      mipscoxxx,
       "MUL",          0,      mipsrtrs,
       "MULU",         0,      mipsrtrs,
       "DIV",          0,      mipsrtrs,
       "DIVU",         0,      mipsrtrs,
       "special1C",    0,      mipscoxxx,
       "special1D",    0,      mipscoxxx,
       "special1E",    0,      mipscoxxx,
       "special1F",    0,      mipscoxxx,
       "ADD",        add,      mipsalu3op,
       "ADDU",       add,      mipsalu3op,
       "SUB",        sub,      mipsalu3op,
       "SUBU",       sub,      mipsalu3op,
       "AND",        add,      mipsalu3op,
       "OR",          or,      mipsalu3op,
       "XOR",        add,      mipsalu3op,
       "NOR",        nor,      mipsalu3op,
       "special28",    0,      mipscoxxx,
       "special29",    0,      mipscoxxx,
       "SGT",          0,      mipsalu3op,
       "SGTU",         0,      mipsalu3op,
       "special2C",    0,      mipscoxxx,
       "special2D",    0,      mipscoxxx,
       "special2E",    0,      mipscoxxx,
       "special2F",    0,      mipscoxxx,
       "tge",          0,      mipscorsrt,
       "tgeu",         0,      mipscorsrt,
       "tlt",          0,      mipscorsrt,
       "tltu",         0,      mipscorsrt,
       "teq",          0,      mipscorsrt,
       "special35",    0,      mipscoxxx,
       "tne",          0,      mipscorsrt,
       "special37",    0,      mipscoxxx,
       "special38",    0,      mipscoxxx,
       "special39",    0,      mipscoxxx,
       "special3A",    0,      mipscoxxx,
       "special3B",    0,      mipscoxxx,
       "special3C",    0,      mipscoxxx,
       "special3D",    0,      mipscoxxx,
       "special3E",    0,      mipscoxxx,
       "special3F",    0,      mipscoxxx,
};

static Opcode ropcodes[32] =
{
       "BLTZ",    branch,      0,
       "BGEZ",    branch,      0,
       "BLTZL",   branch,      0,
       "BGEZL",   branch,      0,
       "regimm04",     0,      mipscoxxx,
       "regimm05",     0,      mipscoxxx,
       "regimm06",     0,      mipscoxxx,
       "regimm07",     0,      mipscoxxx,
       "tgei",         0,      mipscorsi,
       "tgeiu",        0,      mipscorsi,
       "tlti",         0,      mipscorsi,
       "tltiu",        0,      mipscorsi,
       "teqi",         0,      mipscorsi,
       "regimm0D",     0,      mipscoxxx,
       "tnei",         0,      mipscorsi,
       "regimm0F",     0,      mipscoxxx,
       "BLTZAL",  branch,      0,
       "BGEZAL",  branch,      0,
       "BLTZALL", branch,      0,
       "BGEZALL", branch,      0,
       "regimm14",     0,      mipscoxxx,
       "regimm15",     0,      mipscoxxx,
       "regimm16",     0,      mipscoxxx,
       "regimm17",     0,      mipscoxxx,
       "regimm18",     0,      mipscoxxx,
       "regimm19",     0,      mipscoxxx,
       "regimm1A",     0,      mipscoxxx,
       "regimm1B",     0,      mipscoxxx,
       "regimm1C",     0,      mipscoxxx,
       "regimm1D",     0,      mipscoxxx,
       "regimm1E",     0,      mipscoxxx,
       "regimm1F",     0,      mipscoxxx,
};

static Opcode fopcodes[64] =
{
       "ADD%f",        0,      mipsfp3,
       "SUB%f",        0,      mipsfp3,
       "MUL%f",        0,      mipsfp3,
       "DIV%f",        0,      mipsfp3,
       "sqrt.%f",      0,      mipscofp2,
       "ABS%f",        0,      mipsfp2,
       "MOV%f",        0,      mipsfp2,
       "NEG%f",        0,      mipsfp2,
       "finstr08",     0,      mipscoxxx,
       "finstr09",     0,      mipscoxxx,
       "finstr0A",     0,      mipscoxxx,
       "finstr0B",     0,      mipscoxxx,
       "round.w.%f",   0,      mipscofp2,
       "trunc.w%f",    0,      mipscofp2,
       "ceil.w%f",     0,      mipscofp2,
       "floor.w%f",    0,      mipscofp2,
       "finstr10",     0,      mipscoxxx,
       "finstr11",     0,      mipscoxxx,
       "finstr12",     0,      mipscoxxx,
       "finstr13",     0,      mipscoxxx,
       "finstr14",     0,      mipscoxxx,
       "finstr15",     0,      mipscoxxx,
       "finstr16",     0,      mipscoxxx,
       "finstr17",     0,      mipscoxxx,
       "finstr18",     0,      mipscoxxx,
       "finstr19",     0,      mipscoxxx,
       "finstr1A",     0,      mipscoxxx,
       "finstr1B",     0,      mipscoxxx,
       "finstr1C",     0,      mipscoxxx,
       "finstr1D",     0,      mipscoxxx,
       "finstr1E",     0,      mipscoxxx,
       "finstr1F",     0,      mipscoxxx,
       "cvt.s.%f",     0,      mipscofp2,
       "cvt.d.%f",     0,      mipscofp2,
       "cvt.e.%f",     0,      mipscofp2,
       "cvt.q.%f",     0,      mipscofp2,
       "cvt.w.%f",     0,      mipscofp2,
       "finstr25",     0,      mipscoxxx,
       "finstr26",     0,      mipscoxxx,
       "finstr27",     0,      mipscoxxx,
       "finstr28",     0,      mipscoxxx,
       "finstr29",     0,      mipscoxxx,
       "finstr2A",     0,      mipscoxxx,
       "finstr2B",     0,      mipscoxxx,
       "finstr2C",     0,      mipscoxxx,
       "finstr2D",     0,      mipscoxxx,
       "finstr2E",     0,      mipscoxxx,
       "finstr2F",     0,      mipscoxxx,
       "c.f.%f",       0,      mipscofpc,
       "c.un.%f",      0,      mipscofpc,
       "CMPEQ%f",      0,      mipsfpc,
       "c.ueq.%f",     0,      mipscofpc,
       "c.olt.%f",     0,      mipscofpc,
       "c.ult.%f",     0,      mipscofpc,
       "c.ole.%f",     0,      mipscofpc,
       "c.ule.%f",     0,      mipscofpc,
       "c.sf.%f",      0,      mipscofpc,
       "c.ngle.%f",    0,      mipscofpc,
       "c.seq.%f",     0,      mipscofpc,
       "c.ngl.%f",     0,      mipscofpc,
       "CMPGT%f",      0,      mipsfpc,
       "c.nge.%f",     0,      mipscofpc,
       "CMPGE%f",      0,      mipsfpc,
       "c.ngt.%f",     0,      mipscofpc,
};

static char *cop0regs[32] =
{
       "INDEX",
       "RANDOM",
       "TLBPHYS",
       "EntryLo0",
       "CONTEXT",
       "PageMask",
       "Wired",
       "Error",
       "BADVADDR",
       "Count",
       "TLBVIRT",
       "Compare",
       "STATUS",
       "CAUSE",
       "EPC",
       "PRID",
       "Config",
       "LLadr",
       "WatchLo",
       "WatchHi",
       "20",
       "21",
       "22",
       "23",
       "24",
       "25",
       "26",
       "CacheErr",
       "TagLo",
       "TagHi",
       "ErrorEPC",
       "31"
};

static char fsub[16] = {
       'F', 'D', 'e', 'q', 'W', '?', '?', '?',
       '?', '?', '?', '?', '?', '?', '?', '?'
};

static void
format(char *mnemonic, Instr *i, char *f)
{
       if (mnemonic)
               format(0, i, mnemonic);
       if (f == 0)
               return;
       if (mnemonic)
               dprint("\t");
       for ( ; *f; f++) {
               if (*f != '%') {
                       dprint("%c", *f);
                       continue;
               }
               switch (*++f) {

               case 's':
                       dprint("%d", i->rs);
                       break;

               case 't':
                       dprint("%d", i->rt);
                       break;

               case 'd':
                       dprint("%d", i->rd);
                       break;

               case 'a':
                       dprint("%d", i->sa);
                       break;

               case 'l':
                       dprint("%lx(R%d)", i->immediate, i->rs);
                       break;

               case 'i':
                       dprint("$%lx", i->immediate);
                       break;

               case 'u':
                       psymoff(i->immediate, SEGDATA, "(SB)");
                       break;

               case 'j':
                       psymoff((i->target<<2)|(dot & 0xF0000000), myisp, "(SB)");
                       break;

               case 'b':
                       psymoff((i->immediate<<2)+dot+4, myisp, "");
                       break;

               case 'c':
                       dprint("%lux", i->cofun);
                       break;

               case 'w':
                       dprint("[%lux]", i->w0);
                       break;

               case 'm':
                       dprint("M(%s)", cop0regs[i->rd]);
                       break;

               case 'f':
                       dprint("%c", fsub[i->rs & 0x0F]);
                       break;

               case '\0':
                       dprint("%c", '%');
                       return;

               default:
                       dprint("%%%c", *f);
                       break;
               }
       }
}

static void
copz(int cop, Instr *i)
{
       char *f, *m, buf[16];

       m = buf;
       f = "%t,%d";
       switch (i->rs) {

       case 0:
               sprint(buf, "mfc%d", cop);
               break;

       case 2:
               sprint(buf, "cfc%d", cop);
               break;

       case 4:
               sprint(buf, "mtc%d", cop);
               break;

       case 6:
               sprint(buf, "ctc%d", cop);
               break;

       case 8:
               f = "%b";
               switch (i->rt) {

               case 0:
                       sprint(buf, "bc%df", cop);
                       break;

               case 1:
                       sprint(buf, "bc%dt", cop);
                       break;

               case 2:
                       sprint(buf, "bc%dfl", cop);
                       break;

               case 3:
                       sprint(buf, "bc%dtl", cop);
                       break;

               default:
                       sprint(buf, "cop%d", cop);
                       f = mipscoxxx;
                       break;
               }
               break;

       default:
               sprint(buf, "cop%d", cop);
               if (i->rs & 0x10)
                       f = "function %c";
               else
                       f = mipscoxxx;
               break;
       }
       format(m, i, f);
}

static void
cop0(Instr *i)
{
       char *m = 0;

       if (i->rs < 8) {
               switch (i->rs) {

               case 0:
               case 1:
                       format("MOVW", i, "%m,R%t");
                       return;

               case 4:
               case 5:
                       format("MOVW", i, "R%t,%m");
                       return;
               }
       }
       else if (i->rs >= 0x10) {
               switch (i->cofun) {

               case 1:
                       m = "TLBR";
                       break;

               case 2:
                       m = "TLBWI";
                       break;

               case 6:
                       m = "TLBWR";
                       break;

               case 8:
                       m = "TLBP";
                       break;

               case 16:
                       m = "RFE";
                       break;

               case 32:
                       m = "ERET";
                       break;
               }
               if (m) {
                       format(m, i, 0);
                       return;
               }
       }
       copz(0, i);
}

static void
cop1(Instr *i)
{
       char *m = "MOVW";

       switch (i->rs) {

       case 0:
               format(m, i, "F%d,R%t");
               return;

       case 2:
               format(m, i, "FCR%d,R%t");
               return;

       case 4:
               format(m, i, "R%t,F%d");
               return;

       case 6:
               format(m, i, "R%t,FCR%d");
               return;

       case 8:
               switch (i->rt) {

               case 0:
                       format("BFPF", i, "%b");
                       return;

               case 1:
                       format("BFPT", i, "%b");
                       return;
               }
               break;
       }
       copz(1, i);
}

static void
printins(Map *map, char modifier, long isp)
{
       Instr i;
       Opcode *o;
       uchar op;

       USED(modifier);
       mymap = map;
       myisp = isp;
       mkinstr(&i);
       switch (i.op) {

       case 0x00:                                      /* SPECIAL */
               o = sopcodes;
               op = i.function;
               break;

       case 0x01:                                      /* REGIMM */
               o = ropcodes;
               op = i.rt;
               break;

       case 0x10:                                      /* COP0 */
               cop0(&i);
               return;

       case 0x11:                                      /* COP1 */
               if (i.rs & 0x10) {
                       o = fopcodes;
                       op = i.function;
                       break;
               }
               cop1(&i);
               return;

       case 0x12:                                      /* COP2 */
       case 0x13:                                      /* COP3 */
               copz(i.op-0x10, &i);
               return;

       default:
               o = opcodes;
               op = i.op;
               break;
       }
       if (o[op].f)
               (*o[op].f)(&o[op], &i);
       else
               format(o[op].mnemonic, &i, o[op].ken);
}

extern  void    mipscoprintins(Map *, char, int);

void
mipsprintins(Map *map, char modifier, int isp)
{
/*
       if((asstype == AMIPSCO && modifier == 'i')
               || (asstype == AMIPS && modifier == 'I'))
               mipscoprintins(map, modifier, isp);
       else
*/
               printins(map, modifier, isp);
}

int
mipsfoll(ulong pc, ulong *foll)
{
       ulong w, l;
       char buf[8];
       Instr i;

       dot = pc;
       mymap = cormap;
       myisp = SEGDATA;
       mkinstr(&i);
       w = i.w0;

       if((w&0xF3600000) == 0x41000000)        /* branch on coprocessor */
               goto cond;

       l = (w&0xFC000000)>>26;
       switch(l){
       case 0:         /* SPECIAL */
               if((w&0x3E) == 0x08){           /* JR, JALR */
                       sprint(buf, "R%d", (w>>21)&0x1F);
                       dot = look(buf)->v->ival;
                       get4(mymap, dot, myisp, (long*)&foll[0]);
                       return 1;
               }
               foll[0] = pc+dotinc;
               return 1;
       case 1:                                 /* BCOND */
       case 4:                                 /* BEQ */
       case 5:                                 /* BNE */
       case 6:                                 /* BLEZ */
       case 7:                                 /* BGTZ */
       cond:
               foll[0] = pc+8;
               l = ((w&0xFFFF)<<2);
               if(w & 0x8000)
                       l |= 0xFFFC0000;
               foll[1] = pc+4 + l;
               return 2;
       case 2:                                 /* J */
       case 3:                                 /* JAL */
               foll[0] = (pc&0xF0000000) | ((w&0x03FFFFFF)<<2);
               return 1;
       }

       foll[0] = pc+dotinc;
       return 1;
}