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

Subversion Repositories xulalx25soc

[/] [xulalx25soc/] [trunk/] [rtl/] [lldspi.v] - Blame information for rev 116

Go to most recent revision | Details | Compare with Previous | View Log

Line No. Rev Author Line
1 2 dgisselq
///////////////////////////////////////////////////////////////////////////
2
//
3
// Filename:    lldspi.v
4
//
5
// Project:     XuLA2 board
6
//
7
// Purpose:     Reads/writes a word (user selectable number of bytes) of data
8
//              to/from a Quad SPI port.  The port is understood to be 
9
//      a normal SPI port unless the driver requests two bit mode.  (Not yet
10
//      supported.)  When not in use, no bits will toggle.
11
//
12
// Creator:     Dan Gisselquist
13
//              Gisselquist Technology, LLC
14
//
15
///////////////////////////////////////////////////////////////////////////
16
//
17
// Copyright (C) 2015, Gisselquist Technology, LLC
18
//
19
// This program is free software (firmware): you can redistribute it and/or
20
// modify it under the terms of  the GNU General Public License as published
21
// by the Free Software Foundation, either version 3 of the License, or (at
22
// your option) any later version.
23
//
24
// This program is distributed in the hope that it will be useful, but WITHOUT
25
// ANY WARRANTY; without even the implied warranty of MERCHANTIBILITY or
26
// FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
27
// for more details.
28
//
29
// You should have received a copy of the GNU General Public License along
30
// with this program.  (It's in the $(ROOT)/doc directory, run make with no
31
// target there if the PDF file isn't present.)  If not, see
32
// <http://www.gnu.org/licenses/> for a copy.
33
//
34
// License:     GPL, v3, as defined and found on www.gnu.org,
35
//              http://www.gnu.org/licenses/gpl.html
36
//
37
//
38
///////////////////////////////////////////////////////////////////////////
39
`define SPI_IDLE        3'h0
40
`define SPI_START       3'h1
41
`define SPI_BITS        3'h2
42
`define SPI_READY       3'h3
43
`define SPI_HOLDING     3'h4
44
`define SPI_STOP        3'h5
45
`define SPI_STOP_B      3'h6
46 74 dgisselq
`define SPI_WAIT        3'h7
47 2 dgisselq
 
48
// Modes
49
// `define      SPI_MOD_SPI     2'b00
50
// `define      QSPI_MOD_QOUT   2'b10
51
// `define      QSPI_MOD_QIN    2'b11
52
 
53
module  lldspi(i_clk,
54
                // Module interface
55
                i_wr, i_hold, i_word, i_len,
56
                        o_word, o_valid, o_busy,
57
                // QSPI interface
58 74 dgisselq
                o_sck, o_cs_n, i_cs_n, o_mosi, i_miso,
59
                // Bus grant information
60
                i_bus_grant);
61 2 dgisselq
        input                   i_clk;
62
        // Chip interface
63
        //      Can send info
64
        //              i_hold = 0, i_wr = 1,
65
        //                      i_word = { 1'b0, 32'info to send },
66
        //                      i_len = # of bytes in word-1
67
        input                   i_wr, i_hold;
68
        input           [31:0]   i_word;
69
        input           [1:0]    i_len;  // 0=>8bits, 1=>16 bits, 2=>24 bits, 3=>32 bits
70
        output  reg     [31:0]   o_word;
71
        output  reg             o_valid, o_busy;
72
        // Interface with the QSPI lines
73
        output  reg             o_sck;
74
        output  reg             o_cs_n;
75
        input                   i_cs_n; // Feedback from the arbiter
76
        output  reg             o_mosi;
77
        input                   i_miso;
78 74 dgisselq
        // Bus grant
79
        input                   i_bus_grant;
80 2 dgisselq
 
81
        reg     [5:0]    spi_len;
82
        reg     [31:0]   r_word;
83
        reg     [30:0]   r_input;
84
        reg     [2:0]    state;
85
        initial state = `SPI_IDLE;
86
        initial o_sck   = 1'b1;
87
        initial o_cs_n  = 1'b1;
88
        initial o_mosi  = 1'b0;
89
        initial o_valid = 1'b0;
90
        initial o_busy  = 1'b0;
91
        initial r_input = 31'h000;
92
        always @(posedge i_clk)
93
                if ((state == `SPI_IDLE)&&(o_sck))
94
                begin
95
                        o_cs_n <= 1'b1;
96
                        o_valid <= 1'b0;
97
                        o_busy  <= 1'b0;
98
                        if (i_wr)
99
                        begin
100
                                r_word <= i_word;
101 74 dgisselq
                                state <= `SPI_WAIT;
102 2 dgisselq
                                spi_len<= { 1'b0, i_len, 3'b000 } + 6'h8;
103
                                o_cs_n <= 1'b0;
104
                                o_busy <= 1'b1;
105
                                o_sck <= 1'b1;
106
                        end
107 74 dgisselq
                end else if (state == `SPI_WAIT)
108
                begin
109
                        if (i_bus_grant)
110
                                state <= `SPI_START;
111 2 dgisselq
                end else if (state == `SPI_START)
112
                begin // We come in here with sck high, stay here 'til sck is low
