diff options
Diffstat (limited to 'fpga/usrp3/top/x300/gen_ddrlvds.v')
-rw-r--r-- | fpga/usrp3/top/x300/gen_ddrlvds.v | 129 |
1 files changed, 77 insertions, 52 deletions
diff --git a/fpga/usrp3/top/x300/gen_ddrlvds.v b/fpga/usrp3/top/x300/gen_ddrlvds.v index 680b10c84..7b0e4a6a1 100644 --- a/fpga/usrp3/top/x300/gen_ddrlvds.v +++ b/fpga/usrp3/top/x300/gen_ddrlvds.v @@ -1,7 +1,6 @@ -module gen_ddrlvds - ( +module gen_ddrlvds ( // 2X Radio clock input tx_clk_2x, // 1X Radio Clock @@ -23,76 +22,102 @@ module gen_ddrlvds input [15:0] q, // Rising edge sampled on sync_dacs triggers frame sync sequence input sync_dacs - ); - - reg [15:0] i_reg, q_reg; - reg [15:0] i_2x, q_2x; - reg phase, phase_2x; - reg rising_edge; - wire [15:0] i_and_q_2x; - reg sync_2x; - reg sync_dacs_reg; - - - - genvar z; - wire [7:0] tx_int; - wire tx_clk_2x_int; - wire tx_frame_int; - - (* keep = "true", max_fanout = 10 *) wire phase_eq_phase2x = (phase == phase_2x); +); + localparam SYNC_PULSE_WIDTH = 3'd2; + + // + // Figure out the 1X clock level + // + localparam TX_CLK_1X_LOW = 1'b0; + localparam TX_CLK_1X_HIGH = 1'b1; + + reg tx_clk_1x_level; + reg phase, phase_2x; + reg reset_2x; always @(posedge tx_clk_1x) - if (reset) - phase <= 1'b0; - else - phase <= ~phase; + if (reset) + phase <= 1'b0; + else + phase <= ~phase; + always @(posedge tx_clk_2x) + begin + phase_2x <= phase; + //Pipeline reset and tx_clk_1x_level + reset_2x <= reset; + tx_clk_1x_level <= (phase == phase_2x) ? TX_CLK_1X_HIGH : TX_CLK_1X_LOW; + end // // Pipeline input data so that 1x to 2x clock domain jump includes no logic external to this module. // + reg [15:0] i_reg, q_reg; + reg sync_dacs_reg; + always @(posedge tx_clk_1x) - begin - i_reg <= i; - q_reg <= q; - sync_dacs_reg <= sync_dacs; - end + begin + i_reg <= i; + q_reg <= q; + sync_dacs_reg <= sync_dacs; + end + + // + // Generate frame signal and interleave I and Q signals + // + reg [15:0] i_2x, q_2x; + reg [2:0] sync_count; + reg frame; always @(posedge tx_clk_2x) - begin - // Move 1x data to 2x domain, mostly just to add pipeline regs - // for timing closure. - i_2x <= i_reg; - q_2x <= q_reg; - // Sample phase to determine when 1x clock edges occur. - // To sync multiple AD9146 DAC's an extended assertion of FRAME is required, - // when sync flag set, squash one rising_edge assertion which causes a 3 word assertion of FRAME, - // also reset sync flag. "sync_dacs" comes from 1x clk and pulse lasts 2 2x clock cycles...this is accounted for. - sync_2x <= (phase_eq_phase2x && sync_2x) ? 1'b0 /*RESET */ : (sync_dacs_reg) ? 1'b1 /* SET */ : sync_2x /* HOLD */; - rising_edge <= (phase_eq_phase2x && ~sync_2x); - phase_2x <= phase; - end - - // Interleave I and Q as SDR signals - assign i_and_q_2x = rising_edge ? q_2x : i_2x; + begin + // Move 1x data to 2x domain, mostly just to add pipeline regs + // for timing closure. + i_2x <= i_reg; + q_2x <= q_reg; + + // Sample phase to determine when 1x clock edges occur. + // To sync multiple AD9146 DAC's an extended assertion of FRAME is required, + // when sync flag set, squash one frame assertion which causes a SYNC_PULSE_WIDTH+1 word assertion of FRAME, + // also reset sync flag. "sync_dacs" comes from 1x clk and pulse lasts 2 2x clock cycles...this is accounted for. + if (reset_2x) begin + frame <= 0; + sync_count <= 3'd0; + end else begin + frame <= (tx_clk_1x_level == TX_CLK_1X_LOW) | (sync_count != 3'd0); + if ((tx_clk_1x_level == TX_CLK_1X_LOW) & sync_dacs_reg) + sync_count <= SYNC_PULSE_WIDTH; + else if (sync_count > 3'd0) + sync_count <= sync_count - 3'd1; + end + end + + wire [15:0] i_and_q_2x = frame ? i_2x : q_2x; + // + // Instantiate IO primitives for the source synchronous interface + // + wire [7:0] tx_int; + wire tx_clk_2x_int; + wire tx_frame_int; + + genvar z; generate for(z = 0; z < 8; z = z + 1) - begin : gen_pins - OBUFDS obufds (.I(tx_int[z]), .O(tx_d_p[z]), .OB(tx_d_n[z])); - ODDR #(.DDR_CLK_EDGE("SAME_EDGE")) oddr - (.Q(tx_int[z]), .C(tx_clk_2x), - .CE(1'b1), .D1(i_and_q_2x[z+8]), .D2(i_and_q_2x[z]), .S(1'b0), .R(1'b0)); - end + begin : gen_pins + OBUFDS obufds (.I(tx_int[z]), .O(tx_d_p[z]), .OB(tx_d_n[z])); + ODDR #(.DDR_CLK_EDGE("SAME_EDGE")) oddr + (.Q(tx_int[z]), .C(tx_clk_2x), + .CE(1'b1), .D1(i_and_q_2x[z+8]), .D2(i_and_q_2x[z]), .S(1'b0), .R(1'b0)); + end endgenerate // Generate framing signal to identify I and Q OBUFDS obufds_frame (.I(tx_frame_int), .O(tx_frame_p), .OB(tx_frame_n)); ODDR #(.DDR_CLK_EDGE("SAME_EDGE")) oddr_frame (.Q(tx_frame_int), .C(tx_clk_2x), - .CE(1'b1), .D1(~rising_edge), .D2(~rising_edge), .S(1'b0), .R(1'b0)); + .CE(1'b1), .D1(frame), .D2(frame), .S(1'b0), .R(1'b0)); // Source synchronous clk OBUFDS obufds_clk (.I(tx_clk_2x_int), .O(tx_clk_2x_p), .OB(tx_clk_2x_n)); |