diff --git a/litex/soc/software/libbase/crt0-picorv32.S b/litex/soc/software/libbase/crt0-picorv32.S index 054f84d32..7e4c712b3 100644 --- a/litex/soc/software/libbase/crt0-picorv32.S +++ b/litex/soc/software/libbase/crt0-picorv32.S @@ -18,7 +18,23 @@ _start: .org 0x00000010 # IRQ _irq_vector: - j _irq + addi sp, sp, -16 + sw t0, 4(sp) + sw ra, 8(sp) + /* By convention, q2 holds true IRQ vector, but remains caller-save. + We rely on the assumption that compiler-generated code will never touch + the QREGs. q3 is truly scratch/caller-save. */ + picorv32_getq_insn(t0, q2) + sw t0, 12(sp) + + jalr t0 // Call the true IRQ vector. + + lw t0, 12(sp) + picorv32_setq_insn(q2, t0) // Restore the true IRQ vector. + lw ra, 8(sp) + lw t0, 4(sp) + addi sp, sp, 16 + picorv32_retirq_insn() // return from interrupt /* @@ -132,9 +148,7 @@ _irq: /* restore x1 - x2 from q registers */ picorv32_getq_insn(x1, q1) picorv32_getq_insn(x2, q2) - - /* return from interrupt */ - picorv32_retirq_insn() + ret /* * Reset handler, branched to from the vector. @@ -191,6 +205,12 @@ _crt0: /* set main stack */ la sp, _fstack + /* Set up address to IRQ handler since vector is hardcoded. + By convention, q2 keeps the pointer to the true IRQ handler, + to emulate relocatable interrupts. */ + la t0, _irq + picorv32_setq_insn(q2, t0) + /* jump to main */ jal ra, main @@ -214,7 +234,7 @@ _irq_enable: picorv32_maskirq_insn(zero, t0) ret -/* +/* * Disable interrupts by masking all interrupts (the mask should already be * up to date) */ @@ -247,7 +267,7 @@ _irq_setmask: picorv32_maskirq_insn(zero, a0) 1: ret - + .section .bss irq_regs: @@ -280,4 +300,3 @@ _irq_mask: .global _irq_enabled _irq_enabled: .word 0 -