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

Subversion Repositories dvb_s2_ldpc_decoder

[/] [dvb_s2_ldpc_decoder/] [trunk/] [tb/] [tb_cn.v] - Blame information for rev 2

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 2 jcorley
`timescale 1ns/10ps
2
 
3
module tb_cn();
4
 
5
localparam NUM_RUNS           = 1000;
6
localparam ITERATIONS_PER_RUN = 30;
7
localparam MAX_CONNECTIVITY   = 30;
8
 
9
localparam FOLDFACTOR = 1;
10
localparam CN_DEPTH   = 2**(7+FOLDFACTOR);
11
 
12
localparam LLRWIDTH          = 4;
13
localparam MAX_LLR           = 2**(LLRWIDTH-1) -1;
14
localparam MAX_INTERNAL_LLR  = 2**(LLRWIDTH-2) -1;
15
 
16
localparam MIN_SEPARATION = 5;
17
 
18
localparam CLK_PERIOD = 10ns;
19
localparam HOLD       = 1ns;
20
 
21
localparam LASTSHIFTDIST = (FOLDFACTOR==1) ? 11 :
22
                           (FOLDFACTOR==2) ? 5  :
23
                           (FOLDFACTOR==3) ? 3  :
24
                           /* 4 */           2;
25
localparam LASTSHIFTWIDTH  = (FOLDFACTOR==1) ? 4 :
26
                             (FOLDFACTOR==2) ? 3 :
27
                             (FOLDFACTOR==3) ? 2 :
28
                             /* 4 */           2;
29
 
30
//////////////////////////////////////////
31
 
32
reg clk;
33
reg rst;
34
 
35
initial
36
begin
37
  clk <= 1;
38
  rst <= 1;
39
  #0;
40
 
41
  #(CLK_PERIOD/2) clk <= ~clk;
42
  #(CLK_PERIOD/2) clk <= ~clk;
43
  #(CLK_PERIOD/2) clk <= ~clk;
44
 
45
  rst <= #HOLD 0;
46
 
47
  forever
48
    #(CLK_PERIOD/2) clk <= ~clk;
49
end
50
 
51
/////////////////////
52
// Main controller //
53
/////////////////////
54
typedef struct { int iterations;
55
                 int connections_per_node;
56
                 int min_separation;
57
                 bit allow_adjacent_writes;
58
                 } run;
59
run run_source;
60
 
61
mailbox #( run ) run_descriptor;
62
semaphore        generator_done;
63
 
64
initial
65
begin
66
  run_descriptor = new();
67
  @(negedge rst);
68
 
69
  for( int run_num=0; run_num<NUM_RUNS; run_num++ )
70
  begin
71
    run_source.iterations            = ITERATIONS_PER_RUN;
72
    run_source.connections_per_node  = 2 + ({ $random() } % (MAX_CONNECTIVITY -2));
73
    run_source.min_separation        = MIN_SEPARATION;
74
    run_source.allow_adjacent_writes = 1;
75
 
76
    run_descriptor.put( run_source );
77
 
78
    generator_done.get(1);
79
    $display( "%0t: Run %0d done", $time(), run_num );
80
  end
81
 
82
  $display( "Done" );
83
  $stop();
84
end
85
 
86
////////////////////
87
// Data generator //
88
////////////////////
89
localparam EMPTY    = -999999;
90
 
91
int data_sequence[];
92
bit sign_sequence[];
93
bit disable_sequence[];
94
int address[];
95
 
96
int writes_per_iteration;
97
int iterations;
98
 
99
semaphore send_load;
100
semaphore send_run;
101
semaphore load_done;
102
semaphore run_done;
103
 
104
initial
105
begin
106
  generator_done = new();
107
  send_load      = new();
108
  send_run       = new();
109
 
110
  @(negedge rst);
111
 
112
  forever
113
  begin
114
    run run_dest;
115
 
116
    int array_len;
117
    bit start_over;
118
 
119
    run_descriptor.get( run_dest );
120
 
121
    writes_per_iteration = run_dest.connections_per_node*CN_DEPTH;
122
    iterations           = run_dest.iterations;
123
    array_len            = iterations*writes_per_iteration;
124
 
125
    data_sequence    = new[array_len];
126
    sign_sequence    = new[array_len];
127
    disable_sequence = new[writes_per_iteration];
128
    address          = new[writes_per_iteration];
129
 
130
    /////////////////////////////////////////////
131
    // Create data sequence for the entire run //
132
    /////////////////////////////////////////////
133
    start_over = 1;
134
 
135
    // assign random data and clear address array
136
    for( int i=0; i<=writes_per_iteration; i++ )
137
    begin
138
      address[i]          = EMPTY;
139
      disable_sequence[i] = 0;//($random() %100 == 1);
140
    end
141
 
142
    for( int i=0; i<=array_len; i++ )
143
    begin
144
      data_sequence[i] = { $random() } % (MAX_LLR+1);
145
      sign_sequence[i] = $random();
146
    end
147
 
148
    while( start_over )
149
    begin
150
      bit adjacent_write;
151
      int try_addr;
152
 
153
      start_over     = 0;
154
      adjacent_write = 0;
155
      try_addr       = 0;
156
 
157
      for( int j=0; j<CN_DEPTH; j++ )
158
      begin
159
        for( int k=0; k<run_dest.connections_per_node; k++ )
160
        begin
161
          bit good_addr;
162
          bit good_run;
163
 
164
          int try_count;
165
          // Assign somewhat random order, but try to group addresses and
166
          // create "runs" of identical addresses
167
          try_count = 0;
168
          good_addr = 0;
169
 
170
          while( !good_addr && !start_over )
171
          begin
172
            try_count++;
173
            try_addr++;
174
            try_addr = try_addr % writes_per_iteration;
175
 
176
            // try to group even non-adjacent writes fairly closely, to maximize the
177
            // likelihood of memory inconsistency
178
            if( !adjacent_write )
179
            begin
180
              try_addr += run_dest.min_separation - 1;
181
              try_addr += { $random() } % 3;
182
              try_addr = try_addr % writes_per_iteration;
183
            end
184
 
185
            // search for an empty address
186
            while( (address[try_addr]!=EMPTY) && (try_count!=writes_per_iteration) )
187
            begin
188
              try_count++;
189
              try_addr++;
190
              try_addr = try_addr % writes_per_iteration;
191
            end
192
 
193
            good_addr = (address[try_addr]==EMPTY);
194
 
195
            // check whether nearby locations contain identical addresses.  A continuous
196
            // run of identical addresses is allowed
197
            good_run = run_dest.allow_adjacent_writes;
198
 
199
            for( int test_addr=try_addr-1;
200
                 (test_addr >= try_addr-run_dest.min_separation) && (test_addr >= 0);
201
                 test_addr-- )
202
            begin
203
              bit matches1;
204
              matches1 = j==address[test_addr];
205
 
206
              good_run  = good_run & matches1;
207
              good_addr = good_addr & (!matches1 | good_run);
208
            end
209
 
210
            good_run = run_dest.allow_adjacent_writes;
211
 
212
            for( int test_addr=1;
213
                 (test_addr < run_dest.min_separation) &&
214
                 (try_addr+test_addr < writes_per_iteration);
215
                 test_addr++ )
216
            begin
217
              bit matches2;
218
              matches2 = j==address[try_addr+test_addr];
219
 
220
              good_run  = good_run & matches2;
221
              good_addr = good_addr & (!matches2 | good_run);
222
            end
223
 
224
            if( good_addr )
225
              adjacent_write = ({$random()}%3==2) & run_dest.allow_adjacent_writes;
226
            else // if random jump resulted in bad address, try next address
227
              adjacent_write = 1;
228
 
229
            // There's a chance we'll have to start all over due to impossible
230
            // placement.  Detect that here:
231
            if( !good_addr && (try_count==writes_per_iteration) )
232
            begin
233
              int ad;
234
              int co;
235
              ad = j;
236
              co = k;
237
              $display( "Address %0d / %0d, connection %0d / %0d - couldn't find good placement",
238
                        ad, CN_DEPTH, co, run_dest.connections_per_node );
239
              start_over = 1;
240
            end
241
 
242
            if( good_addr )
243
              address[try_addr] = j;
244
          end
245
        end
246
      end
247
    end
248
 
249
    // At this point, address and data_sequence contain valid data
250
    send_load.put(1);
251
    load_done.get(1);
252
    send_run.put(1);
253
    run_done.get(1);
254
 
255
    data_sequence.delete;
256
    sign_sequence.delete;
257
    disable_sequence.delete;
258
    address.delete;
259
 
260
    generator_done.put(1);
261
  end
262
end
263
 
264
////////////////////////////
265
// Load/unload transactor //
266
////////////////////////////
267
reg                   llr_access;
268
reg[7+FOLDFACTOR-1:0] llr_addr;
269
reg                   llr_din_we;
270
 
271
initial
272
begin
273
  load_done = new();
274
 
275
  llr_access  <= 0;
276
  llr_addr    <= 0;
277
  llr_din_we  <= 0;
278
 
279
  @(negedge rst);
280
 
281
  forever
282
  begin
283
    send_load.get( 1 );
284
    @(posedge clk);
285
    llr_access <= #HOLD 1;
286
    repeat(2) @(posedge clk);
287
 
288
    for( int i=0; i<CN_DEPTH; i++ )
289
    begin
290
      llr_addr   <= #HOLD i;
291
      llr_din_we <= #HOLD 1;
292
      @(posedge clk);
293
    end
294
 
295
    llr_access  <= #HOLD 0;
296
    llr_addr    <= #HOLD 0;
297
    llr_din_we  <= #HOLD 0;
298
    repeat(MIN_SEPARATION) @(posedge clk);
299
 
300
    load_done.put( 1 );
301
  end
302
end
303
 
304
////////////////////////////////
305
// Message passing transactor //
306
////////////////////////////////
307
reg                   iteration;
308
reg                   first_half;
309
reg                   first_iteration;
310
reg                   cn_rd;
311
reg                   cn_we;
312
reg                   disable_paritymsg;
313
reg[7+FOLDFACTOR-1:0] addr_cn;
314
 
315
reg[LLRWIDTH-1:0]  sh_msg;
316
wire[LLRWIDTH-1:0] cn_msg;
317
 
318
initial
319
begin
320
  run_done = new();
321
 
322
  iteration         <= 0;
323
  first_half        <= 0;
324
  first_iteration   <= 0;
325
  cn_rd             <= 0;
326
  cn_we             <= 0;
327
  disable_paritymsg <= 0;
328
  addr_cn           <= 0;
329
  sh_msg            <= 0;
330
 
331
  @(negedge rst);
332
 
333
  forever
334
  begin
335
    send_run.get( 1 );
336
    @(posedge clk);
337
 
338
    // downstream
339
    for( int it=0; it<iterations; it++ )
340
    begin
341
      int base_offset;
342
      base_offset = it * writes_per_iteration;
343
 
344
      iteration <= #HOLD it[0];
345
 
346
      for( int half=0; half<2; half++ )
347
      begin
348
        first_half      <= #HOLD half==0;
349
        first_iteration <= #HOLD it==0;
350
        cn_rd           <= #HOLD half==1;
351
        cn_we           <= #HOLD half==0;
352
 
353
        for( int i=0; i<writes_per_iteration; i++ )
354
        begin
355
          sh_msg[LLRWIDTH-1]   <= #HOLD sign_sequence[base_offset + i];
356
          sh_msg[LLRWIDTH-2:0] <= #HOLD data_sequence[base_offset + i];
357
          addr_cn              <= #HOLD address[i];
358
          disable_paritymsg    <= #HOLD disable_sequence[i];
359
          @(posedge clk);
360
        end
361
 
362
        cn_rd <= #HOLD 0;
363
        cn_we <= #HOLD 0;
364
        repeat(2* MIN_SEPARATION) @(posedge clk);
365
      end
366
    end
367
 
368
    repeat(2) @(posedge clk);
369
    run_done.put( 1 );
370
  end
371
end
372
 
373
///////////////////////
374
// Model and checker //
375
///////////////////////
376
// Store states based on received and sent messages
377
localparam CN_MSG_LATENCY = 4;
378
 
379
int recv_counter[0:CN_DEPTH-1];
380
int send_counter[0:CN_DEPTH-1];
381
int last_recv_iteration[0:CN_DEPTH-1];
382
int last_send_iteration[0:CN_DEPTH-1];
383
int recv_msgs[0:CN_DEPTH-1][0:MAX_CONNECTIVITY-1];
384
int sent_msgs[0:CN_DEPTH-1][0:MAX_CONNECTIVITY-1];
385
 
386
bit cn_rd_del[0:CN_MSG_LATENCY-1];
387
int addr_cn_del[0:CN_MSG_LATENCY-1];
388
 
389
always @( posedge clk )
390
begin
391
  if( llr_access && llr_din_we )
392
  begin
393
    last_recv_iteration[llr_addr] = -1;
394
    last_send_iteration[llr_addr] = -1;
395
    for( int i=0; i<MAX_CONNECTIVITY; i++ )
396
    begin
397
      recv_msgs[llr_addr][i] = EMPTY;
398
      sent_msgs[llr_addr][i] = 0;
399
    end
400
  end
401
 
402
  // Writes
403
  if( cn_we & !disable_paritymsg )
404
  begin
405
    int new_sign;
406
    int new_mag;
407
    int new_msg;
408
    int sent_msg;
409
 
410
    // increment counter, or reset counter for new iteration
411
    if( last_recv_iteration[addr_cn]!=iteration )
412
      recv_counter[addr_cn] = 0;
413
    else
414
      recv_counter[addr_cn]++;
415
 
416
    last_recv_iteration[addr_cn] = iteration;
417
 
418
    // stored value = received message - sent message, since a node's own
419
    // contribution to the LLR needs to be ignored
420
    new_sign  = sh_msg[LLRWIDTH-1] ? -1 : 1;
421
    new_mag   = sh_msg[LLRWIDTH-2:0];
422
    sent_msg  = sent_msgs[addr_cn][ recv_counter[addr_cn] ];
423
 
424
    new_msg = new_sign * new_mag;
425
    new_msg = new_msg - sent_msg;
426
 
427
    new_sign = new_msg < 0 ? -1 : 1;
428
    new_mag  = new_sign * new_msg;
429
 
430
    if( new_mag>MAX_INTERNAL_LLR )
431
      new_mag = MAX_INTERNAL_LLR;
432
 
433
    recv_msgs[addr_cn][ recv_counter[addr_cn] ] = new_sign * new_mag;
434
  end
435
 
436
  // Reads
437
  cn_rd_del[0]   <= cn_rd;
438
  addr_cn_del[0] <= addr_cn;
439
  for( int i=1; i<CN_MSG_LATENCY; i++ )
440
  begin
441
    cn_rd_del[i]   <= cn_rd_del[i-1];
442
    addr_cn_del[i] <= addr_cn_del[i-1];
443
  end
444
 
445
  if( cn_rd_del[CN_MSG_LATENCY-1] )
446
  begin
447
    int new_sign;
448
    int new_mag;
449
    int delayed_addr;
450
    int min_prev_val;
451
 
452
    delayed_addr = addr_cn_del[CN_MSG_LATENCY-1];
453
 
454
    // increment counter, or reset counter for new iteration
455
    if( last_send_iteration[delayed_addr]!=iteration )
456
      send_counter[delayed_addr] = 0;
457
    else
458
      send_counter[delayed_addr]++;
459
 
460
    last_send_iteration[delayed_addr] = iteration;
461
 
462
    // store read value in matrix
463
    new_sign = cn_msg[LLRWIDTH-1] ? -1 : 1;
464
    new_mag  = cn_msg[LLRWIDTH-2:0];
465
 
466
    sent_msgs[delayed_addr][ send_counter[delayed_addr] ] = new_sign * new_mag;
467
  end
468
end
469
 
470
// predict messages
471
int predicted_msgs[0:CN_DEPTH-1][0:MAX_CONNECTIVITY-1];
472
 
473
always @( posedge cn_rd )
474
begin
475
  for( int node=0; node<CN_DEPTH; node++ )
476
  begin
477
    // find min, nextmin for each node
478
    int min, nextmin;
479
    int sign_product;
480
 
481
    min     = 999999;
482
    nextmin = 999999;
483
 
484
    for( int msg_num=0; msg_num<=recv_counter[node]; msg_num++ )
485
    begin
486
      int msg_sign;
487
      int msg_mag;
488
      msg_sign = recv_msgs[node][msg_num] < 0 ? -1 : 1;
489
      msg_mag  = msg_sign * recv_msgs[node][msg_num];
490
 
491
      if( msg_mag <= min )
492
      begin
493
        nextmin = min;
494
        min     = msg_mag;
495
      end
496
      if( (msg_mag<nextmin) && (msg_mag!=min) )
497
        nextmin = msg_mag;
498
    end
499
 
500
    if( nextmin==999999 )
501
      nextmin = min;
502
 
503
    // find XOR of received signs
504
    sign_product = 1;
505
    for( int i=0; i<=recv_counter[node]; i++ )
506
      sign_product *= recv_msgs[node][ i ] < 0 ? -1 : 1;
507
 
508
    // assign EMPTY, or positive or negative min or nextmin to each message
509
    for( int msg_num=0; msg_num<MAX_CONNECTIVITY; msg_num++ )
510
    begin
511
      if( msg_num>recv_counter[node] )
512
        predicted_msgs[node][msg_num] = EMPTY;
513
      else
514
      begin
515
        int msg_sign;
516
        int msg_mag;
517
        msg_sign = recv_msgs[node][msg_num] < 0 ? -1 : 1;
518
        msg_mag  = msg_sign * recv_msgs[node][msg_num];
519
 
520
        if( msg_mag==min )
521
          predicted_msgs[node][msg_num] = nextmin;
522
        else
523
          predicted_msgs[node][msg_num] = min;
524
 
525
        if( predicted_msgs[node][msg_num]>MAX_LLR )
526
          predicted_msgs[node][msg_num] = MAX_LLR;
527
        if( predicted_msgs[node][msg_num]<-1 * MAX_LLR )
528
          predicted_msgs[node][msg_num] = -1 * MAX_LLR;
529
 
530
        predicted_msgs[node][msg_num] *= msg_sign * sign_product;
531
      end
532
    end
533
  end
534
end
535
 
536
// Check that sent messages match predicted
537
int predicted;
538
int predicted_counter[0:CN_DEPTH-1];
539
 
540
always @( posedge clk )
541
begin
542
  // clear counters on rising edge of cn_rd
543
  if( cn_rd_del[CN_MSG_LATENCY-2] && !cn_rd_del[CN_MSG_LATENCY-1] )
544
    for( int i=0; i<CN_DEPTH; i++ )
545
      predicted_counter[i] = 0;
546
 
547
  if( cn_rd_del[CN_MSG_LATENCY-1] )
548
  begin
549
    int node;
550
    int msg_num;
551
    int cn_msg_int;
552
 
553
    node    = addr_cn_del[CN_MSG_LATENCY-1];
554
    msg_num = predicted_counter[node];
555
 
556
    cn_msg_int = cn_msg[LLRWIDTH-2:0];
557
    if( cn_msg[LLRWIDTH-1] )
558
      cn_msg_int *= -1;
559
 
560
    predicted = predicted_msgs[node][msg_num];
561
 
562
    if( predicted!=cn_msg_int )
563
      $display( "%0t: Mismatch, predicted cn_msg != actual, %0d != %0d",
564
                $time(), predicted, cn_msg_int );
565
 
566
    predicted_counter[node]++;
567
  end
568
end
569
 
570
///////////////
571
// DUT + RAM //
572
///////////////
573
wire                         dnmsg_we;
574
wire[7+FOLDFACTOR-1:0]       dnmsg_wraddr;
575
wire[7+FOLDFACTOR-1:0]       dnmsg_rdaddr;
576
wire[17+4*(LLRWIDTH-1)+31:0] dnmsg_din;
577
wire[17+4*(LLRWIDTH-1)+31:0] dnmsg_dout;
578
 
579
ldpc_cn #( .FOLDFACTOR    ( FOLDFACTOR ),
580
           .LLRWIDTH      ( LLRWIDTH )
581
) ldpc_cn_i(
582
  .clk              (clk),
583
  .rst              (rst),
584
  .llr_access       (llr_access),
585
  .llr_addr         (llr_addr),
586
  .llr_din_we       (llr_din_we),
587
  .iteration        (iteration),
588
  .first_half       (first_half),
589
  .first_iteration  (first_iteration),
590
  .cn_we            (cn_we),
591
  .cn_rd            (cn_rd),
592
  .disable_paritymsg(disable_paritymsg),
593
  .addr_cn          (addr_cn),
594
  .sh_msg           (sh_msg),
595
  .cn_msg           (cn_msg),
596
  .dnmsg_we         (dnmsg_we),
597
  .dnmsg_wraddr     (dnmsg_wraddr),
598
  .dnmsg_rdaddr     (dnmsg_rdaddr),
599
  .dnmsg_din        (dnmsg_din),
600
  .dnmsg_dout       (dnmsg_dout)
601
);
602
 
603
ldpc_ram_behav #(
604
  .WIDTH    ( 17+4*(LLRWIDTH-1)+32 ),
605
  .LOG2DEPTH( 7+FOLDFACTOR )
606
) ldpc_cnholder_i (
607
  .clk   ( clk ),
608
  .we    ( dnmsg_we ),
609
  .din   ( dnmsg_din ),
610
  .wraddr( dnmsg_wraddr ),
611
  .rdaddr( dnmsg_rdaddr ),
612
  .dout  ( dnmsg_dout )
613
);
614
 
615
endmodule
616
 

powered by: WebSVN 2.1.0

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