Skip to content

Commit e0d6afb

Browse files
Update proxying to do SDA arbitration properly (#312)
1 parent c4d8222 commit e0d6afb

File tree

4 files changed

+120
-33
lines changed

4 files changed

+120
-33
lines changed

hdl/ip/vhd/vunit_components/i2c_target/i2c_target_vc.vhd

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -90,7 +90,7 @@ begin
9090
when IDLE =>
9191
wait on start_condition;
9292
state <= START;
93-
93+
9494
when START =>
9595
event_msg := new_msg(got_start);
9696
send(net, I2C_TARGET_VC.p_actor, event_msg);

hdl/ip/vhd/vunit_components/i2c_target/i2c_target_vc_pkg.vhd

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,11 @@ package i2c_target_vc_pkg is
5151
constant expected_msg : msg_type_t;
5252
);
5353

54+
procedure expect_start (
55+
signal net : inout network_t;
56+
constant vc : i2c_target_vc_t;
57+
);
58+
5459
procedure expect_stop (
5560
signal net : inout network_t;
5661
constant vc : i2c_target_vc_t;
@@ -128,6 +133,14 @@ package body i2c_target_vc_pkg is
128133
end if;
129134
end procedure;
130135

136+
procedure expect_start (
137+
signal net : inout network_t;
138+
constant vc : i2c_target_vc_t;
139+
) is
140+
begin
141+
expect_message(net, vc, got_start);
142+
end procedure;
143+
131144
procedure expect_stop (
132145
signal net : inout network_t;
133146
constant vc : i2c_target_vc_t;

hdl/projects/cosmo_seq/spd_proxy/sims/spd_proxy_top_tb.vhd

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -42,11 +42,9 @@ begin
4242
variable i2c_ctrlr_msg : msg_t;
4343

4444
variable command : cmd_t;
45-
variable ack : boolean := false;
4645

4746
variable data : std_logic_vector(7 downto 0);
4847
variable exp_addr : std_logic_vector(7 downto 0);
49-
variable exp_data : std_logic_vector(7 downto 0);
5048
variable byte_len : natural;
5149
variable byte_idx : natural;
5250

@@ -59,6 +57,15 @@ begin
5957
-- attempting to interrupt
6058
procedure init_controller is
6159
begin
60+
-- we gate the FPGA controller on seeing CPU activity before it will start talking, so
61+
-- fake that out
62+
i2c_ctrlr_msg := new_msg(i2c_send_start);
63+
send(net, I2C_CTRL_VC.p_actor, i2c_ctrlr_msg);
64+
expect_start(net, I2C_TGT_VC);
65+
i2c_ctrlr_msg := new_msg(i2c_send_stop);
66+
send(net, I2C_CTRL_VC.p_actor, i2c_ctrlr_msg);
67+
expect_stop(net, I2C_TGT_VC);
68+
6269
-- arbitrary for the test
6370
exp_addr := X"00";
6471
byte_len := 8;

hdl/projects/cosmo_seq/spd_proxy/spd_proxy_top.vhd

Lines changed: 97 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -40,18 +40,31 @@ entity spd_proxy_top is
4040
end entity;
4141

4242
architecture rtl of spd_proxy_top is
43-
constant CPU_I2C_TSP_CYCLES : integer :=
43+
-- TODO: Just use a single TSP constant?
44+
constant DIMM_I2C_TSP_CYCLES : integer :=
4445
to_integer(calc_ns(get_i2c_settings(I2C_MODE).tsp_ns, CLK_PER_NS, 8));
46+
constant CPU_I2C_TSP_CYCLES : integer :=
47+
to_integer(calc_ns(get_i2c_settings(STANDARD).tsp_ns, CLK_PER_NS, 8));
4548
signal cpu_scl_filt : std_logic;
4649
signal cpu_scl_fedge : std_logic;
50+
signal cpu_scl_redge : std_logic;
51+
signal cpu_sda_filt : std_logic;
4752
signal cpu_sda_fedge : std_logic;
4853
signal cpu_sda_redge : std_logic;
4954
signal cpu_start_detected : std_logic;
5055
signal cpu_stop_detected : std_logic;
51-
signal cpu_busy : boolean;
52-
signal cpu_has_mux : boolean;
56+
signal cpu_busy : std_logic;
57+
signal cpu_has_mux : std_logic;
58+
signal cpu_first_start_seen : boolean;
59+
60+
signal dimm_scl_filt : std_logic;
61+
signal dimm_sda_filt : std_logic;
62+
signal dimm_sda_fedge : std_logic;
63+
signal dimm_sda_redge : std_logic;
64+
65+
signal cpu_sda_oe : std_logic;
66+
signal dimm_sda_oe : std_logic;
5367

54-
signal ctrlr_idle : std_logic;
5568
signal ctrlr_scl_if : tristate;
5669
signal ctrlr_sda_if : tristate;
5770
signal ctrlr_has_int_mux : boolean;
@@ -68,11 +81,34 @@ architecture rtl of spd_proxy_top is
6881
signal sda_sim : std_logic;
6982
signal sda_sim_fedge : std_logic;
7083
signal start_simulated : std_logic;
84+
85+
signal cpu_seen : boolean;
86+
signal fpga_txn_valid : std_logic;
87+
88+
signal cpu_has_sda : std_logic;
89+
signal dimm_has_sda : std_logic;
7190
begin
91+
dimm_glitch_filter_inst: entity work.i2c_glitch_filter
92+
generic map(
93+
filter_cycles => DIMM_I2C_TSP_CYCLES
94+
)
95+
port map(
96+
clk => clk,
97+
reset => reset,
98+
raw_scl => dimm_scl_if.i,
99+
raw_sda => dimm_sda_if.i,
100+
filtered_scl => dimm_scl_filt,
101+
scl_redge => open,
102+
scl_fedge => open,
103+
filtered_sda => dimm_sda_filt,
104+
sda_redge => dimm_sda_redge,
105+
sda_fedge => dimm_sda_fedge
106+
);
107+
72108
--
73109
-- CPU bus monitoring
74110
--
75-
i2c_glitch_filter_inst: entity work.i2c_glitch_filter
111+
cpu_glitch_filter_inst: entity work.i2c_glitch_filter
76112
generic map(
77113
filter_cycles => CPU_I2C_TSP_CYCLES
78114
)
@@ -82,9 +118,9 @@ begin
82118
raw_scl => cpu_scl_if.i,
83119
raw_sda => cpu_sda_if.i,
84120
filtered_scl => cpu_scl_filt,
85-
scl_redge => open,
121+
scl_redge => cpu_scl_redge,
86122
scl_fedge => cpu_scl_fedge,
87-
filtered_sda => open,
123+
filtered_sda => cpu_sda_filt,
88124
sda_redge => cpu_sda_redge,
89125
sda_fedge => cpu_sda_fedge
90126
);
@@ -97,22 +133,33 @@ begin
97133
bus_monitor: process(clk, reset)
98134
begin
99135
if reset then
100-
cpu_busy <= false;
101-
need_start <= false;
136+
cpu_busy <= '0';
137+
need_start <= false;
138+
cpu_first_start_seen <= false;
139+
cpu_seen <= false;
102140
elsif rising_edge(clk) then
103141
if cpu_start_detected then
104-
cpu_busy <= true;
142+
cpu_busy <= '1';
143+
cpu_first_start_seen <= true;
105144
elsif cpu_stop_detected then
106-
cpu_busy <= false;
145+
cpu_busy <= '0';
107146
end if;
108147

109148
-- The FPGA still owns the bus and the START hold time as elapsed. This means before
110149
-- the mux is swapped we need to simulate a START condition .
111-
if ctrlr_idle = '0' and cpu_scl_fedge = '1' then
150+
if i2c_ctrlr_idle = '0' and cpu_scl_fedge = '1' then
112151
need_start <= true;
113152
elsif start_simulated then
114153
need_start <= false;
115154
end if;
155+
156+
-- TODO: enabling the internal controller should probably just be an external thing
157+
-- from registers the SP can set. While proxy is not enabled, we should just assume the
158+
-- CPU always owns the bus.
159+
-- after the first START/STOP detection, register that we've seen CPU activity
160+
if cpu_first_start_seen and cpu_stop_detected = '1' and not cpu_seen then
161+
cpu_seen <= true;
162+
end if;
116163
end if;
117164
end process;
118165

@@ -158,6 +205,8 @@ begin
158205
done => start_simulated
159206
);
160207

