Subversion Repositories planix.SVN

Rev

Blame | Last modification | View Log | RSS feed

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

void add(ulong);
void and(ulong);
void or(ulong);
void xor(ulong);
void sub(ulong);
void andn(ulong);
void xnor(ulong);
void subcc(ulong);
void sll(ulong);
void srl(ulong);
void sra(ulong);
void jmpl(ulong);
void andcc(ulong);
void xorcc(ulong);
void andncc(ulong);
void wry(ulong);
void rdy(ulong);
void mulscc(ulong);
void fcmp(ulong);
void farith(ulong);
void addcc(ulong);
void addx(ulong);
void addxcc(ulong);
void orcc(ulong);
void orncc(ulong);
void xnorcc(ulong);
void orn(ulong);

Inst op2[] = {
        { add,          "add",  Iarith },
        { and,          "and",  Iarith },
        { or,           "or",   Iarith },
        { xor,          "xor",  Iarith },
        { sub,          "sub",  Iarith },
        { andn,         "andn", Iarith },
        { orn,          "orn",  Inop },
        { xnor,         "xnor", Iarith },
        { addx,         "addx", Iarith },
        { undef,        "" },
        { undef,        "" },
        { undef,        "" },
        { undef,        "" },
        { undef,        "" },
        { undef,        "" },
        { undef,        "" },
        { addcc,        "addcc", Iarith },
        { andcc,        "andcc", Iarith },
        { orcc,         "orcc",  Iarith },
        { xorcc,        "xorcc", Iarith },
        { subcc,        "subcc", Iarith },
        { andncc,       "andncc",Iarith },
        { orncc,        "orncc", Iarith },
        { xnorcc,       "xnorcc",Iarith },
        { addxcc,       "addxcc",Iarith },
        { undef,        "" },
        { undef,        "" },
        { undef,        "" },
        { undef,        "" },
        { undef,        "" },
        { undef,        "" },
        { undef,        "" },
        { undef,        "" },
        { undef,        "" },
        { undef,        "" },
        { undef,        "" },
        { mulscc,       "mulscc", Iarith },
        { sll,          "sll",  Iarith },
        { srl,          "srl",  Iarith },
        { sra,          "sra",  Iarith },
        { rdy,          "rdy",  Ireg },
        { undef,        "" },
        { undef,        "" },
        { undef,        "" },
        { undef,        "" },
        { undef,        "" },
        { undef,        "" },
        { undef,        "" },
        { wry,          "wry",  Ireg },
        { undef,        "" },
        { undef,        "" },
        { undef,        "" },
        { farith,       "farith", Ifloat },
        { fcmp,         "fcmp", Ifloat },
        { undef,        "" },
        { undef,        "" },
        { jmpl,         "jmpl", Ibranch },
        { undef,        "" },
        { ta,           "ta",   Isyscall },
        { undef,        "" },
        { undef,        "" },
        { undef,        "" },
        { undef,        "" },
        { undef,        "" },
        { 0 }
};

void st(ulong);
void stb(ulong);
void sth(ulong);
void ld(ulong);
void ldub(ulong);
void ldsb(ulong);
void lduh(ulong);
void stf(ulong);
void ldf(ulong);
void ldsh(ulong);
void std(ulong);
void ldd(ulong);
void ldstub(ulong);
void swap(ulong);
void lddf(ulong);
void stdf(ulong);

Inst op3[] = {
        { ld,           "ld",   Iload },
        { ldub,         "ldub", Iload },
        { lduh,         "lduh", Iload },
        { ldd,          "ldd",  Iload },
        { st,           "st",   Istore },
        { stb,          "stb",  Istore },
        { sth,          "sth",  Istore },
        { std,          "std",  Istore },
        { undef,        "" },
        { ldsb,         "ldsb", Iload },
        { ldsh,         "ldsh", Iload },
        { undef,        "" },
        { undef,        "" },
        { ldstub,       "ldstub", Iload },
        { undef,        "" },
        { swap,         "swap", Iload },
        { undef,        "" },
        { undef,        "" },
        { undef,        "" },
        { undef,        "" },
        { undef,        "" },
        { undef,        "" },
        { undef,        "" },
        { undef,        "" },
        { undef,        "" },
        { undef,        "" },
        { undef,        "" },
        { undef,        "" },
        { undef,        "" },
        { undef,        "" },
        { undef,        "" },
        { undef,        "" },
        { ldf,          "ldf",  Ifloat },
        { undef,        "" },
        { undef,        "" },
        { lddf,         "lddf", Ifloat },
        { stf,          "stf",  Ifloat },
        { undef,        "" },
        { undef,        "" },
        { stdf,         "stdf", Ifloat },
        { undef,        "" },
        { undef,        "" },
        { undef,        "" },
        { undef,        "" },
        { undef,        "" },
        { undef,        "" },
        { undef,        "" },
        { undef,        "" },
        { undef,        "" },
        { undef,        "" },
        { undef,        "" },
        { undef,        "" },
        { undef,        "" },
        { undef,        "" },
        { undef,        "" },
        { undef,        "" },
        { undef,        "" },
        { undef,        "" },
        { undef,        "" },
        { undef,        "" },
        { undef,        "" },
        { undef,        "" },
        { undef,        "" },
        { undef,        "" },
        { 0 }
};

