OpenCores
URL https://opencores.org/ocsvn/ht_tunnel/ht_tunnel/trunk

Subversion Repositories ht_tunnel

[/] [ht_tunnel/] [tags/] [START/] [bench/] [flow_control_l2/] [flow_control_l2_tb/] [flow_control_l2_tb.cpp] - Blame information for rev 2

Go to most recent revision | Details | Compare with Previous | View Log

Line No. Rev Author Line
1 2 acastong
//flow_control_l2_tb.cpp
2
/* ***** BEGIN LICENSE BLOCK *****
3
 * Version: MPL 1.1
4
 *
5
 * The contents of this file are subject to the Mozilla Public License Version
6
 * 1.1 (the "License"); you may not use this file except in compliance with
7
 * the License. You may obtain a copy of the License at
8
 * http://www.mozilla.org/MPL/
9
 *
10
 * Software distributed under the License is distributed on an "AS IS" basis,
11
 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
12
 * for the specific language governing rights and limitations under the
13
 * License.
14
 *
15
 * The Original Code is HyperTransport Tunnel IP Core.
16
 *
17
 * The Initial Developer of the Original Code is
18
 * Ecole Polytechnique de Montreal.
19
 * Portions created by the Initial Developer are Copyright (C) 2005
20
 * the Initial Developer. All Rights Reserved.
21
 *
22
 * Contributor(s):
23
 *   Ami Castonguay <acastong@grm.polymtl.ca>
24
 *
25
 * Alternatively, the contents of this file may be used under the terms
26
 * of the Polytechnique HyperTransport Tunnel IP Core Source Code License
27
 * (the  "PHTICSCL License", see the file PHTICSCL.txt), in which case the
28
 * provisions of PHTICSCL License are applicable instead of those
29
 * above. If you wish to allow use of your version of this file only
30
 * under the terms of the PHTICSCL License and not to allow others to use
31
 * your version of this file under the MPL, indicate your decision by
32
 * deleting the provisions above and replace them with the notice and
33
 * other provisions required by the PHTICSCL License. If you do not delete
34
 * the provisions above, a recipient may use your version of this file
35
 * under either the MPL or the PHTICSCL License."
36
 *
37
 * ***** END LICENSE BLOCK ***** */
38
 
39
#include "flow_control_l2_tb.h"
40
#include <sstream>
41
 
42
using namespace std;
43
 
44
const unsigned flow_control_l2_tb::next_node_databuffers_maximum[3] = {8,8,8};
45
const unsigned flow_control_l2_tb::next_node_buffers_maximum[3] = {8,8,8};
46
const int flow_control_l2_tb::nop_counter_delay = NOP_COUNTER_DELAY;
47
 
48
flow_control_l2_tb::flow_control_l2_tb(sc_module_name name){
49
        SC_THREAD(simulate_memory);
50
        sensitive_pos(clk);
51
 
52
        SC_THREAD(produce_inputs);
53
        sensitive_pos(clk);
54
 
55
        //verify_output() MUST run after produce_inputs, 
56
        //so wait for it to produce an event instead of being sensitive to clock
57
        SC_THREAD(verify_output);
58
        sensitive(input_produced);
59
 
60
        SC_THREAD(control_testbench);
61
        sensitive_pos(clk);
62
 
63
        srand(1987);
64
        error = false;
65
 
66
        for(int n = 0; n < 10; n++)
67
                nop_delay[n].nop_received = false;
68
}
69
 
70
void flow_control_l2_tb::simulate_memory(){
71
        while(true){
72
                history_memory_output = history_memory[(int)history_memory_read_address.read()];
73
                if(history_memory_write.read())
74
                        history_memory[(unsigned)history_memory_write_address.read()] =
75
                                (unsigned)(sc_uint<32>)history_memory_write_data.read();
76
                wait();
77
        }
78
}
79
 
80
void flow_control_l2_tb::control_testbench(){
81
        lk_rx_connected = true;
82
        percent_chance_from_eh = 0;
83
        percent_chance_from_csr = 0;
84
        percent_chance_from_fwd = 0;
85
        percent_chance_from_ui = 0;
86
 
87
        percent_chance_nop_req_db = 0;
88
        percent_chance_nop_req_ro = 0;
89
 
90
        percent_chance_nop_received = 0;
91
 
92
        ldtstopx = true;
93
        resetx = false;
94
        csr_retry = true;
95
        for(int n = 0; n < 3; n++) wait();
96
        if(error) return;
97
        resetx = true;
98
 
99
        percent_chance_from_eh = 20;
100
        percent_chance_from_csr = 40;
101
        percent_chance_from_fwd = 60;
102
        percent_chance_from_ui = 7;
103
 
104
        percent_chance_nop_req_db = 8;
105
        percent_chance_nop_req_ro = 8;
106
 
107
        percent_chance_nop_received = 15;
108
 
109
        for(int n = 0; n < 65; n++) wait();
110
        if(error) return;
111
        cd_initiate_retry_disconnect = true;
112
        wait();
113
        cd_initiate_retry_disconnect = false;
114
 
115
        for(int n = 0; n < 20; n++) wait();
116
 
117
        lk_rx_connected = false;
118
        for(int n = 0; n < 5; n++) wait();
119
        lk_rx_connected = true;
120
 
121
}
122
 
