ref: a847d7a53d64b1f7d11eb3b969c2684ea0aa399b
dir: /sys/src/cmd/qi/iu.c/
#include <u.h> #include <libc.h> #include <bio.h> #include <mach.h> #define Extern extern #include "power.h" void add(ulong); void addc(ulong); void adde(ulong); void addme(ulong); void addze(ulong); void and(ulong); void andc(ulong); void cmp(ulong); void cmpl(ulong); void cntlzw(ulong); void dcbf(ulong); void dcbi(ulong); void dcbst(ulong); void dcbt(ulong); void dcbtst(ulong); void dcbz(ulong); void divw(ulong); void divwu(ulong); void eciwx(ulong); void ecowx(ulong); void eieio(ulong); void eqv(ulong); void extsb(ulong); void extsh(ulong); void icbi(ulong); void lbzx(ulong); void lfdx(ulong); void lfsx(ulong); void lhax(ulong); void lhbrx(ulong); void lhzx(ulong); void lswi(ulong); void lswx(ulong); void lwarx(ulong); void lwbrx(ulong); void lwzx(ulong); void mcrxr(ulong); void mfcr(ulong); void mfmsr(ulong); void mfpmr(ulong); void mfspr(ulong); void mfsr(ulong); void mfsrin(ulong); void mftb(ulong); void mftbu(ulong); void mspr(ulong); void mtcrf(ulong); void mtmsr(ulong); void mtpmr(ulong); void mtspr(ulong); void mtsr(ulong); void mtsrin(ulong); void mttb(ulong); void mttbu(ulong); void mulhw(ulong); void mulhwu(ulong); void mullw(ulong); void nand(ulong); void neg(ulong); void nor(ulong); void or(ulong); void orc(ulong); void slbia(ulong); void slbia(ulong); void slw(ulong); void sraw(ulong); void srawi(ulong); void srw(ulong); void stbx(ulong); void stfdx(ulong); void stfiwx(ulong); void stfsx(ulong); void sthbrx(ulong); void sthx(ulong); void stswi(ulong); void stswx(ulong); void stwbrx(ulong); void stwcx(ulong); void stwx(ulong); void subf(ulong); void subfc(ulong); void subfe(ulong); void subfme(ulong); void subfze(ulong); void sync(ulong); void tlbie(ulong); void tw(ulong); void xor(ulong); Inst op31[] = { [0] {cmp, "cmp", Iarith}, [4] {tw, "tw", Iarith}, [8] {subfc, "subfc", Iarith}, [10] {addc, "addc", Iarith}, [11] {mulhwu, "mulhwu", Iarith}, [19] {mfcr, "mfcr", Iarith}, [20] {lwarx, "lwarx", Iload}, [23] {lwzx, "lwzx", Iload}, [24] {slw, "slw", Ilog}, [26] {cntlzw, "cntlzw", Ilog}, [28] {and, "and", Ilog}, [32] {cmpl, "cmpl", Iarith}, [40] {subf, "subf", Iarith}, [54] {dcbst, "dcbst", Icontrol}, [55] {lwzx, "lwzux", Iload}, [60] {andc, "andc", Ilog}, [75] {mulhw, "mulhw", Iarith}, [83] {0, "mfmsr", Icontrol}, [86] {dcbf, "dcbf", Icontrol}, [87] {lbzx, "lbzx", Iload}, [104] {neg, "neg", Iarith}, [115] {0, "mfpmr", Iarith}, [119] {lbzx, "lbzux", Iload}, [124] {nor, "nor", Iarith}, [136] {subfe, "subfe", Iarith}, [138] {adde, "adde", Iarith}, [144] {mtcrf, "mtcrf", Ireg}, [146] {0, "mtmsr", Icontrol}, [150] {stwcx, "stwcx.", Istore}, [151] {stwx, "stwx", Istore}, [178] {0, "mtpmr", Icontrol}, [183] {stwx, "stwux", Istore}, [200] {subfze, "subfze", Iarith}, [202] {addze, "addze", Iarith}, [210] {0, "mtsr", Ireg}, [215] {stbx, "stbx", Istore}, [232] {subfme, "subfme", Iarith}, [234] {addme, "addme", Iarith}, [235] {mullw, "mullw", Iarith}, [242] {0, "mtsrin", Ireg}, [246] {dcbtst, "dcbtst", Icontrol}, [247] {stbx, "stbux", Istore}, [266] {add, "add", Iarith}, [275] {0, "mftb", Icontrol}, [278] {dcbt, "dcbt", Icontrol}, [279] {lhzx, "lhzx", Iload}, [284] {eqv, "eqv", Ilog}, [306] {0, "tlbie", Icontrol}, [307] {0, "mftbu", Icontrol}, [310] {0, "eciwx", Icontrol}, [311] {lhzx, "lhzux", Iload}, [316] {xor, "xor", Ilog}, [339] {mspr, "mfspr", Ireg}, [343] {lhax, "lhax", Iload}, [375] {lhax, "lhaux", Iload}, [403] {0, "mttb", Icontrol}, [407] {sthx, "sthx", Istore}, [412] {orc, "orc", Ilog}, [434] {0, "slbia", Iarith}, [435] {0, "mttbu", Icontrol}, [438] {0, "ecowx", Icontrol}, [439] {sthx, "sthux", Istore}, [444] {or, "or", Ilog}, [459] {divwu, "divwu", Iarith}, [467] {mspr, "mtspr", Ireg}, [470] {0, "dcbi", Icontrol}, [476] {nand, "nand", Ilog}, [491] {divw, "divw", Iarith}, [498] {0, "slbia", Icontrol}, [512] {mcrxr, "mcrxr", Ireg}, [533] {lswx, "lswx", Iload}, [534] {lwbrx, "lwbrx", Iload}, [535] {lfsx, "lfsx", Ifloat}, [536] {srw, "srw", Ilog}, [567] {lfsx, "lfsux", Ifloat}, [595] {0, "mfsr", Iarith}, [597] {lswi, "lswi", Iarith}, [598] {sync, "sync", Iarith}, [599] {lfdx, "lfdx", Ifloat}, [631] {lfdx, "lfdux", Ifloat}, [659] {0, "mfsrin", Ireg}, [661] {stswx, "stswx", Istore}, [662] {stwbrx, "stwbrx", Istore}, [663] {stfsx, "stfsx", Istore}, [695] {stfsx, "stfsux", Istore}, [725] {stswi, "stswi", Istore}, [727] {stfdx, "stfdx", Istore}, [759] {stfdx, "stfdux", Istore}, [790] {lhbrx, "lhbrx", Iload}, [792] {sraw, "sraw", Ilog}, [824] {srawi, "srawi", Ilog}, [854] {0, "eieio", Icontrol}, [918] {sthbrx, "sthbrx", Istore}, [922] {extsh, "extsh", Iarith}, [954] {extsb, "extsb", Iarith}, [982] {icbi, "icbi", Icontrol}, [983] {unimp, "stfiwx", Istore}, [1014] {dcbz, "dcbz", Icontrol}, }; Inset ops31 = {op31, nelem(op31)}; void mspr(ulong ir) { int rd, ra, rb; ulong *d; char *n; char buf[20]; getarrr(ir); switch((rb<<5) | ra) { case 0: undef(ir); /* was mq */ return; case 1: d = ®.xer; n = "xer"; break; case 268: case 284: d = ®.tbl; n = "tbl"; break; case 269: case 285: d = ®.tbu; n = "tbu"; break; case 22: d = ®.dec; n = "dec"; break; case 8: d = ®.lr; n = "lr"; break; case 9: d = ®.ctr; n = "ctr"; break; default: d = 0; sprint(n = buf, "spr%d", rd); break; } if(getxo(ir) == 339) { if(trace) itrace("%s\tr%d,%s", ci->name, rd, n); if(d != nil) reg.r[rd] = *d; } else { if(trace) itrace("%s\t%s,r%d", ci->name, n, rd); if(d != nil) *d = reg.r[rd]; } } static void setcr(int d, long r) { int c; c = 0; if(reg.xer & XER_SO) c |= 1; if(r == 0) c |= 2; else if(r > 0) c |= 4; else c |= 8; reg.cr = (reg.cr & ~mkCR(d, 0xF)) | mkCR(d, c); } void addi(ulong ir) { int rd, ra; long imm; getairr(ir); if(trace) { if(ra) itrace("%s\tr%d,r%d,$0x%lux", ci->name, rd, ra, imm); else itrace("li\tr%d,$0x%lux", rd, imm); } if(ra) imm += reg.r[ra]; reg.r[rd] = imm; } void addis(ulong ir) { int rd, ra; long imm; getairr(ir); if(trace) { if(ra) itrace("%s\tr%d,r%d,$0x%lux", ci->name, rd, ra, imm); else itrace("lis\tr%d,$0x%lux", rd, imm); } imm <<= 16; if(ra) imm += reg.r[ra]; reg.r[rd] = imm; } void and(ulong ir) { int rs, ra, rb; getlrrr(ir); reg.r[ra] = reg.r[rs] & reg.r[rb]; if(trace) itrace("%s%s\tr%d,r%d,r%d", ci->name, ir&1?".":"", ra, rs, rb); if(ir & 1) setcr(0, reg.r[ra]); } void andc(ulong ir) { int rs, ra, rb; getlrrr(ir); reg.r[ra] = reg.r[rs] & ~reg.r[rb]; if(trace) itrace("%s%s\tr%d,r%d,r%d", ci->name, ir&1?".":"", ra, rs, rb); if(ir & 1) setcr(0, reg.r[ra]); } void andicc(ulong ir) { int rs, ra; ulong imm; getlirr(ir); reg.r[ra] = reg.r[rs] & imm; if(trace) itrace("%s\tr%d,r%d,$0x%lx", ci->name, ra, rs, imm); setcr(0, reg.r[ra]); } void andiscc(ulong ir) { int rs, ra; ulong imm; getlirr(ir); reg.r[ra] = reg.r[rs] & (imm<<16); if(trace) itrace("%s\tr%d,r%d,$0x%lx", ci->name, ra, rs, imm); setcr(0, reg.r[ra]); } void cmpli(ulong ir) { int rd, ra; ulong c; ulong imm, v; getairr(ir); imm &= 0xFFFF; if(rd & 3) undef(ir); rd >>= 2; v = reg.r[ra]; c = 0; if(reg.xer & XER_SO) c |= CRSO; if(v < imm) c |= CRLT; else if(v == imm) c |= CREQ; else c |= CRGT; c >>= 28; reg.cr = (reg.cr & ~mkCR(rd, 0xF)) | mkCR(rd, c); if(trace) itrace("%s\tcrf%d,r%d,0x%lux [cr=#%x]", ci->name, rd, ra, imm, c); } void cmp(ulong ir) { int rd, ra, rb; ulong c; long va, vb; getarrr(ir); if(rd & 3) undef(ir); rd >>= 2; c = 0; if(reg.xer & XER_SO) c |= CRSO; va = reg.r[ra]; vb = reg.r[rb]; if(va < vb) c |= CRLT; else if(va == vb) c |= CREQ; else c |= CRGT; c >>= 28; reg.cr = (reg.cr & ~mkCR(rd, 0xF)) | mkCR(rd, c); if(trace) itrace("%s\tcrf%d,r%d,r%d [cr=#%x]", ci->name, rd, ra, rb, c); } void cmpi(ulong ir) { int rd, ra; ulong c; long imm, v; getairr(ir); if(rd & 3) undef(ir); rd >>= 2; v = reg.r[ra]; c = 0; if(reg.xer & XER_SO) c |= CRSO; if(v < imm) c |= CRLT; else if(v == imm) c |= CREQ; else c |= CRGT; c >>= 28; reg.cr = (reg.cr & ~mkCR(rd, 0xF)) | mkCR(rd, c); if(trace) itrace("%s\tcrf%d,r%d,0x%lux [cr=#%x]", ci->name, rd, ra, imm, c); } void cmpl(ulong ir) { int rd, ra, rb; ulong c; ulong va, vb; getarrr(ir); if(rd & 3) undef(ir); rd >>= 2; c = 0; if(reg.xer & XER_SO) c |= CRSO; va = reg.r[ra]; vb = reg.r[rb]; if(va < vb) c |= CRLT; else if(va == vb) c |= CREQ; else c |= CRGT; c >>= 28; reg.cr = (reg.cr & ~mkCR(rd, 0xF)) | mkCR(rd, c); if(trace) itrace("%s\tcrf%d,r%d,r%d [cr=#%x]", ci->name, rd, ra, rb, c); } void cntlzw(ulong ir) { int rs, ra, rb, n; getlrrr(ir); if(rb) undef(ir); for(n=0; n<32 && (reg.r[rs] & (1L<<(31-n))) == 0; n++) ; reg.r[ra] = n; if(trace) itrace("%s%s\tr%d,r%d", ci->name, ir&1?".":"", ra, rs); if(ir & 1) setcr(0, reg.r[ra]); } void eqv(ulong ir) { int rs, ra, rb; getlrrr(ir); reg.r[ra] = ~(reg.r[rs] ^ reg.r[rb]); if(trace) itrace("%s%s\tr%d,r%d,r%d", ci->name, ir&1?".":"", ra, rs, rb); if(ir & 1) setcr(0, reg.r[ra]); } void extsb(ulong ir) { int rs, ra, rb; getlrrr(ir); if(rb) undef(ir); reg.r[ra] = (schar)reg.r[rs]; if(trace) itrace("%s%s\tr%d,r%d", ci->name, ir&1?".":"", ra, rs); if(ir & 1) setcr(0, reg.r[ra]); } void extsh(ulong ir) { int rs, ra, rb; getlrrr(ir); if(rb) undef(ir); reg.r[ra] = (short)reg.r[rs]; if(trace) itrace("%s%s\tr%d,r%d", ci->name, ir&1?".":"", ra, rs); if(ir & 1) setcr(0, reg.r[ra]); } void add(ulong ir) { int rd, ra, rb; uvlong r; getarrr(ir); r = (uvlong)(ulong)reg.r[ra] + (uvlong)(ulong)reg.r[rb]; if(ir & OE) { reg.xer &= ~XER_OV; if(r >> 16) reg.xer |= XER_SO | XER_OV; /* TO DO: rubbish */ } reg.r[rd] = (ulong)r; if(ir & Rc) setcr(0, reg.r[rd]); if(trace) itrace("%s%s%s\tr%d,r%d,r%d", ci->name, ir&OE?"o":"", ir&1?".":"", rd, ra, rb); } void addc(ulong ir) { int rd, ra, rb; ulong v; uvlong r; getarrr(ir); r = (uvlong)(ulong)reg.r[ra] + (uvlong)(ulong)reg.r[rb]; v = r>>32; reg.xer &= ~XER_CA; if(v) reg.xer |= XER_CA; if(ir & OE) { reg.xer &= ~XER_OV; if(v>>1) reg.xer |= XER_SO | XER_OV; } reg.r[rd] = (ulong)r; if(ir & Rc) setcr(0, reg.r[rd]); if(trace) itrace("%s%s%s\tr%d,r%d,r%d", ci->name, ir&OE?"o":"", ir&1?".":"", rd, ra, rb); } void adde(ulong ir) { int rd, ra, rb; ulong v; uvlong r; getarrr(ir); r = (uvlong)(ulong)reg.r[ra] + (uvlong)(ulong)reg.r[rb] + ((reg.xer&XER_CA)!=0); v = r>>32; reg.xer &= ~XER_CA; if(v) reg.xer |= XER_CA; if(ir & OE) { reg.xer &= ~XER_OV; if(v>>1) reg.xer |= XER_SO | XER_OV; } reg.r[rd] = (ulong)r; if(ir & Rc) setcr(0, reg.r[rd]); if(trace) itrace("%s%s%s\tr%d,r%d,r%d", ci->name, ir&OE?"o":"", ir&1?".":"", rd, ra, rb); } void addic(ulong ir) { int rd, ra; long imm; ulong v; uvlong r; getairr(ir); r = (uvlong)(ulong)reg.r[ra] + (uvlong)(ulong)imm; v = r>>32; reg.xer &= ~XER_CA; if(v) reg.xer |= XER_CA; reg.r[rd] = (ulong)r; if(trace) itrace("%s\tr%d,r%d,$%ld", ci->name, rd, ra, imm); } void addiccc(ulong ir) { int rd, ra; long imm; ulong v; uvlong r; getairr(ir); r = (uvlong)(ulong)reg.r[ra] + (uvlong)(ulong)imm; v = r>>32; reg.xer &= ~XER_CA; if(v) reg.xer |= XER_CA; reg.r[rd] = (ulong)r; setcr(0, reg.r[rd]); if(trace) itrace("%s\tr%d,r%d,$%ld", ci->name, rd, ra, imm); } void addme(ulong ir) { int rd, ra, rb; ulong v; uvlong r; getarrr(ir); if(rb) undef(ir); r = (uvlong)(ulong)reg.r[ra] + (uvlong)0xFFFFFFFFU + ((reg.xer&XER_CA)!=0); v = r>>32; reg.xer &= ~XER_CA; if(v) reg.xer |= XER_CA; if(ir & OE) { reg.xer &= ~XER_OV; if(v>>1) reg.xer |= XER_SO | XER_OV; } reg.r[rd] = (ulong)r; if(ir & Rc) setcr(0, reg.r[rd]); if(trace) itrace("%s%s%s\tr%d,r%d", ci->name, ir&OE?"o":"", ir&1?".":"", rd, ra); } void addze(ulong ir) { int rd, ra, rb; ulong v; uvlong r; getarrr(ir); if(rb) undef(ir); r = (uvlong)(ulong)reg.r[ra] + ((reg.xer&XER_CA)!=0); v = r>>32; reg.xer &= ~XER_CA; if(v) reg.xer |= XER_CA; if(ir & OE) { reg.xer &= ~XER_OV; if(v>>1) reg.xer |= XER_SO | XER_OV; } reg.r[rd] = (ulong)r; if(ir & Rc) setcr(0, reg.r[rd]); if(trace) itrace("%s%s%s\tr%d,r%d", ci->name, ir&OE?"o":"", ir&1?".":"", rd, ra); } void divw(ulong ir) { int rd, ra, rb; getarrr(ir); if(reg.r[rb] != 0 && ((ulong)reg.r[ra] != 0x80000000 || reg.r[rb] != -1)) reg.r[rd] = reg.r[ra]/reg.r[rb]; else if(ir & OE) reg.xer |= XER_SO | XER_OV; if(ir & Rc) setcr(0, reg.r[rd]); if(trace) itrace("%s%s%s\tr%d,r%d,r%d", ci->name, ir&OE?"o":"", ir&1?".":"", rd, ra, rb); } void divwu(ulong ir) { int rd, ra, rb; getarrr(ir); if(reg.r[rb] != 0) reg.r[rd] = (ulong)reg.r[ra]/(ulong)reg.r[rb]; else if(ir & OE) reg.xer |= XER_SO | XER_OV; if(ir & Rc) setcr(0, reg.r[rd]); if(trace) itrace("%s%s%s\tr%d,r%d,r%d", ci->name, ir&OE?"o":"", ir&1?".":"", rd, ra, rb); } void mcrxr(ulong ir) { int rd, ra, rb; getarrr(ir); if(rd & 3 || ra != 0 || rb != 0 || ir & Rc) undef(ir); rd >>= 2; reg.cr = (reg.cr & ~mkCR(rd, 0xF)) | mkCR(rd, reg.xer>>28); reg.xer &= ~(0xF<<28); } void mtcrf(ulong ir) { int rs, crm, i; ulong m; if(ir & ((1<<20)|(1<<11)|Rc)) undef(ir); rs = (ir>>21)&0x1F; crm = (ir>>12)&0xFF; m = 0; for(i = 0x80; i; i >>= 1) { m <<= 4; if(crm & i) m |= 0xF; } reg.cr = (reg.cr & ~m) | (reg.r[rs] & m); } void mfcr(ulong ir) { int rd, ra, rb; getarrr(ir); if(ra != 0 || rb != 0 || ir & Rc) undef(ir); reg.r[rd] = reg.cr; } void mulhw(ulong ir) { int rd, ra, rb; getarrr(ir); reg.r[rd] = ((vlong)(long)reg.r[ra]*(long)reg.r[rb])>>32; if(ir & Rc) setcr(0, reg.r[rd]); if(trace) itrace("%s%s%s\tr%d,r%d,r%d", ci->name, ir&OE?"o":"", ir&Rc?".":"", rd, ra, rb); /* BUG: doesn't set OV */ } void mulhwu(ulong ir) { int rd, ra, rb; getarrr(ir); reg.r[rd] = ((uvlong)(ulong)reg.r[ra]*(ulong)reg.r[rb])>>32; if(ir & Rc) setcr(0, reg.r[rd]); /* not sure whether CR setting is signed or unsigned */ if(trace) itrace("%s%s%s\tr%d,r%d,r%d", ci->name, ir&OE?"o":"", ir&Rc?".":"", rd, ra, rb); /* BUG: doesn't set OV */ } void mullw(ulong ir) { int rd, ra, rb; getarrr(ir); reg.r[rd] = (uvlong)(ulong)reg.r[ra]*(ulong)reg.r[rb]; if(ir & Rc) setcr(0, reg.r[rd]); if(trace) itrace("%s%s%s\tr%d,r%d,r%d", ci->name, ir&OE?"o":"", ir&Rc?".":"", rd, ra, rb); /* BUG: doesn't set OV */ } void mulli(ulong ir) { int rd, ra; long imm; getairr(ir); reg.r[rd] = (uvlong)(ulong)reg.r[ra]*(ulong)imm; if(trace) itrace("%s\tr%d,r%d,$%ld", ci->name, rd, ra, imm); } void nand(ulong ir) { int rs, ra, rb; getlrrr(ir); reg.r[ra] = ~(reg.r[rs] & reg.r[rb]); if(ir & Rc) setcr(0, reg.r[ra]); if(trace) itrace("%s%s\tr%d,r%d,r%d", ci->name, ir&1?".":"", ra, rs, rb); } void neg(ulong ir) { int rd, ra, rb; getarrr(ir); if(rb) undef(ir); if(ir & OE) reg.xer &= ~XER_OV; if((ulong)reg.r[ra] == 0x80000000) { if(ir & OE) reg.xer |= XER_SO | XER_OV; reg.r[rd] = reg.r[ra]; } else reg.r[rd] = -reg.r[ra]; if(ir & Rc) setcr(0, reg.r[rd]); } void nor(ulong ir) { int rs, ra, rb; getlrrr(ir); reg.r[ra] = ~(reg.r[rs] | reg.r[rb]); if(ir & Rc) setcr(0, reg.r[ra]); if(trace) itrace("%s%s\tr%d,r%d,r%d", ci->name, ir&1?".":"", ra, rs, rb); } void or(ulong ir) { int rs, ra, rb; getlrrr(ir); reg.r[ra] = reg.r[rs] | reg.r[rb]; if(ir & Rc) setcr(0, reg.r[ra]); if(trace) { if(rs == rb) itrace("mr%s\tr%d,r%d", ir&1?".":"", ra, rs); else itrace("%s%s\tr%d,r%d,r%d", ci->name, ir&1?".":"", ra, rs, rb); } } void orc(ulong ir) { int rs, ra, rb; getlrrr(ir); reg.r[ra] = reg.r[rs] | ~reg.r[rb]; if(ir & Rc) setcr(0, reg.r[ra]); if(trace) itrace("%s%s\tr%d,r%d,r%d", ci->name, ir&1?".":"", ra, rs, rb); } void ori(ulong ir) { int rs, ra; ulong imm; getlirr(ir); reg.r[ra] = reg.r[rs] | imm; if(trace) itrace("%s\tr%d,r%d,$0x%lx", ci->name, ra, rs, imm); } void oris(ulong ir) { int rs, ra; ulong imm; getlirr(ir); reg.r[ra] = reg.r[rs] | (imm<<16); if(trace) itrace("%s\tr%d,r%d,$0x%lx", ci->name, ra, rs, imm); } static ulong mkmask(int mb, int me) { int i; ulong v; if(mb > me) return mkmask(0, me) | mkmask(mb, 31); v = 0; for(i=mb; i<=me; i++) v |= 1L << (31-i); /* don't need a loop, but i'm lazy */ return v; } static ulong rotl(ulong v, int sh) { if(sh == 0) return v; return (v<<sh) | (v>>(32-sh)); } void rlwimi(ulong ir) { int rs, ra, rb, sh; ulong m; getlrrr(ir); sh = rb; m = mkmask((ir>>6)&0x1F, (ir>>1)&0x1F); reg.r[ra] = (reg.r[ra] & ~m) | (rotl(reg.r[rs], sh) & m); if(trace) itrace("%s\tr%d,r%d,%d,#%lux", ci->name, ra, rs, sh, m); if(ir & 1) setcr(0, reg.r[ra]); } void rlwinm(ulong ir) { int rs, ra, rb, sh; ulong m; getlrrr(ir); sh = rb; m = mkmask((ir>>6)&0x1F, (ir>>1)&0x1F); reg.r[ra] = rotl(reg.r[rs], sh) & m; if(trace) itrace("%s%s\tr%d,r%d,%d,#%lux", ci->name, ir&Rc?".":"", ra, rs, sh, m); if(ir & Rc) setcr(0, reg.r[ra]); } void rlwnm(ulong ir) { int rs, ra, rb, sh; ulong m; getlrrr(ir); sh = reg.r[rb] & 0x1F; m = mkmask((ir>>6)&0x1F, (ir>>1)&0x1F); reg.r[ra] = rotl(reg.r[rs], sh) & m; if(trace) itrace("%s\tr%d,r%d,r%d,#%lux", ci->name, ra, rs, rb, m); if(ir & 1) setcr(0, reg.r[ra]); } void slw(ulong ir) { int rs, ra, rb; long v; getlrrr(ir); v = reg.r[rb]; if((v & 0x20) == 0) { v &= 0x1F; reg.r[ra] = (ulong)reg.r[rs] << v; } else reg.r[ra] = 0; if(ir & Rc) setcr(0, reg.r[ra]); if(trace) itrace("%s%s\tr%d,r%d,r%d", ci->name, ir&1?".":"", ra, rs, rb); } void sraw(ulong ir) { int rs, ra, rb; long v; getlrrr(ir); v = reg.r[rb]; if((v & 0x20) == 0) { v &= 0x1F; if(reg.r[rs]&SIGNBIT && v) reg.r[ra] = reg.r[rs]>>v | ~((1<<(32-v))-1); else reg.r[ra] = reg.r[rs]>>v; } else reg.r[ra] = reg.r[rs]&SIGNBIT? ~0: 0; if(ir & Rc) setcr(0, reg.r[ra]); if(trace) itrace("%s%s\tr%d,r%d,r%d", ci->name, ir&1?".":"", ra, rs, rb); } void srawi(ulong ir) { int rs, ra, rb; long v; getlrrr(ir); v = rb; if((v & 0x20) == 0) { v &= 0x1F; if(reg.r[rs]&SIGNBIT && v) reg.r[ra] = reg.r[rs]>>v | ~((1<<(32-v))-1); else reg.r[ra] = reg.r[rs]>>v; } else reg.r[ra] = reg.r[rs]&SIGNBIT? ~0: 0; if(ir & Rc) setcr(0, reg.r[ra]); if(trace) itrace("%s%s\tr%d,r%d,$%d", ci->name, ir&1?".":"", ra, rs, v); } void srw(ulong ir) { int rs, ra, rb; long v; getlrrr(ir); v = reg.r[rb]; if((v & 0x20) == 0) reg.r[ra] = (ulong)reg.r[rs] >> (v&0x1F); else reg.r[ra] = 0; if(ir & Rc) setcr(0, reg.r[ra]); if(trace) itrace("%s%s\tr%d,r%d,r%d", ci->name, ir&1?".":"", ra, rs, rb); } void subf(ulong ir) { int rd, ra, rb; uvlong r; getarrr(ir); r = (uvlong)((ulong)~reg.r[ra]) + (uvlong)(ulong)reg.r[rb] + 1; if(ir & OE) { reg.xer &= ~XER_OV; if(r >> 16) reg.xer |= XER_SO | XER_OV; } reg.r[rd] = (ulong)r; if(ir & Rc) setcr(0, reg.r[rd]); if(trace) itrace("%s%s%s\tr%d,r%d,r%d", ci->name, ir&OE?"o":"", ir&1?".":"", rd, ra, rb); } void subfc(ulong ir) { int rd, ra, rb; ulong v; uvlong r; getarrr(ir); r = (uvlong)((ulong)~reg.r[ra]) + (uvlong)(ulong)reg.r[rb] + 1; v = r>>32; reg.xer &= ~XER_CA; if(v) reg.xer |= XER_CA; if(ir & OE) { reg.xer &= ~XER_OV; if(v>>1) reg.xer |= XER_SO | XER_OV; } reg.r[rd] = (ulong)r; if(ir & Rc) setcr(0, reg.r[rd]); if(trace) itrace("%s%s%s\tr%d,r%d,r%d", ci->name, ir&OE?"o":"", ir&1?".":"", rd, ra, rb); } void subfe(ulong ir) { int rd, ra, rb; ulong v; uvlong r; getarrr(ir); r = (uvlong)((ulong)~reg.r[ra]) + (uvlong)(ulong)reg.r[rb] + ((reg.xer&XER_CA)!=0); v = r>>32; reg.xer &= ~XER_CA; if(v) reg.xer |= XER_CA; if(ir & OE) { reg.xer &= ~XER_OV; if(v>>1) reg.xer |= XER_SO | XER_OV; } reg.r[rd] = (ulong)r; if(ir & Rc) setcr(0, reg.r[rd]); if(trace) itrace("%s%s%s\tr%d,r%d,r%d", ci->name, ir&OE?"o":"", ir&1?".":"", rd, ra, rb); } void subfic(ulong ir) { int rd, ra; long imm; ulong v; uvlong r; getairr(ir); r = (uvlong)((ulong)~reg.r[ra]) + (uvlong)(ulong)imm + 1; v = r>>32; reg.xer &= ~XER_CA; if(v) reg.xer |= XER_CA; reg.r[rd] = (ulong)r; if(trace) itrace("%s\tr%d,r%d,$%ld", ci->name, rd, ra, imm); } void subfme(ulong ir) { int rd, ra, rb; ulong v; uvlong r; getarrr(ir); if(rb) undef(ir); r = (uvlong)((ulong)~reg.r[ra]) + (uvlong)0xFFFFFFFFU + ((reg.xer&XER_CA)!=0); v = r>>32; reg.xer &= ~XER_CA; if(v) reg.xer |= XER_CA; if(ir & OE) { reg.xer &= ~XER_OV; if(v>>1) reg.xer |= XER_SO | XER_OV; } reg.r[rd] = (ulong)r; if(ir & Rc) setcr(0, reg.r[rd]); if(trace) itrace("%s%s%s\tr%d,r%d", ci->name, ir&OE?"o":"", ir&1?".":"", rd, ra); } void subfze(ulong ir) { int rd, ra, rb; ulong v; uvlong r; getarrr(ir); if(rb) undef(ir); r = (uvlong)((ulong)~reg.r[ra]) + ((reg.xer&XER_CA)!=0); v = r>>32; reg.xer &= ~XER_CA; if(v) reg.xer |= XER_CA; if(ir & OE) { reg.xer &= ~XER_OV; if(v>>1) reg.xer |= XER_SO | XER_OV; } reg.r[rd] = (ulong)r; if(ir & Rc) setcr(0, reg.r[rd]); if(trace) itrace("%s%s%s\tr%d,r%d", ci->name, ir&OE?"o":"", ir&1?".":"", rd, ra); } void xor(ulong ir) { int rs, ra, rb; getlrrr(ir); reg.r[ra] = reg.r[rs] ^ reg.r[rb]; if(trace) itrace("%s\tr%d,r%d,r%d", ci->name, ra, rs, rb); } void xori(ulong ir) { int rs, ra; ulong imm; getlirr(ir); reg.r[ra] = reg.r[rs] ^ imm; if(trace) itrace("%s\tr%d,r%d,$0x%lx", ci->name, ra, rs, imm); } void xoris(ulong ir) { int rs, ra; ulong imm; getlirr(ir); reg.r[ra] = reg.r[rs] ^ (imm<<16); if(trace) itrace("%s\tr%d,r%d,$0x%lx", ci->name, ra, rs, imm); } void lwz(ulong ir) { ulong ea; int ra, rd, upd; long imm; getairr(ir); ea = imm; upd = (ir&(1L<<26))!=0; if(ra) { ea += reg.r[ra]; if(upd) reg.r[ra] = ea; } else { if(upd) undef(ir); } if(trace) itrace("%s\tr%d,%ld(r%d) ea=%lux", ci->name, rd, imm, ra, ea); reg.r[rd] = getmem_w(ea); } void lwzx(ulong ir) { ulong ea; int rb, ra, rd, upd; getarrr(ir); ea = reg.r[rb]; upd = getxo(ir)==55; if(ra) { ea += reg.r[ra]; if(upd) reg.r[ra] = ea; if(trace) itrace("%s\tr%d,(r%d+r%d) ea=%lux", ci->name, rd, ra, rb, ea); } else { if(upd) undef(ir); if(trace) itrace("%s\tr%d,(r%d) ea=%lux", ci->name, rd, rb, ea); } reg.r[rd] = getmem_w(ea); } void lwarx(ulong ir) { lwzx(ir); } void lbz(ulong ir) { ulong ea; int ra, rd, upd; long imm; getairr(ir); ea = imm; upd = (ir&(1L<<26))!=0; if(ra) { ea += reg.r[ra]; if(upd) reg.r[ra] = ea; } else { if(upd) undef(ir); } if(trace) itrace("%s\tr%d,%ld(r%d) ea=%lux", ci->name, rd, imm, ra, ea); reg.r[rd] = getmem_b(ea); } void lbzx(ulong ir) { ulong ea; int rb, ra, rd, upd; getarrr(ir); ea = reg.r[rb]; upd = getxo(ir)==119; if(ra) { ea += reg.r[ra]; if(upd) reg.r[ra] = ea; if(trace) itrace("%s\tr%d,(r%d+r%d) ea=%lux", ci->name, rd, ra, rb, ea); } else { if(upd) undef(ir); if(trace) itrace("%s\tr%d,(r%d) ea=%lux", ci->name, rd, rb, ea); } reg.r[rd] = getmem_b(ea); } void stw(ulong ir) { ulong ea; int ra, rd, upd; long imm; getairr(ir); ea = imm; upd = (ir&(1L<<26))!=0; if(ra) { ea += reg.r[ra]; if(upd) reg.r[ra] = ea; } else { if(upd) undef(ir); } if(trace) itrace("%s\tr%d,%ld(r%d) #%lux=#%lux (%ld)", ci->name, rd, imm, ra, ea, reg.r[rd], reg.r[rd]); putmem_w(ea, reg.r[rd]); } void stwx(ulong ir) { ulong ea; int ra, rd, upd, rb; getarrr(ir); ea = reg.r[rb]; upd = getxo(ir)==183; if(ra) { ea += reg.r[ra]; if(upd) reg.r[ra] = ea; if(trace) itrace("%s\tr%d,(r%d+r%d) #%lux=#%lux (%ld)", ci->name, rd, ra, rb, ea, reg.r[rd], reg.r[rd]); } else { if(upd) undef(ir); if(trace) itrace("%s\tr%d,(r%d) #%lux=#%lux (%ld)", ci->name, rd, rb, ea, reg.r[rd], reg.r[rd]); } putmem_w(ea, reg.r[rd]); } void stwcx(ulong ir) { ulong ea; int ra, rd, rb; if((ir & Rc) == 0) undef(ir); getarrr(ir); ea = reg.r[rb]; if(ra) { ea += reg.r[ra]; if(trace) itrace("%s\tr%d,(r%d+r%d) #%lux=#%lux (%ld)", ci->name, rd, ra, rb, ea, reg.r[rd], reg.r[rd]); } else { if(trace) itrace("%s\tr%d,(r%d) #%lux=#%lux (%ld)", ci->name, rd, rb, ea, reg.r[rd], reg.r[rd]); } putmem_w(ea, reg.r[rd]); /* assume a reservation exists; store succeeded */ setcr(0, 0); } void stb(ulong ir) { ulong ea; int ra, rd, upd, v; long imm; getairr(ir); ea = imm; upd = (ir&(1L<<26))!=0; if(ra) { ea += reg.r[ra]; if(upd) reg.r[ra] = ea; } else { if(upd) undef(ir); } v = reg.r[rd] & 0xFF; if(trace) itrace("%s\tr%d,%ld(r%d) #%lux=#%lux (%ld)", ci->name, rd, imm, ra, ea, v, v); putmem_b(ea, v); } void stbx(ulong ir) { ulong ea; int ra, rd, upd, rb, v; getarrr(ir); ea = reg.r[rb]; upd = getxo(ir)==247; v = reg.r[rd] & 0xFF; if(ra) { ea += reg.r[ra]; if(upd) reg.r[ra] = ea; if(trace) itrace("%s\tr%d,(r%d+r%d) #%lux=#%lux (%ld)", ci->name, rd, ra, rb, ea, v, v); } else { if(upd) undef(ir); if(trace) itrace("%s\tr%d,(r%d) #%lux=#%lux (%ld)", ci->name, rd, rb, ea, v, v); } putmem_b(ea, v); } void lhz(ulong ir) { ulong ea; int imm, ra, rd, upd; getairr(ir); ea = imm; upd = (ir&(1L<<26))!=0; if(ra) { ea += reg.r[ra]; if(upd) reg.r[ra] = ea; } else { if(upd) undef(ir); } if(trace) itrace("%s\tr%d,%ld(r%d) ea=%lux", ci->name, rd, imm, ra, ea); reg.r[rd] = getmem_h(ea); } void lhzx(ulong ir) { ulong ea; int rb, ra, rd, upd; getarrr(ir); ea = reg.r[rb]; upd = getxo(ir)==311; if(ra) { ea += reg.r[ra]; if(upd) reg.r[ra] = ea; if(trace) itrace("%s\tr%d,(r%d+r%d) ea=%lux", ci->name, rd, ra, rb, ea); } else { if(upd) undef(ir); if(trace) itrace("%s\tr%d,(r%d) ea=%lux", ci->name, rd, rb, ea); } reg.r[rd] = getmem_h(ea); } void lha(ulong ir) { ulong ea; int imm, ra, rd, upd; getairr(ir); ea = imm; upd = (ir&(1L<<26))!=0; if(ra) { ea += reg.r[ra]; if(upd) reg.r[ra] = ea; } else { if(upd) undef(ir); } if(trace) itrace("%s\tr%d,%ld(r%d) ea=%lux", ci->name, rd, imm, ra, ea); reg.r[rd] = (short)getmem_h(ea); } void lhax(ulong ir) { ulong ea; int rb, ra, rd, upd; getarrr(ir); ea = reg.r[rb]; upd = getxo(ir)==311; if(ra) { ea += reg.r[ra]; if(upd) reg.r[ra] = ea; if(trace) itrace("%s\tr%d,(r%d+r%d) ea=%lux", ci->name, rd, ra, rb, ea); } else { if(upd) undef(ir); if(trace) itrace("%s\tr%d,(r%d) ea=%lux", ci->name, rd, rb, ea); } reg.r[rd] = (short)getmem_h(ea); } void lhbrx(ulong ir) { ulong ea; int rb, ra, rd; ulong v; getarrr(ir); ea = reg.r[rb]; if(ra) { ea += reg.r[ra]; if(trace) itrace("%s\tr%d,(r%d+r%d) ea=%lux", ci->name, rd, ra, rb, ea); } else { if(trace) itrace("%s\tr%d,(r%d) ea=%lux", ci->name, rd, rb, ea); } v = getmem_h(ea); reg.r[rd] = ((v&0xFF)<<8)|(v&0xFF); } void sth(ulong ir) { ulong ea; int imm, ra, rd, upd, v; getairr(ir); ea = imm; upd = (ir&(1L<<26))!=0; if(ra) { ea += reg.r[ra]; if(upd) reg.r[ra] = ea; } else { if(upd) undef(ir); } v = reg.r[rd] & 0xFFFF; if(trace) itrace("%s\tr%d,%ld(r%d) #%lux=#%lux (%ld)", ci->name, rd, imm, ra, ea, v, v); putmem_h(ea, v); } void sthx(ulong ir) { ulong ea; int ra, rd, upd, rb, v; getarrr(ir); ea = reg.r[rb]; upd = getxo(ir)==247; v = reg.r[rd] & 0xFFFF; if(ra) { ea += reg.r[ra]; if(upd) reg.r[ra] = ea; if(trace) itrace("%s\tr%d,(r%d+r%d) #%lux=#%lux (%ld)", ci->name, rd, ra, rb, ea, v, v); } else { if(upd) undef(ir); if(trace) itrace("%s\tr%d,(r%d) #%lux=#%lux (%ld)", ci->name, rd, rb, ea, v, v); } putmem_h(ea, v); } void sthbrx(ulong ir) { ulong ea; int ra, rd, rb; ulong v; getarrr(ir); ea = reg.r[rb]; v = reg.r[rd]; v = ((v&0xFF)<<8)|(v&0xFF); if(ra) { ea += reg.r[ra]; if(trace) itrace("%s\tr%d,(r%d+r%d) #%lux=#%lux (%ld)", ci->name, rd, ra, rb, ea, v, v); } else { if(trace) itrace("%s\tr%d,(r%d) #%lux=#%lux (%ld)", ci->name, rd, rb, ea, v, v); } putmem_h(ea, v); } void lwbrx(ulong ir) { ulong ea; int rb, ra, rd, i; ulong v; getarrr(ir); if(ir & Rc) undef(ir); ea = reg.r[rb]; if(ra) { ea += reg.r[ra]; if(trace) itrace("%s\tr%d,(r%d+r%d) ea=%lux", ci->name, rd, ra, rb, ea); } else { if(trace) itrace("%s\tr%d,(r%d) ea=%lux", ci->name, rd, rb, ea); } v = 0; for(i = 0; i < 4; i++) v = v>>8 | getmem_b(ea++); /* assume unaligned load is allowed */ reg.r[rd] = v; } void stwbrx(ulong ir) { ulong ea; int rb, ra, rd, i; ulong v; getarrr(ir); if(ir & Rc) undef(ir); ea = reg.r[rb]; if(ra) { ea += reg.r[ra]; if(trace) itrace("%s\tr%d,(r%d+r%d) ea=%lux", ci->name, rd, ra, rb, ea); } else { if(trace) itrace("%s\tr%d,(r%d) ea=%lux", ci->name, rd, rb, ea); } v = 0; for(i = 0; i < 4; i++) { putmem_b(ea++, v & 0xFF); /* assume unaligned store is allowed */ v >>= 8; } } void lswi(ulong ir) { ulong ea; int rb, ra, rd, n, i, r, b; getarrr(ir); if(ir & Rc) undef(ir); n = rb; if(n == 0) n = 32; ea = 0; if(ra) { ea += reg.r[ra]; if(trace) itrace("%s\tr%d,(r%d),%d ea=%lux", ci->name, rd, ra, n, ea); } else { if(trace) itrace("%s\tr%d,(0),%d ea=0", ci->name, rd, n); } i = -1; r = rd-1; while(--n >= 0) { if(i < 0) { r = (r+1)&0x1F; if(ra == 0 || r != ra) reg.r[r] = 0; i = 24; } b = getmem_b(ea++); if(ra == 0 || r != ra) reg.r[r] = (reg.r[r] & ~(0xFF<<i)) | (b << i); i -= 8; } } void lswx(ulong ir) { ulong ea; int rb, ra, rd, n, i, r, b; getarrr(ir); if(ir & Rc) undef(ir); n = reg.xer & 0x7F; ea = reg.r[rb]; if(ra) { ea += reg.r[ra]; if(trace) itrace("%s\tr%d,(r%d+r%d) ea=%lux n=%d", ci->name, rd, ra, rb, ea, n); } else { if(trace) itrace("%s\tr%d,(r%d) ea=%lux n=%d", ci->name, rd, rb, ea, n); } i = -1; r = rd-1; while(--n >= 0) { if(i < 0) { r = (r+1)&0x1F; if((ra == 0 || r != ra) && r != rb) reg.r[r] = 0; i = 24; } b = getmem_b(ea++); if((ra == 0 || r != ra) && r != rb) reg.r[r] = (reg.r[r] & ~(0xFF<<i)) | (b << i); i -= 8; } } void stswx(ulong ir) { ulong ea; int rb, ra, rd, n, i, r; getarrr(ir); if(ir & Rc) undef(ir); n = reg.xer & 0x7F; ea = reg.r[rb]; if(ra) { ea += reg.r[ra]; if(trace) itrace("%s\tr%d,(r%d+r%d) ea=%lux n=%d", ci->name, rd, ra, rb, ea, n); } else { if(trace) itrace("%s\tr%d,(r%d) ea=%lux n=%d", ci->name, rd, rb, ea, n); } i = -1; r = rd-1; while(--n >= 0) { if(i < 0) { r = (r+1)&0x1F; i = 24; } putmem_b(ea++, (reg.r[r]>>i)&0xFF); i -= 8; } } void stswi(ulong ir) { ulong ea; int rb, ra, rd, n, i, r; getarrr(ir); if(ir & Rc) undef(ir); n = rb; if(n == 0) n = 32; ea = 0; if(ra) { ea += reg.r[ra]; if(trace) itrace("%s\tr%d,(r%d),%d ea=%lux", ci->name, rd, ra, n, ea); } else { if(trace) itrace("%s\tr%d,(0),%d ea=0", ci->name, rd, n); } i = -1; r = rd-1; while(--n >= 0) { if(i < 0) { r = (r+1)&0x1F; i = 24; } putmem_b(ea++, (reg.r[r]>>i)&0xFF); i -= 8; } } void lmw(ulong ir) { ulong ea; int ra, rd, r; long imm; getairr(ir); ea = imm; if(ra) ea += reg.r[ra]; if(trace) itrace("%s\tr%d,%ld(r%d) ea=%lux", ci->name, rd, imm, ra, ea); for(r = rd; r <= 31; r++) { if(r != 0 && r != rd) reg.r[rd] = getmem_w(ea); ea += 4; } } void stmw(ulong ir) { ulong ea; int ra, rd, r; long imm; getairr(ir); ea = imm; if(ra) ea += reg.r[ra]; if(trace) itrace("%s\tr%d,%ld(r%d) ea=%lux", ci->name, rd, imm, ra, ea); for(r = rd; r <= 31; r++) { putmem_w(ea, reg.r[rd]); ea += 4; } } void twi(ulong ir) { int rd, ra; long a, imm; getairr(ir); a = reg.r[ra]; if(trace) itrace("twi\t#%.2x,r%d,$0x%lux (%ld)", rd, ra, imm, imm); if(a < imm && rd&0x10 || a > imm && rd&0x08 || a == imm && rd&0x04 || (ulong)a < imm && rd&0x02 || (ulong)a > imm && rd&0x01) { Bprint(bioout, "program_exception (trap type)\n"); longjmp(errjmp, 0); } } void tw(ulong ir) { int rd, ra, rb; long a, b; getarrr(ir); a = reg.r[ra]; b = reg.r[rb]; if(trace) itrace("tw\t#%.2x,r%d,r%d", rd, ra, rb); if(a < b && rd&0x10 || a > b && rd&0x08 || a == b && rd&0x04 || (ulong)a < b && rd&0x02 || (ulong)a > b && rd&0x01) { Bprint(bioout, "program_exception (trap type)\n"); longjmp(errjmp, 0); } } void sync(ulong ir) { USED(ir); if(trace) itrace("sync"); } void icbi(ulong ir) { int rd, ra, rb; if(ir & Rc) undef(ir); getarrr(ir); USED(rd); if(trace) itrace("%s\tr%d,r%d", ci->name, ra, rb); } void dcbf(ulong ir) { int rd, ra, rb; if(ir & Rc) undef(ir); getarrr(ir); USED(rd); if(trace) itrace("%s\tr%d,r%d", ci->name, ra, rb); } void dcbst(ulong ir) { int rd, ra, rb; if(ir & Rc) undef(ir); getarrr(ir); USED(rd); if(trace) itrace("%s\tr%d,r%d", ci->name, ra, rb); } void dcbt(ulong ir) { int rd, ra, rb; if(ir & Rc) undef(ir); getarrr(ir); USED(rd); if(trace) itrace("%s\tr%d,r%d", ci->name, ra, rb); } void dcbtst(ulong ir) { int rd, ra, rb; if(ir & Rc) undef(ir); getarrr(ir); USED(rd); if(trace) itrace("%s\tr%d,r%d", ci->name, ra, rb); } void dcbz(ulong ir) { int rd, ra, rb; if(ir & Rc) undef(ir); getarrr(ir); USED(rd); if(trace) itrace("%s\tr%d,r%d", ci->name, ra, rb); }