add support for RS-232 break signal
[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                         break_o);
94
95 input           clk;
96 input           rst;
97 input           rxd_i;
98 output          txd_o;
99 input           cts_i;
100 output          rts_o; 
101 output          break_o;
102 reg break_r;
103 input           sio_ce;
104 input           sio_ce_x4;
105 input   [7:0]   din_i;
106 output  [7:0]   dout_o;
107 input           re_i, we_i;
108 output          full_o, empty_o;
109
110 ///////////////////////////////////////////////////////////////////
111 //
112 // Local Wires and Registers
113 //
114
115 parameter       START_BIT       = 1'b0,
116                 STOP_BIT        = 1'b1,
117                 IDLE_BIT        = 1'b1;
118
119 wire    [7:0]   txd_p;
120 reg             load;
121 reg             load_r;
122 wire            load_e;
123 reg     [9:0]   hold_reg;
124 wire            txf_empty;
125 reg             txd_o;
126 reg             shift_en;
127 reg     [3:0]   tx_bit_cnt;
128 reg             rxd_s, rxd_r;
129 wire            start;
130 reg     [3:0]   rx_bit_cnt;
131 reg             rx_go;
132 reg     [9:0]   rxr;
133 reg             rx_valid, rx_valid_r;
134 wire            rx_we;
135 wire            rxf_full;
136 reg             rts_o;
137 reg             txf_empty_r;
138 reg             shift_en_r;
139 reg             rxd_r1, rxd_r2;
140 wire            lock_en;
141 reg             change;
142 reg             rx_sio_ce_d, rx_sio_ce_r1, rx_sio_ce_r2, rx_sio_ce;
143 reg     [1:0]   dpll_state, dpll_next_state;
144 reg     [5:0]   rxd_dly; //New input delay used to ensure no baud clocks
145                         // occur twice in one baud period
146 ///////////////////////////////////////////////////////////////////
147 //
148 // IO Fifo's
149 //
150
151 sasc_fifo4 tx_fifo(     .clk(           clk             ),
152                         .rst(           rst             ),
153                         .clr(           1'b0            ),
154                         .din(           din_i           ),
155                         .we(            we_i            ),
156                         .dout(          txd_p           ),
157                         .re(            load_e          ),
158                         .full(          full_o          ),
159                         .empty(         txf_empty       )
160                         );
161
162 sasc_fifo4 rx_fifo(     .clk(           clk             ),
163                         .rst(           rst             ),
164                         .clr(           1'b0            ),
165                         .din(           rxr[9:2]        ),
166                         .we(            rx_we           ),
167                         .dout(          dout_o          ),
168                         .re(            re_i            ),
169                         .full(          rxf_full        ),
170                         .empty(         empty_o         )
171                         );
172
173 ///////////////////////////////////////////////////////////////////
174 //
175 // Transmit Logic
176 //
177 always @(posedge clk)
178         if(!rst)        txf_empty_r <= #1 1'b1;
179         else
180         if(sio_ce)      txf_empty_r <= #1 txf_empty;
181
182 always @(posedge clk)
183         load <= #1 !txf_empty_r & !shift_en & !cts_i;
184
185 always @(posedge clk)
186         load_r <= #1 load;
187
188 assign load_e = load & sio_ce;
189
190 always @(posedge clk)
191         if(load_e)              hold_reg <= #1 {STOP_BIT, txd_p, START_BIT};
192         else
193         if(shift_en & sio_ce)   hold_reg <= #1 {IDLE_BIT, hold_reg[9:1]};
194
195 always @(posedge clk)
196         if(!rst)                                txd_o <= #1 IDLE_BIT;
197         else
198         if(sio_ce)
199                 if(shift_en | shift_en_r)       txd_o <= #1 hold_reg[0];
200                 else                            txd_o <= #1 IDLE_BIT;
201
202 always @(posedge clk)
203         if(!rst)                tx_bit_cnt <= #1 4'h9;
204         else
205         if(load_e)              tx_bit_cnt <= #1 4'h0;
206         else
207         if(shift_en & sio_ce)   tx_bit_cnt <= #1 tx_bit_cnt + 4'h1;
208
209 always @(posedge clk)
210         shift_en <= #1 (tx_bit_cnt != 4'h9);
211
212 always @(posedge clk)
213         if(!rst)        shift_en_r <= #1 1'b0;
214         else
215         if(sio_ce)      shift_en_r <= #1 shift_en;
216
217 ///////////////////////////////////////////////////////////////////
218 //
219 // Recieve Logic
220 //
221
222 always @(posedge clk)
223 begin
224     rxd_dly[5:1] <= #1 rxd_dly[4:0];
225          rxd_dly[0] <= #1rxd_i;
226          rxd_s <= #1rxd_dly[5];  // rxd_s = delay 1
227     rxd_r <= #1 rxd_s;  // rxd_r = delay 2       
228 end
229
230
231 assign start = (rxd_r == IDLE_BIT) & (rxd_s == START_BIT);
232
233 always @(posedge clk)
234         if(!rst)                rx_bit_cnt <= #1 4'ha;
235         else
236         if(!rx_go & start)      rx_bit_cnt <= #1 4'h0;
237         else
238         if(rx_go & rx_sio_ce)   rx_bit_cnt <= #1 rx_bit_cnt + 4'h1;
239
240 always @(posedge clk)
241         rx_go <= #1 (rx_bit_cnt != 4'ha);
242
243 assign break_o = break_r;
244 always @(posedge clk)
245         rx_valid <= #1 (rx_bit_cnt == 4'h9) && (rxd_s == STOP_BIT);
246 always @(posedge clk)
247         break_r  <= #1 (rx_bit_cnt == 4'h9) && (rxr[9:1]==8'b0) && (rxd_s == START_BIT);
248
249 always @(posedge clk)
250         rx_valid_r <= #1 rx_valid;
251
252 assign rx_we = !rx_valid_r & rx_valid & !rxf_full;
253
254 always @(posedge clk)
255         if(rx_go & rx_sio_ce)   rxr <= {rxd_s, rxr[9:1]};
256
257 always @(posedge clk)
258         rts_o <= #1 rxf_full;
259
260 ///////////////////////////////////////////////////////////////////
261 //
262 // Reciever DPLL
263 //
264
265 // Uses 4x baud clock to lock to incoming stream
266
267 // Edge detector
268 always @(posedge clk)
269         if(sio_ce_x4)   rxd_r1 <= #1 rxd_s;
270
271 always @(posedge clk)
272         if(sio_ce_x4)   rxd_r2 <= #1 rxd_r1;
273
274 always @(posedge clk)
275     if(!rst)        
276         change <= #1 1'b0;
277     else if ((rxd_dly[1] != rxd_r1) || (rxd_dly[1] != rxd_s))
278         change <= #1 1'b1;
279     else if(sio_ce_x4)
280         change <= #1 1'b0;
281
282 // DPLL FSM
283 always @(posedge clk or negedge rst)
284         if(!rst)        dpll_state <= #1 2'h1;
285         else
286         if(sio_ce_x4)   dpll_state <= #1 dpll_next_state;
287
288 always @(dpll_state or change)
289    begin
290         rx_sio_ce_d = 1'b0;
291         case(dpll_state)
292            2'h0:
293                 if(change)      dpll_next_state = 3'h0;
294                 else            dpll_next_state = 3'h1;
295            2'h1:begin
296                 rx_sio_ce_d = 1'b1;
297                 if(change)      dpll_next_state = 3'h3;
298                 else            dpll_next_state = 3'h2;
299                 end
300            2'h2:
301                 if(change)      dpll_next_state = 3'h0;
302                 else            dpll_next_state = 3'h3;
303            2'h3:
304                 if(change)      dpll_next_state = 3'h0;
305                 else            dpll_next_state = 3'h0;
306         endcase
307    end
308
309 // Compensate for sync registers at the input - allign sio 
310 // clock enable to be in the middle between two bit changes ...
311 always @(posedge clk)
312         rx_sio_ce_r1 <= #1 rx_sio_ce_d;
313
314 always @(posedge clk)
315         rx_sio_ce_r2 <= #1 rx_sio_ce_r1;
316
317 always @(posedge clk)
318         rx_sio_ce <= #1 rx_sio_ce_r1 & !rx_sio_ce_r2;
319
320 endmodule
321
322