84 lines
2.7 KiB
ArmAsm
84 lines
2.7 KiB
ArmAsm
|
/*
|
||
|
* 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
|