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

Compare with Previous | Blame | View Log

//-------------------------------------------------------------------------
//
// File name    :  ldpc_iocontrol.v
// Title        :
//              :
// Purpose      : Variable node holder/message calculator.  Loads llr
//              : data serially
//
// ----------------------------------------------------------------------
// Revision History :
// ----------------------------------------------------------------------
//   Ver  :| Author   :| Mod. Date   :| Changes Made:
//   v1.0  | JTC      :| 2008/07/02  :|
// ----------------------------------------------------------------------
`timescale 1ns/10ps
 
module ldpc_iocontrol #(
  parameter FOLDFACTOR     = 4,
  parameter LOG2FOLDFACTOR = 2,
  parameter LASTSHIFTWIDTH = 3,
  parameter NUMINSTANCES   = 180
)(
  input clk,
  input rst,
 
  // start command, completion indicator
  input      start,
  input[4:0] mode,
  input[5:0] iter_limit,
  output     done,
 
  // common control outputs
  output iteration,
  output first_iteration,
  output disable_vn,
  output disable_cn,
 
  // control VN's
  output                     we_vnmsg,
  output[7:0]                addr_vn,
  output[LOG2FOLDFACTOR-1:0] addr_vn_lo,
 
  // control shuffler
  output                     first_half,
  output[1:0]                shift0,
  output[2:0]                shift1,
  output[LASTSHIFTWIDTH-1:0] shift2,
 
  // control CN's
  output                     cn_we,
  output                     cn_rd,
  output[7:0]                addr_cn,
  output[LOG2FOLDFACTOR-1:0] addr_cn_lo,
 
  // ROM
  output[12:0]                  romaddr,
  input[8+5+LASTSHIFTWIDTH-1:0] romdata
);
 
localparam DONT_SHIFT = 0; // useful for debugging
 
/*********************************
 * State Machine 1               *
 * Controls the decoding process *
 *********************************/
localparam S_IDLE            = 0;
localparam S_PREPDECODE0     = 1;
localparam S_PREPDECODE1     = 2;
localparam S_FETCHCMD0       = 3;
localparam S_FETCHCMD1       = 4;
localparam S_STOREMSG        = 5;
localparam S_STOREPARITYMSG  = 6;
localparam S_STORESHIFTEDPARITY = 7;
localparam S_FINISHPIPE0     = 8;
localparam S_FINISHPIPE1     = 9;
localparam S_FINISHPIPE2     = 10;
localparam S_FINISHPIPE3     = 11;
localparam S_FINISHPIPE4     = 12;
localparam S_FINISHPIPE5     = 13;
localparam S_FINISHPIPE6     = 14;
localparam S_RESTART         = 15;
 
localparam TURNAROUND_WAITSTATES = 11;
 
reg[3:0] state;
 
reg[7:0] cn_count;
reg[7:0] vn_count;
reg[7:0] ta_count;
 
reg[12:0] romaddr_int;
reg[12:0] start_addr;
reg[12:0] turnaround_addr;
reg[4:0]  group_depth;
reg       turnaround;
reg       turnaround_next;
reg       last_group;
reg       first_group;
reg       last_group_next;
reg       n64k;
reg[7:0]  q;
reg[4:0]  count;
reg[5:0]  iter_count;
reg       done_int;
reg       first_iteration_int;
reg       iteration_int;
 
reg first_half_int;
 
reg[3:0] wait_count;
 
assign romaddr           = romaddr_int;
assign first_iteration   = first_iteration_int;
assign done              = done_int;
assign first_half        = first_half_int;
assign iteration         = iteration_int;
 
// synchronous state machine
always @( posedge rst, posedge clk )
  if( rst )
  begin
    state               <= S_IDLE;
    done_int            <= 0;
    iter_count          <= 0;
    romaddr_int         <= 0;
    first_iteration_int <= 0;
    iteration_int       <= 0;
    count               <= 0;
    cn_count            <= 0;
    vn_count            <= 0;
    first_half_int      <= 0;
    romaddr_int         <= 0;
    start_addr          <= 0;
    turnaround_addr     <= 0;
    q                   <= 0;
    turnaround          <= 0;
    turnaround_next     <= 0;
    last_group          <= 0;
    first_group         <= 0;
    n64k                <= 0;
    last_group_next     <= 0;
    group_depth         <= 0;
    wait_count          <= 0;
  end
  else
  begin
    // defaults
    done_int <= 0;
 
    case( state )
    // wait for start to prepare jump to offset, "mode"
    S_IDLE:
    begin
      if( start )
        state <= S_PREPDECODE0;
 
      romaddr_int      <= 0;
      romaddr_int[4:0] <= mode;
 
      iter_count    <= iter_limit;
      iteration_int <= 0;
 
      first_iteration_int <= 1;
      first_half_int      <= 1;
      cn_count            <= 0;
      vn_count            <= 0;
      ta_count            <= 0;
 
      first_group <= 1;
 
      done_int <= 1;
    end
 
    // "mode" is a pointer to a pointer - jump to mode**
    S_PREPDECODE0:
      state <= S_PREPDECODE1;
 
    S_PREPDECODE1:
    begin
      state <= S_FETCHCMD0;
 
      n64k <= romdata[16];
 
      romaddr_int     <= romdata[12:0];
      start_addr      <= romdata[12:0];
      turnaround_addr <= romdata[12:0];
    end
 
    // interpret code from ROM
    S_FETCHCMD0:
    begin
      state <= S_FETCHCMD1;
 
      if( n64k )
        vn_count <= 179;
      else
        vn_count <= 44;
    end
 
    S_FETCHCMD1:
    begin
      state <= S_STORESHIFTEDPARITY;
 
      romaddr_int <= romaddr_int + 1;
 
      turnaround  <= romdata[14];
      last_group  <= romdata[13];
      group_depth <= romdata[12:8];
      q           <= romdata[7:0];
      count       <= 0;
    end
 
    // write shifted set of parity bits
    S_STORESHIFTEDPARITY:
    begin
      state <= S_STOREMSG;
 
      romaddr_int <= romaddr_int + 1;
      wait_count  <= TURNAROUND_WAITSTATES;
      first_group <= 0;
    end
 
    // Write messages
    S_STOREMSG:
    begin
      if( count==group_depth )
        state <= S_STOREPARITYMSG;
 
      romaddr_int <= romaddr_int + (count!=group_depth);
 
      count    <= count + 1;
      vn_count <= q + cn_count;
    end
 
    // write parity bits to CN
    S_STOREPARITYMSG:
    begin
      if( last_group || turnaround )
        state <= S_FINISHPIPE0;
      else
        state <= S_STORESHIFTEDPARITY;
 
      if( !last_group && !turnaround )
      begin
        cn_count    <= cn_count + 1;
        romaddr_int <= romaddr_int + 1;
 
        turnaround  <= romdata[14];
        last_group  <= romdata[13];
        group_depth <= romdata[12:8];
        q           <= romdata[7:0];
        count       <= 0;
      end
    end
 
    // need waitstates between phases to let the pipeline clear out
    S_FINISHPIPE0:
    begin
      if( wait_count==0 )
      begin
        if( last_group && (iter_count==0) && !first_half_int )
        begin
          state    <= S_IDLE;
          done_int <= 1;
        end
        else
          state <= S_RESTART;
      end
 
      wait_count  <= wait_count - 1;
 
      if( wait_count==0 )
      begin
        turnaround  <= romdata[14];
        last_group  <= romdata[13];
        group_depth <= romdata[12:8];
        q           <= romdata[7:0];
        count       <= 0;
 
        cn_count    <= ta_count;
        romaddr_int <= turnaround_addr;
 
        ta_count        <= cn_count    + 1;
        turnaround_addr <= romaddr_int;
 
        if( last_group && !first_half_int )
        begin
          cn_count            <= 0;
          iteration_int       <= iteration_int ^ ~first_half_int;
          first_iteration_int <= 0;
          romaddr_int         <= start_addr;
          iter_count          <= iter_count - 1;
 
          ta_count        <= 0;
          turnaround_addr <= start_addr;
        end
      end
    end
 
    S_RESTART:
    begin
      state <= S_FETCHCMD1;
 
      if( cn_count==0 )
      begin
        first_group <= 1;
        if( n64k )
          vn_count <= 179;
        else
          vn_count <= 44;
      end
 
      first_half_int <= ~first_half_int;
    end
 
    default: ;
    endcase
  end
 
  // asynchronous portion of state machine
  reg we;
  reg matchpar;
  reg last_step;
 
  always @( * )
  begin
    // defaults
    we        <= 0;
    matchpar  <= 0;
    last_step <= 0;
 
    case( state )
      // Write messages
      S_STOREMSG:
        we <= 1;
 
      // write parity bits to CN's
      S_STOREPARITYMSG:
      begin
        we       <= 1;
        matchpar <= 1;
      end
 
      // write parity bits to next CN location
      S_STORESHIFTEDPARITY:
      begin
        we <= 1;
 
        if( first_group )
          last_step <= 1;
        else
          matchpar  <= 1;
      end
 
      default: ;
    endcase
  end
 
/********************************
 * State Machine Helper         *
 * Adds delays to we and to the *
 * addresses for vn and cn      *
 ********************************/
// determine undelayed controls
wire[7:0]                  orig_cn_addr;
wire[7:0]                  orig_vn_addr;
wire[5+LASTSHIFTWIDTH-1:0] orig_shiftval;
wire                       orig_we_vnmsg;
wire                       orig_cn_we;
wire                       orig_cn_rd;
wire                       orig_disable;
 
assign orig_vn_addr  = ( matchpar || last_step ) ? vn_count
                       : romdata[8+5+LASTSHIFTWIDTH-1:5+LASTSHIFTWIDTH];
assign orig_cn_addr  = cn_count;
assign orig_shiftval = DONT_SHIFT                     ? 0 :
                       matchpar                       ? 0 :
                       (first_half_int && last_step)  ? 1 :
                       (~first_half_int && last_step) ? NUMINSTANCES-1 :
                       first_half_int                 ? romdata[5+LASTSHIFTWIDTH-1:0] :
                                                        NUMINSTANCES - romdata[5+LASTSHIFTWIDTH-1:0];
assign orig_we_vnmsg = we & ~first_half_int;
assign orig_cn_we    = we & first_half_int;
assign orig_cn_rd    = we & ~first_half_int;
assign orig_disable  = last_step;
 
// add delays to compensate for latencies in external modules
localparam LOCAL_DELAY   = 1;  // Local register delays everything by 1
localparam RAM_LATENCY   = 2;  // RAM registers address in and data out
localparam VN_PIPES      = 3;
localparam SHUFFLE_PIPES = 3;
localparam CN_PIPES      = 2;
localparam MAX_PIPES     = VN_PIPES > CN_PIPES ? VN_PIPES : CN_PIPES;
 
localparam SHUFFLE_PREPSTAGES = 1; // we'll use 1 pipe locally to calculate shift addresses
localparam DISABLE_PREPSTAGES = 1; // disable needs 1 local pipe to sort out upstream/downstream
 
localparam LATENCY_VN_DEST  = LOCAL_DELAY + RAM_LATENCY + SHUFFLE_PIPES + CN_PIPES;
localparam LATENCY_CN_DEST  = LOCAL_DELAY + RAM_LATENCY + SHUFFLE_PIPES + VN_PIPES;
localparam LATENCY_CNVN_MAX = LOCAL_DELAY + RAM_LATENCY + SHUFFLE_PIPES + MAX_PIPES;
 
localparam LATENCY_DISABLE_DL = LATENCY_CN_DEST - DISABLE_PREPSTAGES;
localparam LATENCY_DISABLE_UL = LATENCY_VN_DEST - DISABLE_PREPSTAGES;
 
localparam LATENCY_SHIFTVALS_DL  = LOCAL_DELAY + RAM_LATENCY + VN_PIPES - SHUFFLE_PREPSTAGES;
localparam LATENCY_SHIFTVALS_UL  = LOCAL_DELAY + RAM_LATENCY + CN_PIPES - SHUFFLE_PREPSTAGES;
localparam LATENCY_SHIFTVALS_MAX = LOCAL_DELAY + RAM_LATENCY + MAX_PIPES - SHUFFLE_PREPSTAGES;
 
// for code neatness, all shift registers are the same length.  Rely on synthesizer to
// remove unused registers
reg[7:0]                  cn_addr_del[0:LATENCY_CNVN_MAX-1];
reg[7:0]                  vn_addr_del[0:LATENCY_CNVN_MAX-1];
reg[5+LASTSHIFTWIDTH-1:0] shiftval_del[0:LATENCY_CNVN_MAX-1];
reg                       we_vnmsg_del[0:LATENCY_CNVN_MAX-1];
reg                       cn_we_del[0:LATENCY_CNVN_MAX-1];
reg                       cn_rd_del[0:LATENCY_CNVN_MAX-1];
reg                       disable_vn_del[0:LATENCY_CNVN_MAX-1];
reg                       disable_cn_del[0:LATENCY_CNVN_MAX-1];
 
wire[5+LASTSHIFTWIDTH-1:0] shiftval_int;
 
integer loopvar;
 
assign we_vnmsg   = we_vnmsg_del[LATENCY_VN_DEST-1];
assign cn_we      = cn_we_del[LATENCY_CN_DEST-1];
assign cn_rd      = cn_rd_del[LATENCY_CN_DEST-1];
assign addr_vn    = vn_addr_del[LATENCY_VN_DEST-1];
assign addr_cn    = cn_addr_del[LATENCY_CN_DEST-1];
assign disable_vn = disable_vn_del[LATENCY_VN_DEST-1];
assign disable_cn = disable_cn_del[LATENCY_CN_DEST-1];
 
assign shiftval_int = shiftval_del[LATENCY_SHIFTVALS_MAX-1];
 
always @( posedge rst, posedge clk )
  if( rst )
    for( loopvar=0; loopvar<LATENCY_CNVN_MAX; loopvar=loopvar+1 )
    begin
      cn_addr_del[loopvar]    <= 0;
      vn_addr_del[loopvar]    <= 0;
      shiftval_del[loopvar]   <= 0;
      we_vnmsg_del[loopvar]   <= 0;
      cn_we_del[loopvar]      <= 0;
      cn_rd_del[loopvar]      <= 0;
      disable_vn_del[loopvar] <= 0;
      disable_cn_del[loopvar] <= 0;
    end
  else
  begin
    cn_addr_del[0]    <= orig_cn_addr;
    vn_addr_del[0]    <= orig_vn_addr;
    shiftval_del[0]   <= orig_shiftval;
    we_vnmsg_del[0]   <= orig_we_vnmsg;
    cn_we_del[0]      <= orig_cn_we;
    cn_rd_del[0]      <= orig_cn_rd;
    disable_vn_del[0] <= orig_disable;
    disable_cn_del[0] <= orig_disable;
 
    for( loopvar=1; loopvar<LATENCY_CNVN_MAX; loopvar=loopvar+1 )
    begin
      cn_addr_del[loopvar]    <= cn_addr_del[loopvar-1];
      vn_addr_del[loopvar]    <= vn_addr_del[loopvar-1];
      shiftval_del[loopvar]   <= shiftval_del[loopvar-1];
      we_vnmsg_del[loopvar]   <= we_vnmsg_del[loopvar-1];
      cn_we_del[loopvar]      <= cn_we_del[loopvar-1];
      cn_rd_del[loopvar]      <= cn_rd_del[loopvar-1];
      disable_vn_del[loopvar] <= disable_vn_del[loopvar-1];
      disable_cn_del[loopvar] <= disable_cn_del[loopvar-1];
    end
 
    // need some muxes in the middle of the shift registers because of different
    // latencies for upstream and downstream messages
    if( first_half )
    begin
      vn_addr_del[LATENCY_VN_DEST-1]    <= orig_vn_addr;
      we_vnmsg_del[LATENCY_VN_DEST-1]   <= orig_we_vnmsg;
      disable_vn_del[LATENCY_VN_DEST-1] <= orig_disable;
    end
    if( !first_half )
    begin
      cn_addr_del[LATENCY_CN_DEST-1]    <= orig_cn_addr;
      cn_we_del[LATENCY_CN_DEST-1]      <= orig_cn_we;
      cn_rd_del[LATENCY_CN_DEST-1]      <= orig_cn_rd;
      disable_cn_del[LATENCY_CN_DEST-1] <= orig_disable;
    end
 
    if( first_half )
      shiftval_del[LATENCY_SHIFTVALS_MAX-1] <= shiftval_del[LATENCY_SHIFTVALS_DL-2];
    if( !first_half )
      shiftval_del[LATENCY_SHIFTVALS_MAX-1] <= shiftval_del[LATENCY_SHIFTVALS_UL-2];
  end
 
wire[1:0]               shift0_int;
reg[1:0]                shift0_reg;
wire[2:0]               shift1_int;
reg[2:0]                shift1_reg;
reg[LASTSHIFTWIDTH-1:0] shift2_reg;
 
assign shift0 = shift0_reg;
assign shift1 = shift1_reg;
assign shift2 = shift2_reg;
 
reg[8:0]                rem0;
reg[LASTSHIFTWIDTH-1:0] rem1;
 
generate
  if( FOLDFACTOR==1 )
  begin: case360
    assign shift0_int = shiftval_int > 269 ? 3
                      : shiftval_int > 179 ? 2
                      : shiftval_int > 89  ? 1
                      :                      0;
 
    assign shift1_int = rem0 > 83 ? 7
                      : rem0 > 71 ? 6
                      : rem0 > 59 ? 5
                      : rem0 > 47 ? 4
                      : rem0 > 35 ? 3
                      : rem0 > 23 ? 2
                      : rem0 > 11 ? 1
                      :             0;
  end
  if( FOLDFACTOR==2 )
  begin: case180
    assign shift0_int = shiftval_int > 134 ? 3
                      : shiftval_int > 89  ? 2
                      : shiftval_int > 44  ? 1
                      :                      0;
 
 
    assign shift1_int = rem0 > 41 ? 7
                      : rem0 > 35 ? 6
                      : rem0 > 29 ? 5
                      : rem0 > 23 ? 4
                      : rem0 > 17 ? 3
                      : rem0 > 11 ? 2
                      : rem0 > 5  ? 1
                      :             0;
  end
  if( FOLDFACTOR==3 )
  begin: case120
    assign shift0_int = shiftval_int > 89 ? 3
                      : shiftval_int > 59 ? 2
                      : shiftval_int > 29 ? 1
                      :                     0;
 
    assign shift1_int = rem0 > 26 ? 7
                      : rem0 > 22 ? 6
                      : rem0 > 18 ? 5
                      : rem0 > 15 ? 4
                      : rem0 > 11 ? 3
                      : rem0 > 7  ? 2
                      : rem0 > 3  ? 1
                      :             0;
  end
  if( FOLDFACTOR==4 )
  begin: case90
    assign shift0_int = shiftval_int > 66 ? 3
                      : shiftval_int > 44 ? 2
                      : shiftval_int > 22 ? 1
                      :                     0;
 
    assign shift1_int = rem0 > 20 ? 7
                      : rem0 > 17 ? 6
                      : rem0 > 14 ? 5
                      : rem0 > 11 ? 4
                      : rem0 > 8  ? 3
                      : rem0 > 5  ? 2
                      : rem0 > 2  ? 1
                      :             0;
  end
endgenerate
 
always @( posedge rst, posedge clk )
  if( rst )
  begin
    shift0_reg            <= 0;
    shift1_reg            <= 0;
    shift2_reg            <= 0;
    rem0                  <= 0;
    rem1                  <= 0;
  end
  else
  begin
    // shift0 needs to be inverted (this arithmetic should be optimized out)
    shift0_reg <= shift0_int;
    shift1_reg <= shift1_int;
    shift2_reg <= rem1;
 
    // calculate remainders after first two shifts
    if( FOLDFACTOR==1 )
      rem0 <= shift0_int==3 ? shiftval_int-270
            : shift0_int==2 ? shiftval_int-180
            : shift0_int==1 ? shiftval_int-90
            :                 shiftval_int;
    if( FOLDFACTOR==2 )
      rem0 <= shift0_int==3 ? shiftval_int-135
            : shift0_int==2 ? shiftval_int-90
            : shift0_int==1 ? shiftval_int-45
            :                 shiftval_int;
    if( FOLDFACTOR==3 )
      rem0 <= shift0_int==3 ? shiftval_int-90
            : shift0_int==2 ? shiftval_int-60
            : shift0_int==1 ? shiftval_int-30
            :                 shiftval_int;
    if( FOLDFACTOR==4 )
      rem0 <= shift0_int==3 ? shiftval_int-67
            : shift0_int==2 ? shiftval_int-45
            : shift0_int==1 ? shiftval_int-23
            :                 shiftval_int;
 
    if( FOLDFACTOR==1 )
      rem1 <= shift1_int==7 ? rem0-84
            : shift1_int==6 ? rem0-72
            : shift1_int==5 ? rem0-60
            : shift1_int==4 ? rem0-48
            : shift1_int==3 ? rem0-36
            : shift1_int==2 ? rem0-24
            : shift1_int==1 ? rem0-12
            :                 rem0;
    if( FOLDFACTOR==3 )
      rem1 <= shift1_int==7 ? rem0-52
            : shift1_int==6 ? rem0-45
            : shift1_int==5 ? rem0-37
            : shift1_int==4 ? rem0-30
            : shift1_int==3 ? rem0-22
            : shift1_int==2 ? rem0-15
            : shift1_int==1 ? rem0-7
            :                 rem0;
    if( FOLDFACTOR==4 )
      rem1 <= shift1_int==7 ? rem0-21
            : shift1_int==6 ? rem0-18
            : shift1_int==5 ? rem0-15
            : shift1_int==4 ? rem0-12
            : shift1_int==3 ? rem0-9
            : shift1_int==2 ? rem0-6
            : shift1_int==1 ? rem0-3
            :                 rem0;
  end
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.