Add test for IRQ force array
This commit is contained in:
		
							parent
							
								
									f47f603595
								
							
						
					
					
						commit
						a44ff9b6f1
					
				| 
						 | 
				
			
			@ -5,6 +5,13 @@
 | 
			
		|||
#include "stdint.h"
 | 
			
		||||
#include "stdbool.h"
 | 
			
		||||
 | 
			
		||||
// Should match processor configuration in testbench:
 | 
			
		||||
#define NUM_IRQS 32
 | 
			
		||||
 | 
			
		||||
// Declarations for irq_dispatch.S
 | 
			
		||||
extern uintptr_t _external_irq_table[NUM_IRQS];
 | 
			
		||||
extern uint32_t _external_irq_entry_count;
 | 
			
		||||
 | 
			
		||||
#define h3irq_array_read(csr, index) (read_set_csr(csr, (index)) >> 16)
 | 
			
		||||
 | 
			
		||||
#define h3irq_array_write(csr, index, data) (write_csr(csr, (index) | ((uint32_t)(data) << 16)))
 | 
			
		||||
| 
						 | 
				
			
			@ -24,8 +31,17 @@ static inline bool h3irq_pending(unsigned int irq) {
 | 
			
		|||
	return h3irq_array_read(hazard3_csr_meipa, irq >> 4) & (1u << (irq & 0xfu));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static inline bool h3irq_force_pending(unsigned int irq) {
 | 
			
		||||
static inline void h3irq_force_pending(unsigned int irq, bool force) {
 | 
			
		||||
	if (force) {
 | 
			
		||||
		h3irq_array_set(hazard3_csr_meifa, irq >> 4, 1u << (irq & 0xfu));
 | 
			
		||||
	}
 | 
			
		||||
	else {
 | 
			
		||||
		h3irq_array_clear(hazard3_csr_meifa, irq >> 4, 1u << (irq & 0xfu));
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static inline bool h3irq_is_forced(unsigned int irq) {
 | 
			
		||||
	return h3irq_array_read(hazard3_csr_meifa, irq >> 4) & (1u << (irq & 0xfu));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// -1 for no IRQ
 | 
			
		||||
| 
						 | 
				
			
			@ -44,4 +60,29 @@ static inline void h3irq_set_priority(unsigned int irq, uint32_t priority) {
 | 
			
		|||
	h3irq_array_set(hazard3_csr_meipra, irq >> 2, (priority & 0xfu) << (4 * (irq & 0x3)));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static inline void h3irq_set_handler(unsigned int irq, void (*handler)(void)) {
 | 
			
		||||
	_external_irq_table[irq] = (uintptr_t)handler;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static inline void global_irq_enable(bool en) {
 | 
			
		||||
	// mstatus.mie
 | 
			
		||||
	if (en) {
 | 
			
		||||
		set_csr(mstatus, 0x8);
 | 
			
		||||
	}
 | 
			
		||||
	else {
 | 
			
		||||
		clear_csr(mstatus, 0x8);
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static inline void external_irq_enable(bool en) {
 | 
			
		||||
	// mie.meie
 | 
			
		||||
	if (en) {
 | 
			
		||||
		set_csr(mie, 0x800);
 | 
			
		||||
	}
 | 
			
		||||
	else {
 | 
			
		||||
		clear_csr(mie, 0x800);
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
#endif
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -104,7 +104,7 @@ isr_irq\num:
 | 
			
		|||
.word isr_irq\num
 | 
			
		||||
.endm
 | 
			
		||||
 | 
			
		||||
#define NUM_IRQS 64
 | 
			
		||||
#define NUM_IRQS 32
 | 
			
		||||
 | 
			
		||||
.equ i, 0
 | 
			
		||||
.rept NUM_IRQS
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -4,6 +4,7 @@ CCFLAGS    := -march=rv32imac_zicsr -Os
 | 
			
		|||
MAX_CYCLES := 1000000
 | 
			
		||||
INCDIR     := include ../common
 | 
			
		||||
 | 
			
		||||
EXTRA_SRCS_irq_force              := ../common/irq_dispatch.S
 | 
			
		||||
EXTRA_SRCS_irq_preempt_set_in_irq := ../common/irq_dispatch.S
 | 
			
		||||
EXTRA_SRCS_irq_set_all_with_pri   := ../common/irq_dispatch.S
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -0,0 +1,101 @@
 | 
			
		|||
#include "tb_cxxrtl_io.h"
 | 
			
		||||
#include "hazard3_csr.h"
 | 
			
		||||
#include "hazard3_irq.h"
 | 
			
		||||
 | 
			
		||||
// Fire all IRQs simultaneously, and log the resulting handler calls
 | 
			
		||||
 | 
			
		||||
#define mie_meie 0x800u
 | 
			
		||||
 | 
			
		||||
void handler(void);
 | 
			
		||||
 | 
			
		||||
int main() {
 | 
			
		||||
	tb_assert(NUM_IRQS <= 32, "Test invalid for >32 IRQs");
 | 
			
		||||
	global_irq_enable(true);
 | 
			
		||||
	external_irq_enable(true);
 | 
			
		||||
	// Dry run: Check that IRQ force array can be written/read and that it
 | 
			
		||||
	// sets the pending array appropriately
 | 
			
		||||
	for (int i = 0; i < NUM_IRQS; ++i) {
 | 
			
		||||
		h3irq_force_pending(i, true);
 | 
			
		||||
		uint32_t expect_pending = i == 31 ? 0xffffffffu : (1u << (i + 1)) - 1;
 | 
			
		||||
		tb_assert(
 | 
			
		||||
			expect_pending == (
 | 
			
		||||
				h3irq_array_read(hazard3_csr_meifa, 0) |
 | 
			
		||||
				(h3irq_array_read(hazard3_csr_meifa, 1) << 16)
 | 
			
		||||
			),
 | 
			
		||||
			"Bad meifa readback\n"
 | 
			
		||||
		);
 | 
			
		||||
		tb_assert(
 | 
			
		||||
			expect_pending == (
 | 
			
		||||
				h3irq_array_read(hazard3_csr_meipa, 0) |
 | 
			
		||||
				(h3irq_array_read(hazard3_csr_meipa, 1) << 16)
 | 
			
		||||
			),
 | 
			
		||||
			"Bad meipa readback\n"
 | 
			
		||||
		);
 | 
			
		||||
	}
 | 
			
		||||
	for (int i = 0; i < NUM_IRQS; ++i) {
 | 
			
		||||
		h3irq_force_pending(i, false);
 | 
			
		||||
	}
 | 
			
		||||
	tb_assert(h3irq_array_read(hazard3_csr_meifa, 0) == 0, "Failed to clear meifa\n");
 | 
			
		||||
	tb_assert(h3irq_array_read(hazard3_csr_meifa, 1) == 0, "Failed to clear meifa\n");
 | 
			
		||||
	tb_assert(h3irq_array_read(hazard3_csr_meipa, 0) == 0, "Failed to clear meipa\n");
 | 
			
		||||
	tb_assert(h3irq_array_read(hazard3_csr_meipa, 1) == 0, "Failed to clear meipa\n");
 | 
			
		||||
 | 
			
		||||
	// Now fire each interrupt for real and make sure that the meinext read
 | 
			
		||||
	// clears the force bit as it should, so that each interrupt fires
 | 
			
		||||
	// exactly once.
 | 
			
		||||
	for (int i = 0; i < NUM_IRQS; ++i) {
 | 
			
		||||
		h3irq_enable(i, true);
 | 
			
		||||
		h3irq_set_handler(i, handler);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	h3irq_array_write(hazard3_csr_meifa, 0, 0xffffu);
 | 
			
		||||
	h3irq_array_write(hazard3_csr_meifa, 1, 0xffffu);
 | 
			
		||||
 | 
			
		||||
	while (h3irq_pending(31))
 | 
			
		||||
		;
 | 
			
		||||
	tb_printf("EIRQ vector entered %d times\n", _external_irq_entry_count);
 | 
			
		||||
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void handler(void) {
 | 
			
		||||
	tb_printf("IRQ %02x\n", h3irq_get_current_irq());
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/*EXPECTED-OUTPUT***************************************************************
 | 
			
		||||
 | 
			
		||||
IRQ 00
 | 
			
		||||
IRQ 01
 | 
			
		||||
IRQ 02
 | 
			
		||||
IRQ 03
 | 
			
		||||
IRQ 04
 | 
			
		||||
IRQ 05
 | 
			
		||||
IRQ 06
 | 
			
		||||
IRQ 07
 | 
			
		||||
IRQ 08
 | 
			
		||||
IRQ 09
 | 
			
		||||
IRQ 0a
 | 
			
		||||
IRQ 0b
 | 
			
		||||
IRQ 0c
 | 
			
		||||
IRQ 0d
 | 
			
		||||
IRQ 0e
 | 
			
		||||
IRQ 0f
 | 
			
		||||
IRQ 10
 | 
			
		||||
IRQ 11
 | 
			
		||||
IRQ 12
 | 
			
		||||
IRQ 13
 | 
			
		||||
IRQ 14
 | 
			
		||||
IRQ 15
 | 
			
		||||
IRQ 16
 | 
			
		||||
IRQ 17
 | 
			
		||||
IRQ 18
 | 
			
		||||
IRQ 19
 | 
			
		||||
IRQ 1a
 | 
			
		||||
IRQ 1b
 | 
			
		||||
IRQ 1c
 | 
			
		||||
IRQ 1d
 | 
			
		||||
IRQ 1e
 | 
			
		||||
IRQ 1f
 | 
			
		||||
EIRQ vector entered 2 times
 | 
			
		||||
 | 
			
		||||
*******************************************************************************/
 | 
			
		||||
| 
						 | 
				
			
			@ -41,22 +41,17 @@ EIRQ vector was entered 16 times
 | 
			
		|||
*******************************************************************************/
 | 
			
		||||
 | 
			
		||||
#define MAX_PRIORITY 15
 | 
			
		||||
#define NUM_IRQS 64
 | 
			
		||||
 | 
			
		||||
extern uintptr_t _external_irq_table[NUM_IRQS];
 | 
			
		||||
extern uint32_t _external_irq_entry_count;
 | 
			
		||||
 | 
			
		||||
void handler(void);
 | 
			
		||||
 | 
			
		||||
int main() {
 | 
			
		||||
	// Enable external IRQs globally
 | 
			
		||||
	set_csr(mstatus, 0x8);
 | 
			
		||||
	set_csr(mie, 0x800);
 | 
			
		||||
	global_irq_enable(true);
 | 
			
		||||
	external_irq_enable(true);
 | 
			
		||||
	// Enable one external IRQ at each priority level
 | 
			
		||||
	for (int i = 0; i <= MAX_PRIORITY; ++i) {
 | 
			
		||||
		h3irq_enable(i, true);
 | 
			
		||||
		h3irq_set_priority(i, i);
 | 
			
		||||
		_external_irq_table[i] = (uintptr_t)handler;
 | 
			
		||||
		h3irq_set_handler(i, handler);
 | 
			
		||||
	}
 | 
			
		||||
	// Set off the lowest-priority IRQ. The IRQ handler will then set the
 | 
			
		||||
	// next-lowest, which will preempt it. So on, up to the highest level,
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -57,20 +57,16 @@ EIRQ vector was entered 1 times
 | 
			
		|||
#define PRIORITY_LEVELS 16
 | 
			
		||||
#define NUM_IRQS 32
 | 
			
		||||
 | 
			
		||||
extern uintptr_t _external_irq_table[NUM_IRQS];
 | 
			
		||||
extern uint32_t _external_irq_entry_count;
 | 
			
		||||
 | 
			
		||||
void handler(void);
 | 
			
		||||
 | 
			
		||||
int main() {
 | 
			
		||||
	// Enable external IRQs globally
 | 
			
		||||
	set_csr(mstatus, 0x8);
 | 
			
		||||
	set_csr(mie, 0x800);
 | 
			
		||||
	global_irq_enable(true);
 | 
			
		||||
	external_irq_enable(true);
 | 
			
		||||
	// Enable one external IRQ at each priority level
 | 
			
		||||
	for (int i = 0; i < PRIORITY_LEVELS * 2; ++i) {
 | 
			
		||||
		h3irq_enable(i, true);
 | 
			
		||||
		h3irq_set_priority(i, i / 2);
 | 
			
		||||
		_external_irq_table[i] = (uintptr_t)handler;
 | 
			
		||||
		h3irq_set_handler(i, handler);
 | 
			
		||||
	}
 | 
			
		||||
	// Set off the lowest-priority IRQ. The IRQ handler will then set the
 | 
			
		||||
	// next-lowest, which will preempt it. So on, up to the highest level,
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
		Reference in New Issue