|
@@ -131,23 +131,22 @@ module spirom (
|
|
|
//
|
|
|
// FIFO and input latches
|
|
|
//
|
|
|
- reg [0:0] spi_in_q;
|
|
|
- reg spi_in_req;
|
|
|
- reg spi_in_req_q;
|
|
|
+ reg [1:0] spi_in_q;
|
|
|
+ reg spi_ram_in_req;
|
|
|
wire [11:0] wrusedw;
|
|
|
wire [8:0] rdusedw;
|
|
|
wire [15:0] fifo_out;
|
|
|
- wire [1:0] spi_in_data;
|
|
|
+ wire [1:0] spi_in_data;
|
|
|
|
|
|
- assign spi_in_data[0] = spi_dual ? spi_in_q[0] : spi_in_shr[0];
|
|
|
- assign spi_in_data[1] = spi_dual ? spi_in_shr[0] : spi_in_shr[1];
|
|
|
+ assign spi_in_data[0] = spi_dual ? spi_in_q[0] : spi_in_q[1];
|
|
|
+ assign spi_in_data[1] = spi_dual ? spi_in_q[1] : spi_in_shr[0];
|
|
|
|
|
|
ddufifo spirom_fifo (
|
|
|
.aclr ( ~rst_n ),
|
|
|
|
|
|
.wrclk ( rom_clk ),
|
|
|
.data ( spi_in_data ),
|
|
|
- .wrreq ( spi_in_req_q & is_spi ),
|
|
|
+ .wrreq ( spi_ram_in_req ),
|
|
|
.wrusedw ( wrusedw ),
|
|
|
|
|
|
.rdclk ( ram_clk ),
|
|
@@ -231,14 +230,21 @@ module spirom (
|
|
|
// Negative indicies refer to fractional bytes
|
|
|
reg [2:-3] spi_cmd_ctr;
|
|
|
reg [23:-3] spi_data_ctr;
|
|
|
- reg spi_clk_en = 1'b0;
|
|
|
+ reg spi_clk_en;
|
|
|
+ reg [1:0] spi_clk_en_q;
|
|
|
reg spi_mosi_en;
|
|
|
reg [1:0] go_spi_q;
|
|
|
wire go_spi_s;
|
|
|
reg spi_more_q;
|
|
|
reg spi_active;
|
|
|
- reg [3:0] spi_cs_ctr;
|
|
|
+ reg spi_active_q;
|
|
|
reg [31:0] spi_out_shr;
|
|
|
+ reg spi_in_req;
|
|
|
+ reg spi_in_req_q;
|
|
|
+
|
|
|
+ localparam spi_cs_wait_lg2 = 0; // 8 bit times between CS# and first clock
|
|
|
+ reg [spi_cs_wait_lg2:0] spi_cs_ctr;
|
|
|
+ wire spi_cs_ready = spi_cs_ctr[spi_cs_wait_lg2];
|
|
|
|
|
|
// Explicit synchronizers for handshake signals
|
|
|
synchronizer #(.width(1)) go_spi_synchro
|
|
@@ -264,34 +270,47 @@ module spirom (
|
|
|
begin
|
|
|
spi_cmd_ctr <= 6'b0;
|
|
|
spi_clk_en <= 1'b0;
|
|
|
- spi_clk_en_q <= 1'b0;
|
|
|
+ spi_clk_en_q <= 'b0;
|
|
|
spi_data_ctr <= 27'b0;
|
|
|
spi_cs_n <= 1'b1;
|
|
|
spi_cs_ctr <= 'b0;
|
|
|
spi_in_req <= 1'b0;
|
|
|
spi_in_req_q <= 1'b0;
|
|
|
+ spi_ram_in_req <= 1'b0;
|
|
|
spi_mosi_en <= 1'b1;
|
|
|
- spi_in_q <= 1'b0;
|
|
|
spi_in_shr <= 32'b0;
|
|
|
spi_active <= 1'b0;
|
|
|
+ spi_active_q <= 1'b0;
|
|
|
spi_more_q <= 1'b0;
|
|
|
spi_out_shr <= 32'b0;
|
|
|
end
|
|
|
else
|
|
|
begin
|
|
|
- spi_in_req <= 1'b0;
|
|
|
- spi_in_req_q <= spi_in_req;
|
|
|
- spi_clk_en <= 1'b0;
|
|
|
- spi_clk_en_q <= spi_clk_en;
|
|
|
+ // Fun with long pipelined chains of registers...
|
|
|
+ spi_in_req <= 1'b0;
|
|
|
+ spi_in_req_q <= spi_in_req;
|
|
|
+ spi_ram_in_req <= spi_in_req_q & is_ram;
|
|
|
+
|
|
|
+ spi_clk_en <= 1'b0;
|
|
|
+ spi_clk_en_q <= (spi_clk_en_q << 1'b1) | spi_clk_en;
|
|
|
+
|
|
|
+ spi_active_q <= spi_active;
|
|
|
+
|
|
|
+ if ( spi_clk_en_q[1] )
|
|
|
+ spi_in_shr <= { spi_in_shr[30:0], spi_in_q[1] };
|
|
|
|
|
|
// Bit to start transmitting on the next clock down transition
|
|
|
- spi_out_shr <= spi_out_shr << spi_clk_en;
|
|
|
+ // This needs to be delayed by one cycle in order to match
|
|
|
+ // the one-cycle delay imposed by the DDR output buffer
|
|
|
+ // when spi_clk_en goes high.
|
|
|
+ if ( spi_clk_en_q )
|
|
|
+ spi_out_shr <= { spi_out_shr[30:0], 1'b1 };
|
|
|
|
|
|
- // After asserting CS#, wait 16 SPI clock times
|
|
|
+ // After asserting CS#, wait 8 SPI clock times
|
|
|
if (spi_cs_n)
|
|
|
spi_cs_ctr <= 'b0;
|
|
|
else
|
|
|
- spi_cs_ctr <= spi_cs_ctr + ~&spi_cs_ctr;
|
|
|
+ spi_cs_ctr <= spi_cs_ctr + !spi_cs_ready;
|
|
|
|
|
|
// Note: datalen <- spi_data_ctr is a 2-cycle multipath
|
|
|
if (go_spi_s & ~spi_active)
|
|
@@ -314,55 +333,56 @@ module spirom (
|
|
|
end
|
|
|
else
|
|
|
begin
|
|
|
- spi_active <= &spi_cs_ctr;
|
|
|
+ spi_active <= 1'b1;
|
|
|
spi_cs_n <= 1'b0;
|
|
|
|
|
|
- if ( spi_active )
|
|
|
+ if ( spi_active & spi_cs_ready )
|
|
|
begin
|
|
|
// This will block unnecessarily if the DMA queue
|
|
|
// is full from a previous transaction, but that doesn't
|
|
|
// matter in practice... just let it drain.
|
|
|
spi_clk_en <= dma_queue_space;
|
|
|
+ spi_mosi_en <= ~spi_dual | |spi_cmd_ctr;
|
|
|
|
|
|
- if ( spi_clk_en )
|
|
|
- begin
|
|
|
- // Note: spi_in_shr[0] and spi_in_q[1] should
|
|
|
- // be merged into a single register.
|
|
|
- spi_in_shr <= { spi_in_shr[30:0], spi_io[1] };
|
|
|
- spi_in_q[0] <= spi_io[0];
|
|
|
-
|
|
|
- if ( spi_cmd_ctr == 6'd1 )
|
|
|
- spi_mosi_en <= ~spi_dual;
|
|
|
-
|
|
|
- if ( ~|spi_cmd_ctr )
|
|
|
- begin
|
|
|
- spi_in_req <= spi_data_ctr[-3] | spi_dual;
|
|
|
- spi_data_ctr <= spi_data_ctr - (1'b1 << spi_dual);
|
|
|
- end
|
|
|
- else
|
|
|
- begin
|
|
|
- spi_cmd_ctr <= spi_cmd_ctr - 1'b1;
|
|
|
- end
|
|
|
- end // if ( spi_clk_en )
|
|
|
- end // if ( ~spi_cs_n )
|
|
|
- end // else: !if( ~|spi_data_ctr )
|
|
|
+ if ( spi_clk_en & ~|spi_cmd_ctr )
|
|
|
+ spi_in_req <= spi_data_ctr[-3] | spi_dual;
|
|
|
+ end // if ( spi_active & spi_cs_ready )
|
|
|
+
|
|
|
+ if ( (spi_active & ~spi_active_q) | spi_clk_en )
|
|
|
+ begin
|
|
|
+ // This is either the kickoff cycle or advancing
|
|
|
+ if ( ~|spi_cmd_ctr )
|
|
|
+ spi_data_ctr <= spi_data_ctr - (1'b1 << spi_dual);
|
|
|
+ else
|
|
|
+ spi_cmd_ctr <= spi_cmd_ctr - 1'b1;
|
|
|
+ end // if ( spi_clk_en )
|
|
|
+ end // else: !if( ~|{spi_data_ctr, spi_cmd_ctr} )
|
|
|
end // else: !if(~rst_n)
|
|
|
|
|
|
- // SPI output data is shifted on the negative edge
|
|
|
- reg spi_out_q;
|
|
|
+ //
|
|
|
+ // Input I/O: latch on the positive spi_clk, which is the
|
|
|
+ // negative rom_clk.
|
|
|
+ //
|
|
|
always @(negedge rom_clk)
|
|
|
- spi_out_q <= spi_out_shr[31];
|
|
|
+ spi_in_q <= spi_io;
|
|
|
|
|
|
- assign spi_io[0] = spi_mosi_en ? spi_out_q : 1'bz;
|
|
|
+ //
|
|
|
+ // Output I/O: changed on the negative spi_clk, which is the
|
|
|
+ // positive rom_clk (thus matching when these registers are set.)
|
|
|
+ //
|
|
|
+ assign spi_io[0] = spi_mosi_en ? spi_out_shr[31] : 1'bz;
|
|
|
assign spi_io[1] = 1'bz;
|
|
|
|
|
|
//
|
|
|
- // SPI_SCK output buffer: emit a clock pulse iff spi_clk_en_q is high
|
|
|
+ // SPI_SCK output buffer: emit a spi_clk clock pulse if spi_clk_en
|
|
|
+ // is high; note that this is phase-inverted versus the internal
|
|
|
+ // rom_clk, and that this is sampled one full rom_clk before
|
|
|
+ // output, so
|
|
|
//
|
|
|
ddio_out spi_clk_buf (
|
|
|
.aclr ( ~rst_n ),
|
|
|
- .datain_h ( spi_clk_en_q ),
|
|
|
- .datain_l ( 1'b0 ),
|
|
|
+ .datain_h ( 1'b0 ),
|
|
|
+ .datain_l ( spi_clk_en ),
|
|
|
.outclock ( rom_clk ),
|
|
|
.dataout ( spi_sck )
|
|
|
);
|