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

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 2 jcorley
//-------------------------------------------------------------------------
2
//
3
// File name    :  ldpc_cn.v
4
// Title        :
5
//              :
6
// Purpose      : Check node holder/message calculator.  Stores the sign
7
//              : of each received message, along with
8
//
9
// ----------------------------------------------------------------------
10
// Revision History :
11
// ----------------------------------------------------------------------
12
//   Ver  :| Author   :| Mod. Date   :| Changes Made:
13
//   v1.0  | JTC      :| 2008/07/02  :|
14
// ----------------------------------------------------------------------
15
`timescale 1ns/10ps
16
 
17
module ldpc_cn #(
18
  parameter FOLDFACTOR     = 1,
19
  parameter LLRWIDTH       = 6
20
)(
21
  input clk,
22
  input rst,
23
 
24
  // clear RAM iteration count at start-up
25
  input      llr_access,
26
  input[7:0] llr_addr,
27
  input      llr_din_we,
28
 
29
  // message I/O
30
  input                   iteration,         // toggle each iteration
31
  input                   first_half,
32
  input                   first_iteration,   // don't need to subtract-off previous message!
33
  input                   cn_we,
34
  input                   cn_rd,
35
  input                   disable_cn, // parity mix disables one node
36
  input[7+FOLDFACTOR-1:0] addr_cn,
37
  input[LLRWIDTH-1:0]     sh_msg,
38
  output[LLRWIDTH-1:0]    cn_msg,
39
 
40
  // Attached MSG RAM, 135xMSG_WIDTH
41
  output                         dnmsg_we,
42
  output[7+FOLDFACTOR-1:0]       dnmsg_wraddr,
43
  output[7+FOLDFACTOR-1:0]       dnmsg_rdaddr,
44
  output[17+4*(LLRWIDTH-1)+31:0] dnmsg_din,
45
  input[17+4*(LLRWIDTH-1)+31:0]  dnmsg_dout
46
);
47
 
48
// Detect illegal writes
49
// synthesis translate_off
50
integer accesses[0:5];
51
reg     a_run;
52
integer temp_loopvar;
53
 
54
always @( posedge rst, posedge clk )
55
  if( rst )
56
    for( temp_loopvar=0; temp_loopvar<6; temp_loopvar=temp_loopvar+1 )
57
      accesses[temp_loopvar] = -1;
58
  else
59
  begin
60
    for( temp_loopvar=5; temp_loopvar>0; temp_loopvar=temp_loopvar-1 )
61
    begin
62
      accesses[temp_loopvar] = accesses[temp_loopvar-1];
63
      if( !(cn_we|cn_rd) )
64
        accesses[0] = -1;
65
      else
66
        accesses[0] = addr_cn;
67
    end
68
 
69
    a_run = 1;
70
 
71
    for( temp_loopvar=1; temp_loopvar<6; temp_loopvar=temp_loopvar+1 )
72
    begin
73
      a_run = a_run & (accesses[temp_loopvar]==addr_cn);
74
      if( !a_run && (cn_we|cn_rd) && (accesses[temp_loopvar]==addr_cn) )
75
        $display( "%0t: Bad access, addresses %0d", $time(), addr_cn );
76
     end
77
  end
78
// synthesis translate_on
79
 
80
assign dnmsg_rdaddr = llr_access ? llr_addr : addr_cn;
81
 
82
/***********************************
83
 * Calc message/update message RAM *
84
 * Combine 1's complement numbers  *
85
 * Saturate to one bit fewer than  *
86
 * input width                     *
87
 ***********************************/
88
function[LLRWIDTH-1:0] SubSaturate( input[LLRWIDTH-1:0] a,
89
                                    input[LLRWIDTH-1:0] b );
90
  reg[LLRWIDTH-1:0] sum;
91
  reg[LLRWIDTH-2:0] diffa;
92
  reg[LLRWIDTH-2:0] diffb;
93
  reg[LLRWIDTH-3:0] sat_sum;
94
  reg[LLRWIDTH-3:0] sat_diffa;
95
  reg[LLRWIDTH-3:0] sat_diffb;
96
  reg               add;
97
  reg               b_big;
98
  reg               sign;
99
  reg[LLRWIDTH-1:0] result;
100
begin
101
  // basic calculations
102
  sum   = {1'b0, a[LLRWIDTH-2:0]} + {1'b0, b[LLRWIDTH-2:0]};
103
  diffa = a[LLRWIDTH-2:0] - b[LLRWIDTH-2:0];
104
  diffb = b[LLRWIDTH-2:0] - a[LLRWIDTH-2:0];
105
 
106
  // saturate
107
  if( sum[LLRWIDTH-1:LLRWIDTH-2]!=2'b00  )
108
    sat_sum = { (LLRWIDTH-2){1'b1} };
109
  else
110
    sat_sum = sum[LLRWIDTH-3:0];
111
 
112
  if( diffa[LLRWIDTH-2]  )
113
    sat_diffa = { (LLRWIDTH-2){1'b1} };
114
  else
115
    sat_diffa = diffa[LLRWIDTH-3:0];
116
 
117
  if( diffb[LLRWIDTH-2]  )
118
    sat_diffb = { (LLRWIDTH-2){1'b1} };
119
  else
120
    sat_diffb = diffb[LLRWIDTH-3:0];
121
 
122
  // control bits
123
  add   = a[LLRWIDTH-1]!=b[LLRWIDTH-1];
124
  b_big = a[LLRWIDTH-2:0]<b[LLRWIDTH-2:0];
125
  sign  = b_big ? ~b[LLRWIDTH-1] : a[LLRWIDTH-1];
126
 
127
  if( add )
128
    result = { sign, 1'b0, sat_sum };
129
  else if( b_big )
130
    result = { sign, 1'b0, sat_diffb };
131
  else
132
    result = { sign, 1'b0, sat_diffa };
133
 
134
  SubSaturate = result;
135
end
136
endfunction
137
 
138
/**************************************
139
 * Align some signals with RAM output *
140
 **************************************/
141
localparam RAM_LATENCY = 2;
142
 
143
integer loopvar1;
144
 
145
reg                   cn_rd_del[0:RAM_LATENCY-1];
146
reg                   cn_we_del[0:RAM_LATENCY-1];
147
reg[LLRWIDTH-1:0]     sh_msg_del[0:RAM_LATENCY-1];
148
reg[7+FOLDFACTOR-1:0] addr_cn_del[0:RAM_LATENCY-1];
149
 
150
reg repeat_access;
151
 
152
wire                   cn_rd_aligned_ram;
153
wire                   cn_we_aligned_ram;
154
wire[LLRWIDTH-1:0]     sh_msg_aligned_ram;
155
wire[7+FOLDFACTOR-1:0] addr_cn_aligned_ram;
156
 
157
assign cn_rd_aligned_ram   = cn_rd_del[RAM_LATENCY-1];
158
assign cn_we_aligned_ram   = cn_we_del[RAM_LATENCY-1];
159
assign sh_msg_aligned_ram  = sh_msg_del[RAM_LATENCY-1];
160
assign addr_cn_aligned_ram = addr_cn_del[RAM_LATENCY-1];
161
 
162
always @( posedge rst, posedge clk )
163
  if( rst )
164
  begin
165
    for( loopvar1=0; loopvar1<RAM_LATENCY; loopvar1=loopvar1+1 )
166
    begin
167
      cn_rd_del[loopvar1]   <= 0;
168
      cn_we_del[loopvar1]   <= 0;
169
      sh_msg_del[loopvar1]  <= 0;
170
      addr_cn_del[loopvar1] <= 0;
171
    end
172
    repeat_access <= 0;
173
  end
174
  else
175
  begin
176
    cn_rd_del[0]   <= cn_rd & ~disable_cn;
177
    cn_we_del[0]   <= cn_we & ~disable_cn;
178
    sh_msg_del[0]  <= sh_msg;
179
    addr_cn_del[0] <= addr_cn;
180
 
181
    for( loopvar1=1; loopvar1<RAM_LATENCY; loopvar1=loopvar1+1 )
182
    begin
183
      cn_rd_del[loopvar1]   <= cn_rd_del[loopvar1 -1];
184
      cn_we_del[loopvar1]   <= cn_we_del[loopvar1 -1];
185
      sh_msg_del[loopvar1]  <= sh_msg_del[loopvar1 -1];
186
      addr_cn_del[loopvar1] <= addr_cn_del[loopvar1 -1];
187
    end
188
 
189
    repeat_access <= (addr_cn_del[RAM_LATENCY-1]==addr_cn_del[RAM_LATENCY-2]) &&
190
                     ((cn_we_del[RAM_LATENCY-1] && cn_we_del[RAM_LATENCY-2]) ||
191
                      (cn_rd_del[RAM_LATENCY-1] && cn_rd_del[RAM_LATENCY-2]));
192
  end
193
 
194
/****************************
195
 * Pipe stage 0:            *
196
 * Register bits out of RAM *
197
 ****************************/
198
wire start_over;
199
wire switch_up;
200
 
201
reg[4:0]          old_leastpos;
202
reg[4:0]          old_last_leastpos;
203
reg               old_sign_result;
204
reg[4:0]          old_count;
205
reg[LLRWIDTH-2:0] old_least_llr;
206
reg[LLRWIDTH-2:0] old_nextleast_llr;
207
reg[LLRWIDTH-2:0] old_last_least_llr;
208
reg[LLRWIDTH-2:0] old_last_nextleast_llr;
209
reg               old_last_sign_result;
210
reg[29:0]         old_signs;
211
 
212
reg[LLRWIDTH-1:0] sh_msg_aligned_old;
213
reg               start_over_aligned_old;
214
reg               repeat_access_aligned_old;
215
reg               cn_we_aligned_old;
216
 
217
// restart calculations and count if RAM's iteration != controller's iteration
218
assign start_over = (iteration!=dnmsg_dout[0]) & !repeat_access;
219
 
220
// restart count when switching from downstream to upstream messages
221
assign switch_up  = ~first_half & ~dnmsg_dout[1] & !repeat_access;
222
 
223
always @( posedge clk, posedge rst )
224
  if( rst )
225
  begin
226
    old_count                 <= 0;
227
    old_leastpos              <= 0;
228
    old_last_leastpos         <= 0;
229
    old_sign_result           <= 0;
230
    old_least_llr             <= 0;
231
    old_nextleast_llr         <= 0;
232
    old_last_least_llr        <= 0;
233
    old_last_nextleast_llr    <= 0;
234
    old_last_sign_result      <= 0;
235
    old_signs                 <= 0;
236
    sh_msg_aligned_old        <= 0;
237
    start_over_aligned_old    <= 0;
238
    cn_we_aligned_old         <= 0;
239
    repeat_access_aligned_old <= 0;
240
  end
241
  else
242
  begin
243
    if( repeat_access )
244
      old_count <= old_count + 1;
245
    else
246
      old_count <= (start_over | switch_up) ? 0 : dnmsg_dout[16:12];
247
 
248
    old_leastpos           <= dnmsg_dout[6:2];
249
    old_last_leastpos      <= dnmsg_dout[11:7];
250
    old_least_llr          <= dnmsg_dout[16 +1*(LLRWIDTH-1) -: LLRWIDTH-1];
251
    old_nextleast_llr      <= dnmsg_dout[16 +2*(LLRWIDTH-1) -: LLRWIDTH-1];
252
    old_last_least_llr     <= dnmsg_dout[16 +3*(LLRWIDTH-1) -: LLRWIDTH-1];
253
    old_last_nextleast_llr <= dnmsg_dout[16 +4*(LLRWIDTH-1) -: LLRWIDTH-1];
254
    old_sign_result        <= dnmsg_dout[16 +4*(LLRWIDTH-1)+1];
255
    old_last_sign_result   <= dnmsg_dout[16 +4*(LLRWIDTH-1)+2];
256
    old_signs              <= dnmsg_dout[16 +4*(LLRWIDTH-1)+32 -: 30];
257
 
258
    sh_msg_aligned_old        <= sh_msg_aligned_ram;
259
    start_over_aligned_old    <= start_over;
260
    cn_we_aligned_old         <= cn_we_aligned_ram;
261
    repeat_access_aligned_old <= repeat_access;
262
  end
263
 
264
/***************************
265
 * Pipe 1a:                *
266
 * Create outgoing message *
267
 ***************************/
268
reg[LLRWIDTH-1:0] cn_msg_int;
269
 
270
assign cn_msg = cn_msg_int;
271
 
272
always @( posedge rst, posedge clk )
273
  if( rst )
274
    cn_msg_int <= 0;
275
  else
276
  begin
277
    // sign val
278
    cn_msg_int[LLRWIDTH-1] <= old_sign_result ^ old_signs[old_count];
279
 
280
    // min result
281
    if( old_count==old_leastpos )
282
      cn_msg_int[LLRWIDTH-2:0] <= old_nextleast_llr;
283
    else
284
      cn_msg_int[LLRWIDTH-2:0] <= old_least_llr;
285
  end
286
 
287
/****************************************************************
288
 * Pipe stage 1b:                                               *
289
 * Calculate fixed_msg = downlink message - last uplink message *
290
 ****************************************************************/
291
wire[LLRWIDTH-1:0] offset_val;
292
reg[LLRWIDTH-1:0]  fixed_msg;
293
 
294
reg[LLRWIDTH-2:0] old_least_llr_del;
295
reg[LLRWIDTH-2:0] old_nextleast_llr_del;
296
reg[4:0]          old_count_del;
297
reg[4:0]          old_leastpos_del;
298
reg[29:0]         old_signs_del;
299
reg               old_sign_result_del;
300
reg               old_last_sign_result_del;
301
reg[4:0]          old_last_leastpos_del;
302
reg[LLRWIDTH-2:0] old_last_least_llr_del;
303
reg[LLRWIDTH-2:0] old_last_nextleast_llr_del;
304
 
305
reg start_over_aligned_msg;
306
reg cn_we_aligned_msg;
307
reg repeat_access_aligned_msg;
308
 
309
assign offset_val = first_iteration ? 0
310
                      : (old_count==old_last_leastpos) ? { old_last_sign_result^old_signs[old_count], old_last_nextleast_llr }
311
                        : { old_last_sign_result^old_signs[old_count], old_last_least_llr };
312
 
313
always @( posedge rst, posedge clk )
314
  if( rst )
315
  begin
316
    fixed_msg                  <= 0;
317
    old_least_llr_del          <= 0;
318
    old_nextleast_llr_del      <= 0;
319
    old_count_del              <= 0;
320
    old_leastpos_del           <= 0;
321
    old_signs_del              <= 0;
322
    old_sign_result_del        <= 0;
323
    old_last_sign_result_del   <= 0;
324
    old_last_leastpos_del      <= 0;
325
    old_last_least_llr_del     <= 0;
326
    old_last_nextleast_llr_del <= 0;
327
    start_over_aligned_msg     <= 0;
328
    cn_we_aligned_msg          <= 0;
329
    repeat_access_aligned_msg  <= 0;
330
  end
331
  else
332
  begin
333
    fixed_msg <= SubSaturate( sh_msg_aligned_old, offset_val );
334
 
335
    old_least_llr_del     <= old_least_llr;
336
    old_nextleast_llr_del <= old_nextleast_llr;
337
    old_leastpos_del      <= old_leastpos;
338
    old_signs_del         <= old_signs;
339
    old_sign_result_del   <= old_sign_result;
340
 
341
    old_last_sign_result_del   <= old_last_sign_result;
342
    old_last_leastpos_del      <= old_last_leastpos;
343
    old_last_least_llr_del     <= old_last_least_llr;
344
    old_last_nextleast_llr_del <= old_last_nextleast_llr;
345
 
346
    old_count_del <= old_count;
347
 
348
    start_over_aligned_msg    <= start_over_aligned_old;
349
    cn_we_aligned_msg         <= cn_we_aligned_old;
350
    repeat_access_aligned_msg <= repeat_access_aligned_old;
351
  end
352
 
353
/*******************************************
354
 * Pipe stage 2:                           *
355
 * Calculate new values for RAM write-back *
356
 *******************************************/
357
reg               new_iteration;
358
reg               new_up;
359
reg[4:0]          new_leastpos;
360
reg               new_last_sign_result;
361
reg[4:0]          new_last_leastpos;
362
reg[29:0]         new_signs;
363
reg               new_sign_result;
364
reg[4:0]          new_count;
365
reg[LLRWIDTH-2:0] new_least_llr;
366
reg[LLRWIDTH-2:0] new_nextleast_llr;
367
reg[LLRWIDTH-2:0] new_last_least_llr;
368
reg[LLRWIDTH-2:0] new_last_nextleast_llr;
369
 
370
wire[LLRWIDTH-2:0] muxed_least_llr;
371
wire[LLRWIDTH-2:0] muxed_nextleast_llr;
372
wire new_winner;
373
wire new_2nd;
374
 
375
assign muxed_least_llr     = repeat_access_aligned_msg ? new_least_llr[LLRWIDTH-2:0]
376
                                                       : old_least_llr_del[LLRWIDTH-2:0];
377
assign muxed_nextleast_llr = repeat_access_aligned_msg ? new_nextleast_llr[LLRWIDTH-2:0]
378
                                                       : old_nextleast_llr_del[LLRWIDTH-2:0];
379
 
380
assign new_winner = (fixed_msg[LLRWIDTH-2:0] < muxed_least_llr[LLRWIDTH-2:0]);
381
assign new_2nd    = ((fixed_msg[LLRWIDTH-2:0] <= muxed_nextleast_llr[LLRWIDTH-2:0])
382
                      & ~new_winner);
383
 
384
always @( posedge rst, posedge clk )
385
  if( rst )
386
  begin
387
    new_iteration          <= 0;
388
    new_up                 <= 0;
389
    new_count              <= 0;
390
    new_leastpos           <= 0;
391
    new_least_llr          <= 0;
392
    new_nextleast_llr      <= 0;
393
    new_signs              <= 0;
394
    new_sign_result        <= 0;
395
    new_last_sign_result   <= 0;
396
    new_last_leastpos      <= 0;
397
    new_last_least_llr     <= 0;
398
    new_last_nextleast_llr <= 0;
399
  end
400
  else
401
  begin
402
    new_iteration <= iteration | llr_din_we;
403
    new_up        <= ~first_half;
404
    new_count     <= old_count_del + 1;
405
 
406
    // assign new smallest LLR
407
    if( !repeat_access_aligned_msg )
408
    begin
409
      new_signs         <= old_signs_del;
410
      new_leastpos      <= old_leastpos_del;
411
      new_least_llr     <= old_least_llr_del;
412
      new_nextleast_llr <= old_nextleast_llr_del;
413
      new_sign_result   <= old_sign_result_del;
414
    end
415
 
416
    if( cn_we_aligned_msg )
417
    begin
418
      // note: only assigning one bit - others stay at old value
419
      new_signs[old_count_del] <= fixed_msg[LLRWIDTH-1];
420
 
421
      if( new_winner | start_over_aligned_msg )
422
      begin
423
        new_leastpos  <= old_count_del;
424
        new_least_llr <= fixed_msg[LLRWIDTH-2:0];
425
      end
426
 
427
      if( start_over_aligned_msg )
428
        new_nextleast_llr <= { (LLRWIDTH-1){1'b1} };
429
      else if( new_winner && repeat_access_aligned_msg )
430
        new_nextleast_llr <= new_least_llr;
431
      else if( new_winner )
432
        new_nextleast_llr <= old_least_llr_del;
433
      else if( new_2nd )
434
        new_nextleast_llr <= fixed_msg[LLRWIDTH-2:0];
435
 
436
      if( start_over_aligned_msg )
437
        new_sign_result <= fixed_msg[LLRWIDTH-1];
438
      else if( repeat_access_aligned_msg )
439
        new_sign_result <= new_sign_result ^ fixed_msg[LLRWIDTH-1];
440
      else
441
        new_sign_result <= old_sign_result_del ^ fixed_msg[LLRWIDTH-1];
442
    end
443
 
444
    // store old downstream results during upstream messages
445
    new_last_sign_result   <= first_half ? old_last_sign_result_del   : old_sign_result_del;
446
    new_last_leastpos      <= first_half ? old_last_leastpos_del      : old_leastpos_del;
447
    new_last_least_llr     <= first_half ? old_last_least_llr_del     : old_least_llr_del;
448
    new_last_nextleast_llr <= first_half ? old_last_nextleast_llr_del : old_nextleast_llr_del;
449
  end
450
 
451
assign dnmsg_din[0]                                = new_iteration;
452
assign dnmsg_din[1]                                = new_up;
453
assign dnmsg_din[6:2]                              = new_leastpos;
454
assign dnmsg_din[11:7]                             = new_last_leastpos;
455
assign dnmsg_din[16:12]                            = new_count;
456
assign dnmsg_din[16+ 1*(LLRWIDTH-1) -: LLRWIDTH-1] = new_least_llr;
457
assign dnmsg_din[16+ 2*(LLRWIDTH-1) -: LLRWIDTH-1] = new_nextleast_llr;
458
assign dnmsg_din[16+ 3*(LLRWIDTH-1) -: LLRWIDTH-1] = new_last_least_llr;
459
assign dnmsg_din[16+ 4*(LLRWIDTH-1) -: LLRWIDTH-1] = new_last_nextleast_llr;
460
assign dnmsg_din[16+ 4*(LLRWIDTH-1) +1]            = new_sign_result;
461
assign dnmsg_din[16+ 4*(LLRWIDTH-1) +2]            = new_last_sign_result;
462
assign dnmsg_din[16+ 4*(LLRWIDTH-1) +32 -: 30]     = new_signs;
463
 
464
/******************************************
465
 * Align some signals with new RAM inputs *
466
 ******************************************/
467
localparam CALC_LATENCY = 3;
468
 
469
integer loopvar2;
470
 
471
reg                   we_del2[0:CALC_LATENCY-1];
472
reg[7+FOLDFACTOR-1:0] addr_del2[0:CALC_LATENCY-1];
473
 
474
assign dnmsg_we     = ~we_del2[CALC_LATENCY -1];
475
assign dnmsg_wraddr = addr_del2[CALC_LATENCY -1];
476
 
477
always @( posedge clk, posedge rst )
478
  if( rst )
479
    for( loopvar2=0; loopvar2<CALC_LATENCY; loopvar2=loopvar2+1 )
480
    begin
481
      we_del2[loopvar2]   <= 0;
482
      addr_del2[loopvar2] <= 0;
483
    end
484
  else
485
  begin
486
    we_del2[0]   <= cn_we_aligned_ram | cn_rd_aligned_ram;
487
    addr_del2[0] <= addr_cn_aligned_ram;
488
 
489
    for( loopvar2=1; loopvar2<CALC_LATENCY; loopvar2=loopvar2+1 )
490
    begin
491
      we_del2[loopvar2]   <= we_del2[loopvar2 -1];
492
      addr_del2[loopvar2] <= addr_del2[loopvar2 -1];
493
    end
494
 
495
    // last stage - mux in LLR values (if CALC_LATENCY=2, this stage
496
    // supercedes the entire for-loop, above)
497
    we_del2[CALC_LATENCY-1] <= llr_din_we | we_del2[CALC_LATENCY-2];
498
 
499
    if( llr_din_we )
500
      addr_del2[CALC_LATENCY-1] <= llr_addr;
501
    else
502
      addr_del2[CALC_LATENCY-1] <= addr_del2[CALC_LATENCY-2];
503
  end
504
 
505
endmodule

powered by: WebSVN 2.1.0

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