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

Subversion Repositories qspiflash

[/] [qspiflash/] [trunk/] [rtl/] [eqspiflash.v] - Diff between revs 14 and 16

Show entire file | Details | Blame | View Log

Rev 14 Rev 16
Line 1... Line 1...
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
//
//
// Filename:    eqspiflash.v
// Filename:    eqspiflash.v
//
//
// Project:     OpenArty, an entirely open SoC based upon the Arty platform
// Project:     Wishbone Controlled Quad SPI Flash Controller
//
//
// Purpose:     Provide access to the flash device on an Arty, via the Extended
// Purpose:     Provide access to the flash device on an Arty, via the Extended
//              SPI interface.  Reads and writes will use the QuadSPI interface
//              SPI interface.  Reads and writes will use the QuadSPI interface
//      (4-bits at a time) all other commands (register and otherwise) will use
//      (4-bits at a time) all other commands (register and otherwise) will use
//      the SPI interface (1 bit at a time).
//      the SPI interface (1 bit at a time).
Line 88... Line 88...
// 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
Line 100... Line 100...
//
//
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
//
//
//
//
// `define      QSPI_READ_ONLY
// `define      QSPI_READ_ONLY
module  eqspiflash(i_clk_200mhz, i_rst,
module  eqspiflash(i_clk_82mhz, i_rst,
                // Incoming wishbone connection(s)
                // Incoming wishbone connection(s)
                //      The two strobe lines allow the data to live on a
                //      The two strobe lines allow the data to live on a
                //      separate part of the master bus from the control 
                //      separate part of the master bus from the control 
                //      registers.  Only one strobe will ever be active at any
                //      registers.  Only one strobe will ever be active at any
                //      time, no strobes will ever be active unless i_wb_cyc
                //      time, no strobes will ever be active unless i_wb_cyc
Line 118... Line 118...
                // Interrupt the CPU
                // Interrupt the CPU
                o_interrupt, o_cmd_accepted,
                o_interrupt, o_cmd_accepted,
                // Debug the interface
                // Debug the interface
                o_dbg);
                o_dbg);
 
 
        input                   i_clk_200mhz, i_rst;
        input                   i_clk_82mhz, i_rst;
        // Wishbone bus inputs
        // Wishbone bus inputs
        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           [21:0]   i_wb_addr;      // 24 bits of addr space
        input           [21:0]   i_wb_addr;      // 24 bits of addr space
        input           [31:0]   i_wb_data;
        input           [31:0]   i_wb_data;
        // Wishbone bus outputs
        // Wishbone bus outputs
Line 140... Line 140...
        output  reg             o_cmd_accepted;
        output  reg             o_cmd_accepted;
        //
        //
        output  wire    [31:0]   o_dbg;
        output  wire    [31:0]   o_dbg;
 
 
        initial o_cmd_accepted = 1'b0;
        initial o_cmd_accepted = 1'b0;
        always @(posedge i_clk_200mhz)
        always @(posedge i_clk_82mhz)
                o_cmd_accepted=((i_wb_data_stb)||(i_wb_ctrl_stb))&&(~o_wb_stall);
                o_cmd_accepted=((i_wb_data_stb)||(i_wb_ctrl_stb))&&(~o_wb_stall);
        //
        //
        // lleqspi
        // lleqspi
        //
        //
        //      Providing the low-level SPI interface
        //      Providing the low-level SPI interface
