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