Home | Projects | Notes > ARM Cortex-M3/M4 Processor > Thumb State & T Bit of EPSR
This section applies to ARM Cortex M0/M3/M4 Processors. If you are using any other processors, please consult the corresponding document.
Various ARM processors support ARM-Thumb inter-working, the ability to switch between ARM state and Thumb state.
The processor must be in ARM state to execute instructions which are from ARM ISA.
The processor must be in Thumb state to execute instructions of Thumb ISA.
If the T bit of the EPSR is set (1), the processor thinks that the next instruction to execute is from Thumb ISA.
If the T bit of the EPSR is reset (0), the processor thinks that the next instruction to execute is from ARM ISA.
The cortex Mx processor does NOT support the ARM state. Hence, the value of T bit must always be 1. Failing to maintain this is illegal and this will result in the "Usage fault" exception.
The LSB (bit 0) of the program counter (PC) is linked to the T bit. When you load a value (i.e., an address) into PC the bit 0 of the value is loaded into the T bit.
Hence, any address you place in the PC must have its 0th bit as 1. This is usually taken care of by the compiler and programmers don't have to worry about it most of the time.
This is why you see all the vector addresses are incremented by 1 (hence, all odd) in the vector table.
Question! Does this mean that the addresses of user-defined functions are even by default? Based on the "natural size boundary" of the pointers?
Yes! Question! When the compiler adds 1 to the even function address to make the LSB 1 for the PC to maintain the T bit value, does the system later decrements the PC address by 1 again to execute the actual function?
Any branch instruction that writes to PC (Program Counter) only updates bits 31:1 and forces '0' into the 0th bit. This is how the system works well.
The program to demonstrate what the compiler does to the addresses of functions to maintain the T bit (of EPSR) as 1.
xxxxxxxxxx
911
2
3
4
5
6
7
8/*
9 * THREAD MODE : Privileged/Unprivileged access level
10 * HANDLER MODE : Privileged access level only!
11 */
12
13/*
14 * This function executes in THREAD MODE of the processor.
15 * Within this function, we are triggering software interrupt by accessing the
16 * system level registers of the ARM Cortex Mx processor.
17 */
18void generate_interrupt()
19{
20 /*
21 * These are ARM Cortex M4 processor's system control register addresses which
22 * can only be accessed in PRIVILEGED ACCESS LEVEL.
23 * Any attempt to change the contents of these registers from being in UNPRIVILEGED
24 * ACCESS LEVEL will cause a processor fault exception.
25 */
26 uint32_t *pSTIR = (uint32_t *)0xE000EF00;
27 uint32_t *pISER0 = (uint32_t *)0xE000E100;
28
29 // enable IRQ3 interrupt
30 *pISER0 |= (1 << 3);
31
32 // generate an interrupt from software for IRQ3
33 // (interrupt handler "RTC_WKUP_IRQHandler" will be invoked)
34 *pSTIR = (3 & 0x1FF);
35}
36
37void change_access_level_unpriv(void)
38{
39 /*
40 * To make the processor transition into UNPRIVILEGED ACCESS LEVEL,
41 * bit 0 of the CONTROL register must be set to 1.
42 * CONTROL register is NOT a memory mapped register which means that
43 * it is impossible for a programmer to access this register using C
44 * code only. Inline assembly technique is necessary.
45 */
46 __asm volatile("mrs r0, CONTROL"); // read
47 __asm volatile("orr r0, r0, 0x01"); // modify
48 __asm volatile("msr CONTROL, r0"); // write (this is where access level changes to
49 // UNPRIVILEGED
50}
51
52/*
53 * This function executes in THREAD MODE + PRIVILEGED ACCESS LEVEL of the processor.
54 * (Remember, after reset, the processor always starts in THREAD MODE.)
55 * In reality, "Reset_Handler:" is the first function to be called on reset,
56 * but at this point we will assume that the "main" is the first to be called.
57 */
58int main(void)
59{
60 printf("Thread mode: before interrupt\n");
61
62 void (*fn_ptr)(void);
63 fn_ptr = change_access_level_unpriv;
64 // Actual address of 'change_access_level_unpriv' is 0x80001e8 (even).
65 // But, the compiler intentionally increments the address by 1 so that the bit 0 of
66 // the PC becomes 1 and that the T bit of EPSR is guaranteed to be 1.
67
68 fn_ptr(); // to dereference the function pointer (to call the function), use ()
69 // at this point, the address of fn_ptr gets loaded into PC
70
71 printf("Thread mode: after interrupt\n");
72
73 /* Loop forever */
74 for(;;);
75}
76
77/*
78 * This function (ISR) executes in HANDLER MODE of the processor.
79 * In HANDLER MODE, you have the full control over the processor. You have the
80 * privilege to access any resources you want.
81 */
82void RTC_WKUP_IRQHandler(void)
83{
84 printf("Handler mode: ISR\n");
85}
86
87void HardFault_Handler(void)
88{
89 printf("Hard fault detected\n");
90 while(1);
91}
L63 - If you did
fn_ptr = 0x80001e8
(force the original even address), then the execution of L68 will trigger "Hard fault".
Nayak, K. (2022). Embedded Systems Programming on ARM Cortex-M3/M4 Processor [Video file]. Retrieved from https://www.udemy.com/course/embedded-system-programming-on-arm-cortex-m3m4/