|
@@ -16,44 +16,60 @@
|
|
|
// CPU downstream interrupts are set after the transaction completes
|
|
|
// (CS# goes high.)
|
|
|
//
|
|
|
-// A 32-bit address follows, and for a read, 32 dummy bits (16 cycles)
|
|
|
-// All data is processed as 32-bit words only.
|
|
|
+// A 32-bit address follows; for a read, the following 16 cycles
|
|
|
+// contains dummy/status data:
|
|
|
//
|
|
|
-module esp (
|
|
|
- input rst_n,
|
|
|
- input sys_clk,
|
|
|
- input sdram_clk,
|
|
|
-
|
|
|
- input cpu_valid,
|
|
|
- input [4:0] cpu_addr,
|
|
|
- input [3:0] cpu_wstrb,
|
|
|
- input [31:0] cpu_wdata,
|
|
|
- output [31:0] cpu_rdata,
|
|
|
- output reg irq,
|
|
|
-
|
|
|
- dram_bus.dstr dram,
|
|
|
+// Bit [31:16] = adjusted memory address
|
|
|
+// Bit [15:14] = 2'b10
|
|
|
+// Bit [13: 8] = 0 reserved
|
|
|
+// Bit [ 7: 5] = upstream interrupt status
|
|
|
+// Bit 4 = 0 reserved
|
|
|
+// Bit [ 3: 1] = downstream interrupt status
|
|
|
+// Bit 0 = underrun error
|
|
|
+//
|
|
|
+module esp #(
|
|
|
+ parameter dram_bits = 25,
|
|
|
+ parameter [31:0] dram_base = 32'h40000000
|
|
|
+ ) (
|
|
|
+ input rst_n,
|
|
|
+ input sys_clk,
|
|
|
+ input sdram_clk,
|
|
|
+
|
|
|
+ input cpu_valid,
|
|
|
+ input [4:0] cpu_addr,
|
|
|
+ input [3:0] cpu_wstrb,
|
|
|
+ input [31:0] cpu_wdata,
|
|
|
+ output [31:0] cpu_rdata,
|
|
|
+ output reg irq,
|
|
|
+
|
|
|
+ dram_bus.dstr dram,
|
|
|
|
|
|
- output reg esp_int,
|
|
|
- input spi_clk,
|
|
|
- inout [1:0] spi_io,
|
|
|
- input spi_cs_n
|
|
|
- );
|
|
|
-
|
|
|
- reg [24:2] mem_addr;
|
|
|
- reg mem_valid;
|
|
|
- reg [31:0] mem_wdata;
|
|
|
- wire mem_write;
|
|
|
- wire mem_ready;
|
|
|
- wire [31:0] mem_rdata;
|
|
|
-
|
|
|
+ output reg esp_int,
|
|
|
+ input spi_clk,
|
|
|
+ inout [1:0] spi_io,
|
|
|
+ input spi_cs_n
|
|
|
+ );
|
|
|
+
|
|
|
+ reg [31:0] mem_addr = 'b0;
|
|
|
+ wire [31:0] mem_addr_mask = (1'b1 << dram_bits) - 3'd4;
|
|
|
+ wire [31:0] mem_addr_out = (mem_addr & mem_addr_mask)
|
|
|
+ | dram_base;
|
|
|
+
|
|
|
+ reg mem_valid;
|
|
|
+ reg [31:0] mem_wdata;
|
|
|
+ wire mem_write;
|
|
|
+ reg [ 3:0] mem_wstrb;
|
|
|
+ wire mem_ready;
|
|
|
+ wire [31:0] mem_rdata;
|
|
|
+
|
|
|
dram_port #(32) mem
|
|
|
(
|
|
|
.bus ( dram ),
|
|
|
.prio ( 2'd2 ),
|
|
|
- .addr ( {mem_addr, 2'b00} ),
|
|
|
+ .addr ( mem_addr[dram_bits-1:0] ),
|
|
|
.valid ( mem_valid ),
|
|
|
.wd ( mem_wdata ),
|
|
|
- .wstrb ( {4{mem_wrq}} ),
|
|
|
+ .wstrb ( mem_wstrb ),
|
|
|
.ready ( mem_ready ),
|
|
|
.rd ( mem_rdata )
|
|
|
);
|
|
@@ -82,8 +98,11 @@ module esp (
|
|
|
reg [ 3:0] spi_ctr;
|
|
|
reg [ 3:0] cpu_irq;
|
|
|
reg [ 3:1] spi_irq;
|
|
|
+ reg [ 3:1] latched_spi_irq;
|
|
|
reg [ 1:0] spi_out;
|
|
|
reg spi_oe;
|
|
|
+ reg [ 2:0] spi_wbe; // Partial word write byte enables
|
|
|
+ reg [23:0] spi_wdata; // Partial word write data
|
|
|
|
|
|
assign spi_io = spi_oe ? spi_out : 2'bzz;
|
|
|
|
|
@@ -102,6 +121,10 @@ module esp (
|
|
|
cpu_irq <= 'b0;
|
|
|
spi_irq <= 'b0;
|
|
|
spi_oe <= 1'b0;
|
|
|
+ spi_wbe <= 3'b0;
|
|
|
+ mem_addr <= 'b0;
|
|
|
+ mem_wstrb <= 4'b0;
|
|
|
+ mem_valid <= 1'b0;
|
|
|
end
|
|
|
else
|
|
|
begin
|
|
@@ -112,55 +135,100 @@ module esp (
|
|
|
spi_state <= st_cmd;
|
|
|
spi_ctr <= 4'd3;
|
|
|
spi_oe <= 1'b0;
|
|
|
- spi_cmd <= 'b0;
|
|
|
- for (int i = 1; i < 4; i++)
|
|
|
- if (spi_cmd[1:0] == i)
|
|
|
- cpu_irq[i] <= 1'b1;
|
|
|
+ if (~mem_valid)
|
|
|
+ begin
|
|
|
+ spi_cmd <= 'b0;
|
|
|
+ for (int i = 1; i < 4; i++)
|
|
|
+ if (spi_cmd[1:0] == i)
|
|
|
+ cpu_irq[i] <= 1'b1;
|
|
|
+ end
|
|
|
end
|
|
|
else if (spi_clk_q == 2'b01)
|
|
|
begin
|
|
|
spi_ctr <= spi_ctr - 1'b1;
|
|
|
-
|
|
|
- if (|spi_ctr)
|
|
|
- begin
|
|
|
- spi_shr <= spi_indata;
|
|
|
- end
|
|
|
- else
|
|
|
- begin
|
|
|
- // Transfer data to/from memory controller, but
|
|
|
- // we have to shuffle endianness...
|
|
|
- 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];
|
|
|
-
|
|
|
- mem_wdata[31:24] <= spi_indata[ 7: 0];
|
|
|
- mem_wdata[23:16] <= spi_indata[15: 8];
|
|
|
- mem_wdata[15: 8] <= spi_indata[23:16];
|
|
|
- mem_wdata[ 7: 0] <= spi_indata[31:24];
|
|
|
-
|
|
|
- if (mem_valid)
|
|
|
- cpu_irq[0] <= 1'b1; // Overrun/underrun
|
|
|
-
|
|
|
- case (spi_state)
|
|
|
- st_cmd: begin
|
|
|
- spi_cmd <= spi_indata[5:0];
|
|
|
- spi_state <= st_addr;
|
|
|
- for (int i = 1; i < 4; i++)
|
|
|
- if (spi_indata[3:2] == i)
|
|
|
- spi_irq[i] <= 1'b0;
|
|
|
- end
|
|
|
- st_addr: begin
|
|
|
- mem_addr <= spi_indata[25:2];
|
|
|
- spi_state <= st_io;
|
|
|
- mem_valid <= ~mem_write;
|
|
|
- end
|
|
|
- st_io: begin
|
|
|
- mem_valid <= 1'b1;
|
|
|
- end
|
|
|
- endcase
|
|
|
- end
|
|
|
- end
|
|
|
+ spi_shr <= spi_indata;
|
|
|
+
|
|
|
+ case (spi_ctr)
|
|
|
+ 4'b1100:
|
|
|
+ if (spi_state == st_io && mem_write)
|
|
|
+ begin
|
|
|
+ spi_wbe[0] <= 1'b1;
|
|
|
+ spi_wdata[7:0] <= spi_indata[7:0];
|
|
|
+ end
|
|
|
+ 4'b1000:
|
|
|
+ if (spi_state == st_io && mem_write)
|
|
|
+ begin
|
|
|
+ spi_wbe[1] <= 1'b1;
|
|
|
+ spi_wdata[15:8] <= spi_indata[7:0];
|
|
|
+ end
|
|
|
+ 4'b0100:
|
|
|
+ if (spi_state == st_io && mem_write)
|
|
|
+ begin
|
|
|
+ spi_wbe[2] <= 1'b1;
|
|
|
+ spi_wdata[23:16] <= spi_indata[7:0];
|
|
|
+ end
|
|
|
+ 4'b0000: begin
|
|
|
+ // Transfer data to/from memory controller, but
|
|
|
+ // we have to shuffle endianness...
|
|
|
+ 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
|
|
|
+ else
|
|
|
+ begin
|
|
|
+ // Status output
|
|
|
+ spi_shr[31:16] <= mem_addr_out[31:16];
|
|
|
+ spi_shr[15: 8] <= 8'h80;
|
|
|
+ spi_shr[ 7: 4] <= { latched_spi_irq, 1'b0 };
|
|
|
+ spi_shr[ 3: 0] <= cpu_irq;
|
|
|
+ end // else: !if(spi_state == st_io)
|
|
|
+
|
|
|
+ if (mem_valid && spi_state != st_cmd)
|
|
|
+ cpu_irq[0] <= 1'b1; // Overrun/underrun
|
|
|
+
|
|
|
+ case (spi_state)
|
|
|
+ st_cmd: begin
|
|
|
+ spi_cmd <= spi_indata[5:0];
|
|
|
+ spi_state <= st_addr;
|
|
|
+ latched_spi_irq <= spi_irq;
|
|
|
+ for (int i = 1; i < 4; i++)
|
|
|
+ if (spi_indata[3:2] == i)
|
|
|
+ spi_irq[i] <= 1'b0;
|
|
|
+ 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;
|
|
|
+ // If the first word is partial, skip ahead
|
|
|
+ if (mem_write)
|
|
|
+ spi_ctr[3:2] <= ~spi_indata[1:0];
|
|
|
+ end
|
|
|
+ st_io: begin
|
|
|
+ if (mem_write)
|
|
|
+ begin
|
|
|
+ mem_wdata[23: 0] <= spi_wdata[23:0];
|
|
|
+ mem_wdata[31:24] <= spi_indata[7:0];
|
|
|
+ mem_wstrb <= { 1'b1, spi_wbe };
|
|
|
+ end
|
|
|
+ else
|
|
|
+ begin
|
|
|
+ mem_wstrb <= 4'b0000;
|
|
|
+ end // else: !if(mem_write)
|
|
|
+ mem_valid <= 1'b1;
|
|
|
+ spi_wbe <= 3'b000;
|
|
|
+ end
|
|
|
+ endcase
|
|
|
+ end // case: 4'b0000
|
|
|
+ default:
|
|
|
+ ; // Nothing
|
|
|
+ endcase // case (spi_ctr)
|
|
|
+ end // if (spi_clk_q == 2'b01)
|
|
|
else if (spi_clk_q == 2'b10)
|
|
|
begin
|
|
|
spi_out <= spi_shr[31:30];
|
|
@@ -169,8 +237,18 @@ module esp (
|
|
|
|
|
|
if (mem_valid & mem_ready)
|
|
|
begin
|
|
|
+ mem_addr <= mem_addr + 3'd4;
|
|
|
mem_valid <= 1'b0;
|
|
|
- mem_addr <= mem_addr + 1'b1;
|
|
|
+ end
|
|
|
+
|
|
|
+ if (spi_state != st_io & ~mem_valid & |spi_wbe)
|
|
|
+ begin
|
|
|
+ // Complete a partial write terminated by CS#
|
|
|
+ mem_valid <= 1'b1;
|
|
|
+ mem_wstrb <= { 1'b0, spi_wbe };
|
|
|
+ mem_wdata[23:0] <= spi_wdata[23:0];
|
|
|
+ mem_wdata[31:24] <= 8'hxx;
|
|
|
+ spi_wbe <= 3'b000;
|
|
|
end
|
|
|
|
|
|
cpu_valid_q <= cpu_valid;
|