1.1 --- a/src/aica/armcore.c Sat Aug 21 06:15:49 2004 +0000
1.2 +++ b/src/aica/armcore.c Sat Oct 02 05:49:39 2004 +0000
1.5 struct arm_registers armr;
1.7 -/* NB: The arm (one assumes) has a different memory map, but for the meantime... */
1.8 +/* NB: The arm has a different memory map, but for the meantime... */
1.9 +/* Page references are as per ARM DDI 0100E (June 2000) */
1.11 #define MEM_READ_BYTE( addr ) mem_read_byte(addr)
1.12 #define MEM_READ_WORD( addr ) mem_read_word(addr)
1.13 @@ -12,20 +13,635 @@
1.14 #define MEM_WRITE_WORD( addr, val ) mem_write_word(addr, val)
1.15 #define MEM_WRITE_LONG( addr, val ) mem_write_long(addr, val)
1.18 +#define IS_NOTBORROW( result, op1, op2 ) (op2 > op1 ? 0 : 1)
1.19 +#define IS_CARRY( result, op1, op2 ) (result < op1 ? 1 : 0)
1.20 +#define IS_SUBOVERFLOW( result, op1, op2 ) (((op1^op2) & (result^op1)) >> 31)
1.21 +#define IS_ADDOVERFLOW( result, op1, op2 ) (((op1&op2) & (result^op1)) >> 31)
1.23 #define PC armr.r[15];
1.25 +/* Instruction fields */
1.26 +#define COND(ir) (ir>>28)
1.27 +#define GRP(ir) ((ir>>26)&0x03)
1.28 +#define OPCODE(ir) ((ir>>20)&0x1F)
1.29 +#define IFLAG(ir) (ir&0x02000000)
1.30 +#define SFLAG(ir) (ir&0x00100000)
1.31 +#define PFLAG(ir) (ir&0x01000000)
1.32 +#define UFLAG(ir) (ir&0x00800000)
1.33 +#define BFLAG(ir) (ir&0x00400000)
1.34 +#define WFLAG(ir) (IR&0x00200000)
1.35 +#define LFLAG(ir) SFLAG(ir)
1.36 +#define RN(ir) (armr.r[((ir>>16)&0x0F)] + (((ir>>16)&0x0F) == 0x0F ? 4 : 0))
1.37 +#define RD(ir) (armr.r[((ir>>12)&0x0F)] + (((ir>>16)&0x0F) == 0x0F ? 4 : 0))
1.38 +#define RDn(ir) ((ir>>12)&0x0F)
1.39 +#define RS(ir) (armr.r[((ir>>8)&0x0F)] + (((ir>>16)&0x0F) == 0x0F ? 4 : 0))
1.40 +#define RM(ir) (armr.r[(ir&0x0F)] + (((ir>>16)&0x0F) == 0x0F ? 4 : 0))
1.41 +#define LRN(ir) armr.r[((ir>>16)&0x0F)]
1.42 +#define LRD(ir) armr.r[((ir>>12)&0x0F)]
1.43 +#define LRS(ir) armr.r[((ir>>8)&0x0F)]
1.44 +#define LRM(ir) armr.r[(ir&0x0F)]
1.46 +#define IMM8(ir) (ir&0xFF)
1.47 +#define IMM12(ir) (ir&0xFFF)
1.48 +#define SHIFTIMM(ir) ((ir>>7)0x1F)
1.49 +#define IMMROT(ir) ((ir>>7)&1E)
1.50 +#define SHIFT(ir) ((ir>>4)&0x07)
1.51 +#define DISP24(ir) ((ir&0x00FFFFFF))
1.53 +static uint32_t arm_get_shift_operand( uint32_t ir )
1.55 + uint32_t operand, tmp;
1.56 + if( IFLAG(ir) == 0 ) {
1.58 + switch(SHIFT(ir)) {
1.59 + case 0: /* (Rm << imm) */
1.60 + operand = operand << SHIFTIMM(ir);
1.62 + case 1: /* (Rm << Rs) */
1.63 + tmp = RS(ir)&0xFF;
1.64 + if( tmp > 31 ) operand = 0;
1.65 + else operand = operand << tmp;
1.67 + case 2: /* (Rm >> imm) */
1.68 + operand = operand >> SHIFTIMM(ir);
1.70 + case 3: /* (Rm >> Rs) */
1.71 + tmp = RS(ir) & 0xFF;
1.72 + if( tmp > 31 ) operand = 0;
1.73 + else operand = operand >> ir;
1.75 + case 4: /* (Rm >>> imm) */
1.76 + tmp = SHIFTIMM(ir);
1.77 + if( tmp == 0 ) operand = ((int32_t)operand) >> 31;
1.78 + else operand = ((int32_t)operand) >> tmp;
1.80 + case 5: /* (Rm >>> Rs) */
1.81 + tmp = RS(ir) & 0xFF;
1.82 + if( tmp > 31 ) operand = ((int32_t)operand) >> 31;
1.83 + else operand = ((int32_t)operand) >> tmp;
1.86 + tmp = SHIFTIMM(ir);
1.87 + if( tmp == 0 ) /* RRX aka rotate with carry */
1.88 + operand = (operand >> 1) | (arm4.c<<31);
1.90 + operand = ROTATE_RIGHT_LONG(operand,tmp);
1.93 + tmp = RS(ir)&0x1F;
1.94 + operand = ROTATE_RIGHT_LONG(operand,tmp);
1.98 + operand = IMM8(ir);
1.100 + operand = ROTATE_RIGHT_LONG(operand, tmp);
1.106 + * Compute the "shift operand" of the instruction for the data processing
1.107 + * instructions. This variant also sets armr.shift_c (carry result for shifter)
1.108 + * Reason for the variants is that most cases don't actually need the shift_c.
1.110 +static uint32_t arm_get_shift_operand_s( uint32_t ir )
1.112 + uint32_t operand, tmp;
1.113 + if( IFLAG(ir) == 0 ) {
1.114 + operand = RM(ir);
1.115 + switch(SHIFT(ir)) {
1.116 + case 0: /* (Rm << imm) */
1.117 + tmp = SHIFTIMM(ir);
1.118 + if( tmp == 0 ) { /* Rm */
1.119 + armr.shift_c = armr.c;
1.120 + } else { /* Rm << imm */
1.121 + armr.shift_c = (operand >> (32-tmp)) & 0x01;
1.122 + operand = operand << tmp;
1.125 + case 1: /* (Rm << Rs) */
1.126 + tmp = RS(ir)&0xFF;
1.128 + armr.shift_c = armr.c;
1.131 + armr.shift_c = (operand >> (32-tmp)) & 0x01;
1.132 + else armr.shift_c = 0;
1.134 + operand = operand << tmp;
1.135 + else operand = 0;
1.138 + case 2: /* (Rm >> imm) */
1.139 + tmp = SHIFTIMM(ir);
1.141 + armr.shift_c = operand >> 31;
1.144 + armr.shift_c = (operand >> (tmp-1)) & 0x01;
1.145 + operand = RM(ir) >> tmp;
1.148 + case 3: /* (Rm >> Rs) */
1.149 + tmp = RS(ir) & 0xFF;
1.151 + armr.shift_c = armr.c;
1.154 + armr.shift_c = (operand >> (tmp-1))&0x01;
1.155 + else armr.shift_c = 0;
1.157 + operand = operand >> tmp;
1.158 + else operand = 0;
1.161 + case 4: /* (Rm >>> imm) */
1.162 + tmp = SHIFTIMM(ir);
1.164 + armr.shift_c = operand >> 31;
1.165 + operand = -armr.shift_c;
1.167 + armr.shift_c = (operand >> (tmp-1)) & 0x01;
1.168 + operand = ((int32_t)operand) >> tmp;
1.171 + case 5: /* (Rm >>> Rs) */
1.172 + tmp = RS(ir) & 0xFF;
1.174 + armr.shift_c = armr.c;
1.177 + armr.shift_c = (operand >> (tmp-1))&0x01;
1.178 + operand = ((int32_t)operand) >> tmp;
1.180 + armr.shift_c = operand >> 31;
1.181 + operand = ((int32_t)operand) >> 31;
1.186 + tmp = SHIFTIMM(ir);
1.187 + if( tmp == 0 ) { /* RRX aka rotate with carry */
1.188 + armr.shift_c = operand&0x01;
1.189 + operand = (operand >> 1) | (arm4.c<<31);
1.191 + armr.shift_c = operand>>(tmp-1);
1.192 + operand = ROTATE_RIGHT_LONG(operand,tmp);
1.196 + tmp = RS(ir)&0xFF;
1.198 + armr.shift_c = armr.c;
1.202 + armr.shift_c = operand>>31;
1.204 + armr.shift_c = (operand>>(tmp-1))&0x1;
1.205 + operand = ROTATE_RIGHT_LONG(operand,tmp);
1.211 + operand = IMM8(ir);
1.212 + tmp = IMMROT(ir);
1.214 + armr.shift_c = armr.c;
1.216 + operand = ROTATE_RIGHT_LONG(operand, tmp);
1.217 + armr.shift_c = operand>>31;
1.224 + * Another variant of the shifter code for index-based memory addressing.
1.225 + * Distinguished by the fact that it doesn't support register shifts, and
1.226 + * ignores the I flag (WTF do the load/store instructions use the I flag to
1.227 + * mean the _exact opposite_ of what it means for the data processing
1.228 + * instructions ???)
1.230 +static uint32_t arm_get_address_index( uint32_t ir )
1.232 + uint32_t operand = RM(ir);
1.233 + switch(SHIFT(ir)) {
1.234 + case 0: /* (Rm << imm) */
1.235 + operand = operand << SHIFTIMM(ir);
1.237 + case 2: /* (Rm >> imm) */
1.238 + operand = operand >> SHIFTIMM(ir);
1.240 + case 4: /* (Rm >>> imm) */
1.241 + tmp = SHIFTIMM(ir);
1.242 + if( tmp == 0 ) operand = ((int32_t)operand) >> 31;
1.243 + else operand = ((int32_t)operand) >> tmp;
1.246 + tmp = SHIFTIMM(ir);
1.247 + if( tmp == 0 ) /* RRX aka rotate with carry */
1.248 + operand = (operand >> 1) | (arm4.c<<31);
1.250 + operand = ROTATE_RIGHT_LONG(operand,tmp);
1.252 + default: UNIMP(ir);
1.257 +static uint32_t arm_get_address_operand( uint32_t ir )
1.262 + switch( (ir>>21)&0x1D ) {
1.263 + case 0: /* Rn -= imm offset (post-indexed) [5.2.8 A5-28] */
1.266 + RN(ir) = addr - IMM12(ir);
1.268 + case 4: /* Rn += imm offsett (post-indexed) [5.2.8 A5-28] */
1.271 + RN(ir) = addr + IMM12(ir);
1.273 + case 8: /* Rn - imm offset [5.2.2 A5-20] */
1.274 + addr = RN(ir) - IMM12(ir);
1.276 + case 9: /* Rn -= imm offset (pre-indexed) [5.2.5 A5-24] */
1.277 + addr = RN(ir) - IMM12(ir);
1.280 + case 12: /* Rn + imm offset [5.2.2 A5-20] */
1.281 + addr = RN(ir) + IMM12(ir);
1.283 + case 13: /* Rn += imm offset [5.2.5 A5-24 ] */
1.284 + addr = RN(ir) + IMM12(ir);
1.287 + case 16: /* Rn -= Rm (post-indexed) [5.2.10 A5-32 ] */
1.290 + RN(ir) = addr - arm_get_address_index(ir);
1.292 + case 20: /* Rn += Rm (post-indexed) [5.2.10 A5-32 ] */
1.295 + RN(ir) = addr - arm_get_address_index(ir);
1.297 + case 24: /* Rn - Rm [5.2.4 A5-23] */
1.298 + addr = RN(ir) - arm_get_address_index(ir);
1.300 + case 25: /* RN -= Rm (pre-indexed) [5.2.7 A5-26] */
1.301 + addr = RN(ir) - arm_get_address_index(ir);
1.304 + case 28: /* Rn + Rm [5.2.4 A5-23] */
1.305 + addr = RN(ir) + arm_get_address_index(ir);
1.307 + case 29: /* RN += Rm (pre-indexed) [5.2.7 A5-26] */
1.308 + addr = RN(ir) + arm_get_address_index(ir);
1.312 + UNIMP(ir); /* Unreachable */
1.317 void arm_execute_instruction( void )
1.319 - uint32_t ir = MEM_READ_LONG(PC);
1.320 + uint32_t pc = PC;
1.321 + uint32_t ir = MEM_READ_LONG(PC);
1.322 + uint32_t operand, operand2, tmp, armr.shift_c;
1.324 -#define COND(ir) (ir>>28)
1.329 + switch( COND(ir) ) {
1.336 + case 2: /* CS/HS */
1.339 + case 3: /* CC/LO */
1.355 + cond = armr.c && !armr.z;
1.358 + cond = (!armr.c) || armr.z;
1.360 + case 10: /* GE */
1.361 + cond = (armr.n == armr.v);
1.363 + case 11: /* LT */
1.364 + cond = (armr.n != armr.v);
1.366 + case 12: /* GT */
1.367 + cond = (!armr.z) && (armr.n == armr.v);
1.369 + case 13: /* LE */
1.370 + cond = armr.z || (armr.n != armr.v);
1.372 + case 14: /* AL */
1.375 + case 15: /* (NV) */
1.380 + switch( GRP(ir) ) {
1.382 + if( (ir & 0x0D900000) == 0x01000000 ) {
1.383 + /* Instructions that aren't actual data processing */
1.384 + switch( ir & 0x0FF000F0 ) {
1.385 + case 0x01200010: /* BX */
1.387 + case 0x01000000: /* MRS Rd, CPSR */
1.389 + case 0x01400000: /* MRS Rd, SPSR */
1.391 + case 0x01200000: /* MSR CPSR, Rd */
1.393 + case 0x01600000: /* MSR SPSR, Rd */
1.395 + case 0x03200000: /* MSR CPSR, imm */
1.397 + case 0x03600000: /* MSR SPSR, imm */
1.402 + } else if( (ir & 0x0E000090) == 0x00000090 ) {
1.403 + /* Neither are these */
1.404 + switch( (ir>>5)&0x03 ) {
1.406 + /* Arithmetic extension area */
1.407 + switch(OPCODE(ir)) {
1.408 + case 0: /* MUL */
1.410 + case 1: /* MULS */
1.412 + case 2: /* MLA */
1.414 + case 3: /* MLAS */
1.416 + case 8: /* UMULL */
1.418 + case 9: /* UMULLS */
1.420 + case 10: /* UMLAL */
1.422 + case 11: /* UMLALS */
1.424 + case 12: /* SMULL */
1.426 + case 13: /* SMULLS */
1.428 + case 14: /* SMLAL */
1.430 + case 15: /* SMLALS */
1.432 + case 16: /* SWP */
1.434 + case 20: /* SWPB */
1.441 + if( LFLAG(ir) ) {
1.448 + if( LFLAG(ir) ) {
1.455 + if( LFLAG(ir) ) {
1.463 + /* Data processing */
1.465 + switch(OPCODE(ir)) {
1.466 + case 0: /* AND Rd, Rn, operand */
1.467 + RD(ir) = RN(ir) & arm_get_shift_operand(ir);
1.469 + case 1: /* ANDS Rd, Rn, operand */
1.470 + operand = arm_get_shift_operand_s(ir) & RN(ir);
1.471 + RD(ir) = operand;
1.472 + if( RDn(ir) == 15 ) {
1.473 + arm_restore_cpsr();
1.475 + armr.n = operand>>31;
1.476 + armr.z = (operand == 0);
1.477 + armr.c = armr.shift_c;
1.480 + case 2: /* EOR Rd, Rn, operand */
1.481 + RD(ir) = RN(ir) ^ arm_get_shift_operand(ir);
1.483 + case 3: /* EORS Rd, Rn, operand */
1.484 + operand = arm_get_shift_operand_s(ir) ^ RN(ir);
1.485 + RD(ir) = operand;
1.486 + if( RDn(ir) == 15 ) {
1.487 + arm_restore_cpsr();
1.489 + armr.n = operand>>31;
1.490 + armr.z = (operand == 0);
1.491 + armr.c = armr.shift_c;
1.494 + case 4: /* SUB Rd, Rn, operand */
1.495 + RD(ir) = RN(ir) - arm_get_shift_operand(ir);
1.497 + case 5: /* SUBS Rd, Rn, operand */
1.498 + operand = RN(ir);
1.499 + operand2 = arm_get_shift_operand(ir)
1.500 + tmp = operand - operand2;
1.502 + if( RDn(ir) == 15 ) {
1.503 + arm_restore_cpsr();
1.505 + armr.n = tmp>>31;
1.506 + armr.z = (tmp == 0);
1.507 + armr.c = IS_NOTBORROW(tmp,operand,operand2);
1.508 + armr.v = IS_SUBOVERFLOW(tmp,operand,operand2);
1.511 + case 6: /* RSB Rd, operand, Rn */
1.512 + RD(ir) = arm_get_shift_operand(ir) - RN(ir);
1.514 + case 7: /* RSBS Rd, operand, Rn */
1.515 + operand = arm_get_shift_operand(ir);
1.516 + operand2 = RN(ir);
1.517 + tmp = operand - operand2;
1.519 + if( RDn(ir) == 15 ) {
1.520 + arm_restore_cpsr();
1.522 + armr.n = tmp>>31;
1.523 + armr.z = (tmp == 0);
1.524 + armr.c = IS_NOTBORROW(tmp,operand,operand2);
1.525 + armr.v = IS_SUBOVERFLOW(tmp,operand,operand2);
1.528 + case 8: /* ADD Rd, Rn, operand */
1.529 + RD(ir) = RN(ir) + arm_get_shift_operand(ir);
1.531 + case 9: /* ADDS Rd, Rn, operand */
1.532 + operand = arm_get_shift_operand(ir);
1.533 + operand2 = RN(ir);
1.534 + tmp = operand + operand2
1.536 + if( RDn(ir) == 15 ) {
1.537 + arm_restore_cpsr();
1.539 + armr.n = tmp>>31;
1.540 + armr.z = (tmp == 0);
1.541 + armr.c = IS_CARRY(tmp,operand,operand2);
1.542 + armr.v = IS_ADDOVERFLOW(tmp,operand,operand2);
1.545 + case 10: /* ADC */
1.546 + case 11: /* ADCS */
1.547 + case 12: /* SBC */
1.548 + case 13: /* SBCS */
1.549 + case 14: /* RSC */
1.550 + case 15: /* RSCS */
1.552 + case 17: /* TST Rn, operand */
1.553 + operand = arm_get_shift_operand_s(ir) & RN(ir);
1.554 + armr.n = operand>>31;
1.555 + armr.z = (operand == 0);
1.556 + armr.c = armr.shift_c;
1.558 + case 19: /* TEQ Rn, operand */
1.559 + operand = arm_get_shift_operand_s(ir) ^ RN(ir);
1.560 + armr.n = operand>>31;
1.561 + armr.z = (operand == 0);
1.562 + armr.c = armr.shift_c;
1.564 + case 21: /* CMP Rn, operand */
1.565 + operand = RN(ir);
1.566 + operand2 = arm_get_shift_operand(ir)
1.567 + tmp = operand - operand2;
1.568 + armr.n = tmp>>31;
1.569 + armr.z = (tmp == 0);
1.570 + armr.c = IS_NOTBORROW(tmp,operand,operand2);
1.571 + armr.v = IS_SUBOVERFLOW(tmp,operand,operand2);
1.573 + case 23: /* CMN Rn, operand */
1.574 + operand = RN(ir);
1.575 + operand2 = arm_get_shift_operand(ir)
1.576 + tmp = operand + operand2;
1.577 + armr.n = tmp>>31;
1.578 + armr.z = (tmp == 0);
1.579 + armr.c = IS_CARRY(tmp,operand,operand2);
1.580 + armr.v = IS_ADDOVERFLOW(tmp,operand,operand2);
1.582 + case 24: /* ORR Rd, Rn, operand */
1.583 + RD(ir) = RN(ir) | arm_get_shift_operand(ir);
1.585 + case 25: /* ORRS Rd, Rn, operand */
1.586 + operand = arm_get_shift_operand_s(ir) | RN(ir);
1.587 + RD(ir) = operand;
1.588 + if( RDn(ir) == 15 ) {
1.589 + arm_restore_cpsr();
1.591 + armr.n = operand>>31;
1.592 + armr.z = (operand == 0);
1.593 + armr.c = armr.shift_c;
1.596 + case 26: /* MOV Rd, operand */
1.597 + RD(ir) = arm_get_shift_operand(ir);
1.599 + case 27: /* MOVS Rd, operand */
1.600 + operand = arm_get_shift_operand_s(ir);
1.601 + RD(ir) = operand;
1.602 + if( RDn(ir) == 15 ) {
1.603 + arm_restore_cpsr();
1.605 + armr.n = operand>>31;
1.606 + armr.z = (operand == 0);
1.607 + armr.c = armr.shift_c;
1.610 + case 28: /* BIC Rd, Rn, operand */
1.611 + RD(ir) = RN(ir) & (~arm_get_shift_operand(ir));
1.613 + case 29: /* BICS Rd, Rn, operand */
1.614 + operand = RN(ir) & (~arm_get_shift_operand_s(ir));
1.615 + RD(ir) = operand;
1.616 + if( RDn(ir) == 15 ) {
1.617 + arm_restore_cpsr();
1.619 + armr.n = operand>>31;
1.620 + armr.z = (operand == 0);
1.621 + armr.c = armr.shift_c;
1.624 + case 30: /* MVN Rd, operand */
1.625 + RD(ir) = ~arm_get_shift_operand(ir);
1.627 + case 31: /* MVNS Rd, operand */
1.628 + operand = ~arm_get_shift_operand_s(ir);
1.629 + RD(ir) = operand;
1.630 + if( RDn(ir) == 15 ) {
1.631 + arm_restore_cpsr();
1.633 + armr.n = operand>>31;
1.634 + armr.z = (operand == 0);
1.635 + armr.c = armr.shift_c;
1.643 + case 1: /* Load/store */
1.645 + case 2: /* Load/store multiple, branch*/
1.647 + case 3: /* Copro */
1.652 -void arm_execute_thumb_instruction( void )