diff --git a/hw/top_chip/dv/env/seq_lib/top_chip_dv_i2c_host_tx_rx_vseq.sv b/hw/top_chip/dv/env/seq_lib/top_chip_dv_i2c_host_tx_rx_vseq.sv new file mode 100644 index 000000000..c26fdc3d8 --- /dev/null +++ b/hw/top_chip/dv/env/seq_lib/top_chip_dv_i2c_host_tx_rx_vseq.sv @@ -0,0 +1,24 @@ +// Copyright lowRISC contributors (COSMIC project). +// Licensed under the Apache License, Version 2.0, see LICENSE for details. +// SPDX-License-Identifier: Apache-2.0 + +class top_chip_dv_i2c_host_tx_rx_vseq extends top_chip_dv_base_vseq; + `uvm_object_utils(top_chip_dv_i2c_host_tx_rx_vseq) + + // Standard SV/UVM methods + extern function new(string name=""); + extern task body(); +endclass : top_chip_dv_i2c_host_tx_rx_vseq + +function top_chip_dv_i2c_host_tx_rx_vseq::new(string name = ""); + super.new(name); +endfunction : new + +task top_chip_dv_i2c_host_tx_rx_vseq::body(); + i2c_device_response_seq seq = i2c_device_response_seq::type_id::create("seq"); + super.body(); + `DV_WAIT(cfg.sw_test_status_vif.sw_test_status == SwTestStatusInTest); + + `uvm_info(`gfn, "Starting I2C Host TX-RX test", UVM_LOW) + seq.start(p_sequencer.i2c_sqr); +endtask : body diff --git a/hw/top_chip/dv/env/seq_lib/top_chip_dv_vseq_list.sv b/hw/top_chip/dv/env/seq_lib/top_chip_dv_vseq_list.sv index 151f6eb4b..1c38867d8 100644 --- a/hw/top_chip/dv/env/seq_lib/top_chip_dv_vseq_list.sv +++ b/hw/top_chip/dv/env/seq_lib/top_chip_dv_vseq_list.sv @@ -5,3 +5,4 @@ `include "top_chip_dv_base_vseq.sv" `include "top_chip_dv_uart_base_vseq.sv" `include "top_chip_dv_gpio_smoke_vseq.sv" +`include "top_chip_dv_i2c_host_tx_rx_vseq.sv" diff --git a/hw/top_chip/dv/env/top_chip_dv_env.core b/hw/top_chip/dv/env/top_chip_dv_env.core index 7083a2a41..fd7383c98 100644 --- a/hw/top_chip/dv/env/top_chip_dv_env.core +++ b/hw/top_chip/dv/env/top_chip_dv_env.core @@ -13,6 +13,7 @@ filesets: - lowrisc:dv:uart_agent - lowrisc:dv:common_ifs - lowrisc:mocha_dv:gpio_env + - lowrisc:dv:i2c_env files: - top_chip_dv_env_pkg.sv - mem_clear_util.sv: {is_include_file: true} @@ -24,6 +25,7 @@ filesets: - seq_lib/top_chip_dv_base_vseq.sv: {is_include_file: true} - seq_lib/top_chip_dv_uart_base_vseq.sv: {is_include_file: true} - seq_lib/top_chip_dv_gpio_smoke_vseq.sv: {is_include_file: true} + - seq_lib/top_chip_dv_i2c_host_tx_rx_vseq.sv: {is_include_file: true} file_type: systemVerilogSource targets: diff --git a/hw/top_chip/dv/env/top_chip_dv_env.sv b/hw/top_chip/dv/env/top_chip_dv_env.sv index 9440dd4e3..b11f5d062 100644 --- a/hw/top_chip/dv/env/top_chip_dv_env.sv +++ b/hw/top_chip/dv/env/top_chip_dv_env.sv @@ -13,6 +13,7 @@ class top_chip_dv_env extends uvm_env; // Agents uart_agent m_uart_agent; + i2c_agent m_i2c_agent; // Standard SV/UVM methods extern function new(string name = "", uvm_component parent = null); @@ -71,6 +72,12 @@ function void top_chip_dv_env::build_phase(uvm_phase phase); `uvm_fatal(`gfn, "Cannot get peri_clk_vif") end + // Set I2C agent config object for I2C agent + uvm_config_db#(i2c_agent_cfg)::set(this, "m_i2c_agent", "cfg", cfg.m_i2c_agent_cfg); + + // Create I2C agent + m_i2c_agent = i2c_agent::type_id::create("m_i2c_agent", this); + // Instantiate UART agent m_uart_agent = uart_agent::type_id::create("m_uart_agent", this); uvm_config_db#(uart_agent_cfg)::set(this, "m_uart_agent*", "cfg", cfg.m_uart_agent_cfg); @@ -87,6 +94,7 @@ function void top_chip_dv_env::connect_phase(uvm_phase phase); // Track specific agent sequencers in the virtual sequencer. // Allows virtual sequences to use the agents to drive RX items. top_vsqr.uart_sqr = m_uart_agent.sequencer; + top_vsqr.i2c_sqr = m_i2c_agent.sequencer; // Connect monitor output to matching FIFO in the virtual sequencer. // Allows virtual sequences to check TX items. diff --git a/hw/top_chip/dv/env/top_chip_dv_env_cfg.sv b/hw/top_chip/dv/env/top_chip_dv_env_cfg.sv index 9611f6fb7..a4448fac8 100644 --- a/hw/top_chip/dv/env/top_chip_dv_env_cfg.sv +++ b/hw/top_chip/dv/env/top_chip_dv_env_cfg.sv @@ -19,6 +19,7 @@ class top_chip_dv_env_cfg extends uvm_object; // External interface agent configs rand uart_agent_cfg m_uart_agent_cfg; + i2c_agent_cfg m_i2c_agent_cfg; `uvm_object_utils_begin(top_chip_dv_env_cfg) `uvm_object_utils_end @@ -46,6 +47,9 @@ function void top_chip_dv_env_cfg::initialize(); // Configuration is required to perform meaningful monitoring m_uart_agent_cfg.en_tx_monitor = 0; m_uart_agent_cfg.en_rx_monitor = 0; + + // Create I2C agent config object + m_i2c_agent_cfg = i2c_agent_cfg::type_id::create("m_i2c_agent_cfg"); endfunction : initialize function void top_chip_dv_env_cfg::get_mem_image_files_from_plusargs(); diff --git a/hw/top_chip/dv/env/top_chip_dv_virtual_sequencer.sv b/hw/top_chip/dv/env/top_chip_dv_virtual_sequencer.sv index f12a799fc..d6c9a12dc 100644 --- a/hw/top_chip/dv/env/top_chip_dv_virtual_sequencer.sv +++ b/hw/top_chip/dv/env/top_chip_dv_virtual_sequencer.sv @@ -14,6 +14,7 @@ class top_chip_dv_virtual_sequencer extends uvm_sequencer; // Handles to specific interface agent sequencers. Used by some virtual // sequences to drive RX (to-chip) items. uart_sequencer uart_sqr; + i2c_sequencer i2c_sqr; // FIFOs for monitor output. Used by some virtual sequences to check // TX (from-chip) items. diff --git a/hw/top_chip/dv/tb/tb.sv b/hw/top_chip/dv/tb/tb.sv index a0fac5280..2712644d1 100644 --- a/hw/top_chip/dv/tb/tb.sv +++ b/hw/top_chip/dv/tb/tb.sv @@ -35,11 +35,23 @@ module tb; logic [3:0] spi_host_sd; logic [3:0] spi_host_sd_en; + // I2C connections + wire scl; + wire sda; + logic scl_en_o; + logic sda_en_o; + logic scl_o; + logic sda_o; + // ------ Interfaces ------ clk_rst_if sys_clk_if(.clk(clk), .rst_n(rst_n)); clk_rst_if peri_clk_if(.clk(peri_clk), .rst_n(peri_rst_n)); uart_if uart_if(); pins_if #(NUM_GPIOS) gpio_pins_if (.pins(gpio_pads)); + i2c_if i2c_if (.clk_i(clk), + .rst_ni(rst_n), + .scl_io(scl), + .sda_io(sda)); // ------ Mock DRAM ------ top_pkg::axi_dram_req_t dram_req; @@ -69,6 +81,13 @@ module tb; // UART receive and transmit. .uart_rx_i (uart_if.uart_rx ), .uart_tx_o (uart_if.uart_tx ), + // I2C controller/target bidirectional interface. + .i2c_scl_i (scl ), + .i2c_scl_o (scl_o ), + .i2c_scl_en_o (scl_en_o ), + .i2c_sda_i (sda ), + .i2c_sda_o (sda_o ), + .i2c_sda_en_o (sda_en_o ), // External Mailbox port .axi_mailbox_req_i ('0 ), .axi_mailbox_resp_o ( ), @@ -104,6 +123,10 @@ module tb; assign gpio_pads[i] = dut_gpio_en_o[i] ? dut_gpio_o[i] : 1'bz; end + // Modelling the open-drain circuit + assign (strong0, weak1) scl = (scl_en_o) ? scl_o : 1'b1; + assign (strong0, weak1) sda = (sda_en_o) ? sda_o : 1'b1; + // Signals to connect the sink top_pkg::axi_req_t sim_sram_cpu_req; top_pkg::axi_resp_t sim_sram_cpu_resp; @@ -232,6 +255,7 @@ module tb; uvm_config_db#(virtual clk_rst_if)::set(null, "*", "peri_clk_if", peri_clk_if); uvm_config_db#(virtual uart_if)::set(null, "*.env.m_uart_agent*", "vif", uart_if); uvm_config_db#(virtual pins_if #(NUM_GPIOS))::set(null, "*.env", "gpio_vif", gpio_pins_if); + uvm_config_db#(virtual i2c_if)::set(null, "*.env.m_i2c_agent", "vif", i2c_if); // SW logger and test status interfaces. uvm_config_db#(virtual sw_test_status_if)::set( diff --git a/hw/top_chip/dv/top_chip_sim_cfg.hjson b/hw/top_chip/dv/top_chip_sim_cfg.hjson index 193bec2d2..97f2527cb 100644 --- a/hw/top_chip/dv/top_chip_sim_cfg.hjson +++ b/hw/top_chip/dv/top_chip_sim_cfg.hjson @@ -151,7 +151,14 @@ sw_images: ["i2c_host_tx_rx_test_vanilla_sram:5" "bootrom:5"] run_opts: ["+ChipMemSRAM_image_file={run_dir}/i2c_host_tx_rx_test_vanilla_sram.vmem", "+ChipMemROM_image_file={run_dir}/bootrom.vmem"] - } + } + { + name: i2c_host_tx_rx_cheri + uvm_test_seq: top_chip_dv_i2c_host_tx_rx_vseq + sw_images: ["i2c_host_tx_rx_test_cheri_sram:5" "bootrom:5"] + run_opts: ["+ChipMemSRAM_image_file={run_dir}/i2c_host_tx_rx_test_cheri_sram.vmem", + "+ChipMemROM_image_file={run_dir}/bootrom.vmem"] + } { name: i2c_device_tx_rx uvm_test_seq: top_chip_dv_i2c_device_tx_rx_vseq diff --git a/sw/device/tests/CMakeLists.txt b/sw/device/tests/CMakeLists.txt index 798b8fe22..7ef39bd11 100644 --- a/sw/device/tests/CMakeLists.txt +++ b/sw/device/tests/CMakeLists.txt @@ -13,6 +13,7 @@ mocha_add_test(NAME gpio_reg_access_test SOURCES gpio/reg_access_test.c LIBRARIE # driven externally mocha_add_test(NAME gpio_smoketest SOURCES gpio/smoketest.c LIBRARIES ${LIBS} SKIP_VERILATOR SKIP_FPGA) mocha_add_test(NAME i2c_smoketest SOURCES i2c/smoketest.c LIBRARIES ${LIBS}) +mocha_add_test(NAME i2c_host_tx_rx_test SOURCES i2c/host_test.c LIBRARIES ${LIBS}) mocha_add_test(NAME mailbox_smoketest SOURCES mailbox/smoketest.c LIBRARIES ${LIBS}) mocha_add_test(NAME plic_smoketest SOURCES plic/smoketest.c LIBRARIES ${LIBS}) mocha_add_test(NAME rstmgr_software_reset SOURCES rstmgr/software_reset.c LIBRARIES ${LIBS}) diff --git a/sw/device/tests/i2c/host_test.c b/sw/device/tests/i2c/host_test.c new file mode 100644 index 000000000..7c597a146 --- /dev/null +++ b/sw/device/tests/i2c/host_test.c @@ -0,0 +1,21 @@ +// Copyright lowRISC contributors (COSMIC project). +// Licensed under the Apache License, Version 2.0, see LICENSE for details. +// SPDX-License-Identifier: Apache-2.0 + +#include "hal/i2c.h" +#include "hal/mmio.h" +#include "hal/mocha.h" +#include +#include + +bool test_main() +{ + i2c_t i2c = mocha_system_i2c(); + i2c_init(i2c); + // Queue write request + DEV_WRITE(i2c + I2C_FDATA_REG, + ((1u << I2C_FDATA_START) | (((0xAAu << 1) | 0u) << I2C_FDATA_FBYTE))); + DEV_WRITE(i2c + I2C_FDATA_REG, ((1u << I2C_FDATA_STOP) | (0x43u << I2C_FDATA_FBYTE))); + + return true; +}