void sethi(ulong);
void bicc(ulong);
void fbcc(ulong);
void call(ulong);

Inst op0[] = {
        { undef,        "" },
        { undef,        "" },
        { bicc,         "bicc", Ibranch },
        { undef,        "" },
        { sethi,        "sethi",Iarith },
        { undef,        "" },
        { fbcc,         "fbcc", Ibranch },
        { undef,        "" },
        /* This is a fake and connot be reached by op0 decode */
        { call,         "call", Ibranch },
        { 0 }
};

void call(ulong);

void
run(void)
{
        do {
                reg.r[0] = 0;
                reg.ir = ifetch(reg.pc);
                switch(reg.ir>>30) {
                case 0:
                        ci = &op0[(reg.ir>>22)&0x07];
                        ci->count++;
                        (*ci->func)(reg.ir);
                        break;
                case 1:
                        ci = &op0[8];
                        ci->count++;
                        call(reg.ir);
                        break;
                case 2:
                        ci = &op2[(reg.ir>>19)&0x3f];
                        ci->count++;
                        (*ci->func)(reg.ir);
                        break;
                case 3:
                        ci = &op3[(reg.ir>>19)&0x3f];
                        ci->count++;
                        (*ci->func)(reg.ir);
                        break;
                }
                reg.pc += 4;
                if(bplist)
                        brkchk(reg.pc, Instruction);
        }while(--count);
}

void
ilock(int rd)
{
        ulong ir;

        ir = getmem_4(reg.pc+4);
        switch(ir>>30) {
        case 0:
        case 1:
                break;
        case 2:
                if(((ir>>20)&0x1f) == 0x1a)             /* floating point */
                        break;
        case 3:
                if(rd == ((ir>>14)&0x1f)) {
                        loadlock++;
                        break;
                }
                if(ir&IMMBIT)
                        break;
                if(rd == (ir&0x1f))
                        loadlock++;
                break;
        }
}

void
delay(ulong npc)
{
        ulong opc;

        reg.r[0] = 0;
        if(reg.ir != NOP)
                ci->useddelay++;
        switch(reg.ir>>30) {
        case 0:
                ci = &op0[(reg.ir>>22)&0x07];
                ci->count++;
                (*ci->func)(reg.ir);
                break;
        case 1:
                ci = &op0[8];
                ci->count++;
                call(reg.ir);
                break;
        case 2:
                ci = &op2[(reg.ir>>19)&0x3f];
                ci->count++;
                opc = reg.pc;
                reg.pc = npc-4;
                (*ci->func)(reg.ir);
                reg.pc = opc;
                break;
        case 3:
                ci = &op3[(reg.ir>>19)&0x3f];
                ci->count++;
                opc = reg.pc;
                reg.pc = npc-4;
                (*ci->func)(reg.ir);
                reg.pc = opc;
                break;
        }
}

void
undef(ulong ir)
{
/*      Bprint(bioout, "op=%d op2=%d op3=%d\n", ir>>30, (ir>>21)&0x7, (ir>>19)&0x3f); */
        Bprint(bioout, "illegal_instruction IR #%.8lux\n", ir);
        longjmp(errjmp, 0);
}

void
sub(ulong ir)
{
        long v;
        int rd, rs1, rs2;

        getrop23(ir);
        if(ir&IMMBIT) {
                ximm(v, ir);
                if(trace)
                        itrace("sub\tr%d,#0x%x,r%d", rs1, v, rd);
        }
        else {
                v = reg.r[rs2];
                if(trace)
                        itrace("sub\tr%d,r%d,r%d", rs1, rs2, rd);
        }
        reg.r[rd] = reg.r[rs1] - v;
}

void
sll(ulong ir)
{
        long v;
        int rd, rs1, rs2;

        getrop23(ir);
        if(ir&IMMBIT) {
                ximm(v, ir);
                if(trace)
                        itrace("sll\tr%d,#0x%x,r%d", rs1, v, rd);
        }
        else {
                v = reg.r[rs2]&0x1F;
                if(trace)
                        itrace("sll\tr%d,r%d,r%d", rs1, rs2, rd);
        }
        reg.r[rd] = reg.r[rs1] << v;
}

void
srl(ulong ir)
{
        long v;
        int rd, rs1, rs2;

        getrop23(ir);
        if(ir&IMMBIT) {
                ximm(v, ir);
                if(trace)
                        itrace("srl\tr%d,#0x%x,r%d", rs1, v, rd);
        }
        else {
                v = reg.r[rs2];
                if(trace)
                        itrace("srl\tr%d,r%d,r%d", rs1, rs2, rd);
        }
        reg.r[rd] = (ulong)reg.r[rs1] >> v;
}

