OpenCores
URL https://opencores.org/ocsvn/qspiflash/qspiflash/trunk

Subversion Repositories qspiflash

Compare Revisions

  • This comparison shows the changes necessary to convert path
    /qspiflash/trunk/rtl
    from Rev 4 to Rev 7
    Reverse comparison

Rev 4 → Rev 7

/flash_config.v
0,0 → 1,48
///////////////////////////////////////////////////////////////////////////
//
// Filename: flashconfig.v
//
// Project: Wishbone Controlled Quad SPI Flash Controller
//
// Purpose: A configuration file, separated from the controller file, so
// that multiple files can use the same wishbone Quad Spi Flash
// controller, while each having a separate configuration. Currently,
// the configuration only includes whether the flash is read only or not.
// Other configuration options may be added later.
//
//
// Creator: Dan Gisselquist
// Gisselquist Tecnology, LLC
//
///////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 2015, Gisselquist Technology, LLC
//
// 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
// by the Free Software Foundation, either version 3 of the License, or (at
// your option) any later version.
//
// This program is distributed in the hope that it will be useful, but WITHOUT
// ANY WARRANTY; without even the implied warranty of MERCHANTIBILITY or
// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
// for more details.
//
// 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
// target there if the PDF file isn't present.) If not, see
// <http://www.gnu.org/licenses/> for a copy.
//
// License: GPL, v3, as defined and found on www.gnu.org,
// http://www.gnu.org/licenses/gpl.html
//
//
///////////////////////////////////////////////////////////////////////////
//
`ifndef FLASH_CONFIG_V
`define FLASH_CONFIG_V
//
// `define READ_ONLY
//
`endif
//
/wbqspiflash.v
51,37 → 51,46
//
//
///////////////////////////////////////////////////////////////////////////
//
`include "flash_config.v"
//
`define WBQSPI_RESET 0
`define WBQSPI_RESET_QUADMODE 1
`define WBQSPI_IDLE 2
`define WBQSPI_RDIDLE 3 // Idle, but in fast read mode
`define WBQSPI_WBDECODE 4
`define WBQSPI_WAIT_WIP_CLEAR 5
`define WBQSPI_CHECK_WIP_CLEAR 6
`define WBQSPI_CHECK_WIP_DONE 7
`define WBQSPI_WEN 8
`define WBQSPI_PP 9 // Program page
`define WBQSPI_QPP 10 // Program page, 4 bit mode
`define WBQSPI_WR_DATA 11
`define WBQSPI_WR_BUS_CYCLE 12
`define WBQSPI_RD_DUMMY 13
`define WBQSPI_QRD_ADDRESS 14
`define WBQSPI_QRD_DUMMY 15
`define WBQSPI_READ_CMD 16
`define WBQSPI_READ_DATA 17
`define WBQSPI_WAIT_TIL_RDIDLE 18
`define WBQSPI_READ_ID_CMD 19
`define WBQSPI_READ_ID 20
`define WBQSPI_READ_STATUS 21
`define WBQSPI_READ_CONFIG 22
`define WBQSPI_WRITE_STATUS 23
`define WBQSPI_WRITE_CONFIG 24
`define WBQSPI_ERASE_WEN 25
`define WBQSPI_ERASE_CMD 26
`define WBQSPI_ERASE_BLOCK 27
`define WBQSPI_CLEAR_STATUS 28
`define WBQSPI_IDLE_CHECK_WIP 29
`define WBQSPI_WAIT_TIL_IDLE 30
`define WBQSPI_RD_DUMMY 5
`define WBQSPI_QRD_ADDRESS 6
`define WBQSPI_QRD_DUMMY 7
`define WBQSPI_READ_CMD 8
`define WBQSPI_READ_DATA 9
`define WBQSPI_WAIT_TIL_RDIDLE 10
`define WBQSPI_READ_ID_CMD 11
`define WBQSPI_READ_ID 12
`define WBQSPI_READ_STATUS 13
`define WBQSPI_READ_CONFIG 14
`define WBQSPI_WAIT_TIL_IDLE 15
//
//
`ifndef READ_ONLY
//
`define WBQSPI_WAIT_WIP_CLEAR 16
`define WBQSPI_CHECK_WIP_CLEAR 17
`define WBQSPI_CHECK_WIP_DONE 18
`define WBQSPI_WEN 19
`define WBQSPI_PP 20 // Program page
`define WBQSPI_QPP 21 // Program page, 4 bit mode
`define WBQSPI_WR_DATA 22
`define WBQSPI_WR_BUS_CYCLE 23
`define WBQSPI_WRITE_STATUS 24
`define WBQSPI_WRITE_CONFIG 25
`define WBQSPI_ERASE_WEN 26
`define WBQSPI_ERASE_CMD 27
`define WBQSPI_ERASE_BLOCK 28
`define WBQSPI_CLEAR_STATUS 29
`define WBQSPI_IDLE_CHECK_WIP 30
//
`endif
 
module wbqspiflash(i_clk_100mhz,
// Internal wishbone connections
92,10 → 101,11
// Quad Spi connections to the external device
o_qspi_sck, o_qspi_cs_n, o_qspi_mod, o_qspi_dat, i_qspi_dat,
o_interrupt);
parameter ADDRESS_WIDTH=22;
input i_clk_100mhz;
// Wishbone, inputs first
input i_wb_cyc, i_wb_data_stb, i_wb_ctrl_stb, i_wb_we;
input [19:0] i_wb_addr;
input [(ADDRESS_WIDTH-3):0] i_wb_addr;
input [31:0] i_wb_data;
// then outputs
output reg o_wb_ack;
108,6 → 118,7
input [3:0] i_qspi_dat;
// Interrupt line
output reg o_interrupt;
// output wire [31:0] o_debug;
 
reg spi_wr, spi_hold, spi_spd, spi_dir;
reg [31:0] spi_in;
117,6 → 128,7
wire w_qspi_sck, w_qspi_cs_n;
wire [3:0] w_qspi_dat;
wire [1:0] w_qspi_mod;
// wire [22:0] spi_dbg;
llqspi lldriver(i_clk_100mhz,
spi_wr, spi_hold, spi_in, spi_len, spi_spd, spi_dir,
spi_out, spi_valid, spi_busy,
125,11 → 137,11
 
// Erase status tracking
reg write_in_progress, write_protect;
reg [5:0] erased_sector;
reg [(ADDRESS_WIDTH-17):0] erased_sector;
reg dirty_sector;
initial begin
write_in_progress = 1'b0;
erased_sector = 6'h00;
erased_sector = 0;
dirty_sector = 1'b1;
write_protect = 1'b1;
end
137,13 → 149,15
reg [7:0] last_status;
reg quad_mode_enabled;
reg spif_cmd, spif_override;
reg [19:0] spif_addr;
reg [(ADDRESS_WIDTH-3):0] spif_addr;
reg [31:0] spif_data;
reg [5:0] state;
reg spif_ctrl, spif_req;
wire [5:0] spif_sector;
assign spif_sector = spif_addr[19:14];
wire [(ADDRESS_WIDTH-17):0] spif_sector;
assign spif_sector = spif_addr[(ADDRESS_WIDTH-3):14];
 
// assign o_debug = { spi_wr, spi_spd, spi_hold, state, spi_dbg };
 
initial state = `WBQSPI_RESET;
initial o_wb_ack = 1'b0;
initial o_wb_stall = 1'b1;
215,6 → 229,11
 
