1+ -- This Source Code Form is subject to the terms of the Mozilla Public
2+ -- License, v. 2.0. If a copy of the MPL was not distributed with this
3+ -- file, You can obtain one at https://mozilla.org/MPL/2.0/.
4+ --
5+ -- Copyright 2025 Oxide Computer Company
6+
7+ library ieee;
8+ use ieee.std_logic_1164.all ;
9+ use ieee.numeric_std_unsigned.all ;
10+
11+ library vunit_lib;
12+ context vunit_lib.com_context;
13+ context vunit_lib.vunit_context;
14+
15+ entity sda_arbiter_tb is
16+ generic (
17+ runner_cfg : string
18+ );
19+ end entity ;
20+
21+ architecture tb of sda_arbiter_tb is
22+ constant CLK_PER_TIME : time := 8 ns ;
23+ constant HYSTERESIS_CYCLES : integer := 10 ;
24+
25+ signal clk : std_logic := '0' ;
26+ signal reset : std_logic := '1' ;
27+ signal a : std_logic := '1' ;
28+ signal b : std_logic := '1' ;
29+ signal enabled : std_logic := '1' ;
30+ signal a_grant : std_logic ;
31+ signal b_grant : std_logic ;
32+ begin
33+
34+ clk <= not clk after CLK_PER_TIME / 2 ;
35+ reset <= '0' after 100 ns ;
36+
37+ sda_arbiter_inst: entity work.sda_arbiter
38+ generic map (
39+ HYSTERESIS_CYCLES => HYSTERESIS_CYCLES
40+ )
41+ port map (
42+ clk => clk,
43+ reset => reset,
44+ a => a,
45+ b => b,
46+ enabled => enabled,
47+ a_grant => a_grant,
48+ b_grant => b_grant
49+ );
50+
51+ bench: process
52+ variable cycle_counter : integer := 0 ;
53+ begin
54+ -- Always the first thing in the process, set up things for the VUnit test runner
55+ test_runner_setup(runner, runner_cfg);
56+
57+ -- wait for reset to clear
58+ wait until reset = '0' ;
59+
60+ while test_suite loop
61+ if run(" grant_a" ) then
62+ -- assert A bus
63+ b <= '1' ;
64+ wait for 100 ns ;
65+ a <= '0' ;
66+
67+ check_true(a_grant = '0' , " Bus A should not be granted the bus." );
68+ check_true(b_grant = '0' , " Bus B should not be granted the bus." );
69+
70+ -- arbitration grant is registered
71+ wait for CLK_PER_TIME + 1 ns ;
72+
73+ check_true(a_grant = '1' , " Bus A should immediately be granted the bus." );
74+ check_true(b_grant = '0' , " Bus B should not be granted the bus." );
75+ elsif run(" grant_b" ) then
76+ -- assert B bus
77+ a <= '1' ;
78+ wait for 100 ns ;
79+ b <= '0' ;
80+
81+ check_true(a_grant = '0' , " Bus A should not be granted the bus." );
82+ check_true(b_grant = '0' , " Bus B should not be granted the bus." );
83+
84+ -- arbitration grant is registered
85+ wait for CLK_PER_TIME + 1 ns ;
86+
87+ check_true(a_grant = '0' , " Bus A should not be granted the bus." );
88+ check_true(b_grant = '1' , " Bus B should immediately be granted the bus." );
89+ elsif run(" hysteresis" ) then
90+ -- assert A bus
91+ b <= '1' ;
92+ wait for 100 ns ;
93+ a <= '0' ;
94+ wait until a_grant = '1' ;
95+
96+ -- release A bus and assert B bus, expecting the arbitration not to change before
97+ -- HYSTERESIS_CYCLES has passed
98+ a <= '1' ;
99+ b <= '0' ;
100+
101+ while cycle_counter <= HYSTERESIS_CYCLES loop
102+ wait for CLK_PER_TIME;
103+ check_true(a_grant = '1' , " Bus A should be granted the bus." );
104+ check_true(b_grant = '0' , " Bus B should not be granted the bus." );
105+ cycle_counter := cycle_counter + 1 ;
106+ end loop ;
107+
108+ -- after the initial hysteresis period, neither bus should be granted arbitration
109+ cycle_counter := 0 ;
110+ while cycle_counter <= HYSTERESIS_CYCLES loop
111+ wait for CLK_PER_TIME;
112+ check_true(a_grant = '0' , " Bus A should not be granted the bus." );
113+ check_true(b_grant = '0' , " Bus B should not be granted the bus." );
114+ cycle_counter := cycle_counter + 1 ;
115+ end loop ;
116+
117+ -- after the second hysteresis period, B should be granted the bus.
118+ wait until rising_edge (clk);
119+ check_true(a_grant = '0' , " Bus A should not be granted the bus." );
120+ check_true(b_grant = '1' , " Bus B should be granted the bus." );
121+ elsif run(" disable" ) then
122+ -- assert A bus
123+ b <= '1' ;
124+ wait for 100 ns ;
125+ a <= '0' ;
126+ wait until a_grant = '1' ;
127+
128+ enabled <= '0' ;
129+ wait for CLK_PER_TIME + 1 ns ;
130+ check_true(a_grant = '0' , " Bus A should not be granted the bus." );
131+ check_true(b_grant = '0' , " Bus B should not be granted the bus." );
132+ end if ;
133+ end loop ;
134+
135+ wait for 1 us ;
136+ test_runner_cleanup(runner);
137+ wait ;
138+ end process ;
139+
140+ test_runner_watchdog(runner, 10 us );
141+ end architecture ;
0 commit comments