void
sra(ulong ir)
{
        long v;
        int rd, rs1, rs2;

        getrop23(ir);
        if(ir&IMMBIT) {
                ximm(v, ir);
                if(trace)
                        itrace("sra\tr%d,#0x%x,r%d", rs1, v, rd);
        }
        else {
                v = reg.r[rs2];
                if(trace)
                        itrace("sra\tr%d,r%d,r%d", rs1, rs2, rd);
        }
        if(reg.r[rs1]&SIGNBIT)
                reg.r[rd] = reg.r[rs1]>>v | ~((1<<(32-v))-1);
        else
                reg.r[rd] = reg.r[rs1]>>v;
}

void
subcc(ulong ir)
{
        long v;
        int b31rs1, b31op2, b31res, r, rd, rs1, rs2;

        getrop23(ir);
        if(ir&IMMBIT) {
                ximm(v, ir);
                if(trace)
                        itrace("subcc\tr%d,#0x%x,r%d", rs1, v, rd);
        }
        else {
                v = reg.r[rs2];
                if(trace)
                        itrace("subcc\tr%d,r%d,r%d", rs1, rs2, rd);
        }
        r = reg.r[rs1] - v;
        reg.psr &= ~(PSR_z|PSR_n|PSR_c|PSR_v);
        if(r == 0)
                reg.psr |= PSR_z;
        if(r < 0)
                reg.psr |= PSR_n;

        b31rs1 = reg.r[rs1]>>31;
        b31op2 = v>>31;
        b31res = r>>31;

        if((b31rs1 & ~b31op2 & ~b31res)|(~b31rs1 & b31op2 & b31res))
                reg.psr |= PSR_v;

        if((~b31rs1 & b31op2)|(b31res & (~b31rs1|b31op2)))
                reg.psr |= PSR_c;

        reg.r[rd] = r;

}

void
add(ulong ir)
{
        long v;
        int rd, rs1, rs2;

        getrop23(ir);
        if(ir&IMMBIT) {
                ximm(v, ir);
                if(trace)
                        itrace("add\tr%d,#0x%x,r%d", rs1, v, rd);
        }
        else {
                v = reg.r[rs2];
                if(trace)
                        itrace("add\tr%d,r%d,r%d", rs1, rs2, rd);
        }
        reg.r[rd] = reg.r[rs1] + v;
}

void
addcc(ulong ir)
{
        long v, r;
        int rd, rs1, rs2, b31rs1, b31op2, b31r;

        getrop23(ir);
        if(ir&IMMBIT) {
                ximm(v, ir);
                if(trace)
                        itrace("addcc\tr%d,#0x%x,r%d", rs1, v, rd);
        }
        else {
                v = reg.r[rs2];
                if(trace)
                        itrace("addcc\tr%d,r%d,r%d", rs1, rs2, rd);
        }
        r = reg.r[rs1] + v;
        reg.psr &= ~(PSR_z|PSR_n|PSR_c|PSR_v);
        if(r == 0)
                reg.psr |= PSR_z;
        if(r < 0)
                reg.psr |= PSR_n;

        b31rs1 = reg.r[rs1]>>31;
        b31op2 = v>>31;
        b31r = r>>31;
        if((b31rs1 & b31op2 & ~b31r)|(~b31rs1 & ~b31op2 & b31r))
                reg.psr |= PSR_v;
        if((b31rs1 & b31op2) | (~b31r & (b31rs1 | b31op2)))
                reg.psr |= PSR_c;

        reg.r[rd] = r;
}

void
addx(ulong ir)
{
        long v;
        int rd, rs1, rs2;

        getrop23(ir);
        if(ir&IMMBIT) {
                ximm(v, ir);
                if(trace)
                        itrace("addx\tr%d,#0x%x,r%d", rs1, v, rd);
        }
        else {
                v = reg.r[rs2];
                if(trace)
                        itrace("addx\tr%d,r%d,r%d", rs1, rs2, rd);
        }
        if(reg.psr&PSR_c)
                v++;
        reg.r[rd] = reg.r[rs1] + v;
}

void
addxcc(ulong ir)
{
        long r, v;
        int rd, rs1, rs2, b31rs1, b31op2, b31r;

        getrop23(ir);
        if(ir&IMMBIT) {
                ximm(v, ir);
                if(trace)
                        itrace("addxcc\tr%d,#0x%x,r%d", rs1, v, rd);
        }
        else {
                v = reg.r[rs2];
                if(trace)
                        itrace("addxcc\tr%d,r%d,r%d", rs1, rs2, rd);
        }
        if(reg.psr&PSR_c)
                v++;

        r = reg.r[rs1] + v;
        reg.psr &= ~(PSR_z|PSR_n|PSR_c|PSR_v);
        if(r == 0)
                reg.psr |= PSR_z;
        if(r < 0)
                reg.psr |= PSR_n;

        b31rs1 = reg.r[rs1]>>31;
        b31op2 = v>>31;
        b31r = r>>31;
        if((b31rs1 & b31op2 & ~b31r)|(~b31rs1 & ~b31op2 & b31r))
                reg.psr |= PSR_v;
        if((b31rs1 & b31op2) | (~b31r & (b31rs1 | b31op2)))
                reg.psr |= PSR_c;

        reg.r[rd] = r;
}

