162 lines
4.2 KiB
Verilog
162 lines
4.2 KiB
Verilog
//
|
|
// Copyright 2015 Ettus Research, A National Instruments Company
|
|
// SPDX-License-Identifier: LGPL-3.0
|
|
//
|
|
// Description: E31X IO for CMOS interface
|
|
//
|
|
|
|
module b200_io (
|
|
input areset,
|
|
input mimo,
|
|
// Baseband sample interface
|
|
output radio_clk,
|
|
output radio_rst,
|
|
output reg [11:0] rx_i0,
|
|
output reg [11:0] rx_q0,
|
|
output reg [11:0] rx_i1,
|
|
output reg [11:0] rx_q1,
|
|
output reg rx_stb,
|
|
input [11:0] tx_i0,
|
|
input [11:0] tx_q0,
|
|
input [11:0] tx_i1,
|
|
input [11:0] tx_q1,
|
|
output reg tx_stb,
|
|
// AD9361 interface
|
|
input rx_clk,
|
|
input rx_frame,
|
|
input [11:0] rx_data,
|
|
output tx_clk,
|
|
output tx_frame,
|
|
output [11:0] tx_data
|
|
);
|
|
|
|
// Synchronize asynchronous reset and MIMO
|
|
synchronizer #(.STAGES(3), .INITIAL_VAL(1'b1)) sychronizer_radio_rst (
|
|
.clk(radio_clk), .rst(areset), .in(1'b0), .out(radio_rst));
|
|
|
|
wire mimo_sync;
|
|
synchronizer synchronizer_mimo (.clk(radio_clk), .rst(radio_rst), .in(mimo), .out(mimo_sync));
|
|
|
|
/****************************************************************************
|
|
** RX Capture Interface
|
|
****************************************************************************/
|
|
wire rx_clk_bufr; // Capture clock
|
|
wire rx_clk_mimo_bufr;
|
|
|
|
BUFG bufr_rx_clk (.I(rx_clk), .O(rx_clk_bufr));
|
|
|
|
BUFR #(
|
|
.BUFR_DIVIDE("2"), // Values: "BYPASS, 1, 2, 3, 4, 5, 6, 7, 8"
|
|
.SIM_DEVICE("7SERIES") // Must be set to "7SERIES"
|
|
)
|
|
BUFR_inst (
|
|
.O(rx_clk_mimo_bufr),
|
|
.CE(1'b1),
|
|
.CLR(areset),
|
|
.I(rx_clk)
|
|
);
|
|
|
|
BUFGMUX #(
|
|
)
|
|
BUFGMUX_inst (
|
|
.O(radio_clk),
|
|
.I0(rx_clk_bufr),
|
|
.I1(rx_clk_mimo_bufr),
|
|
.S(mimo_sync)
|
|
);
|
|
|
|
|
|
wire [11:0] rx_i, rx_q;
|
|
genvar n;
|
|
generate
|
|
for (n = 0; n < 12; n = n + 1) begin
|
|
IDDR #(.DDR_CLK_EDGE("SAME_EDGE")) iddr (
|
|
.C(rx_clk_bufr), .CE(1'b1), .R(1'b0), .S(1'b0),
|
|
.D(rx_data[n]), .Q1(rx_q[n]), .Q2(rx_i[n]));
|
|
end
|
|
endgenerate
|
|
|
|
wire rx_frame_rising, rx_frame_falling;
|
|
IDDR #(.DDR_CLK_EDGE("SAME_EDGE")) iddr_frame (
|
|
.C(rx_clk_bufr), .CE(1'b1), .R(1'b0), .S(1'b0),
|
|
.D(rx_frame), .Q1(rx_frame_rising), .Q2(rx_frame_falling));
|
|
|
|
always @(posedge rx_clk_bufr or posedge radio_rst) begin
|
|
if (radio_rst) begin
|
|
rx_stb <= 1'b0;
|
|
end else begin
|
|
if (mimo_sync) begin
|
|
if (rx_frame_rising) begin
|
|
rx_i0 <= rx_i;
|
|
rx_q0 <= rx_q;
|
|
end else begin
|
|
rx_i1 <= rx_i;
|
|
rx_q1 <= rx_q;
|
|
end
|
|
rx_stb <= ~rx_frame_rising;
|
|
end else begin
|
|
rx_i0 <= rx_i;
|
|
rx_q0 <= rx_q;
|
|
rx_i1 <= rx_i;
|
|
rx_q1 <= rx_q;
|
|
rx_stb <= 1'b1;
|
|
end
|
|
end
|
|
end
|
|
|
|
/****************************************************************************
|
|
** TX Output Interface
|
|
****************************************************************************/
|
|
reg [11:0] tx_i, tx_q;
|
|
reg tx_frame_int = 1'b1;
|
|
generate
|
|
for (n = 0; n < 12; n = n + 1) begin
|
|
ODDR #(.DDR_CLK_EDGE("SAME_EDGE")) oddr (
|
|
.C(rx_clk_bufr), .CE(1'b1), .R(1'b0), .S(1'b0),
|
|
.D1(tx_i[n]), .D2(tx_q[n]), .Q(tx_data[n]));
|
|
end
|
|
endgenerate
|
|
|
|
ODDR #(.DDR_CLK_EDGE("SAME_EDGE")) oddr_frame (
|
|
.C(rx_clk_bufr), .CE(1'b1), .R(1'b0), .S(1'b0),
|
|
// In SISO mode, TX frame is asserted only on the falling edge
|
|
.D1(tx_frame_int), .D2(tx_frame_int & mimo_sync), .Q(tx_frame));
|
|
|
|
ODDR #(.DDR_CLK_EDGE("SAME_EDGE")) oddr_clk (
|
|
.C(rx_clk_bufr), .CE(1'b1), .R(1'b0), .S(1'b0),
|
|
.D1(1'b1), .D2(1'b0), .Q(tx_clk));
|
|
|
|
reg [11:0] tx_i1_hold, tx_q1_hold;
|
|
always @(posedge rx_clk_bufr or posedge radio_rst) begin
|
|
if (radio_rst) begin
|
|
tx_stb <= 1'b0;
|
|
tx_frame_int <= 1'b1;
|
|
end else begin
|
|
if (mimo_sync) begin
|
|
tx_stb <= ~tx_stb;
|
|
tx_frame_int <= tx_stb;
|
|
if (tx_stb) begin
|
|
tx_i <= tx_i0;
|
|
tx_q <= tx_q0;
|
|
tx_i1_hold <= tx_i1;
|
|
tx_q1_hold <= tx_q1;
|
|
end else begin
|
|
tx_i <= tx_i1_hold;
|
|
tx_q <= tx_q1_hold;
|
|
end
|
|
end else begin
|
|
tx_stb <= 1'b1;
|
|
tx_frame_int <= 1'b1;
|
|
if ({tx_i0,tx_q0} != 24'd0) begin
|
|
tx_i <= tx_i0;
|
|
tx_q <= tx_q0;
|
|
end else begin
|
|
tx_i <= tx_i1;
|
|
tx_q <= tx_q1;
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
endmodule
|