Browse Source

rv32: use a dedicated interrupt stack

Instead of using a shared stack, use a dedicated interrupt stack. This
will be necessary in order to support task switching, and makes
interrupts faster, too.

Signed-off-by: H. Peter Anvin <hpa@zytor.com>
H. Peter Anvin 2 years ago
parent
commit
0115548fc0

BIN
esp32/output/max80.ino.bin


+ 2 - 2
fpga/max80.qpf

@@ -19,12 +19,12 @@
 #
 # Quartus Prime
 # Version 21.1.0 Build 842 10/21/2021 SJ Lite Edition
-# Date created = 22:41:13  January 22, 2023
+# Date created = 00:10:29  January 23, 2023
 #
 # -------------------------------------------------------------------------- #
 
 QUARTUS_VERSION = "21.1"
-DATE = "22:41:13  January 22, 2023"
+DATE = "00:10:29  January 23, 2023"
 
 # Revisions
 

+ 12 - 24
fpga/max80.sv

@@ -471,27 +471,10 @@ module max80
    // Edge-triggered IRQs. picorv32 latches interrupts
    // but doesn't edge detect for a slow signal, so do it
    // here instead and use level triggered signalling to the
-   // CPU. This also allows using an explicit EOI instead of
-   // using EOI-on-INTACK.
-   //
-
-   // sys_irq defined in iodevs.vh
-   reg  [31:0] sys_irq_q;
+   // CPU.
    reg  [31:0] cpu_irq;
-
-   wire [31:0] cpu_eoi = {32{sysreg[4]}}
-	       & {{8{cpu_mem_wstrb[3]}}, {8{cpu_mem_wstrb[2]}},
-		  {8{cpu_mem_wstrb[1]}}, {8{cpu_mem_wstrb[0]}}}
-	       & cpu_mem_wdata;
-
-   // Reading the register shows the current set of pending interrupts.
-   assign sysreg_rdata[4] = cpu_irq;
-
-   // CPU permanently hung?
-   wire	       cpu_trap;
-
-   // Request to halt the CPU on the next instruction boundary
-   wire        cpu_halt;
+   reg  [31:0] sys_irq_q;
+   wire [31:0] cpu_eoi;
 
    always @(negedge rst_n or posedge sys_clk)
      if (~rst_n)
@@ -502,11 +485,16 @@ module max80
      else
        begin
 	  sys_irq_q <= sys_irq & irq_edge_mask;
-
-	  cpu_irq <= (sys_irq & ~sys_irq_q) |
-		     (cpu_irq & irq_edge_mask & ~cpu_eoi);
+	  cpu_irq   <= (sys_irq & ~sys_irq_q) |
+		       (cpu_irq & irq_edge_mask & ~cpu_eoi);
        end
 
+   // CPU permanently hung?
+   wire	       cpu_trap;
+
+   // Request to halt the CPU on the next instruction boundary
+   wire        cpu_halt;
+
    picorv32 #(
 	      .ENABLE_COUNTERS ( 1 ),
 	      .ENABLE_COUNTERS64 ( 1 ),
@@ -553,7 +541,7 @@ module max80
 	.mem_la_wstrb ( cpu_la_wstrb ),
 
 	.irq ( cpu_irq ),
-	.eoi ( )
+	.eoi ( cpu_eoi )
 	);
 
    // Add a mandatory wait state to iodevs to reduce the size

BIN
fpga/output/bypass.jic


BIN
fpga/output/bypass.rbf.gz


BIN
fpga/output/bypass.rpd.gz


BIN
fpga/output/bypass.sof


BIN
fpga/output/bypass.svf.gz


BIN
fpga/output/bypass.xsvf.gz


BIN
fpga/output/max80.fw


BIN
fpga/output/v1.fw


BIN
fpga/output/v1.jic


BIN
fpga/output/v1.rbf.gz


BIN
fpga/output/v1.rpd.gz


BIN
fpga/output/v1.sof


BIN
fpga/output/v1.svf.gz


BIN
fpga/output/v1.xsvf.gz


BIN
fpga/output/v2.fw


BIN
fpga/output/v2.jic


BIN
fpga/output/v2.rbf.gz


BIN
fpga/output/v2.rpd.gz


BIN
fpga/output/v2.sof


BIN
fpga/output/v2.svf.gz


BIN
fpga/output/v2.xsvf.gz


+ 1 - 1
rv32/checksum.h

@@ -1,4 +1,4 @@
 #ifndef CHECKSUM_H
 #define CHECKSUM_H
-#define SDRAM_SUM 0x08d13422
+#define SDRAM_SUM 0x81d1da2a
 #endif

+ 34 - 10
rv32/head.S

@@ -38,31 +38,45 @@ __rom_offset:
 	.section ".init.reset","ax"
 	.globl _reset
 _reset:
+	.option push
+	.option norvc
+	.option norelax
 	rdtime s0		// Record timer at reset
-	li sp,STACK_TOP		// Cheaper than using la sp,___stack_top
+	lui sp,%hi(___stack_top)
+	addi sp,sp,%lo(___stack_top)
 	j __start
+	.option pop
 	.type _reset, @function
 	.size _reset, . - _reset
 
 	.section ".text.hot","ax"
 	.globl __start
