entity dac3283_ctrl is
generic (
START_ADDR : std_logic_vector(27 downto 0) := x"0000000";
STOP_ADDR : std_logic_vector(27 downto 0) := x"00000FF"
);
port (
rst : in std_logic;
clk : in std_logic;
-- Sequence interface
init_ena : in std_logic;
init_done : out std_logic;
-- Command Interface
clk_cmd : in std_logic;
in_cmd_val : in std_logic;
in_cmd : in std_logic_vector(63 downto 0);
out_cmd_val : out std_logic;
out_cmd : out std_logic_vector(63 downto 0);
in_cmd_busy : out std_logic;
-- SPI control
spi_n_oe : out std_logic;
spi_n_cs : out std_logic;
spi_sclk : out std_logic;
spi_sdo : out std_logic;
spi_sdi : in std_logic
);
end dac3283_ctrl;
architecture dac3283_ctrl_syn of dac3283_ctrl is
component fmc150_stellar_cmd is
generic
(
START_ADDR : std_logic_vector(27 downto 0) := x"0000000";
STOP_ADDR : std_logic_vector(27 downto 0) := x"00000FF"
);
port
(
reset : in std_logic;
-- Command Interface
clk_cmd : in std_logic; --cmd_in and cmd_out are synchronous to this clock;
out_cmd : out std_logic_vector(63 downto 0);
out_cmd_val : out std_logic;
in_cmd : in std_logic_vector(63 downto 0);
in_cmd_val : in std_logic;
-- Register interface
clk_reg : in std_logic; --register interface is synchronous to this clock
out_reg : out std_logic_vector(31 downto 0); --caries the out register data
out_reg_val : out std_logic; --the out_reg has valid data (pulse)
out_reg_addr : out std_logic_vector(27 downto 0); --out register address
in_reg : in std_logic_vector(31 downto 0); --requested register data is placed on this bus
in_reg_val : in std_logic; --pulse to indicate requested register is valid
in_reg_req : out std_logic; --pulse to request data
in_reg_addr : out std_logic_vector(27 downto 0); --requested address
--mailbox interface
mbx_in_reg : in std_logic_vector(31 downto 0); --value of the mailbox to send
mbx_in_val : in std_logic --pulse to indicate mailbox is valid
);
end component fmc150_stellar_cmd;
component pulse2pulse
port (
rst : in std_logic;
in_clk : in std_logic;
out_clk : in std_logic;
pulsein : in std_logic;
pulseout : out std_logic;
inbusy : out std_logic
);
end component;
component dac3283_init_mem is
port (
clka : in std_logic;
addra : in std_logic_vector(4 downto 0);
douta : out std_logic_vector(15 downto 0)
);
end component;
constant ADDR_GLOBAL : std_logic_vector := x"0000020";
constant ADDR_MAX_WR : std_logic_vector := x"000001F";
constant ADDR_MAX_RD : std_logic_vector := x"000001F";
type sh_states is (idle, instruct, data_io, data_valid);
signal sh_state : sh_states;
signal serial_clk : std_logic;
signal sclk_ext : std_logic;
signal out_reg_val : std_logic;
signal out_reg_addr : std_logic_vector(27 downto 0);
signal out_reg : std_logic_vector(31 downto 0);
signal in_reg_req : std_logic;
signal in_reg_addr : std_logic_vector(27 downto 0);
signal in_reg_val : std_logic;
signal in_reg : std_logic_vector(31 downto 0);
signal done_sclk : std_logic;
signal init_done_sclk : std_logic;
signal init_done_tmp : std_logic;
signal init_done_prev : std_logic;
signal init : std_logic;
signal init_tmp : std_logic;
signal init_reg : std_logic;
signal inst_val : std_logic;
signal inst_reg_val : std_logic;
signal inst_rw : std_logic;
signal inst_reg : std_logic_vector(4 downto 0);
signal data_reg : std_logic_vector(7 downto 0);
signal sh_counter : integer;
signal shifting : std_logic;
signal read_n_write : std_logic;
signal ncs_int : std_logic;
signal busy : std_logic;
signal sdi : std_logic;
signal shift_reg : std_logic_vector(15 downto 0);
signal init_address : std_logic_vector(4 downto 0);
signal init_data : std_logic_vector(15 downto 0);
signal read_byte_val : std_logic;
signal data_read_val : std_logic;
signal data_read : std_logic_vector(7 downto 0);
begin
----------------------------------------------------------------------------------------------------
-- Generate serial clock (max 20MHz)
----------------------------------------------------------------------------------------------------
process (clk)
-- Divide by 2^4 = 16, CLKmax = 16 x 20MHz = 320MHz
variable clk_div : std_logic_vector(3 downto 0) := (others => '0');
begin
if (rising_edge(clk)) then
clk_div := clk_div + '1';
-- The slave samples the data on the rising edge of SCLK.
-- therefore we make sure the external clock is slightly
-- after the internal clock.
sclk_ext <= clk_div(clk_div'length-1);
serial_clk <= sclk_ext;
end if;
end process;
----------------------------------------------------------------------------------------------------
-- Stellar Command Interface
----------------------------------------------------------------------------------------------------
fmc150_stellar_cmd_inst : fmc150_stellar_cmd
generic map
(
START_ADDR => START_ADDR,
STOP_ADDR => STOP_ADDR
)
port map
(
reset => rst,
clk_cmd => clk_cmd,
in_cmd_val => in_cmd_val,
in_cmd => in_cmd,
out_cmd_val => out_cmd_val,
out_cmd => out_cmd,
clk_reg => clk,
out_reg_val => out_reg_val,
out_reg_addr => out_reg_addr,
out_reg => out_reg,
in_reg_req => in_reg_req,
in_reg_addr => in_reg_addr,
in_reg_val => in_reg_val,
in_reg => in_reg,
mbx_in_val => '0',
mbx_in_reg => (others => '0')
);
----------------------------------------------------------------------------------------------------
-- Shoot commands to the state machine
----------------------------------------------------------------------------------------------------
process (rst, clk)
begin
if (rst = '1') then
init_done <= '0';
init_done_tmp <= '0';
init_done_prev <= '0';
init <= '0';
in_reg_val <= '0';
in_reg <= (others => '0');
inst_val <= '0';
inst_rw <= '0';
inst_reg <= (others=> '0');
data_reg <= (others=> '0');
elsif (rising_edge(clk)) then
init_done <= init_done_sclk;
init_done_tmp <= done_sclk;
init_done_prev <= init_done_tmp;
-- Release the init flag on rising edge init done
if (init_done_tmp = '1' and init_done_prev = '0') then
init <= '0';
-- Enable the init flag when enable flag is high, but done flag is low
elsif (init_ena = '1' and init_done_tmp = '0') then
init <= '1';
-- There is one additional status and control register available
elsif (out_reg_val = '1' and out_reg_addr = ADDR_GLOBAL) then
init <= out_reg(0);
end if;
-- There is one additional status and control register available
if (in_reg_req = '1' and in_reg_addr = ADDR_GLOBAL) then
in_reg_val <= '1';
in_reg <= conv_std_logic_vector(0, 27) & '0' & busy & '0' & '0' & init_done_prev;
-- read from serial if when address is within device range
elsif (in_reg_addr <= ADDR_MAX_RD) then
in_reg_val <= data_read_val;
in_reg <= conv_std_logic_vector(0, 24) & data_read;
else
in_reg_val <= '0';
in_reg <= in_reg;
end if;
-- Write instruction, only when address is within device range
if (out_reg_val = '1' and out_reg_addr <= ADDR_MAX_WR) then
inst_val <= '1';
inst_rw <= '0'; -- write
inst_reg <= out_reg_addr(4 downto 0);
data_reg <= out_reg(7 downto 0);
-- Read instruction, only when address is within device range
elsif (in_reg_req = '1' and in_reg_addr <= ADDR_MAX_RD) then
inst_val <= '1';
inst_rw <= '1'; -- read
inst_reg <= in_reg_addr(4 downto 0);
data_reg <= data_reg;
-- No instruction
else
inst_val <= '0';
inst_rw <= inst_rw;
inst_reg <= inst_reg;
data_reg <= data_reg;
end if;
end if;
end process;
-- Intruction pulse
pulse2pulse_inst0 : pulse2pulse
port map
(
rst => rst,
in_clk => clk,
out_clk => serial_clk,
pulsein => inst_val,
pulseout => inst_reg_val,
inbusy => open
);
----------------------------------------------------------------------------------------------------
-- Serial interface state-machine
----------------------------------------------------------------------------------------------------
process (rst, serial_clk)
begin
if (rst = '1') then
init_tmp <= '0';
init_reg <= '0';
sh_state <= idle;
sh_counter <= 0;
shifting <= '0';
read_n_write <= '0';
ncs_int <= '1';
elsif (rising_edge(serial_clk)) then
-- Double synchonise flag from other clock domain
init_tmp <= init;
init_reg <= init_tmp;
-- Main state machine
case sh_state is
when idle =>
sh_counter <= shift_reg'length-data_reg'length-1; --total length minus data bytes;
-- Accept every instruction
if (inst_reg_val = '1' or init_reg = '1') then
shifting <= '1';
read_n_write <= inst_rw and not init_reg; -- force write during init
ncs_int <= '0';
sh_state <= instruct;
else
shifting <= '0';
ncs_int <= '1';
end if;
when instruct =>
if (sh_counter = 0) then
sh_counter <= data_reg'length-1;
sh_state <= data_io;
else
sh_counter <= sh_counter - 1;
end if;
when data_io =>
if (sh_counter = 0) then
sh_counter <= shift_reg'length-data_reg'length-1; --total length minus one data byte;
shifting <= '0';
ncs_int <= '1';
if (read_n_write = '1') then
sh_state <= data_valid;
else
sh_state <= idle;
end if;
else
sh_counter <= sh_counter - 1;
end if;
when data_valid =>
sh_state <= idle;
when others =>
sh_state <= idle;
end case;
end if;
end process;
busy <= '0' when (sh_state = idle and init_reg = '0') else '1';
|