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

Subversion Repositories s6soc

[/] [s6soc/] [trunk/] [rtl/] [qflashxpress.v] - Blame information for rev 51

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 51 dgisselq
////////////////////////////////////////////////////////////////////////////////
2
//
3
// Filename:    qflashxpress.v
4
//
5
// Project:     CMod S6 System on a Chip, ZipCPU demonstration project
6
//
7
// Purpose:     To provide wishbone controlled read access (and read access
8
//              *only*) to the QSPI flash, using a flash clock of 80MHz, and
9
//      nothing more.  Indeed, this is designed to be a *very* stripped down
10
//      version of a flash driver, with the goal of providing 1) very fast
11
//      access for 2) very low logic count.
12
//
13
//      Two modes/states of operation:
14
//
15
//      STARTUP
16
//       1. Waits for the flash to come on line
17
//              Start out idle for 300 uS
18
//       2. Sends a signal to remove the flash from any QSPI read mode.  In our
19
//              case, we'll send several clocks of an empty command.  In SPI
20
//              mode, it'll get ignored.  In QSPI mode, it'll remove us from
21
//              QSPI mode.
22
//       3. Explicitly places and leaves the flash into QSPI mode
23
//              0xEB 3(0xa0) 0xa0 0xa0 0xa0 4(0x00)
24
//       4. All done
25
//
26
//      NORMAL-OPS
27
//      ODATA <- ?, 3xADDR, 0xa0, 0x00, 0x00 | 0x00, 0x00, 0x00, 0x00 ? (22nibs)
28
//      STALL <- TRUE until closed at the end
29
//      MODE  <- 2'b10 for 4 clks, then 2'b11
30
//      CLK   <- 2'b10 before starting, then 2'b01 until the end
31
//      CSN   <- 0 any time CLK != 2'b11
32
//
33
//
34
//
35
// Creator:     Dan Gisselquist, Ph.D.
36
//              Gisselquist Technology, LLC
37
//
38
////////////////////////////////////////////////////////////////////////////////
39
//
40
// Copyright (C) 2015-2017, Gisselquist Technology, LLC
41
//
42
// This program is free software (firmware): you can redistribute it and/or
43
// modify it under the terms of  the GNU General Public License as published
44
// by the Free Software Foundation, either version 3 of the License, or (at
45
// your option) any later version.
46
//
47
// This program is distributed in the hope that it will be useful, but WITHOUT
48
// ANY WARRANTY; without even the implied warranty of MERCHANTIBILITY or
49
// FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
50
// for more details.
51
//
52
// You should have received a copy of the GNU General Public License along
53
// with this program.  (It's in the $(ROOT)/doc directory.  Run make with no
54
// target there if the PDF file isn't present.)  If not, see
55
// <http://www.gnu.org/licenses/> for a copy.
56
//
57
// License:     GPL, v3, as defined and found on www.gnu.org,
58
//              http://www.gnu.org/licenses/gpl.html
59
//
60
//
61
////////////////////////////////////////////////////////////////////////////////
62
//
63
//
64
`define OPT_FLASH_PIPELINE
65
module  qflashxpress(i_clk,
66
                i_wb_cyc, i_wb_stb, i_wb_addr,
67
                        o_wb_ack, o_wb_stall, o_wb_data,
68
                o_qspi_sck, o_qspi_cs_n, o_qspi_mod, o_qspi_dat, i_qspi_dat);
69
        localparam      AW=24-2;
70
        input                   i_clk;
71
        //
72
        input                   i_wb_cyc, i_wb_stb;
73
        input           [(AW-1):0] i_wb_addr;
74
        //
75
        output  reg             o_wb_ack, o_wb_stall;
76
        output  reg     [31:0]   o_wb_data;
77
        //
78
        output  wire    [1:0]    o_qspi_sck;
79
        output  wire            o_qspi_cs_n;
80
        output  wire    [1:0]    o_qspi_mod;
81
        output  wire    [3:0]    o_qspi_dat;
82
        input   wire    [3:0]    i_qspi_dat;
83
 
84
        //
85
        //
86
        // Maintenance / startup portion
87
        //
88
        //
89
        reg     maintenance;
90
        reg     [14:0]   m_counter;
91
        reg     [1:0]    m_state;
92
        reg     [1:0]    m_mod;
93
        reg             m_cs_n;
94
        reg     [1:0]    m_clk;
95
        reg     [31:0]   m_data;
96
        wire    [3:0]    m_dat;
97
 
98
        initial maintenance = 1'b1;
99
        initial m_counter   = 0;
100
        initial m_state     = 2'b00;
101
        always @(posedge i_clk)
102
        begin
103
                if (maintenance)
104
                        m_counter <= m_counter + 1'b1;
105
                m_mod <= 2'b00; // SPI mode always for maintenance
106
                case(m_state)
107
                2'b00: begin
108
                        // Step one: wait for the flash device to initialize.
109
                        // Perhaps this is more for form than anything else,
110
                        // especially if we just loaded our configuration from
111
                        // the flash, but in case we did not--we do this anyway.
112
                        maintenance <= 1'b1;
113
                        if (m_counter[14:0]==15'h7fff) // 24000 is the limit
114
                                m_state <= 2'b01;
115
                        m_cs_n <= 1'b1;
116
                        m_clk  <= 2'b11;
117
                        end
118
                2'b01: begin
119
                        // Now that the flash has had a chance to start up, feed
120
                        // it with chip selects with no clocks.   This is
121
                        // guaranteed to remove us from any XIP mode we might
122
                        // be in upon startup.  We do this so that we might be
123
                        // placed into a known mode--albeit the wrong one, but
124
                        // a known one.
125
                        maintenance <= 1'b1;
126
                        //
127
                        // 1111 0000 1111 0000 1111 0000 1111 0000
128
                        // 1111 0000 1111 0000 1111 0000 1111 0000
129
                        // 1111 ==> 17 * 4 clocks, or 68 clocks in total
130
                        //
131
                        if (m_counter[14:0] == 15'd138)
132
                                m_state <= 2'b10;
133
                        m_cs_n <= 1'b0;
134
                        m_clk  <= {(2){!m_counter[2]}};
135
                        m_data <= { 32'hfff0f0ff }; // EB command
136
                        m_data[31:28] <= 0; // just ... not yet
137
                        end
138
                2'b10: begin
139
                        // Rest, before issuing our initial read command
140
                        maintenance <= 1'b1;
141
                        if (m_counter[14:0] == 15'd138 + 15'd48)
142
                                m_state <= 2'b11;
143
                        m_cs_n <= 1'b1; // Rest the interface
144
                        m_clk  <= 2'b11;
145
                        m_data <= { 32'hfff0f0ff }; // EB command
146
                        end
147
                2'b11: begin
148
                        if (m_counter[14:0] == 15'd138+15'd48+15'd10)
149
                                maintenance <= 1'b0;
150
                        m_cs_n <= 1'b0;
151
                        m_clk  <= (m_clk == 2'b11)? 2'b10 : 2'b01;
152
                        if (m_clk == 2'b01) // EB QuadIO Read Cmd
153
                                m_data <= {m_data[27:0], 4'h0};
154
                        // We depend upon the non-maintenance code to provide
155
                        // our first (bogus) address, mode, dummy cycles, and
156
                        // data bits.
157
                        end
158
                endcase
159
        end
160
        assign  m_dat = m_data[31:28];
161
 
162
        //
163
        //
164
        // Data / access portion
165
        //
166
        //
167
        reg     [21:0]   busy_pipe;
168
        reg     [31:0]   data_pipe;
169
        reg             pre_ack;
170
        initial data_pipe = 0;
171
        always @(posedge i_clk)
172
                if (((i_wb_stb)&&(!o_wb_stall))||(maintenance))
173
                        data_pipe <= { i_wb_addr, 2'b00, 8'ha0 };
174
                else if (o_qspi_sck == 2'b01)
175
                        data_pipe <= { data_pipe[27:0], 4'h0 };
176
        assign  o_qspi_dat = (maintenance)? m_dat : data_pipe[31:28];
177
 
178
`ifdef  OPT_FLASH_PIPELINE
179
        reg     pipe_req;