+	.balign 4
 __start:
-	not t0,zero
-	maskirq zero,t0,zero
-#if !GP_IS_ZERO
 	.option push
+	.option norvc		// Weird things happen?
 	.option norelax		// Can't make gp references to set up gp...
-	la gp, __global_pointer$
-	.option pop
+
+	not t0,zero
+	maskirq zero,t0,zero
+
+	// Interrupt stack
+	lui t0,%hi(___irqstack_top)
+	addqxi sp,t0,%lo(___irqstack_top)
+
+	// Global pointer register (not actually used...)
+#if GP_IS_ZERO
+	li gp, 0
 #else
-	// Zero gp (linker will usually replace with the zero reg)
-	li gp,0
+	la gp, __global_pointer$
 #endif
+
+	.option pop
 	addqxi gp,gp,0		// Set gp for interrupt code too
 
 	// Clear esplink_head.magic as quickly as possible
 	sw zero,esplink_head,a0
-	
+
 	// Clear bss
 	la a0,__BSS_START__
 	la a1,__BSS_END__
@@ -104,7 +118,17 @@ __datestamp:
 	// Stack definition
 	.section ".stack","aw",@nobits
 	.balign 4
-	.globl ___stack_bottom
+	.globl __irqstack_bottom
+___irqstack:
+	.space IRQSTACK_SIZE
+	.type ___irqstack, @object
+	.size ___irqstack, IRQSTACK_SIZE
+
+	.globl ___irqstack_top
+___irqstack_top:
+
+	.balign 4
+	.globl ___stack
 ___stack:
 	.space STACK_SIZE
 	.type ___stack, @object

+ 0 - 11
rv32/io.h

@@ -100,15 +100,4 @@ static inline uint32_t rdrand(void)
     return RANDOM_DATA;
 }
 
-/* Send EOI for some interrupt(s) */
-static inline void eoi_mask(uint32_t mask)
-{
-    SYS_EOI = mask;
-}
-
-static inline void eoi(unsigned int irq)
-{
-    SYS_EOI = 1 << irq;
-}
-
 #endif /* IO_H */

+ 0 - 1
rv32/ioregs.h

@@ -20,7 +20,6 @@
 #define SYS_RESET_SOFT		1
 #define SYS_RESET_HARD		2
 #define SYS_RESET_RECONFIG	3
-#define SYS_EOI			IODEVL(SYS,4)
 
 #define ROMCOPY_RAMADDR		IODEVL(ROMCOPY,0)
 #define ROMCOPY_ROMCMD		IODEVL(ROMCOPY,1)

+ 1 - 6
rv32/irqasm.S

@@ -7,7 +7,7 @@
 	// The IRQ dispatch code is written in assembly to make
 	// better use of the register bank switching: can simply
 	// use the saved registers here, no saving needed.
-	// registers need to be
+
 	.pushsection ".init.irq","ax"
 	.balign 4
 	.globl _irq
@@ -15,14 +15,9 @@
 	.option norvc		// Just messes up alignment
 	.option arch, +zbb	// Enable the ctz instruction
 _irq:
-	addqxi sp,sp,0
 	// s10 contains the IRQ return address, s11 the mask of
 	// IRQs to be handled.
 
-	// Send EOI for all interrupts (previously done in hardware)
-	// -> move back to hardware?
-	sw s11,SYS_EOI(zero)
-
 .Lirq_loop:
 	ctz a0,s11	// Vector number
 	slli t1,a0,2	// Table index

+ 0 - 1
rv32/jtagupd.c

@@ -38,7 +38,6 @@ void main(void)
 	uint32_t cmd;
 
 	waitfor(VJTAG_IRQ);
-	eoi(VJTAG_IRQ);
 	cmd = VJTAG_CPUCMD;
 
 	if (cmd == VJTAG_FLASH_CMD) {

+ 2 - 2
rv32/max80.ld

@@ -224,9 +224,9 @@ SECTIONS
 	/* Patched in during FPGA compile, must immediately follow _end */
 	.datestamp (NOLOAD) : { KEEP(*(.datestamp)) }
 
-	HIDDEN($sram_size_assert = ASSERT(. <= STACK_BOTTOM, "SRAM overflow"));
+	HIDDEN($sram_size_assert = ASSERT(. <= IRQSTACK_BOTTOM, "SRAM overflow"));
 
-	. = STACK_BOTTOM;
+	. = IRQSTACK_BOTTOM;
 	.stack (NOLOAD) : {
 		KEEP (*(.stack))
 	}

+ 4 - 0
rv32/sys.h

@@ -20,6 +20,10 @@
 #define STACK_TOP	SRAM_END	/* Initial stack pointer */
 #define STACK_BOTTOM	(STACK_TOP - STACK_SIZE)
 
+#define IRQSTACK_SIZE	1024		/* Interrupt stack size */
+#define IRQSTACK_TOP	STACK_BOTTOM
+#define IRQSTACK_BOTTOM	(IRQSTACK_TOP - IRQSTACK_SIZE)
+
 #define SDRAM_SIZE      (0x1 << SDRAM_BITS)
 #define SDRAM_MASK      (SDRAM_SIZE - 1)
 #define SDRAM_END       (SDRAM_ADDR + SDRAM_SIZE)