208+
fpga_txn_valid <= '1' when cpu_seen and i2c_command_valid = '1' else '0';
209+
161210
-- FPGA I2C controller
162211
i2c_ctrl_txn_layer_inst: entity work.i2c_ctrl_txn_layer
163212
generic map(
@@ -170,34 +219,52 @@ begin
170219
scl_if => ctrlr_scl_if,
171220
sda_if => ctrlr_sda_if,
172221
cmd => i2c_command,
173-
cmd_valid => i2c_command_valid,
174-
abort => cpu_start_detected,
222+
cmd_valid => fpga_txn_valid,
223+
abort => cpu_busy,
175224
core_ready => i2c_ctrlr_idle,
176225
tx_st_if => i2c_tx_st_if,
177226
rx_st_if => i2c_rx_st_if
178227
);
179228

180-
-- This mux controls if the I2C controller or the simulated START generator control the
181-
-- FPGA internal I2C bux.
229+
-- for the internal bus, mux between our simulated start and internal controller
182230
ctrlr_has_int_mux <= not need_start or i2c_ctrlr_idle = '0';
183231
fpga_scl_if.o <= ctrlr_scl_if.o when ctrlr_has_int_mux else scl_sim;
184-
fpga_scl_if.oe <= ctrlr_scl_if.oe when ctrlr_has_int_mux else not scl_sim;
232+
fpga_scl_if.oe <= ctrlr_scl_if.oe when ctrlr_has_int_mux else '1';
185233
fpga_sda_if.o <= ctrlr_sda_if.o when ctrlr_has_int_mux else sda_sim;
186-
fpga_sda_if.oe <= ctrlr_sda_if.oe when ctrlr_has_int_mux else not sda_sim;
234+
fpga_sda_if.oe <= ctrlr_sda_if.oe when ctrlr_has_int_mux else '1';
235+
236+
-- Break the fpga input from the bus when it doesn't have the bus
237+
-- The I2C link layer filters SDA so we will feed it the unfiltered signal
238+
ctrlr_scl_if.i <= '1' when cpu_has_mux else dimm_scl_filt;
239+
ctrlr_sda_if.i <= '1' when cpu_has_mux else dimm_sda_if.i;
240+
fpga_scl_if.i <= ctrlr_scl_if.i;
241+
fpga_sda_if.i <= ctrlr_sda_if.i;
242+
243+
sda_arbiter_inst: entity work.sda_arbiter
244+
generic map(
245+
HYSTERESIS_CYCLES => DIMM_I2C_TSP_CYCLES + 7 -- 7 is a bit of a swag given Ruby testing
246+
)
247+
port map(
248+
clk => clk,
249+
reset => reset,
250+
a => cpu_sda_filt,
251+
b => dimm_sda_filt,
252+
enabled => cpu_has_mux,
253+
a_grant => cpu_has_sda,
254+
b_grant => dimm_has_sda
255+
);
187256

