RFToolSDR/fpga/ad9361/ad9361_bidir_if.vhd

260 lines
6.7 KiB
VHDL

library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.NUMERIC_STD.ALL;
library UNISIM;
use UNISIM.VComponents.all;
--AD9361 1Rx1Tx LVDS DDR interface
--Copyright (C) 2016-17 David Shah
--Licensed under the MIT License
entity ad9361_sdr_bidir_if is
port(
--AD9361 side
data_clock_p : in std_logic;
data_clock_n : in std_logic;
fb_clock_p : out std_logic;
fb_clock_n : out std_logic;
rx_frame_p : in std_logic;
rx_frame_n : in std_logic;
tx_frame_p : out std_logic;
tx_frame_n : out std_logic;
p0_d : out std_logic_vector(11 downto 0);
p1_d : in std_logic_vector(11 downto 0);
--User side
user_clock : out std_logic;
rx_data_frame : out std_logic;
rx_data_i : out std_logic_vector(11 downto 0);
rx_data_q : out std_logic_vector(11 downto 0);
tx_data_i : in std_logic_vector(11 downto 0);
tx_data_q : in std_logic_vector(11 downto 0);
tx_data_req : out std_logic);
end ad9361_sdr_bidir_if;
--The following pairs are swapped (ie inverted) on the PCB
--RX_FRAME; TX_FRAME, TX_D0, FB_CLK, RX_D5, RX_D3, RX_D4
--TODO: change this setting to be a VHDL generic
architecture Behavioral of ad9361_sdr_bidir_if is
signal clock_se, clock_buf, fb_clock_se : std_logic;
signal input_data_se : std_logic_vector(5 downto 0);
signal input_data_sdr_rp, input_data_sdr_fp, input_data_sdr_r, input_data_sdr_f : std_logic_vector(5 downto 0);
signal output_data_se : std_logic_vector(5 downto 0);
signal output_data_sdr_rp, output_data_sdr_fp, output_data_sdr_r, output_data_sdr_f : std_logic_vector(5 downto 0);
signal rx_data_lat_i, tx_data_lat_i : std_logic_vector(11 downto 0);
signal rx_data_lat_q, tx_data_lat_q : std_logic_vector(11 downto 0);
signal rx_frame_se_pre, rx_frame_se, tx_frame_se, tx_frame_se_pre, tx_frame_se_inv : std_logic;
begin
clkibuf : IBUFDS
generic map(
IBUF_LOW_PWR => FALSE,
IOSTANDARD => "DEFAULT")
port map(
O => clock_se,
I => data_clock_p,
IB => data_clock_n
);
clkbufio : BUFR
generic map(
BUFR_DIVIDE => "BYPASS",
SIM_DEVICE => "7SERIES")
port map(
O => clock_buf,
CE => '1',
CLR => '0',
I => clock_se);
fbclkdrv : ODDR
generic map(
DDR_CLK_EDGE => "OPPOSITE_EDGE",
INIT => '0',
SRTYPE => "SYNC")
port map(
Q => fb_clock_se,
C => clock_buf,
CE => '1',
D1 => '0',
D2 => '1',
R => '0',
S => '0');
clkobuf : OBUFDS
generic map(
IOSTANDARD => "DEFAULT",
SLEW => "SLOW")
port map(
O => fb_clock_n,
OB => fb_clock_p,
I => fb_clock_se);
gen_io : for i in 0 to 5 generate
gen_inv_i : if (i = 3) or (i = 4) or (i = 5) generate
rxibuf : IBUFDS
generic map(
IBUF_LOW_PWR => FALSE,
IOSTANDARD => "DEFAULT")
port map(
O => input_data_se(i),
I => p1_d((i*2)),
IB => p1_d((i*2)+1));
input_data_sdr_rp(i) <= not input_data_sdr_r(i);
input_data_sdr_fp(i) <= not input_data_sdr_f(i);
end generate;
gen_true_i : if (i = 0) or (i = 1) or (i = 2) generate
rxibuf : IBUFDS
generic map(
IBUF_LOW_PWR => FALSE,
IOSTANDARD => "DEFAULT")
port map(
O => input_data_se(i),
I => p1_d((i*2)+1),
IB => p1_d(i*2));
input_data_sdr_rp(i) <= input_data_sdr_r(i);
input_data_sdr_fp(i) <= input_data_sdr_f(i);
end generate;
rxiddr : IDDR
generic map(
DDR_CLK_EDGE => "OPPOSITE_EDGE",
INIT_Q1 => '0',
INIT_Q2 => '0',
SRTYPE => "SYNC")
port map(
Q1 => input_data_sdr_r(i),
Q2 => input_data_sdr_f(i),
C => clock_buf,
CE => '1',
D => input_data_se(i),
R => '0',
S => '0');
txoddr : ODDR
generic map(
DDR_CLK_EDGE => "OPPOSITE_EDGE",
INIT => '0',
SRTYPE => "SYNC")
port map(
Q => output_data_se(i),
C => clock_buf,
CE => '1',
D1 => output_data_sdr_rp(i),
D2 => output_data_sdr_fp(i),
R => '0',
S => '0');
gen_inv_o : if (i = 0) generate
txobuf : OBUFDS
generic map(
IOSTANDARD => "DEFAULT",
SLEW => "SLOW")
port map(
O => p0_d((i*2)),
OB => p0_d((i*2)+1),
I => output_data_se(i));
output_data_sdr_rp(i) <= not output_data_sdr_r(i);
output_data_sdr_fp(i) <= not output_data_sdr_f(i);
end generate;
gen_true_o : if (i /= 0) generate
txobuf : OBUFDS
generic map(
IOSTANDARD => "DEFAULT",
SLEW => "SLOW")
port map(
O => p0_d((i*2)+1),
OB => p0_d(i*2),
I => output_data_se(i));
output_data_sdr_rp(i) <= output_data_sdr_r(i);
output_data_sdr_fp(i) <= output_data_sdr_f(i);
end generate;
end generate;
rxfbuf : IBUFDS
generic map(
IBUF_LOW_PWR => FALSE,
IOSTANDARD => "DEFAULT")
port map(
O => rx_frame_se_pre,
I => rx_frame_n,
IB => rx_frame_p
);
--ODDR for symmetrical latency between data and output
txfoddr : ODDR
generic map(
DDR_CLK_EDGE => "OPPOSITE_EDGE",
INIT => '0',
SRTYPE => "SYNC")
port map(
Q => tx_frame_se_pre,
C => clock_buf,
CE => '1',
D1 => tx_frame_se_inv,
D2 => tx_frame_se_inv,
R => '0',
S => '0');
txfbuf : OBUFDS
generic map(
IOSTANDARD => "DEFAULT",
SLEW => "SLOW")
port map(
O => tx_frame_n,
OB => tx_frame_p,
I => tx_frame_se_pre);
rx_frame_se <= not rx_frame_se_pre;
tx_frame_se_inv <= not tx_frame_se;
process(clock_buf)
begin
if falling_edge(clock_buf) then
if rx_frame_se = '1' then
rx_data_lat_i(5 downto 0) <= input_data_sdr_fp;
rx_data_lat_q(5 downto 0) <= input_data_sdr_rp;
rx_data_frame <= '0';
else
rx_data_i <= rx_data_lat_i;
rx_data_q <= rx_data_lat_q;
rx_data_frame <= '1';
rx_data_lat_i(11 downto 6) <= input_data_sdr_fp;
rx_data_lat_q(11 downto 6) <= input_data_sdr_rp;
end if;
end if;
end process;
process(clock_buf)
begin
if rising_edge(clock_buf) then
if tx_frame_se = '0' then
output_data_sdr_f <= tx_data_lat_i(11 downto 6);
output_data_sdr_r <= tx_data_lat_q(11 downto 6);
tx_data_req <= '1';
tx_frame_se <= '1';
else
output_data_sdr_f <= tx_data_lat_i(5 downto 0);
output_data_sdr_r <= tx_data_lat_q(5 downto 0);
tx_data_lat_i <= tx_data_i;
tx_data_lat_q <= tx_data_q;
tx_data_req <= '0';
tx_frame_se <= '0';
end if;
end if;
end process;
user_clock <= clock_buf;
end Behavioral;