aboutsummaryrefslogtreecommitdiffstats
path: root/testsuite/gna
diff options
context:
space:
mode:
authorTristan Gingold <tgingold@free.fr>2020-01-02 18:22:19 +0100
committerTristan Gingold <tgingold@free.fr>2020-01-02 18:22:19 +0100
commitdf5e32320e8284763705f0046b91d09caf1164fd (patch)
tree83e695da29fa7ab08e20e18b1ad883f6d6fc82cb /testsuite/gna
parent91faff646998925a81d57f8d5a6e1c5fcf1f7ce8 (diff)
downloadghdl-df5e32320e8284763705f0046b91d09caf1164fd.tar.gz
ghdl-df5e32320e8284763705f0046b91d09caf1164fd.tar.bz2
ghdl-df5e32320e8284763705f0046b91d09caf1164fd.zip
testsuite: add cases for #1051
Diffstat (limited to 'testsuite/gna')
-rw-r--r--testsuite/gna/issue1051/psi_common_array_pkg.vhd55
-rw-r--r--testsuite/gna/issue1051/psi_common_bit_cc.vhd75
-rw-r--r--testsuite/gna/issue1051/psi_common_i2c_master.vhd634
-rw-r--r--testsuite/gna/issue1051/psi_common_i2c_master_tb.vhd679
-rw-r--r--testsuite/gna/issue1051/psi_common_logic_pkg.vhd227
-rw-r--r--testsuite/gna/issue1051/psi_common_math_pkg.vhd259
-rw-r--r--testsuite/gna/issue1051/psi_tb_activity_pkg.vhd258
-rw-r--r--testsuite/gna/issue1051/psi_tb_compare_pkg.vhd256
-rw-r--r--testsuite/gna/issue1051/psi_tb_i2c_pkg.vhd740
-rw-r--r--testsuite/gna/issue1051/psi_tb_txt_util.vhd583
-rw-r--r--testsuite/gna/issue1051/repro.vhdl29
-rw-r--r--testsuite/gna/issue1051/repro2.vhdl28
-rwxr-xr-xtestsuite/gna/issue1051/testsuite.sh32
13 files changed, 3855 insertions, 0 deletions
diff --git a/testsuite/gna/issue1051/psi_common_array_pkg.vhd b/testsuite/gna/issue1051/psi_common_array_pkg.vhd
new file mode 100644
index 000000000..97f3dc319
--- /dev/null
+++ b/testsuite/gna/issue1051/psi_common_array_pkg.vhd
@@ -0,0 +1,55 @@
+------------------------------------------------------------------------------
+-- Copyright (c) 2018 by Paul Scherrer Institute, Switzerland
+-- All rights reserved.
+-- Authors: Waldemar Koprek, Oliver Bruendler
+------------------------------------------------------------------------------
+
+------------------------------------------------------------------------------
+-- Libraries
+------------------------------------------------------------------------------
+library ieee ;
+ use ieee.std_logic_1164.all;
+
+------------------------------------------------------------------------------
+-- Package Header
+------------------------------------------------------------------------------
+package psi_common_array_pkg is
+ type t_aslv2 is array (natural range <>) of std_logic_vector( 1 downto 0);
+ type t_aslv3 is array (natural range <>) of std_logic_vector( 2 downto 0);
+ type t_aslv4 is array (natural range <>) of std_logic_vector( 3 downto 0);
+ type t_aslv5 is array (natural range <>) of std_logic_vector( 4 downto 0);
+ type t_aslv6 is array (natural range <>) of std_logic_vector( 5 downto 0);
+ type t_aslv7 is array (natural range <>) of std_logic_vector( 6 downto 0);
+ type t_aslv8 is array (natural range <>) of std_logic_vector( 7 downto 0);
+ type t_aslv9 is array (natural range <>) of std_logic_vector( 8 downto 0);
+ type t_aslv10 is array (natural range <>) of std_logic_vector( 9 downto 0);
+ type t_aslv11 is array (natural range <>) of std_logic_vector(10 downto 0);
+ type t_aslv12 is array (natural range <>) of std_logic_vector(11 downto 0);
+ type t_aslv13 is array (natural range <>) of std_logic_vector(12 downto 0);
+ type t_aslv14 is array (natural range <>) of std_logic_vector(13 downto 0);
+ type t_aslv15 is array (natural range <>) of std_logic_vector(14 downto 0);
+ type t_aslv16 is array (natural range <>) of std_logic_vector(15 downto 0);
+ type t_aslv17 is array (natural range <>) of std_logic_vector(16 downto 0);
+ type t_aslv18 is array (natural range <>) of std_logic_vector(17 downto 0);
+ type t_aslv19 is array (natural range <>) of std_logic_vector(18 downto 0);
+ type t_aslv20 is array (natural range <>) of std_logic_vector(19 downto 0);
+ type t_aslv21 is array (natural range <>) of std_logic_vector(20 downto 0);
+ type t_aslv22 is array (natural range <>) of std_logic_vector(21 downto 0);
+ type t_aslv23 is array (natural range <>) of std_logic_vector(22 downto 0);
+ type t_aslv24 is array (natural range <>) of std_logic_vector(23 downto 0);
+ type t_aslv25 is array (natural range <>) of std_logic_vector(24 downto 0);
+ type t_aslv26 is array (natural range <>) of std_logic_vector(25 downto 0);
+ type t_aslv27 is array (natural range <>) of std_logic_vector(26 downto 0);
+ type t_aslv28 is array (natural range <>) of std_logic_vector(27 downto 0);
+ type t_aslv29 is array (natural range <>) of std_logic_vector(28 downto 0);
+ type t_aslv30 is array (natural range <>) of std_logic_vector(29 downto 0);
+ type t_aslv32 is array (natural range <>) of std_logic_vector(31 downto 0);
+ type t_aslv36 is array (natural range <>) of std_logic_vector(35 downto 0);
+ type t_aslv48 is array (natural range <>) of std_logic_vector(47 downto 0);
+ type t_aslv64 is array (natural range <>) of std_logic_vector(63 downto 0);
+
+ type t_ainteger is array (natural range <>) of integer;
+ type t_areal is array (natural range <>) of real;
+ type t_abool is array (natural range <>) of boolean;
+
+end psi_common_array_pkg;
diff --git a/testsuite/gna/issue1051/psi_common_bit_cc.vhd b/testsuite/gna/issue1051/psi_common_bit_cc.vhd
new file mode 100644
index 000000000..6078571aa
--- /dev/null
+++ b/testsuite/gna/issue1051/psi_common_bit_cc.vhd
@@ -0,0 +1,75 @@
+------------------------------------------------------------------------------
+-- Copyright (c) 2018 by Paul Scherrer Institute, Switzerland
+-- All rights reserved.
+-- Authors: Oliver Bruendler
+------------------------------------------------------------------------------
+
+------------------------------------------------------------------------------
+-- Description
+------------------------------------------------------------------------------
+-- This is a very basic clock crossing that allows passing multple independent
+-- single-bit signals from one clock domain to another one.
+-- Double stage synchronizers are implemeted for each bit, including then
+-- required attributes.
+--
+------------------------------------------------------------------------------
+-- Libraries
+------------------------------------------------------------------------------
+library ieee ;
+ use ieee.std_logic_1164.all;
+ use ieee.numeric_std.all;
+
+------------------------------------------------------------------------------
+-- Entity Declaration
+------------------------------------------------------------------------------
+entity psi_common_bit_cc is
+ generic (
+ NumBits_g : positive := 1
+ );
+ port (
+ -- Clock Domain A
+ BitsA : in std_logic_vector(NumBits_g-1 downto 0);
+
+ -- Clock Domain B
+ ClkB : in std_logic;
+ BitsB : out std_logic_vector(NumBits_g-1 downto 0)
+ );
+end entity;
+
+------------------------------------------------------------------------------
+-- Architecture Declaration
+------------------------------------------------------------------------------
+architecture rtl of psi_common_bit_cc is
+
+ signal Reg0 : std_logic_vector(NumBits_g-1 downto 0) := (others => '0');
+ signal Reg1 : std_logic_vector(NumBits_g-1 downto 0) := (others => '0');
+
+ attribute syn_srlstyle : string;
+ attribute syn_srlstyle of Reg0 : signal is "registers";
+ attribute syn_srlstyle of Reg1 : signal is "registers";
+
+ attribute shreg_extract : string;
+ attribute shreg_extract of Reg0 : signal is "no";
+ attribute shreg_extract of Reg1 : signal is "no";
+
+ attribute ASYNC_REG : string;
+ attribute ASYNC_REG of Reg0 : signal is "TRUE";
+ attribute ASYNC_REG of Reg1 : signal is "TRUE";
+
+begin
+
+ -- Process
+ p : process(ClkB)
+ begin
+ if rising_edge(ClkB) then
+ Reg0 <= BitsA;
+ Reg1 <= Reg0;
+ end if;
+ end process;
+ BitsB <= Reg1;
+end;
+
+
+
+
+
diff --git a/testsuite/gna/issue1051/psi_common_i2c_master.vhd b/testsuite/gna/issue1051/psi_common_i2c_master.vhd
new file mode 100644
index 000000000..02e47d04b
--- /dev/null
+++ b/testsuite/gna/issue1051/psi_common_i2c_master.vhd
@@ -0,0 +1,634 @@
+------------------------------------------------------------------------------
+-- Copyright (c) 2019 by Paul Scherrer Institute, Switzerland
+-- All rights reserved.
+-- Authors: Oliver Bruendler
+------------------------------------------------------------------------------
+
+------------------------------------------------------------------------------
+-- Description
+------------------------------------------------------------------------------
+-- This entity implements a simple I2C-master (multi master capable)
+
+------------------------------------------------------------------------------
+-- Libraries
+------------------------------------------------------------------------------
+library ieee;
+ use ieee.std_logic_1164.all;
+ use ieee.numeric_std.all;
+ use ieee.math_real.all;
+
+library work;
+ use work.psi_common_math_pkg.all;
+ use work.psi_common_logic_pkg.all;
+
+------------------------------------------------------------------------------
+-- Package for Interface Simplification
+------------------------------------------------------------------------------
+package psi_common_i2c_master_pkg is
+ constant CMD_START : std_logic_vector(2 downto 0) := "000";
+ constant CMD_STOP : std_logic_vector(2 downto 0) := "001";
+ constant CMD_REPSTART : std_logic_vector(2 downto 0) := "010";
+ constant CMD_SEND : std_logic_vector(2 downto 0) := "011";
+ constant CMD_REC : std_logic_vector(2 downto 0) := "100";
+end package;
+
+
+------------------------------------------------------------------------------
+-- Libraries
+------------------------------------------------------------------------------
+library ieee;
+ use ieee.std_logic_1164.all;
+ use ieee.numeric_std.all;
+ use ieee.math_real.all;
+
+library work;
+ use work.psi_common_math_pkg.all;
+ use work.psi_common_logic_pkg.all;
+ use work.psi_common_i2c_master_pkg.all;
+
+------------------------------------------------------------------------------
+-- Entity Declaration
+------------------------------------------------------------------------------
+-- $$ processes=stim,i2c $$
+-- $$ tbpkg=work.psi_tb_compare_pkg,work.psi_tb_activity_pkg,work.psi_tb_txt_util,work.psi_tb_i2c_pkg $$
+entity psi_common_i2c_master is
+ generic (
+ ClockFrequency_g : real := 125.0e6; -- in Hz $$ constant=125.0e6 $$
+ I2cFrequency_g : real := 100.0e3; -- in Hz $$ constant=1.0e6 $$
+ BusBusyTimeout_g : real := 1.0e-3; -- in sec $$ constant=100.0e-6 $$
+ CmdTimeout_g : real := 100.0e-6; -- in sec $$ constant=10.0e-6 $$
+ InternalTriState_g : boolean := true; -- $$ constant=true $$
+ DisableAsserts_g : boolean := false
+ );
+ port (
+ -- Control Signals
+ Clk : in std_logic; -- $$ type=clk; freq=125e6 $$
+ Rst : in std_logic; -- $$ type=rst; clk=Clk $$
+
+ -- Command Interface
+ CmdRdy : out std_logic;
+ CmdVld : in std_logic;
+ CmdType : in std_logic_vector(2 downto 0);
+ CmdData : in std_logic_vector(7 downto 0);
+ CmdAck : in std_logic;
+
+ -- Response Interface
+ RspVld : out std_logic;
+ RspType : out std_logic_vector(2 downto 0);
+ RspData : out std_logic_vector(7 downto 0);
+ RspAck : out std_logic;
+ RspArbLost : out std_logic;
+ RspSeq : out std_logic;
+
+ -- Status Interface
+ BusBusy : out std_logic;
+ TimeoutCmd : out std_logic;
+
+ -- I2c Interface with internal Tri-State (InternalTriState_g = true)
+ I2cScl : inout std_logic := 'Z';
+ I2cSda : inout std_logic := 'Z';
+
+ -- I2c Interface with external Tri-State (InternalTriState_g = false)
+ I2cScl_I : in std_logic := '0';
+ I2cScl_O : out std_logic;
+ I2cScl_T : out std_logic;
+ I2cSda_I : in std_logic := '0';
+ I2cSda_O : out std_logic;
+ I2cSda_T : out std_logic
+
+ );
+end entity;
+
+------------------------------------------------------------------------------
+-- Architecture Declaration
+------------------------------------------------------------------------------
+architecture rtl of psi_common_i2c_master is
+
+ -- *** Constants ***
+ constant BusyTimoutLimit_c : integer := integer(ClockFrequency_g*BusBusyTimeout_g)-1;
+ constant QuarterPeriodLimit_c : integer := integer(ceil(ClockFrequency_g/I2cFrequency_g/4.0))-1;
+ constant CmdTimeoutLimit_c : integer := integer(ClockFrequency_g*CmdTimeout_g)-1;
+
+ -- *** Types ***
+ type Fsm_t is ( BusIdle_s, BusBusy_s, MinIdle_s, Start1_s, Start2_s, WaitCmd_s, WaitLowCenter_s, Stop1_s, Stop2_s, Stop3_s, RepStart1_s,
+ DataBit1_s, DataBit2_s, DataBit3_s, DataBit4_s, ArbitLost_s);
+
+ -- *** Two Process Method ***
+ type two_process_r is record
+ BusBusy : std_logic;
+ CmdRdy : std_logic;
+ SclLast : std_logic;
+ SdaLast : std_logic;
+ BusBusyToCnt : unsigned(log2ceil(BusyTimoutLimit_c+1)-1 downto 0);
+ TimeoutCmdCnt : unsigned(log2ceil(CmdTimeoutLimit_c+1)-1 downto 0);
+ QuartPeriodCnt : unsigned(log2ceil(QuarterPeriodLimit_c+1)-1 downto 0);
+ QPeriodTick : std_logic;
+ CmdTypeLatch : std_logic_vector(CmdType'range);
+ CmdAckLatch : std_logic;
+ Fsm : Fsm_t;
+ SclOut : std_logic;
+ SdaOut : std_logic;
+ RspVld : std_logic;
+ RspAck : std_logic;
+ RspSeq : std_logic;
+ RspData : std_logic_vector(7 downto 0);
+ RspArbLost : std_logic;
+ BitCnt : unsigned(3 downto 0); -- 8 Data + 1 Ack = 9 = 4 bits
+ ShReg : std_logic_vector(8 downto 0);
+ CmdTimeout : std_logic;
+ TimeoutCmd : std_logic;
+ end record;
+ signal r, r_next : two_process_r;
+ attribute dont_touch : string;
+ attribute dont_touch of r : signal is "true"; -- Required to Fix Vivado 2018.2 Synthesis Bug! Is fixed in Vivado 2019.1 according to Xilinx.
+
+ -- Tri-state buffer muxing
+ signal I2cScl_Input : std_logic;
+ signal I2cSda_Input : std_logic;
+ signal I2cScl_Sync : std_logic;
+ signal I2cSda_Sync : std_logic;
+
+begin
+
+ --------------------------------------------------------------------------
+ -- Combinatorial Proccess
+ --------------------------------------------------------------------------
+ p_comb : process( Clk, r, I2cScl_Sync, I2cSda_Sync,
+ CmdVld, CmdType, CmdData, CmdAck)
+ variable v : two_process_r;
+ variable SclRe_v, SclFe_v, SdaRe_v, SdaFe_v : std_logic;
+ variable I2cStart_v, I2cStop_v : std_logic;
+ begin
+ -- *** hold variables stable ***
+ v := r;
+
+ -- *** Edge Detection ***
+ SclRe_v := not r.SclLast and I2cScl_Sync;
+ SclFe_v := r.SclLast and not I2cScl_Sync;
+ SdaRe_v := not r.SdaLast and I2cSda_Sync;
+ SdaFe_v := r.SdaLast and not I2cSda_Sync;
+ v.SclLast := I2cScl_Sync;
+ v.SdaLast := I2cSda_Sync;
+
+ -- *** Start/Stop Detection ***
+ I2cStart_v := r.SclLast and I2cScl_Sync and SdaFe_v;
+ I2cStop_v := r.SclLast and I2cScl_Sync and SdaRe_v;
+
+ -- *** Quarter Period Counter ***
+ -- The FSM may overwrite the counter in some cases!
+ v.QPeriodTick := '0';
+ if (r.Fsm = BusIdle_s) or (r.Fsm = BusBusy_s) then
+ v.QuartPeriodCnt := (others => '0');
+ elsif r.QuartPeriodCnt = QuarterPeriodLimit_c then
+ v.QuartPeriodCnt := (others => '0');
+ v.QPeriodTick := '1';
+ else
+ v.QuartPeriodCnt := r.QuartPeriodCnt + 1;
+ end if;
+
+ -- *** Command Timeout Detection ***
+ if r.Fsm = WaitCmd_s then
+ -- Timeout
+ if r.TimeoutCmdCnt = CmdTimeoutLimit_c then
+ v.CmdTimeout := '1';
+ -- Count
+ else
+ v.TimeoutCmdCnt := r.TimeoutCmdCnt + 1;
+ end if;
+ -- In all states except waiting for command, reset the timer
+ else
+ v.TimeoutCmdCnt := (others => '0');
+ end if;
+
+ -- *** Latch Command ***
+ if (r.CmdRdy = '1') and (CmdVld = '1') then
+ v.CmdTypeLatch := CmdType;
+ v.CmdAckLatch := CmdAck;
+ end if;
+
+ -- *** Default Values ***
+ v.RspVld := '0';
+ v.RspAck := not r.ShReg(0);
+ v.RspData := r.ShReg(8 downto 1);
+ v.RspSeq := '0';
+ v.RspArbLost := '0';
+ v.TimeoutCmd := '0';
+ v.CmdRdy := '0';
+
+ -- *** FSM ***
+ case r.Fsm is
+
+ -- **********************************************************************************************
+ -- Bus Idle
+ -- **********************************************************************************************
+ when BusIdle_s =>
+ -- Default Outputs
+ v.CmdRdy := '1';
+ v.BusBusyToCnt := (others => '0');
+ v.SclOut := '1';
+ v.SdaOut := '1';
+ v.CmdTimeout := '0';
+
+ -- Detect Bus Busy by Start Command
+ if (r.CmdRdy = '1') and (CmdVld = '1') then
+ -- Everyting else than START commands is ignored and an error is printed in this case
+ assert (CmdType = CMD_START) or DisableAsserts_g
+ report "###ERROR###: psi_common_i2c_master: In idle state, only CMD_START commands are allowed!"
+ severity error;
+ if CmdType = CMD_START then
+ v.Fsm := Start1_s;
+ v.CmdRdy := '0';
+ v.CmdTypeLatch := CmdType;
+ else
+ v.RspVld := '1';
+ v.RspSeq := '1';
+ end if;
+ -- Detect Busy from other master
+ elsif (I2cScl_Sync = '0') or (I2cStart_v = '1') then
+ v.Fsm := BusBusy_s;
+ v.CmdRdy := '0';
+ end if;
+
+ -- **********************************************************************************************
+ -- Bus Busy by other master
+ -- **********************************************************************************************
+ when BusBusy_s =>
+ -- Bus released
+ if I2cStop_v = '1' then
+ v.Fsm := MinIdle_s;
+ end if;
+ -- Timeout Handling
+ if I2cScl_Sync = '0' then
+ v.BusBusyToCnt := (others => '0');
+ elsif r.BusBusyToCnt = BusyTimoutLimit_c then
+ v.Fsm := BusIdle_s;
+ else
+ v.BusBusyToCnt := r.BusBusyToCnt + 1;
+ end if;
+
+ v.SclOut := '1';
+ v.SdaOut := '1';
+
+ -- Ensure that SDA stays low for at least half a clock period
+ when MinIdle_s =>
+ if r.QPeriodTick = '1' then
+ v.Fsm := BusIdle_s;
+ end if;
+
+ v.SclOut := '1';
+ v.SdaOut := '1';
+
+ -- **********************************************************************************************
+ -- Start Condition
+ -- **********************************************************************************************
+ -- State BusBusy_s Start1_s Start2_s WaitCmd_s
+ -- __________________________________
+ -- Scl ... |___________ ...
+ -- _______________________
+ -- SDA ... |______________________ ...
+ -- **********************************************************************************************
+
+ when Start1_s =>
+ if r.QPeriodTick = '1' then
+ v.Fsm := Start2_s;
+ end if;
+
+ -- Handle Clock Stretching in case of a repeated start (slave keeps SCL low)
+ if I2cScl_Sync = '0' and r.CmdTypeLatch = CMD_REPSTART then
+ v.QuartPeriodCnt := (others => '0');
+ end if;
+
+ -- Handle Arbitration (other master transmits start condition first)
+ if I2cSda_Sync = '0' then
+ v.Fsm := ArbitLost_s;
+ end if;
+
+ v.SclOut := '1';
+ v.SdaOut := '1';
+
+ when Start2_s =>
+ if r.QPeriodTick = '1' then
+ v.Fsm := WaitCmd_s;
+ v.RspVld := '1';
+ end if;
+ v.SclOut := '1';
+ v.SdaOut := '0';
+
+ -- **********************************************************************************************
+ -- Wait for user command (in first half of SCL low phase)
+ -- **********************************************************************************************
+ when WaitCmd_s =>
+ -- Default Outputs
+ v.CmdRdy := '1';
+ v.SclOut := '0';
+
+ -- All commands except START are allowed, START commands are ignored
+ if (r.CmdRdy = '1') and (CmdVld = '1') then
+ assert (CmdType = CMD_STOP) or (CmdType = CMD_REPSTART) or (CmdType = CMD_SEND) or (CmdType = CMD_REC) or DisableAsserts_g
+ report "###ERROR###: psi_common_i2c_master: In WaitCmd_s state, CMD_START commands are not allowed!"
+ severity error;
+ if (CmdType = CMD_STOP) or (CmdType = CMD_REPSTART) or (CmdType = CMD_SEND) or (CmdType = CMD_REC) then
+ v.Fsm := WaitLowCenter_s;
+ v.CmdRdy := '0';
+ else
+ v.RspVld := '1';
+ v.RspSeq := '1';
+ end if;
+ -- Latch data (used for SEND)
+ v.ShReg := CmdData & '0';
+ -- Command timeout - In this case send a STOP to free the bus
+ elsif r.CmdTimeout = '1' then
+ v.Fsm := WaitLowCenter_s;
+ v.CmdRdy := '0';
+ v.TimeoutCmd := '1';
+ end if;
+
+ -- **********************************************************************************************
+ -- Wait for center of SCL low phase (after user command arrived)
+ -- **********************************************************************************************
+ when WaitLowCenter_s =>
+ -- State Handling
+ v.SclOut := '0';
+ v.BitCnt := (others => '0');
+
+ -- Switch to commands
+ if r.QPeriodTick = '1' then
+ -- In timeout case, send a STOP to free the bus
+ if r.CmdTimeout = '1' then
+ v.Fsm := Stop1_s;
+ -- Else, go to requested command
+ else
+ case r.CmdTypeLatch is
+ when CMD_STOP => v.Fsm := Stop1_s;
+ when CMD_REPSTART => v.Fsm := RepStart1_s;
+ when CMD_SEND => v.Fsm := DataBit1_s;
+ when CMD_REC => v.Fsm := DataBit1_s;
+ when others => null;
+ end case;
+ end if;
+ end if;
+
+ -- **********************************************************************************************
+ -- Start Condition
+ -- **********************************************************************************************
+ -- State RepStart1_s Start1_s Start2_s WaitCmd_s
+ -- _____________________
+ -- Scl ..._________________| |___________ ...
+ -- __________________________
+ -- SDA ...XXX |_____________________ ...
+ -- **********************************************************************************************
+ -- States after RepStart1_s are shared with normal start condition
+
+ when RepStart1_s =>
+ if r.QPeriodTick = '1' then
+ -- The rest of the sequence is same as for START
+ v.Fsm := Start1_s;
+
+ -- Handle Arbitration other master prvents repeating start by transmitting 0
+ if I2cSda_Sync = '0' then
+ v.Fsm := ArbitLost_s;
+ end if;
+ end if;
+ v.SclOut := '0';
+ v.SdaOut := '1';
+
+ -- **********************************************************************************************
+ -- Start Condition
+ -- **********************************************************************************************
+ -- State DataBit1_s DataBit2_s DataBit3_s WaitCmd_s / DataBit4_s
+ -- _________________________
+ -- Scl ...___________| |___________ ...
+ --
+ -- SDA ...XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
+ -- **********************************************************************************************
+ -- The DataBit1_s is the second half of the SCL low period. So the
+ -- SDA Line is set at the beginning of DataBit1_s. After the SCL high period
+ -- of the last bit, the state is changed to WaitCmd_s. Otherwise the first half of the SCL low
+ -- period is executed (DataBit4_s) before the next bit starts (DataBit1_s)
+
+ when DataBit1_s =>
+ if r.QPeriodTick = '1' then
+ v.Fsm := DataBit2_s;
+ end if;
+ v.SclOut := '0';
+
+ -- Send Operation
+ if r.CmdTypeLatch = CMD_SEND then
+ -- For Ack, receive data
+ if r.BitCnt = 8 then
+ v.SdaOut := '1';
+ -- .. else send data
+ else
+ v.SdaOut := r.ShReg(8);
+ end if;
+ -- Receive Operatiom
+ else
+ -- Ack Handling
+ if r.BitCnt = 8 then
+ if r.CmdAckLatch = '1' then
+ v.SdaOut := '0';
+ else
+ v.SdaOut := '1';
+ end if;
+ -- .. else tri-state for receiving
+ else
+ v.SdaOut := '1';
+ end if;
+ end if;
+
+ when DataBit2_s =>
+ if r.QPeriodTick = '1' then
+ v.Fsm := DataBit3_s;
+ -- Shift register in the middle of the CLK pulse
+ v.ShReg := r.ShReg(7 downto 0) & I2cSda_Sync;
+ end if;
+ v.SclOut := '1';
+
+ -- Handle Clock Stretching (slave keeps SCL low)
+ if I2cScl_Sync = '0' then
+ v.QuartPeriodCnt := (others => '0');
+ end if;
+
+ -- Handle Arbitration for Sending (only databits, not ack)
+ if (r.CmdTypeLatch = CMD_SEND) and (r.BitCnt /= 8) then
+ if I2cSda_Sync /= r.SdaOut then
+ v.Fsm := ArbitLost_s;
+ end if;
+ -- Receiving does not need arbitration since slave addresses are unique
+ end if;
+
+
+ when DataBit3_s =>
+ if r.QPeriodTick = '1' then
+ -- Command Done after 9 bits (8 Data + 1 Ack)
+ if r.BitCnt = 8 then
+ v.Fsm := WaitCmd_s;
+ v.RspVld := '1';
+ -- Else goto next bit
+ else
+ v.Fsm := DataBit4_s;
+ end if;
+ end if;
+ v.SclOut := '1';
+
+ -- Handle Arbitration for Sending (only databits, not ack)
+ if (r.CmdTypeLatch = CMD_SEND) and (r.BitCnt /= 8) then
+ if I2cSda_Sync /= r.SdaOut then
+ v.Fsm := ArbitLost_s;
+ end if;
+ -- Receiving does not need arbitration since slave addresses are unique
+ end if;
+
+ when DataBit4_s =>
+ if r.QPeriodTick = '1' then
+ v.Fsm := DataBit1_s;
+ v.BitCnt:= r.BitCnt + 1;
+ end if;
+ v.SclOut := '0';
+
+ -- **********************************************************************************************
+ -- Stop Condition
+ -- **********************************************************************************************
+ -- State WaitCmd_s Stop1_s Stop2_s Stop3_s BusIdle_s
+ -- _____________________
+ -- Scl ..._____________________| |__________ ...
+ -- _____________________
+ -- SDA ...XXXXXXXXXXXX____________________| ...
+ -- **********************************************************************************************
+
+ when Stop1_s =>
+ if r.QPeriodTick = '1' then
+ v.Fsm := Stop2_s;
+ end if;
+ v.SclOut := '0';
+ v.SdaOut := '0';
+
+ when Stop2_s =>
+ if r.QPeriodTick = '1' then
+ v.Fsm := Stop3_s;
+ end if;
+ v.SclOut := '1';
+ v.SdaOut := '0';
+
+ -- Handle Clock Stretching (slave keeps SCL low)
+ if I2cScl_Sync = '0' then
+ v.QuartPeriodCnt := (others => '0');
+ end if;
+
+ when Stop3_s =>
+ if r.QPeriodTick = '1' then
+ -- Handle Arbitration
+ if I2cSda_Sync = '0' then
+ v.Fsm := ArbitLost_s;
+ -- Else the STOP was successful
+ else
+ v.Fsm := BusIdle_s;
+ v.RspVld := '1';
+ end if;
+ end if;
+ v.SclOut := '1';
+ v.SdaOut := '1';
+
+ -- **********************************************************************************************
+ -- Send Response in case the arbitration was lost
+ -- **********************************************************************************************
+
+ when ArbitLost_s =>
+ v.Fsm := BusBusy_s;
+ v.RspVld := '1';
+ v.RspAck := '0';
+ v.RspArbLost := '1';
+ v.SclOut := '1';
+ v.SdaOut := '1';
+
+ when others => null;
+ end case;
+
+ -- TODO: FSM Stuck detection timeout!
+
+ -- *** Bus Busy ***
+ if r.Fsm = BusIdle_s then
+ v.BusBusy := '0';
+ else
+ v.BusBusy := '1';
+ end if;
+
+ -- *** assign signal ***
+ r_next <= v;
+ end process;
+
+ --------------------------------------------------------------------------
+ -- Outputs
+ --------------------------------------------------------------------------
+ BusBusy <= r.BusBusy;
+ CmdRdy <= r.CmdRdy;
+ RspVld <= r.RspVld;
+ RspType <= r.CmdTypeLatch;
+ RspArbLost <= r.RspArbLost;
+ RspAck <= r.RspAck;
+ RspData <= r.RspData;
+ RspSeq <= r.RspSeq;
+ TimeoutCmd <= r.TimeoutCmd;
+ g_intTristate : if InternalTriState_g generate
+ I2cScl <= 'Z' when r.SclOut = '1' else '0';
+ I2cSda <= 'Z' when r.SdaOut = '1' else '0';
+ I2cScl_O <= '0';
+ I2cSda_O <= '0';
+ I2cScl_T <= '1';
+ I2cSda_T <= '1';
+ end generate;
+ g_extTristatte : if not InternalTriState_g generate
+ I2cScl_O <= r.SclOut;
+ I2cSda_O <= r.SdaOut;
+ I2cScl_T <= r.SclOut;
+ I2cSda_T <= r.SdaOut;
+ I2cScl <= 'Z';
+ I2cSda <= 'Z';
+ end generate;
+
+ --------------------------------------------------------------------------
+ -- Sequential Proccess
+ --------------------------------------------------------------------------
+ p_seq : process(Clk)
+ begin
+ if rising_edge(Clk) then
+ r <= r_next;
+ if Rst = '1' then
+ r.BusBusy <= '0';
+ r.CmdRdy <= '0';
+ r.SclLast <= '1';
+ r.SdaLast <= '1';
+ r.BusBusyToCnt <= (others => '0');
+ r.Fsm <= BusIdle_s;
+ r.SclOut <= '1';
+ r.SdaOut <= '1';
+ r.RspVld <= '0';
+ end if;
+ end if;
+ end process;
+
+ --------------------------------------------------------------------------
+ -- Component Instantiations
+ --------------------------------------------------------------------------
+ I2cScl_Input <= To01X(I2cScl) when InternalTriState_g else I2cScl_I;
+ I2cSda_Input <= To01X(I2cSda) when InternalTriState_g else I2cSda_I;
+
+ i_sync : entity work.psi_common_bit_cc
+ generic map (
+ NumBits_g => 2
+ )
+ port map (
+ BitsA(0) => I2cScl_Input,
+ BitsA(1) => I2cSda_Input,
+ ClkB => Clk,
+ BitsB(0) => I2cScl_Sync,
+ BitsB(1) => I2cSda_Sync
+ );
+
+
+end;
+
+
+
+
+
diff --git a/testsuite/gna/issue1051/psi_common_i2c_master_tb.vhd b/testsuite/gna/issue1051/psi_common_i2c_master_tb.vhd
new file mode 100644
index 000000000..0781d1d97
--- /dev/null
+++ b/testsuite/gna/issue1051/psi_common_i2c_master_tb.vhd
@@ -0,0 +1,679 @@
+------------------------------------------------------------
+-- Copyright (c) 2019 by Paul Scherrer Institute, Switzerland
+-- All rights reserved.
+------------------------------------------------------------
+
+------------------------------------------------------------
+-- Testbench generated by TbGen.py
+------------------------------------------------------------
+-- see Library/Python/TbGenerator
+
+------------------------------------------------------------
+-- Libraries
+------------------------------------------------------------
+library ieee;
+ use ieee.std_logic_1164.all;
+ use ieee.numeric_std.all;
+ use ieee.math_real.all;
+
+library work;
+ use work.psi_common_math_pkg.all;
+ use work.psi_common_logic_pkg.all;
+ use work.psi_common_i2c_master_pkg.all;
+
+library work;
+ use work.psi_tb_compare_pkg.all;
+ use work.psi_tb_activity_pkg.all;
+ use work.psi_tb_txt_util.all;
+ use work.psi_tb_i2c_pkg.all;
+
+------------------------------------------------------------
+-- Entity Declaration
+------------------------------------------------------------
+entity psi_common_i2c_master_tb is
+ generic (
+ InternalTriState_g : boolean := true
+ );
+end entity;
+
+------------------------------------------------------------
+-- Architecture
+------------------------------------------------------------
+architecture sim of psi_common_i2c_master_tb is
+ -- *** Fixed Generics ***
+ constant ClockFrequency_g : real := 125.0e6;
+ constant I2cFrequency_g : real := 1.0e6;
+ constant BusBusyTimeout_g : real := 50.0e-6;
+ constant CmdTimeout_g : real := 10.0e-6;
+
+ -- *** Not Assigned Generics (default values) ***
+
+ -- *** TB Control ***
+ signal TbRunning : boolean := True;
+ signal NextCase : integer := -1;
+ signal ProcessDone : std_logic_vector(0 to 1) := (others => '0');
+ constant AllProcessesDone_c : std_logic_vector(0 to 1) := (others => '1');
+ constant TbProcNr_stim_c : integer := 0;
+ constant TbProcNr_i2c_c : integer := 1;
+ signal StimCase : integer := -1;
+ signal I2cCase : integer := -1;
+
+ -- *** DUT Signals ***
+ signal Clk : std_logic := '1';
+ signal Rst : std_logic := '1';
+ signal CmdRdy : std_logic := '0';
+ signal CmdVld : std_logic := '0';
+ signal CmdType : std_logic_vector(2 downto 0) := (others => '0');
+ signal CmdData : std_logic_vector(7 downto 0) := (others => '0');
+ signal CmdAck : std_logic := '0';
+ signal RspVld : std_logic := '0';
+ signal RspData : std_logic_vector(7 downto 0) := (others => '0');
+ signal RspType : std_logic_vector(2 downto 0) := (others => '0');
+ signal RspArbLost : std_logic := '0';
+ signal RspAck : std_logic := '0';
+ signal RspSeq : std_logic := '0';
+ signal BusBusy : std_logic := '0';
+ signal TimeoutCmd : std_logic := '0';
+ signal I2cScl : std_logic := '0';
+ signal I2cSda : std_logic := '0';
+ signal I2cScl_I : std_logic := '0';
+ signal I2cScl_O : std_logic := '0';
+ signal I2cScl_T : std_logic := '0';
+ signal I2cSda_I : std_logic := '0';
+ signal I2cSda_O : std_logic := '0';
+ signal I2cSda_T : std_logic := '0';
+
+ -- *** Helper Functions ***
+ procedure WaitForCase( signal TestCase : in integer;
+ Value : in integer) is
+ begin
+ if TestCase /= Value then
+ wait until TestCase = Value;
+ end if;
+ end procedure;
+
+ procedure ApplyCmd( Command : in std_logic_vector(2 downto 0);
+ Data : in std_logic_vector(7 downto 0);
+ Ack : in std_logic;
+ signal CmdVld : out std_logic;
+ signal CmdRdy : in std_logic;
+ signal CmdType : out std_logic_vector(2 downto 0);
+ signal CmdData : out std_logic_vector(7 downto 0);
+ signal CmdAck : out std_logic) is
+ begin
+ wait until rising_edge(Clk);
+ CmdVld <= '1';
+ CmdType <= Command;
+ CmdData <= Data;
+ CmdAck <= Ack;
+ wait until rising_edge(Clk) and CmdRdy = '1';
+ CmdVld <= '0';
+ CmdType <= (others => '0');
+ CmdData <= (others => '0');
+ CmdAck <= '0';
+ end procedure;
+
+ procedure CheckRsp( Command : in std_logic_vector(2 downto 0);
+ Data : in std_logic_vector;
+ Ack : in std_logic;
+ ArbLost : in std_logic;
+ signal RspVld : in std_logic;
+ signal RspData : in std_logic_vector(7 downto 0);
+ signal RspType : in std_logic_vector(2 downto 0);
+ signal RspArbLost : in std_logic;
+ signal RspAck : in std_logic;
+ signal RspSeq : in std_logic;
+ Msg : in string := "No Msg";
+ Err : in std_logic := '0') is
+ begin
+ wait until rising_edge(Clk) and RspVld = '1';
+ StdlvCompareStdlv(Command, RspType, "Response: Wrong Type - " & Msg);
+ if Data /= "X" then
+ StdlvCompareStdlv(Data, RspData, "Response: Wrong Data - " & Msg);
+ end if;
+ if Ack /= 'X' then
+ StdlCompare(choose(Ack = '1', 1, 0), RspAck, "Response: Wrong Ack - " & Msg);
+ end if;
+ if ArbLost /= 'X' then
+ StdlCompare(choose(ArbLost = '1', 1, 0), RspArbLost, "Response: Wrong ArbLost - " & Msg);
+ end if;
+ StdlCompare(choose(Err = '1', 1, 0), RspSeq, "Response: Wrong Err - " & Msg);
+ end procedure;
+
+begin
+ ------------------------------------------------------------
+ -- DUT Instantiation
+ ------------------------------------------------------------
+ i_dut : entity work.psi_common_i2c_master
+ generic map (
+ ClockFrequency_g => ClockFrequency_g,
+ I2cFrequency_g => I2cFrequency_g,
+ BusBusyTimeout_g => BusBusyTimeout_g,
+ CmdTimeout_g => CmdTimeout_g,
+ InternalTriState_g => InternalTriState_g,
+ DisableAsserts_g => true
+ )
+ port map (
+ Clk => Clk,
+ Rst => Rst,
+ CmdRdy => CmdRdy,
+ CmdVld => CmdVld,
+ CmdType => CmdType,
+ CmdData => CmdData,
+ CmdAck => CmdAck,
+ RspVld => RspVld,
+ RspType => RspType,
+ RspArbLost => RspArbLost,
+ RspData => RspData,
+ RspAck => RspAck,
+ RspSeq => RspSeq,
+ BusBusy => BusBusy,
+ TimeoutCmd => TimeoutCmd,
+ I2cScl => I2cScl,
+ I2cSda => I2cSda,
+ I2cScl_I => I2cScl_I,
+ I2cScl_O => I2cScl_O,
+ I2cScl_T => I2cScl_T,
+ I2cSda_I => I2cSda_I,
+ I2cSda_O => I2cSda_O,
+ I2cSda_T => I2cSda_T
+ );
+
+ ------------------------------------------------------------
+ -- I2C Emulation
+ ------------------------------------------------------------
+ I2cPullup(I2cScl, I2cSda);
+ g_triState : if not InternalTriState_g generate
+ I2cScl <= 'Z' when I2cScl_T = '1' else I2cScl_O;
+ I2cScl_I <= To01X(I2cScl);
+ I2cSda <= 'Z' when I2cSda_T = '1' else I2cSda_O;
+ I2cSda_I <= To01X(I2cSda);
+ end generate;
+
+ ------------------------------------------------------------
+ -- Testbench Control !DO NOT EDIT!
+ ------------------------------------------------------------
+ p_tb_control : process
+ begin
+ wait until Rst = '0';
+ wait until ProcessDone = AllProcessesDone_c;
+ TbRunning <= false;
+ wait;
+ end process;
+
+ ------------------------------------------------------------
+ -- Clocks !DO NOT EDIT!
+ ------------------------------------------------------------
+ p_clock_Clk : process
+ constant Frequency_c : real := real(125e6);
+ begin
+ while TbRunning loop
+ wait for 0.5*(1 sec)/Frequency_c;
+ Clk <= not Clk;
+ end loop;
+ wait;
+ end process;
+
+
+ ------------------------------------------------------------
+ -- Resets
+ ------------------------------------------------------------
+ p_rst_Rst : process
+ begin
+ wait for 1 us;
+ -- Wait for two clk edges to ensure reset is active for at least one edge
+ wait until rising_edge(Clk);
+ wait until rising_edge(Clk);
+ Rst <= '0';
+ wait;
+ end process;
+
+
+ ------------------------------------------------------------
+ -- Processes
+ ------------------------------------------------------------
+ -- *** stim ***
+ p_stim : process
+ begin
+ I2cSetFrequency(I2cFrequency_g);
+ -- start of process !DO NOT EDIT
+ wait until Rst = '0';
+ wait until rising_edge(Clk);
+
+ -- *** Test Bus Busy ***
+ print(">> Test Bus Busy");
+ StimCase <= 0;
+ wait until rising_edge(Clk);
+ WaitForCase(I2cCase, 0);
+ wait for 10 us;
+
+ -- *** Test Start / Repeated-Start / Stop ***
+ print(">> Test Start / Repeated-Start / Stop");
+ StimCase <= 1;
+ wait until rising_edge(Clk);
+ ApplyCmd(CMD_START, X"00", 'X', CmdVld, CmdRdy, CmdType, CmdData, CmdAck);
+ CheckRsp(CMD_START, "X", 'X', '0', RspVld, RspData, RspType, RspArbLost, RspAck, RspSeq, "Start");
+ ApplyCmd(CMD_REPSTART, X"00", 'X', CmdVld, CmdRdy, CmdType, CmdData, CmdAck);
+ CheckRsp(CMD_REPSTART, "X", 'X', '0', RspVld, RspData, RspType, RspArbLost, RspAck, RspSeq, "Start");
+ ApplyCmd(CMD_STOP, X"00", 'X', CmdVld, CmdRdy, CmdType, CmdData, CmdAck);
+ CheckRsp(CMD_STOP, "X", 'X', '0', RspVld, RspData, RspType, RspArbLost, RspAck, RspSeq, "Stop");
+ WaitForCase(I2cCase, 1);
+ wait for 10 us;
+
+ -- *** Test Write ***
+ print(">> Test Write");
+ StimCase <= 2;
+ wait until rising_edge(Clk);
+
+ -- 1Byte ACK
+ ApplyCmd(CMD_START, X"00", 'X', CmdVld, CmdRdy, CmdType, CmdData, CmdAck);
+ CheckRsp(CMD_START, "X", 'X', 'X', RspVld, RspData, RspType, RspArbLost, RspAck, RspSeq, "Start 1b ACK");
+ ApplyCmd(CMD_SEND, X"A3", 'X', CmdVld, CmdRdy, CmdType, CmdData, CmdAck);
+ CheckRsp(CMD_SEND, "X", '1', '0', RspVld, RspData, RspType, RspArbLost, RspAck, RspSeq, "Start 1b ACK");
+ ApplyCmd(CMD_STOP, X"00", 'X', CmdVld, CmdRdy, CmdType, CmdData, CmdAck);
+ CheckRsp(CMD_STOP, "X", 'X', 'X', RspVld, RspData, RspType, RspArbLost, RspAck, RspSeq, "Stop 1b ACK");
+
+ -- 2Byte ACK, then NACK
+ ApplyCmd(CMD_START, X"00", 'X', CmdVld, CmdRdy, CmdType, CmdData, CmdAck);
+ CheckRsp(CMD_START, "X", 'X', 'X', RspVld, RspData, RspType, RspArbLost, RspAck, RspSeq, "Start 2b ACK -> NACK");
+ ApplyCmd(CMD_SEND, X"12", 'X', CmdVld, CmdRdy, CmdType, CmdData, CmdAck);
+ CheckRsp(CMD_SEND, "X", '1', '0', RspVld, RspData, RspType, RspArbLost, RspAck, RspSeq, "Start 2b ACK -> NACK 1");
+ ApplyCmd(CMD_SEND, X"34", 'X', CmdVld, CmdRdy, CmdType, CmdData, CmdAck);
+ CheckRsp(CMD_SEND, "X", '0', '0', RspVld, RspData, RspType, RspArbLost, RspAck, RspSeq, "Start 2b ACK -> NACK 2");
+ ApplyCmd(CMD_STOP, X"00", 'X', CmdVld, CmdRdy, CmdType, CmdData, CmdAck);
+ CheckRsp(CMD_STOP, "X", 'X', 'X', RspVld, RspData, RspType, RspArbLost, RspAck, RspSeq, "Stop 2b ACK -> NACK");
+
+ WaitForCase(I2cCase, 2);
+ wait for 10 us;
+
+ -- *** Test Read ***
+ print(">> Test Read");
+ StimCase <= 3;
+ wait until rising_edge(Clk);
+
+ -- 1Byte ACK
+ ApplyCmd(CMD_START, X"00", 'X', CmdVld, CmdRdy, CmdType, CmdData, CmdAck);
+ CheckRsp(CMD_START, "X", 'X', 'X', RspVld, RspData, RspType, RspArbLost, RspAck, RspSeq, "Start 1b ACK");
+ ApplyCmd(CMD_REC, X"00", '1', CmdVld, CmdRdy, CmdType, CmdData, CmdAck);
+ CheckRsp(CMD_REC, X"67", '1', '0', RspVld, RspData, RspType, RspArbLost, RspAck, RspSeq, "Start 1b ACK");
+ ApplyCmd(CMD_STOP, X"00", 'X', CmdVld, CmdRdy, CmdType, CmdData, CmdAck);
+ CheckRsp(CMD_STOP, "X", 'X', 'X', RspVld, RspData, RspType, RspArbLost, RspAck, RspSeq, "Stop 1b ACK");
+
+ -- 2Byte ACK, then NACK
+ ApplyCmd(CMD_START, X"00", 'X', CmdVld, CmdRdy, CmdType, CmdData, CmdAck);
+ CheckRsp(CMD_START, "X", 'X', 'X', RspVld, RspData, RspType, RspArbLost, RspAck, RspSeq, "Start 2b ACK -> NACK");
+ ApplyCmd(CMD_REC, X"00", '1', CmdVld, CmdRdy, CmdType, CmdData, CmdAck);
+ CheckRsp(CMD_REC, X"34", 'X', '0', RspVld, RspData, RspType, RspArbLost, RspAck, RspSeq, "Start 2b ACK -> NACK 1");
+ ApplyCmd(CMD_REC, X"00", '0', CmdVld, CmdRdy, CmdType, CmdData, CmdAck);
+ CheckRsp(CMD_REC, X"56", 'X', '0', RspVld, RspData, RspType, RspArbLost, RspAck, RspSeq, "Start 2b ACK -> NACK 2");
+ ApplyCmd(CMD_STOP, X"00", 'X', CmdVld, CmdRdy, CmdType, CmdData, CmdAck);
+ CheckRsp(CMD_STOP, "X", 'X', 'X', RspVld, RspData, RspType, RspArbLost, RspAck, RspSeq, "Stop 2b ACK -> NACK");
+
+ WaitForCase(I2cCase, 3);
+ wait for 10 us;
+
+ -- *** Test Clock Stretching ***
+ print(">> Test Clock Stretching");
+ StimCase <= 4;
+ wait until rising_edge(Clk);
+
+ -- 1Byte Read ACK
+ ApplyCmd(CMD_START, X"00", 'X', CmdVld, CmdRdy, CmdType, CmdData, CmdAck);
+ CheckRsp(CMD_START, "X", 'X', 'X', RspVld, RspData, RspType, RspArbLost, RspAck, RspSeq, "Start Read 1b ACK");
+ ApplyCmd(CMD_REC, X"00", '1', CmdVld, CmdRdy, CmdType, CmdData, CmdAck);
+ CheckRsp(CMD_REC, X"67", '1', '0', RspVld, RspData, RspType, RspArbLost, RspAck, RspSeq, "Start Read 1b ACK");
+ ApplyCmd(CMD_STOP, X"00", 'X', CmdVld, CmdRdy, CmdType, CmdData, CmdAck);
+ CheckRsp(CMD_STOP, "X", 'X', 'X', RspVld, RspData, RspType, RspArbLost, RspAck, RspSeq, "Stop Read 1b ACK");
+
+ -- 2Byte ACK, then NACK
+ ApplyCmd(CMD_START, X"00", 'X', CmdVld, CmdRdy, CmdType, CmdData, CmdAck);
+ CheckRsp(CMD_START, "X", 'X', 'X', RspVld, RspData, RspType, RspArbLost, RspAck, RspSeq, "Start 2b Write ACK -> NACK");
+ ApplyCmd(CMD_SEND, X"12", 'X', CmdVld, CmdRdy, CmdType, CmdData, CmdAck);
+ CheckRsp(CMD_SEND, "X", '1', '0', RspVld, RspData, RspType, RspArbLost, RspAck, RspSeq, "Start 2b Write ACK -> NACK 1");
+ ApplyCmd(CMD_SEND, X"34", 'X', CmdVld, CmdRdy, CmdType, CmdData, CmdAck);
+ CheckRsp(CMD_SEND, "X", '0', '0', RspVld, RspData, RspType, RspArbLost, RspAck, RspSeq, "Start 2b Write ACK -> NACK 2");
+ ApplyCmd(CMD_STOP, X"00", 'X', CmdVld, CmdRdy, CmdType, CmdData, CmdAck);
+ CheckRsp(CMD_STOP, "X", 'X', 'X', RspVld, RspData, RspType, RspArbLost, RspAck, RspSeq, "Stop 2b Write ACK -> NACK");
+
+ -- Write / Read
+ ApplyCmd(CMD_START, X"00", 'X', CmdVld, CmdRdy, CmdType, CmdData, CmdAck);
+ CheckRsp(CMD_START, "X", 'X', 'X', RspVld, RspData, RspType, RspArbLost, RspAck, RspSeq, "Start 2b W->R");
+ ApplyCmd(CMD_SEND, X"12", 'X', CmdVld, CmdRdy, CmdType, CmdData, CmdAck);
+ CheckRsp(CMD_SEND, "X", '1', '0', RspVld, RspData, RspType, RspArbLost, RspAck, RspSeq, "Write 2b W->R");
+ ApplyCmd(CMD_REPSTART, X"00", 'X', CmdVld, CmdRdy, CmdType, CmdData, CmdAck);
+ CheckRsp(CMD_REPSTART, "X", 'X', '0', RspVld, RspData, RspType, RspArbLost, RspAck, RspSeq, "RepStart 2b W->R");
+ ApplyCmd(CMD_REC, X"00", '1', CmdVld, CmdRdy, CmdType, CmdData, CmdAck);
+ CheckRsp(CMD_REC, X"67", '1', '0', RspVld, RspData, RspType, RspArbLost, RspAck, RspSeq, "Read 2b W->R");
+ ApplyCmd(CMD_STOP, X"00", 'X', CmdVld, CmdRdy, CmdType, CmdData, CmdAck);
+ CheckRsp(CMD_STOP, "X", 'X', 'X', RspVld, RspData, RspType, RspArbLost, RspAck, RspSeq, "Stop 2b W->R");
+
+ WaitForCase(I2cCase, 4);
+ wait for 10 us;
+
+ -- *** Test Delayed Command *** (clock is held low until command available)
+ print(">> Test Delayed Command");
+ StimCase <= 5;
+ wait until rising_edge(Clk);
+
+ -- 1Byte Read ACK, delay shorter than timeout
+ ApplyCmd(CMD_START, X"00", 'X', CmdVld, CmdRdy, CmdType, CmdData, CmdAck);
+ CheckRsp(CMD_START, "X", 'X', 'X', RspVld, RspData, RspType, RspArbLost, RspAck, RspSeq, "Start Read 1b ACK");
+ wait for CmdTimeout_g/2.0*(1 sec);
+ wait until rising_edge(Clk);
+ ApplyCmd(CMD_REC, X"00", '1', CmdVld, CmdRdy, CmdType, CmdData, CmdAck);
+ CheckRsp(CMD_REC, X"67", '1', '0', RspVld, RspData, RspType, RspArbLost, RspAck, RspSeq, "Start Read 1b ACK");
+ wait for CmdTimeout_g/2.0*(1 sec);
+ wait until rising_edge(Clk);
+ ApplyCmd(CMD_STOP, X"00", 'X', CmdVld, CmdRdy, CmdType, CmdData, CmdAck);
+ CheckRsp(CMD_STOP, "X", 'X', 'X', RspVld, RspData, RspType, RspArbLost, RspAck, RspSeq, "Stop Read 1b ACK");
+
+ -- Command Timeout (Timeout after start, other commands ignored)
+ ApplyCmd(CMD_START, X"00", 'X', CmdVld, CmdRdy, CmdType, CmdData, CmdAck);
+ CheckRsp(CMD_START, "X", 'X', 'X', RspVld, RspData, RspType, RspArbLost, RspAck, RspSeq, "Start Read 1b ACK");
+ wait for CmdTimeout_g*2.0*(1 sec);
+ wait until rising_edge(Clk);
+ ApplyCmd(CMD_REC, X"00", '1', CmdVld, CmdRdy, CmdType, CmdData, CmdAck);
+ CheckRsp(CMD_REC, "X", '1', '0', RspVld, RspData, RspType, RspArbLost, RspAck, RspSeq, "Start Read 1b ACK", Err => '1');
+ wait for CmdTimeout_g*2.0*(1 sec);
+ wait until rising_edge(Clk);
+ ApplyCmd(CMD_STOP, X"00", 'X', CmdVld, CmdRdy, CmdType, CmdData, CmdAck);
+ CheckRsp(CMD_STOP, "X", 'X', 'X', RspVld, RspData, RspType, RspArbLost, RspAck, RspSeq, "Stop Read 1b ACK", Err => '1');
+
+ WaitForCase(I2cCase, 5);
+ wait for 10 us;
+
+ -- *** Test Arbitration ***
+ print(">> Test Arbitration");
+ StimCase <= 6;
+ wait until rising_edge(Clk);
+
+ -- Multi Master, Same Write
+ ApplyCmd(CMD_START, X"00", 'X', CmdVld, CmdRdy, CmdType, CmdData, CmdAck);
+ CheckRsp(CMD_START, "X", 'X', 'X', RspVld, RspData, RspType, RspArbLost, RspAck, RspSeq, "Start 1b ACK");
+ ApplyCmd(CMD_SEND, X"A3", 'X', CmdVld, CmdRdy, CmdType, CmdData, CmdAck);
+ CheckRsp(CMD_SEND, "X", '1', '0', RspVld, RspData, RspType, RspArbLost, RspAck, RspSeq, "Start 1b ACK");
+ ApplyCmd(CMD_STOP, X"00", 'X', CmdVld, CmdRdy, CmdType, CmdData, CmdAck);
+ CheckRsp(CMD_STOP, "X", 'X', 'X', RspVld, RspData, RspType, RspArbLost, RspAck, RspSeq, "Stop 1b ACK");
+
+ -- Arbitration Lost during Write
+ wait for 10 us;
+ ApplyCmd(CMD_START, X"00", 'X', CmdVld, CmdRdy, CmdType, CmdData, CmdAck);
+ CheckRsp(CMD_START, "X", 'X', 'X', RspVld, RspData, RspType, RspArbLost, RspAck, RspSeq, "Start Lost Write");
+ ApplyCmd(CMD_SEND, X"A3", 'X', CmdVld, CmdRdy, CmdType, CmdData, CmdAck);
+ CheckRsp(CMD_SEND, "X", '0', '1', RspVld, RspData, RspType, RspArbLost, RspAck, RspSeq, "Start Lost Write");
+ ApplyCmd(CMD_STOP, X"00", 'X', CmdVld, CmdRdy, CmdType, CmdData, CmdAck);
+ CheckRsp(CMD_STOP, "X", 'X', 'X', RspVld, RspData, RspType, RspArbLost, RspAck, RspSeq, "Lost Write", Err => '1');
+
+ -- Arbitration Lost during STOP (other master continues writing)
+ wait for 10 us;
+ ApplyCmd(CMD_START, X"00", 'X', CmdVld, CmdRdy, CmdType, CmdData, CmdAck);
+ CheckRsp(CMD_START, "X", 'X', 'X', RspVld, RspData, RspType, RspArbLost, RspAck, RspSeq, "Start Lost Stop");
+ ApplyCmd(CMD_SEND, X"A3", 'X', CmdVld, CmdRdy, CmdType, CmdData, CmdAck);
+ CheckRsp(CMD_SEND, "X", '1', '0', RspVld, RspData, RspType, RspArbLost, RspAck, RspSeq, "Start Lost Stop");
+ ApplyCmd(CMD_STOP, X"00", 'X', CmdVld, CmdRdy, CmdType, CmdData, CmdAck);
+ CheckRsp(CMD_STOP, "X", 'X', '1', RspVld, RspData, RspType, RspArbLost, RspAck, RspSeq, "Stop Lost Stop");
+
+ -- Arbitration Lost during repeated start (other master continues writing)
+ wait for 20 us;
+ ApplyCmd(CMD_START, X"00", 'X', CmdVld, CmdRdy, CmdType, CmdData, CmdAck);
+ CheckRsp(CMD_START, "X", 'X', 'X', RspVld, RspData, RspType, RspArbLost, RspAck, RspSeq, "Start Lost RepStartA");
+ ApplyCmd(CMD_SEND, X"A3", 'X', CmdVld, CmdRdy, CmdType, CmdData, CmdAck);
+ CheckRsp(CMD_SEND, "X", '1', '0', RspVld, RspData, RspType, RspArbLost, RspAck, RspSeq, "Start Lost RepStartA");
+ ApplyCmd(CMD_REPSTART, X"00", 'X', CmdVld, CmdRdy, CmdType, CmdData, CmdAck);
+ CheckRsp(CMD_REPSTART, "X", 'X', '1', RspVld, RspData, RspType, RspArbLost, RspAck, RspSeq, "Repstart Lost RepStartA");
+
+ -- Arbitration Lost during repeated start (other master stops)
+ wait for 20 us;
+ ApplyCmd(CMD_START, X"00", 'X', CmdVld, CmdRdy, CmdType, CmdData, CmdAck);
+ CheckRsp(CMD_START, "X", 'X', 'X', RspVld, RspData, RspType, RspArbLost, RspAck, RspSeq, "Start Lost RepStartB");
+ ApplyCmd(CMD_SEND, X"A3", 'X', CmdVld, CmdRdy, CmdType, CmdData, CmdAck);
+ CheckRsp(CMD_SEND, "X", '1', '0', RspVld, RspData, RspType, RspArbLost, RspAck, RspSeq, "Start Lost RepStartB");
+ ApplyCmd(CMD_REPSTART, X"00", 'X', CmdVld, CmdRdy, CmdType, CmdData, CmdAck);
+ CheckRsp(CMD_REPSTART, "X", 'X', '1', RspVld, RspData, RspType, RspArbLost, RspAck, RspSeq, "Repstart Lost RepStartB");
+
+ -- Arbitration lost due to stop (during first bit of data)
+ wait for 10 us;
+ ApplyCmd(CMD_START, X"00", 'X', CmdVld, CmdRdy, CmdType, CmdData, CmdAck);
+ CheckRsp(CMD_START, "X", 'X', 'X', RspVld, RspData, RspType, RspArbLost, RspAck, RspSeq, "Start Lost DueStop");
+ ApplyCmd(CMD_SEND, X"A3", 'X', CmdVld, CmdRdy, CmdType, CmdData, CmdAck);
+ CheckRsp(CMD_SEND, "X", '1', '0', RspVld, RspData, RspType, RspArbLost, RspAck, RspSeq, "Start Lost DueStop 1");
+ ApplyCmd(CMD_SEND, X"F0", 'X', CmdVld, CmdRdy, CmdType, CmdData, CmdAck);
+ CheckRsp(CMD_SEND, "X", '0', '1', RspVld, RspData, RspType, RspArbLost, RspAck, RspSeq, "Start Lost DueStop 2");
+
+ -- Arbitration lost due to rep-start (during first bit of data)
+ wait for 10 us;
+ ApplyCmd(CMD_START, X"00", 'X', CmdVld, CmdRdy, CmdType, CmdData, CmdAck);
+ CheckRsp(CMD_START, "X", 'X', 'X', RspVld, RspData, RspType, RspArbLost, RspAck, RspSeq, "Start Lost DueRepStart");
+ ApplyCmd(CMD_SEND, X"A3", 'X', CmdVld, CmdRdy, CmdType, CmdData, CmdAck);
+ CheckRsp(CMD_SEND, "X", '1', '0', RspVld, RspData, RspType, RspArbLost, RspAck, RspSeq, "Start Lost DueRepStart 1");
+ ApplyCmd(CMD_SEND, X"F0", 'X', CmdVld, CmdRdy, CmdType, CmdData, CmdAck);
+ CheckRsp(CMD_SEND, "X", '0', '1', RspVld, RspData, RspType, RspArbLost, RspAck, RspSeq, "Start Lost DueRepStart 2");
+
+ WaitForCase(I2cCase, 6);
+ wait for 10 us;
+
+
+ -- end of process !DO NOT EDIT!
+ wait for 1 us;
+ ProcessDone(TbProcNr_stim_c) <= '1';
+ wait;
+ end process;
+
+ -- *** i2c slave ***
+ p_i2c_slave : process
+ begin
+ I2cBusFree(I2cScl, I2cSda);
+
+ -- start of process !DO NOT EDIT
+ wait until Rst = '0';
+ wait until rising_edge(Clk);
+
+ -- *** Test Bus Busy ***
+ WaitForCase(StimCase, 0);
+ -- Not busy
+ wait for 1 us;
+ StdlCompare(0, BusBusy, "Busy 0");
+ -- A transfer is goiong on
+ I2cScl <= '0';
+ wait for 1 us;
+ StdlCompare(1, BusBusy, "Busy 1");
+ -- busy is kept
+ I2cScl <= 'Z';
+ wait for 10 us;
+ StdlCompare(1, BusBusy, "Busy 2");
+ -- released after timeout
+ wait for BusBusyTimeout_g*(1 sec);
+ StdlCompare(0, BusBusy, "Busy 3");
+ -- Asserted on start
+ I2cMasterSendStart(I2cScl, I2cSda, "Assert Start");
+ wait for 1 us;
+ StdlCompare(1, BusBusy, "Busy 4");
+ -- Released on stop
+ I2cMasterSendStop(I2cScl, I2cSda, "Assert Start");
+ wait for 1 us;
+ StdlCompare(0, BusBusy, "Busy 4");
+ I2cCase <= 0;
+
+ -- *** Test Start / Stop ***
+ WaitForCase(StimCase, 1);
+ I2cSlaveWaitStart(I2cScl, I2cSda, "Start");
+ I2cSlaveWaitRepeatedStart(I2cScl, I2cSda, "RepStart");
+ I2cSlaveWaitStop(I2cScl, I2cSda, "Stop");
+ I2cCase <= 1;
+
+ -- *** Test Write ***
+ WaitForCase(StimCase, 2);
+
+ -- 1 Byte Ack
+ I2cSlaveWaitStart(I2cScl, I2cSda, "Start 1b Ack");
+ I2cSlaveExpectByte(16#A3#, I2cScl, I2cSda, "Data 1b Ack", '0');
+ I2cSlaveWaitStop(I2cScl, I2cSda, "Stop");
+
+ -- 2 Byte Ack, then NACK
+ I2cSlaveWaitStart(I2cScl, I2cSda, "Start 2b ACK -> NACK");
+ I2cSlaveExpectByte(16#12#, I2cScl, I2cSda, "Data 2b ACK -> NACK 1", '0');
+ I2cSlaveExpectByte(16#34#, I2cScl, I2cSda, "Data 2b ACK -> NACK 2", '1');
+ I2cSlaveWaitStop(I2cScl, I2cSda, "Stop");
+
+ I2cCase <= 2;
+
+ -- *** Test Read ***
+ WaitForCase(StimCase, 3);
+
+ -- 1 Byte Ack
+ I2cSlaveWaitStart(I2cScl, I2cSda, "Start 1b Ack");
+ I2cSlaveSendByte(16#67#, I2cScl, I2cSda, "Data 1b Ack", '0');
+ I2cSlaveWaitStop(I2cScl, I2cSda, "Stop");
+
+ -- 2 Byte Ack, then NACK
+ I2cSlaveWaitStart(I2cScl, I2cSda, "Start 2b ACK -> NACK");
+ I2cSlaveSendByte(16#34#, I2cScl, I2cSda, "Data 2b ACK -> NACK 1", '0');
+ I2cSlaveSendByte(16#56#, I2cScl, I2cSda, "Data 2b ACK -> NACK 2", '1');
+ I2cSlaveWaitStop(I2cScl, I2cSda, "Stop");
+
+ I2cCase <= 3;
+
+ -- *** Test Clock Stretching ***
+ WaitForCase(StimCase, 4);
+
+ -- 1 Byte Read Ack
+ I2cSlaveWaitStart(I2cScl, I2cSda, "Start Read 1b Ack");
+ I2cSlaveSendByte(16#67#, I2cScl, I2cSda, "Data Write 1b Ack", '0', ClkStretch => 1 us);
+ I2cSlaveWaitStop(I2cScl, I2cSda, "Stop", ClkStretch => 1 us);
+
+
+ -- 2 Byte Write Ack, then NACK
+ I2cSlaveWaitStart(I2cScl, I2cSda, "Start 2b Write ACK -> NACK");
+ I2cSlaveExpectByte(16#12#, I2cScl, I2cSda, "Data 2b Write ACK -> NACK 1", '0', ClkStretch => 1 us);
+ I2cSlaveExpectByte(16#34#, I2cScl, I2cSda, "Data 2b Write ACK -> NACK 2", '1', ClkStretch => 1 us);
+ I2cSlaveWaitStop(I2cScl, I2cSda, "Stop", ClkStretch => 1 us);
+
+ -- Write / Read
+ I2cSlaveWaitStart(I2cScl, I2cSda, "Start 2b W->R");
+ I2cSlaveExpectByte(16#12#, I2cScl, I2cSda, "Write 2b W->R", '0', ClkStretch => 1 us);
+ I2cSlaveWaitRepeatedStart(I2cScl, I2cSda, "RepStart 2b W->R", ClkStretch => 1 us);
+ I2cSlaveSendByte(16#67#, I2cScl, I2cSda, "Read 2b W->R", '0', ClkStretch => 1 us);
+ I2cSlaveWaitStop(I2cScl, I2cSda, "Stop 2b W->R", ClkStretch => 1 us);
+
+ I2cCase <= 4;
+
+ -- *** Test Delayed Command ***
+ WaitForCase(StimCase, 5);
+
+ -- 1 Byte Ack, delay shorter than timeout
+ I2cSlaveWaitStart(I2cScl, I2cSda, "Start 1b Ack");
+ I2cSlaveSendByte(16#67#, I2cScl, I2cSda, "Data 1b Ack", '0');
+ I2cSlaveWaitStop(I2cScl, I2cSda, "Stop");
+
+ -- Command Timeout (Timeout after start, stop generated internally)
+ I2cSlaveWaitStart(I2cScl, I2cSda, "Start 1b Ack");
+ I2cSlaveWaitStop(I2cScl, I2cSda, "Stop");
+
+ I2cCase <= 5;
+
+ -- *** Test Arbitration ***
+ WaitForCase(StimCase, 6);
+
+ -- Multi Master, Same Write
+ I2cSlaveWaitStart(I2cScl, I2cSda, "S: Start 1b Ack");
+ I2cSlaveExpectByte(16#A3#, I2cScl, I2cSda, "S: Data 1b Ack", '0');
+ I2cSlaveWaitStop(I2cScl, I2cSda, "S: Stop");
+
+ -- Arbitration Lost during Write
+ I2cSlaveWaitStart(I2cScl, I2cSda, "S: Start Lost Write");
+ I2cSlaveExpectByte(16#87#, I2cScl, I2cSda, "S: Stop Lost Write", '0');
+ I2cSlaveWaitStop(I2cScl, I2cSda, "S: Lost Write Stop");
+
+ -- Arbitration Lost STOP (other master continues writing)
+ I2cSlaveWaitStart(I2cScl, I2cSda, "S: Start Lost Stop");
+ I2cSlaveExpectByte(16#A3#, I2cScl, I2cSda, "S: Data Lost Stop 1", '0');
+ I2cSlaveExpectByte(16#12#, I2cScl, I2cSda, "S: Data Lost Stop 2", '0');
+ I2cSlaveWaitStop(I2cScl, I2cSda, "S: Stop Lost Stop");
+
+ -- Arbitration Lost during repeated start (other master continues writing)
+ I2cSlaveWaitStart(I2cScl, I2cSda, "S: Start Lost RepStartA");
+ I2cSlaveExpectByte(16#A3#, I2cScl, I2cSda, "S: Data Lost RepStartA 1", '0');
+ I2cSlaveExpectByte(16#12#, I2cScl, I2cSda, "S: Data Lost RepStartA 2", '0');
+ I2cSlaveWaitStop(I2cScl, I2cSda, "S: Stop Lost RepStartA");
+
+ -- Arbitration Lost during repeated start (other master stops)
+ I2cSlaveWaitStart(I2cScl, I2cSda, "S: Start Lost RepStartB");
+ I2cSlaveExpectByte(16#A3#, I2cScl, I2cSda, "S: Data Lost RepStartB 1", '0');
+ I2cSlaveWaitStop(I2cScl, I2cSda, "S: Stop Lost RepStartB");
+
+ -- Arbitration lost due to stop (during first bit of data)
+ I2cSlaveWaitStart(I2cScl, I2cSda, "S: Start Lost DueStop");
+ I2cSlaveExpectByte(16#A3#, I2cScl, I2cSda, "S: Data Lost DueStop 1", '0');
+ I2cSlaveWaitStop(I2cScl, I2cSda, "S: Stop Lost DueStop");
+
+ -- Arbitration lost due to rep-start (during first bit of data)
+ I2cSlaveWaitStart(I2cScl, I2cSda, "S: Start Lost RepStart");
+ I2cSlaveExpectByte(16#A3#, I2cScl, I2cSda, "S: Write Lost RepStart 1", '0');
+ I2cSlaveWaitRepeatedStart(I2cScl, I2cSda, "S: Lost RepStart RepStart");
+ I2cSlaveSendByte(16#34#, I2cScl, I2cSda, "S: Read Lost RepStart RepStart", '0');
+ I2cSlaveWaitStop(I2cScl, I2cSda, "S: Stop Lost RepStart");
+
+ I2cCase <= 6;
+
+ -- end of process !DO NOT EDIT!
+ ProcessDone(TbProcNr_i2c_c) <= '1';
+ wait;
+ end process;
+
+ -- *** i2c master ***
+ p_i2c_master : process
+ begin
+ I2cBusFree(I2cScl, I2cSda);
+
+ -- *** Test Arbitration ***
+ WaitForCase(StimCase, 6);
+
+ -- Multi Master, Same Write
+ I2cSlaveWaitStart(I2cScl, I2cSda, "M: Start 1b Ack");
+ -- small delay
+ I2cScl <= '0';
+ wait for 100 ns;
+ -- continue
+ I2cMasterSendByte(16#A3#, I2cScl, I2cSda, "M: Data 1b Ack");
+ I2cMasterSendStop(I2cScl, I2cSda, "M: Stop");
+
+ -- Arbitration Lost during Write
+ I2cSlaveWaitStart(I2cScl, I2cSda, "M: Start Lost Write");
+ I2cMasterSendByte(16#87#, I2cScl, I2cSda, "M: Data Lost Write");
+ I2cMasterSendStop(I2cScl, I2cSda, "M: Stop Loast Read");
+
+ -- Arbitration Lost STOP (other master continues writing)
+ I2cSlaveWaitStart(I2cScl, I2cSda, "M: Start Lost Stop");
+ I2cMasterSendByte(16#A3#, I2cScl, I2cSda, "M: Data Lost Stop 1");
+ I2cMasterSendByte(16#12#, I2cScl, I2cSda, "M: Data Lost Stop 2");
+ I2cMasterSendStop(I2cScl, I2cSda, "M: Stop Lost Stop");
+
+ -- Arbitration Lost during repeated start (other master continues writing)
+ I2cSlaveWaitStart(I2cScl, I2cSda, "M: Start Lost RepStartA");
+ I2cMasterSendByte(16#A3#, I2cScl, I2cSda, "M: Data Lost RepStartA 1");
+ I2cMasterSendByte(16#12#, I2cScl, I2cSda, "M: Data Lost RepStartA 2");
+ I2cMasterSendStop(I2cScl, I2cSda, "M: Stop Lost RepStartA");
+
+ -- Arbitration Lost during repeated start (other master stops)
+ I2cSlaveWaitStart(I2cScl, I2cSda, "M: Start Lost RepStartB");
+ I2cMasterSendByte(16#A3#, I2cScl, I2cSda, "M: Data Lost RepStartB 1");
+ I2cMasterSendStop(I2cScl, I2cSda, "M: Stop Lost RepStartB");
+
+ -- Arbitration lost due to stop (during first bit of data)
+ I2cSlaveWaitStart(I2cScl, I2cSda, "M: Start Lost DueStop");
+ I2cMasterSendByte(16#A3#, I2cScl, I2cSda, "M: Data Lost DueStop 1");
+ I2cMasterSendStop(I2cScl, I2cSda, "M: Stop Lost DueStop");
+
+ -- Arbitration lost due to rep-start (during first bit of data)
+ I2cSlaveWaitStart(I2cScl, I2cSda, "M: Start Lost DueRepstart");
+ I2cMasterSendByte(16#A3#, I2cScl, I2cSda, "M: write Lost DueRepstart 1");
+ I2cMasterSendRepeatedStart(I2cScl, I2cSda, "M: Stop Lost DueRepstart");
+ I2cMasterExpectByte(16#34#, I2cScl, I2cSda, "M: read Lost DueRepstart 1");
+ I2cMasterSendStop(I2cScl, I2cSda, "M: Stop Lost DueRepstart");
+
+ wait;
+
+ end process;
+
+
+end;
diff --git a/testsuite/gna/issue1051/psi_common_logic_pkg.vhd b/testsuite/gna/issue1051/psi_common_logic_pkg.vhd
new file mode 100644
index 000000000..f2e15b4be
--- /dev/null
+++ b/testsuite/gna/issue1051/psi_common_logic_pkg.vhd
@@ -0,0 +1,227 @@
+------------------------------------------------------------------------------
+-- Copyright (c) 2018 by Paul Scherrer Institute, Switzerland
+-- All rights reserved.
+-- Authors: Oliver Bruendler
+------------------------------------------------------------------------------
+
+------------------------------------------------------------------------------
+-- Libraries
+------------------------------------------------------------------------------
+library ieee;
+ use ieee.std_logic_1164.all;
+ use ieee.numeric_std.all;
+
+library work;
+ use work.psi_common_math_pkg.all;
+
+------------------------------------------------------------------------------
+-- Package Header
+------------------------------------------------------------------------------
+package psi_common_logic_pkg is
+
+ function ZerosVector(size : in natural) return std_logic_vector;
+
+ function OnesVector(size : in natural) return std_logic_vector;
+
+ function ShiftLeft( arg : in std_logic_vector;
+ bits : in integer;
+ fill : in std_logic := '0')
+ return std_logic_vector;
+
+ function ShiftRight(arg : in std_logic_vector;
+ bits : in integer;
+ fill : in std_logic := '0')
+ return std_logic_vector;
+
+ function BinaryToGray( binary : in std_logic_vector)
+ return std_logic_vector;
+
+ function GrayToBinary( gray : in std_logic_vector)
+ return std_logic_vector;
+
+ -- Parallel Prefix Computation of the OR function
+ -- Input --> Output
+ -- 0100 --> 0111
+ -- 0101 --> 0111
+ -- 0011 --> 0011
+ -- 0010 --> 0011
+ function PpcOr( inp : in std_logic_vector)
+ return std_logic_vector;
+
+ function IntToStdLogic( int : in integer)
+ return std_logic;
+
+ function ReduceOr( vec : in std_logic_vector)
+ return std_logic;
+
+ function ReduceAnd( vec : in std_logic_vector)
+ return std_logic;
+
+ function To01X( inp : in std_logic)
+ return std_logic;
+
+ function To01X( inp : in std_logic_vector)
+ return std_logic_vector;
+
+end psi_common_logic_pkg;
+
+------------------------------------------------------------------------------
+-- Package Body
+------------------------------------------------------------------------------
+package body psi_common_logic_pkg is
+
+ -- *** ZerosVector ***
+ function ZerosVector(size : in natural) return std_logic_vector is
+ constant c : std_logic_vector(size-1 downto 0) := (others => '0');
+ begin
+ return c;
+ end function;
+
+ -- *** OnesVector ***
+ function OnesVector(size : in natural) return std_logic_vector is
+ constant c : std_logic_vector(size-1 downto 0) := (others => '1');
+ begin
+ return c;
+ end function;
+
+ -- *** ShiftLeft ***
+ function ShiftLeft( arg : in std_logic_vector;
+ bits : in integer;
+ fill : in std_logic := '0')
+ return std_logic_vector is
+ constant argDt : std_logic_vector(arg'high downto 0) := arg;
+ variable v : std_logic_vector(argDt'range);
+ begin
+ if bits < 0 then
+ return ShiftRight(argDt, -bits, fill);
+ else
+ v(v'left downto bits) := argDt(argDt'left-bits downto 0);
+ v(bits-1 downto 0) := (others => fill);
+ return v;
+ end if;
+ end function;
+
+ -- *** ShiftRight ***
+ function ShiftRight( arg : in std_logic_vector;
+ bits : in integer;
+ fill : in std_logic := '0')
+ return std_logic_vector is
+ constant argDt : std_logic_vector(arg'high downto 0) := arg;
+ variable v : std_logic_vector(argDt'range);
+ begin
+ if bits < 0 then
+ return ShiftLeft(argDt, -bits, fill);
+ else
+ v(v'left-bits downto 0) := argDt(argDt'left downto bits);
+ v(v'left downto v'left-bits+1) := (others => fill);
+ return v;
+ end if;
+ end function;
+
+ -- *** BinaryToGray ***
+ function BinaryToGray( binary : in std_logic_vector)
+ return std_logic_vector is
+ variable Gray_v : std_logic_vector(binary'range);
+ begin
+ Gray_v := binary xor ('0' & binary(binary'left downto 1));
+ return Gray_v;
+ end function;
+
+ -- *** GrayToBinary ***
+ function GrayToBinary( gray : in std_logic_vector)
+ return std_logic_vector is
+ variable Binary_v : std_logic_vector(gray'range);
+ begin
+ Binary_v(Binary_v'left) := gray(gray'left);
+ for b in gray'left-1 downto 0 loop
+ Binary_v(b) := gray(b) xor Binary_v(b+1);
+ end loop;
+ return Binary_v;
+ end function;
+
+
+ -- *** PpcOr ***
+ function PpcOr( inp : in std_logic_vector)
+ return std_logic_vector is
+ constant Stages_c : integer := log2ceil(inp'length);
+ constant Pwr2Width_c : integer := 2**Stages_c;
+ type StageOut_t is array (natural range <>) of std_logic_vector(Pwr2Width_c-1 downto 0);
+ variable StageOut_v : StageOut_t(0 to Stages_c);
+ variable BinCnt_v : unsigned(Pwr2Width_c-1 downto 0);
+ begin
+ StageOut_v(0) := (others => '0');
+ StageOut_v(0)(inp'length-1 downto 0) := inp;
+ for stage in 0 to Stages_c-1 loop
+ BinCnt_v := (others => '0');
+ for idx in 0 to Pwr2Width_c-1 loop
+ if BinCnt_v(stage) = '0' then
+ StageOut_v(stage+1)(idx) := StageOut_v(stage)(idx) or StageOut_v(stage)((idx/(2**stage)+1)*2**stage);
+ else
+ StageOut_v(stage+1)(idx) := StageOut_v(stage)(idx);
+ end if;
+ BinCnt_v := BinCnt_v+1;
+ end loop;
+ end loop;
+ return StageOut_v(Stages_c)(inp'length-1 downto 0);
+ end function;
+
+ function IntToStdLogic( int : in integer)
+ return std_logic is
+ begin
+ if int = 1 then
+ return '1';
+ elsif int = 0 then
+ return '0';
+ else
+ return 'X';
+ end if;
+ end function;
+
+ function ReduceOr( vec : in std_logic_vector)
+ return std_logic is
+ variable tmp : std_logic;
+ begin
+ tmp := '0';
+ for i in 0 to vec'high loop
+ tmp := tmp or vec(i);
+ end loop;
+ return tmp;
+ end function;
+
+ function ReduceAnd( vec : in std_logic_vector)
+ return std_logic is
+ variable tmp : std_logic;
+ begin
+ tmp := '1';
+ for i in 0 to vec'high loop
+ tmp := tmp and vec(i);
+ end loop;
+ return tmp;
+ end function;
+
+ function To01X( inp : in std_logic)
+ return std_logic is
+ begin
+ case inp is
+ when '0' | 'L' => return '0';
+ when '1' | 'H' => return '1';
+ when others => return 'X';
+ end case;
+ end function;
+
+ function To01X( inp : in std_logic_vector)
+ return std_logic_vector is
+ variable tmp : std_logic_vector(inp'range);
+ begin
+ for i in inp'low to inp'high loop
+ tmp(i) := to01X(inp(i));
+ end loop;
+ return tmp;
+ end function;
+
+end psi_common_logic_pkg;
+
+
+
+
+
diff --git a/testsuite/gna/issue1051/psi_common_math_pkg.vhd b/testsuite/gna/issue1051/psi_common_math_pkg.vhd
new file mode 100644
index 000000000..183cba97f
--- /dev/null
+++ b/testsuite/gna/issue1051/psi_common_math_pkg.vhd
@@ -0,0 +1,259 @@
+------------------------------------------------------------------------------
+-- Copyright (c) 2018 by Paul Scherrer Institute, Switzerland
+-- All rights reserved.
+-- Authors: Oliver Bruendler
+------------------------------------------------------------------------------
+
+------------------------------------------------------------------------------
+-- Libraries
+------------------------------------------------------------------------------
+library ieee ;
+ use ieee.std_logic_1164.all;
+ use ieee.numeric_std.all;
+
+library work;
+ use work.psi_common_array_pkg.all;
+
+------------------------------------------------------------------------------
+-- Package Header
+------------------------------------------------------------------------------
+package psi_common_math_pkg is
+
+ function log2(arg : in natural) return natural;
+
+ function log2ceil(arg : in natural) return natural;
+
+ function log2ceil(arg : in real) return natural;
+
+ function isLog2(arg : in natural) return boolean;
+
+ function max( a : in integer;
+ b : in integer) return integer;
+
+ function min( a : in integer;
+ b : in integer) return integer;
+
+ -- choose t if s=true else f
+ function choose( s : in boolean;
+ t : in std_logic;
+ f : in std_logic) return std_logic;
+
+ function choose( s : in boolean;
+ t : in std_logic_vector;
+ f : in std_logic_vector) return std_logic_vector;
+
+ function choose( s : in boolean;
+ t : in integer;
+ f : in integer) return integer;
+
+ function choose( s : in boolean;
+ t : in string;
+ f : in string) return string;
+
+ function choose( s : in boolean;
+ t : in real;
+ f : in real) return real;
+
+ function choose( s : in boolean;
+ t : in unsigned;
+ f : in unsigned) return unsigned;
+
+ -- count occurence of a value inside an array
+ function count( a : in t_ainteger;
+ v : in integer) return integer;
+
+ function count( a : in t_abool;
+ v : in boolean) return integer;
+
+ function count( a : in std_logic_vector;
+ v : in std_logic) return integer;
+
+end psi_common_math_pkg;
+
+------------------------------------------------------------------------------
+-- Package Body
+------------------------------------------------------------------------------
+package body psi_common_math_pkg is
+
+ -- *** Log2 integer ***
+ function log2(arg : in natural) return natural is
+ variable v : natural := arg;
+ variable r : natural := 0;
+ begin
+ while v > 1 loop
+ v := v/2;
+ r := r+1;
+ end loop;
+ return r;
+ end function;
+
+ -- *** Log2Ceil integer ***
+ function log2ceil(arg : in natural) return natural is
+ begin
+ if arg = 0 then
+ return 0;
+ end if;
+ return log2(arg*2-1);
+ end function;
+
+ -- *** Log2Ceil real ***
+ function log2ceil(arg : in real) return natural is
+ variable v : real := arg;
+ variable r : natural := 0;
+ begin
+ while v > 1.0 loop
+ v := v/2.0;
+ r := r+1;
+ end loop;
+ return r;
+ end function;
+
+ -- *** isLog2 ***
+ function isLog2(arg : in natural) return boolean is
+ begin
+ if log2(arg) = log2ceil(arg) then
+ return true;
+ else
+ return false;
+ end if;
+ end function;
+
+ -- *** Max ***
+ function max( a : in integer;
+ b : in integer) return integer is
+ begin
+ if a > b then
+ return a;
+ else
+ return b;
+ end if;
+ end function;
+
+ -- *** Min ***
+ function min( a : in integer;
+ b : in integer) return integer is
+ begin
+ if a > b then
+ return b;
+ else
+ return a;
+ end if;
+ end function;
+
+ -- *** Choose (std_logic) ***
+ function choose( s : in boolean;
+ t : in std_logic;
+ f : in std_logic) return std_logic is
+ begin
+ if s then
+ return t;
+ else
+ return f;
+ end if;
+ end function;
+
+ -- *** Choose (std_logic_vector) ***
+ function choose( s : in boolean;
+ t : in std_logic_vector;
+ f : in std_logic_vector) return std_logic_vector is
+ begin
+ if s then
+ return t;
+ else
+ return f;
+ end if;
+ end function;
+
+ -- *** Choose (integer) ***
+ function choose( s : in boolean;
+ t : in integer;
+ f : in integer) return integer is
+ begin
+ if s then
+ return t;
+ else
+ return f;
+ end if;
+ end function;
+
+ -- *** Choose (string) ***
+ function choose( s : in boolean;
+ t : in string;
+ f : in string) return string is
+ begin
+ if s then
+ return t;
+ else
+ return f;
+ end if;
+ end function;
+
+ -- *** Choose (real) ***
+ function choose( s : in boolean;
+ t : in real;
+ f : in real) return real is
+ begin
+ if s then
+ return t;
+ else
+ return f;
+ end if;
+ end function;
+
+ -- *** Choose (unsigned) ***
+ function choose( s : in boolean;
+ t : in unsigned;
+ f : in unsigned) return unsigned is
+ begin
+ if s then
+ return t;
+ else
+ return f;
+ end if;
+ end function;
+
+ -- *** count (integer) ***
+ function count( a : in t_ainteger;
+ v : in integer) return integer is
+ variable cnt_v : integer := 0;
+ begin
+ for idx in a'low to a'high loop
+ if a(idx) = v then
+ cnt_v := cnt_v+1;
+ end if;
+ end loop;
+ return cnt_v;
+ end function;
+
+ -- *** count (bool) ***
+ function count( a : in t_abool;
+ v : in boolean) return integer is
+ variable cnt_v : integer := 0;
+ begin
+ for idx in a'low to a'high loop
+ if a(idx) = v then
+ cnt_v := cnt_v+1;
+ end if;
+ end loop;
+ return cnt_v;
+ end function;
+
+ -- *** count (std_logic) ***
+ function count( a : in std_logic_vector;
+ v : in std_logic) return integer is
+ variable cnt_v : integer := 0;
+ begin
+ for idx in a'low to a'high loop
+ if a(idx) = v then
+ cnt_v := cnt_v+1;
+ end if;
+ end loop;
+ return cnt_v;
+ end function;
+
+end psi_common_math_pkg;
+
+
+
+
+
diff --git a/testsuite/gna/issue1051/psi_tb_activity_pkg.vhd b/testsuite/gna/issue1051/psi_tb_activity_pkg.vhd
new file mode 100644
index 000000000..b99a40207
--- /dev/null
+++ b/testsuite/gna/issue1051/psi_tb_activity_pkg.vhd
@@ -0,0 +1,258 @@
+------------------------------------------------------------------------------
+-- Copyright (c) 2018 by Paul Scherrer Institute, Switzerland
+-- All rights reserved.
+-- Authors: Oliver Bruendler, Benoit Stef
+------------------------------------------------------------------------------
+
+------------------------------------------------------------------------------
+-- Libraries
+------------------------------------------------------------------------------
+library ieee;
+use ieee.std_logic_1164.all;
+use ieee.numeric_std.all;
+use ieee.math_real.all;
+
+library work;
+use work.psi_tb_txt_util.all;
+use work.psi_tb_compare_pkg.all;
+
+------------------------------------------------------------------------------
+-- Package Header
+------------------------------------------------------------------------------
+package psi_tb_activity_pkg is
+
+ -- Wait for a given time and check if the signal is idle
+ procedure CheckNoActivity(signal Sig : in std_logic;
+ IdleTime : in time;
+ Level : in integer range -1 to 1; -- -1 = don't check, 0 = low, 1 = high
+ Msg : in string := "";
+ Prefix : in string := "###ERROR###: ");
+
+ procedure CheckNoActivityStlv(signal Sig : in std_logic_vector;
+ IdleTime : in time;
+ Level : in integer range -1 to integer'high; -- -1 = don't check, otherwise interpreted unsigned
+ Msg : in string := "";
+ Prefix : in string := "###ERROR###: ");
+
+ -- Check when a signal had its last activity (without waiting)
+ procedure CheckLastActivity(signal Sig : in std_logic;
+ IdleTime : in time;
+ Level : in integer range -1 to 1; -- -1 = don't check, 0 = low, 1 = high
+ Msg : in string := "";
+ Prefix : in string := "###ERROR###: ");
+
+ procedure CheckLastActivityStlv(signal Sig : in std_logic_vector;
+ IdleTime : in time;
+ Level : in integer range -1 to integer'high; -- -1 = don't check, otherwise interpreted unsigned
+ Msg : in string := "";
+ Prefix : in string := "###ERROR###: ");
+
+ -- pulse a signal
+ procedure PulseSig(signal Sig : out std_logic;
+ signal Clk : in std_logic);
+
+ -- Clocked wait for a signal
+ procedure ClockedWaitFor(Val : in std_logic;
+ signal Sig : in std_logic;
+ signal Clk : in std_logic);
+
+ -- Wait for a number of clock cycles
+ procedure WaitClockCycles( Cycles : in integer;
+ signal Clk : in std_logic);
+
+ -- Wait for a time and quit on rising edge
+ procedure ClockedWaitTime( Duration : in time;
+ signal Clk : in std_logic);
+
+ -- Strobe generator
+ procedure GenerateStrobe( freq_clock : in real := 100.0E6; -- in Hz
+ freq_str : in real := 1.0E6; -- in Hz
+ rst_pol_g : in std_logic := '1'; -- reset polarity
+ signal rst : in std_logic; -- rst
+ signal clk : in std_logic; -- clk
+ signal str : out std_logic); -- str
+
+ -- check if stdlv is arrived within a defined period of time
+ procedure WaitForValueStdlv(signal Sig : in std_logic_vector; -- Signal to check
+ ExpVal : in std_logic_vector; -- expected value
+ Timeout : in time; -- time to wait for
+ Msg : in string; -- msg to display
+ Prefix : in string := "###ERROR###: "); -- bool out to stop Tb for ex.
+
+ -- check if std is arrived within a defined period of time
+ procedure WaitForValueStdl( signal Sig : in std_logic; -- Signal to check
+ ExpVal : in std_logic; -- expected value
+ Timeout : in time; -- time to wait for
+ Msg : in string; -- msg to display
+ Prefix : in string := "###ERROR###: "); -- bool out to stop Tb for ex.
+
+end psi_tb_activity_pkg;
+
+------------------------------------------------------------------------------
+-- Package Body
+------------------------------------------------------------------------------
+package body psi_tb_activity_pkg is
+
+ -- *** CheckNoActivity ***
+ procedure CheckNoActivity(signal Sig : in std_logic;
+ IdleTime : in time;
+ Level : in integer range -1 to 1; -- -1 = don't check, 0 = low, 1 = high
+ Msg : in string := "";
+ Prefix : in string := "###ERROR###: ") is
+ begin
+ wait for IdleTime;
+ assert Sig'last_event >= IdleTime
+ report Prefix & Msg & "[Unexpected Activity]"
+ severity error;
+ if Level /= -1 then
+ StdlCompare(Level, Sig, "CheckNoActivity: " & Msg, Prefix);
+ end if;
+ end procedure;
+
+ -- *** CheckNoActivityStlv ***
+ procedure CheckNoActivityStlv(signal Sig : in std_logic_vector;
+ IdleTime : in time;
+ Level : in integer range -1 to integer'high; -- -1 = don't check, otherwise interpreted unsigned
+ Msg : in string := "";
+ Prefix : in string := "###ERROR###: ") is
+ begin
+ wait for IdleTime;
+ assert Sig'last_event >= IdleTime
+ report Prefix & Msg & "[Unexpected Activity]"
+ severity error;
+ if Level /= -1 then
+ StdlvCompareInt(Level, Sig, "CheckNoActivityStlv: " & Msg, false, 0, Prefix);
+ end if;
+ end procedure;
+
+ -- *** CheckLastActivity ***
+ procedure CheckLastActivity(signal Sig : in std_logic;
+ IdleTime : in time;
+ Level : in integer range -1 to 1; -- -1 = don't check, 0 = low, 1 = high
+ Msg : in string := "";
+ Prefix : in string := "###ERROR###: ") is
+ begin
+ assert Sig'last_event >= IdleTime
+ report Prefix & Msg & "Unexpected activity, " &
+ "[Expeced idle " & time'image(IdleTime) &
+ ", Actual idle " & time'image(Sig'last_event) & "]"
+ severity error;
+ if Level /= -1 then
+ StdlCompare(Level, Sig, "CheckLastActivity: " & Msg, Prefix);
+ end if;
+ end procedure;
+
+ -- *** CheckLastActivityStlv ***
+ procedure CheckLastActivityStlv(signal Sig : in std_logic_vector;
+ IdleTime : in time;
+ Level : in integer range -1 to integer'high; -- -1 = don't check, otherwise interpreted unsigned
+ Msg : in string := "";
+ Prefix : in string := "###ERROR###: ") is
+ begin
+ assert Sig'last_event >= IdleTime
+ report Prefix & Msg & "Unexpected activity, " &
+ "[Expeced idle " & time'image(IdleTime) &
+ ", Actual idle " & time'image(Sig'last_event) & "]"
+ severity error;
+ if Level /= -1 then
+ StdlvCompareInt(Level, Sig, "CheckLastActivityStlv: " & Msg, false, 0, Prefix);
+ end if;
+ end procedure;
+
+ -- *** PulseSig ***
+ procedure PulseSig(signal Sig : out std_logic;
+ signal Clk : in std_logic) is
+ begin
+ wait until rising_edge(Clk);
+ Sig <= '1';
+ wait until rising_edge(Clk);
+ Sig <= '0';
+ end procedure;
+
+ -- *** ClockedWaitFor ***
+ procedure ClockedWaitFor(Val : in std_logic;
+ signal Sig : in std_logic;
+ signal Clk : in std_logic) is
+ begin
+ wait until rising_edge(Clk) and Sig = Val;
+ end procedure;
+
+ -- *** ClockedWaitFor ***
+ procedure WaitClockCycles( Cycles : in integer;
+ signal Clk : in std_logic) is
+ begin
+ for i in 0 to Cycles-1 loop
+ wait until rising_edge(Clk);
+ end loop;
+ end procedure;
+
+ -- *** ClockedWaitTime ***
+ procedure ClockedWaitTime( Duration : in time;
+ signal Clk : in std_logic) is
+ begin
+ wait for Duration;
+ wait until rising_edge(Clk);
+ end procedure;
+
+ -- *** GenerateStrobe ***
+ procedure GenerateStrobe( freq_clock : in real := 100.0E6;
+ freq_str : in real := 1.0E6;
+ rst_pol_g : in std_logic := '1';
+ signal rst : in std_logic;
+ signal clk : in std_logic;
+ signal str : out std_logic) is
+
+ variable count_v : integer range 0 to (integer(ceil(freq_clock/freq_str))) := 0;
+ begin
+ while true loop
+ wait until rising_edge(clk);
+ if rst = rst_pol_g then
+ count_v := 0;
+ str <= '0';
+ else
+ if count_v /= integer(ceil(freq_clock/freq_str)) - 1 then
+ str <= '0';
+ count_v := count_v + 1;
+ else
+ str <= '1';
+ count_v := 0;
+ end if;
+ end if;
+ end loop;
+ end procedure;
+
+ -- *** Wait for Standard logic vector to happen ***
+ procedure WaitForValueStdlv(signal Sig : in std_logic_vector;
+ ExpVal : in std_logic_vector;
+ Timeout : in time;
+ Msg : in string;
+ Prefix : in string := "###ERROR###: ") is
+ begin
+ wait until ExpVal = Sig for timeout;
+ if ExpVal /= Sig then
+ report Prefix & Msg &
+ " Target state not reached" &
+ " [Expected " & str(ExpVal) & "(0x" & hstr(ExpVal) & ")" &
+ ", Received " & str(Sig) & "(0x" & hstr(Sig) & ")" & "]"
+ severity error;
+ end if;
+ end procedure;
+
+ -- *** Wait for Standard logic to happen ***
+ procedure WaitForValueStdl( signal Sig : in std_logic;
+ ExpVal : in std_logic;
+ Timeout : in time;
+ Msg : in string;
+ Prefix : in string := "###ERROR###: ") is
+ begin
+ wait until ExpVal = Sig for timeout;
+ if ExpVal /= Sig then
+ report Prefix & msg &
+ " Target state not reached" &
+ " [Expected " & str(ExpVal) &
+ ", Received " & str(Sig) & "]"
+ severity error;
+ end if;
+ end procedure;
+
+end psi_tb_activity_pkg;
diff --git a/testsuite/gna/issue1051/psi_tb_compare_pkg.vhd b/testsuite/gna/issue1051/psi_tb_compare_pkg.vhd
new file mode 100644
index 000000000..94c9f6d7c
--- /dev/null
+++ b/testsuite/gna/issue1051/psi_tb_compare_pkg.vhd
@@ -0,0 +1,256 @@
+------------------------------------------------------------------------------
+-- Copyright (c) 2018 by Paul Scherrer Institute, Switzerland
+-- All rights reserved.
+-- Authors: Oliver Bruendler, Benoit Stef
+------------------------------------------------------------------------------
+
+------------------------------------------------------------------------------
+-- Libraries
+------------------------------------------------------------------------------
+library ieee;
+ use ieee.std_logic_1164.all;
+ use ieee.numeric_std.all;
+
+library work;
+ use work.psi_tb_txt_util.all;
+
+------------------------------------------------------------------------------
+-- Package Header
+------------------------------------------------------------------------------
+package psi_tb_compare_pkg is
+
+ -- returns an index string in the form "[3]"
+ function IndexString( Index : integer) return string;
+
+ -- std_logic_vector compare to integer
+ procedure StdlvCompareInt ( Expected : in integer;
+ Actual : in std_logic_vector;
+ Msg : in string;
+ IsSigned : in boolean := true;
+ Tolerance : in integer := 0;
+ Prefix : in string := "###ERROR###: ");
+
+ -- std_logic_vector compare to std_logic_vector
+ procedure StdlvCompareStdlv (Expected : in std_logic_vector;
+ Actual : in std_logic_vector;
+ Msg : in string;
+ Prefix : in string := "###ERROR###: ");
+
+ -- std_logic compare std_logic
+ procedure StdlCompare( Expected : in integer range 0 to 1;
+ Actual : in std_logic;
+ Msg : in string;
+ Prefix : in string := "###ERROR###: ");
+
+ -- integer compare to integer
+ procedure IntCompare( Expected : in integer;
+ Actual : in integer;
+ Msg : in string;
+ Tolerance : in integer := 0;
+ Prefix : in string := "###ERROR###: ");
+
+ -- real compare to real
+ procedure RealCompare( Expected : in real;
+ Actual : in real;
+ Msg : in string;
+ Tolerance : in real := 0.0;
+ Prefix : in string := "###ERROR###: ");
+
+ -- signed compare to signed
+ procedure SignCompare ( Expected : in signed;
+ Actual : in signed;
+ Msg : in string;
+ Tolerance : in integer := 0;
+ Prefix : in string := "###ERROR###: ");
+
+ -- unsigned compare to unsigned
+ procedure UsignCompare (Expected : in unsigned;
+ Actual : in unsigned;
+ Msg : in string;
+ Tolerance : in integer := 0;
+ Prefix : in string := "###ERROR###: ");
+
+ -- signed compare to integer
+ procedure SignCompareInt ( Expected : in integer;
+ Actual : in signed;
+ Msg : in string;
+ Tolerance : in integer := 0;
+ Prefix : in string := "###ERROR###: ");
+
+ -- unsigned compare to integer
+ procedure UsignCompareInt ( Expected : in integer;
+ Actual : in unsigned;
+ Msg : in string;
+ Tolerance : in integer := 0;
+ Prefix : in string := "###ERROR###: ");
+
+end psi_tb_compare_pkg;
+
+------------------------------------------------------------------------------
+-- Package Body
+------------------------------------------------------------------------------
+package body psi_tb_compare_pkg is
+
+ -- *** IndexString ***
+ function IndexString( Index : integer) return string is
+ begin
+ return "[" & to_string(Index) & "]";
+ end function;
+
+ -- *** StdlvCompareInt ***
+ procedure StdlvCompareInt ( Expected : in integer;
+ Actual : in std_logic_vector;
+ Msg : in string;
+ IsSigned : in boolean := true;
+ Tolerance : in integer := 0;
+ Prefix : in string := "###ERROR###: ") is
+ variable ActualInt_v : integer;
+ variable ExpectedStdlv32_v : std_logic_vector(31 downto 0);
+ variable ActualStdlv32_v : std_logic_vector(31 downto 0);
+ begin
+ -- Convert Input
+ if IsSigned then
+ ActualInt_v := to_integer(signed(Actual));
+ ExpectedStdlv32_v := std_logic_vector(to_signed(Expected, 32));
+ ActualStdlv32_v := std_logic_vector(to_signed(ActualInt_v, 32));
+ else
+ ActualInt_v := to_integer(unsigned(Actual));
+ ExpectedStdlv32_v := std_logic_vector(to_unsigned(Expected, 32));
+ ActualStdlv32_v := std_logic_vector(to_unsigned(ActualInt_v, 32));
+ end if;
+ -- Assertion
+ assert (ActualInt_v >= Expected-Tolerance) and (ActualInt_v <= Expected+Tolerance)
+ report Prefix & Msg &
+ " [Expected " & integer'image(Expected) & "(0x" & hstr(ExpectedStdlv32_v) & ")" &
+ ", Received " & integer'image(ActualInt_v) & "(0x" & hstr(ActualStdlv32_v) & ")" &
+ ", Tolerance " & integer'image(Tolerance) & "]"
+ severity error;
+ end procedure;
+
+ -- *** StdlvCompareStdlv ***
+ procedure StdlvCompareStdlv ( Expected : in std_logic_vector;
+ Actual : in std_logic_vector;
+ Msg : in string;
+ Prefix : in string := "###ERROR###: ") is
+ constant Expected_c : std_logic_vector(Expected'length-1 downto 0) := Expected;
+ constant Actual_c : std_logic_vector(Actual'length-1 downto 0) := Actual;
+ begin
+ -- Assertion
+ assert Actual_c = Expected_c
+ report Prefix & Msg &
+ " [Expected " & str(Expected_c) & "(0x" & hstr(Expected_c) & ")" &
+ ", Received " & str(Actual_c) & "(0x" & hstr(Actual_c) & ")" & "]"
+ severity error;
+ end procedure;
+
+ -- *** StdlCompare ***
+ procedure StdlCompare( Expected : in integer range 0 to 1;
+ Actual : in std_logic;
+ Msg : in string;
+ Prefix : in string := "###ERROR###: ") is
+ variable ExStdl_v : std_logic;
+ begin
+ if Expected = 0 then
+ ExStdl_v := '0';
+ else
+ ExStdl_v := '1';
+ end if;
+ assert Actual = ExStdl_v
+ report Prefix & Msg &
+ " [Expected " & str(ExStdl_v) &
+ ", Received " & str(Actual) & "]"
+ severity error;
+ end procedure;
+
+ -- *** IntCompare ***
+ procedure IntCompare( Expected : in integer;
+ Actual : in integer;
+ Msg : in string;
+ Tolerance : in integer := 0;
+ Prefix : in string := "###ERROR###: ") is
+ begin
+ assert (Actual >= Expected-Tolerance) and (Actual <= Expected+Tolerance)
+ report Prefix & Msg &
+ " [Expected " & to_string(Expected) &
+ ", Received " & to_string(Actual) &
+ ", Tolerance " & to_string(Tolerance) & "]"
+ severity error;
+ end procedure;
+
+ -- *** RealCompare ***
+ procedure RealCompare( Expected : in real;
+ Actual : in real;
+ Msg : in string;
+ Tolerance : in real := 0.0;
+ Prefix : in string := "###ERROR###: ") is
+ begin
+ assert (Actual >= Expected-Tolerance) and (Actual <= Expected+Tolerance)
+ report Prefix & Msg &
+ " [Expected " & to_string(Expected) &
+ ", Received " & to_string(Actual) &
+ ", Tolerance " & to_string(Tolerance) & "]"
+ severity error;
+ end procedure;
+
+ -- *** SignCompare ***
+ procedure SignCompare( Expected : in signed;
+ Actual : in signed;
+ Msg : in string;
+ Tolerance : in integer := 0;
+ Prefix : in string := "###ERROR###: ") is
+ begin
+ assert (Actual >= Expected-Tolerance) and (Actual <= Expected+Tolerance)
+ report Prefix & Msg &
+ " [Expected " & to_string(Expected) &
+ ", Received " & to_string(Actual) &
+ ", Tolerance " & to_string(Tolerance) & "]"
+ severity error;
+ end procedure;
+
+ -- *** UsignCompare ***
+ procedure UsignCompare( Expected : in unsigned;
+ Actual : in unsigned;
+ Msg : in string;
+ Tolerance : in integer := 0;
+ Prefix : in string := "###ERROR###: ") is
+ begin
+ assert (Actual >= Expected-Tolerance) and (Actual <= Expected+Tolerance)
+ report Prefix & Msg &
+ " [Expected " & to_string(Expected) &
+ ", Received " & to_string(Actual) &
+ ", Tolerance " & to_string(Tolerance) & "]"
+ severity error;
+ end procedure;
+
+ -- *** SignCompareInt ***
+ procedure SignCompareInt ( Expected : in integer;
+ Actual : in signed;
+ Msg : in string;
+ Tolerance : in integer := 0;
+ Prefix : in string := "###ERROR###: ") is
+ begin
+ StdlvCompareInt ( Expected => Expected,
+ Actual => std_logic_vector(Actual),
+ Msg => Msg,
+ IsSigned => true,
+ Tolerance => Tolerance,
+ Prefix => Prefix);
+ end procedure;
+
+ -- *** UsignCompareInt ***
+ procedure UsignCompareInt ( Expected : in integer;
+ Actual : in unsigned;
+ Msg : in string;
+ Tolerance : in integer := 0;
+ Prefix : in string := "###ERROR###: ") is
+ begin
+ StdlvCompareInt ( Expected => Expected,
+ Actual => std_logic_vector(Actual),
+ Msg => Msg,
+ IsSigned => false,
+ Tolerance => Tolerance,
+ Prefix => Prefix);
+ end procedure;
+
+end psi_tb_compare_pkg;
+
diff --git a/testsuite/gna/issue1051/psi_tb_i2c_pkg.vhd b/testsuite/gna/issue1051/psi_tb_i2c_pkg.vhd
new file mode 100644
index 000000000..285cacdf6
--- /dev/null
+++ b/testsuite/gna/issue1051/psi_tb_i2c_pkg.vhd
@@ -0,0 +1,740 @@
+------------------------------------------------------------------------------
+-- Copyright (c) 2019 by Paul Scherrer Institute, Switzerland
+-- All rights reserved.
+-- Authors: Oliver Bruendler
+------------------------------------------------------------------------------
+
+------------------------------------------------------------------------------
+-- Libraries
+------------------------------------------------------------------------------
+library ieee;
+ use ieee.std_logic_1164.all;
+ use ieee.numeric_std.all;
+
+library work;
+ use work.psi_tb_compare_pkg.all;
+ use work.psi_tb_activity_pkg.all;
+ use work.psi_tb_txt_util.all;
+ use work.psi_common_logic_pkg.all;
+ use work.psi_common_math_pkg.all;
+
+------------------------------------------------------------------------------
+-- Package Header
+------------------------------------------------------------------------------
+package psi_tb_i2c_pkg is
+ -- -----------------------------------------------------------------------
+ -- Constants
+ -- -----------------------------------------------------------------------
+ constant I2c_ACK : std_logic := '0';
+ constant I2c_NACK : std_logic := '1';
+
+ type I2c_Transaction_t is (I2c_READ, I2c_WRITE);
+
+ -- -----------------------------------------------------------------------
+ -- Functions
+ -- -----------------------------------------------------------------------
+ function I2cGetAddr( Addr : in integer;
+ Trans : in I2c_Transaction_t) return integer;
+
+ -- -----------------------------------------------------------------------
+ -- Initialization
+ -- -----------------------------------------------------------------------
+ procedure I2cPullup(signal scl : inout std_logic;
+ signal sda : inout std_logic);
+
+ procedure I2cBusFree( signal scl : inout std_logic;
+ signal sda : inout std_logic);
+
+ procedure I2cSetFrequency( frequencyHz : in real);
+
+ -- -----------------------------------------------------------------------
+ -- Master Side Transactions
+ -- -----------------------------------------------------------------------
+ procedure I2cMasterSendStart( signal Scl : inout std_logic;
+ signal Sda : inout std_logic;
+ Msg : in string := "No Msg";
+ Prefix : in string := "###ERROR###: ");
+
+ procedure I2cMasterSendRepeatedStart( signal Scl : inout std_logic;
+ signal Sda : inout std_logic;
+ Msg : in string := "No Msg";
+ Prefix : in string := "###ERROR###: ");
+
+ procedure I2cMasterSendStop( signal Scl : inout std_logic;
+ signal Sda : inout std_logic;
+ Msg : in string := "No Msg";
+ Prefix : in string := "###ERROR###: ");
+
+ procedure I2cMasterSendAddr( Address : in integer;
+ IsRead : in boolean;
+ signal Scl : inout std_logic;
+ signal Sda : inout std_logic;
+ Msg : in string := "No Msg";
+ AddrBits : in integer := 7; -- 7 or 10
+ ExpectedAck : in std_logic := '0'; -- '0' for ack, '1' for nack, anything else for "don't check"
+ Prefix : in string := "###ERROR###: ");
+
+ procedure I2cMasterSendByte( Data : in integer range -128 to 255;
+ signal Scl : inout std_logic;
+ signal Sda : inout std_logic;
+ Msg : in string := "No Msg";
+ ExpectedAck : in std_logic := '0'; -- '0' for ack, '1' for nack, anything else for "don't check"
+ Prefix : in string := "###ERROR###: ");
+
+ procedure I2cMasterExpectByte( ExpData : in integer range -128 to 255;
+ signal Scl : inout std_logic;
+ signal Sda : inout std_logic;
+ Msg : in string := "No Msg";
+ AckOutput : in std_logic := '0'; -- '0' for ack, '1' for nack
+ Prefix : in string := "###ERROR###: ");
+
+ -- -----------------------------------------------------------------------
+ -- Slave Side Transactions
+ -- -----------------------------------------------------------------------
+ procedure I2cSlaveWaitStart( signal Scl : inout std_logic;
+ signal Sda : inout std_logic;
+ Msg : in string := "No Msg";
+ Timeout : in time := 1 ms;
+ Prefix : in string := "###ERROR###: ");
+
+ procedure I2cSlaveWaitRepeatedStart( signal Scl : inout std_logic;
+ signal Sda : inout std_logic;
+ Msg : in string := "No Msg";
+ Timeout : in time := 1 ms;
+ ClkStretch : in time := 0 ns; -- hold clock-low for at least this time
+ Prefix : in string := "###ERROR###: ");
+
+ procedure I2cSlaveWaitStop( signal Scl : inout std_logic;
+ signal Sda : inout std_logic;
+ Msg : in string := "No Msg";
+ Timeout : in time := 1 ms;
+ ClkStretch : in time := 0 ns; -- hold clock-low for at least this time
+ Prefix : in string := "###ERROR###: ");
+
+ procedure I2cSlaveExpectAddr( Address : in integer;
+ IsRead : in boolean;
+ signal Scl : inout std_logic;
+ signal Sda : inout std_logic;
+ Msg : in string := "No Msg";
+ AddrBits : in integer := 7; -- 7 or 10
+ AckOutput : in std_logic := '0'; -- '0' for ack, '1' for nack
+ Timeout : in time := 1 ms;
+ ClkStretch : in time := 0 ns; -- hold clock-low for at least this time
+ Prefix : in string := "###ERROR###: ");
+
+ procedure I2cSlaveExpectByte( ExpData : in integer range -128 to 255;
+ signal Scl : inout std_logic;
+ signal Sda : inout std_logic;
+ Msg : in string := "No Msg";
+ AckOutput : in std_logic := '0'; -- '0' for ack, '1' for nack
+ Timeout : in time := 1 ms;
+ ClkStretch : in time := 0 ns; -- hold clock-low for at least this time
+ Prefix : in string := "###ERROR###: ");
+
+ procedure I2cSlaveSendByte( Data : in integer range -128 to 255;
+ signal Scl : inout std_logic;
+ signal Sda : inout std_logic;
+ Msg : in string := "No Msg";
+ ExpectedAck : in std_logic := '0'; -- '0' for ack, '1' for nack, anything else for "don't check"
+ Timeout : in time := 1 ms;
+ ClkStretch : in time := 0 ns; -- hold clock-low for at least this time
+ Prefix : in string := "###ERROR###: ");
+
+end psi_tb_i2c_pkg;
+
+------------------------------------------------------------------------------
+-- Package Body
+------------------------------------------------------------------------------
+package body psi_tb_i2c_pkg is
+
+ -- -----------------------------------------------------------------------
+ -- Local Types
+ -- -----------------------------------------------------------------------
+ type MsgInfo_r is record
+ Prefix : string;
+ Func : string;
+ User : string;
+ end record;
+
+ -- -----------------------------------------------------------------------
+ -- Local Variables
+ -- -----------------------------------------------------------------------
+ shared variable FreqClk_v : real := 100.0e3;
+
+ -- -----------------------------------------------------------------------
+ -- Private Procedures
+ -- -----------------------------------------------------------------------
+ -- *** Message Handling ***
+ function GenMessage( Prefix : in string;
+ Func : in string;
+ General : in string;
+ User : in string)
+ return string is
+ begin
+ return Prefix & "- " & Func & " - " & General & " - " & User;
+ end function;
+
+ function GenMessageNoPrefix( Func : in string;
+ General : in string;
+ User : in string)
+ return string is
+ begin
+ return Func & " - " & General & " - " & User;
+ end function;
+
+ -- *** Level Check ***
+ procedure LevelCheck( Expected : in std_logic;
+ signal Sig : in std_logic;
+ Msg : in MsgInfo_r;
+ GeneralMsg : in string) is
+ begin
+ -- Do not check for other inputs than 1 or 0
+ if (Expected = '0') or (Expected = '1') then
+ assert ((Expected = '0') and (Sig = '0')) or ((Expected = '1') and ((Sig = '1') or (Sig = 'H')))
+ report GenMessage(Msg.Prefix, Msg.Func, GeneralMsg, Msg.User)
+ severity error;
+ end if;
+ end procedure;
+
+ procedure LevelWait( Expected : in std_logic;
+ signal Sig : in std_logic;
+ Timeout : in time;
+ Msg : in MsgInfo_r;
+ GeneralMsg : in string) is
+ variable Correct_v : boolean;
+ begin
+ if Sig /= Expected then
+ if Expected = '0' then
+ wait until Sig = '0' for Timeout;
+ Correct_v := (Sig = '0');
+ else
+ wait until (Sig = '1') or (Sig = 'H') for Timeout;
+ Correct_v := ((Sig = '1') or (Sig = 'H'));
+ end if;
+ assert Correct_v
+ report GenMessage(Msg.Prefix, Msg.Func, GeneralMsg, Msg.User)
+ severity error;
+ end if;
+ end procedure;
+
+
+ -- *** Time Calculations ***
+ impure function ClkPeriod return time is
+ begin
+ return (1 sec) / FreqClk_v;
+ end function;
+
+ impure function ClkHalfPeriod return time is
+ begin
+ return (0.5 sec) / FreqClk_v;
+ end function;
+
+ impure function ClkQuartPeriod return time is
+ begin
+ return (0.25 sec) / FreqClk_v;
+ end function;
+
+ -- *** Bit Transfers ***
+ procedure SendBitInclClock( Data : in std_logic;
+ signal Scl : inout std_logic;
+ signal Sda : inout std_logic;
+ BitInfo : in string;
+ Msg : in MsgInfo_r) is
+ begin
+ -- Initial Check
+ LevelCheck('0', Scl, Msg, "SCL must be 0 before SendBitInclClock is called [" & BitInfo & "]");
+
+ -- Assert Data
+ if Data = '0' then
+ Sda <= '0';
+ else
+ Sda <= 'Z';
+ end if;
+ wait for ClkQuartPeriod;
+
+ -- Send Clk Pulse
+ Scl <= 'Z';
+ LevelWait('1', Scl, 1 ms, Msg, "SCL held low by other device");
+ wait for ClkHalfPeriod;
+ CheckLastActivity(Scl, ClkHalfPeriod*0.9, -1, GenMessageNoPrefix(Msg.Func, "SCL high period too short [" & BitInfo & "]", Msg.User), Msg.Prefix);
+ LevelCheck(Data, Sda, Msg, "SDA readback does not match SDA transmit value during SCL pulse [" & BitInfo & "]");
+ CheckLastActivity(Sda, ClkHalfPeriod, -1, GenMessageNoPrefix(Msg.Func, "SDA not stable during SCL pulse [" & BitInfo & "]", Msg.User), Msg.Prefix);
+ Scl <= '0';
+ wait for ClkQuartPeriod;
+ end procedure;
+
+ procedure CheckBitInclClock( Data : in std_logic;
+ signal Scl : inout std_logic;
+ signal Sda : inout std_logic;
+ BitInfo : in string;
+ Msg : in MsgInfo_r) is
+ begin
+ -- Initial Check
+ LevelCheck('0', Scl, Msg, "SCL must be 0 before CheckBitInclClock is called");
+
+ -- Wait for assertion
+ wait for ClkQuartPeriod;
+
+ -- Send Clk Pulse
+ Scl <= 'Z';
+ LevelWait('1', Scl, 1 ms, Msg, "SCL held low by other device");
+ wait for ClkHalfPeriod;
+ CheckLastActivity(Scl, ClkHalfPeriod*0.9, -1, GenMessageNoPrefix(Msg.Func, "SCL high period too short [" & BitInfo & "]", Msg.User), Msg.Prefix);
+ LevelCheck(Data, Sda, Msg, "Received wrong data [" & BitInfo & "]");
+ CheckLastActivity(Sda, ClkHalfPeriod, -1, GenMessageNoPrefix(Msg.Func, "SDA not stable during SCL pulse [" & BitInfo & "]", Msg.User), Msg.Prefix);
+ Scl <= '0';
+ wait for ClkQuartPeriod;
+ end procedure;
+
+ procedure SendBitExclClock( Data : in std_logic;
+ signal Scl : inout std_logic;
+ signal Sda : inout std_logic;
+ Timeout : in time;
+ BitInfo : in string;
+ Msg : in MsgInfo_r;
+ ClockStretch : in time) is
+ variable Stretched_v : boolean := false;
+ begin
+ -- Initial Check
+ LevelCheck('0', Scl, Msg, "SCL must be 0 before SendBitExclClock is called");
+
+ -- Clock stretching
+ if ClockStretch > 0 ns then
+ Scl <= '0';
+ wait for ClockStretch;
+ Stretched_v := true;
+ end if;
+
+ -- Assert Data
+ if Data = '0' then
+ Sda <= '0';
+ else
+ Sda <= 'Z';
+ end if;
+ if Stretched_v then
+ wait for ClkQuartPeriod;
+ Scl <= 'Z';
+ end if;
+
+ -- Wait clock rising edge
+ LevelWait('1', Scl, Timeout, Msg, "SCL did not go high");
+
+ -- wait clock falling edge
+ LevelWait('0', Scl, Timeout, Msg, "SCL did not go low");
+ LevelCheck(Data, Sda, Msg, "Received wrong data [" & BitInfo & "]");
+ CheckLastActivity(Sda, ClkHalfPeriod, -1, GenMessageNoPrefix(Msg.Func, "SDA not stable during SCL pulse [" & BitInfo & "]", Msg.User), Msg.Prefix);
+
+ -- wait until center of low
+ wait for ClkQuartPeriod;
+ end procedure;
+
+ procedure CheckBitExclClock( Data : in std_logic;
+ signal Scl : inout std_logic;
+ signal Sda : inout std_logic;
+ Timeout : in time;
+ BitInfo : in string;
+ Msg : in MsgInfo_r;
+ ClockStretch : in time) is
+ begin
+ -- Initial Check
+ LevelCheck('0', Scl, Msg, "SCL must be 0 before CheckBitExclClock is called");
+
+ -- Wait clock rising edge
+ if ClockStretch > 0 ns then
+ Scl <= '0';
+ wait for ClockStretch;
+ Scl <= 'Z';
+ end if;
+ LevelWait('1', Scl, Timeout, Msg, "SCL did not go high");
+
+ -- wait clock falling edge
+ LevelWait('0', Scl, Timeout, Msg, "SCL did not go low");
+ LevelCheck(Data, Sda, Msg, "Received wrong data [" & BitInfo & "]");
+ CheckLastActivity(Sda, ClkHalfPeriod, -1, GenMessageNoPrefix(Msg.Func, "SDA not stable during SCL pulse [" & BitInfo & "]", Msg.User), Msg.Prefix);
+
+ -- wait until center of low
+ wait for ClkQuartPeriod;
+ end procedure;
+
+
+ -- *** Byte Transfers ***
+ procedure SendByteInclClock( Data : in std_logic_vector(7 downto 0);
+ signal Scl : inout std_logic;
+ signal Sda : inout std_logic;
+ Msg : in MsgInfo_r) is
+ begin
+ -- Do bits
+ for i in 7 downto 0 loop
+ SendBitInclClock(Data(i), Scl, Sda, to_string(i), Msg);
+ end loop;
+ end procedure;
+
+
+
+ procedure ExpectByteExclClock( ExpData : in std_logic_vector(7 downto 0);
+ signal Scl : inout std_logic;
+ signal Sda : inout std_logic;
+ Msg : in MsgInfo_r;
+ Timeout : in time;
+ ClkStretch : in time) is
+ begin
+ -- Do bits
+ for i in 7 downto 0 loop
+ CheckBitExclClock(ExpData(i), Scl, Sda, Timeout, to_string(i), Msg, ClkStretch);
+ end loop;
+ end procedure;
+
+ -- -----------------------------------------------------------------------
+ -- Functions
+ -- -----------------------------------------------------------------------
+ function I2cGetAddr( Addr : in integer;
+ Trans : in I2c_Transaction_t) return integer is
+ begin
+ return Addr*2+choose(Trans=I2c_READ, 1, 0);
+ end function;
+
+ -- -----------------------------------------------------------------------
+ -- Master Side Transactions
+ -- -----------------------------------------------------------------------
+ procedure I2cPullup(signal Scl : inout std_logic;
+ signal Sda : inout std_logic) is
+ begin
+ Scl <= 'H';
+ Sda <= 'H';
+ end procedure;
+
+ procedure I2cBusFree( signal Scl : inout std_logic;
+ signal Sda : inout std_logic) is
+ begin
+ Scl <= 'Z';
+ Sda <= 'Z';
+ end procedure;
+
+ procedure I2cSetFrequency( FrequencyHz : in real) is
+ begin
+ FreqClk_v := FrequencyHz;
+ end procedure;
+
+ procedure I2cMasterSendStart( signal Scl : inout std_logic;
+ signal Sda : inout std_logic;
+ Msg : in string := "No Msg";
+ Prefix : in string := "###ERROR###: ") is
+ constant MsgInfo : MsgInfo_r := (Prefix, "I2cMasterSendStart", Msg);
+ begin
+ -- Initial check
+ LevelCheck('1', Scl, MsgInfo, "SCL must be 1 before procedure is called");
+ LevelCheck('1', Sda, MsgInfo, "SDA must be 1 before procedure is called");
+
+ -- Do start condition
+ wait for ClkQuartPeriod;
+ Sda <= '0';
+ LevelCheck('1', Scl, MsgInfo, "SCL must be 1 during SDA falling edge");
+ wait for ClkQuartPeriod;
+
+ -- Go to center of clk low period
+ Scl <= '0';
+ wait for ClkQuartPeriod;
+ end procedure;
+
+ procedure I2cMasterSendRepeatedStart( signal Scl : inout std_logic;
+ signal Sda : inout std_logic;
+ Msg : in string := "No Msg";
+ Prefix : in string := "###ERROR###: ") is
+ constant MsgInfo : MsgInfo_r := (Prefix, "I2cMasterSendRepeatedStart", Msg);
+ begin
+ -- Initial check
+ if to01X(Scl) = '1' then
+ LevelCheck('1', Sda, MsgInfo, "SDA must be 1 before procedure is called if SCL = 1");
+ end if;
+
+ -- Do repeated start
+ if Scl = '0' then
+ Sda <= 'Z';
+ wait for ClkQuartPeriod;
+ LevelCheck('1', Sda, MsgInfo, "SDA held low by other device");
+ Scl <= 'Z';
+ wait for ClkQuartPeriod;
+ LevelCheck('1', Scl, MsgInfo, "SCL held low by other device");
+ end if;
+ wait for ClkQuartPeriod;
+ Sda <= '0';
+ LevelCheck('1', Scl, MsgInfo, "SCL must be 1 during SDA falling edge");
+ wait for ClkQuartPeriod;
+
+ -- Go to center of clk low period
+ Scl <= '0';
+ wait for ClkQuartPeriod;
+ end procedure;
+
+ procedure I2cMasterSendStop( signal Scl : inout std_logic;
+ signal Sda : inout std_logic;
+ Msg : in string := "No Msg";
+ Prefix : in string := "###ERROR###: ") is
+ constant MsgInfo : MsgInfo_r := (Prefix, "I2cMasterSendStop", Msg);
+ begin
+ -- Initial check
+ if to01X(Scl) = '1' then
+ LevelCheck('0', Sda, MsgInfo, "SDA must be 0 before procedure is called if SCL = 1");
+ end if;
+
+ -- Do stop
+ if Scl = '0' then
+ Sda <= '0';
+ wait for ClkQuartPeriod;
+ Scl <= 'Z';
+ wait for ClkQuartPeriod;
+ LevelCheck('1', Scl, MsgInfo, "SCL held low by other device");
+ else
+ wait for ClkQuartPeriod;
+ end if;
+ Sda <= 'Z';
+ LevelCheck('1', Scl, MsgInfo, "SCL must be 1 during SDA rising edge");
+
+ -- Go to center of clk high period
+ wait for ClkQuartPeriod;
+
+ end procedure;
+
+ procedure I2cMasterSendAddr( Address : in integer;
+ IsRead : in boolean;
+ signal Scl : inout std_logic;
+ signal Sda : inout std_logic;
+ Msg : in string := "No Msg";
+ AddrBits : in integer := 7; -- 7 or 10
+ ExpectedAck : in std_logic := '0'; -- '0' for ack, '1' for nack, anything else for "don't check"
+ Prefix : in string := "###ERROR###: ") is
+ constant AddrSlv_c : std_logic_vector(9 downto 0) := std_logic_vector(to_unsigned(Address, 10));
+ constant Rw_c : std_logic := choose(IsRead, '1', '0');
+ begin
+ -- 7 Bit addressing
+ if AddrBits = 7 then
+ SendByteInclClock(AddrSlv_c(6 downto 0) & Rw_c, Scl, Sda, (Prefix, "I2cMasterSendAddr 7b", Msg));
+ Sda <= 'Z';
+ CheckBitInclClock(ExpectedAck, Scl, Sda, "ACK", (Prefix, "I2cMasterSendAddr 7b", Msg));
+ -- 10 Bit addressing
+ elsif AddrBits = 10 then
+ SendByteInclClock("11110" & AddrSlv_c(9 downto 8) & Rw_c, Scl, Sda, (Prefix, "I2cMasterSendAddr 10b 9:8", Msg));
+ Sda <= 'Z';
+ CheckBitInclClock(ExpectedAck, Scl, Sda, "ACK", (Prefix, "I2cMasterSendAddr 10b 9:8", Msg));
+ SendByteInclClock(AddrSlv_c(7 downto 0), Scl, Sda, (Prefix, "I2cMasterSendAddr 10b 7:0", Msg));
+ Sda <= 'Z';
+ CheckBitInclClock(ExpectedAck, Scl, Sda, "ACK", (Prefix, "I2cMasterSendAddr 10b 7:0", Msg));
+ else
+ report Prefix & "I2cMasterSendAddr - Illegal addrBits (must be 7 or 10) - " & Msg severity error;
+ end if;
+ end procedure;
+
+ procedure I2cMasterSendByte( Data : in integer range -128 to 255;
+ signal Scl : inout std_logic;
+ signal Sda : inout std_logic;
+ Msg : in string := "No Msg";
+ ExpectedAck : in std_logic := '0'; -- '0' for ack, '1' for nack, anything else for "don't check"
+ Prefix : in string := "###ERROR###: ") is
+ variable DataSlv_v : std_logic_vector(7 downto 0);
+ begin
+ -- Do data
+ if Data < 0 then
+ DataSlv_v := std_logic_vector(to_signed(Data, 8));
+ else
+ DataSlv_v := std_logic_vector(to_unsigned(Data, 8));
+ end if;
+ SendByteInclClock(DataSlv_v, Scl, Sda, (Prefix, "I2cMasterSendByte", Msg));
+ Sda <= 'Z';
+ CheckBitInclClock(ExpectedAck, Scl, Sda, "ACK", (Prefix, "I2cMasterSendByte", Msg));
+ end procedure;
+
+
+ procedure I2cMasterExpectByte( ExpData : in integer range -128 to 255;
+ signal Scl : inout std_logic;
+ signal Sda : inout std_logic;
+ Msg : in string := "No Msg";
+ AckOutput : in std_logic := '0'; -- '0' for ack, '1' for nack
+ Prefix : in string := "###ERROR###: ") is
+ variable Data_v : std_logic_vector(7 downto 0);
+ begin
+ -- Convert data
+ if ExpData < 0 then
+ Data_v := std_logic_vector(to_signed(ExpData, 8));
+ else
+ Data_v := std_logic_vector(to_unsigned(ExpData, 8));
+ end if;
+
+ -- do bits
+ Sda <= 'Z';
+ for i in 7 downto 0 loop
+ CheckBitInclClock(Data_v(i), Scl, Sda, to_string(i), (Prefix, "I2cMasterExpectByte", Msg));
+ end loop;
+ SendBitInclClock(AckOutput, Scl, Sda, "ACK", (Prefix, "I2cMasterExpectByte", Msg));
+ end procedure;
+
+ -- -----------------------------------------------------------------------
+ -- Slave Side Transactions
+ -- -----------------------------------------------------------------------
+ procedure I2cSlaveWaitStart( signal Scl : inout std_logic;
+ signal Sda : inout std_logic;
+ Msg : in string := "No Msg";
+ Timeout : in time := 1 ms;
+ Prefix : in string := "###ERROR###: ") is
+ constant MsgInfo : MsgInfo_r := (Prefix, "I2cSlaveWaitStart", Msg);
+ begin
+ -- Initial check
+ LevelCheck('1', Scl, MsgInfo, "SCL must be 1 before procedure is called");
+ LevelCheck('1', Sda, MsgInfo, "SDA must be 1 before procedure is called");
+
+ -- Do start checking
+ LevelWait('0', Sda, Timeout, MsgInfo, "SDA did not go low");
+ LevelCheck('1', Scl, MsgInfo, "SCL must be 1 during SDA falling edge");
+ LevelWait('0', Scl, Timeout, MsgInfo, "SCL did not go low");
+ LevelCheck('0', Sda, MsgInfo, "SDA must be 0 during SCL falling edge");
+
+ -- Wait for center of SCL low
+ wait for ClkQuartPeriod;
+ end procedure;
+
+ procedure I2cSlaveWaitRepeatedStart( signal Scl : inout std_logic;
+ signal Sda : inout std_logic;
+ Msg : in string := "No Msg";
+ Timeout : in time := 1 ms;
+ ClkStretch : in time := 0 ns; -- hold clock-low for at least this time
+ Prefix : in string := "###ERROR###: ") is
+ constant MsgInfo : MsgInfo_r := (Prefix, "I2cSlaveWaitRepeatedStart", Msg);
+ begin
+ -- Initial Check
+ if to01X(Scl) = '1' then
+ LevelCheck('1', Sda, MsgInfo, "SDA must be 1 before procedure is called if SCL = 1");
+ end if;
+
+ -- Do Check
+ if to01X(Scl) = '0' then
+ -- Clock stretching
+ if ClkStretch > 0 ns then
+ Scl <= '0';
+ wait for ClkStretch;
+ Scl <= 'Z';
+ end if;
+ LevelWait('1', Scl, Timeout, MsgInfo, "SCL did not go high");
+ LevelCheck('1', Sda, MsgInfo, "SDA must be 1 before SCL goes high");
+ end if;
+ LevelWait('0', Sda, Timeout, MsgInfo, "SDA did not go low");
+ LevelCheck('1', Scl, MsgInfo, "SCL must be 1 during SDA falling edge");
+ LevelWait('0', Scl, Timeout, MsgInfo, "SCL did not go low");
+ LevelCheck('0', Sda, MsgInfo, "SDA must be 0 during SCL falling edge");
+
+ -- Wait for center of SCL low
+ wait for ClkQuartPeriod;
+ end procedure;
+
+ procedure I2cSlaveWaitStop( signal Scl : inout std_logic;
+ signal Sda : inout std_logic;
+ Msg : in string := "No Msg";
+ Timeout : in time := 1 ms;
+ ClkStretch : in time := 0 ns; -- hold clock-low for at least this time
+ Prefix : in string := "###ERROR###: ") is
+ constant MsgInfo : MsgInfo_r := (Prefix, "I2cSlaveWaitStop", Msg);
+ begin
+ -- Initial check
+ if to01X(Scl) = '1' then
+ LevelCheck('0', Sda, MsgInfo, "SDA must be 0 before procedure is called if SCL = 1");
+ end if;
+
+ -- Do Check
+ if Scl = '0' then
+ -- Clock stretching
+ if ClkStretch > 0 ns then
+ Scl <= '0';
+ wait for ClkStretch;
+ Scl <= 'Z';
+ end if;
+ LevelWait('1', Scl, Timeout, MsgInfo, "SCL did not go high");
+ LevelCheck('0', Sda, MsgInfo, "SDA must be 0 before SCL goes high");
+ end if;
+ LevelWait('1', Sda, Timeout, MsgInfo, "SDA did not go high");
+ LevelCheck('1', Scl, MsgInfo, "SCL must be 1 during SDA rising edge");
+
+ -- Wait for center of SCL low
+ wait for ClkQuartPeriod;
+ end procedure;
+
+ procedure I2cSlaveExpectAddr( Address : in integer;
+ IsRead : in boolean;
+ signal Scl : inout std_logic;
+ signal Sda : inout std_logic;
+ Msg : in string := "No Msg";
+ AddrBits : in integer := 7; -- 7 or 10
+ AckOutput : in std_logic := '0'; -- '0' for ack, '1' for nack
+ Timeout : in time := 1 ms;
+ ClkStretch : in time := 0 ns; -- hold clock-low for at least this time
+ Prefix : in string := "###ERROR###: ") is
+ constant AddrSlv_c : std_logic_vector(9 downto 0) := std_logic_vector(to_unsigned(Address, 10));
+ constant Rw_c : std_logic := choose(IsRead, '1', '0');
+ begin
+ -- 7 Bit addressing
+ if AddrBits = 7 then
+ ExpectByteExclClock(AddrSlv_c(6 downto 0) & Rw_c, Scl, Sda, (Prefix, "I2cSlaveExpectAddr 7b", Msg), Timeout, ClkStretch);
+ SendBitExclClock(AckOutput, Scl, Sda, Timeout, "ACK", (Prefix, "I2cSlaveExpectAddr 7b ack", Msg), ClkStretch);
+ I2cBusFree(Scl, Sda);
+ -- 10 Bit addressing
+ elsif AddrBits = 10 then
+ ExpectByteExclClock("11110" & AddrSlv_c(9 downto 8) & Rw_c, Scl, Sda, (Prefix, "I2cSlaveExpectAddr 10b 9:8" , Msg), Timeout, ClkStretch);
+ SendBitExclClock(AckOutput, Scl, Sda, Timeout, "ACK", (Prefix, "I2cSlaveExpectAddr 10b 9:8 ack", Msg), ClkStretch);
+ I2cBusFree(Scl, Sda);
+ ExpectByteExclClock(AddrSlv_c(7 downto 0), Scl, Sda, (Prefix, "I2cSlaveExpectAddr 10b 7:0", Msg), Timeout, ClkStretch);
+ SendBitExclClock(AckOutput, Scl, Sda, Timeout, "ACK", (Prefix, "I2cSlaveExpectAddr 10b 7:0 ack", Msg), ClkStretch);
+ I2cBusFree(Scl, Sda);
+ else
+ report Prefix & "I2cSlaveExpectAddr - Illegal addrBits (must be 7 or 10) - " & Msg severity error;
+ end if;
+ end procedure;
+
+ procedure I2cSlaveExpectByte( ExpData : in integer range -128 to 255;
+ signal Scl : inout std_logic;
+ signal Sda : inout std_logic;
+ Msg : in string := "No Msg";
+ AckOutput : in std_logic := '0'; -- '0' for ack, '1' for nack
+ Timeout : in time := 1 ms;
+ ClkStretch : in time := 0 ns; -- hold clock-low for at least this time
+ Prefix : in string := "###ERROR###: ") is
+ variable Data_v : std_logic_vector(7 downto 0);
+ begin
+ if ExpData < 0 then
+ Data_v := std_logic_vector(to_signed(ExpData, 8));
+ else
+ Data_v := std_logic_vector(to_unsigned(ExpData, 8));
+ end if;
+ ExpectByteExclClock(Data_v, Scl, Sda, (Prefix, "I2cSlaveExpectByte", Msg), Timeout, ClkStretch);
+ SendBitExclClock(AckOutput, Scl, Sda, Timeout, "ACK", (Prefix, "I2cSlaveExpectByte ack", Msg), ClkStretch);
+ I2cBusFree(Scl, Sda);
+ end procedure;
+
+
+ procedure I2cSlaveSendByte( Data : in integer range -128 to 255;
+ signal Scl : inout std_logic;
+ signal Sda : inout std_logic;
+ Msg : in string := "No Msg";
+ ExpectedAck : in std_logic := '0'; -- '0' for ack, '1' for nack, anything else for "don't check"
+ Timeout : in time := 1 ms;
+ ClkStretch : in time := 0 ns; -- hold clock-low for at least this time
+ Prefix : in string := "###ERROR###: ") is
+ variable Data_v : std_logic_vector(7 downto 0);
+ begin
+ -- Convert Data
+ if Data < 0 then
+ Data_v := std_logic_vector(to_signed(Data, 8));
+ else
+ Data_v := std_logic_vector(to_unsigned(Data, 8));
+ end if;
+
+ -- Send data
+ for i in 7 downto 0 loop
+ SendBitExclClock(Data_v(i), Scl, Sda, Timeout, to_string(i), (Prefix, "I2cSlaveSendByte", Msg), ClkStretch);
+ end loop;
+
+ -- Check ack
+ I2cBusFree(Scl, Sda);
+ CheckBitExclClock(ExpectedAck, Scl, Sda, Timeout, "ACK", (Prefix, "I2cSlaveSendByte", Msg), ClkStretch);
+
+ end procedure;
+
+
+end psi_tb_i2c_pkg;
+
diff --git a/testsuite/gna/issue1051/psi_tb_txt_util.vhd b/testsuite/gna/issue1051/psi_tb_txt_util.vhd
new file mode 100644
index 000000000..626b7373b
--- /dev/null
+++ b/testsuite/gna/issue1051/psi_tb_txt_util.vhd
@@ -0,0 +1,583 @@
+------------------------------------------------------------------------------
+---- ----
+---- Text Utils ----
+---- ----
+---- http://www.opencores.org/ ----
+---- ----
+---- Description: ----
+---- Utils to handle text. Used for the testbenches. ----
+---- ----
+---- To Do: ----
+---- - ----
+---- ----
+---- Authors: ----
+---- - Oyvind Harboe, oyvind.harboe zylin.com ----
+---- - Oliver Bründler, Paul Scherrer Instititute ----
+---- ----
+------------------------------------------------------------------------------
+---- ----
+---- Copyright (c) 2008 Oyvind Harboe <oyvind.harboe zylin.com> ----
+---- Copyright (c) Paul Scherrer Institute (www.psi.ch) ----
+---- ----
+---- Distributed under the BSD license ----
+---- ----
+------------------------------------------------------------------------------
+---- ----
+---- Design unit: txt_util (Package) ----
+---- File name: txt_util.vhdl ----
+---- Note: None ----
+---- Limitations: None known ----
+---- Errors: None known ----
+---- Library: zpu ----
+---- Dependencies: IEEE.std_logic_1164 ----
+---- IEEE.numeric_std ----
+---- std.textio ----
+---- Target FPGA: N/A ----
+---- Language: VHDL ----
+---- Wishbone: No ----
+---- Synthesis tools: Xilinx Release 9.2.03i - xst J.39 ----
+---- Simulation tools: GHDL [Sokcho edition] (0.2x) ----
+---- Text editor: SETEdit 0.5.x ----
+---- ----
+------------------------------------------------------------------------------
+
+library IEEE;
+use IEEE.std_logic_1164.all;
+use IEEE.numeric_std.all;
+
+use std.textio.all;
+
+-- library zpu;
+
+package psi_tb_txt_util is
+ -- prints a message to the screen
+ procedure print(text: string);
+
+ -- prints the message when active
+ -- useful for debug switches
+ procedure print(active: boolean; text: string);
+
+ -- converts std_logic into a character
+ function chr(sl: std_logic) return character;
+
+ -- converts std_logic into a string (1 to 1)
+ function str(sl: std_logic) return string;
+
+ -- converts std_logic_vector into a string (binary base)
+ function str(slv: std_logic_vector) return string;
+
+ -- converts boolean into a string
+ function str(b: boolean) return string;
+
+ -- converts an integer into a single character
+ -- (can also be used for hex conversion and other bases)
+ function chr(int: integer) return character;
+
+ -- converts integer into string using specified base
+ function str(int: integer; base: integer) return string;
+
+ -- converts integer to string, using base 10
+ function str(int: integer) return string;
+
+ -- convert std_logic_vector into a string in hex format
+ function hstr(slv: std_logic_vector) return string;
+ function hstr(slv: unsigned) return string;
+
+ -- convert integer to string, VHDL2008 built-in equivalent
+ function to_string(int : integer) return string;
+
+ -- convert real to string, VHDL2008 built-in equivalent
+ function to_string(num : real) return string;
+
+ -- convert signed to string, VHDL2008 built-in equivalent
+ function to_string(num : signed) return string;
+
+ -- convert unsigned to string, VHDL2008 built-in equivalent
+ function to_string(num : unsigned) return string;
+
+ -- convert std_logic_vector to string, VHDL2008 built-in equivalent
+ function to_string(num : std_logic_vector) return string;
+
+
+ -- functions to manipulate strings
+ -----------------------------------
+
+ -- convert a character to upper case
+ function to_upper(c: character) return character;
+
+ -- convert a character to lower case
+ function to_lower(c: character) return character;
+
+ -- convert a string to upper case
+ function to_upper(s: string) return string;
+
+ -- convert a string to lower case
+ function to_lower(s: string) return string;
+
+
+
+ -- functions to convert strings into other formats
+ --------------------------------------------------
+
+ -- converts a character into std_logic
+ function to_std_logic(c: character) return std_logic;
+
+ -- converts a string into std_logic_vector
+ function to_std_logic_vector(s: string) return std_logic_vector;
+
+
+
+ -- file I/O
+ -----------
+
+ -- read variable length string from input file
+ procedure str_read(file in_file: TEXT;
+ res_string: out string);
+
+ procedure str_write(file out_file: TEXT;
+ new_string: in string);
+
+ -- print string to a file and start new line
+ procedure print(file out_file: TEXT;
+ new_string: in string);
+
+ -- print character to a file and start new line
+ procedure print(file out_file: TEXT;
+ char: in character);
+end package psi_tb_txt_util;
+
+
+
+
+package body psi_tb_txt_util is
+ -- prints text to the screen
+ procedure print(text: string) is
+ variable msg_line: line;
+ begin
+ --synopsys translate off
+ write(msg_line, text);
+ writeline(output, msg_line);
+ --synopsys translate on
+ end procedure print;
+
+ -- prints text to the screen when active
+ procedure print(active: boolean; text: string) is
+ begin
+ if active then
+ print(text);
+ end if;
+ end procedure print;
+
+ -- converts std_logic into a character
+ function chr(sl: std_logic) return character is
+ variable c: character;
+ begin
+ case sl is
+ when 'U' => c:= 'U';
+ when 'X' => c:= 'X';
+ when '0' => c:= '0';
+ when '1' => c:= '1';
+ when 'Z' => c:= 'Z';
+ when 'W' => c:= 'W';
+ when 'L' => c:= 'L';
+ when 'H' => c:= 'H';
+ when '-' => c:= '-';
+ end case;
+ return c;
+ end function chr;
+
+ -- converts std_logic into a string (1 to 1)
+ function str(sl: std_logic) return string is
+ variable s: string(1 to 1);
+ begin
+ s(1):=chr(sl);
+ return s;
+ end function str;
+
+ -- converts std_logic_vector into a string (binary base)
+ -- (this also takes care of the fact that the range of
+ -- a string is natural while a std_logic_vector may
+ -- have an integer range)
+ function str(slv: std_logic_vector) return string is
+ variable result : string (1 to slv'length);
+ variable r : integer;
+ begin
+ r:=1;
+ for i in slv'range loop
+ result(r) := chr(slv(i));
+ r:=r+1;
+ end loop;
+ return result;
+ end function str;
+
+
+ function str(b: boolean) return string is
+ begin
+ if b then
+ return "true";
+ else
+ return "false";
+ end if;
+ end function str;
+
+ -- converts an integer into a character
+ -- for 0 to 9 the obvious mapping is used, higher
+ -- values are mapped to the characters A-Z
+ -- (this is usefull for systems with base > 10)
+ -- (adapted from Steve Vogwell's posting in comp.lang.vhdl)
+ function chr(int: integer) return character is
+ variable c: character;
+ begin
+ case int is
+ when 0 => c := '0';
+ when 1 => c := '1';
+ when 2 => c := '2';
+ when 3 => c := '3';
+ when 4 => c := '4';
+ when 5 => c := '5';
+ when 6 => c := '6';
+ when 7 => c := '7';
+ when 8 => c := '8';
+ when 9 => c := '9';
+ when 10 => c := 'A';
+ when 11 => c := 'B';
+ when 12 => c := 'C';
+ when 13 => c := 'D';
+ when 14 => c := 'E';
+ when 15 => c := 'F';
+ when 16 => c := 'G';
+ when 17 => c := 'H';
+ when 18 => c := 'I';
+ when 19 => c := 'J';
+ when 20 => c := 'K';
+ when 21 => c := 'L';
+ when 22 => c := 'M';
+ when 23 => c := 'N';
+ when 24 => c := 'O';
+ when 25 => c := 'P';
+ when 26 => c := 'Q';
+ when 27 => c := 'R';
+ when 28 => c := 'S';
+ when 29 => c := 'T';
+ when 30 => c := 'U';
+ when 31 => c := 'V';
+ when 32 => c := 'W';
+ when 33 => c := 'X';
+ when 34 => c := 'Y';
+ when 35 => c := 'Z';
+ when others => c := '?';
+ end case;
+ return c;
+ end function chr;
+
+ -- convert integer to string using specified base
+ -- (adapted from Steve Vogwell's posting in comp.lang.vhdl)
+ function str(int: integer; base: integer) return string is
+ variable temp : string(1 to 10);
+ variable num : integer;
+ variable abs_int : integer;
+ variable len : integer:=1;
+ variable power : integer:=1;
+ begin
+ -- bug fix for negative numbers
+ abs_int:=abs(int);
+
+ num :=abs_int;
+
+ while num>=base loop -- Determine how many
+ len:=len+1; -- characters required
+ num:=num/base; -- to represent the
+ end loop; -- number.
+
+ for i in len downto 1 loop -- Convert the number to
+ temp(i):=chr(abs_int/power mod base); -- a string starting
+ power:=power*base; -- with the right hand
+ end loop ; -- side.
+
+ -- return result and add sign if required
+ if int<0 then
+ return '-'& temp(1 to len);
+ else
+ return temp(1 to len);
+ end if;
+ end function str;
+
+ -- convert integer to string, using base 10
+ function str(int: integer) return string is
+ begin
+ return str(int, 10) ;
+ end function str;
+
+ -- converts a std_logic_vector into a hex string.
+ function hstr(slv: std_logic_vector) return string is
+ variable hexlen: integer;
+ variable longslv : std_logic_vector(67 downto 0):=(others => '0');
+ variable hex : string(1 to 16);
+ variable fourbit : std_logic_vector(3 downto 0);
+ begin
+ hexlen:=(slv'left+1)/4;
+ if (slv'left+1) mod 4/=0 then
+ hexlen := hexlen + 1;
+ end if;
+ longslv(slv'left downto 0) := slv;
+ for i in (hexlen-1) downto 0 loop
+ fourbit:=longslv(((i*4)+3) downto (i*4));
+ case fourbit is
+ when "0000" => hex(hexlen-I):='0';
+ when "0001" => hex(hexlen-I):='1';
+ when "0010" => hex(hexlen-I):='2';
+ when "0011" => hex(hexlen-I):='3';
+ when "0100" => hex(hexlen-I):='4';
+ when "0101" => hex(hexlen-I):='5';
+ when "0110" => hex(hexlen-I):='6';
+ when "0111" => hex(hexlen-I):='7';
+ when "1000" => hex(hexlen-I):='8';
+ when "1001" => hex(hexlen-I):='9';
+ when "1010" => hex(hexlen-I):='A';
+ when "1011" => hex(hexlen-I):='B';
+ when "1100" => hex(hexlen-I):='C';
+ when "1101" => hex(hexlen-I):='D';
+ when "1110" => hex(hexlen-I):='E';
+ when "1111" => hex(hexlen-I):='F';
+ when "ZZZZ" => hex(hexlen-I):='z';
+ when "UUUU" => hex(hexlen-I):='u';
+ when "XXXX" => hex(hexlen-I):='x';
+ when others => hex(hexlen-I):='?';
+ end case;
+ end loop;
+ return hex(1 to hexlen);
+ end function hstr;
+
+ function hstr(slv: unsigned) return string is
+ begin
+ return hstr(std_logic_vector(slv));
+ end function hstr;
+
+ -- VHDL2008 to_string built-in equivalents
+ function to_string(int : integer) return string is
+ begin
+ return str(int);
+ end function;
+
+ function to_string(num : real) return string is
+ begin
+ return real'image(num);
+ end function;
+
+ function to_string(num : signed) return string is
+ begin
+ return integer'image(to_integer(num));
+ end function;
+
+ function to_string(num : unsigned) return string is
+ begin
+ return integer'image(to_integer(num));
+ end function;
+
+ function to_string(num : std_logic_vector) return string is
+ begin
+ return str(num);
+ end function;
+
+ -- functions to manipulate strings
+ -----------------------------------
+
+
+ -- convert a character to upper case
+ function to_upper(c: character) return character is
+ variable u: character;
+ begin
+ case c is
+ when 'a' => u:='A';
+ when 'b' => u:='B';
+ when 'c' => u:='C';
+ when 'd' => u:='D';
+ when 'e' => u:='E';
+ when 'f' => u:='F';
+ when 'g' => u:='G';
+ when 'h' => u:='H';
+ when 'i' => u:='I';
+ when 'j' => u:='J';
+ when 'k' => u:='K';
+ when 'l' => u:='L';
+ when 'm' => u:='M';
+ when 'n' => u:='N';
+ when 'o' => u:='O';
+ when 'p' => u:='P';
+ when 'q' => u:='Q';
+ when 'r' => u:='R';
+ when 's' => u:='S';
+ when 't' => u:='T';
+ when 'u' => u:='U';
+ when 'v' => u:='V';
+ when 'w' => u:='W';
+ when 'x' => u:='X';
+ when 'y' => u:='Y';
+ when 'z' => u:='Z';
+ when others => u:=c;
+ end case;
+ return u;
+ end function to_upper;
+
+
+ -- convert a character to lower case
+ function to_lower(c: character) return character is
+ variable l: character;
+ begin
+ case c is
+ when 'A' => l:='a';
+ when 'B' => l:='b';
+ when 'C' => l:='c';
+ when 'D' => l:='d';
+ when 'E' => l:='e';
+ when 'F' => l:='f';
+ when 'G' => l:='g';
+ when 'H' => l:='h';
+ when 'I' => l:='i';
+ when 'J' => l:='j';
+ when 'K' => l:='k';
+ when 'L' => l:='l';
+ when 'M' => l:='m';
+ when 'N' => l:='n';
+ when 'O' => l:='o';
+ when 'P' => l:='p';
+ when 'Q' => l:='q';
+ when 'R' => l:='r';
+ when 'S' => l:='s';
+ when 'T' => l:='t';
+ when 'U' => l:='u';
+ when 'V' => l:='v';
+ when 'W' => l:='w';
+ when 'X' => l:='x';
+ when 'Y' => l:='y';
+ when 'Z' => l:='z';
+ when others => l:=c;
+ end case;
+ return l;
+ end function to_lower;
+
+ -- convert a string to upper case
+ function to_upper(s: string) return string is
+ variable uppercase: string (s'range);
+ begin
+ for i in s'range loop
+ uppercase(i):=to_upper(s(i));
+ end loop;
+ return uppercase;
+ end to_upper;
+
+ -- convert a string to lower case
+ function to_lower(s: string) return string is
+ variable lowercase: string (s'range);
+ begin
+ for i in s'range loop
+ lowercase(i):=to_lower(s(i));
+ end loop;
+ return lowercase;
+ end to_lower;
+
+ -- functions to convert strings into other types
+
+ -- converts a character into a std_logic
+
+ function to_std_logic(c: character) return std_logic is
+ variable sl : std_logic;
+ begin
+ case c is
+ when 'U' =>
+ sl:='U';
+ when 'X' =>
+ sl:='X';
+ when '0' =>
+ sl:='0';
+ when '1' =>
+ sl:='1';
+ when 'Z' =>
+ sl:='Z';
+ when 'W' =>
+ sl:='W';
+ when 'L' =>
+ sl:='L';
+ when 'H' =>
+ sl:='H';
+ when '-' =>
+ sl:='-';
+ when others =>
+ sl:='X';
+ end case;
+ return sl;
+ end function to_std_logic;
+
+
+ -- converts a string into std_logic_vector
+ function to_std_logic_vector(s: string) return std_logic_vector is
+ variable slv : std_logic_vector(s'high-s'low downto 0);
+ variable k : integer;
+ begin
+ k:=s'high-s'low;
+ for i in s'range loop
+ slv(k):=to_std_logic(s(i));
+ k :=k-1;
+ end loop;
+ return slv;
+ end function to_std_logic_vector;
+
+
+ ----------------
+ -- file I/O --
+ ----------------
+
+ -- read variable length string from input file
+ procedure str_read(file in_file: TEXT;
+ res_string: out string) is
+ variable l : line;
+ variable c : character;
+ variable is_string : boolean;
+ begin
+ readline(in_file, l);
+ -- clear the contents of the result string
+ for i in res_string'range loop
+ res_string(i):=' ';
+ end loop;
+ -- read all characters of the line, up to the length
+ -- of the results string
+ for i in res_string'range loop
+ read(l,c,is_string);
+ res_string(i):=c;
+ if not is_string then -- found end of line
+ exit;
+ end if;
+ end loop;
+ end procedure str_read;
+
+ -- print string to a file
+ procedure print(file out_file: TEXT;
+ new_string: in string) is
+ variable l: line;
+ begin
+ write(l,new_string);
+ writeline(out_file,l);
+ end procedure print;
+
+ -- print character to a file and start new line
+ procedure print(file out_file: TEXT;
+ char: in character) is
+ variable l: line;
+ begin
+ write(l,char);
+ writeline(out_file,l);
+ end procedure print;
+
+ -- appends contents of a string to a file until line feed occurs
+ -- (LF is considered to be the end of the string)
+ procedure str_write(file out_file: TEXT;
+ new_string: in string) is
+ begin
+ for i in new_string'range loop
+ print(out_file,new_string(i));
+ if new_string(i)=LF then -- end of string
+ exit;
+ end if;
+ end loop;
+ end str_write;
+end package body psi_tb_txt_util;
diff --git a/testsuite/gna/issue1051/repro.vhdl b/testsuite/gna/issue1051/repro.vhdl
new file mode 100644
index 000000000..3ffa7571f
--- /dev/null
+++ b/testsuite/gna/issue1051/repro.vhdl
@@ -0,0 +1,29 @@
+entity repro is
+end repro;
+
+architecture behav of repro is
+ type msg_t is record
+ pfx : string;
+ func : string;
+ user : string;
+ end record;
+
+ procedure report_msg (m : msg_t) is
+ begin
+ report m.pfx & "." & m.func & ": " & m.user;
+ end report_msg;
+
+ procedure fill (pfx : string := "#err#"; usr : string := "none") is
+ constant m : msg_t := (pfx, "fill", usr);
+ begin
+ report_msg (m);
+ end fill;
+begin
+ process
+ begin
+ fill;
+ fill (pfx => "my err");
+ wait;
+ end process;
+end behav;
+
diff --git a/testsuite/gna/issue1051/repro2.vhdl b/testsuite/gna/issue1051/repro2.vhdl
new file mode 100644
index 000000000..76d31deb2
--- /dev/null
+++ b/testsuite/gna/issue1051/repro2.vhdl
@@ -0,0 +1,28 @@
+entity repro2 is
+end repro2;
+
+architecture behav of repro2 is
+ type msg_t is record
+ pfx : string;
+ func : string;
+ user : string;
+ end record;
+
+ procedure report_msg (m : msg_t) is
+ begin
+ report m.pfx & "." & m.func & ": " & m.user;
+ end report_msg;
+
+ procedure fill (pfx : string := "#err#"; usr : string := "none") is
+ begin
+ report_msg (m => (pfx, "fill", usr));
+ end fill;
+begin
+ process
+ begin
+ fill;
+ fill (pfx => "my err");
+ wait;
+ end process;
+end behav;
+
diff --git a/testsuite/gna/issue1051/testsuite.sh b/testsuite/gna/issue1051/testsuite.sh
new file mode 100755
index 000000000..ad45ae63a
--- /dev/null
+++ b/testsuite/gna/issue1051/testsuite.sh
@@ -0,0 +1,32 @@
+#! /bin/sh
+
+. ../../testenv.sh
+
+FILES="
+psi_common_array_pkg.vhd
+psi_common_math_pkg.vhd
+psi_common_logic_pkg.vhd
+
+psi_tb_txt_util.vhd
+psi_tb_compare_pkg.vhd
+psi_tb_activity_pkg.vhd
+psi_tb_i2c_pkg.vhd
+
+psi_common_bit_cc.vhd
+psi_common_i2c_master.vhd
+psi_common_i2c_master_tb.vhd
+"
+
+export GHDL_STD_FLAGS="--std=08 -frelaxed"
+analyze repro.vhdl
+elab_simulate repro
+
+analyze repro2.vhdl
+elab_simulate repro2
+
+analyze $FILES
+elab_simulate psi_common_i2c_master_tb
+
+clean
+
+echo "Test successful"