implemented bus read and write

This commit is contained in:
2026-05-29 15:54:29 +02:00
parent 55b5511485
commit ff9f7c2795
13 changed files with 355 additions and 14 deletions
@@ -1,6 +1,7 @@
set(SOURCES
${CMAKE_CURRENT_SOURCE_DIR}/src/TCPInterface.cpp
${CMAKE_CURRENT_SOURCE_DIR}/src/CommandLineOptions.cpp
${CMAKE_CURRENT_SOURCE_DIR}/src/MemoryModel.cpp
)
add_library(slsServerObject OBJECT
@@ -0,0 +1,88 @@
#pragma once
#include "RegisterHelperStructs.hpp"
#include "fmt/format.h"
#include <cstdint>
#include <fcntl.h>
#include <map>
#include <memory>
#include <stdexcept>
#include <sys/mman.h>
#include <vector>
// TODO: maybe should be templated on address type (e.g. uint32_t or uint64_t)
// for more flexibility?
namespace sls {
template <typename IPCoreEnumType, typename MemoryModel>
struct IpCoreRegisterBlock {
std::map<IPCoreEnumType, MemoryModel> &operator()() {
return memoryblocks_;
}
private:
std::map<IPCoreEnumType, MemoryModel> memoryblocks_;
};
template <typename IPCoreEnumType, typename MemoryModel>
class BusCommunication {
public:
BusCommunication() = default;
void mapToMemory();
uint32_t readRegister(const Register &register_) const;
void writeRegister(const Register &register_, const uint32_t data) const;
private:
/// @brief stores register blocks for each IP core
IpCoreRegisterBlock<IPCoreEnumType, MemoryModel> ipcoreregisterblocks;
void bus_w(const uint32_t offset, const uint32_t baseadress,
const uint32_t data) const;
uint32_t bus_r(const uint32_t offset, const uint32_t baseadress) const;
};
template <typename IPCoreEnumType, typename MemoryModel>
void BusCommunication<IPCoreEnumType, MemoryModel>::mapToMemory() {
for (auto &map_elem : ipcoreregisterblocks()) {
map_elem.second.mapToMemory();
}
}
template <typename IPCoreEnumType, typename MemoryModel>
uint32_t BusCommunication<IPCoreEnumType, MemoryModel>::readRegister(
const Register &register_) const {
return bus_r(register_.offset_in_bytes,
static_cast<uint32_t>(register_.ip_core));
}
template <typename IPCoreEnumType, typename MemoryModel>
void BusCommunication<IPCoreEnumType, MemoryModel>::writeRegister(
const Register &register_, const uint32_t data) const {
bus_w(register_.offset_in_bytes, static_cast<uint32_t>(register_.ip_core),
data);
}
template <typename IPCoreEnumType, typename MemoryModel>
uint32_t BusCommunication<IPCoreEnumType, MemoryModel>::bus_r(
const uint32_t offset, const uint32_t baseadress) const {
auto ptr1 = ipcoreregisterblocks()[baseadress].getMappedMemoryPtr() +
offset / (sizeof(uint32_t));
return *ptr1;
}
template <typename IPCoreEnumType, typename MemoryModel>
void BusCommunication<IPCoreEnumType, MemoryModel>::bus_w(
const uint32_t offset, const uint32_t baseadress,
const uint32_t data) const {
auto ptr1 = ipcoreregisterblocks()[baseadress].getMappedMemoryPtr() +
offset / (sizeof(uint32_t));
*ptr1 = data;
}
} // namespace sls
@@ -67,7 +67,7 @@ template <typename DerivedDetectorServer> class DetectorServer {
/// @brief TODO what is this?
bool updateMode{true};
/// @brief
/// @brief shared mempory with aquisition status
mutable SharedMemory<acquisitionStatus> shm{
0, 0}; // TODO: is mutable really neccessary?
@@ -162,7 +162,9 @@ ReturnCode DetectorServer<DerivedDetectorServer>::processFunction(
case detFuncs::F_GET_RUN_STATUS:
return static_cast<DerivedDetectorServer *>(this)->get_run_status(
socket);
case detFuncs::F_GET_RECEIVER_PARAMETERS:
return static_cast<DerivedDetectorServer *>(this)
->get_receiver_parameters(socket);
default:
LOG(logDEBUG) << "Checking specific server functions for function ID: "
<< function_id;
@@ -0,0 +1,61 @@
#include "fmt/format.h"
#include <cstdint>
#include <memory>
/// @brief class to handle memory mapping and access for hardware IP cores
class HardwareMemoryModel {
public:
HardwareMemoryModel(const uint32_t IPcore_base_address,
const size_t size_memory_space_);
~HardwareMemoryModel();
void mapToMemory();
void unmapMemory();
volatile uint32_t *getMappedMemoryPtr() const;
private:
volatile uint32_t *mapped_memory_ptr{nullptr};
/// @brief offset of the IP core base address in the memory space, used for
/// mapping
const size_t IPCore_base_address{0};
/// @brief size mapped memory region [bytes]
const size_t size_memory_space{0};
};
/// @brief class to handle memory mapping and access for virtual IP cores (e.g.
/// use software implementation of memory)
class VirtualMemoryModel {
public:
VirtualMemoryModel(const uint32_t IPcore_base_address,
const size_t size_memory_space_);
~VirtualMemoryModel() = default;
VirtualMemoryModel(const VirtualMemoryModel &) = delete;
VirtualMemoryModel &operator=(const VirtualMemoryModel &) = delete;
VirtualMemoryModel(VirtualMemoryModel &&) noexcept = default;
VirtualMemoryModel &
operator=(VirtualMemoryModel &&) = delete; // const members
void mapToMemory();
uint32_t *getMappedMemoryPtr() const;
private:
std::unique_ptr<uint32_t[]> mapped_memory_ptr;
/// @brief offset of the IP core base address in the memory space, used for
/// mapping
const size_t IPCore_base_address{0};
/// @brief size mapped memory region [bytes]
const size_t size_memory_space{0};
};
@@ -0,0 +1,30 @@
#pragma once
#include <cstdint>
#include <string_view>
namespace sls {
enum class IPCore : uint32_t; // forward declaration of IPCore enum class
struct Register {
/// @brief IP core address space
const IPCore ip_core{}; // TODO replace by enum type
/// @brief Offset of the register in bytes from the base address of the IP
/// core
const uint32_t offset_in_bytes{};
};
struct RegisterField {
/// @brief Register to which the field belongs
const Register register_{};
/// @brief Bit position of the least significant bit of the field in the
/// register
const uint32_t bit_position{};
/// @brief Bitmask for the field
const uint32_t bitmask{};
};
} // namespace sls
@@ -0,0 +1,68 @@
#include "MemoryModel.hpp"
#include <fcntl.h>
#include <memory>
#include <stdexcept>
#include <stdio.h>
#include <sys/mman.h>
#include <unistd.h>
HardwareMemoryModel::HardwareMemoryModel(const uint32_t IPcore_base_address,
const size_t size_memory_space_)
: IPCore_base_address(IPcore_base_address),
size_memory_space(size_memory_space_) {}
void HardwareMemoryModel::mapToMemory() {
int fd = open("/dev/mem", O_RDWR | O_SYNC, 0);
if (fd == -1) {
throw std::runtime_error("Can't find /dev/mem");
}
mapped_memory_ptr = reinterpret_cast<volatile uint32_t *>(
mmap(nullptr, size_memory_space, PROT_READ | PROT_WRITE, MAP_SHARED, fd,
IPCore_base_address));
if (mapped_memory_ptr ==
reinterpret_cast<volatile uint32_t *>(MAP_FAILED)) {
throw std::runtime_error(
fmt::format("Failed to map base address: {}",
IPCore_base_address)); // TODO: needs ToString
}
close(fd);
}
volatile uint32_t *HardwareMemoryModel::getMappedMemoryPtr() const {
return mapped_memory_ptr;
}
void HardwareMemoryModel::unmapMemory() {
if (mapped_memory_ptr != nullptr) {
if (munmap(const_cast<uint32_t *>(mapped_memory_ptr),
size_memory_space) < 0) {
throw std::runtime_error(
fmt::format("Failed to unmap memory for IP core: {}",
IPCore_base_address)); // TODO: needs ToString
}
mapped_memory_ptr = nullptr;
}
}
HardwareMemoryModel::~HardwareMemoryModel() { unmapMemory(); }
VirtualMemoryModel::VirtualMemoryModel(const uint32_t IPcore_base_address,
const size_t size_memory_space_)
: IPCore_base_address(IPcore_base_address),
size_memory_space(size_memory_space_) {}
void VirtualMemoryModel::mapToMemory() {
mapped_memory_ptr =
std::make_unique<uint32_t[]>(size_memory_space / sizeof(uint32_t));
}
uint32_t *VirtualMemoryModel::getMappedMemoryPtr() const {
return mapped_memory_ptr.get();
}