diff --git a/include/hxcomm/common/cerealization_quiggeldy_interface_types.h b/include/hxcomm/common/cerealization_quiggeldy_interface_types.h new file mode 100644 index 0000000000000000000000000000000000000000..5ecba3740836d520ea1e0295802ad635f6e22fc0 --- /dev/null +++ b/include/hxcomm/common/cerealization_quiggeldy_interface_types.h @@ -0,0 +1,16 @@ +#pragma once +#include "hxcomm/common/quiggeldy_interface_types.h" +#include <cereal/cereal.hpp> +#include <cereal/types/optional.hpp> + +namespace cereal { + +template <typename Archive, typename ConnectionParameter> +void CEREAL_SERIALIZE_FUNCTION_NAME( + Archive& ar, typename hxcomm::detail::ReinitEntryType<ConnectionParameter>& reinit_entry) +{ + ar(CEREAL_NVP(reinit_entry.request)); + ar(CEREAL_NVP(reinit_entry.snapshot)); +} + +} // namespace cereal diff --git a/include/hxcomm/common/connection_parameter.h b/include/hxcomm/common/connection_parameter.h index 1ace340dd1f5ca9c5c1b937c2eab77735d3bcdfb..b656262a143789e865a87be8086b2f07a0b9c459 100644 --- a/include/hxcomm/common/connection_parameter.h +++ b/include/hxcomm/common/connection_parameter.h @@ -37,6 +37,8 @@ struct UTMessageParameter * @tparam ReceivePhywordType Type of PHY-word of receive UTMessage set * @tparam ReceiveDictionary Dictionary of instructions of received UTMessages * @tparam ReceiveHaltInstructionType Instruction type of Halt message in receive dictionary + * @tparam QuiggeldyScheduleOutToInTransformType Functor to transform a schedule-out result to + * schedule-in instructions in quiggeldy */ template < size_t SendHeaderAlignment, @@ -49,7 +51,8 @@ template < typename ReceivePhywordType, typename ReceiveDictionary, typename ReceiveHaltInstructionType, - typename ReceiveTimeoutInstructionType> + typename ReceiveTimeoutInstructionType, + typename QuiggeldyScheduleOutToInTransformType> struct ConnectionParameter { typedef UTMessageParameter< @@ -67,6 +70,7 @@ struct ConnectionParameter Receive; typedef ReceiveHaltInstructionType ReceiveHalt; typedef ReceiveTimeoutInstructionType ReceiveTimeout; + typedef QuiggeldyScheduleOutToInTransformType QuiggeldyScheduleOutToInTransform; }; } // namespace hxcomm diff --git a/include/hxcomm/common/quiggeldy_interface_types.h b/include/hxcomm/common/quiggeldy_interface_types.h index 0ce1341e2ab8233d7e5f0c3e0ceef7eae655e5e4..311bc65c19ebe586657ef6a4e0032c94399a5c1e 100644 --- a/include/hxcomm/common/quiggeldy_interface_types.h +++ b/include/hxcomm/common/quiggeldy_interface_types.h @@ -4,11 +4,27 @@ #include "hxcomm/common/connection_time_info.h" #include "hxcomm/common/execute_messages.h" +#include <optional> #include <utility> #include <vector> namespace hxcomm { +namespace detail { + +template <typename ConnectionParameter> +struct ReinitEntryType +{ + using request_type = detail::execute_messages_argument_t<ConnectionParameter>; + + request_type request; + + std::optional<request_type> snapshot; + typedef typename ConnectionParameter::QuiggeldyScheduleOutToInTransform transform_type; +}; + +} // namespace detail + template <typename ConnectionParameter> struct quiggeldy_interface_types { @@ -16,8 +32,8 @@ struct quiggeldy_interface_types using request_type = detail::execute_messages_argument_t<ConnectionParameter>; using response_type = detail::execute_messages_return_t<ConnectionParameter>; - using reinit_type = std::vector<request_type>; - using reinit_entry_type = typename reinit_type::value_type; + using reinit_entry_type = detail::ReinitEntryType<ConnectionParameter>; + using reinit_type = std::vector<reinit_entry_type>; }; // convenience partial specialization if only message types are available diff --git a/include/hxcomm/common/quiggeldy_worker.h b/include/hxcomm/common/quiggeldy_worker.h index 1d6129bcdd773adc85bb32a2c3abe88162593da9..6bfb831009df2f60d3241a01701e9f0e36a354fe 100644 --- a/include/hxcomm/common/quiggeldy_worker.h +++ b/include/hxcomm/common/quiggeldy_worker.h @@ -35,7 +35,6 @@ public: using request_type = typename interface_types::request_type; using response_type = typename interface_types::response_type; - // reinit is just another set of FPGA words sent to the chip prior to resuming using reinit_type = typename interface_types::reinit_type; // pair encoding uid and UUID of the session to differentiate them (one per QuiggeldyConnection) @@ -92,6 +91,13 @@ public: */ void perform_reinit(reinit_type const&); + /** + * This function is called whenever we have to relinquish control of our + * hardware resource and the user specified a reinit-program to be snapshotted + * after the previous work-unit was executed. + */ + void perform_reinit_snapshot(reinit_type&); + /** * This function is run whenever the server releases control (and any * associated slurm resources). diff --git a/include/hxcomm/common/quiggeldy_worker.tcc b/include/hxcomm/common/quiggeldy_worker.tcc index 761083ee887a3dfb66ed46c42ffded1a6515adb3..68897fecec3a82fa47b885ebc8ab9b7d94a4781b 100644 --- a/include/hxcomm/common/quiggeldy_worker.tcc +++ b/include/hxcomm/common/quiggeldy_worker.tcc @@ -261,7 +261,33 @@ void QuiggeldyWorker<Connection>::perform_reinit(reinit_type const& reinit) try { for (auto const& entry : reinit) { - execute_messages(*m_connection, entry); + execute_messages(*m_connection, entry.request); + } + } catch (const std::exception& e) { + // TODO: Implement proper exception handling + teardown(); + HXCOMM_LOG_ERROR(m_logger, "Error during word execution: " << e.what()); + throw; + } +} + +template <typename Connection> +void QuiggeldyWorker<Connection>::perform_reinit_snapshot(reinit_type& reinit) +{ + if (m_mock_mode) { + HXCOMM_LOG_DEBUG(m_logger, "Running mock-reinit-snapshot!"); + return; + } + + HXCOMM_LOG_TRACE(m_logger, "Performing reinit snapshot!"); + + try { + for (auto& entry : reinit) { + if (entry.snapshot) { + auto const [response, _] = execute_messages(*m_connection, *(entry.snapshot)); + entry.request = typename std::decay_t<decltype(entry)>::transform_type{}( + response, *(entry.snapshot)); + } } } catch (const std::exception& e) { // TODO: Implement proper exception handling diff --git a/include/hxcomm/common/reinit_stack_entry.tcc b/include/hxcomm/common/reinit_stack_entry.tcc index 4f10854022d8a0717a8f9004887663f8d543befe..8cf74e06668b19432f1253720fc0e2619b79d094 100644 --- a/include/hxcomm/common/reinit_stack_entry.tcc +++ b/include/hxcomm/common/reinit_stack_entry.tcc @@ -149,7 +149,9 @@ void ReinitStackEntry<QuiggeldyConnection, ConnectionVariant>::handle_unsupporte HXCOMM_LOG_TRACE( m_logger, "Connection does not support upload of reinit program, treating enforced " "reinit-like regular program to execute."); - std::visit([&entry](auto& conn) { execute_messages(conn.get(), entry); }, m_connection_ref); + std::visit( + [&entry](auto& conn) { execute_messages(conn.get(), entry.request); }, + m_connection_ref); } else { HXCOMM_LOG_TRACE( m_logger, "Connection does not support upload of reinit program, ignoring " diff --git a/include/hxcomm/vx/connection_parameter.h b/include/hxcomm/vx/connection_parameter.h index ab862ea4066f72f34da7e7f3146305104e6be4b7..2113ea06a6f83c3d07fafb27f8ba3a5410465554 100644 --- a/include/hxcomm/vx/connection_parameter.h +++ b/include/hxcomm/vx/connection_parameter.h @@ -1,5 +1,6 @@ #pragma once #include "hxcomm/common/connection_parameter.h" +#include "hxcomm/vx/quiggeldy_schedule_out_to_in_transform.h" #include "hxcomm/vx/utmessage.h" namespace hxcomm::vx { @@ -15,7 +16,8 @@ typedef hxcomm::ConnectionParameter< ut_message_from_fpga_phyword_type, instruction::FromFPGADictionary, instruction::from_fpga_system::Loopback, - instruction::from_fpga_system::TimeoutNotification> + instruction::from_fpga_system::TimeoutNotification, + detail::QuiggeldyScheduleOutToInTransform> ConnectionParameter; } // namespace hxcomm::vx diff --git a/include/hxcomm/vx/instruction/omnibus_to_fpga.h b/include/hxcomm/vx/instruction/omnibus_to_fpga.h index d49f4f237ad55c4c0e121362e9368745d036593a..2e066a94f64dfcd831da46ee93a6fc27fe2a54f7 100644 --- a/include/hxcomm/vx/instruction/omnibus_to_fpga.h +++ b/include/hxcomm/vx/instruction/omnibus_to_fpga.h @@ -60,6 +60,16 @@ struct Address return os; } + bool get_is_read() const + { + return m_is_read; + } + + void set_is_read(bool value) + { + m_is_read = value; + } + private: uint32_t m_address; bool m_is_read; diff --git a/include/hxcomm/vx/quiggeldy_rcf.h b/include/hxcomm/vx/quiggeldy_rcf.h index aeb8cdf549e9e98ca6b224012b3ac51937d5bd81..eb3629447b387ac26ab2bb33a6e8d07bb59e8f63 100644 --- a/include/hxcomm/vx/quiggeldy_rcf.h +++ b/include/hxcomm/vx/quiggeldy_rcf.h @@ -5,6 +5,7 @@ #include "cereal/types/vector.hpp" #include "hate/visibility.h" +#include "hxcomm/common/cerealization_quiggeldy_interface_types.h" #include "hxcomm/common/cerealization_utmessage.h" #include "hxcomm/common/connection.h" #include "hxcomm/common/connection_time_info.h" @@ -32,9 +33,8 @@ void serialize(Archive& ar, hxcomm::vx::quiggeldy_interface_types::request_type& void serialize(Archive& ar, hxcomm::vx::quiggeldy_interface_types::response_type& qcr) SYMBOL_VISIBLE; -// Note: Currently, hxcomm::vx::quiggeldy_interface_types::reinit_type is the -// same as the request_type and thus no additional declaration of serialize() -// is needed. +void serialize(Archive& ar, hxcomm::vx::quiggeldy_interface_types::reinit_entry_type& qcr) + SYMBOL_VISIBLE; } // namespace SF diff --git a/include/hxcomm/vx/quiggeldy_schedule_out_to_in_transform.h b/include/hxcomm/vx/quiggeldy_schedule_out_to_in_transform.h new file mode 100644 index 0000000000000000000000000000000000000000..e1846957eb2b00d0ebc3601638c9de61f23b0d87 --- /dev/null +++ b/include/hxcomm/vx/quiggeldy_schedule_out_to_in_transform.h @@ -0,0 +1,17 @@ +#pragma once +#include "hate/visibility.h" +#include "hxcomm/vx/utmessage.h" +#include <vector> + +namespace hxcomm::vx::detail { + +struct QuiggeldyScheduleOutToInTransform +{ + using request_type = std::vector<UTMessageToFPGAVariant>; + using response_type = std::vector<UTMessageFromFPGAVariant>; + + request_type operator()(response_type const& response, request_type const& snapshot) + SYMBOL_VISIBLE; +}; + +} // namespace hxcomm::vx::detail diff --git a/src/hxcomm/vx/quiggeldy_rcf.cpp b/src/hxcomm/vx/quiggeldy_rcf.cpp index e3d44b66e120757d3531ca3169f291b3511f821e..b203c09ad9cb3e2624fddb3803cf69f232ac6cf7 100644 --- a/src/hxcomm/vx/quiggeldy_rcf.cpp +++ b/src/hxcomm/vx/quiggeldy_rcf.cpp @@ -29,8 +29,9 @@ void serialize(Archive& ar, hxcomm::vx::quiggeldy_interface_types::response_type translate_sf_cereal(ar, qcr); } -// Note: Currently, hxcomm::vx::quiggeldy_interface_types::reinit_type is the -// same as the request_type and thus no additional declaration of serialize() -// is needed. +void serialize(Archive& ar, hxcomm::vx::quiggeldy_interface_types::reinit_entry_type& qcr) +{ + translate_sf_cereal(ar, qcr); +} } // namespace SF diff --git a/src/hxcomm/vx/quiggeldy_schedule_out_to_in_transform.cpp b/src/hxcomm/vx/quiggeldy_schedule_out_to_in_transform.cpp new file mode 100644 index 0000000000000000000000000000000000000000..13449e6a0bd5f82509ce053a04b3da0ae87be067 --- /dev/null +++ b/src/hxcomm/vx/quiggeldy_schedule_out_to_in_transform.cpp @@ -0,0 +1,56 @@ +#include "hxcomm/vx/quiggeldy_schedule_out_to_in_transform.h" + +#include <variant> + +namespace hxcomm::vx::detail { + +QuiggeldyScheduleOutToInTransform::request_type QuiggeldyScheduleOutToInTransform::operator()( + response_type const& response, request_type const& snapshot) +{ + // simple unchecked transform from Omnibus reads to Omnibus writes + + // filter all read requests + request_type addresses; + for (auto const& ins : snapshot) { + if (!std::holds_alternative<UTMessageToFPGA<instruction::omnibus_to_fpga::Address>>(ins)) { + continue; + } + auto address = std::get<UTMessageToFPGA<instruction::omnibus_to_fpga::Address>>(ins); + auto address_payload = address.decode(); + if (address_payload.get_is_read()) { + address_payload.set_is_read(false); + address.encode(address_payload); + addresses.push_back(address); + } + } + + // filter all read responses + request_type data; + for (auto const& resp : response) { + if (!std::holds_alternative<UTMessageFromFPGA<instruction::omnibus_from_fpga::Data>>( + resp)) { + continue; + } + data.push_back(UTMessageToFPGA<instruction::omnibus_to_fpga::Data>( + std::get<UTMessageFromFPGA<instruction::omnibus_from_fpga::Data>>(resp) + .decode() + .value())); + } + + // combine addresses and data to write accesses + if (addresses.size() != data.size()) { + throw std::runtime_error("Transform to Omnibus writes unsuccessful, mismatch in number " + "of read requests to responses."); + } + request_type ret; + for (size_t i = 0; i < addresses.size(); ++i) { + ret.push_back(addresses.at(i)); + ret.push_back(data.at(i)); + } + // ensure writes are successful + ret.push_back( + UTMessageToFPGA<instruction::timing::Barrier>(instruction::timing::Barrier::omnibus)); + return ret; +} + +} // namespace hxcomm::vx::detail