25 suicide("undefined instruction %8ux @ %8ux", instr, P->R[15] - 4);
29 evenaddr(u32int addr, u32int mask)
31 if((addr & mask) == 0)
33 suicide("unaligned access %8ux @ %8ux", addr, P->R[15] - 4);
38 doshift(u32int instr, u8int *carry)
42 val = P->R[instr & 15];
46 amount = P->R[(instr >> 8) & 15] & 0xFF;
50 amount = (instr >> 7) & 31;
51 if(amount == 0 && (instr & (3<<5)) != 0)
54 switch((instr >> 5) & 3) {
59 *carry = (val >> (32 - amount)) & 1;
66 *carry = (val >> (amount - 1)) & 1;
73 *carry = (val >> (amount - 1)) & 1;
74 return ((long) val) >> amount;
85 *carry = (val >> (amount - 1)) & 1;
86 return (val >> amount) | (val << (32 - amount));
90 return (val>>1) | (amount<<31);
107 offset = doshift(instr, &carry);
109 offset = instr & ((1<<12) - 1);
112 Rn = P->R + ((instr >> 16) & 15);
113 Rd = P->R + ((instr >> 12) & 15);
114 if((instr & (fW | fP)) == fW)
116 if(Rn == P->R + 15) {
125 if((instr & fB) == 0)
126 addr = evenaddr(addr, 3);
127 targ = vaddr(addr, (instr & fB) == 0 ? 4 : 1, &seg);
128 switch(instr & (fB | fL)) {
130 *(u32int*) targ = *Rd;
133 *(u8int*) targ = *Rd;
136 *Rd = *(u32int*) targ;
139 *Rd = *(u8int*) targ;
142 if(Rd == P->R + 15 && !(instr & fL)) {
146 *(u32int*) targ += 8;
151 if((instr & fW) || !(instr & fP))
155 /* atomic compare and swap from libc */
156 extern int cas(u32int *p, u32int old, u32int new);
161 u32int *Rm, *Rn, *Rd, *targ, addr, old, new;
164 Rm = P->R + (instr & 15);
165 Rd = P->R + ((instr >> 12) & 15);
166 Rn = P->R + ((instr >> 16) & 15);
167 if(Rm == P->R + 15 || Rd == P->R + 15 || Rn == P->R + 15)
170 if((instr & fB) == 0)
171 addr = evenaddr(addr, 3);
172 targ = (u32int *) vaddr(addr & ~3, 4, &seg);
179 new |= old & ~(0xFF << 8*(addr&3));
181 } while(!cas(targ, old, new));
191 add(u32int a, u32int b, u8int type, u8int *carry, u8int *overflow)
197 res2 = (u64int)a - b + *carry - 1;
199 if(((a ^ b) & (1<<31)) && !((b ^ res1) & (1<<31))) *overflow = 1;
201 if(res2 & 0x100000000LL) *carry = 0;
204 res2 = (u64int)a + b + *carry;
206 if(!((a ^ b) & (1<<31)) && ((b ^ res1) & (1<<31))) *overflow = 1;
208 if(res2 & 0x100000000LL) *carry = 1;
217 u32int Rn, *Rd, operand, shift, result, op;
218 u8int carry, overflow;
220 Rn = P->R[(instr >> 16) & 15];
221 Rd = P->R + ((instr >> 12) & 15);
222 if(((instr >> 16) & 15) == 15) {
224 if(!(instr & fI) && (instr & (1<<4)))
227 if(Rd == P->R + 15 && (instr & fS))
230 carry = (P->CPSR & flC) != 0;
231 overflow = (P->CPSR & flV) != 0;
234 operand = instr & 0xFF;
235 shift = ((instr >> 8) & 15) << 1;
237 operand = (operand >> shift) | (operand << (32 - shift));
238 carry = operand >> 31;
241 operand = doshift(instr, &carry);
243 op = (instr >> 21) & 15;
244 if(op >= 8 && op <= 11 && !(instr & fS))
245 sysfatal("no PSR transfers plz");
246 if(op >= 5 && op < 8)
247 carry = (P->CPSR & flC) != 0;
249 case 0: case 8: result = Rn & operand; break;
250 case 1: case 9: result = Rn ^ operand; break;
251 case 2: case 10: carry = 1; case 6: result = add(Rn, operand, 1, &carry, &overflow); break;
252 case 3: carry = 1; case 7: result = add(operand, Rn, 1, &carry, &overflow); break;
253 case 4: case 11: carry = 0; case 5: result = add(operand, Rn, 0, &carry, &overflow); break;
254 case 12: result = Rn | operand; break;
255 case 13: result = operand; break;
256 case 14: result = Rn & ~operand; break;
257 case 15: result = ~operand; break;
258 default: result = 0; /* never happens */
271 if(op < 8 || op >= 12)
280 offset = instr & ((1<<24) - 1);
282 offset |= ~((1 << 24) - 1);
286 P->R[15] += offset + 4;
290 halfword(u32int instr)
292 u32int offset, target, *Rn, *Rd;
295 if(instr & (1<<22)) {
296 offset = (instr & 15) | ((instr >> 4) & 0xF0);
298 if((instr & 15) == 15)
300 offset = P->R[instr & 15];
304 if(!(instr & fP) && (instr & fW))
306 Rn = P->R + ((instr >> 16) & 15);
307 Rd = P->R + ((instr >> 12) & 15);
308 if(Rn == P->R + 15 || Rd == P->R + 15)
309 sysfatal("R15 in halfword");
314 target = evenaddr(target, 1);
315 switch(instr & (fSg | fH | fL)) {
316 case fSg: *(u8int*) vaddr(target, 1, &seg) = *Rd; break;
317 case fSg | fL: *Rd = (long) *(char*) vaddr(target, 1, &seg); break;
318 case fH: case fSg | fH: *(u16int*) vaddr(target, 2, &seg) = *Rd; break;
319 case fH | fL: *Rd = *(u16int*) vaddr(target, 2, &seg); break;
320 case fH | fL | fSg: *Rd = (long) *(short*) vaddr(target, 2, &seg); break;
325 if(!(instr & fP) || (instr & fW))
338 Rn = P->R + ((instr >> 16) & 15);
339 if(Rn == P->R + 15 || instr & (1<<15))
340 sysfatal("R15 block");
341 targ = evenaddr(*Rn, 3);
343 for(i = 0; i < 16; i++) {
344 if(!(instr & (1<<i)))
349 P->R[i] = *(u32int*) vaddr(targ, 4, &seg);
351 *(u32int*) vaddr(targ, 4, &seg) = P->R[i];
357 for(i = 15; i >= 0; i--) {
358 if(!(instr & (1<<i)))
363 P->R[i] = *(u32int*) vaddr(targ, 4, &seg);
365 *(u32int*) vaddr(targ, 4, &seg) = P->R[i];
376 multiply(u32int instr)
378 u32int *Rd, *Rn, *Rs, *Rm, res;
380 Rm = P->R + (instr & 15);
381 Rs = P->R + ((instr >> 8) & 15);
382 Rn = P->R + ((instr >> 12) & 15);
383 Rd = P->R + ((instr >> 16) & 15);
384 if(Rd == Rm || Rm == P->R + 15 || Rs == P->R + 15 || Rn == P->R + 15 || Rd == P->R + 15)
390 if(instr & (1<<20)) {
391 P->CPSR &= ~(flN | flZ);
400 multiplylong(u32int instr)
402 u32int *RdH, *RdL, *Rs, *Rm;
405 Rm = P->R + (instr & 15);
406 Rs = P->R + ((instr >> 8) & 15);
407 RdL = P->R + ((instr >> 12) & 15);
408 RdH = P->R + ((instr >> 16) & 15);
409 if(RdL == RdH || RdH == Rm || RdL == Rm || Rm == P->R + 15 || Rs == P->R + 15 || RdL == P->R + 15 || RdH == P->R + 15)
412 res = ((vlong)*(int*)Rs) * *(int*)Rm;
417 if(instr & (1<<21)) {
419 res += ((uvlong)*RdH) << 32;
423 if(instr & (1<<20)) {
433 singleex(u32int instr)
435 u32int *Rn, *Rd, *Rm, *targ, addr;
438 Rd = P->R + ((instr >> 12) & 15);
439 Rn = P->R + ((instr >> 16) & 15);
440 if(Rd == P->R + 15 || Rn == P->R + 15)
442 addr = evenaddr(*Rn, 3);
444 targ = vaddr(addr, 4, &seg);
450 Rm = P->R + (instr & 15);
453 targ = vaddr(addr, 4, &seg);
456 * this is not quite correct as we will succeed even
457 * if the value was modified and then restored to its
458 * original value but good enougth approximation for
459 * libc's _tas(), _cas() and _xinc()/_xdec().
461 *Rd = addr != P->lladdr || !cas(targ, P->llval, *Rm);
489 instr = *(u32int*) vaddr(P->R[15], 4, &seg);
492 print("%d ", P->pid);
497 if(findsym(P->R[15], CTEXT, &s) >= 0)
498 print("%s ", s.name);
499 if(fileline(buf, 512, P->R[15]) >= 0)
502 print("%.8ux %.8ux %c%c%c%c\n", P->R[15], instr,
503 (P->CPSR & flZ) ? 'Z' : ' ',
504 (P->CPSR & flC) ? 'C' : ' ',
505 (P->CPSR & flN) ? 'N' : ' ',
506 (P->CPSR & flV) ? 'V' : ' '
510 switch(instr >> 28) {
511 case 0x0: if(!(P->CPSR & flZ)) return; break;
512 case 0x1: if(P->CPSR & flZ) return; break;
513 case 0x2: if(!(P->CPSR & flC)) return; break;
514 case 0x3: if(P->CPSR & flC) return; break;
515 case 0x4: if(!(P->CPSR & flN)) return; break;
516 case 0x5: if(P->CPSR & flN) return; break;
517 case 0x6: if(!(P->CPSR & flV)) return; break;
518 case 0x7: if(P->CPSR & flV) return; break;
519 case 0x8: if(!(P->CPSR & flC) || (P->CPSR & flZ)) return; break;
520 case 0x9: if((P->CPSR & flC) && !(P->CPSR & flZ)) return; break;
521 case 0xA: if(!(P->CPSR & flN) != !(P->CPSR & flV)) return; break;
522 case 0xB: if(!(P->CPSR & flN) == !(P->CPSR & flV)) return; break;
523 case 0xC: if((P->CPSR & flZ) || !(P->CPSR & flN) != !(P->CPSR & flV)) return; break;
524 case 0xD: if(!(P->CPSR & flZ) && !(P->CPSR & flN) == !(P->CPSR & flV)) return; break;
527 switch(instr & 0xFFF000F0){
528 case 0xF5700010: /* CLREX */
531 case 0xF5700040: /* DSB */
532 case 0xF5700050: /* DMB */
533 case 0xF5700060: /* ISB */
537 default: sysfatal("condition code %x not implemented (instr %ux, ps %ux)", instr >> 28, instr, P->R[15]);
539 if((instr & 0x0FB00FF0) == 0x01000090)
541 else if((instr & 0x0FE000F0) == 0x01800090)
543 else if((instr & 0x0FC000F0) == 0x90)
545 else if((instr & 0x0F8000F0) == 0x800090)
547 else if((instr & ((1<<26) | (1<<27))) == (1 << 26))
549 else if((instr & 0x0E000090) == 0x90 && (instr & 0x60))
551 else if((instr & ((1<<26) | (1<<27))) == 0)
553 else if((instr & (7<<25)) == (5 << 25))
555 else if((instr & (15<<24)) == (15 << 24))
557 else if((instr & (7<<25)) == (4 << 25))
559 else if((instr & 0x0E000F00) == 0x0C000100)
561 else if((instr & 0x0E000F10) == 0x0E000100)
563 else if((instr & 0x0E000F10) == 0x0E000110)
564 fparegtransfer(instr);
565 else if(vfp && ((instr & 0x0F000A10) == 0x0E000A00))
567 else if(vfp && ((instr & 0x0F000F10) == 0x0E000A10))
568 vfpregtransfer(instr);
569 else if(vfp && ((instr & 0x0F000A00) == 0x0D000A00))
570 vfprmtransfer(instr);