void
wry(ulong ir)
{
        long v;
        int rd, rs1, rs2;

        getrop23(ir);
        if(rd != 0)
                undef(ir);
        if(ir&IMMBIT) {
                ximm(v, ir);
                if(trace)
                        itrace("wry\tr%d,#0x%x,Y", rs1, v);
        }
        else {
                v = reg.r[rs2];
                if(trace)
                        itrace("wry\tr%d,r%d,Y", rs1, rs2);
        }
        reg.Y = reg.r[rs1] + v;
}

void
rdy(ulong ir)
{
        int rd, rs1, rs2;

        getrop23(ir);
        USED(rs2);
        if(rs1 != 0)
                undef(ir);
        
        if(trace)
                itrace("rdy\tY,r%d", rd);

        reg.r[rd] = reg.Y;
}

void
and(ulong ir)
{
        long v;
        int rd, rs1, rs2;

        getrop23(ir);
        if(ir&IMMBIT) {
                ximm(v, ir);
                if(trace)
                        itrace("and\tr%d,#0x%x,r%d", rs1, v, rd);
        }
        else {
                v = reg.r[rs2];
                if(trace)
                        itrace("and\tr%d,r%d,r%d", rs1, rs2, rd);
        }
        reg.r[rd] = reg.r[rs1] & v;
}

void
andcc(ulong ir)
{
        long v, r;
        int rd, rs1, rs2;

        getrop23(ir);
        if(ir&IMMBIT) {
                ximm(v, ir);
                if(trace)
                        itrace("andcc\tr%d,#0x%x,r%d", rs1, v, rd);
        }
        else {
                v = reg.r[rs2];
                if(trace)
                        itrace("andcc\tr%d,r%d,r%d", rs1, rs2, rd);
        }
        r = reg.r[rs1] & v;
        reg.psr &= ~(PSR_z|PSR_n|PSR_c|PSR_v);
        if(r == 0)
                reg.psr |= PSR_z;
        if(r < 0)
                reg.psr |= PSR_n;

        reg.r[rd] = r;
}

void
orcc(ulong ir)
{
        long v, r;
        int rd, rs1, rs2;

        getrop23(ir);
        if(ir&IMMBIT) {
                ximm(v, ir);
                if(trace)
                        itrace("orcc\tr%d,#0x%x,r%d", rs1, v, rd);
        }
        else {
                v = reg.r[rs2];
                if(trace)
                        itrace("orcc\tr%d,r%d,r%d", rs1, rs2, rd);
        }
        r = reg.r[rs1] | v;
        reg.psr &= ~(PSR_z|PSR_n|PSR_c|PSR_v);
        if(r == 0)
                reg.psr |= PSR_z;
        if(r < 0)
                reg.psr |= PSR_n;

        reg.r[rd] = r;
}

void
mulscc(ulong ir)
{
        int b, n, v, rd, rs1, rs2;
        long o1, o2, r, b31o1, b31o2, b31r;

        getrop23(ir);
        if(ir&IMMBIT) {
                ximm(o2, ir);
                if(trace)
                        itrace("mulscc\tr%d,#0x%x,r%d", rs1, o2, rd);
        }
        else {
                o2 = reg.r[rs2];
                if(trace)
                        itrace("mulscc\tr%d,r%d,r%d", rs1, rs2, rd);
        }
        o1 = reg.r[rs1]>>1;
        n = reg.psr&PSR_n ? 1 : 0;
        v = reg.psr&PSR_v ? 1 : 0;

        o1 |= (n ^ v)<<31;
        if((reg.Y&1) == 0)
                o2 = 0;

        r = o1 + o2;
        reg.psr &= ~(PSR_z|PSR_n|PSR_c|PSR_v);
        if(r == 0)
                reg.psr |= PSR_z;
        if(r < 0)
                reg.psr |= PSR_n;

        b31o1 = o1>>31;
        b31o2 = o2>>31;
        b31r = r>>31;
        if((b31o1 & b31o2 & ~b31r) | (~b31o1 & ~b31o2 & b31r))
                reg.psr |= PSR_v;
        if((b31o1 & b31o2) | (~b31r & (b31o1 | b31o2)))         
                reg.psr |= PSR_c;

        b = reg.r[rs1]&1;
        reg.Y = (reg.Y>>1)|(b<<31);
        reg.r[rd] = r;
}

