Open Firmware

Open Firmware Svn Source Tree

Root/cpu/arm/armsim.c

Source at commit 3725 created 3 years 6 months ago.
By tooch, core - Tiny lint fixes, detected on Apple LLVM-based SDK. And one not so tiny, as OS X dropped support for sbrk().
1//
2// ARM32 Application-level simulator.
3//
4//
5// Copyright (c) 2007 FirmWorks
6// Copyright 2010 Apple, Inc. All rights reserved.
7// See license at end.
8
9#include <stdio.h>
10#include <stdlib.h>
11#include <signal.h>
12
13typedef char s8;
14typedef short s16;
15typedef int s32;
16typedef long long s64;
17typedef unsigned char u8;
18typedef unsigned short u16;
19typedef unsigned int u32;
20typedef unsigned long long u64;
21
22static u32 trace = 0;
23
24//#if TRACE
25#define INSTR(a) if (trace) printf("%s -- %0x N%d Z%d C%d V%d %s\n", \
26 a, COND, N, Z, C, V, cond ? "true" : "false"); \
27 if (cond == 0) break
28//#else
29//#define INSTR(a) if (cond == 0) break
30//#endif
31
32#define MAXMEM 0x80000
33#define MEM(type, adr) *(type *)(&mem[(adr)])
34
35u32 r[16];
36#define SP r[13]
37#define LR r[14]
38#define PC r[15]
39
40void regdump(u32 instruction, u32 last_pc, u8 cr)
41{
42 printf(" r0 %08x r1 %08x r2 %08x r3 %08x\n", r[0], r[1], r[2], r[3]);
43 printf(" r4 %08x r5 %08x r6 %08x base %08x\n", r[4], r[5], r[6], r[7]);
44 printf(" r8 %08x up %08x tos %08x rp %08x\n", r[8], r[9], r[10], r[11]);
45 printf(" ip %08x sp %08x lr %08x pc %08x\n", r[12], r[13], r[14], r[15]);
46 printf("pc %08x lpc %08x i %08x ", PC - 8, last_pc, instruction);
47 if (cr)
48 putchar('\n');
49}
50
51#define UFIELD(lbit,nbits) ( (instruction << (31 - lbit)) >> (32 - nbits))
52#define SFIELD(lbit,nbits) ((long)(instruction << (31 - lbit)) >> (32 - nbits))
53
54#define COND UFIELD(31, 4)
55#define OP UFIELD(27, 7)
56#define S UFIELD(20, 1)
57#define L UFIELD(20, 1)
58#define RD r[UFIELD(15, 4)]
59#define RN r[UFIELD(19, 4)]
60#define RM r[UFIELD( 3, 4)]
61#define RS r[UFIELD(11, 4)]
62#define TYPE UFIELD( 6, 2)
63#define IMM5 UFIELD(11, 5)
64#define OP1 UFIELD( 4, 1)
65#define OP2 UFIELD( 7, 1)
66#define ROT UFIELD(11, 4)
67#define IMM8 UFIELD( 7, 8)
68#define IMM24 UFIELD(23,24)
69#define LINK UFIELD( 5, 1)
70#define MSB UFIELD(20, 5)
71#define LSB UFIELD(11, 5)
72#define BXTYPE UFIELD( 7, 4)
73#define IMM12 UFIELD(11,12)
74#define IMM16 ((UFIELD(19, 4) << 12) | IMM12)
75#define IMMHL ((UFIELD(11, 4) << 4) | UFIELD( 3, 4))
76#define P UFIELD(24, 1)
77#define U UFIELD(23, 1)
78#define W UFIELD(21, 1)
79
80// In BTGT we want to force a PC update. Since we don't implement Thumb
81// the value "1" must always be invalid for last_pc.
82struct { signed int imm24:24; } sext24;
83#define BTGT { PC += sext24.imm24 = (IMM24 << 2); last_pc = 1; }
84
85int scout; // Hold the last bit shifted out
86#define ROTATE(imm, rot) (((imm) >> (rot)) | ((imm) << (32-(rot))))
87#define IMM32 ROTATE(IMM8, (ROT<<1))
88
89#define TEST_SHIFT0
90#if defined(TEST_SHIFT) && TEST_SHIFT
91#define EXIT(r) goto exit
92#else
93#define EXIT(r) return res
94#endif
95
96u32 shifter(u32 rm, u32 rs, u32 type, u32 imm, u32 imm5, u32 cin, u32 pc, u32 ir)
97{
98 u32 res, res2;
99 int cnt;
100
101#if defined(TEST_SHIFT) && TEST_SHIFT
102 u32 res2;
103 cnt = imm ? imm5 : rs;
104 switch (type) {
105 case 0: res = rm << cnt; break;
106 case 1: res = rm >> cnt; break;
107 case 2: if (cnt == 0) { res = ((s32)(rm) < 0) ? -1 : 0; } else { res = (s32)(rm) >> cnt; } break;
108 case 3: res = ROTATE(rm, cnt);
109 }
110 res2 = res;
111#endif
112
113 if (imm && (imm5 == 0)) {
114 if (type == 0) {
115 res = rm;
116 scout = cin;
117 EXIT(res);
118 return res;
119 }
120
121 if (type == 2) {
122 if ((s32)rm < 0) res = -1;
123 else res = 0;
124 scout = res & 1;
125 EXIT(res);
126 return res;
127 }
128
129 if (type == 3) {
130 res = (cin << 31) | (rm >> 1);
131 scout = rm & 1;
132 EXIT(res);
133 return res;
134 }
135 }
136
137 if (imm) {
138 if (imm5 == 0) cnt = 32;
139 else cnt = imm5;
140 } else cnt = rs & 31;
141
142 if (cnt == 0) {
143 res = rm;
144 scout = cin;
145 EXIT(res);
146 return res;
147 }
148
149 switch (type) {
150 case 0: res = rm << cnt; scout = rm >> (32 - cnt); break;
151 case 1: res = rm >> cnt; scout = rm >> (cnt - 1); break;
152 case 2: res = (s32)rm >> cnt; scout = rm >> (cnt - 1); break;
153 case 3: res = ROTATE(rm, cnt); scout = res >> 31;
154 } /* switch */
155
156 scout &= 1;
157
158 EXIT(res);
159
160#if defined(TEST_SHIFT) && TEST_SHIFT
161exit:
162 if (res != res2) {
163 char *shifts[] = {"lsl", "lsr", "asr", "ror"};
164 printf("PC: %x: %x ", pc, ir);
165 if (imm) {
166 printf("imm = #%d", imm5);
167 } else {
168 printf("RS = %d", rs & 31);
169 }
170 printf(", RM = %x, %s #%d; res = %x, res2 = %x\n", rm, shifts[type], cnt, res, res2);
171// while (1);
172 }
173 return res;
174#endif
175}
176
177
178#define SHFT(res) res = shifter(RM, RS, TYPE, !OP1, IMM5, C, PC, instruction)
179
180#define BF(sb, eb) ((u32)(((s32)0x80000000) >> (sb - eb))) >> (31 - sb);
181
182union {
183 u32 all;
184 struct {
185 u32 res :28;
186 u32 Vbit:1;
187 u32 Zbit:1;
188 u32 Cbit:1;
189 u32 Nbit:1;
190 } bits;
191} APSR;
192
193#define N (APSR.bits.Nbit)
194#define Z (APSR.bits.Zbit)
195#define C (APSR.bits.Cbit)
196#define V (APSR.bits.Vbit)
197
198// FIXME: We're skipping the V bit for now.
199
200/* Leave C alone. */
201#define UPCC(res) \
202{ \
203 if (S) { \
204 N = (res) >> 31; \
205 Z = (res == 0); \
206 } \
207}
208
209/* Factor in the shifted-out Carry. */
210#define SHFT_UPCC(res) \
211{ \
212 if (S) { \
213 N = (res) >> 31; \
214 Z = (res == 0); \
215 C = scout ? 1 : 0; \
216 } \
217}
218
219#define ADC(dest, a, b, c) \
220{ \
221 temp = (a) + (b) + (c); \
222 if (S) { \
223 N = temp >> 31; \
224 Z = temp == 0; \
225 C = (temp < (a)) || ((c) && (temp == (a))); \
226 V = ((((s32)(temp)^(s32)(a)) < 0) && (((s32)(a)^(s32)(b)) >= 0)); \
227 } \
228 dest = temp; \
229}
230
231#define SBB(dest, a, b, c) \
232{ \
233 temp = (a) - (b) - (!(c)); \
234 if (S) { \
235 N = temp >> 31; \
236 Z = temp == 0; \
237 C = !(((a) < temp) || ((!(c)) && ((a) == temp))); \
238 V = ((((s32)temp^(s32)(a)) < 0) && (((s32)(a)^(s32)(b)) < 0)); \
239 } \
240 dest = temp; \
241}
242
243#define UNIMP(s) \
244{ \
245 printf("UNIMPLEMENTED '%s' op %02x s %d bxtype %02x; Source line: %d\n", s, OP, S, BXTYPE, __LINE__); \
246 regdump(instruction, last_pc, 1); \
247 return; \
248}
249
250#define EVAL_COND(cc) \
251{ \
252 switch (cc) { \
253 case 0x0: cond = (Z == 1); break; \
254 case 0x1: cond = (Z == 0); break; \
255 case 0x2: cond = (C == 1); break; \
256 case 0x3: cond = (C == 0); break; \
257 case 0x4: cond = (N == 1); break; \
258 case 0x5: cond = (N == 0); break; \
259 case 0x6: cond = (V == 1); break; \
260 case 0x7: cond = (V == 0); break; \
261 case 0x8: cond = (C == 1 && Z == 0); break; \
262 case 0x9: cond = (C == 0 || Z == 1); break; \
263 case 0xa: cond = (N == V); break; \
264 case 0xb: cond = (N != V); break; \
265 case 0xc: cond = (Z == 0 && N == V); break; \
266 case 0xd: cond = (Z == 1 || N != V); break; \
267 case 0xe: cond = (1); break; \
268 case 0xf: cond = (0xf); break; \
269 } \
270}
271
272u32 instruction;
273u32 last_pc;
274
275void simhandler(int sig)
276{
277 extern void restoremode();
278
279psignal(sig, "forth");
280 regdump(instruction, last_pc, 1);
281 restoremode();
282 exit(1);
283}
284
285 // alf = find(adr, len, link, origin);
286u32 *
287find(u8 *adr, u32 len, u32 *link, void *origin)
288{
289 u8 *wp, *np;
290 u32 namelen;
291
292 while (link != origin) {
293 link -= 1; // Move from code field to link field
294 np = (u8 *)link - 1;
295 namelen = (*np) & 0x1f;
296 if (namelen == len) {
297 np -= namelen;
298 wp = adr;
299 while (namelen--) {
300 if (*np++ != *wp++) {
301 break;
302 }
303 }
304 if (namelen == -1) {
305 return (link);
306 }
307 }
308 link = (u32 *)*link;
309 }
310 return ((u32 *)0);
311}
312
313void
314simulate(u8 *mem, u32 start, u32 header, u32 syscall_vec,
315 u32 memtop, u32 argc, u32 argv)
316{
317 // register u32 instruction;
318 register u32 res;
319 register u32 cond;
320 register u32 temp;
321 s32 indent = 0;
322 u32 name;
323 u32 namelen;
324 // u32 last_pc;
325
326signal(SIGBUS, simhandler);
327signal(SIGSEGV, simhandler);
328
329 APSR.all = 0;
330 PC = start + 8; // Stupid ARM.
331 r[0] = header;
332 r[1] = 0; // Tell Forth it is using the simulator
333 r[2] = memtop;
334 r[3] = argc;
335 SP = memtop;
336 *((u32 *)SP) = argv;
337
338 while (1) {
339 instruction = MEM(u32, PC - 8);
340 last_pc = PC;
341//#if TRACE
342 if (trace)
343 regdump(instruction, last_pc, 0);
344//#endif
345 EVAL_COND(COND);
346 if (cond == 0xf)
347 UNIMP("unconditional");
348 switch (OP) {
349case 0x00: if (OP1 == 0 || OP2 == 0) {
350 INSTR("and"); SHFT(res); RD = RN & res; SHFT_UPCC(RD); break;
351 }
352 switch (BXTYPE) {
353 case 0x9: INSTR("mul"); RN = RS * RM; UPCC(RN); break;
354 // P=0, U=0, bit22=0, W=0 - post-index, add offset, register, no writeback
355 case 0xb:
356 if (L) {
357 INSTR("ldrh");
358 RD = MEM(u16, RN);
359 RN = RN + RM;
360 } else {
361 INSTR("strh");
362 MEM(u16, RN) = RD;
363 RN = RN + RM;
364 }
365 break;
366 case 0xd:
367 if (L) {
368 INSTR("ldrsb");
369 RD = MEM(s8, RN);
370 RN = RN + RM;
371 } else {
372 UNIMP("ldrd");
373 }
374 break;
375 case 0xf: if (L) {
376 INSTR("ldrsh");
377 RD = MEM(s16, RN);
378 RN = RN + RM;
379 } else {
380 UNIMP("strd");
381 }
382 break;
383 default: UNIMP("BXTYPE"); break;
384 } break;
385case 0x01: if (OP1 == 0 || OP2 == 0) {
386 INSTR("eor"); SHFT(res); RD = RN ^ res; SHFT_UPCC(RD); break;
387 }
388 switch (BXTYPE) {
389 case 0x9: UNIMP("mla"); break;
390 // P=0, U=0, bit22=0, W=1 - post-index, add offset, register, writeback - UNPREDICTABLE (P=0, W=1)
391 case 0xb: UNIMP("ldrh"); break; // UNPREDICTABLE
392 case 0xd: UNIMP("ldrd"); break; // UNPREDICTABLE
393 case 0xf: UNIMP("ldrsh"); break; // UNPREDICTABLE
394 } break;
395case 0x02: if (OP1 == 0 || OP2 == 0) {
396 INSTR("sub"); SHFT(res); SBB(RD, RN, res, 1); break;
397 }
398 switch (BXTYPE) {
399 // P=0, U=0, bit22=1, W=0 - post-index, add offset, immediate, no writeback
400 case 0xb:
401 if (L) {
402 INSTR("ldrh");
403 RD = MEM(u16, RN);
404 RN = RN + IMMHL;
405 } else {
406 INSTR("strh");
407 MEM(u16, RN) = RD;
408 RN = RN + IMMHL;
409 }
410 break;
411 case 0xd:
412 if (L) {
413 INSTR("ldrsb");
414 RD = MEM(s8, RN);
415 RN = RN + IMMHL;
416 } else {
417 UNIMP("ldrd");
418 }
419 break;
420 case 0xf: if (L) {
421 INSTR("ldrsh");
422 RD = MEM(s16, RN);
423 RN = RN + IMMHL;
424 } else {
425 UNIMP("strd");
426 }
427 break;
428 default: UNIMP("BXTYPE"); break;
429 } break;
430case 0x03: if (OP1 == 0 || OP2 == 0) {
431 INSTR("rsb"); SHFT(res); SBB(RD, res, RN, 1); break;
432 } else {
433 switch (BXTYPE) {
434 case 0x1:
435 case 0x3:
436 case 0x5:
437 case 0x7: INSTR("rsb"); SHFT(res); SBB(RD, res, RN, 1); break;
438 case 0x9: UNIMP("mls"); break;
439 // P=0, U=0, bit22=1, W=1 - post-index, add offset, immediate, writeback - UNPREDICTABLE (P=0, W=1)
440 case 0xb: UNIMP("ldrh"); break; // UNPREDICTABLE
441 case 0xd: UNIMP("ldrd"); break; // UNPREDICTABLE
442 case 0xf: UNIMP("ldrsh"); break; // UNPREDICTABLE
443 } break;
444 } break;
445case 0x04: if (OP1 == 0 || OP2 == 0) {
446 INSTR("add"); SHFT(res); ADC(RD, RN, res, 0); break;
447 }
448 switch (BXTYPE) {
449 // P=0, U=1, bit22=0, W=0 - post-index, subtract offset, register, no writeback
450 case 0x9: INSTR("umull");
451 { u64 result;
452 result = (u64)RM * (u64)RS;
453 RN = (u32)((result >> 32) & 0xffffffffLL);
454 RD = (u32)(result & 0xffffffffLL);
455 if (S) {
456 N = (RN & 0x80000000LL) ? 1 : 0;
457 Z = (result == 0);
458 }
459 }
460 break;
461
462 case 0xb:
463 if (L) {
464 INSTR("ldrh");
465 RD = MEM(u16, RN);
466 RN = RN - RM;
467 } else {
468 INSTR("strh");
469 MEM(u16, RN) = RD;
470 RN = RN - RM;
471 }
472 break;
473 case 0xd:
474 if (L) {
475 INSTR("ldrsb");
476 RD = MEM(s8, RN);
477 RN = RN - RM;
478 } else {
479 UNIMP("ldrd");
480 }
481 break;
482 case 0xf: if (L) {
483 INSTR("ldrsh");
484 RD = MEM(s16, RN);
485 RN = RN - RM;
486 } else {
487 UNIMP("strd");
488 }
489 break;
490 default: UNIMP("BXTYPE"); break;
491 } break;
492case 0x05: if (OP1 == 0 || OP2 == 0) {
493 INSTR("adc"); SHFT(res); ADC(RD, RN, res, C); break;
494 }
495 switch (BXTYPE) {
496 // P=0, U=1, bit22=0, W=1 - post-index, subtract offset, register, writeback - UNPREDICTABLE (P=0, W=1)
497 case 0xb: UNIMP("ldrh"); break; // UNPREDICTABLE
498 case 0xd: UNIMP("ldrd"); break; // UNPREDICTABLE
499 case 0xf: UNIMP("ldrsh"); break; // UNPREDICTABLE
500 default: UNIMP("BXTYPE"); break;
501 } break;
502case 0x06:
503 if (OP1 == 0 || OP2 == 0) {
504 INSTR("sbc"); SHFT(res);
505// printf("sbc RN %x res %x ~res %x C %x -- ", RN, res, ~(res), C);
506// ADC(RD, RN, ~(res), C);
507// printf("res %x\n", RD);
508// printf("sbc RN %x res %x ~res %x C %x -- ", RN, res, ~(res), C);
509 SBB(RD, RN, res, C);
510// printf("res %x\n", RD);
511break;
512 } else {
513 switch (BXTYPE) {
514 case 0x1:
515 case 0x3:
516 case 0x5:
517 case 0x7: INSTR("sbc"); SHFT(res); SBB(RD, res, RN, C); break;
518 case 0x9: INSTR("smull");
519 { s64 result, a, b;
520 a = (int)RM;
521 b = (int)RS;
522 result = a * b;
523 RN = (u32)((result >> 32) & 0xffffffffLL);
524 RD = (u32)(result & 0xffffffffLL);
525 if (S) {
526 N = (result < 0);
527 Z = (result == 0);
528 }
529 }
530 break;
531 // P=0, U=1, bit22=1, W=0 - post-index, subtract offset, immediate, no writeback
532 case 0xb:
533 if (L) {
534 INSTR("ldrh");
535 RD = MEM(u16, RN);
536 RN = RN - IMMHL;
537 } else {
538 INSTR("strh");
539 MEM(u16, RN) = RD;
540 RN = RN - IMMHL;
541 }
542 break;
543 case 0xd:
544 if (L) {
545 INSTR("ldrsb");
546 RD = MEM(s8, RN);
547 RN = RN - IMMHL;
548 } else {
549 UNIMP("ldrd");
550 }
551 break;
552 case 0xf: if (L) {
553 INSTR("ldrsh");
554 RD = MEM(s16, RN);
555 RN = RN - IMMHL;
556 } else {
557 UNIMP("strd");
558 }
559 break;
560 default: UNIMP("BXTYPE"); break;
561 } break;
562 } break;
563case 0x07: if (OP1 == 0 || OP2 == 0) {
564 INSTR("rsc"); SHFT(res); SBB(RD, res, RN, C); break;
565 } else {
566 switch (BXTYPE) {
567 case 0x1:
568 case 0x3:
569 case 0x5:
570 case 0x7: INSTR("rsc"); SHFT(res); SBB(RD, res, RN, C); break;
571 case 0x9: UNIMP("smlal"); break;
572 // P=0, U=1, bit22=1, W=1 - post-index, subtract offset, immediate, writeback - UNPREDICTABLE (P=0, W=1)
573 case 0xb: UNIMP("ldrh"); break; // UNPREDICTABLE
574 case 0xd: UNIMP("ldrd"); break; // UNPREDICTABLE
575 case 0xf: UNIMP("ldrsh"); break; // UNPREDICTABLE
576 default: UNIMP("BXTYPE"); break;
577 } break;
578 } break;
579case 0x08: switch (BXTYPE) {
580 case 0x0: INSTR("mrs"); RD = APSR.all; break;
581 case 0x5: UNIMP("qadd"); break;
582 case 0x8:
583 case 0xa:
584 case 0xc:
585 case 0xe: UNIMP("smlabb"); break;
586 // P=1, U=0, bit22=0, W=0 - offset/pre-index, subtract offset, register, no writeback
587 case 0xb:
588 if (L) {
589 INSTR("ldrh");
590 RD = MEM(u16, RN - RM);
591 } else {
592 INSTR("strh");
593 MEM(u16, RN - RM) = RD;
594 }
595 break;
596 case 0xd:
597 if (L) {
598 INSTR("ldrsb");
599 RD = MEM(s8, RN - RM);
600 } else {
601 UNIMP("ldrd");
602 }
603 break;
604 case 0xf: if (L) {
605 INSTR("ldrsh");
606 RD = MEM(s16, RN - RM);
607 } else {
608 UNIMP("strd");
609 }
610 break;
611 default: UNIMP("BXTYPE"); break;
612 } break;
613case 0x09: switch (BXTYPE) {
614 case 0x0: INSTR("msr"); APSR.all = RM; break;
615 case 0x1: INSTR("bx"); PC = RM; break;
616 case 0x2: INSTR("bxj"); PC = RM; break;
617 case 0x3: INSTR("blx"); if (LINK) LR = PC - 4; PC = RM; break;
618 case 0x5: UNIMP("qsub"); break;
619 case 0x7: UNIMP("bkpt"); break;
620 case 0x8:
621 case 0xa:
622 case 0xc:
623 case 0xe: UNIMP("smlawb"); break;
624 // P=1, U=0, bit22=0, W=1 - offset/pre-index, subtract offset, register, writeback
625 case 0xb:
626 if (L) {
627 INSTR("ldrh");
628 temp = RN - RM;
629 RD = MEM(u16, temp);
630 RN = temp;
631 } else {
632 INSTR("strh");
633 temp = RN - RM;
634 MEM(u16, temp) = RD;
635 RN = temp;
636 }
637 break;
638 case 0xd:
639 if (L) {
640 INSTR("ldrsb");
641 temp = RN - RM;
642 RD = MEM(s8, temp);
643 RN = temp;
644 } else {
645 UNIMP("ldrd");
646 }
647 break;
648 case 0xf: if (L) {
649 INSTR("ldrsh");
650 temp = RN - RM;
651 RD = MEM(s16, temp);
652 RN = temp;
653 } else {
654 UNIMP("strd");
655 }
656 break;
657 default: UNIMP("BXTYPE"); break;
658 } break;
659case 0x0a: if (OP1 == 0 || OP2 == 0) {
660 INSTR("cmp"); SHFT(res); SBB(res, RN, res, 1); break;
661 }
662 switch (BXTYPE) {
663 case 0x5: UNIMP("qdadd"); break;
664 case 0x8:
665 case 0xa:
666 case 0xc:
667 case 0xe: UNIMP("smlalbb"); break;
668 // P=1, U=0, bit22=1, W=0 - offset/pre-index, subtract offset, immediate, no writeback
669 case 0xb:
670 if (L) {
671 INSTR("ldrh");
672 RD = MEM(u16, RN - IMMHL);
673 } else {
674 INSTR("strh");
675 MEM(u16, RN - IMMHL) = RD;
676 }
677 break;
678 case 0xd:
679 if (L) {
680 INSTR("ldrsb");
681 RD = MEM(s8, RN - IMMHL);
682 } else {
683 UNIMP("ldrd");
684 }
685 break;
686 case 0xf: if (L) {
687 INSTR("ldrsh");
688 RD = MEM(s16, RN - IMMHL);
689 } else {
690 UNIMP("strd");
691 }
692 break;
693 default: UNIMP("BXTYPE"); break;
694 } break;
695case 0x0b: if (OP1 == 0 || OP2 == 0) {
696 if (S) {
697 INSTR("cmn"); SHFT(res); ADC(res, RN, res, 0); break;
698 } else {
699 // "You don't need this instruction anyway."
700 // --mjterave@gmail.com
701 UNIMP("clz"); break;
702 }
703 }
704 switch (BXTYPE) {
705 case 0x5: UNIMP("qdsub"); break;
706 case 0x8:
707 case 0xa:
708 case 0xc:
709 case 0xe: UNIMP("smulbb"); break;
710 // P=1, U=0, bit22=1, W=1 - offset/pre-index, subtract offset, immediate, writeback
711 case 0xb:
712 if (L) {
713 INSTR("ldrh");
714 temp = RN - IMMHL;
715 RD = MEM(u16, temp);
716 RN = temp;
717 } else {
718 INSTR("strh");
719 temp = RN - IMMHL;
720 MEM(u16, temp) = RD;
721 RN = temp;
722 }
723 break;
724 case 0xd:
725 if (L) {
726 INSTR("ldrsb");
727 temp = RN - IMMHL;
728 RD = MEM(s8, temp);
729 RN = temp;
730 } else {
731 UNIMP("ldrd");
732 }
733 break;
734 case 0xf: if (L) {
735 INSTR("ldrsh");
736 temp = RN - IMMHL;
737 RD = MEM(s16, temp);
738 RN = temp;
739 } else {
740 UNIMP("strd");
741 }
742 break;
743 default: UNIMP("BXTYPE"); break;
744 } break;
745case 0x0c: if (OP1 == 0 || OP2 == 0) {
746 INSTR("orr"); SHFT(res); RD = RN | res; SHFT_UPCC(RD);
747 } else {
748 switch (BXTYPE) {
749 case 0x1:
750 case 0x3:
751 case 0x5:
752 case 0x7: INSTR("orr"); SHFT(res); RD = RN | res; SHFT_UPCC(RD);
753 break;
754 case 0x9: UNIMP("ldrex"); break;
755 // P=1, U=0, bit22=0, W=0 - offset/pre-index, subtract offset, register, no writeback
756 case 0xb:
757 if (L) {
758 INSTR("ldrh");
759 RD = MEM(u16, RN + RM);
760 } else {
761 INSTR("strh");
762 MEM(u16, RN + RM) = RD;
763 }
764 break;
765 case 0xd:
766 if (L) {
767 INSTR("ldrsb");
768 RD = MEM(s8, RN + RM);
769 } else {
770 UNIMP("ldrd");
771 }
772 break;
773 case 0xf: if (L) {
774 INSTR("ldrsh");
775 RD = MEM(s16, RN + RM);
776 } else {
777 UNIMP("strd");
778 }
779 break;
780 default: UNIMP("BXTYPE"); break;
781 } break;
782 } break;
783case 0x0d: switch (BXTYPE) {
784 case 0x0:
785 if (instruction == 0xe1a00000) {
786 INSTR("nop"); break;
787 } else if (IMM5 == 0) {
788 if (instruction == 0xe1a0f009) { // mov pc,up i.e. the part of NEXT at the end of each code word
789 INSTR("NEXT");
790 } else {
791 INSTR("mov");
792 }
793 RD = RM; UPCC(RD); break;
794 } /* else fall through */
795 case 0x8:
796 case 0x1: INSTR("lsl"); SHFT(RD); SHFT_UPCC(RD); break;
797 case 0x2:
798 case 0xa:
799 case 0x3: INSTR("lsr"); SHFT(RD); SHFT_UPCC(RD); break;
800 case 0x4:
801 case 0xc:
802 case 0x5: INSTR("asr"); SHFT(RD); SHFT_UPCC(RD); break;
803 case 0x6:
804 case 0xe:
805 case 0x7: INSTR("ror"); SHFT(RD); SHFT_UPCC(RD); break;
806 case 0x9: UNIMP("ldrexd"); break;
807 // P=1, U=1, bit22=0, W=1 - offset/pre-index, add offset, register, writeback
808 case 0xb:
809 if (L) {
810 INSTR("ldrh");
811 temp = RN + RM;
812 RD = MEM(u16, temp);
813 RN = temp;
814 } else {
815 INSTR("strh");
816 temp = RN + RM;
817 MEM(u16, temp) = RD;
818 RN = temp;
819 }
820 break;
821 case 0xd:
822 if (L) {
823 INSTR("ldrsb");
824 temp = RN + RM;
825 RD = MEM(s8, temp);
826 RN = temp;
827 } else {
828 UNIMP("ldrd");
829 }
830 break;
831 case 0xf: if (L) {
832 INSTR("ldrsh");
833 temp = RN + RM;
834 RD = MEM(s16, temp);
835 RN = temp;
836 } else {
837 UNIMP("strd");
838 }
839 break;
840 default: UNIMP("BXTYPE"); break;
841 }; break;
842case 0x0e: if (OP1 == 0 || OP2 == 0) {
843 INSTR("bic"); SHFT(res); RD = RN & ~res; SHFT_UPCC(RD); break;
844 }
845 switch (BXTYPE) {
846 case 0x9: UNIMP("ldrexb"); break;
847 // P=1, U=1, bit22=1, W=0 - offset/pre-index, add offset, immediate, no writeback
848 case 0xb:
849 if (L) {
850 INSTR("ldrh");
851 RD = MEM(u16, RN + IMMHL);
852 } else {
853 INSTR("strh");
854 MEM(u16, RN + IMMHL) = RD;
855 }
856 break;
857 case 0xd:
858 if (L) {
859 INSTR("ldrsb");
860 RD = MEM(s8, RN + IMMHL);
861 } else {
862 UNIMP("ldrd");
863 }
864 break;
865 case 0xf: if (L) {
866 INSTR("ldrsh");
867 RD = MEM(s16, RN + IMMHL);
868 } else {
869 UNIMP("strd");
870 }
871 break;
872 } break;
873case 0x0f: if (OP1 == 0 || OP2 == 0) {
874 INSTR("mvn"); SHFT(res); RD = ~res; SHFT_UPCC(RD); break;
875 } else {
876 switch (BXTYPE) {
877 case 0x9: UNIMP("ldrexh"); break;
878 // P=1, U=1, bit22=1, W=1 - offset/pre-index, add offset, immediate, writeback
879 case 0xb:
880 if (L) {
881 INSTR("ldrh");
882 temp = RN + IMMHL;
883 RD = MEM(u16, temp);
884 RN = temp;
885 } else {
886 INSTR("strh");
887 temp = RN + IMMHL;
888 MEM(u16, temp) = RD;
889 RN = temp;
890 }
891 break;
892 case 0xd:
893 if (L) {
894 INSTR("ldrsb");
895 temp = RN + IMMHL;
896 RD = MEM(s8, temp);
897 RN = temp;
898 } else {
899 UNIMP("ldrd");
900 }
901 break;
902 case 0xf: if (L) {
903 INSTR("ldrsh");
904 temp = RN + IMMHL;
905 RD = MEM(s16, temp);
906 RN = temp;
907 } else {
908 UNIMP("strd");
909 }
910 break;
911 default: UNIMP("BXTYPE"); break;
912 } break;
913 } break;
914case 0x10: INSTR("and"); RD = RN & IMM32; UPCC(RD); break;
915case 0x11: INSTR("eor"); RD = RN ^ IMM32; UPCC(RD); break;
916case 0x12: INSTR("sub"); SBB(RD, RN, IMM32, 1); break;
917case 0x13: INSTR("rsb"); SBB(RD, IMM32, RN, 1); break;
918case 0x14: INSTR("add"); ADC(RD, RN, IMM32, 0); break;
919case 0x15: INSTR("adc"); ADC(RD, RN, IMM32, C); break;
920case 0x16: INSTR("sbc"); SBB(RD, RN, IMM32, C); break;
921case 0x17: INSTR("rsc"); SBB(RD, IMM32, RN, C); break;
922case 0x18: INSTR("movw"); RD = IMM16; break;
923case 0x19: switch (BXTYPE) {
924 case 0x0: INSTR("nop"); break;
925 case 0x1:
926 INSTR("wrc");
927 if (UFIELD(19, 4) == 0xf) { // "wrc pc"
928 printf("Tracing on\n");
929 trace = 1;
930 } else if (UFIELD(19, 4) == 0xe) { // "wrc lr"
931 printf("Tracing off\n");
932 trace = 0;
933 } else if (RN == -1) {
934// trace = 1;
935// printf("find %x %x %x %x\n",r[2], r[1], r[0], r[3]);
936 // alf = find(u8 *adr, u32 len, u32 *link, void *origin);
937 r[0] = (u32)find((u8 *)r[2], r[1], (u32 *)r[0], (u8 *)r[3]);
938// printf("returns %x\n", r[0]);
939 } else {
940 /* Handle Forth wrapper calls - the call# is in RN */
941 r[0] = (*(long (*) ())(*(long *)(syscall_vec + RN)))
942 (r[0],r[1],r[2],r[3],r[4],r[5]);
943 }
944 break;
945
946 case 0xf: UNIMP("dbg"); break;
947 default: UNIMP("msr"); break;
948 } break;
949case 0x1a: if (S) {
950 INSTR("cmp"); SBB(res, RN, IMM32, 1); break;
951 } else {
952 INSTR("movt"); RD = (IMM16 << 16) | (RD & 0xffff); break;
953 }
954case 0x1b: INSTR("cmn"); ADC(res, RN, IMM32, 0); break;
955case 0x1c: INSTR("orr"); RD = RN | IMM32; UPCC(RD); break;
956case 0x1d: INSTR("mov"); RD = IMM32; UPCC(RD); break;
957case 0x1e: INSTR("bic"); RD = RN & (~IMM32); UPCC(RD); break;
958case 0x1f: INSTR("mvn"); RD = ~IMM32; UPCC(RD); break;
959case 0x20:
960case 0x21: if (L) {
961 INSTR("ldr"); RD = MEM(u32, RN); RN -= IMM12;
962 } else {
963 INSTR("str"); MEM(u32, RN) = RD; RN -= IMM12;
964 } break;
965case 0x22:
966case 0x23: if (L) {
967 INSTR("ldrb"); RD = MEM(u8, RN); RN -= IMM12;
968 } else {
969 INSTR("strb"); MEM(u8, RN) = RD; RN -= IMM12;
970 } break;
971case 0x24: if (L) {
972 if (UFIELD(19, 4) == 0xd) {
973 INSTR("pop"); RD = MEM(u32, RN); RN += IMM12;
974 } else {
975 if (instruction == 0xe49cf004) { // ldr pc,[ip],#4 i.e. the guts of NEXT
976 INSTR("DONEXT");
977 } else if (instruction == 0xe49ca004) { // ldr tos,[ip],#4 i.e. the guts of (lit) and (')
978 INSTR("DOLIT");
979 } else {
980 if (instruction == 0xe49bc004) { indent--; if (indent < 0) indent = 0; }
981 INSTR("ldr");
982 }
983 RD = MEM(u32, RN); RN += IMM12;
984 if (trace) {
985 // If NEXT or ('), show the name of the word
986 if ((instruction == 0xe49cf004) || (instruction == 0xe49ca004)) {
987 name = RD - 5;
988 // If name is not in the dictionary area, it is probably a numeric literal
989 if (name >= r[9] && ((name - r[9]) < 0x100000)) {
990 namelen = *(char *)name & 0x3f;
991 name = name - namelen;
992 // Indent with * for EMACS outline mode - handy for hiding subordinate calls
993// for (temp = 0; temp < indent; temp++)
994// putchar('*');
995 while (namelen--)
996 putchar(*(char *)name++);
997 printf(" Stack: %x %x %x %x indent %x\n" ,
998 ((u32 *)r[13])[2], ((u32 *)r[13])[1], ((u32 *)r[13])[0], r[10], indent);
999 }
1000 }
1001 }
1002 }
1003 } else {
1004 INSTR("str"); MEM(u32, RN) = RD; RN += IMM12;
1005 } break;
1006case 0x25: if (L) {
1007 INSTR("ldr"); RD = MEM(u32, RN); RN += IMM12;
1008 } else {
1009 INSTR("str"); MEM(u32, RN) = RD; RN += IMM12;
1010 } break;
1011case 0x26:
1012case 0x27: if (L) {
1013 INSTR("ldrb"); RD = MEM(u8, RN); RN += IMM12;
1014 } else {
1015 INSTR("strb"); MEM(u8, RN) = RD; RN += IMM12;
1016 } break;
1017case 0x28: if (L) {
1018 INSTR("ldr"); RD = MEM(u32, RN - IMM12); break;
1019 } else {
1020 INSTR("str"); MEM(u32, RN - IMM12) = RD; break;
1021 } break;
1022case 0x29: if (L) {
1023 INSTR("ldr"); RN -= IMM12; RD = MEM(u32, RN); break;
1024 } else {
1025 if (instruction == 0xe52bc004) indent++; // DOCOLON
1026 INSTR("str"); RN -= IMM12; MEM(u32, RN) = RD;
1027 break;
1028 } break;
1029case 0x2a: if (L) {
1030 INSTR("ldrb"); RD = MEM(u8, RN - IMM12); break;
1031 } else {
1032 INSTR("strb"); MEM(u8, RN - IMM12) = RD; break;
1033 } break;
1034case 0x2b: if (L) {
1035 INSTR("ldrb"); RN -= IMM12; RD = MEM(u8, RN); break;
1036 } else {
1037 INSTR("strb"); RN -= IMM12; MEM(u8, RN) = RD; break;
1038 } break;
1039case 0x2c: if (L) {
1040 INSTR("ldr"); RD = MEM(u32, RN + IMM12); break;
1041 } else {
1042 INSTR("str"); MEM(u32, RN + IMM12) = RD; break;
1043 } break;
1044case 0x2d: if (L) {
1045 INSTR("ldr"); RN += IMM12; RD = MEM(u32, RN); break;
1046 } else {
1047 INSTR("str"); RN += IMM12; MEM(u32, RN) = RD; break;
1048 } break;
1049case 0x2e: if (L) {
1050 INSTR("ldrb"); RD = MEM(u8, RN + IMM12); break;
1051 } else {
1052 INSTR("strb"); MEM(u8, RN + IMM12) = RD; break;
1053 } break;
1054case 0x2f: if (L) {
1055 INSTR("ldrb"); RN += IMM12; RD = MEM(u8, RN); break;
1056 } else {
1057 INSTR("strb"); RN += IMM12; MEM(u8, RN) = RD; break;
1058 } break;
1059case 0x30:
1060case 0x31: if (OP1) {
1061 UNIMP("mcr"); break;
1062 } else if (L) {
1063 INSTR("ldr"); SHFT(res); RD = MEM(u32, RN); RN -= res; break;
1064 } else {
1065 INSTR("str"); SHFT(res); MEM(u32, RN) = RD; RN -= res; break;
1066 } break;
1067case 0x32:
1068case 0x33: if (OP1) {
1069 UNIMP("mcr"); break;
1070 } else if (L) {
1071 INSTR("ldrb"); SHFT(res); RD = MEM(u8, RN); RN -= res; break;
1072 } else {
1073 INSTR("strb"); SHFT(res); MEM(u8, RN) = RD; RN -= res; break;
1074 } break;
1075case 0x34:
1076case 0x35: if (OP1) {
1077 UNIMP("mcr"); break;
1078 } else if (L) {
1079 INSTR("ldr"); SHFT(res); RD = MEM(u32, RN); RN += res; break;
1080 } else {
1081 INSTR("str"); SHFT(res); MEM(u32, RN) = RD; RN += res; break;
1082 } break;
1083case 0x36:
1084case 0x37: if (OP1) {
1085 UNIMP("mcr"); break;
1086 } else if (L) {
1087 INSTR("ldrb"); SHFT(res); RD = MEM(u8, RN); RN += res; break;
1088 } else {
1089 INSTR("strb"); SHFT(res); MEM(u8, RN) = RD; RN += res; break;
1090 } break;
1091case 0x38: if (OP1) {
1092 UNIMP("smlad"); break;
1093 } else if (L) {
1094 INSTR("ldr"); SHFT(res); RD = MEM(u32, RN - res); break;
1095 } else {
1096 INSTR("str"); SHFT(res); MEM(u32, RN - res) = RD; break;
1097 } break;
1098case 0x39: if (L) {
1099 INSTR("ldr"); SHFT(res); RN -= res; RD = MEM(u32, RN); break;
1100 } else {
1101 INSTR("str"); SHFT(res); RN -= res; MEM(u32, RN) = RD; break;
1102 } break;
1103case 0x3a: if (OP1) {
1104 UNIMP("smlald"); break;
1105 } else if (L) {
1106 INSTR("ldrb"); SHFT(res); RD = MEM(u8, RN - res); break;
1107 } else {
1108 INSTR("strb"); SHFT(res); MEM(u8, RN - res) = RD; break;
1109 } break;
1110case 0x3b: if (L) {
1111 INSTR("ldrb"); SHFT(res); RN -= res; RD = MEM(u8, RN); break;
1112 } else {
1113 INSTR("strb"); SHFT(res); RN -= res; MEM(u8, RN) = RD; break;
1114 }
1115case 0x3c: if (L) {
1116 INSTR("ldr"); SHFT(res); RD = MEM(u32, RN + res); break;
1117 } else {
1118 INSTR("str"); SHFT(res); MEM(u32, RN + res) = RD; break;
1119 }
1120case 0x3d: if (OP1) {
1121 UNIMP("sbfx"); break;
1122 } else if (L) {
1123 INSTR("ldr"); SHFT(res); RN += res; RD = MEM(u32, RN); break;
1124 } else {
1125 INSTR("str"); SHFT(res); RN += res; MEM(u32, RN) = RD; break;
1126 } break;
1127case 0x3e: if (OP1) {
1128 if (UFIELD(3, 4) == 0xf) {
1129 INSTR("bfc"); RD &= ~BF(MSB, LSB);
1130 } else {
1131 INSTR("bfi");
1132 RD &= ~BF(MSB, LSB);
1133 RD |= RN & ~BF(MSB, LSB);
1134 }
1135 } else if (L) {
1136 INSTR("ldrb"); SHFT(res); RD = MEM(u8, RN + res);
1137 } else {
1138 INSTR("strb"); SHFT(res); MEM(u8, RN + res) = RD;
1139 } break;
1140case 0x3f: if (L) {
1141 INSTR("ldrb"); SHFT(res); RN += res; RD = MEM(u8, RN); break;
1142 } else {
1143 INSTR("strb"); SHFT(res); RN += res; MEM(u8, RN) = RD; break;
1144 } break;
1145case 0x40:
1146case 0x41: { u32 base = RN;
1147 u32 reglist = UFIELD(15, 16);
1148 s32 reg;
1149 if (L) {
1150 INSTR("ldmda");
1151 } else {
1152 INSTR("stmda");
1153 }
1154 for (reg = 15; reg >= 0; reg--) {
1155 if ((1 << reg) & reglist) {
1156 if (L) {
1157 r[reg] = MEM(u32, base);
1158 } else {
1159 MEM(u32, base) = r[reg];
1160 }
1161 base -= 4;
1162 }
1163 }
1164 if (W) RN = base;
1165 } break;
1166case 0x42: UNIMP("xxx");
1167case 0x43: UNIMP("xxx");
1168case 0x44:
1169case 0x45: { u32 base = RN;
1170 u32 reglist = UFIELD(15, 16);
1171 s32 reg;
1172 if (L) {
1173 INSTR("ldm");
1174 } else {
1175 INSTR("stm");
1176 }
1177 for (reg = 0; reg < 16; reg++) {
1178 if ((1 << reg) & reglist) {
1179 if (L) {
1180 r[reg] = MEM(u32, base);
1181 } else {
1182 MEM(u32, base) = r[reg];
1183 }
1184 base += 4;
1185 }
1186 }
1187 if (W) RN = base;
1188 } break;
1189case 0x46: UNIMP("xxx");
1190case 0x47: UNIMP("xxx");
1191case 0x48:
1192case 0x49: { u32 base = RN;
1193 u32 reglist = UFIELD(15, 16);
1194 s32 reg;
1195 if (L) {
1196 INSTR("ldmdb");
1197 } else {
1198 INSTR("stmdb");
1199 }
1200 for (reg = 15; reg >= 0; reg--) {
1201 if ((1 << reg) & reglist) {
1202 base -= 4;
1203 if (L) {
1204 r[reg] = MEM(u32, base);
1205 } else {
1206 MEM(u32, base) = r[reg];
1207 }
1208 }
1209 }
1210 if (W) RN = base;
1211 } break;
1212case 0x4a: UNIMP("xxx"); break;
1213case 0x4b: UNIMP("xxx"); break;
1214case 0x4c:
1215case 0x4d: { u32 base = RN + 4;
1216 u32 reglist = UFIELD(15, 16);
1217 s32 reg;
1218 if (L) {
1219 INSTR("ldmib");
1220 } else {
1221 INSTR("stmib");
1222 }
1223 for (reg = 0; reg < 16; reg++) {
1224 if ((1 << reg) & reglist) {
1225 if (L) {
1226 r[reg] = MEM(u32, base);
1227 } else {
1228 MEM(u32, base) = r[reg];
1229 }
1230 base += 4;
1231 }
1232 }
1233 if (W) RN = base;
1234 } break;
1235case 0x4e: UNIMP("xxx"); break;
1236case 0x4f: UNIMP("xxx"); break;
1237case 0x50:
1238case 0x51:
1239case 0x52:
1240case 0x53:
1241case 0x54:
1242case 0x55:
1243case 0x56:
1244case 0x57: INSTR("b"); BTGT; break;
1245case 0x58:
1246case 0x59:
1247case 0x5a:
1248case 0x5b:
1249case 0x5c:
1250case 0x5d:
1251case 0x5e:
1252case 0x5f: INSTR("bl"); LR = PC - 4; BTGT; break;
1253case 0x60:
1254case 0x61: UNIMP("stc"); break;
1255case 0x62: UNIMP("mcrr"); break;
1256case 0x63:
1257case 0x64:
1258case 0x65:
1259case 0x66:
1260case 0x67:
1261case 0x68:
1262case 0x69:
1263case 0x6a:
1264case 0x6b:
1265case 0x6c:
1266case 0x6d:
1267case 0x6e: UNIMP("stc"); break;
1268case 0x6f: UNIMP("ldc"); break;
1269case 0x70:
1270case 0x71:
1271case 0x72:
1272case 0x73:
1273case 0x74:
1274case 0x75:
1275case 0x76:
1276case 0x77: UNIMP("cdp"); break;
1277case 0x78:
1278case 0x79:
1279case 0x7a:
1280case 0x7b:
1281case 0x7c:
1282case 0x7d:
1283case 0x7e:
1284case 0x7f: UNIMP("svc"); break;
1285 } // switch (OP)
1286 if (PC == last_pc)
1287 PC += 4;
1288 else // branch or move
1289 PC += 8;
1290 } // while (1)
1291}
1292
1293// LICENSE_BEGIN
1294// Copyright (c) 2007 FirmWorks
1295// Copyright 2010 Apple, Inc. All rights reserved.
1296//
1297// Permission is hereby granted, free of charge, to any person obtaining
1298// a copy of this software and associated documentation files (the
1299// "Software"), to deal in the Software without restriction, including
1300// without limitation the rights to use, copy, modify, merge, publish,
1301// distribute, sublicense, and/or sell copies of the Software, and to
1302// permit persons to whom the Software is furnished to do so, subject to
1303// the following conditions:
1304//
1305// The above copyright notice and this permission notice shall be
1306// included in all copies or substantial portions of the Software.
1307//
1308// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
1309// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
1310// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
1311// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
1312// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
1313// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
1314// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
1315//
1316// LICENSE_END

Archive Download this file

Revision: 3725