diff --git a/cmake_targets/CMakeLists.txt b/cmake_targets/CMakeLists.txt
index eab3d5a068c7db0378c42efa58067e8769188874..06d93772e261eadae3f89c9e8517598a844acef2 100644
--- a/cmake_targets/CMakeLists.txt
+++ b/cmake_targets/CMakeLists.txt
@@ -1498,6 +1498,7 @@ set(PHY_SRC_UE
   ${OPENAIR1_DIR}/PHY/NR_TRANSPORT/nr_ulsch_demodulation.c
   ${OPENAIR1_DIR}/PHY/NR_REFSIG/nr_dmrs_rx.c
   ${OPENAIR1_DIR}/PHY/NR_REFSIG/nr_gold.c
+  ${OPENAIR1_DIR}/PHY/NR_REFSIG/scrambling_luts.c
   ${OPENAIR1_DIR}/PHY/NR_REFSIG/dmrs_nr.c
   ${OPENAIR1_DIR}/PHY/NR_REFSIG/ptrs_nr.c
   ${OPENAIR1_DIR}/PHY/NR_UE_ESTIMATION/filt16a_32.c
@@ -1519,6 +1520,7 @@ set(PHY_SRC_UE
   ${PHY_SMALLBLOCKSRC}
   ${PHY_NR_CODINGIF}
   ${OPENAIR1_DIR}/PHY/NR_TRANSPORT/pucch_rx.c 
+  ${OPENAIR1_DIR}/PHY/NR_TRANSPORT/nr_uci_tools_common.c
   )
   set(PHY_NR_UE_SRC
   ${OPENAIR1_DIR}/PHY/INIT/nr_parms.c
@@ -1542,6 +1544,7 @@ set(PHY_SRC_UE
   ${OPENAIR1_DIR}/PHY/NR_UE_TRANSPORT/dci_nr.c
   ${OPENAIR1_DIR}/PHY/NR_UE_TRANSPORT/dci_tools_nr.c
   ${OPENAIR1_DIR}/PHY/NR_UE_TRANSPORT/pucch_nr.c
+  ${OPENAIR1_DIR}/PHY/NR_TRANSPORT/nr_uci_tools_common.c
   ${OPENAIR1_DIR}/PHY/NR_UE_TRANSPORT/nr_ulsch_ue.c
   ${OPENAIR1_DIR}/PHY/NR_REFSIG/ul_ref_seq_nr.c
   ${OPENAIR1_DIR}/PHY/NR_REFSIG/nr_dmrs_rx.c
diff --git a/cmake_targets/autotests/test_case_list.xml b/cmake_targets/autotests/test_case_list.xml
index 0e6435aaf3d2cb3dd05284d72bf8139d1bcfd2c0..882670727b7341de4c6d250bdf726b3bf3e0ed80 100644
--- a/cmake_targets/autotests/test_case_list.xml
+++ b/cmake_targets/autotests/test_case_list.xml
@@ -1176,21 +1176,38 @@
 
     <testCase id="015109">
       <class>execution</class>
-      <desc>nr_pucchsim Test cases. (Test1: Format 0 ACK miss 106 PRB),
-                                    (Test2: Format 1 ACK miss 106 PRB),
-				                    (Test3: Format 1 ACK miss 273 PRB),
-			                        (Test4: Format 1 NACKtoACK 106 PRB)</desc>
+      <desc>nr_pucchsim Test cases. (Test1: Format 0 1-bit ACK miss 106 PRB),
+                                    (Test2: Format 0 2-bit ACK miss 106 PRB),
+                                    (Test3: Format 0 2-bit ACK miss, 1-bit SR 106 PRB),
+				    (Test4: Format 2 3-bit 106 PRB),
+                                    (Test5: Format 2 4-bit 106 PRB),
+                                    (Test6: Format 2 5-bit 106 PRB),
+                                    (Test7: Format 2 6-bit 106 PRB),
+                                    (Test8: Format 2 7-bit 106 PRB),
+                                    (Test9: Format 2 8-bit 106 PRB),
+                                    (Test10: Format 2 9-bit 106 PRB),
+                                    (Test11: Format 2 10-bit 106 PRB),
+                                    (Test12: Format 2 11-bit 106 PRB)</desc>
       <pre_compile_prog></pre_compile_prog>
       <compile_prog>$OPENAIR_DIR/cmake_targets/build_oai</compile_prog>
       <compile_prog_args> --phy_simulators  -c </compile_prog_args>
       <pre_exec>$OPENAIR_DIR/cmake_targets/autotests/tools/free_mem.bash</pre_exec>
       <pre_exec_args></pre_exec_args>
       <main_exec> $OPENAIR_DIR/targets/bin/nr_pucchsim.Rel15</main_exec>
-      <main_exec_args>-R 106 -i 1 -P 0 -b 1 -s3 -n100
-	                  -R 106 -i 14 -P 1 -b 1 -s-6 -n100
-                      -R 273 -i 14 -P 1 -b 1 -s-6 -n100
-                      -R 106 -i 14 -P 1 -b 1 -s-6 -T 0.001 -n1000</main_exec_args>
-      <tags>nr_pucchsim.test1 nr_pucchsim.test2 nr_pucchsim.test3 nr_pucchsim.test4</tags>
+      <main_exec_args>-R 106 -i 1 -P 0 -b 1 -s-2 -n1000
+                      -R 106 -i 1 -P 0 -b 2 -s-2 -n1000
+		      -R 106 -i 1 -P 0 -b 2 -s-2 -c -n1000
+                      -R 106 -i 1 -P 2 -b 3 -s0 -n1000
+		      -R 106 -i 1 -P 2 -b 4 -s0 -n1000
+		      -R 106 -i 1 -P 2 -b 5 -s1 -n1000
+		      -R 106 -i 1 -P 2 -b 6 -s2 -n1000
+		      -R 106 -i 1 -P 2 -b 7 -s3 -n1000
+		      -R 106 -i 1 -P 2 -b 8 -s4 -n1000
+		      -R 106 -i 1 -P 2 -b 9 -s5 -n1000
+		      -R 106 -i 1 -P 2 -b 10 -s6 -n1000
+		      -R 106 -i 1 -P 2 -b 11 -s6 -n1000
+                      </main_exec_args>
+      <tags>nr_pucchsim.test1 nr_pucchsim.test2 nr_pucchsim.test3 nr_pucchsim.test4 nr_pucchsim.test5 nr_pucchsim.test6 nr_pucchsim.test7 nr_pucchsim.test8 nr_pucchsim.test9 nr_pucchsim.test10 nr_pucchsim.test11 nr_pucchsim.test12 </tags>
       <search_expr_true>PUCCH test OK</search_expr_true>
       <search_expr_false>segmentation fault|assertion|exiting|fatal</search_expr_false>
       <nruns>3</nruns>
diff --git a/nfapi/open-nFAPI/nfapi/public_inc/nfapi_nr_interface_scf.h b/nfapi/open-nFAPI/nfapi/public_inc/nfapi_nr_interface_scf.h
index 8a25a04f7bd2953ddaae0646b474f0c82190bc93..54b592202d5bd1270355eeac2c61066e602b8658 100644
--- a/nfapi/open-nFAPI/nfapi/public_inc/nfapi_nr_interface_scf.h
+++ b/nfapi/open-nFAPI/nfapi/public_inc/nfapi_nr_interface_scf.h
@@ -19,6 +19,7 @@
 
 #define NFAPI_MAX_NUM_UL_UE_PER_GROUP 6
 #define NFAPI_MAX_NUM_UL_PDU 8
+#define NFAPI_MAX_NUM_UCI_INDICATION 8
 #define NFAPI_MAX_NUM_GROUPS 8
 #define NFAPI_MAX_NUM_CB 8
 
@@ -1519,8 +1520,8 @@ typedef struct
   uint8_t  ul_cqi;
   uint16_t timing_advance;
   uint16_t rssi;
-  nfapi_nr_sr_pdu_0_1_t sr;//67
-  nfapi_nr_harq_pdu_0_1_t harq;//68
+  nfapi_nr_sr_pdu_0_1_t *sr;//67
+  nfapi_nr_harq_pdu_0_1_t *harq;//68
   
 
 }nfapi_nr_uci_pucch_pdu_format_0_1_t;
@@ -1542,28 +1543,22 @@ typedef struct
 
 }nfapi_nr_uci_pucch_pdu_format_2_3_4_t;
 
-//for SR, HARQ and CSI Part 1/ 2 PDUs
-
-typedef struct
-{
-  nfapi_nr_uci_pusch_pdu_t* pusch_pdu;
-  nfapi_nr_uci_pucch_pdu_format_0_1_t* pucch_pdu_format_0_1;
-  nfapi_nr_uci_pucch_pdu_format_2_3_4_t* pucch_pdu_format_2_3_4;
-  nfapi_nr_sr_pdu_0_1_t*   sr_pdu_0_1;
-  nfapi_nr_sr_pdu_2_3_4_t* sr_pdu_2_3_4;
-  nfapi_nr_harq_pdu_0_1_t* harq_pdu_0_1;
-  nfapi_nr_harq_pdu_2_3_4_t* harq_pdu_2_3_4;
-  nfapi_nr_csi_part1_pdu_t*  csi_part1_pdu;
-  nfapi_nr_csi_part2_pdu_t*  csi_part2_pdu;
-
-} nfapi_nr_uci_pdu_information_t;
+typedef enum {
+  NFAPI_NR_UCI_PDCCH_PDU_TYPE  = 0,
+  NFAPI_NR_UCI_FORMAT_0_1_PDU_TYPE  = 1,
+  NFAPI_NR_UCI_FORMAT_2_3_4_PDU_TYPE = 2,
+} nfapi_nr_uci_pdu_type_e;
 
 typedef struct
 {
-  uint16_t pdu_type;
+  uint16_t pdu_type;  // 0 for PDU on PUSCH, 1 for PUCCH format 0 or 1, 2 for PUCCH format 2 to 4
   uint16_t pdu_size;
-  nfapi_nr_uci_pdu_information_t uci_pdu;
-
+  union
+  {
+    nfapi_nr_uci_pusch_pdu_t pusch_pdu;
+    nfapi_nr_uci_pucch_pdu_format_0_1_t pucch_pdu_format_0_1;
+    nfapi_nr_uci_pucch_pdu_format_2_3_4_t pucch_pdu_format_2_3_4;
+  };
 } nfapi_nr_uci_t;
 
 typedef struct
@@ -1571,7 +1566,7 @@ typedef struct
   uint16_t sfn;
   uint16_t slot;
   uint16_t num_ucis;
-  nfapi_nr_uci_t* uci_list;
+  nfapi_nr_uci_t uci_list[NFAPI_MAX_NUM_UCI_INDICATION];
 
 } nfapi_nr_uci_indication_t;
 