123
void flow_control_l2_tb::produce_inputs(){
124
        sc_bv<32> cmd;
125
 
126
        ////////////////////////////////////////////////
127
        //Generate a packet from the different sources
128
        //Output them, but don't make them available yet
129
        /////////////////////////////////////////////////
130
 
131
        //Output Error handler packet
132
        generate_random_response(cmd,data_left_eh);
133
        eh_cmd_data_fc = cmd;
134
        eh_available_fc = false;
135
 
136
        //Output CSR packet
137
        generate_random_response(cmd,data_left_csr);
138
        csr_dword_fc = cmd;
139
        csr_available_fc = false;
140
 
141
        //Output UI packet
142
        sc_bv<64> pkt;
143
        unsigned datalength;
144
        VirtualChannel ui_vc = VC_NONE;
145
        ui_packet_fc = 0;
146
        ui_available_fc = false;
147
 
148
 
149
        //OutputFWD packet
150
        syn_ControlPacketComplete pkt_complete;
151
        VirtualChannel fwd_vc = generate_random_packet(pkt,datalength);
152
        //Not used by flow_control_l3, so any value is ok.  The state machine reads
153
        //the chain bit off of the packet if needed
154
        pkt_complete.isPartOfChain = false;
155
        pkt_complete.packet = pkt;
156
        pkt_complete.error64BitExtension = false;
157
        pkt_complete.data_address = rand();
158
 
159
        ro_packet_fwd = pkt_complete;
160
        ro_packet_vc_fwd = fwd_vc;
161
        ro_available_fwd = false;
162
 
163
        unsigned data_sent_ui = 0;
164
 
165
        crc1 = 0xFFFFFFFF;
166
        crc2 = 0xFFFFFFFF;
167
 
168
        int retry_sequence_count = 0;
169
 
170
 
171
        //////////////////////////////////////
172
        // Misc init
173
        //////////////////////////////////////
174
        current_user_data_vc = VC_NONE;
175
        current_user_data_vc_output = VC_NONE;
176
        fc_status = FC_NONE;
177
 
178
        cd_rx_next_pkt_to_ack_fc = 0;
179
        data_sent_db = 0;
180
 
181
        wait();
182
        while(!error){
183
 
184
                /////////////////////////////////////////////////////
185
                // Handle sending packets from the different sources
186
                /////////////////////////////////////////////////////
187
 
188
                //Randomly set if input data is available
189
                eh_available_fc = (rand() % 100 < percent_chance_from_eh) || fc_status == FC_SENDING_EH;
190
                csr_available_fc = (rand() % 100 < percent_chance_from_csr) || fc_status == FC_SENDING_CSR;
191
                ro_available_fwd = rand() % 100 < percent_chance_from_fwd;
192
 
193
                //If reading data from errorhandler, add it to the queue of expected output dword
194
                if(fc_ack_eh.read() && resetx.read()){
195
                        if(fc_status != FC_SENDING_EH && fc_status != FC_NONE){
196
                                cout << "ERROR: Reading EH while other task not done" <<endl;
197
                                cout << "fc_status: " << fc_status << endl;
198
                                error = true; continue;
199
                        }
200
 
201
                        OutputDword expected;
202
                        expected.dword = eh_cmd_data_fc.read();
203
                        if(fc_status == FC_NONE){
204
                                expected.lctl = true;  expected.hctl = true;
205
                        }
206
                        else{
207
                                expected.lctl = false;  expected.hctl = false;
208
                        }
209
                        expected_output.push_back(expected);
210
 
211
                        if(data_left_eh){
212
                                data_left_eh--;
213
                                getRandomVector(cmd);
214
                                eh_cmd_data_fc = cmd;
215
                                fc_status = FC_SENDING_EH;
216
 
217
                                //In retry mode, calculate the CRC of the packet
218
                                if(csr_retry.read()){
219
                                        bool command = (crc2 == 0xFFFFFFFF);
220
                                        calculate_crc2(eh_cmd_data_fc.read(),command, command);
221
                                }
222
                        }
223
                        else{
224
                                //In retry mode, expect a following CRC
225
                                if(csr_retry.read()){
226
                                        if(crc2 != 0xFFFFFFFF){
227
                                                calculate_crc2(eh_cmd_data_fc.read(),false, false);
228
                                                expected.dword = ~crc2;
229
                                                expected.lctl = false;  expected.hctl = true;
230
                                                crc2 = 0xFFFFFFFF;
231
                                        }
232
                                        else{
233
                                                calculate_crc1(eh_cmd_data_fc.read(),true, true);
234
                                                expected.dword = ~crc1;
235
                                                expected.lctl = true;  expected.hctl = false;
236
                                                crc1 = 0xFFFFFFFF;
237
                                        }
238
                                        expected_output.push_back(expected);
239
                                }
240
 
241
                                //When packet done being sent, generate a new one
242
                                generate_random_response(cmd,data_left_eh);
243
                                eh_cmd_data_fc = cmd;
244
                                fc_status = FC_NONE;
245
                        }
246
                }
247
 
248
                //If reading data from CSR, add it to the queue of expected output dword
249
                if(fc_ack_csr.read() && resetx.read()){
250
                        if(fc_status != FC_SENDING_CSR && fc_status != FC_NONE){
251
                                cout << "ERROR: Reading CSR while other task not done" <<endl;
252
                                cout << "Current status: " << fc_status << endl;
253
                                error = true; continue;
254
                        }
255
 
256
                        OutputDword expected;
257
                        expected.dword = csr_dword_fc.read();
258
                        if(fc_status == FC_NONE){
259
                                expected.lctl = true;  expected.hctl = true;
260
                        }
261
                        else{
262
                                expected.lctl = false;  expected.hctl = false;
263
                        }
264
                        expected_output.push_back(expected);
265
 
266
                        if(data_left_csr){
267
                                data_left_csr--;
268
                                getRandomVector(cmd);
269
                                csr_dword_fc = cmd;
270
                                fc_status = FC_SENDING_CSR;
271
 
272
                                //In retry mode, calculate the CRC of the packet
273
                                if(csr_retry.read()){
274
                                        bool command = (crc2 == 0xFFFFFFFF);
275
                                        calculate_crc2(csr_dword_fc.read(),command, command);
276
                                }
277
                        }
278
                        else{
279
                                //In retry mode, expect a following CRC
280
                                if(csr_retry.read()){
281
                                        if(crc2 != 0xFFFFFFFF){
282
                                                calculate_crc2(csr_dword_fc.read(),false, false);
283
                                                expected.dword = ~crc2;
284
                                                expected.lctl = false;  expected.hctl = true;
285
                                                crc2 = 0xFFFFFFFF;
286
                                        }
287
                                        else{
288
                                                calculate_crc1(csr_dword_fc.read(),true, true);
289
                                                expected.dword = ~crc1;
290
                                                expected.lctl = true;  expected.hctl = false;
291
                                                crc1 = 0xFFFFFFFF;
292
                                        }
293
                                        expected_output.push_back(expected);
294
                                }
295
                                generate_random_response(cmd,data_left_csr);
296
                                csr_dword_fc = cmd;
297
                                fc_status = FC_NONE;
298
                        }
299
                }
300
 
301
 
302
                //If reading data from command buffers, add it to the queue of expected output dword
303
                if(fwd_ack_ro.read() && resetx.read()){
304
                        if(fc_status != FC_NONE){
305
                                cout << "ERROR: Reading FWD command while other task not done" <<endl;
306
                                cout << "  - fc_status=" << fc_status << endl;
307
                                error = true; continue;
308
                        }
309
 
310
                        OutputDword expected;
311
                        expected.dword = ro_packet_fwd.read().packet.range(31,0);
312
                        expected.lctl = true;  expected.hctl = true;
313
                        expected_output.push_back(expected);
314
 
315
                        PacketCommand cmd = getPacketCommand(ro_packet_fwd.read().packet.range(5,0));
316
                        bool current_dword = isDwordPacket(ro_packet_fwd.read().packet,cmd);
317
                        bool current_data = hasDataAssociated(cmd);
318
                        int current_datalength = (int)getDataLengthm1(ro_packet_fwd.read().packet) + 1;
319
                        VirtualChannel current_vc = getVirtualChannel(ro_packet_fwd.read().packet,cmd);
320
 
321
                        if(!current_dword){
322
                                expected.dword = ro_packet_fwd.read().packet.range(63,32);
323
                                expected_output.push_back(expected);
324
                        }
325
 
326
                        if(current_datalength){
327
                                sc_uint<4> addr = ro_packet_fwd.read().data_address;
328
                                update_databuffer_entry(current_datalength,current_vc,addr);
329
                        }
330
 
331
                        fwd_vc = generate_random_packet(pkt,datalength);
332
                        //Not used by flow_control_l3, so any value is ok.  The state machine reads
333
                        //the chain bit off of the packet if needed
334
                        pkt_complete.packet = pkt;
335
                        pkt_complete.data_address = rand();
336
 
337
                        //In retry mode, calculate the CRC of the packet
338
                        if(csr_retry.read()){
339
                                //If it is a command packet with associated data, the CRC will also
340
                                //need to be calculated from the data packet, so don't add the CRC to
341
                                //the expected queue just yet
342
                                if(current_data){
343
                                        calculate_crc2(ro_packet_fwd.read().packet.range(31,0),true, true);
344
                                        if(!current_dword)
345
                                                calculate_crc2(ro_packet_fwd.read().packet.range(63,32),true, true);
346
                                }
347
                                else{
348
                                        //If it is a command packet without associated data, expect a following CRC
349
                                        calculate_crc1(ro_packet_fwd.read().packet.range(31,0),true, true);
350
                                        if(!current_dword)
351
                                                calculate_crc1(ro_packet_fwd.read().packet.range(63,32),true, true);
352
                                        expected.dword = ~crc1;
353
                                        expected.lctl = true;  expected.hctl = false;
354
                                        crc1 = 0xFFFFFFFF;
355
                                        expected_output.push_back(expected);
356
                                }
357
                        }
358
                        if(current_data)
359
                                fc_status = FC_SENDING_FWD;
360
 
361
                        ro_packet_fwd = pkt_complete;
362
                        ro_packet_vc_fwd = fwd_vc;
363
                }
364
 
365
 
366
                ///////////////////////////////////////////////////////////////////////////////
367
                //Packets from UI work a bit differently.  It's a write in a FIFO and we must
368
                //only make a packet available when it CAN be accepted.
369
                ///////////////////////////////////////////////////////////////////////////////
370
                //Generate a random packet
371
                ui_vc = generate_random_packet(pkt,datalength);
372
 
373
                //Check that it can be sent
374
                bool can_send_ui = !(sc_bit)fc_user_fifo_ge2_ui.read()[(unsigned)ui_vc];
375
 
376
                //send if(necessary
377
                bool send_ui = (rand() % 100 < percent_chance_from_ui) && can_send_ui;
378
 
379
                if(send_ui && resetx.read()){
380
                        ui_available_fc = true;
381
 
382
                        if(datalength != 0)
383
                                add_ui_data_packet(datalength,ui_vc,pkt);
384
                        ui_packet_fc = pkt;
385
                        user_packets.push_back(pkt);
386
                        //cout << "SENDING_UI: pkt=" << pkt.to_string(SC_HEX) << " datalength=" << datalength << endl;
387
                }
388
                else{
389
                        ui_available_fc = false;
390
                }
391
 
392
 
393
                /////////////////////////////////////////////////////
394
                // Handle nop related signals
395
                /////////////////////////////////////////////////////
396
                db_nop_req_fc =  rand()% 100 < percent_chance_nop_req_db;;
397
                ro_nop_req_fc =  rand()% 100 < percent_chance_nop_req_ro;;
398
 
399
                ro_buffer_cnt_fc = rand() & 0x3F;
400
                db_buffer_cnt_fc = rand() & 0x3F;
401
 
402
                //Force to 0 the buffer count as if all buffers were sent during retry sequence
403
                //(needed to start the retry sequence)
404
                if(!retry_sequence || !lk_rx_connected.read()) retry_sequence_count = 0;
405
                if(cd_nop_received_fc.read())retry_sequence_count++;
406
 
407
                if(retry_sequence && retry_sequence_count > 2 && retry_sequence_count < 5){
408
                        ro_buffer_cnt_fc = 0;
409
                        db_buffer_cnt_fc = 0;
410
                }
411
 
412
                cd_nop_received_fc = nop_delay[nop_counter_delay-1].nop_received;
413
                if(nop_delay[nop_counter_delay-1].nop_received){
414
                        cd_nop_ack_value_fc = nop_delay[nop_counter_delay-1].nop_ack_value;
415
                        cd_nopinfo_fc = nop_delay[nop_counter_delay-1].nop_information;
416
                }
417
 
418
                //Generate a value that we can check in the received nops.  The 0x20 is just
419
                //an arbitrary value ored in to make sure that rand() doesn't produce 0.  Having
420
                //0 is not wanted because receiving 0 *could* also mean that the design isn't working.
421
                if(resetx.read())
422
                        cd_rx_next_pkt_to_ack_fc = (rand() & 0xFF) | 0x20;
423
                else
424
                        cd_rx_next_pkt_to_ack_fc = 0;
425
 
426
                //If a nop is sent, tag it as being expected with the correct value
427
                if(fc_nop_sent.read() && resetx.read()){
428
                        OutputDword expected;
429
                        expected.dword = 0;
430
                        expected.dword.range(19,18) = db_buffer_cnt_fc.read().range(5,4);
431
                        expected.dword.range(17,16) = ro_buffer_cnt_fc.read().range(5,4);
432
                        expected.dword.range(15,14) = db_buffer_cnt_fc.read().range(3,2);
433
                        expected.dword.range(13,12) = ro_buffer_cnt_fc.read().range(3,2);
434
                        expected.dword.range(11,10) = db_buffer_cnt_fc.read().range(1,0);
435
                        expected.dword.range(9,8)   = ro_buffer_cnt_fc.read().range(1,0);
436
 
437
                        expected.dword.range(31,24) = cd_rx_next_pkt_to_ack_fc.read();
438
                        expected.lctl = true;
439
                        expected.hctl = true;
440
                        expected_output.push_back(expected);
441
 
442
                        if(csr_retry.read()){
443
                                calculate_crc1(expected.dword,true, true);
444
                                expected.dword = ~crc1;
445
                                expected.lctl = true;  expected.hctl = false;
446
                                crc1 = 0xFFFFFFFF;
447
                                expected_output.push_back(expected);
448
                        }
449
                }
450
 
451
                /////////////////////////////////////////////////////
452
                // Handle sending data from Databuffer and UI
453
                /////////////////////////////////////////////////////
454
 
455
                //from databuffer
456
                if(fwd_address_db.read() == databuffer_data.address &&
457
                        fwd_vctype_db.read() == databuffer_data.vc &&
458
                        data_sent_db < (unsigned)databuffer_data.size)
459
                {
460
                        db_data_fwd = databuffer_data.dwords[data_sent_db];
461
                }
462
                else{
463
                        db_data_fwd = 0;
464
                }
465
 
466
                if(fwd_read_db.read() && resetx.read()){
467
                        if(fc_status != FC_SENDING_FWD){
468
                                cout << "ERROR: Reading FWD data without having previously read a fwd command" <<endl;
469
                                cout << "  - fc_status=" << fc_status << endl;
470
                                error = true; continue;
471
                        }
472
                        if(databuffer_output_vc != databuffer_data.vc ||
473
                                databuffer_output_addr != databuffer_data.address ||
474
                                data_sent_db == databuffer_data.size)
475
                        {
476
                                cout << "ERROR: Invalid read to databuffer data" << endl;
477
                                if(databuffer_output_vc != databuffer_data.vc)
478
                                        cout << "  -VC expected: " << databuffer_data.vc << " Received: " << databuffer_output_vc << endl;
479
                                if(databuffer_output_addr != databuffer_data.address)
480
                                        cout << "  -address expected: " << databuffer_data.address << " Received: " << databuffer_output_addr << endl;
481
                                if(data_sent_db == databuffer_data.size) cout << "  completed sending data already" << endl;
482
                                error = true; continue;
483
                        }
484
 
485
                        OutputDword expected;
486
                        expected.dword = db_data_fwd.read();
487
                        expected.lctl = false;  expected.hctl = false;
488
                        expected_output.push_back(expected);
489
                        if(csr_retry.read())
490
                                calculate_crc2( db_data_fwd.read(),false, false);
491
 
492
                        data_sent_db++;
493
 
494
                        //cout << "Data sent db: " << data_sent_db <<  "  Data size: " << databuffer_data.size << endl;
495
 
496
                        if(data_sent_db == databuffer_data.size){
497
                                db_data_fwd = 0;
498
                                fc_status = FC_NONE;
499
                                data_sent_db = 0;
500
                                if(csr_retry.read()){
501
                                        expected.dword = ~crc2;
502
                                        expected.lctl = false;  expected.hctl = true;
503
                                        crc2 = 0xFFFFFFFF;
504
                                        expected_output.push_back(expected);
505
                                }
506
                        }
507
                        else{
508
                                db_data_fwd = databuffer_data.dwords[data_sent_db];
509
                        }
510
                }
511
 
512
                databuffer_output_vc = fwd_vctype_db.read();
513
                databuffer_output_addr = (unsigned)fwd_address_db.read();
514
 
515
                //from UI
516
                if(current_user_data_vc != VC_NONE){
517
                        if(fc_data_vc_ui.read() != current_user_data_vc){
518
                                cout << "ERROR: VC value not held until all UI data read" << endl;
519
                                error = true; continue;
520
                        }
521
 
522
                        if(fc_consume_data_ui.read()){
523
                                data_sent_ui++;
524
                                if(data_sent_ui != user_data[current_user_data_vc].front().size){
525
                                        ui_data_fc = user_data[current_user_data_vc].front().dwords[data_sent_ui];
526
                                }
527
                                else{
528
                                        data_sent_ui = 0;
529
                                        current_user_data_vc = VC_NONE;
530
                                        fc_status = FC_NONE;
531
                                }
532
 
533
                        }
534
                }
535
                else{
536
                        if(fc_consume_data_ui.read()){
537
                                if(fc_status != FC_NONE){
538
                                        cout << "ERROR: Reading UI data while other task not done" <<endl;
539
                                        cout << "  - fc_status=" << fc_status << endl;
540
                                        error = true; continue;
541
                                }
542
                                if(user_data[fc_data_vc_ui.read()].empty() ||
543
                                        fc_data_vc_ui.read() !=current_user_data_vc_output)
544
                                {
545
                                        cout << "ERROR: << Invalid VC when reading UI data" << endl;
546
                                        error = true; continue;
547
                                }
548
                                if(user_data[fc_data_vc_ui.read()].front().size != 1){
549
                                        data_sent_ui = 1;
550
                                        current_user_data_vc = fc_data_vc_ui.read();
551
                                        fc_status = FC_SENDING_UI;
552
                                        ui_data_fc = user_data[fc_data_vc_ui.read()].front().dwords[data_sent_ui];
553
                                }
554
                        }
555
                        else{
556
                                if(fc_data_vc_ui.read() == VC_NONE){
557
                                        ui_data_fc = 0;
558
                                }
559
                                else if(user_data[fc_data_vc_ui.read()].empty())
560
                                        ui_data_fc = 0;
561
                                else{
562
                                        ui_data_fc = user_data[fc_data_vc_ui.read()].front().dwords[0];
563
                                }
564
                        }
565
                }
566
 
567
                current_user_data_vc_output = fc_data_vc_ui.read();
568
 
569
                //verify_output() MUST run after produce_inputs, 
570
                //so when produce_inputs is done, do a notification
571
                input_produced.notify();
572
                wait();
573
        }
574
}
575
 
