Controlling features of the ARM1176jzf-s (Raspberry Pi)
This article is about the Raspberry Pis Processor, the ARM1176jzf-s. It is a 32 Bit ARM-processor, with ARMv6-architecture. It has a VFPv2 Floating Point Unit, can run Java Bytecode natively (Jazelle), can run Thumb(1) code, can use both little and big endian-data, has an MMU and many things more. This article will only talk about some basics of controlling the processor state and features.
Program status register (CPSR)
The CPSR [1] contains flags for the most integral features of the ARM-processor. These are the Jazelle and Thumb state bit, Interrupt and Fast Interrupt disable bits, privilege mode bits [2] and condition bits, which indicate the results of the last test or compare-instruction.
Reading and modifying the CPSR
One cannot read or modify the CPSR with the regular mov or ldr/str instructions. Use the following instructions for reading and writing data from or to the state register:
mrs r0, cpsr // read cpsr into r0
msr cpsr, r0 // write r0 to cpsr
Be aware, that not all bits can be modified by these instructions or should be modified by these instructions or require a privileged mode for modification.
The flags
[1] shows the bits of the CPSR register. There are the condition bits, which I will not be covering here, Jazelle state bit, Endianess, Imprecise abort disable, IRQ and FIQ disable, Thumb state bit and the mode bits. So let's suppose we want to switch to a different mode, like the IRQ-mode, set a stack and return to our previous mode (like the supervisor mode). [3] shows the bit representation of the different modes.
// first read the cpsr register into r0
mrs r0, cpsr
// set the bits last 5 bits to 0
bic r1, r0, #0x1f
// set the appropriate mode bits (0x12 = 0b10010, IRQ mode)
orr r1, r1, #0x12
// write the value to cpsr
msr cpsr, r1
// set the irq-stack (with a predefined label)
ldr sp, =irq_stack_top
// enable interrupts and return to supervisor mode
bic r0, r0, #0x80
msr cpsr, r0
But how can I switch into Jazelle or Thumb-State? You probably already noted, that the msr and mrs instructions should never change the T and J-bits, meaning, that trying to switch into Thumb or Jazelle mode this way will probably result in unpredictable behaviour, i.e. code that does not work as you wanted. [4] depicts the way to jump into Thumb or Jazelle-code: the instructions bx and bxj. These are branch-instructions, which jump into a function, which is compiled as Thumb or Java-Bytecode code. I have yet to try both Thumb and Jazelle.
What about MMU, Caches, Branch Prediction?
Well, enabling the MMU, caches or the branch prediction is in fact not done by the CPSR, but the system control coprocessor. [5] lists its registers. The system control coprocessor has to many features for me to list them here in any way, so take a look into [5]. There are functions to identify the processor and version as well as it's features, there are bits to enable features of the processor, like unaligned access to data, endianess, enabling data and instruction cache on Level 1 or setting the base address for the MMUs translation tables. Hint: Enabling caches without the MMU will probably have no effect, as no page is marked as cacheable, or it could in fact cache registers of I/O-devices, which you would never expect happening. So, just don't!
Accessing the registers of the System Control Coprocessor
You probably already guessed: the registers of the C15-coprocessor cannot be changed by mov or ldr/str either. For accessing these registers we use the mrc and mcr instructions like this:
/// load C15 control register 0,c1,c0,0 into r0
mrc p15, 0, r0, c1, c0, 0
// write r0 into C15 control register 0, c1, c0, 0
mcr p15, 0, r0, c1, c0, 0
Oh god, this looks terribly complicated. Yes, it kind of is, but not really. Let's assume 0,c1,c0,0 is an address. A rather unusual looking address, but nontheless it tells the processor which register of the C15-coprocessor should be written or read from. [5] lists the registers of the coprocessor with these addresses. Let's look up 0,c1,c0,0 - it's the control register. This register has flags for the MMU, Unaligned access, Caches and Branch predictions as well as many others, which I'm not quite sure what they do.
Conclusions
Accessing the CPSR as the central state register of the processor and the registers of the Control Coprocessor is unlike accessing the general purpose registers of the ARM, but it is not much more difficult. Using these registers is an integral part of programming the Raspberry Pi or the ARM1176jzf-s bare metal, as they allow accessing great features of the processor like the MMU or the Interrupt disable-states.
A futures article will introduce the MMU of this processor (family), but for now a good introduction can be found under [6]. This text was originally written by David Welch, I rewrote it for readabilities sake and added explanations as well as bit-layout tables for easier understanding.
References
[1] http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.ddi0301h/I2837.html
[2] http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.ddi0301h/Chdigebi.html
[3] http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.ddi0301h/ch02s10s07.html
[4] http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.ddi0301h/I26052.html
[5] http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.ddi0301h/ch02s09s01.html
[6] https://github.com/naums/raspberrypi/blob/master/mmu/README.md