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_ldpc_vcs.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_ldpc();
4
 
5
localparam CLK_PERIOD = 5ns;
6
localparam HOLD       = 1ns;
7
 
8
localparam SYMS_PER_EBN0 = 1;
9
localparam EBN0_MIN      = 0.6;
10
localparam EBN0_MAX      = 1.8;
11
localparam EBN0_STEP     = 0.2;
12
localparam CODE_TYPE     = "1_4";
13
 
14
localparam LLRWIDTH = 6;
15
 
16
//////////
17
// Clocks
18
//////////
19
logic clk;
20
logic rst;
21
 
22
initial
23
begin
24
  clk <= 1'b0;
25
  forever
26
    #(CLK_PERIOD /2) clk <= ~clk;
27
end
28
 
29
initial
30
begin
31
  rst <= 1'b1;
32
 
33
  repeat(3) @(posedge clk);
34
  rst <= #HOLD 1'b0;
35
end
36
 
37
// VCS was crashing with my old testbench, so I simplified dramatically and got rid of
38
// SystemVerilog classes
39
 
40
int debug_level = 0; // -1=no output, 0=report error, 1=display some info, 2=display lots
41
string label    = CODE_TYPE;
42
 
43
// Data
44
int n;
45
int k;
46
int q;
47
int word_width;
48
 
49
// Parity function
50
int h_defs_file;
51
int h_defs_height;
52
int h_defs_width;
53
int h_defs[];
54
 
55
// binary data
56
int orig_data[64800];
57
int coded_data[64800];
58
int decoded_data[64800];
59
 
60
// data after AWGN
61
real ebn0, N0;
62
real r[64800];
63
int  r_quantized[64800];
64
 
65
///////////////
66
// Functions
67
///////////////
68
function void encode();
69
  int parity_bits[];
70
 
71
  parity_bits = new[n-k];
72
 
73
  for( int rownum=0; rownum<h_defs_height; rownum++ )
74
    for( int colnum=0; colnum<h_defs_width; colnum++ )
75
    begin
76
      int base_position;
77
 
78
      base_position = h_defs[rownum*h_defs_width + colnum];
79
 
80
      if( base_position!=-1 )
81
        for( int local_offset=0; local_offset<360; local_offset++ )
82
        begin
83
          int parity_address;
84
          parity_address = (base_position + local_offset*q) % (n-k);
85
 
86
          parity_bits[parity_address] ^= orig_data[rownum*360 + local_offset];
87
        end
88
    end
89
 
90
  for( int parityloc=1; parityloc<n-k; parityloc++ )
91
    parity_bits[parityloc] ^= parity_bits[parityloc-1];
92
 
93
  // Copy input to output
94
  for( int j=0; j<n; j++ )
95
  begin
96
    if( j<k )
97
      coded_data[j] = -2*orig_data[j] +1;
98
    else
99
      coded_data[j] = -2*parity_bits[j-k] +1;
100
  end
101
 
102
  parity_bits.delete();
103
endfunction
104
 
105
// Add noise to coded data and store result in r
106
function void AddNoise( real ebn0db );
107
  real noisevec[64800];
108
  real rate;
109
 
110
  int  result_10000;
111
  int  stddev_10000;
112
 
113
  rate = (1.0*k)/ (1.0*n);
114
 
115
  N0 = 10.0**(-ebn0db/10.0) / rate / 2.0;
116
  $display( "RATE, N0 = %0f, %0f", rate, N0 );
117
  N0 *= 1.1; // match to C simulation noise
118
 
119
  genNoiseVec( noisevec );
120
 
121
  // print noise vector
122
  for( int j=0; j<n; j++ )
123
    if( debug_level>1 ) $display( "noise %d = %f", j, noisevec[j] );
124
 
125
  // add noise vector
126
  for( int j=0; j<n; j++ )
127
    r[j] = 1.0*coded_data[j] + noisevec[j];
128
 
129
  // Convert to LLR
130
  // Based on IT++: LLR=received * 4 / N0   (I don't know why)
131
  for( int i=0; i<n; i++ )
132
    r[i] *= 4.0 / N0;
133
endfunction
134
 
135
// Quantize LLR to a few bits
136
function void QuantizeLlr( int llr_bits );
137
  real MAXVAL;
138
  int table_range;
139
  real quant_table[2048]; // only 2*table_range is used!
140
 
141
  MAXVAL      = 12.0 / N0;
142
  table_range = 1<<(llr_bits-1);
143
 
144
  // build table
145
  for( int i=0; i<2*table_range; i++ )
