--============================================================================== -- CERN (BE-CO-HT) -- Testbench for CONV-TTL-BLO design --============================================================================== -- -- author: Theodor Stana (t.stana@cern.ch) -- -- date of creation: 2014-02-18 -- -- version: 1.0 -- -- description: -- Design-wide simulation testbench for the CONV-TTL-BLO gateware. Currently -- simulated features include: -- - pulse triggering -- - I2C master for reading register contents -- -- dependencies: -- None. -- --============================================================================== -- GNU LESSER GENERAL PUBLIC LICENSE --============================================================================== -- This source file is free software; you can redistribute it and/or modify it -- under the terms of the GNU Lesser General Public License as published by the -- Free Software Foundation; either version 2.1 of the License, or (at your -- option) any later version. This source is distributed in the hope that it -- will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty -- of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. -- See the GNU Lesser General Public License for more details. You should have -- received a copy of the GNU Lesser General Public License along with this -- source; if not, download it from http://www.gnu.org/licenses/lgpl-2.1.html --============================================================================== -- last changes: -- 2014-02-18 Theodor Stana File created --============================================================================== -- TODO: - --============================================================================== library ieee; use ieee.std_logic_1164.all; use ieee.numeric_std.all; entity testbench is end entity testbench; architecture behav of testbench is --============================================================================ -- Type declarations --============================================================================ type t_state_i2c_mst is ( IDLE, I2C_ADDR, I2C_ADDR_ACK, WB_ADDR_B0, WB_ADDR_B0_ACK, WB_ADDR_B1, WB_ADDR_B1_ACK, ST_OP, RD_RESTART, RD_RESTART_ACK, RD, RD_ACK, WR, WR_ACK, STO, SUCCESS, ERR ); --============================================================================ -- Constant declarations --============================================================================ -- Clock periods constant c_clk_20_per : time := 50 ns; constant c_clk_125_per : time := 8 ns; -- Number of I2C masters and slaves for the I2C bus model constant c_nr_masters : positive := 1; constant c_nr_slaves : positive := 1; --============================================================================ -- Component declarations --============================================================================ component conv_ttl_blo is generic ( g_nr_ttl_chan : natural := 6; g_nr_inv_chan : natural := 4; g_sim : boolean := false ); port ( -- Clocks -- 20 MHz from VCXO clk_20_vcxo_i : in std_logic; -- 125 MHz from clock generator fpga_clk_p_i : in std_logic; fpga_clk_n_i : in std_logic; -- LEDs led_ctrl0_o : out std_logic; led_ctrl0_oen_o : out std_logic; led_ctrl1_o : out std_logic; led_ctrl1_oen_o : out std_logic; led_multicast_2_0_o : out std_logic; led_multicast_3_1_o : out std_logic; led_wr_gmt_ttl_ttln_o : out std_logic; led_wr_link_syserror_o : out std_logic; led_wr_ok_syspw_o : out std_logic; led_wr_ownaddr_i2c_o : out std_logic; -- I/Os for pulses pulse_front_led_n_o : out std_logic_vector(g_nr_ttl_chan downto 1); pulse_rear_led_n_o : out std_logic_vector(g_nr_ttl_chan downto 1); fpga_input_ttl_n_i : in std_logic_vector(g_nr_ttl_chan downto 1); fpga_out_ttl_o : out std_logic_vector(g_nr_ttl_chan downto 1); fpga_blo_in_i : in std_logic_vector(g_nr_ttl_chan downto 1); fpga_trig_blo_o : out std_logic_vector(g_nr_ttl_chan downto 1); inv_in_n_i : in std_logic_vector(g_nr_inv_chan downto 1); inv_out_o : out std_logic_vector(g_nr_inv_chan downto 1); -- Output enable lines fpga_oe_o : out std_logic; fpga_blo_oe_o : out std_logic; fpga_trig_ttl_oe_o : out std_logic; fpga_inv_oe_o : out std_logic; --TTL/INV_TTL_N ttl_switch_n_i : in std_logic; extra_switch_n_i : in std_logic_vector(7 downto 1); -- Lines for the i2c_slave scl_i : in std_logic; scl_o : out std_logic; scl_oe_o : out std_logic; sda_i : in std_logic; sda_o : out std_logic; sda_oe_o : out std_logic; fpga_ga_i : in std_logic_vector(4 downto 0); fpga_gap_i : in std_logic; -- Flash memory lines fpga_prom_cclk_o : out std_logic; fpga_prom_cso_b_n_o : out std_logic; fpga_prom_mosi_o : out std_logic; fpga_prom_miso_i : in std_logic; -- Blocking power supply reset line mr_n_o : out std_logic; -- Thermometer line thermometer_b : inout std_logic; -- PLL DACs -- DAC1: 20 MHz VCXO control fpga_plldac1_din_o : out std_logic; fpga_plldac1_sclk_o : out std_logic; fpga_plldac1_sync_n_o : out std_logic; -- DAC2: 125 MHz clock generator control fpga_plldac2_din_o : out std_logic; fpga_plldac2_sclk_o : out std_logic; fpga_plldac2_sync_n_o : out std_logic; -- SFP lines fpga_sfp_los_i : in std_logic; fpga_sfp_mod_def0_i : in std_logic; fpga_sfp_rate_select_o : out std_logic; fpga_sfp_mod_def1_b : inout std_logic; fpga_sfp_mod_def2_b : inout std_logic; fpga_sfp_tx_disable_o : out std_logic; fpga_sfp_tx_fault_i : in std_logic; -- RTM identifiers, should match with the expected values fpga_rtmm_n_i : in std_logic_vector(2 downto 0); fpga_rtmp_n_i : in std_logic_vector(2 downto 0) ); end component conv_ttl_blo; -- I2C bus model component i2c_bus_model is generic ( g_nr_masters : positive := 1; g_nr_slaves : positive := 1 ); port ( -- Input ports from master lines mscl_i : in std_logic_vector(g_nr_masters-1 downto 0); msda_i : in std_logic_vector(g_nr_masters-1 downto 0); -- Input ports from slave lines sscl_i : in std_logic_vector(g_nr_slaves-1 downto 0); ssda_i : in std_logic_vector(g_nr_slaves-1 downto 0); -- SCL and SDA line outputs scl_o : out std_logic; sda_o : out std_logic ); end component i2c_bus_model; -- I2C master component i2c_master_byte_ctrl is port ( clk : in std_logic; rst : in std_logic; -- synchronous active high reset (WISHBONE compatible) nReset : in std_logic; -- asynchornous active low reset (FPGA compatible) ena : in std_logic; -- core enable signal clk_cnt : in unsigned(15 downto 0); -- 4x SCL -- input signals start, stop, read, write, ack_in : std_logic; din : in std_logic_vector(7 downto 0); -- output signals cmd_ack : out std_logic; -- command done ack_out : out std_logic; i2c_busy : out std_logic; -- arbitration lost i2c_al : out std_logic; -- i2c bus busy dout : out std_logic_vector(7 downto 0); -- i2c lines scl_i : in std_logic; -- i2c clock line input scl_o : out std_logic; -- i2c clock line output scl_oen : out std_logic; -- i2c clock line output enable, active low sda_i : in std_logic; -- i2c data line input sda_o : out std_logic; -- i2c data line output sda_oen : out std_logic -- i2c data line output enable, active low ); end component i2c_master_byte_ctrl; --============================================================================ -- Signal declarations --============================================================================ signal clk_20, clk_125 : std_logic; signal clk_125_p, clk_125_n : std_logic; signal rst_n, rst : std_logic; signal pulse_led_front_n : std_logic_vector(6 downto 1); signal pulse_led_front : std_logic_vector(6 downto 1); signal pulse_led_rear_n : std_logic_vector(6 downto 1); signal pulse_led_rear : std_logic_vector(6 downto 1); signal ttl_inp_n, ttl_outp : std_logic_vector(6 downto 1); signal ttl_pulse : std_logic_vector(6 downto 1); signal inv_pulse : std_logic_vector(6 downto 1); signal blo_inp, blo_outp : std_logic_vector(6 downto 1); signal blo_pulse : std_logic_vector(6 downto 1); signal oe, blo_oe, ttl_oe, inv_oe : std_logic; signal ttl_switch_n : std_logic; signal switches_n : std_logic_vector(7 downto 1); -- I2C signals signal state_i2c_mst : t_state_i2c_mst; signal mst_fsm_op : std_logic; signal mst_fsm_start : std_logic; signal stim_cnt : unsigned(31 downto 0); signal cnt : unsigned(2 downto 0); signal buf_byte_cnt : integer; signal once : boolean; signal byte_cnt : unsigned(1 downto 0); signal rcvd : std_logic_vector(31 downto 0); signal send : std_logic_vector(31 downto 0); signal send_val : std_logic_vector(31 downto 0); signal wrote : std_logic; signal slv_addr : std_logic_vector(6 downto 0); signal adr : std_logic_vector(31 downto 0); signal mst_sta : std_logic; signal mst_sto : std_logic; signal mst_rd : std_logic; signal mst_wr : std_logic; signal mst_ack : std_logic; signal mst_dat_in : std_logic_vector(7 downto 0); signal mst_dat_out : std_logic_vector(7 downto 0); signal mst_cmd_ack : std_logic; signal ack_fr_slv : std_logic; signal mscl, msda : std_logic_vector(c_nr_masters-1 downto 0); signal sscl, ssda : std_logic_vector(c_nr_slaves-1 downto 0); signal scl, sda : std_logic; signal scl_fr_mst : std_logic; signal scl_en_mst : std_logic; signal sda_fr_mst : std_logic; signal sda_en_mst : std_logic; signal scl_fr_slv : std_logic; signal scl_en_slv : std_logic; signal sda_fr_slv : std_logic; signal sda_en_slv : std_logic; signal t : boolean; --============================================================================== -- architecture begin --============================================================================== begin --============================================================================ -- Generate clock signals --============================================================================ p_clk_20 : process begin clk_20 <= '0'; wait for c_clk_20_per/2; clk_20 <= '1'; wait for c_clk_20_per/2; end process; p_clk_125 : process begin clk_125 <= '0'; wait for c_clk_125_per/2; clk_125 <= '1'; wait for c_clk_125_per/2; end process; clk_125_p <= clk_125; clk_125_n <= not clk_125; --============================================================================ -- Instantiate the DUT --============================================================================ cmp_dut : conv_ttl_blo generic map ( g_nr_ttl_chan => 6, g_nr_inv_chan => 4, g_sim => true ) port map ( -- Clocks -- 20 MHz from VCXO clk_20_vcxo_i => clk_20, -- 125 MHz from clock generator fpga_clk_p_i => clk_125_p, fpga_clk_n_i => clk_125_n, -- LEDs led_ctrl0_o => open, led_ctrl0_oen_o => open, led_ctrl1_o => open, led_ctrl1_oen_o => open, led_multicast_2_0_o => open, led_multicast_3_1_o => open, led_wr_gmt_ttl_ttln_o => open, led_wr_link_syserror_o => open, led_wr_ok_syspw_o => open, led_wr_ownaddr_i2c_o => open, -- I/Os for pulses pulse_front_led_n_o => pulse_led_front_n, pulse_rear_led_n_o => pulse_led_rear_n, fpga_input_ttl_n_i => ttl_inp_n, fpga_out_ttl_o => ttl_outp, fpga_blo_in_i => blo_inp, fpga_trig_blo_o => blo_outp, inv_in_n_i => (others => '1'), inv_out_o => open, -- Output enable lines fpga_oe_o => oe, fpga_blo_oe_o => blo_oe, fpga_trig_ttl_oe_o => ttl_oe, fpga_inv_oe_o => inv_oe, --TTL/INV_TTL_N ttl_switch_n_i => ttl_switch_n, extra_switch_n_i => switches_n, -- Lines for the i2c_slave scl_i => scl, scl_o => scl_fr_slv, scl_oe_o => scl_en_slv, sda_i => sda, sda_o => sda_fr_slv, sda_oe_o => sda_en_slv, fpga_ga_i => "11110", fpga_gap_i => '0', -- Flash memory lines fpga_prom_cclk_o => open, fpga_prom_cso_b_n_o => open, fpga_prom_mosi_o => open, fpga_prom_miso_i => 'Z', -- Blocking power supply reset line mr_n_o => rst_n, -- Thermometer line thermometer_b => open, -- PLL DACs -- DAC1: 20 MHz VCXO control fpga_plldac1_din_o => open, fpga_plldac1_sclk_o => open, fpga_plldac1_sync_n_o => open, -- DAC2: 125 MHz clock generator control fpga_plldac2_din_o => open, fpga_plldac2_sclk_o => open, fpga_plldac2_sync_n_o => open, -- SFP lines fpga_sfp_los_i => '1', fpga_sfp_mod_def0_i => '1', fpga_sfp_rate_select_o => open, fpga_sfp_mod_def1_b => open, fpga_sfp_mod_def2_b => open, fpga_sfp_tx_disable_o => open, fpga_sfp_tx_fault_i => '1', -- RTM identifiers, should match with the expected values fpga_rtmm_n_i => (others => '0'), fpga_rtmp_n_i => (others => '0') ); -- Tri-state buffers on the I2C lines sscl(0) <= scl_fr_slv when (scl_en_slv = '1') else '1'; ssda(0) <= sda_fr_slv when (sda_en_slv = '1') else '1'; -- Active-high reset rst <= not rst_n; --============================================================================ -- Pulse outputs assignment based on OE signals --============================================================================ ttl_pulse <= ttl_outp when (oe = '1') and (ttl_oe = '1') else (others => '0'); blo_pulse <= blo_outp when (oe = '1') and (blo_oe = '1') else (others => '0'); inv_pulse <= blo_outp when (oe = '1') and (inv_oe = '1') else (others => '0'); --============================================================================ -- Switches --============================================================================ -- TTL ttl_switch_n <= '0'; -- GF switches_n(1) <= '0'; -- other switches_n(7 downto 2) <= (others => '1'); --============================================================================ -- Pulse LEDs --============================================================================ pulse_led_front <= not pulse_led_front_n; pulse_led_rear <= not pulse_led_rear_n; --============================================================================ -- Pulse stimuli --============================================================================ blo_inp(6) <= '0'; ttl_inp_n(5 downto 1) <= (others => '1'); gen_pulse_chain : for i in 6 downto 2 generate blo_inp(i-1) <= blo_outp(i); end generate gen_pulse_chain; p_stim_pulse : process begin ttl_inp_n(6) <= '1'; wait until t = true; while (t = true) loop wait for 240 us; ttl_inp_n(6) <= '0'; wait for 500 ns; ttl_inp_n(6) <= '1'; if ttl_outp(6) /= '1' then assert false report "ttl_outp not '1'" severity warning; end if; if blo_outp(6) /= '1' then assert false report "blo_outp not '1'" severity warning; end if; end loop; end process p_stim_pulse; process begin t <= true; wait for 2 ms; t <= false; wait for 500 ms; t <= true; wait for 10 ms; t <= false; wait; end process; --============================================================================ -- I2C master --============================================================================ ------------------------------------------------------------------------------ -- First, the component instantiation ------------------------------------------------------------------------------ cmp_master : i2c_master_byte_ctrl port map ( clk => clk_20, rst => rst, nReset => rst_n, ena => '1', clk_cnt => x"0027", -- input signals start => mst_sta, stop => mst_sto, read => mst_rd, write => mst_wr, ack_in => mst_ack, din => mst_dat_in, -- output signals cmd_ack => mst_cmd_ack, ack_out => ack_fr_slv, i2c_busy => open, i2c_al => open, dout => mst_dat_out, -- i2c lines scl_i => scl, scl_o => scl_fr_mst, scl_oen => scl_en_mst, sda_i => sda, sda_o => sda_fr_mst, sda_oen => sda_en_mst ); -- Then, the tri-state_i2c_mst buffers on the line mscl(0) <= scl_fr_mst when (scl_en_mst = '0') else '1'; msda(0) <= sda_fr_mst when (sda_en_mst = '0') else '1'; ------------------------------------------------------------------------------ -- Bus model instantiation and connection to master and slaves ------------------------------------------------------------------------------ cmp_i2c_bus : i2c_bus_model generic map ( g_nr_masters => c_nr_masters, g_nr_slaves => c_nr_slaves ) port map ( mscl_i => mscl, msda_i => msda, sscl_i => sscl, ssda_i => ssda, scl_o => scl, sda_o => sda ); ------------------------------------------------------------------------------ -- This FSM controls the signals to the master component to implement the I2C -- protocol defined together with ELMA. The FSM is controlled by the -- stimuli process below ------------------------------------------------------------------------------ p_mst_fsm : process (clk_20) is begin if rising_edge(clk_20) then if (rst_n = '0') then state_i2c_mst <= IDLE; mst_sta <= '0'; mst_wr <= '0'; mst_sto <= '0'; mst_rd <= '0'; mst_dat_in <= (others => '0'); mst_ack <= '0'; cnt <= (others => '0'); once <= true; byte_cnt <= (others => '0'); rcvd <= (others => '0'); send <= (others => '0'); else case state_i2c_mst is when IDLE => if (mst_fsm_start = '1') then state_i2c_mst <= I2C_ADDR; send <= std_logic_vector(send_val); end if; when I2C_ADDR => mst_sta <= '1'; mst_wr <= '1'; mst_dat_in <= slv_addr & '0'; if (mst_cmd_ack = '1') then mst_sta <= '0'; mst_wr <= '0'; state_i2c_mst <= I2C_ADDR_ACK; end if; when I2C_ADDR_ACK => cnt <= cnt + 1; if (cnt = 7) then if (ack_fr_slv = '0') then state_i2c_mst <= WB_ADDR_B0; else state_i2c_mst <= ERR; end if; end if; when WB_ADDR_B0 => mst_wr <= '1'; mst_dat_in <= adr(15 downto 8); if (mst_cmd_ack = '1') then mst_wr <= '0'; state_i2c_mst <= WB_ADDR_B0_ACK; end if; when WB_ADDR_B0_ACK => cnt <= cnt + 1; if (cnt = 7) then if (ack_fr_slv = '0') then state_i2c_mst <= WB_ADDR_B1; else state_i2c_mst <= ERR; end if; end if; when WB_ADDR_B1 => mst_wr <= '1'; mst_dat_in <= adr(7 downto 0); if (mst_cmd_ack = '1') then mst_wr <= '0'; state_i2c_mst <= WB_ADDR_B1_ACK; end if; when WB_ADDR_B1_ACK => cnt <= cnt + 1; if (cnt = 7) then if (ack_fr_slv = '0') then state_i2c_mst <= ST_OP; else state_i2c_mst <= ERR; end if; end if; when ST_OP => if (mst_fsm_op = '1') then state_i2c_mst <= RD_RESTART; else state_i2c_mst <= WR; end if; when RD_RESTART => mst_wr <= '1'; mst_dat_in <= slv_addr & '1'; mst_sta <= '1'; if (mst_cmd_ack = '1') then mst_sta <= '0'; mst_wr <= '0'; state_i2c_mst <= RD_RESTART_ACK; end if; when RD_RESTART_ACK => cnt <= cnt + 1; if (cnt = 7) then if (ack_fr_slv = '0') then state_i2c_mst <= RD; else state_i2c_mst <= ERR; end if; end if; when RD => mst_rd <= '1'; mst_ack <= '0'; if (byte_cnt = 3) then mst_ack <= '1'; end if; if (mst_cmd_ack = '1') then mst_rd <= '0'; byte_cnt <= byte_cnt + 1; rcvd <= mst_dat_out & rcvd(31 downto 8); mst_ack <= '0'; state_i2c_mst <= RD; if (byte_cnt = 3) then state_i2c_mst <= STO; end if; end if; when RD_ACK => cnt <= cnt + 1; if (cnt = 7) then byte_cnt <= byte_cnt + 1; rcvd <= mst_dat_out & rcvd(31 downto 8); mst_ack <= '0'; state_i2c_mst <= RD; if (byte_cnt = 3) then state_i2c_mst <= STO; end if; end if; when WR => mst_wr <= '1'; mst_dat_in <= send(7 downto 0); if (mst_cmd_ack = '1') then mst_wr <= '0'; state_i2c_mst <= WR_ACK; end if; when WR_ACK => cnt <= cnt + 1; if (cnt = 7) then if (ack_fr_slv = '0') then byte_cnt <= byte_cnt + 1; send <= x"00" & send(31 downto 8); state_i2c_mst <= WR; if (byte_cnt = 3) then state_i2c_mst <= STO; end if; else state_i2c_mst <= ERR; end if; end if; when STO => mst_sto <= '1'; if (mst_cmd_ack = '1') then mst_sto <= '0'; state_i2c_mst <= IDLE; end if; when ERR => if (once) then report("Error!"); once <= false; end if; when others => state_i2c_mst <= ERR; end case; end if; end if; end process p_mst_fsm; ------------------------------------------------------------------------------ -- Process to "stimulate" the master FSM above ------------------------------------------------------------------------------ p_stim_mst_fsm : process (rst_n, t, state_i2c_mst) begin if (rst_n = '0') then mst_fsm_start <= '0'; mst_fsm_op <= '0'; slv_addr <= "1011110"; adr <= (others => '0'); buf_byte_cnt <= 0; elsif (not t) and (state_i2c_mst = IDLE) then mst_fsm_start <= '1'; mst_fsm_op <= '1'; buf_byte_cnt <= buf_byte_cnt + 1; case buf_byte_cnt is when 0 => adr(11 downto 0) <= x"030"; when 1 => adr(11 downto 0) <= x"034"; when 2 => adr(11 downto 0) <= x"038"; when 3 => adr(11 downto 0) <= x"02c"; buf_byte_cnt <= 0; when others => buf_byte_cnt <= 0; end case; else mst_fsm_start <= '0'; end if; end process p_stim_mst_fsm; end architecture behav; --============================================================================== -- architecture end --==============================================================================