/* * This file is part of the UCB release of Plan 9. It is subject to the license * terms in the LICENSE file found in the top-level directory of this * distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No * part of the UCB release of Plan 9, including this file, may be copied, * modified, propagated, or distributed except according to the terms contained * in the LICENSE file. */ #include <u.h>#include <libc.h>#include <bio.h>#include <mach.h>#define Extern extern#include "power.h" void mcrf(ulong);void bclr(ulong);void crop(ulong);void bcctr(ulong);void call(ulong);void ret(ulong);void isync(ulong); Inst op19[] = {[0] {mcrf, "mcrf", Ibranch},[16] {bclr, "bclr", Ibranch},[33] {crop, "crnor", Ibranch},[15] {0, "rfi", Ibranch},[129] {crop, "crandc", Ibranch},[150] {isync, "isync", Ibranch},[193] {crop, "crxor", Ibranch},[225] {crop, "crnand", Ibranch},[257] {crop, "crand", Ibranch},[289] {crop, "creqv", Ibranch},[417] {crop, "crorc", Ibranch},[449] {crop, "cror", Ibranch},[528] {bcctr, "bcctr", Ibranch}, {0, 0, 0}}; Inset ops19 = {op19, nelem(op19)-1}; static char *boname(int bo){ static char buf[8]; switch(bo>>1){ case 0: return "dnzf"; case 1: return "dzf"; case 2: return "f"; case 4: return "dnzt"; case 5: return "dzt"; case 6: return "t"; case 8: return "dnz"; case 9: return "dz"; case 10: return "a"; default: sprint(buf, "%d?", bo); return buf; }} static char *cname(int bo, int bi){ int f; char *p; static char buf[20]; static char *f0[] = {"lt", "gt", "eq", "so/un"}; if(bo == 0x14){ /* branch always */ sprint(buf,"%d", bi); return buf; } for(f = 0; bi >= 4; bi -= 4) f++; p = buf; p += sprint(buf, "%d[", bi); if(f) p += sprint(buf, "cr%d+", f); strcpy(p, f0[bi&3]); strcat(p, "]"); return buf;} static intcondok(ulong ir, int ctr){ int bo, bi, xx; getbobi(ir); if(xx) undef(ir); if((bo & 0x4) == 0) { if(!ctr) undef(ir); reg.ctr--; } if(bo & 0x4 || (reg.ctr!=0)^((bo>>1)&1)) { if(bo & 0x10 || (((reg.cr & bits[bi])!=0)==((bo>>3)&1))) return 1; } return 0;} static voiddobranch(ulong ir, ulong *r, int ctr){ int bo, bi, xx; ulong nia; getbobi(ir); USED(xx); if(condok(ir, ctr)) { ci->taken++; nia = *r & ~3; if(bo & 4) /* assume counting branches aren't returns */ ret(nia); } else nia = reg.pc + 4; if(trace) itrace("%s%s\t%s,%s,#%.8lux", ci->name, ir&1? "l": "", boname(bo), cname(bo, bi), nia); if(ir & 1) { call(nia); reg.lr = reg.pc + 4; } reg.pc = nia-4; /* branch delays? */} voidbcctr(ulong ir){ dobranch(ir, ®.ctr, 1);} voidbclr(ulong ir){ dobranch(ir, ®.lr, 0);} voidbcx(ulong ir){ int bo, bi, xx; ulong ea; long imm; static char *opc[] = {"bc", "bcl", "bca", "bcla"}; getbobi(ir); USED(xx); imm = ir & 0xFFFC; if(ir & 0x08000) imm |= 0xFFFF0000; if((ir & 2) == 0) { /* not absolute address */ ea = reg.pc + imm; if(trace) itrace("%s\t%s,%s,.%s%ld\tea = #%.8lux", opc[ir&3], boname(bo), cname(bo, bi), imm<0?"":"+", imm, ea); } else { ea = imm; if(trace) itrace("%s\t%s,%s,#%.8lux", opc[ir&3], boname(bo), cname(bo, bi), ea); } if(condok(ir&0xFFFF0000, 1)) ci->taken++; else ea = reg.pc + 4; if(ir & 1) { call(ea); reg.lr = reg.pc+4; } reg.pc = ea-4; /* branch delay? */} voidcrop(ulong ir){ int rd, ra, rb, d; getarrr(ir); if(trace) itrace("%s\tcrb%d,crb%d,crb%d", ci->name, rd, ra, rb); ra = (reg.cr & bits[ra]) != 0; rb = (reg.cr & bits[rb]) != 0; d = 0; switch(getxo(ir)) { case 257: d = ra & rb; break; case 129: d = ra & !rb; break; case 289: d = ra == rb; break; case 225: d = !(ra & rb); break; case 33: d = !(ra | rb); break; case 449: d = ra | rb; break; case 417: d = ra | !rb; break; case 193: d = ra ^ rb; break; default: undef(ir); break; } if(d) reg.cr |= bits[rd];} voidmcrf(ulong ir){ int rd, ra, rb; getarrr(ir); if(ir & 1 || rd & 3 || ra & 3 || rb) undef(ir); ra >>= 2; rd >>= 2; reg.cr = (reg.cr & ~mkCR(rd, 0xF)) | mkCR(rd, getCR(ra, reg.cr)); if(trace) itrace("mcrf\tcrf%d,crf%d", rd, ra);} voidcall(ulong npc){ Symbol s; 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'); }} voidret(ulong npc){ Symbol s; if(calltree) { findsym(npc, CTEXT, &s); Bprint(bioout, "%8lux return to #%lux %s r3=#%lux (%ld)\n", reg.pc, npc, s.name, reg.r[3], reg.r[3]); }} voidbx(ulong ir){ ulong ea; long imm; static char *opc[] = {"b", "bl", "ba", "bla"}; imm = ir & 0x03FFFFFC; if(ir & 0x02000000) imm |= 0xFC000000; if((ir & 2) == 0) { /* not absolute address */ ea = reg.pc + imm; if(trace) itrace("%s\t.%s%ld\tea = #%.8lux", opc[ir&3], imm<0?"":"+", imm, ea); } else { ea = imm; if(trace) itrace("%s\t#%.8lux", opc[ir&3], ea); } ci->taken++; if(ir & 1) { call(ea); reg.lr = reg.pc+4; } reg.pc = ea-4; /* branch delay? */} voidisync(ulong ir){ USED(ir); if(trace) itrace("isync");}
/*
* This file is part of the UCB release of Plan 9. It is subject to the license
* terms in the LICENSE file found in the top-level directory of this
* distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No
* part of the UCB release of Plan 9, including this file, may be copied,
* modified, propagated, or distributed except according to the terms contained
* in the LICENSE file.
*/
#include <u.h>
#include <libc.h>
#include <bio.h>
#include <mach.h>
#define Extern extern
#include "power.h"
void mcrf(ulong);
void bclr(ulong);
void crop(ulong);
void bcctr(ulong);
void call(ulong);
void ret(ulong);
void isync(ulong);
Inst op19[] = {
[0] {mcrf, "mcrf", Ibranch},
[16] {bclr, "bclr", Ibranch},
[33] {crop, "crnor", Ibranch},
[15] {0, "rfi", Ibranch},
[129] {crop, "crandc", Ibranch},
[150] {isync, "isync", Ibranch},
[193] {crop, "crxor", Ibranch},
[225] {crop, "crnand", Ibranch},
[257] {crop, "crand", Ibranch},
[289] {crop, "creqv", Ibranch},
[417] {crop, "crorc", Ibranch},
[449] {crop, "cror", Ibranch},
[528] {bcctr, "bcctr", Ibranch},
{0, 0, 0}
};
Inset ops19 = {op19, nelem(op19)-1};
static char *
boname(int bo)
{
static char buf[8];
switch(bo>>1){
case 0: return "dnzf";
case 1: return "dzf";
case 2: return "f";
case 4: return "dnzt";
case 5: return "dzt";
case 6: return "t";
case 8: return "dnz";
case 9: return "dz";
case 10: return "a";
default:
sprint(buf, "%d?", bo);
return buf;
}
}
static char *
cname(int bo, int bi)
{
int f;
char *p;
static char buf[20];
static char *f0[] = {"lt", "gt", "eq", "so/un"};
if(bo == 0x14){ /* branch always */
sprint(buf,"%d", bi);
return buf;
}
for(f = 0; bi >= 4; bi -= 4)
f++;
p = buf;
p += sprint(buf, "%d[", bi);
if(f)
p += sprint(buf, "cr%d+", f);
strcpy(p, f0[bi&3]);
strcat(p, "]");
return buf;
}
static int
condok(ulong ir, int ctr)
{
int bo, bi, xx;
getbobi(ir);
if(xx)
undef(ir);
if((bo & 0x4) == 0) {
if(!ctr)
undef(ir);
reg.ctr--;
}
if(bo & 0x4 || (reg.ctr!=0)^((bo>>1)&1)) {
if(bo & 0x10 || (((reg.cr & bits[bi])!=0)==((bo>>3)&1)))
return 1;
}
return 0;
}
static void
dobranch(ulong ir, ulong *r, int ctr)
{
int bo, bi, xx;
ulong nia;
getbobi(ir);
USED(xx);
if(condok(ir, ctr)) {
ci->taken++;
nia = *r & ~3;
if(bo & 4) /* assume counting branches aren't returns */
ret(nia);
} else
nia = reg.pc + 4;
if(trace)
itrace("%s%s\t%s,%s,#%.8lux", ci->name, ir&1? "l": "", boname(bo), cname(bo, bi), nia);
if(ir & 1) {
call(nia);
reg.lr = reg.pc + 4;
}
reg.pc = nia-4;
/* branch delays? */
}
void
bcctr(ulong ir)
{
dobranch(ir, ®.ctr, 1);
}
void
bclr(ulong ir)
{
dobranch(ir, ®.lr, 0);
}
void
bcx(ulong ir)
{
int bo, bi, xx;
ulong ea;
long imm;
static char *opc[] = {"bc", "bcl", "bca", "bcla"};
getbobi(ir);
USED(xx);
imm = ir & 0xFFFC;
if(ir & 0x08000)
imm |= 0xFFFF0000;
if((ir & 2) == 0) { /* not absolute address */
ea = reg.pc + imm;
if(trace)
itrace("%s\t%s,%s,.%s%ld\tea = #%.8lux", opc[ir&3], boname(bo), cname(bo, bi), imm<0?"":"+", imm, ea);
} else {
ea = imm;
if(trace)
itrace("%s\t%s,%s,#%.8lux", opc[ir&3], boname(bo), cname(bo, bi), ea);
}
if(condok(ir&0xFFFF0000, 1))
ci->taken++;
else
ea = reg.pc + 4;
if(ir & 1) {
call(ea);
reg.lr = reg.pc+4;
}
reg.pc = ea-4;
/* branch delay? */
}
void
crop(ulong ir)
{
int rd, ra, rb, d;
getarrr(ir);
if(trace)
itrace("%s\tcrb%d,crb%d,crb%d", ci->name, rd, ra, rb);
ra = (reg.cr & bits[ra]) != 0;
rb = (reg.cr & bits[rb]) != 0;
d = 0;
switch(getxo(ir)) {
case 257: d = ra & rb; break;
case 129: d = ra & !rb; break;
case 289: d = ra == rb; break;
case 225: d = !(ra & rb); break;
case 33: d = !(ra | rb); break;
case 449: d = ra | rb; break;
case 417: d = ra | !rb; break;
case 193: d = ra ^ rb; break;
default: undef(ir); break;
}
if(d)
reg.cr |= bits[rd];
}
void
mcrf(ulong ir)
{
int rd, ra, rb;
getarrr(ir);
if(ir & 1 || rd & 3 || ra & 3 || rb)
undef(ir);
ra >>= 2;
rd >>= 2;
reg.cr = (reg.cr & ~mkCR(rd, 0xF)) | mkCR(rd, getCR(ra, reg.cr));
if(trace)
itrace("mcrf\tcrf%d,crf%d", rd, ra);
}
void
call(ulong npc)
{
Symbol s;
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');
}
}
void
ret(ulong npc)
{
Symbol s;
if(calltree) {
findsym(npc, CTEXT, &s);
Bprint(bioout, "%8lux return to #%lux %s r3=#%lux (%ld)\n",
reg.pc, npc, s.name, reg.r[3], reg.r[3]);
}
}
void
bx(ulong ir)
{
ulong ea;
long imm;
static char *opc[] = {"b", "bl", "ba", "bla"};
imm = ir & 0x03FFFFFC;
if(ir & 0x02000000)
imm |= 0xFC000000;
if((ir & 2) == 0) { /* not absolute address */
ea = reg.pc + imm;
if(trace)
itrace("%s\t.%s%ld\tea = #%.8lux", opc[ir&3], imm<0?"":"+", imm, ea);
} else {
ea = imm;
if(trace)
itrace("%s\t#%.8lux", opc[ir&3], ea);
}
ci->taken++;
if(ir & 1) {
call(ea);
reg.lr = reg.pc+4;
}
reg.pc = ea-4;
/* branch delay? */
}
void
isync(ulong ir)
{
USED(ir);
if(trace)
itrace("isync");
}