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