From 917f5c85e6638c2a38a74f2f8ca0ab928d7dfd98 Mon Sep 17 00:00:00 2001 From: denis Date: Sat, 22 Jun 2024 15:18:06 +0700 Subject: [PATCH] add optional encoder transpose unit to make code DVB-S2/S2X compliant --- rtl/ldpc_dvb/README.md | 6 +- ...c_engine.sv => ldpc_dvb_enc_engine_fix.sv} | 220 +++++------ rtl/ldpc_dvb/enc/ldpc_dvb_enc_fix.sv | 99 ++++- rtl/ldpc_dvb/enc/ldpc_dvb_enc_mux.sv | 35 +- rtl/ldpc_dvb/enc/ldpc_dvb_enc_transponse.sv | 348 ++++++++++++++++++ .../enc/ldpc_dvb_enc_transponse_acc.sv | 164 +++++++++ .../enc/ldpc_dvb_enc_transponse_ctrl.sv | 340 +++++++++++++++++ 7 files changed, 1062 insertions(+), 150 deletions(-) rename rtl/ldpc_dvb/enc/{ldpc_dvb_enc_engine.sv => ldpc_dvb_enc_engine_fix.sv} (74%) create mode 100644 rtl/ldpc_dvb/enc/ldpc_dvb_enc_transponse.sv create mode 100644 rtl/ldpc_dvb/enc/ldpc_dvb_enc_transponse_acc.sv create mode 100644 rtl/ldpc_dvb/enc/ldpc_dvb_enc_transponse_ctrl.sv diff --git a/rtl/ldpc_dvb/README.md b/rtl/ldpc_dvb/README.md index 8e906b3..ab7d62a 100644 --- a/rtl/ldpc_dvb/README.md +++ b/rtl/ldpc_dvb/README.md @@ -12,7 +12,7 @@ Codec input/core/output work in different clock domains. vivado 2019.1 Kintex 7 - 2 (artix worked but has timings routing problem) -Encoder settings : DVB-S2 coderate = 5/6, block length = 64800 bits, interface 8 bits per tick +Encoder settings : DVB-S2 coderate = 5/6, block length = 64800 bits, interface 8 bits per tick, no internal parity bits transponse Encoder : LUT/REG/RAMB 3.7k/3.5k/15 iface >250MHz(1.65Gbps -> 2Gbps), core >250MHz (~25.5Gbps at output) @@ -30,4 +30,6 @@ pNODE_W = 4 bits (worst codegain for 4 bit LLR) Decoder : LUT/REG/RAMB 41k/49k/87.5 iface >250MHz, core >250MHz (480Mbps -> 240Mbps) -Attention: The coder and decoder correspond each other but can have different bit order with standard codes. Strongly speaking it's not DVB-S2 codec, because there is no parity bits reorder inside. It should be done external of codec during bit interleaving procedure !!! +Attention: The coder and decoder correspond each other but can have different bit order with standard codes. Strongly speaking it's not DVB-S2 codec by default, because there is no parity bits reorder inside. It should be done external of codec during bit interleaving procedure !!! + +PS. There is optinal parity bits transpose unit inside encoder? this unit don't have opponent inside decoder. That's why use it only for encoder aplications. diff --git a/rtl/ldpc_dvb/enc/ldpc_dvb_enc_engine.sv b/rtl/ldpc_dvb/enc/ldpc_dvb_enc_engine_fix.sv similarity index 74% rename from rtl/ldpc_dvb/enc/ldpc_dvb_enc_engine.sv rename to rtl/ldpc_dvb/enc/ldpc_dvb_enc_engine_fix.sv index e87b694..e6ef22c 100644 --- a/rtl/ldpc_dvb/enc/ldpc_dvb_enc_engine.sv +++ b/rtl/ldpc_dvb/enc/ldpc_dvb_enc_engine_fix.sv @@ -8,39 +8,40 @@ parameter int pTAG_W = 4 ; // parameter int pCODEGR = 1 ; + parameter int pCODERATE = 0 ; parameter bit pXMODE = 0 ; - parameter bit pFIX_MODE = 1 ; - logic ldpc_dvb_enc_engine__iclk ; - logic ldpc_dvb_enc_engine__ireset ; - logic ldpc_dvb_enc_engine__iclkena ; + logic ldpc_dvb_enc_engine_fix__iclk ; + logic ldpc_dvb_enc_engine_fix__ireset ; + logic ldpc_dvb_enc_engine_fix__iclkena ; // - logic ldpc_dvb_enc_engine__irbuf_full ; + logic ldpc_dvb_enc_engine_fix__irbuf_full ; // - code_ctx_t ldpc_dvb_enc_engine__icode_ctx ; + logic [cZC_MAX-1 : 0] ldpc_dvb_enc_engine_fix__irdat ; + logic [pTAG_W-1 : 0] ldpc_dvb_enc_engine_fix__irtag ; + logic ldpc_dvb_enc_engine_fix__orempty ; + logic [pRADDR_W-1 : 0] ldpc_dvb_enc_engine_fix__oraddr ; // - logic [cZC_MAX-1 : 0] ldpc_dvb_enc_engine__irdat ; - logic [pTAG_W-1 : 0] ldpc_dvb_enc_engine__irtag ; - logic ldpc_dvb_enc_engine__orempty ; - logic [pRADDR_W-1 : 0] ldpc_dvb_enc_engine__oraddr ; + logic ldpc_dvb_enc_engine_fix__iwbuf_empty ; // - logic ldpc_dvb_enc_engine__iwbuf_empty ; + logic [pWADDR_W-1 : 0] ldpc_dvb_enc_engine_fix__owcol ; + logic [pWADDR_W-1 : 0] ldpc_dvb_enc_engine_fix__owdata_col ; + logic [pWADDR_W-1 : 0] ldpc_dvb_enc_engine_fix__owrow ; // - logic [pWADDR_W-1 : 0] ldpc_dvb_enc_engine__owcol ; - logic [pWADDR_W-1 : 0] ldpc_dvb_enc_engine__owdata_col ; - logic [pWADDR_W-1 : 0] ldpc_dvb_enc_engine__owrow ; + logic ldpc_dvb_enc_engine_fix__owrite ; + logic ldpc_dvb_enc_engine_fix__owfull ; + logic [pWADDR_W-1 : 0] ldpc_dvb_enc_engine_fix__owaddr ; + logic [cZC_MAX-1 : 0] ldpc_dvb_enc_engine_fix__owdat ; + logic [pTAG_W-1 : 0] ldpc_dvb_enc_engine_fix__owtag ; // - logic ldpc_dvb_enc_engine__owrite ; - logic ldpc_dvb_enc_engine__owfull ; - logic [pWADDR_W-1 : 0] ldpc_dvb_enc_engine__owaddr ; - logic [cZC_MAX-1 : 0] ldpc_dvb_enc_engine__owdat ; - logic [pTAG_W-1 : 0] ldpc_dvb_enc_engine__owtag ; + logic ldpc_dvb_enc_engine_fix__opwrite ; + logic [pWADDR_W-1 : 0] ldpc_dvb_enc_engine_fix__opwaddr ; - ldpc_dvb_enc_engine + ldpc_dvb_enc_engine_fix #( .pRADDR_W ( pRADDR_W ) , .pWADDR_W ( pWADDR_W ) , @@ -48,46 +49,46 @@ .pTAG_W ( pTAG_W ) , // .pCODEGR ( pCODEGR ) , - .pXMODE ( pXMODE ) , - .pFIX_MODE ( pFIX_MODE ) + .pCODRATE ( pCODERATE ) , + .pXMODE ( pXMODE ) ) - ldpc_dvb_enc_engine + ldpc_dvb_enc_engine_fix ( - .iclk ( ldpc_dvb_enc_engine__iclk ) , - .ireset ( ldpc_dvb_enc_engine__ireset ) , - .iclkena ( ldpc_dvb_enc_engine__iclkena ) , + .iclk ( ldpc_dvb_enc_engine_fix__iclk ) , + .ireset ( ldpc_dvb_enc_engine_fix__ireset ) , + .iclkena ( ldpc_dvb_enc_engine_fix__iclkena ) , // - .irbuf_full ( ldpc_dvb_enc_engine__irbuf_full ) , + .irbuf_full ( ldpc_dvb_enc_engine_fix__irbuf_full ) , // - .icode_ctx ( ldpc_dvb_enc_engine__icode_ctx ) , + .irdat ( ldpc_dvb_enc_engine_fix__irdat ) , + .irtag ( ldpc_dvb_enc_engine_fix__irtag ) , + .orempty ( ldpc_dvb_enc_engine_fix__orempty ) , + .oraddr ( ldpc_dvb_enc_engine_fix__oraddr ) , // - .irdat ( ldpc_dvb_enc_engine__irdat ) , - .irtag ( ldpc_dvb_enc_engine__irtag ) , - .orempty ( ldpc_dvb_enc_engine__orempty ) , - .oraddr ( ldpc_dvb_enc_engine__oraddr ) , + .iwbuf_empty ( ldpc_dvb_enc_engine_fix__iwbuf_empty ) , // - .iwbuf_empty ( ldpc_dvb_enc_engine__iwbuf_empty ) , + .owcol ( ldpc_dvb_enc_engine_fix__owcol ) , + .owdata_col ( ldpc_dvb_enc_engine_fix__owdata_col ) , + .owrow ( ldpc_dvb_enc_engine_fix__owrow ) , // - .owcol ( ldpc_dvb_enc_engine__owcol ) , - .owdata_col ( ldpc_dvb_enc_engine__owdata_col ) , - .owrow ( ldpc_dvb_enc_engine__owrow ) , + .owrite ( ldpc_dvb_enc_engine_fix__owrite ) , + .owfull ( ldpc_dvb_enc_engine_fix__owfull ) , + .owaddr ( ldpc_dvb_enc_engine_fix__owaddr ) , + .owdat ( ldpc_dvb_enc_engine_fix__owdat ) , + .owtag ( ldpc_dvb_enc_engine_fix__owtag ) // - .owrite ( ldpc_dvb_enc_engine__owrite ) , - .owfull ( ldpc_dvb_enc_engine__owfull ) , - .owaddr ( ldpc_dvb_enc_engine__owaddr ) , - .owdat ( ldpc_dvb_enc_engine__owdat ) , - .owtag ( ldpc_dvb_enc_engine__owtag ) + .opwrite ( ldpc_dvb_enc_engine_fix__opwrite ) , + .opwaddr ( ldpc_dvb_enc_engine_fix__opwaddr ) ); - assign ldpc_dvb_enc_engine__iclk = '0 ; - assign ldpc_dvb_enc_engine__ireset = '0 ; - assign ldpc_dvb_enc_engine__iclkena = '0 ; - assign ldpc_dvb_enc_engine__irbuf_full = '0 ; - assign ldpc_dvb_enc_engine__icode_ctx = '0 ; - assign ldpc_dvb_enc_engine__irdat = '0 ; - assign ldpc_dvb_enc_engine__irtag = '0 ; - assign ldpc_dvb_enc_engine__iwbuf_empty = '0 ; + assign ldpc_dvb_enc_engine_fix__iclk = '0 ; + assign ldpc_dvb_enc_engine_fix__ireset = '0 ; + assign ldpc_dvb_enc_engine_fix__iclkena = '0 ; + assign ldpc_dvb_enc_engine_fix__irbuf_full = '0 ; + assign ldpc_dvb_enc_engine_fix__irdat = '0 ; + assign ldpc_dvb_enc_engine_fix__irtag = '0 ; + assign ldpc_dvb_enc_engine_fix__iwbuf_empty = '0 ; @@ -96,20 +97,20 @@ // // Project : ldpc DVB-S2 // Author : Shekhalev Denis (des00) -// Workfile : ldpc_dvb_enc_engine.sv +// Workfile : ldpc_dvb_enc_engine_fix.sv // Description : variable mode DVB LDPC RTL encoder engine // -module ldpc_dvb_enc_engine +module ldpc_dvb_enc_engine_fix #( parameter int pRADDR_W = 8 , parameter int pWADDR_W = 8 , // parameter int pTAG_W = 4 , // - parameter bit pCODEGR = 1 , // maximum used graph short(0)/large(1) - parameter bit pXMODE = 0 , // DVB-S2X code tables using - parameter bit pFIX_MODE = 0 // use fixed mode encoder or not + parameter int pCODEGR = 1 , // short(0)/large(1)/medium(2) graph + parameter int pCODERATE = 1 , // coderate table see in ldpc_dvb_constants.svh + parameter bit pXMODE = 0 // DVB-S2X code tables using ) ( iclk , @@ -118,8 +119,6 @@ module ldpc_dvb_enc_engine // irbuf_full , // - icode_ctx , - // irdat , irtag , orempty , @@ -135,7 +134,10 @@ module ldpc_dvb_enc_engine owfull , owaddr , owdat , - owtag + owtag , + // + opwrite , + opwaddr ); `include "../ldpc_dvb_constants.svh" @@ -151,8 +153,6 @@ module ldpc_dvb_enc_engine // input ram interface input logic irbuf_full ; // - input code_ctx_t icode_ctx ; - // input logic [cZC_MAX-1 : 0] irdat ; input logic [pTAG_W-1 : 0] irtag ; output logic orempty ; @@ -169,6 +169,9 @@ module ldpc_dvb_enc_engine output logic [pWADDR_W-1 : 0] owaddr ; output logic [cZC_MAX-1 : 0] owdat ; output logic [pTAG_W-1 : 0] owtag ; + // + output logic opwrite ; + output logic [pWADDR_W-1 : 0] opwaddr ; //------------------------------------------------------------------------------------------------------ // @@ -180,7 +183,7 @@ module ldpc_dvb_enc_engine localparam int cBS_DELAY = 3 + cRDAT_DELAY; // barrel shifter delay // parity bit RAM settings - localparam int cPRAM_ADDR_W = pCODEGR ? cLOG2_ROW_MAX : cLOG2_ROW_SHORT_MAX; + localparam int cPRAM_ADDR_W = (pCODEGR == cCODEGR_LARGE) ? cLOG2_ROW_MAX : ((pCODEGR == cCODEGR_MEDIUM) ? cLOG2_ROW_MEDIUM_MAX : cLOG2_ROW_SHORT_MAX); localparam int cPRAM_DAT_W = cZC_MAX; //------------------------------------------------------------------------------------------------------ @@ -276,71 +279,42 @@ module ldpc_dvb_enc_engine logic mux__owrite ; col_t mux__owaddr ; zdat_t mux__owdat ; + // + logic mux__opwrite ; + col_t mux__opwaddr ; //------------------------------------------------------------------------------------------------------ // Hs "generator" //------------------------------------------------------------------------------------------------------ - generate - if (pFIX_MODE) begin : hs_inst_gen - ldpc_dvb_enc_hs - #( - .pXMODE ( pXMODE ) , - .pPIPE ( 1 ) // 2 tick latency - ) - hs - ( - .iclk ( iclk ) , - .ireset ( ireset ) , - .iclkena ( iclkena ) , - // - .icode_ctx ( hs_gen__icode_ctx ) , - // - .oused_col ( hs_gen__oused_col ) , - .oused_data_col ( hs_gen__oused_data_col ) , - .oused_row ( hs_gen__oused_row ) , - .ocycle_max_num ( hs_gen__ocycle_max_num ) , - // - .icycle_read ( hs_gen__icycle_read ) , - .icycle_idx ( hs_gen__icycle_idx ) , - // - .ocycle_read ( hs_gen__ocycle_read ) , - .ocycle_strb ( hs_gen__ocycle_strb ) , - .ocycle_col_idx ( hs_gen__ocycle_col_idx ) , - .ocycle_shift ( hs_gen__ocycle_shift ) - ); - end - else begin - ldpc_dvb_enc_hs_gen - #( - .pXMODE ( pXMODE ) , - .pPIPE ( 1 ) // 2 tick latency - ) - hs_gen - ( - .iclk ( iclk ) , - .ireset ( ireset ) , - .iclkena ( iclkena ) , - // - .icode_ctx ( hs_gen__icode_ctx ) , - // - .oused_col ( hs_gen__oused_col ) , - .oused_data_col ( hs_gen__oused_data_col ) , - .oused_row ( hs_gen__oused_row ) , - .ocycle_max_num ( hs_gen__ocycle_max_num ) , - // - .icycle_read ( hs_gen__icycle_read ) , - .icycle_idx ( hs_gen__icycle_idx ) , - // - .ocycle_read ( hs_gen__ocycle_read ) , - .ocycle_strb ( hs_gen__ocycle_strb ) , - .ocycle_col_idx ( hs_gen__ocycle_col_idx ) , - .ocycle_shift ( hs_gen__ocycle_shift ) - ); - end - endgenerate + ldpc_dvb_enc_hs + #( + .pXMODE ( pXMODE ) , + .pPIPE ( 1 ) // 2 tick latency + ) + hs + ( + .iclk ( iclk ) , + .ireset ( ireset ) , + .iclkena ( iclkena ) , + // + .icode_ctx ( hs_gen__icode_ctx ) , + // + .oused_col ( hs_gen__oused_col ) , + .oused_data_col ( hs_gen__oused_data_col ) , + .oused_row ( hs_gen__oused_row ) , + .ocycle_max_num ( hs_gen__ocycle_max_num ) , + // + .icycle_read ( hs_gen__icycle_read ) , + .icycle_idx ( hs_gen__icycle_idx ) , + // + .ocycle_read ( hs_gen__ocycle_read ) , + .ocycle_strb ( hs_gen__ocycle_strb ) , + .ocycle_col_idx ( hs_gen__ocycle_col_idx ) , + .ocycle_shift ( hs_gen__ocycle_shift ) + ); - assign hs_gen__icode_ctx = icode_ctx; + assign hs_gen__icode_ctx = '{xmode : pXMODE, gr : pCODEGR, coderate : pCODERATE}; assign hs_gen__icycle_read = ctrl__ocycle_read; assign hs_gen__icycle_idx = ctrl__ocycle_idx; @@ -570,7 +544,10 @@ module ldpc_dvb_enc_engine .owfull ( mux__owfull ) , .owrite ( mux__owrite ) , .owaddr ( mux__owaddr ) , - .owdat ( mux__owdat ) + .owdat ( mux__owdat ) , + // + .opwrite ( mux__opwrite ) , + .opwaddr ( mux__opwaddr ) ); always_ff @(posedge iclk) begin @@ -599,6 +576,9 @@ module ldpc_dvb_enc_engine assign owaddr = mux__owaddr[pWADDR_W-1 : 0]; assign owdat = mux__owdat; + assign opwrite = mux__opwrite; + assign opwaddr = mux__opwaddr[pWADDR_W-1 : 0]; + always_ff @(posedge iclk) begin if (iclkena) begin if (ctrl__ostart) begin diff --git a/rtl/ldpc_dvb/enc/ldpc_dvb_enc_fix.sv b/rtl/ldpc_dvb/enc/ldpc_dvb_enc_fix.sv index ad1ac28..03e5711 100644 --- a/rtl/ldpc_dvb/enc/ldpc_dvb_enc_fix.sv +++ b/rtl/ldpc_dvb/enc/ldpc_dvb_enc_fix.sv @@ -5,8 +5,8 @@ parameter int pDAT_W = 8 ; parameter int pTAG_W = 4 ; parameter bit pDO_TRANSPONSE = 0 ; - - parameter bit pCODEGR = 0 ; + parameter int pTR_DAT_W = 8 ; + parameter int pCODEGR = 0 ; parameter int pCODERATE = 9 ; parameter bit pXMODE = 0 ; @@ -42,6 +42,7 @@ .pDAT_W ( pDAT_W ) , .pTAG_W ( pTAG_W ) , .pDO_TRANSPONSE ( pDO_TRANSPONSE ) , + .pTR_DAT_W ( pTR_DAT_W ) , .pCODEGR ( pCODEGR ) , .pCODERATE ( pCODERATE ) , .pXMODE ( pXMODE ) @@ -99,7 +100,6 @@ // Description : fixed mode DVB RTL encoder with asynchronus input/output/core clocks // - module ldpc_dvb_enc_fix ( iclk , @@ -130,11 +130,12 @@ module ldpc_dvb_enc_fix parameter int pDAT_W = 8 ; // must be multiply of cZC_MAX (360) parameter int pTAG_W = 4 ; parameter bit pDO_TRANSPONSE = 0 ; // do output transponse to be like DVB-S standart or not + parameter int pTR_DAT_W = 8 ; // transponce engine internal data bitwidth. only 4/8/16 support `include "../ldpc_dvb_constants.svh" `include "ldpc_dvb_enc_types.svh" - parameter bit pCODEGR = cCODEGR_LARGE ; // short(0)/large(1) graph + parameter int pCODEGR = cCODEGR_LARGE ; // short(0)/large(1)/medium(2) graph parameter int pCODERATE = cCODERATE_5by6 ; // coderate table see in ldpc_dvb_constants.svh parameter bit pXMODE = 0 ; // DVB-S2X code tables using @@ -191,7 +192,7 @@ module ldpc_dvb_enc_fix localparam int cOB_DAT_W = cZC_MAX; localparam int cOB_TAG_W = pTAG_W + cOB_ADDR_W; - localparam int cZC_FACTOR = cIB_RDAT_W/cIB_WDAT_W; + localparam int cZC_FACTOR = cIB_RDAT_W/cIB_WDAT_W; //------------------------------------------------------------------------------------------------------ // @@ -235,7 +236,6 @@ module ldpc_dvb_enc_fix // // engine logic engine__irbuf_full ; - code_ctx_t engine__icode_ctx ; // logic [cZC_MAX-1 : 0] engine__irdat ; logic [pTAG_W-1 : 0] engine__irtag ; @@ -253,6 +253,27 @@ module ldpc_dvb_enc_fix logic [cOB_ADDR_W-1 : 0] engine__owaddr ; logic [cZC_MAX-1 : 0] engine__owdat ; logic [pTAG_W-1 : 0] engine__owtag ; + // + logic engine__opwrite ; + logic [cOB_ADDR_W-1 : 0] engine__opwaddr ; + + // + // optional transponse + logic [cOB_ADDR_W-1 : 0] transponse__iwrow ; + logic [cOB_ADDR_W-1 : 0] transponse__iwdata_col ; + // + logic transponse__iwrite ; + logic transponse__iwfull ; + logic [cOB_ADDR_W-1 : 0] transponse__iwaddr ; + logic [cZC_MAX-1 : 0] transponse__iwdat ; + logic transponse__ipwrite ; + logic [cOB_ADDR_W-1 : 0] transponse__ipwaddr ; + logic transponse__ordy ; + // + logic transponse__owrite ; + logic transponse__owfull ; + logic [cOB_ADDR_W-1 : 0] transponse__owaddr ; + logic [cZC_MAX-1 : 0] transponse__owdat ; // // output buffer @@ -417,7 +438,7 @@ module ldpc_dvb_enc_fix // engine //------------------------------------------------------------------------------------------------------ - ldpc_dvb_enc_engine + ldpc_dvb_enc_engine_fix #( .pRADDR_W ( cIB_RADDR_W ) , .pWADDR_W ( cOB_ADDR_W ) , @@ -425,8 +446,8 @@ module ldpc_dvb_enc_fix .pTAG_W ( pTAG_W ) , // .pCODEGR ( pCODEGR ) , - .pXMODE ( pXMODE ) , - .pFIX_MODE ( 1 ) + .pCODERATE ( pCODERATE ) , + .pXMODE ( pXMODE ) ) engine ( @@ -435,7 +456,6 @@ module ldpc_dvb_enc_fix .iclkena ( 1'b1 ) , // .irbuf_full ( engine__irbuf_full ) , - .icode_ctx ( engine__icode_ctx ) , // .irdat ( engine__irdat ) , .irtag ( engine__irtag ) , @@ -452,12 +472,14 @@ module ldpc_dvb_enc_fix .owfull ( engine__owfull ) , .owaddr ( engine__owaddr ) , .owdat ( engine__owdat ) , - .owtag ( engine__owtag ) + .owtag ( engine__owtag ) , + // + .opwrite ( engine__opwrite ) , + .opwaddr ( engine__opwaddr ) ); assign engine__irbuf_full = ibuffer__orfull; - assign engine__icode_ctx = '{xmode : pXMODE, gr : pCODEGR, coderate : pCODERATE}; assign engine__irtag = ibuffer__ortag; assign engine__irdat = ibuffer__ordat; @@ -468,7 +490,47 @@ module ldpc_dvb_enc_fix generate if (pDO_TRANSPONSE) begin : transponse_inst_gen - assign engine__iwbuf_empty = '0; + ldpc_dvb_enc_transponse + #( + .pADDR_W ( cOB_ADDR_W ) , + .pDAT_W ( cZC_MAX ) , + .pTR_DAT_W ( pTR_DAT_W ) + ) + transponse + ( + .iclk ( iclk ) , + .ireset ( ireset ) , + .iclkena ( 1'b1 ) , + // + .iwrow ( transponse__iwrow ) , + .iwdata_col ( transponse__iwdata_col ) , + // + .iwrite ( transponse__iwrite ) , + .iwfull ( transponse__iwfull ) , + .iwaddr ( transponse__iwaddr ) , + .iwdat ( transponse__iwdat ) , + .ipwrite ( transponse__ipwrite ) , + .ipwaddr ( transponse__ipwaddr ) , + .ordy ( transponse__ordy ) , + // + .owrite ( transponse__owrite ) , + .owfull ( transponse__owfull ) , + .owaddr ( transponse__owaddr ) , + .owdat ( transponse__owdat ) + ); + + assign transponse__iwrow = engine__owrow ; + assign transponse__iwdata_col = engine__owdata_col; + + assign transponse__iwrite = engine__owrite ; + assign transponse__iwfull = engine__owfull ; + assign transponse__iwaddr = engine__owaddr ; + assign transponse__iwdat = engine__owdat ; + // + assign transponse__ipwrite = engine__opwrite ; + assign transponse__ipwaddr = engine__opwaddr ; + // + assign engine__iwbuf_empty = transponse__ordy & obuffer__owempty; end else begin assign engine__iwbuf_empty = obuffer__owempty; @@ -520,12 +582,13 @@ module ldpc_dvb_enc_fix generate if (pDO_TRANSPONSE) begin : transponse_path_gen - assign obuffer__iwrite = '0; - assign obuffer__iwfull = '0; - assign obuffer__iwaddr = '0; - assign obuffer__iwdat = '0; + assign obuffer__iwrite = transponse__owrite; + assign obuffer__iwfull = transponse__owfull; + assign obuffer__iwaddr = transponse__owaddr; + assign obuffer__iwdat = transponse__owdat ; - assign obuffer__iwtag = '0; + // can make so because engine wait for transponse end + assign obuffer__iwtag = {engine__owcol, engine__owtag}; end else begin : no_transponse_path_gen diff --git a/rtl/ldpc_dvb/enc/ldpc_dvb_enc_mux.sv b/rtl/ldpc_dvb/enc/ldpc_dvb_enc_mux.sv index 97ad3c5..cd7c408 100644 --- a/rtl/ldpc_dvb/enc/ldpc_dvb_enc_mux.sv +++ b/rtl/ldpc_dvb/enc/ldpc_dvb_enc_mux.sv @@ -24,6 +24,9 @@ logic ldpc_dvb_enc_mux__owrite ; col_t ldpc_dvb_enc_mux__owaddr ; zdat_t ldpc_dvb_enc_mux__owdat ; + // + logic ldpc_dvb_enc_mux__opwrite ; + col_t ldpc_dvb_enc_mux__opwaddr ; @@ -48,7 +51,10 @@ .owfull ( ldpc_dvb_enc_mux__owfull ) , .owrite ( ldpc_dvb_enc_mux__owrite ) , .owaddr ( ldpc_dvb_enc_mux__owaddr ) , - .owdat ( ldpc_dvb_enc_mux__owdat ) + .owdat ( ldpc_dvb_enc_mux__owdat ) , + // + .opwrite ( ldpc_dvb_enc_mux__opwrite ) , + .opwaddr ( ldpc_dvb_enc_mux__opwaddr ) ); @@ -95,7 +101,10 @@ module ldpc_dvb_enc_mux owfull , owrite , owaddr , - owdat + owdat , + // + opwrite , + opwaddr ); `include "../ldpc_dvb_constants.svh" @@ -124,6 +133,9 @@ module ldpc_dvb_enc_mux output logic owrite ; output col_t owaddr ; output zdat_t owdat ; + // + output logic opwrite ; + output col_t opwaddr ; //------------------------------------------------------------------------------------------------------ // @@ -131,23 +143,26 @@ module ldpc_dvb_enc_mux always_ff @(posedge iclk or posedge ireset) begin if (ireset) begin - owrite <= 1'b0; - owfull <= 1'b0; + owrite <= 1'b0; + owfull <= 1'b0; + opwrite <= 1'b0; end else if (iclkena) begin - owrite <= (ival | ipval); - owfull <= (ipval & ipstrb.eof); + owrite <= (ival | ipval); + owfull <= (ipval & ipstrb.eof); + opwrite <= ipval; end end always_ff @(posedge iclk) begin if (iclkena) begin if (ival | ipval) begin - owaddr <= icol; - owdat <= idat; + owaddr <= icol; + owdat <= idat; if (ipval) begin - owaddr <= ipstrb.sof ? iused_data_col : (owaddr + 1'b1); - owdat <= ipstrb.sof ? (ipacc ^ ipline) : (ipacc ^ owdat); + owaddr <= ipstrb.sof ? iused_data_col : (owaddr + 1'b1); + owdat <= ipstrb.sof ? (ipacc ^ ipline) : (ipacc ^ owdat); + opwaddr <= ipstrb.sof ? '0 : (opwaddr + 1'b1); end end end diff --git a/rtl/ldpc_dvb/enc/ldpc_dvb_enc_transponse.sv b/rtl/ldpc_dvb/enc/ldpc_dvb_enc_transponse.sv new file mode 100644 index 0000000..3454cd3 --- /dev/null +++ b/rtl/ldpc_dvb/enc/ldpc_dvb_enc_transponse.sv @@ -0,0 +1,348 @@ +/* + + + + parameter int pADDR_W = 8 ; + parameter int pDAT_W = 360 ; + parameter int pTR_DAT_W = 8 ; + + + + logic ldpc_dvb_enc_transponse__iclk ; + logic ldpc_dvb_enc_transponse__ireset ; + logic ldpc_dvb_enc_transponse__iclkena ; + // + logic [pADDR_W-1 : 0] ldpc_dvb_enc_transponse__iwrow ; + logic [pADDR_W-1 : 0] ldpc_dvb_enc_transponse__iwdata_col ; + // + logic ldpc_dvb_enc_transponse__iwrite ; + logic ldpc_dvb_enc_transponse__iwfull ; + logic [pADDR_W-1 : 0] ldpc_dvb_enc_transponse__iwaddr ; + logic [pDAT_W-1 : 0] ldpc_dvb_enc_transponse__iwdat ; + logic ldpc_dvb_enc_transponse__ipwrite ; + logic [pADDR_W-1 : 0] ldpc_dvb_enc_transponse__ipwaddr ; + logic ldpc_dvb_enc_transponse__ordy ; + // + logic ldpc_dvb_enc_transponse__owrite ; + logic ldpc_dvb_enc_transponse__owfull ; + logic [pADDR_W-1 : 0] ldpc_dvb_enc_transponse__owaddr ; + logic [pDAT_W-1 : 0] ldpc_dvb_enc_transponse__owdat ; + + + + ldpc_dvb_enc_transponse + #( + .pADDR_W ( pADDR_W ) , + .pDAT_W ( pDAT_W ) , + .pTR_DAT_W ( pTR_DAT_W ) + ) + ldpc_dvb_enc_transponse + ( + .iclk ( ldpc_dvb_enc_transponse__iclk ) , + .ireset ( ldpc_dvb_enc_transponse__ireset ) , + .iclkena ( ldpc_dvb_enc_transponse__iclkena ) , + // + .iwrow ( ldpc_dvb_enc_transponse__iwrow ) , + .iwdata_col ( ldpc_dvb_enc_transponse__iwdata_col ) , + // + .iwrite ( ldpc_dvb_enc_transponse__iwrite ) , + .iwfull ( ldpc_dvb_enc_transponse__iwfull ) , + .iwaddr ( ldpc_dvb_enc_transponse__iwaddr ) , + .iwdat ( ldpc_dvb_enc_transponse__iwdat ) , + .ipwrite ( ldpc_dvb_enc_transponse__ipwrite ) , + .ipwaddr ( ldpc_dvb_enc_transponse__ipwaddr ) , + .ordy ( ldpc_dvb_enc_transponse__ordy ) , + // + .owrite ( ldpc_dvb_enc_transponse__owrite ) , + .owfull ( ldpc_dvb_enc_transponse__owfull ) , + .owaddr ( ldpc_dvb_enc_transponse__owaddr ) , + .owdat ( ldpc_dvb_enc_transponse__owdat ) + ); + + + assign ldpc_dvb_enc_transponse__iclk = '0 ; + assign ldpc_dvb_enc_transponse__ireset = '0 ; + assign ldpc_dvb_enc_transponse__iclkena = '0 ; + assign ldpc_dvb_enc_transponse__iwrow = '0 ; + assign ldpc_dvb_enc_transponse__iwdata_col = '0 ; + assign ldpc_dvb_enc_transponse__iwrite = '0 ; + assign ldpc_dvb_enc_transponse__iwfull = '0 ; + assign ldpc_dvb_enc_transponse__iwaddr = '0 ; + assign ldpc_dvb_enc_transponse__iwdat = '0 ; + assign ldpc_dvb_enc_transponse__ipwrite = '0 ; + assign ldpc_dvb_enc_transponse__ipwaddr = '0 ; + + + +*/ + +// +// Project : ldpc DVB-S2 +// Author : Shekhalev Denis (des00) +// Workfile : ldpc_dvb_enc_transponse.sv +// Description : transponse {row x pDAT_W} parity bits matrix unit +// + +module ldpc_dvb_enc_transponse +#( + parameter int pADDR_W = 8 , + parameter int pDAT_W = 360 , + parameter int pTR_DAT_W = 8 // transponse dat_W +) +( + iclk , + ireset , + iclkena , + // + iwrow , + iwdata_col , + // + iwrite , + iwfull , + iwaddr , + iwdat , + ipwrite , + ipwaddr , + ordy , + // + owrite , + owfull , + owaddr , + owdat +); + + //------------------------------------------------------------------------------------------------------ + // + //------------------------------------------------------------------------------------------------------ + + input logic iclk ; + input logic ireset ; + input logic iclkena ; + // + input logic [pADDR_W-1 : 0] iwrow ; + input logic [pADDR_W-1 : 0] iwdata_col ; + // + input logic iwrite ; + input logic iwfull ; + input logic [pADDR_W-1 : 0] iwaddr ; + input logic [pDAT_W-1 : 0] iwdat ; + input logic ipwrite ; + input logic [pADDR_W-1 : 0] ipwaddr ; + output logic ordy ; + // + output logic owrite ; + output logic owfull ; + output logic [pADDR_W-1 : 0] owaddr ; + output logic [pDAT_W-1 : 0] owdat ; + + //------------------------------------------------------------------------------------------------------ + // + //------------------------------------------------------------------------------------------------------ + + localparam int cLOG2_TR_DAT_W = $clog2(pTR_DAT_W); + + localparam int cMEM_ADDR_W = pADDR_W - cLOG2_TR_DAT_W; + localparam int cMEM_DAT_W = pDAT_W; + + localparam int cSHIFT_W = cLOG2_TR_DAT_W + 1; // +1 bit for full shift + localparam int cROW_W = pADDR_W; + localparam int cSEL_W = $clog2(pDAT_W); + + //------------------------------------------------------------------------------------------------------ + // + //------------------------------------------------------------------------------------------------------ + + // + // parity mem + logic mem__iwrite [pTR_DAT_W]; + logic [cMEM_ADDR_W-1 : 0] mem__iwaddr [pTR_DAT_W]; + logic [cMEM_DAT_W-1 : 0] mem__iwdat [pTR_DAT_W]; + // + logic [cMEM_ADDR_W-1 : 0] mem__iraddr [pTR_DAT_W]; + logic [cMEM_DAT_W-1 : 0] mem__ordat [pTR_DAT_W]; + + // ctrl + logic [cROW_W-1 : 0] ctrl__iwrow ; + logic ctrl__iwfull ; + logic ctrl__ordy ; + // + logic ctrl__ibusy ; + logic ctrl__odone ; + // + logic [cROW_W-1 : 0] ctrl__otrow ; + logic [cSEL_W-1 : 0] ctrl__otsel ; + // + logic ctrl__oval ; + logic ctrl__oload ; + logic ctrl__owrite ; + logic [cSHIFT_W-1 : 0] ctrl__oashift ; + logic [cSHIFT_W-1 : 0] ctrl__otshift ; + + // accumulator + logic acc__ival ; + logic acc__iload ; + logic acc__iwrite ; + logic [cSHIFT_W-1 : 0] acc__iashift ; + logic [cSHIFT_W-1 : 0] acc__itshift ; + logic [pTR_DAT_W-1 : 0] acc__idat ; + // + logic acc__owrite ; + logic [pDAT_W-1 : 0] acc__owdat ; + + //------------------------------------------------------------------------------------------------------ + // small rams buffer (1 tick read delay) for parity bits + //------------------------------------------------------------------------------------------------------ + + genvar g; + + generate + for (g = 0; g < pTR_DAT_W; g++) begin : transp_ram_gen_inst + codec_mem_block + #( + .pADDR_W ( cMEM_ADDR_W ) , + .pDAT_W ( cMEM_DAT_W ) , + .pPIPE ( 0 ) , // 1 tick read delay + .pUSE_DRAM ( (cMEM_ADDR_W <= 6) ) // use distributed ram for <= 64 words + ) + mem + ( + .iclk ( iclk ) , + .ireset ( ireset ) , + .iclkena ( iclkena ) , + // + .iwrite ( mem__iwrite [g] ) , + .iwaddr ( mem__iwaddr [g] ) , + .iwdat ( mem__iwdat [g] ) , + // + .iraddr ( mem__iraddr [g] ) , + .ordat ( mem__ordat [g] ) + ); + + assign mem__iwrite [g] = ipwrite & (ipwaddr[cLOG2_TR_DAT_W-1 : 0] == g); + assign mem__iwaddr [g] = ipwaddr[pADDR_W-1 : cLOG2_TR_DAT_W] ; + assign mem__iwdat [g] = iwdat ; + // + assign mem__iraddr [g] = ctrl__otrow ; + end + endgenerate + + //------------------------------------------------------------------------------------------------------ + // ctrl + //------------------------------------------------------------------------------------------------------ + + ldpc_dvb_enc_transponse_ctrl + #( + .pDAT_W ( pDAT_W ) , + .pTR_DAT_W ( pTR_DAT_W ) , + // + .pROW_W ( cROW_W ) , + .pSEL_W ( cSEL_W ) , + .pSHIFT_W ( cSHIFT_W ) + ) + ctrl + ( + .iclk ( iclk ) , + .ireset ( ireset ) , + .iclkena ( iclkena ) , + // + .iwrow ( ctrl__iwrow ) , + .iwfull ( ctrl__iwfull ) , + .ordy ( ctrl__ordy ) , + // + .ibusy ( ctrl__ibusy ) , + .odone ( ctrl__odone ) , + // + .otrow ( ctrl__otrow ) , + .otsel ( ctrl__otsel ) , + // + .oval ( ctrl__oval ) , + .oload ( ctrl__oload ) , + .owrite ( ctrl__owrite ) , + .oashift ( ctrl__oashift ) , + .otshift ( ctrl__otshift ) + ); + + assign ctrl__iwrow = iwrow ; + assign ctrl__iwfull = iwfull ; + + assign ctrl__ibusy = acc__ival ; + + assign ordy = ctrl__ordy; + + //------------------------------------------------------------------------------------------------------ + // line accumulator + //------------------------------------------------------------------------------------------------------ + + ldpc_dvb_enc_transponse_acc + #( + .pDAT_W ( pDAT_W ) , + .pTR_DAT_W ( pTR_DAT_W ) , + .pSHIFT_W ( cSHIFT_W ) + ) + acc + ( + .iclk ( iclk ) , + .ireset ( ireset ) , + .iclkena ( iclkena ) , + // + .ival ( acc__ival ) , + .iload ( acc__iload ) , + .iwrite ( acc__iwrite ) , + .iashift ( acc__iashift ) , + .itshift ( acc__itshift ) , + .idat ( acc__idat ) , + // + .owrite ( acc__owrite ) , + .owdat ( acc__owdat ) + ); + + // 2 tick delay inside ctrl + assign acc__ival = ctrl__oval; + assign acc__iload = ctrl__oload; + assign acc__iwrite = ctrl__owrite; + assign acc__iashift = ctrl__oashift; + assign acc__itshift = ctrl__otshift; + + //------------------------------------------------------------------------------------------------------ + // // allign 1 tick ram read delay + //------------------------------------------------------------------------------------------------------ + + logic [cSEL_W-1 : 0] ctrl_tsel; + + always_ff @(posedge iclk) begin + if (iclkena) begin + ctrl_tsel <= ctrl__otsel; + for (int i = 0; i < pTR_DAT_W; i++) begin + acc__idat[i] <= mem__ordat[i][ctrl_tsel]; + end + end + end + + //------------------------------------------------------------------------------------------------------ + // output muxer + //------------------------------------------------------------------------------------------------------ + + always_ff @(posedge iclk or posedge ireset) begin + if (ireset) begin + owrite <= 1'b0; + owfull <= 1'b0; + end + else if (iclkena) begin + owrite <= (iwrite & !ipwrite) | acc__owrite; + owfull <= ctrl__odone; + end + end + + always_ff @(posedge iclk) begin + if (iclkena) begin + if (iwrite) begin + owaddr <= !ipwrite ? iwaddr : (iwdata_col - 1'b1); // hold last address for parity start addr with incr + end + else if (acc__owrite) begin + owaddr <= owaddr + 1'b1; + end + owdat <= iwrite ? iwdat : acc__owdat; + end + end + +endmodule diff --git a/rtl/ldpc_dvb/enc/ldpc_dvb_enc_transponse_acc.sv b/rtl/ldpc_dvb/enc/ldpc_dvb_enc_transponse_acc.sv new file mode 100644 index 0000000..f540aa2 --- /dev/null +++ b/rtl/ldpc_dvb/enc/ldpc_dvb_enc_transponse_acc.sv @@ -0,0 +1,164 @@ +/* + + + + parameter int pDAT_W = 360 ; + parameter int pTR_DAT_W = 8 ; + parameter int pSHIFT_W = 8 ; + + + + logic ldpc_dvb_enc_transponse_acc__iclk ; + logic ldpc_dvb_enc_transponse_acc__ireset ; + logic ldpc_dvb_enc_transponse_acc__iclkena ; + // + logic ldpc_dvb_enc_transponse_acc__ival ; + logic ldpc_dvb_enc_transponse_acc__iload ; + logic ldpc_dvb_enc_transponse_acc__iwrite ; + logic [pSHIFT_W-1 : 0] ldpc_dvb_enc_transponse_acc__iashift ; + logic [pSHIFT_W-1 : 0] ldpc_dvb_enc_transponse_acc__itshift ; + logic [pTR_DAT_W-1 : 0] ldpc_dvb_enc_transponse_acc__idat ; + // + logic ldpc_dvb_enc_transponse_acc__owrite ; + logic [pDAT_W-1 : 0] ldpc_dvb_enc_transponse_acc__owdat ; + + + + ldpc_dvb_enc_transponse_acc + #( + .pDAT_W ( pDAT_W ) , + .pTR_DAT_W ( pTR_DAT_W ) , + .pSHIFT_W ( pSHIFT_W ) + ) + ldpc_dvb_enc_transponse_acc + ( + .iclk ( ldpc_dvb_enc_transponse_acc__iclk ) , + .ireset ( ldpc_dvb_enc_transponse_acc__ireset ) , + .iclkena ( ldpc_dvb_enc_transponse_acc__iclkena ) , + // + .ival ( ldpc_dvb_enc_transponse_acc__ival ) , + .iload ( ldpc_dvb_enc_transponse_acc__iload ) , + .iwrite ( ldpc_dvb_enc_transponse_acc__iwrite ) , + .iashift ( ldpc_dvb_enc_transponse_acc__iashift ) , + .itshift ( ldpc_dvb_enc_transponse_acc__itshift ) , + .idat ( ldpc_dvb_enc_transponse_acc__idat ) , + // + .owrite ( ldpc_dvb_enc_transponse_acc__owrite ) , + .owdat ( ldpc_dvb_enc_transponse_acc__owdat ) + ); + + + assign ldpc_dvb_enc_transponse_acc__iclk = '0 ; + assign ldpc_dvb_enc_transponse_acc__ireset = '0 ; + assign ldpc_dvb_enc_transponse_acc__iclkena = '0 ; + assign ldpc_dvb_enc_transponse_acc__ival = '0 ; + assign ldpc_dvb_enc_transponse_acc__iload = '0 ; + assign ldpc_dvb_enc_transponse_acc__iwrite = '0 ; + assign ldpc_dvb_enc_transponse_acc__iashift = '0 ; + assign ldpc_dvb_enc_transponse_acc__itshift = '0 ; + assign ldpc_dvb_enc_transponse_acc__idat = '0 ; + + + +*/ + +// +// Project : ldpc DVB-S2 +// Author : Shekhalev Denis (des00) +// Workfile : ldpc_dvb_enc_transponse_acc.sv +// Description : special DWC accumulator for transponse {row x pDAT_W} parity bits +// + +module ldpc_dvb_enc_transponse_acc +#( + parameter int pDAT_W = 360 , + parameter int pTR_DAT_W = 8 , + parameter int pSHIFT_W = 8 +) +( + iclk , + ireset , + iclkena , + // + ival , + iload , + iwrite , + iashift , + itshift , + idat , + // + owrite , + owdat +); + + //------------------------------------------------------------------------------------------------------ + // + //------------------------------------------------------------------------------------------------------ + + input logic iclk ; + input logic ireset ; + input logic iclkena ; + // + input logic ival ; + input logic iload ; + input logic iwrite ; + input logic [pSHIFT_W-1 : 0] iashift ; + input logic [pSHIFT_W-1 : 0] itshift ; + input logic [pTR_DAT_W-1 : 0] idat ; + // + output logic owrite ; + output logic [pDAT_W-1 : 0] owdat ; + + //------------------------------------------------------------------------------------------------------ + // + //------------------------------------------------------------------------------------------------------ + + logic [pTR_DAT_W-1 : 0] tmp_line; + logic [pDAT_W-1 : 0] acc_line; + + //------------------------------------------------------------------------------------------------------ + // optional write logic + //------------------------------------------------------------------------------------------------------ + + always_ff @(posedge iclk or posedge ireset) begin + if (ireset) begin + owrite <= 1'b0; + end + else if (iclkena) begin + owrite <= ival & iwrite; + end + end + + //------------------------------------------------------------------------------------------------------ + // acc logic + //------------------------------------------------------------------------------------------------------ + + always_ff @(posedge iclk) begin + if (iclkena) begin + if (ival) begin + if (iload) begin + {tmp_line, acc_line} <= {idat, acc_line} >> get_shift_value(iashift); + end + else begin + acc_line <= {tmp_line, acc_line} >> get_shift_value(itshift); + end + end + end + end + + assign owdat = acc_line; + + //------------------------------------------------------------------------------------------------------ + // function to scale shift to range [0 : pDAT_W] + //------------------------------------------------------------------------------------------------------ + + function logic [pSHIFT_W-1 : 0] get_shift_value (logic [pSHIFT_W-1 : 0] shift); + begin + get_shift_value = pDAT_W; + if (shift < pDAT_W) begin + get_shift_value = shift % pDAT_W; + end + end + endfunction + +endmodule diff --git a/rtl/ldpc_dvb/enc/ldpc_dvb_enc_transponse_ctrl.sv b/rtl/ldpc_dvb/enc/ldpc_dvb_enc_transponse_ctrl.sv new file mode 100644 index 0000000..7cdbf84 --- /dev/null +++ b/rtl/ldpc_dvb/enc/ldpc_dvb_enc_transponse_ctrl.sv @@ -0,0 +1,340 @@ +/* + + + + parameter int pDAT_W = 360 ; + parameter int pTR_DAT_W = 8 ; + // + parameter int pROW_W = 8 ; + parameter int pSEL_W = 9 ; + parameter int pSHIFT_W = 8 ; + + + + logic ldpc_dvb_enc_transponse_ctrl__iclk ; + logic ldpc_dvb_enc_transponse_ctrl__ireset ; + logic ldpc_dvb_enc_transponse_ctrl__iclkena ; + // + logic [pROW_W-1 : 0] ldpc_dvb_enc_transponse_ctrl__iwrow ; + logic ldpc_dvb_enc_transponse_ctrl__iwfull ; + logic ldpc_dvb_enc_transponse_ctrl__ordy ; + // + logic ldpc_dvb_enc_transponse_ctrl__ibusy ; + logic ldpc_dvb_enc_transponse_ctrl__odone ; + // + logic [pROW_W-1 : 0] ldpc_dvb_enc_transponse_ctrl__otrow ; + logic [pSEL_W-1 : 0] ldpc_dvb_enc_transponse_ctrl__otsel ; + // + logic ldpc_dvb_enc_transponse_ctrl__oval ; + logic ldpc_dvb_enc_transponse_ctrl__oload ; + logic ldpc_dvb_enc_transponse_ctrl__owrite ; + logic [pSHIFT_W-1 : 0] ldpc_dvb_enc_transponse_ctrl__oashift ; + logic [pSHIFT_W-1 : 0] ldpc_dvb_enc_transponse_ctrl__otshift ; + + + + ldpc_dvb_enc_transponse_ctrl + #( + .pDAT_W ( pDAT_W ) , + .pTR_DAT_W ( pTR_DAT_W ) , + // + .pROW_W ( pROW_W ) , + .pSEL_W ( pSEL_W ) , + .pSHIFT_W ( pSHIFT_W ) + ) + ldpc_dvb_enc_transponse_ctrl + ( + .iclk ( ldpc_dvb_enc_transponse_ctrl__iclk ) , + .ireset ( ldpc_dvb_enc_transponse_ctrl__ireset ) , + .iclkena ( ldpc_dvb_enc_transponse_ctrl__iclkena ) , + // + .iwrow ( ldpc_dvb_enc_transponse_ctrl__iwrow ) , + .iwfull ( ldpc_dvb_enc_transponse_ctrl__iwfull ) , + .ordy ( ldpc_dvb_enc_transponse_ctrl__ordy ) , + // + .ibusy ( ldpc_dvb_enc_transponse_ctrl__ibusy ) , + .odone ( ldpc_dvb_enc_transponse_ctrl__odone ) , + // + .otrow ( ldpc_dvb_enc_transponse_ctrl__otrow ) , + .otsel ( ldpc_dvb_enc_transponse_ctrl__otsel ) , + // + .oval ( ldpc_dvb_enc_transponse_ctrl__oval ) , + .oload ( ldpc_dvb_enc_transponse_ctrl__oload ) , + .owrite ( ldpc_dvb_enc_transponse_ctrl__owrite ) , + .oashift ( ldpc_dvb_enc_transponse_ctrl__oashift ) , + .otshift ( ldpc_dvb_enc_transponse_ctrl__otshift ) + ); + + + assign ldpc_dvb_enc_transponse_ctrl__iclk = '0 ; + assign ldpc_dvb_enc_transponse_ctrl__ireset = '0 ; + assign ldpc_dvb_enc_transponse_ctrl__iclkena = '0 ; + assign ldpc_dvb_enc_transponse_ctrl__iwrow = '0 ; + assign ldpc_dvb_enc_transponse_ctrl__iwfull = '0 ; + assign ldpc_dvb_enc_transponse_ctrl__ibusy = '0 ; + + + +*/ + +// +// Project : ldpc DVB-S2 +// Author : Shekhalev Denis (des00) +// Workfile : ldpc_dvb_enc_transponse_ctrl.sv +// Description : transponse {row x pDAT_W} parity bits matrix controller +// + +module ldpc_dvb_enc_transponse_ctrl +#( + parameter int pDAT_W = 360 , + parameter int pTR_DAT_W = 8 , + // + parameter int pROW_W = 8 , + parameter int pSEL_W = 9 , + parameter int pSHIFT_W = 8 +) +( + iclk , + ireset , + iclkena , + // + iwrow , + iwfull , + ordy , + // + ibusy , + odone , + // + otrow , + otsel , + // + oval , + oload , + owrite , + oashift , + otshift +); + + //------------------------------------------------------------------------------------------------------ + // + //------------------------------------------------------------------------------------------------------ + + input logic iclk ; + input logic ireset ; + input logic iclkena ; + // context + input logic [pROW_W-1 : 0] iwrow ; + input logic iwfull ; + output logic ordy ; + // system control + input logic ibusy ; + output logic odone ; + // ram read control + output logic [pROW_W-1 : 0] otrow ; + output logic [pSEL_W-1 : 0] otsel ; + // accumulator control + output logic oval ; + output logic oload ; + output logic owrite ; + output logic [pSHIFT_W-1 : 0] oashift ; + output logic [pSHIFT_W-1 : 0] otshift ; + + //------------------------------------------------------------------------------------------------------ + // + //------------------------------------------------------------------------------------------------------ + + localparam int cLOG2_TR_DAT_W = $clog2(pTR_DAT_W); + + //------------------------------------------------------------------------------------------------------ + // + //------------------------------------------------------------------------------------------------------ + + enum bit [2 : 0] { + cRESET_STATE , + // + cWAIT_STATE , + // + cINIT_STATE , + cDO_STATE , + // + cWAIT_NBUSY_STATE , + cDONE_STATE , + // + cRES0_STATE , + cRES1_STATE + } state /* synthesis syn_encoding = "sequential", fsm_encoding = "sequential" */; + + logic [pROW_W-1 : 0] max_row_m2; + logic single_row; + logic last_row_unfull; + + struct packed { + logic done; + logic [pSEL_W-1 : 0] value; + } tsel_cnt; + + struct packed { + logic done; + logic [pSEL_W-1 : 0] value; + } trow_cnt; + + logic [pSHIFT_W-1 : 0] bitnum; + logic [pSHIFT_W-1 : 0] bitnum_last; + + logic do_twice_shift; + logic do_tshift; + logic do_write; + + logic [pSEL_W : 0] new_sel; // + 1 bit for signum + logic [pSEL_W : 0] new_sel_m1; + + logic [pSHIFT_W-1 : 0] ashift; + logic [pSHIFT_W-1 : 0] tshift; + + //------------------------------------------------------------------------------------------------------ + // FSM + //------------------------------------------------------------------------------------------------------ + + wire work_done = tsel_cnt.done & trow_cnt.done; + + always_ff @(posedge iclk or posedge ireset) begin + if (ireset) begin + state <= cRESET_STATE; + end + else if (iclkena) begin + case (state) + cRESET_STATE : state <= cWAIT_STATE; + // + cWAIT_STATE : state <= iwfull ? cINIT_STATE : cWAIT_STATE; + // + cINIT_STATE : state <= cDO_STATE; + // + cDO_STATE : state <= work_done ? cWAIT_NBUSY_STATE : cDO_STATE; + // + cWAIT_NBUSY_STATE : state <= ibusy ? cWAIT_NBUSY_STATE : cDONE_STATE; + // + cDONE_STATE : state <= cWAIT_STATE; + // + cRES0_STATE : state <= cRESET_STATE; + cRES1_STATE : state <= cRESET_STATE; + default : state <= cRESET_STATE; + endcase + end + end + + assign ordy = (state == cWAIT_STATE); + assign odone = (state == cDONE_STATE); + + //------------------------------------------------------------------------------------------------------ + // FSM counters + //------------------------------------------------------------------------------------------------------ + + always_ff @(posedge iclk) begin + if (iclkena) begin + case (state) + cWAIT_STATE : begin + max_row_m2 <= (iwrow >> cLOG2_TR_DAT_W) + (iwrow[cLOG2_TR_DAT_W-1 : 0] != 0) - 2; + single_row <= (iwrow <= pTR_DAT_W); + last_row_unfull <= (iwrow[cLOG2_TR_DAT_W-1 : 0] != 0); + // + bitnum_last <= iwrow[cLOG2_TR_DAT_W-1 : 0]; + end + // + cINIT_STATE : begin + tsel_cnt <= '0; + trow_cnt <= '0; + trow_cnt.done <= single_row; + end + // + cDO_STATE : begin + if (!do_twice_shift) begin + trow_cnt.value <= trow_cnt.done ? '0 : (trow_cnt.value + 1'b1); + trow_cnt.done <= single_row | (trow_cnt.value == max_row_m2); + // + if (trow_cnt.done) begin + tsel_cnt.value <= tsel_cnt.value + 1'b1; + tsel_cnt.done <= (tsel_cnt.value == (pDAT_W-2)); + end + end + end + endcase + end + end + + //------------------------------------------------------------------------------------------------------ + // FSM decode transponse + //------------------------------------------------------------------------------------------------------ + + assign bitnum = (trow_cnt.done & last_row_unfull) ? bitnum_last : pTR_DAT_W; + + assign do_twice_shift = new_sel[$high(new_sel)]; + assign do_write = new_sel[$high(new_sel)] | new_sel_m1[$high(new_sel_m1)]; + + always_ff @(posedge iclk) begin + if (iclkena) begin + case (state) + cINIT_STATE : begin + new_sel <= pDAT_W; + new_sel_m1 <= pDAT_W-1; + end + cDO_STATE : begin + if (do_twice_shift) begin // do pause + new_sel <= pDAT_W + new_sel; + new_sel_m1 <= pDAT_W + new_sel_m1; + end + else if (do_write) begin + new_sel <= pDAT_W + new_sel - bitnum; + new_sel_m1 <= pDAT_W + new_sel_m1 - bitnum; + end + else begin + new_sel <= new_sel - bitnum; + new_sel_m1 <= new_sel_m1 - bitnum; + end + end + default : begin + new_sel <= pDAT_W; + new_sel_m1 <= pDAT_W-1; + end + endcase + // + end + end + + //------------------------------------------------------------------------------------------------------ + // output mapping + //------------------------------------------------------------------------------------------------------ + + logic val; + + // tick before val + assign otrow = trow_cnt.value; + assign otsel = tsel_cnt.value; + + always_ff @(posedge iclk or posedge ireset) begin + if (ireset) begin + val <= 1'b0; + oval <= 1'b0; + owrite <= 1'b0; + end + else if (iclkena) begin + val <= (state == cDO_STATE); + oval <= val; + owrite <= val & do_write; + end + end + + always_ff @(posedge iclk) begin + if (iclkena) begin + // align do_write offset + ashift <= bitnum; + // delay second phase of do_twice_shift + do_tshift <= do_twice_shift; + tshift <= 0 - new_sel; + // + oload <= !do_tshift; + oashift <= !do_twice_shift ? ashift : (ashift + new_sel); + otshift <= !do_tshift ? '0 : tshift; + end + end + +endmodule