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
View File
@@ -78,6 +78,7 @@ constexpr RegisterField ModuleIndex{
"""
postpend = r"""
} // namespace Reg
} // namespace sls
// clang-format on
"""
@@ -1,7 +1,10 @@
#pragma once
#include "ArmBusCommunication.hpp"
#include "DetectorServer.h"
#include "MemoryModel.hpp"
#include "RegisterDefs.hpp"
#include "SpecializedTemplates.h"
#include "TCPInterface.h"
// #include "communication_funcs.h"
#include "fmt/format.h"
#include "sls/logger.h"
#include "sls/network_utils.h"
@@ -16,6 +19,9 @@
namespace sls {
class VirtualMatterhornServer; // forward declaration
class MatterhornServer; // forward declaration
/// @brief Base class for Matterhorn Server, can be used to implement a virtual
/// server for testing and actual server
template <typename DerivedServer>
@@ -45,6 +51,8 @@ class BaseMatterhornServer
ReturnCode get_run_status(ServerInterface &socket) const;
ReturnCode get_receiver_parameters(ServerInterface &socket) const;
/**
* @brief call function corresponding to the function ID received from the
* client and send back the result
@@ -54,9 +62,18 @@ class BaseMatterhornServer
ReturnCode processFunction(const detFuncs function_id,
ServerInterface &socket);
protected:
using MemoryModel = std::conditional_t<
std::is_same_v<DerivedServer, VirtualMatterhornServer>,
VirtualMemoryModel, HardwareMemoryModel>;
BusCommunication<IPCore, MemoryModel> busCommunication{};
private:
static std::string getMatterhornServerVersion();
int64_t getNumFrames() const;
static constexpr uint8_t numUDPInterfaces =
1; // only one udp per module for now
};
@@ -119,4 +136,41 @@ ReturnCode BaseMatterhornServer<DerivedServer>::get_run_status(
return static_cast<const DerivedServer *>(this)->get_run_status(socket);
}
template <typename DerivedServer>
ReturnCode BaseMatterhornServer<DerivedServer>::get_receiver_parameters(
ServerInterface &socket) const {
slsDetectorDefs::rxParameters rx_params{};
rx_params.udpInterfaces = numUDPInterfaces;
rx_params.udp_dstip = this->udpDetails[0].dstip;
rx_params.udp_dstport = this->udpDetails[0].dstport;
rx_params.udp_dstmac = this->udpDetails[0].dstmac;
rx_params.frames = static_cast<const DerivedServer *>(this)->get_frames();
// rx_params.triggers = 0;
// rx_params.expTimeNs = 0;
// rx_params.periodNs = 0;
// rx_params.dynamicRange = 0;
// rx_params.timMode = AUTO_TIMING;
// rx_params.counterMask = 0;
return static_cast<ReturnCode>(socket.sendResult(rx_params));
}
template <typename DerivedServer>
int64_t BaseMatterhornServer<DerivedServer>::getNumFrames() const {
// bus_r(Reg::MH_SM_Frames_Reg);
return 0; // TODO: implement
}
} // namespace sls
@@ -1,19 +1,24 @@
// clang-format off
#pragma once
#include "RegisterHelperStructs.hpp"
namespace sls {
/// @brief Enum for IP cores, value are adresses
constexpr enum class IPCore : uint32_t {
MH_RO_SM_AXI = 0, // dummy adresses for now
FHDR_AXI = 1,
AURORA_STATUS = 2,
AURORA_STATUS2 = 3,
enum class IPCore : uint32_t {
MH_RO_SM_AXI = 0xB0010000,
FHDR_AXI = 0xB0011000,
AURORA_STATUS = 0xB0014000,
AURORA_STATUS2 = 0xB0015000,
PACKETIZERREG = 4,
UNKNOWN = 5
UNKNOWN = 0x00000000 // dont know yet
};
constexpr size_t IPCORE_REGISTER_BLOCK_SIZE =
0x1000; // size of each IP core address space in bytes // TODO: maybe add in
// other file definitions
// clang-format off
namespace Reg {
// Register definitions
constexpr Register CTRL_Reg{IPCore::UNKNOWN, 0x0};
@@ -22,7 +27,7 @@ constexpr Register Status_Reg{IPCore::UNKNOWN, 0x4};
constexpr Register FPGAVersionReg{IPCore::UNKNOWN, 0x8};
constexpr Register FPGA_GIT_HEAD{IPCore::UNKNOWN, 0xc};
constexpr Register FPGA_GIT_HEAD_Reg{IPCore::UNKNOWN, 0xc};
constexpr Register FixedPatternReg{IPCore::UNKNOWN, 0x10};
@@ -116,7 +121,7 @@ constexpr RegisterField FPGADetType{
FPGAVersionReg, 24, 0xff};
constexpr RegisterField FPGA_GIT_HEAD{
FPGA_GIT_HEAD, 0, 0xffffffff};
FPGA_GIT_HEAD_Reg, 0, 0xffffffff};
constexpr RegisterField FixedPattern{
FixedPatternReg, 0, 0xffffffff};
@@ -235,6 +240,7 @@ constexpr RegisterField Coordy{
constexpr RegisterField Coordz{
PktCoordReg2, 0, 0xffff};
} // namespace Reg
} // namespace sls
// clang-format on
@@ -0,0 +1,48 @@
#pragma once
#include "ArmBusCommunication.hpp"
#include "RegisterDefs.hpp"
/**
* @file SpecializedTemplates.h
* @short contains specializations of the template classes for the Matterhorn
* server implementation
*/
namespace sls {
template <typename MemoryModel>
struct IpCoreRegisterBlock<IPCore, MemoryModel> {
std::map<IPCore, MemoryModel> &operator()() {
memoryblocks_.try_emplace(
IPCore::MH_RO_SM_AXI,
MemoryModel{static_cast<uint32_t>(IPCore::MH_RO_SM_AXI),
IPCORE_REGISTER_BLOCK_SIZE});
memoryblocks_.try_emplace(
IPCore::FHDR_AXI,
MemoryModel{static_cast<uint32_t>(IPCore::FHDR_AXI),
IPCORE_REGISTER_BLOCK_SIZE});
memoryblocks_.try_emplace(
IPCore::AURORA_STATUS,
MemoryModel{static_cast<uint32_t>(IPCore::AURORA_STATUS),
IPCORE_REGISTER_BLOCK_SIZE});
memoryblocks_.try_emplace(
IPCore::AURORA_STATUS2,
MemoryModel{static_cast<uint32_t>(IPCore::AURORA_STATUS2),
IPCORE_REGISTER_BLOCK_SIZE});
memoryblocks_.try_emplace(
IPCore::PACKETIZERREG,
MemoryModel{static_cast<uint32_t>(IPCore::PACKETIZERREG),
IPCORE_REGISTER_BLOCK_SIZE});
memoryblocks_.try_emplace(
IPCore::UNKNOWN, MemoryModel{static_cast<uint32_t>(IPCore::UNKNOWN),
IPCORE_REGISTER_BLOCK_SIZE});
return memoryblocks_;
}
private:
std::map<IPCore, MemoryModel> memoryblocks_;
};
} // namespace sls
@@ -21,6 +21,8 @@ class VirtualMatterhornServer
ReturnCode initial_checks(ServerInterface &socket);
ReturnCode get_run_status(ServerInterface &socket) const;
size_t get_frames() const;
};
} // namespace sls
@@ -5,7 +5,8 @@ namespace sls {
MatterhornServer::MatterhornServer(uint16_t port)
: BaseMatterhornServer<MatterhornServer>(port) {
// TODO: when do i set the udp mac and ip ?
// map the IP core base addresses to memory
busCommunication.mapToMemory(); // TODO: should this happen in constructor?
// should maybe be part of the constructor?
tcpInterface->startTCPServer();
@@ -8,6 +8,9 @@ VirtualMatterhornServer::VirtualMatterhornServer(uint16_t port)
udpDetails[0].srcip = LOCALHOSTIP_INT;
// map the IP core base addresses to virtual memory
busCommunication.mapToMemory();
// should maybe be part of the constructor?
tcpInterface->startTCPServer();
@@ -42,4 +45,9 @@ VirtualMatterhornServer::get_run_status(ServerInterface &socket) const {
return static_cast<ReturnCode>(socket.sendResult(status));
}
size_t VirtualMatterhornServer::get_frames() const {
// TODO: dummy implementation for now
return 0;
}
} // namespace sls
@@ -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,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();
}