项目作者: nfsu

项目描述 :
A basic ARM7/9TDMI emulator
高级语言: C++
项目地址: git://github.com/nfsu/armulator.git
创建时间: 2019-07-15T20:12:11Z
项目社区:https://github.com/nfsu/armulator

开源协议:MIT License

下载


Armchitecture (ARM7/9)

ARM7/ARM9 are 16/32-bit RISC architectures where every opcode is 1 unit. In ARM-mode this would be 4 bytes, while in Thumb-mode this would be 2 bytes.

ARM7TDMI & ARM9TDMI contain 38 32-bit registers which can be accessed through virtual registers, which change physical register depending on the current active mode. This also contains the PSRs (Program Status Registers); the CPSR (Current PSR) and the SPSR (Saved PSR). The SPSR is used to save the CPSR when a software interrupt is triggered. This allows you to go back to function the interrupt was called from.

The accessible registers are the r0-r15 registers. r15 is the PC (program counter) which points to the current instruction. r14 is the LR (link register) which is used to hold a backup to the previous PC when a jump with link is performed. r13 is the SP (stack pointer) which points to the top (or bottom) of the stack.

The stack is Full Descending and virtual memory access depends on the current system.

Thumb mode

The T in ARM7/9TDMI stands for Thumb; a 16-bit mode. This is a simplified instruction set though it still allows for doing almost the same things, albeit in more instructions. Regular instructions only allows access to r0-r7, though other registers can be manipulated by using the r0-r7 registers as an intermediate and by specialized instructions.

The entire documentation on the instruction set can be found here.

Arm mode

If T is disabled, the program is running in Arm mode; 32-bit mode.

The entire documentation on the instruction set can be found here.

PSR

The PSR is like a regular 32-bit register, except it has bitflags that express how the next instructions will be executed. It contains the condition flags (what instructions will be executed and what branches will be), the thumb flag (if it is using thumb mode or arm mode) and other important flags such at the current mode (the banks it is using). The PSRs are not accessible through a mapped register, though some instructions can save and reset the PSR.

  1. struct PSR {
  2. //Control bits
  3. Mode mode : 5; //The execution mode
  4. bool thumb : 1; //T; if thumb mode is used
  5. bool disableFiq : 1; //F: if FIQ is disabled
  6. bool disableIrq : 1; //I: if IRQ is disabled
  7. //Unused for ARM7/9TDMI (20 bits)
  8. //Padding 2 bytes + 4 bits
  9. u8 p0[2];
  10. u8 p1 : 4;
  11. //Condition flags
  12. bool overflow : 1; //V: the last operation caused a signed overflow
  13. bool carry : 1; //C: the last operation caused an unsigned overflow
  14. bool zero : 1; //Z: the last operation was zero
  15. bool negative : 1; //N: the last operation was negative
  16. };

Condition flags

  1. enum Condition : u8 /* 4-bit */ {
  2. EQ, //Equals (zero)
  3. NE, //Not Equals (!zero)
  4. CS, //Carry Set; unsigned >= (carry)
  5. CC, //Carry Clear; unsigned < (!carry)
  6. MI, //MInus; < 0 (negative)
  7. PL, //PLus; >= 0 (!negative)
  8. VS, //oVerflow Set (overflow)
  9. VC, //oVerflow Clear (!overflow)
  10. HI, //Higher than unsigned > (carry && !zero)
  11. LS, //Less or equal unsigned <= (!carry || zero)
  12. GE, //Greater or equal >= (negative == overflow)
  13. LT, //Less < (negative != overflow)
  14. GT, //Greater > (!zero && negative == overflow)
  15. LE, //Less or equal <= (zero || negative != overflow)
  16. AL, //Always
  17. NV //Never (software interrupt)
  18. };

The conditions are checked from the CPSR to determine if it should execute an operation.

A compare and other operations can set the condition flags, changing the control flow of your program. A compare is the same as subtracting the right variable from the left variable. This will set the respective bits.

  1. # r0 = 0, r1 = 1
  2. MOV r0, 0
  3. MOV r1, 1
  4. # Checks positive for: EQ ==, CC, PL >=, VC, LS <=, GE >=, LE <=, AL
  5. CMP r0, r0 # = 0 - 0 = 0
  6. # Checks positive for: NE !=, CC, MI <, VC, LS <=, LT <, LE <=, AL
  7. CMP r0, r1 # = 0 - 1 = u32_MAX (-1)
  8. # Checks positive for: NE !=, CC, PL >=, VC, HI >, GE >=, GT >, AL
  9. CMP r1, r0 # = 1 - 0 = 1

