|
@@ -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
|