Skip to content

Commit f8be61b

Browse files
committed
Add an SPD proxy mux
1 parent 2b6ac64 commit f8be61b

File tree

9 files changed

+643
-16
lines changed

9 files changed

+643
-16
lines changed

hdl/ip/vhd/i2c/controller/link_layer/i2c_ctrl_link_layer.vhd

+17-14
Original file line numberDiff line numberDiff line change
@@ -293,21 +293,11 @@ begin
293293
v.sda_oe := '0';
294294

295295
if tx_start then
296-
v.state := WAIT_TBUF;
297-
v.counter := STO_TO_STA_BUF_TICKS;
298-
v.count_load := '1';
299-
end if;
300-
301-
-- Wait out tbuf to ensure STOP/START spacing
302-
when WAIT_TBUF =>
303-
if sm_count_done then
304-
-- tbuf is always greater than or equal to the START setup requirement, skip to
305-
-- hold
296+
-- Coming back to IDLE after a transaction means we've waited out tbuf, and tbuf
297+
-- is always greater than or equal to the START setup requirement, skip to hold
306298
v.state := START_HOLD;
307299
v.counter := START_SETUP_HOLD_TICKS;
308300
v.count_load := '1';
309-
else
310-
v.count_decr := '1';
311301
end if;
312302

313303
when WAIT_REPEAT_START =>
@@ -369,7 +359,9 @@ begin
369359
v.state := ACK_RX;
370360
v.bits_shifted := 0;
371361
elsif v.stop_requested then
372-
v.state := STOP_SDA;
362+
-- this is a valid SDA transition cycle so drive SDA low and skip STOP_SDA
363+
v.state := STOP_SCL;
364+
v.sda_oe := '1';
373365
else
374366
v.sda_oe := not sm_reg.tx_data(7);
375367
v.tx_data := sm_reg.tx_data(sm_reg.tx_data'high-1 downto sm_reg.tx_data'low) & '1';
@@ -433,7 +425,18 @@ begin
433425

434426
when STOP_SETUP =>
435427
if sm_count_done then
436-
v := SM_REG_RESET;
428+
v.state := WAIT_TBUF;
429+
v.counter := STO_TO_STA_BUF_TICKS;
430+
v.count_load := '1';
431+
v.sda_oe := '0';
432+
else
433+
v.count_decr := '1';
434+
end if;
435+
436+
-- Wait out tbuf to ensure STOP/START spacing
437+
when WAIT_TBUF =>
438+
if sm_count_done then
439+
v := SM_REG_RESET;
437440
else
438441
v.count_decr := '1';
439442
end if;

hdl/ip/vhd/i2c/controller/txn_layer/sims/i2c_ctrl_txn_layer_th.vhd

-1
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,6 @@ library vunit_lib;
1313
context vunit_lib.com_context;
1414
context vunit_lib.vc_context;
1515

16-
use work.i2c_common_pkg.all;
1716
use work.i2c_common_pkg.all;
1817
use work.tristate_if_pkg.all;
1918
use work.stream8_pkg;

hdl/ip/vhd/vunit_components/i2c_controller/i2c_ctrlr_vc.vhd

+1-1
Original file line numberDiff line numberDiff line change
@@ -120,7 +120,7 @@ begin
120120
sda <= 'Z';
121121
wait for 60 ns; -- need to be longer than 50ns glitch timing
122122
sda <= '0';
123-
wait for thd_sta * 4;
123+
wait for thd_sta;
124124
wait until falling_edge(aligner_int);
125125
scl <= '0'; -- scl is now low, ready for bits
126126
wait for 60 ns; -- need to be longer than 50ns glitch timing

hdl/projects/cosmo_seq/spd_proxy/BUCK