These conditions can then be used as a suffix for every operation:

  1. # Always branch to myLabel
  2. BAL myLabel
  3. # Goto myLabel if the last operation was zero (x == y)
  4. BEQ myLabel

The flags aren’t set by all operations; some operations only set negative & zero flags, while alu operations (regularly) set the negative, zero, carry & overflow flags. Other operations such as barrel shifts generally don’t set the overflow flag.

These flags are calculated the following way; (a = left, b = right, c = result)

  1. //Zero
  2. c == 0;
  3. //Negative
  4. c & i32_MIN;
  5. //Carry
  6. //Depends on the current instruction; most of the time this is true if the number looped around (ADD/SUB)
  7. //However, shifts check the bit that is going to be shifted out.
  8. //5 >> 1 = 4 C 1, 4 >> 1 = 2 C 0.
  9. //Overflow
  10. (a & i32_MIN) == (b & i32_MIN) && (c & i32_MIN) != (a & i32_MIN)

Modes

Some accessible registers map to different registers depending on the mode set in the PSR. These modes are as follows:

  1. enum Mode : u8 /* 5-bit */ {
  2. USR = 0x10,
  3. FIQ = 0x11,
  4. IRQ = 0x12,
  5. SVC = 0x13,
  6. ABT = 0x17,
  7. UND = 0x1B,
  8. SYS = 0x1F
  9. };

There are 7 modes available; USR (16), FIQ (17), IRQ (18), SVC (19), ABT (23), UND (27), SYS (31). Other modes are illegal and will cause the processor to enter an unrecoverable state.

The modes before 1 0000 are legacy modes and aren’t used in ARM7/9 processors. ARM6 supports these 26-bit modes to allow for ARM2/ARM3 compatibility.

All non-user modes are privileged modes allowing them full access to system resources and allowing them to change mode freely.

To check for validity in a PSR mode, the following function can be used

  1. bool isValid(Mode m){
  2. return (m & USR) && ((m & 3) == 3 || m < SVC);
  3. }

Banked registers

r0-r15 and the SPSR are mapped to physical registers. These registers depend on the current mode. The following illustrates how registers are shared with modes:

3

Figure 1: Register organization in ARM state [3]

The SPSR, SP and LR are always affected and for FIQ the r8-r12 registers are as well. The r8_fiq is a different physical register than the regular r8. The mapping is as follows:

  1. struct RegisterData {
  2. u32 loReg[8];
  3. u32 sysUsr[7];
  4. u32 pc;
  5. u32 fiq[7];
  6. u32 irq[2];
  7. u32 svc[2];
  8. u32 abt[2];
  9. u32 und[2];
  10. PSR cpsr;
  11. PSR spsr[6];
  12. };
  13. //Lookup table for mode id from mode enum
  14. static constexpr u8 modeToId[] = {
  15. 6,6,6,6, 6,6,6,6, 6,6,6,6, 6,6,6,6, //Legacy ARM6 modes
  16. 0,1,2,3, 6,6,6,4, 6,6,6,5, 6,6,6,0 //USR, FIQ, IRQ, ABT, UND, SYS
  17. };
  18. //Lookup table for the registers using their mode id
  19. static constexpr u8 registerMapping[][16] = {
  20. { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 }, //SYS and USR
  21. { 0, 1, 2, 3, 4, 5, 6, 7, 16, 17, 18, 19, 20, 21, 22, 15 }, //FIQ
  22. { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 23, 24, 15 }, //IRQ
  23. { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 25, 26, 15 }, //SVC
  24. { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 27, 28, 15 }, //ABT
  25. { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 29, 30, 15 } //UND
  26. };
  27. //registerMapping[modeToId[FIQ]][9] = r9_fiq

Sources

Arm infocenter ARM7TDMI Technical Reference Manual control bits [0]

Keil Current Program Status Register (CPSR) [1]

Arm infocenter The ARM state register set [2]

Arm infocenter Register organization in ARM state [3]