/* * Copyright (c) 2016 Jean-Paul Etienne * * 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 /* 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