updates for ml410 board
[fleet.git] / src / edu / berkeley / fleet / fpga / sasc_top.v
1 /////////////////////////////////////////////////////////////////////
2 ////                                                             ////
3 ////  Simple Asynchronous Serial Comm. Device                    ////
4 ////                                                             ////
5 ////                                                             ////
6 ////  Author: Rudolf Usselmann                                   ////
7 ////          rudi@asics.ws                                      ////
8 ////                                                             ////
9 ////                                                             ////
10 ////  Downloaded from: http://www.opencores.org/cores/sasc/      ////
11 ////                                                             ////
12 /////////////////////////////////////////////////////////////////////
13 ////                                                             ////
14 //// Copyright (C) 2000-2002 Rudolf Usselmann                    ////
15 ////                         www.asics.ws                        ////
16 ////                         rudi@asics.ws                       ////
17 ////                                                             ////
18 //// This source file may be used and distributed without        ////
19 //// restriction provided that this copyright statement is not   ////
20 //// removed from the file and that any derivative work contains ////
21 //// the original copyright notice and the associated disclaimer.////
22 ////                                                             ////
23 ////     THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY     ////
24 //// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED   ////
25 //// TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS   ////
26 //// FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL THE AUTHOR      ////
27 //// OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,         ////
28 //// INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES    ////
29 //// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE   ////
30 //// GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR        ////
31 //// BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF  ////
32 //// LIABILITY, WHETHER IN  CONTRACT, STRICT LIABILITY, OR TORT  ////
33 //// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT  ////
34 //// OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE         ////
35 //// POSSIBILITY OF SUCH DAMAGE.                                 ////
36 ////                                                             ////
37 /////////////////////////////////////////////////////////////////////
38
39 //  CVS Log
40 //
41 //  $Id: sasc_top.v,v 1.2 2006/03/30 02:47:07 rudi Exp $
42 //
43 //  $Date: 2006/03/30 02:47:07 $
44 //  $Revision: 1.2 $
45 //  $Author: rudi $
46 //  $Locker:  $
47 //  $State: Exp $
48 //
49 // Change History:
50 //               $Log: sasc_top.v,v $
51 //               Revision 1.2  2006/03/30 02:47:07  rudi
52 //               Thanks to Darren O'Connor of SPEC, Inc. for fixing a bug
53 //               with the DPLL and data alignment:
54 //
55 //               You were right that it was a problem with the dpll. I found
56 //               that it was possible to get two baud clocks (rx_sio_ce) during
57 //               one bit period.  I fixed the problem by delaying the input data
58 //               signal with a shift register and using that in the equations
59 //               for the "change" variable that controls the DPLL FSM.
60 //
61 //               Revision 1.1.1.1  2002/09/16 16:16:42  rudi
62 //               Initial Checkin
63 //
64 //
65 //
66 //
67 //
68 //
69 //
70 //
71
72 `include "timescale.v"
73
74 /*
75 Serial IO Interface
76 ===============================
77 RTS I Request To Send
78 CTS O Clear to send
79 TD  I Transmit Data
80 RD  O Receive Data
81 */
82
83 module sasc_top(        clk, rst,
84         
85                         // SIO
86                         rxd_i, txd_o, cts_i, rts_o, 
87
88                         // External Baud Rate Generator
89                         sio_ce, sio_ce_x4,
90
91                         // Internal Interface
92                         din_i, dout_o, re_i, we_i, full_o, empty_o);
93
94 input           clk;
95 input           rst;
96 input           rxd_i;
97 output          txd_o;
98 input           cts_i;
99 output          rts_o; 
100 input           sio_ce;
101 input           sio_ce_x4;
102 input   [7:0]   din_i;
103 output  [7:0]   dout_o;
104 input           re_i, we_i;
105 output          full_o, empty_o;
106
107 ///////////////////////////////////////////////////////////////////
108 //
109 // Local Wires and Registers
110 //
111
112 parameter       START_BIT       = 1'b0,
113                 STOP_BIT        = 1'b1,
114                 IDLE_BIT        = 1'b1;
115
116 wire    [7:0]   txd_p;
117 reg             load;
118 reg             load_r;
119 wire            load_e;
120 reg     [9:0]   hold_reg;
121 wire            txf_empty;
122 reg             txd_o;
123 reg             shift_en;
124 reg     [3:0]   tx_bit_cnt;
125 reg             rxd_s, rxd_r;
126 wire            start;
127 reg     [3:0]   rx_bit_cnt;
128 reg             rx_go;
129 reg     [9:0]   rxr;
130 reg             rx_valid, rx_valid_r;
131 wire            rx_we;
132 wire            rxf_full;
133 reg             rts_o;
134 reg             txf_empty_r;
135 reg             shift_en_r;
136 reg             rxd_r1, rxd_r2;
137 wire            lock_en;
138 reg             change;
139 reg             rx_sio_ce_d, rx_sio_ce_r1, rx_sio_ce_r2, rx_sio_ce;
140 reg     [1:0]   dpll_state, dpll_next_state;
141 reg     [5:0]   rxd_dly; //New input delay used to ensure no baud clocks
142                         // occur twice in one baud period
143 ///////////////////////////////////////////////////////////////////
144 //
145 // IO Fifo's
146 //
147
148 sasc_fifo4 tx_fifo(     .clk(           clk             ),
149                         .rst(           rst             ),
150                         .clr(           1'b0            ),
151                         .din(           din_i           ),
152                         .we(            we_i            ),
153                         .dout(          txd_p           ),
154                         .re(            load_e          ),
155                         .full(          full_o          ),
156                         .empty(         txf_empty       )
157                         );
158
159 sasc_fifo4 rx_fifo(     .clk(           clk             ),
160                         .rst(           rst             ),
161                         .clr(           1'b0            ),
162                         .din(           rxr[9:2]        ),
163                         .we(            rx_we           ),
164                         .dout(          dout_o          ),
165                         .re(            re_i            ),
166                         .full(          rxf_full        ),
167                         .empty(         empty_o         )
168                         );
169
170 ///////////////////////////////////////////////////////////////////
171 //
172 // Transmit Logic
173 //
174 always @(posedge clk)
175         if(!rst)        txf_empty_r <= #1 1'b1;
176         else
177         if(sio_ce)      txf_empty_r <= #1 txf_empty;
178
179 always @(posedge clk)
180         load <= #1 !txf_empty_r & !shift_en & !cts_i;
181
182 always @(posedge clk)
183         load_r <= #1 load;
184
185 assign load_e = load & sio_ce;
186
187 always @(posedge clk)
188         if(load_e)              hold_reg <= #1 {STOP_BIT, txd_p, START_BIT};
189         else
190         if(shift_en & sio_ce)   hold_reg <= #1 {IDLE_BIT, hold_reg[9:1]};
191
192 always @(posedge clk)
193         if(!rst)                                txd_o <= #1 IDLE_BIT;
194         else
195         if(sio_ce)
196                 if(shift_en | shift_en_r)       txd_o <= #1 hold_reg[0];
197                 else                            txd_o <= #1 IDLE_BIT;
198
199 always @(posedge clk)
200         if(!rst)                tx_bit_cnt <= #1 4'h9;
201         else
202         if(load_e)              tx_bit_cnt <= #1 4'h0;
203         else
204         if(shift_en & sio_ce)   tx_bit_cnt <= #1 tx_bit_cnt + 4'h1;
205
206 always @(posedge clk)
207         shift_en <= #1 (tx_bit_cnt != 4'h9);
208
209 always @(posedge clk)
210         if(!rst)        shift_en_r <= #1 1'b0;
211         else
212         if(sio_ce)      shift_en_r <= #1 shift_en;
213
214 ///////////////////////////////////////////////////////////////////
215 //
216 // Recieve Logic
217 //
218
219 always @(posedge clk)
220 begin
221     rxd_dly[5:1] <= #1 rxd_dly[4:0];
222          rxd_dly[0] <= #1rxd_i;
223          rxd_s <= #1rxd_dly[5];  // rxd_s = delay 1
224     rxd_r <= #1 rxd_s;  // rxd_r = delay 2       
225 end
226
227
228 assign start = (rxd_r == IDLE_BIT) & (rxd_s == START_BIT);
229
230 always @(posedge clk)
231         if(!rst)                rx_bit_cnt <= #1 4'ha;
232         else
233         if(!rx_go & start)      rx_bit_cnt <= #1 4'h0;
234         else
235         if(rx_go & rx_sio_ce)   rx_bit_cnt <= #1 rx_bit_cnt + 4'h1;
236
237 always @(posedge clk)
238         rx_go <= #1 (rx_bit_cnt != 4'ha);
239
240 always @(posedge clk)
241         rx_valid <= #1 (rx_bit_cnt == 4'h9);
242
243 always @(posedge clk)
244         rx_valid_r <= #1 rx_valid;
245
246 assign rx_we = !rx_valid_r & rx_valid & !rxf_full;
247
248 always @(posedge clk)
249         if(rx_go & rx_sio_ce)   rxr <= {rxd_s, rxr[9:1]};
250
251 always @(posedge clk)
252         rts_o <= #1 rxf_full;
253
254 ///////////////////////////////////////////////////////////////////
255 //
256 // Reciever DPLL
257 //
258
259 // Uses 4x baud clock to lock to incoming stream
260
261 // Edge detector
262 always @(posedge clk)
263         if(sio_ce_x4)   rxd_r1 <= #1 rxd_s;
264
265 always @(posedge clk)
266         if(sio_ce_x4)   rxd_r2 <= #1 rxd_r1;
267
268 always @(posedge clk)
269     if(!rst)        
270         change <= #1 1'b0;
271     else if ((rxd_dly[1] != rxd_r1) || (rxd_dly[1] != rxd_s))
272         change <= #1 1'b1;
273     else if(sio_ce_x4)
274         change <= #1 1'b0;
275
276 // DPLL FSM
277 always @(posedge clk or negedge rst)
278         if(!rst)        dpll_state <= #1 2'h1;
279         else
280         if(sio_ce_x4)   dpll_state <= #1 dpll_next_state;
281
282 always @(dpll_state or change)
283    begin
284         rx_sio_ce_d = 1'b0;
285         case(dpll_state)
286            2'h0:
287                 if(change)      dpll_next_state = 3'h0;
288                 else            dpll_next_state = 3'h1;
289            2'h1:begin
290                 rx_sio_ce_d = 1'b1;
291                 if(change)      dpll_next_state = 3'h3;
292                 else            dpll_next_state = 3'h2;
293                 end
294            2'h2:
295                 if(change)      dpll_next_state = 3'h0;
296                 else            dpll_next_state = 3'h3;
297            2'h3:
298                 if(change)      dpll_next_state = 3'h0;
299                 else            dpll_next_state = 3'h0;
300         endcase
301    end
302
303 // Compensate for sync registers at the input - allign sio 
304 // clock enable to be in the middle between two bit changes ...
305 always @(posedge clk)
306         rx_sio_ce_r1 <= #1 rx_sio_ce_d;
307
308 always @(posedge clk)
309         rx_sio_ce_r2 <= #1 rx_sio_ce_r1;
310
311 always @(posedge clk)
312         rx_sio_ce <= #1 rx_sio_ce_r1 & !rx_sio_ce_r2;
313
314 endmodule
315
316