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 osvvm;
12
+ use osvvm.RandomPkg.RandomPType;
13
+
14
+ library vunit_lib;
15
+ context vunit_lib.com_context;
16
+ context vunit_lib.vunit_context;
17
+ context vunit_lib.vc_context;
18
+
19
+ -- VCs
20
+ use work.basic_stream_pkg.all ;
21
+ use work.i2c_cmd_vc_pkg.all ;
22
+ use work.i2c_common_pkg.all ;
23
+ use work.i2c_ctrl_vc_pkg.all ;
24
+ use work.i2c_target_vc_pkg.all ;
25
+
26
+ use work.spd_proxy_top_tb_pkg.all ;
27
+
28
+ entity spd_proxy_top_tb is
29
+ generic (
30
+ runner_cfg : string
31
+ );
32
+ end entity ;
33
+
34
+ architecture tb of spd_proxy_top_tb is
35
+ begin
36
+
37
+ th : entity work .spd_proxy_top_th;
38
+
39
+ bench: process
40
+ alias reset is << signal th.reset : std_logic >> ;
41
+ variable rnd : RandomPType;
42
+ variable i2c_ctrlr_msg : msg_t;
43
+
44
+ variable command : cmd_t;
45
+ variable ack : boolean := false ;
46
+
47
+ variable data : std_logic_vector (7 downto 0 );
48
+ variable exp_addr : std_logic_vector (7 downto 0 );
49
+ variable exp_data : std_logic_vector (7 downto 0 );
50
+ variable byte_len : natural ;
51
+
52
+ variable cpu_tx_q : queue_t := new_queue;
53
+ variable cpu_ack_q : queue_t := new_queue;
54
+ begin
55
+ -- Always the first thing in the process, set up things for the VUnit test runner
56
+ test_runner_setup(runner, runner_cfg);
57
+ -- Reach into the test harness, which generates and de-asserts reset and hold the
58
+ -- test cases off until we're out of reset. This runs for every test case
59
+ wait until reset = '0' ;
60
+ wait for 500 ns ; -- let the resets propagate
61
+
62
+ while test_suite loop
63
+ if run(" no_cpu_transaction" ) then
64
+ -- arbitrary for the test
65
+ exp_addr := X"00" ;
66
+ byte_len := 8 ;
67
+
68
+ -- write some data in
69
+ command := (
70
+ op => WRITE ,
71
+ addr => address(I2C_TGT_VC),
72
+ reg => std_logic_vector (exp_addr),
73
+ len => to_std_logic_vector(byte_len, command.len'length )
74
+ );
75
+ push_i2c_cmd(net, I2C_CMD_VC, command);
76
+
77
+ start_byte_ack(net, I2C_TGT_VC, ack);
78
+ check_true(ack, " Peripheral did not ACK correct address" );
79
+
80
+ for byte_idx in 0 to byte_len - 1 loop
81
+ data := std_logic_vector (to_std_logic_vector(byte_idx, data'length ));
82
+ exp_addr := to_std_logic_vector(byte_idx, exp_addr'length );
83
+ push_basic_stream(net, TX_DATA_SOURCE_VC, data);
84
+ end loop ;
85
+
86
+ for byte_idx in 0 to byte_len - 1 loop
87
+ data := std_logic_vector (to_std_logic_vector(byte_idx, data'length ));
88
+ exp_addr := to_std_logic_vector(byte_idx, exp_addr'length );
89
+ check_written_byte(net, I2C_TGT_VC, data, exp_addr);
90
+ end loop ;
91
+
92
+ expect_stop(net, I2C_TGT_VC);
93
+ elsif run(" cpu_transaction" ) then
94
+ -- Get the FPGA controller started on a transaction
95
+ -- arbitrary for the test
96
+ exp_addr := X"00" ;
97
+ byte_len := 8 ;
98
+ -- write some data in
99
+ command := (
100
+ op => WRITE ,
101
+ addr => address(I2C_TGT_VC),
102
+ reg => std_logic_vector (exp_addr),
103
+ len => to_std_logic_vector(byte_len, command.len'length )
104
+ );
105
+ push_i2c_cmd(net, I2C_CMD_VC, command);
106
+ for byte_idx in 0 to byte_len - 1 loop
107
+ data := std_logic_vector (to_std_logic_vector(byte_idx, data'length ));
108
+ exp_addr := to_std_logic_vector(byte_idx, exp_addr'length );
109
+ push_basic_stream(net, TX_DATA_SOURCE_VC, data);
110
+ end loop ;
111
+
112
+ -- At some point into the transaction, have the CPU start its own
113
+ wait for rnd.RandInt(500 , 4000 ) * 1 ns ;
114
+
115
+ push_byte(cpu_tx_q, to_integer (rnd.RandSlv(0 , 255 , 8 )));
116
+ i2c_write_txn(net, address(I2C_TGT_VC), cpu_tx_q, cpu_ack_q, I2C_CTRL_VC.p_actor);
117
+
118
+ elsif run(" cpu_with_simulated_start" ) then
119
+ -- Get the FPGA controller started on a transaction
120
+ -- arbitrary for the test
121
+ exp_addr := X"00" ;
122
+ byte_len := 8 ;
123
+ -- write some data in
124
+ command := (
125
+ op => READ ,
126
+ addr => address(I2C_TGT_VC),
127
+ reg => std_logic_vector (exp_addr),
128
+ len => to_std_logic_vector(byte_len, command.len'length )
129
+ );
130
+ push_i2c_cmd(net, I2C_CMD_VC, command);
131
+ for byte_idx in 0 to byte_len - 1 loop
132
+ data := std_logic_vector (to_std_logic_vector(byte_idx, data'length ));
133
+ exp_addr := to_std_logic_vector(byte_idx, exp_addr'length );
134
+ push_basic_stream(net, TX_DATA_SOURCE_VC, data);
135
+ end loop ;
136
+
137
+ -- At some point into the transaction, have the CPU start its own
138
+ wait for 9500 ns ;
139
+
140
+ push_byte(cpu_tx_q, to_integer (rnd.RandSlv(0 , 255 , 8 )));
141
+ i2c_write_txn(net, address(I2C_TGT_VC), cpu_tx_q, cpu_ack_q, I2C_CTRL_VC.p_actor);
142
+ end if ;
143
+ end loop ;
144
+
145
+ wait for 2 us ;
146
+ test_runner_cleanup(runner);
147
+ wait ;
148
+ end process ;
149
+
150
+ test_runner_watchdog(runner, 10 ms );
151
+
152
+ end architecture ;
0 commit comments