diff --git a/libraries/io/i2c/tb/vhdl/dev_pmbus.vhd b/libraries/io/i2c/tb/vhdl/dev_pmbus.vhd new file mode 100644 index 0000000000000000000000000000000000000000..15754ab7edc2c6d2a63a891110557c529c46df27 --- /dev/null +++ b/libraries/io/i2c/tb/vhdl/dev_pmbus.vhd @@ -0,0 +1,112 @@ +------------------------------------------------------------------------------- +-- +-- Copyright (C) 2009 +-- ASTRON (Netherlands Institute for Radio Astronomy) <http://www.astron.nl/> +-- P.O.Box 2, 7990 AA Dwingeloo, The Netherlands +-- +-- This program is free software: you can redistribute it and/or modify +-- it under the terms of the GNU General Public License as published by +-- the Free Software Foundation, either version 3 of the License, or +-- (at your option) any later version. +-- +-- This program 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 General Public License for more details. +-- +-- You should have received a copy of the GNU General Public License +-- along with this program. If not, see <http://www.gnu.org/licenses/>. +-- +------------------------------------------------------------------------------- + +LIBRARY IEEE; +USE IEEE.STD_LOGIC_1164.ALL; +USE IEEE.NUMERIC_STD.ALL; +USE work.i2c_dev_unb2_pkg.ALL; + + +ENTITY dev_pmbus IS + GENERIC( + g_address : STD_LOGIC_VECTOR(6 DOWNTO 0) + ); + PORT( + scl : IN STD_LOGIC; + sda : INOUT STD_LOGIC; + vin : IN INTEGER; + vout : IN INTEGER; + iout : IN INTEGER; + vcap : IN INTEGER; + temp : IN INTEGER + ); +END dev_pmbus; + + +ARCHITECTURE beh OF dev_pmbus IS + + SIGNAL enable : STD_LOGIC; --enable + SIGNAL stop : STD_LOGIC; --stop + SIGNAL wr_dat : STD_LOGIC_VECTOR(7 DOWNTO 0); --I2C write data + SIGNAL wr_val : STD_LOGIC; + SIGNAL rd_dat : STD_LOGIC_VECTOR(7 DOWNTO 0); --I2C read data + SIGNAL rd_req : STD_LOGIC; + + SIGNAL cmd_en : STD_LOGIC := '0'; + SIGNAL cmd : NATURAL; --device command + + SIGNAL config_reg : STD_LOGIC_VECTOR(7 DOWNTO 0) := "00001000"; + SIGNAL status_reg : STD_LOGIC_VECTOR(7 DOWNTO 0) := (OTHERS => '0'); + SIGNAL temp_hi_reg : STD_LOGIC_VECTOR(7 DOWNTO 0) := "01111111"; + SIGNAL temp_lo_reg : STD_LOGIC_VECTOR(7 DOWNTO 0) := "11001001"; + +BEGIN + + i2c_slv_device : ENTITY work.i2c_slv_device + GENERIC MAP ( + g_address => g_address + ) + PORT MAP ( + scl => scl, + sda => sda, + en => enable, + p => stop, + wr_dat => wr_dat, + wr_val => wr_val, + rd_req => rd_req, + rd_dat => rd_dat + ); + + + p_write : PROCESS (enable, wr_val) --first write byte is treated as command + BEGIN + IF RISING_EDGE(enable) THEN + cmd_en <= '1'; + ELSIF FALLING_EDGE(enable) THEN + cmd_en <= '0'; + END IF; + IF RISING_EDGE(wr_val) THEN + cmd_en <= '0'; + IF cmd_en='1' THEN + cmd <= TO_INTEGER(UNSIGNED(wr_dat)); + ELSE + CASE cmd IS -- add write cmd later + WHEN OTHERS => NULL; + END CASE; + END IF; + END IF; + END PROCESS; + + p_read : PROCESS (rd_req) + BEGIN + IF RISING_EDGE(rd_req) THEN + CASE cmd IS --only model some read cmd + WHEN PMBUS_REG_READ_VIN => rd_dat <= STD_LOGIC_VECTOR(TO_SIGNED(vin,8)); + WHEN PMBUS_REG_READ_VOUT => rd_dat <= STD_LOGIC_VECTOR(TO_SIGNED(vout,8)); + WHEN PMBUS_REG_READ_IOUT => rd_dat <= STD_LOGIC_VECTOR(TO_SIGNED(iout,8)); + WHEN PMBUS_REG_READ_VCAP => rd_dat <= STD_LOGIC_VECTOR(TO_SIGNED(vcap,8)); + WHEN PMBUS_REG_READ_TEMP => rd_dat <= STD_LOGIC_VECTOR(TO_SIGNED(temp,8)); + WHEN OTHERS => rd_dat <= (OTHERS => '1'); + END CASE; + END IF; + END PROCESS; + +END beh; diff --git a/libraries/io/i2c/tb/vhdl/tb_i2c_commander_unb2_pmbus.vhd b/libraries/io/i2c/tb/vhdl/tb_i2c_commander_unb2_pmbus.vhd new file mode 100644 index 0000000000000000000000000000000000000000..56443c9f0e351f9ff70b8eb094cba8bc70d73aea --- /dev/null +++ b/libraries/io/i2c/tb/vhdl/tb_i2c_commander_unb2_pmbus.vhd @@ -0,0 +1,437 @@ +------------------------------------------------------------------------------- +-- +-- Copyright (C) 2012 +-- ASTRON (Netherlands Institute for Radio Astronomy) <http://www.astron.nl/> +-- P.O.Box 2, 7990 AA Dwingeloo, The Netherlands +-- +-- This program is free software: you can redistribute it and/or modify +-- it under the terms of the GNU General Public License as published by +-- the Free Software Foundation, either version 3 of the License, or +-- (at your option) any later version. +-- +-- This program 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 General Public License for more details. +-- +-- You should have received a copy of the GNU General Public License +-- along with this program. If not, see <http://www.gnu.org/licenses/>. +-- +------------------------------------------------------------------------------- + + +-- Purpose: Verify the i2c_commander and create a u_protocol_ram init file +-- +-- Description: +-- The protocols for the I2C slaves on UNB are stored in the dev_unb_pkg. +-- The protocols for the I2C slaves on ADU are stored in the dev_adu_pkg. +-- This tb can model both via g_board = "unb" or "adu". The protocols for the +-- board are concatenated into c_protocol_ram_init. +-- The p_mm_stimuli writes the c_protocol_ram_init bytes to u_protocol_ram +-- and in parallel they get written to a file by u_protocol_ram_init_file: +-- +-- data/adu_protocol_ram_init.txt +-- or +-- data/unb_protocol_ram_init.txt +-- +-- See data/how_to_create_memory_init_hex_file.txt for how to +-- create a memory initialization hex file from this. +-- +-- The p_mm_stimuli continues with executing all protocol lists and checking +-- the expected results and ASSERTs ERROR if an access went not OK and in +-- case of read data if the read data value was not OK. +-- +-- Remark: +-- . Use c_protocol_ram_init_file="UNUSED" to initialize the u_protocol_ram +-- with the c_protocol_ram_init sequence, +-- else use the actual protocol_ram_init.hex file and verify that it contains +-- the same as the c_protocol_ram_init sequence. +-- +-- Usage: +-- > do wave_i2c_commander.do +-- > run -all +-- In the Wave Window view the signal u_commander/protocol_index to observe +-- the progress +-- +-- Uniboard2 version derived from tb_i2c_commander November 2015 +-- this version tests the PMBUS bus + + +ENTITY tb_i2c_commander_unb2_pmbus IS + GENERIC ( + g_board : STRING := "unb2" -- only works with UniBoard2 + ); +END tb_i2c_commander_unb2_pmbus; + +LIBRARY IEEE, common_lib, tst_lib; +USE IEEE.std_logic_1164.ALL; +USE common_lib.common_pkg.ALL; +USE common_lib.common_mem_pkg.ALL; +USE common_lib.tb_common_pkg.ALL; +USE common_lib.tb_common_mem_pkg.ALL; +USE work.i2c_smbus_pkg.ALL; +USE work.i2c_dev_max1617_pkg.ALL; +USE work.i2c_dev_unb2_pkg.ALL; +USE work.i2c_pkg.ALL; +USE work.i2c_commander_pkg.ALL; +USE work.i2c_commander_unb2_sens_pkg.ALL; +USE work.i2c_commander_unb2_pmbus_pkg.ALL; -- in case we can add the PMBUS later + + +ARCHITECTURE tb OF tb_i2c_commander_unb2_pmbus IS + + --CONSTANT c_protocol_ram_init_file : STRING := "data/unb2_sens_protocol_ram_init.hex"; + --CONSTANT c_protocol_ram_init_file : STRING := "data/unb2_pmbus_protocol_ram_init.hex"; + CONSTANT c_protocol_ram_init_file : STRING := "UNUSED"; -- start with this, then make a hex file from the txt file? + + CONSTANT c_use_result_ram : BOOLEAN := TRUE; + CONSTANT c_sim : BOOLEAN := TRUE; --FALSE + CONSTANT c_clk_freq_in_MHz : NATURAL := 100; -- 100 MHz + CONSTANT c_clk_period : TIME := (10**3/c_clk_freq_in_MHz) * 1 ns; + CONSTANT c_rst_period : TIME := 4 * c_clk_period; + + CONSTANT c_phy_i2c : t_c_i2c_phy := func_i2c_sel_a_b(c_sim, c_i2c_phy_sim, func_i2c_calculate_phy(c_clk_freq_in_MHz)); + + + --CONSTANT c_pmbus_temp_address : STD_LOGIC_VECTOR := TO_UVEC(MAX1617_ADR_LOW_LOW, 7); -- use other slave address to force I2C errors + CONSTANT c_pmbus_core_address : STD_LOGIC_VECTOR := TO_UVEC(I2C_UNB2_PMB_CORE_BMR464_ADR, 7); + CONSTANT c_pmbus_vccram_address : STD_LOGIC_VECTOR := TO_UVEC(I2C_UNB2_PMB_VCCRAM_BMR461_ADR, 7); + CONSTANT c_pmbus_tcvr0_address : STD_LOGIC_VECTOR := TO_UVEC(I2C_UNB2_PMB_TCVR0_BMR461_ADR, 7); + CONSTANT c_pmbus_tcvr1_address : STD_LOGIC_VECTOR := TO_UVEC(I2C_UNB2_PMB_TCVR1_BMR461_ADR, 7); + CONSTANT c_pmbus_ctrl_address : STD_LOGIC_VECTOR := TO_UVEC(I2C_UNB2_PMB_CTRL_BMR461_ADR, 7); + CONSTANT c_pmbus_fpgaio_address : STD_LOGIC_VECTOR := TO_UVEC(I2C_UNB2_PMB_FPGAIO_BMR461_ADR, 7); + CONSTANT c_max1618_temp : INTEGER := 60; + + + -- Select the expected read data arrays for the result data (the read data values are tb dependent, so therefore they are not obtained from a package) + + TYPE t_i2c_unb2_natural_arr IS ARRAY (INTEGER RANGE 0 TO 31) OF NATURAL; -- needto test some long protocol lists + TYPE t_i2c_unb2_natural_mat IS ARRAY (INTEGER RANGE <>) OF t_i2c_unb2_natural_arr; + + CONSTANT c_default_expected_data_arr : t_i2c_unb2_natural_arr := ( others => 254); + + CONSTANT c_expected_data_mat : t_i2c_unb2_natural_mat(0 TO c_i2c_unb2_nof_protocol_lists-1) := (c_default_expected_data_arr, + c_default_expected_data_arr, + c_default_expected_data_arr, + c_default_expected_data_arr); + + -- RAM sizes + CONSTANT c_mem_i2c : t_c_i2c_mm := c_i2c_cmdr_unb2_pmbus_i2c_mm; + + -- Commander parameters + CONSTANT c_protocol_ram_init : t_nat_natural_arr := c_i2c_cmdr_unb2_pmbus_protocol_ram_init; + CONSTANT c_nof_result_data_arr : t_nat_natural_arr := c_i2c_cmdr_unb2_pmbus_nof_result_data_arr; + + CONSTANT c_protocol_commander : t_c_i2c_cmdr_commander := c_i2c_cmdr_unb2_pmbus_protocol_commander; + + -- Commander MM register word indexes + CONSTANT c_protocol_status_wi : NATURAL := 3*c_protocol_commander.nof_protocols; + CONSTANT c_result_error_cnt_wi : NATURAL := 3*c_protocol_commander.nof_protocols + 1; + CONSTANT c_result_data_wi : NATURAL := 3*c_protocol_commander.nof_protocols + 2; + + + -- Test bench PHY + SIGNAL tb_end : STD_LOGIC := '0'; + SIGNAL clk : STD_LOGIC := '0'; + SIGNAL rst : STD_LOGIC := '1'; + SIGNAL sync : STD_LOGIC := '1'; + + SIGNAL scl_stretch : STD_LOGIC := 'Z'; + SIGNAL scl : STD_LOGIC; + SIGNAL sda : STD_LOGIC; + + -- File interface + SIGNAL file_miso : t_mem_miso; + SIGNAL file_mosi : t_mem_mosi; + + -- MM registers interface + SIGNAL commander_miso : t_mem_miso; + SIGNAL commander_mosi : t_mem_mosi; + SIGNAL protocol_miso : t_mem_miso; + SIGNAL protocol_mosi : t_mem_mosi; + SIGNAL result_miso : t_mem_miso; + SIGNAL result_mosi : t_mem_mosi; + + -- Commander results + SIGNAL protocol_data : NATURAL; + SIGNAL protocol_status : NATURAL; + SIGNAL result_data : NATURAL; + SIGNAL result_error_cnt : NATURAL; + +BEGIN + + -- run -all + + rst <= '0' AFTER 4*c_clk_period; + clk <= (NOT clk) OR tb_end AFTER c_clk_period/2; + + -- I2C bus + scl <= 'H'; -- model I2C pull up + sda <= 'H'; -- model I2C pull up, use '0' and '1' to verify SDA forced low or high error + + scl <= scl_stretch; + + sens_clk_stretch : PROCESS (scl) + BEGIN + IF falling_edge(scl) THEN + scl_stretch <= '0', 'Z' AFTER 50 ns; -- < 10 ns to effectively disable stretching, >= 50 ns to enable it + END IF; + END PROCESS; + + u_protocol_ram_init_file : ENTITY tst_lib.tst_output + GENERIC MAP ( + g_file_name => "data/" & g_board & "_protocol_ram_init.txt", + g_nof_data => 1, + g_data_width => c_byte_w, + g_data_type => "UNSIGNED" + ) + PORT MAP ( + clk => clk, + rst => rst, + in_dat => file_mosi.wrdata(c_byte_w-1 DOWNTO 0), + in_val => file_mosi.wr + ); + + p_mm_stimuli : PROCESS + BEGIN + -- Wait for reset release + commander_mosi <= c_mem_mosi_rst; + file_mosi <= c_mem_mosi_rst; + protocol_mosi <= c_mem_mosi_rst; + result_mosi <= c_mem_mosi_rst; + proc_common_wait_until_low(clk, rst); + proc_common_wait_some_cycles(clk, 10); + + ---------------------------------------------------------------------------- + -- Initialize the u_protocol_ram or verify its default contents + ---------------------------------------------------------------------------- + + IF c_protocol_ram_init_file="UNUSED" THEN + -- Write + FOR I IN 0 TO c_protocol_ram_init'LENGTH-1 LOOP + proc_mem_mm_bus_wr(I, c_protocol_ram_init(I), clk, protocol_miso, protocol_mosi); -- fill u_protocol_ram + END LOOP; + FOR I IN c_protocol_ram_init'LENGTH TO c_mem_i2c.protocol_nof_dat-1 LOOP + proc_mem_mm_bus_wr(I, SMBUS_C_END, clk, protocol_miso, protocol_mosi); -- fill remainder of u_protocol_ram with default + END LOOP; + + ELSE + -- Read and verify + FOR I IN 0 TO c_protocol_ram_init'LENGTH-1 LOOP + proc_mem_mm_bus_rd(I, clk, protocol_miso, protocol_mosi); + proc_mem_mm_bus_rd_latency(c_mem_reg_rd_latency, clk); + protocol_data <= TO_UINT(protocol_miso.rddata(c_byte_w-1 DOWNTO 0)); + proc_common_wait_some_cycles(clk, 1); + ASSERT c_protocol_ram_init(I)=protocol_data + REPORT "Unexpected protocol data" SEVERITY ERROR; + END LOOP; + FOR I IN c_protocol_ram_init'LENGTH TO c_mem_i2c.protocol_nof_dat-1 LOOP + proc_mem_mm_bus_rd(I, clk, protocol_miso, protocol_mosi); + proc_mem_mm_bus_rd_latency(c_mem_reg_rd_latency, clk); + protocol_data <= TO_UINT(protocol_miso.rddata(c_byte_w-1 DOWNTO 0)); + proc_common_wait_some_cycles(clk, 1); + ASSERT SMBUS_C_END=protocol_data + REPORT "Unexpected protocol end data" SEVERITY ERROR; + END LOOP; + END IF; + + proc_common_wait_some_cycles(clk, 10); + + + ---------------------------------------------------------------------------- + -- Create the u_protocol_ram_init_file + ---------------------------------------------------------------------------- + + FOR I IN 0 TO c_protocol_ram_init'LENGTH-1 LOOP + proc_mem_mm_bus_wr(I, c_protocol_ram_init(I), clk, file_miso, file_mosi); -- fill u_protocol_ram_init_file + END LOOP; + FOR I IN c_protocol_ram_init'LENGTH TO c_mem_i2c.protocol_nof_dat-1 LOOP + proc_mem_mm_bus_wr(I, SMBUS_C_END, clk, file_miso, file_mosi); -- fill remainder of u_protocol_ram_init_file with default + END LOOP; + + proc_common_wait_some_cycles(clk, 10); + + + ---------------------------------------------------------------------------- + -- Try and verify all commander protocols + ---------------------------------------------------------------------------- + + FOR P IN 0 TO c_protocol_commander.nof_protocols-1 LOOP + + -- Issue protocol list P + proc_mem_mm_bus_wr(P, 1, clk, commander_miso, commander_mosi); + + -- Wait for protocol done + WHILE protocol_status/=c_i2c_cmdr_state_done LOOP + -- read commander protocol status register + proc_mem_mm_bus_rd(c_protocol_status_wi, clk, commander_miso, commander_mosi); + proc_mem_mm_bus_rd_latency(c_mem_reg_rd_latency, clk); + protocol_status <= TO_UINT(commander_miso.rddata); + proc_common_wait_some_cycles(clk, 1); + END LOOP; + + -- Read commander result error count + proc_mem_mm_bus_rd(c_result_error_cnt_wi, clk, commander_miso, commander_mosi); + proc_mem_mm_bus_rd_latency(c_mem_reg_rd_latency, clk); + result_error_cnt <= TO_UINT(commander_miso.rddata); + proc_common_wait_some_cycles(clk, 1); + ASSERT result_error_cnt=0 + REPORT "The result error count is not 0" SEVERITY ERROR; + + -- Read commander result data + FOR I IN 0 TO c_nof_result_data_arr(P)-1 LOOP + proc_mem_mm_bus_rd(c_result_data_wi+I, clk, commander_miso, commander_mosi); + proc_mem_mm_bus_rd_latency(c_mem_reg_rd_latency, clk); + result_data <= TO_UINT(commander_miso.rddata); + proc_common_wait_some_cycles(clk, 1); + ASSERT c_expected_data_mat(P)(I)=result_data + REPORT "Unexpected result data" SEVERITY WARNING; + END LOOP; + + -- Wait for protocol idle + WHILE protocol_status/=c_i2c_cmdr_state_idle LOOP + -- read commander protocol status register + proc_mem_mm_bus_rd(c_protocol_status_wi, clk, commander_miso, commander_mosi); + proc_mem_mm_bus_rd_latency(c_mem_reg_rd_latency, clk); + protocol_status <= TO_UINT(commander_miso.rddata); + proc_common_wait_some_cycles(clk, 1); + END LOOP; + + -- Wait some time between the protocols + proc_common_wait_some_cycles(clk, 100); + END LOOP; + + ---------------------------------------------------------------------------- + -- The end + ---------------------------------------------------------------------------- + + proc_common_wait_some_cycles(clk, 100); + tb_end <= '1'; + WAIT; + END PROCESS; + + + -- I2C commander + u_commander : ENTITY work.i2c_commander + GENERIC MAP ( + g_sim => c_sim, + g_i2c_cmdr => c_protocol_commander, + g_i2c_mm => c_mem_i2c, + g_i2c_phy => c_phy_i2c, + g_protocol_ram_init_file => c_protocol_ram_init_file, + g_use_result_ram => c_use_result_ram + ) + PORT MAP ( + rst => rst, + clk => clk, + sync => sync, + + --------------------------------------------------------------------------- + -- Memory Mapped slave interfaces + --------------------------------------------------------------------------- + commander_mosi => commander_mosi, + commander_miso => commander_miso, + + -- If the default protocol list in u_protocol_ram is fine, then the protocol slave port can be left no connected + protocol_mosi => protocol_mosi, + protocol_miso => protocol_miso, + + -- Typically the commander status registers are sufficient, so then the results slave port can be left no connected + result_mosi => result_mosi, + result_miso => result_miso, + + --------------------------------------------------------------------------- + -- I2C interface + --------------------------------------------------------------------------- + scl => scl, + sda => sda + ); + + -- I2C slaves + u_pmbus_core : ENTITY work.dev_pmbus + GENERIC MAP ( + g_address => c_pmbus_core_address + ) + PORT MAP ( + scl => scl, + sda => sda, + vin => 90, + vout => 9, + iout => 10, + vcap => 0, + temp => 34 + ); + + u_pmbus_vccram : ENTITY work.dev_pmbus + GENERIC MAP ( + g_address => c_pmbus_vccram_address + ) + PORT MAP ( + scl => scl, + sda => sda, + vin => 91, + vout => 12, + iout => 11, + vcap => 75, + temp => 35 + ); + + u_pmbus_tcvr0 : ENTITY work.dev_pmbus + GENERIC MAP ( + g_address => c_pmbus_tcvr0_address + ) + PORT MAP ( + scl => scl, + sda => sda, + vin => 92, + vout => 18, + iout => 12, + vcap => 0, + temp => 36 + ); + + u_pmbus_tcvr1 : ENTITY work.dev_pmbus + GENERIC MAP ( + g_address => c_pmbus_tcvr1_address + ) + PORT MAP ( + scl => scl, + sda => sda, + vin => 93, + vout => 18, + iout => 13, + vcap => 0, + temp => 37 + ); + + u_pmbus_ctrl : ENTITY work.dev_pmbus + GENERIC MAP ( + g_address => c_pmbus_ctrl_address + ) + PORT MAP ( + scl => scl, + sda => sda, + vin => 94, + vout => 33, + iout => 14, + vcap => 0, + temp => 38 + ); + + u_pmbus_fpgaio : ENTITY work.dev_pmbus + GENERIC MAP ( + g_address => c_pmbus_fpgaio_address + ) + PORT MAP ( + scl => scl, + sda => sda, + vin => 90, + vout => 33, + iout => 15, + vcap => 0, + temp => 39 + ); + + +END tb; + diff --git a/libraries/io/i2c/tb/vhdl/tb_i2c_commander_unb2_sens.vhd b/libraries/io/i2c/tb/vhdl/tb_i2c_commander_unb2_sens.vhd new file mode 100644 index 0000000000000000000000000000000000000000..8e6559b64388aa127e6a8fe5fb77cac769cd51d2 --- /dev/null +++ b/libraries/io/i2c/tb/vhdl/tb_i2c_commander_unb2_sens.vhd @@ -0,0 +1,467 @@ +------------------------------------------------------------------------------- +-- +-- Copyright (C) 2012 +-- ASTRON (Netherlands Institute for Radio Astronomy) <http://www.astron.nl/> +-- P.O.Box 2, 7990 AA Dwingeloo, The Netherlands +-- +-- This program is free software: you can redistribute it and/or modify +-- it under the terms of the GNU General Public License as published by +-- the Free Software Foundation, either version 3 of the License, or +-- (at your option) any later version. +-- +-- This program 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 General Public License for more details. +-- +-- You should have received a copy of the GNU General Public License +-- along with this program. If not, see <http://www.gnu.org/licenses/>. +-- +------------------------------------------------------------------------------- + + +-- Purpose: Verify the i2c_commander and create a u_protocol_ram init file +-- +-- Description: +-- The protocols for the I2C slaves on UNB are stored in the dev_unb_pkg. +-- The protocols for the I2C slaves on ADU are stored in the dev_adu_pkg. +-- This tb can model both via g_board = "unb" or "adu". The protocols for the +-- board are concatenated into c_protocol_ram_init. +-- The p_mm_stimuli writes the c_protocol_ram_init bytes to u_protocol_ram +-- and in parallel they get written to a file by u_protocol_ram_init_file: +-- +-- data/adu_protocol_ram_init.txt +-- or +-- data/unb_protocol_ram_init.txt +-- +-- See data/how_to_create_memory_init_hex_file.txt for how to +-- create a memory initialization hex file from this. +-- +-- The p_mm_stimuli continues with executing all protocol lists and checking +-- the expected results and ASSERTs ERROR if an access went not OK and in +-- case of read data if the read data value was not OK. +-- +-- Remark: +-- . Use c_protocol_ram_init_file="UNUSED" to initialize the u_protocol_ram +-- with the c_protocol_ram_init sequence, +-- else use the actual protocol_ram_init.hex file and verify that it contains +-- the same as the c_protocol_ram_init sequence. +-- +-- Usage: +-- > do wave_i2c_commander.do +-- > run -all +-- In the Wave Window view the signal u_commander/protocol_index to observe +-- the progress +-- +-- Uniboard2 version derived from tb_i2c_commander November 2015 +-- this version tests the SENS bus + + +ENTITY tb_i2c_commander_unb2_sens IS + GENERIC ( + g_board : STRING := "unb2" -- only works with UniBoard2 + ); +END tb_i2c_commander_unb2_sens; + +LIBRARY IEEE, common_lib, tst_lib; +USE IEEE.std_logic_1164.ALL; +USE common_lib.common_pkg.ALL; +USE common_lib.common_mem_pkg.ALL; +USE common_lib.tb_common_pkg.ALL; +USE common_lib.tb_common_mem_pkg.ALL; +USE work.i2c_smbus_pkg.ALL; +USE work.i2c_dev_max1617_pkg.ALL; +USE work.i2c_dev_unb2_pkg.ALL; +USE work.i2c_pkg.ALL; +USE work.i2c_commander_pkg.ALL; +USE work.i2c_commander_unb2_sens_pkg.ALL; +USE work.i2c_commander_unb2_pmbus_pkg.ALL; -- in case we can add the PMBUS later + + +ARCHITECTURE tb OF tb_i2c_commander_unb2_sens IS + + --CONSTANT c_protocol_ram_init_file : STRING := "data/unb2_sens_protocol_ram_init.hex"; + --CONSTANT c_protocol_ram_init_file : STRING := "data/unb2_pmbus_protocol_ram_init.hex"; + CONSTANT c_protocol_ram_init_file : STRING := "UNUSED"; -- start with this, then make a hex file from the txt file? + + CONSTANT c_use_result_ram : BOOLEAN := TRUE; + CONSTANT c_sim : BOOLEAN := TRUE; --FALSE + CONSTANT c_clk_freq_in_MHz : NATURAL := 100; -- 100 MHz + CONSTANT c_clk_period : TIME := (10**3/c_clk_freq_in_MHz) * 1 ns; + CONSTANT c_rst_period : TIME := 4 * c_clk_period; + + CONSTANT c_phy_i2c : t_c_i2c_phy := func_i2c_sel_a_b(c_sim, c_i2c_phy_sim, func_i2c_calculate_phy(c_clk_freq_in_MHz)); + + + --CONSTANT c_sens_temp_address : STD_LOGIC_VECTOR := TO_UVEC(MAX1617_ADR_LOW_LOW, 7); -- use other slave address to force I2C errors + CONSTANT c_sens_temp_address : STD_LOGIC_VECTOR := TO_UVEC(I2C_UNB2_SENS_TEMP_MAX1617_ADR, 7); + CONSTANT c_sens_dcdc_address : STD_LOGIC_VECTOR := TO_UVEC(I2C_UNB2_SENS_DCDC_BMR456_ADR, 7); + CONSTANT c_sens_pim_address : STD_LOGIC_VECTOR := TO_UVEC(I2C_UNB2_SENS_PIM_PIM4328PD_ADR, 7); + CONSTANT c_sens_1v2_address : STD_LOGIC_VECTOR := TO_UVEC(I2C_UNB2_SENS_1V2_BMR461_ADR, 7); + CONSTANT c_sens_3v3_address : STD_LOGIC_VECTOR := TO_UVEC(I2C_UNB2_SENS_3V3_BMR461_ADR, 7); + CONSTANT c_sens_clk_address : STD_LOGIC_VECTOR := TO_UVEC(I2C_UNB2_SENS_CLK_BMR461_ADR, 7); + CONSTANT c_sens_qsfp0_address : STD_LOGIC_VECTOR := TO_UVEC(I2C_UNB2_SENS_QSFP0_BMR464_ADR, 7); + CONSTANT c_sens_qsfp1_address : STD_LOGIC_VECTOR := TO_UVEC(I2C_UNB2_SENS_QSFP1_BMR464_ADR, 7); + CONSTANT c_sens_eeprom_address : STD_LOGIC_VECTOR := TO_UVEC(I2C_UNB2_SENS_EEPROM_CAT24C02_ADR, 7); + CONSTANT c_sens_temp2_address : STD_LOGIC_VECTOR := TO_UVEC(I2C_UNB2_SENS_TEMP_TMP451_ADR, 7); + CONSTANT c_max1618_temp : INTEGER := 60; + + + -- Select the expected read data arrays for the result data (the read data values are tb dependent, so therefore they are not obtained from a package) + + TYPE t_i2c_unb2_natural_arr IS ARRAY (INTEGER RANGE 0 TO 31) OF NATURAL; -- needto test some long protocol lists + TYPE t_i2c_unb2_natural_mat IS ARRAY (INTEGER RANGE <>) OF t_i2c_unb2_natural_arr; + + CONSTANT c_max1618_expected_data_read_temp_arr : t_i2c_unb2_natural_arr := (c_max1618_temp, others => 254); + CONSTANT c_default_expected_data_arr : t_i2c_unb2_natural_arr := ( others => 254); + + CONSTANT c_expected_data_mat : t_i2c_unb2_natural_mat(0 TO c_i2c_unb2_nof_protocol_lists-1) := (c_max1618_expected_data_read_temp_arr, + c_default_expected_data_arr, + c_default_expected_data_arr, + c_default_expected_data_arr); + + -- RAM sizes + CONSTANT c_mem_i2c : t_c_i2c_mm := c_i2c_cmdr_unb2_sens_i2c_mm; + + -- Commander parameters + CONSTANT c_protocol_ram_init : t_nat_natural_arr := c_i2c_cmdr_unb2_sens_protocol_ram_init; + CONSTANT c_nof_result_data_arr : t_nat_natural_arr := c_i2c_cmdr_unb2_sens_nof_result_data_arr; + + CONSTANT c_protocol_commander : t_c_i2c_cmdr_commander := c_i2c_cmdr_unb2_sens_protocol_commander; + + -- Commander MM register word indexes + CONSTANT c_protocol_status_wi : NATURAL := 3*c_protocol_commander.nof_protocols; + CONSTANT c_result_error_cnt_wi : NATURAL := 3*c_protocol_commander.nof_protocols + 1; + CONSTANT c_result_data_wi : NATURAL := 3*c_protocol_commander.nof_protocols + 2; + + + -- Test bench PHY + SIGNAL tb_end : STD_LOGIC := '0'; + SIGNAL clk : STD_LOGIC := '0'; + SIGNAL rst : STD_LOGIC := '1'; + SIGNAL sync : STD_LOGIC := '1'; + + SIGNAL scl_stretch : STD_LOGIC := 'Z'; + SIGNAL scl : STD_LOGIC; + SIGNAL sda : STD_LOGIC; + + -- File interface + SIGNAL file_miso : t_mem_miso; + SIGNAL file_mosi : t_mem_mosi; + + -- MM registers interface + SIGNAL commander_miso : t_mem_miso; + SIGNAL commander_mosi : t_mem_mosi; + SIGNAL protocol_miso : t_mem_miso; + SIGNAL protocol_mosi : t_mem_mosi; + SIGNAL result_miso : t_mem_miso; + SIGNAL result_mosi : t_mem_mosi; + + -- Commander results + SIGNAL protocol_data : NATURAL; + SIGNAL protocol_status : NATURAL; + SIGNAL result_data : NATURAL; + SIGNAL result_error_cnt : NATURAL; + +BEGIN + + -- run -all + + rst <= '0' AFTER 4*c_clk_period; + clk <= (NOT clk) OR tb_end AFTER c_clk_period/2; + + -- I2C bus + scl <= 'H'; -- model I2C pull up + sda <= 'H'; -- model I2C pull up, use '0' and '1' to verify SDA forced low or high error + + scl <= scl_stretch; + + sens_clk_stretch : PROCESS (scl) + BEGIN + IF falling_edge(scl) THEN + scl_stretch <= '0', 'Z' AFTER 50 ns; -- < 10 ns to effectively disable stretching, >= 50 ns to enable it + END IF; + END PROCESS; + + u_protocol_ram_init_file : ENTITY tst_lib.tst_output + GENERIC MAP ( + g_file_name => "data/" & g_board & "_protocol_ram_init.txt", + g_nof_data => 1, + g_data_width => c_byte_w, + g_data_type => "UNSIGNED" + ) + PORT MAP ( + clk => clk, + rst => rst, + in_dat => file_mosi.wrdata(c_byte_w-1 DOWNTO 0), + in_val => file_mosi.wr + ); + + p_mm_stimuli : PROCESS + BEGIN + -- Wait for reset release + commander_mosi <= c_mem_mosi_rst; + file_mosi <= c_mem_mosi_rst; + protocol_mosi <= c_mem_mosi_rst; + result_mosi <= c_mem_mosi_rst; + proc_common_wait_until_low(clk, rst); + proc_common_wait_some_cycles(clk, 10); + + ---------------------------------------------------------------------------- + -- Initialize the u_protocol_ram or verify its default contents + ---------------------------------------------------------------------------- + + IF c_protocol_ram_init_file="UNUSED" THEN + -- Write + FOR I IN 0 TO c_protocol_ram_init'LENGTH-1 LOOP + proc_mem_mm_bus_wr(I, c_protocol_ram_init(I), clk, protocol_miso, protocol_mosi); -- fill u_protocol_ram + END LOOP; + FOR I IN c_protocol_ram_init'LENGTH TO c_mem_i2c.protocol_nof_dat-1 LOOP + proc_mem_mm_bus_wr(I, SMBUS_C_END, clk, protocol_miso, protocol_mosi); -- fill remainder of u_protocol_ram with default + END LOOP; + + ELSE + -- Read and verify + FOR I IN 0 TO c_protocol_ram_init'LENGTH-1 LOOP + proc_mem_mm_bus_rd(I, clk, protocol_miso, protocol_mosi); + proc_mem_mm_bus_rd_latency(c_mem_reg_rd_latency, clk); + protocol_data <= TO_UINT(protocol_miso.rddata(c_byte_w-1 DOWNTO 0)); + proc_common_wait_some_cycles(clk, 1); + ASSERT c_protocol_ram_init(I)=protocol_data + REPORT "Unexpected protocol data" SEVERITY ERROR; + END LOOP; + FOR I IN c_protocol_ram_init'LENGTH TO c_mem_i2c.protocol_nof_dat-1 LOOP + proc_mem_mm_bus_rd(I, clk, protocol_miso, protocol_mosi); + proc_mem_mm_bus_rd_latency(c_mem_reg_rd_latency, clk); + protocol_data <= TO_UINT(protocol_miso.rddata(c_byte_w-1 DOWNTO 0)); + proc_common_wait_some_cycles(clk, 1); + ASSERT SMBUS_C_END=protocol_data + REPORT "Unexpected protocol end data" SEVERITY ERROR; + END LOOP; + END IF; + + proc_common_wait_some_cycles(clk, 10); + + + ---------------------------------------------------------------------------- + -- Create the u_protocol_ram_init_file + ---------------------------------------------------------------------------- + + FOR I IN 0 TO c_protocol_ram_init'LENGTH-1 LOOP + proc_mem_mm_bus_wr(I, c_protocol_ram_init(I), clk, file_miso, file_mosi); -- fill u_protocol_ram_init_file + END LOOP; + FOR I IN c_protocol_ram_init'LENGTH TO c_mem_i2c.protocol_nof_dat-1 LOOP + proc_mem_mm_bus_wr(I, SMBUS_C_END, clk, file_miso, file_mosi); -- fill remainder of u_protocol_ram_init_file with default + END LOOP; + + proc_common_wait_some_cycles(clk, 10); + + + ---------------------------------------------------------------------------- + -- Try and verify all commander protocols + ---------------------------------------------------------------------------- + + FOR P IN 0 TO c_protocol_commander.nof_protocols-1 LOOP + + -- Issue protocol list P + proc_mem_mm_bus_wr(P, 1, clk, commander_miso, commander_mosi); + + -- Wait for protocol done + WHILE protocol_status/=c_i2c_cmdr_state_done LOOP + -- read commander protocol status register + proc_mem_mm_bus_rd(c_protocol_status_wi, clk, commander_miso, commander_mosi); + proc_mem_mm_bus_rd_latency(c_mem_reg_rd_latency, clk); + protocol_status <= TO_UINT(commander_miso.rddata); + proc_common_wait_some_cycles(clk, 1); + END LOOP; + + -- Read commander result error count + proc_mem_mm_bus_rd(c_result_error_cnt_wi, clk, commander_miso, commander_mosi); + proc_mem_mm_bus_rd_latency(c_mem_reg_rd_latency, clk); + result_error_cnt <= TO_UINT(commander_miso.rddata); + proc_common_wait_some_cycles(clk, 1); + ASSERT result_error_cnt=0 + REPORT "The result error count is not 0" SEVERITY ERROR; + + -- Read commander result data + FOR I IN 0 TO c_nof_result_data_arr(P)-1 LOOP + proc_mem_mm_bus_rd(c_result_data_wi+I, clk, commander_miso, commander_mosi); + proc_mem_mm_bus_rd_latency(c_mem_reg_rd_latency, clk); + result_data <= TO_UINT(commander_miso.rddata); + proc_common_wait_some_cycles(clk, 1); + ASSERT c_expected_data_mat(P)(I)=result_data + REPORT "Unexpected result data" SEVERITY WARNING; + END LOOP; + + -- Wait for protocol idle + WHILE protocol_status/=c_i2c_cmdr_state_idle LOOP + -- read commander protocol status register + proc_mem_mm_bus_rd(c_protocol_status_wi, clk, commander_miso, commander_mosi); + proc_mem_mm_bus_rd_latency(c_mem_reg_rd_latency, clk); + protocol_status <= TO_UINT(commander_miso.rddata); + proc_common_wait_some_cycles(clk, 1); + END LOOP; + + -- Wait some time between the protocols + proc_common_wait_some_cycles(clk, 100); + END LOOP; + + ---------------------------------------------------------------------------- + -- The end + ---------------------------------------------------------------------------- + + proc_common_wait_some_cycles(clk, 100); + tb_end <= '1'; + WAIT; + END PROCESS; + + + -- I2C commander + u_commander : ENTITY work.i2c_commander + GENERIC MAP ( + g_sim => c_sim, + g_i2c_cmdr => c_protocol_commander, + g_i2c_mm => c_mem_i2c, + g_i2c_phy => c_phy_i2c, + g_protocol_ram_init_file => c_protocol_ram_init_file, + g_use_result_ram => c_use_result_ram + ) + PORT MAP ( + rst => rst, + clk => clk, + sync => sync, + + --------------------------------------------------------------------------- + -- Memory Mapped slave interfaces + --------------------------------------------------------------------------- + commander_mosi => commander_mosi, + commander_miso => commander_miso, + + -- If the default protocol list in u_protocol_ram is fine, then the protocol slave port can be left no connected + protocol_mosi => protocol_mosi, + protocol_miso => protocol_miso, + + -- Typically the commander status registers are sufficient, so then the results slave port can be left no connected + result_mosi => result_mosi, + result_miso => result_miso, + + --------------------------------------------------------------------------- + -- I2C interface + --------------------------------------------------------------------------- + scl => scl, + sda => sda + ); + + -- I2C slaves + u_sens_dcdc : ENTITY work.dev_pmbus + GENERIC MAP ( + g_address => c_sens_dcdc_address + ) + PORT MAP ( + scl => scl, + sda => sda, + vin => 48, + vout => 9, + iout => 5, + vcap => 0, + temp => 34 + ); + + u_sens_pim : ENTITY work.dev_pmbus + GENERIC MAP ( + g_address => c_sens_pim_address + ) + PORT MAP ( + scl => scl, + sda => sda, + vin => 48, + vout => 0, + iout => 12, + vcap => 75, + temp => 35 + ); + + u_sens_1v2 : ENTITY work.dev_pmbus + GENERIC MAP ( + g_address => c_sens_1v2_address + ) + PORT MAP ( + scl => scl, + sda => sda, + vin => 90, + vout => 12, + iout => 20, + vcap => 0, + temp => 36 + ); + + u_sens_3v3 : ENTITY work.dev_pmbus + GENERIC MAP ( + g_address => c_sens_3v3_address + ) + PORT MAP ( + scl => scl, + sda => sda, + vin => 90, + vout => 33, + iout => 20, + vcap => 0, + temp => 37 + ); + + u_sens_clk : ENTITY work.dev_pmbus + GENERIC MAP ( + g_address => c_sens_clk_address + ) + PORT MAP ( + scl => scl, + sda => sda, + vin => 90, + vout => 25, + iout => 20, + vcap => 0, + temp => 38 + ); + + u_sens_qsfp0 : ENTITY work.dev_pmbus + GENERIC MAP ( + g_address => c_sens_qsfp0_address + ) + PORT MAP ( + scl => scl, + sda => sda, + vin => 90, + vout => 32, + iout => 11, + vcap => 0, + temp => 39 + ); + + u_sens_qsfp1 : ENTITY work.dev_pmbus + GENERIC MAP ( + g_address => c_sens_qsfp1_address + ) + PORT MAP ( + scl => scl, + sda => sda, + vin => 90, + vout => 34, + iout => 10, + vcap => 0, + temp => 40 + ); + + + u_sens_temp : ENTITY work.dev_max1618 -- both on "unb" and on "adu" + GENERIC MAP ( + g_address => c_sens_temp_address + ) + PORT MAP ( + scl => scl, + sda => sda, + temp => c_max1618_temp + ); + + +END tb; +