Line 443... |
Line 443... |
and placed right before the actual application code so it gets executed right after reset.
|
and placed right before the actual application code so it gets executed right after reset.
|
|
|
The `crt0.S` start-up performs the following operations:
|
The `crt0.S` start-up performs the following operations:
|
|
|
[start=1]
|
[start=1]
|
. Initialize all integer registers `x1 - x31` (or jsut `x1 - x15` when using the `E` CPU extension) to a defined value.
|
. Initialize all integer registers `x1 - x31` (or just `x1 - x15` when using the `E` CPU extension) to a defined value.
|
. Initialize the global pointer `gp` and the stack pointer `sp` according to the `.data` segment layout provided by the linker script.
|
. Initialize the global pointer `gp` and the stack pointer `sp` according to the <<_ram_layout>> provided by the linker script.
|
. Initialize all CPU core CSRs and also install a default "dummy" trap handler for _all_ traps. This handler catches all traps during the early boot phase.
|
. Initialize all CPU core CSRs and also install a default "dummy" trap handler for _all_ traps. This handler catches all traps
|
. Clear IO area: Write zero to all memory-mapped registers within the IO region (`iodev` section). If certain devices have not been implemented, a bus access fault exception will occur. This exception is captured by the dummy trap handler.
|
during the early boot phase.
|
|
. All interrupt sources are disabled and all pending interrupts are cleared.
|
|
. Clear all counter CSRs and stop auto-increment.
|
|
. Clear IO area: Write zero to all memory-mapped registers within the IO region (`iodev` section). If certain devices have not
|
|
been implemented, a bus access fault exception will occur. This exception is captured by the dummy trap handler.
|
. Clear the `.bss` section defined by the linker script.
|
. Clear the `.bss` section defined by the linker script.
|
. Copy read-only data from the `.text` section to the `.data` section to set initialized variables.
|
. Copy read-only data from the `.text` section to the `.data` section to set initialized variables.
|
. Call the application's `main` function (with _no_ arguments: `argc` = `argv` = 0).
|
. Call the application's `main` function (with _no_ arguments: `argc` = `argv` = 0).
|
. If the `main` function returns `crt0` can call an "after-main handler" (see below)
|
. If the main function returns...
|
. If there is no after-main handler or after returning from the after-main handler the processor goes to an endless sleep mode (using a simple loop or via the `wfi` instruction if available).
|
** the return value is copied to the <<_mscratch>> CSR to allow inspection by the on-chip debugger.
|
|
** an optional <<_after_main_handler>> is called (if defined at all).
|
|
** the last step the CPU does is entering endless sleep mode (using the `wfi` instruction).
|
|
|
:sectnums:
|
:sectnums:
|
===== After-Main Handler
|
===== After-Main Handler
|
|
|
If the application's `main()` function actually returns, an _after main handler_ can be executed. This handler can be a normal function
|
If the application's `main()` function actually returns, an _after main handler_ can be executed. This handler is a "normal" function
|
since the C runtime is still available when executed. If this handler uses any kind of peripheral/IO modules make sure these are
|
as the C runtime is still available when executed. If this handler uses any kind of peripheral/IO modules make sure these are
|
already initialized within the application or you have to initialize them _inside_ the handler.
|
already initialized within the application. Otherwise you have to initialize them _inside_ the handler.
|
|
|
.After-main handler - function prototype
|
.After-main handler - function prototype
|
[source,c]
|
[source,c]
|
----
|
----
|
int __neorv32_crt0_after_main(int32_t return_code);
|
void __neorv32_crt0_after_main(int32_t return_code);
|
----
|
----
|
|
|
The function has exactly one argument (`return_code`) that provides the _return value_ of the application's main function.
|
The function has exactly one argument (`return_code`) that provides the _return value_ of the application's main function.
|
For instance, this variable contains _-1_ if the main function returned with `return -1;`. The return value of the
|
For instance, this variable contains `-1` if the main function returned with `return -1;`. The after-main handler itself does
|
`__neorv32_crt0_after_main` function is irrelevant as there is no further "software instance" executed afterwards that can check this.
|
not provide a return value.
|
However, the on-chip debugger could still evaluate the return value of the after-main handler.
|
|
|
|
A simple UARt output can be used to inform the user when the application's main function returns
|
A simple UART output can be used to inform the user when the application's main function returns
|
(this example assumes that UART0 has been already properly configured in the actual application):
|
(this example assumes that UART0 has been already properly configured in the actual application):
|
|
|
.After-main handler - simple example
|
.After-main handler - simple example
|
[source,c]
|
[source,c]
|
----
|
----
|
int __neorv32_crt0_after_main(int32_t return_code) {
|
void __neorv32_crt0_after_main(int32_t return_code) {
|
|
|
neorv32_uart0_printf("\n main function returned with exit code %i. \n", return_code); <1>
|
neorv32_uart0_printf("\n main function returned with exit code %i. \n", return_code); <1>
|
return 0;
|
|
}
|
}
|
----
|
----
|
<1> Use `` here to make clear this is a message comes from the runtime environment.
|
<1> Use `` here to make clear this is a message comes from the runtime environment.
|
|
|
|
|