113
                        if (~i_cs_n) // Wait 'til the bus has been granted
114
                                o_sck <= 1'b0;
115
                        if (o_sck == 1'b0)
116
                        begin
117
                                state <= `SPI_BITS;
118
                                spi_len<= spi_len - 6'h1;
119
                                r_word <= { r_word[30:0], 1'b0 };
120
                        end
121
                        o_cs_n <= 1'b0;
122
                        o_busy <= 1'b1;
123
                        o_valid <= 1'b0;
124
                        o_mosi  <= r_word[31];
125
                end else if (~o_sck)
126
                begin
127
                        o_sck <= 1'b1;
128
                        o_busy <= ((state != `SPI_READY)||(~i_wr));
129
                        o_valid <= 1'b0;
130
                end else if (state == `SPI_BITS)
131
                begin
132
                        // Should enter into here with at least a spi_len
133
                        // of one, perhaps more
134
                        o_sck <= 1'b0;
135
                        o_busy <= 1'b1;
136
                        o_mosi <= r_word[31];
137
                        r_word <= { r_word[30:0], 1'b0 };
138
                        spi_len <= spi_len - 6'h1;
139
                        if (spi_len == 6'h1)
140
                                state <= `SPI_READY;
141
 
142
                        o_valid <= 1'b0;
143
                        r_input <= { r_input[29:0], i_miso };
144
                end else if (state == `SPI_READY)
145
                begin
146
                        o_valid <= 1'b0;
147
                        o_cs_n <= 1'b0;
148
                        o_busy <= 1'b1;
149
                        // This is the state on the last clock (both low and
150
                        // high clocks) of the data.  Data is valid during
151
                        // this state.  Here we chose to either STOP or
152
                        // continue and transmit more.
153
                        o_sck <= (i_hold); // No clocks while holding
154
                        if((~o_busy)&&(i_wr))// Acknowledge a new request
155
                        begin
156
                                state <= `SPI_BITS;
157
                                o_busy <= 1'b1;
158
                                o_sck <= 1'b0;
159
 
160
                                // Set up the first bits on the bus
161
                                o_mosi <= i_word[31];
162
                                r_word <= { i_word[30:0], 1'b0 };
163
                                spi_len<= { 1'b0, i_len, 3'b000 } + 6'h8-6'h1;
164
 
165
                                // Read a bit upon any transition
166
                                o_valid <= 1'b1;
167
                                r_input <= { r_input[29:0], i_miso };
168
                                o_word  <= { r_input[30:0], i_miso };
169
                        end else begin
170
                                o_sck <= 1'b1;
171
                                state <= (i_hold)?`SPI_HOLDING : `SPI_STOP;
172
                                o_busy <= (~i_hold);
173
 
174
                                // Read a bit upon any transition
175
                                o_valid <= 1'b1;
176
                                r_input <= { r_input[29:0], i_miso };
177
                                o_word  <= { r_input[30:0], i_miso };
178
                        end
179
                end else if (state == `SPI_HOLDING)
180
                begin
181
                        // We need this state so that the o_valid signal
182
                        // can get strobed with our last result.  Otherwise
183
                        // we could just sit in READY waiting for a new command.
184
                        //
185
                        // Incidentally, the change producing this state was
186
                        // the result of a nasty race condition.  See the
187
                        // commends in wbqspiflash for more details.
188
                        //
189
                        o_valid <= 1'b0;
190
                        o_cs_n <= 1'b0;
191
                        o_busy <= 1'b0;
192
                        if((~o_busy)&&(i_wr))// Acknowledge a new request
193
                        begin
194
                                state  <= `SPI_BITS;
195
                                o_busy <= 1'b1;
196
                                o_sck  <= 1'b0;
197
 
198
                                // Set up the first bits on the bus
199
                                o_mosi <= i_word[31];
200
                                r_word <= { i_word[30:0], 1'b0 };
201
                                spi_len<= { 1'b0, i_len, 3'b111 };
202
                        end else begin
203
                                o_sck <= 1'b1;
204
                                state <= (i_hold)?`SPI_HOLDING : `SPI_STOP;
205
                                o_busy <= (~i_hold);
206
                        end
207
                end else if (state == `SPI_STOP)
208
                begin
209
                        o_sck   <= 1'b1; // Stop the clock
210
                        o_valid <= 1'b0; // Output may have just been valid, but no more
211
                        o_busy  <= 1'b1; // Still busy till port is clear
212
                        state <= `SPI_STOP_B;
213
                end else if (state == `SPI_STOP_B)
214
                begin
215
                        o_cs_n <= 1'b1;
216
                        o_sck <= 1'b1;
217
                        // Do I need this????
218
                        // spi_len <= 3; // Minimum CS high time before next cmd
219
                        state <= `SPI_IDLE;
220
                        o_valid <= 1'b0;
221
                        o_busy <= 1'b1;
222
                end else begin // Invalid states, should never get here
223
                        state   <= `SPI_STOP;
224
                        o_valid <= 1'b0;
225
                        o_busy  <= 1'b1;
226
                        o_cs_n  <= 1'b1;
227
                        o_sck   <= 1'b1;
228
                end
229
 
230
endmodule
231
 

powered by: WebSVN 2.1.0

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