Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add an SPD proxy mux #294

Merged
merged 1 commit into from
Feb 21, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
31 changes: 17 additions & 14 deletions hdl/ip/vhd/i2c/controller/link_layer/i2c_ctrl_link_layer.vhd
Original file line number Diff line number Diff line change
Expand Up @@ -293,21 +293,11 @@ begin
v.sda_oe := '0';

if tx_start then
v.state := WAIT_TBUF;
v.counter := STO_TO_STA_BUF_TICKS;
v.count_load := '1';
end if;

-- Wait out tbuf to ensure STOP/START spacing
when WAIT_TBUF =>
if sm_count_done then
-- tbuf is always greater than or equal to the START setup requirement, skip to
-- hold
-- Coming back to IDLE after a transaction means we've waited out tbuf, and tbuf
-- is always greater than or equal to the START setup requirement, skip to hold
v.state := START_HOLD;
v.counter := START_SETUP_HOLD_TICKS;
v.count_load := '1';
else
v.count_decr := '1';
end if;

when WAIT_REPEAT_START =>
Expand Down Expand Up @@ -369,7 +359,9 @@ begin
v.state := ACK_RX;
v.bits_shifted := 0;
elsif v.stop_requested then
v.state := STOP_SDA;
-- this is a valid SDA transition cycle so drive SDA low and skip STOP_SDA
v.state := STOP_SCL;
v.sda_oe := '1';
else
v.sda_oe := not sm_reg.tx_data(7);
v.tx_data := sm_reg.tx_data(sm_reg.tx_data'high-1 downto sm_reg.tx_data'low) & '1';
Expand Down Expand Up @@ -433,7 +425,18 @@ begin

when STOP_SETUP =>
if sm_count_done then
v := SM_REG_RESET;
v.state := WAIT_TBUF;
v.counter := STO_TO_STA_BUF_TICKS;
v.count_load := '1';
v.sda_oe := '0';
else
v.count_decr := '1';
end if;

-- Wait out tbuf to ensure STOP/START spacing
when WAIT_TBUF =>
if sm_count_done then
v := SM_REG_RESET;
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For context as to why I moved WAIT_TBUF to be after the STOP states: since we indicate controller business by "if I'm not in IDLE", this keeps the controller from advertising it is ready for another transaction until it can actually execute that transaction. Behavior today is that it will accept the new transaction but then wait for TBUF anyway.

else
v.count_decr := '1';
end if;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,6 @@ library vunit_lib;
context vunit_lib.com_context;
context vunit_lib.vc_context;

use work.i2c_common_pkg.all;
use work.i2c_common_pkg.all;
use work.tristate_if_pkg.all;
use work.stream8_pkg;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -120,7 +120,7 @@ begin
sda <= 'Z';
wait for 60 ns; -- need to be longer than 50ns glitch timing
sda <= '0';
wait for thd_sta * 4;
wait for thd_sta;
wait until falling_edge(aligner_int);
scl <= '0'; -- scl is now low, ready for bits
wait for 60 ns; -- need to be longer than 50ns glitch timing
Expand Down
27 changes: 27 additions & 0 deletions hdl/projects/cosmo_seq/spd_proxy/BUCK
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
load("//tools:hdl.bzl", "vhdl_unit", "vunit_sim")

vhdl_unit(
name = "spd_proxy_top",
srcs = glob(["*.vhd"]),
deps = [
"//hdl/ip/vhd/common:tristate_if_pkg",
"//hdl/ip/vhd/i2c/common:i2c_common_pkg",
"//hdl/ip/vhd/i2c/common:i2c_glitch_filter",
"//hdl/ip/vhd/i2c/controller:i2c_ctrl_txn_layer",
],
standard = "2019",
visibility = ['PUBLIC']
)

