zephyr/arch/riscv32/soc/riscv32-qemu/vector.S

84 lines
2.7 KiB
ArmAsm
Raw Normal View History

/*
* Copyright (c) 2016 Jean-Paul Etienne <fractalclone@gmail.com>
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#define _ASMLANGUAGE
#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