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

Subversion Repositories qspiflash

[/] [qspiflash/] [trunk/] [rtl/] [wbqspiflash.v] - Diff between revs 3 and 4

Go to most recent revision | Show entire file | Details | Blame | View Log

Rev 3 Rev 4
Line 50... Line 50...
//              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_WEN        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
`define WBQSPI_WBDECODE         4
`define WBQSPI_WBDECODE         4
`define WBQSPI_WAIT_WIP_CLEAR   5
`define WBQSPI_WAIT_WIP_CLEAR   5
`define WBQSPI_CHECK_WIP_CLEAR  6
`define WBQSPI_CHECK_WIP_CLEAR  6
Line 112... Line 112...
        reg             spi_wr, spi_hold, spi_spd, spi_dir;
        reg             spi_wr, spi_hold, spi_spd, spi_dir;
        reg     [31:0]   spi_in;
        reg     [31:0]   spi_in;
        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;
        wire            spi_valid, spi_busy;
 
        wire            w_qspi_sck, w_qspi_cs_n;
 
        wire    [3:0]    w_qspi_dat;
 
        wire    [1:0]    w_qspi_mod;
        llqspi  lldriver(i_clk_100mhz,
        llqspi  lldriver(i_clk_100mhz,
                        spi_wr, spi_hold, spi_in, spi_len, spi_spd, spi_dir,
                        spi_wr, spi_hold, spi_in, spi_len, spi_spd, spi_dir,
                                spi_out, spi_valid, spi_busy,
                                spi_out, spi_valid, spi_busy,
                        o_qspi_sck, o_qspi_cs_n, o_qspi_mod, o_qspi_dat,
                        w_qspi_sck, w_qspi_cs_n, w_qspi_mod, w_qspi_dat,
                                i_qspi_dat);
                                i_qspi_dat);
 
 
        // Erase status tracking
        // Erase status tracking
        reg             write_in_progress, write_protect;
        reg             write_in_progress, write_protect;
        reg     [5:0]    erased_sector;
        reg     [5:0]    erased_sector;
Line 131... Line 134...
                write_protect = 1'b1;
                write_protect = 1'b1;
        end
        end
 
 
        reg     [7:0]    last_status;
        reg     [7:0]    last_status;
        reg             quad_mode_enabled;
        reg             quad_mode_enabled;
        reg             spif_cmd;
        reg             spif_cmd, spif_override;
        reg     [19:0]   spif_addr;
        reg     [19:0]   spif_addr;
        reg     [31:0]   spif_data;
        reg     [31:0]   spif_data;
        reg     [5:0]    state;
        reg     [5:0]    state;
        reg     [5:0]    spif_return;
 
        reg             spif_ctrl, spif_req;
        reg             spif_ctrl, spif_req;
        wire    [5:0]    spif_sector;
        wire    [5:0]    spif_sector;
        assign  spif_sector = spif_addr[19:14];
        assign  spif_sector = spif_addr[19:14];
 
 
        initial state = `WBQSPI_RESET;
        initial state = `WBQSPI_RESET;
