xref: /inferno-os/libinterp/das-arm.c (revision 7ef44d652ae9e5e1f5b3465d73684e4a54de73c0)
1 #include <lib9.h>
2 
3 typedef struct	Instr	Instr;
4 struct	Instr
5 {
6 	ulong	w;
7 	ulong	addr;
8 	uchar	op;			/* super opcode */
9 
10 	uchar	cond;			/* bits 28-31 */
11 	uchar	store;			/* bit 20 */
12 
13 	uchar	rd;			/* bits 12-15 */
14 	uchar	rn;			/* bits 16-19 */
15 	uchar	rs;			/* bits 0-11 */
16 
17 	long	imm;			/* rotated imm */
18 	char*	curr;			/* fill point in buffer */
19 	char*	end;			/* end of buffer */
20 	char*	err;			/* error message */
21 };
22 
23 typedef struct Opcode Opcode;
24 struct Opcode
25 {
26 	char*	o;
27 	void	(*f)(Opcode*, Instr*);
28 	char*	a;
29 };
30 
31 static	void	format(char*, Instr*, char*);
32 static	int	arminst(ulong, char, char*, int);
33 static	int	armdas(ulong, char*, int);
34 
35 static
36 char*	cond[16] =
37 {
38 	"EQ",	"NE",	"CS",	"CC",
39 	"MI",	"PL",	"VS",	"VC",
40 	"HI",	"LS",	"GE",	"LT",
41 	"GT",	"LE",	0,	"NV"
42 };
43 
44 static
45 char*	shtype[4] =
46 {
47 	"<<",	">>",	"->",	"@>"
48 };
49 
50 static int
51 get4(ulong addr, long *v)
52 {
53 	*v = *(ulong*)addr;
54 	return 1;
55 }
56 
57 static char *
58 _hexify(char *buf, ulong p, int zeros)
59 {
60 	ulong d;
61 
62 	d = p/16;
63 	if(d)
64 		buf = _hexify(buf, d, zeros-1);
65 	else
66 		while(zeros--)
67 			*buf++ = '0';
68 	*buf++ = "0123456789abcdef"[p&0x0f];
69 	return buf;
70 }
71 
72 int
73 armclass(long w)
74 {
75 	int op;
76 
77 	op = (w >> 25) & 0x7;
78 	switch(op) {
79 	case 0:	/* data processing r,r,r */
80 		op = ((w >> 4) & 0xf);
81 		if(op == 0x9) {
82 			op = 48+16;		/* mul */
83 			if(w & (1<<24)) {
84 				op += 2;
85 				if(w & (1<<22))
86 					op++;	/* swap */
87 				break;
88 			}
89 			if(w & (1<<21))
90 				op++;		/* mla */
91 			break;
92 		}
93 		op = (w >> 21) & 0xf;
94 		if(w & (1<<4))
95 			op += 32;
96 		else
97 		if(w & (31<<7))
98 			op += 16;
99 		break;
100 	case 1:	/* data processing i,r,r */
101 		op = (48) + ((w >> 21) & 0xf);
102 		break;
103 	case 2:	/* load/store byte/word i(r) */
104 		op = (48+20) + ((w >> 22) & 0x1) + ((w >> 19) & 0x2);
105 		break;
106 	case 3:	/* load/store byte/word (r)(r) */
107 		op = (48+20+4) + ((w >> 22) & 0x1) + ((w >> 19) & 0x2);
108 		break;
109 	case 4:	/* block data transfer (r)(r) */
110 		op = (48+20+4+4) + ((w >> 20) & 0x1);
111 		break;
112 	case 5:	/* branch / branch link */
113 		op = (48+20+4+4+2) + ((w >> 24) & 0x1);
114 		break;
115 	case 7:	/* coprocessor crap */
116 		op = (48+20+4+4+2+2) + ((w >> 3) & 0x2) + ((w >> 20) & 0x1);
117 		break;
118 	default:
119 		op = (48+20+4+4+2+2+4);
120 		break;
121 	}
122 	return op;
123 }
124 
125 static int
126 decode(ulong pc, Instr *i)
127 {
128 	long w;
129 
130 	get4(pc, &w);
131 	i->w = w;
132 	i->addr = pc;
133 	i->cond = (w >> 28) & 0xF;
134 	i->op = armclass(w);
135 	return 1;
136 }
137 
138 static void
139 bprint(Instr *i, char *fmt, ...)
140 {
141 	va_list arg;
142 
143 	va_start(arg, fmt);
144 	i->curr = vseprint(i->curr, i->end, fmt, arg);
145 	va_end(arg);
146 }
147 
148 static void
149 armdps(Opcode *o, Instr *i)
150 {
151 	i->store = (i->w >> 20) & 1;
152 	i->rn = (i->w >> 16) & 0xf;
153 	i->rd = (i->w >> 12) & 0xf;
154 	i->rs = (i->w >> 0) & 0xf;
155 	if(i->rn == 15 && i->rs == 0) {
156 		if(i->op == 8) {
157 			format("MOVW", i,"CPSR, R%d");
158 			return;
159 		} else
160 		if(i->op == 10) {
161 			format("MOVW", i,"SPSR, R%d");
162 			return;
163 		}
164 	} else
165 	if(i->rn == 9 && i->rd == 15) {
166 		if(i->op == 9) {
167 			format("MOVW", i, "R%s, CPSR");
168 			return;
169 		} else
170 		if(i->op == 11) {
171 			format("MOVW", i, "R%s, SPSR");
172 			return;
173 		}
174 	}
175 	format(o->o, i, o->a);
176 }
177 
178 static void
179 armdpi(Opcode *o, Instr *i)
180 {
181 	ulong v;
182 	int c;
183 
184 	v = (i->w >> 0) & 0xff;
185 	c = (i->w >> 8) & 0xf;
186 	while(c) {
187 		v = (v<<30) | (v>>2);
188 		c--;
189 	}
190 	i->imm = v;
191 	i->store = (i->w >> 20) & 1;
192 	i->rn = (i->w >> 16) & 0xf;
193 	i->rd = (i->w >> 12) & 0xf;
194 	i->rs = i->w&0x0f;
195 
196 		/* RET is encoded as ADD #0,R14,R15 */
197 	if(i->w == 0xe282f000){
198 		format("RET", i, "");
199 		return;
200 	} else
201 	format(o->o, i, o->a);
202 }
203 
204 static void
205 armsdti(Opcode *o, Instr *i)
206 {
207 	ulong v;
208 
209 	v = (i->w >> 0) & 0xfff;
210 	if(!(i->w & (1<<23)))
211 		v = -v;
212 	i->store = ((i->w >> 23) & 0x2) | ((i->w >>21) & 0x1);
213 	i->imm = v;
214 	i->rn = (i->w >> 16) & 0xf;
215 	i->rd = (i->w >> 12) & 0xf;
216 		/* convert load of offset(PC) to a load immediate */
217 	if(i->rn == 15 && (i->w & (1<<20)) && get4(i->addr+v+8, &i->imm) > 0)
218 		format(o->o, i, "$#%i,R%d");
219 	else
220 		format(o->o, i, o->a);
221 }
222 
223 static void
224 armsdts(Opcode *o, Instr *i)
225 {
226 	i->store = ((i->w >> 23) & 0x2) | ((i->w >>21) & 0x1);
227 	i->rs = (i->w >> 0) & 0xf;
228 	i->rn = (i->w >> 16) & 0xf;
229 	i->rd = (i->w >> 12) & 0xf;
230 	format(o->o, i, o->a);
231 }
232 
233 static void
234 armbdt(Opcode *o, Instr *i)
235 {
236 	i->store = (i->w >> 21) & 0x3;		/* S & W bits */
237 	i->rn = (i->w >> 16) & 0xf;
238 	i->imm = i->w & 0xffff;
239 	if(i->w == 0xe8fd8000)
240 		format("RFE", i, "");
241 	else
242 		format(o->o, i, o->a);
243 }
244 
245 static void
246 armund(Opcode *o, Instr *i)
247 {
248 	format(o->o, i, o->a);
249 }
250 
251 static void
252 armcdt(Opcode *o, Instr *i)
253 {
254 	format(o->o, i, o->a);
255 }
256 
257 static void
258 armunk(Opcode *o, Instr *i)
259 {
260 	format(o->o, i, o->a);
261 }
262 
263 static void
264 armb(Opcode *o, Instr *i)
265 {
266 	ulong v;
267 
268 	v = i->w & 0xffffff;
269 	if(v & 0x800000)
270 		v |= ~0xffffff;
271 	i->imm = (v<<2) + i->addr + 8;
272 	format(o->o, i, o->a);
273 }
274 
275 static void
276 armco(Opcode *o, Instr *i)		/* coprocessor instructions */
277 {
278 	int op, p, cp;
279 
280 	char buf[1024];
281 
282 	i->rn = (i->w >> 16) & 0xf;
283 	i->rd = (i->w >> 12) & 0xf;
284 	i->rs = i->w&0xf;
285 	cp = (i->w >> 8) & 0xf;
286 	p = (i->w >> 5) & 0x7;
287 	if(i->w&0x10) {
288 		op = (i->w >> 20) & 0x0f;
289 		snprint(buf, sizeof(buf), "#%x, #%x, R%d, C(%d), C(%d), #%x\n", cp, op, i->rd, i->rn, i->rs, p);
290 	} else {
291 		op = (i->w >> 21) & 0x07;
292 		snprint(buf, sizeof(buf), "#%x, #%x, C(%d), C(%d), C(%d), #%x\n", cp, op, i->rd, i->rn, i->rs, p);
293 	}
294 	format(o->o, i, buf);
295 }
296 
297 static Opcode opcodes[] =
298 {
299 	"AND%C%S",	armdps,	"R%s,R%n,R%d",
300 	"EOR%C%S",	armdps,	"R%s,R%n,R%d",
301 	"SUB%C%S",	armdps,	"R%s,R%n,R%d",
302 	"RSB%C%S",	armdps,	"R%s,R%n,R%d",
303 	"ADD%C%S",	armdps,	"R%s,R%n,R%d",
304 	"ADC%C%S",	armdps,	"R%s,R%n,R%d",
305 	"SBC%C%S",	armdps,	"R%s,R%n,R%d",
306 	"RSC%C%S",	armdps,	"R%s,R%n,R%d",
307 	"TST%C%S",	armdps,	"R%s,R%n,",
308 	"TEQ%C%S",	armdps,	"R%s,R%n,",
309 	"CMP%C%S",	armdps,	"R%s,R%n,",
310 	"CMN%C%S",	armdps,	"R%s,R%n,",
311 	"ORR%C%S",	armdps,	"R%s,R%n,R%d",
312 	"MOVW%C%S",	armdps,	"R%s,R%d",
313 	"BIC%C%S",	armdps,	"R%s,R%n,R%d",
314 	"MVN%C%S",	armdps,	"R%s,R%d",
315 
316 	"AND%C%S",	armdps,	"(R%s%h#%m),R%n,R%d",
317 	"EOR%C%S",	armdps,	"(R%s%h#%m),R%n,R%d",
318 	"SUB%C%S",	armdps,	"(R%s%h#%m),R%n,R%d",
319 	"RSB%C%S",	armdps,	"(R%s%h#%m),R%n,R%d",
320 	"ADD%C%S",	armdps,	"(R%s%h#%m),R%n,R%d",
321 	"ADC%C%S",	armdps,	"(R%s%h#%m),R%n,R%d",
322 	"SBC%C%S",	armdps,	"(R%s%h#%m),R%n,R%d",
323 	"RSC%C%S",	armdps,	"(R%s%h#%m),R%n,R%d",
324 	"TST%C%S",	armdps,	"(R%s%h#%m),R%n,",
325 	"TEQ%C%S",	armdps,	"(R%s%h#%m),R%n,",
326 	"CMP%C%S",	armdps,	"(R%s%h#%m),R%n,",
327 	"CMN%C%S",	armdps,	"(R%s%h#%m),R%n,",
328 	"ORR%C%S",	armdps,	"(R%s%h#%m),R%n,R%d",
329 	"MOVW%C%S",	armdps,	"(R%s%h#%m),R%d",
330 	"BIC%C%S",	armdps,	"(R%s%h#%m),R%n,R%d",
331 	"MVN%C%S",	armdps,	"(R%s%h#%m),R%d",
332 
333 	"AND%C%S",	armdps,	"(R%s%hR%m),R%n,R%d",
334 	"EOR%C%S",	armdps,	"(R%s%hR%m),R%n,R%d",
335 	"SUB%C%S",	armdps,	"(R%s%hR%m),R%n,R%d",
336 	"RSB%C%S",	armdps,	"(R%s%hR%m),R%n,R%d",
337 	"ADD%C%S",	armdps,	"(R%s%hR%m),R%n,R%d",
338 	"ADC%C%S",	armdps,	"(R%s%hR%m),R%n,R%d",
339 	"SBC%C%S",	armdps,	"(R%s%hR%m),R%n,R%d",
340 	"RSC%C%S",	armdps,	"(R%s%hR%m),R%n,R%d",
341 	"TST%C%S",	armdps,	"(R%s%hR%m),R%n,",
342 	"TEQ%C%S",	armdps,	"(R%s%hR%m),R%n,",
343 	"CMP%C%S",	armdps,	"(R%s%hR%m),R%n,",
344 	"CMN%C%S",	armdps,	"(R%s%hR%m),R%n,",
345 	"ORR%C%S",	armdps,	"(R%s%hR%m),R%n,R%d",
346 	"MOVW%C%S",	armdps,	"(R%s%hR%m),R%d",
347 	"BIC%C%S",	armdps,	"(R%s%hR%m),R%n,R%d",
348 	"MVN%C%S",	armdps,	"(R%s%hR%m),R%d",
349 
350 	"AND%C%S",	armdpi,	"$#%i,R%n,R%d",
351 	"EOR%C%S",	armdpi,	"$#%i,R%n,R%d",
352 	"SUB%C%S",	armdpi,	"$#%i,R%n,R%d",
353 	"RSB%C%S",	armdpi,	"$#%i,R%n,R%d",
354 	"ADD%C%S",	armdpi,	"$#%i,R%n,R%d",
355 	"ADC%C%S",	armdpi,	"$#%i,R%n,R%d",
356 	"SBC%C%S",	armdpi,	"$#%i,R%n,R%d",
357 	"RSC%C%S",	armdpi,	"$#%i,R%n,R%d",
358 	"TST%C%S",	armdpi,	"$#%i,R%n,",
359 	"TEQ%C%S",	armdpi,	"$#%i,R%n,",
360 	"CMP%C%S",	armdpi,	"$#%i,R%n,",
361 	"CMN%C%S",	armdpi,	"$#%i,R%n,",
362 	"ORR%C%S",	armdpi,	"$#%i,R%n,R%d",
363 	"MOVW%C%S",	armdpi,	"$#%i,,R%d",
364 	"BIC%C%S",	armdpi,	"$#%i,R%n,R%d",
365 	"MVN%C%S",	armdpi,	"$#%i,,R%d",
366 
367 	"MUL%C%S",	armdpi,	"R%s,R%m,R%n",
368 	"MULA%C%S",	armdpi,	"R%s,R%m,R%n,R%d",
369 	"SWPW",		armdpi,	"R%s,(R%n),R%d",
370 	"SWPB",		armdpi,	"R%s,(R%n),R%d",
371 
372 	"MOVW%C%p",	armsdti,"R%d,#%i(R%n)",
373 	"MOVB%C%p",	armsdti,"R%d,#%i(R%n)",
374 	"MOVW%C%p",	armsdti,"#%i(R%n),R%d",
375 	"MOVB%C%p",	armsdti,"#%i(R%n),R%d",
376 
377 	"MOVW%C%p",	armsdts,"R%d,%D(R%s%h#%m)(R%n)",
378 	"MOVB%C%p",	armsdts,"R%d,%D(R%s%h#%m)(R%n)",
379 	"MOVW%C%p",	armsdts,"%D(R%s%h#%m)(R%n),R%d",
380 	"MOVB%C%p",	armsdts,"%D(R%s%h#%m)(R%n),R%d",
381 
382 	"MOVM%C%P%a",	armbdt,	"R%n,[%r]",
383 	"MOVM%C%P%a",	armbdt,	"[%r],R%n",
384 
385 	"B%C",		armb,	"%b",
386 	"BL%C",		armb,	"%b",
387 
388 	"CDP%C",	armco,	"",
389 	"CDP%C",	armco,	"",
390 	"MCR%C",	armco,	"",
391 	"MRC%C",	armco,	"",
392 
393 	"UNK",		armunk,	"",
394 };
395 
396 static	char *mode[] = { 0, "IA", "DB", "IB" };
397 static	char *pw[] = { "P", "PW", 0, "W" };
398 static	char *sw[] = { 0, "W", "S", "SW" };
399 
400 static void
401 format(char *mnemonic, Instr *i, char *f)
402 {
403 	int j, k, m, n;
404 
405 	if(mnemonic)
406 		format(0, i, mnemonic);
407 	if(f == 0)
408 		return;
409 	if(mnemonic)
410 		if(i->curr < i->end)
411 			*i->curr++ = '\t';
412 	for ( ; *f && i->curr < i->end; f++) {
413 		if(*f != '%') {
414 			*i->curr++ = *f;
415 			continue;
416 		}
417 		switch (*++f) {
418 
419 		case 'C':	/* .CONDITION */
420 			if(cond[i->cond])
421 				bprint(i, ".%s", cond[i->cond]);
422 			break;
423 
424 		case 'S':	/* .STORE */
425 			if(i->store)
426 				bprint(i, ".S");
427 			break;
428 
429 		case 'P':	/* P & U bits for block move */
430 			n = (i->w >>23) & 0x3;
431 			if (mode[n])
432 				bprint(i, ".%s", mode[n]);
433 			break;
434 
435 		case 'D':	/* ~U bit for single data xfer */
436 			if((i->w & (1<<23)) == 0)
437 				bprint(i, "-");
438 			break;
439 
440 		case 'p':	/* P & W bits for single data xfer*/
441 			if (pw[i->store])
442 				bprint(i, ".%s", pw[i->store]);
443 			break;
444 
445 		case 'a':	/* S & W bits for single data xfer*/
446 			if (sw[i->store])
447 				bprint(i, ".%s", sw[i->store]);
448 			break;
449 
450 		case 's':
451 			bprint(i, "%d", i->rs & 0xf);
452 			break;
453 
454 		case 'm':
455 			bprint(i, "%d", (i->w>>7) & 0x1f);
456 			break;
457 
458 		case 'h':
459 			bprint(i, "%s", shtype[(i->w>>5) & 0x3]);
460 			break;
461 
462 		case 'n':
463 			bprint(i, "%d", i->rn);
464 			break;
465 
466 		case 'd':
467 			bprint(i, "%d", i->rd);
468 			break;
469 
470 		case 'i':
471 			bprint(i, "%lux", i->imm);
472 			break;
473 
474 		case 'b':
475 			bprint(i, "%lux", i->imm);
476 			break;
477 
478 		case 'r':
479 			n = i->imm&0xffff;
480 			j = 0;
481 			k = 0;
482 			while(n) {
483 				m = j;
484 				while(n&0x1) {
485 					j++;
486 					n >>= 1;
487 				}
488 				if(j != m) {
489 					if(k)
490 						bprint(i, ",");
491 					if(j == m+1)
492 						bprint(i, "R%d", m);
493 					else
494 						bprint(i, "R%d-R%d", m, j-1);
495 					k = 1;
496 				}
497 				j++;
498 				n >>= 1;
499 			}
500 			break;
501 
502 		case '\0':
503 			*i->curr++ = '%';
504 			return;
505 
506 		default:
507 			bprint(i, "%%%c", *f);
508 			break;
509 		}
510 	}
511 	*i->curr = 0;
512 }
513 
514 void
515 das(ulong *x, int n)
516 {
517 	ulong pc;
518 	Instr i;
519 	char buf[128];
520 
521 	pc = (ulong)x;
522 	while(n > 0) {
523 		i.curr = buf;
524 		i.end = buf+sizeof(buf)-1;
525 
526 		if(decode(pc, &i) < 0)
527 			sprint(buf, "???");
528 		else
529 			(*opcodes[i.op].f)(&opcodes[i.op], &i);
530 
531 		print("%.8lux %.8lux\t%s\n", pc, i.w, buf);
532 		pc += 4;
533 		n--;
534 	}
535 }
536