diff options
Diffstat (limited to 'fpga/usrp3/top/b2xxmini/b205_io.v')
-rw-r--r-- | fpga/usrp3/top/b2xxmini/b205_io.v | 459 |
1 files changed, 459 insertions, 0 deletions
diff --git a/fpga/usrp3/top/b2xxmini/b205_io.v b/fpga/usrp3/top/b2xxmini/b205_io.v new file mode 100644 index 000000000..97e4cba24 --- /dev/null +++ b/fpga/usrp3/top/b2xxmini/b205_io.v @@ -0,0 +1,459 @@ +// +// Copyright 2015 Ettus Research, a National Instruments Company +// +// SPDX-License-Identifier: LGPL-3.0-or-later +// + +//------------------------------------------------------------------ +// NOTE: B205 is a SISO only device. MIMO references are unused code branches. +// +// In SISO mode, we output a clock thats 1x the frequency of the Catalina +// source-synchronous bus clock to be used as the radio_clk. +// +//------------------------------------------------------------------ + +module b205_io + ( + input reset, + + // Baseband sample interface + output radio_clk, + output [11:0] rx_i0, + output [11:0] rx_q0, + input [11:0] tx_i0, + input [11:0] tx_q0, + + // Catalina interface + input rx_clk, + input rx_frame, + input [11:0] rx_data, + output tx_clk, + output tx_frame, + output [11:0] tx_data + ); + + + genvar z; + + + //------------------------------------------------------------------ + // Clock Buffering. + // BUFIO2 drives all IDDR2 and ODDR2 cells directly in bank3. + // Need two pairs of BUFIO2 one pair each for Top Left and Bottom Left half banks. + //------------------------------------------------------------------ + wire rx_clk_buf; + wire siso_clk_unbuf; + wire siso_clk2_unbuf; + + IBUFG clk_ibufg (.O(rx_clk_buf), .I(rx_clk)); + + //------------------------------------------------------------------ + // + // Buffers for LEFT TOP half bank pins + // BUFIO2_X0Y22 + // + //------------------------------------------------------------------ + BUFIO2 #( + .DIVIDE(4), + .DIVIDE_BYPASS("FALSE"), + .I_INVERT("FALSE"), + .USE_DOUBLER("TRUE")) + clk_bufio_lt + ( + .IOCLK(io_clk_lt), + .DIVCLK(), + .SERDESSTROBE(), + .I(rx_clk_buf) + ); + + // BUFIO2_X0Y23 + BUFIO2 #( + .DIVIDE(1), + .DIVIDE_BYPASS("FALSE"), + .I_INVERT("TRUE"), + .USE_DOUBLER("FALSE")) + clk_bufio_lt_b + ( + .IOCLK(io_clk_lt_b), + .DIVCLK(siso_clk2_unbuf), // Inverted source of 1x interface clock for radio_clk + .SERDESSTROBE(), + .I(rx_clk_buf) + ); + + //------------------------------------------------------------------ + // + // Buffers for LEFT BOTTOM half bank pins + // BUFIO2_X1Y14 + // + //------------------------------------------------------------------ + BUFIO2 #( + .DIVIDE(1), + .DIVIDE_BYPASS("FALSE"), + .I_INVERT("FALSE"), + .USE_DOUBLER("FALSE")) + clk_bufio_lb + ( + .IOCLK(io_clk_lb), + .DIVCLK(siso_clk_unbuf), // Non-inverted source of 1x interface clock for local IO use + .SERDESSTROBE(), + .I(rx_clk_buf) + ); + + // BUFIO2_X1Y15 + BUFIO2 #( + .DIVIDE(1), + .DIVIDE_BYPASS("FALSE"), + .I_INVERT("TRUE"), + .USE_DOUBLER("FALSE")) + clk_bufio_lb_b + ( + .IOCLK(io_clk_lb_b), + .DIVCLK(/*siso_clk2_unbuf*/), + .SERDESSTROBE(), + .I(rx_clk_buf) + ); + + //------------------------------------------------------------------ + // Always-on SISO clk needed to load/unload DDR2 I/O Regs + //------------------------------------------------------------------ + BUFG siso_clk_bufg ( + .I(siso_clk_unbuf), + .O(siso_clk) + ); + + //------------------------------------------------------------------ + // BUFG to drive global radio_clk. + //------------------------------------------------------------------ + BUFG radio_clk_bufg ( + .I(siso_clk2_unbuf), + .O(radio_clk) + ); + + //------------------------------------------------------------------ + // RX Frame Signal - In bank 3 LB + //------------------------------------------------------------------ + wire rx_frame_0, rx_frame_1; + + IDDR2 #( + .DDR_ALIGNMENT("C0")) + iddr2_frame ( + .Q0(rx_frame_1), + .Q1(rx_frame_0), + .C0(io_clk_lb), + .C1(io_clk_lb_b), + .CE(1'b1), + .D(rx_frame), + .R(1'b0), + .S(1'b0)); + + reg rx_frame_d1, rx_frame_d2; + always @(posedge siso_clk) + { rx_frame_d2, rx_frame_d1 } <= { rx_frame_1, 1'b0 }; + + + //------------------------------------------------------------------ + // RX Data Bus - In bank3 both LT and LB + //------------------------------------------------------------------ + wire [11:0] rx_i,rx_q; + + // Bit0 LB + IDDR2 #( + .DDR_ALIGNMENT("C0")) + iddr2_i0 ( + .Q0(rx_q[0]), + .Q1(rx_i[0]), + .C0(io_clk_lb), + .C1(io_clk_lb_b), + .CE(1'b1), + .D(rx_data[0]), + .R(1'b0), + .S(1'b0)); + + // Bit1 LB + IDDR2 #( + .DDR_ALIGNMENT("C0")) + iddr2_i1 ( + .Q0(rx_q[1]), + .Q1(rx_i[1]), + .C0(io_clk_lb), + .C1(io_clk_lb_b), + .CE(1'b1), + .D(rx_data[1]), + .R(1'b0), + .S(1'b0)); + + // Bit2 LB + IDDR2 #( + .DDR_ALIGNMENT("C0")) + iddr2_i2 ( + .Q0(rx_q[2]), + .Q1(rx_i[2]), + .C0(io_clk_lt), + .C1(io_clk_lt_b), + .CE(1'b1), + .D(rx_data[2]), + .R(1'b0), + .S(1'b0)); + + // Bit3 LT + IDDR2 #( + .DDR_ALIGNMENT("C0")) + iddr2_i3 ( + .Q0(rx_q[3]), + .Q1(rx_i[3]), + .C0(io_clk_lt), + .C1(io_clk_lt_b), + .CE(1'b1), + .D(rx_data[3]), + .R(1'b0), + .S(1'b0)); + + // Bit4 LB + IDDR2 #( + .DDR_ALIGNMENT("C0")) + iddr2_i4 ( + .Q0(rx_q[4]), + .Q1(rx_i[4]), + .C0(io_clk_lt), + .C1(io_clk_lt_b), + .CE(1'b1), + .D(rx_data[4]), + .R(1'b0), + .S(1'b0)); + + // Bit5 LT + IDDR2 #( + .DDR_ALIGNMENT("C0")) + iddr2_i5 ( + .Q0(rx_q[5]), + .Q1(rx_i[5]), + .C0(io_clk_lt), + .C1(io_clk_lt_b), + .CE(1'b1), + .D(rx_data[5]), + .R(1'b0), + .S(1'b0)); + + // Bit6 LB + IDDR2 #( + .DDR_ALIGNMENT("C0")) + iddr2_i6 ( + .Q0(rx_q[6]), + .Q1(rx_i[6]), + .C0(io_clk_lt), + .C1(io_clk_lt_b), + .CE(1'b1), + .D(rx_data[6]), + .R(1'b0), + .S(1'b0)); + + // Bit7 LT + IDDR2 #( + .DDR_ALIGNMENT("C0")) + iddr2_i7 ( + .Q0(rx_q[7]), + .Q1(rx_i[7]), + .C0(io_clk_lt), + .C1(io_clk_lt_b), + .CE(1'b1), + .D(rx_data[7]), + .R(1'b0), + .S(1'b0)); + + // Bit8 LB + IDDR2 #( + .DDR_ALIGNMENT("C0")) + iddr2_i8 ( + .Q0(rx_q[8]), + .Q1(rx_i[8]), + .C0(io_clk_lb), + .C1(io_clk_lb_b), + .CE(1'b1), + .D(rx_data[8]), + .R(1'b0), + .S(1'b0)); + + // Bit9 LT + IDDR2 #( + .DDR_ALIGNMENT("C0")) + iddr2_i9 ( + .Q0(rx_q[9]), + .Q1(rx_i[9]), + .C0(io_clk_lb), + .C1(io_clk_lb_b), + .CE(1'b1), + .D(rx_data[9]), + .R(1'b0), + .S(1'b0)); + + // Bit10 LB + IDDR2 #( + .DDR_ALIGNMENT("C0")) + iddr2_i10 ( + .Q0(rx_q[10]), + .Q1(rx_i[10]), + .C0(io_clk_lb), + .C1(io_clk_lb_b), + .CE(1'b1), + .D(rx_data[10]), + .R(1'b0), + .S(1'b0)); + + // Bit11 LB + IDDR2 #( + .DDR_ALIGNMENT("C0")) + iddr2_i11 ( + .Q0(rx_q[11]), + .Q1(rx_i[11]), + .C0(io_clk_lb), + .C1(io_clk_lb_b), + .CE(1'b1), + .D(rx_data[11]), + .R(1'b0), + .S(1'b0)); + + //------------------------------------------------------------------ + // + // De-mux I & Q onto fullrate clock. + // + // We grab data from the IDDR2 using negedge of siso_clk. + // IDDR2 updates all Q pins on posedge of io_clk. siso_clk does not have aligned phase + // with io_clk...siso_clk is always a little more delayed than io_clk. + // This small delay is always much smaller than half a clk cycle. Thus by sampling the Q outputs + // with negedge siso_clk we avoid any risk of a race condition (hold violation on receiveing register). + // + //------------------------------------------------------------------ + reg [11:0] rx_i_del, rx_q_del; + reg [11:0] rx_i0_siso_pos; + reg [11:0] rx_q0_siso_pos; + reg [11:0] rx_i0_siso_neg; + reg [11:0] rx_q0_siso_neg; + reg [11:0] rx_i0_siso; + reg [11:0] rx_q0_siso; + + always @(negedge siso_clk) + begin + rx_i0_siso[11:0] <= rx_i[11:0]; + rx_q0_siso[11:0] <= rx_q[11:0]; + end // else: !if(rx_frame_0) + + //------------------------------------------------------------------ + // + // Now prepare data for crossing into radio_clk domain which is always for SISO mode (inverted) siso_clk. + // (Note: posedge is used so that we have massive margin against a fast-path race condition + // betwwen siso_clk and radio_clk). + // + //------------------------------------------------------------------ + + // This code block only relevent in SISO mode. + always @(posedge siso_clk) + begin + rx_i0_siso_pos[11:0] <= rx_i0_siso[11:0]; + rx_q0_siso_pos[11:0] <= rx_q0_siso[11:0]; + end + + assign rx_i0 = rx_i0_siso_pos; + assign rx_q0 = rx_q0_siso_pos; + + + //------------------------------------------------------------------ + // TX Data Bus - In bank3 LB + //------------------------------------------------------------------ + reg [11:0] tx_i,tx_q; + + generate + for(z = 0; z < 12; z = z + 1) + begin : gen_pins + ODDR2 #( + .DDR_ALIGNMENT("C0"), .SRTYPE("ASYNC")) + oddr2 ( + .Q(tx_data[z]), .C0(io_clk_lb), .C1(io_clk_lb_b), + .CE(1'b1), .D0(tx_i[z]), .D1(tx_q[z]), .R(1'b0), .S(1'b0)); + end + endgenerate + + //------------------------------------------------------------------ + // TX Frame Signal - In bank 3 LB + //------------------------------------------------------------------ + ODDR2 #( + .DDR_ALIGNMENT("C0"), .SRTYPE("ASYNC")) + oddr2_frame ( + .Q(tx_frame), .C0(io_clk_lb), .C1(io_clk_lb_b), + .CE(1'b1), .D0(1'b1), .D1(1'b0), .R(1'b0), .S(1'b0)); + + //------------------------------------------------------------------ + // TX Clock Signal - In bank 3 LB + //------------------------------------------------------------------ + ODDR2 #( + .DDR_ALIGNMENT("C0"), .SRTYPE("ASYNC")) + oddr2_clk ( + .Q(tx_clk), .C0(io_clk_lb), .C1(io_clk_lb_b), + .CE(1'b1), .D0(1'b1), .D1(1'b0), .R(1'b0), .S(1'b0)); + + //------------------------------------------------------------------ + // + // Mux I & Q, onto fullrate clock TX bus to AD9361 + // + //------------------------------------------------------------------ + + always @(posedge siso_clk) + begin + {tx_i,tx_q} <= {tx_i0,tx_q0}; + end + + // + // Debug + // +/* -----\/----- EXCLUDED -----\/----- + wire [35:0] CONTROL0; + reg [11:0] tx_i_del_debug, tx_q_del_debug; + reg [11:0] tx_i_debug,tx_q_debug; + reg [11:0] tx_i0_debug,tx_q0_debug; + reg find_radio_clk_phase_debug; + reg find_radio_clk_phase_del_debug; + reg tx_strobe_debug; + reg tx_strobe_del_debug; + + + always @(posedge siso_clk) begin + tx_i_del_debug <= tx_i_del; + tx_q_del_debug <= tx_q_del; + tx_i_debug <= tx_i; + tx_q_debug <= tx_q; + tx_i0_debug <=tx_i0; + tx_q0_debug <= tx_q0; + find_radio_clk_phase_debug <= find_radio_clk_phase; + find_radio_clk_phase_del_debug <= find_radio_clk_phase_del; + tx_strobe_debug <= tx_strobe; + tx_strobe_del_debug <= tx_strobe_del; + end + + + + chipscope_icon chipscope_icon_i0 + ( + .CONTROL0(CONTROL0) // INOUT BUS [35:0] + ); + + chipscope_ila_128 chipscope_ila_i0 + ( + .CONTROL(CONTROL0), // INOUT BUS [35:0] + .CLK(siso_clk), // IN + .TRIG0( + { + tx_i_del_debug[11:0], + tx_q_del_debug[11:0], + tx_i_debug[11:0], + tx_q_debug[11:0], + tx_i0_debug[11:0], + tx_q0_debug[11:0], + find_radio_clk_phase_debug, + find_radio_clk_phase_del_debug, + tx_strobe_debug, + tx_strobe_del_debug + } + ) + + ); + -----/\----- EXCLUDED -----/\----- */ +endmodule |