From d5d04ae8030653ed137122705eb7cb8491a9e993 Mon Sep 17 00:00:00 2001 From: Aaron-Hartwig Date: Wed, 4 Dec 2024 18:26:53 -0600 Subject: [PATCH] wip --- hdl/ip/vhd/i2c/BUCK | 8 + hdl/ip/vhd/i2c/i2c_core_regs.rdl | 51 ++++ hdl/ip/vhd/i2c/i2c_core_regs.vhd | 71 ++++++ .../i2c/{i2c_core.vhd => i2c_core_top.vhd} | 4 +- hdl/ip/vhd/i2c/sims/i2c_cmd_vc.vhd | 67 ----- hdl/ip/vhd/i2c/sims/i2c_cmd_vc_pkg.vhd | 82 ------ hdl/ip/vhd/i2c/sims/i2c_peripheral.vhd | 237 ------------------ hdl/ip/vhd/i2c/sims/i2c_peripheral_pkg.vhd | 165 ------------ .../i2c/sims/txn_layer/i2c_txn_layer_tb.gtkw | 161 ------------ .../i2c/sims/txn_layer/i2c_txn_layer_tb.vhd | 175 ------------- .../i2c/sims/txn_layer/i2c_txn_layer_th.vhd | 160 ------------ 11 files changed, 132 insertions(+), 1049 deletions(-) create mode 100644 hdl/ip/vhd/i2c/i2c_core_regs.rdl create mode 100644 hdl/ip/vhd/i2c/i2c_core_regs.vhd rename hdl/ip/vhd/i2c/{i2c_core.vhd => i2c_core_top.vhd} (94%) delete mode 100644 hdl/ip/vhd/i2c/sims/i2c_cmd_vc.vhd delete mode 100644 hdl/ip/vhd/i2c/sims/i2c_cmd_vc_pkg.vhd delete mode 100644 hdl/ip/vhd/i2c/sims/i2c_peripheral.vhd delete mode 100644 hdl/ip/vhd/i2c/sims/i2c_peripheral_pkg.vhd delete mode 100644 hdl/ip/vhd/i2c/sims/txn_layer/i2c_txn_layer_tb.gtkw delete mode 100644 hdl/ip/vhd/i2c/sims/txn_layer/i2c_txn_layer_tb.vhd delete mode 100644 hdl/ip/vhd/i2c/sims/txn_layer/i2c_txn_layer_th.vhd diff --git a/hdl/ip/vhd/i2c/BUCK b/hdl/ip/vhd/i2c/BUCK index f8f59246..ac60c1c2 100644 --- a/hdl/ip/vhd/i2c/BUCK +++ b/hdl/ip/vhd/i2c/BUCK @@ -1,4 +1,12 @@ load("//tools:hdl.bzl", "vhdl_unit", "vunit_sim") +load("//tools:rdl.bzl", "rdl_file") + +rdl_file( + name = "i2c_core_regs_pkg", + src = "i2c_core_regs.rdl", + outputs = ["i2c_core_regs_pkg.vhd", "i2c_core_regs.html"], + visibility = ['PUBLIC'] +) vhdl_unit( name = "i2c_txn_layer", diff --git a/hdl/ip/vhd/i2c/i2c_core_regs.rdl b/hdl/ip/vhd/i2c/i2c_core_regs.rdl new file mode 100644 index 00000000..39f9037c --- /dev/null +++ b/hdl/ip/vhd/i2c/i2c_core_regs.rdl @@ -0,0 +1,51 @@ +// Copyright 2024 Oxide Computer Company +// This is a SystemRDL description of the SW-accessible registers for the I2C core. + +addrmap i2c_core_regs { + name = "I2C core registers"; + desc = "Registers accessible on the AXI bus for interacting with the I2C core."; + + default regwidth = 32; + default sw = rw; + default hw = r; + + reg { + name = "Receive data"; + default sw = r; + default hw = rw; + + field { + desc = "Last 4 bytes recieved"; + } DATA[31:0] = 0; + } RXD; + + reg { + name = "Transmit data"; + default sw = r; + default hw = rw; + + field { + desc = "Next 4 bytes to send"; + } DATA[31:0] = 0; + } TXD; + + reg { + name = "Control bits for I2C communication."; + + field { + desc = "Number of bytes to read/write in the I2C transaction. up to 128 bytes."; + } COUNT[22:16] = 1; + + field { + desc = "I2C Address of target"; + } ADDR[14:8] = 0; + + field { + desc = "2'b00 to read, 2'b01 to write, 2'b10 to random-read."; + } OP[2:1] = 0; + + field { + desc = "'1' to start next transaction."; + } START[0:0] = 0; + } CONTROL; +}; \ No newline at end of file diff --git a/hdl/ip/vhd/i2c/i2c_core_regs.vhd b/hdl/ip/vhd/i2c/i2c_core_regs.vhd new file mode 100644 index 00000000..cb77c092 --- /dev/null +++ b/hdl/ip/vhd/i2c/i2c_core_regs.vhd @@ -0,0 +1,71 @@ +-- 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 + +-- AXI-accessible registers for the I2C block + +library ieee; +use ieee.std_logic_1164.all; +use ieee.numeric_std.all; +use ieee.numeric_std_unsigned.all; + +use work.axil8x32_pkg.all; + +use work.i2c_core_regs_pkg.all; + +entity i2c_core_regs is + port ( + clk : in std_logic; + reset : in std_logic; + axi_if : view axil_target; + ); +end entity; + +architecture rtl of i2c_core_regs is + constant AXI_OKAY : std_logic_vector(1 downto 0) := "00"; + signal axi_read_ready_int : std_logic; + signal axi_awready : std_logic; + signal axi_wready : std_logic; + signal axi_bvalid : std_logic; + signal axi_bready : std_logic; + signal axi_arready : std_logic; + signal axi_rvalid : std_logic; + signal axi_rdata : std_logic_vector(31 downto 0); +begin + + -- AXI wiring + axi_if.write_response.resp <= AXI_OKAY; + axi_if.write_response.valid <= axi_bvalid; + axi_if.read_data.resp <= AXI_OKAY; + axi_if.write_data.ready <= axi_wready; + axi_if.write_address.ready <= axi_awready; + axi_if.read_address.ready <= axi_arready; + axi_if.read_data.data <= axi_rdata; + axi_if.read_data.valid <= axi_rvalid; + + axi_bready <= axi_if.write_response.ready; + axi_wready <= awready; + axi_arready <= not rvalid; + axi_read_ready_int <= axi_if.read_address.valid and axi_arready; + + axi: process(clk, reset) + begin + if reset then + axi_awready <= '0'; + axi_bvalid <= '0'; + axi_rvalid <= '0'; + elsif rising_edge(clk) then + + -- bvalid is set on every write and then cleared after bv + if axi_awready then + axi_bvalid <= '1'; + elsif axi_bready then + axi_bvalid <= '0'; + end if; + + end if; + end process; + +end architecture; \ No newline at end of file diff --git a/hdl/ip/vhd/i2c/i2c_core.vhd b/hdl/ip/vhd/i2c/i2c_core_top.vhd similarity index 94% rename from hdl/ip/vhd/i2c/i2c_core.vhd rename to hdl/ip/vhd/i2c/i2c_core_top.vhd index ced6d563..6a75eb31 100644 --- a/hdl/ip/vhd/i2c/i2c_core.vhd +++ b/hdl/ip/vhd/i2c/i2c_core_top.vhd @@ -11,7 +11,7 @@ use work.tristate_if_pkg; use work.i2c_common_pkg; -entity i2c_core is +entity i2c_core_top is generic ( CLK_PER_NS : positive; MODE : mode_t; @@ -28,7 +28,7 @@ entity i2c_core is ); end entity; -architecture rtl of i2c_core is +architecture rtl of i2c_core_top is begin diff --git a/hdl/ip/vhd/i2c/sims/i2c_cmd_vc.vhd b/hdl/ip/vhd/i2c/sims/i2c_cmd_vc.vhd deleted file mode 100644 index 12ee43c4..00000000 --- a/hdl/ip/vhd/i2c/sims/i2c_cmd_vc.vhd +++ /dev/null @@ -1,67 +0,0 @@ --- 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; \ No newline at end of file diff --git a/hdl/ip/vhd/i2c/sims/i2c_cmd_vc_pkg.vhd b/hdl/ip/vhd/i2c/sims/i2c_cmd_vc_pkg.vhd deleted file mode 100644 index 2bb642cd..00000000 --- a/hdl/ip/vhd/i2c/sims/i2c_cmd_vc_pkg.vhd +++ /dev/null @@ -1,82 +0,0 @@ --- 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; - push(msg, is_read); - push(msg, is_random); - push(msg, cmd.addr); - push(msg, cmd.reg); - push(msg, cmd.len); - send(net, i2c_cmd_vc.p_actor, msg); - end; - - -end package body; \ No newline at end of file diff --git a/hdl/ip/vhd/i2c/sims/i2c_peripheral.vhd b/hdl/ip/vhd/i2c/sims/i2c_peripheral.vhd deleted file mode 100644 index bf5bf065..00000000 --- a/hdl/ip/vhd/i2c/sims/i2c_peripheral.vhd +++ /dev/null @@ -1,237 +0,0 @@ --- 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; - context vunit_lib.vc_context; -use vunit_lib.sync_pkg.all; - -use work.tristate_if_pkg.all; - -use work.i2c_peripheral_pkg.all; - -entity i2c_peripheral is - generic ( - i2c_peripheral_vc : i2c_peripheral_t - ); - port ( - -- Tri-state signals to I2C interface - scl_if : view tristate_if; - sda_if : view tristate_if; - ); -end entity; - -architecture model of i2c_peripheral is - - type state_t is ( - IDLE, - START, - SEND_ACK, - SEND_NACK, - SEND_BYTE, - GET_START_BYTE, - GET_BYTE, - GET_ACK, - GET_STOP - ); - - signal state : state_t := IDLE; - - signal start_condition : boolean := FALSE; - signal stop_condition : boolean := FALSE; - signal sda_last : std_logic := '1'; - signal rx_data : std_logic_vector(7 downto 0) := (others => '0'); - signal rx_bit_count : unsigned(3 downto 0) := (others => '0'); - signal rx_done : boolean := FALSE; - signal rx_ackd : boolean := FALSE; - signal tx_data : std_logic_vector(7 downto 0) := (others => '0'); - signal tx_bit_count : unsigned(3 downto 0) := (others => '0'); - signal tx_done : boolean := FALSE; - - signal scl_oe : std_logic := '0'; - signal sda_oe : std_logic := '0'; - - signal reg_addr : unsigned(7 downto 0) := (others => '0'); - signal addr_set : boolean := FALSE; - signal addr_incr : boolean := FALSE; -begin - -- I2C interface is open-drain - scl_if.o <= '0'; - sda_if.o <= '0'; - - scl_if.oe <= scl_oe; - sda_if.oe <= sda_oe; - - start_condition <= sda_last = '1' and sda_if.i = '0' and scl_if.i = '1'; - stop_condition <= sda_last = '0' and sda_if.i = '1' and scl_if.i = '1'; - - -- sample SDA regularly to catch transitions - sda_monitor: process - begin - wait for 20 ns; - sda_last <= sda_if.i; - end process; - - transaction_sm: process - variable event_msg : msg_t; - variable is_read : boolean := FALSE; - variable reg_addr_v : unsigned(7 downto 0) := (others => '0'); - variable stop_during_write : boolean := FALSE; - begin - case state is - - when IDLE => - wait on start_condition; - state <= START; - - when START => - event_msg := new_msg(got_start); - send(net, i2c_peripheral_vc.p_actor, event_msg); - state <= GET_START_BYTE; - - when GET_START_BYTE => - wait on rx_done; - if rx_data(7 downto 1) = address(i2c_peripheral_vc) then - state <= SEND_ACK; - is_read := rx_data(0) = '1'; - event_msg := new_msg(address_matched); - send(net, i2c_peripheral_vc.p_actor, event_msg); - else - state <= SEND_NACK; - event_msg := new_msg(address_different); - send(net, i2c_peripheral_vc.p_actor, event_msg); - end if; - - when GET_BYTE => - wait until rx_done or start_condition or stop_condition; - - if start_condition then - state <= START; - elsif stop_condition then - state <= GET_STOP; - stop_during_write := TRUE; - else - state <= SEND_ACK; - - if addr_incr then - reg_addr_v := reg_addr + 1; - end if; - - if addr_set then - write_word(memory(i2c_peripheral_vc), to_integer(reg_addr_v), rx_data); - event_msg := new_msg(got_byte); - send(net, i2c_peripheral_vc.p_actor, event_msg); - addr_incr <= TRUE; - else - addr_set <= TRUE; - reg_addr_v := unsigned(rx_data); - end if; - end if; - - when SEND_ACK => - wait until falling_edge(scl_if.i) and tx_done; - if is_read then - state <= SEND_BYTE; - else - state <= GET_BYTE; - end if; - - when SEND_NACK => - wait until falling_edge(scl_if.i); - state <= GET_STOP; - - when SEND_BYTE => - wait until falling_edge(scl_if.i) and tx_done; - reg_addr_v := reg_addr + 1; - state <= GET_ACK; - - when GET_ACK => - wait on rx_done; - state <= SEND_BYTE when rx_ackd else GET_STOP; - - when GET_STOP => - wait until (stop_condition or stop_during_write); - event_msg := new_msg(got_stop); - send(net, i2c_peripheral_vc.p_actor, event_msg); - state <= IDLE; - addr_set <= FALSE; - addr_incr <= FALSE; - stop_during_write := FALSE; - - end case; - - reg_addr <= reg_addr_v; - - wait for 1 fs; - end process; - - receive_sm: process - begin - wait until rising_edge(scl_if.i); - rx_done <= FALSE; - if state = GET_ACK then - -- '0' = ACK, '1' = NACK - rx_ackd <= TRUE when sda_if.i = '0' else FALSE; - rx_bit_count <= to_unsigned(1, rx_bit_count'length); - elsif state = GET_START_BYTE or state = GET_BYTE then - rx_data <= sda_if.i & rx_data(7 downto 1); - rx_bit_count <= rx_bit_count + 1; - end if; - - wait until falling_edge(scl_if.i) or start_condition or stop_condition; - if not falling_edge(scl_if.i) then - rx_bit_count <= (others => '0'); - wait until falling_edge(scl_if.i); - end if; - - if ((state = GET_START_BYTE or state = GET_BYTE) and rx_bit_count = 8) or - (state = GET_ACK and rx_bit_count = 1) then - rx_done <= TRUE; - rx_bit_count <= (others => '0'); - end if; - end process; - - - transmit_sm: process - variable txd : std_logic_vector(7 downto 0) := (others => '0'); - begin - wait until falling_edge(scl_if.i); - tx_done <= FALSE; - -- delay the SDA transition to a bit after SCL falls to allow the controller to release SDA - wait for 100 ns; - if state = SEND_ACK or state = SEND_NACK then - sda_oe <= '1' when state = SEND_ACK else '0'; - tx_bit_count <= to_unsigned(1, tx_bit_count'length); - elsif state = SEND_BYTE then - if tx_bit_count = 0 then - txd := read_word(i2c_peripheral_vc.p_buffer.p_memory_ref, natural(to_integer(reg_addr)), 1); - else - txd := '1' & tx_data(7 downto 1); - end if; - sda_oe <= not txd(0); - tx_bit_count <= tx_bit_count + 1; - else - -- release the bus - sda_oe <= '0'; - end if; - tx_data <= txd; - - wait until rising_edge(scl_if.i); - - if ((state = SEND_ACK or state = SEND_NACK) and tx_bit_count = 1) or - (state = SEND_BYTE and tx_bit_count = 8) then - tx_done <= TRUE; - tx_bit_count <= (others => '0'); - end if; - - end process; - -end architecture; \ No newline at end of file diff --git a/hdl/ip/vhd/i2c/sims/i2c_peripheral_pkg.vhd b/hdl/ip/vhd/i2c/sims/i2c_peripheral_pkg.vhd deleted file mode 100644 index 31eafdfe..00000000 --- a/hdl/ip/vhd/i2c/sims/i2c_peripheral_pkg.vhd +++ /dev/null @@ -1,165 +0,0 @@ --- 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; - context vunit_lib.vc_context; - -package i2c_peripheral_pkg is - - -- Message definitions - constant got_start : msg_type_t := new_msg_type("got_start"); - constant address_matched : msg_type_t := new_msg_type("address_matched"); - constant address_different : msg_type_t := new_msg_type("address_different"); - constant send_ack : msg_type_t := new_msg_type("send_ack"); - constant got_ack : msg_type_t := new_msg_type("got_ack"); - constant got_byte : msg_type_t := new_msg_type("got_byte"); - constant got_stop : msg_type_t := new_msg_type("got_stop"); - - type i2c_peripheral_t is record - -- private - p_actor : actor_t; - p_buffer : buffer_t; - p_logger : logger_t; - -- I2C peripheral address - P_address : std_logic_vector(6 downto 0); - end record; - - constant i2c_peripheral_vc_logger : logger_t := get_logger("work:i2c_peripheral_vc"); - - impure function new_i2c_peripheral_vc ( - name : string; - address : std_logic_vector(6 downto 0) := b"1010101"; - logger : logger_t := i2c_peripheral_vc_logger - ) return i2c_peripheral_t; - - impure function address (i2c_periph: i2c_peripheral_t) return std_logic_vector; - impure function buf (i2c_periph: i2c_peripheral_t) return buffer_t; - impure function memory (i2c_periph: i2c_peripheral_t) return memory_t; - - procedure expect_message ( - signal net : inout network_t; - constant vc : i2c_peripheral_t; - constant expected_msg : msg_type_t; - ); - - procedure expect_stop ( - signal net : inout network_t; - constant vc : i2c_peripheral_t; - ); - - procedure start_byte_ack ( - signal net : inout network_t; - constant vc : i2c_peripheral_t; - variable ack : out boolean; - ); - - procedure check_written_byte ( - signal net : inout network_t; - constant vc : i2c_peripheral_t; - variable data : std_logic_vector; - variable addr : unsigned; - ); - -end package; - -package body i2c_peripheral_pkg is - - impure function new_i2c_peripheral_vc ( - name : string; - address : std_logic_vector(6 downto 0) := b"1010101"; - logger : logger_t := i2c_peripheral_vc_logger - ) return i2c_peripheral_t is - variable buf : buffer_t; - begin - -- I2C can address 256 bytes, so construct an internal buffer to reflect that - buf := allocate(new_memory, 256, name & "_MEM", 8, read_and_write); - - return ( - p_actor => new_actor(name), - p_buffer => buf, - p_logger => logger, - p_address => address - ); - end; - - impure function address (i2c_periph: i2c_peripheral_t) return std_logic_vector is - begin - return i2c_periph.p_address; - end function; - - impure function buf (i2c_periph: i2c_peripheral_t) return buffer_t is - begin - return i2c_periph.p_buffer; - end function; - - impure function memory (i2c_periph: i2c_peripheral_t) return memory_t is - begin - return i2c_periph.p_buffer.p_memory_ref; - end function; - - procedure expect_message ( - signal net : inout network_t; - constant vc : i2c_peripheral_t; - constant expected_msg : msg_type_t; - ) is - variable msg : msg_t; - variable matched : boolean; - begin - receive(net, vc.p_actor, msg); - matched := message_type(msg) = expected_msg; - check_true(matched, "Received message did not match expected message."); - end procedure; - - procedure expect_stop ( - signal net : inout network_t; - constant vc : i2c_peripheral_t; - ) is - begin - expect_message(net, vc, got_stop); - end procedure; - - procedure start_byte_ack ( - signal net : inout network_t; - constant vc : i2c_peripheral_t; - variable ack : out boolean; - ) is - variable msg : msg_t; - begin - -- receive START event - receive(net, vc.p_actor, msg); - if message_type(msg) = got_start then - -- receive START byte ack - receive(net, vc.p_actor, msg); - if message_type(msg) = address_matched then - ack := true; - elsif message_type(msg) = address_different then - ack := false; - end if; - end if; - end procedure; - - procedure check_written_byte ( - signal net : inout network_t; - constant vc : i2c_peripheral_t; - variable data : std_logic_vector; - variable addr : unsigned; - ) is - variable msg : msg_t; - begin - set_expected_word(memory(vc), to_integer(addr), data); - receive(net, vc.p_actor, msg); - if message_type(msg) = got_byte then - check_expected_was_written(buf(vc)); - end if; - end procedure; - -end package body; diff --git a/hdl/ip/vhd/i2c/sims/txn_layer/i2c_txn_layer_tb.gtkw b/hdl/ip/vhd/i2c/sims/txn_layer/i2c_txn_layer_tb.gtkw deleted file mode 100644 index 7554dee6..00000000 --- a/hdl/ip/vhd/i2c/sims/txn_layer/i2c_txn_layer_tb.gtkw +++ /dev/null @@ -1,161 +0,0 @@ -[*] -[*] GTKWave Analyzer v3.3.104 (w)1999-2020 BSI -[*] Tue Nov 26 23:00:33 2024 -[*] -[dumpfile] "/home/aaron/Oxide/git/quartz/vunit_out/test_output/lib.i2c_tb.write_and_read_many_bytes_735b3cb8aa5b45ddaa977875ceec621188fd3a14/nvc/i2c_tb.fst" -[dumpfile_mtime] "Tue Nov 26 23:00:26 2024" -[dumpfile_size] 6733 -[savefile] "/home/aaron/Oxide/git/quartz/hdl/ip/vhd/i2c/sims/tb_i2c.gtkw" -[timestart] 0 -[size] 2592 1283 -[pos] -1 -1 -*-36.192200 430732000000 -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] i2c_tb. -[treeopen] i2c_tb.th. -[treeopen] i2c_tb.th.dut. -[treeopen] i2c_tb.th.dut.i2c_link_layer_inst. -[treeopen] i2c_tb.th.dut.sm_reg. -[treeopen] i2c_tb.th.dut.sm_reg_next. -[treeopen] i2c_tb.th.i2c_cmd_vc_inst. -[treeopen] i2c_tb.th.peripheral. -[sst_width] 389 -[signals_width] 361 -[sst_expanded] 1 -[sst_vpaned_height] 382 -@200 --I2C_CMD_VC -@28 -i2c_tb.th.i2c_cmd_vc_inst.ready -i2c_tb.th.i2c_cmd_vc_inst.valid -@22 -i2c_tb.th.i2c_cmd_vc_inst.cmd.addr[6:0] -i2c_tb.th.i2c_cmd_vc_inst.cmd.len[7:0] -@28 -i2c_tb.th.i2c_cmd_vc_inst.cmd.op -@22 -i2c_tb.th.i2c_cmd_vc_inst.cmd.reg[7:0] -@200 -- --Transaction Layer -@28 -i2c_tb.th.dut.clk -i2c_tb.th.dut.cmd_valid -i2c_tb.th.dut.core_ready -@200 --I2C Interface --SCL -@28 -i2c_tb.th.dut.scl_if.i -i2c_tb.th.dut.scl_if.oe -@200 --SDA -@28 -i2c_tb.th.dut.sda_if.i -i2c_tb.th.dut.sda_if.oe -@200 --State -@28 -i2c_tb.th.dut.sm_reg.state -i2c_tb.th.dut.sm_reg.do_start -i2c_tb.th.dut.sm_reg.do_ack -i2c_tb.th.dut.sm_reg.do_stop -i2c_tb.th.dut.ll_ready -@200 -- --Link Layer -@28 -i2c_tb.th.dut.i2c_link_layer_inst.scl_toggle -i2c_tb.th.dut.i2c_link_layer_inst.scl_redge -i2c_tb.th.dut.i2c_link_layer_inst.scl_fedge -i2c_tb.th.dut.i2c_link_layer_inst.transition_sda -@200 --Transmit Stream -@28 -i2c_tb.th.dut.i2c_link_layer_inst.tx_data_valid -@23 -i2c_tb.th.dut.i2c_link_layer_inst.tx_data[7:0] -@200 --Receive Stream -@22 -i2c_tb.th.dut.i2c_link_layer_inst.rx_data[7:0] -@28 -i2c_tb.th.dut.i2c_link_layer_inst.rx_data_valid -@200 --State -@28 -i2c_tb.th.dut.i2c_link_layer_inst.sm_reg.ready -i2c_tb.th.dut.i2c_link_layer_inst.sm_reg.state -@24 -i2c_tb.th.dut.i2c_link_layer_inst.sm_reg.bits_shifted -@28 -i2c_tb.th.dut.i2c_link_layer_inst.sm_reg.rx_ack_valid -i2c_tb.th.dut.i2c_link_layer_inst.sm_reg.rx_ack -i2c_tb.th.dut.i2c_link_layer_inst.sm_reg.ack_sending -@200 --Counter -@22 -i2c_tb.th.dut.i2c_link_layer_inst.sm_countdown.counter[7:0] -@28 -i2c_tb.th.dut.i2c_link_layer_inst.sm_countdown.decr -i2c_tb.th.dut.i2c_link_layer_inst.sm_countdown.load -i2c_tb.th.dut.i2c_link_layer_inst.sm_countdown.done -@200 -- --RX Stream VC -@28 -i2c_tb.th.rx_sink_vc.ready -i2c_tb.th.rx_sink_vc.valid -@22 -i2c_tb.th.rx_sink_vc.data[7:0] -@200 --TX Stream VC -@28 -i2c_tb.th.tx_source_vc.ready -i2c_tb.th.tx_source_vc.valid -@22 -i2c_tb.th.tx_source_vc.data[7:0] -@200 -- --Peripheral Model --SCL -@28 -i2c_tb.th.peripheral.scl_if.i -i2c_tb.th.peripheral.scl_if.o -i2c_tb.th.peripheral.scl_if.oe -@200 --SDA -@28 -i2c_tb.th.peripheral.sda_if.i -i2c_tb.th.peripheral.sda_if.o -i2c_tb.th.peripheral.sda_if.oe -i2c_tb.th.peripheral.state -i2c_tb.th.peripheral.start_condition -i2c_tb.th.peripheral.stop_condition -@22 -i2c_tb.th.peripheral.reg_addr[7:0] -@28 -i2c_tb.th.peripheral.addr_set -i2c_tb.th.peripheral.addr_incr -i2c_tb.th.peripheral.rx_done -@22 -i2c_tb.th.peripheral.rx_data[7:0] -i2c_tb.th.peripheral.rx_bit_count[3:0] -@28 -i2c_tb.th.peripheral.tx_done -@c00022 -i2c_tb.th.peripheral.tx_data[7:0] -@28 -(0)i2c_tb.th.peripheral.tx_data[7:0] -(1)i2c_tb.th.peripheral.tx_data[7:0] -(2)i2c_tb.th.peripheral.tx_data[7:0] -(3)i2c_tb.th.peripheral.tx_data[7:0] -(4)i2c_tb.th.peripheral.tx_data[7:0] -(5)i2c_tb.th.peripheral.tx_data[7:0] -(6)i2c_tb.th.peripheral.tx_data[7:0] -(7)i2c_tb.th.peripheral.tx_data[7:0] -@1401200 --group_end -@22 -i2c_tb.th.peripheral.tx_bit_count[3:0] -[pattern_trace] 1 -[pattern_trace] 0 diff --git a/hdl/ip/vhd/i2c/sims/txn_layer/i2c_txn_layer_tb.vhd b/hdl/ip/vhd/i2c/sims/txn_layer/i2c_txn_layer_tb.vhd deleted file mode 100644 index 9c6ab31a..00000000 --- a/hdl/ip/vhd/i2c/sims/txn_layer/i2c_txn_layer_tb.vhd +++ /dev/null @@ -1,175 +0,0 @@ --- 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 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.com_context; - context vunit_lib.vunit_context; - context vunit_lib.vc_context; - -use work.i2c_cmd_vc_pkg.all; -use work.i2c_peripheral_pkg.all; -use work.basic_stream_pkg.all; - -use work.i2c_common_pkg.all; - -entity i2c_txn_layer_tb is - generic ( - runner_cfg : string - ); -end entity; - -architecture tb of i2c_txn_layer_tb is - constant I2C_PERIPHERAL_VC : i2c_peripheral_t := new_i2c_peripheral_vc("I2C_PERIPH"); - constant TX_DATA_SOURCE_VC : basic_source_t := new_basic_source(8); - constant RX_DATA_SINK_VC : basic_sink_t := new_basic_sink(8); - constant I2C_CMD_VC : i2c_cmd_vc_t := new_i2c_cmd_vc; -begin - - th: entity work.i2c_txn_layer_th - generic map ( - tx_source => TX_DATA_SOURCE_VC, - rx_sink => RX_DATA_SINK_VC, - i2c_peripheral => I2C_PERIPHERAL_VC, - i2c_cmd_vc => I2C_CMD_VC - ); - - bench: process - alias reset is << signal th.reset : std_logic >>; - - variable command : cmd_t; - variable ack : boolean := false; - - variable data : std_logic_vector(7 downto 0); - variable expected_addr : unsigned(7 downto 0); - variable expected_data : std_logic_vector(7 downto 0); - variable byte_len : natural; - 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("nack_wrong_address") then - command := CMD_RESET; - push_i2c_cmd(net, I2C_CMD_VC, command); - start_byte_ack(net, I2C_PERIPHERAL_VC, ack); - check_false(ack, "Peripheral did not NACK incorrect address"); - -- transaction is over, receive STOP event - expect_stop(net, I2C_PERIPHERAL_VC); - elsif run("write_and_read_one_byte") then - -- arbitrary for the test - expected_addr := X"9E"; - expected_data := X"A5"; - - -- write some data in - command := ( - op => WRITE, - addr => address(I2C_PERIPHERAL_VC), - reg => std_logic_vector(expected_addr), - len => to_unsigned(1, command.len'length) - ); - push_i2c_cmd(net, I2C_CMD_VC, command); - - start_byte_ack(net, I2C_PERIPHERAL_VC, ack); - check_true(ack, "Peripheral did not ACK correct address"); - - push_basic_stream(net, TX_DATA_SOURCE_VC, expected_data); - check_written_byte(net, I2C_PERIPHERAL_VC, expected_data, expected_addr); - - expect_stop(net, I2C_PERIPHERAL_VC); - - -- read it back out - command := ( - op => READ, - addr => address(I2C_PERIPHERAL_VC), - reg => X"--", -- READ uses internal address set by a WRITE to the peripheral - len => to_unsigned(1, command.len'length) - ); - push_i2c_cmd(net, I2C_CMD_VC, command); - - start_byte_ack(net, I2C_PERIPHERAL_VC, ack); - check_true(ack, "Peripheral did not ACK correct address"); - - pop_basic_stream(net, RX_DATA_SINK_VC, data); - check_equal(data, expected_data, "Expected read data to match"); - - expect_stop(net, I2C_PERIPHERAL_VC); - elsif run("write_and_read_many_bytes") then - -- arbitrary for the test - expected_addr := X"00"; - byte_len := 8; - - -- write some data in - command := ( - op => WRITE, - addr => address(I2C_PERIPHERAL_VC), - reg => std_logic_vector(expected_addr), - len => to_unsigned(byte_len, command.len'length) - ); - push_i2c_cmd(net, I2C_CMD_VC, command); - - start_byte_ack(net, I2C_PERIPHERAL_VC, ack); - check_true(ack, "Peripheral did not ACK correct address"); - - for byte_idx in 0 to byte_len - 1 loop - data := std_logic_vector(to_unsigned(byte_idx, data'length)); - expected_addr := to_unsigned(byte_idx, expected_addr'length); - push_basic_stream(net, TX_DATA_SOURCE_VC, data); - end loop; - - for byte_idx in 0 to byte_len - 1 loop - data := std_logic_vector(to_unsigned(byte_idx, data'length)); - expected_addr := to_unsigned(byte_idx, expected_addr'length); - check_written_byte(net, I2C_PERIPHERAL_VC, data, expected_addr); - end loop; - - expect_stop(net, I2C_PERIPHERAL_VC); - - -- read it back out - expected_addr := X"00"; - command := ( - op => RANDOM_READ, - addr => address(I2C_PERIPHERAL_VC), - reg => std_logic_vector(expected_addr), - len => to_unsigned(byte_len, command.len'length) - ); - push_i2c_cmd(net, I2C_CMD_VC, command); - - -- ACK WRITE portion of the random read - start_byte_ack(net, I2C_PERIPHERAL_VC, ack); - check_true(ack, "Peripheral did not ACK correct address"); - - -- ACK READ portion of the random read - start_byte_ack(net, I2C_PERIPHERAL_VC, ack); - check_true(ack, "Peripheral did not ACK correct address"); - - for byte_idx in 0 to byte_len - 1 loop - expected_data := std_logic_vector(to_unsigned(byte_idx, expected_data'length)); - pop_basic_stream(net, RX_DATA_SINK_VC, data); - check_equal(data, expected_data, "Expected read data to match"); - end loop; - - expect_stop(net, I2C_PERIPHERAL_VC); - end if; - end loop; - - wait for 2 us; - test_runner_cleanup(runner); - wait; - end process; - - -- Example total test timeout dog - test_runner_watchdog(runner, 1 ms); - -end tb; \ No newline at end of file diff --git a/hdl/ip/vhd/i2c/sims/txn_layer/i2c_txn_layer_th.vhd b/hdl/ip/vhd/i2c/sims/txn_layer/i2c_txn_layer_th.vhd deleted file mode 100644 index 6a525411..00000000 --- a/hdl/ip/vhd/i2c/sims/txn_layer/i2c_txn_layer_th.vhd +++ /dev/null @@ -1,160 +0,0 @@ --- 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; - 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; - -use work.i2c_cmd_vc_pkg.all; -use work.i2c_peripheral_pkg.all; -use work.basic_stream_pkg.all; - -entity i2c_txn_layer_th is - generic ( - tx_source : basic_source_t; - rx_sink : basic_sink_t; - i2c_peripheral : i2c_peripheral_t; - i2c_cmd_vc : i2c_cmd_vc_t - ); -end entity; - -architecture th of i2c_txn_layer_th is - signal clk : std_logic := '0'; - signal reset : std_logic := '1'; - - -- I2C interfaces - signal ctrl_scl_tristate : tristate; - signal ctrl_sda_tristate : tristate; - signal periph_scl_tristate : tristate; - signal periph_sda_tristate : tristate; - - -- I2C bus - signal scl : std_logic; - signal sda : std_logic; - - -- command interface - signal command : cmd_t; - signal command_valid : std_logic; - signal core_ready : std_logic; - - -- streaming interfaces - signal tx_data_stream : stream8_pkg.data_channel; - signal rx_data_stream : stream8_pkg.data_channel; - -begin - - -- set up a fastish clock for the sim - -- env and release reset after a bit of time - clk <= not clk after 4 ns; - reset <= '0' after 200 ns; - - dut: entity work.i2c_txn_layer - generic map ( - CLK_PER_NS => 8, - MODE => STANDARD - ) - port map ( - clk => clk, - reset => reset, - scl_if => ctrl_scl_tristate, - sda_if => ctrl_sda_tristate, - cmd => command, - cmd_valid => command_valid, - core_ready => core_ready, - tx_st_if => tx_data_stream, - rx_st_if => rx_data_stream - ); - - i2c_cmd_vc_inst: entity work.i2c_cmd_vc - generic map ( - i2c_cmd_vc => i2c_cmd_vc - ) - port map ( - cmd => command, - valid => command_valid, - ready => core_ready - ); - - peripheral: entity work.i2c_peripheral - generic map ( - i2c_peripheral_vc => i2c_peripheral - ) - port map ( - scl_if.i => periph_scl_tristate.i, - scl_if.o => periph_scl_tristate.o, - scl_if.oe => periph_scl_tristate.oe, - sda_if => periph_sda_tristate - ); - - tx_source_vc : entity work.basic_source - generic map ( - source => tx_source - ) - port map ( - clk => clk, - valid => tx_data_stream.valid, - ready => tx_data_stream.ready, - data => tx_data_stream.data - ); - - rx_sink_vc : entity work.basic_sink - generic map ( - sink => rx_sink - ) - port map ( - clk => clk, - valid => rx_data_stream.valid, - ready => rx_data_stream.ready, - data => rx_data_stream.data - ); - - -- wire the bus to the tristate inputs - ctrl_scl_tristate.i <= scl; - periph_scl_tristate.i <= scl; - ctrl_sda_tristate.i <= sda; - periph_sda_tristate.i <= sda; - i2c_bus_resolver: process(all) - begin - if ctrl_scl_tristate.oe = '1' and periph_scl_tristate.oe = '0' then - -- controller has line - scl <= ctrl_scl_tristate.o; - elsif ctrl_scl_tristate.oe = '0' and periph_scl_tristate.oe = '1' then - -- peripheral has line - scl <= periph_scl_tristate.o; - elsif ctrl_scl_tristate.oe = '1' and periph_scl_tristate.oe = '1' then - -- contention - scl <= 'Z'; - else - -- line floats to pull-up - scl <= '1'; - end if; - - if ctrl_sda_tristate.oe = '1' and periph_sda_tristate.oe = '0' then - -- controller has line - sda <= ctrl_sda_tristate.o; - elsif ctrl_sda_tristate.oe = '0' and periph_sda_tristate.oe = '1' then - -- peripheral has line - sda <= periph_sda_tristate.o; - elsif ctrl_sda_tristate.oe = '1' and periph_sda_tristate.oe = '1' then - -- contention - sda <= 'Z'; - else - -- line floats to pull-up - sda <= '1'; - end if; - end process; - -end th; \ No newline at end of file