+27
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
load("//tools:hdl.bzl", "vhdl_unit", "vunit_sim")
2+
3+
vhdl_unit(
4+
name = "spd_proxy_top",
5+
srcs = glob(["*.vhd"]),
6+
deps = [
7+
"//hdl/ip/vhd/common:tristate_if_pkg",
8+
"//hdl/ip/vhd/i2c/common:i2c_common_pkg",
9+
"//hdl/ip/vhd/i2c/common:i2c_glitch_filter",
10+
"//hdl/ip/vhd/i2c/controller:i2c_ctrl_txn_layer",
11+
],
12+
standard = "2019",
13+
visibility = ['PUBLIC']
14+
)
15+
16+
vunit_sim(
17+
name = "spd_proxy_top_tb",
18+
srcs = glob(["sims/*.vhd"]),
19+
deps = [
20+
":spd_proxy_top",
21+
"//hdl/ip/vhd/vunit_components:basic_stream",
22+
"//hdl/ip/vhd/vunit_components:i2c_cmd_vc",
23+
"//hdl/ip/vhd/vunit_components:i2c_target_vc",
24+
"//hdl/ip/vhd/vunit_components:i2c_controller_vc"
25+
],
26+
visibility = ['PUBLIC'],
27+
)
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
[*]
2+
[*] GTKWave Analyzer v3.3.104 (w)1999-2020 BSI
3+
[*] Wed Feb 19 22:29:57 2025
4+
[*]
5+
[dumpfile] "/home/aaron/Oxide/git/quartz/vunit_out/test_output/lib.spd_proxy_top_tb.cpu_with_simulated_start_009e7a6b9dbd8a7136824e0237951cc80f6be48b/nvc/spd_proxy_top_tb.fst"
6+
[dumpfile_mtime] "Wed Feb 19 22:23:27 2025"
7+
[dumpfile_size] 5095
8+
[savefile] "/home/aaron/Oxide/git/quartz/hdl/projects/cosmo_seq/spd_proxy/sims/spd_proxy_top_tb.gtkw"
9+
[timestart] 0
10+
[size] 2816 1283
11+
[pos] 1074 -22
12+
*-34.132660 19580000000 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1
13+
[treeopen] spd_proxy_top_tb.
14+
[treeopen] spd_proxy_top_tb.th.
15+
[treeopen] spd_proxy_top_tb.th.spd_proxy_top_inst.
16+
[treeopen] spd_proxy_top_tb.th.spd_proxy_top_inst.i2c_ctrl_txn_layer_inst.
17+
[treeopen] spd_proxy_top_tb.th.spd_proxy_top_inst.i2c_ctrl_txn_layer_inst.i2c_ctrl_link_layer_inst.
18+
[sst_width] 281
19+
[signals_width] 337
20+
[sst_expanded] 1
21+
[sst_vpaned_height] 382
22+
@200
23+
-CPU Bus
24+
@28
25+
spd_proxy_top_tb.th.i2c_controller_vc_inst.state
26+
spd_proxy_top_tb.th.cpu_scl
27+
spd_proxy_top_tb.th.cpu_sda
28+
@200
29+
-
30+
-DIMM Bus
31+
@28
32+
spd_proxy_top_tb.th.i2c_target_vc_inst.state
33+
spd_proxy_top_tb.th.dimm_scl
34+
spd_proxy_top_tb.th.dimm_sda
35+
@200
36+
-
37+
-FPGA Bus
38+
@28
39+
spd_proxy_top_tb.th.spd_proxy_top_inst.fpga_scl_if.i
40+
spd_proxy_top_tb.th.spd_proxy_top_inst.fpga_sda_if.i
41+
@200
42+
-
43+
-SPD Proxy Logic
44+
@28
45+
spd_proxy_top_tb.th.spd_proxy_top_inst.cpu_start_detected
46+
spd_proxy_top_tb.th.spd_proxy_top_inst.cpu_stop_detected
47+
spd_proxy_top_tb.th.spd_proxy_top_inst.cpu_busy
48+
spd_proxy_top_tb.th.spd_proxy_top_inst.cpu_has_mux
49+
spd_proxy_top_tb.th.spd_proxy_top_inst.ctrlr_has_int_mux
50+
@200
51+
-
52+
-Simulated START State
53+
@28
54+
spd_proxy_top_tb.th.spd_proxy_top_inst.scl_sim
55+
spd_proxy_top_tb.th.spd_proxy_top_inst.sda_sim
56+
@29
57+
spd_proxy_top_tb.th.spd_proxy_top_inst.sda_sim_fedge
58+
@28
59+
spd_proxy_top_tb.th.spd_proxy_top_inst.need_start
60+
spd_proxy_top_tb.th.spd_proxy_top_inst.start_simulated
61+
@200
62+
-
63+
-Internal I2C Controller
64+
-Transaction Layer
65+
@28
66+
spd_proxy_top_tb.th.spd_proxy_top_inst.i2c_ctrl_txn_layer_inst.abort
67+
spd_proxy_top_tb.th.spd_proxy_top_inst.i2c_ctrl_txn_layer_inst.sm_reg.do_stop
68+
spd_proxy_top_tb.th.spd_proxy_top_inst.i2c_ctrl_txn_layer_inst.sm_reg.state
69+
@200
70+
-Link Layer
71+
@28
72+
spd_proxy_top_tb.th.spd_proxy_top_inst.i2c_ctrl_txn_layer_inst.i2c_ctrl_link_layer_inst.sm_reg.stop_requested
73+
spd_proxy_top_tb.th.spd_proxy_top_inst.i2c_ctrl_txn_layer_inst.i2c_ctrl_link_layer_inst.sm_reg.state
74+
[pattern_trace] 1
75+
[pattern_trace] 0
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,152 @@
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;
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
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+
10+
library vunit_lib;
11+
context vunit_lib.vunit_context;
12+
context vunit_lib.com_context;
13+
context vunit_lib.vc_context;
14+
15+
use work.i2c_cmd_vc_pkg.all;
16+
use work.i2c_ctrl_vc_pkg.all;
17+
use work.i2c_target_vc_pkg.all;
18+
use work.basic_stream_pkg.all;
19+
20+
package spd_proxy_top_tb_pkg is
21+
-- Constants
22+
constant CLK_PER_NS : positive := 8;
23+
24+
-- Verification Components
25+
constant I2C_CTRL_VC : i2c_ctrl_vc_t := new_i2c_ctrl_vc("cpu_i2c_vc");
26+
constant I2C_TGT_VC : i2c_target_vc_t := new_i2c_target_vc("dimm_i2c_vc");
27+
constant I2C_CMD_VC : i2c_cmd_vc_t := new_i2c_cmd_vc;
28+
constant TX_DATA_SOURCE_VC : basic_source_t := new_basic_source(8);
29+
constant RX_DATA_SINK_VC : basic_sink_t := new_basic_sink(8);
30+
31+
end package;

0 commit comments

Comments
 (0)