aboutsummaryrefslogtreecommitdiffstats
path: root/fpga/usrp3/top/x400/rf/400m/dac_gearbox_4x2.v
diff options
context:
space:
mode:
Diffstat (limited to 'fpga/usrp3/top/x400/rf/400m/dac_gearbox_4x2.v')
-rw-r--r--fpga/usrp3/top/x400/rf/400m/dac_gearbox_4x2.v80
1 files changed, 80 insertions, 0 deletions
diff --git a/fpga/usrp3/top/x400/rf/400m/dac_gearbox_4x2.v b/fpga/usrp3/top/x400/rf/400m/dac_gearbox_4x2.v
new file mode 100644
index 000000000..43fb39ec4
--- /dev/null
+++ b/fpga/usrp3/top/x400/rf/400m/dac_gearbox_4x2.v
@@ -0,0 +1,80 @@
+//
+// Copyright 2021 Ettus Research, a National Instruments Brand
+//
+// SPDX-License-Identifier: LGPL-3.0-or-later
+//
+// Module: dac_gearbox_4x2
+//
+// Description:
+//
+// Gearbox DAC data from 4 SPC to 2 SPC and corresponding 2x clock to 1x
+// clock.
+// This module incurs in one clk1x cycle of delay on the data and valid
+// signals from input on the 1x domain to output on the 2x domain.
+//
+
+`default_nettype none
+
+module dac_gearbox_4x2 (
+ input wire clk1x,
+ input wire reset_n_1x,
+ // Data is _presumed_ to be packed [Q3,I3,Q2,I2,Q1,I1,Q0,I0]
+ input wire [127:0] data_in_1x,
+ input wire valid_in_1x,
+ output wire ready_out_1x,
+
+ input wire clk2x,
+ // Data is packed [Q1,I1,Q0,I0] (I in LSBs)
+ output wire [ 63:0] data_out_2x,
+ output wire valid_out_2x
+);
+
+ // Re-create the 1x clock in the 2x domain to produce a deterministic
+ // crossing.
+ reg toggle_1x, toggle_2x = 1'b0, toggle_2x_dly = 1'b0, valid_2x = 1'b0, valid_dly_2x = 1'b0;
+ reg [127:0] data_in_2x_dly0 = 128'b0, data_in_2x_dly1 = 32'b0;
+ reg [63 :0] data_2x_dly = 64'b0;
+
+ // Create a toggle in the 1x clock domain (clock divider /2).
+ always @(posedge clk1x or negedge reset_n_1x) begin
+ if ( ! reset_n_1x) begin
+ toggle_1x <= 1'b0;
+ end else begin
+ toggle_1x <= ! toggle_1x;
+ end
+ end
+
+ // Transfer the toggle from the 1x to the 2x domain. Delay the toggle in the
+ // 2x domain by one cycle and compare it to the non-delayed version. When
+ // they differ, push data_in[63:0] onto the output. When they match, push
+ // [127:64] onto the output.
+ //
+ // It is safe to not reset this domain because all of the input signals will
+ // be cleared by the 1x reset. Safe default values are assigned to all these
+ // registers.
+ always @(posedge clk2x) begin
+ toggle_2x <= toggle_1x;
+ toggle_2x_dly <= toggle_2x;
+ data_in_2x_dly0 <= data_in_1x;
+ data_in_2x_dly1 <= data_in_2x_dly0 ;
+ data_2x_dly <= 64'b0;
+
+ if (valid_2x) begin
+ data_2x_dly <= data_in_2x_dly1[127:64];
+ if (toggle_2x != toggle_2x_dly) begin
+ data_2x_dly <= data_in_2x_dly0[63:0];
+ end
+ end
+ // Valid is simply a transferred version of the 1x clock's valid. Delay it
+ // one more cycle to align outputs.
+ valid_2x <= valid_in_1x;
+ valid_dly_2x <= valid_2x;
+ end
+
+ assign valid_out_2x = valid_dly_2x;
+ assign data_out_2x = data_2x_dly;
+ assign ready_out_1x = 1'b1;
+
+endmodule
+
+`default_nettype wire