180
 
181
        reg     [(AW-1):0]       last_addr;
182
        always  @(posedge i_clk)
183
                if ((i_wb_stb)&&(!o_wb_stall))
184
                        last_addr <= i_wb_addr;
185
 
186
        initial pipe_req = 1'b0;
187
        always @(posedge i_clk)
188
                pipe_req <= (pre_ack)&&(i_wb_stb)
189
                                &&(last_addr + 1'b1 == i_wb_addr);
190
`else
191
        wire    pipe_req;
192
        assign  pipe_req = 1'b0;
193
`endif
194
 
195
 
196
        initial pre_ack = 0;
197
        always @(posedge i_clk)
198
                if ((maintenance)||(!i_wb_cyc))
199
                        pre_ack <= 1'b0;
200
                else if ((i_wb_stb)&&(!o_wb_stall))
201
                        pre_ack <= 1'b1;
202
                else if ((o_wb_ack)&&(!pipe_req))
203
                        pre_ack <= 1'b0;
204
 
205
        reg     [43:0]   clk_pipe;
206
        initial clk_pipe = -1;
207
        always @(posedge i_clk)
208
                if (((i_wb_stb)&&(!o_wb_stall)&&(!pipe_req))||(maintenance))
209
                        clk_pipe <= { 2'b00, {(21){2'b01}}};