576
void flow_control_l2_tb::verify_output(){
577
 
578
        ////////////////////////////////////////////////////
579
        // Initialization
580
        ////////////////////////////////////////////////////
581
 
582
        clear_next_node_information();
583
 
584
        ignore_next_dword_for_ack = false;
585
 
586
        bool receiving_ui_datapacket = false;
587
        VirtualChannel ui_packet_vc = VC_NONE;
588
        unsigned ui_data_received = 0;
589
        bool expected_second_ui_command_dword = false;
590
        bool expecting_nop_crc = false;
591
        sc_bv<32> second_ui_command_dword;
592
 
593
        //At the beggining of a connection, we can expect to receive NOP's
594
        //even though they're not really expected
595
        bool connection_start = true;
596
 
597
        bool expected_discon_nop = false;
598
        bool received_discon_nop = false;
599
        bool retry_discon_nop = false;
600
        int max_delay_discon_nop = 0;
601
 
602
        retry_sequence = false;
603
 
604
        //Loop while no error is detected
605
        //Catch any exception
606
        try     { while(!error){
607
                //Under reset, clear some information
608
                if(!resetx.read()){
609
                        clear_next_node_information();
610
                        connection_start = true;
611
                        retry_sequence = false;
612
                }
613
 
614
                //////////////////////
615
                //Analyze disconnect nops
616
                //////////////////////
617
                if(expected_discon_nop && !received_discon_nop){
618
                        max_delay_discon_nop--;
619
                        if(max_delay_discon_nop <= 0){
620
                                cout << "ERROR: Disconnect nop expected but never received (timeout)" << endl;
621
                                error = true; continue;
622
                        }
623
                }
624
 
625
                if((!ldtstopx.read() ||
626
                        lk_initiate_retry_disconnect.read() && csr_retry.read() ||
627
                        cd_initiate_retry_disconnect.read() && csr_retry.read())&& !expected_discon_nop)
628
                {
629
                        expected_discon_nop = true;
630
                        max_delay_discon_nop = 32;
631
                        retry_discon_nop = csr_retry.read();
632
                }
633
 
634
                if(!retry_discon_nop && ldtstopx.read()){
635
                        expected_discon_nop = false;
636
                        received_discon_nop = false;
637
                }
638
                //////////////////////
639
                //Validate packet sent
640
                //////////////////////
641
                lk_consume_fc = rand() % 10 < 9;
642
 
643
                //There is always a first empty nop at the begginning, read it
644
                if(connection_start && lk_consume_fc.read() && resetx.read()){
645
                        connection_start = false;
646
                        crc1 = 0xFFFFFFFF;
647
                        crc2 = 0xFFFFFFFF;
648
                        //If in retry mode, expect a nop CRC
649
                        OutputDword o; o.dword = 0; o.lctl = true; o.hctl = true;
650
                        expected_output.push_back(o);
651
                        if(csr_retry.read()){
652
                                calculate_crc1(o.dword,true,true);
653
                                o.dword = ~crc1; o.lctl = true; o.hctl = false;
654
                                crc1 = 0xFFFFFFFF;
655
                                expected_output.push_back(o);
656
                        }
657
                }
658
 
659
                //Stop ignoring output when fc_disconnect_lk returns to false
660
                /** It is needed to do it here because if it is done in
661
                    manage_retry_sequence, if there is nothing in the history
662
                        to play back, the first dword would be missed.*/
663
                if(!fc_disconnect_lk.read()) retry_disconnect = false;
664
 
665
 
666
                /**
667
                        In this section, we check if what is received is valid.
668
                        There are two possible correct values : a packet from the
669
                        expected list or a packet that was stored in the UI fifo.
670
 
671
                        All packets exluding packets from the UI are consumed by
672
                        the Flow Control module so we know that we are expecting
673
                        thos packets.  UI packets on the other hand are stored
674
                        in a buffer before being sent, so we do not know exactly
675
                        when they will be received.
676
 
677
                        So we first check if it was from the expected list, and
678
                        then if it's a valid packet that was sent from the UI.
679
                */
680
                if(retry_sequence || retry_disconnect){
681
                        manage_retry_sequence();
682
                }
683
                else if(lk_consume_fc.read() && !connection_start){
684
                        OutputDword expected;
685
                        if(!expected_output.empty())
686
                                expected = expected_output.front();
687
                        /*
688
                                bool receiving_ui_packet = false;
689
                                VirtualChannel ui_packet_vc = VC_NONE;
690
                                unsigned ui_data_received = 0;
691
                        */
692
                        //If we are currently receiving a UI DATA packet
693
                        if(expected_second_ui_command_dword){
694
                                if(fc_dword_lk.read() != second_ui_command_dword ||
695
                                        !fc_lctl_lk.read() || !fc_hctl_lk.read())
696
                                {
697
                                        cout << "ERROR: Invalid second UI dword received" << endl;
698
                                        cout << "Dword expected: " << second_ui_command_dword.to_string(SC_HEX) <<
699
                                                " received: " << fc_dword_lk.read().to_string(SC_HEX) << endl;
700
                                        error = true; continue;
701
                                }
702
                                expected_second_ui_command_dword = false;
703
                        }
704
                        //If expecting a nop CRC, just check that it is correct in the expected
705
                        //dwords list
706
                        else if(expecting_nop_crc){
707
                                if(fc_dword_lk.read() == expected.dword &&
708
                                        fc_lctl_lk.read() == expected.lctl &&
709
                                        fc_hctl_lk.read() == expected.hctl &&
710
                                        !expected_output.empty())
711
                                {
712
                                        expected_output.pop_front();
713
                                        expecting_nop_crc = false;
714
                                }
715
                                else{
716
                                        cout << "ERROR: Invalid NOP CRC received while receiving UI data" << endl;
717
                                }
718
                        }
719
                        //If already receiving data packet
720
                        else if(receiving_ui_datapacket){
721
                                //Check if receiving a nop
722
                                if(fc_lctl_lk.read() || fc_hctl_lk.read()){
723
                                        if(!(fc_lctl_lk.read()&& fc_hctl_lk.read() &&
724
                                                fc_dword_lk.read().range(5,0) == 0))
725
                                        {
726
                                                cout << "ERROR: Invalid non data packet received while receiving UI data" << endl;
727
                                                cout << "Received: " << fc_dword_lk.read().to_string(SC_HEX) << endl;
728
                                                error = true; continue;
729
                                        }
730
                                        if(fc_dword_lk.read() == expected.dword &&
731
                                                fc_lctl_lk.read() == expected.lctl &&
732
                                                fc_hctl_lk.read() == expected.hctl &&
733
                                                !expected_output.empty())
734
                                        {
735
                                                expected_output.pop_front();
736
                                                expecting_nop_crc = csr_retry.read();
737
                                        }
738
                                        else{
739
                                                cout << "ERROR: Unexpected NOP received while receiving UI data" << endl;
740
                                                cout << "Received: " << fc_dword_lk.read().to_string(SC_HEX);
741
                                                error = true; continue;
742
                                        }
743
                                }
744
                                //Check if the correct data is received
745
                                else{
746
                                        PacketData& data = user_data[ui_packet_vc].front();
747
                                        //cout << "Receiving UI datapacket" << fc_dword_lk.read().to_string(SC_HEX) << endl;
748
                                        //cout << "Size of data: " << data.size << " data reveived so far: " << ui_data_received << endl;
749
                                        //cout << "Control packet: " << data.associated_control_pkt.to_string(SC_HEX) << endl;
750
 
751
                                        if(data.dwords[ui_data_received++] != fc_dword_lk.read())
752
                                        {
753
                                                cout << "ERROR: Invalid data received while reveiving ui data" << endl;
754
                                                cout << "Expected: " << sc_uint<32>(data.dwords[ui_data_received-1]).to_string(SC_HEX) <<
755
                                                        " received: " << fc_dword_lk.read().to_string(SC_HEX) << endl;
756
                                                error = true; continue;
757
                                        }
758
                                        //If retry mode, expect the CRC
759
                                        if(data.size == ui_data_received){
760
                                                receiving_ui_datapacket = false;
761
                                                ui_data_received = 0;
762
                                                if(csr_retry.read()){
763
                                                        add_expected_crc_for_packet(user_data[ui_packet_vc].front());
764
                                                }
765
                                                user_data[ui_packet_vc].pop_front();
766
                                        }
767
                                }
768
                        }
769
                        //If the packet is expected
770
                        else if(fc_dword_lk.read() == expected.dword &&
771
                                fc_lctl_lk.read() == expected.lctl &&
772
                                fc_hctl_lk.read() == expected.hctl &&
773
                                !expected_output.empty())
774
                        {
775
                                expected_output.pop_front();
776
                        }
777
                        //Check for a disconnect nop
778
                        else if(fc_lctl_lk.read() && fc_hctl_lk.read() && fc_dword_lk.read() == 0x00000040){
779
                                if(!expected_discon_nop){
780
                                        cout << "ERROR: Unexpected disconnect nop" << endl;
781
                                        error = true; continue;
782
                                }
783
                                else{
784
                                        if(retry_discon_nop){
785
                                                expected_discon_nop = false;
786
                                                start_retry_sequence();
787
                                        }
788
                                        else{
789
                                                received_discon_nop = true;
790
                                        }
791
                                }
792
                        }
793
                        //Check if it is in the UI fifo
794
                        else if(fc_lctl_lk.read() && fc_hctl_lk.read()){
795
                                //Try to find the packet in the list send from UI
796
                                bool found = false;
797
                                deque<sc_bv<64> >::iterator i;
798
                                PacketCommand cmd = getPacketCommand(fc_dword_lk.read().range(5,0));
799
                                receiving_ui_datapacket = hasDataAssociated(cmd);
800
                                for(i = user_packets.begin(); i != user_packets.end();i++){
801
                                        if((*i).range(31,0) == fc_dword_lk.read()){
802
                                                expected_second_ui_command_dword = !isDwordPacket((*i),cmd);
803
                                                second_ui_command_dword = (*i).range(63,32);
804
                                                found = true;
805
 
806
                                                /**This is a hack to keep the code a bit more simple.  When a
807
                                                CRC is expected for a UI packet without data, add it to the
808
                                                expected list.  It is impossible to do this for packets that have
809
                                                data because NOPs might get inserted to the expected list, the CRC
810
                                                calculation is taken car of in the UI data reception code.*/
811
                                                if(csr_retry.read() && !receiving_ui_datapacket){
812
                                                        unsigned tmp = crc1;
813
                                                        crc1 = 0xFFFFFFFF;
814
                                                        calculate_crc1(fc_dword_lk.read(),true,true);
815
                                                        if(expected_second_ui_command_dword)
816
                                                                calculate_crc1((*i).range(63,32),true,true);
817
 
818
                                                        OutputDword o;
819
                                                        o.dword = ~crc1;
820
                                                        o.lctl = true;
821
                                                        o.hctl = false;
822
                                                        expected_output.push_front(o);
823
 
824
                                                        crc1 = tmp;
825
                                                }
826
 
827
                                                break;
828
                                        }
829
                                }
830
 
831
 
832
 
833
                                //If not found, generate an error
834
                                if(!found){
835
                                        cout << "ERROR: Packet not found in the packet list sent from fifo" << endl;
836
                                        cout << "Dword not found: " << fc_dword_lk.read().to_string(SC_HEX) << endl;
837
                                        if(expected_output.empty()){
838
                                                cout << "No expected dword" << endl;
839
                                        }
840
                                        else{
841
                                                cout << "Expected dword: " << expected.dword.to_string(SC_HEX) << endl;
842
                                                cout << "Expected LCTL: " << expected.lctl << endl;
843
                                                cout << "Expected HCTL: " << expected.hctl << endl;
844
                                        }
845
                                        error = true; continue;
846
                                }
847
 
848
                                //Check if it's legal to send that packet by checking the previous packets
849
                                bool passPW = getPassPW(*i);
850
                                ui_packet_vc = getVirtualChannel(*i,cmd);
851
                                bool illegal = false;
852
                                deque<sc_bv<64> >::iterator n;
853
                                for(n = user_packets.begin(); n != i && !illegal;n++){
854
                                        PacketCommand cmd_n = getPacketCommand(n->range(5,0));
855
                                        VirtualChannel vc_n = getVirtualChannel(*n,cmd_n);
856
                                        bool passPW_n = getPassPW(*n);
857
                                        switch(ui_packet_vc){
858
                                                case VC_POSTED:
859
                                                        illegal = vc_n == VC_POSTED && (passPW_n || !passPW);
860
                                                        break;
861
                                                case VC_NON_POSTED:
862
                                                        illegal = !passPW || passPW_n;
863
                                                        break;
864
                                                case VC_RESPONSE:
865
                                                        illegal = vc_n == VC_RESPONSE || !passPW && vc_n == VC_POSTED;
866
                                                        break;
867
                                                default:
868
                                                        cout << "ERROR: Internal error, an invalide packet was received but was expected" << endl;
869
                                                        error = true; continue;
870
                                        }
871
                                        if(illegal) break;
872
                                }
873
                                if(illegal){
874
                                        cout << "ERROR: Received a packet which broke ordering rules within UI FIFO" << endl;
875
                                        cout << "Packet: " << i->to_string(SC_HEX) << " passed: " << n->to_string(SC_HEX) << endl;
876
                                        error = true; continue;
877
                                }
878
                                user_packets.erase(i);
879
                        }
880
                        else{
881
                                cout << "ERROR: Unexpected non command packet received" << endl;
882
                                cout << "Received: " << fc_dword_lk.read().to_string(SC_HEX) <<
883
                                                " LCTL: " << fc_lctl_lk.read() <<
884
                                                " HCTL: " << fc_hctl_lk.read() << endl;
885
                                if(expected_output.empty()){
886
                                        cout << "Nothing expected" << endl;
887
                                }
888
                                else{
889
                                        cout << "Expected: " << expected_output.front().dword.to_string(SC_HEX) <<
890
                                                " LCTL: " << expected_output.front().lctl <<
891
                                                " HCTL: " << expected_output.front().hctl << endl;
892
                                }
893
                                error = true; continue;
894
                        }
895
                }
896
 
897
                manage_ack_buffer_count();
898
                send_next_node_nops();
899
                free_buffers();
900
                if(csr_retry.read()){
901
                        manage_history();
902
                }
903
                wait();
904
        }/* while*/ } // try
905
        catch(TestbenchError tbe){
906
                cout << tbe.message << endl;
907
                error = true;
908
        }
909
        resetx = false;
910
}
911
 