146
  begin
147
    quant_table[i] = 0.5*i * MAXVAL / (1.0*table_range-1.0);
148
    //if( this.debug_level>0 ) $display( "quant table[%0d] = %0f", i, quant_table[i] );
149
  end
150
 
151
  // find correct place in table for all values
152
  for( int i=0; i<n; i++ )
153
  begin
154
    int orig_sign;
155
    int j;
156
 
157
    orig_sign = r[i] < 0.0 ? -1 : 1;
158
    j=2*table_range-1;
159
 
160
    while( (r[i]*orig_sign) < quant_table[j] )
161
      j--;
162
 
163
    j = j>>1;
164
 
165
    r_quantized[i] = orig_sign * j;
166
  end
167
 
168
  if( debug_level>1 )
169
    for( int i=0; i<10; i++ )
170
      $display( "%0d --> %0d --> %0f --> %0d", orig_data[i], coded_data[i], r[i], r_quantized[i] );
171
endfunction
172
 
173
// Compare signs of r_quantized and coded_data to return number of errors
174
function int CountOrigErrs();
175
  CountOrigErrs = 0;
176
 
177
  for( int i=0; i<n; i++ )
178
    if( ((r_quantized[i]<0)  && (coded_data[i]>=0)) ||
179
        ((r_quantized[i]>=0) && (coded_data[i]<0)) )
180
      CountOrigErrs++;
181
endfunction
182
 
183
// Compare signs of r_quantized and coded_data to return number of errors after decode
184
function int CountDecodedErrs();
185
  CountDecodedErrs = 0;
186
 
187
  for( int i=0; i<n; i++ )
188
    if( ((decoded_data[i]<0)  && (coded_data[i]>=0)) ||
189
        ((decoded_data[i]>=0) && (coded_data[i]<0)) )
190
      CountDecodedErrs++;
191
endfunction
192
 
193
function void genNoiseVec( output real result[64800] );
194
  string filename = { "noise_", CODE_TYPE, ".txt" };
195
  real rand_noise_vec[10000];
196
  int noise_file = $fopen( filename, "r" );
197
  int check_eof;
198
 
199
  for( int i=0; i<10000; i++ )
200
    check_eof = $fscanf( noise_file, "%f", rand_noise_vec[i] );
201
 
202
  for( int i=0; i<68000; i++ )
203
    result[i] = rand_noise_vec[ { $random() } % 64800  ];
204
 
205
  $fclose( noise_file );
206
endfunction
207
 
208
 
209
 
210
 
211
//////////////////////////
212
// Read matrix from file
213
//////////////////////////
214
// Variables for file input
215
int found_target;
216
string    oneline;
217
string    locallabel;
218
int       temp_i;
219
 
220
initial
221
begin
222
  if( debug_level>0 )
223
    $display( "Creating object" );
224
 
225
  // H is a sparse matrix. The location of each one is stored as an integer.
226
  // -1 is used to represent unused memory locations.
227
  h_defs_file = $fopen( "dvbs2_hdef.txt", "r" );
228
 
229
  if( !h_defs_file )
230
    $stop( "File dvbs2_hdef.txt not found\n" );
231
  h_defs_width  = 30;
232
 
233
  found_target = 0;
234
 
235
  while( !found_target )
236
  begin
237
    temp_i = $fgets( oneline, h_defs_file );
238
    temp_i = $sscanf( oneline, "label %s lines %d n %d q %d", locallabel, h_defs_height, n, q );
239
 
240
    if( label==locallabel )
241
      found_target = 1;
242
    else // discard this group
243
      for( int linenum=0; linenum<h_defs_height; linenum++ )
244
        temp_i = $fgets( oneline, h_defs_file );
245
 
246
    if( $feof(h_defs_file) )
247
    begin
248
      $fclose(h_defs_file);
249
      $stop( "Didn't find requested code type!" );
250
    end
251
  end
252
 
253
  // at this point, the label has been found and the file pointer is at the correct position
254
  h_defs = new[h_defs_height*h_defs_width];
255
 
256
  // fill array with -1
257
  for( int hdef_pos=0; hdef_pos<h_defs_height*h_defs_width; hdef_pos++ )
258
    h_defs[hdef_pos] = -1;
259
 
260
  // put correct values in array
261
  for( int linenum=0; linenum<h_defs_height; linenum++ )
262
  begin
263
    int eol;
264
    string c;
265
    string onechar;
266
    string oneword;
267
    int word_offset;
268
 
269
    eol         = 0;
