├── .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 | 32 | 33 | 37 | 38 | 43 | 44 | 45 | 56 | 57 | 83 | 148 | 149 | 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 --------------------------------------------------------------------------------