912
void flow_control_l2_tb::manage_retry_sequence(){
913
        //Analyze output when data is read, unless we are ignoring output because
914
        //a retry disconnect sequence was just initiated
915
        if(lk_consume_fc.read() && !retry_disconnect){
916
                //A nop was sent on previous cycle, we expect a nop CRC
917
                if(retry_expect_nop_crc){
918
                        if(retry_playback_history.empty()){
919
                                cout << "*!!!* History playback empty" << endl;
920
                                retry_sequence = false;
921
                        }
922
                        if(expected_output.empty()){
923
                                TestbenchError te;
924
                                te.message = "No nop CRC in expected output (retry sequence)";
925
                                throw te;
926
                        }
927
                        if(expected_output.front().dword != fc_dword_lk.read() ||
928
                                expected_output.front().lctl != fc_lctl_lk.read() ||
929
                                expected_output.front().hctl != fc_hctl_lk.read())
930
                        {
931
                                TestbenchError te;
932
                                ostringstream o;
933
                                o << "Expecting nop CRC (retry sequence), invalid dword received" << endl
934
                                        << "Expected: " << expected_output.front().dword.to_string(SC_HEX) << " Received: " <<
935
                                        fc_dword_lk.read().to_string(SC_HEX) << endl
936
                                        << "Expected LCTL: " << expected_output.front().lctl << " xpected HCTL: " << expected_output.front().hctl;
937
                                te.message = o.str();
938
                                throw te;
939
                        }
940
                        expected_output.pop_front();
941
 
942
                        retry_expect_nop_crc = false;
943
                }
944
                //First dword of a quad word packet sent last cycle, expect the secont dword
945
                else if(retry_second_dword_next){
946
                        retry_second_dword_next = false;
947
                        if(fc_dword_lk.read() != retry_playback_history.front().pkt.range(63,32) ||
948
                                !fc_lctl_lk.read() || !fc_hctl_lk.read())
949
                        {
950
                                TestbenchError err;
951
                                err.message = "ERROR: Wrong second command dword during history playback\n";
952
                                throw err;
953
                        }
954
                }
955
                //Packet was done being sent last cycle, expect the following CRC
956
                else if(retry_crc_next){
957
                        retry_crc_next = false;
958
                        bool has_data = retry_playback_history.front().data_size != 0;
959
                        if(fc_dword_lk.read() != retry_playback_history.front().crc ||
960
                                fc_lctl_lk.read() == has_data || fc_hctl_lk.read() != has_data)
961
                        {
962
                                TestbenchError err;
963
                                err.message = "ERROR: Wrong crc dword during history playback\n";
964
                                throw err;
965
                        }
966
                        retry_playback_history.pop_front();
967
 
968
                        //Retry sequence is over the the playback history is empty
969
                        retry_sequence = !retry_playback_history.empty();
970
                }
971
                //Command packet with data associated received last cycle, now expect the following data
972
                else if(retry_receive_data){
973
                        if(fc_lctl_lk.read() && fc_hctl_lk.read() && !expected_output.empty()){
974
                                if(fc_dword_lk.read() == expected_output.front().dword){
975
                                        expected_output.pop_front();
976
                                        retry_expect_nop_crc = true;
977
                                }
978
                                else{
979
                                        TestbenchError err;
980
                                        ostringstream o;
981
                                        o << "ERROR: Unexpected command packet received while receiving retry data\n" <<
982
                                                "Received: " << fc_dword_lk.read().to_string(SC_HEX) <<
983
                                                " Expected: " << expected_output.front().dword.to_string(SC_HEX);
984
                                        err.message = o.str();
985
                                        throw err;
986
                                }
987
                        }
988
                        else{
989
                                if(fc_dword_lk.read() != retry_playback_history.front().data[retry_data_count++] ||
990
                                        fc_lctl_lk.read() || fc_hctl_lk.read())
991
                                {
992
                                        TestbenchError err;
993
                                        ostringstream o;
994
                                        o << "ERROR: Wrong data dword during history playback\nExpected[" << retry_data_count-1 <<"]: " <<
995
                                                sc_uint<32>(retry_playback_history.front().data[retry_data_count-1]).to_string(SC_HEX)
996
                                                << " Received: " << fc_dword_lk.read().to_string(SC_HEX);
997
                                        err.message = o.str();
998
                                        throw err;
999
                                }
1000
                                //cout << "Data size: " << retry_playback_history.front().data_size << " retry_data_count: " << retry_data_count << endl;
1001
                                retry_receive_data = retry_playback_history.front().data_size != retry_data_count;
1002
                                retry_crc_next = !retry_receive_data;
1003
                        }
1004
                }
1005
                //Expecting another 
1006
                else{
1007
                        if(fc_lctl_lk.read() && fc_hctl_lk.read() && fc_dword_lk.read() == expected_output.front().dword){
1008
                                expected_output.pop_front();
1009
                                retry_expect_nop_crc = true;
1010
                        }
1011
                        else{
1012
                                if(fc_dword_lk.read() != retry_playback_history.front().pkt.range(31,0) ||
1013
                                !fc_lctl_lk.read() || !fc_hctl_lk.read())
1014
                                {
1015
                                        TestbenchError err;
1016
                                        ostringstream o;
1017
                                        o << "ERROR: Wrong first command dword during history playback\n" <<
1018
                                                "Received: " << fc_dword_lk.read().to_string(SC_HEX) << " Expected: " <<
1019
                                                retry_playback_history.front().pkt.to_string(SC_HEX);
1020
                                        err.message = o.str();
1021
                                        throw err;
1022
                                }
1023
                                retry_receive_data = retry_playback_history.front().data_size;
1024
                                retry_data_count = 0;
1025
                                PacketCommand cmd = getPacketCommand( retry_playback_history.front().pkt);
1026
                                retry_second_dword_next = !isDwordPacket(retry_playback_history.front().pkt,cmd);
1027
                                retry_crc_next = !retry_receive_data;
1028
                        }
1029
                }
1030
        }
1031
 
1032
        //Start ignoring output when fc_disconnect_lk is true and output is read
1033
        if(lk_consume_fc.read()){
1034
                retry_disconnect = fc_disconnect_lk.read();
1035
                //If there is no data in playback history, sequence is over
1036
                retry_sequence = !retry_playback_history.empty();
1037
        }
1038
}
1039
 
