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_vn.v] - Rev 2

Compare with Previous | Blame | View Log

//-------------------------------------------------------------------------
//
// File name    :  ldpc_vn.v
// Title        :
//              :
// Purpose      : Variable node holder/message calculator.  Loads llr
//              : data serially, and controls RAM's.  This module is
//              : written to be as compact as possible, since it is
//              : instantiated a large number of times.  Some outputs,
//              : especially RAM controls, are not registered.
//
// ----------------------------------------------------------------------
// Revision History :
// ----------------------------------------------------------------------
//   Ver  :| Author   :| Mod. Date   :| Changes Made:
//   v1.0  | JTC      :| 2008/07/02  :|
// ----------------------------------------------------------------------
`timescale 1ns/10ps
 
module ldpc_vn #(
  parameter FOLDFACTOR     = 1,
  parameter LLRWIDTH       = 6
)(
  input clk,
  input rst,
 
  // LLR I/O
  input                   llr_access,
  input[7+FOLDFACTOR-1:0] llr_addr,
  input                   llr_din_we,
  input[LLRWIDTH-1:0]     llr_din,
  output[LLRWIDTH-1:0]    llr_dout,
 
  // message control
  input                   iteration,
  input                   first_half,
  input                   first_iteration,  // ignore upmsgs
  input                   we_vnmsg,
  input                   disable_vn,
  input[7+FOLDFACTOR-1:0] addr_vn,
 
  // message I/O
  input[LLRWIDTH-1:0]  sh_msg,
  output[LLRWIDTH-1:0] vn_msg,
 
  // Attached RAM, holds iteration number, original LLR and message sum
  output[7+FOLDFACTOR-1:0] vnram_wraddr,
  output[7+FOLDFACTOR-1:0] vnram_rdaddr,
  output                   upmsg_we,
  output[2*LLRWIDTH+4:0]   upmsg_din,
  input[2*LLRWIDTH+4:0]    upmsg_dout
);
 
// Split RAM outputs
wire[LLRWIDTH-1:0] llr_orig;
wire[LLRWIDTH+3:0] stored_msg_sum;
wire               stored_iteration;
 
assign llr_orig         = upmsg_dout[LLRWIDTH-1:0];
assign stored_msg_sum   = upmsg_dout[2*LLRWIDTH+3:LLRWIDTH];
assign stored_iteration = upmsg_dout[2*LLRWIDTH+4];
 
/************************************************************
 * Add 1's complement numbers, assume overflow not possible *
 ************************************************************/
function[LLRWIDTH+3:0] AddNewMsg( input[LLRWIDTH+3:0] a,
                                  input[LLRWIDTH-1:0] b );
  reg               signa;
  reg               signb;
  reg[LLRWIDTH+2:0] maga;
  reg[LLRWIDTH+2:0] magb;
 
  reg[LLRWIDTH+2:0] sum;
  reg[LLRWIDTH+2:0] diffa;
  reg[LLRWIDTH+2:0] diffb;
 
  reg               add;
  reg               b_big;
  reg               sign;
  reg[LLRWIDTH+3:0] result;
 
begin
  // strip out magnitude and sign bits
  signa = a[LLRWIDTH+3];
  signb = b[LLRWIDTH-1];
  maga  = a[LLRWIDTH+2:0];
  magb  = { 4'b0000, b[LLRWIDTH-2:0] };
 
  // basic calculations
  sum   = maga + magb;
  diffa = maga - magb;
  diffb = magb - maga;
 
  // control bits
  add   = signa==signb;
  b_big = maga<magb;
  sign  = b_big ? signb : signa;
 
  if( add )
    result = { sign, sum };
  else if( b_big )
    result = { sign, diffb };
  else
    result = { sign, diffa };
 
  AddNewMsg = result;
end
endfunction
 
/*************************************************
 * Saturate message to fewer bits before passing *
 *************************************************/
function[LLRWIDTH-1:0] SaturateMsg( input[LLRWIDTH+3:0] a );
begin
  if( a[LLRWIDTH+2:LLRWIDTH-1] != 4'b0000 )
    SaturateMsg[LLRWIDTH-2:0] = { (LLRWIDTH-1){1'b1} };
  else
    SaturateMsg[LLRWIDTH-2:0] = a[LLRWIDTH-2:0];
 
  SaturateMsg[LLRWIDTH-1] = a[LLRWIDTH+3];
end
endfunction
 
/********************************************
 * Delays to align controls with RAM output *
 ********************************************/
localparam RAM_LATENCY = 2;
 
integer loopvar1;
 
reg[7+FOLDFACTOR-1:0] vnram_rdaddr_int;
 
reg[LLRWIDTH-1:0]     sh_msg_del[0:RAM_LATENCY-1];
reg                   we_vnmsg_del[0:RAM_LATENCY-1];
reg[7+FOLDFACTOR-1:0] vnram_rdaddr_del[0:RAM_LATENCY-1];
reg                   disable_del[0:RAM_LATENCY-1];    
 
wire[LLRWIDTH-1:0]     sh_msg_aligned_ram;
wire                   we_vnmsg_aligned_ram;
wire[7+FOLDFACTOR-1:0] vnram_rdaddr_aligned_ram;
wire                   disable_aligned_ram;
 
reg recycle_result;
 
// mux in alternative address for final read-out
assign vnram_rdaddr = vnram_rdaddr_int;
always @( * ) vnram_rdaddr_int <= #1 llr_access ? llr_addr : addr_vn;
 
assign sh_msg_aligned_ram       = sh_msg_del[RAM_LATENCY-1];
assign we_vnmsg_aligned_ram     = we_vnmsg_del[RAM_LATENCY-1];
assign vnram_rdaddr_aligned_ram = vnram_rdaddr_del[RAM_LATENCY-1];
assign disable_aligned_ram      = disable_del[RAM_LATENCY-1];    
 
always @( posedge rst, posedge clk )
  if( rst )
  begin
    for( loopvar1=0; loopvar1<RAM_LATENCY; loopvar1=loopvar1+1 )
    begin
      sh_msg_del[loopvar1]       <= 0;
      we_vnmsg_del[loopvar1]     <= 0;
      vnram_rdaddr_del[loopvar1] <= 0;
      disable_del[loopvar1]      <= 0;
    end
    recycle_result <= 0;
  end
  else
  begin
    sh_msg_del[0]        <= sh_msg;
    we_vnmsg_del[0]      <= we_vnmsg;
    vnram_rdaddr_del[0]  <= vnram_rdaddr_int; 
    disable_del[0]       <= disable_vn;
 
    for( loopvar1=1; loopvar1<RAM_LATENCY; loopvar1=loopvar1+1 )
    begin
      sh_msg_del[loopvar1]       <= sh_msg_del[loopvar1 -1];
      we_vnmsg_del[loopvar1]     <= we_vnmsg_del[loopvar1 -1];
      vnram_rdaddr_del[loopvar1] <= vnram_rdaddr_del[loopvar1 -1];
      disable_del[loopvar1]      <= disable_del[loopvar1 -1];
    end
 
    // Use previous result rather than the RAM contents for two adjacent
    // writes to the same address
    recycle_result <= (vnram_rdaddr_aligned_ram==vnram_rdaddr_del[RAM_LATENCY-2]) &
                      we_vnmsg_aligned_ram & we_vnmsg_del[RAM_LATENCY-2];
  end
 
/************************
 * Message calculations *
 ************************/
// Add initial LLR to message offset (except for first iteration)
reg[LLRWIDTH+3:0]  msg0_norst;
wire[LLRWIDTH+3:0] msg0;
reg[LLRWIDTH-1:0]  msg1;
 
wire start_new_upmsg;
reg  rst_msg0;
 
wire[LLRWIDTH+3:0] msg_sum;
 
reg[LLRWIDTH+3:0] msg_sum_reg;
 
// Add upmsg to the result, except:
// - during first iteration, since no upmsg exists
// - first message of each new iteration, where upmsg needs to be reset
assign start_new_upmsg = (stored_iteration!=iteration) & we_vnmsg_aligned_ram;
 
assign msg0 = rst_msg0 ? 0 : msg0_norst;
 
always @( posedge clk, posedge rst )
  if( rst )
  begin
    msg0_norst  <= 0;
    rst_msg0    <= 0;
    msg1        <= 0;
    msg_sum_reg <= 0;
  end
  else
  begin
    // msg0 = sum of received upstream messages
    // clear msg0 when beginning a new set of upstream messages
    msg0_norst <= recycle_result ? msg_sum : stored_msg_sum;
    rst_msg0   <= start_new_upmsg & ~recycle_result;
 
    msg1 <= (llr_access || first_half) ? llr_orig : sh_msg_aligned_ram;
 
    msg_sum_reg <= msg_sum;
  end
 
// When creating downstream messages, or preparing final result:
//      msg_sum = llr + sum of messages
// When receiving upstream messages:
//      msg_sum = new message + sum of messages
assign msg_sum = AddNewMsg( msg0, msg1 );
 
/****************************************
 * Delay controls to align with msg_sum *
 ****************************************/
localparam CALC_LATENCY = 2;
 
integer loopvar2;
 
reg                   we_vnmsg_del2[0:RAM_LATENCY-1];
reg[7+FOLDFACTOR-1:0] vnram_rdaddr_del2[0:RAM_LATENCY-1];
reg[LLRWIDTH-1:0]     llrram_dout_del2[0:RAM_LATENCY-1];
reg                   disable_del2[0:RAM_LATENCY-1];    
 
wire                   we_vnmsg_aligned_msg;
wire[7+FOLDFACTOR-1:0] vnram_rdaddr_aligned_msg;
wire[LLRWIDTH-1:0]     llrram_dout_aligned_msg;
wire                   disable_aligned_msg;
 
assign we_vnmsg_aligned_msg     = we_vnmsg_del2[RAM_LATENCY-1];
assign vnram_rdaddr_aligned_msg = vnram_rdaddr_del2[RAM_LATENCY-1];
assign llrram_dout_aligned_msg  = llrram_dout_del2[RAM_LATENCY-1];
assign disable_aligned_msg      = disable_del2[RAM_LATENCY-1];    
 
always @( posedge rst, posedge clk )
  if( rst )
  begin
    for( loopvar2=0; loopvar2<RAM_LATENCY; loopvar2=loopvar2+1 )
    begin
      we_vnmsg_del2[loopvar2]     <= 0;
      vnram_rdaddr_del2[loopvar2] <= 0;
      llrram_dout_del2[loopvar2]  <= 0;
      disable_del2[loopvar2]      <= 0;
    end
  end
  else
  begin
    we_vnmsg_del2[0]      <= we_vnmsg_aligned_ram;
    vnram_rdaddr_del2[0]  <= vnram_rdaddr_aligned_ram; 
    llrram_dout_del2[0]   <= llr_orig;
    disable_del2[0]       <= disable_aligned_ram;
 
    for( loopvar2=1; loopvar2<RAM_LATENCY; loopvar2=loopvar2+1 )
    begin
      we_vnmsg_del2[loopvar2]     <= we_vnmsg_del2[loopvar2 -1];
      vnram_rdaddr_del2[loopvar2] <= vnram_rdaddr_del2[loopvar2 -1];
      llrram_dout_del2[loopvar2]  <= llrram_dout_del2[loopvar2 -1];
      disable_del2[loopvar2]      <= disable_del2[loopvar2 -1];
    end
  end
 
/*******************************
 * Write message totals to RAM *
 *******************************/
reg[7+FOLDFACTOR-1:0] vnram_wraddr_int;
reg[LLRWIDTH-1:0]     new_llr;
reg                   new_iteration;
reg[LLRWIDTH+3:0]     new_msg_sum;
reg                   upmsg_we_int;
 
assign vnram_wraddr = vnram_wraddr_int;
assign upmsg_din    = { new_iteration, new_msg_sum, new_llr };
assign upmsg_we     = upmsg_we_int;
 
always @( posedge rst, posedge clk )
  if( rst )
  begin
    vnram_wraddr_int <= 0;
    new_llr          <= 0;
    new_msg_sum      <= 0;
    new_iteration    <= 0;
    upmsg_we_int     <= 1;
  end
  else
  begin
    // mux and register outputs
    vnram_wraddr_int <= #1 llr_access ? llr_addr : vnram_rdaddr_aligned_msg;
    new_llr          <= #1 llr_access ? llr_din  : llrram_dout_aligned_msg;
    new_msg_sum      <= #1 llr_access ? 0        : msg_sum_reg;
 
    new_iteration    <= #1 llr_access | iteration;
 
    upmsg_we_int     <= #1 ~(llr_din_we | (we_vnmsg_aligned_msg & ~disable_aligned_msg));
  end
 
/*****************************************************************
 * Saturate message to fewer bits for message passing and output *
 *****************************************************************/
reg[LLRWIDTH-1:0] vn_msg_int;
 
assign llr_dout = vn_msg_int;
assign vn_msg   = vn_msg_int;
 
always @( posedge rst, posedge clk )
  if( rst )
    vn_msg_int <= 0;
  else
    vn_msg_int <= SaturateMsg(msg_sum_reg);
 
endmodule
 
 

Compare with Previous | Blame | View Log

powered by: WebSVN 2.1.0

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