188-
-- Break the controller input from the bus when it does not have this mux
189-
ctrlr_scl_if.i <= fpga_scl_if.i when ctrlr_has_int_mux else '1';
190-
ctrlr_sda_if.i <= fpga_sda_if.i when ctrlr_has_int_mux else '1';
257+
cpu_has_mux <= '1' when cpu_busy = '1' and i2c_ctrlr_idle = '1' and not need_start
258+
else '0';
259+
dimm_scl_if.oe <= '1' when cpu_has_mux else fpga_scl_if.oe;
260+
dimm_scl_if.o <= cpu_scl_filt when cpu_has_mux else fpga_scl_if.o;
191261

192-
-- This mux controls if the CPU or the FPGA control the bus out to the DIMMs
193-
cpu_has_mux <= cpu_busy and i2c_ctrlr_idle = '1' and not need_start;
194-
dimm_scl_if.o <= cpu_scl_if.i when cpu_has_mux else fpga_scl_if.o;
195-
dimm_scl_if.oe <= not cpu_scl_if.i when cpu_has_mux else fpga_scl_if.oe;
196-
dimm_sda_if.o <= cpu_sda_if.i when cpu_has_mux else fpga_sda_if.o;
197-
dimm_sda_if.oe <= not cpu_sda_if.i when cpu_has_mux else fpga_sda_if.oe;
262+
dimm_sda_oe <= not cpu_sda_filt when cpu_has_sda else '0';
263+
dimm_sda_if.oe <= dimm_sda_oe when cpu_has_mux else fpga_sda_if.oe;
264+
dimm_sda_if.o <= '0' when cpu_has_mux else fpga_sda_if.o;
198265

199-
-- Break the fpga input from the bus when it doesn't have the bus
200-
fpga_scl_if.i <= '1' when cpu_has_mux else dimm_scl_if.i;
201-
fpga_sda_if.i <= '1' when cpu_has_mux else dimm_sda_if.i;
266+
cpu_sda_oe <= not dimm_sda_filt when dimm_has_sda else '0';
267+
cpu_sda_if.oe <= cpu_sda_oe when cpu_has_mux else '0';
268+
cpu_sda_if.o <= '0';
202269

203270
end architecture;

0 commit comments

Comments
 (0)