Files

415 lines
15 KiB
VHDL

-------------------------------------------------------------------------------
-- Company:
-- Engineer: Jason M. Blevins
--
-- Create Date: 19:38:12 11/10/2016
-- Design Name:
-- Module Name: dds_pulse_gen - behavioral
-- Project Name:
-- Target Devices:
-- Tool versions:
-- Description:
--
-- Dependencies:
--
-- Revision:
-- Revision 0.01 - File Created
-- Revision 0.02 - Added Sweep Functionality 10-17-2017
-- Additional Comments:
-- * All information is proprietary/confidential *
--
-- A 256-bit control word (32x8 right shifted in) is read from an external FIFO.
-- The control word contains all information needed to create a pulse
--
-- RESERVED = fifo_data_r(255 downto 241) -- 15-bits
-- SWAP IQ CHANELS = fifo_data_r(240) -- 1-bit set to '1' for negative frequencies
-- SCALE FACTOR TO SCALE OUTPUT AMPLITUDE = fifo_data_r(239 downto 224) -- 16-bits, (0,1], full-scale = 1.000000000000000
-- DDS PHASE OFFSET = fifo_data_r(223 downto 192) -- 32-bits, reserved, set to 0x0000_0000
-- DDS PHASE INCREMENT = fifo_data_r(191 downto 160) -- 32-bits
-- # DDS SAMPLES = fifo_data_r(159 downto 128) -- 32-bits
-- # MIDPOINT SAMPLES PRIOR TO PULSE = fifo_data_r(127 downto 96) -- 32-bits
-- RESERVED = fifo_data_r(95 downto 88) -- 8-bit
-- DDS PHASE INCREMENT STEP = fifo_data_r(87 downto 64) -- 24-bits (2's complement SIGNED !!)
-- RESERVED = fifo_data_r(63 downto 48) -- 16-bits
-- DDS PHASE INCREMENT DWELL = fifo_data_r(47 downto 32) -- 16-bits
-- RESERVED = fifo_data_r(31 downto 0) -- 32-bits
--
-------------------------------------------------------------------------------
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
--Library UNIMACRO;
--use UNIMACRO.vcomponents.all;
USE IEEE.NUMERIC_STD.ALL;
entity dds_pulse_gen is
port(
clk_in : in std_logic;
rst_in : in std_logic;
fifo_data_in : in std_logic_vector(31 downto 0);
fifo_dval_in : in std_logic;
fifo_empty_in : in std_logic;
fifo_rden_out : out std_logic;
holdoff_in : in std_logic;
data_out : out std_logic_vector(31 downto 0);
dval_out : out std_logic
);
end entity;
architecture mixed of dds_pulse_gen is
component mult_16signed_x_16unsigned_latency3
port(
clk : in std_logic;
a : in std_logic_vector(15 downto 0);
b : in std_logic_vector(15 downto 0);
ce : in std_logic;
sclr : in std_logic;
p : out std_logic_vector(15 downto 0)
);
end component;
component dds_latency10
port(
-- ce : in std_logic;
-- clk : in std_logic;
-- sclr : in std_logic;
-- pinc_in : in std_logic_vector(31 downto 0);
-- poff_in : in std_logic_vector(31 downto 0);
-- rdy : out std_logic;
-- cosine : out std_logic_vector(15 downto 0);
-- sine : out std_logic_vector(15 downto 0)
aclk : IN STD_LOGIC;
aclken : IN STD_LOGIC;
aresetn : IN STD_LOGIC;
s_axis_phase_tvalid : IN STD_LOGIC;
s_axis_phase_tdata : IN STD_LOGIC_VECTOR(31 DOWNTO 0);
m_axis_data_tvalid : OUT STD_LOGIC;
m_axis_data_tdata : OUT STD_LOGIC_VECTOR(31 DOWNTO 0)
);
end component;
component addsub
port (
a : in std_logic_vector(31 downto 0); -- unsigned
b : in std_logic_vector(23 downto 0); -- signed
--clk : in std_logic;
s : out std_logic_vector(31 downto 0) -- latency=0 ?? Not practical in HW, design should be updated to allow for latency.
);
end component;
constant MIDPOINT : std_logic_vector(31 downto 0) := x"00000000";
type state_type is (s0, s0a, s0b, s0c, s1, s2, s3);
signal state : state_type;
signal state_r : state_type;
signal rst_r : std_logic := '1';
signal rstn_r : std_logic := '0';
signal cnt1_r : unsigned(3 downto 0) := "0000";
signal cnt1 : unsigned(3 downto 0);
signal cnt2_r : unsigned(2 downto 0) := "000";
signal cnt2 : unsigned(2 downto 0);
signal cnt3_r : unsigned(31 downto 0) := x"00000000";
signal cnt3 : unsigned(31 downto 0);
signal cnt4_r : unsigned(31 downto 0) := x"00000000";
signal cnt4 : unsigned(31 downto 0);
signal cnt5_r : unsigned(3 downto 0) := "0000";
signal cnt5 : unsigned(3 downto 0);
signal fifo_data_ce : std_logic;
signal fifo_data_r : std_logic_vector(255 downto 0);
signal fifo_rden : std_logic;
--signal fifo_rden_r : std_logic := '0';
signal dval_r : std_logic := '0';
signal dval : std_logic;
signal dds_data : std_logic_vector(31 downto 0);
signal data : std_logic_vector(31 downto 0);
signal data_r : std_logic_vector(31 downto 0);
signal idle_sample_cnt_r : unsigned(31 downto 0);
signal idle_sample_cnt_r1 : unsigned(31 downto 0);
signal dds_sample_cnt_r : unsigned(31 downto 0);
signal dds_sample_cnt_r1 : unsigned(31 downto 0);
signal phase_inc_init_r : std_logic_vector(31 downto 0);
signal phase_offset_r : std_logic_vector(31 downto 0);
signal swap_r : std_logic := '0';
signal scale_r : std_logic_vector(15 downto 0);
signal mult_dval_r : std_logic := '0';
signal data_swap_scaled : std_logic_vector(31 downto 0);
signal data_scaled : std_logic_vector(31 downto 0);
signal dds_ce : std_logic;
signal dds_rst : std_logic;
signal dds_rdy : std_logic;
signal mult_ce : std_logic;
signal mult_ce_pipe_r : std_logic_vector(1 downto 0) := "00";
signal holdoff_r : std_logic;
--signal phase_inc_mux_sel : std_logic;
signal phase_inc_update_en : std_logic;
--signal phase_inc_mux : std_logic_vector(31 downto 0);
signal phase_inc : std_logic_vector(31 downto 0);
signal phase_inc_r : std_logic_vector(31 downto 0);
signal phase_inc_r1 : std_logic_vector(31 downto 0);
signal phase_inc_step_r : std_logic_vector(23 downto 0) := (others => '0');
signal phase_inc_dwell_r : unsigned(15 downto 0) := x"0000";
signal phase_inc_dwell_cnt_r : unsigned(15 downto 0) := x"0000";
signal phase_inc_dwell_cnt : unsigned(15 downto 0);
signal phase_inc_addsub : std_logic_vector(31 downto 0);
signal rstn : std_logic;
begin
i_addsub : addsub
port map(
a => phase_inc_r,
b => phase_inc_step_r,
--clk => clk_in,
s => phase_inc_addsub
);
fifo_rden_out <= fifo_rden;--fifo_rden_r;
data_out <= data_r;
dval_out <= dval_r;
process(clk_in)
begin
if(rising_edge(clk_in))then
if(rst_r = '1')then
state_r <= s0;
cnt1_r <= (others => '0');
cnt2_r <= (others => '0');
cnt3_r <= (others => '0');
cnt4_r <= (others => '0');
cnt5_r <= (others => '0');
phase_inc_dwell_cnt_r <= (others => '0');
else
state_r <= state;
cnt1_r <= cnt1;
cnt2_r <= cnt2;
cnt3_r <= cnt3;
cnt4_r <= cnt4;
cnt5_r <= cnt5;
phase_inc_dwell_cnt_r <= phase_inc_dwell_cnt;
end if;
if(fifo_data_ce = '1')then
fifo_data_r <= fifo_data_in & fifo_data_r(255 downto 32);--fifo_data_r(223 downto 0) & fifo_data_in;
end if;
rst_r <= rst_in;
rstn_r <= not(rst_in);
dval_r <= dval;
phase_offset_r <= fifo_data_r(223 downto 192);
-- phase_inc_init_r <= fifo_data_r(191 downto 160);
dds_sample_cnt_r <= unsigned(fifo_data_r(159 downto 128));
dds_sample_cnt_r1 <= dds_sample_cnt_r;
swap_r <= fifo_data_r(240);
scale_r <= fifo_data_r(239 downto 224);
idle_sample_cnt_r <= unsigned(fifo_data_r(127 downto 96));
idle_sample_cnt_r1 <= idle_sample_cnt_r;
phase_inc_step_r <= fifo_data_r(87 downto 64);
phase_inc_dwell_r <= unsigned(fifo_data_r(47 downto 32));
data_r <= data;
holdoff_r <= holdoff_in;
phase_inc_r <= phase_inc;
if(phase_inc_update_en = '1')then
phase_inc_r1 <= phase_inc_r;
end if;
end if;
end process;
phase_inc_init_r <= fifo_data_r(191 downto 160);
-- FSM next-state & output process
process(state_r, cnt1_r, cnt2_r, cnt3_r, cnt4_r, cnt5_r, holdoff_r, fifo_empty_in, fifo_dval_in, phase_inc_init_r, phase_inc_r,
mult_dval_r, data_swap_scaled, idle_sample_cnt_r1, dds_sample_cnt_r1, phase_inc_dwell_r, phase_inc_dwell_cnt_r, phase_inc_addsub)
begin
--defaults
fifo_rden <= '0';
cnt1 <= cnt1_r;
cnt2 <= cnt2_r;
cnt3 <= cnt3_r;
cnt4 <= cnt4_r;
cnt5 <= cnt5_r;
state <= state_r;
dds_ce <= '0';
dds_rst <= '1';
dval <= mult_dval_r;
data <= data_swap_scaled;
fifo_data_ce <= '0';
phase_inc_dwell_cnt <= phase_inc_dwell_cnt_r;
phase_inc <= phase_inc_r;
phase_inc_update_en <= '0';
case state_r is
when s0 =>
phase_inc_dwell_cnt <= (others => '0');
if(fifo_empty_in = '0' and cnt1_r < 8)then
fifo_rden <= '1';
cnt1 <= cnt1_r +1;
end if;
if(fifo_dval_in = '1')then
fifo_data_ce <= '1';
if(cnt2_r < 7)then
cnt2 <= cnt2_r +1;
else
cnt2 <= (others => '0');
cnt1 <= (others => '0');
state <= s0a;
end if;
end if;
-- This state is needed to clock the input shift reg data into next set of regs.
-- Possibly can be removed to decrease pulse param processing cycles.
when s0a =>
state <= s0b;--s1;
phase_inc <= phase_inc_init_r;
-- This state is needed to clock the input shift reg data into next set of regs.
-- Possibly can be removed to decrease pulse param processing cycles.
when s0b =>
state <= s1;
phase_inc_update_en <= '1';
phase_inc <= phase_inc_addsub;--phase_inc_r + phase_inc_step_r;
-- This state is needed to clock the input shift reg data into next set of regs.
-- Possibly can be removed to decrease pulse param processing cycles.
-- when s0c =>
-- state <= s1;
-- phase_inc_update_en <= '1';
-- phase_inc <= phase_inc_addsub;--phase_inc_r + phase_inc_step_r;
-- Insert midpoint (idle) samples that preceed the pulse.
when s1 =>
data <= MIDPOINT;
if(cnt3_r < idle_sample_cnt_r1)then
if(holdoff_r = '0')then
cnt3 <= cnt3_r +1;
dval <= '1';
end if;
else
cnt3 <= (others => '0');
if(dds_sample_cnt_r1 > 0)then
state <= s2;
else
state <= s0;
end if;
end if;
-- Turn on DDS for requested number of samples.
when s2 =>
dds_rst <= '0';
if(holdoff_r = '0')then
if(phase_inc_dwell_cnt_r < phase_inc_dwell_r)then
phase_inc_dwell_cnt <= phase_inc_dwell_cnt_r +1;
else
phase_inc_dwell_cnt <= (others => '0');
phase_inc_update_en <= '1';
phase_inc <= phase_inc_addsub;--phase_inc_r + phase_inc_step_r;
end if;
end if;
if(holdoff_r = '0')then
dds_ce <= '1';
if(cnt4_r < dds_sample_cnt_r1)then
cnt4 <= cnt4_r +1;
else
cnt4 <= (others => '0');
state <= s3;
end if;
end if;
-- phase_inc_mux_sel <= '1';
-- --phase_inc_en <= not(holdoff_r);
-- dds_rst <= '0';
-- if(cnt4_r < dds_sample_cnt_r1)then
-- if(holdoff_r = '0')then
-- dds_ce <= '1';
-- cnt4 <= cnt4_r +1;
-- if(phase_inc_dwell_cnt_r < phase_inc_dwell_r)then
-- phase_inc_dwell_cnt <= phase_inc_dwell_cnt_r +1;
-- else
-- phase_inc_dwell_cnt <= x"00000";
-- phase_inc_en <= '1';
-- end if;
-- end if;
-- else
-- if(holdoff_r = '0')then
-- dds_ce <= '1';
-- cnt4 <= (others => '0');
-- state <= s3;
-- end if;
-- end if;
-- Keep DDS enabled to overcome the latency of the core (i.e. wait for our samples to pop out).
when s3 =>
dds_rst <= '0';
if(cnt5_r < 9)then
if(holdoff_r = '0')then
dds_ce <= '1';
cnt5 <= cnt5_r +1;
end if;
else
cnt5 <= (others => '0');
state <= s0;
end if;
when others =>
end case;
end process;
process(clk_in)
begin
if(rising_edge(clk_in))then
mult_dval_r <= mult_ce_pipe_r(1);
mult_ce_pipe_r(1 downto 0) <= mult_ce_pipe_r(0) & (dds_rdy and dds_ce);
end if;
end process;
data_swap_scaled <= data_scaled when swap_r = '0' else data_scaled(15 downto 0) & data_scaled(31 downto 16);
mult_ce <= mult_ce_pipe_r(1) or mult_ce_pipe_r(0) or (dds_rdy and dds_ce);
i_dds : dds_latency10
port map(
-- ce => dds_ce,
-- clk => clk_in,
-- sclr => dds_rst,
-- pinc_in => phase_inc_r1,
-- poff_in => phase_offset_r,
-- rdy => dds_rdy,
-- cosine => dds_data(15 downto 0),
-- sine => dds_data(31 downto 16)
aclk => clk_in,
aclken => dds_ce,
aresetn => rstn_r,
s_axis_phase_tvalid => dds_ce,
s_axis_phase_tdata => phase_inc_r1,
m_axis_data_tvalid => dds_rdy,
m_axis_data_tdata => dds_data(31 downto 0)
);
i_mult1 : mult_16signed_x_16unsigned_latency3
port map(
clk => clk_in,
a => dds_data(15 downto 0),
b => scale_r,
ce => mult_ce,
sclr => '0',
p => data_scaled(15 downto 0)
);
i_mult2 : mult_16signed_x_16unsigned_latency3
port map(
clk => clk_in,
a => dds_data(31 downto 16),
b => scale_r,
ce => mult_ce,
sclr => '0',
p => data_scaled(31 downto 16)
);
end mixed;