1*7d9195a7SDavid du Colombier #include <u.h>
2*7d9195a7SDavid du Colombier #include <libc.h>
3*7d9195a7SDavid du Colombier #include <bio.h>
4*7d9195a7SDavid du Colombier #include <mach.h>
5*7d9195a7SDavid du Colombier #define Extern extern
6*7d9195a7SDavid du Colombier #include "power.h"
7*7d9195a7SDavid du Colombier
8*7d9195a7SDavid du Colombier void mcrf(ulong);
9*7d9195a7SDavid du Colombier void bclr(ulong);
10*7d9195a7SDavid du Colombier void crop(ulong);
11*7d9195a7SDavid du Colombier void bcctr(ulong);
12*7d9195a7SDavid du Colombier void call(ulong);
13*7d9195a7SDavid du Colombier void ret(ulong);
14*7d9195a7SDavid du Colombier void isync(ulong);
15*7d9195a7SDavid du Colombier
16*7d9195a7SDavid du Colombier Inst op19[] = {
17*7d9195a7SDavid du Colombier [0] {mcrf, "mcrf", Ibranch},
18*7d9195a7SDavid du Colombier [16] {bclr, "bclr", Ibranch},
19*7d9195a7SDavid du Colombier [33] {crop, "crnor", Ibranch},
20*7d9195a7SDavid du Colombier [15] {0, "rfi", Ibranch},
21*7d9195a7SDavid du Colombier [129] {crop, "crandc", Ibranch},
22*7d9195a7SDavid du Colombier [150] {isync, "isync", Ibranch},
23*7d9195a7SDavid du Colombier [193] {crop, "crxor", Ibranch},
24*7d9195a7SDavid du Colombier [225] {crop, "crnand", Ibranch},
25*7d9195a7SDavid du Colombier [257] {crop, "crand", Ibranch},
26*7d9195a7SDavid du Colombier [289] {crop, "creqv", Ibranch},
27*7d9195a7SDavid du Colombier [417] {crop, "crorc", Ibranch},
28*7d9195a7SDavid du Colombier [449] {crop, "cror", Ibranch},
29*7d9195a7SDavid du Colombier [528] {bcctr, "bcctr", Ibranch},
30*7d9195a7SDavid du Colombier {0, 0, 0}
31*7d9195a7SDavid du Colombier };
32*7d9195a7SDavid du Colombier
33*7d9195a7SDavid du Colombier Inset ops19 = {op19, nelem(op19)-1};
34*7d9195a7SDavid du Colombier
35*7d9195a7SDavid du Colombier static char *
boname(int bo)36*7d9195a7SDavid du Colombier boname(int bo)
37*7d9195a7SDavid du Colombier {
38*7d9195a7SDavid du Colombier static char buf[8];
39*7d9195a7SDavid du Colombier
40*7d9195a7SDavid du Colombier switch(bo>>1){
41*7d9195a7SDavid du Colombier case 0: return "dnzf";
42*7d9195a7SDavid du Colombier case 1: return "dzf";
43*7d9195a7SDavid du Colombier case 2: return "f";
44*7d9195a7SDavid du Colombier case 4: return "dnzt";
45*7d9195a7SDavid du Colombier case 5: return "dzt";
46*7d9195a7SDavid du Colombier case 6: return "t";
47*7d9195a7SDavid du Colombier case 8: return "dnz";
48*7d9195a7SDavid du Colombier case 9: return "dz";
49*7d9195a7SDavid du Colombier case 10: return "a";
50*7d9195a7SDavid du Colombier default:
51*7d9195a7SDavid du Colombier sprint(buf, "%d?", bo);
52*7d9195a7SDavid du Colombier return buf;
53*7d9195a7SDavid du Colombier }
54*7d9195a7SDavid du Colombier }
55*7d9195a7SDavid du Colombier
56*7d9195a7SDavid du Colombier static char *
cname(int bo,int bi)57*7d9195a7SDavid du Colombier cname(int bo, int bi)
58*7d9195a7SDavid du Colombier {
59*7d9195a7SDavid du Colombier int f;
60*7d9195a7SDavid du Colombier char *p;
61*7d9195a7SDavid du Colombier static char buf[20];
62*7d9195a7SDavid du Colombier static char *f0[] = {"lt", "gt", "eq", "so/un"};
63*7d9195a7SDavid du Colombier
64*7d9195a7SDavid du Colombier if(bo == 0x14){ /* branch always */
65*7d9195a7SDavid du Colombier sprint(buf,"%d", bi);
66*7d9195a7SDavid du Colombier return buf;
67*7d9195a7SDavid du Colombier }
68*7d9195a7SDavid du Colombier for(f = 0; bi >= 4; bi -= 4)
69*7d9195a7SDavid du Colombier f++;
70*7d9195a7SDavid du Colombier p = buf;
71*7d9195a7SDavid du Colombier p += sprint(buf, "%d[", bi);
72*7d9195a7SDavid du Colombier if(f)
73*7d9195a7SDavid du Colombier p += sprint(buf, "cr%d+", f);
74*7d9195a7SDavid du Colombier strcpy(p, f0[bi&3]);
75*7d9195a7SDavid du Colombier strcat(p, "]");
76*7d9195a7SDavid du Colombier return buf;
77*7d9195a7SDavid du Colombier }
78*7d9195a7SDavid du Colombier
79*7d9195a7SDavid du Colombier static int
condok(ulong ir,int ctr)80*7d9195a7SDavid du Colombier condok(ulong ir, int ctr)
81*7d9195a7SDavid du Colombier {
82*7d9195a7SDavid du Colombier int bo, bi, xx;
83*7d9195a7SDavid du Colombier
84*7d9195a7SDavid du Colombier getbobi(ir);
85*7d9195a7SDavid du Colombier if(xx)
86*7d9195a7SDavid du Colombier undef(ir);
87*7d9195a7SDavid du Colombier if((bo & 0x4) == 0) {
88*7d9195a7SDavid du Colombier if(!ctr)
89*7d9195a7SDavid du Colombier undef(ir);
90*7d9195a7SDavid du Colombier reg.ctr--;
91*7d9195a7SDavid du Colombier }
92*7d9195a7SDavid du Colombier if(bo & 0x4 || (reg.ctr!=0)^((bo>>1)&1)) {
93*7d9195a7SDavid du Colombier if(bo & 0x10 || (((reg.cr & bits[bi])!=0)==((bo>>3)&1)))
94*7d9195a7SDavid du Colombier return 1;
95*7d9195a7SDavid du Colombier }
96*7d9195a7SDavid du Colombier return 0;
97*7d9195a7SDavid du Colombier }
98*7d9195a7SDavid du Colombier
99*7d9195a7SDavid du Colombier static void
dobranch(ulong ir,ulong * r,int ctr)100*7d9195a7SDavid du Colombier dobranch(ulong ir, ulong *r, int ctr)
101*7d9195a7SDavid du Colombier {
102*7d9195a7SDavid du Colombier int bo, bi, xx;
103*7d9195a7SDavid du Colombier ulong nia;
104*7d9195a7SDavid du Colombier
105*7d9195a7SDavid du Colombier getbobi(ir);
106*7d9195a7SDavid du Colombier USED(xx);
107*7d9195a7SDavid du Colombier if(condok(ir, ctr)) {
108*7d9195a7SDavid du Colombier ci->taken++;
109*7d9195a7SDavid du Colombier nia = *r & ~3;
110*7d9195a7SDavid du Colombier if(bo & 4) /* assume counting branches aren't returns */
111*7d9195a7SDavid du Colombier ret(nia);
112*7d9195a7SDavid du Colombier } else
113*7d9195a7SDavid du Colombier nia = reg.pc + 4;
114*7d9195a7SDavid du Colombier if(trace)
115*7d9195a7SDavid du Colombier itrace("%s%s\t%s,%s,#%.8lux", ci->name, ir&1? "l": "", boname(bo), cname(bo, bi), nia);
116*7d9195a7SDavid du Colombier if(ir & 1) {
117*7d9195a7SDavid du Colombier call(nia);
118*7d9195a7SDavid du Colombier reg.lr = reg.pc + 4;
119*7d9195a7SDavid du Colombier }
120*7d9195a7SDavid du Colombier reg.pc = nia-4;
121*7d9195a7SDavid du Colombier /* branch delays? */
122*7d9195a7SDavid du Colombier }
123*7d9195a7SDavid du Colombier
124*7d9195a7SDavid du Colombier void
bcctr(ulong ir)125*7d9195a7SDavid du Colombier bcctr(ulong ir)
126*7d9195a7SDavid du Colombier {
127*7d9195a7SDavid du Colombier dobranch(ir, ®.ctr, 1);
128*7d9195a7SDavid du Colombier }
129*7d9195a7SDavid du Colombier
130*7d9195a7SDavid du Colombier void
bclr(ulong ir)131*7d9195a7SDavid du Colombier bclr(ulong ir)
132*7d9195a7SDavid du Colombier {
133*7d9195a7SDavid du Colombier dobranch(ir, ®.lr, 0);
134*7d9195a7SDavid du Colombier }
135*7d9195a7SDavid du Colombier
136*7d9195a7SDavid du Colombier void
bcx(ulong ir)137*7d9195a7SDavid du Colombier bcx(ulong ir)
138*7d9195a7SDavid du Colombier {
139*7d9195a7SDavid du Colombier int bo, bi, xx;
140*7d9195a7SDavid du Colombier ulong ea;
141*7d9195a7SDavid du Colombier long imm;
142*7d9195a7SDavid du Colombier static char *opc[] = {"bc", "bcl", "bca", "bcla"};
143*7d9195a7SDavid du Colombier
144*7d9195a7SDavid du Colombier getbobi(ir);
145*7d9195a7SDavid du Colombier USED(xx);
146*7d9195a7SDavid du Colombier imm = ir & 0xFFFC;
147*7d9195a7SDavid du Colombier if(ir & 0x08000)
148*7d9195a7SDavid du Colombier imm |= 0xFFFF0000;
149*7d9195a7SDavid du Colombier if((ir & 2) == 0) { /* not absolute address */
150*7d9195a7SDavid du Colombier ea = reg.pc + imm;
151*7d9195a7SDavid du Colombier if(trace)
152*7d9195a7SDavid du Colombier itrace("%s\t%s,%s,.%s%ld\tea = #%.8lux", opc[ir&3], boname(bo), cname(bo, bi), imm<0?"":"+", imm, ea);
153*7d9195a7SDavid du Colombier } else {
154*7d9195a7SDavid du Colombier ea = imm;
155*7d9195a7SDavid du Colombier if(trace)
156*7d9195a7SDavid du Colombier itrace("%s\t%s,%s,#%.8lux", opc[ir&3], boname(bo), cname(bo, bi), ea);
157*7d9195a7SDavid du Colombier }
158*7d9195a7SDavid du Colombier if(condok(ir&0xFFFF0000, 1))
159*7d9195a7SDavid du Colombier ci->taken++;
160*7d9195a7SDavid du Colombier else
161*7d9195a7SDavid du Colombier ea = reg.pc + 4;
162*7d9195a7SDavid du Colombier if(ir & 1) {
163*7d9195a7SDavid du Colombier call(ea);
164*7d9195a7SDavid du Colombier reg.lr = reg.pc+4;
165*7d9195a7SDavid du Colombier }
166*7d9195a7SDavid du Colombier reg.pc = ea-4;
167*7d9195a7SDavid du Colombier /* branch delay? */
168*7d9195a7SDavid du Colombier }
169*7d9195a7SDavid du Colombier
170*7d9195a7SDavid du Colombier void
crop(ulong ir)171*7d9195a7SDavid du Colombier crop(ulong ir)
172*7d9195a7SDavid du Colombier {
173*7d9195a7SDavid du Colombier int rd, ra, rb, d;
174*7d9195a7SDavid du Colombier
175*7d9195a7SDavid du Colombier getarrr(ir);
176*7d9195a7SDavid du Colombier if(trace)
177*7d9195a7SDavid du Colombier itrace("%s\tcrb%d,crb%d,crb%d", ci->name, rd, ra, rb);
178*7d9195a7SDavid du Colombier ra = (reg.cr & bits[ra]) != 0;
179*7d9195a7SDavid du Colombier rb = (reg.cr & bits[rb]) != 0;
180*7d9195a7SDavid du Colombier d = 0;
181*7d9195a7SDavid du Colombier switch(getxo(ir)) {
182*7d9195a7SDavid du Colombier case 257: d = ra & rb; break;
183*7d9195a7SDavid du Colombier case 129: d = ra & !rb; break;
184*7d9195a7SDavid du Colombier case 289: d = ra == rb; break;
185*7d9195a7SDavid du Colombier case 225: d = !(ra & rb); break;
186*7d9195a7SDavid du Colombier case 33: d = !(ra | rb); break;
187*7d9195a7SDavid du Colombier case 449: d = ra | rb; break;
188*7d9195a7SDavid du Colombier case 417: d = ra | !rb; break;
189*7d9195a7SDavid du Colombier case 193: d = ra ^ rb; break;
190*7d9195a7SDavid du Colombier default: undef(ir); break;
191*7d9195a7SDavid du Colombier }
192*7d9195a7SDavid du Colombier if(d)
193*7d9195a7SDavid du Colombier reg.cr |= bits[rd];
194*7d9195a7SDavid du Colombier }
195*7d9195a7SDavid du Colombier
196*7d9195a7SDavid du Colombier void
mcrf(ulong ir)197*7d9195a7SDavid du Colombier mcrf(ulong ir)
198*7d9195a7SDavid du Colombier {
199*7d9195a7SDavid du Colombier int rd, ra, rb;
200*7d9195a7SDavid du Colombier
201*7d9195a7SDavid du Colombier getarrr(ir);
202*7d9195a7SDavid du Colombier if(ir & 1 || rd & 3 || ra & 3 || rb)
203*7d9195a7SDavid du Colombier undef(ir);
204*7d9195a7SDavid du Colombier ra >>= 2;
205*7d9195a7SDavid du Colombier rd >>= 2;
206*7d9195a7SDavid du Colombier reg.cr = (reg.cr & ~mkCR(rd, 0xF)) | mkCR(rd, getCR(ra, reg.cr));
207*7d9195a7SDavid du Colombier if(trace)
208*7d9195a7SDavid du Colombier itrace("mcrf\tcrf%d,crf%d", rd, ra);
209*7d9195a7SDavid du Colombier }
210*7d9195a7SDavid du Colombier
211*7d9195a7SDavid du Colombier void
call(ulong npc)212*7d9195a7SDavid du Colombier call(ulong npc)
213*7d9195a7SDavid du Colombier {
214*7d9195a7SDavid du Colombier Symbol s;
215*7d9195a7SDavid du Colombier
216*7d9195a7SDavid du Colombier if(calltree) {
217*7d9195a7SDavid du Colombier findsym(npc, CTEXT, &s);
218*7d9195a7SDavid du Colombier Bprint(bioout, "%8lux %s(", reg.pc, s.name);
219*7d9195a7SDavid du Colombier printparams(&s, reg.r[1]);
220*7d9195a7SDavid du Colombier Bprint(bioout, "from ");
221*7d9195a7SDavid du Colombier printsource(reg.pc);
222*7d9195a7SDavid du Colombier Bputc(bioout, '\n');
223*7d9195a7SDavid du Colombier }
224*7d9195a7SDavid du Colombier }
225*7d9195a7SDavid du Colombier
226*7d9195a7SDavid du Colombier void
ret(ulong npc)227*7d9195a7SDavid du Colombier ret(ulong npc)
228*7d9195a7SDavid du Colombier {
229*7d9195a7SDavid du Colombier Symbol s;
230*7d9195a7SDavid du Colombier
231*7d9195a7SDavid du Colombier if(calltree) {
232*7d9195a7SDavid du Colombier findsym(npc, CTEXT, &s);
233*7d9195a7SDavid du Colombier Bprint(bioout, "%8lux return to #%lux %s r3=#%lux (%ld)\n",
234*7d9195a7SDavid du Colombier reg.pc, npc, s.name, reg.r[3], reg.r[3]);
235*7d9195a7SDavid du Colombier }
236*7d9195a7SDavid du Colombier }
237*7d9195a7SDavid du Colombier
238*7d9195a7SDavid du Colombier void
bx(ulong ir)239*7d9195a7SDavid du Colombier bx(ulong ir)
240*7d9195a7SDavid du Colombier {
241*7d9195a7SDavid du Colombier ulong ea;
242*7d9195a7SDavid du Colombier long imm;
243*7d9195a7SDavid du Colombier static char *opc[] = {"b", "bl", "ba", "bla"};
244*7d9195a7SDavid du Colombier
245*7d9195a7SDavid du Colombier imm = ir & 0x03FFFFFC;
246*7d9195a7SDavid du Colombier if(ir & 0x02000000)
247*7d9195a7SDavid du Colombier imm |= 0xFC000000;
248*7d9195a7SDavid du Colombier if((ir & 2) == 0) { /* not absolute address */
249*7d9195a7SDavid du Colombier ea = reg.pc + imm;
250*7d9195a7SDavid du Colombier if(trace)
251*7d9195a7SDavid du Colombier itrace("%s\t.%s%ld\tea = #%.8lux", opc[ir&3], imm<0?"":"+", imm, ea);
252*7d9195a7SDavid du Colombier } else {
253*7d9195a7SDavid du Colombier ea = imm;
254*7d9195a7SDavid du Colombier if(trace)
255*7d9195a7SDavid du Colombier itrace("%s\t#%.8lux", opc[ir&3], ea);
256*7d9195a7SDavid du Colombier }
257*7d9195a7SDavid du Colombier ci->taken++;
258*7d9195a7SDavid du Colombier if(ir & 1) {
259*7d9195a7SDavid du Colombier call(ea);
260*7d9195a7SDavid du Colombier reg.lr = reg.pc+4;
261*7d9195a7SDavid du Colombier }
262*7d9195a7SDavid du Colombier reg.pc = ea-4;
263*7d9195a7SDavid du Colombier /* branch delay? */
264*7d9195a7SDavid du Colombier }
265*7d9195a7SDavid du Colombier
266*7d9195a7SDavid du Colombier void
isync(ulong ir)267*7d9195a7SDavid du Colombier isync(ulong ir)
268*7d9195a7SDavid du Colombier {
269*7d9195a7SDavid du Colombier USED(ir);
270*7d9195a7SDavid du Colombier if(trace)
271*7d9195a7SDavid du Colombier itrace("isync");
272*7d9195a7SDavid du Colombier }
273