1040
void flow_control_l2_tb::start_retry_sequence(){
1041
        retry_sequence = true;
1042
        retry_disconnect = false;
1043
        retry_second_dword_next = false;
1044
        retry_crc_next = false;
1045
        retry_receive_data = false;
1046
 
1047
        //Tag the nops in the delay loop so that they're not sent
1048
        for(int n = nop_counter_delay - 1; n != 0; n--)
1049
                nop_delay[n].nop_received = false;
1050
 
1051
        //Reset the next_node_ack_value to the last sent value
1052
        next_node_ack_value = cd_nop_ack_value_fc.read();
1053
        next_node_ack_value_pending = cd_nop_ack_value_fc.read();
1054
 
1055
        //Reset buffer counts
1056
        for(int n = 0; n < 3; n++){
1057
                next_node_buffers_advertised[n] = 0;
1058
                next_node_databuffers_advertised[n] = 0;
1059
        }
1060
 
1061
 
1062
        //history might get modified while playback so we take a snapshot for the playback
1063
        retry_playback_history = history;
1064
 
1065
        cout << "First packet in history at retry begin : " << history.front().pkt.to_string(SC_HEX) <<
1066
                " ID: " << history.front().nop_ack_value << endl;
1067
 
1068
        //We enter retry sequence when receiving a disconnect nop, expect the following crc
1069
        retry_expect_nop_crc = true;
1070
        crc1 = 0xFFFFFFFF;
1071
        calculate_crc1(fc_dword_lk.read(),true,true);
1072
        OutputDword o;
1073
        o.dword = ~crc1; o.lctl = true; o.hctl = false;
1074
        crc1 = 0xFFFFFFFF;
1075
        expected_output.push_back(o);
1076
}
1077
 