vunit_sim(
name = "spd_proxy_top_tb",
srcs = glob(["sims/*.vhd"]),
deps = [
":spd_proxy_top",
"//hdl/ip/vhd/vunit_components:basic_stream",
"//hdl/ip/vhd/vunit_components:i2c_cmd_vc",
"//hdl/ip/vhd/vunit_components:i2c_target_vc",
"//hdl/ip/vhd/vunit_components:i2c_controller_vc"
],
visibility = ['PUBLIC'],
)
75 changes: 75 additions & 0 deletions hdl/projects/cosmo_seq/spd_proxy/sims/spd_proxy_top_tb.gtkw
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
[*]
[*] GTKWave Analyzer v3.3.104 (w)1999-2020 BSI
[*] Wed Feb 19 22:29:57 2025
[*]
[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"
[dumpfile_mtime] "Wed Feb 19 22:23:27 2025"
[dumpfile_size] 5095
[savefile] "/home/aaron/Oxide/git/quartz/hdl/projects/cosmo_seq/spd_proxy/sims/spd_proxy_top_tb.gtkw"
[timestart] 0
[size] 2816 1283
[pos] 1074 -22
*-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
[treeopen] spd_proxy_top_tb.
[treeopen] spd_proxy_top_tb.th.
[treeopen] spd_proxy_top_tb.th.spd_proxy_top_inst.
[treeopen] spd_proxy_top_tb.th.spd_proxy_top_inst.i2c_ctrl_txn_layer_inst.
[treeopen] spd_proxy_top_tb.th.spd_proxy_top_inst.i2c_ctrl_txn_layer_inst.i2c_ctrl_link_layer_inst.
[sst_width] 281
[signals_width] 337
[sst_expanded] 1
[sst_vpaned_height] 382
@200
-CPU Bus
@28
spd_proxy_top_tb.th.i2c_controller_vc_inst.state
spd_proxy_top_tb.th.cpu_scl
spd_proxy_top_tb.th.cpu_sda
@200
-
-DIMM Bus
@28
spd_proxy_top_tb.th.i2c_target_vc_inst.state
spd_proxy_top_tb.th.dimm_scl
spd_proxy_top_tb.th.dimm_sda
@200
-
-FPGA Bus
@28
spd_proxy_top_tb.th.spd_proxy_top_inst.fpga_scl_if.i
spd_proxy_top_tb.th.spd_proxy_top_inst.fpga_sda_if.i
@200
-
-SPD Proxy Logic
@28
spd_proxy_top_tb.th.spd_proxy_top_inst.cpu_start_detected
spd_proxy_top_tb.th.spd_proxy_top_inst.cpu_stop_detected
spd_proxy_top_tb.th.spd_proxy_top_inst.cpu_busy
spd_proxy_top_tb.th.spd_proxy_top_inst.cpu_has_mux
spd_proxy_top_tb.th.spd_proxy_top_inst.ctrlr_has_int_mux
@200
-
-Simulated START State
@28
spd_proxy_top_tb.th.spd_proxy_top_inst.scl_sim
spd_proxy_top_tb.th.spd_proxy_top_inst.sda_sim
@29
spd_proxy_top_tb.th.spd_proxy_top_inst.sda_sim_fedge
@28
spd_proxy_top_tb.th.spd_proxy_top_inst.need_start
spd_proxy_top_tb.th.spd_proxy_top_inst.start_simulated
@200
-
-Internal I2C Controller
-Transaction Layer
@28
spd_proxy_top_tb.th.spd_proxy_top_inst.i2c_ctrl_txn_layer_inst.abort
spd_proxy_top_tb.th.spd_proxy_top_inst.i2c_ctrl_txn_layer_inst.sm_reg.do_stop
spd_proxy_top_tb.th.spd_proxy_top_inst.i2c_ctrl_txn_layer_inst.sm_reg.state
@200
-Link Layer
@28
spd_proxy_top_tb.th.spd_proxy_top_inst.i2c_ctrl_txn_layer_inst.i2c_ctrl_link_layer_inst.sm_reg.stop_requested
spd_proxy_top_tb.th.spd_proxy_top_inst.i2c_ctrl_txn_layer_inst.i2c_ctrl_link_layer_inst.sm_reg.state
[pattern_trace] 1
[pattern_trace] 0
129 changes: 129 additions & 0 deletions hdl/projects/cosmo_seq/spd_proxy/sims/spd_proxy_top_tb.vhd
Original file line number Diff line number Diff line change
@@ -0,0 +1,129 @@
-- This Source Code Form is subject to the terms of the Mozilla Public
-- License, v. 2.0. If a copy of the MPL was not distributed with this
-- file, You can obtain one at https://mozilla.org/MPL/2.0/.
--
-- Copyright 2025 Oxide Computer Company

library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std_unsigned.all;

library osvvm;
use osvvm.RandomPkg.RandomPType;

library vunit_lib;
context vunit_lib.com_context;
context vunit_lib.vunit_context;
context vunit_lib.vc_context;

-- VCs
use work.basic_stream_pkg.all;
use work.i2c_cmd_vc_pkg.all;
use work.i2c_common_pkg.all;
use work.i2c_ctrl_vc_pkg.all;
use work.i2c_target_vc_pkg.all;

use work.spd_proxy_top_tb_pkg.all;

entity spd_proxy_top_tb is
generic (
runner_cfg : string
);
end entity;

architecture tb of spd_proxy_top_tb is
begin

th: entity work.spd_proxy_top_th;

bench: process
alias reset is << signal th.reset : std_logic >>;
variable rnd : RandomPType;
variable i2c_ctrlr_msg : msg_t;

variable command : cmd_t;
variable ack : boolean := false;

variable data : std_logic_vector(7 downto 0);
variable exp_addr : std_logic_vector(7 downto 0);
variable exp_data : std_logic_vector(7 downto 0);
variable byte_len : natural;
variable byte_idx : natural;

variable cpu_tx_q : queue_t := new_queue;
variable cpu_ack_q : queue_t := new_queue;
variable fpga_tx_q : queue_t := new_queue;
variable fpga_exp_q : queue_t := new_queue;

-- helper to get the internal FPGA controller doing _something_ before we have the CPU
-- attempting to interrupt
procedure init_controller is
begin
-- arbitrary for the test
exp_addr := X"00";
byte_len := 8;
for i in 0 to byte_len - 1 loop
push_byte(fpga_tx_q, rnd.RandInt(0, 255));
end loop;
fpga_exp_q := copy(fpga_tx_q);

-- write some data in
command := (
op => WRITE,
addr => address(I2C_TGT_VC),
reg => std_logic_vector(exp_addr),
len => to_std_logic_vector(byte_len, command.len'length)
);
issue_i2c_cmd(net, command, fpga_tx_q);
end procedure;
begin
-- Always the first thing in the process, set up things for the VUnit test runner
test_runner_setup(runner, runner_cfg);
-- Reach into the test harness, which generates and de-asserts reset and hold the
-- test cases off until we're out of reset. This runs for every test case
wait until reset = '0';
wait for 500 ns; -- let the resets propagate

while test_suite loop
if run("no_cpu_transaction") then
init_controller;

byte_idx := to_integer(exp_addr);
while not is_empty(fpga_exp_q) loop
data := to_std_logic_vector(pop_byte(fpga_exp_q), data'length);
exp_addr := to_std_logic_vector(byte_idx, exp_addr'length);
check_written_byte(net, I2C_TGT_VC, data, exp_addr);
byte_idx := byte_idx + 1;
end loop;

expect_stop(net, I2C_TGT_VC);
elsif run("cpu_transaction") then
-- Get the FPGA controller started on a transaction
init_controller;

-- At some point into the transaction, have the CPU start its own
wait for rnd.RandInt(500, 4000) * 1 ns;

push_byte(cpu_tx_q, to_integer(rnd.RandSlv(0, 255, 8)));
i2c_write_txn(net, address(I2C_TGT_VC), cpu_tx_q, cpu_ack_q, I2C_CTRL_VC.p_actor);

elsif run("cpu_with_simulated_start") then
-- Get the FPGA controller started on a transaction
init_controller;

-- At some point into the transaction, have the CPU start its own
wait for 9500 ns;

push_byte(cpu_tx_q, to_integer(rnd.RandSlv(0, 255, 8)));
i2c_write_txn(net, address(I2C_TGT_VC), cpu_tx_q, cpu_ack_q, I2C_CTRL_VC.p_actor);
end if;
end loop;

wait for 2 us;
test_runner_cleanup(runner);
wait;
end process;

test_runner_watchdog(runner, 10 ms);

end architecture;
59 changes: 59 additions & 0 deletions hdl/projects/cosmo_seq/spd_proxy/sims/spd_proxy_top_tb_pkg.vhd
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
-- This Source Code Form is subject to the terms of the Mozilla Public
-- License, v. 2.0. If a copy of the MPL was not distributed with this
-- file, You can obtain one at https://mozilla.org/MPL/2.0/.
--
-- Copyright 2025 Oxide Computer Company

library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std_unsigned.all;

library vunit_lib;
context vunit_lib.vunit_context;
context vunit_lib.com_context;
context vunit_lib.vc_context;

use work.i2c_cmd_vc_pkg.all;
use work.i2c_ctrl_vc_pkg.all;
use work.i2c_target_vc_pkg.all;
use work.basic_stream_pkg.all;

use work.i2c_common_pkg.all;

package spd_proxy_top_tb_pkg is
-- Constants
constant CLK_PER_NS : positive := 8;

-- Verification Components
constant I2C_CTRL_VC : i2c_ctrl_vc_t := new_i2c_ctrl_vc("cpu_i2c_vc");
constant I2C_TGT_VC : i2c_target_vc_t := new_i2c_target_vc("dimm_i2c_vc");
constant I2C_CMD_VC : i2c_cmd_vc_t := new_i2c_cmd_vc;
constant TX_DATA_SOURCE_VC : basic_source_t := new_basic_source(8);
constant RX_DATA_SINK_VC : basic_sink_t := new_basic_sink(8);

procedure issue_i2c_cmd (
signal net : inout network_t;
constant command : cmd_t;
constant tx_data : queue_t;
);

end package;

package body spd_proxy_top_tb_pkg is

procedure issue_i2c_cmd (
signal net : inout network_t;
constant command : cmd_t;
constant tx_data : queue_t;
) is
variable ack : boolean := FALSE;
begin
push_i2c_cmd(net, I2C_CMD_VC, command);
start_byte_ack(net, I2C_TGT_VC, ack);
check_true(ack, "Peripheral did not ACK correct address");
while not is_empty(tx_data) loop
push_basic_stream(net, TX_DATA_SOURCE_VC, to_std_logic_vector(pop_byte(tx_data), 8));
end loop;
end procedure;

end package body;
Loading