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

Details | Compare with Previous | View Log

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

powered by: WebSVN 2.1.0

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