URL
https://opencores.org/ocsvn/qspiflash/qspiflash/trunk
Subversion Repositories qspiflash
Compare Revisions
- This comparison shows the changes necessary to convert path
/qspiflash/trunk/rtl
- from Rev 3 to Rev 4
- ↔ Reverse comparison
Rev 3 → Rev 4
/wbqspiflash.v
52,7 → 52,7
// |
/////////////////////////////////////////////////////////////////////////// |
`define WBQSPI_RESET 0 |
`define WBQSPI_RESET_WEN 1 |
`define WBQSPI_RESET_QUADMODE 1 |
`define WBQSPI_IDLE 2 |
`define WBQSPI_RDIDLE 3 // Idle, but in fast read mode |
`define WBQSPI_WBDECODE 4 |
114,10 → 114,13
reg [1:0] spi_len; |
wire [31:0] spi_out; |
wire spi_valid, spi_busy; |
wire w_qspi_sck, w_qspi_cs_n; |
wire [3:0] w_qspi_dat; |
wire [1:0] w_qspi_mod; |
llqspi lldriver(i_clk_100mhz, |
spi_wr, spi_hold, spi_in, spi_len, spi_spd, spi_dir, |
spi_out, spi_valid, spi_busy, |
o_qspi_sck, o_qspi_cs_n, o_qspi_mod, o_qspi_dat, |
w_qspi_sck, w_qspi_cs_n, w_qspi_mod, w_qspi_dat, |
i_qspi_dat); |
|
// Erase status tracking |
133,11 → 136,10
|
reg [7:0] last_status; |
reg quad_mode_enabled; |
reg spif_cmd; |
reg spif_cmd, spif_override; |
reg [19:0] spif_addr; |
reg [31:0] spif_data; |
reg [5:0] state; |
reg [5:0] spif_return; |
reg spif_ctrl, spif_req; |
wire [5:0] spif_sector; |
assign spif_sector = spif_addr[19:14]; |
150,6 → 152,8
initial quad_mode_enabled = 1'b0; |
initial o_interrupt = 1'b0; |
always @(posedge i_clk_100mhz) |
begin |
spif_override <= 1'b0; |
if (state == `WBQSPI_RESET) |
begin |
// From a reset, we should |
159,46 → 163,38
// immediately .... |
o_wb_ack <= 1'b0; |
o_wb_stall <= 1'b1; |
spi_wr <= 1'b0; |
spi_hold <= 1'b0; |
spi_spd <= 1'b0; |
spi_dir <= 1'b0; |
last_status <= 8'h00; |
if (spi_len < 2'b11) |
spi_len <= spi_len + 1; |
state <= `WBQSPI_IDLE; |
state <= `WBQSPI_RESET_QUADMODE; |
spif_req <= 1'b0; |
/* |
// This next bit of logic is confusing ... |
// I wish to enable quad SPI mode automatically. However, this is |
// a configuration register thing, so once written it never needs to |
// be adjusted again. Further, some bits within the configuration |
// register cannot be undone, and my inkling might be to set those. |
// Finally, the configuration register affects the control of the |
// block protect registers in the status register. So ... |
// let's just leave these registers alone, or command them from the |
// UART-wishbone interface. |
else if (~spi_busy) |
begin |
spi_wr <= 1'b1; |
spi_len <= 2'b00; // 1 byte |
spi_in <= { 8'h06, 24'h000 }; |
end |
end else if (state == `WBQSPI_RESET_WEN) |
spif_override <= 1'b1; |
last_status <= 8'hfc; // |
// This guarantees that we aren't starting in quad |
// I/O mode, where the FPGA configuration scripts may |
// have left us. |
end else if (state == `WBQSPI_RESET_QUADMODE) |
begin |
spi_wr <= 1'b0; |
if ((~spi_busy)&&(~spi_wr)&&(o_qspi_cs_n)) |
// Okay, so here's the problem: we don't know whether or not |
// the Xilinx loader started us up in Quad Read I/O idle mode. |
// So, thus we need to |
// Not ready to handle the bus yet, so stall any requests |
o_wb_ack <= 1'b0; |
o_wb_stall <= 1'b1; |
|
// Do something ... |
if (last_status == 8'h00) |
begin |
spi_wr <= 1'b1; |
spi_spd <= 1'b0; |
spi_len <= 2'b10; // 3 bytes |
// Command, status, config, then don't care |
spi_in <= { 8'h01, 8'h00, 8'h0b, 8'h00 }; |
spi_dir <= 1'b0; |
quad_mode_enabled <= 1'b1; |
state <= `WBQSPI_WAIT_TIL_IDLE; |
write_in_progress <= 1'b1; |
spif_override <= 1'b0; |
state <= `WBQSPI_IDLE; |
end else begin |
last_status <= last_status - 8'h1; |
spif_override <= 1'b1; |
spif_cmd <= last_status[3]; // Toggle CS_n |
spif_ctrl <= last_status[0]; // Toggle clock too |
end |
*/ |
end else if (state == `WBQSPI_IDLE) |
begin |
o_interrupt <= 1'b0; |
403,7 → 399,7
begin // Continue our read ... send the new address / mode |
o_wb_stall <= 1'b1; |
spi_wr <= 1'b1; |
spi_len <= 2'b10; |
spi_len <= 2'b10; // Write address, but not mode byte |
spi_in <= { 2'h0, i_wb_addr[19:0], 2'h0, 8'ha0 }; |
state <= `WBQSPI_QRD_DUMMY; |
end else if((i_wb_cyc)&&(i_wb_ctrl_stb)&&(~i_wb_we)&&(i_wb_addr[1:0] == 2'b00)) |
631,10 → 627,12
if (quad_mode_enabled) |
begin |
spi_in <= { 8'heb, 2'b00, spif_addr[19:0], 2'b00 }; |
state <= `WBQSPI_QRD_DUMMY; |
state <= `WBQSPI_QRD_ADDRESS; |
// spi_len <= 2'b00; // single byte, cmd only |
end else begin |
spi_in <= { 8'h0b, 2'b00, spif_addr[19:0], 2'b00 }; |
state <= `WBQSPI_RD_DUMMY; |
spi_len <= 2'b11; // Send cmd and addr |
end end |
4'b10??: begin // Write data to ... anywhere |
spi_wr <= 1'b1; |
674,8 → 672,8
o_wb_stall <= 1'b1; |
spif_req<= (spif_req) && (i_wb_cyc); |
if ((~spi_busy)&&(o_qspi_cs_n)&&(~spi_wr)) // Let's come to a full stop |
// state <= (quad_mode_enabled)?`WBQSPI_QPP:`WBQSPI_PP; |
state <= `WBQSPI_PP; |
state <= (quad_mode_enabled)?`WBQSPI_QPP:`WBQSPI_PP; |
// state <= `WBQSPI_PP; |
end else if (state == `WBQSPI_PP) |
begin // We come here under a full stop / full port idle mode |
// Issue our command immediately |
794,7 → 792,7
|
spi_wr <= 1'b1; // Non-stop |
spi_in <= { 2'b0, spif_addr, 2'b0, 8'ha0 }; |
spi_len <= 2'b11; // Write all 32 bits bits |
spi_len <= 2'b10; // Write address, not mode byte |
spi_spd <= 1'b1; |
spi_dir <= 1'b0; // Still writing |
spi_hold <= 1'b0; |
836,12 → 834,23
begin |
// Pipelined read support |
spi_wr <=((i_wb_cyc)&&(i_wb_data_stb)&&(~i_wb_we)&&(i_wb_addr== (spif_addr+1))); |
// spi_wr <= 1'b0; // No pipelined read support |
spi_in <= 32'h00; |
spi_len <= 2'b11; |
// Don't adjust the speed here, it was set in the setup |
spi_dir <= 1'b1; // Now we get to read |
spi_hold <= 1'b0; |
spi_dir <= 1'b1; // Now we get to read |
// Don't let the device go to idle until the bus cycle ends. |
// This actually prevents a *really* nasty race condition, |
// where the strobe comes in after the lower level device |
// has decided to stop waiting. The write is then issued, |
// but no one is listening. By leaving the device open, |
// the device is kept in a state where a valid strobe |
// here will be useful. Of course, we don't accept |
// all commands, just reads. Further, the strobe needs |
// to be high for two clocks cycles without changing |
// anything on the bus--one for us to notice it and pull |
// our head out of the sand, and a second for whoever |
// owns the bus to realize their command went through. |
spi_hold <= 1'b1; |
spif_req<= (spif_req) && (i_wb_cyc); |
if ((spi_valid)&&(~spi_in[31])) |
begin // Single pulse acknowledge and write data out |
853,8 → 862,16
state <= (spi_wr)?`WBQSPI_READ_DATA |
: ((spi_spd) ? `WBQSPI_WAIT_TIL_RDIDLE : `WBQSPI_WAIT_TIL_IDLE); |
spif_req <= spi_wr; |
spi_hold <= (~spi_wr); |
if (spi_wr) |
spif_addr <= i_wb_addr; |
end else if (~i_wb_cyc) |
begin // FAIL SAFE: If the bus cycle ends, forget why we're |
// here, just go back to idle |
state <= ((spi_spd) ? `WBQSPI_WAIT_TIL_RDIDLE : `WBQSPI_WAIT_TIL_IDLE); |
spi_hold <= 1'b0; |
o_wb_ack <= 1'b0; |
o_wb_stall <= 1'b1; |
end else begin |
o_wb_ack <= 1'b0; |
o_wb_stall <= 1'b1; |
895,7 → 912,7
o_wb_ack <= 1'b0; // Assuming we're still waiting |
o_wb_stall <= 1'b1; |
|
spi_wr <= 1'b0; // No more writes, we'ev already written the cmd |
spi_wr <= 1'b0; // No more writes, we've already written the cmd |
spi_hold <= 1'b0; |
spif_req <= (spif_req) && (i_wb_cyc); |
|
908,7 → 925,7
o_wb_data <= spi_out[31:0]; |
o_wb_ack <= spif_req; |
spif_req <= 1'b0; |
end else if ((~spi_busy)&&(~o_qspi_cs_n)) |
end else if ((~spi_busy)&&(o_qspi_cs_n)) |
begin |
state <= `WBQSPI_IDLE; |
o_wb_stall <= 1'b0; |
1097,5 → 1114,11
o_wb_ack <= 1'b0; // Shouldn't be acking anything here |
end |
end |
end |
|
// Command and control during the reset sequence |
assign o_qspi_cs_n = (spif_override)?spif_cmd :w_qspi_cs_n; |
assign o_qspi_sck = (spif_override)?spif_ctrl:w_qspi_sck; |
assign o_qspi_mod = (spif_override)? 2'b01 :w_qspi_mod; |
assign o_qspi_dat = (spif_override)? 4'b00 :w_qspi_dat; |
endmodule |
/llqspi.v
37,12 → 37,13
// |
// |
/////////////////////////////////////////////////////////////////////////// |
`define QSPI_IDLE 0 |
`define QSPI_START 1 |
`define QSPI_BITS 2 |
`define QSPI_READY 3 |
`define QSPI_STOP 4 |
`define QSPI_STOP_B 5 |
`define QSPI_IDLE 3'h0 |
`define QSPI_START 3'h1 |
`define QSPI_BITS 3'h2 |
`define QSPI_READY 3'h3 |
`define QSPI_HOLDING 3'h4 |
`define QSPI_STOP 3'h5 |
`define QSPI_STOP_B 3'h6 |
|
// Modes |
`define QSPI_MOD_SPI 2'b00 |
266,7 → 267,7
// high clocks) of the data. Data is valid during |
// this state. Here we chose to either STOP or |
// continue and transmit more. |
o_sck <= (i_hold); // Stay here on hold, no clocks |
o_sck <= (i_hold); // No clocks while holding |
if((~o_busy)&&(i_wr))// Acknowledge a new request |
begin |
state <= `QSPI_BITS; |
303,13 → 304,10
r_input <= { r_input[26:0], i_dat }; |
o_word <= { r_input[27:0], i_dat }; |
end |
end else if (i_hold) |
begin // Stay here, holding the clock high, if the user |
// has more data, but it isn't ready yet. |
o_busy <= 1'b0; |
end else begin |
o_sck <= 1'b1; |
state <= `QSPI_STOP; |
state <= (i_hold)?`QSPI_HOLDING : `QSPI_STOP; |
o_busy <= (~i_hold); |
|
// Read a bit upon any transition |
o_valid <= 1'b1; |
323,6 → 321,45
o_word <= { r_input[27:0], i_dat }; |
end |
end |
end else if (state == `QSPI_HOLDING) |
begin |
// We need this state so that the o_valid signal |
// can get strobed with our last result. Otherwise |
// we could just sit in READY waiting for a new command. |
// |
// Incidentally, the change producing this state was |
// the result of a nasty race condition. See the |
// commends in wbqspiflash for more details. |
// |
o_valid <= 1'b0; |
o_cs_n <= 1'b0; |
o_busy <= 1'b0; |
if((~o_busy)&&(i_wr))// Acknowledge a new request |
begin |
state <= `QSPI_BITS; |
o_busy <= 1'b1; |
o_sck <= 1'b0; |
|
// Read the new request off the bus |
r_spd <= i_spd; |
r_dir <= i_dir; |
// Set up the first bits on the bus |
o_mod<=(i_spd)?{ 1'b1, i_dir } : `QSPI_MOD_SPI; |
if (i_spd) |
begin |
o_dat <= i_word[31:28]; |
r_word <= { i_word[27:0], 4'h0 }; |
spi_len<= { 1'b0, i_len, 3'b100 }; |
end else begin |
o_dat <= { 3'b110, i_word[31] }; |
r_word <= { i_word[30:0], 1'b0 }; |
spi_len<= { 1'b0, i_len, 3'b111 }; |
end |
end else begin |
o_sck <= 1'b1; |
state <= (i_hold)?`QSPI_HOLDING : `QSPI_STOP; |
o_busy <= (~i_hold); |
end |
end else if (state == `QSPI_STOP) |
begin |
o_sck <= 1'b1; // Stop the clock |