mirror of
https://github.com/openhwgroup/cvw
synced 2025-02-11 06:05:49 +00:00
added more comprehensive vectoring, interrupt causing and handing
This commit is contained in:
parent
1af47c9d25
commit
1a9c312700
@ -84,7 +84,7 @@ cause_instr_access:
|
|||||||
ret
|
ret
|
||||||
|
|
||||||
cause_illegal_instr:
|
cause_illegal_instr:
|
||||||
.word 0x00000000 // a 32 bit zros is an illegal instruction
|
.word 0x00000000 // 32 bit zero is an illegal instruction
|
||||||
ret
|
ret
|
||||||
|
|
||||||
cause_breakpnt:
|
cause_breakpnt:
|
||||||
@ -118,7 +118,7 @@ cause_ecall:
|
|||||||
ecall
|
ecall
|
||||||
ret
|
ret
|
||||||
|
|
||||||
cause_time_interrupt:
|
cause_m_time_interrupt:
|
||||||
// The following code works for both RV32 and RV64.
|
// The following code works for both RV32 and RV64.
|
||||||
// RV64 alone would be easier using double-word adds and stores
|
// RV64 alone would be easier using double-word adds and stores
|
||||||
li x28, 0x30 // Desired offset from the present time
|
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
|
sw x31,4(x29) // store into most significant word of MTIMECMP
|
||||||
nowrap:
|
nowrap:
|
||||||
sw x28, 0(x29) // store into least significant word of MTIMECMP
|
sw x28, 0(x29) // store into least significant word of MTIMECMP
|
||||||
loop:
|
time_loop:
|
||||||
wfi
|
wfi
|
||||||
j loop // wait until interrupt occurs
|
j time_loop // wait until interrupt occurs
|
||||||
ret
|
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
|
la x28, 0x02000000 // MSIP register in CLINT
|
||||||
li x29, 1 // 1 in the lsb
|
li x29, 1 // 1 in the lsb
|
||||||
sw x29, 0(x28) // Write MSIP bit
|
sw x29, 0(x28) // Write MSIP bit
|
||||||
ret
|
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 x28, 0x10060000 // load base GPIO memory location
|
||||||
li x29, 0x1
|
li x29, 0x1
|
||||||
sw x29, 8(x28) // enable the first pin as an output
|
sw x29, 0x08(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 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
|
ret
|
||||||
|
|
||||||
end_trap_triggers:
|
end_trap_triggers:
|
||||||
@ -216,7 +292,7 @@ end_trap_triggers:
|
|||||||
//
|
//
|
||||||
// --------------------------------------------------------------------------------------------
|
// --------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
.align 2
|
.align 3
|
||||||
trap_handler_\MODE\():
|
trap_handler_\MODE\():
|
||||||
j trap_unvectored_\MODE\() // for the unvectored implimentation: jump past this table of addresses into the actual handler
|
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
|
// *** 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
|
// Respond to trap based on cause
|
||||||
// All interrupts should return after being logged
|
// All interrupts should return after being logged
|
||||||
csrr x1, \MODE\()cause
|
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
|
li x5, 0x8000000000000000 // if msb is set, it is an interrupt
|
||||||
and x5, x5, x1
|
and x5, x5, x1
|
||||||
bnez x5, interrupt_handler_\MODE\() // return from interrupt
|
bnez x5, interrupt_handler_\MODE\() // return from interrupt
|
||||||
// Other trap handling is specified in the vector Table
|
// Other trap handling is specified in the vector Table
|
||||||
la x5, exception_vector_table_\MODE\()
|
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
|
add x5, x5, x1 // compute address of vector in Table
|
||||||
ld x5, 0(x5) // fectch address of handler from vector Table
|
ld x5, 0(x5) // fectch address of handler from vector Table
|
||||||
jr x5 // and jump to the handler
|
jr x5 // and jump to the handler
|
||||||
|
|
||||||
interrupt_handler_\MODE\():
|
interrupt_handler_\MODE\():
|
||||||
la x5, interrupt_vector_table_\MODE\() // NOTE THIS IS NOT THE SAME AS VECTORED INTERRUPTS!!!
|
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
|
add x5, x5, x1 // compute address of vector in Table
|
||||||
ld x5, 0(x5) // fectch address of handler from vector Table
|
ld x5, 0(x5) // fectch address of handler from vector Table
|
||||||
jr x5 // and jump to the handler
|
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 x7, -24(sp) // restore registers from stack before returning
|
||||||
ld x5, -16(sp)
|
ld x5, -16(sp)
|
||||||
ld x1, -8(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
|
\MODE\()ret // return from trap
|
||||||
|
|
||||||
ecallhandler_\MODE\():
|
ecallhandler_\MODE\():
|
||||||
@ -364,7 +442,7 @@ ecallhandler_changetomachinemode_\MODE\():
|
|||||||
|
|
||||||
ecallhandler_changetosupervisormode_\MODE\():
|
ecallhandler_changetosupervisormode_\MODE\():
|
||||||
// Force status.MPP (bits 12:11) to 01 to enter supervisor mode after mret
|
// Force status.MPP (bits 12:11) to 01 to enter supervisor mode after mret
|
||||||
li x1, 0b1100000000000
|
li x1, 0b1000000000000
|
||||||
csrc \MODE\()status, x1
|
csrc \MODE\()status, x1
|
||||||
li x1, 0b0100000000000
|
li x1, 0b0100000000000
|
||||||
csrs \MODE\()status, x1
|
csrs \MODE\()status, x1
|
||||||
@ -440,22 +518,42 @@ vectored_int_end_\MODE\():
|
|||||||
j trap_stack_saved_\MODE\()
|
j trap_stack_saved_\MODE\()
|
||||||
|
|
||||||
soft_interrupt_\MODE\():
|
soft_interrupt_\MODE\():
|
||||||
la x28, 0x02000000 // Reset by clearing MSIP interrupt from CLINT
|
la x5, 0x02000000 // Reset by clearing MSIP interrupt from CLINT
|
||||||
sw x0, 0(x28)
|
sw x0, 0(x5)
|
||||||
j trapreturn_\MODE\()
|
|
||||||
|
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\():
|
time_interrupt_\MODE\():
|
||||||
la x29, 0x02004000 // MTIMECMP register in CLINT
|
la x5, 0x02004000 // MTIMECMP register in CLINT
|
||||||
li x30, 0xFFFFFFFF
|
li x7, 0xFFFFFFFF
|
||||||
sd x30, 0(x29) // reset interrupt by setting mtimecmp to 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
|
j trapreturn_finished_\MODE\() // return to the code at ra value from before trap
|
||||||
|
|
||||||
ext_interrupt_\MODE\():
|
ext_interrupt_\MODE\():
|
||||||
li x28, 0x10060000 // reset interrupt by clearing all the GPIO bits
|
li x28, 0x10060000 // reset interrupt by clearing all the GPIO bits
|
||||||
sw x0, 8(x28) // disable the first pin as an output
|
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)
|
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\()
|
j trapreturn_\MODE\()
|
||||||
|
|
||||||
// Table of trap behavior
|
// Table of trap behavior
|
||||||
@ -485,17 +583,17 @@ exception_vector_table_\MODE\():
|
|||||||
.align 3 // aligns this data table to an 8 byte boundary
|
.align 3 // aligns this data table to an 8 byte boundary
|
||||||
interrupt_vector_table_\MODE\():
|
interrupt_vector_table_\MODE\():
|
||||||
.8byte segfault_\MODE\() // 0: reserved
|
.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 segfault_\MODE\() // 2: reserved
|
||||||
.8byte m_soft_vector_\MODE\() // 3: breakpoint
|
.8byte soft_interrupt_\MODE\() // 3: breakpoint
|
||||||
.8byte segfault_\MODE\() // 4: reserved
|
.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 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 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 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
|
.align 3
|
||||||
trap_return_pagetype_table_\MODE\():
|
trap_return_pagetype_table_\MODE\():
|
||||||
|
Loading…
Reference in New Issue
Block a user