- // ZX-Evo Base Configuration (c) NedoPC 2008,2009,2010,2011,2012,2013,2014 
- // 
- // SPI mode 0 8-bit master module 
-   
- /* 
-     This file is part of ZX-Evo Base Configuration firmware. 
-   
-     ZX-Evo Base Configuration firmware is free software: 
-     you can redistribute it and/or modify it under the terms of 
-     the GNU General Public License as published by 
-     the Free Software Foundation, either version 3 of the License, or 
-     (at your option) any later version. 
-   
-     ZX-Evo Base Configuration firmware is distributed in the hope that 
-     it will be useful, but WITHOUT ANY WARRANTY; without even 
-     the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 
-     See the GNU General Public License for more details. 
-   
-     You should have received a copy of the GNU General Public License 
-     along with ZX-Evo Base Configuration firmware. 
-     If not, see <http://www.gnu.org/licenses/>. 
- */ 
-   
-   
- // short diagram for speed=0 (Fclk/Fspi=2, no rdy shown) 
- // 
- // clock:   ^  ^  ^  ^  ^  ^  ^  ^  ^  ^  ^  ^  ^  ^  ^  ^  ^  ^  ^  ^  ^  ^  ^  ^ (positive edges) 
- // counter: |00|00|10|11|12|13|14|15|16|17|18|19|1A|1B|1C|1D|1E|1F|00|00|00 // internal! 
- // sck:   ___________/``\__/``\__/``\__/``\__/``\__/``\__/``\__/``\_______ 
- // sdo:   --------< do7 X do6 X do5 X do4 X do3 X do2 X do1 X do0 >------- 
- // sdi:   --------< di7 X di6 X di5 X di4 X di3 X di2 X di1 X di0 >------- 
- // bsync: ________/`````\_________________________________________________ 
- // start: _____/``\_______________________________________________________ 
- // din:   -----<IN>------------------------------------------------------- 
- // dout:   old old old old old old old old old old old old old | new new new 
- // 
- // data on sdo must be latched by slave on rising sck edge. data on sdo changes on falling edge of sck 
- // 
- // data from sdi is latched by master on positive edge of sck, while slave changes it on falling edge. 
- //  WARNING: slave must emit valid di7 bit BEFORE first pulse on sck! 
- // 
- // bsync is 1 while do7 is outting, otherwise it is 0 
- // 
- // start is synchronous pulse, which starts all transfer and also latches din data on the same clock edge 
- //  as it is registered high. start can be given anytime (only when speed=0), 
- //  so it is functioning then as synchronous reset. when speed!=0, there is global enable for majority of 
- //  flipflops in the module, so start can't be accepted at any time 
- // 
- // dout updates with freshly received data at the clock edge in which sck goes high for the last time, thus 
- //  latching last bit on sdi. 
- // 
- // sdo emits last bit shifted out after the transfer end 
- // 
- // when speed=0, data transfer rate could be as fast as one byte every 16 clock pulses. To achieve that, 
- //   start must be pulsed high simultaneously with the last high pulse of sck 
- // 
- // speed[1:0] determines Fclk/Fspi 
- // 
- //  speed | Fclk/Fspi 
- //  ------+---------- 
- //  2'b00 | 2 
- //  2'b01 | 4 
- //  2'b10 | 8 
- //  2'b11 | 16 
- // 
- // for speed=0 you can start new transfer as fast as every 16 clocks 
- // for speed=1 - every 34 clocks. 
- // alternatively, you can check rdy output: it goes to 0 after start pulse and when it goes back to 1, you can 
- // issue another start at the next clock cycle. See spi2_modelled.png and .zip (modelsim project) 
- // 
- // warning: if using rdy-driven transfers and speed=0, new transfer will be started every 18 clocks. 
- //  it is recommended to use rdy-driven transfers when speed!=0 
- // 
- // warning: this module does not contain asynchronous reset. Provided clock is stable, start=0 
- //  and speed=0, module returns to initial ready state after maximum of 18+8=26 clocks. To reset module 
- //  to the known state from any operational state, set speed=0 and start=1 for 8 clocks 
- //  (that starts Fclk/Fspi=2 speed transfer for sure), then remain start=0, speed=0 for at least 18 clocks. 
-   
- module spi2( 
-   
-         clock, // system clock 
-   
-         sck,   // SPI bus pins... 
-         sdo,   // 
-         sdi,   // 
-         bsync, // ...and bsync for vs1001 
-   
-         start, // positive strobe that starts transfer 
-         rdy,   // ready (idle) - when module can accept data 
-   
-         speed, // =2'b00 - sck full speed (1/2 of clock), =2'b01 - half (1/4 of clock), =2'b10 - one fourth (1/8 of clock), =2'b11 - one eighth (1/16 of clock) 
-   
-         din,  // input 
-         dout  // and output 8bit busses 
- ); 
-   
-         input clock; 
-   
-   
-         output sck; 
-         wire   sck; 
-   
-         output sdo; 
-   
-         input sdi; 
-   
-         output reg bsync; 
-   
-         input start; 
-   
-         output rdy; 
-   
-   
-         input [1:0] speed; 
-   
-         input [7:0] din; 
-   
-         output reg [7:0] dout; 
-   
-   
-   
-         // internal regs 
-   
-         reg [4:0] counter; // governs transmission 
-   
-         wire enable_n; // =1 when transmission in progress 
-   
-         reg [6:0] shiftin; // shifting in data from sdi before emitting it on dout 
-   
-         reg [7:0] shiftout; // shifting out data to the sdo 
-   
-         wire ena_shout_load; // enable load of shiftout register 
-   
-         wire g_ena; 
-         reg [2:0] wcnt; 
-   
-   
-         initial // for simulation only! 
-         begin 
-                 counter = 5'b10000; 
-                 shiftout = 8'd0; 
-                 shiftout = 7'd0; 
-                 bsync = 1'd0; 
-                 dout = 1'b0; 
-         end 
-   
-   
-         // rdy is enable_n 
-         assign rdy = enable_n; 
-   
-         // sck is low bit of counter 
-         assign sck = counter[0]; 
-   
-         // enable_n is high bit of counter 
-         assign enable_n = counter[4]; 
-   
-         // sdo is high bit of shiftout 
-         assign sdo = shiftout[7]; 
-   
-         assign ena_shout_load = (start | sck) & g_ena; 
-   
-   
-   
-   
-         always @(posedge clock) 
-         begin 
-                 if( g_ena ) 
-                 begin 
-                         if( start ) 
-                         begin 
-                                 counter <= 5'b00000; // enable_n = 0; sck = 0; 
-                                 bsync <= 1'b1; // begin bsync pulse 
-                         end 
-                         else 
-                         begin 
-                                 if( !sck ) // on the rising edge of sck 
-                                 begin 
-                           shiftin[6:0] <= { shiftin[5:0], sdi }; 
-   
-                                         if( (&counter[3:1]) && (!enable_n) ) 
-                                                 dout <= { shiftin[6:0], sdi }; // update dout at the last sck rising edge 
-                                 end 
-                                 else // on the falling edge of sck 
-                                 begin 
-                                         bsync <= 1'b0; 
-                                 end 
-   
-                                 if( !enable_n ) 
-                                         counter <= counter + 5'd1; 
-                         end 
-                 end 
-         end 
-   
-   
-         // shiftout treatment is done so just to save LCELLs in acex1k 
-         always @(posedge clock) 
-         begin 
-                 if( ena_shout_load ) 
-                 begin 
-                         if( start ) 
-                                 shiftout <= din; 
-                         else // sck 
-                                 shiftout[7:0] <= { shiftout[6:0], shiftout[0] }; // last bit remains after end of exchange 
-                 end 
-         end 
-   
-   
-         // slow speeds - governed by g_ena 
-         always @(posedge clock) 
-         begin 
-                 if( speed!=2'b00 ) 
-                 begin 
-                         if( start ) 
-                                 wcnt <= 3'b001; 
-                         else if( enable_n ) 
-                                 wcnt <= 3'b000; 
-                         else 
-                                 wcnt <= wcnt + 3'd1; 
-                 end 
-                 else 
-                         wcnt <= 3'b000; 
-         end 
-   
-         assign g_ena = (speed==2'b00) ? 1'b1 : 
-                        (speed==2'b01) ? (wcnt[0]  == 1'b0   ) : 
-                        (speed==2'b10) ? (wcnt[1:0]== 2'b00  ) : 
-                                         (wcnt[2:0]== 3'b000 ) ; 
-   
-   
- endmodule 
-   
-