I'm playing with ARM using an STM32F103C8T6 Blue Pill board. According to its Programming Manual (Section 2.3.4 Vector Table), there are a total of 83 exception vectors to be set. However, this tutorial only fills the first 6 and this tutorial the first 10. Curiously, I can verify that both firmware executes as expected, despite the absence of a lot of exception handlers.
Just to clarify, below is the very part I am referring to (link to original file). As you can see, only the first few words get assigned a handler, and all subsequent space is used to hold the .text
section.
.section .isr_vector
.align 2
.global _isr_vector
_isr_vector:
.long __StackTop /* we will need this later */
.long Reset_Handler
.long Default_Handler
.long Default_Handler
.long Default_Handler
.long Default_Handler
.long Default_Handler
.long 0
.long 0
.long 0
.long 0
.long Default_Handler
.long Default_Handler
.long 0
.long Default_Handler
.long Default_Handler
This confuses me: what is the least amount of exception handlers I need to fill? In my use case (which is nothing more than a toy project), there are no exceptions to be excepted, so can I just set the Reset Handler?
As a bonus, the Programming Manual specifies that "The least-significant bit of each vector must be 1, indicating that the exception handler is Thumb code." However, the code above clearly doesn't follow this convention, so how does it correctly call the reset handler on boot?
.thumb
.global _start
_start:
.word 0x20001000
.word one
.word two
.align
.thumb_func
one:
b .
two:
b .
arm-none-eabi-as so.s -o so.o
arm-none-eabi-ld -Ttext=0x08000000 so.o -o so.elf
arm-none-eabi-objdump -D so.elf
so.elf: file format elf32-littlearm
Disassembly of section .text:
08000000 <_start>:
8000000: 20001000 andcs r1, r0, r0
8000004: 0800000d stmdaeq r0, {r0, r2, r3}
8000008: 0800000e stmdaeq r0, {r1, r2, r3}
0800000c <one>:
800000c: e7fe b.n 800000c <one>
0800000e <two>:
800000e: e7fe b.n 800000e <two>
First off, _start is not required, you will get a warning, it's easier just to put it in there.
You need to declare the label as a function there are a couple of ways to do this in gnu assembler. .thumb_func is easy it does not have to be the line just before you can have other stuff between .thumb_func and the label, but the next label is marked a function.
You will see the output of the compiler do something like this (use -save-temps or -S to see the compiler output), there is another way to declare a function in gas, for full sized arm there is a different one you have to use.
You can see when properly declared the tools take care of you and orr the lsbit of the address in the vector table when you don't declare it properly then you get the wrong address in the vector table which won't work.
And as answered minimum is two entries only because you need to have something at offset/address 4. Note that 0x08000000 maps to 0x00000000 when booting on these STM32 platforms. The minimum is the reset vector if you don't need any of the others, but being at an offset you need to pad the first four bytes. Might as well put a stack pointer initial value in there and same some code later setting it up.
There is nothing really magical about the vector table, it is just an address space you can do fetches as well as data cycles.
Two being the minimum, but if you do end up with an alignment fault or other fault then its going to try to find a vector there, if an even number then that's a problem if odd, then try to execute from that address (the lsbit is stripped off the pc does not have an odd number in it, its just a mechanism to indicate thumb vs arm). So while technically one vector, reset is the minimum its probably a good idea to cover the first 16 (15) just in case.
.thumb
.global _start
_start:
.word 0x20001000
.word reset
.word loop
.word loop
.word loop
.word loop
.word loop
.word loop
.word loop
.word loop
.word loop
.word loop
.word loop
.word loop
.word loop
.word loop
.thumb_func
reset:
b .
.thumb_func
loop:
b .
While you can mix code and vectors if you end up using an interrupt handler for a peripheral then you probably want to not mess with mixing code between the exceptions and wherever your interrupt handler vector is. If you are really desperate for code space in the flash though then technically you can...
As far as minimum P__J__'s answer is the answer. I have added this answer to cover the lsbit question.