Core 1 Execution Start Address Ambiguity in Dual-Core Bare-Metal Systems

In a dual-core ARM Cortex-A9 system running bare-metal programs, one of the most critical challenges is ensuring that Core 1 begins execution at the correct memory address after being released from reset. The Cortex-A9 cores, by default, start executing instructions from address 0x00000000 or 0xFFFF0000 (depending on the configuration of the exception vector table). However, when running two separate bare-metal programs on Core 0 and Core 1, the programs are typically loaded into shared SDRAM, which may not align with these default start addresses. This discrepancy creates a synchronization problem: Core 0 must inform Core 1 of the correct execution start address before releasing it from reset.

The issue is further complicated by the shared memory architecture, where both cores access the same SDRAM region. Core 0 must write a startup sequence or branch instruction at the default start address of Core 1 to redirect its execution to the correct location in SDRAM. This requires careful handling of memory remapping, cache coherency, and synchronization mechanisms to ensure that Core 1 begins execution reliably and without conflicts.

Default Start Address Constraints and Memory Remapping Requirements

The ARM Cortex-A9 cores are hardwired to begin execution from specific memory addresses after reset. Core 0 and Core 1 both start fetching instructions from either 0x00000000 or 0xFFFF0000, depending on the configuration of the exception vector table. This behavior is dictated by the processor’s architecture and cannot be changed without modifying the memory map or using hardware remapping techniques.

In a typical bare-metal system, the programs for Core 0 and Core 1 are loaded into SDRAM, which may start at a different address (e.g., 0x00100000). To ensure that Core 1 begins execution at the correct location, Core 0 must write a branch instruction (e.g., B 0x00100000) at the default start address of Core 1 before releasing it from reset. This branch instruction redirects Core 1 to the actual program location in SDRAM.

However, writing to the default start address may not be straightforward if the address is mapped to read-only memory (e.g., ROM or flash) or on-chip SRAM. In such cases, memory remapping is required to make the default start address writable. This can be achieved by configuring the memory controller or using hardware-specific remapping features to map the default start address to a writable memory region, such as SDRAM or on-chip SRAM.

Additionally, cache coherency must be considered when writing the branch instruction. If the default start address is cached, Core 0 must ensure that the branch instruction is written to main memory and not just the cache. This can be achieved using data synchronization barriers (DSB) and cache maintenance operations.

Writing and Verifying the Core 1 Startup Sequence

To implement the Core 1 startup sequence, Core 0 must perform the following steps:

  1. Determine the Core 1 Program Location: Identify the memory address in SDRAM where the Core 1 program is loaded. This address is typically known at compile time or can be determined dynamically by Core 0.

  2. Write the Branch Instruction: Core 0 writes a branch instruction (e.g., B 0x00100000) at the default start address of Core 1 (0x00000000 or 0xFFFF0000). This instruction redirects Core 1 to the actual program location in SDRAM.

  3. Ensure Memory Visibility: Use data synchronization barriers (DSB) to ensure that the branch instruction is written to main memory and not just the cache. If the default start address is cached, perform cache maintenance operations to invalidate the cache line and ensure that Core 1 fetches the updated instruction from main memory.

  4. Release Core 1 from Reset: After writing the branch instruction, Core 0 releases Core 1 from reset. Core 1 begins execution at the default start address, fetches the branch instruction, and jumps to the correct program location in SDRAM.

  5. Verify Core 1 Execution: Core 0 can verify that Core 1 has started execution by checking a shared memory location or using inter-core communication mechanisms (e.g., mailboxes or semaphores). This ensures that Core 1 has successfully branched to the correct program location and is executing as expected.

Example Implementation

Below is an example of how Core 0 can write the Core 1 startup sequence in assembly language:

    ; Core 0 code
    LDR R0, =0x00000000       ; Default start address of Core 1
    LDR R1, =0x00100000       ; Core 1 program location in SDRAM
    LDR R2, =0xEA000000       ; Opcode for branch instruction (B)
    ORR R2, R2, R1, LSR #2    ; Calculate branch offset
    STR R2, [R0]              ; Write branch instruction to default start address
    DSB                       ; Data synchronization barrier
    ; Release Core 1 from reset
    ; Verify Core 1 execution

Memory Remapping Considerations

If the default start address is not writable, memory remapping must be performed before writing the branch instruction. This can be done using the memory controller or hardware-specific remapping features. For example, on-chip SRAM can be remapped to the default start address to make it writable. The following steps outline the remapping process:

  1. Configure Memory Controller: Modify the memory controller settings to remap the default start address to a writable memory region, such as on-chip SRAM or SDRAM.

  2. Write Branch Instruction: Write the branch instruction to the remapped address.

  3. Restore Memory Map: After writing the branch instruction, restore the original memory map to ensure that Core 1 fetches the branch instruction from the correct location.

Cache Coherency and Synchronization

Cache coherency is critical when writing the Core 1 startup sequence. If the default start address is cached, Core 0 must ensure that the branch instruction is written to main memory and not just the cache. This can be achieved using the following steps:

  1. Invalidate Cache Line: Invalidate the cache line corresponding to the default start address to ensure that Core 1 fetches the updated instruction from main memory.

  2. Data Synchronization Barrier: Use a data synchronization barrier (DSB) to ensure that the branch instruction is written to main memory before releasing Core 1 from reset.

  3. Instruction Synchronization Barrier: Use an instruction synchronization barrier (ISB) to ensure that Core 1 fetches the updated instruction after the branch instruction is written.

Debugging and Verification

Debugging the Core 1 startup sequence can be challenging, especially in a bare-metal environment. The following techniques can be used to verify that Core 1 begins execution correctly:

  1. JTAG Debugging: Use a JTAG debugger to single-step through the Core 1 startup sequence and verify that the branch instruction is executed correctly.

  2. Shared Memory Flags: Use shared memory locations to store status flags that indicate the progress of Core 1 execution. Core 0 can check these flags to verify that Core 1 has started execution.

  3. LEDs or GPIOs: Use LEDs or GPIOs to indicate the execution status of Core 1. For example, Core 1 can toggle a GPIO pin after branching to the correct program location.

  4. Serial Output: Use a serial port to output debug messages from Core 1. This can help verify that Core 1 has started execution and is running the correct program.

Conclusion

Implementing a reliable Core 1 startup sequence in a dual-core ARM Cortex-A9 bare-metal system requires careful handling of memory remapping, cache coherency, and synchronization mechanisms. By following the steps outlined above, Core 0 can ensure that Core 1 begins execution at the correct program location in SDRAM. Debugging and verification techniques, such as JTAG debugging and shared memory flags, can be used to confirm that Core 1 is executing as expected. With proper implementation, the dual-core system can achieve reliable and efficient operation, leveraging the full capabilities of the Cortex-A9 architecture.

Similar Posts

Leave a Reply

Your email address will not be published. Required fields are marked *