|
@@ -20,65 +20,82 @@ module spirom (
|
|
|
output reg spi_cs_n,
|
|
|
|
|
|
/* SDRAM interface */
|
|
|
- output [15:0] wd, // Data to RAM
|
|
|
+ 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 4/8 bytes)
|
|
|
- input wacc, // Data accepted (ready for next data)
|
|
|
+ output reg [1:0] wrq, // Write request (min 4/8 bytes)
|
|
|
+ input wacc, // Data accepted (ready for next data)
|
|
|
|
|
|
/* CPU control interface */
|
|
|
output reg [31:0] cpu_rdata,
|
|
|
input [31:0] cpu_wdata,
|
|
|
input cpu_valid,
|
|
|
input [3:0] cpu_wstrb,
|
|
|
- input [1:0] cpu_addr,
|
|
|
+ input [2:0] cpu_addr,
|
|
|
output reg irq
|
|
|
);
|
|
|
|
|
|
- reg [24:3] ramstart;
|
|
|
- reg [23:3] romstart;
|
|
|
- reg [23:3] datalen;
|
|
|
- reg is_spi;
|
|
|
+ reg [24:2] ramstart;
|
|
|
+ reg [31:0] romcmd;
|
|
|
+ reg [23:2] datalen;
|
|
|
+ reg [2:0] cmdlen;
|
|
|
reg go_zero;
|
|
|
reg go_spi;
|
|
|
- reg done;
|
|
|
+ reg spi_dual;
|
|
|
+ reg spi_more; // Do not raise CS# after command done
|
|
|
+ reg ram_done;
|
|
|
+ reg ram_done_q;
|
|
|
reg [1:0] done_q;
|
|
|
+ reg busy;
|
|
|
+ reg [31:0] spi_in_shr; // Input shift register for one-bit input
|
|
|
+
|
|
|
+ reg spi_active;
|
|
|
+ reg spi_active_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;
|
|
|
+ ramstart <= 23'b0;
|
|
|
+ romcmd <= 32'b0;
|
|
|
+ datalen <= 22'b0;
|
|
|
+ cmdlen <= 3'bx;
|
|
|
+ go_zero <= 1'b0;
|
|
|
+ go_spi <= 1'b0;
|
|
|
+ ram_done_q <= 1'b1;
|
|
|
+ done_q <= 2'b11;
|
|
|
+ busy <= 1'b0;
|
|
|
+ spi_active_q <= 1'b0;
|
|
|
+ irq <= 1'b1;
|
|
|
+ spi_dual <= 1'b0;
|
|
|
+ spi_more <= 1'b0;
|
|
|
end
|
|
|
else
|
|
|
begin
|
|
|
- done_q <= { done_q[0], done };
|
|
|
+ ram_done_q <= ram_done;
|
|
|
+ spi_active_q <= spi_active;
|
|
|
+ done_q <= { done_q[0], ram_done_q & ~spi_active_q };
|
|
|
+
|
|
|
+ irq <= ~(busy | spi_active_q);
|
|
|
|
|
|
if (cpu_valid & cpu_wstrb[0])
|
|
|
begin
|
|
|
- // Only full word writes supported!!
|
|
|
+ // Only full word accesses supported via DMA!!
|
|
|
case (cpu_addr)
|
|
|
2'b00: begin
|
|
|
- ramstart <= cpu_wdata[24:3];
|
|
|
+ ramstart <= cpu_wdata[24:2];
|
|
|
end
|
|
|
2'b01: begin
|
|
|
- romstart <= cpu_wdata[23:3];
|
|
|
- is_spi <= |cpu_wdata[23:3];
|
|
|
+ romcmd <= cpu_wdata[31:0];
|
|
|
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
|
|
|
+ datalen <= cpu_wdata[23:2];
|
|
|
+ cmdlen <= cpu_wdata[26:24];
|
|
|
+ go_spi <= cpu_wdata[26:24] != 3'd0;
|
|
|
+ go_zero <= cpu_wdata[26:24] == 3'd0;
|
|
|
+ spi_dual <= cpu_wdata[27];
|
|
|
+ spi_more <= cpu_wdata[28];
|
|
|
+ busy <= 1'b1;
|
|
|
+ irq <= 1'b0;
|
|
|
end
|
|
|
default: begin
|
|
|
// Do nothing
|
|
@@ -89,16 +106,18 @@ module spirom (
|
|
|
begin
|
|
|
go_zero <= 1'b0;
|
|
|
go_spi <= 1'b0;
|
|
|
- irq <= 1'b1;
|
|
|
+ busy <= 1'b0;
|
|
|
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 };
|
|
|
+ 3'b000: cpu_rdata = { 7'b0, ramstart, 2'b0 };
|
|
|
+ 3'b001: cpu_rdata = romcmd;
|
|
|
+ 3'b010: cpu_rdata = { 3'b0, spi_more, spi_dual, cmdlen, datalen, 2'b0 };
|
|
|
+ 3'b011: cpu_rdata = { 31'b0, irq };
|
|
|
+ 3'b100: cpu_rdata = spi_in_shr;
|
|
|
+ default: cpu_rdata = 32'bx;
|
|
|
endcase // case (cpu_addr)
|
|
|
|
|
|
//
|
|
@@ -110,6 +129,7 @@ module spirom (
|
|
|
wire [11:0] wrusedw;
|
|
|
wire [8:0] rdusedw;
|
|
|
wire [15:0] fifo_out;
|
|
|
+ reg from_spi;
|
|
|
|
|
|
ddufifo spirom_fifo (
|
|
|
.aclr ( ~rst_n ),
|
|
@@ -121,7 +141,7 @@ module spirom (
|
|
|
|
|
|
.rdclk ( ram_clk ),
|
|
|
.q ( fifo_out ),
|
|
|
- .rdreq ( wacc & go_spi ),
|
|
|
+ .rdreq ( wacc & from_spi ),
|
|
|
.rdusedw ( rdusedw )
|
|
|
);
|
|
|
|
|
@@ -131,15 +151,15 @@ module spirom (
|
|
|
// Shuffle fifo_out because SPI brings in data in bigendian bit
|
|
|
// order within bytes, but the FIFO IP assumes littleendian
|
|
|
//
|
|
|
- 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[ 7: 6] = {2{from_spi}} & fifo_out[ 1: 0];
|
|
|
+ assign wd[ 5: 4] = {2{from_spi}} & fifo_out[ 3: 2];
|
|
|
+ assign wd[ 3: 2] = {2{from_spi}} & fifo_out[ 5: 4];
|
|
|
+ assign wd[ 1: 0] = {2{from_spi}} & fifo_out[ 7: 6];
|
|
|
|
|
|
- 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];
|
|
|
+ assign wd[15:14] = {2{from_spi}} & fifo_out[ 9: 8];
|
|
|
+ assign wd[13:12] = {2{from_spi}} & fifo_out[11:10];
|
|
|
+ assign wd[11:10] = {2{from_spi}} & fifo_out[13:12];
|
|
|
+ assign wd[ 9: 8] = {2{from_spi}} & fifo_out[15:14];
|
|
|
|
|
|
reg [24:1] waddr_q;
|
|
|
reg [23:1] ram_data_ctr;
|
|
@@ -154,7 +174,7 @@ module spirom (
|
|
|
waddr_q <= 24'bx;
|
|
|
ram_data_ctr <= 23'bx;
|
|
|
wacc_q <= 1'b0;
|
|
|
- done <= 1'b1;
|
|
|
+ ram_done <= 1'b1;
|
|
|
go_ram_q <= 2'b00;
|
|
|
wrq <= 2'b00;
|
|
|
end
|
|
@@ -162,13 +182,19 @@ module spirom (
|
|
|
begin
|
|
|
wrq <= 2'b00;
|
|
|
|
|
|
- if (go_spi & ~done)
|
|
|
+ if (ram_done)
|
|
|
+ begin
|
|
|
+ wrq <= 2'b00;
|
|
|
+ end
|
|
|
+ else if (from_spi)
|
|
|
begin
|
|
|
+ // Reading from SPI ROM
|
|
|
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)
|
|
|
+ else
|
|
|
begin
|
|
|
+ // Zeroing memory
|
|
|
wrq[0] <= |ram_data_ctr[23:3];
|
|
|
wrq[1] <= |ram_data_ctr[23:4];
|
|
|
end
|
|
@@ -178,24 +204,27 @@ module spirom (
|
|
|
|
|
|
if (go_ram_q == 2'b01)
|
|
|
begin
|
|
|
- waddr_q <= {ramstart, 2'b00};
|
|
|
- ram_data_ctr <= { datalen, 2'b00};
|
|
|
- done <= 1'b0;
|
|
|
+ waddr_q <= { ramstart, 1'b0 };
|
|
|
+ ram_data_ctr <= { datalen, 1'b0 };
|
|
|
+ ram_done <= !datalen;
|
|
|
+ from_spi <= go_spi;
|
|
|
end
|
|
|
- else if (~done)
|
|
|
+ else if (~ram_done)
|
|
|
begin
|
|
|
waddr_q <= waddr_q + wacc_q;
|
|
|
ram_data_ctr <= ram_data_ctr - wacc_q;
|
|
|
- done <= !(ram_data_ctr - wacc_q);
|
|
|
+ ram_done <= !(ram_data_ctr - wacc_q);
|
|
|
end
|
|
|
end // else: !if(~rst_n)
|
|
|
|
|
|
- reg [5:0] spi_cmd_ctr;
|
|
|
+ // Negative indicies refer to fractional bytes
|
|
|
+ reg [2:-3] spi_cmd_ctr;
|
|
|
reg [23:-2] spi_data_ctr;
|
|
|
reg spi_clk_en = 1'b0;
|
|
|
reg spi_mosi_en;
|
|
|
reg [1:0] go_spi_q;
|
|
|
wire go_spi_s;
|
|
|
+ reg spi_more_q;
|
|
|
|
|
|
// Explicit synchronizer for go_spi
|
|
|
synchronizer #(.width(1)) go_spi_synchro
|
|
@@ -216,7 +245,11 @@ module spirom (
|
|
|
spi_in_req <= 1'b0;
|
|
|
spi_in_req_q <= 1'b0;
|
|
|
spi_mosi_en <= 1'b1;
|
|
|
- go_spi_q <= 4'b0000;
|
|
|
+ spi_in_q <= 2'bx;
|
|
|
+ spi_in_shr <= 32'b0;
|
|
|
+ go_spi_q <= 2'b00;
|
|
|
+ spi_active <= 1'b0;
|
|
|
+ spi_more_q <= 1'b0;
|
|
|
end
|
|
|
else
|
|
|
begin
|
|
@@ -225,41 +258,49 @@ module spirom (
|
|
|
spi_in_req <= 1'b0;
|
|
|
spi_in_req_q <= spi_in_req;
|
|
|
spi_clk_en <= 1'b0;
|
|
|
- spi_cs_n <= 1'b1;
|
|
|
|
|
|
// Note: datalen <- spi_data_ctr is a 2-cycle multipath
|
|
|
if (go_spi_q == 2'b01)
|
|
|
begin
|
|
|
- spi_data_ctr <= { datalen, 5'b0 };
|
|
|
- spi_cmd_ctr <= 6'b0;
|
|
|
+ spi_cmd_ctr <= { cmdlen, 3'b0 };
|
|
|
+ spi_data_ctr <= { datalen, 4'b0 };
|
|
|
+ spi_active <= 1'b1;
|
|
|
spi_cs_n <= 1'b0;
|
|
|
+ spi_more_q <= spi_more;
|
|
|
end
|
|
|
|
|
|
- if ( ~|spi_data_ctr | ~go_spi_q[1] )
|
|
|
+ if ( ~|{spi_data_ctr, spi_cmd_ctr} )
|
|
|
begin
|
|
|
spi_clk_en <= 1'b0;
|
|
|
spi_mosi_en <= 1'b1;
|
|
|
+ spi_active <= 1'b0;
|
|
|
+ spi_cs_n <= ~spi_more_q;
|
|
|
end
|
|
|
else
|
|
|
begin
|
|
|
- spi_cs_n <= 1'b0;
|
|
|
- if ( ~spi_cs_n )
|
|
|
+ spi_active <= 1'b1;
|
|
|
+ spi_cs_n <= 1'b0;
|
|
|
+
|
|
|
+ if ( spi_active )
|
|
|
begin
|
|
|
// 64/4 = 16 bytes min space
|
|
|
spi_clk_en <= (~wrusedw) >= 12'd128;
|
|
|
+
|
|
|
if ( spi_clk_en )
|
|
|
begin
|
|
|
- if ( spi_cmd_ctr[5] & spi_cmd_ctr[2] )
|
|
|
- spi_mosi_en <= 1'b0;
|
|
|
+ spi_in_shr <= { spi_in_shr[30:0], spi_io[1] };
|
|
|
|
|
|
- if ( spi_cmd_ctr[5] & spi_cmd_ctr[3] )
|
|
|
+ if ( spi_cmd_ctr == 6'd1 )
|
|
|
+ spi_mosi_en <= ~spi_dual;
|
|
|
+
|
|
|
+ if ( spi_cmd_ctr == 6'd0 )
|
|
|
begin
|
|
|
- spi_in_req <= 1'b1;
|
|
|
+ spi_in_req <= 1'b1;
|
|
|
spi_data_ctr <= spi_data_ctr - 1'b1;
|
|
|
end
|
|
|
else
|
|
|
begin
|
|
|
- spi_cmd_ctr <= spi_cmd_ctr + 1'b1;
|
|
|
+ spi_cmd_ctr <= spi_cmd_ctr - 1'b1;
|
|
|
end
|
|
|
end // if ( spi_clk_en )
|
|
|
end // if ( ~spi_cs_n )
|
|
@@ -267,29 +308,26 @@ module spirom (
|
|
|
end // else: !if(~rst_n)
|
|
|
|
|
|
// SPI output data is shifted on the negative edge
|
|
|
- reg [31:0] spi_cmd;
|
|
|
+ reg [31:0] spi_out_shr;
|
|
|
reg spi_clk_en_q;
|
|
|
|
|
|
- assign spi_io[0] = spi_mosi_en ? spi_cmd[31] : 1'bz;
|
|
|
+ assign spi_io[0] = spi_mosi_en ? spi_out_shr[31] : 1'bz;
|
|
|
assign spi_io[1] = 1'bz;
|
|
|
|
|
|
always @(negedge rst_n or negedge rom_clk)
|
|
|
if (~rst_n)
|
|
|
begin
|
|
|
- spi_cmd <= 32'bx; // Fast Read Dual Output
|
|
|
+ spi_out_shr <= 32'b0;
|
|
|
spi_clk_en_q <= 1'b0;
|
|
|
end
|
|
|
else
|
|
|
begin
|
|
|
- if (spi_cs_n)
|
|
|
- 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;
|
|
|
+
|
|
|
+ if (~spi_active)
|
|
|
+ spi_out_shr <= romcmd;
|
|
|
+ else if ( spi_clk_en_q )
|
|
|
+ spi_out_shr <= { spi_out_shr[30:0], 1'b0 };
|
|
|
end
|
|
|
|
|
|
//
|