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

Subversion Repositories xulalx25soc

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

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
 
47
// Modes
48
// `define      SPI_MOD_SPI     2'b00
49
// `define      QSPI_MOD_QOUT   2'b10
50
// `define      QSPI_MOD_QIN    2'b11
51
 
52
module  lldspi(i_clk,
53
                // Module interface
54
                i_wr, i_hold, i_word, i_len,
55
                        o_word, o_valid, o_busy,
56
                // QSPI interface
57
                o_sck, o_cs_n, i_cs_n, o_mosi, i_miso);
58
        input                   i_clk;
59
        // Chip interface
60
        //      Can send info
61
        //              i_hold = 0, i_wr = 1,
62
        //                      i_word = { 1'b0, 32'info to send },
63
        //                      i_len = # of bytes in word-1
64
        input                   i_wr, i_hold;
65
        input           [31:0]   i_word;
66
        input           [1:0]    i_len;  // 0=>8bits, 1=>16 bits, 2=>24 bits, 3=>32 bits
67
        output  reg     [31:0]   o_word;
68
        output  reg             o_valid, o_busy;
69
        // Interface with the QSPI lines
70
        output  reg             o_sck;
71
        output  reg             o_cs_n;
72
        input                   i_cs_n; // Feedback from the arbiter
73
        output  reg             o_mosi;
74
        input                   i_miso;
75
 
76
        reg     [5:0]    spi_len;
77
        reg     [31:0]   r_word;
78
        reg     [30:0]   r_input;
79
        reg     [2:0]    state;
80
        initial state = `SPI_IDLE;
81
        initial o_sck   = 1'b1;
82
        initial o_cs_n  = 1'b1;
83
        initial o_mosi  = 1'b0;
84
        initial o_valid = 1'b0;
85
        initial o_busy  = 1'b0;
86
        initial r_input = 31'h000;
87
        always @(posedge i_clk)
88
                if ((state == `SPI_IDLE)&&(o_sck))
89
                begin
90
                        o_cs_n <= 1'b1;
91
                        o_valid <= 1'b0;
92
                        o_busy  <= 1'b0;
93
                        if (i_wr)
94
                        begin
95
                                r_word <= i_word;
96
                                state <= `SPI_START;
97
                                spi_len<= { 1'b0, i_len, 3'b000 } + 6'h8;
98
                                o_cs_n <= 1'b0;
99
                                o_busy <= 1'b1;
100
                                o_sck <= 1'b1;
101
                        end
102
                end else if (state == `SPI_START)
103
                begin // We come in here with sck high, stay here 'til sck is low
104
                        if (~i_cs_n) // Wait 'til the bus has been granted
105
                                o_sck <= 1'b0;
106
                        if (o_sck == 1'b0)
107
                        begin
108
                                state <= `SPI_BITS;
109
                                spi_len<= spi_len - 6'h1;
110
                                r_word <= { r_word[30:0], 1'b0 };
111
                        end
112
                        o_cs_n <= 1'b0;
113
                        o_busy <= 1'b1;
114
                        o_valid <= 1'b0;
115
                        o_mosi  <= r_word[31];
116
                end else if (~o_sck)
117
                begin
118
                        o_sck <= 1'b1;
119
                        o_busy <= ((state != `SPI_READY)||(~i_wr));
120
                        o_valid <= 1'b0;
121
                end else if (state == `SPI_BITS)
122
                begin
123
                        // Should enter into here with at least a spi_len
124
                        // of one, perhaps more
125
                        o_sck <= 1'b0;
126
                        o_busy <= 1'b1;
127
                        o_mosi <= r_word[31];
128
                        r_word <= { r_word[30:0], 1'b0 };
129
                        spi_len <= spi_len - 6'h1;
130
                        if (spi_len == 6'h1)
131
                                state <= `SPI_READY;
132
 
133
                        o_valid <= 1'b0;
134
                        r_input <= { r_input[29:0], i_miso };
135
                end else if (state == `SPI_READY)
136
                begin
137
                        o_valid <= 1'b0;
138
                        o_cs_n <= 1'b0;
139
                        o_busy <= 1'b1;
140
                        // This is the state on the last clock (both low and
141
                        // high clocks) of the data.  Data is valid during
142
                        // this state.  Here we chose to either STOP or
143
                        // continue and transmit more.
144
                        o_sck <= (i_hold); // No clocks while holding
145
                        if((~o_busy)&&(i_wr))// Acknowledge a new request
146
                        begin
147
                                state <= `SPI_BITS;
148
                                o_busy <= 1'b1;
149
                                o_sck <= 1'b0;
150
 
151
                                // Set up the first bits on the bus
152
                                o_mosi <= i_word[31];
153
                                r_word <= { i_word[30:0], 1'b0 };
154
                                spi_len<= { 1'b0, i_len, 3'b000 } + 6'h8-6'h1;
155
 
156
                                // Read a bit upon any transition
157
                                o_valid <= 1'b1;
158
                                r_input <= { r_input[29:0], i_miso };
159
                                o_word  <= { r_input[30:0], i_miso };
160
                        end else begin
161
                                o_sck <= 1'b1;
162
                                state <= (i_hold)?`SPI_HOLDING : `SPI_STOP;
163
                                o_busy <= (~i_hold);
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
170
                end else if (state == `SPI_HOLDING)
171
                begin
172
                        // We need this state so that the o_valid signal
173
                        // can get strobed with our last result.  Otherwise
174
                        // we could just sit in READY waiting for a new command.
175
                        //
176
                        // Incidentally, the change producing this state was
177
                        // the result of a nasty race condition.  See the
178
                        // commends in wbqspiflash for more details.
179
                        //
180
                        o_valid <= 1'b0;
181
                        o_cs_n <= 1'b0;
182
                        o_busy <= 1'b0;
183
                        if((~o_busy)&&(i_wr))// Acknowledge a new request
184
                        begin
185
                                state  <= `SPI_BITS;
186
                                o_busy <= 1'b1;
187
                                o_sck  <= 1'b0;
188
 
189
                                // Set up the first bits on the bus
190
                                o_mosi <= i_word[31];
191
                                r_word <= { i_word[30:0], 1'b0 };
192
                                spi_len<= { 1'b0, i_len, 3'b111 };
193
                        end else begin
194
                                o_sck <= 1'b1;
195
                                state <= (i_hold)?`SPI_HOLDING : `SPI_STOP;
196
                                o_busy <= (~i_hold);
197
                        end
198
                end else if (state == `SPI_STOP)
199
                begin
200
                        o_sck   <= 1'b1; // Stop the clock
201
                        o_valid <= 1'b0; // Output may have just been valid, but no more
202
                        o_busy  <= 1'b1; // Still busy till port is clear
203
                        state <= `SPI_STOP_B;
204
                end else if (state == `SPI_STOP_B)
205
                begin
206
                        o_cs_n <= 1'b1;
207
                        o_sck <= 1'b1;
208
                        // Do I need this????
209
                        // spi_len <= 3; // Minimum CS high time before next cmd
210
                        state <= `SPI_IDLE;
211
                        o_valid <= 1'b0;
212
                        o_busy <= 1'b1;
213
                end else begin // Invalid states, should never get here
214
                        state   <= `SPI_STOP;
215
                        o_valid <= 1'b0;
216
                        o_busy  <= 1'b1;
217
                        o_cs_n  <= 1'b1;
218
                        o_sck   <= 1'b1;
219
                end
220
 
221
endmodule
222
 

powered by: WebSVN 2.1.0

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