270
    oneword     = "";
271
    word_offset = 0;
272
 
273
    while( !$feof(h_defs_file) && !eol )
274
    begin
275
      c       = $fgetc( h_defs_file );
276
      // onechar = (string)c;
277
      eol     = (c=="\n");
278
      oneword = { oneword, c };
279
 
280
      if( eol || (c==" ") )
281
      begin
282
        temp_i = $sscanf( oneword, "%d", h_defs[linenum*h_defs_width + word_offset] );
283
 
284
        word_offset = word_offset + 1;
285
        oneword     = "";
286
      end
287
    end
288
  end
289
 
290
  $fclose(h_defs_file);
291
 
292
  k = n - 360*q;
293
end
294
 
295
//////////////
296
// Transactors
297
//////////////
298
// Load data into LLR
299
// LLR I/O
300
logic      llr_access;
301
logic[7:0] llr_addr;
302
logic      llr_din_we;
303
logic[LLRWIDTH-1:0] llr_din;
304
bit signed[LLRWIDTH-1:0]  llr_dout;
305
 
306
// start command; completion indicator
307
logic      start;
308
logic[4:0] mode;
309
logic[5:0] iter_limit;
310
bit        done;
311
 
312
initial
313
begin
314
  debug_level = 0;
315
 
316
  llr_access  <= 0;
317
  llr_addr    <= 0;
318
  llr_din_we  <= 0;
319
  llr_din     <= 0;
320
  start       <= 0;
321
  mode        <= 0;
322
  iter_limit  <= 30;
323
 
324
  @( posedge rst );
325
  repeat( 5 ) @( posedge clk );
326
 
327
  for( real ebn0dB=EBN0_MIN; ebn0dB<EBN0_MAX; ebn0dB+=EBN0_STEP )
328
  begin
329
    int err_bits    = 0;
330
    int tested_bits = 0;
331
    real ber_result;
332
 
333
    err_bits    = 0;
334
    tested_bits = 0;
335
 
336
    //for( int symnum=0; symnum<SYMS_PER_EBN0; symnum++ )
337
    while( (err_bits<1000) && (tested_bits<1000000) )
338
    begin
339
      // create random data
340
      for( int i=0; i<k; i++ )
341
        orig_data[i] = {$random()} % 2;
342
 
343
      encode();
344
 
345
      AddNoise( ebn0dB );
346
      QuantizeLlr( LLRWIDTH );
347
 
348
      // begin testing DUT
349
      llr_access <= 1;
350
      @(posedge clk);
351
 
352
      // write normal data bits
353
      for( int i=0; i<k; i++ )
354
      begin
355
        int wr_val;
356
        int abs_wr_val;
357
 
358
        wr_val = r_quantized[i];
359
        abs_wr_val = wr_val < 0 ? -1*wr_val : wr_val;
360
 
361
        llr_addr   <= #HOLD i/360;
362
        llr_din_we <= #HOLD (i%360)==359;
363
        llr_din    <= #HOLD (wr_val<0) ? { 1'b1, abs_wr_val[LLRWIDTH-2:0] }