Line 152... Line 152...
        reg     spi_wr, spi_hold, spi_spd, spi_dir, spi_recycle;
        reg     spi_wr, spi_hold, spi_spd, spi_dir, spi_recycle;
        reg     [31:0]   spi_word;
        reg     [31:0]   spi_word;
        reg     [1:0]    spi_len;
        reg     [1:0]    spi_len;
        wire    [31:0]   spi_out;
        wire    [31:0]   spi_out;
        wire            spi_valid, spi_busy, spi_stopped;
        wire            spi_valid, spi_busy, spi_stopped;
        lleqspi lowlvl(i_clk_200mhz, spi_wr, spi_hold, spi_word, spi_len,
        lleqspi lowlvl(i_clk_82mhz, spi_wr, spi_hold, spi_word, spi_len,
                        spi_spd, spi_dir, spi_recycle, spi_out, spi_valid, spi_busy,
                        spi_spd, spi_dir, spi_recycle, spi_out, spi_valid, spi_busy,
                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);
        assign  spi_stopped = (o_qspi_cs_n)&&(~spi_busy)&&(~spi_wr);
        assign  spi_stopped = (o_qspi_cs_n)&&(~spi_busy)&&(~spi_wr);
 
 
 
 
Line 179... Line 179...
                        bus_pipewr, bus_endwr, bus_ctreq, bus_idreq,
                        bus_pipewr, bus_endwr, bus_ctreq, bus_idreq,
                        bus_other_req,
                        bus_other_req,
        // Live parameters
        // Live parameters
                        w_xip, w_quad, w_idloaded, w_leave_xip;
                        w_xip, w_quad, w_idloaded, w_leave_xip;
        reg             bus_wip;
        reg             bus_wip;
        qspibus preproc(i_clk_200mhz, i_rst,
        qspibus preproc(i_clk_82mhz, i_rst,
                        i_wb_cyc, i_wb_data_stb, i_wb_ctrl_stb,
                        i_wb_cyc, i_wb_data_stb, i_wb_ctrl_stb,
                                i_wb_we, i_wb_addr, i_wb_data,
                                i_wb_we, i_wb_addr, i_wb_data,
                                bus_wb_ack, bus_wb_stall, bus_wb_data,
                                bus_wb_ack, bus_wb_stall, bus_wb_data,
                        bus_wr, bus_addr, bus_data, bus_sector,
                        bus_wr, bus_addr, bus_data, bus_sector,
                                bus_readreq, bus_piperd,
                                bus_readreq, bus_piperd,
Line 209... Line 209...
        wire            rd_spi_wr, rd_spi_hold, rd_spi_spd, rd_spi_dir,
        wire            rd_spi_wr, rd_spi_hold, rd_spi_spd, rd_spi_dir,
                        rd_spi_recycle;
                        rd_spi_recycle;
        wire    [31:0]   rd_spi_word;
        wire    [31:0]   rd_spi_word;
        wire    [1:0]    rd_spi_len;
        wire    [1:0]    rd_spi_len;
        //
        //
        readqspi        rdproc(i_clk_200mhz, bus_readreq, bus_piperd,
        readqspi        rdproc(i_clk_82mhz, bus_readreq, bus_piperd,
                                        bus_other_req,
                                        bus_other_req,
                                bus_addr, rd_bus_ack,
                                bus_addr, rd_bus_ack,
                                rd_qspi_req, rd_qspi_grant,
                                rd_qspi_req, rd_qspi_grant,
                                rd_spi_wr, rd_spi_hold, rd_spi_word, rd_spi_len,
                                rd_spi_wr, rd_spi_hold, rd_spi_word, rd_spi_len,
                                rd_spi_spd, rd_spi_dir, rd_spi_recycle,
                                rd_spi_spd, rd_spi_dir, rd_spi_recycle,
Line 239... Line 239...
        wire    [31:0]   ew_spi_word;
        wire    [31:0]   ew_spi_word;
        wire    [1:0]    ew_spi_len;
        wire    [1:0]    ew_spi_len;
        //
        //
        wire            w_ew_wip;
        wire            w_ew_wip;
        //
        //
        writeqspi       ewproc(i_clk_200mhz, bus_wreq,bus_ereq,
        writeqspi       ewproc(i_clk_82mhz, bus_wreq,bus_ereq,
                                        bus_pipewr, bus_endwr,
                                        bus_pipewr, bus_endwr,
                                        bus_addr, bus_data,
                                        bus_addr, bus_data,
                                ew_bus_ack, ew_qspi_req, ew_qspi_grant,
                                ew_bus_ack, ew_qspi_req, ew_qspi_grant,
                                ew_spi_wr, ew_spi_hold, ew_spi_word, ew_spi_len,
                                ew_spi_wr, ew_spi_hold, ew_spi_word, ew_spi_len,
                                        ew_spi_spd, ew_spi_dir,
                                        ew_spi_spd, ew_spi_dir,
Line 266... Line 266...
        // SPI control wires
        // SPI control wires
        wire            ct_spi_wr, ct_spi_hold, ct_spi_spd, ct_spi_dir;
        wire            ct_spi_wr, ct_spi_hold, ct_spi_spd, ct_spi_dir;
        wire    [31:0]   ct_spi_word;
        wire    [31:0]   ct_spi_word;
        wire    [1:0]    ct_spi_len;
        wire    [1:0]    ct_spi_len;
        //
        //
        ctrlspi         ctproc(i_clk_200mhz,
        ctrlspi         ctproc(i_clk_82mhz,
                                bus_ctreq, bus_wr, bus_addr[3:0], bus_data, bus_sector,
                                bus_ctreq, bus_wr, bus_addr[3:0], bus_data, bus_sector,
                                ct_qspi_req, ct_grant,
                                ct_qspi_req, ct_grant,
                                ct_spi_wr, ct_spi_hold, ct_spi_word, ct_spi_len,
                                ct_spi_wr, ct_spi_hold, ct_spi_word, ct_spi_len,
                                        ct_spi_spd, ct_spi_dir,
                                        ct_spi_spd, ct_spi_dir,
                                        spi_out, spi_valid, spi_busy, spi_stopped,
                                        spi_out, spi_valid, spi_busy, spi_stopped,
Line 297... Line 297...
        wire    [31:0]   id_spi_word;
        wire    [31:0]   id_spi_word;
        wire    [1:0]    id_spi_len;
        wire    [1:0]    id_spi_len;
        //
        //
        wire            w_id_wip;
        wire            w_id_wip;
        //
        //
        idotpqspi       idotp(i_clk_200mhz, bus_idreq,
        idotpqspi       idotp(i_clk_82mhz, bus_idreq,
                                bus_wr, bus_pipewr, bus_addr[4:0], bus_data, id_bus_ack,
                                bus_wr, bus_pipewr, bus_addr[4:0], bus_data, id_bus_ack,
                                id_qspi_req, id_qspi_grant,
                                id_qspi_req, id_qspi_grant,
                                id_spi_wr, id_spi_hold, id_spi_word, id_spi_len,
                                id_spi_wr, id_spi_hold, id_spi_word, id_spi_len,
                                        id_spi_spd, id_spi_dir,
                                        id_spi_spd, id_spi_dir,
                                        spi_out, spi_valid, spi_busy, spi_stopped,
                                        spi_out, spi_valid, spi_busy, spi_stopped,
Line 309... Line 309...
 
 
        // Arbitrator
        // Arbitrator
        reg             owned;
        reg             owned;
        reg     [1:0]    owner;
        reg     [1:0]    owner;
        initial         owned = 1'b0;
        initial         owned = 1'b0;
        always @(posedge i_clk_200mhz) // 7 inputs (spi_stopped is the CE)
        always @(posedge i_clk_82mhz) // 7 inputs (spi_stopped is the CE)
                if ((~owned)&&(spi_stopped))
                if ((~owned)&&(spi_stopped))
                begin
                begin
                        casez({rd_qspi_req,ew_qspi_req,id_qspi_req,ct_qspi_req})
                        casez({rd_qspi_req,ew_qspi_req,id_qspi_req,ct_qspi_req})
                        4'b1???: begin owned<= 1'b1; owner <= 2'b00; end
                        4'b1???: begin owned<= 1'b1; owner <= 2'b00; end
                        4'b01??: begin owned<= 1'b1; owner <= 2'b01; end
                        4'b01??: begin owned<= 1'b1; owner <= 2'b01; end
Line 336... Line 336...
        assign  ew_qspi_grant = (owned)&&(owner == 2'b01);
        assign  ew_qspi_grant = (owned)&&(owner == 2'b01);
        assign  id_qspi_grant = (owned)&&(owner == 2'b10);
        assign  id_qspi_grant = (owned)&&(owner == 2'b10);
        assign  ct_grant      = (owned)&&(owner == 2'b11);
        assign  ct_grant      = (owned)&&(owner == 2'b11);
 
 
        // Module controller
        // Module controller
        always @(posedge i_clk_200mhz)
        always @(posedge i_clk_82mhz)
        case(owner)
        case(owner)
        2'b00: begin
        2'b00: begin
                spi_wr      <= (owned)&&(rd_spi_wr);
                spi_wr      <= (owned)&&(rd_spi_wr);
                spi_hold    <= rd_spi_hold;
                spi_hold    <= rd_spi_hold;
                spi_word    <= rd_spi_word;
                spi_word    <= rd_spi_word;
Line 380... Line 380...
 
 
        reg     last_wip;
        reg     last_wip;
        initial bus_wip = 1'b0;
        initial bus_wip = 1'b0;
        initial last_wip = 1'b0;
        initial last_wip = 1'b0;
        initial o_interrupt = 1'b0;
        initial o_interrupt = 1'b0;
        always @(posedge i_clk_200mhz)
        always @(posedge i_clk_82mhz)
        begin
        begin
                bus_wip <= w_ew_wip || w_id_wip;
                bus_wip <= w_ew_wip || w_id_wip;
                last_wip <= bus_wip;
                last_wip <= bus_wip;
                o_interrupt <= ((~bus_wip)&&(last_wip));
                o_interrupt <= ((~bus_wip)&&(last_wip));
        end
        end
 
 
 
 
        // Now, let's return values onto the wb bus
        // Now, let's return values onto the wb bus
        always @(posedge i_clk_200mhz)
        always @(posedge i_clk_82mhz)
        begin
        begin
                // Ack our internal bus controller.  This means the command was
                // Ack our internal bus controller.  This means the command was
                // accepted, and the bus can go on to looking for the next 
                // accepted, and the bus can go on to looking for the next 
                // command.  It controls the i_wb_stall line, just not the
                // command.  It controls the i_wb_stall line, just not the
                // i_wb_ack line.
                // i_wb_ack line.
Line 449... Line 449...
 
 
 
 
        //
        //
        reg     pending, lcl_wrreq, lcl_ctreq, lcl_ack, ack, wp_err, wp;
        reg     pending, lcl_wrreq, lcl_ctreq, lcl_ack, ack, wp_err, wp;
        reg     lcl_reg;
        reg     lcl_reg;
        reg     [14:0]   esector;
        reg     [12:0]   esector;
        reg     [21:0]   next_addr;
        reg     [21:0]   next_addr;
 
 
 
 
        reg     pipeable;
        reg     pipeable;
        reg     same_page;
        reg     same_page;
Line 581... Line 581...
        always @(posedge i_clk)
        always @(posedge i_clk)
                last_wip <= i_wip;
                last_wip <= i_wip;
        wire    new_req;
        wire    new_req;
        assign  new_req = (pending)&&(~last_pending);
        assign  new_req = (pending)&&(~last_pending);
 
 
        initial esector   = 15'h00;
        initial esector   = 13'h00;
        initial o_wrreq   = 1'b0;
        initial o_wrreq   = 1'b0;
        initial o_erreq   = 1'b0;
        initial o_erreq   = 1'b0;
        initial wp_err    = 1'b0;
        initial wp_err    = 1'b0;
        initial lcl_ack   = 1'b0;
        initial lcl_ack   = 1'b0;
        initial r_other   = 1'b0;
        initial r_other   = 1'b0;
Line 611... Line 611...
                // Default ACK is always set to zero, unless the following ...
                // Default ACK is always set to zero, unless the following ...
                o_wb_ack <= 1'b0;
                o_wb_ack <= 1'b0;
 
 
                if (set_sector)
                if (set_sector)
                begin
                begin
                        esector[13:0] <= { o_data[23:14], 4'h0 };
                        esector[11:0] <= { o_data[21:14], 4'h0 };
                        wp <= (o_data[30])&&(new_req)||(wp)&&(~new_req);
                        wp <= (o_data[30])&&(new_req)||(wp)&&(~new_req);
                        esector[14] <= o_data[28]; // Subsector
                        esector[12] <= o_data[28]; // Subsector
                        if (o_data[28])
                        if (o_data[28])
                        begin
                        begin
                                esector[3:0] <= o_data[13:10];
                                esector[3:0] <= o_data[13:10];
                        end
                        end
                end
                end
Line 677... Line 677...
                end
                end
 
 
        end
        end
 
 
 
 
        assign o_wb_data[31:0] = { i_wip, ~wp, i_quad, esector[14],
        assign o_wb_data[31:0] = { i_wip, ~wp, i_quad, esector[12],
                        i_idloaded, wp_err, i_xip, i_spi_stopped,
                        i_idloaded, wp_err, i_xip, i_spi_stopped,
                        esector[13:0], 10'h00 };
                        2'b00, esector[11:0], 10'h00 };
        assign  o_sector = { esector[13:0], 8'h00 }; // 22 bits
        assign  o_sector = { 2'b00, esector[11:0], 8'h00 }; // 22 bits
        assign  o_other = (r_other)||(o_idreq);
        assign  o_other = (r_other)||(o_idreq);
 
 
endmodule
endmodule
 
 
 
 
Line 696... Line 696...
`define RD_QUAD_DUMMY           4'h5
`define RD_QUAD_DUMMY           4'h5
`define RD_QUAD_ADDRESS         4'h6
`define RD_QUAD_ADDRESS         4'h6
`define RD_XIP                  4'h7
`define RD_XIP                  4'h7
`define RD_GO_TO_IDLE           4'h8
`define RD_GO_TO_IDLE           4'h8
`define RD_GO_TO_XIP            4'h9
`define RD_GO_TO_XIP            4'h9
 
`define RD_IDLE_QUAD_PORT       4'ha
 
 
module  readqspi(i_clk, i_readreq, i_piperd, i_other_req, i_addr, o_bus_ack,
module  readqspi(i_clk, i_readreq, i_piperd, i_other_req, i_addr, o_bus_ack,
                o_qspi_req, i_grant,
                o_qspi_req, i_grant,
                        o_spi_wr, o_spi_hold, o_spi_word, o_spi_len,
                        o_spi_wr, o_spi_hold, o_spi_word, o_spi_len,
                                o_spi_spd, o_spi_dir, o_spi_recycle,
                                o_spi_spd, o_spi_dir, o_spi_recycle,
Line 744... Line 745...
                invalid_ack_pipe <= { invalid_ack_pipe[2:0], accepted };
                invalid_ack_pipe <= { invalid_ack_pipe[2:0], accepted };
                case(rd_state)
                case(rd_state)
                `RD_IDLE: begin
                `RD_IDLE: begin
                        r_requested <= 1'b0;
                        r_requested <= 1'b0;
                        o_qspi_req <= 1'b0;
                        o_qspi_req <= 1'b0;
                        o_spi_word <= { ((i_quad)? 8'h6B: 8'h0b), i_addr, 2'b00 };
                        // 0x0b is a fast read, uses all SPI protocol
 
                        // 0x6b is a Quad output fast read, uses SPI cmd,
 
                        //                      SPI address, QSPI data
 
                        // 0xeb is a Quad I/O fast read, using SPI cmd,
 
                        //                      QSPI address and data
 
                        o_spi_word <= { ((i_quad)? 8'hEB: 8'h0b), i_addr, 2'b00 };
                        o_spi_wr <= 1'b0;
                        o_spi_wr <= 1'b0;
                        o_spi_dir <= 1'b0;
                        o_spi_dir <= 1'b0;
                        o_spi_spd <= 1'b0;
                        o_spi_spd <= 1'b0;
                        o_spi_len <= 2'b11;
                        o_spi_len <= (i_quad)? 2'b00 : 2'b11;
                        r_xip <= (i_xip)&&(i_quad);
                        r_xip <= (i_xip)&&(i_quad);
                        r_leave_xip <= 1'b0; // Not in it, so can't leave it
                        r_leave_xip <= 1'b0; // Not in it, so can't leave it
                        r_quad <= i_quad;
                        r_quad <= i_quad;
                        if (i_readreq)
                        if (i_readreq)
                        begin
                        begin
Line 761... Line 767...
                        end end
                        end end
                `RD_IDLE_GET_PORT: begin
                `RD_IDLE_GET_PORT: begin
                        o_spi_wr <= 1'b1; // Write the address
                        o_spi_wr <= 1'b1; // Write the address
                        o_qspi_req <= 1'b1;
                        o_qspi_req <= 1'b1;
                        if (accepted)
                        if (accepted)
 
                        begin
 
                                rd_state <= (r_quad) ? `RD_IDLE_QUAD_PORT : `RD_SLOW_DUMMY;
 
                                o_spi_word[31:8] <= o_spi_word[23:0];
 
                        end end
 
                `RD_IDLE_QUAD_PORT: begin
 
                        o_spi_wr <= 1'b1; // Write the command
 
                        o_qspi_req <= 1'b1;
 
                        o_spi_spd <= 1'b1;
 
                        o_spi_dir <= 1'b0;
 
                        o_spi_len <= 2'b10;
 
 
 
                        // We haven't saved our address any where but in the
 
                        // SPI word we just sent.  Hence, let's just
 
                        // grab it from there.
 
                        if (accepted)
                                rd_state <= `RD_SLOW_DUMMY;
                                rd_state <= `RD_SLOW_DUMMY;
                        end
                        end
                `RD_SLOW_DUMMY: begin
                `RD_SLOW_DUMMY: begin
                        o_spi_wr <= 1'b1; // Write 8 dummy clocks
                        o_spi_wr <= 1'b1; // Write 8 dummy clocks--this is the same for
                        o_qspi_req <= 1'b1;
                        o_qspi_req <= 1'b1; // both Quad I/O, Quad O, and fast-read commands
                        o_spi_dir <= 1'b0;
                        o_spi_dir <= 1'b0;
                        o_spi_spd <= 1'b0;
                        o_spi_spd <= r_quad;
                        o_spi_word[31:24] <= (r_xip) ? 8'h00 : 8'hff;
                        o_spi_word[31:0] <= (r_xip) ? 32'h00 : 32'hffffffff;
                        o_spi_len  <= 2'b00; // 8 clocks = 8-bits
                        o_spi_len  <= (r_quad)? 2'b11:2'b00; // 8 clocks
                        if (accepted)
                        if (accepted)
                                rd_state <= (r_quad)?`RD_QUAD_READ_DATA
                                rd_state <= (r_quad)?`RD_QUAD_READ_DATA
                                                : `RD_SLOW_READ_DATA;
                                                : `RD_SLOW_READ_DATA;
                        end
                        end
                `RD_SLOW_READ_DATA: begin
                `RD_SLOW_READ_DATA: begin

powered by: WebSVN 2.1.0

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