72 lines
2.1 KiB
ArmAsm
72 lines
2.1 KiB
ArmAsm
/*
|
|
* Copyright (c) 2016 Jean-Paul Etienne <fractalclone@gmail.com>
|
|
*
|
|
* SPDX-License-Identifier: Apache-2.0
|
|
*/
|
|
|
|
#include <toolchain.h>
|
|
|
|
/* imports */
|
|
GTEXT(__reset)
|
|
GTEXT(__irq_wrapper)
|
|
|
|
/*
|
|
* following riscv32-qemu specs
|
|
* IVT is placed at 0x000001000 and is mapped as follows:
|
|
* 0x00001000: reset
|
|
* 0x00001004: non-maskable interrupt (nmi) vector
|
|
* 0x00001010: machine trap (mt) vector
|
|
*
|
|
* Call __irq_wrapper to handle all interrupts/exceptions/faults
|
|
*/
|
|
SECTION_FUNC(vectors, vinit)
|
|
.option norvc;
|
|
|
|
/*
|
|
* jal instruction cannot be used to jump to address whose offset
|
|
* is > 12-bits wide. In this case, we have to use a call or tail
|
|
* instruction to jump to a far-away sub-routine.
|
|
*
|
|
* Given that IVT is found at a different address-space than the
|
|
* RAM in riscv32-qemu, we have to use call or tail instructions
|
|
* to jump to __reset or __isr_wrapper subroutines.
|
|
* However, call or tail instructions are pseudo instructions,
|
|
* which generate two base-instructions upon compilation. In this case,
|
|
* using them at a particular entry in the IVT will overwrite the next
|
|
* entry in the IVT. For example, using tail instruction in the
|
|
* reset vector, will overwrite the nmi-vector entry. To prevent this,
|
|
* perform a two-phase jump instructions to __reset or __irq_wrapper
|
|
* subroutines. The first jump performs a jal instruction, which will
|
|
* jump to an offset in the same vector address-space, but outside the
|
|
* IVT. The second jump performs a tail instruction to the __reset
|
|
* or __irq_wrapper subroutines.
|
|
*/
|
|
|
|
/* Call __reset for reset vector */
|
|
jal x0, do_reset
|
|
|
|
/* Call __irq_wrapper for nmi vector */
|
|
jal x0, do_irq_wrapper
|
|
|
|
.org 0x10
|
|
/* Call __irq_wrapper for mt vector */
|
|
jal x0, do_irq_wrapper
|
|
|
|
.org 0x400 /* we are outside IVT */
|
|
do_reset:
|
|
/*
|
|
* Set mtvec (Machine Trap-Vector Base-Address Register)
|
|
* to __irq_wrapper, so that we jump directly to __irq_wrapper,
|
|
* instead to the default machine trap vector address in IVT.
|
|
* This will preserve us from performing two jump instructions upon
|
|
* an interrupt.
|
|
*/
|
|
la t0, __irq_wrapper
|
|
csrw mtvec, t0
|
|
|
|
/* Jump to __reset */
|
|
tail __reset
|
|
|
|
do_irq_wrapper:
|
|
tail __irq_wrapper
|