Line 1... |
Line 1... |
///////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
//
|
//
|
// Filename: wbspiflashp.v
|
// Filename: wbspiflashp.v
|
//
|
//
|
// Project: CMod S6 System on a Chip, ZipCPU demonstration project
|
// Project: CMod S6 System on a Chip, ZipCPU demonstration project
|
//
|
//
|
Line 9... |
Line 9... |
// is configured to be read only.
|
// is configured to be read only.
|
//
|
//
|
// Creator: Dan Gisselquist
|
// Creator: Dan Gisselquist
|
// Gisselquist Technology, LLC
|
// Gisselquist Technology, LLC
|
//
|
//
|
///////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
//
|
//
|
// Copyright (C) 2015-2016, Gisselquist Technology, LLC
|
// Copyright (C) 2015-2017, Gisselquist Technology, LLC
|
//
|
//
|
// This program is free software (firmware): you can redistribute it and/or
|
// This program is free software (firmware): you can redistribute it and/or
|
// modify it under the terms of the GNU General Public License as published
|
// modify it under the terms of the GNU General Public License as published
|
// by the Free Software Foundation, either version 3 of the License, or (at
|
// by the Free Software Foundation, either version 3 of the License, or (at
|
// your option) any later version.
|
// your option) any later version.
|
Line 24... |
Line 24... |
// ANY WARRANTY; without even the implied warranty of MERCHANTIBILITY or
|
// ANY WARRANTY; without even the implied warranty of MERCHANTIBILITY or
|
// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
// for more details.
|
// for more details.
|
//
|
//
|
// You should have received a copy of the GNU General Public License along
|
// You should have received a copy of the GNU General Public License along
|
// with this program. (It's in the $(ROOT)/doc directory, run make with no
|
// with this program. (It's in the $(ROOT)/doc directory. Run make with no
|
// target there if the PDF file isn't present.) If not, see
|
// target there if the PDF file isn't present.) If not, see
|
// <http://www.gnu.org/licenses/> for a copy.
|
// <http://www.gnu.org/licenses/> for a copy.
|
//
|
//
|
// License: GPL, v3, as defined and found on www.gnu.org,
|
// License: GPL, v3, as defined and found on www.gnu.org,
|
// http://www.gnu.org/licenses/gpl.html
|
// http://www.gnu.org/licenses/gpl.html
|
//
|
//
|
//
|
//
|
///////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
|
//
|
//
|
//
|
`define WBQSPI_RESET 0
|
`define WBQSPI_RESET 0
|
`define WBQSPI_RESET_QUADMODE 1
|
`define WBQSPI_RESET_QUADMODE 1
|
`define WBQSPI_IDLE 2
|
`define WBQSPI_IDLE 2
|
`define WBQSPI_RDIDLE 3 // Idle, but in fast read mode
|
`define WBQSPI_RDIDLE 3 // Idle, but in fast read mode
|
Line 82... |
Line 83... |
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;
|
|
localparam AW = ADDRESS_WIDTH-2;
|
input i_clk_100mhz;
|
input i_clk_100mhz;
|
// Wishbone, inputs first
|
// Wishbone, inputs first
|
input i_wb_cyc, i_wb_data_stb, i_wb_ctrl_stb, i_wb_we;
|
input i_wb_cyc, i_wb_data_stb, i_wb_ctrl_stb, i_wb_we;
|
input [(ADDRESS_WIDTH-3):0] i_wb_addr;
|
input [(AW-1):0] i_wb_addr;
|
input [31:0] i_wb_data;
|
input [31:0] i_wb_data;
|
// then outputs
|
// then outputs
|
output reg o_wb_ack;
|
output reg o_wb_ack;
|
output reg o_wb_stall;
|
output reg o_wb_stall;
|
output reg [31:0] o_wb_data;
|
output reg [31:0] o_wb_data;
|
Line 127... |
Line 129... |
dirty_sector = 1'b1;
|
dirty_sector = 1'b1;
|
write_protect = 1'b1;
|
write_protect = 1'b1;
|
end
|
end
|
|
|
reg [7:0] last_status;
|
reg [7:0] last_status;
|
|
reg [9:0] reset_counter;
|
reg quad_mode_enabled;
|
reg quad_mode_enabled;
|
reg spif_cmd, spif_override;
|
reg spif_cmd, spif_override;
|
reg [(ADDRESS_WIDTH-3):0] spif_addr;
|
reg [(AW-1):0] spif_addr;
|
reg [31:0] spif_data;
|
reg [31:0] spif_data;
|
reg [5:0] state;
|
reg [5:0] state;
|
reg spif_ctrl, spif_req;
|
reg spif_ctrl, spif_req;
|
|
reg alt_cmd, alt_ctrl;
|
wire [(ADDRESS_WIDTH-17):0] spif_sector;
|
wire [(ADDRESS_WIDTH-17):0] spif_sector;
|
assign spif_sector = spif_addr[(ADDRESS_WIDTH-3):14];
|
assign spif_sector = spif_addr[(AW-1):14];
|
|
|
// assign o_debug = { spi_wr, spi_spd, spi_hold, state, spi_dbg };
|
// assign o_debug = { spi_wr, spi_spd, spi_hold, state, spi_dbg };
|
|
|
initial state = `WBQSPI_RESET;
|
initial state = `WBQSPI_RESET;
|
initial o_wb_ack = 1'b0;
|
initial o_wb_ack = 1'b0;
|
initial o_wb_stall = 1'b1;
|
initial o_wb_stall = 1'b1;
|
initial spi_wr = 1'b0;
|
initial spi_wr = 1'b0;
|
initial spi_len = 2'b00;
|
initial spi_len = 2'b00;
|
initial quad_mode_enabled = 1'b0;
|
initial quad_mode_enabled = 1'b0;
|
initial o_interrupt = 1'b0;
|
initial o_interrupt = 1'b0;
|
|
initial spif_override = 1'b1;
|
|
initial spif_ctrl = 1'b0;
|
always @(posedge i_clk_100mhz)
|
always @(posedge i_clk_100mhz)
|
begin
|
begin
|
spif_override <= 1'b0;
|
spif_override <= 1'b0;
|
|
alt_cmd <= (reset_counter[9:8]==2'b10)?reset_counter[3]:1'b1; // Toggle CS_n
|
|
alt_ctrl <= (reset_counter[9:8]==2'b10)?reset_counter[0]:1'b1; // Toggle clock too
|
if (state == `WBQSPI_RESET)
|
if (state == `WBQSPI_RESET)
|
begin
|
begin
|
// From a reset, we should
|
// From a reset, we should
|
// Enable the Quad I/O mode
|
// Enable the Quad I/O mode
|
// Disable the Write protection bits in the status register
|
// Disable the Write protection bits in the status register
|
Line 165... |
Line 173... |
spi_dir <= 1'b0;
|
spi_dir <= 1'b0;
|
last_status <= 8'h00;
|
last_status <= 8'h00;
|
state <= `WBQSPI_RESET_QUADMODE;
|
state <= `WBQSPI_RESET_QUADMODE;
|
spif_req <= 1'b0;
|
spif_req <= 1'b0;
|
spif_override <= 1'b1;
|
spif_override <= 1'b1;
|
last_status <= 8'hfc; //
|
last_status <= 8'h00; //
|
|
reset_counter <= 10'h3fc; //
|
// This guarantees that we aren't starting in quad
|
// This guarantees that we aren't starting in quad
|
// I/O mode, where the FPGA configuration scripts may
|
// I/O mode, where the FPGA configuration scripts may
|
// have left us.
|
// have left us.
|
end else if (state == `WBQSPI_RESET_QUADMODE)
|
end else if (state == `WBQSPI_RESET_QUADMODE)
|
begin
|
begin
|
// Okay, so here's the problem: we don't know whether or not
|
// Okay, so here's the problem: we don't know whether or not
|
// the Xilinx loader started us up in Quad Read I/O idle mode.
|
// the Xilinx loader started us up in Quad Read I/O idle mode.
|
// So, thus we need to
|
// So, thus we need to toggle the clock and CS_n, with fewer
|
|
// clocks than are necessary to transmit a word.
|
|
//
|
// Not ready to handle the bus yet, so stall any requests
|
// Not ready to handle the bus yet, so stall any requests
|
o_wb_ack <= 1'b0;
|
o_wb_ack <= 1'b0;
|
o_wb_stall <= 1'b1;
|
o_wb_stall <= 1'b1;
|
|
|
// Do something ...
|
// Do something ...
|
if (last_status == 8'h00)
|
if (reset_counter == 10'h00)
|
begin
|
begin
|
spif_override <= 1'b0;
|
spif_override <= 1'b0;
|
state <= `WBQSPI_IDLE;
|
state <= `WBQSPI_IDLE;
|
|
|
|
// Find out if we can use Quad I/O mode ...
|
|
state <= `WBQSPI_READ_CONFIG;
|
|
spi_wr <= 1'b1;
|
|
spi_len <= 2'b01;
|
|
spi_in <= { 8'h35, 24'h00};
|
|
|
end else begin
|
end else begin
|
last_status <= last_status - 8'h1;
|
reset_counter <= reset_counter - 10'h1;
|
spif_override <= 1'b1;
|
spif_override <= 1'b1;
|
spif_cmd <= last_status[3]; // Toggle CS_n
|
|
spif_ctrl <= last_status[0]; // Toggle clock too
|
|
end
|
end
|
end else if (state == `WBQSPI_IDLE)
|
end else if (state == `WBQSPI_IDLE)
|
begin
|
begin
|
o_interrupt <= 1'b0;
|
o_interrupt <= 1'b0;
|
o_wb_stall <= 1'b0;
|
o_wb_stall <= 1'b0;
|
Line 204... |
Line 220... |
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)&&(i_wb_cyc))
|
if (i_wb_data_stb)
|
begin
|
begin
|
|
|
if (i_wb_we) // Request to write a page
|
if (i_wb_we) // Request to write a page
|
begin
|
begin
|
`ifdef READ_ONLY
|
`ifdef READ_ONLY
|
Line 247... |
Line 263... |
spi_wr <= 1'b1; // Write cmd to device
|
spi_wr <= 1'b1; // Write cmd to device
|
if (quad_mode_enabled)
|
if (quad_mode_enabled)
|
begin
|
begin
|
spi_in <= { 8'heb,
|
spi_in <= { 8'heb,
|
{(24-ADDRESS_WIDTH){1'b0}},
|
{(24-ADDRESS_WIDTH){1'b0}},
|
i_wb_addr[(ADDRESS_WIDTH-3):0], 2'b00 };
|
i_wb_addr[(AW-1):0], 2'b00 };
|
state <= `WBQSPI_QRD_ADDRESS;
|
state <= `WBQSPI_QRD_ADDRESS;
|
spi_len <= 2'b00; // single byte, cmd only
|
spi_len <= 2'b00; // single byte, cmd only
|
end else begin
|
end else begin
|
spi_in <= { 8'h0b,
|
spi_in <= { 8'h0b,
|
{(24-ADDRESS_WIDTH){1'b0}},
|
{(24-ADDRESS_WIDTH){1'b0}},
|
i_wb_addr[(ADDRESS_WIDTH-3):0], 2'b00 };
|
i_wb_addr[(AW-1):0], 2'b00 };
|
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
|
`ifndef READ_ONLY
|
end else begin
|
end else begin
|
Line 266... |
Line 282... |
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
|
`endif
|
end
|
end
|
end else if ((i_wb_cyc)&&(i_wb_ctrl_stb)&&(i_wb_we))
|
end else if ((i_wb_ctrl_stb)&&(i_wb_we))
|
begin
|
begin
|
`ifdef READ_ONLY
|
`ifdef READ_ONLY
|
o_wb_ack <= 1'b1;
|
o_wb_ack <= 1'b1;
|
o_wb_stall <= 1'b0;
|
o_wb_stall <= 1'b0;
|
`else
|
`else
|
Line 332... |
Line 348... |
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
|
`endif
|
end else if ((i_wb_cyc)&&(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
|
begin// register, is write still in progress?
|
begin// register, is write still in progress?
|
Line 408... |
Line 424... |
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_cyc)&&(i_wb_data_stb)&&(~i_wb_we))
|
if ((i_wb_data_stb)&&(~i_wb_we))
|
begin // Continue our read ... send the new address / mode
|
begin // Continue our read ... send the new address / mode
|
o_wb_stall <= 1'b1;
|
o_wb_stall <= 1'b1;
|
spi_wr <= 1'b1;
|
spi_wr <= 1'b1;
|
spi_len <= 2'b10; // Write address, but not mode byte
|
spi_len <= 2'b10; // Write address, but not mode byte
|
spi_in <= { {(24-ADDRESS_WIDTH){1'b0}},
|
spi_in <= { {(24-ADDRESS_WIDTH){1'b0}},
|
i_wb_addr[(ADDRESS_WIDTH-3):0], 2'b00, 8'ha0 };
|
i_wb_addr[(AW-1):0], 2'b00, 8'ha0 };
|
state <= `WBQSPI_QRD_DUMMY;
|
state <= `WBQSPI_QRD_DUMMY;
|
end else if((i_wb_cyc)&&(i_wb_ctrl_stb)&&(~i_wb_we)&&(i_wb_addr[1:0] == 2'b00))
|
end else if((i_wb_ctrl_stb)&&(~i_wb_we)&&(i_wb_addr[1:0] == 2'b00))
|
begin
|
begin
|
// A local read that doesn't touch the device, so leave
|
// A local read that doesn't touch the device, so leave
|
// the device in its current state
|
// the device in its current state
|
o_wb_stall <= 1'b0;
|
o_wb_stall <= 1'b0;
|
o_wb_ack <= 1'b1;
|
o_wb_ack <= 1'b1;
|
Line 428... |
Line 444... |
dirty_sector, spi_busy,
|
dirty_sector, spi_busy,
|
~write_protect,
|
~write_protect,
|
quad_mode_enabled,
|
quad_mode_enabled,
|
{(29-ADDRESS_WIDTH){1'b0}},
|
{(29-ADDRESS_WIDTH){1'b0}},
|
erased_sector, 14'h000 };
|
erased_sector, 14'h000 };
|
end else if((i_wb_cyc)&&((i_wb_ctrl_stb)||(i_wb_data_stb)))
|
end else if(((i_wb_ctrl_stb)||(i_wb_data_stb)))
|
begin // Need to release the device from quad mode for all else
|
begin // Need to release the device from quad mode for all else
|
o_wb_ack <= 1'b0;
|
o_wb_ack <= 1'b0;
|
o_wb_stall <= 1'b1;
|
o_wb_stall <= 1'b1;
|
spi_wr <= 1'b1;
|
spi_wr <= 1'b1;
|
spi_len <= 2'b11;
|
spi_len <= 2'b11;
|
Line 626... |
Line 642... |
o_wb_ack <= 1'b0;
|
o_wb_ack <= 1'b0;
|
o_wb_stall <= 1'b1;
|
o_wb_stall <= 1'b1;
|
|
|
spi_wr <= 1'b1; // Non-stop
|
spi_wr <= 1'b1; // Non-stop
|
spi_in <= { {(24-ADDRESS_WIDTH){1'b0}},
|
spi_in <= { {(24-ADDRESS_WIDTH){1'b0}},
|
spif_addr[(ADDRESS_WIDTH-3):0], 2'b00, 8'ha0 };
|
spif_addr[(AW-1):0], 2'b00, 8'ha0 };
|
spi_len <= 2'b10; // Write address, not mode byte
|
spi_len <= 2'b10; // Write address, not mode byte
|
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);
|
Line 668... |
Line 684... |
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_cyc)&&(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)));
|
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 692... |
Line 708... |
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[7:0], spi_out[15:8],
|
o_wb_data <= spi_out;
|
spi_out[23:16], spi_out[31:24] };
|
|
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)
|
Line 882... |
Line 897... |
spi_wr <= 1'b1; // Write cmd to device
|
spi_wr <= 1'b1; // Write cmd to device
|
if (quad_mode_enabled)
|
if (quad_mode_enabled)
|
begin
|
begin
|
spi_in <= { 8'heb,
|
spi_in <= { 8'heb,
|
{(24-ADDRESS_WIDTH){1'b0}},
|
{(24-ADDRESS_WIDTH){1'b0}},
|
spif_addr[(ADDRESS_WIDTH-3):0], 2'b00 };
|
spif_addr[(AW-1):0], 2'b00 };
|
state <= `WBQSPI_QRD_ADDRESS;
|
state <= `WBQSPI_QRD_ADDRESS;
|
// spi_len <= 2'b00; // single byte, cmd only
|
// spi_len <= 2'b00; // single byte, cmd only
|
end else begin
|
end else begin
|
spi_in <= { 8'h0b,
|
spi_in <= { 8'h0b,
|
{(24-ADDRESS_WIDTH){1'b0}},
|
{(24-ADDRESS_WIDTH){1'b0}},
|
spif_addr[(ADDRESS_WIDTH-3):0], 2'b00 };
|
spif_addr[(AW-1):0], 2'b00 };
|
state <= `WBQSPI_RD_DUMMY;
|
state <= `WBQSPI_RD_DUMMY;
|
spi_len <= 2'b11; // Send cmd and addr
|
spi_len <= 2'b11; // Send cmd and addr
|
end end
|
end end
|
4'b10??: begin // Write data to ... anywhere
|
4'b10??: begin // Write data to ... anywhere
|
spi_wr <= 1'b1;
|
spi_wr <= 1'b1;
|
Line 938... |
Line 953... |
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,
|
spi_in <= { 8'h02,
|
{(24-ADDRESS_WIDTH){1'b0}},
|
{(24-ADDRESS_WIDTH){1'b0}},
|
spif_addr[(ADDRESS_WIDTH-3):0], 2'b00 };
|
spif_addr[(AW-1):0], 2'b00 };
|
spi_len <= 2'b11;
|
spi_len <= 2'b11;
|
spi_hold <= 1'b1;
|
spi_hold <= 1'b1;
|
spi_spd <= 1'b0;
|
spi_spd <= 1'b0;
|
spi_dir <= 1'b0; // Writing
|
spi_dir <= 1'b0; // Writing
|
spif_req<= (spif_req) && (i_wb_cyc);
|
spif_req<= (spif_req) && (i_wb_cyc);
|
Line 956... |
Line 971... |
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,
|
spi_in <= { 8'h32,
|
{(24-ADDRESS_WIDTH){1'b0}},
|
{(24-ADDRESS_WIDTH){1'b0}},
|
spif_addr[(ADDRESS_WIDTH-3):0], 2'b00 };
|
spif_addr[(AW-1):0], 2'b00 };
|
spi_len <= 2'b11;
|
spi_len <= 2'b11;
|
spi_hold <= 1'b1;
|
spi_hold <= 1'b1;
|
spi_spd <= 1'b0;
|
spi_spd <= 1'b0;
|
spi_dir <= 1'b0; // Writing
|
spi_dir <= 1'b0; // Writing
|
spif_req<= (spif_req) && (i_wb_cyc);
|
spif_req<= (spif_req) && (i_wb_cyc);
|
Line 979... |
Line 994... |
end else if (state == `WBQSPI_WR_DATA)
|
end else if (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 <= {
|
spi_in <= spif_data;
|
spif_data[ 7: 0],
|
|
spif_data[15: 8],
|
|
spif_data[23:16],
|
|
spif_data[31:24] };
|
|
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
|
Line 1009... |
Line 1020... |
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 ((i_wb_data_stb)&&(i_wb_we)
|
&&(i_wb_addr == (spif_addr+1))
|
&&(i_wb_addr == (spif_addr+1))
|
&&(i_wb_addr[(ADDRESS_WIDTH-3):6]==spif_addr[(ADDRESS_WIDTH-3):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;
|
spif_addr <= i_wb_addr;
|
spif_addr <= i_wb_addr;
|
spif_ctrl <= 1'b0;
|
spif_ctrl <= 1'b0;
|
Line 1082... |
Line 1093... |
spi_in <= { 8'hd8, 2'h0, spif_data[19:14], 14'h000, 2'b00 };
|
spi_in <= { 8'hd8, 2'h0, spif_data[19:14], 14'h000, 2'b00 };
|
spi_len <= 2'b11; // 32 bit write
|
spi_len <= 2'b11; // 32 bit write
|
// together with setting our copy of the WIP bit
|
// together with setting our copy of the WIP bit
|
write_in_progress <= 1'b1;
|
write_in_progress <= 1'b1;
|
// keeping track of which sector we just erased
|
// keeping track of which sector we just erased
|
erased_sector <= spif_data[(ADDRESS_WIDTH-3):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))
|
Line 1100... |
Line 1111... |
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
|
|
// here.
|
if ((~spi_busy)&&(~spi_wr))
|
if ((~spi_busy)&&(~spi_wr))
|
begin
|
|
o_wb_ack <= spif_req;
|
|
state <= `WBQSPI_IDLE;
|
state <= `WBQSPI_IDLE;
|
end
|
|
end else if (state == `WBQSPI_CLEAR_STATUS)
|
end else if (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
|
Line 1164... |
Line 1174... |
end
|
end
|
end
|
end
|
end
|
end
|
|
|
// Command and control during the reset sequence
|
// Command and control during the reset sequence
|
assign o_qspi_cs_n = (spif_override)?spif_cmd :w_qspi_cs_n;
|
assign o_qspi_cs_n = (spif_override)?alt_cmd :w_qspi_cs_n;
|
assign o_qspi_sck = (spif_override)?spif_ctrl:w_qspi_sck;
|
assign o_qspi_sck = (spif_override)?alt_ctrl:w_qspi_sck;
|
assign o_qspi_mod = (spif_override)? 2'b01 :w_qspi_mod;
|
assign o_qspi_mod = (spif_override)? 2'b01 :w_qspi_mod;
|
assign o_qspi_dat = (spif_override)? 4'b00 :w_qspi_dat;
|
assign o_qspi_dat = (spif_override)? 4'b00 :w_qspi_dat;
|
endmodule
|
endmodule
|
|
|
No newline at end of file
|
No newline at end of file
|