]> git.ozlabs.org Git - minimigmac.git/blob - fpga/spi_slave.v
Initial commit
[minimigmac.git] / fpga / spi_slave.v
1 `timescale 1ns / 100ps
2
3 /* SPI slave module
4  *
5  * Expected configuration on the master is SPI mode 0
6  * (CPOL 0 CPHA 0)
7  *  - SCK idle state is 0
8  *  - We latch input on positive edges of SCK
9  *  - We setup output on negative edge of SCK
10  * 
11  * IE. For a PIC, this means setting:
12  *    CKP=0 CKE=1 SMP=0
13  */
14 module spi_slave
15 (
16    input                sysclk,
17    input                reset,  /* Async system reset */
18    input                _scs,
19    input                sdi,
20    output               sdo,
21    input                sck,
22    input [7:0]          wdata,  /* Output data */
23    output reg [7:0]     rdata,  /* Input data */
24    output               rx,     /* One-sysclk signal of a new byte */
25    output reg           cmd     /* Indicate first byte of rx, variable len */
26 );
27
28         reg [6:0] in_sr;
29         reg [7:0] out_sr;
30         reg [2:0] cnt;  
31         reg       first;
32         reg       new_byte;
33         reg       rx1;
34         reg       rx2;
35         reg       rx3;
36         reg       tx;   
37
38         /* Bit counter */
39         always@(posedge sck or posedge _scs) begin
40                 if (_scs) begin
41                         cnt <= 0;
42                 end else begin
43                         cnt <= cnt + 1;
44                 end
45         end
46         
47         /* Shift input, latch on positive edge of sck. We only shift in 7
48          * bits as we'll take sdi directly into the final latch.
49          */
50         always@(posedge sck) begin
51                 if (!_scs) begin
52                         in_sr[6:0] <= { in_sr[5:0], sdi };
53                 end
54         end
55
56         /* We latch the input byte so it remains stable for a while byte for
57          * consumption by sysclk domain.
58          */
59         always@(posedge sck) begin
60                 if (!_scs && cnt == 3'b111) begin
61                         rdata[7:0] <= { in_sr[6:0], sdi };
62                 end
63         end
64
65         /* Shift output. We latch "data" on bit 7 falling edge (so before we
66          * set new_byte and thus before rx catches up sysclk domain).
67          * 
68          * That means we are ahead by one bit, so we add a one bit delay latch
69          * on sdo
70          * 
71          */
72         always@(negedge sck or posedge _scs) begin
73                 if (_scs) begin
74                         out_sr <= 8'hff;
75                 end else begin          
76                         if (cnt == 3'b111) begin
77                                 out_sr <= wdata;
78                         end else begin
79                                 out_sr[7:0] <= { out_sr[6:0], 1'b0 };
80                         end                     
81                 end
82         end
83
84         always@(negedge sck or posedge _scs) begin
85                 if (_scs) begin
86                         tx <= 1;
87                 end else begin
88                         tx <= out_sr[7];
89                 end
90         end     
91         
92         /* We keep output hi-z if chip select not set. We do have a transcient
93          * undefined state between _scs assertion and the first clock, which
94          * I'm happy to ignore for now
95          */
96         assign sdo = _scs ? 1'bz : tx;
97
98         /* Now we need to generate rx. It's tricky because sck can/will stop
99          * immediately after the last bit.
100          * 
101          * What we do is we generate a signal "new_byte" at the same time as
102          * latching the input byte, which we clear half way through the next
103          * byte. We then double flip-flop synchronize that into sysclk domain
104          * where we do an edge detection. If we lose sck, this signal will
105          * remains set until we start a new transmission, but since the delay
106          * between two transmissions is unpredictable, we must make sure we
107          * don't clear it until half way through the new byte (ie, we keep it
108          * set even when SCS is gone). For the same reason we don't
109          * clear our input latch either when SCS is gone.
110          * 
111          * Now, the nasty thing is we need to reset that dude asynchronously
112          * from sysclk domain, which could probably use some sychronisation
113          * too. For now, we assume the sysclk reset happens long enough before
114          * sck toggles. This will do for us, but in a more complex system,
115          * some logic might be needed to ensure sck is effectively masked
116          * out until a few clocks after reset completes to avoid metastability
117          * 
118          * Note: FPGAs are nice, we could probably just rely on new_byte being
119          * 0 at powerup time :-)
120          */
121         always@(posedge sck or posedge reset) begin
122                 if (reset) begin
123                         new_byte <= 0;
124                 end else begin
125                         if (cnt == 3'b111) begin
126                                 new_byte <= 1;
127                         end else if (cnt == 3'b011) begin
128                                 new_byte <= 0;
129                         end
130                 end             
131         end
132
133         always@(posedge sysclk or posedge reset) begin
134                 if (reset) begin
135                         rx1 <= 0;
136                         rx2 <= 0;
137                         rx3 <= 0;                       
138                 end else begin
139                         rx1 <= new_byte;
140                         rx2 <= rx1;
141                         rx3 <= rx2;                     
142                 end
143         end
144
145         assign rx = rx2 & !rx3;
146
147         /* "first" is set in sck domain during clocking of first byte,
148          * and flushed into "cmd" at bit 7, thus cmd moves along with
149          * the data itself and will be sampled with the data by the user.
150          */
151         always@(posedge sck or posedge _scs) begin
152                 if (_scs) begin
153                         first <= 1;
154                 end else if (cnt == 3'b111) begin
155                         first <= 0;
156                         cmd <= first;
157                 end
158         end
159 endmodule