nr_dlsch.c 12.3 KB
Newer Older
Guy De Souza's avatar
Guy De Souza committed
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
/*
 * 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
 */

22
23
24
25
/*! \file PHY/NR_TRANSPORT/dlsch_decoding.c
* \brief Top-level routines for transmission of the PDSCH 38211 v 15.2.0
* \author Guy De Souza
* \date 2018
Guy De Souza's avatar
Guy De Souza committed
26
27
* \version 0.1
* \company Eurecom
28
* \email: desouza@eurecom.fr
Guy De Souza's avatar
Guy De Souza committed
29
30
31
* \note
* \warning
*/
Guy De Souza's avatar
Guy De Souza committed
32

33
34
#include "nr_dlsch.h"
#include "nr_dci.h"
Guy De Souza's avatar
Guy De Souza committed
35
#include "nr_sch_dmrs.h"
Guy De Souza's avatar
Guy De Souza committed
36

Guy De Souza's avatar
Guy De Souza committed
37
//#define DEBUG_DLSCH
Guy De Souza's avatar
Guy De Souza committed
38
//#define DEBUG_DLSCH_MAPPING
Guy De Souza's avatar
Guy De Souza committed
39

40
41
42
uint8_t mod_order[5] = {1, 2, 4, 6, 8};
uint16_t mod_offset[5] = {1,3,7,23,87};

Guy De Souza's avatar
Guy De Souza committed
43
void nr_pdsch_codeword_scrambling(uint8_t *in,
Guy De Souza's avatar
Guy De Souza committed
44
                         uint16_t size,
45
46
47
48
49
                         uint8_t q,
                         uint32_t Nid,
                         uint32_t n_RNTI,
                         uint32_t* out) {

50
  uint8_t reset, b_idx;
51
52
53
54
55
56
  uint32_t x1, x2, s=0;

  reset = 1;
  x2 = (n_RNTI<<15) + (q<<14) + Nid;

  for (int i=0; i<size; i++) {
57
58
    b_idx = i&0x1f;
    if (b_idx==0) {
59
60
      s = lte_gold_generic(&x1, &x2, reset);
      reset = 0;
61
62
      if (i)
        out++;
63
    }
64
    *out ^= (((in[i])&1) ^ ((s>>b_idx)&1))<<b_idx;
Guy De Souza's avatar
Guy De Souza committed
65
    //printf("i %d b_idx %d in %d s 0x%08x out 0x%08x\n", i, b_idx, in[i], s, *out);
66
67
68
69
  }

}

Guy De Souza's avatar
Guy De Souza committed
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
void nr_modulation(uint32_t *in,
                   uint16_t length,
                   nr_mod_t modulation_type,
                   int16_t *out) {

  uint16_t offset;
	uint16_t order;
	order = mod_order[modulation_type];
	offset = mod_offset[modulation_type];
   
  for (int i=0; i<length/order; i++) {
    uint8_t idx = 0, b_idx;

    for (int j=0; j<order; j++) {
      b_idx = (i*order+j)&0x1f;
      if (i && (!b_idx))
        in++;
      idx ^= (((*in)>>b_idx)&1)<<(order-j-1);
    }

    out[i<<1] = nr_mod_table[(offset+idx)<<1];
    out[(i<<1)+1] = nr_mod_table[((offset+idx)<<1)+1];
  }
}

