xref: /plan9/sys/src/cmd/qi/branch.c (revision 7d9195a7bc3493d7fc3e1166ef25bf446be66b1a)
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, &reg.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, &reg.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