| 1 |
3 |
dgisselq |
///////////////////////////////////////////////////////////////////////////
|
| 2 |
|
|
//
|
| 3 |
|
|
// Filename: wbspiflash.v
|
| 4 |
|
|
//
|
| 5 |
|
|
// Project: Wishbone Controlled Quad SPI Flash Controller
|
| 6 |
|
|
//
|
| 7 |
|
|
// Purpose: Access a Quad SPI flash via a WISHBONE interface. This
|
| 8 |
|
|
// includes both read and write (and erase) commands to the SPI
|
| 9 |
|
|
// flash. All read/write commands are accomplished using the
|
| 10 |
|
|
// high speed (4-bit) interface. Further, the device will be
|
| 11 |
|
|
// left/kept in the 4-bit read interface mode between accesses,
|
| 12 |
|
|
// for a minimum read latency.
|
| 13 |
|
|
//
|
| 14 |
|
|
// Wishbone Registers (See spec sheet for more detail):
|
| 15 |
|
|
// 0: local config(r) / erase commands(w) / deep power down cmds / etc.
|
| 16 |
|
|
// R: (Write in Progress), (dirty-block), (spi_port_busy), 1'b0, 9'h00,
|
| 17 |
|
|
// { last_erased_sector, 14'h00 } if (WIP)
|
| 18 |
|
|
// else { current_sector_being_erased, 14'h00 }
|
| 19 |
|
|
// current if write in progress, last if written
|
| 20 |
|
|
// W: (1'b1 to erase), (12'h ignored), next_erased_block, 14'h ignored)
|
| 21 |
|
|
// 1: Configuration register
|
| 22 |
|
|
// 2: Status register (R/w)
|
| 23 |
|
|
// 3: Read ID (read only)
|
| 24 |
|
|
// (19 bits): Data (R/w, but expect writes to take a while)
|
| 25 |
|
|
//
|
| 26 |
|
|
//
|
| 27 |
|
|
// Creator: Dan Gisselquist, Ph.D.
|
| 28 |
|
|
// Gisselquist Technology, LLC
|
| 29 |
|
|
//
|
| 30 |
|
|
///////////////////////////////////////////////////////////////////////////
|
| 31 |
|
|
//
|
| 32 |
|
|
// Copyright (C) 2015-2016, Gisselquist Technology, LLC
|
| 33 |
|
|
//
|
| 34 |
|
|
// This program is free software (firmware): you can redistribute it and/or
|
| 35 |
|
|
// modify it under the terms of the GNU General Public License as published
|
| 36 |
|
|
// by the Free Software Foundation, either version 3 of the License, or (at
|
| 37 |
|
|
// your option) any later version.
|
| 38 |
|
|
//
|
| 39 |
|
|
// This program is distributed in the hope that it will be useful, but WITHOUT
|
| 40 |
|
|
// ANY WARRANTY; without even the implied warranty of MERCHANTIBILITY or
|
| 41 |
|
|
// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
| 42 |
|
|
// for more details.
|
| 43 |
|
|
//
|
| 44 |
|
|
// You should have received a copy of the GNU General Public License along
|
| 45 |
|
|
// with this program. (It's in the $(ROOT)/doc directory, run make with no
|
| 46 |
|
|
// target there if the PDF file isn't present.) If not, see
|
| 47 |
|
|
// <http://www.gnu.org/licenses/> for a copy.
|
| 48 |
|
|
//
|
| 49 |
|
|
// License: GPL, v3, as defined and found on www.gnu.org,
|
| 50 |
|
|
// http://www.gnu.org/licenses/gpl.html
|
| 51 |
|
|
//
|
| 52 |
|
|
//
|
| 53 |
|
|
///////////////////////////////////////////////////////////////////////////
|
| 54 |
|
|
//
|
| 55 |
|
|
`include "flash_config.v"
|
| 56 |
|
|
//
|
| 57 |
|
|
`define WBQSPI_RESET 0
|
| 58 |
|
|
`define WBQSPI_RESET_QUADMODE 1
|
| 59 |
|
|
`define WBQSPI_IDLE 2
|
| 60 |
|
|
`define WBQSPI_RDIDLE 3 // Idle, but in fast read mode
|
| 61 |
|
|
`define WBQSPI_WBDECODE 4
|
| 62 |
|
|
`define WBQSPI_RD_DUMMY 5
|
| 63 |
|
|
`define WBQSPI_QRD_ADDRESS 6
|
| 64 |
|
|
`define WBQSPI_QRD_DUMMY 7
|
| 65 |
|
|
`define WBQSPI_READ_CMD 8
|
| 66 |
|
|
`define WBQSPI_READ_DATA 9
|
| 67 |
|
|
`define WBQSPI_WAIT_TIL_RDIDLE 10
|
| 68 |
|
|
`define WBQSPI_READ_ID_CMD 11
|
| 69 |
|
|
`define WBQSPI_READ_ID 12
|
| 70 |
|
|
`define WBQSPI_READ_STATUS 13
|
| 71 |
|
|
`define WBQSPI_READ_CONFIG 14
|
| 72 |
|
|
`define WBQSPI_WAIT_TIL_IDLE 15
|
| 73 |
|
|
//
|
| 74 |
|
|
//
|
| 75 |
|
|
`ifndef READ_ONLY
|
| 76 |
|
|
//
|
| 77 |
|
|
`define WBQSPI_WAIT_WIP_CLEAR 16
|
| 78 |
|
|
`define WBQSPI_CHECK_WIP_CLEAR 17
|
| 79 |
|
|
`define WBQSPI_CHECK_WIP_DONE 18
|
| 80 |
|
|
`define WBQSPI_WEN 19
|
| 81 |
|
|
`define WBQSPI_PP 20 // Program page
|
| 82 |
|
|
`define WBQSPI_QPP 21 // Program page, 4 bit mode
|
| 83 |
|
|
`define WBQSPI_WR_DATA 22
|
| 84 |
|
|
`define WBQSPI_WR_BUS_CYCLE 23
|
| 85 |
|
|
`define WBQSPI_WRITE_STATUS 24
|
| 86 |
|
|
`define WBQSPI_WRITE_CONFIG 25
|
| 87 |
|
|
`define WBQSPI_ERASE_WEN 26
|
| 88 |
|
|
`define WBQSPI_ERASE_CMD 27
|
| 89 |
|
|
`define WBQSPI_ERASE_BLOCK 28
|
| 90 |
|
|
`define WBQSPI_CLEAR_STATUS 29
|
| 91 |
|
|
`define WBQSPI_IDLE_CHECK_WIP 30
|
| 92 |
|
|
//
|
| 93 |
|
|
`endif
|
| 94 |
|
|
|
| 95 |
|
|
module wbqspiflash(i_clk,
|
| 96 |
|
|
// Internal wishbone connections
|
| 97 |
|
|
i_wb_cyc, i_wb_data_stb, i_wb_ctrl_stb, i_wb_we,
|
| 98 |
|
|
i_wb_addr, i_wb_data,
|
| 99 |
|
|
// Wishbone return values
|
| 100 |
|
|
o_wb_ack, o_wb_stall, o_wb_data,
|
| 101 |
|
|
// Quad Spi connections to the external device
|
| 102 |
|
|
o_qspi_sck, o_qspi_cs_n, o_qspi_mod, o_qspi_dat, i_qspi_dat,
|
| 103 |
|
|
o_interrupt);
|
| 104 |
|
|
parameter ADDRESS_WIDTH=22;
|
| 105 |
|
|
input i_clk;
|
| 106 |
|
|
// Wishbone, inputs first
|
| 107 |
|
|
input i_wb_cyc, i_wb_data_stb, i_wb_ctrl_stb, i_wb_we;
|
| 108 |
|
|
input [(ADDRESS_WIDTH-3):0] i_wb_addr;
|
| 109 |
|
|
input [31:0] i_wb_data;
|
| 110 |
|
|
// then outputs
|
| 111 |
|
|
output reg o_wb_ack;
|
| 112 |
|
|
output reg o_wb_stall;
|
| 113 |
|
|
output reg [31:0] o_wb_data;
|
| 114 |
|
|
// Quad SPI control wires
|
| 115 |
|
|
output wire o_qspi_sck, o_qspi_cs_n;
|
| 116 |
|
|
output wire [1:0] o_qspi_mod;
|
| 117 |
|
|
output wire [3:0] o_qspi_dat;
|
| 118 |
|
|
input [3:0] i_qspi_dat;
|
| 119 |
|
|
// Interrupt line
|
| 120 |
|
|
output reg o_interrupt;
|
| 121 |
|
|
// output wire [31:0] o_debug;
|
| 122 |
|
|
|
| 123 |
|
|
reg spi_wr, spi_hold, spi_spd, spi_dir;
|
| 124 |
|
|
reg [31:0] spi_in;
|
| 125 |
|
|
reg [1:0] spi_len;
|
| 126 |
|
|
wire [31:0] spi_out;
|
| 127 |
|
|
wire spi_valid, spi_busy;
|
| 128 |
|
|
wire w_qspi_sck, w_qspi_cs_n;
|
| 129 |
|
|
wire [3:0] w_qspi_dat;
|
| 130 |
|
|
wire [1:0] w_qspi_mod;
|
| 131 |
|
|
// wire [22:0] spi_dbg;
|
| 132 |
|
|
llqspi lldriver(i_clk,
|
| 133 |
|
|
spi_wr, spi_hold, spi_in, spi_len, spi_spd, spi_dir,
|
| 134 |
|
|
spi_out, spi_valid, spi_busy,
|
| 135 |
|
|
w_qspi_sck, w_qspi_cs_n, w_qspi_mod, w_qspi_dat,
|
| 136 |
|
|
i_qspi_dat);
|
| 137 |
|
|
|
| 138 |
|
|
// Erase status tracking
|
| 139 |
|
|
reg write_in_progress, write_protect;
|
| 140 |
|
|
reg [(ADDRESS_WIDTH-17):0] erased_sector;
|
| 141 |
|
|
reg dirty_sector;
|
| 142 |
|
|
initial begin
|
| 143 |
|
|
write_in_progress = 1'b0;
|
| 144 |
|
|
erased_sector = 0;
|
| 145 |
|
|
dirty_sector = 1'b1;
|
| 146 |
|
|
write_protect = 1'b1;
|
| 147 |
|
|
end
|
| 148 |
|
|
|
| 149 |
|
|
reg qspi_full_stop;
|
| 150 |
|
|
always @(posedge i_clk)
|
| 151 |
|
|
qspi_full_stop <= ((~spi_busy)&&(o_qspi_cs_n)&&(~spi_wr));
|
| 152 |
|
|
|
| 153 |
|
|
reg [7:0] last_status;
|
| 154 |
|
|
reg quad_mode_enabled;
|
| 155 |
|
|
reg spif_cmd, spif_override, wr_same_row, pipeline_read;
|
| 156 |
|
|
reg [(ADDRESS_WIDTH-3):0] spif_addr;
|
| 157 |
|
|
reg [31:0] spif_data;
|
| 158 |
|
|
reg [5:0] state;
|
| 159 |
|
|
reg spif_ctrl, spif_req;
|
| 160 |
|
|
wire [(ADDRESS_WIDTH-17):0] spif_sector;
|
| 161 |
|
|
assign spif_sector = spif_addr[(ADDRESS_WIDTH-3):14];
|
| 162 |
|
|
|
| 163 |
|
|
// assign o_debug = { spi_wr, spi_spd, spi_hold, state, spi_dbg };
|
| 164 |
|
|
|
| 165 |
|
|
initial state = `WBQSPI_RESET;
|
| 166 |
|
|
initial o_wb_ack = 1'b0;
|
| 167 |
|
|
initial o_wb_stall = 1'b1;
|
| 168 |
|
|
initial spi_wr = 1'b0;
|
| 169 |
|
|
initial spi_len = 2'b00;
|
| 170 |
|
|
initial quad_mode_enabled = 1'b0;
|
| 171 |
|
|
initial o_interrupt = 1'b0;
|
| 172 |
|
|
always @(posedge i_clk)
|
| 173 |
|
|
begin
|
| 174 |
|
|
spif_override <= 1'b0;
|
| 175 |
|
|
if (state == `WBQSPI_RESET)
|
| 176 |
|
|
begin
|
| 177 |
|
|
// From a reset, we should
|
| 178 |
|
|
// Enable the Quad I/O mode
|
| 179 |
|
|
// Disable the Write protection bits in the status register
|
| 180 |
|
|
// Chip should already be up and running, so we can start
|
| 181 |
|
|
// immediately ....
|
| 182 |
|
|
o_wb_ack <= 1'b0;
|
| 183 |
|
|
o_wb_stall <= 1'b1;
|
| 184 |
|
|
spi_wr <= 1'b0;
|
| 185 |
|
|
spi_hold <= 1'b0;
|
| 186 |
|
|
spi_spd <= 1'b0;
|
| 187 |
|
|
spi_dir <= 1'b0;
|
| 188 |
|
|
last_status <= 8'h00;
|
| 189 |
|
|
state <= `WBQSPI_RESET_QUADMODE;
|
| 190 |
|
|
spif_req <= 1'b0;
|
| 191 |
|
|
spif_override <= 1'b1;
|
| 192 |
|
|
last_status <= 8'hfc; //
|
| 193 |
|
|
// This guarantees that we aren't starting in quad
|
| 194 |
|
|
// I/O mode, where the FPGA configuration scripts may
|
| 195 |
|
|
// have left us.
|
| 196 |
|
|
end else if (state == `WBQSPI_RESET_QUADMODE)
|
| 197 |
|
|
begin
|
| 198 |
|
|
// Okay, so here's the problem: we don't know whether or not
|
| 199 |
|
|
// the Xilinx loader started us up in Quad Read I/O idle mode.
|
| 200 |
|
|
// So, thus we need to
|
| 201 |
|
|
// Not ready to handle the bus yet, so stall any requests
|
| 202 |
|
|
o_wb_ack <= 1'b0;
|
| 203 |
|
|
o_wb_stall <= 1'b1;
|
| 204 |
|
|
|
| 205 |
|
|
// Do something ...
|
| 206 |
|
|
if (last_status == 8'h00)
|
| 207 |
|
|
begin
|
| 208 |
|
|
spif_override <= 1'b0;
|
| 209 |
|
|
state <= `WBQSPI_IDLE;
|
| 210 |
|
|
end else begin
|
| 211 |
|
|
last_status <= last_status - 8'h1;
|
| 212 |
|
|
spif_override <= 1'b1;
|
| 213 |
|
|
spif_cmd <= last_status[3]; // Toggle CS_n
|
| 214 |
|
|
spif_ctrl <= last_status[0]; // Toggle clock too
|
| 215 |
|
|
end
|
| 216 |
|
|
end else if (state == `WBQSPI_IDLE)
|
| 217 |
|
|
begin
|
| 218 |
|
|
o_interrupt <= 1'b0;
|
| 219 |
|
|
o_wb_stall <= 1'b0;
|
| 220 |
|
|
o_wb_ack <= 1'b0;
|
| 221 |
|
|
spif_cmd <= i_wb_we;
|
| 222 |
|
|
spif_addr <= i_wb_addr;
|
| 223 |
|
|
spif_data <= i_wb_data;
|
| 224 |
|
|
spif_ctrl <= (i_wb_ctrl_stb)&&(~i_wb_data_stb);
|
| 225 |
|
|
spif_req <= (i_wb_ctrl_stb)||(i_wb_data_stb);
|
| 226 |
|
|
spi_wr <= 1'b0; // Keep the port idle, unless told otherwise
|
| 227 |
|
|
spi_hold <= 1'b0;
|
| 228 |
|
|
spi_spd <= 1'b0;
|
| 229 |
|
|
spi_dir <= 1'b0; // Write (for now, 'cause of cmd)
|
| 230 |
|
|
//
|
| 231 |
|
|
if ((i_wb_data_stb)&&(~i_wb_we)&&(~write_in_progress))
|
| 232 |
|
|
begin // Read access, normal mode(s)
|
| 233 |
|
|
o_wb_ack <= 1'b0;
|
| 234 |
|
|
o_wb_stall <= 1'b1;
|
| 235 |
|
|
spi_wr <= 1'b1; // Write cmd to device
|
| 236 |
|
|
spi_len <= 2'b11;
|
| 237 |
|
|
if (quad_mode_enabled)
|
| 238 |
|
|
begin
|
| 239 |
|
|
// spi_in <= { 8'heb, bus_address };
|
| 240 |
|
|
state <= `WBQSPI_QRD_ADDRESS;
|
| 241 |
|
|
end else begin
|
| 242 |
|
|
//spi_in <= { 8'h0b, bus_address };
|
| 243 |
|
|
state <= `WBQSPI_RD_DUMMY;
|
| 244 |
|
|
end
|
| 245 |
|
|
end else if((i_wb_ctrl_stb)&&(~i_wb_we)&&(i_wb_addr[1:0] == 2'b00))
|
| 246 |
|
|
begin
|
| 247 |
|
|
// A local read that doesn't touch the device, so leave
|
| 248 |
|
|
// the device in its current state
|
| 249 |
|
|
o_wb_stall <= 1'b0;
|
| 250 |
|
|
o_wb_ack <= 1'b1;
|
| 251 |
|
|
o_wb_data <= { write_in_progress,
|
| 252 |
|
|
dirty_sector, spi_busy,
|
| 253 |
|
|
~write_protect,
|
| 254 |
|
|
quad_mode_enabled,
|
| 255 |
|
|
{(29-ADDRESS_WIDTH){1'b0}},
|
| 256 |
|
|
erased_sector, 14'h000 };
|
| 257 |
|
|
end else if ((i_wb_ctrl_stb)||(i_wb_data_stb))
|
| 258 |
|
|
begin // Need to release the device from quad mode for all else
|
| 259 |
|
|
o_wb_ack <= 1'b0;
|
| 260 |
|
|
o_wb_stall <= 1'b1;
|
| 261 |
|
|
spi_wr <= 1'b0;
|
| 262 |
|
|
spi_len <= 2'b11;
|
| 263 |
|
|
// spi_in <= 32'h00;
|
| 264 |
|
|
state <= `WBQSPI_WBDECODE;
|
| 265 |
|
|
end
|
| 266 |
|
|
end else if (state == `WBQSPI_RDIDLE)
|
| 267 |
|
|
begin
|
| 268 |
|
|
spi_wr <= 1'b0;
|
| 269 |
|
|
o_wb_stall <= 1'b0;
|
| 270 |
|
|
o_wb_ack <= 1'b0;
|
| 271 |
|
|
spif_cmd <= i_wb_we;
|
| 272 |
|
|
spif_addr <= i_wb_addr;
|
| 273 |
|
|
spif_data <= i_wb_data;
|
| 274 |
|
|
spif_ctrl <= (i_wb_ctrl_stb)&&(~i_wb_data_stb);
|
| 275 |
|
|
spif_req <= (i_wb_ctrl_stb)||(i_wb_data_stb);
|
| 276 |
|
|
spi_hold <= 1'b0;
|
| 277 |
|
|
spi_spd<= 1'b1;
|
| 278 |
|
|
spi_dir <= 1'b0; // Write (for now)
|
| 279 |
|
|
if ((i_wb_data_stb)&&(~i_wb_we))
|
| 280 |
|
|
begin // Continue our read ... send the new address / mode
|
| 281 |
|
|
o_wb_stall <= 1'b1;
|
| 282 |
|
|
spi_wr <= 1'b1;
|
| 283 |
|
|
spi_len <= 2'b10; // Write address, but not mode byte
|
| 284 |
|
|
// spi_in <= { bus_address, 8'ha0 };
|
| 285 |
|
|
state <= `WBQSPI_QRD_DUMMY;
|
| 286 |
|
|
end else if((i_wb_ctrl_stb)&&(~i_wb_we)&&(i_wb_addr[1:0] == 2'b00))
|
| 287 |
|
|
begin
|
| 288 |
|
|
// A local read that doesn't touch the device, so leave
|
| 289 |
|
|
// the device in its current state
|
| 290 |
|
|
o_wb_stall <= 1'b0;
|
| 291 |
|
|
o_wb_ack <= 1'b1;
|
| 292 |
|
|
o_wb_data <= { write_in_progress,
|
| 293 |
|
|
dirty_sector, spi_busy,
|
| 294 |
|
|
~write_protect,
|
| 295 |
|
|
quad_mode_enabled,
|
| 296 |
|
|
{(29-ADDRESS_WIDTH){1'b0}},
|
| 297 |
|
|
erased_sector, 14'h000 };
|
| 298 |
|
|
end else if ((i_wb_ctrl_stb)||(i_wb_data_stb))
|
| 299 |
|
|
begin // Need to release the device from quad mode for all else
|
| 300 |
|
|
o_wb_ack <= 1'b0;
|
| 301 |
|
|
o_wb_stall <= 1'b1;
|
| 302 |
|
|
spi_wr <= 1'b1;
|
| 303 |
|
|
spi_len <= 2'b11;
|
| 304 |
|
|
// spi_in <= 32'h00;
|
| 305 |
|
|
state <= `WBQSPI_WBDECODE;
|
| 306 |
|
|
end
|
| 307 |
|
|
end else if (state == `WBQSPI_WBDECODE)
|
| 308 |
|
|
begin
|
| 309 |
|
|
// We were in quad SPI read mode, and had to get out.
|
| 310 |
|
|
// Now we've got a command (not data read) to read and
|
| 311 |
|
|
// execute. Accomplish what we would've done while in the
|
| 312 |
|
|
// IDLE state here, save only that we don't have to worry
|
| 313 |
|
|
// about data reads, and we need to operate on a stored
|
| 314 |
|
|
// version of the bus command
|
| 315 |
|
|
o_wb_stall <= 1'b1;
|
| 316 |
|
|
o_wb_ack <= 1'b0;
|
| 317 |
|
|
spi_wr <= 1'b0; // Keep the port idle, unless told otherwise
|
| 318 |
|
|
spi_hold <= 1'b0;
|
| 319 |
|
|
spi_spd <= 1'b0;
|
| 320 |
|
|
spi_dir <= 1'b0;
|
| 321 |
|
|
spif_req<= (spif_req) && (i_wb_cyc);
|
| 322 |
|
|
if (qspi_full_stop) // only in full idle ...
|
| 323 |
|
|
begin
|
| 324 |
|
|
// Data register access
|
| 325 |
|
|
if (~spif_ctrl)
|
| 326 |
|
|
begin
|
| 327 |
|
|
if (spif_cmd) // Request to write a page
|
| 328 |
|
|
begin
|
| 329 |
|
|
`ifdef READ_ONLY
|
| 330 |
|
|
o_wb_ack <= spif_req;
|
| 331 |
|
|
o_wb_stall <= 1'b0;
|
| 332 |
|
|
state <= `WBQSPI_IDLE;
|
| 333 |
|
|
`else
|
| 334 |
|
|
if((~write_protect)&&(~write_in_progress))
|
| 335 |
|
|
begin // 00
|
| 336 |
|
|
spi_wr <= 1'b1;
|
| 337 |
|
|
spi_len <= 2'b00; // 8 bits
|
| 338 |
|
|
// Send a write enable command
|
| 339 |
|
|
// spi_in <= { 8'h06, 24'h00 };
|
| 340 |
|
|
state <= `WBQSPI_WEN;
|
| 341 |
|
|
|
| 342 |
|
|
o_wb_ack <= 1'b0;
|
| 343 |
|
|
o_wb_stall <= 1'b1;
|
| 344 |
|
|
end else if (write_protect)
|
| 345 |
|
|
begin // whether or not write-in_progress ...
|
| 346 |
|
|
// Do nothing on a write protect
|
| 347 |
|
|
// violation
|
| 348 |
|
|
//
|
| 349 |
|
|
o_wb_ack <= spif_req;
|
| 350 |
|
|
o_wb_stall <= 1'b0;
|
| 351 |
|
|
state <= `WBQSPI_IDLE;
|
| 352 |
|
|
end else begin // write is in progress, wait
|
| 353 |
|
|
// for it to complete
|
| 354 |
|
|
state <= `WBQSPI_WAIT_WIP_CLEAR;
|
| 355 |
|
|
o_wb_ack <= 1'b0;
|
| 356 |
|
|
o_wb_stall <= 1'b1;
|
| 357 |
|
|
end
|
| 358 |
|
|
// end else if (~write_in_progress) // always true
|
| 359 |
|
|
// but ... we wouldn't get here on a normal read access
|
| 360 |
|
|
`endif
|
| 361 |
|
|
end else begin
|
| 362 |
|
|
// Something's wrong, we should never
|
| 363 |
|
|
// get here
|
| 364 |
|
|
// Attempt to go to idle to recover
|
| 365 |
|
|
state <= `WBQSPI_IDLE;
|
| 366 |
|
|
end
|
| 367 |
|
|
end else if ((spif_ctrl)&&(spif_cmd))
|
| 368 |
|
|
begin
|
| 369 |
|
|
`ifdef READ_ONLY
|
| 370 |
|
|
o_wb_ack <= spif_req;
|
| 371 |
|
|
o_wb_stall <= 1'b0;
|
| 372 |
|
|
state <= `WBQSPI_IDLE;
|
| 373 |
|
|
`else
|
| 374 |
|
|
o_wb_stall <= 1'b1;
|
| 375 |
|
|
case(spif_addr[1:0])
|
| 376 |
|
|
2'b00: begin // Erase command register
|
| 377 |
|
|
o_wb_ack <= spif_req;
|
| 378 |
|
|
o_wb_stall <= 1'b0;
|
| 379 |
|
|
state <= `WBQSPI_IDLE;
|
| 380 |
|
|
write_protect <= ~spif_data[28];
|
| 381 |
|
|
// Are we commanding an erase?
|
| 382 |
|
|
// We're in read mode, writes cannot
|
| 383 |
|
|
// be in progress, so ...
|
| 384 |
|
|
if (spif_data[31]) // Command an erase
|
| 385 |
|
|
begin
|
| 386 |
|
|
// Since we're not going back
|
| 387 |
|
|
// to IDLE, we must stall the
|
| 388 |
|
|
// bus here
|
| 389 |
|
|
o_wb_stall <= 1'b1;
|
| 390 |
|
|
spi_wr <= 1'b1;
|
| 391 |
|
|
spi_len <= 2'b00;
|
| 392 |
|
|
// Send a write enable command
|
| 393 |
|
|
// spi_in <= { 8'h06, 24'h00 };
|
| 394 |
|
|
state <= `WBQSPI_ERASE_CMD;
|
| 395 |
|
|
end end
|
| 396 |
|
|
2'b01: begin
|
| 397 |
|
|
// Write the configuration register
|
| 398 |
|
|
o_wb_ack <= spif_req;
|
| 399 |
|
|
o_wb_stall <= 1'b1;
|
| 400 |
|
|
|
| 401 |
|
|
// Need to send a write enable command first
|
| 402 |
|
|
spi_wr <= 1'b1;
|
| 403 |
|
|
spi_len <= 2'b00; // 8 bits
|
| 404 |
|
|
// Send a write enable command
|
| 405 |
|
|
// spi_in <= { 8'h06, 24'h00 };
|
| 406 |
|
|
state <= `WBQSPI_WRITE_CONFIG;
|
| 407 |
|
|
end
|
| 408 |
|
|
2'b10: begin
|
| 409 |
|
|
// Write the status register
|
| 410 |
|
|
o_wb_ack <= spif_req; // Ack immediately
|
| 411 |
|
|
o_wb_stall <= 1'b1; // Stall other cmds
|
| 412 |
|
|
// Need to send a write enable command first
|
| 413 |
|
|
spi_wr <= 1'b1;
|
| 414 |
|
|
spi_len <= 2'b00; // 8 bits
|
| 415 |
|
|
// Send a write enable command
|
| 416 |
|
|
// spi_in <= { 8'h06, 24'h00 };
|
| 417 |
|
|
state <= `WBQSPI_WRITE_STATUS;
|
| 418 |
|
|
end
|
| 419 |
|
|
2'b11: begin // Write the ID register??? makes no sense
|
| 420 |
|
|
o_wb_ack <= spif_req;
|
| 421 |
|
|
o_wb_stall <= 1'b0;
|
| 422 |
|
|
state <= `WBQSPI_IDLE;
|
| 423 |
|
|
end
|
| 424 |
|
|
endcase
|
| 425 |
|
|
`endif
|
| 426 |
|
|
end else begin // on (~spif_we)
|
| 427 |
|
|
case(spif_addr[1:0])
|
| 428 |
|
|
2'b00: begin // Read local register
|
| 429 |
|
|
// Nonsense case--would've done this
|
| 430 |
|
|
// already
|
| 431 |
|
|
state <= `WBQSPI_IDLE;
|
| 432 |
|
|
o_wb_ack <= spif_req;
|
| 433 |
|
|
o_wb_stall <= 1'b0;
|
| 434 |
|
|
end
|
| 435 |
|
|
2'b01: begin // Read configuration register
|
| 436 |
|
|
state <= `WBQSPI_READ_CONFIG;
|
| 437 |
|
|
spi_wr <= 1'b1;
|
| 438 |
|
|
spi_len <= 2'b01;
|
| 439 |
|
|
// spi_in <= { 8'h35, 24'h00};
|
| 440 |
|
|
|
| 441 |
|
|
o_wb_ack <= 1'b0;
|
| 442 |
|
|
o_wb_stall <= 1'b1;
|
| 443 |
|
|
end
|
| 444 |
|
|
2'b10: begin // Read status register
|
| 445 |
|
|
state <= `WBQSPI_READ_STATUS;
|
| 446 |
|
|
spi_wr <= 1'b1;
|
| 447 |
|
|
spi_len <= 2'b01; // 8 bits out, 8 bits in
|
| 448 |
|
|
// spi_in <= { 8'h05, 24'h00};
|
| 449 |
|
|
|
| 450 |
|
|
o_wb_ack <= 1'b0;
|
| 451 |
|
|
o_wb_stall <= 1'b1;
|
| 452 |
|
|
end
|
| 453 |
|
|
2'b11: begin // Read ID register
|
| 454 |
|
|
state <= `WBQSPI_READ_ID_CMD;
|
| 455 |
|
|
spi_wr <= 1'b1;
|
| 456 |
|
|
spi_len <= 2'b00;
|
| 457 |
|
|
// spi_in <= { 8'h9f, 24'h00};
|
| 458 |
|
|
|
| 459 |
|
|
o_wb_ack <= 1'b0;
|
| 460 |
|
|
o_wb_stall <= 1'b1;
|
| 461 |
|
|
end
|
| 462 |
|
|
endcase
|
| 463 |
|
|
end
|
| 464 |
|
|
end
|
| 465 |
|
|
//
|
| 466 |
|
|
//
|
| 467 |
|
|
// READ DATA section: for both data and commands
|
| 468 |
|
|
//
|
| 469 |
|
|
end else if (state == `WBQSPI_RD_DUMMY)
|
| 470 |
|
|
begin
|
| 471 |
|
|
o_wb_ack <= 1'b0;
|
| 472 |
|
|
o_wb_stall <= 1'b1;
|
| 473 |
|
|
|
| 474 |
|
|
spi_wr <= 1'b1; // Non-stop
|
| 475 |
|
|
// Need to read one byte of dummy data,
|
| 476 |
|
|
// just to consume 8 clocks
|
| 477 |
|
|
// spi_in <= { 8'h00, 24'h00 };
|
| 478 |
|
|
spi_len <= 2'b00; // Read 8 bits
|
| 479 |
|
|
spi_spd <= 1'b0;
|
| 480 |
|
|
spi_hold <= 1'b0;
|
| 481 |
|
|
spif_req<= (spif_req) && (i_wb_cyc);
|
| 482 |
|
|
|
| 483 |
|
|
if ((~spi_busy)&&(~o_qspi_cs_n))
|
| 484 |
|
|
// Our command was accepted
|
| 485 |
|
|
state <= `WBQSPI_READ_CMD;
|
| 486 |
|
|
end else if (state == `WBQSPI_QRD_ADDRESS)
|
| 487 |
|
|
begin
|
| 488 |
|
|
// We come in here immediately upon issuing a QRD read
|
| 489 |
|
|
// command (8-bits), but we have to pause to give the
|
| 490 |
|
|
// address (24-bits) and mode (8-bits) in quad speed.
|
| 491 |
|
|
o_wb_ack <= 1'b0;
|
| 492 |
|
|
o_wb_stall <= 1'b1;
|
| 493 |
|
|
|
| 494 |
|
|
spi_wr <= 1'b1; // Non-stop
|
| 495 |
|
|
// spi_in <= { {(24-ADDRESS_WIDTH){1'b0}},
|
| 496 |
|
|
// spif_addr[(ADDRESS_WIDTH-3):0], 2'b00, 8'ha0 };
|
| 497 |
|
|
spi_len <= 2'b10; // Write address, not mode byte
|
| 498 |
|
|
spi_spd <= 1'b1;
|
| 499 |
|
|
spi_dir <= 1'b0; // Still writing
|
| 500 |
|
|
spi_hold <= 1'b0;
|
| 501 |
|
|
spif_req<= (spif_req) && (i_wb_cyc);
|
| 502 |
|
|
|
| 503 |
|
|
if ((~spi_busy)&&(spi_spd))
|
| 504 |
|
|
// Our command was accepted
|
| 505 |
|
|
state <= `WBQSPI_QRD_DUMMY;
|
| 506 |
|
|
end else if (state == `WBQSPI_QRD_DUMMY)
|
| 507 |
|
|
begin
|
| 508 |
|
|
o_wb_ack <= 1'b0;
|
| 509 |
|
|
o_wb_stall <= 1'b1;
|
| 510 |
|
|
|
| 511 |
|
|
spi_wr <= 1'b1; // Non-stop
|
| 512 |
|
|
// spi_in <= { 8'ha0, 24'h00 }; // Mode byte, then 2 bytes dummy
|
| 513 |
|
|
spi_len <= 2'b10; // Write 8 bits
|
| 514 |
|
|
spi_spd <= 1'b1;
|
| 515 |
|
|
spi_dir <= 1'b0; // Still writing
|
| 516 |
|
|
spi_hold <= 1'b0;
|
| 517 |
|
|
spif_req<= (spif_req) && (i_wb_cyc);
|
| 518 |
|
|
|
| 519 |
|
|
if ((~spi_busy)&&(spi_in[31:28] == 4'ha))
|
| 520 |
|
|
// Our command was accepted
|
| 521 |
|
|
state <= `WBQSPI_READ_CMD;
|
| 522 |
|
|
end else if (state == `WBQSPI_READ_CMD)
|
| 523 |
|
|
begin // Issue our first command to read 32 bits.
|
| 524 |
|
|
o_wb_ack <= 1'b0;
|
| 525 |
|
|
o_wb_stall <= 1'b1;
|
| 526 |
|
|
|
| 527 |
|
|
spi_wr <= 1'b1;
|
| 528 |
|
|
// spi_in <= { 8'hff, 24'h00 }; // Empty
|
| 529 |
|
|
spi_len <= 2'b11; // Read 32 bits
|
| 530 |
|
|
spi_dir <= 1'b1; // Now reading
|
| 531 |
|
|
spi_hold <= 1'b0;
|
| 532 |
|
|
spif_req<= (spif_req) && (i_wb_cyc);
|
| 533 |
|
|
if ((spi_valid)&&(spi_len == 2'b11))
|
| 534 |
|
|
state <= `WBQSPI_READ_DATA;
|
| 535 |
|
|
end else if (state == `WBQSPI_READ_DATA)
|
| 536 |
|
|
begin
|
| 537 |
|
|
// Pipelined read support
|
| 538 |
|
|
spi_wr <=pipeline_read;
|
| 539 |
|
|
// spi_in <= 32'h00;
|
| 540 |
|
|
spi_len <= 2'b11;
|
| 541 |
|
|
// Don't adjust the speed here, it was set in the setup
|
| 542 |
|
|
spi_dir <= 1'b1; // Now we get to read
|
| 543 |
|
|
// Don't let the device go to idle until the bus cycle ends.
|
| 544 |
|
|
// This actually prevents a *really* nasty race condition,
|
| 545 |
|
|
// where the strobe comes in after the lower level device
|
| 546 |
|
|
// has decided to stop waiting. The write is then issued,
|
| 547 |
|
|
// but no one is listening. By leaving the device open,
|
| 548 |
|
|
// the device is kept in a state where a valid strobe
|
| 549 |
|
|
// here will be useful. Of course, we don't accept
|
| 550 |
|
|
// all commands, just reads. Further, the strobe needs
|
| 551 |
|
|
// to be high for two clocks cycles without changing
|
| 552 |
|
|
// anything on the bus--one for us to notice it and pull
|
| 553 |
|
|
// our head out of the sand, and a second for whoever
|
| 554 |
|
|
// owns the bus to realize their command went through.
|
| 555 |
|
|
spi_hold <= 1'b1;
|
| 556 |
|
|
spif_req<= (spif_req) && (i_wb_cyc);
|
| 557 |
|
|
if ((spi_valid)&&(~spi_in[31]))
|
| 558 |
|
|
begin // Single pulse acknowledge and write data out
|
| 559 |
|
|
o_wb_ack <= spif_req;
|
| 560 |
|
|
o_wb_stall <= (~spi_wr);
|
| 561 |
|
|
// adjust endian-ness to match the PC
|
| 562 |
|
|
o_wb_data <= { spi_out[7:0], spi_out[15:8],
|
| 563 |
|
|
spi_out[23:16], spi_out[31:24] };
|
| 564 |
|
|
state <= (spi_wr)?`WBQSPI_READ_DATA
|
| 565 |
|
|
: ((spi_spd) ? `WBQSPI_WAIT_TIL_RDIDLE : `WBQSPI_WAIT_TIL_IDLE);
|
| 566 |
|
|
spif_req <= spi_wr;
|
| 567 |
|
|
spi_hold <= (~spi_wr);
|
| 568 |
|
|
if (spi_wr)
|
| 569 |
|
|
spif_addr <= i_wb_addr;
|
| 570 |
|
|
end else if (~i_wb_cyc)
|
| 571 |
|
|
begin // FAIL SAFE: If the bus cycle ends, forget why we're
|
| 572 |
|
|
// here, just go back to idle
|
| 573 |
|
|
state <= ((spi_spd) ? `WBQSPI_WAIT_TIL_RDIDLE : `WBQSPI_WAIT_TIL_IDLE);
|
| 574 |
|
|
spi_hold <= 1'b0;
|
| 575 |
|
|
o_wb_ack <= 1'b0;
|
| 576 |
|
|
o_wb_stall <= 1'b1;
|
| 577 |
|
|
end else begin
|
| 578 |
|
|
o_wb_ack <= 1'b0;
|
| 579 |
|
|
o_wb_stall <= 1'b1;
|
| 580 |
|
|
end
|
| 581 |
|
|
end else if (state == `WBQSPI_WAIT_TIL_RDIDLE)
|
| 582 |
|
|
begin // Wait 'til idle, but then go to fast read idle instead of full
|
| 583 |
|
|
spi_wr <= 1'b0; // idle
|
| 584 |
|
|
spi_hold <= 1'b0;
|
| 585 |
|
|
o_wb_stall <= 1'b1;
|
| 586 |
|
|
o_wb_ack <= 1'b0;
|
| 587 |
|
|
spif_req <= 1'b0;
|
| 588 |
|
|
if (qspi_full_stop) // Wait for a full
|
| 589 |
|
|
begin // clearing of the SPI port before moving on
|
| 590 |
|
|
state <= `WBQSPI_RDIDLE;
|
| 591 |
|
|
o_wb_stall <= 1'b0;
|
| 592 |
|
|
o_wb_ack <= 1'b0;// Shouldn't be acking anything here
|
| 593 |
|
|
end
|
| 594 |
|
|
end else if (state == `WBQSPI_READ_ID_CMD)
|
| 595 |
|
|
begin // We came into here immediately after issuing a 0x9f command
|
| 596 |
|
|
// Now we need to read 32 bits of data. Result should be
|
| 597 |
|
|
// 0x0102154d (8'h manufacture ID, 16'h device ID, followed
|
| 598 |
|
|
// by the number of extended bytes available 8'h4d).
|
| 599 |
|
|
o_wb_ack <= 1'b0;
|
| 600 |
|
|
o_wb_stall<= 1'b1;
|
| 601 |
|
|
|
| 602 |
|
|
spi_wr <= 1'b1; // No data to send, but need four bytes, since
|
| 603 |
|
|
spi_len <= 2'b11; // 32 bits of data are ... useful
|
| 604 |
|
|
// spi_in <= 32'h00; // Irrelevant
|
| 605 |
|
|
spi_spd <= 1'b0; // Slow speed
|
| 606 |
|
|
spi_dir <= 1'b1; // Reading
|
| 607 |
|
|
spi_hold <= 1'b0;
|
| 608 |
|
|
spif_req <= (spif_req) && (i_wb_cyc);
|
| 609 |
|
|
if ((~spi_busy)&&(~o_qspi_cs_n)&&(spi_len == 2'b11))
|
| 610 |
|
|
// Our command was accepted, now go read the result
|
| 611 |
|
|
state <= `WBQSPI_READ_ID;
|
| 612 |
|
|
end else if (state == `WBQSPI_READ_ID)
|
| 613 |
|
|
begin
|
| 614 |
|
|
o_wb_ack <= 1'b0; // Assuming we're still waiting
|
| 615 |
|
|
o_wb_stall <= 1'b1;
|
| 616 |
|
|
|
| 617 |
|
|
spi_wr <= 1'b0; // No more writes, we've already written the cmd
|
| 618 |
|
|
spi_hold <= 1'b0;
|
| 619 |
|
|
spif_req <= (spif_req) && (i_wb_cyc);
|
| 620 |
|
|
|
| 621 |
|
|
// Here, we just wait until the result comes back
|
| 622 |
|
|
// The problem is, the result may be the previous result.
|
| 623 |
|
|
// So we use spi_len as an indicator
|
| 624 |
|
|
spi_len <= 2'b00;
|
| 625 |
|
|
if((spi_valid)&&(spi_len==2'b00))
|
| 626 |
|
|
begin // Put the results out as soon as possible
|
| 627 |
|
|
o_wb_data <= spi_out[31:0];
|
| 628 |
|
|
o_wb_ack <= spif_req;
|
| 629 |
|
|
spif_req <= 1'b0;
|
| 630 |
|
|
end else if ((~spi_busy)&&(o_qspi_cs_n))
|
| 631 |
|
|
begin
|
| 632 |
|
|
state <= `WBQSPI_IDLE;
|
| 633 |
|
|
o_wb_stall <= 1'b0;
|
| 634 |
|
|
end
|
| 635 |
|
|
end else if (state == `WBQSPI_READ_STATUS)
|
| 636 |
|
|
begin // We enter after the command has been given, for now just
|
| 637 |
|
|
// read and return
|
| 638 |
|
|
spi_wr <= 1'b0;
|
| 639 |
|
|
o_wb_ack <= 1'b0;
|
| 640 |
|
|
spi_hold <= 1'b0;
|
| 641 |
|
|
spif_req <= (spif_req) && (i_wb_cyc);
|
| 642 |
|
|
if (spi_valid)
|
| 643 |
|
|
begin
|
| 644 |
|
|
o_wb_ack <= spif_req;
|
| 645 |
|
|
o_wb_stall <= 1'b1;
|
| 646 |
|
|
spif_req <= 1'b0;
|
| 647 |
|
|
last_status <= spi_out[7:0];
|
| 648 |
|
|
write_in_progress <= spi_out[0];
|
| 649 |
|
|
if (spif_addr[1:0] == 2'b00) // Local read, checking
|
| 650 |
|
|
begin // status, 'cause we're writing
|
| 651 |
|
|
o_wb_data <= { spi_out[0],
|
| 652 |
|
|
dirty_sector, spi_busy,
|
| 653 |
|
|
~write_protect,
|
| 654 |
|
|
quad_mode_enabled,
|
| 655 |
|
|
{(29-ADDRESS_WIDTH){1'b0}},
|
| 656 |
|
|
erased_sector, 14'h000 };
|
| 657 |
|
|
end else begin
|
| 658 |
|
|
o_wb_data <= { 24'h00, spi_out[7:0] };
|
| 659 |
|
|
end
|
| 660 |
|
|
end
|
| 661 |
|
|
|
| 662 |
|
|
if (qspi_full_stop)
|
| 663 |
|
|
state <= `WBQSPI_IDLE;
|
| 664 |
|
|
end else if (state == `WBQSPI_READ_CONFIG)
|
| 665 |
|
|
begin // We enter after the command has been given, for now just
|
| 666 |
|
|
// read and return
|
| 667 |
|
|
spi_wr <= 1'b0;
|
| 668 |
|
|
o_wb_ack <= 1'b0;
|
| 669 |
|
|
o_wb_stall <= 1'b1;
|
| 670 |
|
|
spi_hold <= 1'b0;
|
| 671 |
|
|
spif_req <= (spif_req) && (i_wb_cyc);
|
| 672 |
|
|
|
| 673 |
|
|
if (spi_valid)
|
| 674 |
|
|
begin
|
| 675 |
|
|
o_wb_data <= { 24'h00, spi_out[7:0] };
|
| 676 |
|
|
quad_mode_enabled <= spi_out[1];
|
| 677 |
|
|
end
|
| 678 |
|
|
|
| 679 |
|
|
if (qspi_full_stop)
|
| 680 |
|
|
begin
|
| 681 |
|
|
state <= `WBQSPI_IDLE;
|
| 682 |
|
|
o_wb_ack <= spif_req;
|
| 683 |
|
|
o_wb_stall <= 1'b0;
|
| 684 |
|
|
spif_req <= 1'b0;
|
| 685 |
|
|
end
|
| 686 |
|
|
|
| 687 |
|
|
//
|
| 688 |
|
|
//
|
| 689 |
|
|
// Write/erase data section
|
| 690 |
|
|
//
|
| 691 |
|
|
`ifndef READ_ONLY
|
| 692 |
|
|
end else if (state == `WBQSPI_WAIT_WIP_CLEAR)
|
| 693 |
|
|
begin
|
| 694 |
|
|
o_wb_stall <= 1'b1;
|
| 695 |
|
|
o_wb_ack <= 1'b0;
|
| 696 |
|
|
spi_wr <= 1'b0;
|
| 697 |
|
|
spif_req<= (spif_req) && (i_wb_cyc);
|
| 698 |
|
|
if (~spi_busy)
|
| 699 |
|
|
begin
|
| 700 |
|
|
spi_wr <= 1'b1;
|
| 701 |
|
|
// spi_in <= { 8'h05, 24'h0000 };
|
| 702 |
|
|
spi_hold <= 1'b1;
|
| 703 |
|
|
spi_len <= 2'b01; // 16 bits write, so we can read 8
|
| 704 |
|
|
state <= `WBQSPI_CHECK_WIP_CLEAR;
|
| 705 |
|
|
spi_spd <= 1'b0; // Slow speed
|
| 706 |
|
|
spi_dir <= 1'b0;
|
| 707 |
|
|
end
|
| 708 |
|
|
end else if (state == `WBQSPI_CHECK_WIP_CLEAR)
|
| 709 |
|
|
begin
|
| 710 |
|
|
o_wb_stall <= 1'b1;
|
| 711 |
|
|
o_wb_ack <= 1'b0;
|
| 712 |
|
|
// Repeat as often as necessary until we are clear
|
| 713 |
|
|
spi_wr <= 1'b1;
|
| 714 |
|
|
// spi_in <= 32'h0000; // Values here are actually irrelevant
|
| 715 |
|
|
spi_hold <= 1'b1;
|
| 716 |
|
|
spi_len <= 2'b00; // One byte at a time
|
| 717 |
|
|
spi_spd <= 1'b0; // Slow speed
|
| 718 |
|
|
spi_dir <= 1'b0;
|
| 719 |
|
|
spif_req<= (spif_req) && (i_wb_cyc);
|
| 720 |
|
|
if ((spi_valid)&&(~spi_out[0]))
|
| 721 |
|
|
begin
|
| 722 |
|
|
state <= `WBQSPI_CHECK_WIP_DONE;
|
| 723 |
|
|
spi_wr <= 1'b0;
|
| 724 |
|
|
spi_hold <= 1'b0;
|
| 725 |
|
|
write_in_progress <= 1'b0;
|
| 726 |
|
|
last_status <= spi_out[7:0];
|
| 727 |
|
|
end
|
| 728 |
|
|
end else if (state == `WBQSPI_CHECK_WIP_DONE)
|
| 729 |
|
|
begin
|
| 730 |
|
|
o_wb_stall <= 1'b1;
|
| 731 |
|
|
o_wb_ack <= 1'b0;
|
| 732 |
|
|
// Let's let the SPI port come back to a full idle,
|
| 733 |
|
|
// and the chip select line go low before continuing
|
| 734 |
|
|
spi_wr <= 1'b0;
|
| 735 |
|
|
spi_len <= 2'b00;
|
| 736 |
|
|
spi_hold <= 1'b0;
|
| 737 |
|
|
spi_spd <= 1'b0; // Slow speed
|
| 738 |
|
|
spi_dir <= 1'b0;
|
| 739 |
|
|
spif_req<= (spif_req) && (i_wb_cyc);
|
| 740 |
|
|
if ((o_qspi_cs_n)&&(~spi_busy)) // Chip select line is high, we can continue
|
| 741 |
|
|
begin
|
| 742 |
|
|
spi_wr <= 1'b0;
|
| 743 |
|
|
spi_hold <= 1'b0;
|
| 744 |
|
|
|
| 745 |
|
|
casez({ spif_cmd, spif_ctrl, spif_addr[1:0] })
|
| 746 |
|
|
4'b00??: begin // Read data from ... somewhere
|
| 747 |
|
|
spi_wr <= 1'b1; // Write cmd to device
|
| 748 |
|
|
if (quad_mode_enabled)
|
| 749 |
|
|
begin
|
| 750 |
|
|
// spi_in <= { 8'heb,
|
| 751 |
|
|
// {(24-ADDRESS_WIDTH){1'b0}},
|
| 752 |
|
|
// spif_addr[(ADDRESS_WIDTH-3):0], 2'b00 };
|
| 753 |
|
|
state <= `WBQSPI_QRD_ADDRESS;
|
| 754 |
|
|
// spi_len <= 2'b00; // single byte, cmd only
|
| 755 |
|
|
end else begin
|
| 756 |
|
|
// spi_in <= { 8'h0b,
|
| 757 |
|
|
// {(24-ADDRESS_WIDTH){1'b0}},
|
| 758 |
|
|
// spif_addr[(ADDRESS_WIDTH-3):0], 2'b00 };
|
| 759 |
|
|
state <= `WBQSPI_RD_DUMMY;
|
| 760 |
|
|
spi_len <= 2'b11; // Send cmd and addr
|
| 761 |
|
|
end end
|
| 762 |
|
|
4'b10??: begin // Write data to ... anywhere
|
| 763 |
|
|
spi_wr <= 1'b1;
|
| 764 |
|
|
spi_len <= 2'b00; // 8 bits
|
| 765 |
|
|
// Send a write enable command
|
| 766 |
|
|
// spi_in <= { 8'h06, 24'h00 };
|
| 767 |
|
|
state <= `WBQSPI_WEN;
|
| 768 |
|
|
end
|
| 769 |
|
|
4'b0110: begin // Read status register
|
| 770 |
|
|
state <= `WBQSPI_READ_STATUS;
|
| 771 |
|
|
spi_wr <= 1'b1;
|
| 772 |
|
|
spi_len <= 2'b01; // 8 bits out, 8 bits in
|
| 773 |
|
|
// spi_in <= { 8'h05, 24'h00};
|
| 774 |
|
|
end
|
| 775 |
|
|
4'b0111: begin
|
| 776 |
|
|
state <= `WBQSPI_READ_ID_CMD;
|
| 777 |
|
|
spi_wr <= 1'b1;
|
| 778 |
|
|
spi_len <= 2'b00;
|
| 779 |
|
|
// spi_in <= { 8'h9f, 24'h00};
|
| 780 |
|
|
end
|
| 781 |
|
|
default: begin //
|
| 782 |
|
|
o_wb_stall <= 1'b1;
|
| 783 |
|
|
o_wb_ack <= spif_req;
|
| 784 |
|
|
state <= `WBQSPI_WAIT_TIL_IDLE;
|
| 785 |
|
|
end
|
| 786 |
|
|
endcase
|
| 787 |
|
|
// spif_cmd <= i_wb_we;
|
| 788 |
|
|
// spif_addr <= i_wb_addr;
|
| 789 |
|
|
// spif_data <= i_wb_data;
|
| 790 |
|
|
// spif_ctrl <= (i_wb_ctrl_stb)&&(~i_wb_data_stb);
|
| 791 |
|
|
// spi_wr <= 1'b0; // Keep the port idle, unless told otherwise
|
| 792 |
|
|
end
|
| 793 |
|
|
end else if (state == `WBQSPI_WEN)
|
| 794 |
|
|
begin // We came here after issuing a write enable command
|
| 795 |
|
|
spi_wr <= 1'b0;
|
| 796 |
|
|
o_wb_ack <= 1'b0;
|
| 797 |
|
|
o_wb_stall <= 1'b1;
|
| 798 |
|
|
spif_req<= (spif_req) && (i_wb_cyc);
|
| 799 |
|
|
if (qspi_full_stop) // Let's come to a full stop
|
| 800 |
|
|
state <= (quad_mode_enabled)?`WBQSPI_QPP:`WBQSPI_PP;
|
| 801 |
|
|
// state <= `WBQSPI_PP;
|
| 802 |
|
|
end else if (state == `WBQSPI_PP)
|
| 803 |
|
|
begin // We come here under a full stop / full port idle mode
|
| 804 |
|
|
// Issue our command immediately
|
| 805 |
|
|
spi_wr <= 1'b1;
|
| 806 |
|
|
// spi_in <= { 8'h02,
|
| 807 |
|
|
// {(24-ADDRESS_WIDTH){1'b0}},
|
| 808 |
|
|
// spif_addr[(ADDRESS_WIDTH-3):0], 2'b00 };
|
| 809 |
|
|
spi_len <= 2'b11;
|
| 810 |
|
|
spi_hold <= 1'b1;
|
| 811 |
|
|
spi_spd <= 1'b0;
|
| 812 |
|
|
spi_dir <= 1'b0; // Writing
|
| 813 |
|
|
spif_req<= (spif_req) && (i_wb_cyc);
|
| 814 |
|
|
|
| 815 |
|
|
// Once we get busy, move on
|
| 816 |
|
|
if (spi_busy)
|
| 817 |
|
|
state <= `WBQSPI_WR_DATA;
|
| 818 |
|
|
if (spif_sector == erased_sector)
|
| 819 |
|
|
dirty_sector <= 1'b1;
|
| 820 |
|
|
end else if (state == `WBQSPI_QPP)
|
| 821 |
|
|
begin // We come here under a full stop / full port idle mode
|
| 822 |
|
|
// Issue our command immediately
|
| 823 |
|
|
spi_wr <= 1'b1;
|
| 824 |
|
|
// spi_in <= { 8'h32,
|
| 825 |
|
|
// {(24-ADDRESS_WIDTH){1'b0}},
|
| 826 |
|
|
// spif_addr[(ADDRESS_WIDTH-3):0], 2'b00 };
|
| 827 |
|
|
spi_len <= 2'b11;
|
| 828 |
|
|
spi_hold <= 1'b1;
|
| 829 |
|
|
spi_spd <= 1'b0;
|
| 830 |
|
|
spi_dir <= 1'b0; // Writing
|
| 831 |
|
|
spif_req<= (spif_req) && (i_wb_cyc);
|
| 832 |
|
|
|
| 833 |
|
|
// Once we get busy, move on
|
| 834 |
|
|
if (spi_busy)
|
| 835 |
|
|
begin
|
| 836 |
|
|
// spi_wr is irrelevant here ...
|
| 837 |
|
|
// Set the speed value once, but wait til we get busy
|
| 838 |
|
|
// to do so.
|
| 839 |
|
|
spi_spd <= 1'b1;
|
| 840 |
|
|
state <= `WBQSPI_WR_DATA;
|
| 841 |
|
|
end
|
| 842 |
|
|
if (spif_sector == erased_sector)
|
| 843 |
|
|
dirty_sector <= 1'b1;
|
| 844 |
|
|
end else if (state == `WBQSPI_WR_DATA)
|
| 845 |
|
|
begin
|
| 846 |
|
|
o_wb_stall <= 1'b1;
|
| 847 |
|
|
o_wb_ack <= 1'b0;
|
| 848 |
|
|
spi_wr <= 1'b1; // write without waiting
|
| 849 |
|
|
// spi_in <= {
|
| 850 |
|
|
// spif_data[ 7: 0],
|
| 851 |
|
|
// spif_data[15: 8],
|
| 852 |
|
|
// spif_data[23:16],
|
| 853 |
|
|
// spif_data[31:24] };
|
| 854 |
|
|
spi_len <= 2'b11; // Write 4 bytes
|
| 855 |
|
|
spi_hold <= 1'b1;
|
| 856 |
|
|
if (~spi_busy)
|
| 857 |
|
|
begin
|
| 858 |
|
|
o_wb_ack <= spif_req; // Ack when command given
|
| 859 |
|
|
state <= `WBQSPI_WR_BUS_CYCLE;
|
| 860 |
|
|
end
|
| 861 |
|
|
spif_req<= (spif_req) && (i_wb_cyc);
|
| 862 |
|
|
end else if (state == `WBQSPI_WR_BUS_CYCLE)
|
| 863 |
|
|
begin
|
| 864 |
|
|
o_wb_ack <= 1'b0; // Turn off our ack and stall flags
|
| 865 |
|
|
o_wb_stall <= 1'b1;
|
| 866 |
|
|
spi_wr <= 1'b0;
|
| 867 |
|
|
spi_hold <= 1'b1;
|
| 868 |
|
|
write_in_progress <= 1'b1;
|
| 869 |
|
|
spif_req<= (spif_req) && (i_wb_cyc);
|
| 870 |
|
|
if (~i_wb_cyc)
|
| 871 |
|
|
begin
|
| 872 |
|
|
state <= `WBQSPI_WAIT_TIL_IDLE;
|
| 873 |
|
|
spi_hold <= 1'b0;
|
| 874 |
|
|
end else if (spi_wr)
|
| 875 |
|
|
begin // Give the SPI a chance to get busy on the last write
|
| 876 |
|
|
// Do nothing here.
|
| 877 |
|
|
end else if (wr_same_row)
|
| 878 |
|
|
begin
|
| 879 |
|
|
spif_cmd <= 1'b1;
|
| 880 |
|
|
spif_data <= i_wb_data;
|
| 881 |
|
|
spif_addr <= i_wb_addr;
|
| 882 |
|
|
spif_ctrl <= 1'b0;
|
| 883 |
|
|
spif_req<= 1'b1;
|
| 884 |
|
|
// We'll keep the bus stalled on this request
|
| 885 |
|
|
// for a while
|
| 886 |
|
|
state <= `WBQSPI_WR_DATA;
|
| 887 |
|
|
o_wb_ack <= 1'b0;
|
| 888 |
|
|
o_wb_stall <= 1'b0;
|
| 889 |
|
|
end else if ((i_wb_data_stb|i_wb_ctrl_stb)&&(~o_wb_ack)) // Writing out of bounds
|
| 890 |
|
|
begin
|
| 891 |
|
|
spi_hold <= 1'b0;
|
| 892 |
|
|
spi_wr <= 1'b0;
|
| 893 |
|
|
state <= `WBQSPI_WAIT_TIL_IDLE;
|
| 894 |
|
|
end // Otherwise we stay here
|
| 895 |
|
|
end else if (state == `WBQSPI_WRITE_CONFIG)
|
| 896 |
|
|
begin // We enter immediately after commanding a WEN
|
| 897 |
|
|
o_wb_ack <= 1'b0;
|
| 898 |
|
|
o_wb_stall <= 1'b1;
|
| 899 |
|
|
|
| 900 |
|
|
spi_len <= 2'b10;
|
| 901 |
|
|
// spi_in <= { 8'h01, last_status, 6'h0, spif_data[1:0], 8'h00 };
|
| 902 |
|
|
spi_wr <= 1'b0;
|
| 903 |
|
|
spi_hold <= 1'b0;
|
| 904 |
|
|
spif_req <= (spif_req) && (i_wb_cyc);
|
| 905 |
|
|
if ((~spi_busy)&&(~spi_wr))
|
| 906 |
|
|
begin
|
| 907 |
|
|
spi_wr <= 1'b1;
|
| 908 |
|
|
state <= `WBQSPI_WAIT_TIL_IDLE;
|
| 909 |
|
|
write_in_progress <= 1'b1;
|
| 910 |
|
|
quad_mode_enabled <= spif_data[1];
|
| 911 |
|
|
end
|
| 912 |
|
|
end else if (state == `WBQSPI_WRITE_STATUS)
|
| 913 |
|
|
begin // We enter immediately after commanding a WEN
|
| 914 |
|
|
o_wb_ack <= 1'b0;
|
| 915 |
|
|
o_wb_stall <= 1'b1;
|
| 916 |
|
|
|
| 917 |
|
|
spi_len <= 2'b01;
|
| 918 |
|
|
// spi_in <= { 8'h01, spif_data[7:0], 16'h00 };
|
| 919 |
|
|
// last_status <= i_wb_data[7:0]; // We'll read this in a moment
|
| 920 |
|
|
spi_wr <= 1'b0;
|
| 921 |
|
|
spi_hold <= 1'b0;
|
| 922 |
|
|
spif_req <= (spif_req) && (i_wb_cyc);
|
| 923 |
|
|
if ((~spi_busy)&&(~spi_wr))
|
| 924 |
|
|
begin
|
| 925 |
|
|
spi_wr <= 1'b1;
|
| 926 |
|
|
last_status <= spif_data[7:0];
|
| 927 |
|
|
write_in_progress <= 1'b1;
|
| 928 |
|
|
if(((last_status[6])||(last_status[5]))
|
| 929 |
|
|
&&((~spif_data[6])&&(~spif_data[5])))
|
| 930 |
|
|
state <= `WBQSPI_CLEAR_STATUS;
|
| 931 |
|
|
else
|
| 932 |
|
|
state <= `WBQSPI_WAIT_TIL_IDLE;
|
| 933 |
|
|
end
|
| 934 |
|
|
end else if (state == `WBQSPI_ERASE_CMD)
|
| 935 |
|
|
begin // Know that WIP is clear on entry, WEN has just been commanded
|
| 936 |
|
|
spi_wr <= 1'b0;
|
| 937 |
|
|
o_wb_ack <= 1'b0;
|
| 938 |
|
|
o_wb_stall <= 1'b1;
|
| 939 |
|
|
spi_hold <= 1'b0;
|
| 940 |
|
|
spi_spd <= 1'b0;
|
| 941 |
|
|
spi_dir <= 1'b0;
|
| 942 |
|
|
spif_req <= (spif_req) && (i_wb_cyc);
|
| 943 |
|
|
|
| 944 |
|
|
// Here's the erase command
|
| 945 |
|
|
// spi_in <= { 8'hd8, 2'h0, spif_data[19:14], 14'h000, 2'b00 };
|
| 946 |
|
|
spi_len <= 2'b11; // 32 bit write
|
| 947 |
|
|
// together with setting our copy of the WIP bit
|
| 948 |
|
|
write_in_progress <= 1'b1;
|
| 949 |
|
|
// keeping track of which sector we just erased
|
| 950 |
|
|
erased_sector <= spif_data[(ADDRESS_WIDTH-3):14];
|
| 951 |
|
|
// and marking this erase sector as no longer dirty
|
| 952 |
|
|
dirty_sector <= 1'b0;
|
| 953 |
|
|
|
| 954 |
|
|
// Wait for a full stop before issuing this command
|
| 955 |
|
|
if ((~spi_busy)&&(~spi_wr)&&(o_qspi_cs_n))
|
| 956 |
|
|
begin // When our command is accepted, move to the next state
|
| 957 |
|
|
spi_wr <= 1'b1;
|
| 958 |
|
|
state <= `WBQSPI_ERASE_BLOCK;
|
| 959 |
|
|
end
|
| 960 |
|
|
end else if (state == `WBQSPI_ERASE_BLOCK)
|
| 961 |
|
|
begin
|
| 962 |
|
|
spi_wr <= 1'b0;
|
| 963 |
|
|
spi_hold <= 1'b0;
|
| 964 |
|
|
o_wb_stall <= 1'b1;
|
| 965 |
|
|
o_wb_ack <= 1'b0;
|
| 966 |
|
|
spif_req <= (spif_req) && (i_wb_cyc);
|
| 967 |
|
|
// When the port clears, we can head back to idle
|
| 968 |
|
|
if ((~spi_busy)&&(~spi_wr))
|
| 969 |
|
|
begin
|
| 970 |
|
|
o_wb_ack <= spif_req;
|
| 971 |
|
|
state <= `WBQSPI_IDLE;
|
| 972 |
|
|
end
|
| 973 |
|
|
end else if (state == `WBQSPI_CLEAR_STATUS)
|
| 974 |
|
|
begin // Issue a clear status command
|
| 975 |
|
|
spi_wr <= 1'b1;
|
| 976 |
|
|
spi_hold <= 1'b0;
|
| 977 |
|
|
spi_len <= 2'b00; // 8 bit command
|
| 978 |
|
|
// spi_in <= { 8'h30, 24'h00 };
|
| 979 |
|
|
spi_spd <= 1'b0;
|
| 980 |
|
|
spi_dir <= 1'b0;
|
| 981 |
|
|
last_status[6:5] <= 2'b00;
|
| 982 |
|
|
spif_req <= (spif_req) && (i_wb_cyc);
|
| 983 |
|
|
if ((spi_wr)&&(~spi_busy))
|
| 984 |
|
|
state <= `WBQSPI_WAIT_TIL_IDLE;
|
| 985 |
|
|
end else if (state == `WBQSPI_IDLE_CHECK_WIP)
|
| 986 |
|
|
begin // We are now in read status register mode
|
| 987 |
|
|
|
| 988 |
|
|
// No bus commands have (yet) been given
|
| 989 |
|
|
o_wb_stall <= 1'b1;
|
| 990 |
|
|
o_wb_ack <= 1'b0;
|
| 991 |
|
|
spif_req <= (spif_req) && (i_wb_cyc);
|
| 992 |
|
|
|
| 993 |
|
|
// Stay in this mode unless/until we get a command, or
|
| 994 |
|
|
// the write is over
|
| 995 |
|
|
spi_wr <= (((~i_wb_cyc)||((~i_wb_data_stb)&&(~i_wb_ctrl_stb)))
|
| 996 |
|
|
&&(write_in_progress));
|
| 997 |
|
|
spi_len <= 2'b00; // 8 bit reads
|
| 998 |
|
|
spi_spd <= 1'b0; // SPI, not quad
|
| 999 |
|
|
spi_dir <= 1'b1; // Read
|
| 1000 |
|
|
if (spi_valid)
|
| 1001 |
|
|
begin
|
| 1002 |
|
|
write_in_progress <= spi_out[0];
|
| 1003 |
|
|
if ((~spi_out[0])&&(write_in_progress))
|
| 1004 |
|
|
o_interrupt <= 1'b1;
|
| 1005 |
|
|
end else
|
| 1006 |
|
|
o_interrupt <= 1'b0;
|
| 1007 |
|
|
|
| 1008 |
|
|
if ((~spi_wr)&&(~spi_busy)&&(o_qspi_cs_n))
|
| 1009 |
|
|
begin // We can now go to idle and process a command
|
| 1010 |
|
|
o_wb_stall <= 1'b0;
|
| 1011 |
|
|
o_wb_ack <= 1'b0;
|
| 1012 |
|
|
state <= `WBQSPI_IDLE;
|
| 1013 |
|
|
end
|
| 1014 |
|
|
`endif // !READ_ONLY
|
| 1015 |
|
|
end else // if (state == `WBQSPI_WAIT_TIL_IDLE) or anything else
|
| 1016 |
|
|
begin
|
| 1017 |
|
|
spi_wr <= 1'b0;
|
| 1018 |
|
|
spi_hold <= 1'b0;
|
| 1019 |
|
|
o_wb_stall <= 1'b1;
|
| 1020 |
|
|
o_wb_ack <= 1'b0;
|
| 1021 |
|
|
spif_req <= 1'b0;
|
| 1022 |
|
|
if ((~spi_busy)&&(o_qspi_cs_n)&&(~spi_wr)) // Wait for a full
|
| 1023 |
|
|
begin // clearing of the SPI port before moving on
|
| 1024 |
|
|
state <= `WBQSPI_IDLE;
|
| 1025 |
|
|
o_wb_stall <= 1'b0;
|
| 1026 |
|
|
o_wb_ack <= 1'b0; // Shouldn't be acking anything here
|
| 1027 |
|
|
end
|
| 1028 |
|
|
end
|
| 1029 |
|
|
end
|
| 1030 |
|
|
|
| 1031 |
|
|
|
| 1032 |
|
|
wire [23:0] bus_address, reg_address;
|
| 1033 |
|
|
generate
|
| 1034 |
|
|
if (ADDRESS_WIDTH<24)
|
| 1035 |
|
|
begin
|
| 1036 |
|
|
assign bus_address = { {(24-ADDRESS_WIDTH){1'b0}},
|
| 1037 |
|
|
i_wb_addr[(ADDRESS_WIDTH-3):0], 2'b00 };
|
| 1038 |
|
|
assign reg_address = { {(24-ADDRESS_WIDTH){1'b0}},
|
| 1039 |
|
|
spif_addr[(ADDRESS_WIDTH-3):0], 2'b00 };
|
| 1040 |
|
|
end else begin
|
| 1041 |
|
|
assign bus_address = { i_wb_addr[(ADDRESS_WIDTH-3):0], 2'b00 };
|
| 1042 |
|
|
assign reg_address = { spif_addr[(ADDRESS_WIDTH-3):0], 2'b00 };
|
| 1043 |
|
|
end endgenerate
|
| 1044 |
|
|
|
| 1045 |
|
|
// Set the spi_in register, and that register only
|
| 1046 |
|
|
always @(posedge i_clk)
|
| 1047 |
|
|
begin
|
| 1048 |
|
|
if (state == `WBQSPI_IDLE)
|
| 1049 |
|
|
begin
|
| 1050 |
|
|
if (quad_mode_enabled)
|
| 1051 |
|
|
spi_in <= { 8'heb, bus_address };
|
| 1052 |
|
|
else
|
| 1053 |
|
|
spi_in <= { 8'h0b, bus_address };
|
| 1054 |
|
|
end else if (state == `WBQSPI_RDIDLE)
|
| 1055 |
|
|
begin
|
| 1056 |
|
|
spi_in <= 32'h00;
|
| 1057 |
|
|
if ((i_wb_data_stb)&&(~i_wb_we))
|
| 1058 |
|
|
begin // Send the new address / mode
|
| 1059 |
|
|
spi_in <= { bus_address, 8'ha0 };
|
| 1060 |
|
|
end
|
| 1061 |
|
|
end else if (state == `WBQSPI_WBDECODE)
|
| 1062 |
|
|
begin
|
| 1063 |
|
|
if ((~spi_busy)&&(o_qspi_cs_n)&&(~spi_wr)) // only in full idle ...
|
| 1064 |
|
|
begin
|
| 1065 |
|
|
// Data register access
|
| 1066 |
|
|
if (~spif_ctrl)
|
| 1067 |
|
|
begin
|
| 1068 |
|
|
spi_in <= { 8'h06, 24'h00 };
|
| 1069 |
|
|
end else if ((spif_ctrl)&&(spif_cmd))
|
| 1070 |
|
|
begin
|
| 1071 |
|
|
`ifdef READ_ONLY
|
| 1072 |
|
|
`else
|
| 1073 |
|
|
spi_in <= { 8'h06, 24'h00 };
|
| 1074 |
|
|
`endif
|
| 1075 |
|
|
end else begin // on (~spif_we)
|
| 1076 |
|
|
case(spif_addr[1:0])
|
| 1077 |
|
|
2'b00: ;// Read local register
|
| 1078 |
|
|
2'b01: // Read configuration register
|
| 1079 |
|
|
spi_in <= { 8'h35, 24'h00};
|
| 1080 |
|
|
2'b10: // Read status register
|
| 1081 |
|
|
spi_in <= { 8'h05, 24'h00};
|
| 1082 |
|
|
2'b11: // Read ID register
|
| 1083 |
|
|
spi_in <= { 8'h9f, 24'h00};
|
| 1084 |
|
|
endcase
|
| 1085 |
|
|
end
|
| 1086 |
|
|
end
|
| 1087 |
|
|
end else if (state == `WBQSPI_RD_DUMMY)
|
| 1088 |
|
|
begin
|
| 1089 |
|
|
spi_in <= { 8'h00, 24'h00 };
|
| 1090 |
|
|
end else if (state == `WBQSPI_QRD_ADDRESS)
|
| 1091 |
|
|
begin
|
| 1092 |
|
|
spi_in <= { reg_address, 8'ha0 };
|
| 1093 |
|
|
end else if (state == `WBQSPI_QRD_DUMMY)
|
| 1094 |
|
|
begin
|
| 1095 |
|
|
spi_in <= { 8'ha0, 24'h00 }; // Mode byte, then 2 bytes dummy
|
| 1096 |
|
|
end else if (state == `WBQSPI_READ_CMD)
|
| 1097 |
|
|
begin // Issue our first command to read 32 bits.
|
| 1098 |
|
|
spi_in <= { 8'hff, 24'h00 }; // Empty
|
| 1099 |
|
|
end else if (state == `WBQSPI_READ_DATA)
|
| 1100 |
|
|
begin
|
| 1101 |
|
|
spi_in <= 32'h00;
|
| 1102 |
|
|
end else if (state == `WBQSPI_WAIT_TIL_RDIDLE)
|
| 1103 |
|
|
begin // Wait 'til idle, but then go to fast read idle instead of full
|
| 1104 |
|
|
end else if (state == `WBQSPI_READ_ID_CMD)
|
| 1105 |
|
|
begin // We came into here immediately after issuing a 0x9f command
|
| 1106 |
|
|
spi_in <= 32'h00; // Irrelevant
|
| 1107 |
|
|
end else if (state == `WBQSPI_READ_ID)
|
| 1108 |
|
|
begin
|
| 1109 |
|
|
end else if (state == `WBQSPI_READ_STATUS)
|
| 1110 |
|
|
begin // We enter after the command has been given, for now just
|
| 1111 |
|
|
end else if (state == `WBQSPI_READ_CONFIG)
|
| 1112 |
|
|
begin // We enter after the command has been given, for now just
|
| 1113 |
|
|
`ifndef READ_ONLY
|
| 1114 |
|
|
end else if (state == `WBQSPI_WAIT_WIP_CLEAR)
|
| 1115 |
|
|
begin
|
| 1116 |
|
|
if (~spi_busy)
|
| 1117 |
|
|
spi_in <= { 8'h05, 24'h0000 };
|
| 1118 |
|
|
end else if (state == `WBQSPI_CHECK_WIP_CLEAR)
|
| 1119 |
|
|
begin
|
| 1120 |
|
|
spi_in <= 32'h0000; // Values here are actually irrelevant
|
| 1121 |
|
|
end else if (state == `WBQSPI_CHECK_WIP_DONE)
|
| 1122 |
|
|
begin
|
| 1123 |
|
|
if ((o_qspi_cs_n)&&(~spi_busy)) // Chip select line is high, we can continue
|
| 1124 |
|
|
begin
|
| 1125 |
|
|
// The bottom 24 bits are either don't cares, or the
|
| 1126 |
|
|
// address we want. Set them to be the address always,
|
| 1127 |
|
|
// to spare a touch on their logic.
|
| 1128 |
|
|
spi_in <= { 8'heb, reg_address };
|
| 1129 |
|
|
casez({ spif_cmd, spif_ctrl, spif_addr[1:0] })
|
| 1130 |
|
|
4'b00??: begin // Read data from ... somewhere
|
| 1131 |
|
|
if (quad_mode_enabled)
|
| 1132 |
|
|
begin
|
| 1133 |
|
|
spi_in[31:24] <= 8'heb;
|
| 1134 |
|
|
end else begin
|
| 1135 |
|
|
spi_in[31:24] <= 8'h0b;
|
| 1136 |
|
|
end end
|
| 1137 |
|
|
4'b10??: // Write data to ... anywhere
|
| 1138 |
|
|
spi_in[31:24] <= 8'h06 ;
|
| 1139 |
|
|
4'b0110: // Read status register
|
| 1140 |
|
|
spi_in[31:24] <= 8'h05 ;
|
| 1141 |
|
|
4'b0111:
|
| 1142 |
|
|
spi_in[31:24] <= 8'h9f ;
|
| 1143 |
|
|
default: begin //
|
| 1144 |
|
|
end
|
| 1145 |
|
|
endcase
|
| 1146 |
|
|
end
|
| 1147 |
|
|
end else if (state == `WBQSPI_WEN)
|
| 1148 |
|
|
begin // We came here after issuing a write enable command
|
| 1149 |
|
|
end else if (state == `WBQSPI_PP)
|
| 1150 |
|
|
begin // We come here under a full stop / full port idle mode
|
| 1151 |
|
|
spi_in <= { 8'h02, reg_address };
|
| 1152 |
|
|
end else if (state == `WBQSPI_QPP)
|
| 1153 |
|
|
begin // We come here under a full stop / full port idle mode
|
| 1154 |
|
|
spi_in <= { 8'h32, reg_address };
|
| 1155 |
|
|
end else if (state == `WBQSPI_WR_DATA)
|
| 1156 |
|
|
begin
|
| 1157 |
|
|
spi_in <= {
|
| 1158 |
|
|
spif_data[ 7: 0],
|
| 1159 |
|
|
spif_data[15: 8],
|
| 1160 |
|
|
spif_data[23:16],
|
| 1161 |
|
|
spif_data[31:24] };
|
| 1162 |
|
|
end else if (state == `WBQSPI_WR_BUS_CYCLE)
|
| 1163 |
|
|
begin
|
| 1164 |
|
|
end else if (state == `WBQSPI_WRITE_CONFIG)
|
| 1165 |
|
|
begin // We enter immediately after commanding a WEN
|
| 1166 |
|
|
// spi_in <= { 8'h01, last_status, spif_data[7:0], 8'h00 };
|
| 1167 |
|
|
spi_in <= { 8'h01, last_status, 6'h0, spif_data[1:0], 8'h00 };
|
| 1168 |
|
|
end else if (state == `WBQSPI_WRITE_STATUS)
|
| 1169 |
|
|
begin // We enter immediately after commanding a WEN
|
| 1170 |
|
|
spi_in <= { 8'h01, spif_data[7:0], 16'h00 };
|
| 1171 |
|
|
end else if (state == `WBQSPI_ERASE_CMD)
|
| 1172 |
|
|
begin // Know that WIP is clear on entry, WEN has just been commanded
|
| 1173 |
|
|
// Here's the erase command
|
| 1174 |
|
|
spi_in <= { 8'hd8, 2'h0, spif_data[19:14], 14'h000, 2'b00 };
|
| 1175 |
|
|
end else if (state == `WBQSPI_ERASE_BLOCK)
|
| 1176 |
|
|
begin
|
| 1177 |
|
|
end else if (state == `WBQSPI_CLEAR_STATUS)
|
| 1178 |
|
|
begin // Issue a clear status command
|
| 1179 |
|
|
spi_in <= { 8'h30, 24'h00 };
|
| 1180 |
|
|
end else if (state == `WBQSPI_IDLE_CHECK_WIP)
|
| 1181 |
|
|
begin // We are now in read status register mode
|
| 1182 |
|
|
`endif // !READ_ONLY
|
| 1183 |
|
|
end
|
| 1184 |
|
|
end
|
| 1185 |
|
|
|
| 1186 |
|
|
|
| 1187 |
|
|
initial wr_same_row = 1'b0;
|
| 1188 |
|
|
always @(posedge i_clk)
|
| 1189 |
|
|
wr_same_row <= ((i_wb_data_stb)&&(i_wb_we)
|
| 1190 |
|
|
&&(i_wb_addr[5:0] == (spif_addr[5:0]+6'h1))
|
| 1191 |
|
|
&&(i_wb_addr[(ADDRESS_WIDTH-3):6]
|
| 1192 |
|
|
==spif_addr[(ADDRESS_WIDTH-3):6]));
|
| 1193 |
|
|
initial pipeline_read = 1'b0;
|
| 1194 |
|
|
always @(posedge i_clk)
|
| 1195 |
|
|
pipeline_read <=((i_wb_data_stb)&&(~i_wb_we)&&(i_wb_addr== (spif_addr+1)));
|
| 1196 |
|
|
|
| 1197 |
|
|
// Command and control during the reset sequence
|
| 1198 |
|
|
assign o_qspi_cs_n = (spif_override)?spif_cmd :w_qspi_cs_n;
|
| 1199 |
|
|
assign o_qspi_sck = (spif_override)?spif_ctrl:w_qspi_sck;
|
| 1200 |
|
|
assign o_qspi_mod = (spif_override)? 2'b01 :w_qspi_mod;
|
| 1201 |
|
|
assign o_qspi_dat = (spif_override)? 4'b00 :w_qspi_dat;
|
| 1202 |
|
|
endmodule
|