if (i_wb_we) // Request to write a page
begin
`ifdef READ_ONLY
o_wb_ack <= 1'b1;
o_wb_stall <= 1'b0;
end else
`else
if((~write_protect)&&(~write_in_progress))
begin // 00
spi_wr <= 1'b1;
239,6 → 258,7
o_wb_stall <= 1'b1;
end
end else if (~write_in_progress)
`endif
begin // Read access, normal mode(s)
o_wb_ack <= 1'b0;
o_wb_stall <= 1'b1;
245,14 → 265,19
spi_wr <= 1'b1; // Write cmd to device
if (quad_mode_enabled)
begin
spi_in <= { 8'heb, 2'b00, i_wb_addr[19:0], 2'b00 };
spi_in <= { 8'heb,
{(24-ADDRESS_WIDTH){1'b0}},
i_wb_addr[(ADDRESS_WIDTH-3):0], 2'b00 };
state <= `WBQSPI_QRD_ADDRESS;
spi_len <= 2'b00; // single byte, cmd only
end else begin
spi_in <= { 8'h0b, 2'b00, i_wb_addr[19:0], 2'b00 };
spi_in <= { 8'h0b,
{(24-ADDRESS_WIDTH){1'b0}},
i_wb_addr[(ADDRESS_WIDTH-3):0], 2'b00 };
state <= `WBQSPI_RD_DUMMY;
spi_len <= 2'b11; // cmd+addr,32bits
end
`ifndef READ_ONLY
end else begin
// A write is in progress ... need to stall
// the bus until the write is complete.
259,9 → 284,14
state <= `WBQSPI_WAIT_WIP_CLEAR;
o_wb_ack <= 1'b0;
o_wb_stall <= 1'b1;
`endif
end
end else if ((i_wb_cyc)&&(i_wb_ctrl_stb)&&(i_wb_we))
begin
`ifdef READ_ONLY
o_wb_ack <= 1'b1;
o_wb_stall <= 1'b0;
`else
o_wb_stall <= 1'b1;
case(i_wb_addr[1:0])
2'b00: begin // Erase command register
321,6 → 351,7
o_wb_stall <= 1'b0;
end
endcase
`endif
end else if ((i_wb_cyc)&&(i_wb_ctrl_stb)) // &&(~i_wb_we))
begin
case(i_wb_addr[1:0])
341,7 → 372,7
dirty_sector, spi_busy,
~write_protect,
quad_mode_enabled,
7'h00,
{(29-ADDRESS_WIDTH){1'b0}},
erased_sector, 14'h000 };
end end
2'b01: begin // Read configuration register
372,6 → 403,7
o_wb_stall <= 1'b1;
end
endcase
`ifndef READ_ONLY
end else if ((~i_wb_cyc)&&(write_in_progress))
begin
state <= `WBQSPI_IDLE_CHECK_WIP;
381,6 → 413,7
 
o_wb_ack <= 1'b0;
o_wb_stall <= 1'b1;
`endif
end
end else if (state == `WBQSPI_RDIDLE)
begin
400,7 → 433,8
o_wb_stall <= 1'b1;
spi_wr <= 1'b1;
spi_len <= 2'b10; // Write address, but not mode byte
spi_in <= { 2'h0, i_wb_addr[19:0], 2'h0, 8'ha0 };
spi_in <= { {(24-ADDRESS_WIDTH){1'b0}},
i_wb_addr[(ADDRESS_WIDTH-3):0], 2'b00, 8'ha0 };
state <= `WBQSPI_QRD_DUMMY;
end else if((i_wb_cyc)&&(i_wb_ctrl_stb)&&(~i_wb_we)&&(i_wb_addr[1:0] == 2'b00))
begin
412,7 → 446,7
dirty_sector, spi_busy,
~write_protect,
quad_mode_enabled,
7'h00,
{(29-ADDRESS_WIDTH){1'b0}},
erased_sector, 14'h000 };
end else if((i_wb_cyc)&&((i_wb_ctrl_stb)||(i_wb_data_stb)))
begin // Need to release the device from quad mode for all else
445,6 → 479,11
begin
if (spif_cmd) // Request to write a page
begin
`ifdef READ_ONLY
o_wb_ack <= spif_req;
o_wb_stall <= 1'b0;
state <= `WBQSPI_IDLE;
`else
if((~write_protect)&&(~write_in_progress))
begin // 00
spi_wr <= 1'b1;
471,13 → 510,20
end
// end else if (~write_in_progress) // always true
// but ... we wouldn't get here on a normal read access
`endif
end else begin
// Something's wrong, we should never get here
// Something's wrong, we should never
// get here
// Attempt to go to idle to recover
state <= `WBQSPI_IDLE;
end
end else if ((spif_ctrl)&&(spif_cmd))
begin
`ifdef READ_ONLY
o_wb_ack <= spif_req;
o_wb_stall <= 1'b0;
state <= `WBQSPI_IDLE;
`else
o_wb_stall <= 1'b1;
case(spif_addr[1:0])
2'b00: begin // Erase command register
529,6 → 575,7
state <= `WBQSPI_IDLE;
end
endcase
`endif
end else begin // on (~spif_we)
case(spif_addr[1:0])
2'b00: begin // Read local register
568,203 → 615,10
endcase
end
end
end else if (state == `WBQSPI_WAIT_WIP_CLEAR)
begin
o_wb_stall <= 1'b1;
o_wb_ack <= 1'b0;
spi_wr <= 1'b0;
spif_req<= (spif_req) && (i_wb_cyc);
if (~spi_busy)
begin
spi_wr <= 1'b1;
spi_in <= { 8'h05, 24'h0000 };
spi_hold <= 1'b1;
spi_len <= 2'b01; // 16 bits write, so we can read 8
state <= `WBQSPI_CHECK_WIP_CLEAR;
spi_spd <= 1'b0; // Slow speed
spi_dir <= 1'b0;
end
end else if (state == `WBQSPI_CHECK_WIP_CLEAR)
begin
o_wb_stall <= 1'b1;
o_wb_ack <= 1'b0;
// Repeat as often as necessary until we are clear
spi_wr <= 1'b1;
spi_in <= 32'h0000; // Values here are actually irrelevant
spi_hold <= 1'b1;
spi_len <= 2'b00; // One byte at a time
spi_spd <= 1'b0; // Slow speed
spi_dir <= 1'b0;
spif_req<= (spif_req) && (i_wb_cyc);
if ((spi_valid)&&(~spi_out[0]))
begin
state <= `WBQSPI_CHECK_WIP_DONE;
spi_wr <= 1'b0;
spi_hold <= 1'b0;
write_in_progress <= 1'b0;
last_status <= spi_out[7:0];
end
end else if (state == `WBQSPI_CHECK_WIP_DONE)
begin
o_wb_stall <= 1'b1;
o_wb_ack <= 1'b0;
// Let's let the SPI port come back to a full idle,
// and the chip select line go low before continuing
spi_wr <= 1'b0;
spi_len <= 2'b00;
spi_hold <= 1'b0;
spi_spd <= 1'b0; // Slow speed
spi_dir <= 1'b0;
spif_req<= (spif_req) && (i_wb_cyc);
if ((o_qspi_cs_n)&&(~spi_busy)) // Chip select line is high, we can continue
begin
spi_wr <= 1'b0;
spi_hold <= 1'b0;
 
casez({ spif_cmd, spif_ctrl, spif_addr[1:0] })
4'b00??: begin // Read data from ... somewhere
spi_wr <= 1'b1; // Write cmd to device
if (quad_mode_enabled)
begin
spi_in <= { 8'heb, 2'b00, spif_addr[19:0], 2'b00 };
state <= `WBQSPI_QRD_ADDRESS;
// spi_len <= 2'b00; // single byte, cmd only
end else begin
spi_in <= { 8'h0b, 2'b00, spif_addr[19:0], 2'b00 };
state <= `WBQSPI_RD_DUMMY;
spi_len <= 2'b11; // Send cmd and addr
end end
4'b10??: begin // Write data to ... anywhere
spi_wr <= 1'b1;
spi_len <= 2'b00; // 8 bits
// Send a write enable command
spi_in <= { 8'h06, 24'h00 };
state <= `WBQSPI_WEN;
end
4'b0110: begin // Read status register
state <= `WBQSPI_READ_STATUS;
spi_wr <= 1'b1;
spi_len <= 2'b01; // 8 bits out, 8 bits in
spi_in <= { 8'h05, 24'h00};
end
4'b0111: begin
state <= `WBQSPI_READ_ID_CMD;
spi_wr <= 1'b1;
spi_len <= 2'b00;
spi_in <= { 8'h9f, 24'h00};
end
default: begin //
o_wb_stall <= 1'b1;
o_wb_ack <= spif_req;
state <= `WBQSPI_WAIT_TIL_IDLE;
end
endcase
// spif_cmd <= i_wb_we;
// spif_addr <= i_wb_addr;
// spif_data <= i_wb_data;
// spif_ctrl <= (i_wb_ctrl_stb)&&(~i_wb_data_stb);
// spi_wr <= 1'b0; // Keep the port idle, unless told otherwise
end
end else if (state == `WBQSPI_WEN)
begin // We came here after issuing a write enable command
spi_wr <= 1'b0;
o_wb_ack <= 1'b0;
o_wb_stall <= 1'b1;
spif_req<= (spif_req) && (i_wb_cyc);
if ((~spi_busy)&&(o_qspi_cs_n)&&(~spi_wr)) // Let's come to a full stop
state <= (quad_mode_enabled)?`WBQSPI_QPP:`WBQSPI_PP;
// state <= `WBQSPI_PP;
end else if (state == `WBQSPI_PP)
begin // We come here under a full stop / full port idle mode
// Issue our command immediately
spi_wr <= 1'b1;
spi_in <= { 8'h02, 2'h0, spif_addr, 2'b00 };
spi_len <= 2'b11;
spi_hold <= 1'b1;
spi_spd <= 1'b0;
spi_dir <= 1'b0; // Writing
spif_req<= (spif_req) && (i_wb_cyc);
 
// Once we get busy, move on
if (spi_busy)
state <= `WBQSPI_WR_DATA;
if (spif_sector == erased_sector)
dirty_sector <= 1'b1;
end else if (state == `WBQSPI_QPP)
begin // We come here under a full stop / full port idle mode
// Issue our command immediately
spi_wr <= 1'b1;
spi_in <= { 8'h32, 2'h0, spif_addr, 2'b00 };
spi_len <= 2'b11;
spi_hold <= 1'b1;
spi_spd <= 1'b0;
spi_dir <= 1'b0; // Writing
spif_req<= (spif_req) && (i_wb_cyc);
 
// Once we get busy, move on
if (spi_busy)
begin
// spi_wr is irrelevant here ...
// Set the speed value once, but wait til we get busy
// to do so.
spi_spd <= 1'b1;
state <= `WBQSPI_WR_DATA;
end
if (spif_sector == erased_sector)
dirty_sector <= 1'b1;
end else if (state == `WBQSPI_WR_DATA)
begin
o_wb_stall <= 1'b1;
o_wb_ack <= 1'b0;
spi_wr <= 1'b1; // write without waiting
spi_in <= {
spif_data[ 7: 0],
spif_data[15: 8],
spif_data[23:16],
spif_data[31:24] };
spi_len <= 2'b11; // Write 4 bytes
spi_hold <= 1'b1;
if (~spi_busy)
begin
o_wb_ack <= spif_req; // Ack when command given
state <= `WBQSPI_WR_BUS_CYCLE;
end
spif_req<= (spif_req) && (i_wb_cyc);
end else if (state == `WBQSPI_WR_BUS_CYCLE)
begin
o_wb_ack <= 1'b0; // Turn off our ack and stall flags
o_wb_stall <= 1'b1;
spi_wr <= 1'b0;
spi_hold <= 1'b1;
write_in_progress <= 1'b1;
spif_req<= (spif_req) && (i_wb_cyc);
if (~i_wb_cyc)
begin
state <= `WBQSPI_WAIT_TIL_IDLE;
spi_hold <= 1'b0;
end else if (spi_wr)
begin // Give the SPI a chance to get busy on the last write
// Do nothing here.
end else if ((i_wb_data_stb)&&(i_wb_we)
&&(i_wb_addr == (spif_addr+1))
&&(i_wb_addr[19:6]==spif_addr[19:6]))
begin
spif_cmd <= 1'b1;
spif_data <= i_wb_data;
spif_addr <= i_wb_addr;
spif_ctrl <= 1'b0;
spif_req<= 1'b1;
// We'll keep the bus stalled on this request
// for a while
state <= `WBQSPI_WR_DATA;
o_wb_ack <= 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
begin
spi_hold <= 1'b0;
spi_wr <= 1'b0;
state <= `WBQSPI_WAIT_TIL_IDLE;
end // Otherwise we stay here
//
//
// READ DATA section: for both data and commands
//
end else if (state == `WBQSPI_RD_DUMMY)
begin
o_wb_ack <= 1'b0;
791,7 → 645,8
o_wb_stall <= 1'b1;
 
spi_wr <= 1'b1; // Non-stop
spi_in <= { 2'b0, spif_addr, 2'b0, 8'ha0 };
spi_in <= { {(24-ADDRESS_WIDTH){1'b0}},
spif_addr[(ADDRESS_WIDTH-3):0], 2'b00, 8'ha0 };
spi_len <= 2'b10; // Write address, not mode byte
spi_spd <= 1'b1;
spi_dir <= 1'b0; // Still writing
950,7 → 805,7
dirty_sector, spi_busy,
~write_protect,
quad_mode_enabled,
7'h00,
{(29-ADDRESS_WIDTH){1'b0}},
erased_sector, 14'h000 };
end else begin
o_wb_data <= { 24'h00, spi_out[7:0] };
981,6 → 836,217
o_wb_stall <= 1'b0;
spif_req <= 1'b0;
end
 
//
//
// Write/erase data section
//
`ifndef READ_ONLY
end else if (state == `WBQSPI_WAIT_WIP_CLEAR)
begin
o_wb_stall <= 1'b1;
o_wb_ack <= 1'b0;
spi_wr <= 1'b0;
spif_req<= (spif_req) && (i_wb_cyc);
if (~spi_busy)
begin
spi_wr <= 1'b1;
spi_in <= { 8'h05, 24'h0000 };
spi_hold <= 1'b1;
spi_len <= 2'b01; // 16 bits write, so we can read 8
state <= `WBQSPI_CHECK_WIP_CLEAR;
spi_spd <= 1'b0; // Slow speed
spi_dir <= 1'b0;
end
end else if (state == `WBQSPI_CHECK_WIP_CLEAR)
begin
o_wb_stall <= 1'b1;
o_wb_ack <= 1'b0;
// Repeat as often as necessary until we are clear
spi_wr <= 1'b1;
spi_in <= 32'h0000; // Values here are actually irrelevant
spi_hold <= 1'b1;
spi_len <= 2'b00; // One byte at a time
spi_spd <= 1'b0; // Slow speed
spi_dir <= 1'b0;
spif_req<= (spif_req) && (i_wb_cyc);
if ((spi_valid)&&(~spi_out[0]))
begin
state <= `WBQSPI_CHECK_WIP_DONE;
spi_wr <= 1'b0;
spi_hold <= 1'b0;
write_in_progress <= 1'b0;
last_status <= spi_out[7:0];
end
end else if (state == `WBQSPI_CHECK_WIP_DONE)
begin
o_wb_stall <= 1'b1;
o_wb_ack <= 1'b0;
// Let's let the SPI port come back to a full idle,
// and the chip select line go low before continuing
spi_wr <= 1'b0;
spi_len <= 2'b00;
spi_hold <= 1'b0;
spi_spd <= 1'b0; // Slow speed
spi_dir <= 1'b0;
spif_req<= (spif_req) && (i_wb_cyc);
if ((o_qspi_cs_n)&&(~spi_busy)) // Chip select line is high, we can continue
begin
spi_wr <= 1'b0;
spi_hold <= 1'b0;
 
casez({ spif_cmd, spif_ctrl, spif_addr[1:0] })
4'b00??: begin // Read data from ... somewhere
spi_wr <= 1'b1; // Write cmd to device
if (quad_mode_enabled)
begin
spi_in <= { 8'heb,
{(24-ADDRESS_WIDTH){1'b0}},
spif_addr[(ADDRESS_WIDTH-3):0], 2'b00 };
state <= `WBQSPI_QRD_ADDRESS;
// spi_len <= 2'b00; // single byte, cmd only
end else begin
spi_in <= { 8'h0b,
{(24-ADDRESS_WIDTH){1'b0}},
spif_addr[(ADDRESS_WIDTH-3):0], 2'b00 };
state <= `WBQSPI_RD_DUMMY;
spi_len <= 2'b11; // Send cmd and addr
end end
4'b10??: begin // Write data to ... anywhere
spi_wr <= 1'b1;
spi_len <= 2'b00; // 8 bits
// Send a write enable command
spi_in <= { 8'h06, 24'h00 };
state <= `WBQSPI_WEN;
end
4'b0110: begin // Read status register
state <= `WBQSPI_READ_STATUS;
spi_wr <= 1'b1;
spi_len <= 2'b01; // 8 bits out, 8 bits in
spi_in <= { 8'h05, 24'h00};
end
4'b0111: begin
state <= `WBQSPI_READ_ID_CMD;
spi_wr <= 1'b1;
spi_len <= 2'b00;
spi_in <= { 8'h9f, 24'h00};
end
default: begin //
o_wb_stall <= 1'b1;
o_wb_ack <= spif_req;
state <= `WBQSPI_WAIT_TIL_IDLE;
end
endcase
// spif_cmd <= i_wb_we;
// spif_addr <= i_wb_addr;
// spif_data <= i_wb_data;
// spif_ctrl <= (i_wb_ctrl_stb)&&(~i_wb_data_stb);
// spi_wr <= 1'b0; // Keep the port idle, unless told otherwise
end
end else if (state == `WBQSPI_WEN)
begin // We came here after issuing a write enable command
spi_wr <= 1'b0;
o_wb_ack <= 1'b0;
o_wb_stall <= 1'b1;
spif_req<= (spif_req) && (i_wb_cyc);
if ((~spi_busy)&&(o_qspi_cs_n)&&(~spi_wr)) // Let's come to a full stop
state <= (quad_mode_enabled)?`WBQSPI_QPP:`WBQSPI_PP;
// state <= `WBQSPI_PP;
end else if (state == `WBQSPI_PP)
begin // We come here under a full stop / full port idle mode
// Issue our command immediately
spi_wr <= 1'b1;
spi_in <= { 8'h02,
{(24-ADDRESS_WIDTH){1'b0}},
spif_addr[(ADDRESS_WIDTH-3):0], 2'b00 };
spi_len <= 2'b11;
spi_hold <= 1'b1;
spi_spd <= 1'b0;
spi_dir <= 1'b0; // Writing
spif_req<= (spif_req) && (i_wb_cyc);
 
// Once we get busy, move on
if (spi_busy)
state <= `WBQSPI_WR_DATA;
if (spif_sector == erased_sector)
dirty_sector <= 1'b1;
end else if (state == `WBQSPI_QPP)
begin // We come here under a full stop / full port idle mode
// Issue our command immediately
spi_wr <= 1'b1;
spi_in <= { 8'h32,
{(24-ADDRESS_WIDTH){1'b0}},
spif_addr[(ADDRESS_WIDTH-3):0], 2'b00 };
spi_len <= 2'b11;
spi_hold <= 1'b1;
spi_spd <= 1'b0;
spi_dir <= 1'b0; // Writing
spif_req<= (spif_req) && (i_wb_cyc);
 
// Once we get busy, move on
if (spi_busy)
begin
// spi_wr is irrelevant here ...
// Set the speed value once, but wait til we get busy
// to do so.
spi_spd <= 1'b1;
state <= `WBQSPI_WR_DATA;
end
if (spif_sector == erased_sector)
dirty_sector <= 1'b1;
end else if (state == `WBQSPI_WR_DATA)
begin
o_wb_stall <= 1'b1;
o_wb_ack <= 1'b0;
spi_wr <= 1'b1; // write without waiting
spi_in <= {
spif_data[ 7: 0],
spif_data[15: 8],
spif_data[23:16],
spif_data[31:24] };
spi_len <= 2'b11; // Write 4 bytes
spi_hold <= 1'b1;
if (~spi_busy)
begin
o_wb_ack <= spif_req; // Ack when command given
state <= `WBQSPI_WR_BUS_CYCLE;
end
spif_req<= (spif_req) && (i_wb_cyc);
end else if (state == `WBQSPI_WR_BUS_CYCLE)
begin
o_wb_ack <= 1'b0; // Turn off our ack and stall flags
o_wb_stall <= 1'b1;
spi_wr <= 1'b0;
spi_hold <= 1'b1;
write_in_progress <= 1'b1;
spif_req<= (spif_req) && (i_wb_cyc);
if (~i_wb_cyc)
begin
state <= `WBQSPI_WAIT_TIL_IDLE;
spi_hold <= 1'b0;
end else if (spi_wr)
begin // Give the SPI a chance to get busy on the last write
// Do nothing here.
end else if ((i_wb_data_stb)&&(i_wb_we)
&&(i_wb_addr == (spif_addr+1))
&&(i_wb_addr[(ADDRESS_WIDTH-3):6]==spif_addr[(ADDRESS_WIDTH-3):6]))
begin
spif_cmd <= 1'b1;
spif_data <= i_wb_data;
spif_addr <= i_wb_addr;
spif_ctrl <= 1'b0;
spif_req<= 1'b1;
// We'll keep the bus stalled on this request
// for a while
state <= `WBQSPI_WR_DATA;
o_wb_ack <= 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
begin
spi_hold <= 1'b0;
spi_wr <= 1'b0;
state <= `WBQSPI_WAIT_TIL_IDLE;
end // Otherwise we stay here
end else if (state == `WBQSPI_WRITE_CONFIG)
begin // We enter immediately after commanding a WEN
o_wb_ack <= 1'b0;
1036,7 → 1102,7
// together with setting our copy of the WIP bit
write_in_progress <= 1'b1;
// keeping track of which sector we just erased
erased_sector <= spif_data[19:14];
erased_sector <= spif_data[(ADDRESS_WIDTH-3):14];
// and marking this erase sector as no longer dirty
dirty_sector <= 1'b0;
 
1100,6 → 1166,7
o_wb_ack <= 1'b0;
state <= `WBQSPI_IDLE;
end
`endif // !READ_ONLY
end else // if (state == `WBQSPI_WAIT_TIL_IDLE) or anything else
begin
spi_wr <= 1'b0;
/llqspi.v
76,6 → 76,10
output reg [3:0] o_dat;
input [3:0] i_dat;
 
// output wire [22:0] o_dbg;
// assign o_dbg = { state, spi_len,
// o_busy, o_valid, o_cs_n, o_sck, o_mod, o_dat, i_dat };
 
// Timing:
//
// Tick Clk BSY/WR CS_n BIT/MO STATE

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.