Browse Source

esplink: change to 7 interrupt/status bits per direction

3 interrupt/status bits turned out to be a bit tight. Change to 7
interrupt/status bits for each direction of the link.
H. Peter Anvin 2 years ago
parent
commit
54aa67c9dd

+ 6 - 4
esp32/max80/fpga.h

@@ -14,10 +14,12 @@ extern_c void fpga_service_enable(bool);
 extern_c void fpga_timesync_trigger(void);
 
 #define FPGA_CMD_IRQ(x)	((x) << 0)
-#define FPGA_CMD_ACK(x)	((x) << 2)
-#define FPGA_CMD_WR	(0 << 4)
-#define FPGA_CMD_RD	(1 << 4)
-#define FPGA_CMD_CONTROL_MASK 0x0f
+#define FPGA_CMD_ACK(x)	((x) << 3)
+#define FPGA_CMD_WR	(0 << 6)
+#define FPGA_CMD_RD	(1 << 6)
+#define FPGA_CMD_STAMP	(1 << 7) /* Save timestamp */
+
+/* Internal bits, not sent over the wire: */
 #define FPGA_CMD_NULL	(1 << 8) /* Don't skip an empty command */
 #define FPGA_CMD_STATUS	(1 << 9) /* Include status in read command */
 

+ 15 - 8
esp32/max80/fpgasvc.c