95
96
97
void nr_pdsch_codeword_modulation(uint32_t *in,
                         uint8_t  Qm,
                         uint32_t length,
Guy De Souza's avatar
Guy De Souza committed
98
                         int16_t *out) {
99
100
101
102
103
104
105
106
107
108
109
110

  uint16_t offset = (Qm==2)? NR_MOD_TABLE_QPSK_OFFSET : (Qm==4)? NR_MOD_TABLE_QAM16_OFFSET : \
                    (Qm==6)? NR_MOD_TABLE_QAM64_OFFSET: (Qm==8)? NR_MOD_TABLE_QAM256_OFFSET : 0;
  AssertFatal(offset, "Invalid modulation order %d\n", Qm);

  for (int i=0; i<length/Qm; i++) {
    uint8_t idx = 0, b_idx;

    for (int j=0; j<Qm; j++) {
      b_idx = (i*Qm+j)&0x1f;
      if (i && (!b_idx))
        in++;
Guy De Souza's avatar
Guy De Souza committed
111
      idx ^= (((*in)>>b_idx)&1)<<(Qm-j-1);
112
113
114
115
116
117
118
    }

    out[i<<1] = nr_mod_table[(offset+idx)<<1];
    out[(i<<1)+1] = nr_mod_table[((offset+idx)<<1)+1];
  }
}

Guy De Souza's avatar
Guy De Souza committed
119
void nr_pdsch_layer_mapping(int16_t **mod_symbs,
120
                         uint8_t n_layers,
Guy De Souza's avatar
Guy De Souza committed
121
                         uint16_t n_symbs,
Guy De Souza's avatar
Guy De Souza committed
122
                         int16_t **tx_layers) {
123
124
125
126

  switch (n_layers) {

    case 1:
Guy De Souza's avatar
Guy De Souza committed
127
      memcpy((void*)tx_layers[0], (void*)mod_symbs[0], (n_symbs<<1)*sizeof(int16_t));
128
129
130
131
132
    break;

    case 2:
    case 3:
    case 4:
Guy De Souza's avatar
Guy De Souza committed
133
      for (int i=0; i<n_symbs/n_layers; i++)
134
135
136
137
138
139
140
        for (int l=0; l<n_layers; l++) {
          tx_layers[l][i<<1] = mod_symbs[0][(n_layers*i+l)<<1];
          tx_layers[l][(i<<1)+1] = mod_symbs[0][((n_layers*i+l)<<1)+1];
        }
    break;

    case 5:
Guy De Souza's avatar
Guy De Souza committed
141
      for (int i=0; i<n_symbs>>1; i++)
142
143
144
145
        for (int l=0; l<2; l++) {
          tx_layers[l][i<<1] = mod_symbs[0][((i<<1)+l)<<1];
          tx_layers[l][(i<<1)+1] = mod_symbs[0][(((i<<1)+l)<<1)+1];
        }
Guy De Souza's avatar
Guy De Souza committed
146
      for (int i=0; i<n_symbs/3; i++)
147
148
149
150
151
152
153
154
        for (int l=2; l<5; l++) {
          tx_layers[l][i<<1] = mod_symbs[1][(3*i+l)<<1];
          tx_layers[l][(i<<1)+1] = mod_symbs[1][((3*i+l)<<1)+1];
      }
    break;

    case 6:
      for (int q=0; q<2; q++)
Guy De Souza's avatar
Guy De Souza committed
155
        for (int i=0; i<n_symbs/3; i++)
156
157
158
159
160
161
162
          for (int l=0; l<3; l++) {
            tx_layers[l][i<<1] = mod_symbs[q][(3*i+l)<<1];
            tx_layers[l][(i<<1)+1] = mod_symbs[q][((3*i+l)<<1)+1];
          }
    break;

    case 7:
Guy De Souza's avatar
Guy De Souza committed
163
      for (int i=0; i<n_symbs/3; i++)
164
165
166
167
        for (int l=0; l<3; l++) {
          tx_layers[l][i<<1] = mod_symbs[1][(3*i+l)<<1];
          tx_layers[l][(i<<1)+1] = mod_symbs[1][((3*i+l)<<1)+1];
        }
Guy De Souza's avatar
Guy De Souza committed
168
      for (int i=0; i<n_symbs/4; i++)
169
170
171
172
173
174
175
176
        for (int l=3; l<7; l++) {
          tx_layers[l][i<<1] = mod_symbs[0][((i<<2)+l)<<1];
          tx_layers[l][(i<<1)+1] = mod_symbs[0][(((i<<2)+l)<<1)+1];
        }
    break;

    case 8:
      for (int q=0; q<2; q++)
Guy De Souza's avatar
Guy De Souza committed
177
        for (int i=0; i<n_symbs>>2; i++)
178
179
180
181
182
183
184
          for (int l=0; l<3; l++) {
            tx_layers[l][i<<1] = mod_symbs[q][((i<<2)+l)<<1];
            tx_layers[l][(i<<1)+1] = mod_symbs[q][(((i<<2)+l)<<1)+1];
          }
    break;

  default:
Guy De Souza's avatar
Guy De Souza committed
185
  AssertFatal(0, "Invalid number of layers %d\n", n_layers);
186
187
188
  }
}