void
or(ulong ir)
{
        long v;
        int rd, rs1, rs2;

        getrop23(ir);
        if(ir&IMMBIT) {
                ximm(v, ir);
                if(trace)
                        itrace("or\tr%d,#0x%x,r%d", rs1, v, rd);
        }
        else {
                v = reg.r[rs2];
                if(trace)
                        itrace("or\tr%d,r%d,r%d", rs1, rs2, rd);
        }
        reg.r[rd] = reg.r[rs1] | v;
}

void
xor(ulong ir)
{
        long v;
        int rd, rs1, rs2;

        getrop23(ir);
        if(ir&IMMBIT) {
                ximm(v, ir);
                if(trace)
                        itrace("xor\tr%d,#0x%x,r%d", rs1, v, rd);
        }
        else {
                v = reg.r[rs2];
                if(trace)
                        itrace("xor\tr%d,r%d,r%d", rs1, rs2, rd);
        }
        reg.r[rd] = reg.r[rs1] ^ v;
}

void
xorcc(ulong ir)
{
        long v, r;
        int rd, rs1, rs2;

        getrop23(ir);
        if(ir&IMMBIT) {
                ximm(v, ir);
                if(trace)
                        itrace("xorcc\tr%d,#0x%x,r%d", rs1, v, rd);
        }
        else {
                v = reg.r[rs2];
                if(trace)
                        itrace("xorcc\tr%d,r%d,r%d", rs1, rs2, rd);
        }
        r = reg.r[rs1] ^ v;
        reg.psr &= ~(PSR_z|PSR_n|PSR_c|PSR_v);
        if(r == 0)
                reg.psr |= PSR_z;
        if(r < 0)
                reg.psr |= PSR_n;

        reg.r[rd] = r;
}

void
andn(ulong ir)
{
        long v;
        int rd, rs1, rs2;

        getrop23(ir);
        if(ir&IMMBIT) {
                ximm(v, ir);
                if(trace)
                        itrace("andn\tr%d,#0x%x,r%d", rs1, v, rd);
        }
        else {
                v = reg.r[rs2];
                if(trace)
                        itrace("andn\tr%d,r%d,r%d", rs1, rs2, rd);
        }
        reg.r[rd] = reg.r[rs1] & ~v;
}

void
andncc(ulong ir)
{
        long v, r;
        int rd, rs1, rs2;

        getrop23(ir);
        if(ir&IMMBIT) {
                ximm(v, ir);
                if(trace)
                        itrace("andncc\tr%d,#0x%x,r%d", rs1, v, rd);
        }
        else {
                v = reg.r[rs2];
                if(trace)
                        itrace("andncc\tr%d,r%d,r%d", rs1, rs2, rd);
        }
        r = reg.r[rs1] & ~v;
        reg.psr &= ~(PSR_z|PSR_n|PSR_c|PSR_v);
        if(r == 0)
                reg.psr |= PSR_z;
        if(r < 0)
                reg.psr |= PSR_n;

        reg.r[rd] = r;
}

void
orn(ulong ir)
{
        long v;
        int rd, rs1, rs2;

        getrop23(ir);
        if(rd == 0 && rs1 == 0) /* ken used orn r0,r0,r0 as nop */
                nopcount++;

        if(ir&IMMBIT) {
                ximm(v, ir);
                if(trace)
                        itrace("orn\tr%d,#0x%x,r%d", rs1, v, rd);
        }
        else {
                v = reg.r[rs2];
                if(trace)
                        itrace("orn\tr%d,r%d,r%d", rs1, rs2, rd);
        }
        reg.r[rd] = reg.r[rs1] | ~v;
}

void
orncc(ulong ir)
{
        long r, v;
        int rd, rs1, rs2;

        getrop23(ir);
        if(ir&IMMBIT) {
                ximm(v, ir);
                if(trace)
                        itrace("orncc\tr%d,#0x%x,r%d", rs1, v, rd);
        }
        else {
                v = reg.r[rs2];
                if(trace)
                        itrace("orncc\tr%d,r%d,r%d", rs1, rs2, rd);
        }
        r = reg.r[rs1] | ~v;
        reg.psr &= ~(PSR_z|PSR_n|PSR_c|PSR_v);
        if(r == 0)
                reg.psr |= PSR_z;
        if(r < 0)
                reg.psr |= PSR_n;

        reg.r[rd] = r;
}

void
xnor(ulong ir)
{
        long v;
        int rd, rs1, rs2;

        getrop23(ir);
        if(ir&IMMBIT) {
                ximm(v, ir);
                if(trace)
                        itrace("xnor\tr%d,#0x%x,r%d", rs1, v, rd);
        }
        else {
                v = reg.r[rs2];
                if(trace)
                        itrace("xnor\tr%d,r%d,r%d", rs1, rs2, rd);
        }
        reg.r[rd] = reg.r[rs1] ^ ~v;
}

