mirror of
https://gitlab.eurecom.fr/oai/openairinterface5g.git
synced 2026-07-13 04:30:28 +00:00
Compare commits
29 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
1617c32e3c | ||
|
|
ae780bae57 | ||
|
|
2834088ea0 | ||
|
|
0b320c8dce | ||
|
|
9fc066394e | ||
|
|
04ce714f37 | ||
|
|
d420f8c123 | ||
|
|
e92dfe2f93 | ||
|
|
35965a1418 | ||
|
|
103c1d48e3 | ||
|
|
0755086cc2 | ||
|
|
c8ff0819f8 | ||
|
|
ee4018b5d0 | ||
|
|
49e6575910 | ||
|
|
79ebf23a80 | ||
|
|
3cbf0927be | ||
|
|
6c534c3b76 | ||
|
|
b5e0cf6a2b | ||
|
|
4d67a6e513 | ||
|
|
ced388a0f4 | ||
|
|
134d750a88 | ||
|
|
13963ba70d | ||
|
|
28c1634fdd | ||
|
|
ec171483e9 | ||
|
|
d75b8963ab | ||
|
|
3329877914 | ||
|
|
0538ea4937 | ||
|
|
b5aa2d87fb | ||
|
|
58f00921c8 |
@@ -1,6 +1,6 @@
|
||||
<!-- SPDX-License-Identifier: CC-BY-4.0 -->
|
||||
|
||||
# Contributing to OpenAirInterface #
|
||||
# Contributing to OpenAirInterface
|
||||
|
||||
We want to make contributing to this project as easy and transparent as possible.
|
||||
|
||||
@@ -11,10 +11,10 @@ Please refer to the steps described on our website: [How to contribute to OAI](h
|
||||
if you do not have any.
|
||||
- We recommend that you register with a professional or student email address.
|
||||
- If your email domain (`@domain.com`) is not whitelisted, please contact us
|
||||
(mailto:contact@openairinterface.org).
|
||||
(mailto:oaicicdteam@openairinterface.org).
|
||||
- Eurecom GitLab does NOT accept public email domains.
|
||||
3. Provide the OAI team with the **username** of this account to
|
||||
(mailto:contact@openairinterface.org) ; we will give you the developer
|
||||
(mailto:oaicicdteam@openairinterface.org) ; we will give you the developer
|
||||
rights on this repository.
|
||||
4. The contributing policies are described in the [corresponding documentation
|
||||
page](doc/code-style-contrib.md).
|
||||
@@ -24,8 +24,43 @@ Please refer to the steps described on our website: [How to contribute to OAI](h
|
||||
request from a forked repository.
|
||||
* This decision was made for the license reasons.
|
||||
* The Continuous Integration will reject your merge request.
|
||||
5. Mandatory signing of all the commits using the email address used for CLA.
|
||||
|
||||
# License #
|
||||
## Commit Guidelines
|
||||
|
||||
### Signing Commits
|
||||
|
||||
To sign commits:
|
||||
|
||||
You can also get the verified label
|
||||
on your commits via using [SSH KEYS or GPG KEYS](https://docs.gitlab.com/user/project/repository/signed_commits/)
|
||||
|
||||
```
|
||||
# Edit .git/config in the git repository you are working on
|
||||
# Add the user section
|
||||
[user]
|
||||
name = YOUR NAME
|
||||
email = YOUR EMAIL ADDRESS
|
||||
|
||||
# If you use a signing key, use the below configuration instead
|
||||
[user]
|
||||
name = YOUR NAME
|
||||
email = YOUR EMAIL ADDRESS
|
||||
signingkey = LOCATION OF SSH KEYS or GPG KEY
|
||||
|
||||
[gpg]
|
||||
format = ssh
|
||||
|
||||
[commit]
|
||||
gpgsign = true
|
||||
```
|
||||
|
||||
> **NOTE:** If your commits are not signed the CI framework will not accept the MR.
|
||||
|
||||
For more information regarding contribution guidelines
|
||||
please check [this document](doc/code-style-contrib.md)
|
||||
|
||||
## License
|
||||
|
||||
By contributing to OpenAirInterface, you agree that your contributions will be
|
||||
licensed under
|
||||
|
||||
@@ -89,6 +89,19 @@ pipeline {
|
||||
echo "GitLab Usermail is ${gitCommitAuthorEmailAddr}"
|
||||
// GitLab-Jenkins plugin integration is lacking to perform the merge by itself
|
||||
// Doing it manually --> it may have merge conflicts
|
||||
|
||||
// Validate MR commits: checks for missing Signed-off-by and merge commits
|
||||
def mrValidationLog = "signedCommit_${env.BUILD_NUMBER}.log"
|
||||
def mrValidationExitCode = sh(
|
||||
script: "bash ./ci-scripts/pre-ci-check.sh -s origin/${env.gitlabSourceBranch} -t origin/${env.gitlabTargetBranch} > ${mrValidationLog} 2>&1",
|
||||
returnStatus: true
|
||||
)
|
||||
def mrValidationMessage = readFile(mrValidationLog).trim()
|
||||
sh "rm -f ${mrValidationLog}"
|
||||
addGitLabMRComment comment: "${mrValidationMessage}"
|
||||
if (mrValidationExitCode >= 2) {
|
||||
error("${mrValidationMessage}")
|
||||
}
|
||||
sh "./ci-scripts/doGitLabMerge.sh --src-branch ${env.gitlabSourceBranch} --src-commit ${env.gitlabMergeRequestLastCommit} --target-branch ${env.gitlabTargetBranch} --target-commit ${GIT_COMMIT}"
|
||||
} else {
|
||||
echo "Git Branch is ${GIT_BRANCH}"
|
||||
|
||||
@@ -70,7 +70,7 @@ gNBs =
|
||||
initialULBWPsubcarrierSpacing = 3;
|
||||
#rach-ConfigCommon
|
||||
#rach-ConfigGeneric
|
||||
prach_ConfigurationIndex = 52;
|
||||
prach_ConfigurationIndex = 70;
|
||||
#prach_msg1_FDM
|
||||
#0 = one, 1=two, 2=four, 3=eight
|
||||
prach_msg1_FDM = 0;
|
||||
@@ -112,7 +112,7 @@ gNBs =
|
||||
hoppingId = 40;
|
||||
p0_nominal = -90;
|
||||
|
||||
ssb_PositionsInBurst_Bitmap = 1;
|
||||
ssb_PositionsInBurst_Bitmap = 85;
|
||||
|
||||
# ssb_periodicityServingCell
|
||||
# 0 = ms5, 1=ms10, 2=ms20, 3=ms40, 4=ms80, 5=ms160, 6=spare2, 7=spare1
|
||||
@@ -179,7 +179,7 @@ MACRLCs = ({
|
||||
set_analog_beamforming = "lophy";
|
||||
beam_duration = 1;
|
||||
beams_per_period = 1;
|
||||
beam_weights = [0]; // single SSB -> one analog beam
|
||||
beam_weights = [0, 1, 2, 3]; // 4 SSBs -> 4 analog beams
|
||||
});
|
||||
|
||||
L1s = (
|
||||
|
||||
94
ci-scripts/pre-ci-check.sh
Executable file
94
ci-scripts/pre-ci-check.sh
Executable file
@@ -0,0 +1,94 @@
|
||||
#!/bin/bash
|
||||
# SPDX-License-Identifier: LicenseRef-CSSL-1.0
|
||||
|
||||
function usage {
|
||||
echo "OAI GitLab MR validation script (Signed-off-by and merge commits)"
|
||||
echo ""
|
||||
echo "Usage:"
|
||||
echo "------"
|
||||
echo " $0 -s <source-branch> -t <target-branch>"
|
||||
echo ""
|
||||
echo "Options:"
|
||||
echo "--------"
|
||||
echo " -s"
|
||||
echo " The source branch of the merge request. Default value is current Git Branch (HEAD)"
|
||||
echo ""
|
||||
echo " -t"
|
||||
echo " The target branch of the merge request. Default value is develop"
|
||||
echo ""
|
||||
echo " -h"
|
||||
echo " Print this help message."
|
||||
echo ""
|
||||
}
|
||||
|
||||
# Parse arguments properly
|
||||
SOURCE_BRANCH=$(git rev-parse --abbrev-ref HEAD)
|
||||
TARGET_BRANCH="origin/develop"
|
||||
|
||||
git fetch --quiet
|
||||
|
||||
while getopts ":s:t:h" opt; do
|
||||
case "$opt" in
|
||||
s)
|
||||
SOURCE_BRANCH="$OPTARG"
|
||||
;;
|
||||
t)
|
||||
TARGET_BRANCH="$OPTARG"
|
||||
;;
|
||||
h)
|
||||
usage
|
||||
exit 0
|
||||
;;
|
||||
:)
|
||||
echo "Error: Option -$OPTARG requires a value."
|
||||
echo ""
|
||||
usage
|
||||
exit 2
|
||||
;;
|
||||
\?)
|
||||
echo "Error: Invalid option -$OPTARG"
|
||||
echo ""
|
||||
usage
|
||||
exit 2
|
||||
;;
|
||||
esac
|
||||
done
|
||||
|
||||
# ----------------------------
|
||||
# Merged commits
|
||||
# ----------------------------
|
||||
mergeCommits=$(git rev-list --merges --abbrev-commit "$TARGET_BRANCH".."$SOURCE_BRANCH")
|
||||
if [[ -n "$mergeCommits" ]]; then
|
||||
message="> ERROR: Following merge commits are found in the source branch history. Please rebase your branch.\n>\n"
|
||||
message+="> $(echo "$mergeCommits" | paste -sd ',' -)\n"
|
||||
echo -e "$message"
|
||||
exit 3
|
||||
fi
|
||||
|
||||
# ----------------------------
|
||||
# Check unsigned commits
|
||||
# ----------------------------
|
||||
unsignedCommits=$(
|
||||
for c in $(git rev-list "$TARGET_BRANCH".."$SOURCE_BRANCH"); do
|
||||
if ! git log -1 --format=%B "$c" | grep -q "Signed-off-by:"; then
|
||||
git log -1 --format='%h' "$c"
|
||||
fi
|
||||
done | paste -sd ","
|
||||
)
|
||||
|
||||
# ----------------------------
|
||||
# Report unsigned commits
|
||||
# ----------------------------
|
||||
message=""
|
||||
|
||||
if [ -n "$unsignedCommits" ]; then
|
||||
message="> WARNING: The following commit(s) are missing a Signed-off-by:\n>\n> $unsignedCommits\n>\n"
|
||||
message+="> Please use 'git commit -s' to sign your commits.\n>\n"
|
||||
message+="> For detailed instructions, refer to the CONTRIBUTING file at the root of this repository."
|
||||
echo -e "$message"
|
||||
exit 1
|
||||
else
|
||||
message="> All commits are signed off using 'git commit -s'."
|
||||
echo -e "$message"
|
||||
exit 0
|
||||
fi
|
||||
@@ -99,6 +99,7 @@ services:
|
||||
- ALL
|
||||
environment:
|
||||
USE_ADDITIONAL_OPTIONS: --rfsim --log_config.global_log_options level,nocolor,time
|
||||
--rfsimulator.[0].enable_beams --rfsimulator.[0].beam_gains 0,-20,-30,-40
|
||||
ASAN_OPTIONS: detect_leaks=0
|
||||
networks:
|
||||
public_net:
|
||||
@@ -125,6 +126,7 @@ services:
|
||||
USE_ADDITIONAL_OPTIONS: --rfsim
|
||||
--rfsimulator.[0].serveraddr 192.168.71.140 --log_config.global_log_options level,nocolor,time
|
||||
-C 27975360000 -r 66 --numerology 3 --ssb 48 --band 257
|
||||
--rfsimulator.[0].enable_beams --rfsimulator.[0].beam_gains 0,-20,-30,-40 --rfsimulator.[0].beam_ids 2
|
||||
ASAN_OPTIONS: detect_leaks=0
|
||||
devices:
|
||||
- /dev/net/tun:/dev/net/tun
|
||||
|
||||
@@ -18,7 +18,7 @@ HWs=""
|
||||
BUILD_DIR=ran_build
|
||||
CMAKE_BUILD_TYPE="RelWithDebInfo"
|
||||
CMAKE_CMD="$CMAKE"
|
||||
OPTIONAL_LIBRARIES="telnetsrv enbscope uescope nrscope ldpc_aal ldpc_xdma websrv oai_iqplayer imscope imscope_record"
|
||||
OPTIONAL_LIBRARIES="telnetsrv enbscope uescope nrscope ldpc_aal websrv oai_iqplayer imscope imscope_record"
|
||||
TARGET_LIST=""
|
||||
BUILD_TOOL_OPT="-j$(nproc)"
|
||||
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
|
||||
#include "spsc_q.h"
|
||||
|
||||
spsc_q_t spsc_q_alloc(size_t cnt, size_t elsiz)
|
||||
bool spsc_q_alloc(spsc_q_t *rbn, size_t cnt, size_t elsiz)
|
||||
{
|
||||
/* internally, use one element more: the ringbuffer is full if
|
||||
* (write_idx + 1) % cnt == read_idx, so it's full if one element is still
|
||||
@@ -17,7 +17,8 @@ spsc_q_t spsc_q_alloc(size_t cnt, size_t elsiz)
|
||||
cnt += 1;
|
||||
spsc_q_t rb = {.cnt = cnt, .elsiz = elsiz};
|
||||
rb.buf = calloc(cnt, elsiz);
|
||||
return rb;
|
||||
*rbn = rb;
|
||||
return rb.buf != NULL;
|
||||
}
|
||||
|
||||
void spsc_q_free(spsc_q_t *rb)
|
||||
|
||||
@@ -25,7 +25,7 @@ typedef struct spsc_q {
|
||||
atomic_size_t read_idx;
|
||||
} spsc_q_t;
|
||||
|
||||
spsc_q_t spsc_q_alloc(size_t cnt, size_t elsiz);
|
||||
bool spsc_q_alloc(spsc_q_t *rbn, size_t cnt, size_t elsiz);
|
||||
void spsc_q_free(spsc_q_t *rb);
|
||||
|
||||
bool spsc_q_put(spsc_q_t *rb, const void *src, size_t elsiz);
|
||||
|
||||
@@ -8,7 +8,8 @@ extern "C" {
|
||||
}
|
||||
|
||||
TEST(spsc_q, basic_test) {
|
||||
spsc_q_t rb = spsc_q_alloc(2, sizeof(int));
|
||||
spsc_q_t rb;
|
||||
EXPECT_TRUE(spsc_q_alloc(&rb, 2, sizeof(int)));
|
||||
|
||||
int a = 1;
|
||||
EXPECT_TRUE(spsc_q_put(&rb, &a, sizeof(a)));
|
||||
@@ -26,7 +27,8 @@ TEST(spsc_q, basic_test) {
|
||||
}
|
||||
|
||||
TEST(spsc_q, cont_write) {
|
||||
spsc_q_t rb = spsc_q_alloc(10, sizeof(int));
|
||||
spsc_q_t rb;
|
||||
EXPECT_TRUE(spsc_q_alloc(&rb, 10, sizeof(int)));
|
||||
|
||||
int a = 1;
|
||||
for (int i = 0; i < 1111; ++i) {
|
||||
@@ -57,7 +59,8 @@ bool count(const void *data, void *user)
|
||||
return true; /* count all */
|
||||
}
|
||||
TEST(spsc_q, iterator) {
|
||||
spsc_q_t rb = spsc_q_alloc(10, sizeof(int));
|
||||
spsc_q_t rb;
|
||||
EXPECT_TRUE(spsc_q_alloc(&rb, 10, sizeof(int)));
|
||||
int n = 8;
|
||||
for (int i = 0; i < n; ++i)
|
||||
EXPECT_TRUE(spsc_q_put(&rb, &i, sizeof(i)));
|
||||
@@ -85,7 +88,8 @@ bool drop(const void *data, void *user)
|
||||
return true; /* drop all */
|
||||
}
|
||||
TEST(spsc_q, drop) {
|
||||
spsc_q_t rb = spsc_q_alloc(10, sizeof(int));
|
||||
spsc_q_t rb;
|
||||
EXPECT_TRUE(spsc_q_alloc(&rb, 10, sizeof(int)));
|
||||
int n = 8;
|
||||
for (int i = 0; i < n; ++i)
|
||||
EXPECT_TRUE(spsc_q_put(&rb, &i, sizeof(i)));
|
||||
@@ -104,7 +108,8 @@ TEST(spsc_q, drop) {
|
||||
|
||||
TEST(spsc_q, full) {
|
||||
int n = 3;
|
||||
spsc_q_t rb = spsc_q_alloc(n, sizeof(int));
|
||||
spsc_q_t rb;
|
||||
EXPECT_TRUE(spsc_q_alloc(&rb, n, sizeof(int)));
|
||||
int a = 1;
|
||||
EXPECT_TRUE(spsc_q_put(&rb, &a, sizeof(a)));
|
||||
a++;
|
||||
|
||||
@@ -1,163 +0,0 @@
|
||||
<!-- SPDX-License-Identifier: CC-BY-4.0 -->
|
||||
|
||||
# LDPC offload with the XDMA driver
|
||||
|
||||
[TOC]
|
||||
|
||||
This documentation aims to provide a tutorial for using Xilinx PCIe-XDMA based FPGA LDPC decoding within OAI. LDPC decoding is offloaded to FPGA.
|
||||
|
||||
## XDMA Driver Build & Install
|
||||
|
||||
- Get XDMA driver source
|
||||
```bash
|
||||
git clone https://github.com/Xilinx/dma_ip_drivers.git
|
||||
cd dma_ip_drivers/XDMA/linux-kernel
|
||||
```
|
||||
The *xdma_driver* directory contains the following:
|
||||
|
||||
```bash
|
||||
dma_ip_drivers/XDMA/linux-kernel/
|
||||
├── COPYING
|
||||
├── include
|
||||
├── LICENSE
|
||||
├── readme.txt
|
||||
├── RELEASE
|
||||
├── tests
|
||||
├── tools
|
||||
└── xdma
|
||||
```
|
||||
|
||||
Before building the driver, ensure that your system recognizes the Xilinx device. You can check this using the `lspci` command:
|
||||
|
||||
```bash
|
||||
$ lspci | grep Xilinx
|
||||
01:00.0 Serial controller: Xilinx Corporation Device 8038
|
||||
```
|
||||
|
||||
Building and Installing the Driver
|
||||
|
||||
```bash
|
||||
cd ~/dma_ip_drivers/XDMA/linux-kernel/xdma
|
||||
make clean
|
||||
make
|
||||
# install to make the driver loading automatically at system startup
|
||||
sudo make install
|
||||
```
|
||||
|
||||
Load the Driver
|
||||
|
||||
```bash
|
||||
cd ~/dma_ip_drivers/XDMA/linux-kernel/tests
|
||||
sudo ./load_driver.sh
|
||||
```
|
||||
|
||||
## OAI Build
|
||||
|
||||
```bash
|
||||
# Get openairinterface5g source code
|
||||
git clone https://gitlab.eurecom.fr/oai/openairinterface5g.git ~/openairinterface5g
|
||||
cd ~/openairinterface5g
|
||||
|
||||
# Install OAI dependencies
|
||||
cd ~/openairinterface5g/cmake_targets
|
||||
./build_oai -I
|
||||
|
||||
# Build OAI gNB & UE
|
||||
cd ~/openairinterface5g
|
||||
source oaienv
|
||||
cd cmake_targets
|
||||
./build_oai --ninja -w SIMU --gNB --nrUE -P --build-lib "ldpc_xdma" -C -c
|
||||
```
|
||||
|
||||
Shared object file *libldpc_xdma.so* is created during the compilation. This object is conditionally compiled. Selection of the library to compile is done using `--build-lib ldpc_xdma`.
|
||||
|
||||
## 5G PHY simulators
|
||||
|
||||
The simulated test uses the option `--loader.ldpc.shlibversion _xdma` to select the XDMA version for loading into the LDPC interface. Additionally, the option `--nrLDPC_coding_xdma.num_threads_prepare` is used to specify the number of threads for preparing data before the LDPC processing, specifically for the deinterleaving and rate matching parts.
|
||||
|
||||
Another way to activate the feature is to add the `xdma.conf` file with the following content:
|
||||
|
||||
```
|
||||
nrLDPC_coding_xdma : {
|
||||
num_threads_prepare : 2;
|
||||
};
|
||||
|
||||
loader : {
|
||||
ldpc : {
|
||||
shlibversion : "_xdma";
|
||||
};
|
||||
};
|
||||
|
||||
```
|
||||
|
||||
and use option `-O xdma.conf`.
|
||||
|
||||
### nr_ulsim test
|
||||
|
||||
Example command for running nr_ulsim with LDPC decoding offload to the FPGA:
|
||||
|
||||
```bash
|
||||
cd ~/openairinterface5g/cmake_targets/ran_build/build
|
||||
sudo ./nr_ulsim -n100 -m28 -r273 -R273 -s22 -I10 -C8 -P --loader.ldpc.shlibversion _xdma --nrLDPC_coding_xdma.num_threads_prepare 2
|
||||
```
|
||||
|
||||
or
|
||||
|
||||
```
|
||||
sudo ./nr_ulsim -n100 -m28 -r273 -R273 -s22 -I10 -C8 -P -O xdma.conf
|
||||
```
|
||||
|
||||
## Run
|
||||
|
||||
Both gNB and nrUE use the option `--loader.ldpc.shlibversion _xdma` to select the XDMA version for loading into the LDPC interface and `--nrLDPC_coding_xdma.num_threads_prepare` to specify the number of threads for preparing data before the LDPC processing, specifically for the deinterleaving and rate matching parts.
|
||||
|
||||
Another way to activate the feature is to add the following content to the `.conf` file you want to use:
|
||||
|
||||
```
|
||||
nrLDPC_coding_xdma : {
|
||||
num_threads_prepare : 2;
|
||||
};
|
||||
|
||||
loader : {
|
||||
ldpc : {
|
||||
shlibversion : "_xdma";
|
||||
};
|
||||
};
|
||||
|
||||
```
|
||||
|
||||
and use option `-O *.conf`.
|
||||
|
||||
### gNB
|
||||
|
||||
Example command using rfsim:
|
||||
|
||||
```bash
|
||||
cd ~/openairinterface5g/cmake_targets/ran_build/build
|
||||
sudo ./nr-softmodem --rfsim --log_config.global_log_options level,nocolor,time -O ../../../ci-scripts/conf_files/gnb.sa.band78.106prb.rfsim.conf --loader.ldpc.shlibversion _xdma --nrLDPC_coding_xdma.num_threads_prepare 2
|
||||
```
|
||||
|
||||
or
|
||||
|
||||
```bash
|
||||
sudo ./nr-softmodem --rfsim --log_config.global_log_options level,nocolor,time -O ../../../ci-scripts/conf_files/gnb.sa.band78.106prb.rfsim.conf
|
||||
```
|
||||
|
||||
if you have added the configuration to the `.conf` file.
|
||||
|
||||
### UE
|
||||
|
||||
Example command using rfsim:
|
||||
|
||||
```bash
|
||||
cd ~/openairinterface5g/cmake_targets/ran_build/build
|
||||
sudo ./nr-uesoftmodem --rfsim -r 106 --numerology 1 --band 78 -C 3319680000 --ue-nb-ant-tx 1 --ue-nb-ant-rx 1 -O ../../../ci-scripts/conf_files/nrue1.uicc.cluCN.conf --rfsimulator.[0].serveraddr 10.201.1.100 --loader.ldpc.shlibversion _xdma --nrLDPC_coding_xdma.num_threads_prepare 2
|
||||
```
|
||||
|
||||
or
|
||||
|
||||
```bash
|
||||
sudo ./nr-uesoftmodem --rfsim -r 106 --numerology 1 --band 78 -C 3319680000 --ue-nb-ant-tx 1 --ue-nb-ant-rx 1 -O ../../../ci-scripts/conf_files/nrue1.uicc.cluCN.conf --rfsimulator.[0].serveraddr 10.201.1.100
|
||||
```
|
||||
|
||||
if you have added the configuration to the `.conf` file.
|
||||
@@ -617,9 +617,9 @@ jumboframe 1 # enable jumbo frame
|
||||
|
||||
###### FR2
|
||||
|
||||
The OAI configuration file [`gnb.sa.band257.66prb.fhi72.2x2-liteon.conf`](../targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb.sa.band257.66prb.fhi72.2x2-liteon.conf) corresponds to:
|
||||
- TDD pattern `DDDDDDDSUU`, 1.25ms
|
||||
- Bandwidth 100MHz
|
||||
The OAI configuration file [`gnb.sa.band257.132prb.fhi72.2x2-liteon.conf`](../targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb.sa.band257.132prb.fhi72.2x2-liteon.conf) corresponds to:
|
||||
- TDD pattern `DDDSU`, 0.625ms
|
||||
- Bandwidth 200MHz
|
||||
- FW v02.00.07
|
||||
- DL uses jumbo frame, UL uses standard MTU of 1500 bytes
|
||||
|
||||
|
||||
@@ -92,18 +92,17 @@ static void tx_func(processingData_L1tx_t *info)
|
||||
pushNotifiedFIFO(&gNB->resp_L1, res);
|
||||
|
||||
int tx_slot_type = nr_slot_select(cfg, frame_tx, slot_tx);
|
||||
// TODO check for analog_bf_vendor_ext set to 1 is a workaround while no beam API for beam selection is implemented
|
||||
if (tx_slot_type == NR_DOWNLINK_SLOT || tx_slot_type == NR_MIXED_SLOT || get_softmodem_params()->continuous_tx
|
||||
|| IS_SOFTMODEM_RFSIM || cfg->analog_beamforming_ve.analog_bf_vendor_ext.value) {
|
||||
if (tx_slot_type == NR_DOWNLINK_SLOT || tx_slot_type == NR_MIXED_SLOT || get_softmodem_params()->continuous_tx || IS_SOFTMODEM_RFSIM) {
|
||||
start_meas(&info->gNB->phy_proc_tx);
|
||||
phy_procedures_gNB_TX(info->gNB, &sched_response.DL_req, &sched_response.TX_req, &sched_response.UL_dci_req, frame_tx,slot_tx);
|
||||
|
||||
PHY_VARS_gNB *gNB = info->gNB;
|
||||
processingData_RU_t syncMsgRU;
|
||||
syncMsgRU.frame_tx = frame_tx;
|
||||
syncMsgRU.slot_tx = slot_tx;
|
||||
syncMsgRU.ru = gNB->RU_list[0];
|
||||
syncMsgRU.timestamp_tx = info->timestamp_tx;
|
||||
}
|
||||
processingData_RU_t syncMsgRU;
|
||||
syncMsgRU.frame_tx = frame_tx;
|
||||
syncMsgRU.slot_tx = slot_tx;
|
||||
syncMsgRU.ru = gNB->RU_list[0];
|
||||
syncMsgRU.timestamp_tx = info->timestamp_tx;
|
||||
ru_ctrl_func((void *)&syncMsgRU);
|
||||
if (tx_slot_type == NR_DOWNLINK_SLOT || tx_slot_type == NR_MIXED_SLOT || get_softmodem_params()->continuous_tx || IS_SOFTMODEM_RFSIM) {
|
||||
LOG_D(PHY, "gNB: %d.%d : calling RU TX function\n", syncMsgRU.frame_tx, syncMsgRU.slot_tx);
|
||||
ru_tx_func((void *)&syncMsgRU);
|
||||
stop_meas(&info->gNB->phy_proc_tx);
|
||||
|
||||
@@ -347,17 +347,28 @@ static void rx_rf(RU_t *ru, int *frame, int *slot)
|
||||
AssertFatal(*slot < fp->slots_per_frame && *slot >= 0, "slot %d is illegal (%d)\n", *slot, fp->slots_per_frame);
|
||||
|
||||
start_meas(&ru->rx_fhaul);
|
||||
int nb = ru->nb_rx * ru->num_beams_period;
|
||||
void *rxp[nb];
|
||||
for (int i = 0; i < nb; i++)
|
||||
rxp[i] = (void *)&ru->common.rxdata[i][get_samples_slot_timestamp(fp, *slot)];
|
||||
|
||||
openair0_timestamp_t old_ts = proc->timestamp_rx;
|
||||
LOG_D(PHY,"Reading %d samples for slot %d (%p)\n", samples_per_slot, *slot, rxp[0]);
|
||||
|
||||
openair0_timestamp_t ts;
|
||||
unsigned int rxs;
|
||||
rxs = ru->rfdevice.trx_read_func(&ru->rfdevice, &ts, rxp, samples_per_slot, nb);
|
||||
metadata mt = {.slot = *slot, .frame = *frame};
|
||||
if (ru->num_beams_period > 1) {
|
||||
void *rxp_flat[ru->num_beams_period * ru->nb_rx];
|
||||
void **rxp[ru->num_beams_period];
|
||||
for (int j = 0; j < ru->num_beams_period; j++) {
|
||||
for (int i = 0; i < ru->nb_rx; i++)
|
||||
rxp_flat[i + j * ru->nb_rx] = (void *)&ru->common.rxdata[i + j * ru->nb_rx][get_samples_slot_timestamp(fp, *slot)];
|
||||
rxp[j] = &rxp_flat[j * ru->nb_rx];
|
||||
}
|
||||
rxs = ru->rfdevice.trx_read_beams_func(&ru->rfdevice, &ts, (void ***)rxp, samples_per_slot, ru->nb_rx, ru->num_beams_period);
|
||||
gNBscopeCopyWithMetadata(ru, gNbTimeDomainSamples, rxp[0][0], sizeof(c16_t), 1, samples_per_slot, 0, &mt);
|
||||
} else {
|
||||
void *rxp[ru->nb_rx];
|
||||
for (int i = 0; i < ru->nb_rx; i++)
|
||||
rxp[i] = (void *)&ru->common.rxdata[i][get_samples_slot_timestamp(fp, *slot)];
|
||||
rxs = ru->rfdevice.trx_read_func(&ru->rfdevice, &ts, rxp, samples_per_slot, ru->nb_rx);
|
||||
gNBscopeCopyWithMetadata(ru, gNbTimeDomainSamples, rxp[0], sizeof(c16_t), 1, samples_per_slot, 0, &mt);
|
||||
}
|
||||
|
||||
proc->timestamp_rx = ts-ru->ts_offset;
|
||||
|
||||
if (rxs != samples_per_slot)
|
||||
@@ -422,17 +433,28 @@ static void rx_rf(RU_t *ru, int *frame, int *slot)
|
||||
proc->first_rx = 0;
|
||||
*frame = proc->frame_rx;
|
||||
*slot = proc->tti_rx;
|
||||
samples_per_slot = get_samples_per_slot(*slot, fp); // slot number might change depending on the timestamp
|
||||
|
||||
// Align to slot boundary
|
||||
uint64_t samples_to_slot_boundary = 0;
|
||||
uint64_t sample_offset_within_frame = proc->timestamp_rx % fp->samples_per_frame;
|
||||
uint64_t sample_offset_within_slot = sample_offset_within_frame - get_samples_slot_timestamp(fp, *slot);
|
||||
if (sample_offset_within_slot > 0) {
|
||||
samples_to_slot_boundary = get_samples_per_slot(*slot, fp) - sample_offset_within_slot;
|
||||
samples_to_slot_boundary = samples_per_slot - sample_offset_within_slot;
|
||||
LOG_A(NR_PHY, "Aligning to the slot boundary %lu\n", samples_to_slot_boundary);
|
||||
|
||||
// Read and discard the samples in the first_rx to align to the slot boundary
|
||||
rxs = ru->rfdevice.trx_read_func(&ru->rfdevice, &ts, rxp, samples_to_slot_boundary, nb);
|
||||
if (ru->num_beams_period > 1) {
|
||||
void *rxp_skip_b[ru->num_beams_period][ru->nb_rx];
|
||||
rxs = ru->rfdevice.trx_read_beams_func(&ru->rfdevice,
|
||||
&ts,
|
||||
(void ***)rxp_skip_b,
|
||||
samples_to_slot_boundary,
|
||||
ru->nb_rx,
|
||||
ru->num_beams_period);
|
||||
} else {
|
||||
void *rxp_skip[ru->nb_rx];
|
||||
rxs = ru->rfdevice.trx_read_func(&ru->rfdevice, &ts, rxp_skip, samples_to_slot_boundary, ru->nb_rx);
|
||||
}
|
||||
if (rxs != samples_to_slot_boundary)
|
||||
LOG_E(PHY, "rx_rf: Asked for %ld samples, got %d from USRP\n", samples_to_slot_boundary, rxs);
|
||||
|
||||
@@ -442,64 +464,92 @@ static void rx_rf(RU_t *ru, int *frame, int *slot)
|
||||
*slot = (*slot + 1) % fp->slots_per_frame;
|
||||
}
|
||||
}
|
||||
|
||||
metadata mt = {.slot = *slot, .frame = *frame};
|
||||
gNBscopeCopyWithMetadata(ru, gNbTimeDomainSamples, rxp[0], sizeof(c16_t), 1, samples_per_slot, 0, &mt);
|
||||
|
||||
if (rxs != samples_per_slot) {
|
||||
//exit_fun( "problem receiving samples" );
|
||||
LOG_E(PHY, "problem receiving samples\n");
|
||||
}
|
||||
|
||||
stop_meas(&ru->rx_fhaul);
|
||||
}
|
||||
|
||||
static radio_tx_gpio_flag_t get_gpio_flags(RU_t *ru, int slot)
|
||||
static void ctrl_rf(RU_t *ru, int frame, int slot, uint64_t timestamp)
|
||||
{
|
||||
radio_tx_gpio_flag_t flags_gpio = 0;
|
||||
NR_DL_FRAME_PARMS *fp = ru->nr_frame_parms;
|
||||
openair0_config_t *cfg0 = &ru->openair0_cfg;
|
||||
int num_events = 0;
|
||||
int event_symbol[fp->symbols_per_slot];
|
||||
int event_counts[fp->symbols_per_slot];
|
||||
int beam_events[fp->symbols_per_slot][ru->num_beams_period];
|
||||
|
||||
switch (cfg0->gpio_controller) {
|
||||
case RU_GPIO_CONTROL_GENERIC:
|
||||
// currently we switch beams at the beginning of a slot and we take the beam index of the first symbol of this slot
|
||||
// we only send the beam to the gpio if the beam is different from the previous slot
|
||||
int last_applied_beams[ru->num_beams_period];
|
||||
for (int i = 0; i < ru->num_beams_period; i++)
|
||||
last_applied_beams[i] = -1;
|
||||
|
||||
if (ru->common.beam_id) {
|
||||
int prev_slot = (slot - 1 + fp->slots_per_frame) % fp->slots_per_frame;
|
||||
const int *beam_ids = ru->common.beam_id[0];
|
||||
int prev_beam = beam_ids[prev_slot * fp->symbols_per_slot];
|
||||
int beam = beam_ids[slot * fp->symbols_per_slot];
|
||||
if (prev_beam != beam) {
|
||||
flags_gpio = beam | TX_GPIO_CHANGE; // enable change of gpio
|
||||
LOG_I(HW, "slot %d, beam %d\n", slot, ru->common.beam_id[0][slot * fp->symbols_per_slot]);
|
||||
}
|
||||
}
|
||||
break;
|
||||
int first_available_sym = 0;
|
||||
bool idle_beam = true;
|
||||
for (int j = 0; j < fp->symbols_per_slot; j++) {
|
||||
int current_beams[ru->num_beams_period];
|
||||
int active_count = 0;
|
||||
bool differs = false;
|
||||
|
||||
case RU_GPIO_CONTROL_INTERDIGITAL: {
|
||||
// the beam index is written in bits 8-10 of the flags
|
||||
// bit 11 enables the gpio programming
|
||||
int beam = 0;
|
||||
if ((slot % 10 == 0) && ru->common.beam_id && (ru->common.beam_id[0][slot * fp->symbols_per_slot] < 64)) {
|
||||
// beam = ru->common.beam_id[0][slot*fp->symbols_per_slot] | 64;
|
||||
beam = 1024; // hardcoded now for beam32 boresight
|
||||
// beam = 127; //for the sake of trying beam63
|
||||
LOG_D(HW, "slot %d, beam %d\n", slot, beam);
|
||||
}
|
||||
flags_gpio = beam | TX_GPIO_CHANGE;
|
||||
// flags_gpio |= beam << 8; // MSB 8 bits are used for beam
|
||||
LOG_I(HW, "slot %d, beam %d, flags_gpio %d\n", slot, beam, flags_gpio);
|
||||
break;
|
||||
for (int i = 0; i < ru->num_beams_period; i++) {
|
||||
current_beams[i] = ru->common.beam_id[i][slot * fp->symbols_per_slot + j];
|
||||
if (current_beams[i] != last_applied_beams[i])
|
||||
differs = true;
|
||||
if (current_beams[i] != -1)
|
||||
active_count++;
|
||||
}
|
||||
|
||||
if (active_count > 0) {
|
||||
if (differs) {
|
||||
event_symbol[num_events] = first_available_sym;
|
||||
event_counts[num_events] = 0;
|
||||
for (int i = 0; i < ru->num_beams_period; i++) {
|
||||
if (current_beams[i] != -1) {
|
||||
beam_events[num_events][event_counts[num_events]] = current_beams[i];
|
||||
event_counts[num_events]++;
|
||||
}
|
||||
last_applied_beams[i] = current_beams[i];
|
||||
}
|
||||
num_events++;
|
||||
}
|
||||
idle_beam = false;
|
||||
first_available_sym = j;
|
||||
} else {
|
||||
if (!idle_beam) {
|
||||
first_available_sym = j;
|
||||
idle_beam = true;
|
||||
for (int i = 0; i < ru->num_beams_period; i++)
|
||||
last_applied_beams[i] = -1;
|
||||
}
|
||||
}
|
||||
default:
|
||||
AssertFatal(false, "illegal GPIO controller %d\n", cfg0->gpio_controller);
|
||||
}
|
||||
|
||||
return flags_gpio;
|
||||
nfapi_nr_config_request_scf_t *cfg = &ru->config;
|
||||
uint64_t slot_base_ts = timestamp + ru->ts_offset;
|
||||
if (cfg->cell_config.frame_duplex_type.value == TDD
|
||||
&& nr_slot_select(cfg, frame, slot % fp->slots_per_frame) == NR_DOWNLINK_SLOT
|
||||
&& nr_slot_select(cfg, frame, (slot + fp->slots_per_frame - 1) % fp->slots_per_frame) == NR_UPLINK_SLOT
|
||||
&& !get_softmodem_params()->continuous_tx && !IS_SOFTMODEM_RFSIM) {
|
||||
slot_base_ts -= ru->sf_extension;
|
||||
}
|
||||
|
||||
for (int e = 0; e < num_events; e++) {
|
||||
if (e > 0 && event_symbol[e] == event_symbol[e-1])
|
||||
continue;
|
||||
|
||||
uint64_t symbol_offset = 0;
|
||||
if (event_symbol[e] > 0)
|
||||
symbol_offset = get_samples_symbol_duration(fp, slot, 0, event_symbol[e]);
|
||||
|
||||
uint64_t event_ts = slot_base_ts + symbol_offset;
|
||||
for (int n = 0; n < event_counts[e]; n++)
|
||||
LOG_D(NR_PHY,
|
||||
"RU Control [%d.%d]: Trigger Sym %d, Beam %d at TS %lu\n",
|
||||
frame,
|
||||
slot,
|
||||
event_symbol[e],
|
||||
beam_events[e][n],
|
||||
event_ts);
|
||||
ru->rfdevice.trx_set_beams2(&ru->rfdevice, beam_events[e], event_counts[e], event_ts);
|
||||
}
|
||||
}
|
||||
|
||||
void tx_rf(RU_t *ru, int frame,int slot, uint64_t timestamp)
|
||||
static void tx_rf(RU_t *ru, int frame, int slot, uint64_t timestamp)
|
||||
{
|
||||
RU_proc_t *proc = &ru->proc;
|
||||
NR_DL_FRAME_PARMS *fp = ru->nr_frame_parms;
|
||||
@@ -514,7 +564,6 @@ void tx_rf(RU_t *ru, int frame,int slot, uint64_t timestamp)
|
||||
int sf_extension = 0;
|
||||
int siglen = get_samples_per_slot(slot, fp);
|
||||
radio_tx_burst_flag_t flags_burst = TX_BURST_INVALID;
|
||||
radio_tx_gpio_flag_t flags_gpio = 0;
|
||||
|
||||
if (cfg->cell_config.frame_duplex_type.value == TDD && !get_softmodem_params()->continuous_tx && !IS_SOFTMODEM_RFSIM) {
|
||||
int slot_type = nr_slot_select(cfg,frame,slot%fp->slots_per_frame);
|
||||
@@ -558,24 +607,41 @@ void tx_rf(RU_t *ru, int frame,int slot, uint64_t timestamp)
|
||||
flags_burst = proc->first_tx == 1 ? TX_BURST_START : TX_BURST_MIDDLE;
|
||||
}
|
||||
|
||||
if (ru->openair0_cfg.gpio_controller != RU_GPIO_CONTROL_NONE)
|
||||
flags_gpio = get_gpio_flags(ru, slot);
|
||||
|
||||
const int flags = flags_burst | (flags_gpio << 4);
|
||||
proc->first_tx = 0;
|
||||
|
||||
int nt = ru->nb_tx * ru->num_beams_period;
|
||||
void *txp[nt];
|
||||
for (int i = 0; i < nt; i++)
|
||||
txp[i] = (void *)&ru->common.txdata[i][get_samples_slot_timestamp(fp, slot)] - sf_extension * sizeof(int32_t);
|
||||
double sig_en = 0;
|
||||
uint32_t txs;
|
||||
if (ru->num_beams_period > 1) {
|
||||
void *txp_flat[ru->num_beams_period * ru->nb_tx];
|
||||
void **txp[ru->num_beams_period];
|
||||
for (int b = 0; b < ru->num_beams_period; b++) {
|
||||
for (int i = 0; i < ru->nb_tx; i++)
|
||||
txp_flat[b * ru->nb_tx + i] = (void *)&ru->common.txdata[i + b * ru->nb_tx][get_samples_slot_timestamp(fp, slot)] - sf_extension * sizeof(int32_t);
|
||||
txp[b] = &txp_flat[b * ru->nb_tx];
|
||||
}
|
||||
sig_en = (double)signal_energy(txp[0][0], siglen + sf_extension);
|
||||
txs = ru->rfdevice.trx_write_beams_func(&ru->rfdevice,
|
||||
timestamp + ru->ts_offset - sf_extension,
|
||||
(void ***)txp,
|
||||
siglen + sf_extension,
|
||||
ru->nb_tx,
|
||||
ru->num_beams_period,
|
||||
flags_burst);
|
||||
} else {
|
||||
void *txp[ru->nb_tx];
|
||||
for (int i = 0; i < ru->nb_tx; i++)
|
||||
txp[i] = (void *)&ru->common.txdata[i][get_samples_slot_timestamp(fp, slot)] - sf_extension * sizeof(int32_t);
|
||||
|
||||
sig_en = (double)signal_energy(txp[0], siglen + sf_extension);
|
||||
// prepare tx buffer pointers
|
||||
txs = ru->rfdevice.trx_write_func(&ru->rfdevice,
|
||||
timestamp + ru->ts_offset - sf_extension,
|
||||
txp,
|
||||
siglen + sf_extension,
|
||||
ru->nb_tx,
|
||||
flags_burst);
|
||||
}
|
||||
|
||||
// prepare tx buffer pointers
|
||||
uint32_t txs = ru->rfdevice.trx_write_func(&ru->rfdevice,
|
||||
timestamp + ru->ts_offset - sf_extension,
|
||||
txp,
|
||||
siglen + sf_extension,
|
||||
nt,
|
||||
flags);
|
||||
LOG_D(PHY,
|
||||
"[TXPATH] RU %d tx_rf, writing to TS %lu, %d.%d, unwrapped_frame %d, slot %d, flags %d, siglen+sf_extension %d, "
|
||||
"returned %d, E %f\n",
|
||||
@@ -585,10 +651,10 @@ void tx_rf(RU_t *ru, int frame,int slot, uint64_t timestamp)
|
||||
slot,
|
||||
proc->frame_tx_unwrap,
|
||||
slot,
|
||||
flags,
|
||||
flags_burst,
|
||||
siglen + sf_extension,
|
||||
txs,
|
||||
10 * log10((double)signal_energy(txp[0], siglen + sf_extension)));
|
||||
10 * log10(sig_en));
|
||||
}
|
||||
|
||||
static void fill_rf_config(RU_t *ru, char *rf_config_file)
|
||||
@@ -742,6 +808,25 @@ int setup_RU_buffers(RU_t *ru)
|
||||
return(0);
|
||||
}
|
||||
|
||||
void ru_ctrl_func(void *param)
|
||||
{
|
||||
processingData_RU_t *info = (processingData_RU_t *) param;
|
||||
int frame = info->frame_tx;
|
||||
int slot = info->slot_tx;
|
||||
LOG_D(PHY,"ru_ctrl_func: frame = %d, slot = %d\n", frame, slot);
|
||||
RU_t *ru = info->ru;
|
||||
NR_DL_FRAME_PARMS *fp = ru->nr_frame_parms;
|
||||
if (ru->gNB_list[0]->common_vars.analog_bf) {
|
||||
for (int i = 0; i < ru->num_beams_period; i++) {
|
||||
memcpy((void*) &ru->common.beam_id[i][slot * fp->symbols_per_slot],
|
||||
(void*) &ru->gNB_list[0]->common_vars.beam_id[i][slot * fp->symbols_per_slot],
|
||||
(fp->symbols_per_slot) * sizeof(int));
|
||||
}
|
||||
}
|
||||
if (ru->fh_south_ctrl)
|
||||
ru->fh_south_ctrl(ru, frame, slot, info->timestamp_tx);
|
||||
}
|
||||
|
||||
void ru_tx_func(void *param)
|
||||
{
|
||||
processingData_RU_t *info = (processingData_RU_t *) param;
|
||||
@@ -1134,6 +1219,7 @@ void set_function_spec_param(RU_t *ru)
|
||||
ru->rfdevice.host_type = RAU_HOST;
|
||||
ru->fh_south_in = rx_rf; // local synchronous RF RX
|
||||
ru->fh_south_out = tx_rf; // local synchronous RF TX
|
||||
ru->fh_south_ctrl = ctrl_rf; // local sunchronous RF control
|
||||
ru->start_rf = start_rf; // need to start the local RF interface
|
||||
ru->stop_rf = stop_rf;
|
||||
ru->start_write_thread = start_write_thread; // starting RF TX in different thread
|
||||
|
||||
@@ -310,7 +310,7 @@ extern int64_t uplink_frequency_offset[MAX_NUM_CCs][4];
|
||||
extern int usrp_tx_thread;
|
||||
extern int sf_ahead;
|
||||
extern int oai_exit;
|
||||
|
||||
void ru_ctrl_func(void *param);
|
||||
void ru_tx_func(void *param);
|
||||
void configure_ru(void *, void *arg);
|
||||
void configure_rru(void *, void *arg);
|
||||
|
||||
@@ -48,30 +48,6 @@ Please refer to the dedicated documentation at [LDPC_OFFLOAD_SETUP.md](file://..
|
||||
|
||||
`libldpc_aal.so` has its decoder and its encoder implemented in [nrLDPC_coding_aal.c](file://../nrLDPC_coding/nrLDPC_coding_aal/nrLDPC_coding_aal.c).
|
||||
|
||||
loading `libldpc_xdma.so` instead of `libldpc.so`:
|
||||
|
||||
`make ldpc_xdma` or `ninja ldpc_xdma`
|
||||
|
||||
This command creates the `libldpc_xdma.so` shared library.
|
||||
|
||||
```
|
||||
ninja ldpc_xdma
|
||||
[2/2] Linking C shared module libldpc_xdma.so
|
||||
```
|
||||
|
||||
At runtime, to successfully use the xdma, you need to install vendor specific drivers and tools.\
|
||||
Please refer to the dedicated documentation at [LDPC_XDMA_OFFLOAD_SETUP.md](file://../../../../doc/LDPC_XDMA_OFFLOAD_SETUP.md).
|
||||
|
||||
```
|
||||
./nr-softmodem -O libconfig:gnb.band78.sa.fr1.106PRB.usrpb210.conf:dbgl5 --rfsim --rfsimulator.[0].serveraddr server --log_config.gtpu_log_level info --loader.ldpc.shlibversion _xdma --nrLDPC_coding_xdma.num_threads_prepare 2
|
||||
```
|
||||
|
||||
`libldpc_xdma.so` has its decoder implemented in [nrLDPC_coding_xdma.c](file://../nrLDPC_coding/nrLDPC_coding_xdma/nrLDPC_coding_xdma.c).\
|
||||
Its encoder is implemented in [nrLDPC_coding_segment_encoder.c](file://../nrLDPC_coding/nrLDPC_coding_segment/nrLDPC_coding_segment_encoder.c).
|
||||
|
||||
*Note: `libldpc_xdma.so` relies on a segment coding library for encoding.*
|
||||
*The segment coding library is `libldpc.so` by default but it can be chosen with option `--nrLDPC_coding_xdma.encoder_shlibversion` followed by the library version - like with `--loder.ldpc.shlibversion` in the segment coding case above -*
|
||||
|
||||
#### Examples of ldpc shared lib selection when running ldpctest:
|
||||
|
||||
Slot coding libraries cannot be used yet within ldpctest.
|
||||
@@ -86,8 +62,6 @@ Libraries implementing the slotwise LDPC coding must be named `libldpc<_version>
|
||||
|
||||
`libldpc_aal.so` is completed.
|
||||
|
||||
`libldpc_xdma.so` is completed.
|
||||
|
||||
## LDPC segment coding
|
||||
The interface of the library is defined in [nrLDPC_defs.h](file://../nrLDPC_defs.h) as typedefs of the functions of the interface.
|
||||
The name of the functions implementing these typedefs can be found in [nrLDPC_extern.h](file://../nrLDPC_extern.h).
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
# SPDX-License-Identifier: LicenseRef-CSSL-1.0
|
||||
|
||||
add_subdirectory(nrLDPC_coding_segment)
|
||||
add_subdirectory(nrLDPC_coding_xdma)
|
||||
add_subdirectory(nrLDPC_coding_aal)
|
||||
|
||||
@@ -1,31 +0,0 @@
|
||||
# SPDX-License-Identifier: LicenseRef-CSSL-1.0
|
||||
|
||||
##########################################################
|
||||
|
||||
# LDPC offload library - XDMA
|
||||
##########################################################
|
||||
|
||||
add_boolean_option(ENABLE_LDPC_XDMA OFF "Build support for LDPC Offload to XDMA library" OFF)
|
||||
|
||||
if (ENABLE_LDPC_XDMA)
|
||||
|
||||
add_library(ldpc_xdma MODULE
|
||||
nrLDPC_coding_xdma_offload.c
|
||||
nrLDPC_coding_xdma.c
|
||||
../nrLDPC_coding_segment/nr_rate_matching.c
|
||||
../nrLDPC_coding_segment/nrLDPC_coding_segment_encoder.c
|
||||
../../nrLDPC_encoder/ldpc_encoder_optim8segmulti.c
|
||||
)
|
||||
target_include_directories(ldpc_xdma PRIVATE ../nrLDPC_coding_segment)
|
||||
|
||||
target_link_libraries(ldpc_xdma PRIVATE ldpc_gen_HEADERS log_headers)
|
||||
set_target_properties(ldpc_xdma PROPERTIES LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR})
|
||||
|
||||
add_dependencies(nr-softmodem ldpc_xdma)
|
||||
add_dependencies(nr-uesoftmodem ldpc_xdma)
|
||||
add_dependencies(nr_ulsim ldpc_xdma)
|
||||
add_dependencies(nr_ulschsim ldpc_xdma)
|
||||
add_dependencies(nr_dlsim ldpc_xdma)
|
||||
add_dependencies(nr_dlschsim ldpc_xdma)
|
||||
|
||||
endif()
|
||||
@@ -1,414 +0,0 @@
|
||||
/*
|
||||
* SPDX-License-Identifier: LicenseRef-CSSL-1.0
|
||||
*/
|
||||
|
||||
/*! \file PHY/CODING/nrLDPC_coding/nrLDPC_coding_xdma/nrLDPC_coding_xdma.c
|
||||
* \brief Top-level routines for decoding LDPC (ULSCH) transport channels
|
||||
* decoding implemented using a FEC IP core on FPGA through XDMA driver
|
||||
*/
|
||||
|
||||
// [from gNB coding]
|
||||
#include <syscall.h>
|
||||
|
||||
#include <nr_rate_matching.h>
|
||||
#include "PHY/CODING/coding_defs.h"
|
||||
#include "PHY/CODING/coding_extern.h"
|
||||
#include "PHY/CODING/nrLDPC_coding/nrLDPC_coding_xdma/nrLDPC_coding_xdma_offload.h"
|
||||
#include "PHY/CODING/nrLDPC_extern.h"
|
||||
#include "common/utils/LOG/log.h"
|
||||
#include "defs.h"
|
||||
// #define DEBUG_ULSCH_DECODING
|
||||
// #define gNB_DEBUG_TRACE
|
||||
|
||||
#define OAI_UL_LDPC_MAX_NUM_LLR 27000 // 26112 // NR_LDPC_NCOL_BG1*NR_LDPC_ZMAX = 68*384
|
||||
// #define DEBUG_CRC
|
||||
#ifdef DEBUG_CRC
|
||||
#define PRINT_CRC_CHECK(a) a
|
||||
#else
|
||||
#define PRINT_CRC_CHECK(a)
|
||||
#endif
|
||||
|
||||
#include "nfapi/open-nFAPI/nfapi/public_inc/nfapi_interface.h"
|
||||
#include "nfapi/open-nFAPI/nfapi/public_inc/nfapi_nr_interface.h"
|
||||
|
||||
#include "PHY/CODING/nrLDPC_coding/nrLDPC_coding_interface.h"
|
||||
|
||||
// Global var to limit the rework of the dirty legacy code
|
||||
int num_threads_prepare_max = 0;
|
||||
char *user_device = NULL;
|
||||
char *enc_read_device = NULL;
|
||||
char *enc_write_device = NULL;
|
||||
char *dec_read_device = NULL;
|
||||
char *dec_write_device = NULL;
|
||||
|
||||
/*!
|
||||
* \typedef args_fpga_decode_prepare_t
|
||||
* \struct args_fpga_decode_prepare_s
|
||||
* \brief arguments structure for passing arguments to the nr_ulsch_FPGA_decoding_prepare_blocks function
|
||||
*/
|
||||
typedef struct args_fpga_decode_prepare_s {
|
||||
nrLDPC_TB_decoding_parameters_t *TB_params; /*!< transport blocks parameters */
|
||||
|
||||
uint8_t *multi_indata; /*!< pointer to the head of the block destination array that is then passed to the FPGA decoding */
|
||||
int no_iteration_ldpc; /*!< pointer to the number of iteration set by this function */
|
||||
uint32_t r_first; /*!< index of the first block to be prepared within this function */
|
||||
uint32_t r_span; /*!< number of blocks to be prepared within this function */
|
||||
int r_offset; /*!< r index expressed in bits */
|
||||
int input_CBoffset; /*!< */
|
||||
int Kc; /*!< ratio between the number of columns in the parity check graph and the lifting size */
|
||||
int Kprime; /*!< size of payload and CRC bits in a code block */
|
||||
task_ans_t *ans; /*!< pointer to the answer that is used by thread pool to detect job completion */
|
||||
} args_fpga_decode_prepare_t;
|
||||
|
||||
int32_t nrLDPC_coding_init(void);
|
||||
int32_t nrLDPC_coding_shutdown(void);
|
||||
int32_t nrLDPC_coding_decoder(nrLDPC_slot_decoding_parameters_t *slot_params, int frame_rx, int slot_rx);
|
||||
// int32_t nrLDPC_coding_encoder(void);
|
||||
int decoder_xdma(nrLDPC_TB_decoding_parameters_t *TB_params, int frame_rx, int slot_rx, tpool_t *ldpc_threadPool);
|
||||
void nr_ulsch_FPGA_decoding_prepare_blocks(void *args);
|
||||
|
||||
int32_t nrLDPC_coding_init(void)
|
||||
{
|
||||
paramdef_t LoaderParams[] = {
|
||||
{"num_threads_prepare", NULL, 0, .iptr = &num_threads_prepare_max, .defintval = 0, TYPE_INT, 0, NULL},
|
||||
{"user_device", NULL, 0, .strptr = &user_device, .defstrval = DEVICE_NAME_DEFAULT_USER, TYPE_STRING, 0, NULL},
|
||||
{"enc_read_device", NULL, 0, .strptr = &enc_read_device, .defstrval = DEVICE_NAME_DEFAULT_ENC_READ, TYPE_STRING, 0, NULL},
|
||||
{"enc_write_device", NULL, 0, .strptr = &enc_write_device, .defstrval = DEVICE_NAME_DEFAULT_ENC_WRITE, TYPE_STRING, 0, NULL},
|
||||
{"dec_read_device", NULL, 0, .strptr = &dec_read_device, .defstrval = DEVICE_NAME_DEFAULT_DEC_READ, TYPE_STRING, 0, NULL},
|
||||
{"dec_write_device", NULL, 0, .strptr = &dec_write_device, .defstrval = DEVICE_NAME_DEFAULT_DEC_WRITE, TYPE_STRING, 0, NULL}};
|
||||
config_get(config_get_if(), LoaderParams, sizeofArray(LoaderParams), "nrLDPC_coding_xdma");
|
||||
AssertFatal(num_threads_prepare_max != 0, "nrLDPC_coding_xdma.num_threads_prepare was not provided");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int32_t nrLDPC_coding_shutdown(void)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
int32_t nrLDPC_coding_decoder(nrLDPC_slot_decoding_parameters_t *slot_params, int frame_rx, int slot_rx)
|
||||
{
|
||||
int nbDecode = 0;
|
||||
for (int ULSCH_id = 0; ULSCH_id < slot_params->nb_TBs; ULSCH_id++)
|
||||
nbDecode += decoder_xdma(&slot_params->TBs[ULSCH_id], frame_rx, slot_rx, slot_params->threadPool);
|
||||
return nbDecode;
|
||||
}
|
||||
|
||||
/*
|
||||
int32_t nrLDPC_coding_encoder(void)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
*/
|
||||
|
||||
int decoder_xdma(nrLDPC_TB_decoding_parameters_t *TB_params, int frame_rx, int slot_rx, tpool_t *ldpc_threadPool)
|
||||
{
|
||||
const uint32_t K = TB_params->K;
|
||||
const int Kc = TB_params->BG == 2 ? 52 : 68;
|
||||
int r_offset = 0, offset = 0;
|
||||
int Kprime = K - TB_params->F;
|
||||
|
||||
// FPGA parameter preprocessing
|
||||
static uint8_t multi_indata[27000 * 25]; // FPGA input data
|
||||
static uint8_t multi_outdata[1100 * 25]; // FPGA output data
|
||||
|
||||
int bg_len = TB_params->BG == 1 ? 22 : 10;
|
||||
|
||||
// Calc input CB offset
|
||||
int input_CBoffset = TB_params->Z * Kc * 8;
|
||||
if ((input_CBoffset & 0x7F) == 0)
|
||||
input_CBoffset = input_CBoffset / 8;
|
||||
else
|
||||
input_CBoffset = 16 * ((input_CBoffset / 128) + 1);
|
||||
|
||||
DecIFConf dec_conf = {0};
|
||||
dec_conf.Zc = TB_params->Z;
|
||||
dec_conf.BG = TB_params->BG;
|
||||
dec_conf.max_iter = TB_params->max_ldpc_iterations;
|
||||
dec_conf.numCB = TB_params->C;
|
||||
// input soft bits length, Zc x 66 - length of filler bits
|
||||
dec_conf.numChannelLls = (Kprime - 2 * TB_params->Z) + (Kc * TB_params->Z - K);
|
||||
// filler bits length
|
||||
dec_conf.numFillerBits = TB_params->F;
|
||||
dec_conf.max_schedule = 0;
|
||||
dec_conf.SetIdx = 12;
|
||||
dec_conf.nRows = (dec_conf.BG == 1) ? 46 : 42;
|
||||
|
||||
dec_conf.user_device = user_device;
|
||||
dec_conf.enc_read_device = enc_read_device;
|
||||
dec_conf.enc_write_device = enc_write_device;
|
||||
dec_conf.dec_read_device = dec_read_device;
|
||||
dec_conf.dec_write_device = dec_write_device;
|
||||
|
||||
int out_CBoffset = dec_conf.Zc * bg_len;
|
||||
if ((out_CBoffset & 0x7F) == 0)
|
||||
out_CBoffset = out_CBoffset / 8;
|
||||
else
|
||||
out_CBoffset = 16 * ((out_CBoffset / 128) + 1);
|
||||
|
||||
#ifdef LDPC_DATA
|
||||
printf("\n------------------------\n");
|
||||
printf("BG:\t\t%d\n", dec_conf.BG);
|
||||
printf("TB_params->C: %d\n", TB_params->C);
|
||||
printf("TB_params->K: %d\n", TB_params->K);
|
||||
printf("TB_params->Z: %d\n", TB_params->Z);
|
||||
printf("TB_params->F: %d\n", TB_params->F);
|
||||
printf("numChannelLls:\t %d = (%d - 2 * %d) + (%d * %d - %d)\n",
|
||||
dec_conf.numChannelLls,
|
||||
Kprime,
|
||||
TB_params->Z,
|
||||
Kc,
|
||||
TB_params->Z,
|
||||
K);
|
||||
printf("numFillerBits:\t %d\n", TB_params->F);
|
||||
printf("------------------------\n");
|
||||
// ===================================
|
||||
// debug mode
|
||||
// ===================================
|
||||
FILE *fptr_llr, *fptr_ldpc;
|
||||
fptr_llr = fopen("../../../cmake_targets/log/ulsim_ldpc_llr.txt", "w");
|
||||
fptr_ldpc = fopen("../../../cmake_targets/log/ulsim_ldpc_output.txt", "w");
|
||||
// ===================================
|
||||
#endif
|
||||
|
||||
int length_dec = lenWithCrc(TB_params->C, TB_params->A);
|
||||
uint8_t crc_type = crcType(TB_params->C, TB_params->A);
|
||||
int no_iteration_ldpc = 2;
|
||||
|
||||
uint32_t num_threads_prepare = 0;
|
||||
|
||||
// calculate required number of jobs
|
||||
uint32_t r_while = 0;
|
||||
while (r_while < TB_params->C) {
|
||||
// calculate number of segments processed in the new job
|
||||
uint32_t modulus = (TB_params->C - r_while) % (num_threads_prepare_max - num_threads_prepare);
|
||||
uint32_t quotient = (TB_params->C - r_while) / (num_threads_prepare_max - num_threads_prepare);
|
||||
uint32_t r_span_max = modulus == 0 ? quotient : quotient + 1;
|
||||
|
||||
// saturate to be sure to not go above C
|
||||
uint32_t r_span = TB_params->C - r_while < r_span_max ? TB_params->C - r_while : r_span_max;
|
||||
|
||||
// increment
|
||||
num_threads_prepare++;
|
||||
r_while += r_span;
|
||||
}
|
||||
|
||||
args_fpga_decode_prepare_t arr[num_threads_prepare];
|
||||
task_ans_t ans[num_threads_prepare];
|
||||
memset(ans, 0, num_threads_prepare * sizeof(task_ans_t));
|
||||
thread_info_tm_t t_info = {.buf = (uint8_t *)arr, .len = 0, .cap = num_threads_prepare, .ans = ans};
|
||||
|
||||
// start the prepare jobs
|
||||
uint32_t r_remaining = 0;
|
||||
for (uint32_t r = 0; r < TB_params->C; r++) {
|
||||
nrLDPC_segment_decoding_parameters_t *segment_params = &TB_params->segments[r];
|
||||
if (r_remaining == 0) {
|
||||
// TODO: int nr_tti_rx = 0;
|
||||
|
||||
args_fpga_decode_prepare_t *args = &((args_fpga_decode_prepare_t *)t_info.buf)[t_info.len];
|
||||
DevAssert(t_info.len < t_info.cap);
|
||||
args->ans = &t_info.ans[t_info.len];
|
||||
t_info.len += 1;
|
||||
|
||||
args->TB_params = TB_params;
|
||||
args->multi_indata = multi_indata;
|
||||
args->no_iteration_ldpc = no_iteration_ldpc;
|
||||
args->r_first = r;
|
||||
|
||||
uint32_t modulus = (TB_params->C - r) % (num_threads_prepare_max - num_threads_prepare);
|
||||
uint32_t quotient = (TB_params->C - r) / (num_threads_prepare_max - num_threads_prepare);
|
||||
uint32_t r_span_max = modulus == 0 ? quotient : quotient + 1;
|
||||
|
||||
uint32_t r_span = TB_params->C - r < r_span_max ? TB_params->C - r : r_span_max;
|
||||
args->r_span = r_span;
|
||||
args->r_offset = r_offset;
|
||||
args->input_CBoffset = input_CBoffset;
|
||||
args->Kc = Kc;
|
||||
args->Kprime = Kprime;
|
||||
|
||||
r_remaining = r_span;
|
||||
|
||||
task_t t = {.func = &nr_ulsch_FPGA_decoding_prepare_blocks, .args = args};
|
||||
pushTpool(ldpc_threadPool, t);
|
||||
|
||||
LOG_D(PHY, "Added %d block(s) to prepare for decoding, in pipe: %d to %d\n", r_span, r, r + r_span - 1);
|
||||
}
|
||||
r_offset += segment_params->E;
|
||||
offset += ((K >> 3) - (TB_params->F >> 3) - ((TB_params->C > 1) ? 3 : 0));
|
||||
r_remaining -= 1;
|
||||
}
|
||||
|
||||
// reset offset in order to properly fill the output array later
|
||||
offset = 0;
|
||||
|
||||
DevAssert(num_threads_prepare == t_info.len);
|
||||
|
||||
// wait for the prepare jobs to complete
|
||||
join_task_ans(t_info.ans);
|
||||
|
||||
for (uint32_t job = 0; job < num_threads_prepare; job++) {
|
||||
args_fpga_decode_prepare_t *args = &arr[job];
|
||||
if (args->no_iteration_ldpc >= TB_params->max_ldpc_iterations)
|
||||
no_iteration_ldpc = TB_params->max_ldpc_iterations;
|
||||
}
|
||||
|
||||
// launch decode with FPGA
|
||||
LOG_I(PHY, "Run the LDPC ------[FPGA version]------\n");
|
||||
//==================================================================
|
||||
// Xilinx FPGA LDPC decoding function -> nrLDPC_decoder_FPGA_PYM()
|
||||
//==================================================================
|
||||
start_meas(&TB_params->segments[0].ts_ldpc_decode);
|
||||
nrLDPC_decoder_FPGA_PYM(&multi_indata[0], &multi_outdata[0], dec_conf);
|
||||
// printf("Xilinx FPGA -> CB = %d\n", harq_process->C);
|
||||
stop_meas(&TB_params->segments[0].ts_ldpc_decode);
|
||||
|
||||
*TB_params->processedSegments = 0;
|
||||
for (uint32_t r = 0; r < TB_params->C; r++) {
|
||||
// ------------------------------------------------------------
|
||||
// --------------------- copy FPGA output ---------------------
|
||||
// ------------------------------------------------------------
|
||||
nrLDPC_segment_decoding_parameters_t *segment_params = &TB_params->segments[r];
|
||||
if (check_crc(multi_outdata, length_dec, crc_type)) {
|
||||
#ifdef DEBUG_CRC
|
||||
LOG_I(PHY, "Segment %d CRC OK\n", r);
|
||||
#endif
|
||||
no_iteration_ldpc = 2;
|
||||
} else {
|
||||
#ifdef DEBUG_CRC
|
||||
LOG_I(PHY, "segment %d CRC NOK\n", r);
|
||||
#endif
|
||||
no_iteration_ldpc = TB_params->max_ldpc_iterations;
|
||||
}
|
||||
for (int i = 0; i < out_CBoffset; i++) {
|
||||
segment_params->c[i] = multi_outdata[i + r * out_CBoffset];
|
||||
}
|
||||
segment_params->decodeSuccess = (no_iteration_ldpc < TB_params->max_ldpc_iterations);
|
||||
if (segment_params->decodeSuccess) {
|
||||
*TB_params->processedSegments = *TB_params->processedSegments + 1;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*!
|
||||
* \fn nr_ulsch_FPGA_decoding_prepare_blocks(void *args)
|
||||
* \brief prepare blocks for LDPC decoding on FPGA
|
||||
*
|
||||
* \param args pointer to the arguments of the function in a structure of type args_fpga_decode_prepare_t
|
||||
*/
|
||||
void nr_ulsch_FPGA_decoding_prepare_blocks(void *args)
|
||||
{
|
||||
// extract the arguments
|
||||
args_fpga_decode_prepare_t *arguments = (args_fpga_decode_prepare_t *)args;
|
||||
|
||||
nrLDPC_TB_decoding_parameters_t *TB_params = arguments->TB_params;
|
||||
|
||||
uint8_t Qm = TB_params->Qm;
|
||||
|
||||
uint8_t BG = TB_params->BG;
|
||||
uint8_t rv_index = TB_params->rv_index;
|
||||
uint8_t max_ldpc_iterations = TB_params->max_ldpc_iterations;
|
||||
|
||||
uint32_t tbslbrm = TB_params->tbslbrm;
|
||||
uint32_t K = TB_params->K;
|
||||
uint32_t Z = TB_params->Z;
|
||||
uint32_t F = TB_params->F;
|
||||
|
||||
uint32_t C = TB_params->C;
|
||||
|
||||
nrLDPC_segment_decoding_parameters_t *segment_params = &TB_params->segments[0];
|
||||
|
||||
short *ulsch_llr = segment_params->llr;
|
||||
|
||||
uint8_t *multi_indata = arguments->multi_indata;
|
||||
int no_iteration_ldpc = arguments->no_iteration_ldpc;
|
||||
uint32_t r_first = arguments->r_first;
|
||||
uint32_t r_span = arguments->r_span;
|
||||
int r_offset = arguments->r_offset;
|
||||
int input_CBoffset = arguments->input_CBoffset;
|
||||
int Kc = arguments->Kc;
|
||||
int Kprime = arguments->Kprime;
|
||||
|
||||
int16_t z[68 * 384 + 16] __attribute__((aligned(16)));
|
||||
simde__m128i *pv = (simde__m128i *)&z;
|
||||
|
||||
// the function processes r_span blocks starting from block at index r_first in ulsch_llr
|
||||
for (uint32_t r = r_first; r < (r_first + r_span); r++) {
|
||||
nrLDPC_segment_decoding_parameters_t *segment_params = &TB_params->segments[r];
|
||||
// ----------------------- FPGA pre process ------------------------
|
||||
simde__m128i ones = simde_mm_set1_epi8(255); // Generate a vector with all elements set to 255
|
||||
simde__m128i *temp_multi_indata = (simde__m128i *)&multi_indata[r * input_CBoffset];
|
||||
// -----------------------------------------------------------------
|
||||
|
||||
// code blocks after bit selection in rate matching for LDPC code (38.212 V15.4.0 section 5.4.2.1)
|
||||
int16_t harq_e[segment_params->E];
|
||||
// -------------------------------------------------------------------------------------------
|
||||
// deinterleaving
|
||||
// -------------------------------------------------------------------------------------------
|
||||
start_meas(&segment_params->ts_deinterleave);
|
||||
nr_deinterleaving_ldpc(segment_params->E, Qm, harq_e, ulsch_llr + r_offset);
|
||||
stop_meas(&segment_params->ts_deinterleave);
|
||||
// -------------------------------------------------------------------------------------------
|
||||
// dematching
|
||||
// -------------------------------------------------------------------------------------------
|
||||
start_meas(&segment_params->ts_rate_unmatch);
|
||||
if (nr_rate_matching_ldpc_rx(tbslbrm,
|
||||
BG,
|
||||
Z,
|
||||
segment_params->d,
|
||||
harq_e,
|
||||
C,
|
||||
rv_index,
|
||||
*segment_params->d_to_be_cleared,
|
||||
segment_params->E,
|
||||
F,
|
||||
K - F - 2 * Z)
|
||||
== -1) {
|
||||
stop_meas(&segment_params->ts_rate_unmatch);
|
||||
LOG_E(PHY, "ulsch_decoding.c: Problem in rate_matching\n");
|
||||
no_iteration_ldpc = max_ldpc_iterations;
|
||||
arguments->no_iteration_ldpc = no_iteration_ldpc;
|
||||
return;
|
||||
} else {
|
||||
stop_meas(&segment_params->ts_rate_unmatch);
|
||||
}
|
||||
|
||||
*segment_params->d_to_be_cleared = false;
|
||||
|
||||
memset(segment_params->c, 0, K >> 3);
|
||||
|
||||
// set first 2*Z_c bits to zeros
|
||||
memset(&z[0], 0, 2 * Z * sizeof(int16_t));
|
||||
// set Filler bits
|
||||
memset((&z[0] + Kprime), 127, F * sizeof(int16_t));
|
||||
// Move coded bits before filler bits
|
||||
memcpy((&z[0] + 2 * Z), segment_params->d, (Kprime - 2 * Z) * sizeof(int16_t));
|
||||
// skip filler bits
|
||||
memcpy((&z[0] + K), segment_params->d + (K - 2 * Z), (Kc * Z - K) * sizeof(int16_t));
|
||||
|
||||
// Saturate coded bits before decoding into 8 bits values
|
||||
for (int i = 0, j = 0; j < ((Kc * Z) >> 4); i += 2, j++) {
|
||||
temp_multi_indata[j] =
|
||||
simde_mm_xor_si128(simde_mm_packs_epi16(pv[i], pv[i + 1]),
|
||||
simde_mm_cmpeq_epi32(ones,
|
||||
ones)); // Perform NOT operation and write the result to temp_multi_indata[j]
|
||||
}
|
||||
|
||||
// the last bytes before reaching "Kc * harq_process->Z" should not be written 128 bits at a time to avoid overwritting the
|
||||
// following block in multi_indata
|
||||
simde__m128i tmp =
|
||||
simde_mm_xor_si128(simde_mm_packs_epi16(pv[2 * ((Kc * Z) >> 4)], pv[2 * ((Kc * Z) >> 4) + 1]),
|
||||
simde_mm_cmpeq_epi32(ones,
|
||||
ones)); // Perform NOT operation and write the result to temp_multi_indata[j]
|
||||
uint8_t *tmp_p = (uint8_t *)&tmp;
|
||||
for (int i = 0, j = ((Kc * Z) & 0xfffffff0); j < Kc * Z; i++, j++) {
|
||||
multi_indata[r * input_CBoffset + j] = tmp_p[i];
|
||||
}
|
||||
|
||||
r_offset += segment_params->E;
|
||||
}
|
||||
|
||||
arguments->no_iteration_ldpc = no_iteration_ldpc;
|
||||
}
|
||||
@@ -1,783 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2016-present, Xilinx, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This source code is licensed under the BSD-style license
|
||||
* the terms of the BSD Licence are reported below:
|
||||
*
|
||||
* BSD License
|
||||
*
|
||||
* For Xilinx DMA IP software
|
||||
*
|
||||
* Copyright (c) 2016-present, Xilinx, Inc. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without modification,
|
||||
* are permitted provided that the following conditions are met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright notice, this
|
||||
* list of conditions and the following disclaimer.
|
||||
*
|
||||
* * Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* * Neither the name Xilinx nor the names of its contributors may be used to
|
||||
* endorse or promote products derived from this software without specific
|
||||
* prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
|
||||
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
||||
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#define _DEFAULT_SOURCE
|
||||
#define _XOPEN_SOURCE 500
|
||||
|
||||
#include <assert.h>
|
||||
#include <fcntl.h>
|
||||
#include <getopt.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include <errno.h>
|
||||
#include <time.h>
|
||||
#include <byteswap.h>
|
||||
#include <signal.h>
|
||||
#include <ctype.h>
|
||||
#include <termios.h>
|
||||
|
||||
#include <sys/mman.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/time.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
#include "xdma_diag.h"
|
||||
#include "nrLDPC_coding_xdma_offload.h"
|
||||
|
||||
#include "common/utils/assertions.h"
|
||||
|
||||
typedef unsigned long long U64;
|
||||
void* map_base;
|
||||
int fd;
|
||||
int fd_enc_write, fd_enc_read;
|
||||
char *dev_enc_write, *dev_enc_read;
|
||||
int fd_dec_write, fd_dec_read;
|
||||
char *dev_dec_write, *dev_dec_read;
|
||||
char allocated_write[24 * 1024] __attribute__((aligned(4096)));
|
||||
char allocated_read[24 * 1024 * 3] __attribute__((aligned(4096)));
|
||||
|
||||
// dma_from_device.c
|
||||
|
||||
// [Start] #include "dma_utils.c" ===================================
|
||||
|
||||
/*
|
||||
* man 2 write:
|
||||
* On Linux, write() (and similar system calls) will transfer at most
|
||||
* 0x7ffff000 (2,147,479,552) bytes, returning the number of bytes
|
||||
* actually transferred. (This is true on both 32-bit and 64-bit
|
||||
* systems.)
|
||||
*/
|
||||
|
||||
#define RW_MAX_SIZE 0x7ffff000
|
||||
|
||||
int verbose = 0;
|
||||
|
||||
uint64_t getopt_integer(char* optarg)
|
||||
{
|
||||
int rc;
|
||||
uint64_t value;
|
||||
|
||||
rc = sscanf(optarg, "0x%lx", &value);
|
||||
if (rc <= 0)
|
||||
rc = sscanf(optarg, "%lu", &value);
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
ssize_t read_to_buffer(char* fname, int fd, char* buffer, uint64_t size, uint64_t base)
|
||||
{
|
||||
ssize_t rc;
|
||||
uint64_t count = 0;
|
||||
char* buf = buffer;
|
||||
off_t offset = base;
|
||||
|
||||
while (count < size) {
|
||||
uint64_t bytes = size - count;
|
||||
|
||||
if (bytes > RW_MAX_SIZE)
|
||||
bytes = RW_MAX_SIZE;
|
||||
|
||||
if (offset) {
|
||||
rc = lseek(fd, offset, SEEK_SET);
|
||||
if (rc != offset) {
|
||||
fprintf(stderr, "%s, seek off 0x%lx != 0x%lx.\n", fname, rc, offset);
|
||||
perror("seek file");
|
||||
return -EIO;
|
||||
}
|
||||
}
|
||||
/* read data from file into memory buffer */
|
||||
rc = read(fd, buf, bytes);
|
||||
|
||||
if (rc != bytes) {
|
||||
fprintf(stderr, "%s, R off 0x%lx, 0x%lx != 0x%lx.\n", fname, count, rc, bytes);
|
||||
perror("read file");
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
count += bytes;
|
||||
buf += bytes;
|
||||
offset += bytes;
|
||||
}
|
||||
|
||||
if (count != size) {
|
||||
fprintf(stderr, "%s, R failed 0x%lx != 0x%lx.\n", fname, count, size);
|
||||
return -EIO;
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
||||
ssize_t write_from_buffer(char* fname, int fd, char* buffer, uint64_t size, uint64_t base)
|
||||
{
|
||||
ssize_t rc;
|
||||
uint64_t count = 0;
|
||||
char* buf = buffer;
|
||||
off_t offset = base;
|
||||
|
||||
while (count < size) {
|
||||
uint64_t bytes = size - count;
|
||||
|
||||
if (bytes > RW_MAX_SIZE)
|
||||
bytes = RW_MAX_SIZE;
|
||||
|
||||
if (offset) {
|
||||
rc = lseek(fd, offset, SEEK_SET);
|
||||
if (rc != offset) {
|
||||
fprintf(stderr, "%s, seek off 0x%lx != 0x%lx.\n", fname, rc, offset);
|
||||
perror("seek file");
|
||||
return -EIO;
|
||||
}
|
||||
}
|
||||
|
||||
/* write data to file from memory buffer */
|
||||
rc = write(fd, buf, bytes);
|
||||
if (rc != bytes) {
|
||||
fprintf(stderr, "%s, W off 0x%lx, 0x%lx != 0x%lx.\n", fname, offset, rc, bytes);
|
||||
perror("write file");
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
count += bytes;
|
||||
buf += bytes;
|
||||
offset += bytes;
|
||||
}
|
||||
|
||||
if (count != size) {
|
||||
fprintf(stderr, "%s, R failed 0x%lx != 0x%lx.\n", fname, count, size);
|
||||
return -EIO;
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
||||
// [End] #include "dma_utils.c" ===================================
|
||||
|
||||
int test_dma_enc_read(char* EncOut, EncIPConf Confparam)
|
||||
{
|
||||
ssize_t rc;
|
||||
|
||||
void* virt_addr;
|
||||
|
||||
uint64_t size;
|
||||
uint32_t writeval;
|
||||
|
||||
uint32_t Z_val;
|
||||
|
||||
uint16_t max_schedule, mb, id, bg, z_j, kb, z_a;
|
||||
uint16_t z_set;
|
||||
uint32_t ctrl_data;
|
||||
uint32_t CB_num = CB_PROCESS_NUMBER;
|
||||
|
||||
// this values should be given by Shane
|
||||
max_schedule = 0;
|
||||
mb = Confparam.mb;
|
||||
id = CB_num;
|
||||
bg = Confparam.BGSel - 1;
|
||||
z_set = Confparam.z_set - 1;
|
||||
z_j = Confparam.z_j;
|
||||
|
||||
if (z_set == 0)
|
||||
z_a = 2;
|
||||
else if (z_set == 1)
|
||||
z_a = 3;
|
||||
else if (z_set == 2)
|
||||
z_a = 5;
|
||||
else if (z_set == 3)
|
||||
z_a = 7;
|
||||
else if (z_set == 4)
|
||||
z_a = 9;
|
||||
else if (z_set == 5)
|
||||
z_a = 11;
|
||||
else if (z_set == 6)
|
||||
z_a = 13;
|
||||
else
|
||||
z_a = 15;
|
||||
|
||||
if (bg == 0)
|
||||
kb = 22;
|
||||
else if (bg == 1)
|
||||
kb = 10;
|
||||
else if (bg == 2)
|
||||
kb = 9;
|
||||
else if (bg == 3)
|
||||
kb = 8;
|
||||
else
|
||||
kb = 6;
|
||||
mb = Confparam.kb_1 + kb;
|
||||
Z_val = (unsigned int)(z_a << z_j);
|
||||
ctrl_data = (max_schedule << 30) | ((mb - kb) << 24) | (id << 19) | (bg << 6) | (z_set << 3) | z_j;
|
||||
uint32_t OutDataNUM = Z_val * mb;
|
||||
uint32_t Out_dwNumItems_p128;
|
||||
uint32_t Out_dwNumItems;
|
||||
|
||||
if ((OutDataNUM & 0x7F) == 0)
|
||||
Out_dwNumItems_p128 = OutDataNUM >> 5;
|
||||
else
|
||||
Out_dwNumItems_p128 = ((OutDataNUM >> 7) + 1) << 2;
|
||||
Out_dwNumItems = ((Out_dwNumItems_p128 << 2) * CB_num);
|
||||
size = Out_dwNumItems;
|
||||
writeval = ctrl_data;
|
||||
|
||||
/* calculate the virtual address to be accessed */
|
||||
virt_addr = map_base + OFFSET_ENC_OUT;
|
||||
|
||||
/* swap 32-bit endianess if host is not little-endian */
|
||||
writeval = htoll(writeval);
|
||||
*((uint32_t*)virt_addr) = writeval;
|
||||
if (fd_enc_read < 0) {
|
||||
fprintf(stderr, "unable to open device %s, %d.\n", dev_enc_read, fd_enc_read);
|
||||
perror("open device");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* lseek & read data from AXI MM into buffer using SGDMA */
|
||||
rc = read_to_buffer(dev_enc_read, fd_enc_read, EncOut, size, 0);
|
||||
if (rc < 0)
|
||||
goto out;
|
||||
|
||||
rc = 0;
|
||||
|
||||
out:
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
int test_dma_enc_write(char* data, EncIPConf Confparam)
|
||||
{
|
||||
ssize_t rc;
|
||||
void* virt_addr;
|
||||
|
||||
uint64_t size;
|
||||
uint32_t writeval;
|
||||
|
||||
uint32_t Z_val;
|
||||
uint16_t max_schedule, mb, id, bg, z_j, kb, z_a;
|
||||
uint16_t z_set;
|
||||
uint32_t ctrl_data;
|
||||
uint32_t CB_num = CB_PROCESS_NUMBER;
|
||||
|
||||
// this values should be given by Shane
|
||||
max_schedule = 0;
|
||||
|
||||
mb = Confparam.mb;
|
||||
id = CB_num;
|
||||
bg = Confparam.BGSel - 1;
|
||||
z_set = Confparam.z_set - 1;
|
||||
z_j = Confparam.z_j;
|
||||
|
||||
if (z_set == 0)
|
||||
z_a = 2;
|
||||
else if (z_set == 1)
|
||||
z_a = 3;
|
||||
else if (z_set == 2)
|
||||
z_a = 5;
|
||||
else if (z_set == 3)
|
||||
z_a = 7;
|
||||
else if (z_set == 4)
|
||||
z_a = 9;
|
||||
else if (z_set == 5)
|
||||
z_a = 11;
|
||||
else if (z_set == 6)
|
||||
z_a = 13;
|
||||
else
|
||||
z_a = 15;
|
||||
|
||||
if (bg == 0)
|
||||
kb = 22;
|
||||
else if (bg == 1)
|
||||
kb = 10;
|
||||
else if (bg == 2)
|
||||
kb = 9;
|
||||
else if (bg == 3)
|
||||
kb = 8;
|
||||
else
|
||||
kb = 6;
|
||||
mb = Confparam.kb_1 + kb;
|
||||
Z_val = (unsigned int)(z_a << z_j);
|
||||
ctrl_data = (max_schedule << 30) | ((mb - kb) << 24) | (id << 19) | (bg << 6) | (z_set << 3) | z_j;
|
||||
uint32_t InDataNUM = Z_val * kb;
|
||||
uint32_t In_dwNumItems_p128;
|
||||
uint32_t In_dwNumItems;
|
||||
|
||||
if ((InDataNUM & 0x7F) == 0)
|
||||
In_dwNumItems_p128 = InDataNUM >> 5;
|
||||
else
|
||||
In_dwNumItems_p128 = ((InDataNUM >> 7) + 1) << 2;
|
||||
|
||||
In_dwNumItems = ((In_dwNumItems_p128 << 2) * CB_num);
|
||||
size = In_dwNumItems;
|
||||
writeval = ctrl_data;
|
||||
|
||||
/* calculate the virtual address to be accessed */
|
||||
virt_addr = map_base + OFFSET_ENC_IN;
|
||||
|
||||
/* swap 32-bit endianess if host is not little-endian */
|
||||
writeval = htoll(writeval);
|
||||
*((uint32_t*)virt_addr) = writeval;
|
||||
if (fd_enc_write < 0) {
|
||||
fprintf(stderr, "unable to open device %s, %d.\n", dev_enc_write, fd_enc_write);
|
||||
perror("open device");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
rc = write_from_buffer(dev_enc_write, fd_enc_write, data, size, 0);
|
||||
if (rc < 0)
|
||||
goto out;
|
||||
rc = 0;
|
||||
|
||||
out:
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
// int test_dma_dec_read(unsigned int *DecOut, DecIPConf Confparam)
|
||||
int test_dma_dec_read(char* DecOut, DecIPConf Confparam)
|
||||
{
|
||||
ssize_t rc;
|
||||
|
||||
void* virt_addr;
|
||||
|
||||
uint64_t size;
|
||||
uint32_t writeval;
|
||||
|
||||
uint32_t Z_val;
|
||||
|
||||
uint16_t max_schedule, mb, id, bg, z_j, kb, z_a, max_iter, sc_idx;
|
||||
uint16_t z_set;
|
||||
uint32_t ctrl_data;
|
||||
uint32_t CB_num = Confparam.CB_num;
|
||||
|
||||
// this values should be given by Shane
|
||||
max_schedule = 0;
|
||||
mb = Confparam.mb;
|
||||
id = CB_num;
|
||||
bg = Confparam.BGSel - 1;
|
||||
z_set = Confparam.z_set - 1;
|
||||
z_j = Confparam.z_j;
|
||||
max_iter = 8;
|
||||
sc_idx = 12;
|
||||
|
||||
if (z_set == 0)
|
||||
z_a = 2;
|
||||
else if (z_set == 1)
|
||||
z_a = 3;
|
||||
else if (z_set == 2)
|
||||
z_a = 5;
|
||||
else if (z_set == 3)
|
||||
z_a = 7;
|
||||
else if (z_set == 4)
|
||||
z_a = 9;
|
||||
else if (z_set == 5)
|
||||
z_a = 11;
|
||||
else if (z_set == 6)
|
||||
z_a = 13;
|
||||
else
|
||||
z_a = 15;
|
||||
|
||||
if (bg == 0)
|
||||
kb = 22;
|
||||
else if (bg == 1)
|
||||
kb = 10;
|
||||
else if (bg == 2)
|
||||
kb = 9;
|
||||
else if (bg == 3)
|
||||
kb = 8;
|
||||
else
|
||||
kb = 6;
|
||||
|
||||
Z_val = (unsigned int)(z_a << z_j);
|
||||
ctrl_data =
|
||||
(max_schedule << 30) | ((mb - kb) << 24) | (id << 19) | (max_iter << 13) | (sc_idx << 9) | (bg << 6) | (z_set) << 3 | z_j;
|
||||
|
||||
uint32_t OutDataNUM = Z_val * kb;
|
||||
uint32_t Out_dwNumItems_p128;
|
||||
uint32_t Out_dwNumItems;
|
||||
|
||||
if (CB_num & 0x01) // odd cb number
|
||||
{
|
||||
if ((OutDataNUM & 0xFF) == 0)
|
||||
Out_dwNumItems_p128 = OutDataNUM;
|
||||
else
|
||||
Out_dwNumItems_p128 = 256 * ((OutDataNUM / 256) + 1);
|
||||
|
||||
Out_dwNumItems = (Out_dwNumItems_p128 * CB_num) >> 3;
|
||||
} else {
|
||||
if ((OutDataNUM & 0x7F) == 0)
|
||||
Out_dwNumItems_p128 = OutDataNUM;
|
||||
else
|
||||
Out_dwNumItems_p128 = 128 * ((OutDataNUM / 128) + 1);
|
||||
|
||||
Out_dwNumItems = (Out_dwNumItems_p128 * CB_num) >> 3;
|
||||
if ((Out_dwNumItems & 0x1f) != 0)
|
||||
Out_dwNumItems = ((Out_dwNumItems + 31) >> 5) << 5;
|
||||
|
||||
}
|
||||
size = Out_dwNumItems;
|
||||
writeval = ctrl_data;
|
||||
|
||||
/* calculate the virtual address to be accessed */
|
||||
virt_addr = map_base + OFFSET_DEC_OUT;
|
||||
|
||||
/* swap 32-bit endianess if host is not little-endian */
|
||||
writeval = htoll(writeval);
|
||||
*((uint32_t*)virt_addr) = writeval;
|
||||
|
||||
if (fd_dec_read < 0) {
|
||||
fprintf(stderr, "unable to open device %s, %d.\n", dev_dec_read, fd_dec_read);
|
||||
perror("open device");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* lseek & read data from AXI MM into buffer using SGDMA */
|
||||
rc = read_to_buffer(dev_dec_read, fd_dec_read, DecOut, size, 0);
|
||||
if (rc < 0)
|
||||
goto out;
|
||||
|
||||
rc = 0;
|
||||
|
||||
out:
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
// int test_dma_dec_write(unsigned int *data, DecIPConf Confparam)
|
||||
int test_dma_dec_write(char* data, DecIPConf Confparam)
|
||||
{
|
||||
ssize_t rc;
|
||||
|
||||
void* virt_addr;
|
||||
|
||||
uint64_t size;
|
||||
uint32_t writeval;
|
||||
|
||||
uint32_t Z_val;
|
||||
uint16_t max_schedule, mb, id, bg, z_j, kb, z_a, max_iter, sc_idx;
|
||||
uint16_t z_set;
|
||||
uint32_t ctrl_data;
|
||||
uint32_t CB_num = Confparam.CB_num; // CB_PROCESS_NUMBER_Dec;//
|
||||
|
||||
// this values should be given by Shane
|
||||
max_schedule = 0;
|
||||
mb = Confparam.mb;
|
||||
id = CB_num;
|
||||
bg = Confparam.BGSel - 1;
|
||||
z_set = Confparam.z_set - 1;
|
||||
z_j = Confparam.z_j;
|
||||
|
||||
max_iter = 8;
|
||||
sc_idx = 12;
|
||||
|
||||
if (z_set == 0)
|
||||
z_a = 2;
|
||||
else if (z_set == 1)
|
||||
z_a = 3;
|
||||
else if (z_set == 2)
|
||||
z_a = 5;
|
||||
else if (z_set == 3)
|
||||
z_a = 7;
|
||||
else if (z_set == 4)
|
||||
z_a = 9;
|
||||
else if (z_set == 5)
|
||||
z_a = 11;
|
||||
else if (z_set == 6)
|
||||
z_a = 13;
|
||||
else
|
||||
z_a = 15;
|
||||
|
||||
if (bg == 0)
|
||||
kb = 22;
|
||||
else if (bg == 1)
|
||||
kb = 10;
|
||||
else if (bg == 2)
|
||||
kb = 9;
|
||||
else if (bg == 3)
|
||||
kb = 8;
|
||||
else
|
||||
kb = 6;
|
||||
|
||||
Z_val = (unsigned int)(z_a << z_j);
|
||||
ctrl_data =
|
||||
(max_schedule << 30) | ((mb - kb) << 24) | (id << 19) | (max_iter << 13) | (sc_idx << 9) | (bg << 6) | (z_set) << 3 | z_j;
|
||||
|
||||
uint32_t InDataNUM = Z_val * mb;
|
||||
uint32_t In_dwNumItems_p128;
|
||||
uint32_t In_dwNumItems;
|
||||
|
||||
InDataNUM = Z_val * mb * 8;
|
||||
if ((InDataNUM & 0x7F) == 0)
|
||||
In_dwNumItems_p128 = InDataNUM;
|
||||
else
|
||||
In_dwNumItems_p128 = 128 * ((InDataNUM / 128) + 1);
|
||||
|
||||
In_dwNumItems = (In_dwNumItems_p128 * CB_num) >> 3;
|
||||
if ((In_dwNumItems & 0x1f) != 0)
|
||||
In_dwNumItems = ((In_dwNumItems + 31) >> 5) << 5;
|
||||
|
||||
size = In_dwNumItems;
|
||||
writeval = ctrl_data;
|
||||
|
||||
/* calculate the virtual address to be accessed */
|
||||
virt_addr = map_base + OFFSET_DEC_IN;
|
||||
|
||||
/* swap 32-bit endianess if host is not little-endian */
|
||||
writeval = htoll(writeval);
|
||||
*((uint32_t*)virt_addr) = writeval;
|
||||
|
||||
if (fd_dec_write < 0) {
|
||||
fprintf(stderr, "unable to open device %s, %d.\n", dev_dec_write, fd_dec_write);
|
||||
perror("open device");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
rc = write_from_buffer(dev_dec_write, fd_dec_write, data, size, 0);
|
||||
if (rc < 0)
|
||||
goto out;
|
||||
|
||||
rc = 0;
|
||||
|
||||
out:
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
void test_dma_init(devices_t devices)
|
||||
{
|
||||
/* access width */
|
||||
char* device2 = devices.user_device;
|
||||
|
||||
AssertFatal((fd = open(device2, O_RDWR | O_SYNC)) != -1, "CHARACTER DEVICE %s OPEN FAILURE\n", device2);
|
||||
fflush(stdout);
|
||||
|
||||
/* map one page */
|
||||
map_base = mmap(0, MAP_SIZE, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
|
||||
AssertFatal(map_base != (void*)-1, "MEMORY MAP AT ADDRESS %p FAILED\n", map_base);
|
||||
|
||||
void* virt_addr;
|
||||
virt_addr = map_base + OFFSET_RESET;
|
||||
*((uint32_t*)virt_addr) = 1;
|
||||
|
||||
dev_enc_write = devices.enc_write_device;
|
||||
dev_enc_read = devices.enc_read_device;
|
||||
dev_dec_write = devices.dec_write_device;
|
||||
dev_dec_read = devices.dec_read_device;
|
||||
|
||||
fd_enc_write = open(dev_enc_write, O_RDWR);
|
||||
fd_enc_read = open(dev_enc_read, O_RDWR);
|
||||
fd_dec_write = open(dev_dec_write, O_RDWR);
|
||||
fd_dec_read = open(dev_dec_read, O_RDWR);
|
||||
|
||||
fflush(stdout);
|
||||
|
||||
}
|
||||
|
||||
void dma_reset(devices_t devices)
|
||||
{
|
||||
char* device2 = devices.user_device;
|
||||
|
||||
void* virt_addr;
|
||||
virt_addr = map_base + PCIE_OFF;
|
||||
*((uint32_t*)virt_addr) = 1;
|
||||
|
||||
AssertFatal(munmap(map_base, MAP_SIZE) != -1, "munmap failure");
|
||||
close(fd_enc_write);
|
||||
close(fd_enc_read);
|
||||
close(fd_dec_write);
|
||||
close(fd_dec_read);
|
||||
close(fd);
|
||||
|
||||
AssertFatal((fd = open(device2, O_RDWR | O_SYNC)) != -1, "CHARACTER DEVICE %s OPEN FAILURE\n", device2);
|
||||
fflush(stdout);
|
||||
|
||||
/* map one page */
|
||||
map_base = mmap(0, MAP_SIZE, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
|
||||
AssertFatal(map_base != (void*)-1, "MEMORY MAP AT ADDRESS %p FAILED\n", map_base);
|
||||
|
||||
virt_addr = map_base + PCIE_OFF;
|
||||
*((uint32_t*)virt_addr) = 1;
|
||||
|
||||
virt_addr = map_base + OFFSET_RESET;
|
||||
*((uint32_t*)virt_addr) = 1;
|
||||
|
||||
dev_enc_write = devices.enc_write_device;
|
||||
dev_enc_read = devices.enc_read_device;
|
||||
dev_dec_write = devices.dec_write_device;
|
||||
dev_dec_read = devices.dec_read_device;
|
||||
|
||||
fd_enc_write = open(dev_enc_write, O_RDWR);
|
||||
fd_enc_read = open(dev_enc_read, O_RDWR);
|
||||
fd_dec_write = open(dev_dec_write, O_RDWR);
|
||||
fd_dec_read = open(dev_dec_read, O_RDWR);
|
||||
|
||||
fflush(stdout);
|
||||
}
|
||||
|
||||
void test_dma_shutdown()
|
||||
{
|
||||
|
||||
void* virt_addr;
|
||||
virt_addr = map_base + PCIE_OFF;
|
||||
*((uint32_t*)virt_addr) = 1;
|
||||
|
||||
AssertFatal(munmap(map_base, MAP_SIZE) != -1, "munmap failure");
|
||||
close(fd_enc_write);
|
||||
close(fd_enc_read);
|
||||
close(fd_dec_write);
|
||||
close(fd_dec_read);
|
||||
close(fd);
|
||||
|
||||
}
|
||||
|
||||
// reg_rx.c
|
||||
int nrLDPC_decoder_FPGA_PYM(uint8_t* buf_in, uint8_t* buf_out, DecIFConf dec_conf)
|
||||
{
|
||||
struct timespec ts_start0; // evaluate time from input setting to output setting including xdma
|
||||
|
||||
int Zc;
|
||||
int nRows;
|
||||
int baseGraph;
|
||||
int CB_num;
|
||||
|
||||
DecIPConf Confparam;
|
||||
int z_a, z_tmp;
|
||||
int z_j = 0;
|
||||
|
||||
|
||||
int input_CBoffset, output_CBoffset;
|
||||
|
||||
uint8_t i_LS;
|
||||
|
||||
devices_t devices = {
|
||||
.user_device = dec_conf.user_device,
|
||||
.enc_write_device = dec_conf.enc_write_device,
|
||||
.enc_read_device = dec_conf.enc_read_device,
|
||||
.dec_write_device = dec_conf.dec_write_device,
|
||||
.dec_read_device = dec_conf.dec_read_device
|
||||
};
|
||||
|
||||
static int init_flag = 0;
|
||||
if (init_flag == 0) {
|
||||
/*Init*/
|
||||
test_dma_init(devices);
|
||||
init_flag = 1;
|
||||
} else {
|
||||
dma_reset(devices);
|
||||
}
|
||||
|
||||
clock_gettime(CLOCK_MONOTONIC, &ts_start0); // time start0
|
||||
// LDPC input parameter
|
||||
Zc = dec_conf.Zc; // shifting size
|
||||
nRows = dec_conf.nRows; // number of Rows
|
||||
baseGraph = dec_conf.BG; // base graph
|
||||
CB_num = dec_conf.numCB; // 31 number of code block
|
||||
|
||||
// calc xdma LDPC parameter
|
||||
// calc i_LS
|
||||
if ((Zc % 15) == 0)
|
||||
i_LS = 7;
|
||||
else if ((Zc % 13) == 0)
|
||||
i_LS = 6;
|
||||
else if ((Zc % 11) == 0)
|
||||
i_LS = 5;
|
||||
else if ((Zc % 9) == 0)
|
||||
i_LS = 4;
|
||||
else if ((Zc % 7) == 0)
|
||||
i_LS = 3;
|
||||
else if ((Zc % 5) == 0)
|
||||
i_LS = 2;
|
||||
else if ((Zc % 3) == 0)
|
||||
i_LS = 1;
|
||||
else
|
||||
i_LS = 0;
|
||||
|
||||
// calc z_a
|
||||
if (i_LS == 0)
|
||||
z_a = 2;
|
||||
else
|
||||
z_a = i_LS * 2 + 1;
|
||||
|
||||
// calc z_j
|
||||
z_tmp = Zc / z_a;
|
||||
while (z_tmp % 2 == 0) {
|
||||
z_j = z_j + 1;
|
||||
z_tmp = z_tmp / 2;
|
||||
}
|
||||
|
||||
// calc CB_num and mb
|
||||
Confparam.CB_num = CB_num;
|
||||
if (baseGraph == 1)
|
||||
Confparam.mb = 22 + nRows;
|
||||
else
|
||||
Confparam.mb = 10 + nRows;
|
||||
|
||||
// set BGSel, z_set, z_j
|
||||
Confparam.BGSel = baseGraph;
|
||||
Confparam.z_set = i_LS + 1;
|
||||
Confparam.z_j = z_j;
|
||||
|
||||
// Calc input CB offset
|
||||
input_CBoffset = Zc * Confparam.mb * 8;
|
||||
if ((input_CBoffset & 0x7F) == 0)
|
||||
input_CBoffset = input_CBoffset / 8;
|
||||
else
|
||||
input_CBoffset = 16 * ((input_CBoffset / 128) + 1);
|
||||
|
||||
// Calc output CB offset
|
||||
output_CBoffset = Zc * (Confparam.mb - nRows);
|
||||
if ((output_CBoffset & 0x7F) == 0)
|
||||
output_CBoffset = output_CBoffset / 8;
|
||||
else
|
||||
output_CBoffset = 16 * ((output_CBoffset / 128) + 1);
|
||||
|
||||
// LDPC accelerator start
|
||||
// write into accelerator
|
||||
if (test_dma_dec_write((char *)buf_in, Confparam) != 0) {
|
||||
exit(1);
|
||||
printf("write exit!!\n");
|
||||
}
|
||||
|
||||
// read output of accelerator
|
||||
if (test_dma_dec_read((char *)buf_out, Confparam) != 0) {
|
||||
exit(1);
|
||||
printf("read exit!!\n");
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -1,46 +0,0 @@
|
||||
/*
|
||||
* SPDX-License-Identifier: LicenseRef-CSSL-1.0
|
||||
*/
|
||||
|
||||
/*!
|
||||
* \briefFPGA accelerator integrated into OAI (for one and multi code block)
|
||||
*/
|
||||
|
||||
#ifndef __NRLDPC_CODING_XDMA_OFFLOAD__H_
|
||||
|
||||
#define __NRLDPC_CODING_XDMA_OFFLOAD__H_
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#define DEVICE_NAME_DEFAULT_USER "/dev/xdma0_user"
|
||||
#define DEVICE_NAME_DEFAULT_ENC_READ "/dev/xdma0_c2h_1"
|
||||
#define DEVICE_NAME_DEFAULT_ENC_WRITE "/dev/xdma0_h2c_1"
|
||||
#define DEVICE_NAME_DEFAULT_DEC_READ "/dev/xdma0_c2h_0"
|
||||
#define DEVICE_NAME_DEFAULT_DEC_WRITE "/dev/xdma0_h2c_0"
|
||||
|
||||
/**
|
||||
\brief LDPC input parameter
|
||||
\param Zc shifting size
|
||||
\param Rows
|
||||
\param baseGraph base graph
|
||||
\param CB_num number of code block
|
||||
\param numChannelLlrs input soft bits length, Zc x 66 - length of filler bits
|
||||
\param numFillerBits filler bits length
|
||||
*/
|
||||
typedef struct {
|
||||
char *user_device, *enc_write_device, *enc_read_device, *dec_write_device, *dec_read_device;
|
||||
unsigned char max_schedule;
|
||||
unsigned char SetIdx;
|
||||
int Zc;
|
||||
unsigned char numCB;
|
||||
unsigned char BG;
|
||||
unsigned char max_iter;
|
||||
int nRows;
|
||||
int numChannelLls;
|
||||
int numFillerBits;
|
||||
} DecIFConf;
|
||||
|
||||
int nrLDPC_decoder_FPGA_PYM(uint8_t *buf_in, uint8_t *buf_out, DecIFConf dec_conf);
|
||||
|
||||
#endif // __NRLDPC_CODING_XDMA_OFFLOAD__H_
|
||||
|
||||
@@ -1,119 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2016-present, Xilinx, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This source code is licensed under the BSD-style license
|
||||
* the terms of the BSD Licence are reported below:
|
||||
*
|
||||
* BSD License
|
||||
*
|
||||
* For Xilinx DMA IP software
|
||||
*
|
||||
* Copyright (c) 2016-present, Xilinx, Inc. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without modification,
|
||||
* are permitted provided that the following conditions are met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright notice, this
|
||||
* list of conditions and the following disclaimer.
|
||||
*
|
||||
* * Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* * Neither the name Xilinx nor the names of its contributors may be used to
|
||||
* endorse or promote products derived from this software without specific
|
||||
* prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
|
||||
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
||||
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#ifndef MODULES_TXCTRL_INC_XDMA_DIAG_H_
|
||||
#define MODULES_TXCTRL_INC_XDMA_DIAG_H_
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
typedef struct {
|
||||
unsigned char max_schedule; // max_schedule = 0;
|
||||
unsigned char mb; // mb = 32;
|
||||
unsigned char CB_num; // id = CB_num;
|
||||
unsigned char BGSel; // bg = 1;
|
||||
unsigned char z_set; // z_set = 0;
|
||||
unsigned char z_j; // z_j = 6;
|
||||
unsigned char max_iter; // max_iter = 8;
|
||||
unsigned char SetIdx; // sc_idx = 12;
|
||||
} DecIPConf;
|
||||
|
||||
typedef struct {
|
||||
int SetIdx;
|
||||
int NumCBSegm;
|
||||
int PayloadLen;
|
||||
int Z;
|
||||
int z_set;
|
||||
int z_j;
|
||||
int Kbmax;
|
||||
int BGSel;
|
||||
unsigned mb;
|
||||
unsigned char CB_num;
|
||||
unsigned char kb_1;
|
||||
} EncIPConf;
|
||||
|
||||
typedef struct {
|
||||
char *user_device, *enc_write_device, *enc_read_device, *dec_write_device, *dec_read_device;
|
||||
} devices_t;
|
||||
|
||||
/* ltoh: little to host */
|
||||
/* htol: little to host */
|
||||
#if __BYTE_ORDER == __LITTLE_ENDIAN
|
||||
#define ltohl(x) (x)
|
||||
#define ltohs(x) (x)
|
||||
#define htoll(x) (x)
|
||||
#define htols(x) (x)
|
||||
#elif __BYTE_ORDER == __BIG_ENDIAN
|
||||
#define ltohl(x) __bswap_32(x)
|
||||
#define ltohs(x) __bswap_16(x)
|
||||
#define htoll(x) __bswap_32(x)
|
||||
#define htols(x) __bswap_16(x)
|
||||
#endif
|
||||
|
||||
#define MAP_SIZE (32 * 1024UL)
|
||||
#define MAP_MASK (MAP_SIZE - 1)
|
||||
|
||||
#define SIZE_DEFAULT (32)
|
||||
#define COUNT_DEFAULT (1)
|
||||
|
||||
#define OFFSET_DEC_IN 0x0000
|
||||
#define OFFSET_DEC_OUT 0x0004
|
||||
#define OFFSET_ENC_IN 0x0008
|
||||
#define OFFSET_ENC_OUT 0x000c
|
||||
#define OFFSET_RESET 0x0020
|
||||
#define PCIE_OFF 0x0030
|
||||
|
||||
#define CB_PROCESS_NUMBER 24 // add by JW
|
||||
#define CB_PROCESS_NUMBER_Dec 24
|
||||
|
||||
// dma_from_device.c
|
||||
|
||||
int test_dma_enc_read(char *EncOut, EncIPConf Confparam);
|
||||
int test_dma_enc_write(char *data, EncIPConf Confparam);
|
||||
int test_dma_dec_read(char *DecOut, DecIPConf Confparam);
|
||||
int test_dma_dec_write(char *data, DecIPConf Confparam);
|
||||
void test_dma_init(devices_t devices);
|
||||
void test_dma_shutdown();
|
||||
void dma_reset(devices_t devices);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
@@ -424,11 +424,15 @@ void init_nr_transport(PHY_VARS_gNB *gNB)
|
||||
gNB->max_nb_pusch = buffer_ul_slots ? MAX_MOBILES_PER_GNB * buffer_ul_slots : 1;
|
||||
|
||||
int max_nb_pucch = buffer_ul_slots ? MAX_MOBILES_PER_GNB * buffer_ul_slots : 1;
|
||||
gNB->pucch_queue = spsc_q_alloc(max_nb_pucch, sizeof(NR_gNB_PUCCH_job_t));
|
||||
gNB->pusch_queue = spsc_q_alloc(gNB->max_nb_pusch, sizeof(NR_gNB_PUSCH_job_t));
|
||||
bool ret;
|
||||
ret = spsc_q_alloc(&gNB->pucch_queue, max_nb_pucch, sizeof(NR_gNB_PUCCH_job_t));
|
||||
DevAssert(ret);
|
||||
ret = spsc_q_alloc(&gNB->pusch_queue, gNB->max_nb_pusch, sizeof(NR_gNB_PUSCH_job_t));
|
||||
DevAssert(ret);
|
||||
|
||||
int max_nb_srs = buffer_ul_slots ? buffer_ul_slots << 1 : 1; // assuming at most 2 SRS per slot
|
||||
gNB->srs_queue = spsc_q_alloc(max_nb_srs, sizeof(NR_gNB_SRS_job_t));
|
||||
ret = spsc_q_alloc(&gNB->srs_queue, max_nb_srs, sizeof(NR_gNB_SRS_job_t));
|
||||
DevAssert(ret);
|
||||
|
||||
gNB->ulsch = (NR_gNB_ULSCH_t *)malloc16(gNB->max_nb_pusch * sizeof(NR_gNB_ULSCH_t));
|
||||
for (int i = 0; i < gNB->max_nb_pusch; i++) {
|
||||
|
||||
@@ -15,8 +15,11 @@
|
||||
void init_nr_prach(PHY_VARS_gNB *gNB)
|
||||
{
|
||||
int num_prach = 16;
|
||||
gNB->prach_ru_queue = spsc_q_alloc(num_prach, sizeof(prach_item_t));
|
||||
gNB->prach_l1rx_queue = spsc_q_alloc(num_prach, sizeof(prach_item_t));
|
||||
bool ret;
|
||||
ret = spsc_q_alloc(&gNB->prach_ru_queue, num_prach, sizeof(prach_item_t));
|
||||
DevAssert(ret);
|
||||
ret = spsc_q_alloc(&gNB->prach_l1rx_queue, num_prach, sizeof(prach_item_t));
|
||||
DevAssert(ret);
|
||||
}
|
||||
|
||||
void reset_nr_prach(PHY_VARS_gNB *gNB)
|
||||
|
||||
@@ -490,6 +490,8 @@ typedef struct RU_t_s {
|
||||
void (*fh_south_in)(struct RU_t_s *ru, int *frame, int *subframe);
|
||||
/// function pointer to synchronous TX fronthaul function
|
||||
void (*fh_south_out)(struct RU_t_s *ru, int frame_tx, int tti_tx, uint64_t timestamp_tx);
|
||||
/// function pointer to synchronous control fronthaul function
|
||||
void (*fh_south_ctrl)(struct RU_t_s *ru, int frame, int slot, uint64_t timestamp);
|
||||
/// function pointer to synchronous RX fronthaul function (RRU)
|
||||
void (*fh_north_in)(struct RU_t_s *ru, int *frame, int *subframe);
|
||||
/// function pointer to synchronous RX fronthaul function (RRU)
|
||||
|
||||
@@ -151,14 +151,6 @@ void nr_feptx_prec(RU_t *ru, int frame_tx, int slot_tx)
|
||||
NR_DL_FRAME_PARMS *fp = ru->nr_frame_parms;
|
||||
start_meas(&ru->precoding_stats);
|
||||
|
||||
if (gNB->common_vars.analog_bf) {
|
||||
for (int i = 0; i < ru->num_beams_period; i++) {
|
||||
memcpy((void*) &ru->common.beam_id[i][slot_tx * fp->symbols_per_slot],
|
||||
(void*) &gNB->common_vars.beam_id[i][slot_tx * fp->symbols_per_slot],
|
||||
(fp->symbols_per_slot) * sizeof(int));
|
||||
}
|
||||
}
|
||||
|
||||
if (nr_slot_select(cfg,frame_tx,slot_tx) == NR_UPLINK_SLOT)
|
||||
return;
|
||||
|
||||
@@ -197,16 +189,9 @@ void nr_feptx(void *arg)
|
||||
if (tx_idx == 0)
|
||||
start_meas(&ru->precoding_stats);
|
||||
|
||||
if (ru->gNB_list[0]->common_vars.analog_bf) {
|
||||
memcpy(&ru->common.beam_id[bb][slot * fp->symbols_per_slot],
|
||||
&ru->gNB_list[0]->common_vars.beam_id[bb][slot * fp->symbols_per_slot],
|
||||
(fp->symbols_per_slot) * sizeof(int));
|
||||
}
|
||||
|
||||
// If there is no digital beamforming we just need to copy the data to RU
|
||||
if (ru->config.dbt_config.num_dig_beams == 0 || ru->gNB_list[0]->common_vars.analog_bf) {
|
||||
// FFT shift
|
||||
const NR_DL_FRAME_PARMS *fp = &ru->gNB_list[0]->frame_parms;
|
||||
fft_shift(ru->gNB_list[0]->common_vars.txdataF[bb][aa],
|
||||
fp->ofdm_symbol_size,
|
||||
fp->N_RB_DL,
|
||||
|
||||
@@ -462,11 +462,10 @@ static void configure_prach_occasions(NR_UE_MAC_INST_t *mac, int scs)
|
||||
for (int s = 0; s < prach_info.N_RA_sfn; s++) { // subframe/60kHz slot occasions in period
|
||||
while (((temp_s_map >> sf) & 0x01) == 0)
|
||||
sf++;
|
||||
int sl = sf;
|
||||
int sl = scs == 1 || scs == 3 ? sf * 2 : sf;
|
||||
for (int i = 0; i < prach_slots_in_sf; i++) { // slot per subframe/60kHz slot
|
||||
int add_slot = i;
|
||||
if (scs == 1 || scs == 3) {
|
||||
sl *= 2;
|
||||
// if only 1 slot per subframe (or 60kHz slot) in case of 30 or 120kHz it's the odd one
|
||||
// as defined in 5.3.2 of 211
|
||||
if (((prach_info.format & 0xff) > 3) && prach_slots_in_sf == 1)
|
||||
@@ -528,6 +527,14 @@ static void configure_prach_occasions(NR_UE_MAC_INST_t *mac, int scs)
|
||||
LOG_D(NR_MAC, "PRACH configuration period %d association period %d\n", config_period, ra->association_periods);
|
||||
|
||||
select_prach_occasion(ra, mac->ssb_list.nb_tx_ssb, max_num_occasions, ra_occasions_period, num_ra_occasions_period);
|
||||
const prach_occasion_info_t *pi = &ra->sched_ro_info;
|
||||
LOG_I(NR_MAC,
|
||||
"[UE %d] selected PRACH occasion: start_symbol %d fdm %d slot %d format %d\n",
|
||||
mac->ue_id,
|
||||
pi->start_symbol,
|
||||
pi->fdm,
|
||||
pi->slot,
|
||||
pi->format);
|
||||
}
|
||||
|
||||
/* TS 38.321 subclause 7.3 - return DELTA_PREAMBLE values in dB */
|
||||
|
||||
@@ -272,6 +272,12 @@ void nr_rrc_trigger_f1_ho(gNB_RRC_INST *rrc,
|
||||
DevAssert(rrc != NULL);
|
||||
DevAssert(ue != NULL);
|
||||
|
||||
/* 3GPP TS 38.473, clause 8.3.1.2: The gNB-CU shall only initiate UeContextSetupRequest
|
||||
* for handover when at least one DRB is setup for the UE. */
|
||||
if (!seq_arr_size(&ue->drbs)) {
|
||||
LOG_W(NR_RRC, "UE %u: no DRB configured, cannot trigger handover\n", ue->rrc_ue_id);
|
||||
return;
|
||||
}
|
||||
uint8_t buf[NR_RRC_BUF_SIZE];
|
||||
int size = do_NR_HandoverPreparationInformation(ue->ue_cap_buffer.buf, ue->ue_cap_buffer.len, buf, sizeof buf);
|
||||
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
/*!
|
||||
* \brief common APIs for different RF frontend device
|
||||
*/
|
||||
#include <pthread.h>
|
||||
#include <stdio.h>
|
||||
#include <strings.h>
|
||||
#include <dlfcn.h>
|
||||
@@ -126,6 +127,8 @@ int openair0_device_load(openair0_device_t *device, openair0_config_t *openair0_
|
||||
} else
|
||||
AssertFatal(false, "can't open the radio device: %s\n", get_devname(device->type));
|
||||
|
||||
pthread_mutex_init(&device->reOrder.mutex_store, NULL);
|
||||
pthread_mutex_init(&device->reOrder.mutex_write, NULL);
|
||||
return rc;
|
||||
}
|
||||
|
||||
@@ -223,15 +226,15 @@ int openair0_write_reorder_common(nrue_ru_write_t nrue_ru_write,
|
||||
int wroteSamples = 0;
|
||||
re_order_t *ctx = &device->reOrder;
|
||||
LOG_D(HW, "received write order ts: %lu, nb samples %d, next ts %luflags %d\n", timestamp, nsamps, timestamp + nsamps, flags);
|
||||
pthread_mutex_lock(&ctx->mutex_store);
|
||||
if (!ctx->initDone) {
|
||||
ctx->nextTS = timestamp;
|
||||
pthread_mutex_init(&ctx->mutex_write, NULL);
|
||||
pthread_mutex_init(&ctx->mutex_store, NULL);
|
||||
for (int i = 0; i < WRITE_QUEUE_SZ; i++) {
|
||||
ctx->queue[i].txp = malloc(sizeof(void *) * NB_ANTENNAS_TX);
|
||||
}
|
||||
ctx->initDone = true;
|
||||
}
|
||||
pthread_mutex_unlock(&ctx->mutex_store);
|
||||
if (pthread_mutex_trylock(&ctx->mutex_write) == 0) {
|
||||
// We have the write exclusivity
|
||||
if (llabs(timestamp - ctx->nextTS) < MAX_GAP) { // We are writing in sequence of the previous write
|
||||
@@ -274,13 +277,13 @@ void openair0_write_reorder_clear_context(openair0_device_t *device)
|
||||
return;
|
||||
if (pthread_mutex_trylock(&ctx->mutex_write) != 0)
|
||||
LOG_E(HW, "write_reorder_clear_context call while still writing on the device\n");
|
||||
pthread_mutex_destroy(&ctx->mutex_write);
|
||||
else
|
||||
pthread_mutex_unlock(&ctx->mutex_write);
|
||||
pthread_mutex_lock(&ctx->mutex_store);
|
||||
for (int i = 0; i < WRITE_QUEUE_SZ; i++) {
|
||||
ctx->queue[i].active = false;
|
||||
free(ctx->queue[i].txp);
|
||||
}
|
||||
pthread_mutex_unlock(&ctx->mutex_store);
|
||||
pthread_mutex_destroy(&ctx->mutex_store);
|
||||
ctx->initDone = false;
|
||||
pthread_mutex_unlock(&ctx->mutex_store);
|
||||
}
|
||||
|
||||
@@ -80,6 +80,7 @@ typedef struct {
|
||||
int64_t rx_count;
|
||||
int wait_for_first_pps;
|
||||
int use_gps;
|
||||
int prev_beam;
|
||||
//int first_tx;
|
||||
//int first_rx;
|
||||
//! timestamp of RX packet
|
||||
@@ -313,6 +314,7 @@ static int trx_usrp_start(openair0_device_t *device)
|
||||
//s->first_tx = 1;
|
||||
//s->first_rx = 1;
|
||||
s->rx_timestamp = 0;
|
||||
s->prev_beam = -1;
|
||||
|
||||
//wait for next pps
|
||||
uhd::time_spec_t last_pps = s->usrp->get_time_last_pps();
|
||||
@@ -359,6 +361,43 @@ static void trx_usrp_finish_rx(usrp_state_t *s)
|
||||
} while (samples > 0);
|
||||
}
|
||||
|
||||
static int trx_set_beam(openair0_device_t *device, int *beams, int num_beams, openair0_timestamp_t timestamp)
|
||||
{
|
||||
AssertFatal(beams, "Invalid input for beams %p, vector not present\n", beams);
|
||||
AssertFatal(num_beams == 1, "Cannot handle more than 1 concurrent beam in USRP\n");
|
||||
usrp_state_t *s = (usrp_state_t *)device->priv;
|
||||
// to keep consistent with previous integration where we sent beam information to GPIO
|
||||
// only if it changed to avoid unnecessary timing issues that the procedure may cause
|
||||
if (beams[0] == s->prev_beam)
|
||||
return 0;
|
||||
else
|
||||
s->prev_beam = beams[0];
|
||||
int gpio = 0;
|
||||
switch (device->openair0_cfg->gpio_controller) {
|
||||
case RU_GPIO_CONTROL_GENERIC:
|
||||
AssertFatal(beams[0] < 8, "Only 3 bits available for setting beams\n");
|
||||
gpio = s->prev_beam | TX_GPIO_CHANGE;
|
||||
break;
|
||||
case RU_GPIO_CONTROL_INTERDIGITAL:
|
||||
// TODO
|
||||
break;
|
||||
default:
|
||||
AssertFatal(false, "illegal GPIO controller for beam handling %d\n", device->openair0_cfg->gpio_controller);
|
||||
}
|
||||
radio_tx_gpio_flag_t flags_gpio = (radio_tx_gpio_flag_t) gpio;
|
||||
// bit 13 enables gpio
|
||||
timestamp -= device->openair0_cfg->command_line_sample_advance + device->openair0_cfg->tx_sample_advance;
|
||||
s->tx_md.time_spec = uhd::time_spec_t::from_ticks(timestamp, s->sample_rate);
|
||||
|
||||
VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_BEAM_SWITCHING_GPIO, 1);
|
||||
// push GPIO bits
|
||||
s->usrp->set_command_time(s->tx_md.time_spec);
|
||||
s->usrp->set_gpio_attr(s->gpio_bank, "OUT", flags_gpio, MAN_MASK);
|
||||
s->usrp->clear_command_time();
|
||||
VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_BEAM_SWITCHING_GPIO, 0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void trx_usrp_write_reset(openair0_thread_t *wt);
|
||||
|
||||
/*! \brief Terminate operation of the USRP transceiver -- free all associated resources
|
||||
@@ -418,7 +457,6 @@ static int trx_usrp_write(openair0_device_t *device,
|
||||
int nsamps2; // aligned to upper 32 or 16 byte boundary
|
||||
|
||||
radio_tx_burst_flag_t flags_burst = (radio_tx_burst_flag_t) (flags & 0xf);
|
||||
radio_tx_gpio_flag_t flags_gpio = (radio_tx_gpio_flag_t) ((flags >> 4) & 0x1fff);
|
||||
|
||||
int end;
|
||||
openair0_thread_t *write_thread = &device->write_thread;
|
||||
@@ -480,16 +518,6 @@ static int trx_usrp_write(openair0_device_t *device,
|
||||
s->tx_md.time_spec = uhd::time_spec_t::from_ticks(timestamp, s->sample_rate);
|
||||
s->tx_count++;
|
||||
|
||||
VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_BEAM_SWITCHING_GPIO, 1);
|
||||
// bit 13 enables gpio
|
||||
if ((flags_gpio & TX_GPIO_CHANGE) != 0) {
|
||||
// push GPIO bits
|
||||
s->usrp->set_command_time(s->tx_md.time_spec);
|
||||
s->usrp->set_gpio_attr(s->gpio_bank, "OUT", flags_gpio, MAN_MASK);
|
||||
s->usrp->clear_command_time();
|
||||
}
|
||||
VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_BEAM_SWITCHING_GPIO, 0);
|
||||
|
||||
if (cc > 1) {
|
||||
std::vector<void *> buff_ptrs;
|
||||
|
||||
@@ -524,7 +552,7 @@ static int trx_usrp_write(openair0_device_t *device,
|
||||
write_package[end].cc = cc;
|
||||
write_package[end].first_packet = first_packet_state;
|
||||
write_package[end].last_packet = last_packet_state;
|
||||
write_package[end].flags_gpio = flags_gpio;
|
||||
//write_package[end].flags_gpio = flags_gpio;
|
||||
for (int i = 0; i < cc; i++)
|
||||
write_package[end].buff[i] = buff[i];
|
||||
write_thread->count_write++;
|
||||
@@ -1519,6 +1547,7 @@ extern "C" {
|
||||
LOG_I(HW,"Device timestamp: %f...\n", s->usrp->get_time_now().get_real_secs());
|
||||
device->trx_write_func = trx_usrp_write;
|
||||
device->trx_read_func = trx_usrp_read;
|
||||
device->trx_set_beams2 = trx_set_beam;
|
||||
s->sample_rate = openair0_cfg[0].sample_rate;
|
||||
|
||||
// TODO:
|
||||
|
||||
@@ -1363,7 +1363,7 @@ static void rfsimulator_read_internal(rfsimulator_state_t *t,
|
||||
int16_t noise_power = (int16_t)(32767.0 / powf(10.0, .05 * -get_noise_power_dBFS()));
|
||||
for (int a = 0; a < nbAnt; a++) {
|
||||
for (int i = 0; i < nsamps; i++) {
|
||||
temp_array[a][i].r += noise_power + gaussZiggurat(0.0, 1.0);
|
||||
temp_array[a][i].r += noise_power * gaussZiggurat(0.0, 1.0);
|
||||
temp_array[a][i].i += noise_power * gaussZiggurat(0.0, 1.0);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -179,12 +179,13 @@ void cirdb_connect(int id,
|
||||
float want_speed = (sel && sel->want_speed_mps > 0) ? sel->want_speed_mps : -1.0f;
|
||||
|
||||
LOG_I(HW,
|
||||
"CIRDB: Searching for entry with model_id=%d, antennas=%dx%d, DS=%.1fns, speed=%.1fm/s\n",
|
||||
"CIRDB: Searching for entry with model_id=%d, antennas=%dx%d, DS=%.1fns, speed=%.1fm/s, AoA=%.1fdeg\n",
|
||||
want_model_id,
|
||||
G.num_tx,
|
||||
G.num_rx,
|
||||
want_ds,
|
||||
want_speed);
|
||||
want_speed,
|
||||
sel->want_aoa_deg);
|
||||
|
||||
cirdb_entry_meta_t m = (cirdb_entry_meta_t){0};
|
||||
cirdb_select_req_t req = {.want_model_id = want_model_id,
|
||||
@@ -192,6 +193,7 @@ void cirdb_connect(int id,
|
||||
.want_rx = G.num_rx,
|
||||
.want_ds_ns = want_ds,
|
||||
.want_speed_mps = want_speed,
|
||||
.want_aoa_deg = sel->want_aoa_deg,
|
||||
.allow_shape_swap = 0,
|
||||
.w_ds = 1.0f,
|
||||
.w_speed = 0.2f,
|
||||
@@ -279,7 +281,7 @@ void cirdb_connect(int id,
|
||||
}
|
||||
|
||||
LOG_I(HW,
|
||||
"CIRDB: Selected entry - model=%d DS=%.3fns shape=%ux%u L=%u/%u S=%u fs=%.0f dt=%.6fs speed=%.3fm/s\n",
|
||||
"CIRDB: Selected entry - model=%d DS=%.3fns shape=%ux%u L=%u/%u S=%u fs=%.0f dt=%.6fs speed=%.3fm/s aoa=%.1fdeg\n",
|
||||
G.model_id,
|
||||
G.ds_ns,
|
||||
G.n_tx,
|
||||
@@ -289,7 +291,8 @@ void cirdb_connect(int id,
|
||||
G.S,
|
||||
G.fs_hz,
|
||||
G.snapshot_dt_s,
|
||||
G.speed_mps);
|
||||
G.speed_mps,
|
||||
sel->want_aoa_deg);
|
||||
}
|
||||
|
||||
void cirdb_update(uint64_t ns_since_start)
|
||||
|
||||
@@ -25,6 +25,7 @@ typedef struct {
|
||||
int want_model_id; /* 0..4, or <0 for no preference */
|
||||
float want_ds_ns; /* nonnegative, or <0 for no preference */
|
||||
float want_speed_mps; /* nonnegative, or <0 for no preference */
|
||||
float want_aoa_deg; /* degrees; TDL-D/E only; 0.0 = broadside default */
|
||||
} cirdb_select_opts_t;
|
||||
|
||||
/* Initialize provider and publish snapshot 0 through channel_desc_out. */
|
||||
|
||||
@@ -96,6 +96,11 @@ int cirdb_yaml_select(const cirdb_select_req_t *req, cirdb_entry_meta_t *out)
|
||||
|
||||
float ds_ns = e["ds_ns"].as<float>(0.0f);
|
||||
float sp = e["speed_mps"].as<float>(0.0f);
|
||||
float aoa = e["los_aoa_deg"].as<float>(0.0f);
|
||||
|
||||
// STRICT: AoA exact match when entry has los_aoa_deg field
|
||||
if (e["los_aoa_deg"].IsDefined() && dabs(aoa - req->want_aoa_deg) > 0.01)
|
||||
continue;
|
||||
|
||||
// FLEXIBLE: delay spread and speed - find closest match using cost function
|
||||
double cds = 0.0;
|
||||
|
||||
@@ -15,6 +15,7 @@ typedef struct {
|
||||
int want_rx; // exact match
|
||||
float want_ds_ns; // nearest
|
||||
float want_speed_mps; // nearest
|
||||
float want_aoa_deg; // exact match; 0.0 = broadside default
|
||||
int allow_shape_swap; // allow TX/RX swap when matching
|
||||
float w_ds; // DS distance weight
|
||||
float w_speed; // speed distance weight
|
||||
|
||||
@@ -76,6 +76,7 @@ typedef enum { ROLE_SERVER = 1, ROLE_CLIENT } role;
|
||||
{"cirdb_model_id", "Preferred TDL model id 0..4", 0, .iptr = &vrtsim_state->cirdb_model_id, .defintval = 0, TYPE_INT, 0}, \
|
||||
{"cirdb_ds_ns", "Desired RMS delay spread in ns", 0, .dblptr = &vrtsim_state->cirdb_ds_ns, .defdblval = 10.0, TYPE_DOUBLE, 0}, \
|
||||
{"cirdb_speed_mps", "Desired speed in m/s", 0, .dblptr = &vrtsim_state->cirdb_speed_mps, .defdblval = 1.5, TYPE_DOUBLE, 0}, \
|
||||
{"cirdb_aoa_deg", "Desired AoA in degrees (TDL-D/E only)", 0, .dblptr = &vrtsim_state->cirdb_aoa_deg, .defdblval = 0.0, TYPE_DOUBLE, 0}, \
|
||||
{"num_ues", "Number of UE slots (server only)\n", 0, .iptr = &vrtsim_state->num_ues, .defintval = 1, TYPE_INT, 0}, \
|
||||
{"ue_id", "UE slot index 0..num_ues-1 (client only)\n", 0, .iptr = &vrtsim_state->ue_id, .defintval = 0, TYPE_INT, 0}, \
|
||||
{"thread-pool", TPOOL_HLP, .strptr = &vrtsim_state->thread_pool_cores, .defstrval = "-1,-1,-1,-1", TYPE_STRING, 0} \
|
||||
@@ -106,6 +107,7 @@ typedef struct {
|
||||
int model_id;
|
||||
double ds_ns;
|
||||
double speed_mps;
|
||||
double aoa_deg;
|
||||
} cirdb_conf_t;
|
||||
|
||||
typedef struct {
|
||||
@@ -148,6 +150,7 @@ typedef struct {
|
||||
int cirdb_model_id;
|
||||
double cirdb_ds_ns;
|
||||
double cirdb_speed_mps;
|
||||
double cirdb_aoa_deg;
|
||||
// Multi-UE support
|
||||
int num_ues;
|
||||
int ue_id;
|
||||
@@ -323,13 +326,16 @@ static void parse_ue_config(vrtsim_state_t *vrtsim_state)
|
||||
int model_id = vrtsim_state->cirdb_model_id;
|
||||
double ds_ns = vrtsim_state->cirdb_ds_ns;
|
||||
double speed_mps = vrtsim_state->cirdb_speed_mps;
|
||||
double aoa_deg = vrtsim_state->cirdb_aoa_deg;
|
||||
|
||||
paramdef_t ue_params[] = {
|
||||
{"antennas", "Antenna config e.g. \"1x2\"", 0, .strptr = &antennas, .defstrval = NULL, TYPE_STRING, 0},
|
||||
{"model_id", "TDL model id 0..4", 0, .iptr = &model_id, .defintval = vrtsim_state->cirdb_model_id, TYPE_INT, 0},
|
||||
{"ds_ns", "Delay spread in ns", 0, .dblptr = &ds_ns, .defdblval = vrtsim_state->cirdb_ds_ns, TYPE_DOUBLE, 0},
|
||||
{"speed_mps", "Speed in m/s", 0, .dblptr = &speed_mps, .defdblval = vrtsim_state->cirdb_speed_mps, TYPE_DOUBLE, 0},
|
||||
{"aoa_deg", "LOS AoA in degrees (TDL-D/E only)", 0, .dblptr = &aoa_deg, .defdblval = vrtsim_state->cirdb_aoa_deg, TYPE_DOUBLE, 0},
|
||||
};
|
||||
|
||||
config_get(config_get_if(), ue_params, sizeofArray(ue_params), prefix);
|
||||
|
||||
if (antennas != NULL) {
|
||||
@@ -357,12 +363,13 @@ static void parse_ue_config(vrtsim_state_t *vrtsim_state)
|
||||
vrtsim_state->ue_conf[i].cir_conf.model_id = model_id;
|
||||
vrtsim_state->ue_conf[i].cir_conf.ds_ns = ds_ns;
|
||||
vrtsim_state->ue_conf[i].cir_conf.speed_mps = speed_mps;
|
||||
vrtsim_state->ue_conf[i].cir_conf.aoa_deg = aoa_deg;
|
||||
|
||||
LOG_I(HW, "VRTSIM: UE %d - %dx%d antennas, Model %d (TDL-%c), DS %.1fns, Speed %.1fm/s\n",
|
||||
LOG_I(HW, "VRTSIM: UE %d - %dx%d antennas, Model %d (TDL-%c), DS %.1fns, Speed %.1fm/s, AoA %.1fdeg\n",
|
||||
i,
|
||||
vrtsim_state->ue_conf[i].tx_ant,
|
||||
vrtsim_state->ue_conf[i].rx_ant,
|
||||
model_id, 'A' + model_id, ds_ns, speed_mps);
|
||||
model_id, 'A' + model_id, ds_ns, speed_mps, aoa_deg);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -450,14 +457,17 @@ static int vrtsim_connect(openair0_device_t *device)
|
||||
vrtsim_state->cirdb_model_id = vrtsim_state->ue.cir_conf.model_id;
|
||||
vrtsim_state->cirdb_ds_ns = vrtsim_state->ue.cir_conf.ds_ns;
|
||||
vrtsim_state->cirdb_speed_mps = vrtsim_state->ue.cir_conf.speed_mps;
|
||||
vrtsim_state->cirdb_aoa_deg = vrtsim_state->ue.cir_conf.aoa_deg;
|
||||
|
||||
|
||||
LOG_I(HW,
|
||||
"VRTSIM: UE %d channel - Model %d (TDL-%c), DS %.1fns, Speed %.1fm/s\n",
|
||||
"VRTSIM: UE %d channel - Model %d (TDL-%c), DS %.1fns, Speed %.1fm/s, AoA %.1fdeg\n",
|
||||
vrtsim_state->ue_id,
|
||||
vrtsim_state->cirdb_model_id,
|
||||
'A' + vrtsim_state->cirdb_model_id,
|
||||
vrtsim_state->cirdb_ds_ns,
|
||||
vrtsim_state->cirdb_speed_mps);
|
||||
vrtsim_state->cirdb_speed_mps,
|
||||
vrtsim_state->cirdb_aoa_deg);
|
||||
}
|
||||
vrtsim_state->channel = shm_td_iq_channel_connect(DEFAULT_CHANNEL_NAME, 10);
|
||||
vrtsim_state->peer_info.num_rx_antennas = client_info.gnb_num_rx_ant;
|
||||
@@ -507,6 +517,7 @@ static int vrtsim_connect(openair0_device_t *device)
|
||||
sel.want_model_id = vrtsim_state->cirdb_model_id;
|
||||
sel.want_ds_ns = (float)(vrtsim_state->cirdb_ds_ns > 0.0 ? vrtsim_state->cirdb_ds_ns : -1.0);
|
||||
sel.want_speed_mps = (float)(vrtsim_state->cirdb_speed_mps > 0.0 ? vrtsim_state->cirdb_speed_mps : -1.0);
|
||||
sel.want_aoa_deg = (float)vrtsim_state->cirdb_aoa_deg;
|
||||
|
||||
LOG_A(HW,
|
||||
"VRTSIM: CIR DB select yaml='%s' bin='%s'\n",
|
||||
@@ -520,6 +531,7 @@ static int vrtsim_connect(openair0_device_t *device)
|
||||
ue_sel.want_model_id = vrtsim_state->ue_conf[u].cir_conf.model_id;
|
||||
ue_sel.want_ds_ns = vrtsim_state->ue_conf[u].cir_conf.ds_ns;
|
||||
ue_sel.want_speed_mps = vrtsim_state->ue_conf[u].cir_conf.speed_mps;
|
||||
ue_sel.want_aoa_deg = (float)vrtsim_state->ue_conf[u].cir_conf.aoa_deg;
|
||||
|
||||
AssertFatal(ue_sel.want_model_id >= 0 && ue_sel.want_model_id <= 4,
|
||||
"Invalid CIRDB model_id=%d for UE %d\n",
|
||||
|
||||
@@ -26,7 +26,7 @@ gNBs =
|
||||
maxMIMO_layers = 2;
|
||||
do_CSIRS = 1;
|
||||
do_SRS = 0;
|
||||
min_rxtxtime = 4;
|
||||
min_rxtxtime = 3;
|
||||
|
||||
servingCellConfigCommon = (
|
||||
{
|
||||
@@ -37,20 +37,20 @@ gNBs =
|
||||
# downlinkConfigCommon
|
||||
#frequencyInfoDL
|
||||
# center frequency = 28701.12 MHz
|
||||
# selected SSB frequency = 28691.04 MHz
|
||||
absoluteFrequencySSB = 2090683;
|
||||
# selected SSB frequency = 28656.48 MHz
|
||||
absoluteFrequencySSB = 2090107;
|
||||
dl_frequencyBand = 257;
|
||||
# frequency point A = 28653.6 MHz
|
||||
dl_absoluteFrequencyPointA = 2090059;
|
||||
# frequency point A = 28606.08 MHz
|
||||
dl_absoluteFrequencyPointA = 2089267;
|
||||
#scs-SpecificCarrierList
|
||||
dl_offstToCarrier = 0;
|
||||
# subcarrierSpacing
|
||||
# 0=kHz15, 1=kHz30, 2=kHz60, 3=kHz120
|
||||
dl_subcarrierSpacing = 3;
|
||||
dl_carrierBandwidth = 66;
|
||||
dl_carrierBandwidth = 132;
|
||||
#initialDownlinkBWP
|
||||
#genericParameters
|
||||
initialDLBWPlocationAndBandwidth = 17875;
|
||||
initialDLBWPlocationAndBandwidth = 36025;
|
||||
# subcarrierSpacing
|
||||
# 0=kHz15, 1=kHz30, 2=kHz60, 3=kHz120
|
||||
initialDLBWPsubcarrierSpacing = 3;
|
||||
@@ -66,11 +66,11 @@ gNBs =
|
||||
# subcarrierSpacing
|
||||
# 0=kHz15, 1=kHz30, 2=kHz60, 3=kHz120
|
||||
ul_subcarrierSpacing = 3;
|
||||
ul_carrierBandwidth = 66;
|
||||
ul_carrierBandwidth = 132;
|
||||
pMax = 20;
|
||||
#initialUplinkBWP
|
||||
#genericParameters
|
||||
initialULBWPlocationAndBandwidth = 17875;
|
||||
initialULBWPlocationAndBandwidth = 36025;
|
||||
# subcarrierSpacing
|
||||
# 0=kHz15, 1=kHz30, 2=kHz60, 3=kHz120
|
||||
initialULBWPsubcarrierSpacing = 3;
|
||||
@@ -90,7 +90,7 @@ gNBs =
|
||||
powerRampingStep = 2;
|
||||
#ssb_perRACH_OccasionAndCB_PreamblesPerSSB_PR
|
||||
#1=oneeighth,2=onefourth,3=half,4=one,5=two,6=four,7=eight,8=sixteen
|
||||
ssb_perRACH_OccasionAndCB_PreamblesPerSSB_PR = 3;
|
||||
ssb_perRACH_OccasionAndCB_PreamblesPerSSB_PR = 4;
|
||||
#one (0..15) 4,8,12,16,...60,64
|
||||
ssb_perRACH_OccasionAndCB_PreamblesPerSSB = 15;
|
||||
#ra_ContentionResolutionTimer
|
||||
@@ -119,11 +119,11 @@ gNBs =
|
||||
hoppingId = 40;
|
||||
p0_nominal = -90;
|
||||
|
||||
ssb_PositionsInBurst_Bitmap = 1;
|
||||
ssb_PositionsInBurst_Bitmap = 4;
|
||||
|
||||
# ssb_periodicityServingCell
|
||||
# 0 = ms5, 1=ms10, 2=ms20, 3=ms40, 4=ms80, 5=ms160, 6=spare2, 7=spare1
|
||||
ssb_periodicityServingCell = 1;
|
||||
ssb_periodicityServingCell = 4;
|
||||
|
||||
# dmrs_TypeA_position
|
||||
# 0 = pos2, 1 = pos3
|
||||
@@ -141,11 +141,11 @@ gNBs =
|
||||
# pattern1
|
||||
# dl_UL_TransmissionPeriodicity
|
||||
# 0=ms0p5, 1=ms0p625, 2=ms1, 3=ms1p25, 4=ms2, 5=ms2p5, 6=ms5, 7=ms10
|
||||
dl_UL_TransmissionPeriodicity = 3;
|
||||
nrofDownlinkSlots = 7;
|
||||
nrofDownlinkSymbols = 6;
|
||||
nrofUplinkSlots = 2;
|
||||
nrofUplinkSymbols = 4;
|
||||
dl_UL_TransmissionPeriodicity = 1;
|
||||
nrofDownlinkSlots = 3;
|
||||
nrofDownlinkSymbols = 10;
|
||||
nrofUplinkSlots = 1;
|
||||
nrofUplinkSymbols = 2;
|
||||
|
||||
ssPBCH_BlockPower = 0;
|
||||
}
|
||||
@@ -166,8 +166,8 @@ gNBs =
|
||||
|
||||
NETWORK_INTERFACES :
|
||||
{
|
||||
GNB_IPV4_ADDRESS_FOR_NG_AMF = "172.21.16.51";
|
||||
GNB_IPV4_ADDRESS_FOR_NGU = "172.21.16.51";
|
||||
GNB_IPV4_ADDRESS_FOR_NG_AMF = "172.21.18.51";
|
||||
GNB_IPV4_ADDRESS_FOR_NGU = "172.21.18.51";
|
||||
GNB_PORT_FOR_S1U = 2152; # Spec 2152
|
||||
};
|
||||
}
|
||||
@@ -178,7 +178,7 @@ MACRLCs = (
|
||||
tr_s_preference = "local_L1";
|
||||
tr_n_preference = "local_RRC";
|
||||
pusch_TargetSNRx10 = 200;
|
||||
pucch_TargetSNRx10 = 200;
|
||||
pucch_TargetSNRx10 = 250;
|
||||
pusch_FailureThres = 1000;
|
||||
#ul_bler_target_upper =.02;
|
||||
#ul_bler_target_lower =.01;
|
||||
@@ -195,12 +195,12 @@ L1s = (
|
||||
{
|
||||
tr_n_preference = "local_mac";
|
||||
prach_dtx_threshold = 250;
|
||||
pucch0_dtx_threshold = 100;
|
||||
pucch0_dtx_threshold = 150;
|
||||
pusch_dtx_threshold = -200;
|
||||
max_ldpc_iterations = 10;
|
||||
tx_amp_backoff_dB = 18;
|
||||
L1_rx_thread_core = 10;
|
||||
L1_tx_thread_core = 11;
|
||||
L1_rx_thread_core = 37;
|
||||
L1_tx_thread_core = 36;
|
||||
phase_compensation = 1;
|
||||
|
||||
}
|
||||
@@ -219,8 +219,8 @@ RUs = (
|
||||
max_rxgain = 60;
|
||||
#sf_extension = 0;
|
||||
eNB_instances = [0];
|
||||
ru_thread_core = 9;
|
||||
sl_ahead = 10;
|
||||
ru_thread_core = 35;
|
||||
sl_ahead = 5;
|
||||
tr_preference = "raw_if4p5";
|
||||
do_precoding = 0;
|
||||
}
|
||||
@@ -257,10 +257,10 @@ log_config :
|
||||
};
|
||||
|
||||
fhi_72 = {
|
||||
dpdk_devices = ("0000:c1:11.0", "0000:c1:11.1"); # one VF can be used as well
|
||||
system_core = 6;
|
||||
io_core = 7;
|
||||
worker_cores = (8);
|
||||
dpdk_devices = ("01:01.0","01:01.1");
|
||||
system_core = 32;
|
||||
io_core = 33;
|
||||
worker_cores = (34);
|
||||
ru_addr = ("E8:C7:4F:1E:C7:5B", "E8:C7:4F:1E:C7:5B");
|
||||
mtu = 9216;
|
||||
fh_config = ({
|
||||
Reference in New Issue
Block a user