Some chips keep the second core powered down until you enable clocks for it and bring it out of reset. On the RP2040, the second core runs right away. A register exists that the bootrom code can test to find out if the code running is core 0 or core 1. When it detects core 1 starting up, it diverts it into special code that comments in the boot code calls a "holding pen". Take a look at "pico-bootrom/bootrom/bootrom_rt0.S" to see all of this.
Many other multi-core processors do something like this, and usually the protocol the bring a core out of the "holding pen" is quite simple. Typically you write the address you want it to run at into a register dedicated to that purpose, and the job is done. Code at that address will need to set up a stack and perform whatever other processor initialization is necessary or desired.
The RP2040 has the most complicated scheme that I have seen to date. The RP2040 has a pair of FIFO devices between the two cores, one for each direction (core 0 to 1 and core 1 to 0). A sequence of values is written to the "0 to 1" fifo, a proper response is monitored on the "1 to 0" fifo and that is how the game is played. The data sheet explains all of this in section 2.8.2 (page 133). The sequence that is written to the 32 bit fifo register is:
0 0 1 vector table stack pointer entry address
A note is in order about the entry address. The way the ARM processor works, when you perform a jump in this way (and this is also true of entries in the vector table), you must set the low bit in the address in the table. The ARM processor takes note of this bit and clears it, so it does not jump to an odd address as would seem to be the case. What the bit does is the tell the processor to run code at that address in thumb mode, hence this bit is called the thumb bit.
If you are writing assembly language, you will designate functions with ".thumb_func" and the assembler will take care of this for you. If you are building a table by hand, you will probably need to do something explicit to set this bit yourself.
The ARM Cortex-M series processors only execute thumb instructions. You would think this would make this entirely unnecessary, but it works the other way -- you must set the "thumb bit" to reassure them that they should keep doing the only thing they know how to do. If you don't set the bit, things "just don't work" -- presumably the processor takes a hard fault exception or something (and ends up spinning given the handler for that I have provided), but I have never been curious enough to investigate the details.
The C compiler knows all about this and does the right thing, setting the thumb bit for function pointers. Note that the actual address itself is not odd (that would be badly aligned and cause other troubles.
Here is a nice discussion of how you fire up core 1 on the RP2040:
The SEV instruction is a partner to this. On a single core machine it will be a NOP. On a multicore machine it "causes an event to be signaled to all cores within a multiprocessor system." It should be easy to see how all of this works.
It must be 256 byte (64 word) aligned for the RP2040. The first 16 entries are exceptions. The next 32 entries are IRQ vectors. (This leaves 16 entries, i.e. 64 bytes unused in the 256 byte section set aside for this). The RP2040 only defines 26 of the 32, and most of the 16 exception entries are "reserved"
Also, as near as I can tell, each core has its own VTOR (vector table offset register). This means each core can have its own vector table, but stand by for more on this when I start working with interrupts and the NVIC.
It was all fairly straightforward to work out and I got the second core out of the "holding pen" and running my code with little trouble as per this:
Tom's electronics pages / firstname.lastname@example.org