Line 1... |
Line 1... |
///////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
//
|
//
|
// Filename: llqspi.v
|
// Filename: llqspi.v
|
//
|
//
|
// Project: Wishbone Controlled Quad SPI Flash Controller
|
// Project: Wishbone Controlled Quad SPI Flash Controller
|
//
|
//
|
Line 8... |
Line 8... |
// to/from a Quad SPI port. The port is understood to be
|
// to/from a Quad SPI port. The port is understood to be
|
// a normal SPI port unless the driver requests four bit mode.
|
// a normal SPI port unless the driver requests four bit mode.
|
// When not in use, unlike our previous SPI work, no bits will
|
// When not in use, unlike our previous SPI work, no bits will
|
// toggle.
|
// toggle.
|
//
|
//
|
// Creator: Dan Gisselquist
|
// Creator: Dan Gisselquist, Ph.D.
|
// Gisselquist Technology, LLC
|
// Gisselquist Technology, LLC
|
//
|
//
|
///////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
//
|
//
|
// Copyright (C) 2015, Gisselquist Technology, LLC
|
// Copyright (C) 2015,2017, Gisselquist Technology, LLC
|
//
|
//
|
// This program is free software (firmware): you can redistribute it and/or
|
// This program is free software (firmware): you can redistribute it and/or
|
// modify it under the terms of the GNU General Public License as published
|
// modify it under the terms of the GNU General Public License as published
|
// by the Free Software Foundation, either version 3 of the License, or (at
|
// by the Free Software Foundation, either version 3 of the License, or (at
|
// your option) any later version.
|
// your option) any later version.
|
Line 26... |
Line 26... |
// ANY WARRANTY; without even the implied warranty of MERCHANTIBILITY or
|
// ANY WARRANTY; without even the implied warranty of MERCHANTIBILITY or
|
// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
// for more details.
|
// for more details.
|
//
|
//
|
// You should have received a copy of the GNU General Public License along
|
// You should have received a copy of the GNU General Public License along
|
// with this program. (It's in the $(ROOT)/doc directory, run make with no
|
// with this program. (It's in the $(ROOT)/doc directory. Run make with no
|
// target there if the PDF file isn't present.) If not, see
|
// target there if the PDF file isn't present.) If not, see
|
// <http://www.gnu.org/licenses/> for a copy.
|
// <http://www.gnu.org/licenses/> for a copy.
|
//
|
//
|
// License: GPL, v3, as defined and found on www.gnu.org,
|
// License: GPL, v3, as defined and found on www.gnu.org,
|
// http://www.gnu.org/licenses/gpl.html
|
// http://www.gnu.org/licenses/gpl.html
|
//
|
//
|
//
|
//
|
///////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
//
|
//
|
//
|
//
|
`default_nettype none
|
`default_nettype none
|
//
|
//
|
`define QSPI_IDLE 3'h0
|
`define QSPI_IDLE 3'h0
|
Line 191... |
Line 191... |
initial o_cs_n = 1'b1;
|
initial o_cs_n = 1'b1;
|
initial o_dat = 4'hd;
|
initial o_dat = 4'hd;
|
initial o_valid = 1'b0;
|
initial o_valid = 1'b0;
|
initial o_busy = 1'b0;
|
initial o_busy = 1'b0;
|
initial r_input = 31'h000;
|
initial r_input = 31'h000;
|
|
initial o_mod = `QSPI_MOD_SPI;
|
always @(posedge i_clk)
|
always @(posedge i_clk)
|
if ((state == `QSPI_IDLE)&&(o_sck))
|
if ((state == `QSPI_IDLE)&&(o_sck))
|
begin
|
begin
|
o_cs_n <= 1'b1;
|
o_cs_n <= 1'b1;
|
o_valid <= 1'b0;
|
o_valid <= 1'b0;
|
o_busy <= 1'b0;
|
o_busy <= 1'b0;
|
o_mod <= `QSPI_MOD_SPI;
|
o_mod <= `QSPI_MOD_SPI;
|
if (i_wr)
|
|
begin
|
|
r_word <= i_word;
|
r_word <= i_word;
|
state <= `QSPI_START;
|
|
r_spd <= i_spd;
|
r_spd <= i_spd;
|
r_dir <= i_dir;
|
r_dir <= i_dir;
|
|
if (i_wr)
|
|
begin
|
|
state <= `QSPI_START;
|
spi_len<= { 1'b0, i_len, 3'b000 } + 6'h8;
|
spi_len<= { 1'b0, i_len, 3'b000 } + 6'h8;
|
o_cs_n <= 1'b0;
|
o_cs_n <= 1'b0;
|
|
// o_sck <= 1'b1;
|
o_busy <= 1'b1;
|
o_busy <= 1'b1;
|
o_sck <= 1'b1;
|
|
end
|
end
|
end else if (state == `QSPI_START)
|
end else if (state == `QSPI_START)
|
begin // We come in here with sck high, stay here 'til sck is low
|
begin // We come in here with sck high, stay here 'til sck is low
|
o_sck <= 1'b0;
|
o_sck <= 1'b0;
|
if (o_sck == 1'b0)
|
if (o_sck == 1'b0)
|
Line 226... |
Line 227... |
o_mod <= (r_spd) ? { 1'b1, r_dir } : `QSPI_MOD_SPI;
|
o_mod <= (r_spd) ? { 1'b1, r_dir } : `QSPI_MOD_SPI;
|
o_cs_n <= 1'b0;
|
o_cs_n <= 1'b0;
|
o_busy <= 1'b1;
|
o_busy <= 1'b1;
|
o_valid <= 1'b0;
|
o_valid <= 1'b0;
|
if (r_spd)
|
if (r_spd)
|
begin
|
|
o_dat <= r_word[31:28];
|
o_dat <= r_word[31:28];
|
// r_word <= { r_word[27:0], 4'h0 };
|
else
|
end else begin
|
|
o_dat <= { 3'b110, r_word[31] };
|
o_dat <= { 3'b110, r_word[31] };
|
// r_word <= { r_word[30:0], 1'b0 };
|
|
end
|
|
end else if (~o_sck)
|
end else if (~o_sck)
|
begin
|
begin
|
o_sck <= 1'b1;
|
o_sck <= 1'b1;
|
o_busy <= ((state != `QSPI_READY)||(~i_wr));
|
o_busy <= ((state != `QSPI_READY)||(~i_wr));
|
o_valid <= 1'b0;
|
o_valid <= 1'b0;
|
Line 274... |
Line 271... |
// This is the state on the last clock (both low and
|
// This is the state on the last clock (both low and
|
// high clocks) of the data. Data is valid during
|
// high clocks) of the data. Data is valid during
|
// this state. Here we chose to either STOP or
|
// this state. Here we chose to either STOP or
|
// continue and transmit more.
|
// continue and transmit more.
|
o_sck <= (i_hold); // No clocks while holding
|
o_sck <= (i_hold); // No clocks while holding
|
|
r_spd <= i_spd;
|
|
r_dir <= i_dir;
|
|
if (i_spd)
|
|
begin
|
|
r_word <= { i_word[27:0], 4'h0 };
|
|
spi_len<= { 1'b0, i_len, 3'b000 } + 6'h8 - 6'h4;
|
|
end else begin
|
|
r_word <= { i_word[30:0], 1'b0 };
|
|
spi_len<= { 1'b0, i_len, 3'b000 } + 6'h8 - 6'h1;
|
|
end
|
if((~o_busy)&&(i_wr))// Acknowledge a new request
|
if((~o_busy)&&(i_wr))// Acknowledge a new request
|
begin
|
begin
|
state <= `QSPI_BITS;
|
state <= `QSPI_BITS;
|
o_busy <= 1'b1;
|
o_busy <= 1'b1;
|
o_sck <= 1'b0;
|
o_sck <= 1'b0;
|
|
|
// Read the new request off the bus
|
// Read the new request off the bus
|
r_spd <= i_spd;
|
|
r_dir <= i_dir;
|
|
// Set up the first bits on the bus
|
// Set up the first bits on the bus
|
o_mod <= (i_spd) ? { 1'b1, i_dir } : `QSPI_MOD_SPI;
|
o_mod <= (i_spd) ? { 1'b1, i_dir } : `QSPI_MOD_SPI;
|
if (i_spd)
|
if (i_spd)
|
begin
|
|
o_dat <= i_word[31:28];
|
o_dat <= i_word[31:28];
|
r_word <= { i_word[27:0], 4'h0 };
|
else
|
// spi_len <= spi_len - 4;
|
|
spi_len<= { 1'b0, i_len, 3'b000 } + 6'h8
|
|
- 6'h4;
|
|
end else begin
|
|
o_dat <= { 3'b110, i_word[31] };
|
o_dat <= { 3'b110, i_word[31] };
|
r_word <= { i_word[30:0], 1'b0 };
|
|
spi_len<= { 1'b0, i_len, 3'b000 } + 6'h8
|
|
- 6'h1;
|
|
end
|
|
|
|
// Read a bit upon any transition
|
|
o_valid <= 1'b1;
|
|
if (~o_mod[1])
|
|
begin
|
|
r_input <= { r_input[29:0], i_miso };
|
|
o_word <= { r_input[30:0], i_miso };
|
|
end else if (o_mod[1])
|
|
begin
|
|
r_input <= { r_input[26:0], i_dat };
|
|
o_word <= { r_input[27:0], i_dat };
|
|
end
|
|
end else begin
|
end else begin
|
o_sck <= 1'b1;
|
o_sck <= 1'b1;
|
state <= (i_hold)?`QSPI_HOLDING : `QSPI_STOP;
|
state <= (i_hold)?`QSPI_HOLDING : `QSPI_STOP;
|
o_busy <= (~i_hold);
|
o_busy <= (~i_hold);
|
|
end
|
|
|
// Read a bit upon any transition
|
// Read a bit upon any transition
|
o_valid <= 1'b1;
|
o_valid <= 1'b1;
|
if (~o_mod[1])
|
if (~o_mod[1])
|
begin
|
begin
|
Line 326... |
Line 312... |
end else if (o_mod[1])
|
end else if (o_mod[1])
|
begin
|
begin
|
r_input <= { r_input[26:0], i_dat };
|
r_input <= { r_input[26:0], i_dat };
|
o_word <= { r_input[27:0], i_dat };
|
o_word <= { r_input[27:0], i_dat };
|
end
|
end
|
end
|
|
end else if (state == `QSPI_HOLDING)
|
end else if (state == `QSPI_HOLDING)
|
begin
|
begin
|
// We need this state so that the o_valid signal
|
// We need this state so that the o_valid signal
|
// can get strobed with our last result. Otherwise
|
// can get strobed with our last result. Otherwise
|
// we could just sit in READY waiting for a new command.
|
// we could just sit in READY waiting for a new command.
|