void
xnorcc(ulong ir)
{
        long v, r;
        int rd, rs1, rs2;

        getrop23(ir);
        if(ir&IMMBIT) {
                ximm(v, ir);
                if(trace)
                        itrace("xnorcc\tr%d,#0x%x,r%d", rs1, v, rd);
        }
        else {
                v = reg.r[rs2];
                if(trace)
                        itrace("xnorcc\tr%d,r%d,r%d", rs1, rs2, rd);
        }
        r = reg.r[rs1] ^ ~v;
        reg.psr &= ~(PSR_z|PSR_n|PSR_c|PSR_v);
        if(r == 0)
                reg.psr |= PSR_z;
        if(r < 0)
                reg.psr |= PSR_n;

        reg.r[rd] = r;
}

void
st(ulong ir)
{
        ulong ea;
        int rd, rs1, rs2;

        getrop23(ir);
        if(ir&IMMBIT) {
                ximm(ea, ir);
                if(trace)
                        itrace("st\tr%d,0x%lux(r%d) %lux=%lux",
                                        rd, ea, rs1, ea+reg.r[rs1], reg.r[rd]);
                ea += reg.r[rs1];
        }
        else {
                ea = reg.r[rs1] + reg.r[rs2];
                if(trace)
                        itrace("st\tr%d,[r%d+r%d] %lux=%lux",
                                        rd, rs1, rs2, ea, reg.r[rd]);
        }

        putmem_w(ea, reg.r[rd]);
}

void
std(ulong ir)
{
        ulong ea;
        int rd, rs1, rs2;

        getrop23(ir);
        if(ir&IMMBIT) {
                ximm(ea, ir);
                if(trace)
                        itrace("std\tr%d,0x%lux(r%d) %lux=%lux",
                                        rd, ea, rs1, ea+reg.r[rs1], reg.r[rd]);
                ea += reg.r[rs1];
        }
        else {
                ea = reg.r[rs1] + reg.r[rs2];
                if(trace)
                        itrace("std\tr%d,[r%d+r%d] %lux=%lux",
                                        rd, rs1, rs2, ea, reg.r[rd]);
        }

        putmem_w(ea, reg.r[rd]);
        putmem_w(ea+4, reg.r[rd+1]);
}

void
stb(ulong ir)
{
        ulong ea;
        int rd, rs1, rs2;

        getrop23(ir);
        if(ir&IMMBIT) {
                ximm(ea, ir);
                if(trace)
                        itrace("stb\tr%d,0x%lux(r%d) %lux=%lux",
                                        rd, ea, rs1, ea+reg.r[rs1], reg.r[rd]&0xff);
                ea += reg.r[rs1];
        }
        else {
                ea = reg.r[rs1] + reg.r[rs2];
                if(trace)
                        itrace("stb\tr%d,[r%d+r%d] %lux=%lux",
                                        rd, rs1, rs2, ea, reg.r[rd]&0xff);
        }

        putmem_b(ea, reg.r[rd]);
}

void
sth(ulong ir)
{
        ulong ea;
        int rd, rs1, rs2;

        getrop23(ir);
        if(ir&IMMBIT) {
                ximm(ea, ir);
                if(trace)
                        itrace("sth\tr%d,0x%lux(r%d) %lux=%lux",
                                        rd, ea, rs1, ea+reg.r[rs1], reg.r[rd]&0xffff);
                ea += reg.r[rs1];
        }
        else {
                ea = reg.r[rs1] + reg.r[rs2];
                if(trace)
                        itrace("sth\tr%d,[r%d+r%d] %lux=%lux",
                                        rd, rs1, rs2, ea, reg.r[rd]&0xffff);
        }

        putmem_h(ea, reg.r[rd]);
}

void
ld(ulong ir)
{
        ulong ea;
        int rd, rs1, rs2;

        getrop23(ir);
        if(ir&IMMBIT) {
                ximm(ea, ir);
                if(trace)
                        itrace("ld\tr%d,0x%lux(r%d) ea=%lux",rd, ea, rs1, ea+reg.r[rs1]);
                ea += reg.r[rs1];
        }
        else {
                ea = reg.r[rs1] + reg.r[rs2];
                if(trace)
                        itrace("ld\tr%d,[r%d+r%d] ea=%lux", rd, rs1, rs2, ea);
        }

        reg.r[rd] = getmem_w(ea);
        ilock(rd);
}

void
swap(ulong ir)
{
        ulong t, ea;
        int rd, rs1, rs2;

        getrop23(ir);
        if(ir&IMMBIT) {
                ximm(ea, ir);
                if(trace)
                        itrace("swap\tr%d,0x%lux(r%d) ea=%lux",
                                                rd, ea, rs1, ea+reg.r[rs1]);
                ea += reg.r[rs1];
        }
        else {
                ea = reg.r[rs1] + reg.r[rs2];
                if(trace)
                        itrace("swap\tr%d,[r%d+r%d] ea=%lux", rd, rs1, rs2, ea);
        }

        t = reg.r[rd];
        reg.r[rd] = getmem_w(ea);
        putmem_w(ea, t);
}

