├── .project
├── LICENSE.txt
├── Mojo-Base.xise
├── ipcore_dir
└── .gitignore
├── iseconfig
├── Mojo-Base.projectmgr
└── mojo_top.xreport
├── src
├── avr_interface.v
├── cclk_detector.v
├── mojo.ucf
├── mojo_top.v
├── serial_rx.v
├── serial_tx.v
└── spi_slave.v
└── syn
└── .gitignore
/.project:
--------------------------------------------------------------------------------
1 |
2 |
3 | Mojo-Demo
4 |
5 |
6 |
7 |
8 |
9 | net.sourceforge.veditor.simulateBuilder
10 |
11 |
12 | net.sourceforge.veditor.simulateBuilder.00000000Default.CleanCommand
13 | echo 'Clean'
14 |
15 |
16 | net.sourceforge.veditor.simulateBuilder.00000000Default.buildOrder
17 | 0
18 |
19 |
20 | net.sourceforge.veditor.simulateBuilder.00000000Default.command
21 | echo 'No Build Configuration Specified'
22 |
23 |
24 | net.sourceforge.veditor.simulateBuilder.00000000Default.enable
25 | false
26 |
27 |
28 | net.sourceforge.veditor.simulateBuilder.00000000Default.name
29 | Default
30 |
31 |
32 | net.sourceforge.veditor.simulateBuilder.00000000Default.parser
33 |
34 |
35 |
36 | net.sourceforge.veditor.simulateBuilder.00000000Default.workFolder
37 |
38 |
39 |
40 |
41 |
42 |
43 | net.sourceforge.veditor.HdlNature
44 |
45 |
46 |
--------------------------------------------------------------------------------
/LICENSE.txt:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 |
3 | Copyright (c) 2015 Embedded Micro
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in
13 | all copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21 | THE SOFTWARE.
22 |
--------------------------------------------------------------------------------
/Mojo-Base.xise:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 |
81 |
82 |
83 |
84 |
85 |
86 |
87 |
88 |
89 |
90 |
91 |
92 |
93 |
94 |
95 |
96 |
97 |
98 |
99 |
100 |
101 |
102 |
103 |
104 |
105 |
106 |
107 |
108 |
109 |
110 |
111 |
112 |
113 |
114 |
115 |
116 |
117 |
118 |
119 |
120 |
121 |
122 |
123 |
124 |
125 |
126 |
127 |
128 |
129 |
130 |
131 |
132 |
133 |
134 |
135 |
136 |
137 |
138 |
139 |
140 |
141 |
142 |
143 |
144 |
145 |
146 |
147 |
148 |
149 |
150 |
151 |
152 |
153 |
154 |
155 |
156 |
157 |
158 |
159 |
160 |
161 |
162 |
163 |
164 |
165 |
166 |
167 |
168 |
169 |
170 |
171 |
172 |
173 |
174 |
175 |
176 |
177 |
178 |
179 |
180 |
181 |
182 |
183 |
184 |
185 |
186 |
187 |
188 |
189 |
190 |
191 |
192 |
193 |
194 |
195 |
196 |
197 |
198 |
199 |
200 |
201 |
202 |
203 |
204 |
205 |
206 |
207 |
208 |
209 |
210 |
211 |
212 |
213 |
214 |
215 |
216 |
217 |
218 |
219 |
220 |
221 |
222 |
223 |
224 |
225 |
226 |
227 |
228 |
229 |
230 |
231 |
232 |
233 |
234 |
235 |
236 |
237 |
238 |
239 |
240 |
241 |
242 |
243 |
244 |
245 |
246 |
247 |
248 |
249 |
250 |
251 |
252 |
253 |
254 |
255 |
256 |
257 |
258 |
259 |
260 |
261 |
262 |
263 |
264 |
265 |
266 |
267 |
268 |
269 |
270 |
271 |
272 |
273 |
274 |
275 |
276 |
277 |
278 |
279 |
280 |
281 |
282 |
283 |
284 |
285 |
286 |
287 |
288 |
289 |
290 |
291 |
292 |
293 |
294 |
295 |
296 |
297 |
298 |
299 |
300 |
301 |
302 |
303 |
304 |
305 |
306 |
307 |
308 |
309 |
310 |
311 |
312 |
313 |
314 |
315 |
316 |
317 |
318 |
319 |
320 |
321 |
322 |
323 |
324 |
325 |
326 |
327 |
328 |
329 |
330 |
331 |
332 |
333 |
334 |
335 |
336 |
337 |
338 |
339 |
340 |
341 |
342 |
343 |
344 |
345 |
346 |
347 |
348 |
349 |
350 |
351 |
352 |
353 |
354 |
355 |
356 |
357 |
358 |
359 |
360 |
361 |
362 |
363 |
364 |
365 |
366 |
367 |
368 |
369 |
370 |
371 |
372 |
373 |
374 |
375 |
376 |
377 |
378 |
379 |
380 |
381 |
382 |
383 |
384 |
385 |
386 |
387 |
388 |
--------------------------------------------------------------------------------
/ipcore_dir/.gitignore:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/embmicro/mojo-base-project/469b6ee60b143c5f4fca25f63be0f18cee15e5c1/ipcore_dir/.gitignore
--------------------------------------------------------------------------------
/iseconfig/Mojo-Base.projectmgr:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 | 2
10 | /avr_interface |home|justin|workspace|Mojo-Tutorials|Mojo-Base|src|avr_interface.v
11 |
12 |
13 | mojo_top (/home/justin/workspace/Mojo-Tutorials/Mojo-Base/src/mojo_top.v)
14 |
15 | 0
16 | 0
17 | 000000ff0000000000000001000000010000000000000000000000000000000002020000000100000001000000640000010a000000020000000000000000000000000200000064ffffffff0000008100000003000000020000010a0000000100000003000000000000000100000003
18 | true
19 | mojo_top (/home/justin/workspace/Mojo-Tutorials/Mojo-Base/src/mojo_top.v)
20 |
21 |
22 |
23 | 1
24 | Configure Target Device
25 | Design Utilities
26 | Implement Design/Map
27 | Implement Design/Place & Route
28 | Implement Design/Translate
29 | Synthesize - XST
30 | User Constraints
31 |
32 |
33 | Generate Programming File
34 |
35 | 0
36 | 0
37 | 000000ff00000000000000010000000100000000000000000000000000000000000000000000000153000000010000000100000000000000000000000064ffffffff000000810000000000000001000001530000000100000000
38 | false
39 | Generate Programming File
40 |
41 |
42 |
43 | 1
44 |
45 |
46 | 0
47 | 0
48 | 000000ff000000000000000100000000000000000100000000000000000000000000000000000005a7000000040101000100000000000000000000000064ffffffff000000810000000000000004000000770000000100000000000000c50000000100000000000000790000000100000000000003f20000000100000000
49 | false
50 | avr_interface.v
51 |
52 |
53 |
54 | 1
55 | work
56 |
57 |
58 | 0
59 | 0
60 | 000000ff00000000000000010000000000000000010000000000000000000000000000000000000128000000010001000100000000000000000000000064ffffffff000000810000000000000001000001280000000100000000
61 | false
62 | work
63 |
64 | 000000ff0000000000000002000001380000011b01000000040100000002
65 | Implementation
66 |
67 |
68 | 1
69 | Design Utilities
70 |
71 |
72 |
73 |
74 | 0
75 | 0
76 | 000000ff000000000000000100000001000000000000000000000000000000000000000000000000f6000000010000000100000000000000000000000064ffffffff000000810000000000000001000000f60000000100000000
77 | false
78 |
79 |
80 |
81 |
82 | 1
83 | User Constraints
84 |
85 |
86 |
87 |
88 | 0
89 | 0
90 | 000000ff000000000000000100000001000000000000000000000000000000000000000000000000f6000000010000000100000000000000000000000064ffffffff000000810000000000000001000000f60000000100000000
91 | false
92 |
93 |
94 |
95 |
--------------------------------------------------------------------------------
/iseconfig/mojo_top.xreport:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | 2014-02-20T09:25:01
5 | mojo_top
6 | 2013-04-16T10:54:27
7 | /home/justin/workspace/Mojo-Tutorials/Mojo-Base/iseconfig/mojo_top.xreport
8 | /home/justin/workspace/Mojo-Tutorials/Mojo-Base/syn/
9 | 2012-11-08T12:38:20
10 | false
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 |
81 |
82 |
83 |
84 |
85 |
86 |
87 |
88 |
89 |
90 |
91 |
92 |
93 |
94 |
95 |
96 |
97 |
98 |
99 |
100 |
101 |
102 |
103 |
104 |
105 |
106 |
107 |
108 |
109 |
110 |
111 |
112 |
113 |
114 |
115 |
116 |
117 |
118 |
119 |
120 |
121 |
122 |
123 |
124 |
125 |
126 |
127 |
128 |
129 |
130 |
131 |
132 |
133 |
134 |
135 |
136 |
137 |
138 |
139 |
140 |
141 |
142 |
143 |
144 |
145 |
146 |
147 |
148 |
149 |
150 |
151 |
152 |
153 |
154 |
155 |
156 |
157 |
158 |
159 |
160 |
161 |
162 |
163 |
164 |
165 |
166 |
167 |
168 |
169 |
170 |
171 |
172 |
173 |
174 |
175 |
176 |
177 |
178 |
179 |
180 |
181 |
182 |
183 |
184 |
185 |
186 |
187 |
188 |
189 |
190 |
191 |
192 |
193 |
194 |
195 |
196 |
197 |
198 |
199 |
200 |
201 |
202 |
203 |
204 |
205 |
206 |
207 |
208 |
209 |
210 |
211 |
212 |
213 |
214 |
215 |
216 |
--------------------------------------------------------------------------------
/src/avr_interface.v:
--------------------------------------------------------------------------------
1 | module avr_interface #(
2 | parameter CLK_RATE = 50000000,
3 | parameter SERIAL_BAUD_RATE = 500000
4 | )(
5 | input clk,
6 | input rst,
7 |
8 | // cclk, or configuration clock is used when the FPGA is begin configured.
9 | // The AVR will hold cclk high when it has finished initializing.
10 | // It is important not to drive the lines connecting to the AVR
11 | // until cclk is high for a short period of time to avoid contention.
12 | input cclk,
13 |
14 | // AVR SPI Signals
15 | output spi_miso,
16 | input spi_mosi,
17 | input spi_sck,
18 | input spi_ss,
19 | output [3:0] spi_channel,
20 |
21 | // AVR Serial Signals
22 | output tx,
23 | input rx,
24 |
25 | // ADC Interface Signals
26 | input [3:0] channel,
27 | output new_sample,
28 | output [9:0] sample,
29 | output [3:0] sample_channel,
30 |
31 | // Serial TX User Interface
32 | input [7:0] tx_data,
33 | input new_tx_data,
34 | output tx_busy,
35 | input tx_block,
36 |
37 | // Serial Rx User Interface
38 | output [7:0] rx_data,
39 | output new_rx_data
40 | );
41 |
42 | wire ready;
43 | wire n_rdy = !ready;
44 | wire spi_done;
45 | wire [7:0] spi_dout;
46 |
47 | wire tx_m;
48 | wire spi_miso_m;
49 |
50 | reg byte_ct_d, byte_ct_q;
51 | reg [9:0] sample_d, sample_q;
52 | reg new_sample_d, new_sample_q;
53 | reg [3:0] sample_channel_d, sample_channel_q;
54 | reg [3:0] block_d, block_q;
55 | reg busy_d, busy_q;
56 |
57 | // cclk_detector is used to detect when cclk is high signaling when
58 | // the AVR is ready
59 | cclk_detector #(.CLK_RATE(CLK_RATE)) cclk_detector (
60 | .clk(clk),
61 | .rst(rst),
62 | .cclk(cclk),
63 | .ready(ready)
64 | );
65 |
66 | spi_slave spi_slave (
67 | .clk(clk),
68 | .rst(n_rdy),
69 | .ss(spi_ss),
70 | .mosi(spi_mosi),
71 | .miso(spi_miso_m),
72 | .sck(spi_sck),
73 | .done(spi_done),
74 | .din(8'hff),
75 | .dout(spi_dout)
76 | );
77 |
78 | // CLK_PER_BIT is the number of cycles each 'bit' lasts for
79 | // rtoi converts a 'real' number to an 'integer'
80 | parameter CLK_PER_BIT = $rtoi($ceil(CLK_RATE/SERIAL_BAUD_RATE));
81 |
82 | serial_rx #(.CLK_PER_BIT(CLK_PER_BIT)) serial_rx (
83 | .clk(clk),
84 | .rst(n_rdy),
85 | .rx(rx),
86 | .data(rx_data),
87 | .new_data(new_rx_data)
88 | );
89 |
90 | serial_tx #(.CLK_PER_BIT(CLK_PER_BIT)) serial_tx (
91 | .clk(clk),
92 | .rst(n_rdy),
93 | .tx(tx_m),
94 | .block(busy_q),
95 | .busy(tx_busy),
96 | .data(tx_data),
97 | .new_data(new_tx_data)
98 | );
99 |
100 | // Output declarations
101 | assign new_sample = new_sample_q;
102 | assign sample = sample_q;
103 | assign sample_channel = sample_channel_q;
104 |
105 | // these signals connect to the AVR and should be Z when the AVR isn't ready
106 | assign spi_channel = ready ? channel : 4'bZZZZ;
107 | assign spi_miso = ready && !spi_ss ? spi_miso_m : 1'bZ;
108 | assign tx = ready ? tx_m : 1'bZ;
109 |
110 | always @(*) begin
111 | byte_ct_d = byte_ct_q;
112 | sample_d = sample_q;
113 | new_sample_d = 1'b0;
114 | sample_channel_d = sample_channel_q;
115 |
116 | busy_d = busy_q;
117 | block_d = {block_q[2:0], tx_block};
118 |
119 | if (block_q[3] ^ block_q[2])
120 | busy_d = 1'b0;
121 |
122 | if (!tx_busy && new_tx_data)
123 | busy_d = 1'b1;
124 |
125 | if (spi_ss) begin // device is not selected
126 | byte_ct_d = 1'b0;
127 | end
128 |
129 | if (spi_done) begin // sent/received data from SPI
130 | if (byte_ct_q == 1'b0) begin
131 | sample_d[7:0] = spi_dout; // first byte is the 8 LSB of the sample
132 | byte_ct_d = 1'b1;
133 | end else begin
134 | sample_d[9:8] = spi_dout[1:0]; // second byte is the channel 2 MSB of the sample
135 | sample_channel_d = spi_dout[7:4]; // and the channel that was sampled
136 | byte_ct_d = 1'b1; // slave-select must be brought high before the next transfer
137 | new_sample_d = 1'b1;
138 | end
139 | end
140 | end
141 |
142 | always @(posedge clk) begin
143 | if (n_rdy) begin
144 | byte_ct_q <= 1'b0;
145 | sample_q <= 10'b0;
146 | new_sample_q <= 1'b0;
147 | end else begin
148 | byte_ct_q <= byte_ct_d;
149 | sample_q <= sample_d;
150 | new_sample_q <= new_sample_d;
151 | end
152 |
153 | block_q <= block_d;
154 | busy_q <= busy_d;
155 | sample_channel_q <= sample_channel_d;
156 | end
157 |
158 | endmodule
--------------------------------------------------------------------------------
/src/cclk_detector.v:
--------------------------------------------------------------------------------
1 | module cclk_detector #(
2 | parameter CLK_RATE = 50000000
3 | )(
4 | input clk,
5 | input rst,
6 | input cclk,
7 | output ready
8 | );
9 |
10 | parameter CTR_SIZE = $clog2(CLK_RATE/50000);
11 |
12 | reg [CTR_SIZE-1:0] ctr_d, ctr_q;
13 | reg ready_d, ready_q;
14 |
15 | assign ready = ready_q;
16 |
17 | // ready should only go high once cclk has been high for a while
18 | // if cclk ever falls, ready should go low again
19 | always @(ctr_q or cclk) begin
20 | ready_d = 1'b0;
21 | if (cclk == 1'b0) begin // when cclk is 0 reset the counter
22 | ctr_d = 1'b0;
23 | end else if (ctr_q != {CTR_SIZE{1'b1}}) begin
24 | ctr_d = ctr_q + 1'b1; // counter isn't max value yet
25 | end else begin
26 | ctr_d = ctr_q;
27 | ready_d = 1'b1; // counter reached the max, we are ready
28 | end
29 |
30 | end
31 |
32 | always @(posedge clk) begin
33 | if (rst) begin
34 | ctr_q <= 1'b0;
35 | ready_q <= 1'b0;
36 | end else begin
37 | ctr_q <= ctr_d;
38 | ready_q <= ready_d;
39 | end
40 | end
41 | endmodule
42 |
--------------------------------------------------------------------------------
/src/mojo.ucf:
--------------------------------------------------------------------------------
1 | #Created by Constraints Editor (xc6slx9-tqg144-3) - 2012/11/05
2 | NET "clk" TNM_NET = clk;
3 | TIMESPEC TS_clk = PERIOD "clk" 50 MHz HIGH 50%;
4 |
5 | # PlanAhead Generated physical constraints
6 | NET "clk" LOC = P56 | IOSTANDARD = LVTTL;
7 | NET "rst_n" LOC = P38 | IOSTANDARD = LVTTL;
8 |
9 | NET "cclk" LOC = P70 | IOSTANDARD = LVTTL;
10 |
11 | NET "led<0>" LOC = P134 | IOSTANDARD = LVTTL;
12 | NET "led<1>" LOC = P133 | IOSTANDARD = LVTTL;
13 | NET "led<2>" LOC = P132 | IOSTANDARD = LVTTL;
14 | NET "led<3>" LOC = P131 | IOSTANDARD = LVTTL;
15 | NET "led<4>" LOC = P127 | IOSTANDARD = LVTTL;
16 | NET "led<5>" LOC = P126 | IOSTANDARD = LVTTL;
17 | NET "led<6>" LOC = P124 | IOSTANDARD = LVTTL;
18 | NET "led<7>" LOC = P123 | IOSTANDARD = LVTTL;
19 |
20 | NET "spi_mosi" LOC = P44 | IOSTANDARD = LVTTL;
21 | NET "spi_miso" LOC = P45 | IOSTANDARD = LVTTL;
22 | NET "spi_ss" LOC = P48 | IOSTANDARD = LVTTL;
23 | NET "spi_sck" LOC = P43 | IOSTANDARD = LVTTL;
24 | NET "spi_channel<0>" LOC = P46 | IOSTANDARD = LVTTL;
25 | NET "spi_channel<1>" LOC = P61 | IOSTANDARD = LVTTL;
26 | NET "spi_channel<2>" LOC = P62 | IOSTANDARD = LVTTL;
27 | NET "spi_channel<3>" LOC = P65 | IOSTANDARD = LVTTL;
28 |
29 | NET "avr_tx" LOC = P55 | IOSTANDARD = LVTTL;
30 | NET "avr_rx" LOC = P59 | IOSTANDARD = LVTTL;
31 | NET "avr_rx_busy" LOC = P39 | IOSTANDARD = LVTTL;
32 |
33 |
--------------------------------------------------------------------------------
/src/mojo_top.v:
--------------------------------------------------------------------------------
1 | module mojo_top(
2 | // 50MHz clock input
3 | input clk,
4 | // Input from reset button (active low)
5 | input rst_n,
6 | // cclk input from AVR, high when AVR is ready
7 | input cclk,
8 | // Outputs to the 8 onboard LEDs
9 | output[7:0]led,
10 | // AVR SPI connections
11 | output spi_miso,
12 | input spi_ss,
13 | input spi_mosi,
14 | input spi_sck,
15 | // AVR ADC channel select
16 | output [3:0] spi_channel,
17 | // Serial connections
18 | input avr_tx, // AVR Tx => FPGA Rx
19 | output avr_rx, // AVR Rx => FPGA Tx
20 | input avr_rx_busy // AVR Rx buffer full
21 | );
22 |
23 | wire rst = ~rst_n; // make reset active high
24 |
25 | // these signals should be high-z when not used
26 | assign spi_miso = 1'bz;
27 | assign avr_rx = 1'bz;
28 | assign spi_channel = 4'bzzzz;
29 |
30 | assign led = 8'b0;
31 |
32 | endmodule
--------------------------------------------------------------------------------
/src/serial_rx.v:
--------------------------------------------------------------------------------
1 | module serial_rx #(
2 | parameter CLK_PER_BIT = 50
3 | )(
4 | input clk,
5 | input rst,
6 | input rx,
7 | output [7:0] data,
8 | output new_data
9 | );
10 |
11 | // clog2 is 'ceiling of log base 2' which gives you the number of bits needed to store a value
12 | parameter CTR_SIZE = $clog2(CLK_PER_BIT);
13 |
14 | localparam STATE_SIZE = 2;
15 | localparam IDLE = 2'd0,
16 | WAIT_HALF = 2'd1,
17 | WAIT_FULL = 2'd2,
18 | WAIT_HIGH = 2'd3;
19 |
20 | reg [CTR_SIZE-1:0] ctr_d, ctr_q;
21 | reg [2:0] bit_ctr_d, bit_ctr_q;
22 | reg [7:0] data_d, data_q;
23 | reg new_data_d, new_data_q;
24 | reg [STATE_SIZE-1:0] state_d, state_q = IDLE;
25 | reg rx_d, rx_q;
26 |
27 | assign new_data = new_data_q;
28 | assign data = data_q;
29 |
30 | always @(*) begin
31 | rx_d = rx;
32 | state_d = state_q;
33 | ctr_d = ctr_q;
34 | bit_ctr_d = bit_ctr_q;
35 | data_d = data_q;
36 | new_data_d = 1'b0;
37 |
38 | case (state_q)
39 | IDLE: begin
40 | bit_ctr_d = 3'b0;
41 | ctr_d = 1'b0;
42 | if (rx_q == 1'b0) begin
43 | state_d = WAIT_HALF;
44 | end
45 | end
46 | WAIT_HALF: begin
47 | ctr_d = ctr_q + 1'b1;
48 | if (ctr_q == (CLK_PER_BIT >> 1)) begin
49 | ctr_d = 1'b0;
50 | state_d = WAIT_FULL;
51 | end
52 | end
53 | WAIT_FULL: begin
54 | ctr_d = ctr_q + 1'b1;
55 | if (ctr_q == CLK_PER_BIT - 1) begin
56 | data_d = {rx_q, data_q[7:1]};
57 | bit_ctr_d = bit_ctr_q + 1'b1;
58 | ctr_d = 1'b0;
59 | if (bit_ctr_q == 3'd7) begin
60 | state_d = WAIT_HIGH;
61 | new_data_d = 1'b1;
62 | end
63 | end
64 | end
65 | WAIT_HIGH: begin
66 | if (rx_q == 1'b1) begin
67 | state_d = IDLE;
68 | end
69 | end
70 | default: begin
71 | state_d = IDLE;
72 | end
73 | endcase
74 |
75 | end
76 |
77 | always @(posedge clk) begin
78 | if (rst) begin
79 | ctr_q <= 1'b0;
80 | bit_ctr_q <= 3'b0;
81 | new_data_q <= 1'b0;
82 | state_q <= IDLE;
83 | end else begin
84 | ctr_q <= ctr_d;
85 | bit_ctr_q <= bit_ctr_d;
86 | new_data_q <= new_data_d;
87 | state_q <= state_d;
88 | end
89 |
90 | rx_q <= rx_d;
91 | data_q <= data_d;
92 | end
93 |
94 | endmodule
--------------------------------------------------------------------------------
/src/serial_tx.v:
--------------------------------------------------------------------------------
1 | module serial_tx #(
2 | parameter CLK_PER_BIT = 50
3 | )(
4 | input clk,
5 | input rst,
6 | output tx,
7 | input block,
8 | output busy,
9 | input [7:0] data,
10 | input new_data
11 | );
12 |
13 | // clog2 is 'ceiling of log base 2' which gives you the number of bits needed to store a value
14 | parameter CTR_SIZE = $clog2(CLK_PER_BIT);
15 |
16 | localparam STATE_SIZE = 2;
17 | localparam IDLE = 2'd0,
18 | START_BIT = 2'd1,
19 | DATA = 2'd2,
20 | STOP_BIT = 2'd3;
21 |
22 | reg [CTR_SIZE-1:0] ctr_d, ctr_q;
23 | reg [2:0] bit_ctr_d, bit_ctr_q;
24 | reg [7:0] data_d, data_q;
25 | reg [STATE_SIZE-1:0] state_d, state_q = IDLE;
26 | reg tx_d, tx_q;
27 | reg busy_d, busy_q;
28 | reg block_d, block_q;
29 |
30 | assign tx = tx_q;
31 | assign busy = busy_q;
32 |
33 | always @(*) begin
34 | block_d = block;
35 | ctr_d = ctr_q;
36 | bit_ctr_d = bit_ctr_q;
37 | data_d = data_q;
38 | state_d = state_q;
39 | busy_d = busy_q;
40 |
41 | case (state_q)
42 | IDLE: begin
43 | if (block_q) begin
44 | busy_d = 1'b1;
45 | tx_d = 1'b1;
46 | end else begin
47 | busy_d = 1'b0;
48 | tx_d = 1'b1;
49 | bit_ctr_d = 3'b0;
50 | ctr_d = 1'b0;
51 | if (new_data) begin
52 | data_d = data;
53 | state_d = START_BIT;
54 | busy_d = 1'b1;
55 | end
56 | end
57 | end
58 | START_BIT: begin
59 | busy_d = 1'b1;
60 | ctr_d = ctr_q + 1'b1;
61 | tx_d = 1'b0;
62 | if (ctr_q == CLK_PER_BIT - 1) begin
63 | ctr_d = 1'b0;
64 | state_d = DATA;
65 | end
66 | end
67 | DATA: begin
68 | busy_d = 1'b1;
69 | tx_d = data_q[bit_ctr_q];
70 | ctr_d = ctr_q + 1'b1;
71 | if (ctr_q == CLK_PER_BIT - 1) begin
72 | ctr_d = 1'b0;
73 | bit_ctr_d = bit_ctr_q + 1'b1;
74 | if (bit_ctr_q == 7) begin
75 | state_d = STOP_BIT;
76 | end
77 | end
78 | end
79 | STOP_BIT: begin
80 | busy_d = 1'b1;
81 | tx_d = 1'b1;
82 | ctr_d = ctr_q + 1'b1;
83 | if (ctr_q == CLK_PER_BIT - 1) begin
84 | state_d = IDLE;
85 | end
86 | end
87 | default: begin
88 | state_d = IDLE;
89 | end
90 | endcase
91 | end
92 |
93 | always @(posedge clk) begin
94 | if (rst) begin
95 | state_q <= IDLE;
96 | tx_q <= 1'b1;
97 | end else begin
98 | state_q <= state_d;
99 | tx_q <= tx_d;
100 | end
101 |
102 | block_q <= block_d;
103 | data_q <= data_d;
104 | bit_ctr_q <= bit_ctr_d;
105 | ctr_q <= ctr_d;
106 | busy_q <= busy_d;
107 | end
108 |
109 | endmodule
--------------------------------------------------------------------------------
/src/spi_slave.v:
--------------------------------------------------------------------------------
1 | module spi_slave(
2 | input clk,
3 | input rst,
4 | input ss,
5 | input mosi,
6 | output miso,
7 | input sck,
8 | output done,
9 | input [7:0] din,
10 | output [7:0] dout
11 | );
12 |
13 | reg mosi_d, mosi_q;
14 | reg ss_d, ss_q;
15 | reg sck_d, sck_q;
16 | reg sck_old_d, sck_old_q;
17 | reg [7:0] data_d, data_q;
18 | reg done_d, done_q;
19 | reg [2:0] bit_ct_d, bit_ct_q;
20 | reg [7:0] dout_d, dout_q;
21 | reg miso_d, miso_q;
22 |
23 | assign miso = miso_q;
24 | assign done = done_q;
25 | assign dout = dout_q;
26 |
27 | always @(*) begin
28 | ss_d = ss;
29 | mosi_d = mosi;
30 | miso_d = miso_q;
31 | sck_d = sck;
32 | sck_old_d = sck_q;
33 | data_d = data_q;
34 | done_d = 1'b0;
35 | bit_ct_d = bit_ct_q;
36 | dout_d = dout_q;
37 |
38 | if (ss_q) begin
39 | bit_ct_d = 3'b0;
40 | data_d = din;
41 | miso_d = data_q[7];
42 | end else begin
43 | if (!sck_old_q && sck_q) begin // rising edge
44 | data_d = {data_q[6:0], mosi_q};
45 | bit_ct_d = bit_ct_q + 1'b1;
46 | if (bit_ct_q == 3'b111) begin
47 | dout_d = {data_q[6:0], mosi_q};
48 | done_d = 1'b1;
49 | data_d = din;
50 | end
51 | end else if (sck_old_q && !sck_q) begin // falling edge
52 | miso_d = data_q[7];
53 | end
54 | end
55 | end
56 |
57 | always @(posedge clk) begin
58 | if (rst) begin
59 | done_q <= 1'b0;
60 | bit_ct_q <= 3'b0;
61 | dout_q <= 8'b0;
62 | miso_q <= 1'b1;
63 | end else begin
64 | done_q <= done_d;
65 | bit_ct_q <= bit_ct_d;
66 | dout_q <= dout_d;
67 | miso_q <= miso_d;
68 | end
69 |
70 | sck_q <= sck_d;
71 | mosi_q <= mosi_d;
72 | ss_q <= ss_d;
73 | data_q <= data_d;
74 | sck_old_q <= sck_old_d;
75 |
76 | end
77 |
78 |
79 | endmodule
80 |
--------------------------------------------------------------------------------
/syn/.gitignore:
--------------------------------------------------------------------------------
1 | # Ignore everything in this directory
2 | *
3 | # Except this file
4 | !.gitignore
--------------------------------------------------------------------------------