Line 148... Line 150...
        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;
        always @(posedge i_clk_100mhz)
        always @(posedge i_clk_100mhz)
 
        begin
 
        spif_override <= 1'b0;
        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
                //      Chip should already be up and running, so we can start
                //      Chip should already be up and running, so we can start
                //      immediately ....
                //      immediately ....
                o_wb_ack <= 1'b0;
                o_wb_ack <= 1'b0;
                o_wb_stall <= 1'b1;
                o_wb_stall <= 1'b1;
 
                spi_wr   <= 1'b0;
                spi_hold <= 1'b0;
                spi_hold <= 1'b0;
                spi_spd  <= 1'b0;
                spi_spd  <= 1'b0;
                spi_dir  <= 1'b0;
                spi_dir  <= 1'b0;
                last_status <= 8'h00;
                last_status <= 8'h00;
                if (spi_len < 2'b11)
                state <= `WBQSPI_RESET_QUADMODE;
                        spi_len <= spi_len + 1;
 
                state <= `WBQSPI_IDLE;
 
                spif_req <= 1'b0;
                spif_req <= 1'b0;
        /*
                spif_override <= 1'b1;
        // This next bit of logic is confusing ...
                last_status <= 8'hfc; //
        // I wish to enable quad SPI mode automatically.  However, this is
                        // This guarantees that we aren't starting in quad
        // a configuration register thing, so once written it never needs to
                        // I/O mode, where the FPGA configuration scripts may
        // be adjusted again.  Further, some bits within the configuration
                        // have left us.
        // register cannot be undone, and my inkling might be to set those.
        end else if (state == `WBQSPI_RESET_QUADMODE)
        // Finally, the configuration register affects the control of the
        begin
        // block protect registers in the status register.  So ...
                // Okay, so here's the problem: we don't know whether or not
        // let's just leave these registers alone, or command them from the
                // the Xilinx loader started us up in Quad Read I/O idle mode.
        // UART-wishbone interface.
                // So, thus we need to 
                else if (~spi_busy)
                // Not ready to handle the bus yet, so stall any requests
                begin
                o_wb_ack   <= 1'b0;
                        spi_wr  <= 1'b1;
                o_wb_stall <= 1'b1;
                        spi_len <= 2'b00; // 1 byte
 
                        spi_in  <= { 8'h06, 24'h000 };
                // Do something ...
                end
                if (last_status == 8'h00)
        end else if (state == `WBQSPI_RESET_WEN)
                begin
        begin
                        spif_override <= 1'b0;
                spi_wr <= 1'b0;
                        state <= `WBQSPI_IDLE;
                if ((~spi_busy)&&(~spi_wr)&&(o_qspi_cs_n))
                end else begin
                begin
                        last_status <= last_status - 8'h1;
                        spi_wr  <= 1'b1;
                        spif_override <= 1'b1;
                        spi_spd <= 1'b0;
                        spif_cmd  <= last_status[3]; // Toggle CS_n
                        spi_len <= 2'b10; // 3 bytes
                        spif_ctrl <= last_status[0]; // Toggle clock too
                        // Command, status, config, then don't care
                end
                        spi_in <= { 8'h01, 8'h00, 8'h0b, 8'h00 };
 
                        spi_dir <= 1'b0;
 
                        quad_mode_enabled <= 1'b1;
 
                        state <= `WBQSPI_WAIT_TIL_IDLE;
 
                        write_in_progress <= 1'b1;
 
                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;
                o_wb_ack <= 1'b0;
                o_wb_ack <= 1'b0;
Line 401... Line 397...
                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_cyc)&&(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;
                        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 <= { 2'h0, i_wb_addr[19:0], 2'h0, 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_cyc)&&(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
Line 629... Line 625...
                        4'b00??: begin // Read data from ... somewhere
                        4'b00??: begin // Read data from ... somewhere
                                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, 2'b00, spif_addr[19:0], 2'b00 };
                                        spi_in <= { 8'heb, 2'b00, spif_addr[19:0], 2'b00 };
                                        state <= `WBQSPI_QRD_DUMMY;
                                        state <= `WBQSPI_QRD_ADDRESS;
 
                                        // spi_len    <= 2'b00; // single byte, cmd only
                                end else begin
                                end else begin
                                        spi_in <= { 8'h0b, 2'b00, spif_addr[19:0], 2'b00 };
                                        spi_in <= { 8'h0b, 2'b00, spif_addr[19:0], 2'b00 };
                                        state <= `WBQSPI_RD_DUMMY;
                                        state <= `WBQSPI_RD_DUMMY;
 
                                        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;
                                spi_len <= 2'b00; // 8 bits
                                spi_len <= 2'b00; // 8 bits
                                // Send a write enable command
                                // Send a write enable command
Line 672... Line 670...
                spi_wr <= 1'b0;
                spi_wr <= 1'b0;
                o_wb_ack <= 1'b0;
                o_wb_ack <= 1'b0;
                o_wb_stall <= 1'b1;
                o_wb_stall <= 1'b1;
                spif_req<= (spif_req) && (i_wb_cyc);
                spif_req<= (spif_req) && (i_wb_cyc);
                if ((~spi_busy)&&(o_qspi_cs_n)&&(~spi_wr)) // Let's come to a full stop
                if ((~spi_busy)&&(o_qspi_cs_n)&&(~spi_wr)) // Let's come to a full stop
                        // state <= (quad_mode_enabled)?`WBQSPI_QPP:`WBQSPI_PP;
                        state <= (quad_mode_enabled)?`WBQSPI_QPP:`WBQSPI_PP;
                        state <= `WBQSPI_PP;
                        // state <= `WBQSPI_PP;
        end else if (state == `WBQSPI_PP)
        end else if (state == `WBQSPI_PP)
        begin // We come here under a full stop / full port idle mode
        begin // We come here under a full stop / full port idle mode
                // Issue our command immediately
                // Issue our command immediately
                spi_wr <= 1'b1;
                spi_wr <= 1'b1;
                spi_in <= { 8'h02, 2'h0, spif_addr, 2'b00 };
                spi_in <= { 8'h02, 2'h0, spif_addr, 2'b00 };
Line 792... Line 790...
                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 <= { 2'b0, spif_addr, 2'b0, 8'ha0 };
                spi_in <= { 2'b0, spif_addr, 2'b0, 8'ha0 };
                spi_len <= 2'b11; // Write all 32 bits bits
                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 834... Line 832...
                        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_cyc)&&(i_wb_data_stb)&&(~i_wb_we)&&(i_wb_addr== (spif_addr+1)));
                // spi_wr <= 1'b0; // No pipelined read support
 
                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
                spi_hold <= 1'b0;
                // Don't let the device go to idle until the bus cycle ends.
 
                //      This actually prevents a *really* nasty race condition,
 
                //      where the strobe comes in after the lower level device
 
                //      has decided to stop waiting.  The write is then issued,
 
                //      but no one is listening.  By leaving the device open,
 
                //      the device is kept in a state where a valid strobe
 
                //      here will be useful.  Of course, we don't accept
 
                //      all commands, just reads.  Further, the strobe needs
 
                //      to be high for two clocks cycles without changing
 
                //      anything on the bus--one for us to notice it and pull
 
                //      our head out of the sand, and a second for whoever
 
                //      owns the bus to realize their command went through.
 
                spi_hold <= 1'b1;
                spif_req<= (spif_req) && (i_wb_cyc);
                spif_req<= (spif_req) && (i_wb_cyc);
                if ((spi_valid)&&(~spi_in[31]))
                if ((spi_valid)&&(~spi_in[31]))
                begin // Single pulse acknowledge and write data out
                begin // Single pulse acknowledge and write data out
                        o_wb_ack <= spif_req;
                        o_wb_ack <= spif_req;
                        o_wb_stall <= (~spi_wr);
                        o_wb_stall <= (~spi_wr);
Line 851... Line 860...
                        o_wb_data <= { spi_out[7:0], spi_out[15:8],
                        o_wb_data <= { spi_out[7:0], spi_out[15:8],
                                spi_out[23:16], spi_out[31:24] };
                                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);
                        if (spi_wr)
                        if (spi_wr)
                                spif_addr <= i_wb_addr;
                                spif_addr <= i_wb_addr;
 
                end else if (~i_wb_cyc)
 
                begin // FAIL SAFE: If the bus cycle ends, forget why we're
 
                        // here, just go back to idle
 
                        state <= ((spi_spd) ? `WBQSPI_WAIT_TIL_RDIDLE : `WBQSPI_WAIT_TIL_IDLE);
 
                        spi_hold <= 1'b0;
 
                        o_wb_ack <= 1'b0;
 
                        o_wb_stall <= 1'b1;
                end else begin
                end else begin
                        o_wb_ack <= 1'b0;
                        o_wb_ack <= 1'b0;
                        o_wb_stall <= 1'b1;
                        o_wb_stall <= 1'b1;
                end
                end
        end else if (state == `WBQSPI_WAIT_TIL_RDIDLE)
        end else if (state == `WBQSPI_WAIT_TIL_RDIDLE)
Line 893... Line 910...
        end else if (state == `WBQSPI_READ_ID)
        end else if (state == `WBQSPI_READ_ID)
        begin
        begin
                o_wb_ack <= 1'b0; // Assuming we're still waiting
                o_wb_ack <= 1'b0; // Assuming we're still waiting
                o_wb_stall <= 1'b1;
                o_wb_stall <= 1'b1;
 
 
                spi_wr <= 1'b0; // No more writes, we'ev already written the cmd
                spi_wr <= 1'b0; // No more writes, we've already written the cmd
                spi_hold <= 1'b0;
                spi_hold <= 1'b0;
                spif_req <= (spif_req) && (i_wb_cyc);
                spif_req <= (spif_req) && (i_wb_cyc);
 
 
                // Here, we just wait until the result comes back
                // Here, we just wait until the result comes back
                // The problem is, the result may be the previous result.
                // The problem is, the result may be the previous result.
Line 906... Line 923...
                if((spi_valid)&&(spi_len==2'b00))
                if((spi_valid)&&(spi_len==2'b00))
                begin // Put the results out as soon as possible
                begin // Put the results out as soon as possible
                        o_wb_data <= spi_out[31:0];
                        o_wb_data <= spi_out[31:0];
                        o_wb_ack <= spif_req;
                        o_wb_ack <= spif_req;
                        spif_req <= 1'b0;
                        spif_req <= 1'b0;
                end else if ((~spi_busy)&&(~o_qspi_cs_n))
                end else if ((~spi_busy)&&(o_qspi_cs_n))
                begin
                begin
                        state <= `WBQSPI_IDLE;
                        state <= `WBQSPI_IDLE;
                        o_wb_stall <= 1'b0;
                        o_wb_stall <= 1'b0;
                end
                end
        end else if (state == `WBQSPI_READ_STATUS)
        end else if (state == `WBQSPI_READ_STATUS)
Line 1095... Line 1112...
                        state <= `WBQSPI_IDLE;
                        state <= `WBQSPI_IDLE;
                        o_wb_stall <= 1'b0;
                        o_wb_stall <= 1'b0;
                        o_wb_ack   <= 1'b0; // Shouldn't be acking anything here
                        o_wb_ack   <= 1'b0; // Shouldn't be acking anything here
                end
                end
        end
        end
 
        end
 
 
 
        // Command and control during the reset sequence
 
        assign  o_qspi_cs_n = (spif_override)?spif_cmd :w_qspi_cs_n;
 
        assign  o_qspi_sck  = (spif_override)?spif_ctrl:w_qspi_sck;
 
        assign  o_qspi_mod  = (spif_override)?   2'b01 :w_qspi_mod;
 
        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

powered by: WebSVN 2.1.0

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