void
ldd(ulong ir)
{
        ulong ea;
        int rd, rs1, rs2;

        getrop23(ir);
        if(ir&IMMBIT) {
                ximm(ea, ir);
                if(trace)
                        itrace("ldd\tr%d,0x%lux(r%d) ea=%lux",rd, ea, rs1, ea+reg.r[rs1]);
                ea += reg.r[rs1];
        }
        else {
                ea = reg.r[rs1] + reg.r[rs2];
                if(trace)
                        itrace("ldd\tr%d,[r%d+r%d] ea=%lux", rd, rs1, rs2, ea);
        }

        reg.r[rd] = getmem_w(ea);
        reg.r[rd+1] = getmem_w(ea+4);
}

void
ldub(ulong ir)
{
        ulong ea;
        int rd, rs1, rs2;

        getrop23(ir);
        if(ir&IMMBIT) {
                ximm(ea, ir);
                if(trace)
                        itrace("ldub\tr%d,0x%lux(r%d) ea=%lux",
                                                rd, ea, rs1, ea+reg.r[rs1]);
                ea += reg.r[rs1];
        }
        else {
                ea = reg.r[rs1] + reg.r[rs2];
                if(trace)
                        itrace("ldub\tr%d,[r%d+r%d] ea=%lux", rd, rs1, rs2, ea);
        }

        reg.r[rd] = getmem_b(ea) & 0xff;
        ilock(rd);
}

void
ldstub(ulong ir)
{
        ulong ea;
        int rd, rs1, rs2;

        getrop23(ir);
        if(ir&IMMBIT) {
                ximm(ea, ir);
                if(trace)
                        itrace("ldstub\tr%d,0x%lux(r%d) ea=%lux",
                                                rd, ea, rs1, ea+reg.r[rs1]);
                ea += reg.r[rs1];
        }
        else {
                ea = reg.r[rs1] + reg.r[rs2];
                if(trace)
                        itrace("ldstub\tr%d,[r%d+r%d] ea=%lux", rd, rs1, rs2, ea);
        }

        reg.r[rd] = getmem_b(ea) & 0xff;
        putmem_b(ea, 0xff);
}

void
ldsb(ulong ir)
{
        ulong ea;
        int rd, rs1, rs2;

        getrop23(ir);
        if(ir&IMMBIT) {
                ximm(ea, ir);
                if(trace)
                        itrace("ldsb\tr%d,0x%lux(r%d) ea=%lux",
                                                rd, ea, rs1, ea+reg.r[rs1]);
                ea += reg.r[rs1];
        }
        else {
                ea = reg.r[rs1] + reg.r[rs2];
                if(trace)
                        itrace("ldsb\tr%d,[r%d+r%d] ea=%lux", rd, rs1, rs2, ea);
        }

        reg.r[rd] = (schar)getmem_b(ea);
        ilock(rd);
}

void
lduh(ulong ir)
{
        ulong ea;
        int rd, rs1, rs2;

        getrop23(ir);
        if(ir&IMMBIT) {
                ximm(ea, ir);
                if(trace)
                        itrace("lduh\tr%d,0x%lux(r%d) ea=%lux",
                                                rd, ea, rs1, ea+reg.r[rs1]);
                ea += reg.r[rs1];
        }
        else {
                ea = reg.r[rs1] + reg.r[rs2];
                if(trace)
                        itrace("lduh\tr%d,[r%d+r%d] ea=%lux", rd, rs1, rs2, ea);
        }

        reg.r[rd] = getmem_h(ea) & 0xffff;
        ilock(rd);
}

void
ldsh(ulong ir)
{
        ulong ea;
        int rd, rs1, rs2;

        getrop23(ir);
        if(ir&IMMBIT) {
                ximm(ea, ir);
                if(trace)
                        itrace("ldsh\tr%d,0x%lux(r%d) ea=%lux",
                                                rd, ea, rs1, ea+reg.r[rs1]);
                ea += reg.r[rs1];
        }
        else {
                ea = reg.r[rs1] + reg.r[rs2];
                if(trace)
                        itrace("ldsh\tr%d,[r%d+r%d] ea=%lux", rd, rs1, rs2, ea);
        }

        reg.r[rd] = (short)getmem_h(ea);
        ilock(rd);
}

void
sethi(ulong ir)
{
        int rd;
        ulong v;

        rd = (ir>>25)&0x1f;
        v = (ir&0x3FFFFF)<<10;

        if(rd == 0)
                nopcount++;

        if(trace)
                itrace("sethi\t0x%lux,r%d", v, rd);

        reg.r[rd] = v;
}