diff --git a/openair1/PHY/CODING/nrLDPC_decoder/nrLDPC_mPass.h b/openair1/PHY/CODING/nrLDPC_decoder/nrLDPC_mPass.h
index 10b45ac0e786acc4bee2201d9b9aba14e26004db..b76750459d90830e3abd4ba103befb182e24376d 100644
--- a/openair1/PHY/CODING/nrLDPC_decoder/nrLDPC_mPass.h
+++ b/openair1/PHY/CODING/nrLDPC_decoder/nrLDPC_mPass.h
@@ -135,25 +135,25 @@ static inline void nrLDPC_llr2llrProcBuf(t_nrLDPC_lut* p_lut, int8_t* llr, t_nrL
 */
 static inline void nrLDPC_llr2CnProcBuf_BG1(t_nrLDPC_lut* p_lut, int8_t* llr, t_nrLDPC_procBuf* p_procBuf, uint16_t Z)
 {
-    const uint16_t (*lut_circShift_CNG3) [lut_numCnInCnGroups_BG1_R13[0]] = (uint16_t(*)[lut_numCnInCnGroups_BG1_R13[0]]) p_lut->circShift[0];
-    const uint16_t (*lut_circShift_CNG4) [lut_numCnInCnGroups_BG1_R13[1]] = (uint16_t(*)[lut_numCnInCnGroups_BG1_R13[1]]) p_lut->circShift[1];
-    const uint16_t (*lut_circShift_CNG5) [lut_numCnInCnGroups_BG1_R13[2]] = (uint16_t(*)[lut_numCnInCnGroups_BG1_R13[2]]) p_lut->circShift[2];
-    const uint16_t (*lut_circShift_CNG6) [lut_numCnInCnGroups_BG1_R13[3]] = (uint16_t(*)[lut_numCnInCnGroups_BG1_R13[3]]) p_lut->circShift[3];
-    const uint16_t (*lut_circShift_CNG7) [lut_numCnInCnGroups_BG1_R13[4]] = (uint16_t(*)[lut_numCnInCnGroups_BG1_R13[4]]) p_lut->circShift[4];
-    const uint16_t (*lut_circShift_CNG8) [lut_numCnInCnGroups_BG1_R13[5]] = (uint16_t(*)[lut_numCnInCnGroups_BG1_R13[5]]) p_lut->circShift[5];
-    const uint16_t (*lut_circShift_CNG9) [lut_numCnInCnGroups_BG1_R13[6]] = (uint16_t(*)[lut_numCnInCnGroups_BG1_R13[6]]) p_lut->circShift[6];
-    const uint16_t (*lut_circShift_CNG10)[lut_numCnInCnGroups_BG1_R13[7]] = (uint16_t(*)[lut_numCnInCnGroups_BG1_R13[7]]) p_lut->circShift[7];
-    const uint16_t (*lut_circShift_CNG19)[lut_numCnInCnGroups_BG1_R13[8]] = (uint16_t(*)[lut_numCnInCnGroups_BG1_R13[8]]) p_lut->circShift[8];
-
-    const uint8_t (*lut_posBnInCnProcBuf_CNG3) [lut_numCnInCnGroups_BG1_R13[0]] = (uint8_t(*)[lut_numCnInCnGroups_BG1_R13[0]]) p_lut->posBnInCnProcBuf[0];
-    const uint8_t (*lut_posBnInCnProcBuf_CNG4) [lut_numCnInCnGroups_BG1_R13[1]] = (uint8_t(*)[lut_numCnInCnGroups_BG1_R13[1]]) p_lut->posBnInCnProcBuf[1];
-    const uint8_t (*lut_posBnInCnProcBuf_CNG5) [lut_numCnInCnGroups_BG1_R13[2]] = (uint8_t(*)[lut_numCnInCnGroups_BG1_R13[2]]) p_lut->posBnInCnProcBuf[2];
-    const uint8_t (*lut_posBnInCnProcBuf_CNG6) [lut_numCnInCnGroups_BG1_R13[3]] = (uint8_t(*)[lut_numCnInCnGroups_BG1_R13[3]]) p_lut->posBnInCnProcBuf[3];
-    const uint8_t (*lut_posBnInCnProcBuf_CNG7) [lut_numCnInCnGroups_BG1_R13[4]] = (uint8_t(*)[lut_numCnInCnGroups_BG1_R13[4]]) p_lut->posBnInCnProcBuf[4];
-    const uint8_t (*lut_posBnInCnProcBuf_CNG8) [lut_numCnInCnGroups_BG1_R13[5]] = (uint8_t(*)[lut_numCnInCnGroups_BG1_R13[5]]) p_lut->posBnInCnProcBuf[5];
-    const uint8_t (*lut_posBnInCnProcBuf_CNG9) [lut_numCnInCnGroups_BG1_R13[6]] = (uint8_t(*)[lut_numCnInCnGroups_BG1_R13[6]]) p_lut->posBnInCnProcBuf[6];
-    const uint8_t (*lut_posBnInCnProcBuf_CNG10)[lut_numCnInCnGroups_BG1_R13[7]] = (uint8_t(*)[lut_numCnInCnGroups_BG1_R13[7]]) p_lut->posBnInCnProcBuf[7];
-    const uint8_t (*lut_posBnInCnProcBuf_CNG19)[lut_numCnInCnGroups_BG1_R13[8]] = (uint8_t(*)[lut_numCnInCnGroups_BG1_R13[8]]) p_lut->posBnInCnProcBuf[8];
+    const uint16_t (*lut_circShift_CNG3) [lut_numCnInCnGroups_BG1_R13[0]] = (const uint16_t(*)[lut_numCnInCnGroups_BG1_R13[0]]) p_lut->circShift[0];
+    const uint16_t (*lut_circShift_CNG4) [lut_numCnInCnGroups_BG1_R13[1]] = (const uint16_t(*)[lut_numCnInCnGroups_BG1_R13[1]]) p_lut->circShift[1];
+    const uint16_t (*lut_circShift_CNG5) [lut_numCnInCnGroups_BG1_R13[2]] = (const uint16_t(*)[lut_numCnInCnGroups_BG1_R13[2]]) p_lut->circShift[2];
+    const uint16_t (*lut_circShift_CNG6) [lut_numCnInCnGroups_BG1_R13[3]] = (const uint16_t(*)[lut_numCnInCnGroups_BG1_R13[3]]) p_lut->circShift[3];
+    const uint16_t (*lut_circShift_CNG7) [lut_numCnInCnGroups_BG1_R13[4]] = (const uint16_t(*)[lut_numCnInCnGroups_BG1_R13[4]]) p_lut->circShift[4];
+    const uint16_t (*lut_circShift_CNG8) [lut_numCnInCnGroups_BG1_R13[5]] = (const uint16_t(*)[lut_numCnInCnGroups_BG1_R13[5]]) p_lut->circShift[5];
+    const uint16_t (*lut_circShift_CNG9) [lut_numCnInCnGroups_BG1_R13[6]] = (const uint16_t(*)[lut_numCnInCnGroups_BG1_R13[6]]) p_lut->circShift[6];
+    const uint16_t (*lut_circShift_CNG10)[lut_numCnInCnGroups_BG1_R13[7]] = (const uint16_t(*)[lut_numCnInCnGroups_BG1_R13[7]]) p_lut->circShift[7];
+    const uint16_t (*lut_circShift_CNG19)[lut_numCnInCnGroups_BG1_R13[8]] = (const uint16_t(*)[lut_numCnInCnGroups_BG1_R13[8]]) p_lut->circShift[8];
+
+    const uint8_t (*lut_posBnInCnProcBuf_CNG3) [lut_numCnInCnGroups_BG1_R13[0]] = (const uint8_t(*)[lut_numCnInCnGroups_BG1_R13[0]]) p_lut->posBnInCnProcBuf[0];
+    const uint8_t (*lut_posBnInCnProcBuf_CNG4) [lut_numCnInCnGroups_BG1_R13[1]] = (const uint8_t(*)[lut_numCnInCnGroups_BG1_R13[1]]) p_lut->posBnInCnProcBuf[1];
+    const uint8_t (*lut_posBnInCnProcBuf_CNG5) [lut_numCnInCnGroups_BG1_R13[2]] = (const uint8_t(*)[lut_numCnInCnGroups_BG1_R13[2]]) p_lut->posBnInCnProcBuf[2];
+    const uint8_t (*lut_posBnInCnProcBuf_CNG6) [lut_numCnInCnGroups_BG1_R13[3]] = (const uint8_t(*)[lut_numCnInCnGroups_BG1_R13[3]]) p_lut->posBnInCnProcBuf[3];
+    const uint8_t (*lut_posBnInCnProcBuf_CNG7) [lut_numCnInCnGroups_BG1_R13[4]] = (const uint8_t(*)[lut_numCnInCnGroups_BG1_R13[4]]) p_lut->posBnInCnProcBuf[4];
+    const uint8_t (*lut_posBnInCnProcBuf_CNG8) [lut_numCnInCnGroups_BG1_R13[5]] = (const uint8_t(*)[lut_numCnInCnGroups_BG1_R13[5]]) p_lut->posBnInCnProcBuf[5];
+    const uint8_t (*lut_posBnInCnProcBuf_CNG9) [lut_numCnInCnGroups_BG1_R13[6]] = (const uint8_t(*)[lut_numCnInCnGroups_BG1_R13[6]]) p_lut->posBnInCnProcBuf[6];
+    const uint8_t (*lut_posBnInCnProcBuf_CNG10)[lut_numCnInCnGroups_BG1_R13[7]] = (const uint8_t(*)[lut_numCnInCnGroups_BG1_R13[7]]) p_lut->posBnInCnProcBuf[7];
+    const uint8_t (*lut_posBnInCnProcBuf_CNG19)[lut_numCnInCnGroups_BG1_R13[8]] = (const uint8_t(*)[lut_numCnInCnGroups_BG1_R13[8]]) p_lut->posBnInCnProcBuf[8];
 
     const uint8_t*  lut_numCnInCnGroups = p_lut->numCnInCnGroups;
     const uint32_t* lut_startAddrCnGroups = p_lut->startAddrCnGroups;
@@ -344,19 +344,19 @@ static inline void nrLDPC_llr2CnProcBuf_BG1(t_nrLDPC_lut* p_lut, int8_t* llr, t_
 */
 static inline void nrLDPC_llr2CnProcBuf_BG2(t_nrLDPC_lut* p_lut, int8_t* llr, t_nrLDPC_procBuf* p_procBuf, uint16_t Z)
 {
-    const uint16_t (*lut_circShift_CNG3)  [lut_numCnInCnGroups_BG2_R15[0]] = (uint16_t(*)[lut_numCnInCnGroups_BG2_R15[0]]) p_lut->circShift[0];
-    const uint16_t (*lut_circShift_CNG4)  [lut_numCnInCnGroups_BG2_R15[1]] = (uint16_t(*)[lut_numCnInCnGroups_BG2_R15[1]]) p_lut->circShift[1];
-    const uint16_t (*lut_circShift_CNG5)  [lut_numCnInCnGroups_BG2_R15[2]] = (uint16_t(*)[lut_numCnInCnGroups_BG2_R15[2]]) p_lut->circShift[2];
-    const uint16_t (*lut_circShift_CNG6)  [lut_numCnInCnGroups_BG2_R15[3]] = (uint16_t(*)[lut_numCnInCnGroups_BG2_R15[3]]) p_lut->circShift[3];
-    const uint16_t (*lut_circShift_CNG8)  [lut_numCnInCnGroups_BG2_R15[4]] = (uint16_t(*)[lut_numCnInCnGroups_BG2_R15[4]]) p_lut->circShift[4];
-    const uint16_t (*lut_circShift_CNG10) [lut_numCnInCnGroups_BG2_R15[5]] = (uint16_t(*)[lut_numCnInCnGroups_BG2_R15[5]]) p_lut->circShift[5];
-
-    const uint8_t (*lut_posBnInCnProcBuf_CNG3)  [lut_numCnInCnGroups_BG2_R15[0]] = (uint8_t(*)[lut_numCnInCnGroups_BG2_R15[0]]) p_lut->posBnInCnProcBuf[0];
-    const uint8_t (*lut_posBnInCnProcBuf_CNG4)  [lut_numCnInCnGroups_BG2_R15[1]] = (uint8_t(*)[lut_numCnInCnGroups_BG2_R15[1]]) p_lut->posBnInCnProcBuf[1];
-    const uint8_t (*lut_posBnInCnProcBuf_CNG5)  [lut_numCnInCnGroups_BG2_R15[2]] = (uint8_t(*)[lut_numCnInCnGroups_BG2_R15[2]]) p_lut->posBnInCnProcBuf[2];
-    const uint8_t (*lut_posBnInCnProcBuf_CNG6)  [lut_numCnInCnGroups_BG2_R15[3]] = (uint8_t(*)[lut_numCnInCnGroups_BG2_R15[3]]) p_lut->posBnInCnProcBuf[3];
-    const uint8_t (*lut_posBnInCnProcBuf_CNG8)  [lut_numCnInCnGroups_BG2_R15[4]] = (uint8_t(*)[lut_numCnInCnGroups_BG2_R15[4]]) p_lut->posBnInCnProcBuf[4];
-    const uint8_t (*lut_posBnInCnProcBuf_CNG10) [lut_numCnInCnGroups_BG2_R15[5]] = (uint8_t(*)[lut_numCnInCnGroups_BG2_R15[5]]) p_lut->posBnInCnProcBuf[5];
+    const uint16_t (*lut_circShift_CNG3)  [lut_numCnInCnGroups_BG2_R15[0]] = (const uint16_t(*)[lut_numCnInCnGroups_BG2_R15[0]]) p_lut->circShift[0];
+    const uint16_t (*lut_circShift_CNG4)  [lut_numCnInCnGroups_BG2_R15[1]] = (const uint16_t(*)[lut_numCnInCnGroups_BG2_R15[1]]) p_lut->circShift[1];
+    const uint16_t (*lut_circShift_CNG5)  [lut_numCnInCnGroups_BG2_R15[2]] = (const uint16_t(*)[lut_numCnInCnGroups_BG2_R15[2]]) p_lut->circShift[2];
+    const uint16_t (*lut_circShift_CNG6)  [lut_numCnInCnGroups_BG2_R15[3]] = (const uint16_t(*)[lut_numCnInCnGroups_BG2_R15[3]]) p_lut->circShift[3];
+    const uint16_t (*lut_circShift_CNG8)  [lut_numCnInCnGroups_BG2_R15[4]] = (const uint16_t(*)[lut_numCnInCnGroups_BG2_R15[4]]) p_lut->circShift[4];
+    const uint16_t (*lut_circShift_CNG10) [lut_numCnInCnGroups_BG2_R15[5]] = (const uint16_t(*)[lut_numCnInCnGroups_BG2_R15[5]]) p_lut->circShift[5];
+
+    const uint8_t (*lut_posBnInCnProcBuf_CNG3)  [lut_numCnInCnGroups_BG2_R15[0]] = (const uint8_t(*)[lut_numCnInCnGroups_BG2_R15[0]]) p_lut->posBnInCnProcBuf[0];
+    const uint8_t (*lut_posBnInCnProcBuf_CNG4)  [lut_numCnInCnGroups_BG2_R15[1]] = (const uint8_t(*)[lut_numCnInCnGroups_BG2_R15[1]]) p_lut->posBnInCnProcBuf[1];
+    const uint8_t (*lut_posBnInCnProcBuf_CNG5)  [lut_numCnInCnGroups_BG2_R15[2]] = (const uint8_t(*)[lut_numCnInCnGroups_BG2_R15[2]]) p_lut->posBnInCnProcBuf[2];
+    const uint8_t (*lut_posBnInCnProcBuf_CNG6)  [lut_numCnInCnGroups_BG2_R15[3]] = (const uint8_t(*)[lut_numCnInCnGroups_BG2_R15[3]]) p_lut->posBnInCnProcBuf[3];
+    const uint8_t (*lut_posBnInCnProcBuf_CNG8)  [lut_numCnInCnGroups_BG2_R15[4]] = (const uint8_t(*)[lut_numCnInCnGroups_BG2_R15[4]]) p_lut->posBnInCnProcBuf[4];
+    const uint8_t (*lut_posBnInCnProcBuf_CNG10) [lut_numCnInCnGroups_BG2_R15[5]] = (const uint8_t(*)[lut_numCnInCnGroups_BG2_R15[5]]) p_lut->posBnInCnProcBuf[5];
 
     const uint8_t*  lut_numCnInCnGroups = p_lut->numCnInCnGroups;
     const uint32_t* lut_startAddrCnGroups = p_lut->startAddrCnGroups;
@@ -483,26 +483,26 @@ static inline void nrLDPC_cn2bnProcBuf_BG2(t_nrLDPC_lut* p_lut, t_nrLDPC_procBuf
     const uint8_t*  lut_numCnInCnGroups = p_lut->numCnInCnGroups;
     const uint32_t* lut_startAddrCnGroups = p_lut->startAddrCnGroups;
 
-    const uint16_t (*lut_circShift_CNG3)  [lut_numCnInCnGroups_BG2_R15[0]] = (uint16_t(*)[lut_numCnInCnGroups_BG2_R15[0]]) p_lut->circShift[0];
-    const uint16_t (*lut_circShift_CNG4)  [lut_numCnInCnGroups_BG2_R15[1]] = (uint16_t(*)[lut_numCnInCnGroups_BG2_R15[1]]) p_lut->circShift[1];
-    const uint16_t (*lut_circShift_CNG5)  [lut_numCnInCnGroups_BG2_R15[2]] = (uint16_t(*)[lut_numCnInCnGroups_BG2_R15[2]]) p_lut->circShift[2];
-    const uint16_t (*lut_circShift_CNG6)  [lut_numCnInCnGroups_BG2_R15[3]] = (uint16_t(*)[lut_numCnInCnGroups_BG2_R15[3]]) p_lut->circShift[3];
-    const uint16_t (*lut_circShift_CNG8)  [lut_numCnInCnGroups_BG2_R15[4]] = (uint16_t(*)[lut_numCnInCnGroups_BG2_R15[4]]) p_lut->circShift[4];
-    const uint16_t (*lut_circShift_CNG10) [lut_numCnInCnGroups_BG2_R15[5]] = (uint16_t(*)[lut_numCnInCnGroups_BG2_R15[5]]) p_lut->circShift[5];
-
-    const uint32_t (*lut_startAddrBnProcBuf_CNG3)  [lut_numCnInCnGroups[0]] = (uint32_t(*)[lut_numCnInCnGroups[0]]) p_lut->startAddrBnProcBuf[0];
-    const uint32_t (*lut_startAddrBnProcBuf_CNG4)  [lut_numCnInCnGroups[1]] = (uint32_t(*)[lut_numCnInCnGroups[1]]) p_lut->startAddrBnProcBuf[1];
-    const uint32_t (*lut_startAddrBnProcBuf_CNG5)  [lut_numCnInCnGroups[2]] = (uint32_t(*)[lut_numCnInCnGroups[2]]) p_lut->startAddrBnProcBuf[2];
-    const uint32_t (*lut_startAddrBnProcBuf_CNG6)  [lut_numCnInCnGroups[3]] = (uint32_t(*)[lut_numCnInCnGroups[3]]) p_lut->startAddrBnProcBuf[3];
-    const uint32_t (*lut_startAddrBnProcBuf_CNG8)  [lut_numCnInCnGroups[4]] = (uint32_t(*)[lut_numCnInCnGroups[4]]) p_lut->startAddrBnProcBuf[4];
-    const uint32_t (*lut_startAddrBnProcBuf_CNG10) [lut_numCnInCnGroups[5]] = (uint32_t(*)[lut_numCnInCnGroups[5]]) p_lut->startAddrBnProcBuf[5];
-
-    const uint8_t (*lut_bnPosBnProcBuf_CNG3)  [lut_numCnInCnGroups[0]] = (uint8_t(*)[lut_numCnInCnGroups[0]]) p_lut->bnPosBnProcBuf[0];
-    const uint8_t (*lut_bnPosBnProcBuf_CNG4)  [lut_numCnInCnGroups[1]] = (uint8_t(*)[lut_numCnInCnGroups[1]]) p_lut->bnPosBnProcBuf[1];
-    const uint8_t (*lut_bnPosBnProcBuf_CNG5)  [lut_numCnInCnGroups[2]] = (uint8_t(*)[lut_numCnInCnGroups[2]]) p_lut->bnPosBnProcBuf[2];
-    const uint8_t (*lut_bnPosBnProcBuf_CNG6)  [lut_numCnInCnGroups[3]] = (uint8_t(*)[lut_numCnInCnGroups[3]]) p_lut->bnPosBnProcBuf[3];
-    const uint8_t (*lut_bnPosBnProcBuf_CNG8)  [lut_numCnInCnGroups[4]] = (uint8_t(*)[lut_numCnInCnGroups[4]]) p_lut->bnPosBnProcBuf[4];
-    const uint8_t (*lut_bnPosBnProcBuf_CNG10) [lut_numCnInCnGroups[5]] = (uint8_t(*)[lut_numCnInCnGroups[5]]) p_lut->bnPosBnProcBuf[5];
+    const uint16_t (*lut_circShift_CNG3)  [lut_numCnInCnGroups_BG2_R15[0]] = (const uint16_t(*)[lut_numCnInCnGroups_BG2_R15[0]]) p_lut->circShift[0];
+    const uint16_t (*lut_circShift_CNG4)  [lut_numCnInCnGroups_BG2_R15[1]] = (const uint16_t(*)[lut_numCnInCnGroups_BG2_R15[1]]) p_lut->circShift[1];
+    const uint16_t (*lut_circShift_CNG5)  [lut_numCnInCnGroups_BG2_R15[2]] = (const uint16_t(*)[lut_numCnInCnGroups_BG2_R15[2]]) p_lut->circShift[2];
+    const uint16_t (*lut_circShift_CNG6)  [lut_numCnInCnGroups_BG2_R15[3]] = (const uint16_t(*)[lut_numCnInCnGroups_BG2_R15[3]]) p_lut->circShift[3];
+    const uint16_t (*lut_circShift_CNG8)  [lut_numCnInCnGroups_BG2_R15[4]] = (const uint16_t(*)[lut_numCnInCnGroups_BG2_R15[4]]) p_lut->circShift[4];
+    const uint16_t (*lut_circShift_CNG10) [lut_numCnInCnGroups_BG2_R15[5]] = (const uint16_t(*)[lut_numCnInCnGroups_BG2_R15[5]]) p_lut->circShift[5];
+
+    const uint32_t (*lut_startAddrBnProcBuf_CNG3)  [lut_numCnInCnGroups[0]] = (const uint32_t(*)[lut_numCnInCnGroups[0]]) p_lut->startAddrBnProcBuf[0];
+    const uint32_t (*lut_startAddrBnProcBuf_CNG4)  [lut_numCnInCnGroups[1]] = (const uint32_t(*)[lut_numCnInCnGroups[1]]) p_lut->startAddrBnProcBuf[1];
+    const uint32_t (*lut_startAddrBnProcBuf_CNG5)  [lut_numCnInCnGroups[2]] = (const uint32_t(*)[lut_numCnInCnGroups[2]]) p_lut->startAddrBnProcBuf[2];
+    const uint32_t (*lut_startAddrBnProcBuf_CNG6)  [lut_numCnInCnGroups[3]] = (const uint32_t(*)[lut_numCnInCnGroups[3]]) p_lut->startAddrBnProcBuf[3];
+    const uint32_t (*lut_startAddrBnProcBuf_CNG8)  [lut_numCnInCnGroups[4]] = (const uint32_t(*)[lut_numCnInCnGroups[4]]) p_lut->startAddrBnProcBuf[4];
+    const uint32_t (*lut_startAddrBnProcBuf_CNG10) [lut_numCnInCnGroups[5]] = (const uint32_t(*)[lut_numCnInCnGroups[5]]) p_lut->startAddrBnProcBuf[5];
+
+    const uint8_t (*lut_bnPosBnProcBuf_CNG3)  [lut_numCnInCnGroups[0]] = (const uint8_t(*)[lut_numCnInCnGroups[0]]) p_lut->bnPosBnProcBuf[0];
+    const uint8_t (*lut_bnPosBnProcBuf_CNG4)  [lut_numCnInCnGroups[1]] = (const uint8_t(*)[lut_numCnInCnGroups[1]]) p_lut->bnPosBnProcBuf[1];
+    const uint8_t (*lut_bnPosBnProcBuf_CNG5)  [lut_numCnInCnGroups[2]] = (const uint8_t(*)[lut_numCnInCnGroups[2]]) p_lut->bnPosBnProcBuf[2];
+    const uint8_t (*lut_bnPosBnProcBuf_CNG6)  [lut_numCnInCnGroups[3]] = (const uint8_t(*)[lut_numCnInCnGroups[3]]) p_lut->bnPosBnProcBuf[3];
+    const uint8_t (*lut_bnPosBnProcBuf_CNG8)  [lut_numCnInCnGroups[4]] = (const uint8_t(*)[lut_numCnInCnGroups[4]]) p_lut->bnPosBnProcBuf[4];
+    const uint8_t (*lut_bnPosBnProcBuf_CNG10) [lut_numCnInCnGroups[5]] = (const uint8_t(*)[lut_numCnInCnGroups[5]]) p_lut->bnPosBnProcBuf[5];
 
     int8_t* cnProcBufRes = p_procBuf->cnProcBufRes;
     int8_t* bnProcBuf    = p_procBuf->bnProcBuf;
@@ -626,34 +626,34 @@ static inline void nrLDPC_cn2bnProcBuf_BG1(t_nrLDPC_lut* p_lut, t_nrLDPC_procBuf
     const uint8_t*  lut_numCnInCnGroups = p_lut->numCnInCnGroups;
     const uint32_t* lut_startAddrCnGroups = p_lut->startAddrCnGroups;
 
-    const uint16_t (*lut_circShift_CNG3) [lut_numCnInCnGroups_BG1_R13[0]] = (uint16_t(*)[lut_numCnInCnGroups_BG1_R13[0]]) p_lut->circShift[0];
-    const uint16_t (*lut_circShift_CNG4) [lut_numCnInCnGroups_BG1_R13[1]] = (uint16_t(*)[lut_numCnInCnGroups_BG1_R13[1]]) p_lut->circShift[1];
-    const uint16_t (*lut_circShift_CNG5) [lut_numCnInCnGroups_BG1_R13[2]] = (uint16_t(*)[lut_numCnInCnGroups_BG1_R13[2]]) p_lut->circShift[2];
-    const uint16_t (*lut_circShift_CNG6) [lut_numCnInCnGroups_BG1_R13[3]] = (uint16_t(*)[lut_numCnInCnGroups_BG1_R13[3]]) p_lut->circShift[3];
-    const uint16_t (*lut_circShift_CNG7) [lut_numCnInCnGroups_BG1_R13[4]] = (uint16_t(*)[lut_numCnInCnGroups_BG1_R13[4]]) p_lut->circShift[4];
-    const uint16_t (*lut_circShift_CNG8) [lut_numCnInCnGroups_BG1_R13[5]] = (uint16_t(*)[lut_numCnInCnGroups_BG1_R13[5]]) p_lut->circShift[5];
-    const uint16_t (*lut_circShift_CNG9) [lut_numCnInCnGroups_BG1_R13[6]] = (uint16_t(*)[lut_numCnInCnGroups_BG1_R13[6]]) p_lut->circShift[6];
-    const uint16_t (*lut_circShift_CNG10)[lut_numCnInCnGroups_BG1_R13[7]] = (uint16_t(*)[lut_numCnInCnGroups_BG1_R13[7]]) p_lut->circShift[7];
-    const uint16_t (*lut_circShift_CNG19)[lut_numCnInCnGroups_BG1_R13[8]] = (uint16_t(*)[lut_numCnInCnGroups_BG1_R13[8]]) p_lut->circShift[8];
-
-    const uint32_t (*lut_startAddrBnProcBuf_CNG3) [lut_numCnInCnGroups[0]] = (uint32_t(*)[lut_numCnInCnGroups[0]]) p_lut->startAddrBnProcBuf[0];
-    const uint32_t (*lut_startAddrBnProcBuf_CNG4) [lut_numCnInCnGroups[1]] = (uint32_t(*)[lut_numCnInCnGroups[1]]) p_lut->startAddrBnProcBuf[1];
-    const uint32_t (*lut_startAddrBnProcBuf_CNG5) [lut_numCnInCnGroups[2]] = (uint32_t(*)[lut_numCnInCnGroups[2]]) p_lut->startAddrBnProcBuf[2];
-    const uint32_t (*lut_startAddrBnProcBuf_CNG6) [lut_numCnInCnGroups[3]] = (uint32_t(*)[lut_numCnInCnGroups[3]]) p_lut->startAddrBnProcBuf[3];
-    const uint32_t (*lut_startAddrBnProcBuf_CNG7) [lut_numCnInCnGroups[4]] = (uint32_t(*)[lut_numCnInCnGroups[4]]) p_lut->startAddrBnProcBuf[4];
-    const uint32_t (*lut_startAddrBnProcBuf_CNG8) [lut_numCnInCnGroups[5]] = (uint32_t(*)[lut_numCnInCnGroups[5]]) p_lut->startAddrBnProcBuf[5];
-    const uint32_t (*lut_startAddrBnProcBuf_CNG9) [lut_numCnInCnGroups[6]] = (uint32_t(*)[lut_numCnInCnGroups[6]]) p_lut->startAddrBnProcBuf[6];
-    const uint32_t (*lut_startAddrBnProcBuf_CNG10)[lut_numCnInCnGroups[7]] = (uint32_t(*)[lut_numCnInCnGroups[7]]) p_lut->startAddrBnProcBuf[7];
-    const uint32_t (*lut_startAddrBnProcBuf_CNG19)[lut_numCnInCnGroups[8]] = (uint32_t(*)[lut_numCnInCnGroups[8]]) p_lut->startAddrBnProcBuf[8];
-
-    const uint8_t (*lut_bnPosBnProcBuf_CNG4) [lut_numCnInCnGroups[1]] = (uint8_t(*)[lut_numCnInCnGroups[1]]) p_lut->bnPosBnProcBuf[1];
-    const uint8_t (*lut_bnPosBnProcBuf_CNG5) [lut_numCnInCnGroups[2]] = (uint8_t(*)[lut_numCnInCnGroups[2]]) p_lut->bnPosBnProcBuf[2];
-    const uint8_t (*lut_bnPosBnProcBuf_CNG6) [lut_numCnInCnGroups[3]] = (uint8_t(*)[lut_numCnInCnGroups[3]]) p_lut->bnPosBnProcBuf[3];
-    const uint8_t (*lut_bnPosBnProcBuf_CNG7) [lut_numCnInCnGroups[4]] = (uint8_t(*)[lut_numCnInCnGroups[4]]) p_lut->bnPosBnProcBuf[4];
-    const uint8_t (*lut_bnPosBnProcBuf_CNG8) [lut_numCnInCnGroups[5]] = (uint8_t(*)[lut_numCnInCnGroups[5]]) p_lut->bnPosBnProcBuf[5];
-    const uint8_t (*lut_bnPosBnProcBuf_CNG9) [lut_numCnInCnGroups[6]] = (uint8_t(*)[lut_numCnInCnGroups[6]]) p_lut->bnPosBnProcBuf[6];
-    const uint8_t (*lut_bnPosBnProcBuf_CNG10)[lut_numCnInCnGroups[7]] = (uint8_t(*)[lut_numCnInCnGroups[7]]) p_lut->bnPosBnProcBuf[7];
-    const uint8_t (*lut_bnPosBnProcBuf_CNG19)[lut_numCnInCnGroups[8]] = (uint8_t(*)[lut_numCnInCnGroups[8]]) p_lut->bnPosBnProcBuf[8];
+    const uint16_t (*lut_circShift_CNG3) [lut_numCnInCnGroups_BG1_R13[0]] = (const uint16_t(*)[lut_numCnInCnGroups_BG1_R13[0]]) p_lut->circShift[0];
+    const uint16_t (*lut_circShift_CNG4) [lut_numCnInCnGroups_BG1_R13[1]] = (const uint16_t(*)[lut_numCnInCnGroups_BG1_R13[1]]) p_lut->circShift[1];
+    const uint16_t (*lut_circShift_CNG5) [lut_numCnInCnGroups_BG1_R13[2]] = (const uint16_t(*)[lut_numCnInCnGroups_BG1_R13[2]]) p_lut->circShift[2];
+    const uint16_t (*lut_circShift_CNG6) [lut_numCnInCnGroups_BG1_R13[3]] = (const uint16_t(*)[lut_numCnInCnGroups_BG1_R13[3]]) p_lut->circShift[3];
+    const uint16_t (*lut_circShift_CNG7) [lut_numCnInCnGroups_BG1_R13[4]] = (const uint16_t(*)[lut_numCnInCnGroups_BG1_R13[4]]) p_lut->circShift[4];
+    const uint16_t (*lut_circShift_CNG8) [lut_numCnInCnGroups_BG1_R13[5]] = (const uint16_t(*)[lut_numCnInCnGroups_BG1_R13[5]]) p_lut->circShift[5];
+    const uint16_t (*lut_circShift_CNG9) [lut_numCnInCnGroups_BG1_R13[6]] = (const uint16_t(*)[lut_numCnInCnGroups_BG1_R13[6]]) p_lut->circShift[6];
+    const uint16_t (*lut_circShift_CNG10)[lut_numCnInCnGroups_BG1_R13[7]] = (const uint16_t(*)[lut_numCnInCnGroups_BG1_R13[7]]) p_lut->circShift[7];
+    const uint16_t (*lut_circShift_CNG19)[lut_numCnInCnGroups_BG1_R13[8]] = (const uint16_t(*)[lut_numCnInCnGroups_BG1_R13[8]]) p_lut->circShift[8];
+
+    const uint32_t (*lut_startAddrBnProcBuf_CNG3) [lut_numCnInCnGroups[0]] = (const uint32_t(*)[lut_numCnInCnGroups[0]]) p_lut->startAddrBnProcBuf[0];
+    const uint32_t (*lut_startAddrBnProcBuf_CNG4) [lut_numCnInCnGroups[1]] = (const uint32_t(*)[lut_numCnInCnGroups[1]]) p_lut->startAddrBnProcBuf[1];
+    const uint32_t (*lut_startAddrBnProcBuf_CNG5) [lut_numCnInCnGroups[2]] = (const uint32_t(*)[lut_numCnInCnGroups[2]]) p_lut->startAddrBnProcBuf[2];
+    const uint32_t (*lut_startAddrBnProcBuf_CNG6) [lut_numCnInCnGroups[3]] = (const uint32_t(*)[lut_numCnInCnGroups[3]]) p_lut->startAddrBnProcBuf[3];
+    const uint32_t (*lut_startAddrBnProcBuf_CNG7) [lut_numCnInCnGroups[4]] = (const uint32_t(*)[lut_numCnInCnGroups[4]]) p_lut->startAddrBnProcBuf[4];
+    const uint32_t (*lut_startAddrBnProcBuf_CNG8) [lut_numCnInCnGroups[5]] = (const uint32_t(*)[lut_numCnInCnGroups[5]]) p_lut->startAddrBnProcBuf[5];
+    const uint32_t (*lut_startAddrBnProcBuf_CNG9) [lut_numCnInCnGroups[6]] = (const uint32_t(*)[lut_numCnInCnGroups[6]]) p_lut->startAddrBnProcBuf[6];
+    const uint32_t (*lut_startAddrBnProcBuf_CNG10)[lut_numCnInCnGroups[7]] = (const uint32_t(*)[lut_numCnInCnGroups[7]]) p_lut->startAddrBnProcBuf[7];
+    const uint32_t (*lut_startAddrBnProcBuf_CNG19)[lut_numCnInCnGroups[8]] = (const uint32_t(*)[lut_numCnInCnGroups[8]]) p_lut->startAddrBnProcBuf[8];
+
+    const uint8_t (*lut_bnPosBnProcBuf_CNG4) [lut_numCnInCnGroups[1]] = (const uint8_t(*)[lut_numCnInCnGroups[1]]) p_lut->bnPosBnProcBuf[1];
+    const uint8_t (*lut_bnPosBnProcBuf_CNG5) [lut_numCnInCnGroups[2]] = (const uint8_t(*)[lut_numCnInCnGroups[2]]) p_lut->bnPosBnProcBuf[2];
+    const uint8_t (*lut_bnPosBnProcBuf_CNG6) [lut_numCnInCnGroups[3]] = (const uint8_t(*)[lut_numCnInCnGroups[3]]) p_lut->bnPosBnProcBuf[3];
+    const uint8_t (*lut_bnPosBnProcBuf_CNG7) [lut_numCnInCnGroups[4]] = (const uint8_t(*)[lut_numCnInCnGroups[4]]) p_lut->bnPosBnProcBuf[4];
+    const uint8_t (*lut_bnPosBnProcBuf_CNG8) [lut_numCnInCnGroups[5]] = (const uint8_t(*)[lut_numCnInCnGroups[5]]) p_lut->bnPosBnProcBuf[5];
+    const uint8_t (*lut_bnPosBnProcBuf_CNG9) [lut_numCnInCnGroups[6]] = (const uint8_t(*)[lut_numCnInCnGroups[6]]) p_lut->bnPosBnProcBuf[6];
+    const uint8_t (*lut_bnPosBnProcBuf_CNG10)[lut_numCnInCnGroups[7]] = (const uint8_t(*)[lut_numCnInCnGroups[7]]) p_lut->bnPosBnProcBuf[7];
+    const uint8_t (*lut_bnPosBnProcBuf_CNG19)[lut_numCnInCnGroups[8]] = (const uint8_t(*)[lut_numCnInCnGroups[8]]) p_lut->bnPosBnProcBuf[8];
 
     int8_t* cnProcBufRes = p_procBuf->cnProcBufRes;
     int8_t* bnProcBuf    = p_procBuf->bnProcBuf;
@@ -824,26 +824,26 @@ static inline void nrLDPC_bn2cnProcBuf_BG2(t_nrLDPC_lut* p_lut, t_nrLDPC_procBuf
     const uint8_t*  lut_numCnInCnGroups = p_lut->numCnInCnGroups;
     const uint32_t* lut_startAddrCnGroups = p_lut->startAddrCnGroups;
 
-    const uint16_t (*lut_circShift_CNG3)  [lut_numCnInCnGroups_BG2_R15[0]] = (uint16_t(*)[lut_numCnInCnGroups_BG2_R15[0]]) p_lut->circShift[0];
-    const uint16_t (*lut_circShift_CNG4)  [lut_numCnInCnGroups_BG2_R15[1]] = (uint16_t(*)[lut_numCnInCnGroups_BG2_R15[1]]) p_lut->circShift[1];
-    const uint16_t (*lut_circShift_CNG5)  [lut_numCnInCnGroups_BG2_R15[2]] = (uint16_t(*)[lut_numCnInCnGroups_BG2_R15[2]]) p_lut->circShift[2];
-    const uint16_t (*lut_circShift_CNG6)  [lut_numCnInCnGroups_BG2_R15[3]] = (uint16_t(*)[lut_numCnInCnGroups_BG2_R15[3]]) p_lut->circShift[3];
-    const uint16_t (*lut_circShift_CNG8)  [lut_numCnInCnGroups_BG2_R15[4]] = (uint16_t(*)[lut_numCnInCnGroups_BG2_R15[4]]) p_lut->circShift[4];
-    const uint16_t (*lut_circShift_CNG10) [lut_numCnInCnGroups_BG2_R15[5]] = (uint16_t(*)[lut_numCnInCnGroups_BG2_R15[5]]) p_lut->circShift[5];
-
-    const uint32_t (*lut_startAddrBnProcBuf_CNG3)  [lut_numCnInCnGroups[0]] = (uint32_t(*)[lut_numCnInCnGroups[0]]) p_lut->startAddrBnProcBuf[0];
-    const uint32_t (*lut_startAddrBnProcBuf_CNG4)  [lut_numCnInCnGroups[1]] = (uint32_t(*)[lut_numCnInCnGroups[1]]) p_lut->startAddrBnProcBuf[1];
-    const uint32_t (*lut_startAddrBnProcBuf_CNG5)  [lut_numCnInCnGroups[2]] = (uint32_t(*)[lut_numCnInCnGroups[2]]) p_lut->startAddrBnProcBuf[2];
-    const uint32_t (*lut_startAddrBnProcBuf_CNG6)  [lut_numCnInCnGroups[3]] = (uint32_t(*)[lut_numCnInCnGroups[3]]) p_lut->startAddrBnProcBuf[3];
-    const uint32_t (*lut_startAddrBnProcBuf_CNG8)  [lut_numCnInCnGroups[4]] = (uint32_t(*)[lut_numCnInCnGroups[4]]) p_lut->startAddrBnProcBuf[4];
-    const uint32_t (*lut_startAddrBnProcBuf_CNG10) [lut_numCnInCnGroups[5]] = (uint32_t(*)[lut_numCnInCnGroups[5]]) p_lut->startAddrBnProcBuf[5];
-
-    const uint8_t (*lut_bnPosBnProcBuf_CNG3)  [lut_numCnInCnGroups[0]] = (uint8_t(*)[lut_numCnInCnGroups[0]]) p_lut->bnPosBnProcBuf[0];
-    const uint8_t (*lut_bnPosBnProcBuf_CNG4)  [lut_numCnInCnGroups[1]] = (uint8_t(*)[lut_numCnInCnGroups[1]]) p_lut->bnPosBnProcBuf[1];
-    const uint8_t (*lut_bnPosBnProcBuf_CNG5)  [lut_numCnInCnGroups[2]] = (uint8_t(*)[lut_numCnInCnGroups[2]]) p_lut->bnPosBnProcBuf[2];
-    const uint8_t (*lut_bnPosBnProcBuf_CNG6)  [lut_numCnInCnGroups[3]] = (uint8_t(*)[lut_numCnInCnGroups[3]]) p_lut->bnPosBnProcBuf[3];
-    const uint8_t (*lut_bnPosBnProcBuf_CNG8)  [lut_numCnInCnGroups[4]] = (uint8_t(*)[lut_numCnInCnGroups[4]]) p_lut->bnPosBnProcBuf[4];
-    const uint8_t (*lut_bnPosBnProcBuf_CNG10) [lut_numCnInCnGroups[5]] = (uint8_t(*)[lut_numCnInCnGroups[5]]) p_lut->bnPosBnProcBuf[5];
+    const uint16_t (*lut_circShift_CNG3)  [lut_numCnInCnGroups_BG2_R15[0]] = (const uint16_t(*)[lut_numCnInCnGroups_BG2_R15[0]]) p_lut->circShift[0];
+    const uint16_t (*lut_circShift_CNG4)  [lut_numCnInCnGroups_BG2_R15[1]] = (const uint16_t(*)[lut_numCnInCnGroups_BG2_R15[1]]) p_lut->circShift[1];
+    const uint16_t (*lut_circShift_CNG5)  [lut_numCnInCnGroups_BG2_R15[2]] = (const uint16_t(*)[lut_numCnInCnGroups_BG2_R15[2]]) p_lut->circShift[2];
+    const uint16_t (*lut_circShift_CNG6)  [lut_numCnInCnGroups_BG2_R15[3]] = (const uint16_t(*)[lut_numCnInCnGroups_BG2_R15[3]]) p_lut->circShift[3];
+    const uint16_t (*lut_circShift_CNG8)  [lut_numCnInCnGroups_BG2_R15[4]] = (const uint16_t(*)[lut_numCnInCnGroups_BG2_R15[4]]) p_lut->circShift[4];
+    const uint16_t (*lut_circShift_CNG10) [lut_numCnInCnGroups_BG2_R15[5]] = (const uint16_t(*)[lut_numCnInCnGroups_BG2_R15[5]]) p_lut->circShift[5];
+
+    const uint32_t (*lut_startAddrBnProcBuf_CNG3)  [lut_numCnInCnGroups[0]] = (const uint32_t(*)[lut_numCnInCnGroups[0]]) p_lut->startAddrBnProcBuf[0];
+    const uint32_t (*lut_startAddrBnProcBuf_CNG4)  [lut_numCnInCnGroups[1]] = (const uint32_t(*)[lut_numCnInCnGroups[1]]) p_lut->startAddrBnProcBuf[1];
+    const uint32_t (*lut_startAddrBnProcBuf_CNG5)  [lut_numCnInCnGroups[2]] = (const uint32_t(*)[lut_numCnInCnGroups[2]]) p_lut->startAddrBnProcBuf[2];
+    const uint32_t (*lut_startAddrBnProcBuf_CNG6)  [lut_numCnInCnGroups[3]] = (const uint32_t(*)[lut_numCnInCnGroups[3]]) p_lut->startAddrBnProcBuf[3];
+    const uint32_t (*lut_startAddrBnProcBuf_CNG8)  [lut_numCnInCnGroups[4]] = (const uint32_t(*)[lut_numCnInCnGroups[4]]) p_lut->startAddrBnProcBuf[4];
+    const uint32_t (*lut_startAddrBnProcBuf_CNG10) [lut_numCnInCnGroups[5]] = (const uint32_t(*)[lut_numCnInCnGroups[5]]) p_lut->startAddrBnProcBuf[5];
+
+    const uint8_t (*lut_bnPosBnProcBuf_CNG3)  [lut_numCnInCnGroups[0]] = (const uint8_t(*)[lut_numCnInCnGroups[0]]) p_lut->bnPosBnProcBuf[0];
+    const uint8_t (*lut_bnPosBnProcBuf_CNG4)  [lut_numCnInCnGroups[1]] = (const uint8_t(*)[lut_numCnInCnGroups[1]]) p_lut->bnPosBnProcBuf[1];
+    const uint8_t (*lut_bnPosBnProcBuf_CNG5)  [lut_numCnInCnGroups[2]] = (const uint8_t(*)[lut_numCnInCnGroups[2]]) p_lut->bnPosBnProcBuf[2];
+    const uint8_t (*lut_bnPosBnProcBuf_CNG6)  [lut_numCnInCnGroups[3]] = (const uint8_t(*)[lut_numCnInCnGroups[3]]) p_lut->bnPosBnProcBuf[3];
+    const uint8_t (*lut_bnPosBnProcBuf_CNG8)  [lut_numCnInCnGroups[4]] = (const uint8_t(*)[lut_numCnInCnGroups[4]]) p_lut->bnPosBnProcBuf[4];
+    const uint8_t (*lut_bnPosBnProcBuf_CNG10) [lut_numCnInCnGroups[5]] = (const uint8_t(*)[lut_numCnInCnGroups[5]]) p_lut->bnPosBnProcBuf[5];
 
     int8_t* cnProcBuf    = p_procBuf->cnProcBuf;
     int8_t* bnProcBufRes = p_procBuf->bnProcBufRes;
@@ -966,34 +966,34 @@ static inline void nrLDPC_bn2cnProcBuf_BG1(t_nrLDPC_lut* p_lut, t_nrLDPC_procBuf
     const uint8_t*  lut_numCnInCnGroups = p_lut->numCnInCnGroups;
     const uint32_t* lut_startAddrCnGroups = p_lut->startAddrCnGroups;
 
-    const uint16_t (*lut_circShift_CNG3) [lut_numCnInCnGroups_BG1_R13[0]] = (uint16_t(*)[lut_numCnInCnGroups_BG1_R13[0]]) p_lut->circShift[0];
-    const uint16_t (*lut_circShift_CNG4) [lut_numCnInCnGroups_BG1_R13[1]] = (uint16_t(*)[lut_numCnInCnGroups_BG1_R13[1]]) p_lut->circShift[1];
-    const uint16_t (*lut_circShift_CNG5) [lut_numCnInCnGroups_BG1_R13[2]] = (uint16_t(*)[lut_numCnInCnGroups_BG1_R13[2]]) p_lut->circShift[2];
-    const uint16_t (*lut_circShift_CNG6) [lut_numCnInCnGroups_BG1_R13[3]] = (uint16_t(*)[lut_numCnInCnGroups_BG1_R13[3]]) p_lut->circShift[3];
-    const uint16_t (*lut_circShift_CNG7) [lut_numCnInCnGroups_BG1_R13[4]] = (uint16_t(*)[lut_numCnInCnGroups_BG1_R13[4]]) p_lut->circShift[4];
-    const uint16_t (*lut_circShift_CNG8) [lut_numCnInCnGroups_BG1_R13[5]] = (uint16_t(*)[lut_numCnInCnGroups_BG1_R13[5]]) p_lut->circShift[5];
-    const uint16_t (*lut_circShift_CNG9) [lut_numCnInCnGroups_BG1_R13[6]] = (uint16_t(*)[lut_numCnInCnGroups_BG1_R13[6]]) p_lut->circShift[6];
-    const uint16_t (*lut_circShift_CNG10)[lut_numCnInCnGroups_BG1_R13[7]] = (uint16_t(*)[lut_numCnInCnGroups_BG1_R13[7]]) p_lut->circShift[7];
-    const uint16_t (*lut_circShift_CNG19)[lut_numCnInCnGroups_BG1_R13[8]] = (uint16_t(*)[lut_numCnInCnGroups_BG1_R13[8]]) p_lut->circShift[8];
-
-    const uint32_t (*lut_startAddrBnProcBuf_CNG3) [lut_numCnInCnGroups[0]] = (uint32_t(*)[lut_numCnInCnGroups[0]]) p_lut->startAddrBnProcBuf[0];
-    const uint32_t (*lut_startAddrBnProcBuf_CNG4) [lut_numCnInCnGroups[1]] = (uint32_t(*)[lut_numCnInCnGroups[1]]) p_lut->startAddrBnProcBuf[1];
-    const uint32_t (*lut_startAddrBnProcBuf_CNG5) [lut_numCnInCnGroups[2]] = (uint32_t(*)[lut_numCnInCnGroups[2]]) p_lut->startAddrBnProcBuf[2];
-    const uint32_t (*lut_startAddrBnProcBuf_CNG6) [lut_numCnInCnGroups[3]] = (uint32_t(*)[lut_numCnInCnGroups[3]]) p_lut->startAddrBnProcBuf[3];
-    const uint32_t (*lut_startAddrBnProcBuf_CNG7) [lut_numCnInCnGroups[4]] = (uint32_t(*)[lut_numCnInCnGroups[4]]) p_lut->startAddrBnProcBuf[4];
-    const uint32_t (*lut_startAddrBnProcBuf_CNG8) [lut_numCnInCnGroups[5]] = (uint32_t(*)[lut_numCnInCnGroups[5]]) p_lut->startAddrBnProcBuf[5];
-    const uint32_t (*lut_startAddrBnProcBuf_CNG9) [lut_numCnInCnGroups[6]] = (uint32_t(*)[lut_numCnInCnGroups[6]]) p_lut->startAddrBnProcBuf[6];
-    const uint32_t (*lut_startAddrBnProcBuf_CNG10)[lut_numCnInCnGroups[7]] = (uint32_t(*)[lut_numCnInCnGroups[7]]) p_lut->startAddrBnProcBuf[7];
-    const uint32_t (*lut_startAddrBnProcBuf_CNG19)[lut_numCnInCnGroups[8]] = (uint32_t(*)[lut_numCnInCnGroups[8]]) p_lut->startAddrBnProcBuf[8];
-
-    const uint8_t (*lut_bnPosBnProcBuf_CNG4) [lut_numCnInCnGroups[1]] = (uint8_t(*)[lut_numCnInCnGroups[1]]) p_lut->bnPosBnProcBuf[1];
-    const uint8_t (*lut_bnPosBnProcBuf_CNG5) [lut_numCnInCnGroups[2]] = (uint8_t(*)[lut_numCnInCnGroups[2]]) p_lut->bnPosBnProcBuf[2];
-    const uint8_t (*lut_bnPosBnProcBuf_CNG6) [lut_numCnInCnGroups[3]] = (uint8_t(*)[lut_numCnInCnGroups[3]]) p_lut->bnPosBnProcBuf[3];
-    const uint8_t (*lut_bnPosBnProcBuf_CNG7) [lut_numCnInCnGroups[4]] = (uint8_t(*)[lut_numCnInCnGroups[4]]) p_lut->bnPosBnProcBuf[4];
-    const uint8_t (*lut_bnPosBnProcBuf_CNG8) [lut_numCnInCnGroups[5]] = (uint8_t(*)[lut_numCnInCnGroups[5]]) p_lut->bnPosBnProcBuf[5];
-    const uint8_t (*lut_bnPosBnProcBuf_CNG9) [lut_numCnInCnGroups[6]] = (uint8_t(*)[lut_numCnInCnGroups[6]]) p_lut->bnPosBnProcBuf[6];
-    const uint8_t (*lut_bnPosBnProcBuf_CNG10)[lut_numCnInCnGroups[7]] = (uint8_t(*)[lut_numCnInCnGroups[7]]) p_lut->bnPosBnProcBuf[7];
-    const uint8_t (*lut_bnPosBnProcBuf_CNG19)[lut_numCnInCnGroups[8]] = (uint8_t(*)[lut_numCnInCnGroups[8]]) p_lut->bnPosBnProcBuf[8];
+    const uint16_t (*lut_circShift_CNG3) [lut_numCnInCnGroups_BG1_R13[0]] = (const uint16_t(*)[lut_numCnInCnGroups_BG1_R13[0]]) p_lut->circShift[0];
+    const uint16_t (*lut_circShift_CNG4) [lut_numCnInCnGroups_BG1_R13[1]] = (const uint16_t(*)[lut_numCnInCnGroups_BG1_R13[1]]) p_lut->circShift[1];
+    const uint16_t (*lut_circShift_CNG5) [lut_numCnInCnGroups_BG1_R13[2]] = (const uint16_t(*)[lut_numCnInCnGroups_BG1_R13[2]]) p_lut->circShift[2];
+    const uint16_t (*lut_circShift_CNG6) [lut_numCnInCnGroups_BG1_R13[3]] = (const uint16_t(*)[lut_numCnInCnGroups_BG1_R13[3]]) p_lut->circShift[3];
+    const uint16_t (*lut_circShift_CNG7) [lut_numCnInCnGroups_BG1_R13[4]] = (const uint16_t(*)[lut_numCnInCnGroups_BG1_R13[4]]) p_lut->circShift[4];
+    const uint16_t (*lut_circShift_CNG8) [lut_numCnInCnGroups_BG1_R13[5]] = (const uint16_t(*)[lut_numCnInCnGroups_BG1_R13[5]]) p_lut->circShift[5];
+    const uint16_t (*lut_circShift_CNG9) [lut_numCnInCnGroups_BG1_R13[6]] = (const uint16_t(*)[lut_numCnInCnGroups_BG1_R13[6]]) p_lut->circShift[6];
+    const uint16_t (*lut_circShift_CNG10)[lut_numCnInCnGroups_BG1_R13[7]] = (const uint16_t(*)[lut_numCnInCnGroups_BG1_R13[7]]) p_lut->circShift[7];
+    const uint16_t (*lut_circShift_CNG19)[lut_numCnInCnGroups_BG1_R13[8]] = (const uint16_t(*)[lut_numCnInCnGroups_BG1_R13[8]]) p_lut->circShift[8];
+
+    const uint32_t (*lut_startAddrBnProcBuf_CNG3) [lut_numCnInCnGroups[0]] = (const uint32_t(*)[lut_numCnInCnGroups[0]]) p_lut->startAddrBnProcBuf[0];
+    const uint32_t (*lut_startAddrBnProcBuf_CNG4) [lut_numCnInCnGroups[1]] = (const uint32_t(*)[lut_numCnInCnGroups[1]]) p_lut->startAddrBnProcBuf[1];
+    const uint32_t (*lut_startAddrBnProcBuf_CNG5) [lut_numCnInCnGroups[2]] = (const uint32_t(*)[lut_numCnInCnGroups[2]]) p_lut->startAddrBnProcBuf[2];
+    const uint32_t (*lut_startAddrBnProcBuf_CNG6) [lut_numCnInCnGroups[3]] = (const uint32_t(*)[lut_numCnInCnGroups[3]]) p_lut->startAddrBnProcBuf[3];
+    const uint32_t (*lut_startAddrBnProcBuf_CNG7) [lut_numCnInCnGroups[4]] = (const uint32_t(*)[lut_numCnInCnGroups[4]]) p_lut->startAddrBnProcBuf[4];
+    const uint32_t (*lut_startAddrBnProcBuf_CNG8) [lut_numCnInCnGroups[5]] = (const uint32_t(*)[lut_numCnInCnGroups[5]]) p_lut->startAddrBnProcBuf[5];
+    const uint32_t (*lut_startAddrBnProcBuf_CNG9) [lut_numCnInCnGroups[6]] = (const uint32_t(*)[lut_numCnInCnGroups[6]]) p_lut->startAddrBnProcBuf[6];
+    const uint32_t (*lut_startAddrBnProcBuf_CNG10)[lut_numCnInCnGroups[7]] = (const uint32_t(*)[lut_numCnInCnGroups[7]]) p_lut->startAddrBnProcBuf[7];
+    const uint32_t (*lut_startAddrBnProcBuf_CNG19)[lut_numCnInCnGroups[8]] = (const uint32_t(*)[lut_numCnInCnGroups[8]]) p_lut->startAddrBnProcBuf[8];
+
+    const uint8_t (*lut_bnPosBnProcBuf_CNG4) [lut_numCnInCnGroups[1]] = (const uint8_t(*)[lut_numCnInCnGroups[1]]) p_lut->bnPosBnProcBuf[1];
+    const uint8_t (*lut_bnPosBnProcBuf_CNG5) [lut_numCnInCnGroups[2]] = (const uint8_t(*)[lut_numCnInCnGroups[2]]) p_lut->bnPosBnProcBuf[2];
+    const uint8_t (*lut_bnPosBnProcBuf_CNG6) [lut_numCnInCnGroups[3]] = (const uint8_t(*)[lut_numCnInCnGroups[3]]) p_lut->bnPosBnProcBuf[3];
+    const uint8_t (*lut_bnPosBnProcBuf_CNG7) [lut_numCnInCnGroups[4]] = (const uint8_t(*)[lut_numCnInCnGroups[4]]) p_lut->bnPosBnProcBuf[4];
+    const uint8_t (*lut_bnPosBnProcBuf_CNG8) [lut_numCnInCnGroups[5]] = (const uint8_t(*)[lut_numCnInCnGroups[5]]) p_lut->bnPosBnProcBuf[5];
+    const uint8_t (*lut_bnPosBnProcBuf_CNG9) [lut_numCnInCnGroups[6]] = (const uint8_t(*)[lut_numCnInCnGroups[6]]) p_lut->bnPosBnProcBuf[6];
+    const uint8_t (*lut_bnPosBnProcBuf_CNG10)[lut_numCnInCnGroups[7]] = (const uint8_t(*)[lut_numCnInCnGroups[7]]) p_lut->bnPosBnProcBuf[7];
+    const uint8_t (*lut_bnPosBnProcBuf_CNG19)[lut_numCnInCnGroups[8]] = (const uint8_t(*)[lut_numCnInCnGroups[8]]) p_lut->bnPosBnProcBuf[8];
 
     int8_t* cnProcBuf    = p_procBuf->cnProcBuf;
     int8_t* bnProcBufRes = p_procBuf->bnProcBufRes;
diff --git a/openair1/PHY/INIT/nr_init.c b/openair1/PHY/INIT/nr_init.c
index af411fc7d776e4a4ac4d0d4308ab4901ac4d59a9..813d419429be678a4dd95e6340c158c0c6192f05 100644
--- a/openair1/PHY/INIT/nr_init.c
+++ b/openair1/PHY/INIT/nr_init.c
@@ -112,6 +112,8 @@ int phy_init_nr_gNB(PHY_VARS_gNB *gNB,
           );*/
   LOG_D(PHY,"[MSC_NEW][FRAME 00000][PHY_gNB][MOD %02"PRIu8"][]\n", gNB->Mod_id);
   crcTableInit();
+  init_scrambling_luts();
+  init_pucch2_luts();
   load_nrLDPClib();
   // PBCH DMRS gold sequences generation
   nr_init_pbch_dmrs(gNB);
diff --git a/openair1/PHY/NR_REFSIG/nr_refsig.h b/openair1/PHY/NR_REFSIG/nr_refsig.h
index 5af0e880999dcac8e8dec184be57835197e61fcb..d18f6405d7bf2a5f602ca60399cb10a124004495 100644
--- a/openair1/PHY/NR_REFSIG/nr_refsig.h
+++ b/openair1/PHY/NR_REFSIG/nr_refsig.h
@@ -26,7 +26,7 @@
 
 #include "PHY/defs_gNB.h"
 #include "PHY/LTE_REFSIG/lte_refsig.h"
-
+#include "PHY/sse_intrin.h"
 
 /*!\brief This function generates the NR Gold sequence (38-211, Sec 5.2.1) for the PBCH DMRS.
 @param PHY_VARS_gNB* gNB structure provides configuration, frame parameters and the pointers to the 32 bits sequence storage tables
@@ -49,4 +49,10 @@ int nr_pusch_dmrs_rx(PHY_VARS_gNB *gNB,
                      unsigned char lp,
                      unsigned short nb_pusch_rb,
                      uint8_t dmrs_type);
+
+void init_scrambling_luts(void);
+
+extern __m64 byte2m64_re[256];
+extern __m64 byte2m64_im[256];
+
 #endif
diff --git a/openair1/PHY/NR_REFSIG/scrambling_luts.c b/openair1/PHY/NR_REFSIG/scrambling_luts.c
new file mode 100644
index 0000000000000000000000000000000000000000..eae54f94fb431c211380118e20a71607145d234b
--- /dev/null
+++ b/openair1/PHY/NR_REFSIG/scrambling_luts.c
@@ -0,0 +1,62 @@
+/*
+ * Licensed to the OpenAirInterface (OAI) Software Alliance under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The OpenAirInterface Software Alliance licenses this file to You under
+ * the OAI Public License, Version 1.1  (the "License"); you may not use this file
+ * except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.openairinterface.org/?page_id=698
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *-------------------------------------------------------------------------------
+ * For more information about the OpenAirInterface (OAI) Software Alliance:
+ *      contact@openairinterface.org
+ */
+
+/* Lookup tables for 3GPP scrambling/unscrambling */
+
+/* Author R. Knopp / EURECOM / OpenAirInterface.org */
+#ifndef __SCRAMBLING_LUTS__C__
+#define __SCRAMBLING_LUTS__C__
+
+#include "PHY/impl_defs_nr.h"
+#include "PHY/sse_intrin.h"
+
+__m64 byte2m64_re[256];
+__m64 byte2m64_im[256];
+
+void init_byte2m64() {
+
+  for (int s=0;s<256;s++) {
+    byte2m64_re[s] = _mm_insert_pi16(byte2m64_re[s],(1-2*(s&1)),0);
+    byte2m64_im[s] = _mm_insert_pi16(byte2m64_im[s],(1-2*((s>>1)&1)),0);
+    byte2m64_re[s] = _mm_insert_pi16(byte2m64_re[s],(1-2*((s>>2)&1)),1);
+    byte2m64_im[s] = _mm_insert_pi16(byte2m64_im[s],(1-2*((s>>3)&1)),1);
+    byte2m64_re[s] = _mm_insert_pi16(byte2m64_re[s],(1-2*((s>>4)&1)),2);
+    byte2m64_im[s] = _mm_insert_pi16(byte2m64_im[s],(1-2*((s>>5)&1)),2);
+    byte2m64_re[s] = _mm_insert_pi16(byte2m64_re[s],(1-2*((s>>6)&1)),3);
+    byte2m64_im[s] = _mm_insert_pi16(byte2m64_im[s],(1-2*((s>>7)&1)),3);
+     printf("init_scrambling_luts: s %x (%d) ((%d,%d),(%d,%d),(%d,%d),(%d,%d))\n",
+	    ((uint16_t*)&s)[0],
+	    (1-2*(s&1)),
+	    ((int16_t*)&byte2m64_re[s])[0],((int16_t*)&byte2m64_im[s])[0],    
+	    ((int16_t*)&byte2m64_re[s])[1],((int16_t*)&byte2m64_im[s])[1],    
+	    ((int16_t*)&byte2m64_re[s])[2],((int16_t*)&byte2m64_im[s])[2],    
+	    ((int16_t*)&byte2m64_re[s])[3],((int16_t*)&byte2m64_im[s])[3]);    
+
+  }
+}
+
+void init_scrambling_luts() {
+
+  init_byte2m64();
+
+}
+
+#endif
diff --git a/openair1/PHY/NR_TRANSPORT/nr_transport.h b/openair1/PHY/NR_TRANSPORT/nr_transport.h
index fea782c30ea4094752d751bb1d5ddd48ef235608..98e5930c4c3b6992a4c456c617ab30c6adf33ec5 100644
--- a/openair1/PHY/NR_TRANSPORT/nr_transport.h
+++ b/openair1/PHY/NR_TRANSPORT/nr_transport.h
@@ -130,4 +130,25 @@ void compute_nr_prach_seq(uint16_t rootSequenceIndex,
 			  lte_frame_type_t frame_type,
 			  nr_frequency_range_e fr,
 			  uint32_t X_u[64][839]);
+
+void nr_decode_pucch1(int32_t **rxdataF,
+                      pucch_GroupHopping_t pucch_GroupHopping,
+                      uint32_t n_id,       // hoppingID higher layer parameter
+                      uint64_t *payload,
+                      NR_DL_FRAME_PARMS *frame_parms,
+                      int16_t amp,
+                      int nr_tti_tx,
+                      uint8_t m0,
+                      uint8_t nrofSymbols,
+                      uint8_t startingSymbolIndex,
+                      uint16_t startingPRB,
+                      uint16_t startingPRB_intraSlotHopping,
+                      uint8_t timeDomainOCC,
+                      uint8_t nr_bit);
+
+void nr_decode_pucch0(PHY_VARS_gNB *gNB,
+		      int slot,
+                      nfapi_nr_uci_pucch_pdu_format_0_1_t* uci_pdu,
+                      nfapi_nr_pucch_pdu_t* pucch_pdu);
+
 #endif /*__NR_TRANSPORT__H__*/
diff --git a/openair1/PHY/NR_TRANSPORT/nr_transport_common_proto.h b/openair1/PHY/NR_TRANSPORT/nr_transport_common_proto.h
index 762346048f94f9e62e7733ecdbb4010ffa107dd1..85f3c00b906888507449d9dcff5d9ee9c2a0786d 100644
--- a/openair1/PHY/NR_TRANSPORT/nr_transport_common_proto.h
+++ b/openair1/PHY/NR_TRANSPORT/nr_transport_common_proto.h
@@ -41,7 +41,19 @@
 #define NR_PUSCH_y 3 // UCI placeholder bit 
 
 
+void nr_group_sequence_hopping(pucch_GroupHopping_t PUCCH_GroupHopping,
+                               uint32_t n_id,
+                               uint8_t n_hop,
+                               int nr_tti_tx,
+                               uint8_t *u,
+                               uint8_t *v);
 
+double nr_cyclic_shift_hopping(uint32_t n_id,
+                               uint8_t m0,
+                               uint8_t mcs,
+                               uint8_t lnormal,
+                               uint8_t lprime,
+                               int nr_tti_tx);
 
 
 /** \brief Computes available bits G. */
diff --git a/openair1/PHY/NR_TRANSPORT/nr_uci_tools_common.c b/openair1/PHY/NR_TRANSPORT/nr_uci_tools_common.c
new file mode 100644
index 0000000000000000000000000000000000000000..2b0cbe72b3a91c8757c12d3ccbf194d5d08f740c
--- /dev/null
+++ b/openair1/PHY/NR_TRANSPORT/nr_uci_tools_common.c
@@ -0,0 +1,167 @@
+/*
+ * Licensed to the OpenAirInterface (OAI) Software Alliance under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The OpenAirInterface Software Alliance licenses this file to You under
+ * the OAI Public License, Version 1.1  (the "License"); you may not use this file
+ * except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.openairinterface.org/?page_id=698
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *-------------------------------------------------------------------------------
+ * For more information about the OpenAirInterface (OAI) Software Alliance:
+ *      contact@openairinterface.org
+ */
+
+/*! \file PHY/NR_TRANSPORT/nr_dci_tools_common.c
+ * \brief
+ * \author
+ * \date 2020
+ * \version 0.1
+ * \company Eurecom
+ * \email:
+ * \note
+ * \warning
+ */
+
+#include "nr_dci.h"
+
+void nr_group_sequence_hopping (pucch_GroupHopping_t PUCCH_GroupHopping,
+  				uint32_t n_id,
+  				uint8_t n_hop,
+  				int nr_tti_tx,
+  				uint8_t *u,
+  				uint8_t *v) {
+  /*
+   * Implements TS 38.211 subclause 6.3.2.2.1 Group and sequence hopping
+   * The following variables are set by higher layers:
+   *    - PUCCH_GroupHopping:
+   *    - n_id: higher-layer parameter hoppingId
+   *    - n_hop: frequency hopping index
+   *             if intra-slot frequency hopping is disabled by the higher-layer parameter PUCCH-frequency-hopping
+   *                n_hop=0
+   *             if frequency hopping is enabled by the higher-layer parameter PUCCH-frequency-hopping
+   *                n_hop=0 for the first hop
+   *                n_hop=1 for the second hop
+   */
+  // depending on the value of the PUCCH_GroupHopping, we will obtain different values for u,v
+  //pucch_GroupHopping_t PUCCH_GroupHopping = ue->pucch_config_common_nr->pucch_GroupHopping; // from higher layers FIXME!!!
+  // n_id defined as per TS 38.211 subclause 6.3.2.2.1 (is given by the higher-layer parameter hoppingId)
+  // it is hoppingId from PUCCH-ConfigCommon:
+  // Cell-Specific scrambling ID for group hoppping and sequence hopping if enabled
+  // Corresponds to L1 parameter 'HoppingID' (see 38.211, section 6.3.2.2) BIT STRING (SIZE (10))
+  //uint16_t n_id = ue->pucch_config_common_nr->hoppingId; // from higher layers FIXME!!!
+#ifdef DEBUG_NR_PUCCH_TX
+  printf("\t\t [nr_group_sequence_hopping] PUCCH_GroupHopping=%u, n_id=%u \n",PUCCH_GroupHopping,n_id);
+#endif
+  uint8_t f_ss=0,f_gh=0;
+  *u=0;
+  *v=0;
+  uint32_t c_init = 0; 
+  uint32_t x1,s; // TS 38.211 Subclause 5.2.1
+  int l = 32, minShift = ((2*nr_tti_tx+n_hop)<<3);
+  int tmpShift =0;
+#ifdef DEBUG_NR_PUCCH_TX
+  printf("\t\t [nr_group_sequence_hopping] calculating u,v -> ");
+#endif
+
+  if (PUCCH_GroupHopping == neither) { // PUCCH_GroupHopping 'neither'
+    f_ss = n_id%30;
+  }
+
+  if (PUCCH_GroupHopping == enable) { // PUCCH_GroupHopping 'enabled'
+    c_init = floor(n_id/30); // we initialize c_init to calculate u,v according to 6.3.2.2.1 of 38.211
+    s = lte_gold_generic(&x1, &c_init, 1); // TS 38.211 Subclause 5.2.1
+    for (int m=0; m<8; m++) {
+      while(minShift >= l) {
+        s = lte_gold_generic(&x1, &c_init, 0);
+        l = l+32;
+      }
+
+      tmpShift = (minShift&((1<<5)-1)); //minShift%32;
+      f_gh = f_gh + ((1<<m)*((uint8_t)((s>>tmpShift)&1)));
+      minShift ++;
+    }
+
+    f_gh = f_gh%30;
+    f_ss = n_id%30;
+    /*    for (int m=0; m<8; m++){
+          f_gh = f_gh + ((1<<m)*((uint8_t)((s>>(8*(2*nr_tti_tx+n_hop)+m))&1))); // Not sure we have to use nr_tti_tx FIXME!!!
+        }
+        f_gh = f_gh%30;
+        f_ss = n_id%30;*/
+  }
+
+  if (PUCCH_GroupHopping == disable) { // PUCCH_GroupHopping 'disabled'
+    c_init = (1<<5)*floor(n_id/30)+(n_id%30); // we initialize c_init to calculate u,v
+    s = lte_gold_generic(&x1, &c_init, 1); // TS 38.211 Subclause 5.2.1
+    f_ss = n_id%30;
+    l = 32, minShift = (2*nr_tti_tx+n_hop);
+
+    while(minShift >= l) {
+      s = lte_gold_generic(&x1, &c_init, 0);
+      l = l+32;
+    }
+
+    tmpShift = (minShift&((1<<5)-1)); //minShift%32;
+    *v = (uint8_t)((s>>tmpShift)&1);
+    //    *v = (uint8_t)((s>>(2*nr_tti_tx+n_hop))&1); // Not sure we have to use nr_tti_tx FIXME!!!
+  }
+
+  *u = (f_gh+f_ss)%30;
+#ifdef DEBUG_NR_PUCCH_TX
+  printf("%d,%d\n",*u,*v);
+#endif
+}
+
+double nr_cyclic_shift_hopping(uint32_t n_id,
+                               uint8_t m0,
+                               uint8_t mcs,
+                               uint8_t lnormal,
+                               uint8_t lprime,
+                               int nr_tti_tx) {
+  /*
+   * Implements TS 38.211 subclause 6.3.2.2.2 Cyclic shift hopping
+   *     - n_id: higher-layer parameter hoppingId
+   *     - m0: provided by higher layer parameter PUCCH-F0-F1-initial-cyclic-shift of PUCCH-F0-resource-config
+   *     - mcs: mcs=0 except for PUCCH format 0 when it depends on information to be transmitted according to TS 38.213 subclause 9.2
+   *     - lnormal: lnormal is the OFDM symbol number in the PUCCH transmission where l=0 corresponds to the first OFDM symbol of the PUCCH transmission
+   *     - lprime: lprime is the index of the OFDM symbol in the slot that corresponds to the first OFDM symbol of the PUCCH transmission in the slot given by [5, TS 38.213]
+   */
+  // alpha_init initialized to 2*PI/12=0.5235987756
+  double alpha = 0.5235987756;
+  uint32_t c_init = n_id; // we initialize c_init again to calculate n_cs
+
+  uint32_t x1,s = lte_gold_generic(&x1, &c_init, 1); // TS 38.211 Subclause 5.2.1
+  uint8_t n_cs=0;
+  int l = 32, minShift = (14*8*nr_tti_tx )+ 8*(lnormal+lprime);
+  int tmpShift =0;
+#ifdef DEBUG_NR_PUCCH_TX
+  printf("\t\t [nr_cyclic_shift_hopping] calculating alpha (cyclic shift) using c_init=%u -> \n",c_init);
+#endif
+
+  for (int m=0; m<8; m++) {
+    while(minShift >= l) {
+      s = lte_gold_generic(&x1, &c_init, 0);
+      l = l+32;
+    }
+
+    tmpShift = (minShift&((1<<5)-1)); //minShift%32;
+    minShift ++;
+    n_cs = n_cs+((1<<m)*((uint8_t)((s>>tmpShift)&1)));
+    // calculating n_cs (Not sure we have to use nr_tti_tx FIXME!!!)
+    // n_cs = n_cs+((1<<m)*((uint8_t)((s>>((14*8*nr_tti_tx) + 8*(lnormal+lprime) + m))&1)));
+  }
+
+  alpha = (alpha * (double)((m0+mcs+n_cs)%12));
+#ifdef DEBUG_NR_PUCCH_TX
+  printf("n_cs=%d -> %lf\n",n_cs,alpha);
+#endif
+  return(alpha);
+}
diff --git a/openair1/PHY/NR_TRANSPORT/pucch_rx.c b/openair1/PHY/NR_TRANSPORT/pucch_rx.c
index b74b078dfd6ffcd63faa97b59314335405e0f546..62ced5af9d28631caa6eea2b886844eb3d117c66 100644
--- a/openair1/PHY/NR_TRANSPORT/pucch_rx.c
+++ b/openair1/PHY/NR_TRANSPORT/pucch_rx.c
@@ -1,3 +1,34 @@
+/*
+ * Licensed to the OpenAirInterface (OAI) Software Alliance under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The OpenAirInterface Software Alliance licenses this file to You under
+ * the OAI Public License, Version 1.1  (the "License"); you may not use this file
+ * except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.openairinterface.org/?page_id=698
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *-------------------------------------------------------------------------------
+ * For more information about the OpenAirInterface (OAI) Software Alliance:
+ *      contact@openairinterface.org
+ */
+
+/*! \file PHY/NR_TRANSPORT/pucch_rx.c
+* \brief Top-level routines for decoding the PUCCH physical channel
+* \author A. Mico Pereperez, Padarthi Naga Prasanth, Francesco Mani, Raymond Knopp
+* \date 2020
+* \version 0.2
+* \company Eurecom
+* \email:
+* \note
+* \warning
+*/
 #include<stdio.h>
 #include <string.h>
 #include <math.h>
@@ -8,38 +39,112 @@
 
 #include "PHY/impl_defs_nr.h"
 #include "PHY/defs_nr_common.h"
-#include "PHY/defs_nr_UE.h"
+#include "PHY/defs_gNB.h"
+#include "PHY/sse_intrin.h"
 #include "PHY/NR_UE_TRANSPORT/pucch_nr.h"
-#include "PHY/NR_UE_TRANSPORT/nr_transport_proto_ue.h"
-
+#include "PHY/NR_TRANSPORT/nr_transport_common_proto.h"
+#include "PHY/NR_TRANSPORT/nr_transport.h"
+#include "PHY/NR_REFSIG/nr_refsig.h"
 #include "common/utils/LOG/log.h"
 #include "common/utils/LOG/vcd_signal_dumper.h"
 
 #include "T.h"
 
+//#define DEBUG_NR_PUCCH_RX 1
+
+int get_pucch0_cs_lut_index(PHY_VARS_gNB *gNB,nfapi_nr_pucch_pdu_t* pucch_pdu) {
+
+  int i=0;
+
+#ifdef DEBUG_NR_PUCCH_RX
+  printf("getting index for LUT with %d entries, Nid %d\n",gNB->pucch0_lut.nb_id, pucch_pdu->hopping_id);
+#endif
+
+  for (i=0;i<gNB->pucch0_lut.nb_id;i++) {
+    if (gNB->pucch0_lut.Nid[i] == pucch_pdu->hopping_id) break;
+  }
+#ifdef DEBUG_NR_PUCCH_RX
+  printf("found index %d\n",i);
+#endif
+  if (i<gNB->pucch0_lut.nb_id) return(i);
+
+#ifdef DEBUG_NR_PUCCH_RX
+  printf("Initializing PUCCH0 LUT index %i with Nid %d\n",i, pucch_pdu->hopping_id);
+#endif
+  // initialize
+  gNB->pucch0_lut.Nid[gNB->pucch0_lut.nb_id]=pucch_pdu->hopping_id;
+  for (int slot=0;slot<10<<pucch_pdu->subcarrier_spacing;slot++)
+    for (int symbol=0;symbol<14;symbol++)
+      gNB->pucch0_lut.lut[gNB->pucch0_lut.nb_id][slot][symbol] = (int)floor(nr_cyclic_shift_hopping(pucch_pdu->hopping_id,0,0,symbol,0,slot)/0.5235987756);
+  gNB->pucch0_lut.nb_id++;
+  return(gNB->pucch0_lut.nb_id-1);
+}
+
+
+  
+int16_t idft12_re[12][12] = {
+  {23170,23170,23170,23170,23170,23170,23170,23170,23170,23170,23170,23170},
+  {23170,20066,11585,0,-11585,-20066,-23170,-20066,-11585,0,11585,20066},
+  {23170,11585,-11585,-23170,-11585,11585,23170,11585,-11585,-23170,-11585,11585},
+  {23170,0,-23170,0,23170,0,-23170,0,23170,0,-23170,0},
+  {23170,-11585,-11585,23170,-11585,-11585,23170,-11585,-11585,23170,-11585,-11585},
+  {23170,-20066,11585,0,-11585,20066,-23170,20066,-11585,0,11585,-20066},
+  {23170,-23170,23170,-23170,23170,-23170,23170,-23170,23170,-23170,23170,-23170},
+  {23170,-20066,11585,0,-11585,20066,-23170,20066,-11585,0,11585,-20066},
+  {23170,-11585,-11585,23170,-11585,-11585,23170,-11585,-11585,23170,-11585,-11585},
+  {23170,0,-23170,0,23170,0,-23170,0,23170,0,-23170,0},
+  {23170,11585,-11585,-23170,-11585,11585,23170,11585,-11585,-23170,-11585,11585},
+  {23170,20066,11585,0,-11585,-20066,-23170,-20066,-11585,0,11585,20066}
+};
+
+int16_t idft12_im[12][12] = {
+  {0,0,0,0,0,0,0,0,0,0,0,0},
+  {0,11585,20066,23170,20066,11585,0,-11585,-20066,-23170,-20066,-11585},
+  {0,20066,20066,0,-20066,-20066,0,20066,20066,0,-20066,-20066},
+  {0,23170,0,-23170,0,23170,0,-23170,0,23170,0,-23170},
+  {0,20066,-20066,0,20066,-20066,0,20066,-20066,0,20066,-20066},
+  {0,11585,-20066,23170,-20066,11585,0,-11585,20066,-23170,20066,-11585},
+  {0,0,0,0,0,0,0,0,0,0,0,0},
+  {0,-11585,20066,-23170,20066,-11585,0,11585,-20066,23170,-20066,11585},
+  {0,-20066,20066,0,-20066,20066,0,-20066,20066,0,-20066,20066},
+  {0,-23170,0,23170,0,-23170,0,23170,0,-23170,0,23170},
+  {0,-20066,-20066,0,20066,20066,0,-20066,-20066,0,20066,20066},
+  {0,-11585,-20066,-23170,-20066,-11585,0,11585,20066,23170,20066,11585}
+};
+
+
+void nr_decode_pucch0(PHY_VARS_gNB *gNB,
+                      int slot,
+                      nfapi_nr_uci_pucch_pdu_format_0_1_t* uci_pdu,
+                      nfapi_nr_pucch_pdu_t* pucch_pdu) {
+
+
+  int32_t **rxdataF = gNB->common_vars.rxdataF;
+  NR_DL_FRAME_PARMS *frame_parms = &gNB->frame_parms;
 
-void nr_decode_pucch0( int32_t **rxdataF,
-			pucch_GroupHopping_t pucch_GroupHopping,
-			uint32_t n_id,       // hoppingID higher layer parameter                                        
-                        uint64_t *payload,
-                        NR_DL_FRAME_PARMS *frame_parms,
-                        int16_t amp,
-                        int nr_tti_tx,
-                        uint8_t m0,                                          // should come from resource set
-                        uint8_t nrofSymbols,				    // should come from resource set	
-                        uint8_t startingSymbolIndex,			    // should come from resource set
-                        uint16_t startingPRB,				   // should come from resource set
-			uint8_t nr_bit) {                                 // is number of UCI bits to be decoded
   int nr_sequences;
   const uint8_t *mcs;
-  if(nr_bit==1){
+
+  pucch_GroupHopping_t pucch_GroupHopping = pucch_pdu->group_hop_flag + (pucch_pdu->sequence_hop_flag<<1);
+
+  AssertFatal(pucch_pdu->bit_len_harq > 0 || pucch_pdu->sr_flag > 0,
+	      "Either bit_len_harq (%d) or sr_flag (%d) must be > 0\n",
+	      pucch_pdu->bit_len_harq,pucch_pdu->sr_flag);
+
+  if(pucch_pdu->bit_len_harq==0){
     mcs=table1_mcs;
-    nr_sequences=4;
+    nr_sequences=1;
+  }
+  else if(pucch_pdu->bit_len_harq==1){
+    mcs=table1_mcs;
+    nr_sequences=4>>(1-pucch_pdu->sr_flag);
   }
   else{
     mcs=table2_mcs;
-    nr_sequences=8;
+    nr_sequences=8>>(1-pucch_pdu->sr_flag);
   }
+
+  int cs_ind = get_pucch0_cs_lut_index(gNB,pucch_pdu);
   /*
    * Implement TS 38.211 Subclause 6.3.2.3.1 Sequence generation
    *
@@ -53,8 +158,6 @@ void nr_decode_pucch0( int32_t **rxdataF,
   //uint8_t lnormal;
   // lprime is the index of the OFDM symbol in the slot that corresponds to the first OFDM symbol of the PUCCH transmission in the slot given by [5, TS 38.213]
   //uint8_t lprime;
-  // mcs is provided by TC 38.213 subclauses 9.2.3, 9.2.4, 9.2.5 FIXME!
-  //uint8_t mcs;
 
   /*
    * in TS 38.213 Subclause 9.2.1 it is said that:
@@ -73,76 +176,76 @@ void nr_decode_pucch0( int32_t **rxdataF,
   // if frequency hopping is enabled by the higher-layer parameter PUCCH-frequency-hopping
   //              n_hop = 0 for first hop
   //              n_hop = 1 for second hop
-  uint8_t n_hop = 0;
-  //uint8_t PUCCH_Frequency_Hopping; // from higher layers FIXME!!
+  uint8_t n_hop = 0;  // Frequnecy hopping not implemented FIXME!!
 
   // x_n contains the sequence r_u_v_alpha_delta(n)
-  int16_t x_n_re[nr_sequences][24],x_n_im[nr_sequences][24];
+
   int n,i,l;
+  nr_group_sequence_hopping(pucch_GroupHopping,pucch_pdu->hopping_id,n_hop,slot,&u,&v); // calculating u and v value
+
+  uint32_t re_offset=0;
+  uint8_t l2;
+
+#ifdef OLD_IMPL
+  int16_t x_n_re[nr_sequences][24],x_n_im[nr_sequences][24];
+
   for(i=0;i<nr_sequences;i++){ 
   // we proceed to calculate alpha according to TS 38.211 Subclause 6.3.2.2.2
-    for (l=0; l<nrofSymbols; l++){
-    // if frequency hopping is enabled n_hop = 1 for second hop. Not sure frequency hopping concerns format 0. FIXME!!!
-    // if ((PUCCH_Frequency_Hopping == 1)&&(l == (nrofSymbols-1))) n_hop = 1;
-      nr_group_sequence_hopping(pucch_GroupHopping,n_id,n_hop,nr_tti_tx,&u,&v); // calculating u and v value
-      alpha = nr_cyclic_shift_hopping(n_id,m0,mcs[i],l,startingSymbolIndex,nr_tti_tx);
-      #ifdef DEBUG_NR_PUCCH_RX
-        printf("\t [nr_generate_pucch0] sequence generation \tu=%d \tv=%d \talpha=%lf \t(for symbol l=%d)\n",u,v,alpha,l);
-      #endif
+    for (l=0; l<pucch_pdu->nr_of_symbols; l++){
+      alpha = nr_cyclic_shift_hopping(pucch_pdu->hopping_id,pucch_pdu->initial_cyclic_shift,mcs[i],l,pucch_pdu->start_symbol_index,slot);
+#ifdef DEBUG_NR_PUCCH_RX
+      printf("\t [nr_generate_pucch0] sequence generation \tu=%d \tv=%d \talpha=%lf \t(for symbol l=%d/%d,mcs %d)\n",u,v,alpha,l,l+pucch_pdu->start_symbol_index,mcs[i]);
+      printf("lut output %d\n",gNB->pucch0_lut.lut[cs_ind][slot][l+pucch_pdu->start_symbol_index]);
+#endif
+      alpha=0.0;
       for (n=0; n<12; n++){
-        x_n_re[i][(12*l)+n] = (int16_t)((int32_t)(amp)*(int16_t)(((((int32_t)(round(32767*cos(alpha*n))) * table_5_2_2_2_2_Re[u][n])>>15)
-                                  - (((int32_t)(round(32767*sin(alpha*n))) * table_5_2_2_2_2_Im[u][n])>>15)))>>15); // Re part of base sequence shifted by alpha
-        x_n_im[i][(12*l)+n] =(int16_t)((int32_t)(amp)* (int16_t)(((((int32_t)(round(32767*cos(alpha*n))) * table_5_2_2_2_2_Im[u][n])>>15)
-                                  + (((int32_t)(round(32767*sin(alpha*n))) * table_5_2_2_2_2_Re[u][n])>>15)))>>15); // Im part of base sequence shifted by alpha
-        #ifdef DEBUG_NR_PUCCH_RX
-          printf("\t [nr_generate_pucch0] sequence generation \tu=%d \tv=%d \talpha=%lf \tx_n(l=%d,n=%d)=(%d,%d)\n",
-                u,v,alpha,l,n,x_n_re[(12*l)+n],x_n_im[(12*l)+n]);
-        #endif
+        x_n_re[i][(12*l)+n] = (int16_t)((int16_t)(((((int32_t)(round(32767*cos(alpha*n))) * table_5_2_2_2_2_Re[u][n])>>15)
+                                  - (((int32_t)(round(32767*sin(alpha*n))) * table_5_2_2_2_2_Im[u][n])>>15)))); // Re part of base sequence shifted by alpha
+        x_n_im[i][(12*l)+n] =(int16_t)((int16_t)(((((int32_t)(round(32767*cos(alpha*n))) * table_5_2_2_2_2_Im[u][n])>>15)
+                                  + (((int32_t)(round(32767*sin(alpha*n))) * table_5_2_2_2_2_Re[u][n])>>15)))); // Im part of base sequence shifted by alpha
+#ifdef DEBUG_NR_PUCCH_RX
+          printf("\t [nr_generate_pucch0] sequence generation \tu=%d \tv=%d \talpha=%lf \tx_n(l=%d,n=%d)=(%d,%d) %d,%d\n",
+		 u,v,alpha,l,n,x_n_re[i][(12*l)+n],x_n_im[i][(12*l)+n],
+		 (int32_t)(round(32767*cos(alpha*n))),
+		 (int32_t)(round(32767*sin(alpha*n))));
+#endif
       }
     }
   }
-  int16_t r_re[24],r_im[24];
   /*
-   * Implementing TS 38.211 Subclause 6.3.2.3.2 Mapping to physical resources FIXME!
+   * Implementing TS 38.211 Subclause 6.3.2.3.2 Mapping to physical resources
    */
-  uint32_t re_offset=0;
-  for (l=0; l<nrofSymbols; l++) {
-    if ((startingPRB <  (frame_parms->N_RB_DL>>1)) && ((frame_parms->N_RB_DL & 1) == 0)) { // if number RBs in bandwidth is even and current PRB is lower band
-      re_offset = ((l+startingSymbolIndex)*frame_parms->ofdm_symbol_size) + (12*startingPRB) + frame_parms->first_carrier_offset;
-    }
-    if ((startingPRB >= (frame_parms->N_RB_DL>>1)) && ((frame_parms->N_RB_DL & 1) == 0)) { // if number RBs in bandwidth is even and current PRB is upper band
-      re_offset = ((l+startingSymbolIndex)*frame_parms->ofdm_symbol_size) + (12*(startingPRB-(frame_parms->N_RB_DL>>1)));
-    }
-    if ((startingPRB <  (frame_parms->N_RB_DL>>1)) && ((frame_parms->N_RB_DL & 1) == 1)) { // if number RBs in bandwidth is odd  and current PRB is lower band
-      re_offset = ((l+startingSymbolIndex)*frame_parms->ofdm_symbol_size) + (12*startingPRB) + frame_parms->first_carrier_offset;
-    }
-    if ((startingPRB >  (frame_parms->N_RB_DL>>1)) && ((frame_parms->N_RB_DL & 1) == 1)) { // if number RBs in bandwidth is odd  and current PRB is upper band
-      re_offset = ((l+startingSymbolIndex)*frame_parms->ofdm_symbol_size) + (12*(startingPRB-(frame_parms->N_RB_DL>>1))) + 6;
-    }
-    if ((startingPRB == (frame_parms->N_RB_DL>>1)) && ((frame_parms->N_RB_DL & 1) == 1)) { // if number RBs in bandwidth is odd  and current PRB contains DC
-      re_offset = ((l+startingSymbolIndex)*frame_parms->ofdm_symbol_size) + (12*startingPRB) + frame_parms->first_carrier_offset;
-    }
+
+  int16_t r_re[24],r_im[24];
+
+  for (l=0; l<pucch_pdu->nr_of_symbols; l++) {
+
+    l2 = l+pucch_pdu->start_symbol_index;
+    re_offset = (12*pucch_pdu->prb_start) + (12*pucch_pdu->bwp_start) + frame_parms->first_carrier_offset;
+    if (re_offset>= frame_parms->ofdm_symbol_size) 
+      re_offset-=frame_parms->ofdm_symbol_size;
+
     for (n=0; n<12; n++){
-      if ((n==6) && (startingPRB == (frame_parms->N_RB_DL>>1)) && ((frame_parms->N_RB_DL & 1) == 1)) {
-        // if number RBs in bandwidth is odd  and current PRB contains DC, we need to recalculate the offset when n=6 (for second half PRB)
-        re_offset = ((l+startingSymbolIndex)*frame_parms->ofdm_symbol_size);
-      }
-      r_re[(12*l)+n]=((int16_t *)&rxdataF[0][re_offset])[0];
-      r_im[(12*l)+n]=((int16_t *)&rxdataF[0][re_offset])[1];
+
+      r_re[(12*l)+n]=((int16_t *)&rxdataF[0][(l2*frame_parms->ofdm_symbol_size)+re_offset])[0];
+      r_im[(12*l)+n]=((int16_t *)&rxdataF[0][(l2*frame_parms->ofdm_symbol_size)+re_offset])[1];
       #ifdef DEBUG_NR_PUCCH_RX
-        printf("\t [nr_generate_pucch0] mapping to RE \t amp=%d \tofdm_symbol_size=%d \tN_RB_DL=%d \tfirst_carrier_offset=%d \ttxptr(%d)=(x_n(l=%d,n=%d)=(%d,%d))\n",
-                amp,frame_parms->ofdm_symbol_size,frame_parms->N_RB_DL,frame_parms->first_carrier_offset,re_offset,
-                l,n,((int16_t *)&rxdataF[0][re_offset])[0],((int16_t *)&rxdataF[0][re_offset])[1]);
+        printf("\t [nr_generate_pucch0] mapping to RE \tofdm_symbol_size=%d \tN_RB_DL=%d \tfirst_carrier_offset=%d \ttxptr(%d)=(x_n(l=%d,n=%d)=(%d,%d))\n",
+                frame_parms->ofdm_symbol_size,frame_parms->N_RB_DL,frame_parms->first_carrier_offset,(l2*frame_parms->ofdm_symbol_size)+re_offset,
+                l,n,((int16_t *)&rxdataF[0][(l2*frame_parms->ofdm_symbol_size)+re_offset])[0],
+                ((int16_t *)&rxdataF[0][(l2*frame_parms->ofdm_symbol_size)+re_offset])[1]);
       #endif
       re_offset++;
+      if (re_offset>= frame_parms->ofdm_symbol_size) 
+        re_offset-=frame_parms->ofdm_symbol_size;
     }
-  }   
+  }  
   double corr[nr_sequences],corr_re[nr_sequences],corr_im[nr_sequences];
   memset(corr,0,nr_sequences*sizeof(double));
   memset(corr_re,0,nr_sequences*sizeof(double));
   memset(corr_im,0,nr_sequences*sizeof(double));
   for(i=0;i<nr_sequences;i++){
-    for(l=0;l<nrofSymbols;l++){
+    for(l=0;l<pucch_pdu->nr_of_symbols;l++){
       for(n=0;n<12;n++){
         corr_re[i]+= (double)(r_re[12*l+n])/32767*(double)(x_n_re[i][12*l+n])/32767+(double)(r_im[12*l+n])/32767*(double)(x_n_im[i][12*l+n])/32767;
 	corr_im[i]+= (double)(r_re[12*l+n])/32767*(double)(x_n_im[i][12*l+n])/32767-(double)(r_im[12*l+n])/32767*(double)(x_n_re[i][12*l+n])/32767;
@@ -151,14 +254,122 @@ void nr_decode_pucch0( int32_t **rxdataF,
     corr[i]=corr_re[i]*corr_re[i]+corr_im[i]*corr_im[i];
   }
   float max_corr=corr[0];
-  int index=0;
+  uint8_t index=0;
   for(i=1;i<nr_sequences;i++){
     if(corr[i]>max_corr){
       index= i;
       max_corr=corr[i];
     }
   }
-  *payload=(uint64_t)index;  // payload bits 00..b3b2b0, b0 is the SR bit and b3b2 are HARQ bits
+#else
+
+  int16_t *x_re = table_5_2_2_2_2_Re[u],*x_im = table_5_2_2_2_2_Im[u];
+  int16_t xr[24]  __attribute__((aligned(32)));
+  int16_t xrt[24] __attribute__((aligned(32)));
+  int32_t xrtmag=0;
+  int maxpos=0;
+  int n2=0;
+  uint8_t index=0;
+  memset((void*)xr,0,24*sizeof(int16_t));
+
+  for (l=0; l<pucch_pdu->nr_of_symbols; l++) {
+
+    l2 = l+pucch_pdu->start_symbol_index;
+    re_offset = (12*pucch_pdu->prb_start) + frame_parms->first_carrier_offset;
+    if (re_offset>= frame_parms->ofdm_symbol_size) 
+      re_offset-=frame_parms->ofdm_symbol_size;
+  
+    AssertFatal(re_offset+12 < frame_parms->ofdm_symbol_size,"pucch straddles DC carrier, handle this!\n");
+
+    int16_t *r=(int16_t*)&rxdataF[0][(l2*frame_parms->ofdm_symbol_size+re_offset)];
+    for (n=0;n<12;n++,n2+=2) {
+      xr[n2]  =(int16_t)(((int32_t)x_re[n]*r[n2]+(int32_t)x_im[n]*r[n2+1])>>15);
+      xr[n2+1]=(int16_t)(((int32_t)x_re[n]*r[n2+1]-(int32_t)x_im[n]*r[n2])>>15);
+#ifdef DEBUG_NR_PUCCH_RX
+      printf("x (%d,%d), r (%d,%d), xr (%d,%d)\n",
+	     x_re[n],x_im[n],r[n2],r[n2+1],xr[n2],xr[n2+1]);
+#endif
+    }
+  }
+  int32_t corr_re,corr_im,temp;
+  int seq_index;
+
+  for(i=0;i<nr_sequences;i++){
+    corr_re=0;corr_im=0;
+    n2=0;
+    for (l=0;l<pucch_pdu->nr_of_symbols;l++) {
+
+       seq_index = (pucch_pdu->initial_cyclic_shift+
+		   mcs[i]+
+		   gNB->pucch0_lut.lut[cs_ind][slot][l+pucch_pdu->start_symbol_index])%12;
+      for (n=0;n<12;n++,n2+=2) {
+	corr_re+=(xr[n2]*idft12_re[seq_index][n]+xr[n2+1]*idft12_im[seq_index][n])>>15;
+	corr_im+=(xr[n2]*idft12_im[seq_index][n]-xr[n2+1]*idft12_re[seq_index][n])>>15;
+      }
+    }
+
+#ifdef DEBUG_NR_PUCCH_RX
+    printf("PUCCH IDFT[%d/%d] = (%d,%d)=>%f\n",mcs[i],seq_index,corr_re,corr_im,10*log10(corr_re*corr_re + corr_im*corr_im));
+#endif
+    if ((temp=corr_re*corr_re + corr_im*corr_im)>xrtmag) {
+      xrtmag=temp;
+      maxpos=i;
+    }
+  }
+
+  uint8_t xrtmag_dB = dB_fixed(xrtmag);
+  
+#ifdef DEBUG_NR_PUCCH_RX
+  printf("PUCCH 0 : maxpos %d\n",maxpos);
+#endif
+
+  index=maxpos;
+#endif
+  // first bit of bitmap for sr presence and second bit for acknack presence
+  uci_pdu->pdu_bit_map = pucch_pdu->sr_flag | ((pucch_pdu->bit_len_harq>0)<<1);
+  uci_pdu->pucch_format = 0; // format 0
+  uci_pdu->ul_cqi = 0xff; // currently not valid
+  uci_pdu->timing_advance = 0xffff; // currently not valid
+  uci_pdu->rssi = 0xffff; // currently not valid
+
+  if (pucch_pdu->bit_len_harq==0) {
+    uci_pdu->harq = NULL;
+    uci_pdu->sr = calloc(1,sizeof(*uci_pdu->sr));
+    if (xrtmag_dB>(gNB->measurements.n0_subband_power_tot_dB[pucch_pdu->prb_start]+gNB->pucch0_thres)) {
+      uci_pdu->sr->sr_indication = 1;
+      uci_pdu->sr->sr_confidence_level = xrtmag_dB-(gNB->measurements.n0_subband_power_tot_dB[pucch_pdu->prb_start]+gNB->pucch0_thres);
+    } else {
+      uci_pdu->sr->sr_indication = 0;
+      uci_pdu->sr->sr_confidence_level = (gNB->measurements.n0_subband_power_tot_dB[pucch_pdu->prb_start]+gNB->pucch0_thres)-xrtmag_dB;
+    }
+  }
+  else if (pucch_pdu->bit_len_harq==1) {
+    uci_pdu->harq = calloc(1,sizeof(*uci_pdu->harq));
+    uci_pdu->harq->num_harq = 1;
+    uci_pdu->harq->harq_confidence_level = xrtmag_dB-(gNB->measurements.n0_subband_power_tot_dB[pucch_pdu->prb_start]+gNB->pucch0_thres);
+    uci_pdu->harq->harq_list = (nfapi_nr_harq_t*)malloc(1);
+    uci_pdu->harq->harq_list[0].harq_value = index&0x01;
+    if (pucch_pdu->sr_flag == 1) {
+      uci_pdu->sr = calloc(1,sizeof(*uci_pdu->sr));
+      uci_pdu->sr->sr_indication = (index>1) ? 1 : 0;
+      uci_pdu->sr->sr_confidence_level = xrtmag_dB-(gNB->measurements.n0_subband_power_tot_dB[pucch_pdu->prb_start]+gNB->pucch0_thres);
+    }
+  }
+  else {
+    uci_pdu->harq = calloc(1,sizeof(*uci_pdu->harq));
+    uci_pdu->harq->num_harq = 2;
+    uci_pdu->harq->harq_confidence_level = xrtmag_dB-(gNB->measurements.n0_subband_power_tot_dB[pucch_pdu->prb_start]+gNB->pucch0_thres);
+    uci_pdu->harq->harq_list = (nfapi_nr_harq_t*)malloc(2);
+
+    uci_pdu->harq->harq_list[0].harq_value = index&0x01;
+    uci_pdu->harq->harq_list[1].harq_value = (index>>1)&0x01;
+
+    if (pucch_pdu->sr_flag == 1) {
+      uci_pdu->sr = calloc(1,sizeof(*uci_pdu->sr));
+      uci_pdu->sr->sr_indication = (index>3) ? 1 : 0;
+      uci_pdu->sr->sr_confidence_level = xrtmag_dB-(gNB->measurements.n0_subband_power_tot_dB[pucch_pdu->prb_start]+gNB->pucch0_thres);
+    }
+  }
 }
 
 
@@ -274,7 +485,6 @@ void nr_decode_pucch1(  int32_t **rxdataF,
       re_offset = ((l+startingSymbolIndex)*frame_parms->ofdm_symbol_size) + (12*startingPRB) + frame_parms->first_carrier_offset;
     }
 
-    //txptr = &txdataF[0][re_offset];
     for (int n=0; n<12; n++) {
       if ((n==6) && (startingPRB == (frame_parms->N_RB_DL>>1)) && ((frame_parms->N_RB_DL & 1) == 1)) {
         // if number RBs in bandwidth is odd  and current PRB contains DC, we need to recalculate the offset when n=6 (for second half PRB)
@@ -287,7 +497,7 @@ void nr_decode_pucch1(  int32_t **rxdataF,
 #ifdef DEBUG_NR_PUCCH_RX
         printf("\t [nr_generate_pucch1] mapping PUCCH to RE \t amp=%d \tofdm_symbol_size=%d \tN_RB_DL=%d \tfirst_carrier_offset=%d \tz_pucch[%d]=txptr(%d)=(x_n(l=%d,n=%d)=(%d,%d))\n",
                amp,frame_parms->ofdm_symbol_size,frame_parms->N_RB_DL,frame_parms->first_carrier_offset,i+n,re_offset,
-               l,n,((int16_t *)&txdataF[0][re_offset])[0],((int16_t *)&txdataF[0][re_offset])[1]);
+               l,n,((int16_t *)&rxdataF[0][re_offset])[0],((int16_t *)&rxdataF[0][re_offset])[1]);
 #endif
       }
 
@@ -298,7 +508,7 @@ void nr_decode_pucch1(  int32_t **rxdataF,
 #ifdef DEBUG_NR_PUCCH_RX
         printf("\t [nr_generate_pucch1] mapping DM-RS to RE \t amp=%d \tofdm_symbol_size=%d \tN_RB_DL=%d \tfirst_carrier_offset=%d \tz_dm-rs[%d]=txptr(%d)=(x_n(l=%d,n=%d)=(%d,%d))\n",
                amp,frame_parms->ofdm_symbol_size,frame_parms->N_RB_DL,frame_parms->first_carrier_offset,i+n,re_offset,
-               l,n,((int16_t *)&txdataF[0][re_offset])[0],((int16_t *)&txdataF[0][re_offset])[1]);
+               l,n,((int16_t *)&rxdataF[0][re_offset])[0],((int16_t *)&rxdataF[0][re_offset])[1]);
 #endif
 //        printf("l=%d\ti=%d\tre_offset=%d\treceived dmrs re=%d\tim=%d\n",l,i,re_offset,z_dmrs_re_rx[i+n],z_dmrs_im_rx[i+n]);
       }
@@ -409,7 +619,7 @@ void nr_decode_pucch1(  int32_t **rxdataF,
                      mprime, m, n, (mprime*12*N_SF_mprime0_PUCCH_1)+(m*12)+n,
                      table_6_3_2_4_1_2_Wi_Re[N_SF_mprime_PUCCH_1][w_index][m],y_n_re[n],table_6_3_2_4_1_2_Wi_Im[N_SF_mprime_PUCCH_1][w_index][m],y_n_im[n],
                      table_6_3_2_4_1_2_Wi_Re[N_SF_mprime_PUCCH_1][w_index][m],y_n_im[n],table_6_3_2_4_1_2_Wi_Im[N_SF_mprime_PUCCH_1][w_index][m],y_n_re[n],
-                     z_re[(mprime*12*N_SF_mprime0_PUCCH_1)+(m*12)+n],z_im[(mprime*12*N_SF_mprime0_PUCCH_1)+(m*12)+n]);
+                     z_re_rx[(mprime*12*N_SF_mprime0_PUCCH_1)+(m*12)+n],z_im_rx[(mprime*12*N_SF_mprime0_PUCCH_1)+(m*12)+n]);
 #endif   
 	      // multiplying with conjugate of low papr sequence  
 	      z_re_temp = (int16_t)(((((int32_t)(r_u_v_alpha_delta_re[n])*z_re_rx[(mprime*12*N_SF_mprime0_PUCCH_1)+(m*12)+n])>>15)
@@ -443,7 +653,7 @@ void nr_decode_pucch1(  int32_t **rxdataF,
                      mprime, m, n, (mprime*12*N_SF_mprime0_PUCCH_1)+(m*12)+n,
                      table_6_3_2_4_1_2_Wi_Re[N_SF_mprime_PUCCH_1][w_index][m],r_u_v_alpha_delta_dmrs_re[n],table_6_3_2_4_1_2_Wi_Im[N_SF_mprime_PUCCH_1][w_index][m],r_u_v_alpha_delta_dmrs_im[n],
                      table_6_3_2_4_1_2_Wi_Re[N_SF_mprime_PUCCH_1][w_index][m],r_u_v_alpha_delta_dmrs_im[n],table_6_3_2_4_1_2_Wi_Im[N_SF_mprime_PUCCH_1][w_index][m],r_u_v_alpha_delta_dmrs_re[n],
-                     z_dmrs_re[(mprime*12*N_SF_mprime0_PUCCH_1)+(m*12)+n],z_dmrs_im[(mprime*12*N_SF_mprime0_PUCCH_1)+(m*12)+n]);
+                     z_dmrs_re_rx[(mprime*12*N_SF_mprime0_PUCCH_1)+(m*12)+n],z_dmrs_im_rx[(mprime*12*N_SF_mprime0_PUCCH_1)+(m*12)+n]);
 #endif
               //finding channel coeffcients by dividing received dmrs with actual dmrs and storing them in z_dmrs_re_rx and z_dmrs_im_rx arrays
               z_dmrs_re_temp = (int16_t)(((((int32_t)(r_u_v_alpha_delta_dmrs_re[n])*z_dmrs_re_rx[(mprime*12*N_SF_mprime0_PUCCH_DMRS_1)+(m*12)+n])>>15)
@@ -494,7 +704,7 @@ void nr_decode_pucch1(  int32_t **rxdataF,
                        mprime, m, n, (mprime*12*N_SF_mprime0_PUCCH_1)+(m*12)+n,
                        table_6_3_2_4_1_2_Wi_Re[N_SF_mprime_PUCCH_1][w_index][m],y_n_re[n],table_6_3_2_4_1_2_Wi_Im[N_SF_mprime_PUCCH_1][w_index][m],y_n_im[n],
                        table_6_3_2_4_1_2_Wi_Re[N_SF_mprime_PUCCH_1][w_index][m],y_n_im[n],table_6_3_2_4_1_2_Wi_Im[N_SF_mprime_PUCCH_1][w_index][m],y_n_re[n],
-                       z_re[(mprime*12*N_SF_mprime0_PUCCH_1)+(m*12)+n],z_im[(mprime*12*N_SF_mprime0_PUCCH_1)+(m*12)+n]);
+                       z_re_rx[(mprime*12*N_SF_mprime0_PUCCH_1)+(m*12)+n],z_im_rx[(mprime*12*N_SF_mprime0_PUCCH_1)+(m*12)+n]);
 #endif 
                 z_re_temp = (int16_t)(((((int32_t)(r_u_v_alpha_delta_re[n])*z_re_rx[(mprime*12*N_SF_mprime0_PUCCH_1)+(m*12)+n])>>15)
                             + (((int32_t)(r_u_v_alpha_delta_im[n])*z_im_rx[(mprime*12*N_SF_mprime0_PUCCH_1)+(m*12)+n])>>15))>>1); 
@@ -522,7 +732,7 @@ void nr_decode_pucch1(  int32_t **rxdataF,
                        mprime, m, n, (mprime*12*N_SF_mprime0_PUCCH_1)+(m*12)+n,
                        table_6_3_2_4_1_2_Wi_Re[N_SF_mprime_PUCCH_1][w_index][m],r_u_v_alpha_delta_dmrs_re[n],table_6_3_2_4_1_2_Wi_Im[N_SF_mprime_PUCCH_1][w_index][m],r_u_v_alpha_delta_dmrs_im[n],
                        table_6_3_2_4_1_2_Wi_Re[N_SF_mprime_PUCCH_1][w_index][m],r_u_v_alpha_delta_dmrs_im[n],table_6_3_2_4_1_2_Wi_Im[N_SF_mprime_PUCCH_1][w_index][m],r_u_v_alpha_delta_dmrs_re[n],
-                       z_dmrs_re[(mprime*12*N_SF_mprime0_PUCCH_1)+(m*12)+n],z_dmrs_im[(mprime*12*N_SF_mprime0_PUCCH_1)+(m*12)+n]);
+                       z_dmrs_re_rx[(mprime*12*N_SF_mprime0_PUCCH_1)+(m*12)+n],z_dmrs_im_rx[(mprime*12*N_SF_mprime0_PUCCH_1)+(m*12)+n]);
 #endif
                 //finding channel coeffcients by dividing received dmrs with actual dmrs and storing them in z_dmrs_re_rx and z_dmrs_im_rx arrays
                 z_dmrs_re_temp = (int16_t)(((((int32_t)(r_u_v_alpha_delta_dmrs_re[n])*z_dmrs_re_rx[(mprime*12*N_SF_mprime0_PUCCH_DMRS_1)+(m*12)+n])>>15)
@@ -641,3 +851,496 @@ void nr_decode_pucch1(  int32_t **rxdataF,
   }
 }
 
+__m256i pucch2_3bit[8*2];
+__m256i pucch2_4bit[16*2];
+__m256i pucch2_5bit[32*2];
+__m256i pucch2_6bit[64*2];
+__m256i pucch2_7bit[128*2];
+__m256i pucch2_8bit[256*2];
+__m256i pucch2_9bit[512*2];
+__m256i pucch2_10bit[1024*2];
+__m256i pucch2_11bit[2048*2];
+
+__m256i *pucch2_lut[9]={pucch2_3bit,
+			pucch2_4bit,
+			pucch2_5bit,
+			pucch2_6bit,
+			pucch2_7bit,
+			pucch2_8bit,
+			pucch2_9bit,
+			pucch2_10bit,
+			pucch2_11bit};
+
+void init_pucch2_luts() {
+
+  uint32_t out;
+  int8_t bit; 
+  
+  for (int b=3;b<12;b++) {
+    for (uint16_t i=0;i<(1<<b);i++) {
+      out=encodeSmallBlock(&i,b);
+      if (b==3) printf("in %d, out %x\n",i,out);
+      __m256i *lut_i=&pucch2_lut[b-3][i<<1];
+      __m256i *lut_ip1=&pucch2_lut[b-3][1+(i<<1)];
+      bit = (out&0x1) > 0 ? -1 : 1;
+      *lut_i = _mm256_insert_epi16(*lut_i,bit,0);
+      bit = (out&0x2) > 0 ? -1 : 1;
+      *lut_ip1 = _mm256_insert_epi16(*lut_ip1,bit,0);
+      bit = (out&0x4) > 0 ? -1 : 1;
+      *lut_i = _mm256_insert_epi16(*lut_i,bit,1);
+      bit = (out&0x8) > 0 ? -1 : 1;
+      *lut_ip1 = _mm256_insert_epi16(*lut_ip1,bit,1);
+      bit = (out&0x10) > 0 ? -1 : 1;
+      *lut_i = _mm256_insert_epi16(*lut_i,bit,2);
+      bit = (out&0x20) > 0 ? -1 : 1;
+      *lut_ip1 = _mm256_insert_epi16(*lut_ip1,bit,2);
+      bit = (out&0x40) > 0 ? -1 : 1;
+      *lut_i = _mm256_insert_epi16(*lut_i,bit,3);
+      bit = (out&0x80) > 0 ? -1 : 1;
+      *lut_ip1 = _mm256_insert_epi16(*lut_ip1,bit,3);
+      bit = (out&0x100) > 0 ? -1 : 1;
+      *lut_i = _mm256_insert_epi16(*lut_i,bit,4);
+      bit = (out&0x200) > 0 ? -1 : 1;
+      *lut_ip1 = _mm256_insert_epi16(*lut_ip1,bit,4);
+      bit = (out&0x400) > 0 ? -1 : 1;
+      *lut_i = _mm256_insert_epi16(*lut_i,bit,5);
+      bit = (out&0x800) > 0 ? -1 : 1;
+      *lut_ip1 = _mm256_insert_epi16(*lut_ip1,bit,5);
+      bit = (out&0x1000) > 0 ? -1 : 1;
+      *lut_i = _mm256_insert_epi16(*lut_i,bit,6);
+      bit = (out&0x2000) > 0 ? -1 : 1;
+      *lut_ip1 = _mm256_insert_epi16(*lut_ip1,bit,6);
+      bit = (out&0x4000) > 0 ? -1 : 1;
+      *lut_i = _mm256_insert_epi16(*lut_i,bit,7);
+      bit = (out&0x8000) > 0 ? -1 : 1;
+      *lut_ip1 = _mm256_insert_epi16(*lut_ip1,bit,7);
+      bit = (out&0x10000) > 0 ? -1 : 1;
+      *lut_i = _mm256_insert_epi16(*lut_i,bit,8);
+      bit = (out&0x20000) > 0 ? -1 : 1;
+      *lut_ip1 = _mm256_insert_epi16(*lut_ip1,bit,8);
+      bit = (out&0x40000) > 0 ? -1 : 1;
+      *lut_i = _mm256_insert_epi16(*lut_i,bit,9);
+      bit = (out&0x80000) > 0 ? -1 : 1;
+      *lut_ip1 = _mm256_insert_epi16(*lut_ip1,bit,9);
+      bit = (out&0x100000) > 0 ? -1 : 1;
+      *lut_i = _mm256_insert_epi16(*lut_i,bit,10);
+      bit = (out&0x200000) > 0 ? -1 : 1;
+      *lut_ip1 = _mm256_insert_epi16(*lut_ip1,bit,10);
+      bit = (out&0x400000) > 0 ? -1 : 1;
+      *lut_i = _mm256_insert_epi16(*lut_i,bit,11);
+      bit = (out&0x800000) > 0 ? -1 : 1;
+      *lut_ip1 = _mm256_insert_epi16(*lut_ip1,bit,11);
+      bit = (out&0x1000000) > 0 ? -1 : 1;
+      *lut_i = _mm256_insert_epi16(*lut_i,bit,12);
+      bit = (out&0x2000000) > 0 ? -1 : 1;
+      *lut_ip1 = _mm256_insert_epi16(*lut_ip1,bit,12);
+      bit = (out&0x4000000) > 0 ? -1 : 1;
+      *lut_i = _mm256_insert_epi16(*lut_i,bit,13);
+      bit = (out&0x8000000) > 0 ? -1 : 1;
+      *lut_ip1 = _mm256_insert_epi16(*lut_ip1,bit,13);
+      bit = (out&0x10000000) > 0 ? -1 : 1;
+      *lut_i = _mm256_insert_epi16(*lut_i,bit,14);
+      bit = (out&0x20000000) > 0 ? -1 : 1;
+      *lut_ip1 = _mm256_insert_epi16(*lut_ip1,bit,14);
+      bit = (out&0x40000000) > 0 ? -1 : 1;
+      *lut_i = _mm256_insert_epi16(*lut_i,bit,15);
+      bit = (out&0x80000000) > 0 ? -1 : 1;
+      *lut_ip1 = _mm256_insert_epi16(*lut_ip1,bit,15);
+    }
+  }
+}
+
+
+void nr_decode_pucch2(PHY_VARS_gNB *gNB,
+                      int slot,
+                      nfapi_nr_uci_pucch_pdu_format_2_3_4_t* uci_pdu,
+                      nfapi_nr_pucch_pdu_t* pucch_pdu) {
+
+  int32_t **rxdataF = gNB->common_vars.rxdataF;
+  NR_DL_FRAME_PARMS *frame_parms = &gNB->frame_parms;
+  pucch_GroupHopping_t pucch_GroupHopping = pucch_pdu->group_hop_flag + (pucch_pdu->sequence_hop_flag<<1);
+
+  AssertFatal(pucch_pdu->nr_of_symbols==1 || pucch_pdu->nr_of_symbols==2,
+	      "Illegal number of symbols  for PUCCH 2 %d\n",pucch_pdu->nr_of_symbols);
+
+
+  //extract pucch and dmrs first
+
+  int l2;
+  int re_offset = (12*pucch_pdu->prb_start) + (12*pucch_pdu->bwp_start) + frame_parms->first_carrier_offset;
+  if (re_offset>= frame_parms->ofdm_symbol_size) 
+    re_offset-=frame_parms->ofdm_symbol_size;
+  
+  AssertFatal(pucch_pdu->prb_size*pucch_pdu->nr_of_symbols > 1,"number of PRB*SYMB (%d,%d)< 2",
+	      pucch_pdu->prb_size,pucch_pdu->nr_of_symbols);
+
+  int Prx = gNB->gNB_config.carrier_config.num_rx_ant.value;
+  int Prx2 = (Prx==1)?2:Prx;
+  // use 2 for Nb antennas in case of single antenna to allow the following allocations
+  int16_t r_re_ext[Prx2][8*pucch_pdu->nr_of_symbols*pucch_pdu->prb_size] __attribute__((aligned(32)));
+  int16_t r_im_ext[Prx2][8*pucch_pdu->nr_of_symbols*pucch_pdu->prb_size] __attribute__((aligned(32)));
+  int16_t r_re_ext2[Prx2][8*pucch_pdu->nr_of_symbols*pucch_pdu->prb_size] __attribute__((aligned(32)));
+  int16_t r_im_ext2[Prx2][8*pucch_pdu->nr_of_symbols*pucch_pdu->prb_size] __attribute__((aligned(32)));
+  int16_t rd_re_ext[Prx2][4*pucch_pdu->nr_of_symbols*pucch_pdu->prb_size] __attribute__((aligned(32)));
+  int16_t rd_im_ext[Prx2][4*pucch_pdu->nr_of_symbols*pucch_pdu->prb_size] __attribute__((aligned(32)));
+
+  int16_t *rp[Prx2];
+  __m64 dmrs_re,dmrs_im;
+
+  for (int aa=0;aa<Prx;aa++) rp[aa] = ((int16_t *)&rxdataF[aa][(l2*frame_parms->ofdm_symbol_size)+re_offset]);
+
+#ifdef DEBUG_NR_PUCCH_RX
+  printf("Decoding pucch2 for %d symbols, %d PRB\n",pucch_pdu->nr_of_symbols,pucch_pdu->prb_size);
+#endif
+
+  int nc_group_size=1; // 2 PRB
+  int ngroup = pucch_pdu->prb_size/nc_group_size/2;
+  int32_t corr32_re[ngroup][Prx2],corr32_im[ngroup][Prx2];
+  for (int aa=0;aa<Prx;aa++) for (int group=0;group<ngroup;group++) { corr32_re[group][aa]=0; corr32_im[group][aa]=0;}
+
+  if (pucch_pdu->nr_of_symbols == 1) {
+     AssertFatal((pucch_pdu->prb_size&1) == 0,"prb_size %d is not a multiple of 2\n",pucch_pdu->prb_size);
+     // 24 PRBs contains 48x16-bit, so 6x8x16-bit 
+     for (int prb=0;prb<pucch_pdu->prb_size;prb+=2) {
+        for (int aa=0;aa<Prx;aa++) {
+
+	  r_re_ext[aa][0]=rp[aa][0];
+	  r_im_ext[aa][0]=rp[aa][1];
+	  rd_re_ext[aa][0]=rp[aa][2];
+	  rd_im_ext[aa][0]=rp[aa][3];
+	  r_re_ext[aa][1]=rp[aa][4];
+	  r_im_ext[aa][1]=rp[aa][5];
+
+	  r_re_ext[aa][2]=rp[aa][6];
+	  r_im_ext[aa][2]=rp[aa][7];
+	  rd_re_ext[aa][1]=rp[aa][8];
+	  rd_im_ext[aa][1]=rp[aa][9];
+	  r_re_ext[aa][3]=rp[aa][10];
+	  r_im_ext[aa][3]=rp[aa][11];
+
+	  r_re_ext[aa][4]=rp[aa][12];
+	  r_im_ext[aa][4]=rp[aa][13];
+	  rd_re_ext[aa][2]=rp[aa][14];
+	  rd_im_ext[aa][2]=rp[aa][15];
+	  r_re_ext[aa][5]=rp[aa][16];
+	  r_im_ext[aa][5]=rp[aa][17];
+
+	  r_re_ext[aa][6]=rp[aa][18];
+	  r_im_ext[aa][6]=rp[aa][19];
+	  rd_re_ext[aa][3]=rp[aa][20];
+	  rd_im_ext[aa][3]=rp[aa][21];
+	  r_re_ext[aa][7]=rp[aa][22];
+	  r_im_ext[aa][7]=rp[aa][23];
+
+	  r_re_ext[aa][8]=rp[aa][24];
+	  r_im_ext[aa][8]=rp[aa][25];
+	  rd_re_ext[aa][4]=rp[aa][26];
+	  rd_im_ext[aa][4]=rp[aa][27];
+	  r_re_ext[aa][9]=rp[aa][28];
+	  r_im_ext[aa][9]=rp[aa][29];
+
+	  r_re_ext[aa][10]=rp[aa][30];
+	  r_im_ext[aa][10]=rp[aa][31];
+	  rd_re_ext[aa][5]=rp[aa][32];
+	  rd_im_ext[aa][5]=rp[aa][33];
+	  r_re_ext[aa][11]=rp[aa][34];
+	  r_im_ext[aa][11]=rp[aa][35];
+
+	  r_re_ext[aa][12]=rp[aa][36];
+	  r_im_ext[aa][12]=rp[aa][37];
+	  rd_re_ext[aa][6]=rp[aa][38];
+	  rd_im_ext[aa][6]=rp[aa][39];
+	  r_re_ext[aa][13]=rp[aa][40];
+	  r_im_ext[aa][13]=rp[aa][41];
+
+	  r_re_ext[aa][14]=rp[aa][42];
+	  r_im_ext[aa][14]=rp[aa][43];
+	  rd_re_ext[aa][7]=rp[aa][44];
+	  rd_im_ext[aa][7]=rp[aa][45];
+	  r_re_ext[aa][15]=rp[aa][46];
+	  r_im_ext[aa][15]=rp[aa][47];
+		  
+#ifdef DEBUG_NR_PUCCH_RX
+	  for (int i=0;i<8;i++) printf("Ant %d PRB %d dmrs[%d] -> (%d,%d)\n",aa,prb+(i>>2),i,rd_re_ext[aa][i],rd_im_ext[aa],i);
+#endif
+	} // aa
+     } // prb
+
+
+     // first compute DMRS component
+     uint32_t x1, x2, s=0;
+     x2 = (((1<<17)*((14*slot) + (pucch_pdu->start_symbol_index) + 1)*((2*pucch_pdu->dmrs_scrambling_id) + 1)) + (2*pucch_pdu->dmrs_scrambling_id))%(1U<<31); // c_init calculation according to TS38.211 subclause
+#ifdef DEBUG_NR_PUCCH_RX
+     printf("slot %d, start_symbol_index %d, dmrs_scrambling_id %d\n",
+       slot,pucch_pdu->start_symbol_index,pucch_pdu->dmrs_scrambling_id);
+#endif
+     s = lte_gold_generic(&x1, &x2, 1);
+
+
+     for (int group=0;group<ngroup;group++) {
+     // each group has 8*nc_group_size elements, compute 1 complex correlation with DMRS per group
+     // non-coherent combining across groups
+       dmrs_re = byte2m64_re[((uint8_t*)&s)[(group&1)<<1]];
+       dmrs_im = byte2m64_im[((uint8_t*)&s)[(group&1)<<1]];
+#ifdef DEBUG_NR_PUCCH_RX
+       printf("Group %d: s %x x2 %x ((%d,%d),(%d,%d),(%d,%d),(%d,%d))\n",
+	      group,
+	      ((uint16_t*)&s)[0],x2,
+	      ((int16_t*)&dmrs_re)[0],((int16_t*)&dmrs_im)[0],    
+	      ((int16_t*)&dmrs_re)[1],((int16_t*)&dmrs_im)[1],    
+	      ((int16_t*)&dmrs_re)[2],((int16_t*)&dmrs_im)[2],    
+	      ((int16_t*)&dmrs_re)[3],((int16_t*)&dmrs_im)[3]);   
+#endif
+       for (int aa=0;aa<Prx;aa++) {
+#ifdef DEBUG_NR_PUCCH_RX
+	 printf("Group %d: rd ((%d,%d),(%d,%d),(%d,%d),(%d,%d))\n",
+		group,
+		rd_re_ext[aa][0],rd_im_ext[aa][0],
+		rd_re_ext[aa][1],rd_im_ext[aa][1],
+		rd_re_ext[aa][2],rd_im_ext[aa][2],
+		rd_re_ext[aa][3],rd_im_ext[aa][3]);
+#endif
+	 corr32_re[group][aa]+=(rd_re_ext[aa][0]*((int16_t*)&dmrs_re)[0] + rd_im_ext[aa][0]*((int16_t*)&dmrs_im)[0]); 
+	 corr32_im[group][aa]+=(-rd_re_ext[aa][0]*((int16_t*)&dmrs_im)[0] + rd_im_ext[aa][0]*((int16_t*)&dmrs_re)[0]); 
+	 corr32_re[group][aa]+=(rd_re_ext[aa][1]*((int16_t*)&dmrs_re)[1] + rd_im_ext[aa][1]*((int16_t*)&dmrs_im)[1]); 
+	 corr32_im[group][aa]+=(-rd_re_ext[aa][1]*((int16_t*)&dmrs_im)[1] + rd_im_ext[aa][1]*((int16_t*)&dmrs_re)[1]); 
+	 corr32_re[group][aa]+=(rd_re_ext[aa][2]*((int16_t*)&dmrs_re)[2] + rd_im_ext[aa][2]*((int16_t*)&dmrs_im)[2]); 
+	 corr32_im[group][aa]+=(-rd_re_ext[aa][2]*((int16_t*)&dmrs_im)[2] + rd_im_ext[aa][2]*((int16_t*)&dmrs_re)[2]); 
+	 corr32_re[group][aa]+=(rd_re_ext[aa][3]*((int16_t*)&dmrs_re)[3] + rd_im_ext[aa][3]*((int16_t*)&dmrs_im)[3]); 
+	 corr32_im[group][aa]+=(-rd_re_ext[aa][3]*((int16_t*)&dmrs_im)[3] + rd_im_ext[aa][3]*((int16_t*)&dmrs_re)[3]); 
+       }
+       dmrs_re = byte2m64_re[((uint8_t*)&s)[1+((group&1)<<1)]];
+       dmrs_im = byte2m64_im[((uint8_t*)&s)[1+((group&1)<<1)]];
+#ifdef DEBUG_NR_PUCCH_RX
+       printf("Group %d: s %x ((%d,%d),(%d,%d),(%d,%d),(%d,%d))\n",
+	      group,
+	      ((uint16_t*)&s)[1],
+	      ((int16_t*)&dmrs_re)[0],((int16_t*)&dmrs_im)[0],    
+	      ((int16_t*)&dmrs_re)[1],((int16_t*)&dmrs_im)[1],    
+	      ((int16_t*)&dmrs_re)[2],((int16_t*)&dmrs_im)[2],    
+	      ((int16_t*)&dmrs_re)[3],((int16_t*)&dmrs_im)[3]);
+#endif
+       for (int aa=0;aa<Prx;aa++) {
+#ifdef DEBUG_NR_PUCCH_RX
+	 printf("Group %d: rd ((%d,%d),(%d,%d),(%d,%d),(%d,%d))\n",
+		group,
+		rd_re_ext[aa][4],rd_im_ext[aa][4],
+		rd_re_ext[aa][5],rd_im_ext[aa][5],
+		rd_re_ext[aa][6],rd_im_ext[aa][6],
+		rd_re_ext[aa][7],rd_im_ext[aa][7]);
+#endif
+	 corr32_re[group][aa]+=(rd_re_ext[aa][4]*((int16_t*)&dmrs_re)[0] + rd_im_ext[aa][4]*((int16_t*)&dmrs_im)[0]); 
+	 corr32_im[group][aa]+=(-rd_re_ext[aa][4]*((int16_t*)&dmrs_im)[0] + rd_im_ext[aa][4]*((int16_t*)&dmrs_re)[0]); 
+	 corr32_re[group][aa]+=(rd_re_ext[aa][5]*((int16_t*)&dmrs_re)[1] + rd_im_ext[aa][5]*((int16_t*)&dmrs_im)[1]); 
+	 corr32_im[group][aa]+=(-rd_re_ext[aa][5]*((int16_t*)&dmrs_im)[1] + rd_im_ext[aa][5]*((int16_t*)&dmrs_re)[1]); 
+	 corr32_re[group][aa]+=(rd_re_ext[aa][6]*((int16_t*)&dmrs_re)[2] + rd_im_ext[aa][6]*((int16_t*)&dmrs_im)[2]); 
+	 corr32_im[group][aa]+=(-rd_re_ext[aa][6]*((int16_t*)&dmrs_im)[2] + rd_im_ext[aa][6]*((int16_t*)&dmrs_re)[2]); 
+	 corr32_re[group][aa]+=(rd_re_ext[aa][7]*((int16_t*)&dmrs_re)[3] + rd_im_ext[aa][7]*((int16_t*)&dmrs_im)[3]); 
+	 corr32_im[group][aa]+=(-rd_re_ext[aa][7]*((int16_t*)&dmrs_im)[3] + rd_im_ext[aa][7]*((int16_t*)&dmrs_re)[3]); 
+	 corr32_re[group][aa]>>=5;
+	 corr32_im[group][aa]>>=5;
+#ifdef DEBUG_NR_PUCCH_RX
+	 printf("Group %d: corr32 (%d,%d)\n",group,corr32_re[group][aa],corr32_im[group][aa]);
+#endif
+       } //aa    
+       
+       if ((group&3) == 3) s = lte_gold_generic(&x1, &x2, 0);
+     } // group
+  }
+  else { // 2 symbol case
+     AssertFatal(1==0, "Fill in 2 symbol PUCCH2 case\n");
+  }
+
+  uint32_t x1, x2, s=0;  
+  // unscrambling
+  x2 = ((pucch_pdu->rnti)<<15)+pucch_pdu->data_scrambling_id;
+  s = lte_gold_generic(&x1, &x2, 1);
+#ifdef DEBUG_NR_PUCCH_RX
+  printf("x2 %x, s %x\n",x2,s);
+#endif
+  __m64 c_re0,c_im0,c_re1,c_im1,c_re2,c_im2,c_re3,c_im3;
+  re_offset=0;
+  for (int prb=0;prb<pucch_pdu->prb_size;prb+=2,re_offset+=16) {
+    c_re0 = byte2m64_re[((uint8_t*)&s)[0]];
+    c_im0 = byte2m64_im[((uint8_t*)&s)[0]];
+    c_re1 = byte2m64_re[((uint8_t*)&s)[1]];
+    c_im1 = byte2m64_im[((uint8_t*)&s)[1]];
+    c_re2 = byte2m64_re[((uint8_t*)&s)[2]];
+    c_im2 = byte2m64_im[((uint8_t*)&s)[2]];
+    c_re3 = byte2m64_re[((uint8_t*)&s)[3]];
+    c_im3 = byte2m64_im[((uint8_t*)&s)[3]];
+
+    for (int aa=0;aa<Prx;aa++) {
+#ifdef DEBUG_NR_PUCCH_RX
+      printf("prb %d: rd ((%d,%d),(%d,%d),(%d,%d),(%d,%d),(%d,%d),(%d,%d),(%d,%d),(%d,%d))\n",
+		prb,
+		r_re_ext[aa][re_offset],r_im_ext[aa][re_offset],
+		r_re_ext[aa][re_offset+1],r_im_ext[aa][re_offset+1],
+		r_re_ext[aa][re_offset+2],r_im_ext[aa][re_offset+2],
+		r_re_ext[aa][re_offset+3],r_im_ext[aa][re_offset+3],
+		r_re_ext[aa][re_offset+4],r_im_ext[aa][re_offset+4],
+		r_re_ext[aa][re_offset+5],r_im_ext[aa][re_offset+5],
+		r_re_ext[aa][re_offset+6],r_im_ext[aa][re_offset+6],
+		r_re_ext[aa][re_offset+7],r_im_ext[aa][re_offset+7]);
+      printf("prb %d: c ((%d,%d),(%d,%d),(%d,%d),(%d,%d),(%d,%d),(%d,%d),(%d,%d),(%d,%d))\n",
+		prb,
+		((int16_t*)&c_re0)[0],((int16_t*)&c_im0)[0],
+		((int16_t*)&c_re0)[1],((int16_t*)&c_im0)[1],
+		((int16_t*)&c_re0)[2],((int16_t*)&c_im0)[2],
+		((int16_t*)&c_re0)[3],((int16_t*)&c_im0)[3],
+		((int16_t*)&c_re1)[0],((int16_t*)&c_im1)[0],
+		((int16_t*)&c_re1)[1],((int16_t*)&c_im1)[1],
+		((int16_t*)&c_re1)[2],((int16_t*)&c_im1)[2],
+		((int16_t*)&c_re1)[3],((int16_t*)&c_im1)[3]
+		);
+      printf("prb %d: rd ((%d,%d),(%d,%d),(%d,%d),(%d,%d),(%d,%d),(%d,%d),(%d,%d),(%d,%d))\n",
+		prb+1,
+		r_re_ext[aa][re_offset+8],r_im_ext[aa][re_offset+8],
+		r_re_ext[aa][re_offset+9],r_im_ext[aa][re_offset+9],
+		r_re_ext[aa][re_offset+10],r_im_ext[aa][re_offset+10],
+		r_re_ext[aa][re_offset+11],r_im_ext[aa][re_offset+11],
+		r_re_ext[aa][re_offset+12],r_im_ext[aa][re_offset+12],
+		r_re_ext[aa][re_offset+13],r_im_ext[aa][re_offset+13],
+		r_re_ext[aa][re_offset+14],r_im_ext[aa][re_offset+14],
+		r_re_ext[aa][re_offset+15],r_im_ext[aa][re_offset+15]);
+      printf("prb %d: c ((%d,%d),(%d,%d),(%d,%d),(%d,%d),(%d,%d),(%d,%d),(%d,%d),(%d,%d))\n",
+		prb+1,
+		((int16_t*)&c_re2)[0],((int16_t*)&c_im2)[0],
+		((int16_t*)&c_re2)[1],((int16_t*)&c_im2)[1],
+		((int16_t*)&c_re2)[2],((int16_t*)&c_im2)[2],
+		((int16_t*)&c_re2)[3],((int16_t*)&c_im2)[3],
+		((int16_t*)&c_re3)[0],((int16_t*)&c_im3)[0],
+		((int16_t*)&c_re3)[1],((int16_t*)&c_im3)[1],
+		((int16_t*)&c_re3)[2],((int16_t*)&c_im3)[2],
+		((int16_t*)&c_re3)[3],((int16_t*)&c_im3)[3]
+		);
+#endif
+
+      ((__m64*)&r_re_ext2[aa][re_offset])[0] = _mm_mullo_pi16(((__m64*)&r_re_ext[aa][re_offset])[0],c_im0);
+      ((__m64*)&r_re_ext[aa][re_offset])[0] = _mm_mullo_pi16(((__m64*)&r_re_ext[aa][re_offset])[0],c_re0);
+      ((__m64*)&r_im_ext2[aa][re_offset])[0] = _mm_mullo_pi16(((__m64*)&r_im_ext[aa][re_offset])[0],c_re0);
+      ((__m64*)&r_im_ext[aa][re_offset])[0] = _mm_mullo_pi16(((__m64*)&r_im_ext[aa][re_offset])[0],c_im0);
+
+      ((__m64*)&r_re_ext2[aa][re_offset])[1] = _mm_mullo_pi16(((__m64*)&r_re_ext[aa][re_offset])[1],c_im1);
+      ((__m64*)&r_re_ext[aa][re_offset])[1] = _mm_mullo_pi16(((__m64*)&r_re_ext[aa][re_offset])[1],c_re1);
+      ((__m64*)&r_im_ext2[aa][re_offset])[1] = _mm_mullo_pi16(((__m64*)&r_im_ext[aa][re_offset])[1],c_re1);
+      ((__m64*)&r_im_ext[aa][re_offset])[1] = _mm_mullo_pi16(((__m64*)&r_im_ext[aa][re_offset])[1],c_im1);
+
+      ((__m64*)&r_re_ext2[aa][re_offset])[2] = _mm_mullo_pi16(((__m64*)&r_re_ext[aa][re_offset])[2],c_im2);
+      ((__m64*)&r_re_ext[aa][re_offset])[2] = _mm_mullo_pi16(((__m64*)&r_re_ext[aa][re_offset])[2],c_re2);
+      ((__m64*)&r_im_ext2[aa][re_offset])[2] = _mm_mullo_pi16(((__m64*)&r_im_ext[aa][re_offset])[2],c_re2);
+      ((__m64*)&r_im_ext[aa][re_offset])[2] = _mm_mullo_pi16(((__m64*)&r_im_ext[aa][re_offset])[2],c_im2);
+
+      ((__m64*)&r_re_ext2[aa][re_offset])[3] = _mm_mullo_pi16(((__m64*)&r_re_ext[aa][re_offset])[3],c_im3);
+      ((__m64*)&r_re_ext[aa][re_offset])[3] = _mm_mullo_pi16(((__m64*)&r_re_ext[aa][re_offset])[3],c_re3);
+      ((__m64*)&r_im_ext2[aa][re_offset])[3] = _mm_mullo_pi16(((__m64*)&r_im_ext[aa][re_offset])[3],c_re3);
+      ((__m64*)&r_im_ext[aa][re_offset])[3] = _mm_mullo_pi16(((__m64*)&r_im_ext[aa][re_offset])[3],c_im3);
+
+#ifdef DEBUG_NR_PUCCH_RX
+      printf("prb %d: r ((%d,%d),(%d,%d),(%d,%d),(%d,%d),(%d,%d),(%d,%d),(%d,%d),(%d,%d))\n",
+	     prb,
+	     r_re_ext[aa][re_offset],r_im_ext[aa][re_offset],
+	     r_re_ext[aa][re_offset+1],r_im_ext[aa][re_offset+1],
+	     r_re_ext[aa][re_offset+2],r_im_ext[aa][re_offset+2],
+	     r_re_ext[aa][re_offset+3],r_im_ext[aa][re_offset+3],
+	     r_re_ext[aa][re_offset+4],r_im_ext[aa][re_offset+4],
+	     r_re_ext[aa][re_offset+5],r_im_ext[aa][re_offset+5],
+	     r_re_ext[aa][re_offset+6],r_im_ext[aa][re_offset+6],
+	     r_re_ext[aa][re_offset+7],r_im_ext[aa][re_offset+7]);
+      printf("prb %d: r ((%d,%d),(%d,%d),(%d,%d),(%d,%d),(%d,%d),(%d,%d),(%d,%d),(%d,%d))\n",
+	     prb+1,
+	     r_re_ext[aa][re_offset+8],r_im_ext[aa][re_offset+8],
+	     r_re_ext[aa][re_offset+9],r_im_ext[aa][re_offset+9],
+	     r_re_ext[aa][re_offset+10],r_im_ext[aa][re_offset+10],
+	     r_re_ext[aa][re_offset+11],r_im_ext[aa][re_offset+11],
+	     r_re_ext[aa][re_offset+12],r_im_ext[aa][re_offset+12],
+	     r_re_ext[aa][re_offset+13],r_im_ext[aa][re_offset+13],
+	     r_re_ext[aa][re_offset+14],r_im_ext[aa][re_offset+14],
+	     r_re_ext[aa][re_offset+15],r_im_ext[aa][re_offset+15]);
+#endif      
+    }
+    s = lte_gold_generic(&x1, &x2, 0);
+  }
+  AssertFatal(pucch_pdu->bit_len_csi_part1 + pucch_pdu->bit_len_csi_part2 == 0,"no csi for now\n");
+  AssertFatal((pucch_pdu->bit_len_harq+pucch_pdu->sr_flag > 2 ) && (pucch_pdu->bit_len_harq+pucch_pdu->sr_flag < 12),"illegal length (%d,%d)\n",pucch_pdu->bit_len_harq,pucch_pdu->sr_flag);
+  int nb_bit = pucch_pdu->bit_len_harq+pucch_pdu->sr_flag;
+  __m256i *rp_re[Prx2];
+  __m256i *rp2_re[Prx2];
+  __m256i *rp_im[Prx2];
+  __m256i *rp2_im[Prx2];
+  for (int aa=0;aa<Prx;aa++) {
+    rp_re[aa] = (__m256i*)r_re_ext[aa];
+    rp_im[aa] = (__m256i*)r_im_ext[aa];
+    rp2_re[aa] = (__m256i*)r_re_ext2[aa];
+    rp2_im[aa] = (__m256i*)r_im_ext2[aa];
+  }
+  __m256i prod_re[Prx2],prod_im[Prx2];
+  int64_t corr=0;
+  int cw_ML=0;
+
+  for (int cw=0;cw<1<<nb_bit;cw++) {
+#ifdef DEBUG_NR_PUCCH_RX
+    printf("cw %d:",cw);
+    for (int i=0;i<32;i+=2) {
+      printf("%d,%d,",
+	     ((int16_t*)&pucch2_lut[nb_bit-3][cw<<1])[i>>1],
+	     ((int16_t*)&pucch2_lut[nb_bit-3][cw<<1])[1+(i>>1)]);
+    }
+    printf("\n");
+#endif
+    // do complex correlation
+    for (int aa=0;aa<Prx;aa++) {
+      prod_re[aa] = _mm256_srai_epi16(_mm256_adds_epi16(_mm256_mullo_epi16(pucch2_lut[nb_bit-3][cw<<1],rp_re[aa][0]),
+							_mm256_mullo_epi16(pucch2_lut[nb_bit-3][(cw<<1)+1],rp_im[aa][0])),5);
+      prod_im[aa] = _mm256_srai_epi16(_mm256_subs_epi16(_mm256_mullo_epi16(pucch2_lut[nb_bit-3][cw<<1],rp2_im[aa][0]),
+							_mm256_mullo_epi16(pucch2_lut[nb_bit-3][(cw<<1)+1],rp2_re[aa][0])),5);
+      prod_re[aa] = _mm256_hadds_epi16(prod_re[aa],prod_re[aa]);// 0+1
+      prod_im[aa] = _mm256_hadds_epi16(prod_im[aa],prod_im[aa]);
+      prod_re[aa] = _mm256_hadds_epi16(prod_re[aa],prod_re[aa]);// 0+1+2+3
+      prod_im[aa] = _mm256_hadds_epi16(prod_im[aa],prod_im[aa]);
+      prod_re[aa] = _mm256_hadds_epi16(prod_re[aa],prod_re[aa]);// 0+1+2+3+4+5+6+7
+      prod_im[aa] = _mm256_hadds_epi16(prod_im[aa],prod_im[aa]);
+      prod_re[aa] = _mm256_hadds_epi16(prod_re[aa],prod_re[aa]);// 0+1+2+3+4+5+6+7+8+9+10+11+12+13+14+15
+      prod_im[aa] = _mm256_hadds_epi16(prod_im[aa],prod_im[aa]);
+    }
+    int64_t corr_re=0,corr_im=0;
+
+    for (int aa=0;aa<Prx;aa++) {
+      LOG_D(PHY,"pucch2 cw %d aa %d: (%d,%d)+(%d,%d) = (%d,%d)\n",cw,aa,
+	    corr32_re[0][aa],corr32_im[0][aa],
+	    ((int16_t*)(&prod_re[aa]))[0],
+	    ((int16_t*)(&prod_im[aa]))[0],
+	    corr32_re[0][aa]+((int16_t*)(&prod_re[0]))[0],
+	    corr32_im[0][aa]+((int16_t*)(&prod_im[0]))[0]);
+	     
+      corr_re += ( corr32_re[0][aa]+((int16_t*)(&prod_re[0]))[0]);
+      corr_im += ( corr32_im[0][aa]+((int16_t*)(&prod_im[0]))[0]);
+
+    }
+    int64_t corr_tmp = corr_re*corr_re + corr_im*corr_im;
+    if (corr_tmp > corr) {
+      corr = corr_tmp;
+      cw_ML=cw;
+    }
+  }
+  uint8_t corr_dB = dB_fixed64((uint64_t)corr);
+  LOG_D(PHY,"cw_ML %d, metric %d dB\n",cw_ML,corr_dB);
+  uci_pdu->harq.harq_bit_len = pucch_pdu->bit_len_harq;
+
+  
+  int harq_bytes=pucch_pdu->bit_len_harq>>3;
+  if ((pucch_pdu->bit_len_harq&7) > 0) harq_bytes++;
+  uci_pdu->harq.harq_payload = (nfapi_nr_harq_t*)malloc(harq_bytes);
+  uci_pdu->harq.harq_crc = 2;
+  for (int i=0;i<harq_bytes;i++) {
+    uci_pdu->harq.harq_payload[i] = cw_ML & 255;
+    cw_ML>>=8;
+  }
+  
+  if (pucch_pdu->sr_flag == 1) {
+    uci_pdu->sr.sr_bit_len = 1;
+    uci_pdu->sr.sr_payload = malloc(1);
+    uci_pdu->sr.sr_payload[0] = cw_ML;
+  }
+}
+    
diff --git a/openair1/PHY/NR_UE_TRANSPORT/pucch_nr.c b/openair1/PHY/NR_UE_TRANSPORT/pucch_nr.c
index 351c4ea22a5126ef2e26dd447594210dd6f00d90..2a08d54c5ab141dbddc62719abbbe08b404c12ce 100644
--- a/openair1/PHY/NR_UE_TRANSPORT/pucch_nr.c
+++ b/openair1/PHY/NR_UE_TRANSPORT/pucch_nr.c
@@ -37,157 +37,19 @@
 //#include "LAYER2/MAC/extern.h"
 #include "PHY/NR_UE_TRANSPORT/pucch_nr.h"
 #include "PHY/NR_UE_TRANSPORT/nr_transport_proto_ue.h"
-
+#include "PHY/NR_TRANSPORT/nr_transport_common_proto.h"
 #include "common/utils/LOG/log.h"
 #include "common/utils/LOG/vcd_signal_dumper.h"
 
 #include "T.h"
+//#define NR_UNIT_TEST 1
 #ifdef NR_UNIT_TEST
   #define DEBUG_PUCCH_TX
   #define DEBUG_NR_PUCCH_TX
 #endif
-//#define ONE_OVER_SQRT2 23170 // 32767/sqrt(2) = 23170 (ONE_OVER_SQRT2)
-
-void nr_group_sequence_hopping (pucch_GroupHopping_t PUCCH_GroupHopping,
-  				uint32_t n_id,
-  				uint8_t n_hop,
-  				int nr_tti_tx,
-  				uint8_t *u,
-  				uint8_t *v) {
-  /*
-   * Implements TS 38.211 subclause 6.3.2.2.1 Group and sequence hopping
-   * The following variables are set by higher layers:
-   *    - PUCCH_GroupHopping:
-   *    - n_id: higher-layer parameter hoppingId
-   *    - n_hop: frequency hopping index
-   *             if intra-slot frequency hopping is disabled by the higher-layer parameter PUCCH-frequency-hopping
-   *                n_hop=0
-   *             if frequency hopping is enabled by the higher-layer parameter PUCCH-frequency-hopping
-   *                n_hop=0 for the first hop
-   *                n_hop=1 for the second hop
-   */
-  // depending on the value of the PUCCH_GroupHopping, we will obtain different values for u,v
-  //pucch_GroupHopping_t PUCCH_GroupHopping = ue->pucch_config_common_nr->pucch_GroupHopping; // from higher layers FIXME!!!
-  // n_id defined as per TS 38.211 subclause 6.3.2.2.1 (is given by the higher-layer parameter hoppingId)
-  // it is hoppingId from PUCCH-ConfigCommon:
-  // Cell-Specific scrambling ID for group hoppping and sequence hopping if enabled
-  // Corresponds to L1 parameter 'HoppingID' (see 38.211, section 6.3.2.2) BIT STRING (SIZE (10))
-  //uint16_t n_id = ue->pucch_config_common_nr->hoppingId; // from higher layers FIXME!!!
-#ifdef DEBUG_NR_PUCCH_TX
-  // initialization to be removed
-  PUCCH_GroupHopping=neither;
-  n_id=10;
-  printf("\t\t [nr_group_sequence_hopping] initialization PUCCH_GroupHopping=%u, n_id=%u -> variable initializations TO BE REMOVED\n",PUCCH_GroupHopping,n_id);
-#endif
-  uint8_t f_ss=0,f_gh=0;
-  *u=0;
-  *v=0;
-  uint32_t c_init = 0; 
-  uint32_t x1,s; // TS 38.211 Subclause 5.2.1
-  int l = 32, minShift = ((2*nr_tti_tx+n_hop)<<3);
-  int tmpShift =0;
-#ifdef DEBUG_NR_PUCCH_TX
-  printf("\t\t [nr_group_sequence_hopping] calculating u,v -> ");
-#endif
-
-  if (PUCCH_GroupHopping == neither) { // PUCCH_GroupHopping 'neither'
-    f_ss = n_id%30;
-  }
-
-  if (PUCCH_GroupHopping == enable) { // PUCCH_GroupHopping 'enabled'
-    c_init = floor(n_id/30); // we initialize c_init to calculate u,v according to 6.3.2.2.1 of 38.211
-    s = lte_gold_generic(&x1, &c_init, 1); // TS 38.211 Subclause 5.2.1
-    for (int m=0; m<8; m++) {
-      while(minShift >= l) {
-        s = lte_gold_generic(&x1, &c_init, 0);
-        l = l+32;
-      }
-
-      tmpShift = (minShift&((1<<5)-1)); //minShift%32;
-      f_gh = f_gh + ((1<<m)*((uint8_t)((s>>tmpShift)&1)));
-      minShift ++;
-    }
-
-    f_gh = f_gh%30;
-    f_ss = n_id%30;
-    /*    for (int m=0; m<8; m++){
-          f_gh = f_gh + ((1<<m)*((uint8_t)((s>>(8*(2*nr_tti_tx+n_hop)+m))&1))); // Not sure we have to use nr_tti_tx FIXME!!!
-        }
-        f_gh = f_gh%30;
-        f_ss = n_id%30;*/
-  }
-
-  if (PUCCH_GroupHopping == disable) { // PUCCH_GroupHopping 'disabled'
-    c_init = (1<<5)*floor(n_id/30)+(n_id%30); // we initialize c_init to calculate u,v
-    s = lte_gold_generic(&x1, &c_init, 1); // TS 38.211 Subclause 5.2.1
-    f_ss = n_id%30;
-    l = 32, minShift = (2*nr_tti_tx+n_hop);
-
-    while(minShift >= l) {
-      s = lte_gold_generic(&x1, &c_init, 0);
-      l = l+32;
-    }
-
-    tmpShift = (minShift&((1<<5)-1)); //minShift%32;
-    *v = (uint8_t)((s>>tmpShift)&1);
-    //    *v = (uint8_t)((s>>(2*nr_tti_tx+n_hop))&1); // Not sure we have to use nr_tti_tx FIXME!!!
-  }
-
-  *u = (f_gh+f_ss)%30;
-#ifdef DEBUG_NR_PUCCH_TX
-  printf("%d,%d\n",*u,*v);
-#endif
-}
-
-double nr_cyclic_shift_hopping(uint32_t n_id,
-                               uint8_t m0,
-                               uint8_t mcs,
-                               uint8_t lnormal,
-                               uint8_t lprime,
-                               int nr_tti_tx) {
-  /*
-   * Implements TS 38.211 subclause 6.3.2.2.2 Cyclic shift hopping
-   *     - n_id: higher-layer parameter hoppingId
-   *     - m0: provided by higher layer parameter PUCCH-F0-F1-initial-cyclic-shift of PUCCH-F0-resource-config
-   *     - mcs: mcs=0 except for PUCCH format 0 when it depends on information to be transmitted according to TS 38.213 subclause 9.2
-   *     - lnormal: lnormal is the OFDM symbol number in the PUCCH transmission where l=0 corresponds to the first OFDM symbol of the PUCCH transmission
-   *     - lprime: lprime is the index of the OFDM symbol in the slot that corresponds to the first OFDM symbol of the PUCCH transmission in the slot given by [5, TS 38.213]
-   */
-  // alpha_init initialized to 2*PI/12=0.5235987756
-  double alpha = 0.5235987756;
-  uint32_t c_init = n_id; // we initialize c_init again to calculate n_cs
-#ifdef DEBUG_NR_PUCCH_TX
-  // initialization to be remo.ved
-  c_init=10;
-  printf("\t\t [nr_cyclic_shift_hopping] initialization c_init=%u -> variable initialization TO BE REMOVED\n",c_init);
-#endif
-  uint32_t x1,s = lte_gold_generic(&x1, &c_init, 1); // TS 38.211 Subclause 5.2.1
-  uint8_t n_cs=0;
-  int l = 32, minShift = (14*8*nr_tti_tx )+ 8*(lnormal+lprime);
-  int tmpShift =0;
-#ifdef DEBUG_NR_PUCCH_TX
-  printf("\t\t [nr_cyclic_shift_hopping] calculating alpha (cyclic shift) using c_init=%u -> \n",c_init);
-#endif
-
-  for (int m=0; m<8; m++) {
-    while(minShift >= l) {
-      s = lte_gold_generic(&x1, &c_init, 0);
-      l = l+32;
-    }
 
-    tmpShift = (minShift&((1<<5)-1)); //minShift%32;
-    minShift ++;
-    n_cs = n_cs+((1<<m)*((uint8_t)((s>>tmpShift)&1)));
-    // calculating n_cs (Not sure we have to use nr_tti_tx FIXME!!!)
-    // n_cs = n_cs+((1<<m)*((uint8_t)((s>>((14*8*nr_tti_tx) + 8*(lnormal+lprime) + m))&1)));
-  }
+//#define ONE_OVER_SQRT2 23170 // 32767/sqrt(2) = 23170 (ONE_OVER_SQRT2)
 
-  alpha = (alpha * (double)((m0+mcs+n_cs)%12));
-#ifdef DEBUG_NR_PUCCH_TX
-  printf("n_cs=%d -> %lf\n",n_cs,alpha);
-#endif
-  return(alpha);
-}
 void nr_generate_pucch0(PHY_VARS_NR_UE *ue,
                         int32_t **txdataF,
                         NR_DL_FRAME_PARMS *frame_parms,
@@ -271,46 +133,31 @@ void nr_generate_pucch0(PHY_VARS_NR_UE *ue,
    */
   //int32_t *txptr;
   uint32_t re_offset=0;
+  uint8_t l2;
 
   for (int l=0; l<nrofSymbols; l++) {
-    if ((startingPRB <  (frame_parms->N_RB_DL>>1)) && ((frame_parms->N_RB_DL & 1) == 0)) { // if number RBs in bandwidth is even and current PRB is lower band
-      re_offset = ((l+startingSymbolIndex)*frame_parms->ofdm_symbol_size) + (12*startingPRB) + frame_parms->first_carrier_offset;
-    }
-
-    if ((startingPRB >= (frame_parms->N_RB_DL>>1)) && ((frame_parms->N_RB_DL & 1) == 0)) { // if number RBs in bandwidth is even and current PRB is upper band
-      re_offset = ((l+startingSymbolIndex)*frame_parms->ofdm_symbol_size) + (12*(startingPRB-(frame_parms->N_RB_DL>>1)));
-    }
-
-    if ((startingPRB <  (frame_parms->N_RB_DL>>1)) && ((frame_parms->N_RB_DL & 1) == 1)) { // if number RBs in bandwidth is odd  and current PRB is lower band
-      re_offset = ((l+startingSymbolIndex)*frame_parms->ofdm_symbol_size) + (12*startingPRB) + frame_parms->first_carrier_offset;
-    }
-
-    if ((startingPRB >  (frame_parms->N_RB_DL>>1)) && ((frame_parms->N_RB_DL & 1) == 1)) { // if number RBs in bandwidth is odd  and current PRB is upper band
-      re_offset = ((l+startingSymbolIndex)*frame_parms->ofdm_symbol_size) + (12*(startingPRB-(frame_parms->N_RB_DL>>1))) + 6;
-    }
-
-    if ((startingPRB == (frame_parms->N_RB_DL>>1)) && ((frame_parms->N_RB_DL & 1) == 1)) { // if number RBs in bandwidth is odd  and current PRB contains DC
-      re_offset = ((l+startingSymbolIndex)*frame_parms->ofdm_symbol_size) + (12*startingPRB) + frame_parms->first_carrier_offset;
-    }
+    l2=l+startingSymbolIndex;
+    re_offset = (12*startingPRB) + frame_parms->first_carrier_offset;
+    if (re_offset>= frame_parms->ofdm_symbol_size) 
+      re_offset-=frame_parms->ofdm_symbol_size;
 
     //txptr = &txdataF[0][re_offset];
     for (int n=0; n<12; n++) {
-      if ((n==6) && (startingPRB == (frame_parms->N_RB_DL>>1)) && ((frame_parms->N_RB_DL & 1) == 1)) {
-        // if number RBs in bandwidth is odd  and current PRB contains DC, we need to recalculate the offset when n=6 (for second half PRB)
-        re_offset = ((l+startingSymbolIndex)*frame_parms->ofdm_symbol_size);
-      }
 
-      ((int16_t *)&txdataF[0][re_offset])[0] = (int16_t)(((int32_t)(amp) * x_n_re[(12*l)+n])>>15);
-      ((int16_t *)&txdataF[0][re_offset])[1] = (int16_t)(((int32_t)(amp) * x_n_im[(12*l)+n])>>15);
+      ((int16_t *)&txdataF[0][(l2*frame_parms->ofdm_symbol_size) + re_offset])[0] = (int16_t)(((int32_t)(amp) * x_n_re[(12*l)+n])>>15);
+      ((int16_t *)&txdataF[0][(l2*frame_parms->ofdm_symbol_size) + re_offset])[1] = (int16_t)(((int32_t)(amp) * x_n_im[(12*l)+n])>>15);
       //((int16_t *)txptr[0][re_offset])[0] = (int16_t)((int32_t)amp * x_n_re[(12*l)+n])>>15;
       //((int16_t *)txptr[0][re_offset])[1] = (int16_t)((int32_t)amp * x_n_im[(12*l)+n])>>15;
       //txptr[re_offset] = (x_n_re[(12*l)+n]<<16) + x_n_im[(12*l)+n];
 #ifdef DEBUG_NR_PUCCH_TX
       printf("\t [nr_generate_pucch0] mapping to RE \t amp=%d \tofdm_symbol_size=%d \tN_RB_DL=%d \tfirst_carrier_offset=%d \ttxptr(%u)=(x_n(l=%d,n=%d)=(%d,%d))\n",
-             amp,frame_parms->ofdm_symbol_size,frame_parms->N_RB_DL,frame_parms->first_carrier_offset,re_offset,
-             l,n,((int16_t *)&txdataF[0][re_offset])[0],((int16_t *)&txdataF[0][re_offset])[1]);
+             amp,frame_parms->ofdm_symbol_size,frame_parms->N_RB_DL,frame_parms->first_carrier_offset,(l2*frame_parms->ofdm_symbol_size) + re_offset,
+             l2,n,((int16_t *)&txdataF[0][(l2*frame_parms->ofdm_symbol_size) + re_offset])[0],
+             ((int16_t *)&txdataF[0][(l2*frame_parms->ofdm_symbol_size) + re_offset])[1]);
 #endif
       re_offset++;
+      if (re_offset>= frame_parms->ofdm_symbol_size) 
+        re_offset-=frame_parms->ofdm_symbol_size;
     }
   }
 }
@@ -1059,7 +906,9 @@ void nr_uci_encoding(uint64_t payload,
   if (A<=11) {
     // procedure in subclause 6.3.1.2.2 (UCI encoded by channel coding of small block lengths -> subclause 6.3.1.3.2)
     // CRC bits are not attached, and coding small block lengths (subclause 5.3.3)
+    b[0] = encodeSmallBlock((uint16_t*)&payload,A);
   } else if (A>=12) {
+    AssertFatal(1==0,"Polar encoding not supported yet for UCI\n");
     // procedure in subclause 6.3.1.2.1 (UCI encoded by Polar code -> subclause 6.3.1.3.1)
     /*if ((A>=360 && E>=1088)||(A>=1013)) {
       I_seg = 1;
@@ -1078,10 +927,13 @@ void nr_uci_encoding(uint64_t payload,
     // code block segmentation and CRC attachment is performed according to subclause 5.2.1
     // polar coding subclause 5.3.1
   }
+  
 }
 //#if 0
 void nr_generate_pucch2(PHY_VARS_NR_UE *ue,
                         uint16_t crnti,
+			uint32_t dmrs_scrambling_id,
+			uint32_t data_scrambling_id,
                         int32_t **txdataF,
                         NR_DL_FRAME_PARMS *frame_parms,
                         PUCCH_CONFIG_DEDICATED *pucch_config_dedicated,
@@ -1115,14 +967,14 @@ void nr_generate_pucch2(PHY_VARS_NR_UE *ue,
    */
   uint8_t *btilde = malloc(sizeof(int8_t)*M_bit);
   // rnti is given by the C-RNTI
-  uint16_t rnti=crnti, n_id=0;
+  uint16_t rnti=crnti;
 #ifdef DEBUG_NR_PUCCH_TX
   printf("\t [nr_generate_pucch2] rnti = %d ,\n",rnti);
 #endif
   /*
    * Implementing TS 38.211 Subclause 6.3.2.5.1 scrambling format 2
    */
-  nr_pucch2_3_4_scrambling(M_bit,rnti,n_id,b,btilde);
+  nr_pucch2_3_4_scrambling(M_bit,rnti,data_scrambling_id,b,btilde);
   /*
    * Implementing TS 38.211 Subclause 6.3.2.5.2 modulation format 2
    * btilde shall be modulated as described in subclause 5.1 using QPSK
@@ -1170,10 +1022,10 @@ void nr_generate_pucch2(PHY_VARS_NR_UE *ue,
   int m=0;
 
   for (int l=0; l<nrofSymbols; l++) {
-    x2 = (((1<<17)*((14*nr_tti_tx) + (l+startingSymbolIndex) + 1)*((2*n_id) + 1)) + (2*n_id))%(1U<<31); // c_init calculation according to TS38.211 subclause
+    x2 = (((1<<17)*((14*nr_tti_tx) + (l+startingSymbolIndex) + 1)*((2*dmrs_scrambling_id) + 1)) + (2*dmrs_scrambling_id))%(1U<<31); // c_init calculation according to TS38.211 subclause
+
     s = lte_gold_generic(&x1, &x2, 1);
     m = 0;
-
     for (int rb=0; rb<nrofPRB; rb++) {
       //startingPRB = startingPRB + rb;
       if (((rb+startingPRB) <  (frame_parms->N_RB_DL>>1)) && ((frame_parms->N_RB_DL & 1) == 0)) { // if number RBs in bandwidth is even and current PRB is lower band
diff --git a/openair1/PHY/NR_UE_TRANSPORT/pucch_nr.h b/openair1/PHY/NR_UE_TRANSPORT/pucch_nr.h
index e8cd147526be502ba16ab3e0e88e9c490e1c43b9..510abb8373838d75bbcb0eb389c4eb2ef6f629f9 100644
--- a/openair1/PHY/NR_UE_TRANSPORT/pucch_nr.h
+++ b/openair1/PHY/NR_UE_TRANSPORT/pucch_nr.h
@@ -20,7 +20,7 @@
  */
 
 /*! \file PHY/NR_UE_TRANSPORT/pucch_nr.c
-* \brief Top-level routines for generating and decoding the PUCCH physical channel
+* \brief Top-level routines for generating the PUCCH physical channel
 * \author A. Mico Pereperez
 * \date 2018
 * \version 0.1
@@ -42,46 +42,7 @@
 #include "T.h"
 #define ONE_OVER_SQRT2 23170 // 32767/sqrt(2) = 23170 (ONE_OVER_SQRT2)
 
-void nr_decode_pucch1(  int32_t **rxdataF,
-                        pucch_GroupHopping_t pucch_GroupHopping,
-                        uint32_t n_id,       // hoppingID higher layer parameter
-                        uint64_t *payload,
-                        NR_DL_FRAME_PARMS *frame_parms,
-                        int16_t amp,
-                        int nr_tti_tx,
-                        uint8_t m0,
-                        uint8_t nrofSymbols,
-                        uint8_t startingSymbolIndex,
-                        uint16_t startingPRB,
-                        uint16_t startingPRB_intraSlotHopping,
-                        uint8_t timeDomainOCC,
-                        uint8_t nr_bit);
-
-void nr_decode_pucch0( int32_t **rxdataF,
-			pucch_GroupHopping_t PUCCH_GroupHopping,
-                        uint32_t n_id,                                       //PHY_VARS_gNB *gNB, generally rxdataf is in gNB->common_vars
-                        uint64_t *payload,
-                        NR_DL_FRAME_PARMS *frame_parms,
-                        int16_t amp,
-                        int nr_tti_tx,
-                        uint8_t m0,                                          // should come from resource set
-                        uint8_t nrofSymbols,				    // should come from resource set	
-                        uint8_t startingSymbolIndex,			    // should come from resource set
-                        uint16_t startingPRB,				   // should come from resource set
-			uint8_t nr_bit);
 
-void nr_group_sequence_hopping (pucch_GroupHopping_t PUCCH_GroupHopping,
-                                uint32_t n_id,
-                                uint8_t n_hop,
-                                int nr_tti_tx,
-                                uint8_t *u,
-                                uint8_t *v);
-double nr_cyclic_shift_hopping(uint32_t n_id,
-                               uint8_t m0,
-                               uint8_t mcs,
-                               uint8_t lnormal,
-                               uint8_t lprime,
-                               int nr_tti_tx);
 void nr_generate_pucch0(PHY_VARS_NR_UE *ue,
                         int32_t **txdataF,
                         NR_DL_FRAME_PARMS *frame_parms,
@@ -109,6 +70,8 @@ void nr_generate_pucch1(PHY_VARS_NR_UE *ue,
                         uint8_t nr_bit);
 void nr_generate_pucch2(PHY_VARS_NR_UE *ue,
                         uint16_t crnti,
+			uint32_t dmrs_scrambling_id,
+			uint32_t data_scrambling_id,
                         int32_t **txdataF,
                         NR_DL_FRAME_PARMS *frame_parms,
                         PUCCH_CONFIG_DEDICATED *pucch_config_dedicated,
@@ -139,8 +102,8 @@ void nr_generate_pucch3_4(PHY_VARS_NR_UE *ue,
                           uint8_t occ_index_format4);
 
 // tables for mcs values for different payloads 
- static const uint8_t table1_mcs[]={0,3,6,9};
- static const uint8_t table2_mcs[]={0,1,3,4,6,7,9,10};
+ static const uint8_t table1_mcs[]={0,6,3,9};
+ static const uint8_t table2_mcs[]={0,3,9,6,1,4,10,7};
 
   /*
    * The following tables implement TS 38.211 Subclause 5.2.2.2 Base sequences of length less than 36 (rows->u {0,1,..,29} / columns->n {0,1,...,M_ZC-1)
diff --git a/openair1/PHY/TOOLS/oai_dfts.c b/openair1/PHY/TOOLS/oai_dfts.c
index d0b39184bb63aed51bb91623bd4fcd233e91ecf5..bd516cd1e05c8aa973826feb34c760745996f7f4 100644
--- a/openair1/PHY/TOOLS/oai_dfts.c
+++ b/openair1/PHY/TOOLS/oai_dfts.c
@@ -2439,6 +2439,10 @@ static inline void idft16(int16_t *x,int16_t *y)
 #endif
 }
 
+void idft16f(int16_t *x,int16_t *y) {
+  idft16(x,y);
+}
+
 #if defined(__x86_64__) || defined(__i386__)
 #ifdef __AVX2__
 // Does two 16-point IDFTS (x[0 .. 15] is 128 LSBs of input vector, x[16..31] is in 128 MSBs) 
diff --git a/openair1/PHY/TOOLS/tools_defs.h b/openair1/PHY/TOOLS/tools_defs.h
index 86916cab21b4021cdb1e7e174b177992010d6053..61ea785db82f6256ba403a4aaa7d58e653e67069 100644
--- a/openair1/PHY/TOOLS/tools_defs.h
+++ b/openair1/PHY/TOOLS/tools_defs.h
@@ -187,7 +187,6 @@ This function performs optimized fixed-point radix-2 FFT/IFFT.
 
 
 
-
 #ifdef OAIDFTS_MAIN
 typedef  void(*adftfunc_t)(int16_t *sigF,int16_t *sig,unsigned char scale_flag);  
 typedef  void(*aidftfunc_t)(int16_t *sigF,int16_t *sig,unsigned char scale_flag);     
diff --git a/openair1/PHY/defs_gNB.h b/openair1/PHY/defs_gNB.h
index 7dbb2e796bb9b46eae2949d999e133890c62a3a1..aa794da818cae311b874b4a8651916eba3b85b55 100644
--- a/openair1/PHY/defs_gNB.h
+++ b/openair1/PHY/defs_gNB.h
@@ -44,6 +44,13 @@
 #include "PHY/CODING/nrLDPC_decoder/nrLDPC_types.h"
 
 #define MAX_NUM_RU_PER_gNB MAX_NUM_RU_PER_eNB
+#define MAX_PUCCH0_NID 8
+
+typedef struct {
+  int nb_id;
+  int Nid[MAX_PUCCH0_NID];
+  int lut[MAX_PUCCH0_NID][160][14];
+} NR_gNB_PUCCH0_LUT_t;
 
 typedef struct {
   uint32_t pbch_a;
@@ -561,13 +568,13 @@ typedef struct {
   //! estimated avg noise power (dB)
   short n0_power_tot_dBm;
   //! estimated avg noise power per RB per RX ant (lin)
-  unsigned short n0_subband_power[MAX_NUM_RU_PER_gNB][100];
+  unsigned short n0_subband_power[MAX_NUM_RU_PER_gNB][275];
   //! estimated avg noise power per RB per RX ant (dB)
-  unsigned short n0_subband_power_dB[MAX_NUM_RU_PER_gNB][100];
+  unsigned short n0_subband_power_dB[MAX_NUM_RU_PER_gNB][275];
   //! estimated avg noise power per RB (dB)
-  short n0_subband_power_tot_dB[100];
+  short n0_subband_power_tot_dB[275];
   //! estimated avg noise power per RB (dBm)
-  short n0_subband_power_tot_dBm[100];
+  short n0_subband_power_tot_dBm[275];
   // gNB measurements (per user)
   //! estimated received spatial signal power (linear)
   unsigned int   rx_spatial_power[NUMBER_OF_NR_DLSCH_MAX][2][2];
@@ -587,13 +594,13 @@ typedef struct {
   /// Wideband CQI (sum of all RX antennas, in dB)
   char           wideband_cqi_tot[NUMBER_OF_NR_DLSCH_MAX];
   /// Subband CQI per RX antenna and RB (= SINR)
-  int            subband_cqi[NUMBER_OF_NR_DLSCH_MAX][MAX_NUM_RU_PER_gNB][100];
+  int            subband_cqi[NUMBER_OF_NR_DLSCH_MAX][MAX_NUM_RU_PER_gNB][275];
   /// Total Subband CQI and RB (= SINR)
-  int            subband_cqi_tot[NUMBER_OF_NR_DLSCH_MAX][100];
+  int            subband_cqi_tot[NUMBER_OF_NR_DLSCH_MAX][275];
   /// Subband CQI in dB and RB (= SINR dB)
-  int            subband_cqi_dB[NUMBER_OF_NR_DLSCH_MAX][MAX_NUM_RU_PER_gNB][100];
+  int            subband_cqi_dB[NUMBER_OF_NR_DLSCH_MAX][MAX_NUM_RU_PER_gNB][275];
   /// Total Subband CQI and RB
-  int            subband_cqi_tot_dB[NUMBER_OF_NR_DLSCH_MAX][100];
+  int            subband_cqi_tot_dB[NUMBER_OF_NR_DLSCH_MAX][275];
   /// PRACH background noise level
   int            prach_I0;
 } PHY_MEASUREMENTS_gNB;
@@ -644,6 +651,7 @@ typedef struct PHY_VARS_gNB_s {
 
   //Sched_Rsp_t         Sched_INFO;
   nfapi_nr_ul_tti_request_t     UL_tti_req;
+  nfapi_nr_uci_indication_t uci_indication;
   
   nfapi_nr_dl_tti_pdcch_pdu    *pdcch_pdu;
   nfapi_nr_ul_dci_request_pdus_t  *ul_dci_pdu;
@@ -662,6 +670,8 @@ typedef struct PHY_VARS_gNB_s {
   uint8_t pbch_configured;
   char gNB_generate_rar;
 
+  // PUCCH0 Look-up table for cyclic-shifts
+  NR_gNB_PUCCH0_LUT_t pucch0_lut;
   /// NR synchronization sequences
   int16_t d_pss[NR_PSS_LENGTH];
   int16_t d_sss[NR_SSS_LENGTH];
@@ -713,6 +723,7 @@ typedef struct PHY_VARS_gNB_s {
   /// counter to average prach energh over first 100 prach opportunities
   int prach_energy_counter;
 
+  int pucch0_thres;
   /*
   time_stats_t phy_proc;
   */
diff --git a/openair1/SCHED_NR/phy_procedures_nr_gNB.c b/openair1/SCHED_NR/phy_procedures_nr_gNB.c
index be8ad0470f98c0d963aef49a7d9260bfe74156c0..60f9d4747af4908c355423d866e2ba8c23713c67 100644
--- a/openair1/SCHED_NR/phy_procedures_nr_gNB.c
+++ b/openair1/SCHED_NR/phy_procedures_nr_gNB.c
@@ -28,6 +28,7 @@
 #include "PHY/NR_TRANSPORT/nr_dlsch.h"
 #include "PHY/NR_TRANSPORT/nr_ulsch.h"
 #include "PHY/NR_ESTIMATION/nr_ul_estimation.h"
+#include "PHY/NR_UE_TRANSPORT/pucch_nr.h"
 #include "SCHED/sched_eNB.h"
 #include "sched_nr.h"
 #include "SCHED/sched_common_extern.h"
@@ -379,33 +380,67 @@ void phy_procedures_gNB_common_RX(PHY_VARS_gNB *gNB, int frame_rx, int slot_rx)
 
 void phy_procedures_gNB_uespec_RX(PHY_VARS_gNB *gNB, int frame_rx, int slot_rx) {
 
-  nfapi_nr_ul_tti_request_t     *UL_tti_req  = &gNB->UL_tti_req;
-  int num_pusch_pdu = UL_tti_req->n_pdus;
+  nfapi_nr_ul_tti_request_t *UL_tti_req  = &gNB->UL_tti_req;
+  int num_pdus = UL_tti_req->n_pdus;
 
-  LOG_D(PHY,"phy_procedures_gNB_uespec_RX frame %d, slot %d, num_pusch_pdu %d\n",frame_rx,slot_rx,num_pusch_pdu);
+  nfapi_nr_uci_indication_t *uci_indication = &gNB->uci_indication;
+  uci_indication->sfn = frame_rx;
+  uci_indication->slot = slot_rx;
+  uci_indication->num_ucis = 0;
+
+
+  LOG_D(PHY,"phy_procedures_gNB_uespec_RX frame %d, slot %d, num_pdus %d\n",frame_rx,slot_rx,num_pdus);
 
   gNB->UL_INFO.rx_ind.number_of_pdus = 0;
   gNB->UL_INFO.crc_ind.number_crcs = 0;
 
-  for (int i = 0; i < num_pusch_pdu; i++) {
+  for (int i = 0; i < num_pdus; i++) {
     switch (UL_tti_req->pdus_list[i].pdu_type) {
-    case NFAPI_NR_UL_CONFIG_PUSCH_PDU_TYPE:{
-      LOG_D(PHY,"frame %d, slot %d, Got NFAPI_NR_UL_CONFIG_PUSCH_PDU_TYPE\n",frame_rx,slot_rx);
-
-      nfapi_nr_pusch_pdu_t  *pusch_pdu = &UL_tti_req->pdus_list[0].pusch_pdu;
-      nr_fill_ulsch(gNB,frame_rx,slot_rx,pusch_pdu);
-      
-      uint8_t ULSCH_id =  find_nr_ulsch(pusch_pdu->rnti,gNB,SEARCH_EXIST);
-      uint8_t harq_pid = pusch_pdu->pusch_data.harq_process_id;
-      uint8_t symbol_start = pusch_pdu->start_symbol_index;
-      uint8_t symbol_end = symbol_start + pusch_pdu->nr_of_symbols;
-      
-      for(uint8_t symbol = symbol_start; symbol < symbol_end; symbol++) {
-        nr_rx_pusch(gNB, ULSCH_id, frame_rx, slot_rx, symbol, harq_pid);
+    case NFAPI_NR_UL_CONFIG_PUSCH_PDU_TYPE:
+      {
+	LOG_D(PHY,"frame %d, slot %d, Got NFAPI_NR_UL_CONFIG_PUSCH_PDU_TYPE\n",frame_rx,slot_rx);
+	
+	nfapi_nr_pusch_pdu_t  *pusch_pdu = &UL_tti_req->pdus_list[0].pusch_pdu;
+	nr_fill_ulsch(gNB,frame_rx,slot_rx,pusch_pdu);
+	
+	uint8_t ULSCH_id =  find_nr_ulsch(pusch_pdu->rnti,gNB,SEARCH_EXIST);
+	uint8_t harq_pid = pusch_pdu->pusch_data.harq_process_id;
+	uint8_t symbol_start = pusch_pdu->start_symbol_index;
+	uint8_t symbol_end = symbol_start + pusch_pdu->nr_of_symbols;
+	
+	for(uint8_t symbol = symbol_start; symbol < symbol_end; symbol++) {
+	  nr_rx_pusch(gNB, ULSCH_id, frame_rx, slot_rx, symbol, harq_pid);
+	}
+	//LOG_M("rxdataF_comp.m","rxF_comp",gNB->pusch_vars[0]->rxdataF_comp[0],6900,1,1);
+	//LOG_M("rxdataF_ext.m","rxF_ext",gNB->pusch_vars[0]->rxdataF_ext[0],6900,1,1);
+	nr_ulsch_procedures(gNB, frame_rx, slot_rx, ULSCH_id, harq_pid);
       }
-      //LOG_M("rxdataF_comp.m","rxF_comp",gNB->pusch_vars[0]->rxdataF_comp[0],6900,1,1);
-      //LOG_M("rxdataF_ext.m","rxF_ext",gNB->pusch_vars[0]->rxdataF_ext[0],6900,1,1);
-      nr_ulsch_procedures(gNB, frame_rx, slot_rx, ULSCH_id, harq_pid);
+      break;
+    case NFAPI_NR_UL_CONFIG_PUCCH_PDU_TYPE:
+      {
+	LOG_D(PHY,"frame %d, slot %d, Got NFAPI_NR_UL_CONFIG_PUCCH_PDU_TYPE\n",frame_rx,slot_rx);
+	
+	nfapi_nr_pucch_pdu_t  *pucch_pdu = &UL_tti_req->pdus_list[i].pucch_pdu;
+	switch (pucch_pdu->format_type) {
+	case 0:
+	  uci_indication->uci_list[uci_indication->num_ucis].pdu_type = NFAPI_NR_UCI_FORMAT_0_1_PDU_TYPE;
+	  uci_indication->uci_list[uci_indication->num_ucis].pdu_size = sizeof(nfapi_nr_uci_pucch_pdu_format_0_1_t);
+	  nfapi_nr_uci_pucch_pdu_format_0_1_t *uci_pdu_format0 = &uci_indication->uci_list[uci_indication->num_ucis].pucch_pdu_format_0_1;
+	  
+	  nr_decode_pucch0(gNB,
+			   slot_rx,
+			   uci_pdu_format0,
+			   pucch_pdu);
+	  
+	  uci_indication->num_ucis += 1;
+	  break;
+	case 1:
+	  break;
+	case 2:
+	  break;
+	default:
+	  AssertFatal(1==0,"Only PUCCH format 0,1 and 2 are currently supported\n");
+	}
       }
     }
   }
diff --git a/openair1/SCHED_NR_UE/pucch_uci_ue_nr.c b/openair1/SCHED_NR_UE/pucch_uci_ue_nr.c
index 326c617dfb5413cffabd52a6b957a2c9574f1aa7..1b62ff81bff321a17cac23e662fd54bbf5f92284 100644
--- a/openair1/SCHED_NR_UE/pucch_uci_ue_nr.c
+++ b/openair1/SCHED_NR_UE/pucch_uci_ue_nr.c
@@ -186,6 +186,8 @@ bool pucch_procedures_ue_nr(PHY_VARS_NR_UE *ue, uint8_t gNB_id, UE_nr_rxtx_proc_
   int       pucch_resource_id = MAX_NB_OF_PUCCH_RESOURCES;
   int       pucch_resource_indicator = MAX_PUCCH_RESOURCE_INDICATOR;
   int       n_HARQ_ACK;
+  uint16_t crnti=0x1234;
+  int dmrs_scrambling_id=0,data_scrambling_id=0;
 
   /* update current context */
 
@@ -591,7 +593,9 @@ bool pucch_procedures_ue_nr(PHY_VARS_NR_UE *ue, uint8_t gNB_id, UE_nr_rxtx_proc_
     case pucch_format2_nr:
     {
       nr_generate_pucch2(ue,
-                         0,//ue->pdcch_vars[ue->current_thread_id[proc->nr_tti_rx]][gNB_id]->crnti,
+                         crnti,
+			 dmrs_scrambling_id,
+			 data_scrambling_id,
                          ue->common_vars.txdataF,
                          &ue->frame_parms,
                          &ue->pucch_config_dedicated[gNB_id],
diff --git a/openair1/SIMULATION/NR_PHY/dlsim.c b/openair1/SIMULATION/NR_PHY/dlsim.c
index 7982937e6d52d025157cbdfd60b1d0162e034dcb..5c0573acbdc83f9bff6ed61e168602d421229a87 100644
--- a/openair1/SIMULATION/NR_PHY/dlsim.c
+++ b/openair1/SIMULATION/NR_PHY/dlsim.c
@@ -171,6 +171,7 @@ int main(int argc, char **argv)
   //int pbch_tx_ant;
   int N_RB_DL=106,mu=1;
   nfapi_nr_dl_tti_pdsch_pdu_rel15_t dlsch_config;
+  NR_sched_pucch pucch_sched;
 
   //unsigned char frame_type = 0;
 
@@ -707,7 +708,7 @@ int main(int argc, char **argv)
 
       memset(RC.nrmac[0]->cce_list[1][0],0,MAX_NUM_CCE*sizeof(int));
       clear_nr_nfapi_information(RC.nrmac[0], 0, frame, slot);
-      if (css_flag == 0) nr_schedule_uss_dlsch_phytest(0,frame,slot,&dlsch_config);
+      if (css_flag == 0) nr_schedule_uss_dlsch_phytest(0,frame,slot,&pucch_sched,&dlsch_config);
       else               nr_schedule_css_dlsch_phytest(0,frame,slot);
       
       
diff --git a/openair1/SIMULATION/NR_PHY/pucchsim.c b/openair1/SIMULATION/NR_PHY/pucchsim.c
index 445c45693ed7ce5c46a52cd7021f9101adc0a29c..d36f42f6c63084e9f5839672145a5b1397c168e7 100644
--- a/openair1/SIMULATION/NR_PHY/pucchsim.c
+++ b/openair1/SIMULATION/NR_PHY/pucchsim.c
@@ -66,7 +66,7 @@ int main(int argc, char **argv)
   double sigma2, sigma2_dB=10,SNR,snr0=-2.0,snr1=2.0;
   double cfo=0;
   uint8_t snr1set=0;
-  int **txdata;
+  int **txdataF,**rxdataF;
   double **s_re,**s_im,**r_re,**r_im;
   //int sync_pos, sync_pos_slot;
   //FILE *rx_frame_file;
@@ -87,22 +87,24 @@ int main(int argc, char **argv)
   uint8_t nacktoack_flag=0;
   int16_t amp=0x7FFF;
   int nr_tti_tx=0; 
-  uint64_t actual_payload=0,payload_received;//payload bits b7b6...b2b1b0 where b7..b3=0 b2b1=HARQ b0 is SR. payload maximum value is 7 for pucch format 0 
+  uint64_t actual_payload=0,payload_received;
   int nr_bit=1; // maximum value possible is 2
   uint8_t m0=0;// higher layer paramater initial cyclic shift
   uint8_t nrofSymbols=1; //number of OFDM symbols can be 1-2 for format 1
   uint8_t startingSymbolIndex=0; // resource allocated see 9.2.1, 38.213 for more info.should be actually present in the resource set provided
   uint16_t startingPRB=0,startingPRB_intraSlotHopping=0; //PRB number not sure see 9.2.1, 38.213 for more info. Should be actually present in the resource set provided
+  uint16_t nrofPRB=2;
   uint8_t timeDomainOCC=0;
   SCM_t channel_model=AWGN;//Rayleigh1_anticorr;
   
   int N_RB_DL=273,mu=1;
-  float target_error_rate=0.01;
+  float target_error_rate=0.001;
   int frame_length_complex_samples;
   //int frame_length_complex_samples_no_prefix;
   NR_DL_FRAME_PARMS *frame_parms;
   //unsigned char frame_type = 0;
   int loglvl=OAILOG_WARNING;
+  int sr_flag = 0;
 
   cpuf = get_cpu_freq_GHz();
 
@@ -112,9 +114,8 @@ int main(int argc, char **argv)
 
   randominit(0);
   logInit();
-  set_glog(loglvl);
 
-  while ((c = getopt (argc, argv, "f:hA:f:g:i:P:b:T:n:o:s:S:x:y:z:N:F:GR:IL")) != -1) {
+  while ((c = getopt (argc, argv, "f:hA:f:g:i:I:P:B:b:T:m:n:r:o:s:S:x:y:z:N:F:GR:IL:q:c")) != -1) {
     switch (c) {
     case 'f':
       //write_output_file=1;
@@ -257,12 +258,30 @@ int main(int argc, char **argv)
     case 'i':
       nrofSymbols=(uint8_t)atoi(optarg);
       break;
+    case 'I':
+      startingSymbolIndex=(uint8_t)atoi(optarg);
+      break;
+    case 'r':
+      startingPRB=atoi(optarg);
+      break;
+    case 'q':
+      nrofPRB=atoi(optarg);
+      break;
     case 'P':
       format=atoi(optarg);
       break;
+    case 'm':
+      m0=atoi(optarg);
+      break;
     case 'b':
       nr_bit=atoi(optarg);
       break;
+    case 'c':
+      sr_flag=1;
+      break;
+    case 'B':
+      actual_payload=atoi(optarg);
+      break;
     case 'T':
       nacktoack_flag=(uint8_t)atoi(optarg);
       target_error_rate=0.001;
@@ -292,23 +311,42 @@ int main(int argc, char **argv)
       printf("-f Output filename (.txt format) for Pe/SNR results\n");
       printf("-F Input filename (.txt format) for RX conformance testing\n");
       printf("-i Enter number of ofdm symbols for pucch\n");
+      printf("-I Starting symbol index for pucch\n");
+      printf("-r PUCCH starting PRB\n");
+      printf("-q PUCCH number of PRB\n");
       printf("-P Enter the format of PUCCH\n");
       printf("-b number of HARQ bits (1-2)\n");
+      printf("-B payload to be transmitted on PUCCH\n");
+      printf("-m initial cyclic shift m0\n");
       printf("-T to check nacktoack miss for format 1");
       exit (-1);
       break;
     }
   }
 
+  set_glog(loglvl);
+
   if (snr1set==0) snr1 = snr0+10;
 
   printf("Initializing gNodeB for mu %d, N_RB_DL %d\n",mu,N_RB_DL);
 
+  if((format!=0) && (format!=1) && (format!=2)){
+    printf("PUCCH format %d not supported\n",format);
+    exit(0); 
+  }
+
+  AssertFatal(((format < 2)&&(nr_bit<3)&&(actual_payload<4)) ||
+	      ((format == 2)&&(nr_bit>2)&&(nr_bit<12)),"illegal combination format %d, nr_bit %d\n",
+	      format,nr_bit);
+
+  actual_payload &= ((1<<nr_bit)-1);
+
+  printf("Transmitted payload is %ld\n",actual_payload);
 
   RC.gNB = (PHY_VARS_gNB**) malloc(sizeof(PHY_VARS_gNB *));
   RC.gNB[0] = malloc(sizeof(PHY_VARS_gNB));
   gNB = RC.gNB[0];
-
+  memset((void*)gNB,0,sizeof(*gNB));
   frame_parms = &gNB->frame_parms; //to be initialized I suppose (maybe not necessary for PBCH)
   frame_parms->nb_antennas_tx = n_tx;
   frame_parms->nb_antennas_rx = n_rx;
@@ -374,8 +412,10 @@ int main(int argc, char **argv)
   s_im = malloc(2*sizeof(double*));
   r_re = malloc(2*sizeof(double*));
   r_im = malloc(2*sizeof(double*));
-  txdata = malloc(2*sizeof(int*));
-
+  txdataF = malloc(2*sizeof(int*));
+  rxdataF = malloc(2*sizeof(int*));
+  gNB->common_vars.rxdataF=rxdataF;
+  memcpy((void*)&gNB->frame_parms,(void*)frame_parms,sizeof(frame_parms));
   for (i=0; i<2; i++) {
 
     s_re[i] = malloc(frame_length_complex_samples*sizeof(double));
@@ -388,16 +428,18 @@ int main(int argc, char **argv)
     r_im[i] = malloc(frame_length_complex_samples*sizeof(double));
     bzero(r_im[i],frame_length_complex_samples*sizeof(double));
 
-    printf("Allocating %d samples for txdata\n",frame_length_complex_samples);
-    txdata[i] = malloc(frame_length_complex_samples*sizeof(int));
-    bzero(r_re[i],frame_length_complex_samples*sizeof(int));
-  
+    printf("Allocating %d samples for txdataF/rxdataF\n",14*frame_parms->ofdm_symbol_size);
+    txdataF[i] = memalign(32,14*frame_parms->ofdm_symbol_size*sizeof(int));
+    bzero(txdataF[i],14*frame_parms->ofdm_symbol_size*sizeof(int));
+    rxdataF[i] = memalign(32,14*frame_parms->ofdm_symbol_size*sizeof(int));
+    bzero(rxdataF[i],14*frame_parms->ofdm_symbol_size*sizeof(int));
   }
 
 
   //configure UE
   UE = malloc(sizeof(PHY_VARS_NR_UE));
   memcpy(&UE->frame_parms,frame_parms,sizeof(NR_DL_FRAME_PARMS));
+  UE->pucch_config_common_nr->hoppingId = Nid_cell;
   //phy_init_nr_top(UE); //called from init_nr_ue_signal
                       
   UE->perfect_ce = 0;
@@ -413,83 +455,110 @@ int main(int argc, char **argv)
   uint8_t mcs=0;
   startingPRB_intraSlotHopping=N_RB_DL-1;
   pucch_GroupHopping_t PUCCH_GroupHopping=UE->pucch_config_common_nr->pucch_GroupHopping;
-  uint32_t n_id=UE->pucch_config_common_nr->hoppingId;
-  if((format!=0) && (format!=1)){
-    printf("format not supported\n");
-    exit(0); 
+  uint32_t hopping_id=UE->pucch_config_common_nr->hoppingId;
+  uint32_t dmrs_scrambling_id = 0, data_scrambling_id=0;
+  if(format==0){
+  // for now we are not considering SR just HARQ-ACK
+    if (nr_bit ==0) 
+      mcs=table1_mcs[0];
+    else if(nr_bit==1)
+      mcs=table1_mcs[actual_payload];
+    else if(nr_bit==2)
+      mcs=table2_mcs[actual_payload];
+    else AssertFatal(1==0,"Either nr_bit %d or sr_flag %d must be non-zero\n");
   }
-  if(nacktoack_flag==0){ 
-    if(format==0){
-      if(nr_bit==1){
-        actual_payload=2;
-        mcs=table1_mcs[actual_payload];
-      }
-      else if(nr_bit==2){
-        actual_payload=6;
-        mcs=table2_mcs[actual_payload];
-      }
-      else{
-        printf("Number of HARQ bits possible is 1-2\n");
-        exit(0);
-      }
-    }
-    else {
-      if(nr_bit==1)
-        actual_payload=1;
-      else if(nr_bit==2)
-        actual_payload=3;
-      else{
-        printf("number of bits carried by PUCCH format1 is 1-2\n");
-      }
-    }
-  }   
+
   for(SNR=snr0;SNR<=snr1;SNR=SNR+1){
     ack_nack_errors=0;
     n_errors = 0;
-    sigma2_dB = 20*log10((double)amp/32767)-SNR;
-    sigma2 = pow(10,sigma2_dB/10);
     for (trial=0; trial<n_trials; trial++) {
-      bzero(txdata[0],frame_length_complex_samples*sizeof(int));
+      bzero(txdataF[aa],frame_parms->ofdm_symbol_size*sizeof(int));
       if(format==0){
-        nr_generate_pucch0(UE,txdata,frame_parms,UE->pucch_config_dedicated,amp,nr_tti_tx,m0,mcs,nrofSymbols,startingSymbolIndex,startingPRB);
+        nr_generate_pucch0(UE,txdataF,frame_parms,UE->pucch_config_dedicated,amp,nr_tti_tx,m0,mcs,nrofSymbols,startingSymbolIndex,startingPRB);
       }
-      else{
-        nr_generate_pucch1(UE,txdata,frame_parms,UE->pucch_config_dedicated,actual_payload,amp,nr_tti_tx,m0,nrofSymbols,startingSymbolIndex,startingPRB,startingPRB_intraSlotHopping,0,nr_bit);	
+      else if (format == 1){
+        nr_generate_pucch1(UE,txdataF,frame_parms,UE->pucch_config_dedicated,actual_payload,amp,nr_tti_tx,m0,nrofSymbols,startingSymbolIndex,startingPRB,startingPRB_intraSlotHopping,0,nr_bit);	
       }
-      for(i=0; i<frame_length_complex_samples; i++) {
-        r_re[aa][i]=((double)(((int16_t *)txdata[0])[(i<<1)])/32767 + sqrt(sigma2/2)*gaussdouble(0.0,1.0));
-        r_im[aa][i]=((double)(((int16_t *)txdata[0])[(i<<1)+1])/32767+ sqrt(sigma2/2)*gaussdouble(0.0,1.0));
-        r_re[aa][i]=r_re[0][i]/(sqrt(sigma2/2)+1);
-        r_im[aa][i]=r_im[0][i]/(sqrt(sigma2/2)+1);
-        if(r_re[aa][i]<-1)
-          r_re[aa][i]=-1; 
-        else if(r_re[aa][i]>1)
-          r_re[aa][i]=1;
-        if(r_im[aa][i]<-1)
-          r_im[aa][i]=-1;
-        else if(r_im[aa][i]>1)
-          r_im[aa][i]=1;	
-        ((int16_t *)txdata[aa])[(i<<1)]  = (int16_t)round(r_re[aa][i]*32767);
-        ((int16_t *)txdata[aa])[(i<<1)+1] =(int16_t)round(r_im[aa][i]*32767);
+      else {
+	nr_generate_pucch2(UE,0x1234,dmrs_scrambling_id,data_scrambling_id,txdataF,frame_parms,UE->pucch_config_dedicated,actual_payload,amp,nr_tti_tx,nrofSymbols,startingSymbolIndex,nrofPRB,startingPRB,nr_bit);	
       }
+      
+      int txlev = signal_energy(&txdataF[aa][startingSymbolIndex*frame_parms->ofdm_symbol_size],
+				frame_parms->ofdm_symbol_size);
+      //      printf("txlev %d (%d dB), offset %d\n",txlev,dB_fixed(txlev),startingSymbolIndex*frame_parms->ofdm_symbol_size);
+	    
+      // note : this scaling
+      int nb_re = (format == 0 || format == 1)? 12 : 12*nrofPRB;
+      sigma2_dB = 10*log10((double)txlev*UE->frame_parms.ofdm_symbol_size/nb_re)-SNR;
+      sigma2 = pow(10,sigma2_dB/10);
+      
+      for(i=startingSymbolIndex*frame_parms->ofdm_symbol_size; i<(startingSymbolIndex+1)*frame_parms->ofdm_symbol_size; i++) {
+        ((int16_t*)rxdataF[aa])[i<<1] = (int16_t)(100.0*((double)(((int16_t *)txdataF[aa])[(i<<1)]) + sqrt(sigma2/2)*gaussdouble(0.0,1.0))/sqrt((double)txlev));
+        ((int16_t*)rxdataF[aa])[1+(i<<1)]=(int16_t)(100.0*((double)(((int16_t *)txdataF[aa])[(i<<1)+1])+ sqrt(sigma2/2)*gaussdouble(0.0,1.0))/sqrt((double)txlev));
+      }
+      int rxlev = signal_energy(&rxdataF[aa][startingSymbolIndex*frame_parms->ofdm_symbol_size],
+				frame_parms->ofdm_symbol_size);
+      //      printf("rxlev %d (%d dB), sigma2 %f dB, SNR %f, TX %f\n",rxlev,dB_fixed(rxlev),sigma2_dB,SNR,10*log10((double)txlev*UE->frame_parms.ofdm_symbol_size/12));
       if(format==0){
-        nr_decode_pucch0(txdata,PUCCH_GroupHopping,n_id,&(payload_received),frame_parms,amp,nr_tti_tx,m0,nrofSymbols,startingSymbolIndex,startingPRB,nr_bit);
+	nfapi_nr_uci_pucch_pdu_format_0_1_t uci_pdu;
+	nfapi_nr_pucch_pdu_t pucch_pdu;
+	pucch_pdu.subcarrier_spacing    = 1;
+	pucch_pdu.group_hop_flag        = PUCCH_GroupHopping&1;
+	pucch_pdu.sequence_hop_flag     = (PUCCH_GroupHopping>>1)&1;
+	pucch_pdu.bit_len_harq          = nr_bit;
+	pucch_pdu.sr_flag               = sr_flag;
+	pucch_pdu.nr_of_symbols         = nrofSymbols;
+	pucch_pdu.hopping_id            = hopping_id;
+	pucch_pdu.initial_cyclic_shift  = 0;
+	pucch_pdu.start_symbol_index    = startingSymbolIndex;
+	pucch_pdu.prb_start             = startingPRB;
+        nr_decode_pucch0(gNB,nr_tti_tx,&uci_pdu,&pucch_pdu);
         if(nr_bit==1)
-          ack_nack_errors+=(((actual_payload^payload_received)&2)>>1);
+          ack_nack_errors+=(actual_payload^uci_pdu.harq->harq_list[0].harq_value);
         else
-          ack_nack_errors+=(((actual_payload^payload_received)&2)>>1) + (((actual_payload^payload_received)&4)>>2);
+          ack_nack_errors+=(((actual_payload&1)^uci_pdu.harq->harq_list[0].harq_value)+((actual_payload>>1)^uci_pdu.harq->harq_list[1].harq_value));
+	free(uci_pdu.harq->harq_list);
       }
-      else{
-        nr_decode_pucch1(txdata,PUCCH_GroupHopping,n_id,&(payload_received),frame_parms,amp,nr_tti_tx,m0,nrofSymbols,startingSymbolIndex,startingPRB,startingPRB_intraSlotHopping,timeDomainOCC,nr_bit);
+      else if (format==1) {
+	
+        nr_decode_pucch1(rxdataF,PUCCH_GroupHopping,hopping_id,&(payload_received),frame_parms,amp,nr_tti_tx,m0,nrofSymbols,startingSymbolIndex,startingPRB,startingPRB_intraSlotHopping,timeDomainOCC,nr_bit);
         if(nr_bit==1)
           ack_nack_errors+=((actual_payload^payload_received)&1);
         else
           ack_nack_errors+=((actual_payload^payload_received)&1) + (((actual_payload^payload_received)&2)>>1);
       }
+      else if (format==2) {
+	nfapi_nr_uci_pucch_pdu_format_2_3_4_t uci_pdu;
+	nfapi_nr_pucch_pdu_t pucch_pdu;
+	pucch_pdu.rnti = 0x1234;
+	pucch_pdu.subcarrier_spacing    = 1;
+	pucch_pdu.group_hop_flag        = PUCCH_GroupHopping&1;
+	pucch_pdu.sequence_hop_flag     = (PUCCH_GroupHopping>>1)&1;
+	pucch_pdu.bit_len_harq          = nr_bit;
+	pucch_pdu.sr_flag               = 0;
+	pucch_pdu.nr_of_symbols         = nrofSymbols;
+	pucch_pdu.hopping_id            = hopping_id;
+	pucch_pdu.initial_cyclic_shift  = 0;
+	pucch_pdu.start_symbol_index    = startingSymbolIndex;
+	pucch_pdu.prb_size              = nrofPRB;
+	pucch_pdu.prb_start             = startingPRB;
+	pucch_pdu.dmrs_scrambling_id    = dmrs_scrambling_id;
+	pucch_pdu.data_scrambling_id    = data_scrambling_id;
+        nr_decode_pucch2(gNB,nr_tti_tx,&uci_pdu,&pucch_pdu);
+	int harq_bytes=pucch_pdu.bit_len_harq>>3;
+	if ((pucch_pdu.bit_len_harq&7) > 0) harq_bytes++;
+	for (int i=0;i<harq_bytes;i++)
+	  if (uci_pdu.harq.harq_payload[i] != ((int8_t*)&actual_payload)[i]) {
+	    ack_nack_errors++;
+	    break;
+	  }
+	free(uci_pdu.harq.harq_payload);
+
+      }
       n_errors=((actual_payload^payload_received)&1)+(((actual_payload^payload_received)&2)>>1)+(((actual_payload^payload_received)&4)>>2)+n_errors;
     }
-    printf("SNR=%f, n_trials=%d, n_bit_errors=%d\n",SNR,n_trials,n_errors);
-    if((float)ack_nack_errors/(float)(nr_bit*n_trials)<=target_error_rate){
+    printf("SNR=%f, n_trials=%d, n_bit_errors=%d\n",SNR,n_trials,ack_nack_errors);
+    if((float)ack_nack_errors/(float)(n_trials)<=target_error_rate){
       printf("PUCCH test OK\n");
       break;
     }
@@ -500,13 +569,15 @@ int main(int argc, char **argv)
     free(s_im[i]);
     free(r_re[i]);
     free(r_im[i]);
-    free(txdata[i]);
+    free(txdataF[i]);
+    free(rxdataF[i]);
   }
   free(s_re);
   free(s_im);
   free(r_re);
   free(r_im);
-  free(txdata);
+  free(txdataF);
+  free(rxdataF);
 
   if (output_fd) fclose(output_fd);
   if (input_fd)  fclose(input_fd);
diff --git a/openair2/GNB_APP/RRC_nr_paramsvalues.h b/openair2/GNB_APP/RRC_nr_paramsvalues.h
index 82873f22b4bcdbf8ab68b3ca73e023c12b91a832..4c5da80764c98b150d2c94e7c52af54756126df0 100644
--- a/openair2/GNB_APP/RRC_nr_paramsvalues.h
+++ b/openair2/GNB_APP/RRC_nr_paramsvalues.h
@@ -128,18 +128,18 @@
 #define GNB_CONFIG_STRING_RARESPONSEWINDOW                      "ra_ResponseWindow"
 #define GNB_CONFIG_STRING_SSBPERRACHOCCASIONANDCBPREAMBLESPERSSBPR   "ssb_perRACH_OccasionAndCB_PreamblesPerSSB_PR"
 #define GNB_CONFIG_STRING_SSBPERRACHOCCASIONANDCBPREAMBLESPERSSB     "ssb_perRACH_OccasionAndCB_PreamblesPerSSB"
-#define GNB_CONFIG_STRING_RACONTENTIONRESOLUTIONTIMER                    "ra_ContentionResolutionTimer"                     
-#define GNB_CONFIG_STRING_RSRPTHRESHOLDSSB                               "rsrp_ThresholdSSB"                                
-#define GNB_CONFIG_STRING_PRACHROOTSEQUENCEINDEXPR                     "prach_RootSequenceIndex_PR"                     
-#define GNB_CONFIG_STRING_PRACHROOTSEQUENCEINDEX                     "prach_RootSequenceIndex"                     
-#define GNB_CONFIG_STRING_MSG1SUBCARRIERSPACING                          "msg1_SubcarrierSpacing"                           
-#define GNB_CONFIG_STRING_RESTRICTEDSETCONFIG                            "restrictedSetConfig"                              
-#define GNB_CONFIG_STRING_PUSCHTIMEDOMAINALLOCATIONLIST                  "puschTimeDomainAllocationList"
-#define GNB_CONFIG_STRING_MSG3DELTAPREABMLE                              "msg3_DeltaPreamble"
-#define GNB_CONFIG_STRING_P0NOMINALWITHGRANT                             "p0_NominalWithGrant"
-#define GNB_CONFIG_STRING_PUCCHGROUPHOPPING                              "pucchGroupHopping"
-#define GNB_CONFIG_STRING_HOPPINGID                                      "hoppingId"
-#define GNB_CONFIG_STRING_P0NOMINAL                                      "p0_nominal"
+#define GNB_CONFIG_STRING_RACONTENTIONRESOLUTIONTIMER           "ra_ContentionResolutionTimer"                     
+#define GNB_CONFIG_STRING_RSRPTHRESHOLDSSB                      "rsrp_ThresholdSSB"                                
+#define GNB_CONFIG_STRING_PRACHROOTSEQUENCEINDEXPR              "prach_RootSequenceIndex_PR"                     
+#define GNB_CONFIG_STRING_PRACHROOTSEQUENCEINDEX                "prach_RootSequenceIndex"                     
+#define GNB_CONFIG_STRING_MSG1SUBCARRIERSPACING                 "msg1_SubcarrierSpacing"                           
+#define GNB_CONFIG_STRING_RESTRICTEDSETCONFIG                   "restrictedSetConfig"                              
+#define GNB_CONFIG_STRING_PUSCHTIMEDOMAINALLOCATIONLIST         "puschTimeDomainAllocationList"
+#define GNB_CONFIG_STRING_MSG3DELTAPREABMLE                     "msg3_DeltaPreamble"
+#define GNB_CONFIG_STRING_P0NOMINALWITHGRANT                    "p0_NominalWithGrant"
+#define GNB_CONFIG_STRING_PUCCHGROUPHOPPING                     "pucchGroupHopping"
+#define GNB_CONFIG_STRING_HOPPINGID                             "hoppingId"
+#define GNB_CONFIG_STRING_P0NOMINAL                             "p0_nominal"
 #define GNB_CONFIG_STRING_INITIALULBWPK2_0                      "initialULBWPk2_0"
 #define GNB_CONFIG_STRING_INITIALULBWPMAPPINGTYPE_0             "initialULBWPmappingType_0"
 #define GNB_CONFIG_STRING_INITIALULBWPSTARTSYMBOLANDLENGTH_0    "initialULBWPstartSymbolAndLength_0"
diff --git a/openair2/LAYER2/NR_MAC_gNB/config.c b/openair2/LAYER2/NR_MAC_gNB/config.c
index c911fbd56a6c6aa5d53048131067815e014b4d0b..b5fdea6760450ecaf8f2c89d0c0f0a3886e4e19b 100644
--- a/openair2/LAYER2/NR_MAC_gNB/config.c
+++ b/openair2/LAYER2/NR_MAC_gNB/config.c
@@ -51,7 +51,6 @@ extern RAN_CONTEXT_t RC;
 extern void mac_top_init_gNB(void);
 extern uint8_t nfapi_mode;
 
-
 void config_common(int Mod_idP, int pdsch_AntennaPorts, NR_ServingCellConfigCommon_t *scc) {
 
   nfapi_nr_config_request_scf_t *cfg = &RC.nrmac[Mod_idP]->config[0];
@@ -283,7 +282,6 @@ void config_common(int Mod_idP, int pdsch_AntennaPorts, NR_ServingCellConfigComm
   else LOG_I(PHY,"TDD has been properly configurated\n");
   }
 
-
 /*
   // PDCCH-ConfigCommon
   cfg->pdcch_config.controlResourceSetZero.value = scc->downlinkConfigCommon->initialDownlinkBWP->pdcch_ConfigCommon->choice.setup->controlResourceSetZero;
diff --git a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler.c b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler.c
index e5840d9cd194c8db84bb7799f3b5c375e2ffc719..7c3a9e758467f1c4a8eafdf9b81c6fb9a1799159 100644
--- a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler.c
+++ b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler.c
@@ -61,6 +61,8 @@
 
 uint16_t nr_pdcch_order_table[6] = { 31, 31, 511, 2047, 2047, 8191 };
 
+uint8_t nr_slots_per_frame[5] = {10, 20, 40, 80, 160};
+
 void clear_nr_nfapi_information(gNB_MAC_INST * gNB,
                                 int CC_idP,
                                 frame_t frameP,
@@ -299,6 +301,67 @@ void copy_nr_ulreq(module_id_t module_idP, frame_t frameP, sub_frame_t slotP)
 }
 */
 
+void nr_schedule_pucch(int Mod_idP,
+                       int UE_id,
+                       frame_t frameP,
+                       sub_frame_t slotP) {
+
+  uint16_t O_uci;
+  uint16_t O_ack;
+  uint8_t SR_flag = 0; // no SR in PUCCH implemented for now
+  NR_ServingCellConfigCommon_t *scc = RC.nrmac[Mod_idP]->common_channels->ServingCellConfigCommon;
+  NR_UE_list_t *UE_list = &RC.nrmac[Mod_idP]->UE_list;
+  AssertFatal(UE_list->active[UE_id] >=0,"Cannot find UE_id %d is not active\n",UE_id);
+
+  NR_CellGroupConfig_t *secondaryCellGroup = UE_list->secondaryCellGroup[UE_id];
+  int bwp_id=1;
+  NR_BWP_Uplink_t *ubwp=secondaryCellGroup->spCellConfig->spCellConfigDedicated->uplinkConfig->uplinkBWP_ToAddModList->list.array[bwp_id-1];
+  nfapi_nr_ul_tti_request_t *UL_tti_req = &RC.nrmac[Mod_idP]->UL_tti_req[0];
+
+  NR_sched_pucch *curr_pucch = UE_list->UE_sched_ctrl[UE_id].sched_pucch;
+  NR_sched_pucch *temp_pucch;
+  int release_pucch = 0;
+
+  if (curr_pucch != NULL) {
+    if ((frameP == curr_pucch->frame) && (slotP == curr_pucch->ul_slot)) {
+      UL_tti_req->SFN = frameP;
+      UL_tti_req->Slot = slotP;
+      UL_tti_req->pdus_list[UL_tti_req->n_pdus].pdu_type = NFAPI_NR_UL_CONFIG_PUCCH_PDU_TYPE;
+      UL_tti_req->pdus_list[UL_tti_req->n_pdus].pdu_size = sizeof(nfapi_nr_pucch_pdu_t);
+      nfapi_nr_pucch_pdu_t  *pucch_pdu = &UL_tti_req->pdus_list[UL_tti_req->n_pdus].pucch_pdu;
+      memset(pucch_pdu,0,sizeof(nfapi_nr_pucch_pdu_t));
+      UL_tti_req->n_pdus+=1;
+      O_ack = curr_pucch->dai_c;
+      O_uci = O_ack; // for now we are just sending acknacks in pucch
+
+      nr_configure_pucch(pucch_pdu,
+			 scc,
+			 ubwp,
+                         curr_pucch->resource_indicator,
+                         O_uci,
+                         O_ack,
+                         SR_flag);
+
+      release_pucch = 1;
+    }
+  }
+
+  if (release_pucch) {
+    temp_pucch = UE_list->UE_sched_ctrl[UE_id].sched_pucch;
+    UE_list->UE_sched_ctrl[UE_id].sched_pucch = UE_list->UE_sched_ctrl[UE_id].sched_pucch->next_sched_pucch;
+    free(temp_pucch);
+  }
+
+}
+
+bool is_xlsch_in_slot(uint64_t bitmap, sub_frame_t slot){
+
+  if((bitmap>>slot)&0x01)
+    return true;
+  else
+    return false;
+}
+
 void gNB_dlsch_ulsch_scheduler(module_id_t module_idP,
                                frame_t frame_rxP,
                                sub_frame_t slot_rxP,
@@ -314,6 +377,7 @@ void gNB_dlsch_ulsch_scheduler(module_id_t module_idP,
   NR_UE_list_t *UE_list = &gNB->UE_list;
   UE_sched_ctrl_t *ue_sched_ctl = &UE_list->UE_sched_ctrl[UE_id];
   NR_COMMON_channels_t *cc = gNB->common_channels;
+  NR_sched_pucch *pucch_sched = (NR_sched_pucch*) malloc(sizeof(NR_sched_pucch));
 
   start_meas(&RC.nrmac[module_idP]->eNB_scheduler);
   VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_ENB_DLSCH_ULSCH_SCHEDULER,VCD_FUNCTION_IN);
@@ -327,27 +391,27 @@ void gNB_dlsch_ulsch_scheduler(module_id_t module_idP,
   // Check if there are downlink symbols in the slot, 
   if (is_nr_DL_slot(cc->ServingCellConfigCommon,slot_txP)) {
 
-  memset(RC.nrmac[module_idP]->cce_list[1][0],0,MAX_NUM_CCE*sizeof(int));
-  for (CC_id = 0; CC_id < MAX_NUM_CCs; CC_id++) {
-    //mbsfn_status[CC_id] = 0;
+    memset(RC.nrmac[module_idP]->cce_list[1][0],0,MAX_NUM_CCE*sizeof(int));
+    for (CC_id = 0; CC_id < MAX_NUM_CCs; CC_id++) {
+      //mbsfn_status[CC_id] = 0;
 
-    // clear vrb_maps
-    memset(cc[CC_id].vrb_map, 0, 100);
-    memset(cc[CC_id].vrb_map_UL, 0, 100);
+      // clear vrb_maps
+      memset(cc[CC_id].vrb_map, 0, 100);
+      memset(cc[CC_id].vrb_map_UL, 0, 100);
 
-    clear_nr_nfapi_information(RC.nrmac[module_idP], CC_id, frame_txP, slot_txP);
-  }
+      clear_nr_nfapi_information(RC.nrmac[module_idP], CC_id, frame_txP, slot_txP);
+    }
 
-  // refresh UE list based on UEs dropped by PHY in previous subframe
-  /*
-  for (i = 0; i < MAX_MOBILES_PER_GNB; i++) {
-    if (UE_list->active[i]) {
+    // refresh UE list based on UEs dropped by PHY in previous subframe
+    /*
+    for (i = 0; i < MAX_MOBILES_PER_GNB; i++) {
+      if (UE_list->active[i]) {
 
-      nfapi_nr_config_request_t *cfg = &RC.nrmac[module_idP]->config[CC_id];
+        nfapi_nr_config_request_t *cfg = &RC.nrmac[module_idP]->config[CC_id];
       
       
-      rnti = 0;//UE_RNTI(module_idP, i);
-      CC_id = 0;//UE_PCCID(module_idP, i);
+        rnti = 0;//UE_RNTI(module_idP, i);
+        CC_id = 0;//UE_PCCID(module_idP, i);
       
     } //END if (UE_list->active[i])
   } //END for (i = 0; i < MAX_MOBILES_PER_GNB; i++)
@@ -374,16 +438,16 @@ void gNB_dlsch_ulsch_scheduler(module_id_t module_idP,
 
   // Phytest scheduling
   if (get_softmodem_params()->phy_test && slot_txP==1){
-    nr_schedule_uss_dlsch_phytest(module_idP, frame_txP, slot_txP,NULL);
-    // resetting ta flag
+    nr_schedule_uss_dlsch_phytest(module_idP, frame_txP, slot_txP, pucch_sched, NULL);
+        // resetting ta flag
     gNB->ta_len = 0;
   }
 
-  /*
-  // Allocate CCEs for good after scheduling is done
-  for (CC_id = 0; CC_id < MAX_NUM_CCs; CC_id++)
-    allocate_CCEs(module_idP, CC_id, subframeP, 0);
-  */
+    /*
+    // Allocate CCEs for good after scheduling is done
+    for (CC_id = 0; CC_id < MAX_NUM_CCs; CC_id++)
+      allocate_CCEs(module_idP, CC_id, subframeP, 0);
+    */
 
   } //is_nr_DL_slot
 
diff --git a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_phytest.c b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_phytest.c
index 6aba6e7e63c401bbdd521d7e62c261c6b3687837..198ba63e445bbf7805fb685dc16d272928a5e42e 100644
--- a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_phytest.c
+++ b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_phytest.c
@@ -249,9 +249,14 @@ void nr_schedule_css_dlsch_phytest(module_id_t   module_idP,
   }
 }
 
+
+
+
+
 int configure_fapi_dl_pdu(int Mod_idP,
                           int *CCEIndex,
                           nfapi_nr_dl_tti_request_body_t *dl_req,
+			  NR_sched_pucch *pucch_sched,
                           uint8_t *mcsIndex,
                           uint16_t *rbSize,
                           uint16_t *rbStart) {
@@ -260,13 +265,12 @@ int configure_fapi_dl_pdu(int Mod_idP,
   gNB_MAC_INST                        *nr_mac  = RC.nrmac[Mod_idP];
   NR_COMMON_channels_t                *cc      = nr_mac->common_channels;
   NR_ServingCellConfigCommon_t        *scc     = cc->ServingCellConfigCommon;
-  
+
   nfapi_nr_dl_tti_request_pdu_t  *dl_tti_pdcch_pdu;
   nfapi_nr_dl_tti_request_pdu_t  *dl_tti_pdsch_pdu;
   int TBS, bwp_id = 1, UE_id = 0;
   NR_UE_list_t *UE_list = &RC.nrmac[Mod_idP]->UE_list;
 
-
   NR_CellGroupConfig_t *secondaryCellGroup = UE_list->secondaryCellGroup[UE_id];
   AssertFatal(secondaryCellGroup->spCellConfig->spCellConfigDedicated->downlinkBWP_ToAddModList->list.count == 1,
 	      "downlinkBWP_ToAddModList has %d BWP!\n",
@@ -351,10 +355,10 @@ int configure_fapi_dl_pdu(int Mod_idP,
   dci_pdu_rel15[0].ndi = 1;
   dci_pdu_rel15[0].rv = 0;
   dci_pdu_rel15[0].harq_pid = 0;
-  dci_pdu_rel15[0].dai = 2;
+  dci_pdu_rel15[0].dai = (pucch_sched->dai_c-1)&3;
   dci_pdu_rel15[0].tpc = 2;
-  dci_pdu_rel15[0].pucch_resource_indicator = 7;
-  dci_pdu_rel15[0].pdsch_to_harq_feedback_timing_indicator = 7;
+  dci_pdu_rel15[0].pucch_resource_indicator = pucch_sched->resource_indicator;
+  dci_pdu_rel15[0].pdsch_to_harq_feedback_timing_indicator = pucch_sched->timing_indicator;
   
   LOG_D(MAC, "[gNB scheduler phytest] DCI type 1 payload: freq_alloc %d (%d,%d,%d), time_alloc %d, vrb to prb %d, mcs %d tb_scaling %d ndi %d rv %d\n",
 	dci_pdu_rel15[0].frequency_domain_assignment,
@@ -413,7 +417,6 @@ int configure_fapi_dl_pdu(int Mod_idP,
 	pdsch_pdu_rel15->NrOfCodewords,
 	pdsch_pdu_rel15->mcsIndex[0],
 	TBS);
-
   return TBS; //Return TBS in bytes
 }
 
@@ -491,6 +494,7 @@ void configure_fapi_dl_Tx(module_id_t Mod_idP,
 void nr_schedule_uss_dlsch_phytest(module_id_t   module_idP,
                                    frame_t       frameP,
                                    sub_frame_t   slotP,
+                                   NR_sched_pucch *pucch_sched,
                                    nfapi_nr_dl_tti_pdsch_pdu_rel15_t *dlsch_config){
 
   LOG_D(MAC, "In nr_schedule_uss_dlsch_phytest \n");
@@ -537,7 +541,8 @@ void nr_schedule_uss_dlsch_phytest(module_id_t   module_idP,
 
   TBS_bytes = configure_fapi_dl_pdu(module_idP,
                                     CCEIndices,
-                                    dl_req, 
+                                    dl_req,
+				    pucch_sched, 
                                     dlsch_config!=NULL ? dlsch_config->mcsIndex : NULL,
                                     dlsch_config!=NULL ? &dlsch_config->rbSize : NULL,
                                     dlsch_config!=NULL ? &dlsch_config->rbStart : NULL);
@@ -598,13 +603,11 @@ void nr_schedule_uss_dlsch_phytest(module_id_t   module_idP,
       break;
       }
     }
-
   } //if (IS_SOFTMODEM_NOS1)
   else {
 
     //When the --NOS1 option is not enabled, DLSCH transmissions with random data
     //occur every time that the current function is called (dlsch phytest mode)
-
     LOG_D(MAC,"Configuring DL_TX in %d.%d\n", frameP, slotP);
 
     // fill dlsch_buffer with random data
@@ -718,12 +721,12 @@ void nr_schedule_uss_ulsch_phytest(int Mod_idP,
 
   UL_tti_req->SFN = frameP;
   UL_tti_req->Slot = slotP;
-  UL_tti_req->n_pdus = 1;
-  UL_tti_req->pdus_list[0].pdu_type = NFAPI_NR_UL_CONFIG_PUSCH_PDU_TYPE;
-  UL_tti_req->pdus_list[0].pdu_size = sizeof(nfapi_nr_pusch_pdu_t);
-  nfapi_nr_pusch_pdu_t  *pusch_pdu = &UL_tti_req->pdus_list[0].pusch_pdu;
+  UL_tti_req->pdus_list[UL_tti_req->n_pdus].pdu_type = NFAPI_NR_UL_CONFIG_PUSCH_PDU_TYPE;
+  UL_tti_req->pdus_list[UL_tti_req->n_pdus].pdu_size = sizeof(nfapi_nr_pusch_pdu_t);
+  nfapi_nr_pusch_pdu_t  *pusch_pdu = &UL_tti_req->pdus_list[UL_tti_req->n_pdus].pusch_pdu;
   memset(pusch_pdu,0,sizeof(nfapi_nr_pusch_pdu_t));
-  
+  UL_tti_req->n_pdus+=1;  
+
   LOG_D(MAC, "Scheduling UE specific PUSCH\n");
   //UL_tti_req = &nr_mac->UL_tti_req[CC_id];
   /*
@@ -820,7 +823,6 @@ void nr_schedule_uss_ulsch_phytest(int Mod_idP,
 		     1, // ue-specific,
 		     scc,
 		     bwp);
-
   
   dci_pdu_rel15_t dci_pdu_rel15[MAX_DCI_CORESET];
 
diff --git a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_primitives.c b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_primitives.c
index b7fddf9b733fba3d9bc74d66af550b825a027cdc..6d3f69f217927609facef8fa70f46ca0689e701a 100644
--- a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_primitives.c
+++ b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_primitives.c
@@ -545,12 +545,196 @@ void nr_configure_pdcch(nfapi_nr_dl_tti_pdcch_pdu_rel15_t* pdcch_pdu,
 }
 
 
+// This function configures pucch pdu fapi structure
+void nr_configure_pucch(nfapi_nr_pucch_pdu_t* pucch_pdu,
+			NR_ServingCellConfigCommon_t *scc,
+			NR_BWP_Uplink_t *bwp,
+                        uint8_t pucch_resource,
+                        uint16_t O_uci,
+                        uint16_t O_ack,
+                        uint8_t SR_flag) {
+
+  NR_PUCCH_Config_t *pucch_Config;
+  NR_PUCCH_Resource_t *pucchres;
+  NR_PUCCH_ResourceSet_t *pucchresset;
+  NR_PUCCH_FormatConfig_t *pucchfmt;
+  NR_PUCCH_ResourceId_t *resource_id = NULL;
+
+  long *id0 = NULL;
+  int n_list, n_set;
+  uint16_t N2,N3;
+  int res_found = 0;
+
+  pucch_pdu->bit_len_harq = O_ack;
+
+  if (bwp) { // This is not the InitialBWP
+
+    NR_PUSCH_Config_t *pusch_Config = bwp->bwp_Dedicated->pusch_Config->choice.setup;
+    long *pusch_id = pusch_Config->dataScramblingIdentityPUSCH;
+
+    if (pusch_Config->dmrs_UplinkForPUSCH_MappingTypeA != NULL)
+      id0 = pusch_Config->dmrs_UplinkForPUSCH_MappingTypeA->choice.setup->transformPrecodingDisabled->scramblingID0;
+    if (pusch_Config->dmrs_UplinkForPUSCH_MappingTypeB != NULL)
+      id0 = pusch_Config->dmrs_UplinkForPUSCH_MappingTypeB->choice.setup->transformPrecodingDisabled->scramblingID0;
+
+    // hop flags and hopping id are valid for any BWP
+    switch (bwp->bwp_Common->pucch_ConfigCommon->choice.setup->pucch_GroupHopping){
+      case 0 :
+        // if neither, both disabled
+        pucch_pdu->group_hop_flag = 0;
+        pucch_pdu->sequence_hop_flag = 0;
+        break;
+      case 1 :
+        // if enable, group enabled
+        pucch_pdu->group_hop_flag = 1;
+        pucch_pdu->sequence_hop_flag = 0;
+        break;
+      case 2 :
+        // if disable, sequence disabled
+        pucch_pdu->group_hop_flag = 0;
+        pucch_pdu->sequence_hop_flag = 1;
+        break;
+      default:
+        AssertFatal(1==0,"Group hopping flag %ld undefined (0,1,2) \n", bwp->bwp_Common->pucch_ConfigCommon->choice.setup->pucch_GroupHopping);
+    }
+
+    if (bwp->bwp_Common->pucch_ConfigCommon->choice.setup->hoppingId != NULL)
+      pucch_pdu->hopping_id = *bwp->bwp_Common->pucch_ConfigCommon->choice.setup->hoppingId;
+    else
+      pucch_pdu->hopping_id = *scc->physCellId;
+
+    pucch_pdu->bwp_size  = NRRIV2BW(bwp->bwp_Common->genericParameters.locationAndBandwidth,275);
+    pucch_pdu->bwp_start = NRRIV2PRBOFFSET(bwp->bwp_Common->genericParameters.locationAndBandwidth,275);
+    pucch_pdu->subcarrier_spacing = bwp->bwp_Common->genericParameters.subcarrierSpacing;
+    pucch_pdu->cyclic_prefix = (bwp->bwp_Common->genericParameters.cyclicPrefix==NULL) ? 0 : *bwp->bwp_Common->genericParameters.cyclicPrefix;
+
+    pucch_Config = bwp->bwp_Dedicated->pucch_Config->choice.setup;
+
+    AssertFatal(pucch_Config->resourceSetToAddModList!=NULL,
+		"PUCCH resourceSetToAddModList is null\n");
+
+    n_set = pucch_Config->resourceSetToAddModList->list.count; 
+    AssertFatal(n_set>0,"PUCCH resourceSetToAddModList is empty\n");
+
+    N2 = 2;
+    // procedure to select pucch resource id from resource sets according to 
+    // number of uci bits and pucch resource indicator pucch_resource
+    // ( see table 9.2.3.2 in 38.213)
+    for (int i=0; i<n_set; i++) {
+      pucchresset = pucch_Config->resourceSetToAddModList->list.array[i];
+      n_list = pucchresset->resourceList.list.count;
+      if (pucchresset->pucch_ResourceSetId == 0 && O_uci<3) {
+        if (pucch_resource < n_list)
+          resource_id = pucchresset->resourceList.list.array[pucch_resource];
+        else 
+          AssertFatal(1==0,"Couldn't fine pucch resource indicator %d in PUCCH resource set %d for %d UCI bits",pucch_resource,i,O_uci);
+      }
+      else {
+        N3 = pucchresset->maxPayloadMinus1!= NULL ?  *pucchresset->maxPayloadMinus1 : 1706;
+        if (N2<O_uci && N3>O_uci) {
+          if (pucch_resource < n_list)
+            resource_id = pucchresset->resourceList.list.array[pucch_resource];
+          else 
+            AssertFatal(1==0,"Couldn't fine pucch resource indicator %d in PUCCH resource set %d for %d UCI bits",pucch_resource,i,O_uci);
+        }
+        else N2 = N3;
+      }
+    }
+
+    AssertFatal(resource_id!=NULL,"Couldn-t find any matching PUCCH resource in the PUCCH resource sets");
+
+    AssertFatal(pucch_Config->resourceToAddModList!=NULL,
+		"PUCCH resourceToAddModList is null\n");
+
+    n_list = pucch_Config->resourceToAddModList->list.count; 
+    AssertFatal(n_list>0,"PUCCH resourceToAddModList is empty\n");
+
+    // going through the list of PUCCH resources to find the one indexed by resource_id
+    for (int i=0; i<n_list; i++) {
+      pucchres = pucch_Config->resourceToAddModList->list.array[i];
+      if (pucchres->pucch_ResourceId == *resource_id) {
+        res_found = 1;
+        pucch_pdu->prb_start = pucchres->startingPRB;
+        // FIXME why there is only one frequency hopping flag
+        // what about inter slot frequency hopping?
+        pucch_pdu->freq_hop_flag = pucchres->intraSlotFrequencyHopping!= NULL ?  1 : 0;
+        pucch_pdu->second_hop_prb = pucchres->secondHopPRB!= NULL ?  *pucchres->secondHopPRB : 0;
+        switch(pucchres->format.present) {
+          case NR_PUCCH_Resource__format_PR_format0 :
+            pucch_pdu->format_type = 0;
+            pucch_pdu->initial_cyclic_shift = pucchres->format.choice.format0->initialCyclicShift;
+            pucch_pdu->nr_of_symbols = pucchres->format.choice.format0->nrofSymbols;
+            pucch_pdu->start_symbol_index = pucchres->format.choice.format0->startingSymbolIndex;
+            pucch_pdu->sr_flag = SR_flag;
+            break;
+          case NR_PUCCH_Resource__format_PR_format1 :
+            pucch_pdu->format_type = 1;
+            pucch_pdu->initial_cyclic_shift = pucchres->format.choice.format1->initialCyclicShift;
+            pucch_pdu->nr_of_symbols = pucchres->format.choice.format1->nrofSymbols;
+            pucch_pdu->start_symbol_index = pucchres->format.choice.format1->startingSymbolIndex;
+            pucch_pdu->time_domain_occ_idx = pucchres->format.choice.format1->timeDomainOCC;
+            pucch_pdu->sr_flag = SR_flag;
+            break;
+          case NR_PUCCH_Resource__format_PR_format2 :
+            pucch_pdu->format_type = 2;
+            pucch_pdu->nr_of_symbols = pucchres->format.choice.format2->nrofSymbols;
+            pucch_pdu->start_symbol_index = pucchres->format.choice.format2->startingSymbolIndex;
+            pucch_pdu->prb_size = pucchres->format.choice.format2->nrofPRBs;
+            pucch_pdu->data_scrambling_id = pusch_id!= NULL ? *pusch_id : *scc->physCellId;
+            pucch_pdu->dmrs_scrambling_id = id0!= NULL ? *id0 : *scc->physCellId;
+            break;
+          case NR_PUCCH_Resource__format_PR_format3 :
+            pucch_pdu->format_type = 3;
+            pucch_pdu->nr_of_symbols = pucchres->format.choice.format3->nrofSymbols;
+            pucch_pdu->start_symbol_index = pucchres->format.choice.format3->startingSymbolIndex;
+            pucch_pdu->prb_size = pucchres->format.choice.format3->nrofPRBs;
+            pucch_pdu->data_scrambling_id = pusch_id!= NULL ? *pusch_id : *scc->physCellId;
+            if (pucch_Config->format3 == NULL) {
+              pucch_pdu->pi_2bpsk = 0;
+              pucch_pdu->add_dmrs_flag = 0;
+            }
+            else {
+              pucchfmt = pucch_Config->format3->choice.setup;
+              pucch_pdu->pi_2bpsk = pucchfmt->pi2BPSK!= NULL ?  1 : 0;
+              pucch_pdu->add_dmrs_flag = pucchfmt->additionalDMRS!= NULL ?  1 : 0;
+            }
+            break;
+          case NR_PUCCH_Resource__format_PR_format4 :
+            pucch_pdu->format_type = 4;
+            pucch_pdu->nr_of_symbols = pucchres->format.choice.format4->nrofSymbols;
+            pucch_pdu->start_symbol_index = pucchres->format.choice.format4->startingSymbolIndex;
+            pucch_pdu->pre_dft_occ_len = pucchres->format.choice.format4->occ_Length;
+            pucch_pdu->pre_dft_occ_idx = pucchres->format.choice.format4->occ_Index;
+            pucch_pdu->data_scrambling_id = pusch_id!= NULL ? *pusch_id : *scc->physCellId;
+            if (pucch_Config->format3 == NULL) {
+              pucch_pdu->pi_2bpsk = 0;
+              pucch_pdu->add_dmrs_flag = 0;
+            }
+            else {
+              pucchfmt = pucch_Config->format3->choice.setup;
+              pucch_pdu->pi_2bpsk = pucchfmt->pi2BPSK!= NULL ?  1 : 0;
+              pucch_pdu->add_dmrs_flag = pucchfmt->additionalDMRS!= NULL ?  1 : 0;
+            }
+            break;
+          default :
+            AssertFatal(1==0,"Undefined PUCCH format \n");
+        }
+      }
+    }
+    AssertFatal(res_found==1,"No PUCCH resource found corresponding to id %ld\n",*resource_id);
+  }  
+  else { // this is for InitialBWP
+    AssertFatal(1==0,"Fill in InitialBWP PUCCH configuration\n");
+  }
+
+}
+
+
 
 void fill_dci_pdu_rel15(nfapi_nr_dl_tti_pdcch_pdu_rel15_t *pdcch_pdu_rel15,
 			dci_pdu_rel15_t *dci_pdu_rel15,
 			int *dci_formats,
-			int *rnti_types
-			) {
+			int *rnti_types) {
   
   uint16_t N_RB = pdcch_pdu_rel15->BWPSize;
   uint8_t fsize=0, pos=0;
@@ -1003,6 +1187,171 @@ int add_new_nr_ue(module_id_t mod_idP, rnti_t rntiP){
   return -1;
 }
 
+
+void get_pdsch_to_harq_feedback(int Mod_idP,
+                                int UE_id,
+                                NR_SearchSpace__searchSpaceType_PR ss_type,
+                                uint8_t *pdsch_to_harq_feedback) {
+
+  int bwp_id=1;
+  NR_UE_list_t *UE_list = &RC.nrmac[Mod_idP]->UE_list;
+  NR_CellGroupConfig_t *secondaryCellGroup = UE_list->secondaryCellGroup[UE_id];
+  NR_BWP_Downlink_t *bwp=secondaryCellGroup->spCellConfig->spCellConfigDedicated->downlinkBWP_ToAddModList->list.array[bwp_id-1];
+  NR_BWP_Uplink_t *ubwp=secondaryCellGroup->spCellConfig->spCellConfigDedicated->uplinkConfig->uplinkBWP_ToAddModList->list.array[bwp_id-1];
+
+  NR_SearchSpace_t *ss;
+
+  // common search type uses DCI format 1_0
+  if (ss_type == NR_SearchSpace__searchSpaceType_PR_common) {
+    for (int i=0; i<8; i++)
+      pdsch_to_harq_feedback[i] = i+1;
+  }
+  else {
+    // searching for a ue specific search space
+    int found=0;
+
+    for (int i=0;i<bwp->bwp_Dedicated->pdcch_Config->choice.setup->searchSpacesToAddModList->list.count;i++) {
+      ss=bwp->bwp_Dedicated->pdcch_Config->choice.setup->searchSpacesToAddModList->list.array[i];
+      AssertFatal(ss->controlResourceSetId != NULL,"ss->controlResourceSetId is null\n");
+      AssertFatal(ss->searchSpaceType != NULL,"ss->searchSpaceType is null\n");
+      if (ss->searchSpaceType->present == ss_type) {
+	found=1;
+	break;
+      }
+    }
+    AssertFatal(found==1,"Couldn't find a ue specific searchspace\n");
+    if (ss->searchSpaceType->choice.ue_Specific->dci_Formats == NR_SearchSpace__searchSpaceType__ue_Specific__dci_Formats_formats0_0_And_1_0) {
+      for (int i=0; i<8; i++)
+        pdsch_to_harq_feedback[i] = i+1;
+    }
+    else {
+      if(ubwp->bwp_Dedicated->pucch_Config->choice.setup->dl_DataToUL_ACK != NULL)
+        pdsch_to_harq_feedback = (uint8_t *)ubwp->bwp_Dedicated->pucch_Config->choice.setup->dl_DataToUL_ACK;
+      else
+        AssertFatal(found==1,"There is no allocated dl_DataToUL_ACK for pdsch to harq feedback\n");
+    }
+  }
+}
+
+
+// function to update pucch scheduling parameters in UE list when a USS DL is scheduled
+void nr_update_pucch_scheduling(int Mod_idP,
+                                int UE_id,
+                                frame_t frameP,
+                                sub_frame_t slotP,
+                                int slots_per_tdd,
+                                NR_sched_pucch *sched_pucch) {
+
+  NR_ServingCellConfigCommon_t *scc = RC.nrmac[Mod_idP]->common_channels->ServingCellConfigCommon;
+  NR_UE_list_t *UE_list = &RC.nrmac[Mod_idP]->UE_list;
+  int first_ul_slot_tdd,k;
+  NR_sched_pucch *curr_pucch;
+  uint8_t pdsch_to_harq_feedback[8];
+  int found = 0;
+  int i = 0;
+  int nr_ulmix_slots = scc->tdd_UL_DL_ConfigurationCommon->pattern1.nrofUplinkSlots;
+  if (scc->tdd_UL_DL_ConfigurationCommon->pattern1.nrofUplinkSymbols!=0)
+    nr_ulmix_slots++;
+
+  // this is hardcoded for now as ue specific
+  NR_SearchSpace__searchSpaceType_PR ss_type = NR_SearchSpace__searchSpaceType_PR_ue_Specific;
+  get_pdsch_to_harq_feedback(Mod_idP,UE_id,ss_type,pdsch_to_harq_feedback);
+
+  // if the list of pucch to be scheduled is empty
+  if (UE_list->UE_sched_ctrl[UE_id].sched_pucch == NULL) {
+    sched_pucch->frame = frameP;
+    sched_pucch->next_sched_pucch = NULL;
+    sched_pucch->dai_c = 1;
+    sched_pucch->resource_indicator = 0; // in phytest with only 1 UE we are using just the 1st resource
+    if ( nr_ulmix_slots > 0 ) {
+      // first pucch occasion in first UL or MIXED slot
+      first_ul_slot_tdd = scc->tdd_UL_DL_ConfigurationCommon->pattern1.nrofDownlinkSlots;
+      for (k=0; k<nr_ulmix_slots; k++) { // for each possible UL or mixed slot
+        while (i<8 && found == 0)  {  // look if timing indicator is among allowed values
+          if (pdsch_to_harq_feedback[i]==(first_ul_slot_tdd+k)-(slotP % slots_per_tdd))
+            found = 1;
+          if (found == 0) i++;
+        }
+        if (found == 1) break;
+      }
+      if (found == 1) {
+        // computing slot in which pucch is scheduled
+        sched_pucch->ul_slot = first_ul_slot_tdd + k + (slotP - (slotP % slots_per_tdd));
+        sched_pucch->timing_indicator = pdsch_to_harq_feedback[i];
+      }
+      else
+        AssertFatal(1==0,"No Uplink slot available in accordance to allowed timing indicator\n");
+    }
+    else
+      AssertFatal(1==0,"No Uplink Slots in this Frame\n");
+
+    UE_list->UE_sched_ctrl[UE_id].sched_pucch = sched_pucch;
+  }
+  else {  // to be tested
+    curr_pucch = UE_list->UE_sched_ctrl[UE_id].sched_pucch;
+    if (curr_pucch->dai_c<MAX_ACK_BITS) {     // we are scheduling at most MAX_UCI_BITS harq-ack in the same pucch
+      while (i<8 && found == 0)  {  // look if timing indicator is among allowed values for current pucch
+        if (pdsch_to_harq_feedback[i]==(curr_pucch->ul_slot % slots_per_tdd)-(slotP % slots_per_tdd))
+          found = 1;
+        if (found == 0) i++;
+      }
+      if (found == 1) {  // scheduling this harq-ack in current pucch
+        sched_pucch = curr_pucch;
+        sched_pucch->dai_c = 1 + sched_pucch->dai_c;
+        sched_pucch->timing_indicator = pdsch_to_harq_feedback[i];
+      }
+    }
+    if (curr_pucch->dai_c==MAX_ACK_BITS || found == 0) { // if current pucch is full or no timing indicator allowed
+      // look for pucch occasions in other UL of mixed slots
+      for (k=scc->tdd_UL_DL_ConfigurationCommon->pattern1.nrofDownlinkSlots; k<slots_per_tdd; k++) { // for each possible UL or mixed slot
+        if (k!=(curr_pucch->ul_slot % slots_per_tdd)) { // skip current scheduled slot (already checked)
+          i = 0;
+          while (i<8 && found == 0)  {  // look if timing indicator is among allowed values
+            if (pdsch_to_harq_feedback[i]==k-(slotP % slots_per_tdd))
+              found = 1;
+            if (found == 0) i++;
+          }
+          if (found == 1) {
+            if (k<(curr_pucch->ul_slot % slots_per_tdd)) { // we need to add a pucch occasion before current pucch
+              sched_pucch->frame = frameP;
+              sched_pucch->ul_slot =  k + (slotP - (slotP % slots_per_tdd));
+              sched_pucch->next_sched_pucch = curr_pucch;
+              sched_pucch->dai_c = 1;
+              sched_pucch->resource_indicator = 0; // in phytest with only 1 UE we are using just the 1st resource
+              sched_pucch->timing_indicator = pdsch_to_harq_feedback[i];
+              UE_list->UE_sched_ctrl[UE_id].sched_pucch = sched_pucch;
+            }
+            else {
+              while (curr_pucch->next_sched_pucch != NULL && k!=(curr_pucch->ul_slot % slots_per_tdd))
+                curr_pucch = curr_pucch->next_sched_pucch;
+              if (curr_pucch == NULL) {  // creating a new item in the list
+                sched_pucch->frame = frameP;
+                sched_pucch->next_sched_pucch = NULL;
+                sched_pucch->dai_c = 1;
+                sched_pucch->timing_indicator = pdsch_to_harq_feedback[i];
+                sched_pucch->resource_indicator = 0; // in phytest with only 1 UE we are using just the 1st resource
+                sched_pucch->ul_slot = k + (slotP - (slotP % slots_per_tdd));
+                curr_pucch->next_sched_pucch = (NR_sched_pucch*) malloc(sizeof(NR_sched_pucch));
+                curr_pucch->next_sched_pucch = sched_pucch;
+              }
+              else {
+                if (curr_pucch->dai_c==MAX_ACK_BITS)
+                  found = 0; // if pucch at index k is already full we have to find a new one in a following occasion
+                else { // scheduling this harq-ack in current pucch
+                  sched_pucch = curr_pucch;
+                  sched_pucch->dai_c = 1 + sched_pucch->dai_c;
+                  sched_pucch->timing_indicator = pdsch_to_harq_feedback[i];
+                }
+              }
+            }
+          }
+        }
+      }
+    }
+  }
+}
+
+
 /*void fill_nfapi_coresets_and_searchspaces(NR_CellGroupConfig_t *cg,
 					  nfapi_nr_coreset_t *coreset,
 					  nfapi_nr_search_space_t *search_space) {
diff --git a/openair2/LAYER2/NR_MAC_gNB/mac_proto.h b/openair2/LAYER2/NR_MAC_gNB/mac_proto.h
index d55a188817d5cab9c0b0bcb1586cff73108b4ada..e294d118d92b8c84cb1da8b4a4b79174823a93b9 100644
--- a/openair2/LAYER2/NR_MAC_gNB/mac_proto.h
+++ b/openair2/LAYER2/NR_MAC_gNB/mac_proto.h
@@ -35,6 +35,8 @@
 #include "PHY/defs_gNB.h"
 #include "NR_TAG-Id.h"
 
+#define MAX_ACK_BITS 2 //only format 0 is available for now
+
 void set_cset_offset(uint16_t);
 
 void mac_top_init_gNB(void);
@@ -83,6 +85,7 @@ void nr_schedule_css_dlsch_phytest(module_id_t   module_idP,
 int configure_fapi_dl_pdu(int Mod_id,
                          int *CCEIndeces,
                          nfapi_nr_dl_tti_request_body_t *dl_req,
+                         NR_sched_pucch *pucch_sched,
                          uint8_t *mcsIndex,
                          uint16_t *rbSize,
                          uint16_t *rbStart);
@@ -100,11 +103,24 @@ void configure_fapi_dl_Tx(module_id_t Mod_idP,
 void nr_schedule_uss_dlsch_phytest(module_id_t   module_idP,
                                    frame_t       frameP,
                                    sub_frame_t   slotP,
+                                   NR_sched_pucch *pucch_sched,
                                    nfapi_nr_dl_tti_pdsch_pdu_rel15_t *pdsch_config);
 
 void nr_schedule_uss_ulsch_phytest(int Mod_idP,
                                    frame_t       frameP,
                                    sub_frame_t   slotP);
+
+void nr_update_pucch_scheduling(int Mod_idP,
+                                int UE_id,
+                                frame_t frameP,
+                                sub_frame_t slotP,
+                                int slots_per_tdd,
+                                NR_sched_pucch *sched_pucch);
+
+void get_pdsch_to_harq_feedback(int Mod_idP,
+                                int UE_id,
+                                NR_SearchSpace__searchSpaceType_PR ss_type,
+                                uint8_t *pdsch_to_harq_feedback);
   
 void nr_configure_css_dci_initial(nfapi_nr_dl_tti_pdcch_pdu_rel15_t* pdcch_pdu,
                                   nr_scs_e scs_common,
@@ -124,7 +140,13 @@ int nr_is_dci_opportunity(nfapi_nr_search_space_t search_space,
                           uint16_t slot,
                           nfapi_nr_config_request_scf_t cfg);
 */
-
+void nr_configure_pucch(nfapi_nr_pucch_pdu_t* pucch_pdu,
+			NR_ServingCellConfigCommon_t *scc,
+			NR_BWP_Uplink_t *bwp,
+                        uint8_t pucch_resource,
+                        uint16_t O_uci,
+                        uint16_t O_ack,
+                        uint8_t SR_flag);
 void nr_configure_pdcch(nfapi_nr_dl_tti_pdcch_pdu_rel15_t* pdcch_pdu,
                         int ss_type,
                         NR_ServingCellConfigCommon_t *scc,
@@ -134,7 +156,6 @@ void fill_dci_pdu_rel15(nfapi_nr_dl_tti_pdcch_pdu_rel15_t *pdcch_pdu_rel15,
                         dci_pdu_rel15_t *dci_pdu_rel15,
                         int *dci_formats,
                         int *rnti_types);
-
 int get_spf(nfapi_nr_config_request_scf_t *cfg);
 
 int to_absslot(nfapi_nr_config_request_scf_t *cfg,int frame,int slot);
diff --git a/openair2/LAYER2/NR_MAC_gNB/nr_mac_gNB.h b/openair2/LAYER2/NR_MAC_gNB/nr_mac_gNB.h
index 5bc320d5e2ee67ec8d0e76e12fb5f07d3b4b716f..86dac1e11fcd6d5efb824bc05ac2327cb7a70e70 100644
--- a/openair2/LAYER2/NR_MAC_gNB/nr_mac_gNB.h
+++ b/openair2/LAYER2/NR_MAC_gNB/nr_mac_gNB.h
@@ -102,9 +102,20 @@ typedef struct {
   uint8_t num_sf_allocation_pattern;
 } NR_COMMON_channels_t;
 
-/*! \brief scheduling control information set through an API (not used)*/
+typedef struct NR_sched_pucch {
+  int frame;
+  int ul_slot;
+  uint8_t dai_c;
+  uint8_t timing_indicator;
+  uint8_t resource_indicator;
+  struct NR_sched_pucch *next_sched_pucch;
+} NR_sched_pucch;
+
+/*! \brief scheduling control information set through an API */
 typedef struct {
-  int dummy;
+  uint64_t dlsch_in_slot_bitmap;  // static bitmap signaling which slot in a tdd period contains dlsch
+  uint64_t ulsch_in_slot_bitmap;  // static bitmap signaling which slot in a tdd period contains ulsch
+  NR_sched_pucch *sched_pucch;
 } NR_UE_sched_ctrl_t;
 
 /*! \brief UE list used by eNB to order UEs/CC for scheduling*/
@@ -112,7 +123,7 @@ typedef struct {
 
   DLSCH_PDU DLSCH_pdu[4][MAX_MOBILES_PER_GNB];
   /// scheduling control info
-  UE_sched_ctrl_t UE_sched_ctrl[MAX_MOBILES_PER_GNB];
+  NR_UE_sched_ctrl_t UE_sched_ctrl[MAX_MOBILES_PER_GNB];
   int next[MAX_MOBILES_PER_GNB];
   int head;
   int next_ul[MAX_MOBILES_PER_GNB];
@@ -124,7 +135,7 @@ typedef struct {
   NR_CellGroupConfig_t *secondaryCellGroup[MAX_MOBILES_PER_GNB];
 } NR_UE_list_t;
 
-/*! \brief top level eNB MAC structure */
+/*! \brief top level gNB MAC structure */
 typedef struct gNB_MAC_INST_s {
   /// Ethernet parameters for northbound midhaul interface
   eth_params_t                    eth_params_n;
@@ -191,64 +202,62 @@ typedef struct gNB_MAC_INST_s {
 } gNB_MAC_INST;
 
 typedef struct {
-
-
-uint8_t format_indicator; //1 bit
-uint16_t frequency_domain_assignment; //up to 16 bits
-uint8_t time_domain_assignment; // 4 bits
-uint8_t frequency_hopping_flag; //1 bit
-
-uint8_t ra_preamble_index; //6 bits
-uint8_t ss_pbch_index; //6 bits
-uint8_t prach_mask_index; //4 bits
-
-uint8_t vrb_to_prb_mapping; //0 or 1 bit
-uint8_t mcs; //5 bits
-uint8_t ndi; //1 bit
-uint8_t rv; //2 bits
-uint8_t harq_pid; //4 bits
-uint8_t dai; //0, 2 or 4 bits
-uint8_t dai1; //1 or 2 bits
-uint8_t dai2; //0 or 2 bits
-uint8_t tpc; //2 bits
-uint8_t pucch_resource_indicator; //3 bits
-uint8_t pdsch_to_harq_feedback_timing_indicator; //0, 1, 2 or 3 bits
-
-uint8_t short_messages_indicator; //2 bits
-uint8_t short_messages; //8 bits
-uint8_t tb_scaling; //2 bits
-
-uint8_t carrier_indicator; //0 or 3 bits
-uint8_t bwp_indicator; //0, 1 or 2 bits
-uint8_t prb_bundling_size_indicator; //0 or 1 bits
-uint8_t rate_matching_indicator; //0, 1 or 2 bits
-uint8_t zp_csi_rs_trigger; //0, 1 or 2 bits
-uint8_t transmission_configuration_indication; //0 or 3 bits
-uint8_t srs_request; //2 bits
-uint8_t cbgti; //CBG Transmission Information: 0, 2, 4, 6 or 8 bits
-uint8_t cbgfi; //CBG Flushing Out Information: 0 or 1 bit
-uint8_t dmrs_sequence_initialization; //0 or 1 bit
-
-uint8_t srs_resource_indicator;
-uint8_t precoding_information;
-uint8_t csi_request;
-uint8_t ptrs_dmrs_association;
-uint8_t beta_offset_indicator; //0 or 2 bits
-
-uint8_t slot_format_indicator_count;
-uint8_t *slot_format_indicators;
-
-uint8_t pre_emption_indication_count;
-uint16_t *pre_emption_indications; //14 bit
-
-uint8_t block_number_count;
-uint8_t *block_numbers;
-
-uint8_t ul_sul_indicator; //0 or 1 bit
-uint8_t antenna_ports;
-
-uint16_t reserved; //1_0/C-RNTI:10 bits, 1_0/P-RNTI: 6 bits, 1_0/SI-&RA-RNTI: 16 bits
-uint16_t padding;
+  uint8_t format_indicator; //1 bit
+  uint16_t frequency_domain_assignment; //up to 16 bits
+  uint8_t time_domain_assignment; // 4 bits
+  uint8_t frequency_hopping_flag; //1 bit
+  
+  uint8_t ra_preamble_index; //6 bits
+  uint8_t ss_pbch_index; //6 bits
+  uint8_t prach_mask_index; //4 bits
+  
+  uint8_t vrb_to_prb_mapping; //0 or 1 bit
+  uint8_t mcs; //5 bits
+  uint8_t ndi; //1 bit
+  uint8_t rv; //2 bits
+  uint8_t harq_pid; //4 bits
+  uint8_t dai; //0, 2 or 4 bits
+  uint8_t dai1; //1 or 2 bits
+  uint8_t dai2; //0 or 2 bits
+  uint8_t tpc; //2 bits
+  uint8_t pucch_resource_indicator; //3 bits
+  uint8_t pdsch_to_harq_feedback_timing_indicator; //0, 1, 2 or 3 bits
+  
+  uint8_t short_messages_indicator; //2 bits
+  uint8_t short_messages; //8 bits
+  uint8_t tb_scaling; //2 bits
+  
+  uint8_t carrier_indicator; //0 or 3 bits
+  uint8_t bwp_indicator; //0, 1 or 2 bits
+  uint8_t prb_bundling_size_indicator; //0 or 1 bits
+  uint8_t rate_matching_indicator; //0, 1 or 2 bits
+  uint8_t zp_csi_rs_trigger; //0, 1 or 2 bits
+  uint8_t transmission_configuration_indication; //0 or 3 bits
+  uint8_t srs_request; //2 bits
+  uint8_t cbgti; //CBG Transmission Information: 0, 2, 4, 6 or 8 bits
+  uint8_t cbgfi; //CBG Flushing Out Information: 0 or 1 bit
+  uint8_t dmrs_sequence_initialization; //0 or 1 bit
+  
+  uint8_t srs_resource_indicator;
+  uint8_t precoding_information;
+  uint8_t csi_request;
+  uint8_t ptrs_dmrs_association;
+  uint8_t beta_offset_indicator; //0 or 2 bits
+  
+  uint8_t slot_format_indicator_count;
+  uint8_t *slot_format_indicators;
+  
+  uint8_t pre_emption_indication_count;
+  uint16_t *pre_emption_indications; //14 bit
+  
+  uint8_t block_number_count;
+  uint8_t *block_numbers;
+  
+  uint8_t ul_sul_indicator; //0 or 1 bit
+  uint8_t antenna_ports;
+  
+  uint16_t reserved; //1_0/C-RNTI:10 bits, 1_0/P-RNTI: 6 bits, 1_0/SI-&RA-RNTI: 16 bits
+  uint16_t padding;
 
 } dci_pdu_rel15_t;