@@ -40,18 +40,31 @@ entity spd_proxy_top is
4040end entity ;
4141
4242architecture 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 ;
7190begin
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 )
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
203270end architecture ;
0 commit comments