210
                else if (((i_wb_stb)&&(!o_wb_stall))||(maintenance))
211
                        clk_pipe <= { {(8){2'b01}}, {(14){2'b11}} };
212
                else
213
                        clk_pipe <= { clk_pipe[41:0], 2'b11 };
214
        assign  o_qspi_sck = (maintenance)? m_clk : clk_pipe[43:42];
215
        assign  o_qspi_cs_n= (maintenance)?m_cs_n : (clk_pipe[43:42] == 2'b11);
216
 
217
        reg     [9:0]    mod_pipe;
218
        always @(posedge i_clk)
219
                if(((i_wb_stb)&&(!o_wb_stall)&&(!pipe_req))||(maintenance))
220
                        mod_pipe <= { 10'h0 }; // Always quad, but in/out
221
                else
222
                        mod_pipe <= { mod_pipe[8:0], 1'b1 }; // Add input at end
223
        assign  o_qspi_mod = (maintenance) ? m_mod :(mod_pipe[9]? 2'b11:2'b10);
224
 
225
        initial busy_pipe = 22'h3fffff;
226
        always @(posedge i_clk)
227
                if (((i_wb_stb)&&(!o_wb_stall)&&(!pipe_req))||(maintenance))
228
                        busy_pipe <= { 22'h3fffff };
229
                else if ((i_wb_stb)&&(!o_wb_stall))
230
                        busy_pipe <= { 22'h3fc000 };
231
                else
232
                        busy_pipe <= { busy_pipe[20:0], 1'b0 };
233
 
234
        initial o_wb_stall = 1'b1;
235
        always @(posedge i_clk)
236
                o_wb_stall <= ((i_wb_stb)&&(!o_wb_stall))
237
                        ||(busy_pipe[19])||((busy_pipe[20])&&(!pipe_req));
238
 
239
        reg     ack_pipe;
240
        initial ack_pipe = 1'b0;
241
        always @(posedge i_clk)
242
                ack_pipe <= (pre_ack)&&(busy_pipe[20:19] == 2'b10);
243
        initial o_wb_ack = 1'b0;
244
        always @(posedge i_clk)
245
                o_wb_ack <= (pre_ack)&&(ack_pipe);
246
 
247
        always @(posedge i_clk)
248
                o_wb_data <= { o_wb_data[27:0], i_qspi_dat };
249
 
250
endmodule
251
 

powered by: WebSVN 2.1.0

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