1078
void flow_control_l2_tb::manage_ack_buffer_count(){
1079
        /////////////////////////////////////////////
1080
        //Calculate Ack value and update buffer count
1081
        /////////////////////////////////////////////
1082
        if(lk_consume_fc.read()){
1083
                ///Ignore the second dword of a quad word command packet
1084
                if(ignore_next_dword_for_ack){
1085
                        ignore_next_dword_for_ack = false;
1086
                }
1087
                ///Check for dwords that are command packets (both CTL asserted)
1088
                else if(fc_lctl_lk.read() && fc_hctl_lk.read()){
1089
                        //Set the last ack value (value pending) only when another command packet is sent
1090
                        //Meaning that it has been completely sent
1091
                        next_node_ack_value = next_node_ack_value_pending;
1092
 
1093
                        sc_bv<64> pkt = fc_dword_lk.read();
1094
                        PacketCommand cmd = getPacketCommand(pkt.range(6,0));
1095
                        bool dword = isDwordPacket(pkt,cmd);
1096
                        VirtualChannel vc = getVirtualChannel(pkt,cmd);
1097
                        bool has_data = hasDataAssociated(cmd);
1098
 
1099
                        ///Increment the ack value
1100
                        if(csr_retry.read() &&
1101
                                fc_dword_lk.read().range(5,0) != "000000" && //Unless it's a nop
1102
                                fc_dword_lk.read().range(5,0) != "110111" && //A flow control packet
1103
                                fc_dword_lk.read().range(5,0) != "111111") next_node_ack_value_pending++;//Or a sync packet
1104
 
1105
                        if(vc != VC_NONE){
1106
                                ignore_next_dword_for_ack = !dword;
1107
                                if(has_data){
1108
                                        if(next_node_databuffers_advertised[vc] == 0){
1109
                                                TestbenchError err;
1110
                                                err.message = "ERROR: Received a packet for a Virtual channel that did not have available buffers" ;
1111
                                                throw err;
1112
                                        }
1113
                                        next_node_databuffers_advertised[vc]--;
1114
                                }
1115
                                else{
1116
                                        if(next_node_buffers_advertised[vc] == 0){
1117
                                                TestbenchError err;
1118
                                                err.message = "ERROR: Received a packet for a Virtual channel that did not have available buffers";
1119
                                                throw err;
1120
                                        }
1121
                                        next_node_buffers_advertised[vc]--;
1122
                                }
1123
                        }
1124
                }
1125
        }
1126
}
1127
 
1128
 
1129
void flow_control_l2_tb::send_next_node_nops(){
1130
        //////////////////////
1131
        //Send next node nops
1132
        //////////////////////
1133
 
1134
        //Take care of the delay
1135
        for(int n = nop_counter_delay - 1; n != 0; n--)
1136
                nop_delay[n] = nop_delay[n-1];
1137
 
1138
        //Decide if sending nop
1139
        nop_delay[0].nop_received = rand()% 100 < percent_chance_nop_received &&
1140
                !fc_disconnect_lk.read() && lk_rx_connected.read();
1141
 
1142
        //If sending nop, choose content
1143
        if(nop_delay[0].nop_received){
1144
                //Set the current ack value
1145
                nop_delay[0].nop_ack_value = next_node_ack_value;
1146
 
1147
                //Randomly set how many buffers are freed
1148
                sc_bv<12> nop_information = 0;
1149
 
1150
                nop_information = rand();
1151
 
1152
                //If the randomly set value exceeds the maximum value, saturate it.  Repeat for every
1153
                //kind of buffer (3 vcs for data and for command)
1154
                if(((sc_uint<2>)(sc_bv<2>)nop_information.range(1,0) + next_node_buffers_advertised[VC_POSTED])
1155
                                > next_node_buffers_free[VC_POSTED])
1156
                        nop_information.range(1,0) = next_node_buffers_free[VC_POSTED] - next_node_buffers_advertised[VC_POSTED];
1157
                if(((sc_uint<2>)(sc_bv<2>)nop_information.range(3,2) + next_node_databuffers_advertised[VC_POSTED])
1158
                                > next_node_databuffers_free[VC_POSTED])
1159
                        nop_information.range(3,2) = next_node_databuffers_free[VC_POSTED] - next_node_databuffers_advertised[VC_POSTED];
1160
                if(((sc_uint<2>)(sc_bv<2>)nop_information.range(5,4) + next_node_buffers_advertised[VC_RESPONSE])
1161
                                > next_node_buffers_free[VC_RESPONSE])
1162
                        nop_information.range(5,4) = next_node_buffers_free[VC_RESPONSE] - next_node_buffers_advertised[VC_RESPONSE];
1163
                if(((sc_uint<2>)(sc_bv<2>)nop_information.range(7,6) + next_node_databuffers_advertised[VC_RESPONSE])
1164
                                > next_node_databuffers_free[VC_RESPONSE])
1165
                        nop_information.range(7,6) = next_node_databuffers_free[VC_RESPONSE] - next_node_databuffers_advertised[VC_RESPONSE];
1166
                if(((sc_uint<2>)(sc_bv<2>)nop_information.range(9,8) + next_node_buffers_advertised[VC_NON_POSTED])
1167
                                > next_node_buffers_free[VC_NON_POSTED])
1168
                        nop_information.range(9,8) = next_node_buffers_free[VC_NON_POSTED] - next_node_buffers_advertised[VC_NON_POSTED];
1169
                if(((sc_uint<2>)(sc_bv<2>)nop_information.range(11,10) + next_node_databuffers_advertised[VC_NON_POSTED])
1170
                                > next_node_databuffers_free[VC_NON_POSTED])
1171
                        nop_information.range(11,10) = next_node_databuffers_free[VC_NON_POSTED] - next_node_databuffers_advertised[VC_NON_POSTED];
1172
 
1173
                //Add the advertised value
1174
                next_node_buffers_advertised[VC_POSTED] += (unsigned)(sc_uint<2>)(sc_bv<2>)nop_information.range(1,0);
1175
                next_node_databuffers_advertised[VC_POSTED] += (unsigned)(sc_uint<2>)(sc_bv<2>)nop_information.range(3,2);
1176
                next_node_buffers_advertised[VC_RESPONSE] += (unsigned)(sc_uint<2>)(sc_bv<2>)nop_information.range(5,4);
1177
                next_node_databuffers_advertised[VC_RESPONSE] += (unsigned)(sc_uint<2>)(sc_bv<2>)nop_information.range(7,6);
1178
                next_node_buffers_advertised[VC_NON_POSTED] += (unsigned)(sc_uint<2>)(sc_bv<2>)nop_information.range(9,8);
1179
                next_node_databuffers_advertised[VC_NON_POSTED] += (unsigned)(sc_uint<2>)(sc_bv<2>)nop_information.range(11,10);
1180
 
1181
 
1182
                nop_delay[0].nop_information = nop_information;
1183
        }
1184
}
1185
 