@@ -565,11 +565,11 @@ static void fpga_service_task(void *dummy)
 	  printf("[FPGA] FPGA status flags = 0x%08x\n", status);
 
 	  if (!digitalRead(PIN_FPGA_INT)) {
-	      if (status & 0x40)
-		  fpga_io_status(FPGA_CMD_ACK(2));
-	      if (status & 0x80)
-		  fpga_io_status(FPGA_CMD_ACK(3));
-	      if ((status & 0xf031) == 0x9030) {
+	      for (unsigned int i = 2; i < 8; i++) {
+		  if (status & (0x100 << i))
+		      status = fpga_io_status(FPGA_CMD_ACK(i));
+	      }
+	      if ((status & 0x301) == 0x300) {
 		  if (fpga_online())
 		      fpga_state = FPGA_ONLINE;
 	      }
@@ -590,7 +590,7 @@ static void fpga_service_task(void *dummy)
 	    while (!digitalRead(PIN_FPGA_INT)) {
 		status = fpga_io_status(0);
 
-		if ((status & 0xf031) != 0x9010) {
+		if ((status & 0x301) != 0x100) {
 		    fpga_offline();
 		    printf("[FPGA] FPGA offline, status = 0x%08x\n", status);
 		    fpga_state = FPGA_OFFLINE;
@@ -598,11 +598,18 @@ static void fpga_service_task(void *dummy)
 		    break;
 		}
 
-		if (status & 0x80)
+		if (status & (0x100 << EL_UIRQ_TIME))
 		    fpga_get_time();
 
-		if (status & 0x40)
+		if (status & (0x100 << EL_UIRQ_RINGBUF))
 		    esplink_poll();
+
+		for (unsigned int i = 4; i < 8; i++) {
+		    if (status & (0x100 << i)) {
+			printf("[FPGA] Invalid interrupt %u received\n", i);
+			status = fpga_io_status(FPGA_CMD_ACK(i));
+		    }
+		}
 	    }
 
 	    if (notifiers & NOTIFY_TIMESYNC)

BIN
esp32/output/max80.ino.bin


+ 63 - 61
fpga/esp.sv

@@ -3,15 +3,16 @@
 //
 // This is a DIO (2-bit, including command) SPI slave interface which
 // allows direct access to content in SDRAM. Additionally, each
-// direction has three interrupt flags (3-1); the FPGA CPU additionally
-// has a fourth interrupt condition (0) which indicates DRAM timing
-// overrun/underrun.
+// direction has 7 interrupt condition flags (7-1); the FPGA CPU
+// additionally has an internal interrupt condition (0) which
+// indicates DRAM timing overrun/underrun, also visible in the status
+// word as bit 0.
 //
 // The SPI command byte is:
-// Bit [7:5]  - reserved, must be 0
-// Bit    4   - read/write#
-// Bit [3:2]  - clear upstream (FPGA->ESP) interrupt flag if nonzero
-// Bit [1:0]  - set downstream (ESP->FPGA) interrupt flag if nonzero
+// Bit    7   - save command timestamp
+// Bit    6   - read/write#
+// Bit [5:3]  - clear upstream (FPGA->ESP) interrupt flag if nonzero
+// Bit [2:0]  - set downstream (ESP->FPGA) interrupt flag if nonzero
 //
 // CPU downstream interrupts are set after the transaction completes
 // (CS# goes high.)
@@ -20,19 +21,18 @@
 // contains dummy/status data:
 //
 // Bit [31:16] = 16 LSB of 32 kHz RTC counter
-// Bit [15:12] = 4'b1001
-// Bit [11: 8] = 0 reserved
-// Bit [ 7: 5] = upstream interrupts pending
-// Bit      4  = downstream writes enabled
-// Bit [ 3: 1] = downstream interrupts pending
+// Bit [15: 9] = upstream interrupts pending
+// Bit      8  = downstream writes enabled
+// Bit [ 7: 1] = downstream interrupts pending
 // Bit      0  = underrun error
 //
 // The following CPU registers are defined:
 //
-// 0	       = status bits [3:0] (downstream)
-// 1	       = write-1-clear of status bits [3:0]
-// 2           = status bits [7:4] (upstream)
-// 3           = write-1-set of status bits [7:4]
+// 0	       = status bits [7:0] (downstream)
+// 1	       = write-1-clear of status bits [7:0]
+// 2           = status bits [15:8] (upstream)
+// 3           = write-1-set of status bits [15:8]
+// 4           = timestamp (16 LSB of 32 kHz RTC counter) saved by cmd bit 7
 //
 module esp #(
 	     parameter        dram_bits = 25,
@@ -103,14 +103,15 @@ module esp #(
 
    state_t    spi_state;
 
-   reg [ 4:0] spi_cmd;
+   reg [ 7:0] spi_cmd;
    reg [31:0] spi_shr;
    reg [ 3:0] spi_ctr;
-   reg [ 3:0] cpu_irq;
-   reg [ 3:0] cpu_set_irq;	// CPU IRQs to set once idle
+   reg [ 7:0] cpu_irq;
+   reg [ 7:0] cpu_set_irq;	// CPU IRQs to set once idle
    reg        cpu_send_irq;	// Ready to set CPU IRQs
-   reg [ 3:1] spi_irq;
-   reg [ 3:1] latched_spi_irq;	// SPI IRQ as of transition start
+   reg [ 7:1] spi_irq;
+   reg [ 7:1] latched_spi_irq;	// SPI IRQ as of transition start
+   reg [15:0] timestamp_q;
    reg [ 1:0] spi_out;
    reg	      spi_oe;
    reg [ 2:0] spi_wbe;		// Partial word write byte enables
@@ -120,7 +121,7 @@ module esp #(
 
    assign spi_io = spi_oe ? spi_out : 2'bzz;
 
-   assign mem_write = ~spi_cmd[4];
+   assign mem_write = ~spi_cmd[6];
 
    wire [31:0] spi_indata = { spi_shr[29:0], spi_io_q };
 
@@ -191,22 +192,14 @@ module esp #(
 		 4'b0000: begin
 		       // Load spi_shr, but account for endianness here...
 		       if (spi_state == st_io)
-			 begin
-			    // Memory output
-			    spi_shr[31:24]  <= mem_rdata[ 7: 0];
-			    spi_shr[23:16]  <= mem_rdata[15: 8];
-			    spi_shr[15: 8]  <= mem_rdata[23:16];
-			    spi_shr[ 7: 0]  <= mem_rdata[31:24];
-			 end
+			 spi_shr <= bswap32(mem_rdata);
 		       else
-			 begin
-			    // Status output
-			    spi_shr[31:28]  <= { latched_spi_irq, spi_wr_en };
-			    spi_shr[27:24]  <= cpu_irq;
-			    spi_shr[23:16]  <= 8'b1001_0000;
-			    spi_shr[15: 8]  <= rtc_ctr[ 7: 0];
-			    spi_shr[ 7: 0]  <= rtc_ctr[15: 8];
-			 end // else: !if(spi_state == st_io)
+			 // Status output
+			 spi_shr <= bswap32({
+					     rtc_ctr,
+					     latched_spi_irq, spi_wr_en,
+					     cpu_irq
+					     });
 
 		       if (mem_valid && spi_state != st_cmd)
 			 begin
@@ -220,24 +213,26 @@ module esp #(
 			    // Do nothing
 			 end
 			 st_cmd: begin
-			    spi_cmd         <= spi_indata[5:0];
+			    spi_cmd         <= spi_indata[7:0];
 			    spi_state       <= st_addr;
 			    latched_spi_irq <= spi_irq;
-			    spi_mem_en      <= ~mem_write | spi_wr_en;
-			    for (int i = 1; i < 4; i++)
+			    for (int i = 1; i < 8; i++)
 			      begin
-				 if (spi_indata[3:2] == i)
+				 if (spi_indata[5:3] == i)
 				   spi_irq[i] <= 1'b0;
-				 if (spi_indata[1:0] == i)
+				 if (spi_indata[2:0] == i)
 				   cpu_set_irq[i] <= 1'b1;
 			      end
+			    if (spi_indata[7])
+			      timestamp_q <= rtc_ctr;
 			 end
 			 st_addr: begin
-			    mem_addr  <= spi_indata & mem_addr_mask;
-			    spi_state <= st_io;
-			    mem_valid <= ~mem_write;
-			    mem_wstrb <= 4'b0;
-			    spi_wbe   <= 3'b000;
+			    mem_addr   <= spi_indata & mem_addr_mask;
+			    spi_state  <= st_io;
+			    mem_valid  <= ~mem_write;
+			    spi_mem_en <= ~mem_write | spi_wr_en;
+			    mem_wstrb  <= 4'b0;
+			    spi_wbe    <= 3'b000;
 			    // If the first word is partial, skip ahead
 			    if (mem_write)
 			      spi_ctr[3:2] <= ~spi_indata[1:0];
@@ -287,34 +282,41 @@ module esp #(
 
 	  cpu_valid_q <= cpu_valid;
 	  if (cpu_valid & ~cpu_valid_q & cpu_wstrb[0])
-	    case (cpu_addr[1:0])
-	      2'b00:
-		 cpu_irq <= cpu_wdata[3:0];
-	      2'b01:
-		for (int i = 0; i < 4; i++)
+	    case (cpu_addr[2:0])
+	      3'b000:
+		 cpu_irq <= cpu_wdata[7:0];
+	      3'b001:
+		for (int i = 0; i < 8; i++)
 		  if (cpu_wdata[i])
 		    cpu_irq[i] <= cpu_send_irq & cpu_set_irq[i];
-	      2'b10:
-		 { spi_irq, spi_wr_en } <= cpu_wdata[3:0];
-	      2'b11: begin
+	      3'b010:
+		 { spi_irq, spi_wr_en } <= cpu_wdata[7:0];
+	      3'b011: begin
 		if (cpu_wdata[0])
 		  spi_wr_en <= 1'b1;
-		for (int i = 1; i < 4; i++)
+		for (int i = 1; i < 8; i++)
 		  if (cpu_wdata[i])
 		    spi_irq[i] <= 1'b1;
 	      end
-	    endcase // case (cpu_addr[1:0])
+	      default: begin
+		 // Do nothing
+	      end
+	    endcase // case (cpu_addr[2:0])
        end // else: !if(~rst_n)
 
    always @(posedge sys_clk)
      irq <= |cpu_irq;
 
    always @(*)
-     casez (cpu_addr[1:0])
-       2'b0?:
+     casez (cpu_addr[2:0])
+       3'b000:
 	 cpu_rdata = { 28'b0, cpu_irq };
-       2'b1?:
+       3'b010:
 	 cpu_rdata = { 28'b0, spi_irq, spi_wr_en };
-     endcase // casez (cpu_addr[1:0])
+       3'b100:
+	 cpu_rdata = { 16'b0, timestamp_q };
+       default:
+	 cpu_rdata = 32'bx;
+     endcase // casez (cpu_addr[2:0])
 
 endmodule // esp

+ 12 - 0
fpga/functions.sv

@@ -75,3 +75,15 @@ function longint unsigned
   round_div(input longint unsigned num, input longint unsigned den);
    round_div = (num + (den >> 1))/den;
 endfunction // round_div
+
+function logic [15:0] bswap16(input logic [15:0] d);
+   bswap16 = { d[7:0], d[15:8] };
+endfunction // bswap16
+
+function logic [31:0] bswap32(input logic [31:0] d);
+   bswap32 = { bswap16(d[15:0]), bswap16(d[31:16]) };
+endfunction // bswap32
+
+function logic [63:0] bswap64(input logic [63:0] d);
+   bswap64 = { bswap32(d[31:0]), bswap32(d[63:32]) };
+endfunction // bswap64

+ 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:34:16  May 17, 2022
+# Date created = 09:52:16  May 18, 2022
 #
 # -------------------------------------------------------------------------- #
 
 QUARTUS_VERSION = "21.1"
-DATE = "22:34:16  May 17, 2022"
+DATE = "09:52:16  May 18, 2022"
 
 # Revisions
 

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 - 0
rv32/ioregs.h

@@ -156,6 +156,7 @@
 #define ESP_CPU_IRQ_CLR		IODEVL(ESP,1)
 #define ESP_SPI_IRQ		IODEVL(ESP,2)
 #define ESP_SPI_IRQ_SET		IODEVL(ESP,3)
+#define ESP_TIMESTAMP		IODEVRL(ESP,4)
 
 #define VJTAG_CPUCMD		IODEVRL(VJTAG,0)
 #define VJTAG_CPUINFO		IODEVL(VJTAG,1)