Guy De Souza's avatar
Guy De Souza committed
189
190
191
192
193
static inline uint16_t get_pdsch_dmrs_idx(uint8_t n, uint8_t k_prime, uint8_t delta, uint8_t dmrs_type) {
  uint16_t dmrs_idx = (dmrs_type)? (6*n+k_prime+delta):((n<<2)+(k_prime<<1)+delta);
  return dmrs_idx;
}

194
195
uint8_t nr_generate_pdsch(NR_gNB_DLSCH_t dlsch,
                          NR_gNB_DCI_ALLOC_t dci_alloc,
Guy De Souza's avatar
Guy De Souza committed
196
                          uint32_t ***pdsch_dmrs,
197
198
                          int32_t** txdataF,
                          int16_t amp,
199
                          uint8_t slot,
200
201
202
                          NR_DL_FRAME_PARMS frame_parms,
                          nfapi_nr_config_request_t config) {

Guy De Souza's avatar
Guy De Souza committed
203
204
205
  NR_DL_gNB_HARQ_t *harq = dlsch.harq_processes[dci_alloc.harq_pid];
  nfapi_nr_dl_config_dlsch_pdu_rel15_t *rel15 = &harq->dlsch_pdu.dlsch_pdu_rel15;
  nfapi_nr_dl_config_pdcch_parameters_rel15_t pdcch_params = dci_alloc.pdcch_params;
Guy De Souza's avatar
Guy De Souza committed
206
  uint32_t scrambled_output[NR_MAX_NB_CODEWORDS][NR_MAX_PDSCH_ENCODED_LENGTH>>5];
Guy De Souza's avatar
Guy De Souza committed
207
208
  int16_t **mod_symbs = (int16_t**)dlsch.mod_symbs;
  int16_t **tx_layers = (int16_t**)dlsch.txdataF;
209
210
  int8_t Wf[2], Wt[2], l0, l_prime[2], delta;
  uint16_t nb_symbols = rel15->nb_mod_symbols;
Guy De Souza's avatar
Guy De Souza committed
211
  uint8_t Qm = rel15->modulation_order;
212
  uint16_t encoded_length = nb_symbols*Qm;
Guy De Souza's avatar
Guy De Souza committed
213
214

  /// CRC, coding, interleaving and rate matching
215
  nr_dlsch_encoding(harq->pdu, slot, &dlsch, &frame_parms);
Guy De Souza's avatar
Guy De Souza committed
216
217
#ifdef DEBUG_DLSCH
printf("PDSCH encoding:\nPayload:\n");
218
for (int i=0; i<harq->B>>7; i++) {
Guy De Souza's avatar
Guy De Souza committed
219
220
221
222
223
  for (int j=0; j<16; j++)
    printf("0x%02x\t", harq->pdu[(i<<4)+j]);
  printf("\n");
}
printf("\nEncoded payload:\n");
Guy De Souza's avatar
Guy De Souza committed
224
225
226
227
for (int i=0; i<encoded_length>>3; i++) {
  for (int j=0; j<8; j++)
    printf("%d", harq->f[(i<<3)+j]);
  printf("\t");
Guy De Souza's avatar
Guy De Souza committed
228
}
Guy De Souza's avatar
Guy De Souza committed
229
printf("\n");
Guy De Souza's avatar
Guy De Souza committed
230
#endif
Guy De Souza's avatar
Guy De Souza committed
231
232

  /// scrambling
Guy De Souza's avatar
Guy De Souza committed
233
234
  for (int q=0; q<rel15->nb_codewords; q++)
    memset((void*)scrambled_output[q], 0, (encoded_length>>5)*sizeof(uint32_t));
Guy De Souza's avatar
Guy De Souza committed
235
236
237
238
239
  uint16_t n_RNTI = (pdcch_params.search_space_type == NFAPI_NR_SEARCH_SPACE_TYPE_UE_SPECIFIC)? \
  ((pdcch_params.scrambling_id)?pdcch_params.rnti:0) : 0;
  uint16_t Nid = (pdcch_params.search_space_type == NFAPI_NR_SEARCH_SPACE_TYPE_UE_SPECIFIC)? \
  pdcch_params.scrambling_id : config.sch_config.physical_cell_id.value;
  for (int q=0; q<rel15->nb_codewords; q++)
Guy De Souza's avatar
Guy De Souza committed
240
    nr_pdsch_codeword_scrambling(harq->f,
241
                         encoded_length,
Guy De Souza's avatar
Guy De Souza committed
242
243
244
245
                         q,
                         Nid,
                         n_RNTI,
                         scrambled_output[q]);
Guy De Souza's avatar
Guy De Souza committed
246
#ifdef DEBUG_DLSCH
Guy De Souza's avatar
Guy De Souza committed
247
printf("PDSCH scrambling:\n");
Guy De Souza's avatar
Guy De Souza committed
248
for (int i=0; i<encoded_length>>8; i++) {
Guy De Souza's avatar
Guy De Souza committed
249
250
251
252
  for (int j=0; j<8; j++)
    printf("0x%08x\t", scrambled_output[0][(i<<3)+j]);
  printf("\n");
}
Guy De Souza's avatar
Guy De Souza committed
253
#endif
Guy De Souza's avatar
Guy De Souza committed
254
255
 
  /// Modulation
Guy De Souza's avatar
Guy De Souza committed
256
  for (int q=0; q<rel15->nb_codewords; q++)
Guy De Souza's avatar
Guy De Souza committed
257
    nr_pdsch_codeword_modulation(scrambled_output[q],
Guy De Souza's avatar
Guy De Souza committed
258
                         Qm,
259
                         encoded_length,
Guy De Souza's avatar
Guy De Souza committed
260
                         mod_symbs[q]);
Guy De Souza's avatar
Guy De Souza committed
261
#ifdef DEBUG_DLSCH
Guy De Souza's avatar
Guy De Souza committed
262
printf("PDSCH Modulation: Qm %d(%d)\n", Qm, nb_symbols);
263
for (int i=0; i<nb_symbols>>3; i++) {
Guy De Souza's avatar
Guy De Souza committed
264
265
  for (int j=0; j<8; j++) {
    printf("%d %d\t", mod_symbs[0][((i<<3)+j)<<1], mod_symbs[0][(((i<<3)+j)<<1)+1]);
Guy De Souza's avatar
Guy De Souza committed
266
  }
Guy De Souza's avatar
Guy De Souza committed
267
268
  printf("\n");
}
Guy De Souza's avatar
Guy De Souza committed
269
270
#endif

Guy De Souza's avatar
Guy De Souza committed
271
272

  /// Layer mapping
Guy De Souza's avatar
Guy De Souza committed
273
  nr_pdsch_layer_mapping(mod_symbs,
Guy De Souza's avatar
Guy De Souza committed
274
                         rel15->nb_layers,
275
                         nb_symbols,
Guy De Souza's avatar
Guy De Souza committed
276
                         tx_layers);
Guy De Souza's avatar
Guy De Souza committed
277
278
279
#ifdef DEBUG_DLSCH
printf("Layer mapping (%d layers):\n", rel15->nb_layers);
for (int l=0; l<rel15->nb_layers; l++)
Guy De Souza's avatar
Guy De Souza committed
280
  for (int i=0; i<(nb_symbols/rel15->nb_layers)>>3; i++) {
Guy De Souza's avatar
Guy De Souza committed
281
282
283
284
285
286
    for (int j=0; j<8; j++) {
      printf("%d %d\t", tx_layers[l][((i<<3)+j)<<1], tx_layers[l][(((i<<3)+j)<<1)+1]);
    }
    printf("\n");
  }
#endif
Guy De Souza's avatar
Guy De Souza committed
287

Guy De Souza's avatar
Guy De Souza committed
288
289
290
291
  /// Antenna port mapping
    //to be moved to init phase potentially, for now tx_layers 1-8 are mapped on antenna ports 1000-1007

  /// DMRS QPSK modulation
Guy De Souza's avatar
Guy De Souza committed
292
  uint16_t n_dmrs = (rel15->n_prb*rel15->nb_re_dmrs)<<1;
293
  int16_t mod_dmrs[n_dmrs<<1];
Guy De Souza's avatar
Guy De Souza committed
294
  uint8_t dmrs_type = config.pdsch_config.dmrs_type.value;
Guy De Souza's avatar
Guy De Souza committed
295
  l0 = get_l0(dmrs_type, 2);//config.pdsch_config.dmrs_typeA_position.value);
Guy De Souza's avatar
Guy De Souza committed
296
  nr_modulation(pdsch_dmrs[l0][0], n_dmrs, MOD_QPSK, mod_dmrs); // currently only codeword 0 is modulated
297
#ifdef DEBUG_DLSCH
298
299
printf("DMRS modulation (single symbol %d, %d symbols, type %d):\n", l0, n_dmrs>>1, dmrs_type);
for (int i=0; i<n_dmrs>>4; i++) {
Guy De Souza's avatar
Guy De Souza committed
300
301
302
303
304
  for (int j=0; j<8; j++) {
    printf("%d %d\t", mod_dmrs[((i<<3)+j)<<1], mod_dmrs[(((i<<3)+j)<<1)+1]);
  }
  printf("\n");
}
305
#endif
Guy De Souza's avatar
Guy De Souza committed
306
307

  /// Resource mapping
308

Guy De Souza's avatar
Guy De Souza committed
309
310

    // Non interleaved VRB to PRB mapping
311
312
313
 uint16_t start_sc = frame_parms.first_carrier_offset + rel15->start_prb*NR_NB_SC_PER_RB;
 if (start_sc >= frame_parms.ofdm_symbol_size)
   start_sc -= frame_parms.ofdm_symbol_size;
Guy De Souza's avatar
Guy De Souza committed
314

Guy De Souza's avatar
Guy De Souza committed
315
#ifdef DEBUG_DLSCH_MAPPING
316
317
 printf("PDSCH resource mapping started (start SC %d\tstart symbol %d\tN_PRB %d\tnb_symbols %d)\n",
	start_sc, rel15->start_symbol, rel15->n_prb, rel15->nb_symbols);
Guy De Souza's avatar
Guy De Souza committed
318
319
#endif

Guy De Souza's avatar
Guy De Souza committed
320
321
322
  for (int ap=0; ap<rel15->nb_layers; ap++) {

    // DMRS params for this ap
323
324
    get_Wt(Wt, ap, dmrs_type);
    get_Wf(Wf, ap, dmrs_type);
Guy De Souza's avatar
Guy De Souza committed
325
    delta = get_delta(ap, dmrs_type);
326
    l_prime[0] = 0; // single symbol ap 0
Guy De Souza's avatar
Guy De Souza committed
327
    uint8_t dmrs_symbol = l0+l_prime[0];
Guy De Souza's avatar
Guy De Souza committed
328
#ifdef DEBUG_DLSCH_MAPPING
329
330
printf("DMRS params for ap %d: Wt %d %d \t Wf %d %d \t delta %d \t l_prime %d \t l0 %d\tDMRS symbol %d\n",
ap, Wt[0], Wt[1], Wf[0], Wf[1], delta, l_prime[0], l0, dmrs_symbol);
Guy De Souza's avatar
Guy De Souza committed
331
#endif
Guy De Souza's avatar
Guy De Souza committed
332
    uint8_t k_prime=0;
333
334
335
336
337
    uint16_t m=0, n=0, dmrs_idx=0, k=0;

    for (int l=rel15->start_symbol; l<rel15->start_symbol+rel15->nb_symbols; l++) {
      k = start_sc;
      for (int i=0; i<rel15->n_prb*NR_NB_SC_PER_RB; i++) {
Guy De Souza's avatar
Guy De Souza committed
338
339
340
        if ((l == dmrs_symbol) && (k == ((start_sc+get_pdsch_dmrs_idx(n, k_prime, delta, dmrs_type))%(frame_parms.ofdm_symbol_size)))) {
          ((int16_t*)txdataF[ap])[(l*frame_parms.ofdm_symbol_size + k)<<1] = (Wt[l_prime[0]]*Wf[k_prime]*amp*mod_dmrs[dmrs_idx<<1]) >> 15;
          ((int16_t*)txdataF[ap])[((l*frame_parms.ofdm_symbol_size + k)<<1) + 1] = (Wt[l_prime[0]]*Wf[k_prime]*amp*mod_dmrs[(dmrs_idx<<1) + 1]) >> 15;
Guy De Souza's avatar
Guy De Souza committed
341
#ifdef DEBUG_DLSCH_MAPPING
Guy De Souza's avatar
Guy De Souza committed
342
printf("dmrs_idx %d\t l %d \t k %d \t k_prime %d \t n %d \t txdataF: %d %d\n",
343
344
dmrs_idx, l, k, k_prime, n, ((int16_t*)txdataF[ap])[(l*frame_parms.ofdm_symbol_size + k)<<1],
((int16_t*)txdataF[ap])[((l*frame_parms.ofdm_symbol_size + k)<<1) + 1]);
Guy De Souza's avatar
Guy De Souza committed
345
#endif
346
347
348
          dmrs_idx++;
          k_prime++;
          k_prime&=1;
Guy De Souza's avatar
Guy De Souza committed
349
          n+=(k_prime)?0:1;
Guy De Souza's avatar
Guy De Souza committed
350
351
        }

Guy De Souza's avatar
Guy De Souza committed
352
353
        else {

Guy De Souza's avatar
Guy De Souza committed
354
355
          ((int16_t*)txdataF[ap])[(l*frame_parms.ofdm_symbol_size + k)<<1] = (amp * tx_layers[ap][m<<1]) >> 15;
          ((int16_t*)txdataF[ap])[((l*frame_parms.ofdm_symbol_size + k)<<1) + 1] = (amp * tx_layers[ap][(m<<1) + 1]) >> 15;
Guy De Souza's avatar
Guy De Souza committed
356
#ifdef DEBUG_DLSCH_MAPPING
Guy De Souza's avatar
Guy De Souza committed
357
printf("m %d\t l %d \t k %d \t txdataF: %d %d\n",
358
359
m, l, k, ((int16_t*)txdataF[ap])[(l*frame_parms.ofdm_symbol_size + k)<<1],
((int16_t*)txdataF[ap])[((l*frame_parms.ofdm_symbol_size + k)<<1) + 1]);
Guy De Souza's avatar
Guy De Souza committed
360
#endif
Guy De Souza's avatar
Guy De Souza committed
361
362
          m++;
        }
363
364
        if (++k >= frame_parms.ofdm_symbol_size)
          k -= frame_parms.ofdm_symbol_size;
Guy De Souza's avatar
Guy De Souza committed
365
      }
366
    }
Guy De Souza's avatar
Guy De Souza committed
367
  }
368
369
  return 0;
}