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_vn.v] - Blame information for rev 2

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 2 jcorley
`timescale 1ns/1ns
2
 
3
module tb_vn();
4
 
5
localparam NUM_RUNS           = 1000;
6
localparam ITERATIONS_PER_RUN = 30;
7
localparam MAX_CONNECTIVITY   = 8;
8
 
9
localparam FOLDFACTOR = 1;
10
localparam VN_DEPTH   = 2**(7+FOLDFACTOR);
11
 
12
localparam LLRWIDTH         = 4;
13
localparam MAX_LLR          = (2**(LLRWIDTH-1)) -1;
14
localparam MAX_INTERNAL_LLR = (2**(LLRWIDTH+3)) -1;
15
 
16
localparam MIN_SEPARATION = 5;
17
 
18
localparam CLK_PERIOD = 10ns;
19
localparam HOLD       = 1ns;
20
 
21
//////////////////////////////////////////
22
 
23
reg clk;
24
reg rst;
25
 
26
initial
27
begin
28
  clk <= 1;
29
  rst <= 1;
30
  #0;
31
 
32
  #(CLK_PERIOD/2) clk <= ~clk;
33
  #(CLK_PERIOD/2) clk <= ~clk;
34
  #(CLK_PERIOD/2) clk <= ~clk;
35
 
36
  rst <= 0;
37
 
38
  forever
39
    #(CLK_PERIOD/2) clk <= ~clk;
40
end
41
 
42
/////////////////////
43
// Main controller //
44
/////////////////////
45
typedef struct { int iterations;
46
                 int connections_per_node;
47
                 int min_separation;
48
                 bit allow_adjacent_writes;
49
                 } run;
50
run run_source;
51
 
52
mailbox #( run ) run_descriptor;
53
semaphore        generator_done;
54
 
55
initial
56
begin
57
  run_descriptor = new();
58
  @(negedge rst);
59
 
60
  for( int run_num=0; run_num<NUM_RUNS; run_num++ )
61
  begin
62
    run_source.iterations            = ITERATIONS_PER_RUN;
63
    run_source.connections_per_node  = 1 + { $random() } % MAX_CONNECTIVITY;
64
    run_source.min_separation        = MIN_SEPARATION;
65
    run_source.allow_adjacent_writes = 1;
66
 
67
    run_descriptor.put( run_source );
68
 
69
    generator_done.get(1);
70
    $display( "%0t: Run %0d done", $time(), run_num );
71
  end
72
 
73
  $display( "Done" );
74
  $stop();
75
end
76
 
77
////////////////////
78
// Data generator //
79
////////////////////
80
localparam EMPTY    = -999999;
81
 
82
int data_sequence[];
83
bit sign_sequence[];
84
bit disable_sequence[];
85
int address[];
86
 
87
int writes_per_iteration;
88
int iterations;
89
 
90
semaphore send_load;
91
semaphore send_run;
92
semaphore load_done;
93
semaphore run_done;
94
 
95
initial
96
begin
97
  generator_done = new();
98
  send_load      = new();
99
  send_run       = new();
100
 
101
  @(negedge rst);
102
 
103
  forever
104
  begin
105
    run run_dest;
106
 
107
    int array_len;
108
    bit start_over;
109
 
110
    run_descriptor.get( run_dest );
111
 
112
    writes_per_iteration = run_dest.connections_per_node*VN_DEPTH;
113
    iterations           = run_dest.iterations;
114
    array_len            = iterations*writes_per_iteration;
115
 
116
    data_sequence    = new[array_len];
117
    sign_sequence    = new[array_len];
118
    disable_sequence = new[array_len];
119
    address          = new[array_len];
120
 
121
    /////////////////////////////////////////////
122
    // Create data sequence for the entire run //
123
    /////////////////////////////////////////////
124
    start_over = 1;
125
 
126
    // assign random data and clear address array
127
    for( int i=0; i<=array_len; i++ )
128
    begin
129
      address[i]          = EMPTY;
130
      disable_sequence[i] =  0;//($random() %100 == 1);
131
 
132
      data_sequence[i] = { $random() } % (MAX_LLR+1);
133
      sign_sequence[i] = $random();
134
    end
135
 
136
    while( start_over )
137
    begin
138
      start_over = 0;
139
 
140
      for( int i=0; i<iterations; i++ )
141
      begin
142
        bit adjacent_write;
143
        int try_addr;
144
 
145
        int this_iteration_start;
146
 
147
        this_iteration_start = i*writes_per_iteration;
148
 
149
        adjacent_write   = 0;
150
        try_addr         = 0;
151
 
152
        for( int j=0; j<VN_DEPTH; j++ )
153
        begin
154
          for( int k=0; k<run_dest.connections_per_node; k++ )
155
          begin
156
            bit good_addr;
157
            bit good_run;
158
 
159
            int try_count;
160
            // Assign somewhat random order, but try to group addresses and
161
            // create "runs" of identical addresses
162
            try_count = 0;
163
            good_addr = 0;
164
 
165
            while( !good_addr && !start_over )
166
            begin
167
              int this_array_location;
168
              bit increment_search;
169
 
170
              try_count++;
171
              try_addr++;
172
 
173
              if( !adjacent_write )
174
              begin
175
                try_addr += run_dest.min_separation - 1;
176
                try_addr += { $random() } % 3;
177
              end
178
 
179
              try_addr            = try_addr % writes_per_iteration;
180
              this_array_location = this_iteration_start + try_addr;
181
 
182
              // test whether the selected locaiton is valid
183
              good_addr        = (address[this_array_location]==EMPTY);
184
              increment_search = !good_addr;
185
 
186
              // check whether nearby locations contain identical addresses.  A continuous
187
              // run of identical addresses is allowed
188
              good_run = run_dest.allow_adjacent_writes;
189
 
190
              for( int test_addr=this_array_location-1;
191
                   (test_addr >= this_array_location-run_dest.min_separation) &&
192
                   (test_addr >= this_iteration_start);
193
                   test_addr-- )
194
              begin
195
                bit matches1;
196
                matches1 = j==address[test_addr];
197
 
198
                good_run  = good_run & matches1;
199
                good_addr = good_addr & (!matches1 | good_run);
200
              end
201
 
202
              good_run = run_dest.allow_adjacent_writes;
203
 
204
              for( int test_addr=1;
205
                   (test_addr < run_dest.min_separation) &&
206
                   (this_array_location+test_addr < writes_per_iteration);
207
                   test_addr++ )
208
              begin
209
                bit matches2;
210
                matches2 = j==address[this_array_location+test_addr];
211
 
212
                good_run  = good_run & matches2;
213
                good_addr = good_addr & (!matches2 | good_run);
214
              end
215
 
216
              if( good_addr )
217
                adjacent_write = ({$random()}%3==2) & run_dest.allow_adjacent_writes;
218
              else // if random jump resulted in bad address, try next address
219
                adjacent_write = 1;
220
 
221
              // There's a chance we'll have to start all over due to impossible
222
              // placement.  Detect that here:
223
              if( !good_addr && (try_count==writes_per_iteration) )
224
              begin
225
                int it;
226
                int ad;
227
                int co;
228
                it = i;
229
                ad = j;
230
                co = k;
231
                $display( "Iteration %0d / %0d, address %0d / %0d, connection %0d / %0d - couldn't find good placement",
232
                          it, iterations, ad, VN_DEPTH, co, run_dest.connections_per_node );
233
                start_over = 1;
234
              end
235
 
236
              if( good_addr )
237
                address[this_array_location] = j;
238
            end
239
          end
240
        end
241
      end
242
    end
243
 
244
    // At this point, address and data_sequence contain valid data
245
    send_load.put(1);
246
    load_done.get(1);
247
    send_run.put(1);
248
    run_done.get(1);
249
 
250
    data_sequence.delete;
251
    sign_sequence.delete;
252
    disable_sequence.delete;
253
    address.delete;
254
 
255
    generator_done.put(1);
256
  end
257
end
258
 
259
////////////////////////////
260
// Load/unload transactor //
261
////////////////////////////
262
reg                   llr_access;
263
reg[7+FOLDFACTOR-1:0] llr_addr;
264
reg                   llr_din_we;
265
reg[LLRWIDTH-1:0]     llr_din;
266
 
267
wire[LLRWIDTH-1:0]    llr_dout;
268
 
269
initial
270
begin
271
  load_done = new();
272
 
273
  llr_access  <= 0;
274
  llr_addr    <= 0;
275
  llr_din_we  <= 0;
276
  llr_din     <= 0;
277
 
278
  @(negedge rst);
279
 
280
  forever
281
  begin
282
    send_load.get( 1 );
283
    @(posedge clk);
284
    llr_access <= #HOLD 1;
285
    repeat(2) @(posedge clk);
286
 
287
    // Fill in random data, in order.  Use data from data_sequence, since it's already
288
    // in the right format (-2**(LLRWIDTH-1) -1 .. 2**(LLRWIDTH-1) -1)
289
    for( int i=0; i<VN_DEPTH; i++ )
290
    begin
291
      llr_addr   <= #HOLD i;
292
      llr_din_we <= #HOLD 1;
293
 
294
      llr_din[LLRWIDTH-1]   <= #HOLD $random();
295
      llr_din[LLRWIDTH-2:0] <= #HOLD data_sequence[ {$random()} % (iterations*writes_per_iteration) ];
296
      @(posedge clk);
297
    end
298
 
299
    llr_access  <= #HOLD 0;
300
    llr_addr    <= #HOLD 0;
301
    llr_din_we  <= #HOLD 0;
302
    llr_din     <= #HOLD 0;
303
    repeat(MIN_SEPARATION) @(posedge clk);
304
 
305
    load_done.put( 1 );
306
  end
307
end
308
 
309
////////////////////////////////
310
// Message passing transactor //
311
////////////////////////////////
312
reg                   iteration;
313
reg                   first_half;
314
reg                   first_iteration;
315
reg                   we_vnmsg;
316
reg                   disable_paritymsg;
317
reg[7+FOLDFACTOR-1:0] addr_vn;
318
bit                   start_read;
319
 
320
reg[LLRWIDTH-1:0]  sh_msg;
321
wire[LLRWIDTH-1:0] vn_msg;
322
 
323
initial
324
begin
325
  run_done = new();
326
 
327
  iteration         <= 0;
328
  first_half        <= 0;
329
  first_iteration   <= 0;
330
  we_vnmsg          <= 0;
331
  disable_paritymsg <= 0;
332
  addr_vn           <= 0;
333
  sh_msg            <= 0;
334
  start_read        <= 0;
335
 
336
  @(negedge rst);
337
 
338
  forever
339
  begin
340
    send_run.get( 1 );
341
    @(posedge clk);
342
 
343
    // downstream
344
    for( int it=0; it<iterations; it++ )
345
    begin
346
      int base_offset;
347
      base_offset = it * writes_per_iteration;
348
 
349
      iteration <= #HOLD it[0];
350
 
351
      for( int half=0; half<2; half++ )
352
      begin
353
        first_half      <= #HOLD half==0;
354
        first_iteration <= #HOLD it==0;
355
        we_vnmsg        <= #HOLD half==1;
356
        start_read      <= #HOLD half==0;
357
 
358
        for( int i=0; i<writes_per_iteration; i++ )
359
        begin
360
          sh_msg[LLRWIDTH-1]   <= #HOLD sign_sequence[base_offset + i];
361
          sh_msg[LLRWIDTH-2:0] <= #HOLD data_sequence[base_offset + i];
362
          addr_vn              <= #HOLD address[base_offset + i];
363
          disable_paritymsg    <= #HOLD disable_sequence[base_offset + i];
364
          @(posedge clk);
365
        end
366
 
367
        we_vnmsg          <= #HOLD 0;
368
        start_read        <= #HOLD 0;
369
        repeat(2* MIN_SEPARATION) @(posedge clk);
370
      end
371
    end
372
 
373
    repeat(2) @(posedge clk);
374
    run_done.put( 1 );
375
  end
376
end
377
 
378
///////////////////////
379
// Model and checker //
380
///////////////////////
381
// Mimic intended behavior of VN
382
int llr_values[0:VN_DEPTH-1];
383
int msg_sums[0:VN_DEPTH-1];
384
int last_msgwrite_iteration[0:VN_DEPTH-1];
385
 
386
int predicted_llr_dout;
387
int predicted_vn_msg;
388
 
389
always @( posedge clk )
390
begin
391
  if( llr_access && llr_din_we )
392
  begin
393
    llr_values[llr_addr] = llr_din[LLRWIDTH-2:0];
394
    if( llr_din[LLRWIDTH-1] )
395
      llr_values[llr_addr] *= -1;
396
    msg_sums[llr_addr] = 0;
397
  end
398
 
399
  if( we_vnmsg & !disable_paritymsg )
400
  begin
401
    // clear messages on new iteration, and store current iteration
402
    if( last_msgwrite_iteration[addr_vn]!=iteration )
403
      msg_sums[addr_vn] = 0;
404
    last_msgwrite_iteration[addr_vn] = iteration;
405
 
406
    // add in new message
407
    if( sh_msg[LLRWIDTH-1] )
408
      msg_sums[addr_vn] = msg_sums[addr_vn] - sh_msg[LLRWIDTH-2:0];
409
    else
410
      msg_sums[addr_vn] = msg_sums[addr_vn] + sh_msg[LLRWIDTH-2:0];
411
 
412
    // Limit sum-of-messages value to a saturation level
413
    if( msg_sums[addr_vn]>MAX_INTERNAL_LLR )
414
      msg_sums[addr_vn] = MAX_INTERNAL_LLR;
415
    if( msg_sums[addr_vn]<-1 * MAX_INTERNAL_LLR )
416
      msg_sums[addr_vn] = -1 * MAX_INTERNAL_LLR;
417
  end
418
 
419
  // llr_dout is the sum of the original LLR and the sum of the messages
420
  predicted_llr_dout = llr_values[llr_addr] + msg_sums[llr_addr];
421
  if( predicted_llr_dout>MAX_LLR )
422
    predicted_llr_dout = MAX_LLR;
423
  if( predicted_llr_dout<-1 * MAX_LLR )
424
    predicted_llr_dout = -1 * MAX_LLR;
425
 
426
  // llr_dout is the sum of the original LLR and the sum of the messages
427
  predicted_vn_msg = llr_values[addr_vn] + msg_sums[addr_vn];
428
  if( predicted_vn_msg>MAX_LLR )
429
    predicted_vn_msg = MAX_LLR;
430
  if( predicted_vn_msg<-1 * MAX_LLR )
431
    predicted_vn_msg = -1 * MAX_LLR;
432
end
433
 
434
// Add latency and check behavior of VN
435
localparam LLR_DOUT_LATENCY = 6;
436
localparam VN_MSG_LATENCY   = 6;
437
 
438
int predicted_llr_dout_del[0:LLR_DOUT_LATENCY-2];
439
bit check_llr_dout_del[0:LLR_DOUT_LATENCY-2];
440
int predicted_vn_msg_del[0:VN_MSG_LATENCY-2];
441
bit check_vn_msg_del[0:VN_MSG_LATENCY-2];
442
 
443
int llr_dout_int;
444
int vn_msg_int;
445
 
446
always @( posedge rst, posedge clk )
447
  if( rst )
448
  begin
449
    for( int i=0; i<LLR_DOUT_LATENCY-1; i++ )
450
    begin
451
      predicted_llr_dout_del[i] <= EMPTY;
452
      check_llr_dout_del[i]     <= 0;
453
    end
454
    for( int i=0; i<VN_MSG_LATENCY-1; i++ )
455
    begin
456
      predicted_vn_msg_del[i] <= EMPTY;
457
      check_vn_msg_del[i]     <= 0;
458
    end
459
  end
460
  else
461
  begin
462
    predicted_llr_dout_del[0] <= predicted_llr_dout;
463
    check_llr_dout_del[0]     <= llr_access & ~llr_din_we;
464
 
465
    predicted_vn_msg_del[0] <= predicted_vn_msg;
466
    check_vn_msg_del[0]     <= start_read;
467
 
468
    for( int i=1; i<LLR_DOUT_LATENCY-1; i++ )
469
    begin
470
      predicted_llr_dout_del[i] <= predicted_llr_dout_del[i-1];
471
      check_llr_dout_del[i]     <= check_llr_dout_del[i-1];
472
    end
473
 
474
    for( int i=1; i<VN_MSG_LATENCY-1; i++ )
475
    begin
476
      predicted_vn_msg_del[i] <= predicted_vn_msg_del[i-1];
477
      check_vn_msg_del[i]     <= check_vn_msg_del[i-1];
478
    end
479
 
480
    llr_dout_int = llr_dout[LLRWIDTH-2:0];
481
    if( llr_dout[LLRWIDTH-1] )
482
      llr_dout_int *= -1;
483
 
484
    vn_msg_int = vn_msg[LLRWIDTH-2:0];
485
    if( vn_msg[LLRWIDTH-1] )
486
      vn_msg_int *= -1;
487
 
488
    if( check_llr_dout_del[LLR_DOUT_LATENCY-2] &&
489
        (predicted_llr_dout_del[LLR_DOUT_LATENCY-2]!=EMPTY) &&
490
        (predicted_llr_dout_del[LLR_DOUT_LATENCY-2]!=llr_dout_int) )
491
      $display( "%0t: Mismatch, predicted llr_dout != actual, %0d != %0d",
492
                $time(),
493
                predicted_llr_dout_del[LLR_DOUT_LATENCY-2],
494
                llr_dout_int );
495
 
496
    if( check_vn_msg_del[VN_MSG_LATENCY-2] &&
497
        (predicted_vn_msg_del[VN_MSG_LATENCY-2]!=EMPTY) &&
498
        (predicted_vn_msg_del[VN_MSG_LATENCY-2]!=vn_msg_int) )
499
      $display( "%0t: Mismatch, predicted vn_msg != actual, %0d != %0d",
500
                $time(),
501
                predicted_vn_msg_del[VN_MSG_LATENCY-2],
502
                vn_msg_int );
503
  end
504
 
505
///////////////
506
// DUT + RAM //
507
///////////////
508
wire[7+FOLDFACTOR-1:0] vnram_wraddr;
509
wire[7+FOLDFACTOR-1:0] vnram_rdaddr;
510
wire                   upmsg_we;
511
wire[2*LLRWIDTH+4:0]   upmsg_din;
512
wire[2*LLRWIDTH+4:0]   upmsg_dout;
513
 
514
ldpc_vn #(
515
  .FOLDFACTOR (FOLDFACTOR),
516
  .LLRWIDTH   (LLRWIDTH)
517
) ldpc_vn_i(
518
  .clk(clk),
519
  .rst(rst),
520
 
521
  // LLR I/O
522
  .llr_access( llr_access ),
523
  .llr_addr  ( llr_addr ),
524
  .llr_din_we( llr_din_we ),
525
  .llr_din   ( llr_din ),
526
  .llr_dout  ( llr_dout ),
527
 
528
  // message control
529
  .iteration        (iteration),
530
  .first_half       (first_half),
531
  .first_iteration  (first_iteration),
532
  .we_vnmsg         (we_vnmsg),
533
  .disable_paritymsg(disable_paritymsg),
534
  .addr_vn          (addr_vn),
535
 
536
  // message I/O
537
  .sh_msg(sh_msg),
538
  .vn_msg(vn_msg),
539
 
540
  // Attached RAM holds iteration number original LLR and message sum
541
  .vnram_wraddr(vnram_wraddr),
542
  .vnram_rdaddr(vnram_rdaddr),
543
  .upmsg_we    (upmsg_we),
544
  .upmsg_din   (upmsg_din),
545
  .upmsg_dout  (upmsg_dout)
546
);
547
 
548
ldpc_ram_behav #(
549
  .WIDTH    ( 2*LLRWIDTH+5 ),
550
  .LOG2DEPTH(7+FOLDFACTOR)
551
) ldpc_vn_rami (
552
  .clk   (clk),
553
  .we    (upmsg_we),
554
  .din   (upmsg_din),
555
  .wraddr(vnram_wraddr),
556
  .rdaddr(vnram_rdaddr),
557
  .dout  (upmsg_dout)
558
);
559
 
560
endmodule
561
 

powered by: WebSVN 2.1.0

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