1186
void flow_control_l2_tb::free_buffers(){
1187
        //////////////////////
1188
        //Free some buffers
1189
        //////////////////////
1190
        for(int n = 0; n < 3; n++){
1191
                //Free command packets
1192
 
1193
                //Generate a random free value that has a maximum of 3
1194
                unsigned tmp = rand() % 20;
1195
                unsigned free = tmp;
1196
                if(free > 3) free = 0;
1197
 
1198
                //Add the value to the number of free buffers (and saturated at the maximum)
1199
                if((next_node_buffers_free[n] + free) > next_node_buffers_maximum[n])
1200
                        next_node_buffers_free[n] = next_node_buffers_maximum[n];
1201
                else
1202
                        next_node_buffers_free[n] += free;
1203
 
1204
                //Free data packets
1205
 
1206
                //Generate a random free value that has a maximum of 3
1207
                tmp = rand() % 20;
1208
                free = tmp;
1209
                if(free > 3) free = 0;
1210
 
1211
                //Add the value to the number of free buffers (and saturated at the maximum)
1212
                if((next_node_databuffers_free[n] + free) > next_node_buffers_maximum[n])
1213
                        next_node_databuffers_free[n] = next_node_buffers_maximum[n];
1214
                else
1215
                        next_node_databuffers_free[n] += free;
1216
        }
1217
}
1218
 
1219
void flow_control_l2_tb::manage_history(){
1220
        //Start by erasing packet acked in the history
1221
        bool done = false;
1222
 
1223
        if(!resetx.read()){
1224
                history_ack_value = 0;
1225
                history_ignore_nop_crc = false;
1226
                history_crc_next = false;
1227
                history_data_count = 0;
1228
                current_history_entry.data_size = 0;
1229
        }
1230
 
1231
        while(!history.empty() && !done){
1232
                sc_uint<8> current_ack_value = history.front().nop_ack_value;
1233
                int diff = ((int)(cd_nop_ack_value_fc.read() - current_ack_value)+256) % 256;
1234
                if(diff < 128){
1235
                        //cout << "Popping history" << endl;
1236
                        //cout << "cd_nop_ack_value_fc: " << cd_nop_ack_value_fc.read() << " current_ack_value: " << current_ack_value << endl;
1237
                        history.pop_front();
1238
                }
1239
                else done = true;
1240
        }
1241
 
1242
        //Add entries to the history
1243
        if(!retry_sequence && resetx.read()){
1244
                if(lk_consume_fc.read()){
1245
                        if(history_ignore_nop_crc){
1246
                                history_ignore_nop_crc = false;
1247
                        }
1248
                        else if(history_second_dword_next){
1249
                                history_second_dword_next = false;
1250
                                current_history_entry.pkt.range(63,32) = fc_dword_lk.read();
1251
                                if(current_history_entry.data_size == 0) history_crc_next = true;
1252
                        }
1253
                        else if(history_crc_next){
1254
                                history_crc_next = false;
1255
                                current_history_entry.crc = (int)(sc_uint<32>)fc_dword_lk.read();
1256
                                //cout << "History entry pushed in" << endl;
1257
                                history.push_back(current_history_entry);
1258
                        }
1259
                        else if(history_data_count != current_history_entry.data_size){
1260
                                //Means we have a nop
1261
                                if(fc_lctl_lk.read()){
1262
                                        history_ignore_nop_crc = true;
1263
                                }
1264
                                else{
1265
                                        current_history_entry.data[history_data_count++] = (int)(sc_uint<32>)fc_dword_lk.read();
1266
                                        if(history_data_count == current_history_entry.data_size)
1267
                                                history_crc_next = true;
1268
                                }
1269
                        }
1270
                        else{
1271
                                if(fc_dword_lk.read().range(5,0) != 0)
1272
                                {
1273
                                        //cout << "HISTORY: Adding packet: " << fc_dword_lk.read().to_string(SC_HEX) << endl;
1274
                                        sc_bv<64> pkt = fc_dword_lk.read();
1275
                                        current_history_entry.pkt = pkt;
1276
                                        PacketCommand cmd = getPacketCommand(pkt.range(5,0));
1277
                                        history_second_dword_next = !isDwordPacket(pkt,cmd);
1278
                                        if(hasDataAssociated(cmd)){
1279
                                                current_history_entry.data_size = (int)getDataLengthm1(pkt) + 1;
1280
                                        }
1281
                                        else{
1282
                                                current_history_entry.data_size = 0;
1283
                                        }
1284
                                        history_crc_next = !history_second_dword_next && current_history_entry.data_size == 0;
1285
                                        history_ack_value = (history_ack_value + 1) % 256;
1286
                                        current_history_entry.nop_ack_value = history_ack_value;
1287
                                        history_data_count = 0;
1288
                                }
1289
                                else{
1290
                                        history_ignore_nop_crc = true;
1291
                                }
1292
                        }
1293
                }
1294
        }
1295
}
1296
 
1297
void flow_control_l2_tb::clear_next_node_information(){
1298
        //This is the number of buffers that are free (command and data)
1299
        for(int n = 0; n < 3; n++){
1300
                next_node_buffers_free[n] = next_node_buffers_maximum[n];
1301
                next_node_databuffers_free[3] = next_node_databuffers_maximum[n];
1302
        }
1303
 
1304
        for(int n = 0; n < 3; n++){
1305
                //This is the number of buffers that have been advertised as being free through
1306
                //nops as seen by the next node (does not take into account the nop delay)
1307
                next_node_buffers_advertised[n] = 0;
1308
                next_node_databuffers_advertised[n] = 0;
1309
 
1310
                //This is the number of buffers that have been advertised as being free through
1311
                //nops as seen by the current node (takes into account the nop delay)
1312
                buffers_available[n] = 0;
1313
                databuffers_available[n] = 0;
1314
        }
1315
 
1316
        next_node_ack_value = 0;
1317
        next_node_ack_value_pending = 0;
1318
        user_packets.clear();
1319
        user_data[0].clear();user_data[1].clear();user_data[2].clear();
1320
        expected_output.clear();
1321
}
1322
 
1323
void flow_control_l2_tb::generate_random_response(sc_bv<32> &pkt, unsigned &data_size){
1324
        int type = rand() % 2;
1325
        sc_bv<6> command;
1326
        sc_uint<4> data_size_m1;
1327
        switch(type){
1328
        case 0:
1329
                //RdResponse
1330
                data_size_m1 = rand() % 16;
1331
                data_size = (unsigned)data_size_m1 + 1;
1332
                getRandomVector(pkt);
1333
                command = "110000";
1334
                pkt.range(5,0) = command;
1335
                pkt.range(25,22) = data_size_m1;
1336
                break;
1337
        case 1:
1338
                //TargetDone
1339
                data_size = 0;
1340
                getRandomVector(pkt);
1341
                command = "110011";
1342
                pkt.range(5,0) = command;
1343
        }
1344
}
1345
 