void
call(ulong ir)
{
        Symbol s;
        ulong npc;

        npc = (ir<<2) + reg.pc;
        if(trace)
                itrace("call\t%lux", npc);

        ci->taken++;
        reg.r[15] = reg.pc;
        reg.ir = ifetch(reg.pc+4);
        delay(npc);

        if(calltree) {
                findsym(npc, CTEXT, &s);
                Bprint(bioout, "%8lux %s(", reg.pc, s.name);
                printparams(&s, reg.r[1]);
                Bprint(bioout, "from ");
                printsource(reg.pc);
                Bputc(bioout, '\n');
        }
        npc -= 4;
        reg.pc = npc;
}

void
jmpl(ulong ir)
{
        ulong ea, o;
        Symbol s;
        int rd, rs1, rs2;

        getrop23(ir);
        if(ir&IMMBIT) {
                ximm(ea, ir);
                o = ea;
                if(trace)
                        itrace("jmpl\t0x%lux(r%d),r%d", ea, rs1, rd);

                ea += reg.r[rs1];
                if(calltree && rd == 0 && o == 8) {
                        findsym(ea-4, CTEXT, &s);
                        Bprint(bioout, "%8lux return to %lux %s r7=%lux\n",
                                                reg.pc, ea-4, s.name, reg.r[7]);
                }
        }
        else {
                ea = reg.r[rs1] + reg.r[rs2];
                if(trace)
                        itrace("jmpl\t[r%d+r%d],r%d", rs1, rs2, rd);
        }

        ci->taken++;
        reg.r[rd] = reg.pc;
        reg.ir = ifetch(reg.pc+4);
        delay(ea);
        reg.pc = ea-4;
}

void
bicc(ulong ir)
{
        char *op;
        ulong npc, anul, ba;
        int takeit, z, v, n, c;

        SET(op, takeit);
        ba = 0;
        switch((ir>>25)&0x0F) {
        case 0:
                op = "bn";
                takeit = 0;
                break;
        case 1:
                op = "be";
                takeit = reg.psr&PSR_z;
                break;
        case 2:
                op = "ble";
                z = reg.psr&PSR_z ? 1 : 0;
                v = reg.psr&PSR_v ? 1 : 0;
                n = reg.psr&PSR_n ? 1 : 0;
                takeit = z | (n ^ v);
                break;
        case 3:
                op = "bl";
                v = reg.psr&PSR_v ? 1 : 0;
                n = reg.psr&PSR_n ? 1 : 0;
                takeit = n ^ v;
                break;
        case 4:
                op = "bleu";
                z = reg.psr&PSR_z ? 1 : 0;
                c = reg.psr&PSR_c ? 1 : 0;
                takeit = c | z;
                break;
        case 5:
                op = "bcs";
                takeit = reg.psr&PSR_c;
                break;
        case 6:
                op = "bneg";
                takeit = reg.psr&PSR_n;
                break;
        case 7:
                op = "bvs";
                takeit = reg.psr&PSR_v;
                break;
        case 8:
                op = "ba";
                ba = 1;
                takeit = 1;
                break;
        case 9:
                op = "bne";
                takeit = !(reg.psr&PSR_z);
                break;
        case 10:
                op = "bg";
                z = reg.psr&PSR_z ? 1 : 0;
                v = reg.psr&PSR_v ? 1 : 0;
                n = reg.psr&PSR_n ? 1 : 0;
                takeit = !(z | (n ^ v));
                break;
        case 11:
                op = "bge";
                v = reg.psr&PSR_v ? 1 : 0;
                n = reg.psr&PSR_n ? 1 : 0;
                takeit = !(n ^ v);
                break;
        case 12:
                op = "bgu";
                z = reg.psr&PSR_z ? 1 : 0;
                c = reg.psr&PSR_c ? 1 : 0;
                takeit = !(c | z);
                break;
        case 13:
                op = "bcc";
                takeit = !(reg.psr&PSR_c);
                break;
        case 14:
                op = "bpos";
                takeit = !(reg.psr&PSR_n);
                break;
        case 15:
                op = "bvc";
                takeit = !(reg.psr&PSR_v);
                break;
        }

        npc = ir & 0x3FFFFF;
        if(npc & (1<<21))
                npc |= ~((1<<22)-1);
        npc = (npc<<2) + reg.pc;

        anul = ir&ANUL;
        if(trace) {
                if(anul)
                        itrace("%s,a\t%lux", op, npc);
                else
                        itrace("%s\t%lux", op, npc);
        }

        if(takeit == 0) {
                reg.pc += 4;
                if(anul == 0) {
                        reg.ir = ifetch(reg.pc);
                        delay(reg.pc+4);
                }
                else
                        anulled++;
                return;
        }

        ci->taken++;
        if(ba && anul) {
                anulled++;
                reg.pc = npc-4;
                return; 
        }
        reg.ir = ifetch(reg.pc+4);
        delay(npc);
        reg.pc = npc-4;
}