From 1a9c3127005d7d097ae8364e122e4489ea477b7c Mon Sep 17 00:00:00 2001 From: Kip Macsai-Goren Date: Sun, 17 Apr 2022 20:56:15 +0000 Subject: [PATCH] added more comprehensive vectoring, interrupt causing and handing --- .../rv64i_m/privilege/src/WALLY-TEST-LIB-64.h | 150 +++++++++++++++--- 1 file changed, 124 insertions(+), 26 deletions(-) diff --git a/tests/wally-riscv-arch-test/riscv-test-suite/rv64i_m/privilege/src/WALLY-TEST-LIB-64.h b/tests/wally-riscv-arch-test/riscv-test-suite/rv64i_m/privilege/src/WALLY-TEST-LIB-64.h index 4f96071ea..60f793f56 100644 --- a/tests/wally-riscv-arch-test/riscv-test-suite/rv64i_m/privilege/src/WALLY-TEST-LIB-64.h +++ b/tests/wally-riscv-arch-test/riscv-test-suite/rv64i_m/privilege/src/WALLY-TEST-LIB-64.h @@ -84,7 +84,7 @@ cause_instr_access: ret cause_illegal_instr: - .word 0x00000000 // a 32 bit zros is an illegal instruction + .word 0x00000000 // 32 bit zero is an illegal instruction ret cause_breakpnt: @@ -118,7 +118,7 @@ cause_ecall: ecall ret -cause_time_interrupt: +cause_m_time_interrupt: // The following code works for both RV32 and RV64. // RV64 alone would be easier using double-word adds and stores li x28, 0x30 // Desired offset from the present time @@ -132,23 +132,99 @@ cause_time_interrupt: sw x31,4(x29) // store into most significant word of MTIMECMP nowrap: sw x28, 0(x29) // store into least significant word of MTIMECMP -loop: - wfi - j loop // wait until interrupt occurs +time_loop: + wfi + j time_loop // wait until interrupt occurs ret -cause_soft_interrupt: +cause_s_time_interrupt: + li x28, 0x20 + csrs mip, x28 // set supervisor time interrupt pending. SIP is a subset of MIP, so writing this should also change MIP. + nop // added extra nops in so the csrs can get through the pipeline before returning. + ret + +cause_m_soft_interrupt: la x28, 0x02000000 // MSIP register in CLINT li x29, 1 // 1 in the lsb sw x29, 0(x28) // Write MSIP bit ret -cause_ext_interrupt: +cause_s_soft_interrupt: + li x28, 0x2 + csrs sip, x28 // set supervisor software interrupt pending. SIP is a subset of MIP, so writing this should also change MIP. + ret + +cause_m_ext_interrupt: + # ========== Configure PLIC ========== + # m priority threshold = 0 + li t0, 0xC200000 + li t1, 0 + sw t1, 0(t0) + # source 3 (GPIO) priority = 1 + li t0, 0xC000000 + li t1, 1 + sw t1, 0x0C(t0) + # enable source 3 + li t0, 0x0C002000 + li t1, 0b1000 + sw t1, 0(t0) + li x28, 0x10060000 // load base GPIO memory location li x29, 0x1 - sw x29, 8(x28) // enable the first pin as an output - sw x29, 28(x28) // set first pin to high interrupt enable - sw x29, 40(x28) // write a 1 to the first output pin (cause interrupt) + sw x29, 0x08(x28) // enable the first pin as an output + + sw x0, 0x1C(x28) // clear rise_ip + sw x0, 0x24(x28) // clear fall_ip + sw x0, 0x2C(x28) // clear high_ip + sw x0, 0x34(x28) // clear low_ip + + sw x29, 0x28(x28) // set first to interrupt on a rising value + sw x29, 0x0C(x28) // write a 1 to the first output pin (cause interrupt) +m_ext_loop: + wfi + lw x29, 0x8(x28) + bnez x28, m_ext_loop // go through this loop until the trap handler has disabled the GPIO output pins. + ret + +cause_s_ext_interrupt_GPIO: + # ========== Configure PLIC ========== + # s priority threshold = 0 + li t0, 0xC201000 + li t1, 0 + sw t1, 0(t0) + # m priority threshold = 7 + li t0, 0xC200000 + li t1, 7 + sw t1, 0(t0) + # source 3 (GPIO) priority = 1 + li t0, 0xC000000 + li t1, 1 + sw t1, 0x0C(t0) + # enable source 3 + li t0, 0x0C002000 + li t1, 0b1000 + sw t1, 0(t0) + + li x28, 0x10060000 // load base GPIO memory location + li x29, 0x1 + sw x29, 0x08(x28) // enable the first pin as an output + + sw x0, 0x1C(x28) // clear rise_ip + sw x0, 0x24(x28) // clear fall_ip + sw x0, 0x2C(x28) // clear high_ip + sw x0, 0x34(x28) // clear low_ip + + sw x29, 0x28(x28) // set first to interrupt on a rising value + sw x29, 0x0C(x28) // write a 1 to the first output pin (cause interrupt) +s_ext_loop: + wfi + lw x29, 0x8(x28) + bnez x28, s_ext_loop // go through this loop until the trap handler has disabled the GPIO output pins. + ret + +cause_s_ext_interrupt_IP: + li x28, 0x200 + csrs mip, x28 // set supervisor external interrupt pending. SIP is a subset of MIP, so writing this should also change MIP. ret end_trap_triggers: @@ -216,7 +292,7 @@ end_trap_triggers: // // -------------------------------------------------------------------------------------------- -.align 2 +.align 3 trap_handler_\MODE\(): j trap_unvectored_\MODE\() // for the unvectored implimentation: jump past this table of addresses into the actual handler // *** ASSUMES that a cause value of 0 for an interrupt is unimplemented @@ -273,18 +349,19 @@ trap_stack_saved_\MODE\(): // jump here after handling vectored interupt since w // Respond to trap based on cause // All interrupts should return after being logged csrr x1, \MODE\()cause - slli x1, x1, 3 // multiply cause by 8 to get offset in vector Table li x5, 0x8000000000000000 // if msb is set, it is an interrupt and x5, x5, x1 bnez x5, interrupt_handler_\MODE\() // return from interrupt // Other trap handling is specified in the vector Table la x5, exception_vector_table_\MODE\() + slli x1, x1, 3 // multiply cause by 8 to get offset in vector Table add x5, x5, x1 // compute address of vector in Table ld x5, 0(x5) // fectch address of handler from vector Table jr x5 // and jump to the handler interrupt_handler_\MODE\(): la x5, interrupt_vector_table_\MODE\() // NOTE THIS IS NOT THE SAME AS VECTORED INTERRUPTS!!! + slli x1, x1, 3 // multiply cause by 8 to get offset in vector Table add x5, x5, x1 // compute address of vector in Table ld x5, 0(x5) // fectch address of handler from vector Table jr x5 // and jump to the handler @@ -343,6 +420,7 @@ trapreturn_finished_\MODE\(): ld x7, -24(sp) // restore registers from stack before returning ld x5, -16(sp) ld x1, -8(sp) + csrrw sp, \MODE\()scratch, sp // switch sp and scratch stack back to restore the non-trap stack pointer \MODE\()ret // return from trap ecallhandler_\MODE\(): @@ -364,7 +442,7 @@ ecallhandler_changetomachinemode_\MODE\(): ecallhandler_changetosupervisormode_\MODE\(): // Force status.MPP (bits 12:11) to 01 to enter supervisor mode after mret - li x1, 0b1100000000000 + li x1, 0b1000000000000 csrc \MODE\()status, x1 li x1, 0b0100000000000 csrs \MODE\()status, x1 @@ -440,22 +518,42 @@ vectored_int_end_\MODE\(): j trap_stack_saved_\MODE\() soft_interrupt_\MODE\(): - la x28, 0x02000000 // Reset by clearing MSIP interrupt from CLINT - sw x0, 0(x28) - j trapreturn_\MODE\() + la x5, 0x02000000 // Reset by clearing MSIP interrupt from CLINT + sw x0, 0(x5) + + csrci sip, 0x2 // clear supervisor software interrupt pending bit + ld x1, -8(sp) // load return address from stack into ra (the address to return to after causing this interrupt) + // Note: we do this because the mepc loads in the address of the instruction after the sw that causes the interrupt + // This means that this trap handler will return to the next address after that one, which might be unpredictable behavior. + j trapreturn_finished_\MODE\() // return to the code at ra value from before trap + time_interrupt_\MODE\(): - la x29, 0x02004000 // MTIMECMP register in CLINT - li x30, 0xFFFFFFFF - sd x30, 0(x29) // reset interrupt by setting mtimecmp to 0xFFFFFFFF + la x5, 0x02004000 // MTIMECMP register in CLINT + li x7, 0xFFFFFFFF + sd x7, 0(x5) // reset interrupt by setting mtimecmp to 0xFFFFFFFF - ld x1, -8(sp) // load return address from stack into ra (the address AFTER the jal to the faulting address) + ld x1, -8(sp) // load return address from stack into ra (the address to return to after the loop is complete) j trapreturn_finished_\MODE\() // return to the code at ra value from before trap ext_interrupt_\MODE\(): li x28, 0x10060000 // reset interrupt by clearing all the GPIO bits sw x0, 8(x28) // disable the first pin as an output sw x0, 40(x28) // write a 0 to the first output pin (reset interrupt) + + # reset PLIC to turn off external interrupts + # priority threshold = 7 + li t0, 0xC200000 + li t1, 0x7 + sw t1, 0(t0) + # source 3 (GPIO) priority = 0 + li t0, 0xC000000 + li t1, 0 + sw t1, 0x0C(t0) + # disable source 3 + li t0, 0x0C002000 + li t1, 0b0000 + sw t1, 0(t0) j trapreturn_\MODE\() // Table of trap behavior @@ -485,17 +583,17 @@ exception_vector_table_\MODE\(): .align 3 // aligns this data table to an 8 byte boundary interrupt_vector_table_\MODE\(): .8byte segfault_\MODE\() // 0: reserved - .8byte s_soft_vector_\MODE\() // 1: instruction access fault // the zero spot is taken up by the instruction to skip this table. + .8byte soft_interrupt_\MODE\() // 1: instruction access fault // the zero spot is taken up by the instruction to skip this table. .8byte segfault_\MODE\() // 2: reserved - .8byte m_soft_vector_\MODE\() // 3: breakpoint + .8byte soft_interrupt_\MODE\() // 3: breakpoint .8byte segfault_\MODE\() // 4: reserved - .8byte s_time_vector_\MODE\() // 5: load access fault + .8byte time_interrupt_\MODE\() // 5: load access fault .8byte segfault_\MODE\() // 6: reserved - .8byte m_time_vector_\MODE\() // 7: store access fault + .8byte time_interrupt_\MODE\() // 7: store access fault .8byte segfault_\MODE\() // 8: reserved - .8byte s_ext_vector_\MODE\() // 9: ecall from S-mode + .8byte ext_interrupt_\MODE\() // 9: ecall from S-mode .8byte segfault_\MODE\() // 10: reserved - .8byte m_ext_vector_\MODE\() // 11: ecall from M-mode + .8byte ext_interrupt_\MODE\() // 11: ecall from M-mode .align 3 trap_return_pagetype_table_\MODE\():