1//
2// Copyright 2011 Ettus Research LLC
3//
4// This program is free software: you can redistribute it and/or modify
5// it under the terms of the GNU General Public License as published by
6// the Free Software Foundation, either version 3 of the License, or
7// (at your option) any later version.
8//
9// This program is distributed in the hope that it will be useful,
10// but WITHOUT ANY WARRANTY; without even the implied warranty of
11// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12// GNU General Public License for more details.
13//
14// You should have received a copy of the GNU General Public License
15// along with this program.  If not, see <http://www.gnu.org/licenses/>.
16//
17
18
19// FIXME need to add flow control
20
21module serdes_tb();
22
23   reg clk, rst;
24   wire ser_rx_clk, ser_tx_clk;
25   wire ser_rklsb, ser_rkmsb, ser_tklsb, ser_tkmsb;
26   wire [15:0] ser_r, ser_t;
27
28   initial clk = 0;
29   initial rst = 1;
30   initial #1000 rst = 0;
31   always #100 clk = ~clk;
32
33   // Wishbone
34   reg [31:0]  wb_dat_i;
35   wire [31:0] wb_dat_o_rx, wb_dat_o_tx;
36   reg 	       wb_we, wb_en_rx, wb_en_tx;
37   reg [8:0]   wb_adr;
38
39   // Buffer Control
40   reg 	       go, clear, read, write;
41   reg [3:0]   buf_num;
42   wire [31:0] ctrl_word = {buf_num,3'b0,clear,write,read,step,lastline,firstline};
43   reg [8:0]   firstline = 0, lastline = 0;
44   reg [3:0]   step = 1;
45   reg 	       first_tx = 1, first_rx = 1;  // for verif
46
47   // TX Side
48   reg 	       wb_we_tx;
49   wire        en_tx, we_tx;
50   wire [8:0]  addr_tx;
51   wire [31:0] f2r_tx, r2f_tx;
52   wire [31:0] data_tx;
53   wire        read_tx, done_tx, error_tx, sop_tx, eop_tx;
54
55   wire        fdone_tx, ferror_tx;
56
57   reg 	       even;
58   reg 	       channel_error = 0;
59
60   serdes_tx serdes_tx
61     (.clk(clk),.rst(rst),
62      .ser_tx_clk(ser_tx_clk),.ser_t(ser_t),.ser_tklsb(ser_tklsb),.ser_tkmsb(ser_tkmsb),
63      .rd_dat_i(data_tx),.rd_read_o(read_tx),.rd_done_o(done_tx),
64      .rd_error_o(error_tx),.rd_sop_i(sop_tx),.rd_eop_i(eop_tx) );
65
66   ram_2port #(.DWIDTH(32),.AWIDTH(9))
67     ram_tx(.clka(clk),.ena(wb_en_tx),.wea(wb_we_tx),.addra(wb_adr),.dia(wb_dat_i),.doa(wb_dat_o_tx),
68            .clkb(clk),.enb(en_tx),.web(we_tx),.addrb(addr_tx),.dib(f2r_tx),.dob(r2f_tx));
69
70   buffer_int #(.BUFF_NUM(1)) buffer_int_tx
71     (.clk(clk),.rst(rst),
72      .ctrl_word(ctrl_word),.go(go),
73      .done(fdone_tx),.error(ferror_tx),
74
75      .en_o(en_tx),.we_o(we_tx),.addr_o(addr_tx),.dat_to_buf(f2r_tx),.dat_from_buf(r2f_tx),
76
77      .wr_dat_i(0),.wr_write_i(0),.wr_done_i(0),
78      .wr_error_i(0),.wr_ready_o(),.wr_full_o(),
79
80      .rd_dat_o(data_tx),.rd_read_i(read_tx),.rd_done_i(done_tx),
81      .rd_error_i(error_tx),.rd_sop_o(sop_tx),.rd_eop_o(eop_tx) );
82
83
84   // RX Side
85   reg 	       wb_we_rx;
86   wire        en_rx, we_rx;
87   wire [8:0]  addr_rx;
88   wire [31:0] f2r_rx, r2f_rx;
89   wire [31:0] data_rx;
90   wire        write_rx, done_rx, error_rx, ready_rx, empty_rx;
91
92   wire        fdone_rx, ferror_rx;
93
94   serdes_rx serdes_rx
95     (.clk(clk),.rst(rst),
96      .ser_rx_clk(ser_rx_clk),.ser_r(ser_r),.ser_rklsb(ser_rklsb),.ser_rkmsb(ser_rkmsb),
97      .wr_dat_o(data_rx),.wr_write_o(write_rx),.wr_done_o(done_rx),
98      .wr_error_o(error_rx),.wr_ready_i(ready_rx),.wr_full_i(full_rx) );
99
100   ram_2port #(.DWIDTH(32),.AWIDTH(9))
101     ram_rx(.clka(clk),.ena(wb_en_rx),.wea(wb_we_rx),.addra(wb_adr),.dia(wb_dat_i),.doa(wb_dat_o_rx),
102            .clkb(clk),.enb(en_rx),.web(we_rx),.addrb(addr_rx),.dib(f2r_rx),.dob(r2f_rx) );
103
104   buffer_int #(.BUFF_NUM(0)) buffer_int_rx
105     (.clk(clk),.rst(rst),
106      .ctrl_word(ctrl_word),.go(go),
107      .done(fdone_rx),.error(ferror_rx),
108
109      .en_o(en_rx),.we_o(we_rx),.addr_o(addr_rx),.dat_to_buf(f2r_rx),.dat_from_buf(r2f_rx),
110
111      .wr_dat_i(data_rx),.wr_write_i(write_rx),.wr_done_i(done_rx),
112      .wr_error_i(error_rx),.wr_ready_o(ready_rx),.wr_full_o(full_rx),
113
114      .rd_dat_o(),.rd_read_i(0),.rd_done_i(0),
115      .rd_error_i(0),.rd_sop_o(),.rd_eop_o() );
116
117   // Simulate the connection
118   serdes_model serdes_model
119     (.ser_tx_clk(ser_tx_clk), .ser_tkmsb(ser_tkmsb), .ser_tklsb(ser_tklsb), .ser_t(ser_t),
120      .ser_rx_clk(ser_rx_clk), .ser_rkmsb(ser_rkmsb), .ser_rklsb(ser_rklsb), .ser_r(ser_r),
121      .even(even), .error(channel_error) );
122
123   initial begin
124      wb_en_rx <= 0;
125      wb_en_tx <=0;
126      wb_we_tx <= 0;
127      wb_we_rx <= 0;
128      wb_adr <= 0;
129      wb_dat_i <= 0;
130      go <= 0;
131      even <= 0;
132      @(negedge rst);
133      @(posedge clk);
134      FillTXRAM;
135      ClearRXRAM;
136      ResetBuffer(0);
137      ResetBuffer(1);
138
139      // receive a full buffer
140      ReceiveSERDES(0,10);
141      SendSERDES(0,10);
142
143      // Receive a partial buffer
144      SendSERDES(11,20);
145      ReceiveSERDES(11,50);
146
147      // Receive too many for buffer
148      SendSERDES(21,100);
149      ReceiveSERDES(21,30);
150
151      // Send 3 packets, then wait to receive them, so they stack up in the rx fifo
152      SendSERDES(31,40);
153      SendSERDES(41,50);
154      SendSERDES(51,60);
155      repeat (10)
156	@(posedge clk);
157      ReceiveSERDES(31,40);
158      ReceiveSERDES(41,50);
159      repeat (1000)
160	@(posedge clk);
161      ReceiveSERDES(51,60);
162
163      // Overfill the FIFO, should get an error on 3rd packet
164      SendSERDES(1,400);
165      SendSERDES(1,400);
166
167
168      WaitForTX;
169      //WaitForRX;
170
171
172      repeat(1000)
173	@(posedge clk);
174      ReceiveSERDES(101,500);
175      ReceiveSERDES(101,500);
176      ReadRAM(80);
177      $finish;
178   end // initial begin
179
180   always @(posedge clk)
181     if(write_rx)
182       $display("SERDES RX, FIFO WRITE %x, FIFO RDY %d, FIFO FULL %d",data_rx, ready_rx, full_rx);
183
184   always @(posedge clk)
185     if(read_tx)
186       $display("SERDES TX, FIFO READ %x, SOP %d, EOP %d",data_tx, sop_tx, eop_tx);
187
188   initial begin
189      $dumpfile("serdes_tb.vcd");
190      $dumpvars(0,serdes_tb);
191   end
192
193   initial #10000000 $finish;
194
195   initial #259300 channel_error <= 1;
196   initial #259500 channel_error <= 0;
197
198   task FillTXRAM;
199      begin
200	 wb_adr <= 0;
201	 wb_dat_i <= 32'h10802000;
202	 wb_we_tx <= 1;
203	 wb_en_tx <= 1;
204	 @(posedge clk);
205	 repeat(511) begin
206	    wb_dat_i <= wb_dat_i + 32'h00010001;
207	    wb_adr <= wb_adr + 1;
208	    @(posedge clk);
209	 end // repeat (511)
210	 wb_we_tx <= 0;
211	 wb_en_tx <= 0;
212	 @(posedge clk);
213	 $display("Done entering Data into TX RAM\n");
214      end
215   endtask // FillTXRAM
216
217   task ClearRXRAM;
218      begin
219	 wb_adr <= 0;
220	 wb_dat_i <= 0;
221	 wb_we_rx <= 1;
222	 wb_en_rx <= 1;
223	 wb_dat_i <= 0;
224	 @(posedge clk);
225	 repeat(511) begin
226	    wb_adr <= wb_adr + 1;
227	    @(posedge clk);
228	 end // repeat (511)
229	 wb_we_rx <= 0;
230	 wb_en_rx <= 0;
231	 @(posedge clk);
232	 $display("Done clearing RX RAM\n");
233      end
234   endtask // FillRAM
235
236   task ReadRAM;
237      input [8:0] lastline;
238      begin
239	 wb_en_rx <= 1;
240	 wb_adr <= 0;
241	 @(posedge clk);
242	 @(posedge clk);
243	 repeat(lastline) begin
244	    $display("ADDR: %h  DATA %h", wb_adr, wb_dat_o_rx);
245	    wb_adr <= wb_adr + 1;
246	    @(posedge clk);
247	    @(posedge clk);
248	 end // repeat (511)
249	 $display("ADDR: %h  DATA %h", wb_adr, wb_dat_o_rx);
250	 wb_en_rx <= 0;
251	 @(posedge clk);
252	 $display("Done reading out RX RAM\n");
253      end
254   endtask // FillRAM
255
256   task ResetBuffer;
257      input [3:0] buffer_num;
258      begin
259	 buf_num <= buffer_num;
260	 clear <= 1; read <= 0; write <= 0;
261	 go <= 1;
262	 @(posedge clk);
263	 go <= 0;
264	 @(posedge clk);
265	 $display("Buffer Reset");
266      end
267   endtask // ClearBuffer
268
269   task SetBufferWrite;
270      input [3:0] buffer_num;
271      input [8:0] start;
272      input [8:0] stop;
273      begin
274	 buf_num <= buffer_num;
275	 clear <= 0; read <= 0; write <= 1;
276	 firstline <= start;
277	 lastline <= stop;
278	 go <= 1;
279	 @(posedge clk);
280	 go <= 0;
281	 @(posedge clk);
282	 $display("Buffer Set for Write");
283      end
284   endtask // SetBufferWrite
285
286   task SetBufferRead;
287      input [3:0] buffer_num;
288      input [8:0] start;
289      input [8:0] stop;
290      begin
291	 buf_num <= buffer_num;
292	 clear <= 0; read <= 1; write <= 0;
293	 firstline <= start;
294	 lastline <= stop;
295	 go <= 1;
296	 @(posedge clk);
297	 go <= 0;
298	 @(posedge clk);
299	 $display("Buffer Set for Read");
300      end
301   endtask // SetBufferRead
302
303   task WaitForTX;
304      begin
305	 while (!(fdone_tx | ferror_tx))
306	   @(posedge clk);
307      end
308   endtask // WaitForTX
309
310   task WaitForRX;
311      begin
312	 while (!(fdone_rx | ferror_rx))
313	   @(posedge clk);
314      end
315   endtask // WaitForRX
316
317   task SendSERDES;
318      input [8:0] start;
319      input [8:0] stop;
320      begin
321	 if(~first_tx)
322	   WaitForTX;
323	 else
324	   first_tx <= 0;
325	 ResetBuffer(1);
326	 SetBufferRead(1,start,stop);
327	 $display("Here");
328      end
329   endtask // SendSERDES
330
331   task ReceiveSERDES;
332      input [8:0] start;
333      input [8:0] stop;
334      begin
335	 if(~first_rx)
336	   WaitForRX;
337	 else
338	   first_rx <= 0;
339	 ResetBuffer(0);
340	 SetBufferWrite(0,start,stop);
341	 $display("Here2");
342      end
343   endtask // ReceiveSERDES
344
345endmodule // serdes_tb
346