1346
void flow_control_l2_tb::generate_random_posted(sc_bv<64> &pkt, unsigned &data_size){
1347
        int type = rand() % 3;
1348
        sc_bv<6> command;
1349
        sc_uint<4> data_size_m1;
1350
        switch(type){
1351
        case 0:
1352
                //Posted write
1353
                data_size_m1 = rand() % 16;
1354
                data_size = (unsigned)data_size_m1 + 1;
1355
                getRandomVector(pkt);
1356
                command = "101";
1357
                pkt.range(5,3) = command;
1358
                pkt.range(25,22) = data_size_m1;
1359
 
1360
                //Never create a chain packet.  If it is desired to test
1361
                //chains, they must be explicitely generated for the purpose of
1362
                //that test
1363
                pkt[19] = false;
1364
                break;
1365
        case 1:
1366
                //Broadcast
1367
                data_size = 0;
1368
                getRandomVector(pkt);
1369
                command = "111010";
1370
                pkt.range(5,0) = command;
1371
                break;
1372
        case 2:
1373
                //Fence
1374
                data_size = 0;
1375
                getRandomVector(pkt);
1376
                pkt.range(63,32) = 0;
1377
                command = "111100";
1378
                pkt.range(5,0) = command;
1379
        }
1380
}
1381
 
1382
void flow_control_l2_tb::generate_random_nposted(sc_bv<64> &pkt, unsigned &data_size){
1383
        int type = rand() % 5;
1384
 
1385
        bool dword_read = true;
1386
        sc_uint<4> data_size_m1 = rand() % 16;
1387
        data_size = (unsigned)data_size_m1 + 1;
1388
        switch(type){
1389
        case 0:
1390
                {
1391
                        //NPosted write
1392
                        getRandomVector(pkt);
1393
                        sc_bv<3> command = "001";
1394
                        pkt.range(5,3) = command;
1395
                        pkt.range(25,22) = data_size_m1;
1396
                }
1397
                break;
1398
        case 1:
1399
                //Read Byte
1400
                dword_read = false;
1401
        case 2:
1402
                {
1403
                        //Read Dword
1404
                        getRandomVector(pkt);
1405
                        sc_bv<2> command = "01";
1406
                        pkt.range(5,4) = command;
1407
                        pkt[2] = dword_read;
1408
                        pkt.range(25,22) = data_size_m1;
1409
                        data_size = 0;
1410
                }
1411
                break;
1412
        case 3:
1413
                {
1414
                        //Atomic
1415
                        getRandomVector(pkt);
1416
                        sc_bv<6> command = "111101";
1417
                        pkt.range(5,0) = command;
1418
                        pkt.range(25,22) = data_size_m1;
1419
                }
1420
                break;
1421
        case 4:
1422
                {
1423
                        //Flush
1424
                        data_size = 0;
1425
                        getRandomVector(pkt);
1426
                        pkt.range(63,32) = 0;
1427
                        sc_bv<6> command = "000010";
1428
                        pkt.range(5,0) = command;
1429
                }
1430
        }
1431
}
1432
 
1433
VirtualChannel flow_control_l2_tb::generate_random_packet(sc_bv<64> &pkt, unsigned &data_size){
1434
 
1435
        int vc = rand() % 3;
1436
        switch(vc){
1437
        case VC_POSTED:
1438
                generate_random_posted(pkt,data_size);
1439
                break;
1440
        case VC_NON_POSTED:
1441
                generate_random_nposted(pkt,data_size);
1442
                break;
1443
        default:
1444
                sc_bv<32> r_pkt;
1445
                generate_random_response(r_pkt,data_size);
1446
                pkt = 0;
1447
                pkt.range(31,0) = r_pkt;
1448
        }
1449
        return vc;
1450
}
1451
 
1452
 
1453
void flow_control_l2_tb::getRandomVector(sc_bv<32> &vector){
1454
        vector.range(14,0) = sc_uint<15>(rand());
1455
        vector.range(29,15) = sc_uint<15>(rand());
1456
        vector.range(31,30) = sc_uint<2>(rand());
1457
}
1458
 
1459
void flow_control_l2_tb::getRandomVector(sc_bv<64> &vector){
1460
        for(int n = 0; n < 4; n++)
1461
                vector.range(15*(n+1) - 1,15*n) = sc_uint<15>(rand());
1462
        vector.range(63,60) = sc_uint<4>(rand());
1463
}
1464
 
1465
void flow_control_l2_tb::add_ui_data_packet(unsigned datalength,
1466
                                                                           VirtualChannel ui_vc,
1467
                                                                           sc_bv<64> &associated_control_packet){
1468
        PacketData data;
1469
        data.associated_control_pkt = associated_control_packet;
1470
        data.size = datalength;
1471
        for(unsigned n = 0; n < datalength; n++){
1472
                data.dwords[n] =
1473
                        (rand() & 0x7FFF) |  ((rand() & 0x7FFF ) << 15) | ((rand() & 0x3 ) << 30);
1474
        }
1475
        //cout << "ADDED UI DATA ENTRY: " << data.associated_control_pkt.to_string(SC_HEX)
1476
        //      << " Datalength: " << data.size << endl;
1477
        user_data[ui_vc].push_back(data);
1478
}
1479
 
1480
void flow_control_l2_tb::update_databuffer_entry(unsigned datalength,
1481
                                                                                VirtualChannel ui_vc,
1482
                                                                                sc_uint<4> &databuffer_address)
1483
{
1484
        databuffer_data.vc = ui_vc;
1485
        databuffer_data.size = datalength;
1486
        for(unsigned n = 0; n < datalength; n++){
1487
                databuffer_data.dwords[n] =
1488
                        (rand() & 0x7FFF) |  ((rand() & 0x7FFF ) << 15) | ((rand() & 0x3 ) << 30);
1489
        }
1490
        databuffer_data.address = databuffer_address;
1491
}
1492
 
1493
void flow_control_l2_tb::calculate_crc1(sc_bv<32> dword,bool lctl, bool hctl){
1494
        sc_bv<34> data;
1495
        data[33] = hctl;
1496
        data.range(32,17) = dword.range(31,16);
1497
        data[16] = lctl;
1498
        data.range(15,0) = dword.range(15,0);
1499
        calculate_crc(crc1,data);
1500
}
1501
 
1502
void flow_control_l2_tb::calculate_crc2(sc_bv<32> dword,bool lctl, bool hctl){
1503
        sc_bv<34> data;
1504
        data[33] = hctl;
1505
        data.range(32,17) = dword.range(31,16);
1506
        data[16] = lctl;
1507
        data.range(15,0) = dword.range(15,0);
1508
        calculate_crc(crc2,data);
1509
}
1510
 
1511
void flow_control_l2_tb::calculate_crc(unsigned &crc,sc_bv<34> &data){
1512
        static unsigned poly = 0x04C11DB7;
1513
 
1514
        for(int i = 0; i < 34; i++){
1515
                /* xor highest bit w/ message: */
1516
                unsigned tmp = ((crc >> 31) & 1) ^ ( ((sc_bit)data[i]) ? 1 : 0);
1517
 
1518
                /* substract poly if greater: */
1519
                crc = (tmp) ? (crc << 1) ^ poly : ((crc << 1) | tmp);
1520
        }
1521
}
1522
 
1523
ostream &operator<<(ostream &out,const flow_control_l2_tb::FlowControlStatus fc_status){
1524
        switch(fc_status){
1525
                case flow_control_l2_tb::FC_SENDING_CSR:
1526
                        out << "FC_SENDING_CSR";
1527
                        break;
1528
                case flow_control_l2_tb::FC_SENDING_EH:
1529
                        out << "FC_SENDING_EH";
1530
                        break;
1531
                case flow_control_l2_tb::FC_SENDING_FWD:
1532
                        out << "FC_SENDING_FWD";
1533
                        break;
1534
                case flow_control_l2_tb::FC_SENDING_UI:
1535
                        out << "FC_SENDING_UI";
1536
                        break;
1537
                case flow_control_l2_tb::FC_NONE:
1538
                        out << "FC_NONE";
1539
                        break;
1540
                default:
1541
                        out << "Invalid FlowControlStatus value";
1542
        }
1543
        return out;
1544
}
1545
 
1546
void flow_control_l2_tb::add_expected_crc_for_packet(PacketData &data){
1547
        unsigned tmp;
1548
        tmp = crc2;
1549
        crc2 = 0xFFFFFFFF;
1550
 
1551
        calculate_crc2(data.associated_control_pkt.range(31,0),true,true);
1552
        PacketCommand cmd = getPacketCommand(data.associated_control_pkt.range(5,0));
1553
        if(!isDwordPacket(data.associated_control_pkt,cmd))
1554
                calculate_crc2(data.associated_control_pkt.range(63,32),true,true);
1555
 
1556
        for(int n = 0; n < data.size; n++){
1557
                calculate_crc2(data.dwords[n],false,false);
1558
        }
1559
 
1560
        OutputDword o;
1561
        o.dword = ~crc2;
1562
        o.lctl = false;
1563
        o.hctl = true;
1564
        expected_output.push_front(o);
1565
 
1566
        crc2 = tmp;
1567
}
1568
 
1569
 
1570
 

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.