- BlackBox: name: Clash.Explicit.Testbench.assert imports: - ~INCLUDENAME[0].all includes: - name: slv2string extension: vhdl template: |- -- helper function of Clash.Explicit.Testbench.assert library IEEE; use IEEE.STD_LOGIC_1164.ALL; package ~INCLUDENAME[0] is function slv2string (slv : std_logic_vector) return STRING; end; package body ~INCLUDENAME[0] is function slv2string (slv : std_logic_vector) return STRING is variable result : string (1 to slv'length); variable res_l : string (1 to 3); variable r : integer; begin r := 1; for i in slv'range loop res_l := std_logic'image(slv(i)); result(r) := res_l(2); r := r + 1; end loop; return result; end slv2string; end; kind: Declaration type: |- assert :: (KnownDomain dom, Eq a, ShowX a) -- (ARG[0],ARG[1],ARG[2]) => Clock dom -- ARG[3] -> Reset dom -- ARG[4] -> String -- ARG[5] -> Signal dom a -- Checked value (ARG[6]) -> Signal dom a -- Expected value (ARG[7]) -> Signal dom b -- Return valued (ARG[8]) -> Signal dom b template: |- -- assert begin ~GENSYM[assert][0] : block -- pragma translate_off signal ~GENSYM[actual][2] : ~TYP[6]; signal ~GENSYM[expected][3] : ~TYP[7]; -- pragma translate_on begin -- pragma translate_off ~SYM[2] <= ~ARG[6]; ~SYM[3] <= ~ARG[7]; process(~ARG[3]) is begin if (~IF~ACTIVEEDGE[Rising][0]~THENrising_edge~ELSEfalling_edge~FI(~ARG[3])) then assert (toSLV(~SYM[2]) = toSLV(~SYM[3])) report (~LIT[5] & ", expected: " & ~INCLUDENAME[0].slv2string(toSLV(~SYM[3])) & ", actual: " & ~INCLUDENAME[0].slv2string(toSLV(~SYM[2]))) severity error; end if; end process; -- pragma translate_on ~RESULT <= ~ARG[8]; end block; -- assert end - BlackBox: name: Clash.Explicit.Testbench.assertBitVector imports: - ~INCLUDENAME[0].all includes: - name: assertBitVector extension: vhdl template: | -- helper functions of Clash.Explicit.Testbench.assertBitVector library IEEE; use IEEE.STD_LOGIC_1164.ALL; package ~INCLUDENAME[0] is function non_std_match (l, r : std_logic_vector) return boolean; function slv2string (slv : std_logic_vector) return STRING; end; package body ~INCLUDENAME[0] is type match_table_type is array (std_ulogic, std_ulogic) of boolean; constant match_table: match_table_type := ('0' | 'L' => ('0' | 'L' | '-' => true, others => false), '1' | 'H' => ('1' | 'H' | '-' => true, others => false), '-' => ('-' => true, others => false), others => ('-' => true, others => false) ); -- non_std_match is like std_match -- But only accepts '-' as don't care in its the second argument r. function non_std_match (l, r : std_logic_vector) return boolean is alias la : std_logic_vector (l'length downto 1) is l; alias ra : std_logic_vector (r'length downto 1) is r; begin for i in l'range loop if not match_table (l (i), r (i)) then return false; end if; end loop; return true; end non_std_match; function slv2string (slv : std_logic_vector) return STRING is variable result : string (1 to slv'length); variable res_l : string (1 to 3); variable r : integer; begin r := 1; for i in slv'range loop res_l := std_logic'image(slv(i)); result(r) := res_l(2); r := r + 1; end loop; return result; end slv2string; end; kind: Declaration type: |- assertBitVector :: ( KnownDomain dom -- ARG[0] , KnownNat n ) -- ARG[1] => Clock dom -- ARG[2] -> Reset dom -- ARG[3] -> String -- ARG[4] -> Signal dom (BitVector n) -- Checked value (ARG[5]) -> Signal dom (BitVector n) -- Expected value (ARG[6]) -> Signal dom b -- Return valued (ARG[7]) -> Signal dom b template: |- -- assertBitVector begin ~GENSYM[assert][0] : block -- pragma translate_off signal ~GENSYM[actual][2] : ~TYP[5]; signal ~GENSYM[expected][3] : ~TYP[6]; -- pragma translate_on begin -- pragma translate_off ~SYM[2] <= ~ARG[5]; ~SYM[3] <= ~ARG[6]; process(~ARG[2]) is begin if (~IF~ACTIVEEDGE[Rising][0]~THENrising_edge~ELSEfalling_edge~FI(~ARG[2])) then assert (~INCLUDENAME[0].non_std_match(toSLV(~SYM[2]),toSLV(~SYM[3]))) report (~LIT[4] & ", expected: " & ~INCLUDENAME[0].slv2string(toSLV(~SYM[3])) & ", actual: " & ~INCLUDENAME[0].slv2string(toSLV(~SYM[2]))) severity error; end if; end process; -- pragma translate_on ~RESULT <= ~ARG[7]; end block; -- assertBitVector end - BlackBox: name: Clash.Explicit.Testbench.tbClockGen comment: |- ModelSim and Vivado seem to round time values to an integer number of picoseconds. Use two half periods to prevent rounding errors from affecting the full period. kind: Declaration type: |- tbClockGen :: KnownDomain dom -- ARG[0] => Signal dom Bool -- ARG[1] -> Clock dom template: |- -- tbClockGen begin -- pragma translate_off ~GENSYM[clkGen][0] : process is constant ~GENSYM[half_periodH][1] : time := ~PERIOD[0]000 fs / 2; constant ~GENSYM[half_periodL][2] : time := ~PERIOD[0]000 fs - ~SYM[1]; begin ~RESULT <= ~IF~ACTIVEEDGE[Rising][0]~THEN'0'~ELSE'1'~FI; wait for ~LONGESTPERIOD ps; while ~ARG[1] loop ~RESULT <= not ~RESULT; wait for ~SYM[1]; ~RESULT <= not ~RESULT; wait for ~SYM[2]; end loop; wait; end process; -- pragma translate_on -- tbClockGen end warning: Clash.Signal.Internal.tbClockGen is not synthesizable! workInfo: Always - BlackBox: name: Clash.Explicit.Testbench.tbEnableGen kind: Declaration type: 'tbEnableGen :: Enable dom' template: ~RESULT <= true; workInfo: Always