Line 1... |
Line 1... |
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
//
|
//
|
// Filename: wbspiflash.v
|
// Filename: wbspiflash.v
|
//
|
//
|
// Project: Wishbone Controlled Quad SPI Flash Controller
|
// Project: A Set of Wishbone Controlled SPI Flash Controllers
|
//
|
//
|
// Purpose: Access a Quad SPI flash via a WISHBONE interface. This
|
// Purpose: Access a Quad SPI flash via a WISHBONE interface. This
|
// includes both read and write (and erase) commands to the SPI
|
// includes both read and write (and erase) commands to the SPI
|
// flash. All read/write commands are accomplished using the
|
// flash. All read/write commands are accomplished using the
|
// high speed (4-bit) interface. Further, the device will be
|
// high speed (4-bit) interface. Further, the device will be
|
Line 27... |
Line 27... |
// Creator: Dan Gisselquist, Ph.D.
|
// Creator: Dan Gisselquist, Ph.D.
|
// Gisselquist Technology, LLC
|
// Gisselquist Technology, LLC
|
//
|
//
|
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
//
|
//
|
// Copyright (C) 2015-2017, Gisselquist Technology, LLC
|
// Copyright (C) 2015-2019, Gisselquist Technology, LLC
|
//
|
//
|
// This program is free software (firmware): you can redistribute it and/or
|
// This file is part of the set of Wishbone controlled SPI flash controllers
|
// modify it under the terms of the GNU General Public License as published
|
// project
|
// by the Free Software Foundation, either version 3 of the License, or (at
|
//
|
// your option) any later version.
|
// The Wishbone SPI flash controller project is free software (firmware):
|
//
|
// you can redistribute it and/or modify it under the terms of the GNU Lesser
|
// This program is distributed in the hope that it will be useful, but WITHOUT
|
// General Public License as published by the Free Software Foundation, either
|
// ANY WARRANTY; without even the implied warranty of MERCHANTIBILITY or
|
// version 3 of the License, or (at your option) any later version.
|
// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
//
|
// for more details.
|
// The Wishbone SPI flash controller project is distributed in the hope
|
//
|
// that it will be useful, but WITHOUT ANY WARRANTY; without even the implied
|
// You should have received a copy of the GNU General Public License along
|
// warranty of MERCHANTIBILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
// with this program. (It's in the $(ROOT)/doc directory. Run make with no
|
// GNU Lesser General Public License for more details.
|
// target there if the PDF file isn't present.) If not, see
|
//
|
|
// You should have received a copy of the GNU Lesser General Public License
|
|
// along 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
|
// <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: LGPL, v3, as defined and found on www.gnu.org,
|
// http://www.gnu.org/licenses/gpl.html
|
// http://www.gnu.org/licenses/lgpl.html
|
//
|
//
|
//
|
//
|
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
//
|
//
|
//
|
//
|
`include "flashconfig.v"
|
//
|
`default_nettype none
|
`default_nettype none
|
//
|
//
|
`define WBQSPI_RESET 5'd0
|
`define WBQSPI_RESET 5'd0
|
`define WBQSPI_RESET_QUADMODE 5'd1
|
`define WBQSPI_RESET_QUADMODE 5'd1
|
`define WBQSPI_IDLE 5'd2
|
`define WBQSPI_IDLE 5'd2
|
Line 72... |
Line 75... |
`define WBQSPI_READ_STATUS 5'd13
|
`define WBQSPI_READ_STATUS 5'd13
|
`define WBQSPI_READ_CONFIG 5'd14
|
`define WBQSPI_READ_CONFIG 5'd14
|
`define WBQSPI_WAIT_TIL_IDLE 5'd15
|
`define WBQSPI_WAIT_TIL_IDLE 5'd15
|
//
|
//
|
//
|
//
|
`ifndef READ_ONLY
|
|
//
|
|
`define WBQSPI_WAIT_WIP_CLEAR 5'd16
|
`define WBQSPI_WAIT_WIP_CLEAR 5'd16
|
`define WBQSPI_CHECK_WIP_CLEAR 5'd17
|
`define WBQSPI_CHECK_WIP_CLEAR 5'd17
|
`define WBQSPI_CHECK_WIP_DONE 5'd18
|
`define WBQSPI_CHECK_WIP_DONE 5'd18
|
`define WBQSPI_WEN 5'd19
|
`define WBQSPI_WEN 5'd19
|
`define WBQSPI_PP 5'd20 // Program page
|
`define WBQSPI_PP 5'd20 // Program page
|
Line 90... |
Line 91... |
`define WBQSPI_ERASE_CMD 5'd27
|
`define WBQSPI_ERASE_CMD 5'd27
|
`define WBQSPI_ERASE_BLOCK 5'd28
|
`define WBQSPI_ERASE_BLOCK 5'd28
|
`define WBQSPI_CLEAR_STATUS 5'd29
|
`define WBQSPI_CLEAR_STATUS 5'd29
|
`define WBQSPI_IDLE_CHECK_WIP 5'd30
|
`define WBQSPI_IDLE_CHECK_WIP 5'd30
|
//
|
//
|
`endif
|
|
|
|
module wbqspiflash(i_clk,
|
module wbqspiflash(i_clk,
|
// Internal wishbone connections
|
// Internal wishbone connections
|
i_wb_cyc, i_wb_data_stb, i_wb_ctrl_stb, i_wb_we,
|
i_wb_cyc, i_wb_data_stb, i_wb_ctrl_stb, i_wb_we,
|
i_wb_addr, i_wb_data,
|
i_wb_addr, i_wb_data,
|
// Wishbone return values
|
// Wishbone return values
|
o_wb_ack, o_wb_stall, o_wb_data,
|
o_wb_ack, o_wb_stall, o_wb_data,
|
// Quad Spi connections to the external device
|
// Quad Spi connections to the external device
|
o_qspi_sck, o_qspi_cs_n, o_qspi_mod, o_qspi_dat, i_qspi_dat,
|
o_qspi_sck, o_qspi_cs_n, o_qspi_mod, o_qspi_dat, i_qspi_dat,
|
o_interrupt);
|
o_interrupt);
|
parameter ADDRESS_WIDTH=22;
|
parameter ADDRESS_WIDTH=22;
|
|
parameter [0:0] OPT_READ_ONLY = 1'b0;
|
localparam AW = ADDRESS_WIDTH-2;
|
localparam AW = ADDRESS_WIDTH-2;
|
input wire i_clk;
|
input wire i_clk;
|
// Wishbone, inputs first
|
// Wishbone, inputs first
|
input wire i_wb_cyc, i_wb_data_stb, i_wb_ctrl_stb, i_wb_we;
|
input wire i_wb_cyc, i_wb_data_stb, i_wb_ctrl_stb, i_wb_we;
|
input wire [(AW-1):0] i_wb_addr;
|
input wire [(AW-1):0] i_wb_addr;
|
Line 249... |
Line 249... |
o_wb_stall <= 1'b0;
|
o_wb_stall <= 1'b0;
|
o_wb_ack <= 1'b0;
|
o_wb_ack <= 1'b0;
|
spif_cmd <= i_wb_we;
|
spif_cmd <= i_wb_we;
|
spif_addr <= i_wb_addr;
|
spif_addr <= i_wb_addr;
|
spif_data <= i_wb_data;
|
spif_data <= i_wb_data;
|
spif_ctrl <= (i_wb_ctrl_stb)&&(~i_wb_data_stb);
|
spif_ctrl <= (i_wb_ctrl_stb)&&(!i_wb_data_stb);
|
spif_req <= (i_wb_ctrl_stb)||(i_wb_data_stb);
|
spif_req <= (i_wb_ctrl_stb)||(i_wb_data_stb);
|
spi_wr <= 1'b0; // Keep the port idle, unless told otherwise
|
spi_wr <= 1'b0; // Keep the port idle, unless told otherwise
|
spi_hold <= 1'b0;
|
spi_hold <= 1'b0;
|
spi_spd <= 1'b0;
|
spi_spd <= 1'b0;
|
spi_dir <= 1'b0; // Write (for now, 'cause of cmd)
|
spi_dir <= 1'b0; // Write (for now, 'cause of cmd)
|
// Data register access
|
// Data register access
|
if (i_wb_data_stb)
|
if (i_wb_data_stb)
|
begin
|
begin
|
|
|
if (i_wb_we) // Request to write a page
|
if ((OPT_READ_ONLY)&&(i_wb_we)) // Write request
|
begin
|
begin
|
`ifdef READ_ONLY
|
|
o_wb_ack <= 1'b1;
|
o_wb_ack <= 1'b1;
|
o_wb_stall <= 1'b0;
|
o_wb_stall <= 1'b0;
|
end else
|
end else if (i_wb_we) // Request to write a page
|
`else
|
begin
|
if((~write_protect)&&(~write_in_progress))
|
if((!write_protect)&&(!write_in_progress))
|
begin // 00
|
begin // 00
|
spi_wr <= 1'b1;
|
spi_wr <= 1'b1;
|
spi_len <= 2'b00; // 8 bits
|
spi_len <= 2'b00; // 8 bits
|
// Send a write enable command
|
// Send a write enable command
|
spi_in <= { 8'h06, 24'h00 };
|
spi_in <= { 8'h06, 24'h00 };
|
Line 289... |
Line 288... |
// for it to complete
|
// for it to complete
|
state <= `WBQSPI_WAIT_WIP_CLEAR;
|
state <= `WBQSPI_WAIT_WIP_CLEAR;
|
o_wb_ack <= 1'b0;
|
o_wb_ack <= 1'b0;
|
o_wb_stall <= 1'b1;
|
o_wb_stall <= 1'b1;
|
end
|
end
|
end else if (~write_in_progress)
|
end else if (!write_in_progress)
|
`endif
|
|
begin // Read access, normal mode(s)
|
begin // Read access, normal mode(s)
|
o_wb_ack <= 1'b0;
|
o_wb_ack <= 1'b0;
|
o_wb_stall <= 1'b1;
|
o_wb_stall <= 1'b1;
|
spi_wr <= 1'b1; // Write cmd to device
|
spi_wr <= 1'b1; // Write cmd to device
|
if (quad_mode_enabled)
|
if (quad_mode_enabled)
|
Line 305... |
Line 303... |
end else begin
|
end else begin
|
spi_in <= { 8'h0b, w_wb_addr };
|
spi_in <= { 8'h0b, w_wb_addr };
|
state <= `WBQSPI_RD_DUMMY;
|
state <= `WBQSPI_RD_DUMMY;
|
spi_len <= 2'b11; // cmd+addr,32bits
|
spi_len <= 2'b11; // cmd+addr,32bits
|
end
|
end
|
`ifndef READ_ONLY
|
end else if (!OPT_READ_ONLY) begin
|
end else begin
|
|
// A write is in progress ... need to stall
|
// A write is in progress ... need to stall
|
// the bus until the write is complete.
|
// the bus until the write is complete.
|
state <= `WBQSPI_WAIT_WIP_CLEAR;
|
state <= `WBQSPI_WAIT_WIP_CLEAR;
|
o_wb_ack <= 1'b0;
|
o_wb_ack <= 1'b0;
|
o_wb_stall <= 1'b1;
|
o_wb_stall <= 1'b1;
|
`endif
|
|
end
|
end
|
end else if ((i_wb_ctrl_stb)&&(i_wb_we))
|
end else if ((OPT_READ_ONLY)&&(i_wb_ctrl_stb)&&(i_wb_we))
|
begin
|
begin
|
`ifdef READ_ONLY
|
|
o_wb_ack <= 1'b1;
|
o_wb_ack <= 1'b1;
|
o_wb_stall <= 1'b0;
|
o_wb_stall <= 1'b0;
|
`else
|
end else if ((i_wb_ctrl_stb)&&(i_wb_we))
|
|
begin
|
o_wb_stall <= 1'b1;
|
o_wb_stall <= 1'b1;
|
case(i_wb_addr[1:0])
|
case(i_wb_addr[1:0])
|
2'b00: begin // Erase command register
|
2'b00: begin // Erase command register
|
write_protect <= !i_wb_data[28];
|
write_protect <= !i_wb_data[28];
|
o_wb_stall <= 1'b0;
|
o_wb_stall <= 1'b0;
|
Line 333... |
Line 329... |
// Command an erase--ack it immediately
|
// Command an erase--ack it immediately
|
|
|
o_wb_ack <= 1'b1;
|
o_wb_ack <= 1'b1;
|
o_wb_stall <= 1'b0;
|
o_wb_stall <= 1'b0;
|
|
|
if ((i_wb_data[31])&&(~write_protect))
|
if ((i_wb_data[31])&&(!write_protect))
|
begin
|
begin
|
spi_wr <= 1'b1;
|
spi_wr <= 1'b1;
|
spi_len <= 2'b00;
|
spi_len <= 2'b00;
|
// Send a write enable command
|
// Send a write enable command
|
spi_in <= { 8'h06, 24'h00 };
|
spi_in <= { 8'h06, 24'h00 };
|
Line 347... |
Line 343... |
end else if (i_wb_data[31])
|
end else if (i_wb_data[31])
|
begin
|
begin
|
state <= `WBQSPI_WAIT_WIP_CLEAR;
|
state <= `WBQSPI_WAIT_WIP_CLEAR;
|
o_wb_ack <= 1'b1;
|
o_wb_ack <= 1'b1;
|
o_wb_stall <= 1'b1;
|
o_wb_stall <= 1'b1;
|
end else
|
end else begin
|
o_wb_ack <= 1'b1;
|
o_wb_ack <= 1'b1;
|
o_wb_stall <= 1'b0;
|
o_wb_stall <= 1'b0;
|
end
|
end end
|
2'b01: begin
|
2'b01: begin
|
// Write the configuration register
|
// Write the configuration register
|
o_wb_ack <= 1'b1;
|
o_wb_ack <= 1'b1;
|
o_wb_stall <= 1'b1;
|
o_wb_stall <= 1'b1;
|
|
|
Line 379... |
Line 375... |
2'b11: begin // Write the ID register??? makes no sense
|
2'b11: begin // Write the ID register??? makes no sense
|
o_wb_ack <= 1'b1;
|
o_wb_ack <= 1'b1;
|
o_wb_stall <= 1'b0;
|
o_wb_stall <= 1'b0;
|
end
|
end
|
endcase
|
endcase
|
`endif
|
|
end else if (i_wb_ctrl_stb) // &&(!i_wb_we))
|
end else if (i_wb_ctrl_stb) // &&(!i_wb_we))
|
begin
|
begin
|
case(i_wb_addr[1:0])
|
case(i_wb_addr[1:0])
|
2'b00: begin // Read local register
|
2'b00: begin // Read local register
|
if (write_in_progress) // Read status
|
if (write_in_progress) // Read status
|
Line 431... |
Line 426... |
|
|
o_wb_ack <= 1'b0;
|
o_wb_ack <= 1'b0;
|
o_wb_stall <= 1'b1;
|
o_wb_stall <= 1'b1;
|
end
|
end
|
endcase
|
endcase
|
`ifndef READ_ONLY
|
end else if ((!OPT_READ_ONLY)&&(!i_wb_cyc)&&(write_in_progress))
|
end else if ((~i_wb_cyc)&&(write_in_progress))
|
|
begin
|
begin
|
state <= `WBQSPI_IDLE_CHECK_WIP;
|
state <= `WBQSPI_IDLE_CHECK_WIP;
|
spi_wr <= 1'b1;
|
spi_wr <= 1'b1;
|
spi_len <= 2'b01; // 8 bits out, 8 bits in
|
spi_len <= 2'b01; // 8 bits out, 8 bits in
|
spi_in <= { 8'h05, 24'h00};
|
spi_in <= { 8'h05, 24'h00};
|
|
|
o_wb_ack <= 1'b0;
|
o_wb_ack <= 1'b0;
|
o_wb_stall <= 1'b1;
|
o_wb_stall <= 1'b1;
|
`endif
|
|
end
|
end
|
end else if (state == `WBQSPI_RDIDLE)
|
end else if (state == `WBQSPI_RDIDLE)
|
begin
|
begin
|
spi_wr <= 1'b0;
|
spi_wr <= 1'b0;
|
o_wb_stall <= 1'b0;
|
o_wb_stall <= 1'b0;
|
o_wb_ack <= 1'b0;
|
o_wb_ack <= 1'b0;
|
spif_cmd <= i_wb_we;
|
spif_cmd <= i_wb_we;
|
spif_addr <= i_wb_addr;
|
spif_addr <= i_wb_addr;
|
spif_data <= i_wb_data;
|
spif_data <= i_wb_data;
|
spif_ctrl <= (i_wb_ctrl_stb)&&(~i_wb_data_stb);
|
spif_ctrl <= (i_wb_ctrl_stb)&&(!i_wb_data_stb);
|
spif_req <= (i_wb_ctrl_stb)||(i_wb_data_stb);
|
spif_req <= (i_wb_ctrl_stb)||(i_wb_data_stb);
|
spi_hold <= 1'b0;
|
spi_hold <= 1'b0;
|
spi_spd<= 1'b1;
|
spi_spd<= 1'b1;
|
spi_dir <= 1'b0; // Write (for now)
|
spi_dir <= 1'b0; // Write (for now)
|
if ((i_wb_data_stb)&&(!i_wb_we))
|
if ((i_wb_data_stb)&&(!i_wb_we))
|
Line 499... |
Line 492... |
spi_wr <= 1'b0; // Keep the port idle, unless told otherwise
|
spi_wr <= 1'b0; // Keep the port idle, unless told otherwise
|
spi_hold <= 1'b0;
|
spi_hold <= 1'b0;
|
spi_spd <= 1'b0;
|
spi_spd <= 1'b0;
|
spi_dir <= 1'b0;
|
spi_dir <= 1'b0;
|
spif_req<= (spif_req) && (i_wb_cyc);
|
spif_req<= (spif_req) && (i_wb_cyc);
|
if ((~spi_busy)&&(o_qspi_cs_n)&&(~spi_wr)) // only in full idle ...
|
if ((!spi_busy)&&(o_qspi_cs_n)&&(!spi_wr)) // only in full idle ...
|
begin
|
begin
|
// Data register access
|
// Data register access
|
if (~spif_ctrl)
|
if (!spif_ctrl)
|
begin
|
begin
|
if (spif_cmd) // Request to write a page
|
if ((OPT_READ_ONLY)&&(spif_cmd)) // Request to write a page
|
begin
|
begin
|
`ifdef READ_ONLY
|
|
o_wb_ack <= spif_req;
|
o_wb_ack <= spif_req;
|
o_wb_stall <= 1'b0;
|
o_wb_stall <= 1'b0;
|
state <= `WBQSPI_IDLE;
|
state <= `WBQSPI_IDLE;
|
`else
|
end else if (spif_cmd)
|
if((~write_protect)&&(~write_in_progress))
|
begin
|
|
if((!write_protect)&&(!write_in_progress))
|
begin // 00
|
begin // 00
|
spi_wr <= 1'b1;
|
spi_wr <= 1'b1;
|
spi_len <= 2'b00; // 8 bits
|
spi_len <= 2'b00; // 8 bits
|
// Send a write enable command
|
// Send a write enable command
|
spi_in <= { 8'h06, 24'h00 };
|
spi_in <= { 8'h06, 24'h00 };
|
Line 535... |
Line 528... |
// for it to complete
|
// for it to complete
|
state <= `WBQSPI_WAIT_WIP_CLEAR;
|
state <= `WBQSPI_WAIT_WIP_CLEAR;
|
o_wb_ack <= 1'b0;
|
o_wb_ack <= 1'b0;
|
o_wb_stall <= 1'b1;
|
o_wb_stall <= 1'b1;
|
end
|
end
|
// end else if (~write_in_progress) // always true
|
// end else if (!write_in_progress) // always true
|
// but ... we wouldn't get here on a normal read access
|
// but ... we wouldn't get here on a normal read access
|
`endif
|
|
end else begin
|
end else begin
|
// Something's wrong, we should never
|
// Something's wrong, we should never
|
// get here
|
// get here
|
// Attempt to go to idle to recover
|
// Attempt to go to idle to recover
|
state <= `WBQSPI_IDLE;
|
state <= `WBQSPI_IDLE;
|
end
|
end
|
end else if ((spif_ctrl)&&(spif_cmd))
|
end else if ((OPT_READ_ONLY)&&(spif_ctrl)&&(spif_cmd))
|
begin
|
begin
|
`ifdef READ_ONLY
|
|
o_wb_ack <= spif_req;
|
o_wb_ack <= spif_req;
|
o_wb_stall <= 1'b0;
|
o_wb_stall <= 1'b0;
|
state <= `WBQSPI_IDLE;
|
state <= `WBQSPI_IDLE;
|
`else
|
end else if ((spif_ctrl)&&(spif_cmd)) begin
|
o_wb_stall <= 1'b1;
|
o_wb_stall <= 1'b1;
|
case(spif_addr[1:0])
|
case(spif_addr[1:0])
|
2'b00: begin // Erase command register
|
2'b00: begin // Erase command register
|
o_wb_ack <= spif_req;
|
o_wb_ack <= spif_req;
|
o_wb_stall <= 1'b0;
|
o_wb_stall <= 1'b0;
|
Line 602... |
Line 593... |
o_wb_ack <= spif_req;
|
o_wb_ack <= spif_req;
|
o_wb_stall <= 1'b0;
|
o_wb_stall <= 1'b0;
|
state <= `WBQSPI_IDLE;
|
state <= `WBQSPI_IDLE;
|
end
|
end
|
endcase
|
endcase
|
`endif
|
end else begin // on (!spif_we)
|
end else begin // on (~spif_we)
|
|
case(spif_addr[1:0])
|
case(spif_addr[1:0])
|
2'b00: begin // Read local register
|
2'b00: begin // Read local register
|
// Nonsense case--would've done this
|
// Nonsense case--would've done this
|
// already
|
// already
|
state <= `WBQSPI_IDLE;
|
state <= `WBQSPI_IDLE;
|
Line 660... |
Line 650... |
spi_len <= 2'b00; // Read 8 bits
|
spi_len <= 2'b00; // Read 8 bits
|
spi_spd <= 1'b0;
|
spi_spd <= 1'b0;
|
spi_hold <= 1'b0;
|
spi_hold <= 1'b0;
|
spif_req<= (spif_req) && (i_wb_cyc);
|
spif_req<= (spif_req) && (i_wb_cyc);
|
|
|
if ((~spi_busy)&&(~o_qspi_cs_n))
|
if ((!spi_busy)&&(!o_qspi_cs_n))
|
// Our command was accepted
|
// Our command was accepted
|
state <= `WBQSPI_READ_CMD;
|
state <= `WBQSPI_READ_CMD;
|
end else if (state == `WBQSPI_QRD_ADDRESS)
|
end else if (state == `WBQSPI_QRD_ADDRESS)
|
begin
|
begin
|
// We come in here immediately upon issuing a QRD read
|
// We come in here immediately upon issuing a QRD read
|
Line 679... |
Line 669... |
spi_spd <= 1'b1;
|
spi_spd <= 1'b1;
|
spi_dir <= 1'b0; // Still writing
|
spi_dir <= 1'b0; // Still writing
|
spi_hold <= 1'b0;
|
spi_hold <= 1'b0;
|
spif_req<= (spif_req) && (i_wb_cyc);
|
spif_req<= (spif_req) && (i_wb_cyc);
|
|
|
if ((~spi_busy)&&(spi_spd))
|
if ((!spi_busy)&&(spi_spd))
|
// Our command was accepted
|
// Our command was accepted
|
state <= `WBQSPI_QRD_DUMMY;
|
state <= `WBQSPI_QRD_DUMMY;
|
end else if (state == `WBQSPI_QRD_DUMMY)
|
end else if (state == `WBQSPI_QRD_DUMMY)
|
begin
|
begin
|
o_wb_ack <= 1'b0;
|
o_wb_ack <= 1'b0;
|
Line 695... |
Line 685... |
spi_spd <= 1'b1;
|
spi_spd <= 1'b1;
|
spi_dir <= 1'b0; // Still writing
|
spi_dir <= 1'b0; // Still writing
|
spi_hold <= 1'b0;
|
spi_hold <= 1'b0;
|
spif_req<= (spif_req) && (i_wb_cyc);
|
spif_req<= (spif_req) && (i_wb_cyc);
|
|
|
if ((~spi_busy)&&(spi_in[31:28] == 4'ha))
|
if ((!spi_busy)&&(spi_in[31:28] == 4'ha))
|
// Our command was accepted
|
// Our command was accepted
|
state <= `WBQSPI_READ_CMD;
|
state <= `WBQSPI_READ_CMD;
|
end else if (state == `WBQSPI_READ_CMD)
|
end else if (state == `WBQSPI_READ_CMD)
|
begin // Issue our first command to read 32 bits.
|
begin // Issue our first command to read 32 bits.
|
o_wb_ack <= 1'b0;
|
o_wb_ack <= 1'b0;
|
Line 714... |
Line 704... |
if ((spi_valid)&&(spi_len == 2'b11))
|
if ((spi_valid)&&(spi_len == 2'b11))
|
state <= `WBQSPI_READ_DATA;
|
state <= `WBQSPI_READ_DATA;
|
end else if (state == `WBQSPI_READ_DATA)
|
end else if (state == `WBQSPI_READ_DATA)
|
begin
|
begin
|
// Pipelined read support
|
// Pipelined read support
|
spi_wr <=((i_wb_data_stb)&&(~i_wb_we)&&(i_wb_addr== (spif_addr+1)));
|
spi_wr <=((i_wb_data_stb)&&(!i_wb_we)&&(i_wb_addr== (spif_addr+1)))&&(spif_req);
|
spi_in <= 32'h00;
|
spi_in <= 32'h00;
|
spi_len <= 2'b11;
|
spi_len <= 2'b11;
|
// Don't adjust the speed here, it was set in the setup
|
// Don't adjust the speed here, it was set in the setup
|
spi_dir <= 1'b1; // Now we get to read
|
spi_dir <= 1'b1; // Now we get to read
|
// Don't let the device go to idle until the bus cycle ends.
|
// Don't let the device go to idle until the bus cycle ends.
|
Line 733... |
Line 723... |
// anything on the bus--one for us to notice it and pull
|
// anything on the bus--one for us to notice it and pull
|
// our head out of the sand, and a second for whoever
|
// our head out of the sand, and a second for whoever
|
// owns the bus to realize their command went through.
|
// owns the bus to realize their command went through.
|
spi_hold <= 1'b1;
|
spi_hold <= 1'b1;
|
spif_req<= (spif_req) && (i_wb_cyc);
|
spif_req<= (spif_req) && (i_wb_cyc);
|
if ((spi_valid)&&(~spi_in[31]))
|
if ((spi_valid)&&(!spi_in[31]))
|
begin // Single pulse acknowledge and write data out
|
begin // Single pulse acknowledge and write data out
|
o_wb_ack <= spif_req;
|
o_wb_ack <= spif_req;
|
o_wb_stall <= (~spi_wr);
|
o_wb_stall <= (!spi_wr);
|
// adjust endian-ness to match the PC
|
// adjust endian-ness to match the PC
|
o_wb_data <= spi_out;
|
o_wb_data <= spi_out;
|
state <= (spi_wr)?`WBQSPI_READ_DATA
|
state <= (spi_wr)?`WBQSPI_READ_DATA
|
: ((spi_spd) ? `WBQSPI_WAIT_TIL_RDIDLE : `WBQSPI_WAIT_TIL_IDLE);
|
: ((spi_spd) ? `WBQSPI_WAIT_TIL_RDIDLE : `WBQSPI_WAIT_TIL_IDLE);
|
spif_req <= spi_wr;
|
spif_req <= spi_wr;
|
spi_hold <= (~spi_wr);
|
spi_hold <= (!spi_wr);
|
if (spi_wr)
|
if (spi_wr)
|
spif_addr <= i_wb_addr;
|
spif_addr <= i_wb_addr;
|
end else if (~i_wb_cyc)
|
end else if ((!spif_req)||(!i_wb_cyc))
|
begin // FAIL SAFE: If the bus cycle ends, forget why we're
|
begin // FAIL SAFE: If the bus cycle ends, forget why we're
|
// here, just go back to idle
|
// here, just go back to idle
|
state <= ((spi_spd) ? `WBQSPI_WAIT_TIL_RDIDLE : `WBQSPI_WAIT_TIL_IDLE);
|
state <= ((spi_spd) ? `WBQSPI_WAIT_TIL_RDIDLE : `WBQSPI_WAIT_TIL_IDLE);
|
spi_hold <= 1'b0;
|
spi_hold <= 1'b0;
|
o_wb_ack <= 1'b0;
|
o_wb_ack <= 1'b0;
|
Line 763... |
Line 753... |
spi_wr <= 1'b0; // idle
|
spi_wr <= 1'b0; // idle
|
spi_hold <= 1'b0;
|
spi_hold <= 1'b0;
|
o_wb_stall <= 1'b1;
|
o_wb_stall <= 1'b1;
|
o_wb_ack <= 1'b0;
|
o_wb_ack <= 1'b0;
|
spif_req <= 1'b0;
|
spif_req <= 1'b0;
|
if ((~spi_busy)&&(o_qspi_cs_n)&&(~spi_wr)) // Wait for a full
|
if ((!spi_busy)&&(o_qspi_cs_n)&&(!spi_wr)) // Wait for a full
|
begin // clearing of the SPI port before moving on
|
begin // clearing of the SPI port before moving on
|
state <= `WBQSPI_RDIDLE;
|
state <= `WBQSPI_RDIDLE;
|
o_wb_stall <= 1'b0;
|
o_wb_stall <= 1'b0;
|
o_wb_ack <= 1'b0;// Shouldn't be acking anything here
|
o_wb_ack <= 1'b0;// Shouldn't be acking anything here
|
end
|
end
|
Line 784... |
Line 774... |
spi_in <= 32'h00; // Irrelevant
|
spi_in <= 32'h00; // Irrelevant
|
spi_spd <= 1'b0; // Slow speed
|
spi_spd <= 1'b0; // Slow speed
|
spi_dir <= 1'b1; // Reading
|
spi_dir <= 1'b1; // Reading
|
spi_hold <= 1'b0;
|
spi_hold <= 1'b0;
|
spif_req <= (spif_req) && (i_wb_cyc);
|
spif_req <= (spif_req) && (i_wb_cyc);
|
if ((~spi_busy)&&(~o_qspi_cs_n)&&(spi_len == 2'b11))
|
if ((!spi_busy)&&(!o_qspi_cs_n)&&(spi_len == 2'b11))
|
// Our command was accepted, now go read the result
|
// Our command was accepted, now go read the result
|
state <= `WBQSPI_READ_ID;
|
state <= `WBQSPI_READ_ID;
|
end else if (state == `WBQSPI_READ_ID)
|
end else if (state == `WBQSPI_READ_ID)
|
begin
|
begin
|
o_wb_ack <= 1'b0; // Assuming we're still waiting
|
o_wb_ack <= 1'b0; // Assuming we're still waiting
|
Line 805... |
Line 795... |
if((spi_valid)&&(spi_len==2'b00))
|
if((spi_valid)&&(spi_len==2'b00))
|
begin // Put the results out as soon as possible
|
begin // Put the results out as soon as possible
|
o_wb_data <= spi_out[31:0];
|
o_wb_data <= spi_out[31:0];
|
o_wb_ack <= spif_req;
|
o_wb_ack <= spif_req;
|
spif_req <= 1'b0;
|
spif_req <= 1'b0;
|
end else if ((~spi_busy)&&(o_qspi_cs_n))
|
end else if ((!spi_busy)&&(o_qspi_cs_n))
|
begin
|
begin
|
state <= `WBQSPI_IDLE;
|
state <= `WBQSPI_IDLE;
|
o_wb_stall <= 1'b0;
|
o_wb_stall <= 1'b0;
|
end
|
end
|
end else if (state == `WBQSPI_READ_STATUS)
|
end else if (state == `WBQSPI_READ_STATUS)
|
Line 837... |
Line 827... |
end else begin
|
end else begin
|
o_wb_data <= { 24'h00, spi_out[7:0] };
|
o_wb_data <= { 24'h00, spi_out[7:0] };
|
end
|
end
|
end
|
end
|
|
|
if ((~spi_busy)&&(~spi_wr))
|
if ((!spi_busy)&&(!spi_wr))
|
state <= `WBQSPI_IDLE;
|
state <= `WBQSPI_IDLE;
|
end else if (state == `WBQSPI_READ_CONFIG)
|
end else if (state == `WBQSPI_READ_CONFIG)
|
begin // We enter after the command has been given, for now just
|
begin // We enter after the command has been given, for now just
|
// read and return
|
// read and return
|
spi_wr <= 1'b0;
|
spi_wr <= 1'b0;
|
Line 854... |
Line 844... |
begin
|
begin
|
o_wb_data <= { 24'h00, spi_out[7:0] };
|
o_wb_data <= { 24'h00, spi_out[7:0] };
|
quad_mode_enabled <= spi_out[1];
|
quad_mode_enabled <= spi_out[1];
|
end
|
end
|
|
|
if ((~spi_busy)&&(~spi_wr))
|
if ((!spi_busy)&&(!spi_wr))
|
begin
|
begin
|
state <= `WBQSPI_IDLE;
|
state <= `WBQSPI_IDLE;
|
o_wb_ack <= spif_req;
|
o_wb_ack <= spif_req;
|
o_wb_stall <= 1'b0;
|
o_wb_stall <= 1'b0;
|
spif_req <= 1'b0;
|
spif_req <= 1'b0;
|
Line 866... |
Line 856... |
|
|
//
|
//
|
//
|
//
|
// Write/erase data section
|
// Write/erase data section
|
//
|
//
|
`ifndef READ_ONLY
|
end else if ((!OPT_READ_ONLY)&&(state == `WBQSPI_WAIT_WIP_CLEAR))
|
end else if (state == `WBQSPI_WAIT_WIP_CLEAR)
|
|
begin
|
begin
|
o_wb_stall <= 1'b1;
|
o_wb_stall <= 1'b1;
|
o_wb_ack <= 1'b0;
|
o_wb_ack <= 1'b0;
|
spi_wr <= 1'b0;
|
spi_wr <= 1'b0;
|
spif_req<= (spif_req) && (i_wb_cyc);
|
spif_req<= (spif_req) && (i_wb_cyc);
|
if (~spi_busy)
|
if (!spi_busy)
|
begin
|
begin
|
spi_wr <= 1'b1;
|
spi_wr <= 1'b1;
|
spi_in <= { 8'h05, 24'h0000 };
|
spi_in <= { 8'h05, 24'h0000 };
|
spi_hold <= 1'b1;
|
spi_hold <= 1'b1;
|
spi_len <= 2'b01; // 16 bits write, so we can read 8
|
spi_len <= 2'b01; // 16 bits write, so we can read 8
|
state <= `WBQSPI_CHECK_WIP_CLEAR;
|
state <= `WBQSPI_CHECK_WIP_CLEAR;
|
spi_spd <= 1'b0; // Slow speed
|
spi_spd <= 1'b0; // Slow speed
|
spi_dir <= 1'b0;
|
spi_dir <= 1'b0;
|
end
|
end
|
end else if (state == `WBQSPI_CHECK_WIP_CLEAR)
|
end else if ((!OPT_READ_ONLY)&&(state == `WBQSPI_CHECK_WIP_CLEAR))
|
begin
|
begin
|
o_wb_stall <= 1'b1;
|
o_wb_stall <= 1'b1;
|
o_wb_ack <= 1'b0;
|
o_wb_ack <= 1'b0;
|
// Repeat as often as necessary until we are clear
|
// Repeat as often as necessary until we are clear
|
spi_wr <= 1'b1;
|
spi_wr <= 1'b1;
|
Line 895... |
Line 884... |
spi_hold <= 1'b1;
|
spi_hold <= 1'b1;
|
spi_len <= 2'b00; // One byte at a time
|
spi_len <= 2'b00; // One byte at a time
|
spi_spd <= 1'b0; // Slow speed
|
spi_spd <= 1'b0; // Slow speed
|
spi_dir <= 1'b0;
|
spi_dir <= 1'b0;
|
spif_req<= (spif_req) && (i_wb_cyc);
|
spif_req<= (spif_req) && (i_wb_cyc);
|
if ((spi_valid)&&(~spi_out[0]))
|
if ((spi_valid)&&(!spi_out[0]))
|
begin
|
begin
|
state <= `WBQSPI_CHECK_WIP_DONE;
|
state <= `WBQSPI_CHECK_WIP_DONE;
|
spi_wr <= 1'b0;
|
spi_wr <= 1'b0;
|
spi_hold <= 1'b0;
|
spi_hold <= 1'b0;
|
write_in_progress <= 1'b0;
|
write_in_progress <= 1'b0;
|
last_status <= spi_out[7:0];
|
last_status <= spi_out[7:0];
|
end
|
end
|
end else if (state == `WBQSPI_CHECK_WIP_DONE)
|
end else if ((!OPT_READ_ONLY)&&(state == `WBQSPI_CHECK_WIP_DONE))
|
begin
|
begin
|
o_wb_stall <= 1'b1;
|
o_wb_stall <= 1'b1;
|
o_wb_ack <= 1'b0;
|
o_wb_ack <= 1'b0;
|
// Let's let the SPI port come back to a full idle,
|
// Let's let the SPI port come back to a full idle,
|
// and the chip select line go low before continuing
|
// and the chip select line go low before continuing
|
Line 915... |
Line 904... |
spi_len <= 2'b00;
|
spi_len <= 2'b00;
|
spi_hold <= 1'b0;
|
spi_hold <= 1'b0;
|
spi_spd <= 1'b0; // Slow speed
|
spi_spd <= 1'b0; // Slow speed
|
spi_dir <= 1'b0;
|
spi_dir <= 1'b0;
|
spif_req<= (spif_req) && (i_wb_cyc);
|
spif_req<= (spif_req) && (i_wb_cyc);
|
if ((o_qspi_cs_n)&&(~spi_busy)) // Chip select line is high, we can continue
|
if ((o_qspi_cs_n)&&(!spi_busy)) // Chip select line is high, we can continue
|
begin
|
begin
|
spi_wr <= 1'b0;
|
spi_wr <= 1'b0;
|
spi_hold <= 1'b0;
|
spi_hold <= 1'b0;
|
|
|
casez({ spif_cmd, spif_ctrl, spif_addr[1:0] })
|
casez({ spif_cmd, spif_ctrl, spif_addr[1:0] })
|
Line 961... |
Line 950... |
end
|
end
|
endcase
|
endcase
|
// spif_cmd <= i_wb_we;
|
// spif_cmd <= i_wb_we;
|
// spif_addr <= i_wb_addr;
|
// spif_addr <= i_wb_addr;
|
// spif_data <= i_wb_data;
|
// spif_data <= i_wb_data;
|
// spif_ctrl <= (i_wb_ctrl_stb)&&(~i_wb_data_stb);
|
// spif_ctrl <= (i_wb_ctrl_stb)&&(!i_wb_data_stb);
|
// spi_wr <= 1'b0; // Keep the port idle, unless told otherwise
|
// spi_wr <= 1'b0; // Keep the port idle, unless told otherwise
|
end
|
end
|
end else if (state == `WBQSPI_WEN)
|
end else if ((!OPT_READ_ONLY)&&(state == `WBQSPI_WEN))
|
begin // We came here after issuing a write enable command
|
begin // We came here after issuing a write enable command
|
spi_wr <= 1'b0;
|
spi_wr <= 1'b0;
|
o_wb_ack <= 1'b0;
|
o_wb_ack <= 1'b0;
|
o_wb_stall <= 1'b1;
|
o_wb_stall <= 1'b1;
|
spif_req<= (spif_req) && (i_wb_cyc);
|
spif_req<= (spif_req) && (i_wb_cyc);
|
if ((~spi_busy)&&(o_qspi_cs_n)&&(~spi_wr)) // Let's come to a full stop
|
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 <= (quad_mode_enabled)?`WBQSPI_QPP:`WBQSPI_PP;
|
// state <= `WBQSPI_PP;
|
// state <= `WBQSPI_PP;
|
end else if (state == `WBQSPI_PP)
|
end else if ((!OPT_READ_ONLY)&&(state == `WBQSPI_PP))
|
begin // We come here under a full stop / full port idle mode
|
begin // We come here under a full stop / full port idle mode
|
// Issue our command immediately
|
// Issue our command immediately
|
spi_wr <= 1'b1;
|
spi_wr <= 1'b1;
|
spi_in <= { 8'h02, w_spif_addr };
|
spi_in <= { 8'h02, w_spif_addr };
|
spi_len <= 2'b11;
|
spi_len <= 2'b11;
|
Line 989... |
Line 978... |
// Once we get busy, move on
|
// Once we get busy, move on
|
if (spi_busy)
|
if (spi_busy)
|
state <= `WBQSPI_WR_DATA;
|
state <= `WBQSPI_WR_DATA;
|
if (spif_sector == erased_sector)
|
if (spif_sector == erased_sector)
|
dirty_sector <= 1'b1;
|
dirty_sector <= 1'b1;
|
end else if (state == `WBQSPI_QPP)
|
end else if ((!OPT_READ_ONLY)&&(state == `WBQSPI_QPP))
|
begin // We come here under a full stop / full port idle mode
|
begin // We come here under a full stop / full port idle mode
|
// Issue our command immediately
|
// Issue our command immediately
|
spi_wr <= 1'b1;
|
spi_wr <= 1'b1;
|
spi_in <= { 8'h32, w_spif_addr };
|
spi_in <= { 8'h32, w_spif_addr };
|
spi_len <= 2'b11;
|
spi_len <= 2'b11;
|
Line 1011... |
Line 1000... |
spi_spd <= 1'b1;
|
spi_spd <= 1'b1;
|
state <= `WBQSPI_WR_DATA;
|
state <= `WBQSPI_WR_DATA;
|
end
|
end
|
if (spif_sector == erased_sector)
|
if (spif_sector == erased_sector)
|
dirty_sector <= 1'b1;
|
dirty_sector <= 1'b1;
|
end else if (state == `WBQSPI_WR_DATA)
|
end else if ((!OPT_READ_ONLY)&&(state == `WBQSPI_WR_DATA))
|
begin
|
begin
|
o_wb_stall <= 1'b1;
|
o_wb_stall <= 1'b1;
|
o_wb_ack <= 1'b0;
|
o_wb_ack <= 1'b0;
|
spi_wr <= 1'b1; // write without waiting
|
spi_wr <= 1'b1; // write without waiting
|
spi_in <= spif_data;
|
spi_in <= spif_data;
|
spi_len <= 2'b11; // Write 4 bytes
|
spi_len <= 2'b11; // Write 4 bytes
|
spi_hold <= 1'b1;
|
spi_hold <= 1'b1;
|
if (~spi_busy)
|
if (!spi_busy)
|
begin
|
begin
|
o_wb_ack <= spif_req; // Ack when command given
|
o_wb_ack <= spif_req; // Ack when command given
|
state <= `WBQSPI_WR_BUS_CYCLE;
|
state <= `WBQSPI_WR_BUS_CYCLE;
|
end
|
end
|
spif_req<= (spif_req) && (i_wb_cyc);
|
spif_req<= (spif_req) && (i_wb_cyc);
|
end else if (state == `WBQSPI_WR_BUS_CYCLE)
|
end else if ((!OPT_READ_ONLY)&&(state == `WBQSPI_WR_BUS_CYCLE))
|
begin
|
begin
|
o_wb_ack <= 1'b0; // Turn off our ack and stall flags
|
o_wb_ack <= 1'b0; // Turn off our ack and stall flags
|
o_wb_stall <= 1'b1;
|
o_wb_stall <= 1'b1;
|
spi_wr <= 1'b0;
|
spi_wr <= 1'b0;
|
spi_hold <= 1'b1;
|
spi_hold <= 1'b1;
|
write_in_progress <= 1'b1;
|
write_in_progress <= 1'b1;
|
spif_req<= (spif_req) && (i_wb_cyc);
|
spif_req<= (spif_req) && (i_wb_cyc);
|
if (~i_wb_cyc)
|
if (!i_wb_cyc)
|
begin
|
begin
|
state <= `WBQSPI_WAIT_TIL_IDLE;
|
state <= `WBQSPI_WAIT_TIL_IDLE;
|
spi_hold <= 1'b0;
|
spi_hold <= 1'b0;
|
end else if (spi_wr)
|
end else if (spi_wr)
|
begin // Give the SPI a chance to get busy on the last write
|
begin // Give the SPI a chance to get busy on the last write
|
// Do nothing here.
|
// Do nothing here.
|
end else if ((i_wb_data_stb)&&(i_wb_we)
|
end else if ((spif_req)&&(i_wb_data_stb)&&(i_wb_we)
|
&&(i_wb_addr == (spif_addr+1))
|
&&(i_wb_addr == (spif_addr+1))
|
&&(i_wb_addr[(AW-1):6]==spif_addr[(AW-1):6]))
|
&&(i_wb_addr[(AW-1):6]==spif_addr[(AW-1):6]))
|
begin
|
begin
|
spif_cmd <= 1'b1;
|
spif_cmd <= 1'b1;
|
spif_data <= i_wb_data;
|
spif_data <= i_wb_data;
|
Line 1054... |
Line 1043... |
// We'll keep the bus stalled on this request
|
// We'll keep the bus stalled on this request
|
// for a while
|
// for a while
|
state <= `WBQSPI_WR_DATA;
|
state <= `WBQSPI_WR_DATA;
|
o_wb_ack <= 1'b0;
|
o_wb_ack <= 1'b0;
|
o_wb_stall <= 1'b0;
|
o_wb_stall <= 1'b0;
|
end else if ((i_wb_data_stb|i_wb_ctrl_stb)&&(~o_wb_ack)) // Writing out of bounds
|
end else if ((i_wb_data_stb|i_wb_ctrl_stb)&&(!o_wb_ack)) // Writing out of bounds
|
begin
|
begin
|
spi_hold <= 1'b0;
|
spi_hold <= 1'b0;
|
spi_wr <= 1'b0;
|
spi_wr <= 1'b0;
|
state <= `WBQSPI_WAIT_TIL_IDLE;
|
state <= `WBQSPI_WAIT_TIL_IDLE;
|
end // Otherwise we stay here
|
end // Otherwise we stay here
|
end else if (state == `WBQSPI_WRITE_CONFIG)
|
end else if ((!OPT_READ_ONLY)&&(state == `WBQSPI_WRITE_CONFIG))
|
begin // We enter immediately after commanding a WEN
|
begin // We enter immediately after commanding a WEN
|
o_wb_ack <= 1'b0;
|
o_wb_ack <= 1'b0;
|
o_wb_stall <= 1'b1;
|
o_wb_stall <= 1'b1;
|
|
|
spi_len <= 2'b10;
|
spi_len <= 2'b10;
|
spi_in <= { 8'h01, last_status, spif_data[7:0], 8'h00 };
|
spi_in <= { 8'h01, last_status, spif_data[7:0], 8'h00 };
|
spi_wr <= 1'b0;
|
spi_wr <= 1'b0;
|
spi_hold <= 1'b0;
|
spi_hold <= 1'b0;
|
spif_req <= (spif_req) && (i_wb_cyc);
|
spif_req <= (spif_req) && (i_wb_cyc);
|
if ((~spi_busy)&&(~spi_wr))
|
if ((!spi_busy)&&(!spi_wr))
|
begin
|
begin
|
spi_wr <= 1'b1;
|
spi_wr <= 1'b1;
|
state <= `WBQSPI_WAIT_TIL_IDLE;
|
state <= `WBQSPI_WAIT_TIL_IDLE;
|
write_in_progress <= 1'b1;
|
write_in_progress <= 1'b1;
|
quad_mode_enabled <= spif_data[1];
|
quad_mode_enabled <= spif_data[1];
|
end
|
end
|
end else if (state == `WBQSPI_WRITE_STATUS)
|
end else if ((!OPT_READ_ONLY)&&(state == `WBQSPI_WRITE_STATUS))
|
begin // We enter immediately after commanding a WEN
|
begin // We enter immediately after commanding a WEN
|
o_wb_ack <= 1'b0;
|
o_wb_ack <= 1'b0;
|
o_wb_stall <= 1'b1;
|
o_wb_stall <= 1'b1;
|
|
|
spi_len <= 2'b01;
|
spi_len <= 2'b01;
|
spi_in <= { 8'h01, spif_data[7:0], 16'h00 };
|
spi_in <= { 8'h01, spif_data[7:0], 16'h00 };
|
// last_status <= i_wb_data[7:0]; // We'll read this in a moment
|
// last_status <= i_wb_data[7:0]; // We'll read this in a moment
|
spi_wr <= 1'b0;
|
spi_wr <= 1'b0;
|
spi_hold <= 1'b0;
|
spi_hold <= 1'b0;
|
spif_req <= (spif_req) && (i_wb_cyc);
|
spif_req <= (spif_req) && (i_wb_cyc);
|
if ((~spi_busy)&&(~spi_wr))
|
if ((!spi_busy)&&(!spi_wr))
|
begin
|
begin
|
spi_wr <= 1'b1;
|
spi_wr <= 1'b1;
|
last_status <= spif_data[7:0];
|
last_status <= spif_data[7:0];
|
write_in_progress <= 1'b1;
|
write_in_progress <= 1'b1;
|
if(((last_status[6])||(last_status[5]))
|
if(((last_status[6])||(last_status[5]))
|
&&((~spif_data[6])&&(~spif_data[5])))
|
&&((!spif_data[6])&&(!spif_data[5])))
|
state <= `WBQSPI_CLEAR_STATUS;
|
state <= `WBQSPI_CLEAR_STATUS;
|
else
|
else
|
state <= `WBQSPI_WAIT_TIL_IDLE;
|
state <= `WBQSPI_WAIT_TIL_IDLE;
|
end
|
end
|
end else if (state == `WBQSPI_ERASE_CMD)
|
end else if ((!OPT_READ_ONLY)&&(state == `WBQSPI_ERASE_CMD))
|
begin // Know that WIP is clear on entry, WEN has just been commanded
|
begin // Know that WIP is clear on entry, WEN has just been commanded
|
spi_wr <= 1'b0;
|
spi_wr <= 1'b0;
|
o_wb_ack <= 1'b0;
|
o_wb_ack <= 1'b0;
|
o_wb_stall <= 1'b1;
|
o_wb_stall <= 1'b1;
|
spi_hold <= 1'b0;
|
spi_hold <= 1'b0;
|
Line 1120... |
Line 1109... |
erased_sector <= spif_data[(AW-1):14];
|
erased_sector <= spif_data[(AW-1):14];
|
// and marking this erase sector as no longer dirty
|
// and marking this erase sector as no longer dirty
|
dirty_sector <= 1'b0;
|
dirty_sector <= 1'b0;
|
|
|
// Wait for a full stop before issuing this command
|
// Wait for a full stop before issuing this command
|
if ((~spi_busy)&&(~spi_wr)&&(o_qspi_cs_n))
|
if ((!spi_busy)&&(!spi_wr)&&(o_qspi_cs_n))
|
begin // When our command is accepted, move to the next state
|
begin // When our command is accepted, move to the next state
|
spi_wr <= 1'b1;
|
spi_wr <= 1'b1;
|
state <= `WBQSPI_ERASE_BLOCK;
|
state <= `WBQSPI_ERASE_BLOCK;
|
end
|
end
|
end else if (state == `WBQSPI_ERASE_BLOCK)
|
end else if ((!OPT_READ_ONLY)&&(state == `WBQSPI_ERASE_BLOCK))
|
begin
|
begin
|
spi_wr <= 1'b0;
|
spi_wr <= 1'b0;
|
spi_hold <= 1'b0;
|
spi_hold <= 1'b0;
|
o_wb_stall <= 1'b1;
|
o_wb_stall <= 1'b1;
|
o_wb_ack <= 1'b0;
|
o_wb_ack <= 1'b0;
|
spif_req <= (spif_req) && (i_wb_cyc);
|
spif_req <= (spif_req) && (i_wb_cyc);
|
// When the port clears, we can head back to idle
|
// When the port clears, we can head back to idle
|
// No ack necessary, we ackd before getting
|
// No ack necessary, we ackd before getting
|
// here.
|
// here.
|
if ((~spi_busy)&&(~spi_wr))
|
if ((!spi_busy)&&(!spi_wr))
|
state <= `WBQSPI_IDLE;
|
state <= `WBQSPI_IDLE;
|
end else if (state == `WBQSPI_CLEAR_STATUS)
|
end else if ((!OPT_READ_ONLY)&&(state == `WBQSPI_CLEAR_STATUS))
|
begin // Issue a clear status command
|
begin // Issue a clear status command
|
spi_wr <= 1'b1;
|
spi_wr <= 1'b1;
|
spi_hold <= 1'b0;
|
spi_hold <= 1'b0;
|
spi_len <= 2'b00; // 8 bit command
|
spi_len <= 2'b00; // 8 bit command
|
spi_in <= { 8'h30, 24'h00 };
|
spi_in <= { 8'h30, 24'h00 };
|
spi_spd <= 1'b0;
|
spi_spd <= 1'b0;
|
spi_dir <= 1'b0;
|
spi_dir <= 1'b0;
|
last_status[6:5] <= 2'b00;
|
last_status[6:5] <= 2'b00;
|
spif_req <= (spif_req) && (i_wb_cyc);
|
spif_req <= (spif_req) && (i_wb_cyc);
|
if ((spi_wr)&&(~spi_busy))
|
if ((spi_wr)&&(!spi_busy))
|
state <= `WBQSPI_WAIT_TIL_IDLE;
|
state <= `WBQSPI_WAIT_TIL_IDLE;
|
end else if (state == `WBQSPI_IDLE_CHECK_WIP)
|
end else if ((!OPT_READ_ONLY)&&(state == `WBQSPI_IDLE_CHECK_WIP))
|
begin // We are now in read status register mode
|
begin // We are now in read status register mode
|
|
|
// No bus commands have (yet) been given
|
// No bus commands have (yet) been given
|
o_wb_stall <= 1'b1;
|
o_wb_stall <= 1'b1;
|
o_wb_ack <= 1'b0;
|
o_wb_ack <= 1'b0;
|
spif_req <= (spif_req) && (i_wb_cyc);
|
spif_req <= (spif_req) && (i_wb_cyc);
|
|
|
// Stay in this mode unless/until we get a command, or
|
// Stay in this mode unless/until we get a command, or
|
// the write is over
|
// the write is over
|
spi_wr <= (((~i_wb_cyc)||((~i_wb_data_stb)&&(~i_wb_ctrl_stb)))
|
spi_wr <= (((!i_wb_cyc)||((!i_wb_data_stb)&&(!i_wb_ctrl_stb)))
|
&&(write_in_progress));
|
&&(write_in_progress));
|
spi_len <= 2'b00; // 8 bit reads
|
spi_len <= 2'b00; // 8 bit reads
|
spi_spd <= 1'b0; // SPI, not quad
|
spi_spd <= 1'b0; // SPI, not quad
|
spi_dir <= 1'b1; // Read
|
spi_dir <= 1'b1; // Read
|
if (spi_valid)
|
if (spi_valid)
|
begin
|
begin
|
write_in_progress <= spi_out[0];
|
write_in_progress <= spi_out[0];
|
if ((~spi_out[0])&&(write_in_progress))
|
if ((!spi_out[0])&&(write_in_progress))
|
o_interrupt <= 1'b1;
|
o_interrupt <= 1'b1;
|
end else
|
end else
|
o_interrupt <= 1'b0;
|
o_interrupt <= 1'b0;
|
|
|
if ((~spi_wr)&&(~spi_busy)&&(o_qspi_cs_n))
|
if ((!spi_wr)&&(!spi_busy)&&(o_qspi_cs_n))
|
begin // We can now go to idle and process a command
|
begin // We can now go to idle and process a command
|
o_wb_stall <= 1'b0;
|
o_wb_stall <= 1'b0;
|
o_wb_ack <= 1'b0;
|
o_wb_ack <= 1'b0;
|
state <= `WBQSPI_IDLE;
|
state <= `WBQSPI_IDLE;
|
end
|
end
|
`endif // !READ_ONLY
|
|
end else // if (state == `WBQSPI_WAIT_TIL_IDLE) or anything else
|
end else // if (state == `WBQSPI_WAIT_TIL_IDLE) or anything else
|
begin
|
begin
|
spi_wr <= 1'b0;
|
spi_wr <= 1'b0;
|
spi_hold <= 1'b0;
|
spi_hold <= 1'b0;
|
o_wb_stall <= 1'b1;
|
o_wb_stall <= 1'b1;
|
o_wb_ack <= 1'b0;
|
o_wb_ack <= 1'b0;
|
spif_req <= 1'b0;
|
spif_req <= 1'b0;
|
if ((~spi_busy)&&(o_qspi_cs_n)&&(~spi_wr)) // Wait for a full
|
if ((!spi_busy)&&(o_qspi_cs_n)&&(!spi_wr)) // Wait for a full
|
begin // clearing of the SPI port before moving on
|
begin // clearing of the SPI port before moving on
|
state <= `WBQSPI_IDLE;
|
state <= `WBQSPI_IDLE;
|
o_wb_stall <= 1'b0;
|
o_wb_stall <= 1'b0;
|
o_wb_ack <= 1'b0; // Shouldn't be acking anything here
|
o_wb_ack <= 1'b0; // Shouldn't be acking anything here
|
end
|
end
|