|
@@ -1,116 +1,201 @@
|
|
|
//
|
|
|
-// Fast data download from 2-bit SPI flash.
|
|
|
+// Fast data download from 2-bit SPI flash, or zero SDRAM.
|
|
|
//
|
|
|
// Feed a FIFO that then writes to SDRAM.
|
|
|
-// This unit is designed to write 8-byte chunks.
|
|
|
+// Requires writes in aligned 8-byte chunks.
|
|
|
//
|
|
|
// This unit does *not* require a 2x SPI clock;
|
|
|
// it uses a DDR buffer for clock out.
|
|
|
//
|
|
|
|
|
|
module spirom (
|
|
|
- input rst_n,
|
|
|
- input rom_clk,
|
|
|
- input ram_clk,
|
|
|
+ input rst_n,
|
|
|
+ input rom_clk,
|
|
|
+ input ram_clk,
|
|
|
+ input sys_clk,
|
|
|
|
|
|
- output spi_sck,
|
|
|
- inout [1:0] spi_io,
|
|
|
- output reg spi_cs_n,
|
|
|
+ /* SPI ROM interface */
|
|
|
+ output spi_sck,
|
|
|
+ inout [1:0] spi_io,
|
|
|
+ output reg spi_cs_n,
|
|
|
|
|
|
- output [15:0] wd, // Data to RAM
|
|
|
+ /* SDRAM interface */
|
|
|
+ output [15:0] wd, // Data to RAM
|
|
|
(* syn_preserve = 1 *) // Don't merge into FIFO
|
|
|
- output [24:1] waddr, // RAM address
|
|
|
- output reg [1:0] wrq, // Write request (min 8/16 bytes)
|
|
|
- input wacc, // Data accepted (ready for next data)
|
|
|
+ output [24:1] waddr, // RAM address
|
|
|
+ output reg [1:0] wrq, // Write request (min 4/8 bytes)
|
|
|
+ input wacc, // Data accepted (ready for next data)
|
|
|
|
|
|
- output reg done
|
|
|
+ /* CPU control interface */
|
|
|
+ output [31:0] cpu_rdata,
|
|
|
+ input [31:0] cpu_wdata,
|
|
|
+ input cpu_valid,
|
|
|
+ input [3:0] cpu_wstrb,
|
|
|
+ input [1:0] cpu_addr,
|
|
|
+ output reg irq
|
|
|
);
|
|
|
|
|
|
- //
|
|
|
- // XXX: make these CPU programmable
|
|
|
- //
|
|
|
- parameter [24:0] ramstart = 25'h000_0000;
|
|
|
- parameter [23:0] romstart = 24'h10_0000; // 1 MB
|
|
|
- parameter [23:0] datalen = 24'h08_0000; // 512K
|
|
|
+ reg [24:3] ramstart;
|
|
|
+ reg [23:3] romstart;
|
|
|
+ reg [23:3] datalen;
|
|
|
+ reg is_spi;
|
|
|
+ reg go_zero;
|
|
|
+ reg go_spi;
|
|
|
+ reg done;
|
|
|
+ reg [1:0] done_q;
|
|
|
+
|
|
|
+ always @(negedge rst_n or posedge sys_clk)
|
|
|
+ if (~rst_n)
|
|
|
+ begin
|
|
|
+ ramstart <= 23'bx;
|
|
|
+ romstart <= 23'bx;
|
|
|
+ datalen <= 21'bx;
|
|
|
+ is_spi <= 1'b0;
|
|
|
+ go_zero <= 1'b0;
|
|
|
+ go_spi <= 1'b0;
|
|
|
+ done_q <= 2'b11;
|
|
|
+ irq <= 1'b1;
|
|
|
+ end
|
|
|
+ else
|
|
|
+ begin
|
|
|
+ done_q <= { done_q[0], done };
|
|
|
+
|
|
|
+ if (cpu_valid & cpu_wstrb[0])
|
|
|
+ begin
|
|
|
+ // Only full word writes supported!!
|
|
|
+ case (cpu_addr)
|
|
|
+ 2'b00: begin
|
|
|
+ ramstart <= cpu_wdata[24:3];
|
|
|
+ end
|
|
|
+ 2'b01: begin
|
|
|
+ romstart <= cpu_wdata[23:3];
|
|
|
+ is_spi <= |cpu_wdata[23:3];
|
|
|
+ end
|
|
|
+ 2'b10: begin
|
|
|
+ datalen <= cpu_wdata[23:3];
|
|
|
+ if (|cpu_wdata[23:3])
|
|
|
+ begin
|
|
|
+ go_zero <= ~is_spi;
|
|
|
+ go_spi <= is_spi;
|
|
|
+ irq <= 1'b0;
|
|
|
+ end
|
|
|
+ end
|
|
|
+ default: begin
|
|
|
+ // Do nothing
|
|
|
+ end
|
|
|
+ endcase // case (cpu_addr)
|
|
|
+ end // if (cpu_valid & cpu_wstrb[0])
|
|
|
+ else if (done_q == 2'b01)
|
|
|
+ begin
|
|
|
+ go_zero <= 1'b0;
|
|
|
+ go_spi <= 1'b0;
|
|
|
+ irq <= 1'b1;
|
|
|
+ end
|
|
|
+ end // else: !if(~rst_n)
|
|
|
+
|
|
|
+ always_comb
|
|
|
+ case (cpu_addr)
|
|
|
+ 2'b00: cpu_rdata = { 7'b0, ramstart, 3'b0 };
|
|
|
+ 2'b01: cpu_rdata = { 8'b0, romstart, 3'b0 };
|
|
|
+ 2'b10: cpu_rdata = { 8'b0, datalen, 3'b0 };
|
|
|
+ 2'b11: cpu_rdata = { 31'b0, irq };
|
|
|
+ endcase // case (cpu_addr)
|
|
|
|
|
|
//
|
|
|
// FIFO and input latches
|
|
|
//
|
|
|
- reg [1:0] spi_in_q;
|
|
|
- reg spi_in_req;
|
|
|
- reg spi_in_req_q;
|
|
|
- wire [11:0] wrusedw;
|
|
|
- wire [8:0] rdusedw;
|
|
|
- wire [15:0] fifo_out;
|
|
|
- wire rdempty;
|
|
|
-
|
|
|
+ reg [1:0] spi_in_q;
|
|
|
+ reg spi_in_req;
|
|
|
+ reg spi_in_req_q;
|
|
|
+ wire [11:0] wrusedw;
|
|
|
+ wire [8:0] rdusedw;
|
|
|
+ wire [15:0] fifo_out;
|
|
|
+
|
|
|
ddufifo spirom_fifo (
|
|
|
.aclr ( ~rst_n ),
|
|
|
|
|
|
.wrclk ( rom_clk ),
|
|
|
.data ( spi_in_q ),
|
|
|
.wrreq ( spi_in_req_q ),
|
|
|
- .wrfull ( ),
|
|
|
.wrusedw ( wrusedw ),
|
|
|
|
|
|
.rdclk ( ram_clk ),
|
|
|
.q ( fifo_out ),
|
|
|
- .rdreq ( wacc ),
|
|
|
- .rdempty ( rdempty ),
|
|
|
+ .rdreq ( wacc & go_spi ),
|
|
|
.rdusedw ( rdusedw )
|
|
|
);
|
|
|
|
|
|
//
|
|
|
- // Interfacing between FIFO and output signals
|
|
|
+ // Interfacing between FIFO and input signals
|
|
|
//
|
|
|
// Shuffle fifo_out because SPI brings in data in bigendian bit
|
|
|
// order within bytes, but the FIFO IP assumes littleendian
|
|
|
//
|
|
|
- assign wd[ 7: 6] = fifo_out[ 1: 0];
|
|
|
- assign wd[ 5: 4] = fifo_out[ 3: 2];
|
|
|
- assign wd[ 3: 2] = fifo_out[ 5: 4];
|
|
|
- assign wd[ 1: 0] = fifo_out[ 7: 6];
|
|
|
+ assign wd[ 7: 6] = {2{go_spi}} & fifo_out[ 1: 0];
|
|
|
+ assign wd[ 5: 4] = {2{go_spi}} & fifo_out[ 3: 2];
|
|
|
+ assign wd[ 3: 2] = {2{go_spi}} & fifo_out[ 5: 4];
|
|
|
+ assign wd[ 1: 0] = {2{go_spi}} & fifo_out[ 7: 6];
|
|
|
|
|
|
- assign wd[15:14] = fifo_out[ 9: 8];
|
|
|
- assign wd[13:12] = fifo_out[11:10];
|
|
|
- assign wd[11:10] = fifo_out[13:12];
|
|
|
- assign wd[ 9: 8] = fifo_out[15:14];
|
|
|
-
|
|
|
- always @(negedge rst_n or posedge ram_clk)
|
|
|
- if (~rst_n)
|
|
|
- begin
|
|
|
- wrq <= 2'b00;
|
|
|
- end
|
|
|
- else
|
|
|
- begin
|
|
|
- wrq[0] <= rdusedw >= 9'd4; // 4*2 = 8 bytes min available
|
|
|
- wrq[1] <= rdusedw >= 9'd8; // 8*2 = 16 bytes min available
|
|
|
- end
|
|
|
+ assign wd[15:14] = {2{go_spi}} & fifo_out[ 9: 8];
|
|
|
+ assign wd[13:12] = {2{go_spi}} & fifo_out[11:10];
|
|
|
+ assign wd[11:10] = {2{go_spi}} & fifo_out[13:12];
|
|
|
+ assign wd[ 9: 8] = {2{go_spi}} & fifo_out[15:14];
|
|
|
|
|
|
reg [24:1] waddr_q;
|
|
|
- reg wacc_q;
|
|
|
+ reg [23:1] ram_data_ctr;
|
|
|
+ reg wacc_q;
|
|
|
+ reg [1:0] go_ram_q;
|
|
|
|
|
|
assign waddr = waddr_q;
|
|
|
|
|
|
always @(negedge rst_n or posedge ram_clk)
|
|
|
if (~rst_n)
|
|
|
begin
|
|
|
- waddr_q <= ramstart >> 1;
|
|
|
- wacc_q <= 1'b0;
|
|
|
- done <= 1'b0;
|
|
|
+ waddr_q <= 24'bx;
|
|
|
+ ram_data_ctr <= 23'bx;
|
|
|
+ wacc_q <= 1'b0;
|
|
|
+ done <= 1'b1;
|
|
|
+ go_ram_q <= 2'b00;
|
|
|
+ wrq <= 2'b00;
|
|
|
end
|
|
|
else
|
|
|
begin
|
|
|
- wacc_q <= wacc;
|
|
|
- waddr_q <= waddr_q + wacc_q;
|
|
|
- done <= done |
|
|
|
- (wacc_q & (waddr_q == (((ramstart + datalen) >> 1) - 1'b1)));
|
|
|
+ wrq <= 2'b00;
|
|
|
+
|
|
|
+ if (go_spi & ~done)
|
|
|
+ begin
|
|
|
+ wrq[0] <= rdusedw >= 9'd4; // 4*2 = 8 bytes min available
|
|
|
+ wrq[1] <= rdusedw >= 9'd8; // 8*2 = 16 bytes min available
|
|
|
+ end
|
|
|
+ else if (go_zero & ~done)
|
|
|
+ begin
|
|
|
+ wrq[0] <= |ram_data_ctr[23:3];
|
|
|
+ wrq[1] <= |ram_data_ctr[23:4];
|
|
|
+ end
|
|
|
+
|
|
|
+ wacc_q <= wacc;
|
|
|
+ go_ram_q <= { go_ram_q[0], go_spi|go_zero };
|
|
|
+
|
|
|
+ if (go_ram_q == 2'b01)
|
|
|
+ begin
|
|
|
+ waddr_q <= {ramstart, 2'b00};
|
|
|
+ ram_data_ctr <= { datalen, 2'b00};
|
|
|
+ done <= 1'b0;
|
|
|
+ end
|
|
|
+ else if (~done)
|
|
|
+ begin
|
|
|
+ waddr_q <= waddr_q + wacc_q;
|
|
|
+ ram_data_ctr <= ram_data_ctr - wacc_q;
|
|
|
+ done <= !(ram_data_ctr - wacc_q);
|
|
|
+ end
|
|
|
end // else: !if(~rst_n)
|
|
|
|
|
|
- reg [5:0] spi_cmd_ctr;
|
|
|
- reg [26:0] spi_data_ctr;
|
|
|
- reg spi_clk_en = 1'b0;
|
|
|
- reg spi_mosi_en = 1'b1;
|
|
|
+ reg [5:0] spi_cmd_ctr;
|
|
|
+ reg [23:-2] spi_data_ctr;
|
|
|
+ reg spi_clk_en = 1'b0;
|
|
|
+ reg spi_mosi_en = 1'b1;
|
|
|
+ reg [1:0] go_spi_q;
|
|
|
+ reg load_cmd;
|
|
|
|
|
|
ddio_out spi_clk_buf (
|
|
|
.aclr ( ~rst_n ),
|
|
@@ -125,18 +210,26 @@ module spirom (
|
|
|
begin
|
|
|
spi_cmd_ctr <= 6'b0;
|
|
|
spi_clk_en <= 1'b0;
|
|
|
- spi_data_ctr <= datalen << 2;
|
|
|
+ spi_data_ctr <= 26'b0;
|
|
|
spi_cs_n <= 1'b1;
|
|
|
spi_in_req <= 1'b0;
|
|
|
spi_in_req_q <= 1'b0;
|
|
|
+ go_spi_q <= 2'b00;
|
|
|
end
|
|
|
else
|
|
|
begin
|
|
|
+ go_spi_q <= { go_spi_q[0], go_spi };
|
|
|
spi_in_q <= spi_io;
|
|
|
spi_in_req <= 1'b0;
|
|
|
spi_in_req_q <= spi_in_req;
|
|
|
spi_clk_en <= 1'b0;
|
|
|
|
|
|
+ if (go_spi_q == 2'b01)
|
|
|
+ begin
|
|
|
+ spi_data_ctr <= { datalen, 5'b0 };
|
|
|
+ spi_cmd_ctr <= 6'b0;
|
|
|
+ end
|
|
|
+
|
|
|
if ( ~|spi_data_ctr )
|
|
|
begin
|
|
|
spi_cs_n <= 1'b1;
|
|
@@ -167,7 +260,7 @@ module spirom (
|
|
|
|
|
|
// SPI output data is shifted on the negative edge
|
|
|
reg [31:0] spi_cmd;
|
|
|
- reg spi_clk_en_q;
|
|
|
+ reg spi_clk_en_q;
|
|
|
|
|
|
assign spi_io[0] = spi_mosi_en ? spi_cmd[31] : 1'bz;
|
|
|
assign spi_io[1] = 1'bz;
|
|
@@ -175,12 +268,18 @@ module spirom (
|
|
|
always @(negedge rst_n or negedge rom_clk)
|
|
|
if (~rst_n)
|
|
|
begin
|
|
|
- spi_cmd <= { 8'h3b, romstart }; // Fast Read Dual Output
|
|
|
+ spi_cmd <= 32'bx; // Fast Read Dual Output
|
|
|
spi_mosi_en <= 1'b1;
|
|
|
spi_clk_en_q <= 1'b0;
|
|
|
end
|
|
|
else
|
|
|
begin
|
|
|
+ if (!spi_cmd_ctr)
|
|
|
+ begin
|
|
|
+ spi_cmd[31:24] <= 8'h3b; // Fast Read Dual Output
|
|
|
+ spi_cmd[23: 0] <= { romstart, 3'b000 }; // Byte address
|
|
|
+ end
|
|
|
+
|
|
|
spi_clk_en_q <= spi_clk_en;
|
|
|
if ( spi_clk_en_q )
|
|
|
spi_cmd <= (spi_cmd << 1) | 1'b1;
|