364
                                       : { 1'b0, abs_wr_val[LLRWIDTH-2:0] };
365
        @( posedge clk );
366
      end
367
 
368
      // write parity bits
369
      for( int i=0; i<(n-k); i++ )
370
      begin
371
        int rotate_pos;
372
        int wr_val;
373
        int abs_wr_val;
374
 
375
        rotate_pos = k + (i/360) + ((i%360)*q);
376
 
377
        llr_addr   <= #HOLD (k + i)/360;
378
        llr_din_we <= #HOLD (i%360)==359;
379
 
380
        wr_val = r_quantized[rotate_pos];
381
        abs_wr_val = wr_val < 0 ? -1*wr_val : wr_val;
382
 
383
        llr_din    <= #HOLD (wr_val<0) ? { 1'b1, abs_wr_val[LLRWIDTH-2:0] }
384
                                       : { 1'b0, abs_wr_val[LLRWIDTH-2:0] };
385
        @( posedge clk );
386
      end
387
 
388
      llr_din_we <= #HOLD 0;
389
      llr_access <= #HOLD 0;
390
      @( posedge clk );
391
 
392
      //controls
393
      start <= #HOLD 1;
394
 
395
      case( CODE_TYPE )
396
        "1_4":    mode <= #HOLD 0;
397
        "1_3":    mode <= #HOLD 1;
398
        "2_5":    mode <= #HOLD 2;
399
        "1_2":    mode <= #HOLD 3;
400
        "3_5":    mode <= #HOLD 4;
401
        "2_3":    mode <= #HOLD 5;
402
        "3_4":    mode <= #HOLD 6;
403
        "4_5":    mode <= #HOLD 7;
404
        "5_6":    mode <= #HOLD 8;
405
        "8_9":    mode <= #HOLD 9;
406
        "9_10":   mode <= #HOLD 10;
407
        "1_5s":   mode <= #HOLD 11;
408
        "1_3s":   mode <= #HOLD 12;
409
        "2_5s":   mode <= #HOLD 13;
410
        "4_9s":   mode <= #HOLD 14;
411
        "3_5s":   mode <= #HOLD 15;
412
        "2_3s":   mode <= #HOLD 16;
413
        "11_15s": mode <= #HOLD 17;
414
        "7_9s":   mode <= #HOLD 18;
415
        "37_45s": mode <= #HOLD 19;
416
        "8_9s":   mode <= #HOLD 20;
417
        default: $stop( "Illegal code type!" );
418
      endcase
419
      @( posedge clk );
420
      start <= #HOLD 0;
421
      @( posedge clk );
422
 
423
      // read data out
424
      @(posedge done);
425
      @(posedge clk);
426
 
427
      llr_addr   <= #HOLD 0;
428
      llr_access <= #HOLD 1;
429
      @(posedge clk);
430
 
431
      // read normal data bits
432
      for( int i=0; i<k; i++ )
433
      begin
434
        int result;
435
 
436
        if( (i%360)==0 )
437
        begin
438
          llr_addr   <= #HOLD i/360;
439
          repeat(2) @(posedge clk);
440
          llr_din_we <= #HOLD 1; //load up from RAM
441
          @( posedge clk );
442
          llr_din_we <= #HOLD 0;
443
          @( posedge clk );
444
        end
445
 
446
        llr_din <= #HOLD { LLRWIDTH{1'bX} };
447
 
448
        result = llr_dout[LLRWIDTH-1] ? -1 * llr_dout[LLRWIDTH-2:0]
449
                                      : llr_dout[LLRWIDTH-2:0];
450
        decoded_data[i] = result;
451
        //if( i<10 ) $display( "After decode: pos=%0d, result=%0d", i, result );
452
        @( posedge clk );
453
      end
454
 
455
      $display( "Begin read parity bits" );
456
      // read parity bits
457
      for( int i=0; i<(n-k); i++ )
458
      begin
459
        int result;
460
        int rotate_pos;
461
 
462
        if( ((k + i)%360)==0 )
463
        begin
464
          llr_addr <= #HOLD (k + i)/360;
465
          repeat(2) @(posedge clk);
466
          llr_din_we <= #HOLD 1; //load up from RAM
467
          @( posedge clk );
468
          llr_din_we <= #HOLD 0;
469
          @( posedge clk );
470
        end
471
 
472
        rotate_pos = k + (i/360) + ((i%360)*q);
473
 
474
        llr_din    <= #HOLD { LLRWIDTH{1'bX} };
475
 
476
        result = llr_dout[LLRWIDTH-1] ? -1 * llr_dout[LLRWIDTH-2:0]
477
                                      : llr_dout[LLRWIDTH-2:0];
478
        decoded_data[rotate_pos] = result;
479
        @( posedge clk );
480
      end
481
 
482
      llr_din_we <= #HOLD 0;
483
      llr_access <= #HOLD 0;
484
      @( posedge clk );
485
 
486
      tested_bits += 64800;
487
      err_bits    += CountDecodedErrs();
488
    end
489
 
490
    $write( "EbN0 = %0fdB: ", ebn0dB );
491
    ber_result = 1.0*err_bits / (1.0*tested_bits);
492
    $write( "%0d errs / %0d bits ==> BER = %0f\n", err_bits, tested_bits, ber_result );
493
  end
494
 
495
  h_defs.delete();
496
  $finish();
497
end
498
 
499
////////////
500
// Instance
501
////////////
502
ldp_top ldp_top_i(
503
  .clk(clk),
504
  .rst(rst),
505
 
506
  .llr_access (llr_access),
507
  .llr_addr   (llr_addr),
508
  .llr_din_we (llr_din_we),
509
  .llr_din    (llr_din),
510
  .llr_dout   (llr_dout),
511
 
512
  .start     (start),
513
  .mode      (mode),
514
  .iter_limit(iter_limit),
515
  .done      (done)
516
);
517
 
518
endmodule

powered by: WebSVN 2.1.0

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