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

Adds the transaction and physical layers of an I2C controller #253

Merged
merged 3 commits into from
Dec 11, 2024
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
19 changes: 19 additions & 0 deletions hdl/ip/vhd/i2c/common/BUCK
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
load("//tools:hdl.bzl", "vhdl_unit", "vunit_sim")

vhdl_unit(
name = "i2c_common_pkg",
srcs = ["i2c_common_pkg.vhd"],
visibility = ['PUBLIC']
)

vhdl_unit(
name = "i2c_cmd_vc",
srcs = ["sims/i2c_cmd_vc.vhd", "sims/i2c_cmd_vc_pkg.vhd"],
visibility = ['PUBLIC']
)

vhdl_unit(
name = "i2c_target_vc",
srcs = ["sims/i2c_target_vc.vhd", "sims/i2c_target_vc_pkg.vhd"],
visibility = ['PUBLIC']
)
91 changes: 91 additions & 0 deletions hdl/ip/vhd/i2c/common/i2c_common_pkg.vhd
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
-- 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 2024 Oxide Computer Company

library ieee;
use ieee.std_logic_1164.all;

package i2c_common_pkg is

--
-- Link Layer
--

type mode_t is (
STANDARD, -- up to 100 Kbps
FAST, -- up to 400 Kbps
FAST_PLUS -- up to 1 Mbps
);

-- A group of settings for generics to generate constants
-- all times in nanoseconds (ns)
type settings_t is record
fscl_period_ns : positive; -- SCL clock period
sda_su_ns : positive; -- data set-up time
sta_su_hd_ns : positive; -- START set-up/hold time
sto_su_ns : positive; -- STOP set-up time
sto_sta_buf_ns : positive; -- bus free time between STOP and START
end record;

function get_i2c_settings (constant mode : mode_t) return settings_t;

--
-- Transaction Layer
--

type op_t is (
READ,
WRITE,
-- RANDOM_READ will write an address byte and one more byte (intended to set an internal
-- address register on a peripheral) before issuing a repeated start for a read.
RANDOM_READ
);

type cmd_t is record
op : op_t;
addr : std_logic_vector(6 downto 0);
reg : std_logic_vector(7 downto 0);
len : std_logic_vector(7 downto 0);
end record;
constant CMD_RESET : cmd_t := (READ, (others => '0'), (others => '0'), (others => '0'));

end package;

package body i2c_common_pkg is

function get_i2c_settings (constant mode : mode_t) return settings_t is
variable r : settings_t;
begin
case mode is
when STANDARD =>
r := (
10_000, -- 10^9 / 100_000Hz
250,
4700,
4000,
4700
);
when FAST =>
r := (
2500, -- 10^9 / 400_000Hz
100,
600,
600,
1300
);
when FAST_PLUS =>
r := (
1000, -- 10^9 / 1_000_000Hz
50,
260,
260,
500
);
end case;

return r;
end;

end package body;
67 changes: 67 additions & 0 deletions hdl/ip/vhd/i2c/common/sims/i2c_cmd_vc.vhd
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
-- 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 2024 Oxide Computer Company

library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;

library vunit_lib;
context vunit_lib.vunit_context;
context vunit_lib.com_context;
use vunit_lib.sync_pkg.all;

use work.i2c_common_pkg.all;
use work.i2c_cmd_vc_pkg.all;

entity i2c_cmd_vc is
generic (
i2c_cmd_vc : i2c_cmd_vc_t
);
port (
cmd : out cmd_t := CMD_RESET;
valid : out std_logic := '0';
ready : in std_logic;
);
end entity;

architecture model of i2c_cmd_vc is
begin

handle_messages: process
variable msg : msg_t;
variable msg_type : msg_type_t;
variable command : cmd_t;
variable is_read : boolean;
variable is_random : boolean;
begin
receive(net, i2c_cmd_vc.p_actor, msg);
msg_type := message_type(msg);

if msg_type = push_i2c_cmd_msg then
is_read := pop(msg);
is_random := pop(msg);
if is_read then
if is_random then
command.op := RANDOM_READ;
else
command.op := READ;
end if;
else
command.op := WRITE;
end if;
command.addr := pop(msg);
command.reg := pop(msg);
command.len := pop(msg);
cmd <= command;
valid <= '1';
wait until ready;
valid <= '0';
else
unexpected_msg_type(msg_type);
end if;
end process;

end architecture;
86 changes: 86 additions & 0 deletions hdl/ip/vhd/i2c/common/sims/i2c_cmd_vc_pkg.vhd
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
-- 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 2024 Oxide Computer Company

library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.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 vunit_lib.sync_pkg.all;

use work.i2c_common_pkg.all;

package i2c_cmd_vc_pkg is

type i2c_cmd_vc_t is record
-- private
p_actor : actor_t;
p_logger : logger_t;
end record;

constant i2c_cmd_vc_logger : logger_t := get_logger("work:i2c_cmd_vc_pkg");

impure function new_i2c_cmd_vc(
actor : actor_t := null_actor;
logger : logger_t := i2c_cmd_vc_logger;
) return i2c_cmd_vc_t;

constant push_i2c_cmd_msg : msg_type_t := new_msg_type("push_i2c_cmd");

procedure push_i2c_cmd(
signal net : inout network_t;
i2c_cmd_vc : i2c_cmd_vc_t;
cmd : cmd_t;
);

end package;

package body i2c_cmd_vc_pkg is

impure function new_i2c_cmd_vc(
actor : actor_t := null_actor;
logger : logger_t := i2c_cmd_vc_logger;
) return i2c_cmd_vc_t is
variable p_actor : actor_t;
begin
p_actor := actor when actor /= null_actor else new_actor;

return (
p_actor => p_actor,
p_logger => logger
);
end function;

procedure push_i2c_cmd(
signal net : inout network_t;
i2c_cmd_vc : i2c_cmd_vc_t;
cmd : cmd_t
) is
variable msg : msg_t := new_msg(push_i2c_cmd_msg);
variable is_read : boolean;
variable is_random : boolean;
begin
-- breaking down our type since we can't push enums in VUnit
is_read := false when cmd.op = WRITE else true;
is_random := true when cmd.op = RANDOM_READ else false;

-- We break down cmd_t into it's primitive types to push them into the message where we will
-- pop them off when we receive it in order to reconstruct a cmd_t.
-- TODO: implement push/pop for our custom type so we wouldn't have to do this?
push(msg, is_read); -- boolean
push(msg, is_random); -- boolean
push(msg, cmd.addr); -- std_logic_vector
push(msg, cmd.reg); -- std_logic_vector
push(msg, cmd.len); -- std_logic_vector
send(net, i2c_cmd_vc.p_actor, msg);
end;


end package body;
Loading