mirror of
https://github.com/EttusResearch/uhd.git
synced 2026-10-25 17:36:10 +00:00
Compare commits
5 Commits
2af4ddb962
...
050c7e2dad
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
050c7e2dad | ||
|
|
98d1a0aab8 | ||
|
|
1b0c95e31a | ||
|
|
632f9927e5 | ||
|
|
7b7f518ad4 |
@ -5,8 +5,20 @@
|
||||
//
|
||||
// Module: rf_nco_reset_controller
|
||||
//
|
||||
// This entity has the logic needed to synchronously reset the NCO inside the
|
||||
// RF section.
|
||||
// This entity has the logic needed to synchronously reset the NCO phase inside the RFDC.
|
||||
//
|
||||
// It connects to the real-time NCO signal interface ports of the RFDC. The reset sequence is
|
||||
// described in AMD's PG269 (RF Data Converter Product Guide), in the Multi-Tile NCO Update figure.
|
||||
// Additionally, the module takes SYSREF into account to align NCO phase updates across multiple
|
||||
// devices, which may complete at different times.
|
||||
//
|
||||
// The NCO control signals are driven in the config_clk domain. The reset control logic runs on
|
||||
// pll_ref_clk, and SYSREF is sampled in this domain. Synchronizers transfer signals between
|
||||
// pll_ref_clk and config_clk. The pll_ref_clk and data_clk (provided by the radio block) are
|
||||
// integer-related clocks, so signals transfer directly between them without synchronizers.
|
||||
//
|
||||
// NOTE: All ADCs and DACs have to be operated on the same clock settings as there is only one
|
||||
// sequence for the full RFDC including all ADCs and DACs.
|
||||
//
|
||||
|
||||
module rf_nco_reset_controller(
|
||||
@ -16,10 +28,17 @@ module rf_nco_reset_controller(
|
||||
input wire p_sysref,
|
||||
input wire d_start_nco_reset,
|
||||
|
||||
// DAC common NCO update controls and status.
|
||||
// DAC 0 NCO update busy status:
|
||||
// Bit 1 is high while SYSREF is disabled (applicable when multi-tile
|
||||
// synchronization is selected); bit 0 is high while the NCO update is in progress.
|
||||
input wire [1:0] c_dac0_nco_update_busy,
|
||||
// Assert high to request an update of the NCO settings.
|
||||
output wire c_dac0_nco_update_req,
|
||||
// When asserted, the IP core disables SYSREF (applicable to DAC tile 0
|
||||
// when multi-tile synchronization is enabled).
|
||||
output wire c_dac0_sysref_int_gating,
|
||||
// When asserted, the IP core re-enables SYSREF after the NCO update completes.
|
||||
// In multi-device systems, re-enable SYSREF on all devices at the same time.
|
||||
output wire c_dac0_sysref_int_reenable,
|
||||
|
||||
// DAC Tile 229
|
||||
@ -41,11 +60,9 @@ module rf_nco_reset_controller(
|
||||
// ADC Tile 227
|
||||
input wire c_adc3_nco_update_busy,
|
||||
|
||||
// NCO reset can be initiated only when c_nco_phase_rst is set to '1' and
|
||||
// c_nco_update_en = 0x20. The FSM in this entity will set these values when
|
||||
// an NCO reset is initiated during synchronization. These ports are common
|
||||
// for all the converters. So, we will fan these signals out to each
|
||||
// converter outside this entity.
|
||||
// NCO reset requires c_nco_phase_rst = 1 and c_nco_update_en = 0x20. This
|
||||
// module drives these common values continuously; they are fanned out to
|
||||
// each converter outside this entity.
|
||||
output reg c_nco_phase_rst,
|
||||
output reg [5:0] c_nco_update_en,
|
||||
|
||||
@ -76,7 +93,7 @@ module rf_nco_reset_controller(
|
||||
|
||||
reg [7:0] p_sysref_counter = 8'b0;
|
||||
|
||||
typedef enum logic [2:0] {IDLE, REQ_GATING, CHECK_GATING, CHECK_UPDATE_DONE,
|
||||
typedef enum logic [2:0] {IDLE, REQ_GATING, CHECK_GATING, CHECK_UPDATE_BUSY, CHECK_UPDATE_DONE,
|
||||
CHECK_RESET_DONE} ResetState_t;
|
||||
|
||||
ResetState_t p_reset_state = IDLE;
|
||||
@ -120,7 +137,7 @@ module rf_nco_reset_controller(
|
||||
end
|
||||
end
|
||||
|
||||
// Check if all data converters have completed their NCO reset
|
||||
// Check whether DAC 1 and all ADC updates have completed.
|
||||
always_ff @(posedge config_clk) begin
|
||||
c_nco_reset_complete <= !c_dac1_nco_update_busy & !c_adc0_nco_update_busy & !c_adc1_nco_update_busy
|
||||
& !c_adc2_nco_update_busy & !c_adc3_nco_update_busy;
|
||||
@ -147,10 +164,8 @@ module rf_nco_reset_controller(
|
||||
end
|
||||
|
||||
case (p_reset_state)
|
||||
// Stay in this state until NCO reset sequence is initiated. NCO reset
|
||||
// is initiated only on the rising edge of SYSREF.
|
||||
// When NCO reset is initiated, gate the RFDC internal SYSREF. To gate
|
||||
// internal SYSREF set cSysrefIntGating to 1.
|
||||
// Wait for a latched reset request and a rising SYSREF edge. Assert the
|
||||
// internal SYSREF gating request before issuing the DAC 0 update request.
|
||||
IDLE : begin
|
||||
if (p_sysref_pulse & d_start_nco_reset_reg) begin
|
||||
p_reset_state <= REQ_GATING;
|
||||
@ -161,42 +176,46 @@ module rf_nco_reset_controller(
|
||||
end
|
||||
end
|
||||
|
||||
// To request NCO reset strobe c_dac0_nco_update_req for one config_clk period.
|
||||
// At this point, we can only request NCO reset for RF-DAC tile 228.
|
||||
// Pulse the update request for RF-DAC tile 0. The IP waits for its startup
|
||||
// sequence, then writes the registers needed to gate SYSREF internally.
|
||||
REQ_GATING : begin
|
||||
p_reset_state <= CHECK_GATING;
|
||||
p_dac0_nco_update_req <= 1'b1;
|
||||
p_clear_nco_reset_reg <= 1'b1;
|
||||
end
|
||||
|
||||
// Since we are gating c_dac0_nco_update_busyng SYSREF inside RFDC, we need to wait until SYSREF
|
||||
// is gated internally. RFDC sets c_dac0_nco_update_busy[0] to '1' when
|
||||
// SYSREF is gated. c_dac0_nco_update_busy[1] is also set to '1' to
|
||||
// indicate that NCO reset is still in progress. After the SYSREF is
|
||||
// gated request NCO reset on all other converter tiles.
|
||||
// Wait for DAC 0 busy = 2'b10: bit 1 indicates SYSREF is gated and bit 0
|
||||
// indicates no NCO update is in progress. Then request updates for DAC 1
|
||||
// and all ADC tiles in the synchronization group.
|
||||
CHECK_GATING : begin
|
||||
if (p_dac0_nco_update_busy == 2'b11) begin
|
||||
p_reset_state <= CHECK_UPDATE_DONE;
|
||||
if (p_dac0_nco_update_busy == 2'b10) begin
|
||||
p_reset_state <= CHECK_UPDATE_BUSY;
|
||||
p_all_other_nco_update_req <= 1'b1;
|
||||
end
|
||||
end
|
||||
|
||||
// In this state, we check if the RFDC block is ready for NCO reset.
|
||||
// This check is done using the *Busy signal from RFDC. Once RFDC is
|
||||
// ready for NCO reset and d_sysref_wait_cycles Sysref edges have arrived,
|
||||
// disable internal SYSREF gating.
|
||||
// Wait until at least one of the other converters reports busy, confirming
|
||||
// that its requested NCO update has started.
|
||||
CHECK_UPDATE_BUSY : begin
|
||||
if (p_nco_reset_complete == 1'b0) begin
|
||||
p_reset_state <= CHECK_UPDATE_DONE;
|
||||
end
|
||||
end
|
||||
|
||||
// Wait until DAC 1 and all ADC busy signals are low, indicating that
|
||||
// their NCO register writes are complete. Also wait for the configured
|
||||
// SYSREF edges, then pulse the request to re-enable SYSREF.
|
||||
CHECK_UPDATE_DONE : begin
|
||||
// Wait until the minimum number of sysref cycles is reached
|
||||
if (p_dac0_nco_update_busy == 2'b10 & p_nco_reset_complete &
|
||||
p_sysref_counter >= d_sysref_wait_cycles) begin
|
||||
// Wait until the minimum number of SYSREF cycles is reached.
|
||||
if (p_nco_reset_complete & p_sysref_counter >= d_sysref_wait_cycles) begin
|
||||
p_dac0_sysref_int_reenable <= 1'b1;
|
||||
p_reset_state <= CHECK_RESET_DONE;
|
||||
end
|
||||
end
|
||||
|
||||
// Wait until c_dac0_nco_update_busy[1] is set to 0. This indicates that the
|
||||
// NCO has completed its reset. p_sysref_int_gating can be set to 0 here,
|
||||
// since it does not have an effect after p_dac0_sysref_int_reenable is set to 1.
|
||||
// Wait until both DAC 0 busy bits are low: bit 1 indicates SYSREF has been
|
||||
// re-enabled and bit 0 indicates the NCO update is no longer in progress.
|
||||
// Then deassert our SYSREF gating request and report completion.
|
||||
CHECK_RESET_DONE : begin
|
||||
p_sysref_counter <= 8'b0;
|
||||
|
||||
|
||||
@ -47,7 +47,7 @@ architecture RTL of tb_rf_nco_reset is
|
||||
signal cDac0xSysrefIntGatingDlyd : std_logic := '0';
|
||||
signal cNcoPhaseRstDlyd : std_logic_vector(2 downto 0) := "000";
|
||||
|
||||
type RfdcNcoState_t is (Idle, GateSysref, UpdateReq, CheckUpdate,
|
||||
type RfdcNcoState_t is (Idle, GateSysref, UpdateReq, CheckUpdate, SysrefGated,
|
||||
SysrefEn, WaitForSysref);
|
||||
signal cRfdcNcoState : RfdcNcoState_t := Idle;
|
||||
|
||||
@ -211,19 +211,30 @@ begin
|
||||
when GateSysref =>
|
||||
cRfdcNcoState <= GateSysref;
|
||||
if cDac0xNcoUpdateReq = '1' then
|
||||
cRfdcNcoState <= UpdateReq;
|
||||
cRfdcNcoState <= SysrefGated;
|
||||
cDac0xNcoUpdateBusy <= "11";
|
||||
cConfigClkCounter <= 0;
|
||||
end if;
|
||||
|
||||
when SysrefGated =>
|
||||
cRfdcNcoState <= SysrefGated;
|
||||
if cConfigClkCounter >= NumConfigClkCycles/2 then
|
||||
cDac0xNcoUpdateBusy <= "10"; --Indicates that SYSREF is gated.
|
||||
cRfdcNcoState <= UpdateReq;
|
||||
end if;
|
||||
|
||||
-- If NCO reset is requested on other tiles, assert NCO update busy on
|
||||
-- other tiles as well.
|
||||
when UpdateReq =>
|
||||
cRfdcNcoState <= CheckUpdate;
|
||||
cDac1xNcoUpdateBusy <= cDac1xNcoUpdateReq;
|
||||
cAdc0xNcoUpdateBusy <= cDac1xNcoUpdateReq;
|
||||
cAdc1xNcoUpdateBusy <= cDac1xNcoUpdateReq;
|
||||
cAdc2xNcoUpdateBusy <= cDac1xNcoUpdateReq;
|
||||
cAdc3xNcoUpdateBusy <= cDac1xNcoUpdateReq;
|
||||
cRfdcNcoState <= UpdateReq;
|
||||
if cDac1xNcoUpdateReq = '1' then
|
||||
cRfdcNcoState <= CheckUpdate;
|
||||
cDac1xNcoUpdateBusy <= '1';
|
||||
cAdc0xNcoUpdateBusy <= '1';
|
||||
cAdc1xNcoUpdateBusy <= '1';
|
||||
cAdc2xNcoUpdateBusy <= '1';
|
||||
cAdc3xNcoUpdateBusy <= '1';
|
||||
end if;
|
||||
|
||||
-- The total rfdc reset procedure take about 110 config_clk periods,
|
||||
-- longer than the datasheet claims. To emulate this behaviour,
|
||||
@ -233,7 +244,6 @@ begin
|
||||
-- It takes ~110 ConfigClk cycles to update the RFDC internal registers
|
||||
if cConfigClkCounter >= NumConfigClkCycles then
|
||||
cRfdcNcoState <= SysrefEn;
|
||||
cDac0xNcoUpdateBusy <= "10"; --Indicates that SYSREF is gated.
|
||||
cDac1xNcoUpdateBusy <= '0';
|
||||
cAdc0xNcoUpdateBusy <= '0';
|
||||
cAdc1xNcoUpdateBusy <= '0';
|
||||
|
||||
@ -49,18 +49,7 @@ public:
|
||||
size_t num_send_frames,
|
||||
size_t num_recv_frames,
|
||||
size_t send_frame_size,
|
||||
disconnect_callback_t disconnect)
|
||||
{
|
||||
return std::make_shared<chdr_ctrl_xport>(io_srv,
|
||||
send_link,
|
||||
recv_link,
|
||||
pkt_factory,
|
||||
my_epid,
|
||||
num_send_frames,
|
||||
num_recv_frames,
|
||||
send_frame_size,
|
||||
disconnect);
|
||||
}
|
||||
disconnect_callback_t disconnect);
|
||||
|
||||
/*!
|
||||
* Make a chdr_ctrl_xport
|
||||
|
||||
@ -24,6 +24,9 @@ class rfdc_control
|
||||
public:
|
||||
using sptr = std::shared_ptr<rfdc_control>;
|
||||
|
||||
//! Default SYSREF wait time for an NCO reset, in SYSREF cycles
|
||||
static constexpr uint32_t DEFAULT_SYSREF_WAIT_CYCLES = 14;
|
||||
|
||||
struct regmap
|
||||
{
|
||||
//! Address of the NCO reset register
|
||||
|
||||
@ -13,6 +13,27 @@ using namespace uhd::rfnoc;
|
||||
using namespace uhd::rfnoc::chdr;
|
||||
using namespace uhd::transport;
|
||||
|
||||
chdr_ctrl_xport::sptr chdr_ctrl_xport::make(io_service::sptr io_srv,
|
||||
send_link_if::sptr send_link,
|
||||
recv_link_if::sptr recv_link,
|
||||
const chdr::chdr_packet_factory& pkt_factory,
|
||||
sep_id_t my_epid,
|
||||
size_t num_send_frames,
|
||||
size_t num_recv_frames,
|
||||
size_t send_frame_size,
|
||||
disconnect_callback_t disconnect)
|
||||
{
|
||||
return std::make_shared<chdr_ctrl_xport>(io_srv,
|
||||
send_link,
|
||||
recv_link,
|
||||
pkt_factory,
|
||||
my_epid,
|
||||
num_send_frames,
|
||||
num_recv_frames,
|
||||
send_frame_size,
|
||||
disconnect);
|
||||
}
|
||||
|
||||
chdr_ctrl_xport::chdr_ctrl_xport(io_service::sptr io_srv,
|
||||
send_link_if::sptr send_link,
|
||||
recv_link_if::sptr recv_link,
|
||||
|
||||
@ -53,7 +53,7 @@ nirio_status usrprio_rpc_client::niusrprio_enumerate(NIUSRPRIO_ENUMERATE_ARGS)
|
||||
if (nirio_status_not_fatal(status) && vtr_size > 0) {
|
||||
device_info_vtr.resize(vtr_size);
|
||||
for (size_t i = 0; i < (size_t)vtr_size; i++) {
|
||||
usrprio_device_info info;
|
||||
usrprio_device_info info{};
|
||||
try {
|
||||
out_args >> info;
|
||||
} catch (std::exception&) {
|
||||
|
||||
@ -4,13 +4,17 @@
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
//
|
||||
|
||||
// Python.h must be included before any system header that pulls in features.h,
|
||||
// otherwise Python 3.14+ pyconfig.h will attempt to redefine _POSIX_C_SOURCE
|
||||
// and _XOPEN_SOURCE after glibc has already set them to newer values.
|
||||
// Need this import because pybind11 doesn't have an equivalent to Py_IsInitialized()
|
||||
#include <Python.h>
|
||||
|
||||
#include "mpmd_devices.hpp"
|
||||
#include "mpmd_impl.hpp"
|
||||
#include <uhd/device.hpp>
|
||||
#include <uhd/utils/static.hpp>
|
||||
#include <uhdlib/rfnoc/rfnoc_device.hpp>
|
||||
// Need this import because pybind doesn't have an equivalent to Py_IsInitialized()
|
||||
#include <Python.h>
|
||||
#include <pybind11/embed.h>
|
||||
#include <pybind11/pybind11.h>
|
||||
#include <chrono>
|
||||
|
||||
@ -27,8 +27,9 @@ void rfdc_control::reset_ncos(
|
||||
}
|
||||
UHD_LOG_TRACE(_log_id, "Resetting " << ncos.size() << " NCOs...");
|
||||
|
||||
// Initialize the NCO reset delay to a default of 11 SYSREF cycles
|
||||
constexpr uint32_t reset_word = (11 & 0xFF) << regmap::SYSREF_WAIT_LSB
|
||||
// Initialize the NCO reset delay to the default number of SYSREF cycles
|
||||
constexpr uint32_t reset_word = (DEFAULT_SYSREF_WAIT_CYCLES & 0xFF)
|
||||
<< regmap::SYSREF_WAIT_LSB
|
||||
| 0x1 << regmap::WRITE_SYSREF_WAIT | 1;
|
||||
|
||||
// Initiate NCO reset
|
||||
|
||||
@ -173,7 +173,15 @@ BOOST_AUTO_TEST_CASE(simple_read_if_chdr_pkt)
|
||||
mock_reg_iface->add_connection(ddc1_id, 0, sep1_id, 0);
|
||||
constexpr size_t num_edges = 8; // Number of lines above
|
||||
|
||||
// GCC16 comes with a bug that produces a spurious warning here.
|
||||
#if defined(__GNUC__) && __GNUC__ >= 16
|
||||
# pragma GCC diagnostic push
|
||||
# pragma GCC diagnostic ignored "-Warray-bounds"
|
||||
#endif
|
||||
auto mock_client0 = std::make_shared<uhd::rfnoc::detail::client_zero>(mock_reg_iface);
|
||||
#if defined(__GNUC__) && __GNUC__ >= 16
|
||||
# pragma GCC diagnostic pop
|
||||
#endif
|
||||
|
||||
BOOST_CHECK_EQUAL(mock_client0->get_proto_ver(), mock_reg_iface->GLOBAL_PROTOVER);
|
||||
BOOST_CHECK_EQUAL(mock_client0->get_device_type(), mock_reg_iface->DEVICE_TYPE);
|
||||
|
||||
@ -148,7 +148,15 @@ public:
|
||||
|
||||
BOOST_AUTO_TEST_CASE(test_mb_controller)
|
||||
{
|
||||
// GCC16 comes with a bug that produces a spurious warning here.
|
||||
#if defined(__GNUC__) && __GNUC__ >= 16
|
||||
# pragma GCC diagnostic push
|
||||
# pragma GCC diagnostic ignored "-Warray-bounds"
|
||||
#endif
|
||||
auto mmbc = std::make_shared<mock_mb_controller>();
|
||||
#if defined(__GNUC__) && __GNUC__ >= 16
|
||||
# pragma GCC diagnostic pop
|
||||
#endif
|
||||
|
||||
BOOST_REQUIRE_EQUAL(mmbc->get_num_timekeepers(), 1);
|
||||
auto tk = mmbc->get_timekeeper(0);
|
||||
|
||||
@ -778,7 +778,8 @@ BOOST_FIXTURE_TEST_CASE(zbx_phase_sync_test, x400_radio_fixture)
|
||||
// Set reset complete bit
|
||||
regs[nco_sync_addr] = 1 << 1;
|
||||
constexpr uint32_t nco_sync_val =
|
||||
(11 & 0xFF) << uhd::rfnoc::x400::rfdc_control::regmap::SYSREF_WAIT_LSB
|
||||
(uhd::rfnoc::x400::rfdc_control::DEFAULT_SYSREF_WAIT_CYCLES & 0xFF)
|
||||
<< uhd::rfnoc::x400::rfdc_control::regmap::SYSREF_WAIT_LSB
|
||||
| 1 << uhd::rfnoc::x400::rfdc_control::regmap::WRITE_SYSREF_WAIT
|
||||
| 1 << uhd::rfnoc::x400::rfdc_control::regmap::NCO_RESET_DONE_MSB
|
||||
| 1 << uhd::rfnoc::x400::rfdc_control::regmap::NCO_RESET_START_MSB;
|
||||
|
||||
Loading…
Reference in New Issue
Block a user