Search code examples
armembeddedbootloadertrace32

If the program counter (PC) reset in arm, how the booting resumes?


I have an arm controller and I have an option to reset the CPU registers using Lauterbach Trace32. Now after resetting the CPU registers also , when I press "Play" in the Trace32 ,2 times my board is up and running. So when there is no way to know where to fetch the commands from (Since I presume PC is the guy who tells where to look for instructions) how this work out?. I went and saw the code and I can see that after the CPU registers are reset the PC value is 0. The behavior is like this

  1. I reset all CPU registers
  2. resume running
  3. The processor stops with message , "stopped by vector catch"
  4. I again resume running

The board is up and running !!


Solution

  • infocenter.arm.com contains critical documentation for what you are asking, go read those.

    But you need to know which ones to read. There are lets say three major flavors of arm with some sub-flavors. One is the traditional arm transitions from acorn, starting with the ARMv4T, the classic ARM7TDMI core that got ARM that we know today started. That architecture included the classic 32 bit ARM instructions as well as smaller thumb instructions. We move through ARMv5T, ARMv6 (don't think it needed to carry the T any more) and then ARMv6M. ARMv7 and ARMv7m.

    The first microcontroller not an ARM7TDMI was the cortex-m3 which is ARMv7m based and is a thumb only machine, no full sized arm instructions, it did have about 150 thumb2 extensions which are two halfword sized instructions, first halfword is decoded as you would expect with a thumb decoder then formerly undefined instructions are now defined as thumb2 extension the next halfword is decoded. The cortex-m3 simply hit the streets first, then later the cortex-m0 came out which is armv6m based. The ARMv8 which is an entirely new instruction set that includes 64 bit registers, also will generally have an ARMv7 compatibility mode which is the end of the line of the classic 32 bit arm instruction set. Yes there is an ARMv8m for microcontrollers and it is mostly ARMv6m instructions with some of the ARMv7m thumb2 extensions, but it is compile (of the logic) time optional if I remember right. There are very few of these on the street at the time of this writing.

    So arm does not make chips they make cores, look at your chip vendors documentation and look for cortex-a or cortex-m initially if not then arm7 or arm9 or arm11. You can then go to arms infocenter page and look for the technical reference manual for that specific core, in that document you will find the architecture (cortex-m3 for example) and then you go to the reference manuals and find the architectural reference manual for that architecture, and in there lies your answers.

    For the traditional cores, the ones without the m, the non-cortexms, so arm7 (not armv7, arm7) arm9, arm10, arm11, cortex-a, and cortex-r.

    Generally address 0x00000000 contains the first INSTRUCTION executed after reset is released, there are straps on the core to allow for a high address to be fetched, but generally assume 0x00000000 also the chip vendor would have to somehow use that strap either allow you access or they use it for a bootloader. if the chip vendor boots the core on their bootloader first then all bets are off as to where your application code can start, generally they create the illusion of a reset by using the stock reset solution for that core (a number of microcontrollers ARM7TDMIs and cortex-ms, but not all it is up to the chip design).

    So don't get confused about the role of the program counter, in real, modern processors think of there being multiple program counters, certainly in arm you have an address that is used for prefetching an address used for fetching within that, an address used for execution at a minimum. What matters to us is that the architecture document says the first instruction EXECUTED lives at address 0x00000000 for these full sized classic arms. For this class of ARM architecture there is also an exception that has its first instruction EXECUTED at address 0x00000004 so you have to get out of the way of these special addresses (The ones you are using if not expecting or using other events then you can just start your code at zero) you need to branch by either using an unconditional branch or an ldr pc,something.

    The cortex-ms (cortex-m0, cortex-m0+, cortex-m1.....) use a classic interrupt vector table approach, one simple exception but it is still a vector table approach.

    For these, and there can be a strap on the core to override, but assume the normal use case of address 0x00000000 contains the value you would like to initialize the stack pointer with, a lot of chip vendors start their ram at 0x20000000 but not all so you might put 0x20004000 here for example of you have 0x4000 bytes of sram on that part. Address 0x00000004 in the cores address space contains the reset vector and here you as the programmer place the address to your reset code, the first instructions you want to execute. Being a thumb machine and since we think of thumb addresses when used for interworking the lsbit is set and you need the lsbit set so if your first instruction you want to EXECUTE is at address 0x00000100 then you need to set address 0x00000004 to 0x00000101, the processor logic (stop thinking about program counters) will read address 0x00000004 after a reset checks the lsbit, strips it and uses 0x100 to fetch the first instruction.

    Addresses 0x00000008 and on for as many as a hundred or two entries can be used, depends on the core, and the chip vendors implementation. The idea is performance, every tiny little thing that can have an interrupt has the potential of having its own vector, depends on the chip vendors design. Unlike the old days of a single interrupt then you have to go read a bunch of interrupt controller registers then maybe poll through some peripherals to find who caused the interrupt you save a few steps and aim generally at the one peripheral with this design.

    The 64 bit cores. These have history in the classic arm approach but with the different execution modes and countless features related to protection and control I'll let you read that yourself. For the boring reset you come in at address 0x00000000 and execute the first instruction there. But beware the mpcore which is an arm11/armv6 the armv7 full sized and the armv8s have multicore flavors, each core with a separate clock enable and reset that the CHIP VENDOR (not ARM) wires up, so the two basic designs are one core is released from reset it starts executing at address 0x00000000, then that core talks to chip vendor logic to release other cores, before doing that it can change the code or execution path so that that core runs different code than core0, and/or the code written can "sort the cores" by using arm specific id registers in each core to cause the code to branch into core specific code so each core is doing its own thing.

    The other thing you may find (think raspberry pi, but that is simply because we don't mess with the gpu and don't know where these chip specific registers are) is that all the cores release at the same time so you have multiple processors executing address zero at or near the same time, and you definitely have to sort them to get one booting the rest of the chip and the others not interfering. But for simple reset the aarch64 cores (armv8 currently being the only architecture) the first instruction executed is at address 0x00000000.

    You as the programmer are ultimately responsible for linking such that the right instructions or addresses are at the right place. Very often you will start your bare-metal experience with a toolchain or someone else's code that has done all of this for you, and maybe you are at that point where you want to understand this. So one you have to write the code or build the table you want at address zero, then second you have to link it right, then third load it into the processor or feed the processor right so it all works.

    Some microcontrollers have bootloaders that interfere with this in some way, but for small programs I don't think I have seen one that won't let you build for address zero. Some will mirror address zero and a higher address say 0x08000000 for the ST parts, and you can put vectors like 0x08000101 in the vector table to fetch right into the application flash space. in general with mcus though your first job after knowing the core used is to find where sram and flash/rom are and start to work on your linker script.