Skip to content
Draft
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
52 changes: 52 additions & 0 deletions hw/top_chip/dv/env/seq_lib/top_chip_dv_gpio_smoke_vseq.sv
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
// 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_gpio_smoke_vseq extends top_chip_dv_base_vseq;
`uvm_object_utils(top_chip_dv_gpio_smoke_vseq)

// Standard SV/UVM methods
extern function new(string name="");
extern task body();

// Class specific methods
//
// Wait for the pattern to appear on the GPIO's pads
extern virtual task wait_for_pattern(logic [NUM_GPIOS-1:0] exp_val);
endclass : top_chip_dv_gpio_smoke_vseq

function top_chip_dv_gpio_smoke_vseq::new (string name = "");
super.new(name);
endfunction : new

task top_chip_dv_gpio_smoke_vseq::body();
super.body();
`DV_WAIT(cfg.sw_test_status_vif.sw_test_status == SwTestStatusInTest);

`uvm_info(`gfn, "Starting GPIOs outputs test", UVM_LOW)

// Disable the pull-ups on the pins that was enabled due to support SW booting process
cfg.gpio_vif.set_pullup_en('0);

// SW first drives walking 1's on each pin. Wait till those patterns are visible
for (int i = 0; i < NUM_GPIOS; i++) begin
wait_for_pattern(1 << i);
end

// Wait for Z so that the pads can safely be driven in inputs
wait_for_pattern('Z);

// The outputs on the pads are seen on the edge of sys_clk_if.clk so wait at least a negedge
// before driving the pads in inputs.
cfg.sys_clk_vif.wait_n_clks(1);

`uvm_info(`gfn, "Starting GPIOs inputs test", UVM_LOW)

// Drive the pads as inputs
cfg.gpio_vif.drive('h5555_5555);
endtask : body

task top_chip_dv_gpio_smoke_vseq::wait_for_pattern(logic [NUM_GPIOS-1:0] exp_val);
`DV_SPINWAIT(wait(cfg.gpio_vif.pins === exp_val);,
$sformatf("Timed out waiting for GPIOs == %0h", exp_val))
endtask : wait_for_pattern
1 change: 1 addition & 0 deletions hw/top_chip/dv/env/seq_lib/top_chip_dv_vseq_list.sv
Original file line number Diff line number Diff line change
Expand Up @@ -4,3 +4,4 @@

`include "top_chip_dv_base_vseq.sv"
`include "top_chip_dv_uart_base_vseq.sv"
`include "top_chip_dv_gpio_smoke_vseq.sv"
2 changes: 2 additions & 0 deletions hw/top_chip/dv/env/top_chip_dv_env.core
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ filesets:
- lowrisc:dv:mem_bkdr_util
- lowrisc:dv:uart_agent
- lowrisc:dv:common_ifs
- lowrisc:mocha_dv:gpio_env
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

This looks reasonable, but I noticed that the first commit adds gpio_env as a direct dependency of the sim. Can we drop it from there, maybe?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

No then the environment is unable to find NUM_GPIOS. There must be a dependency mess-up because I just saw in build.log that it is unable to find top_chip_dv_env_pkg

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Well, I spent a while to make it work somehow. The problem atm is that I want to use NUM_GPIOS parameter from gpio_env_pkg in tb.sv and uvm. I have an import import gpio_env_pkg::NUM_GPIOS; in top_chip_dv_env_pkg to be able to use that parameter in UVM. To achieve that I need to have - lowrisc:mocha_dv:gpio_env in top_chip_dv_env.core

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Hmm. I think that the dependency chain should be:

  1. The sim core contains tb.sv.
  2. That sim core depends on the chip-level test.
  3. The test depends on the chip-level environment.
  4. The chip-level environment depends on the block-level environments for the various blocks.

But I just looked and I don't think lowrisc:mocha_dv:top_chip_sim depends on lowrisc:mocha_dv:top_chip_dv_test. This is a bug! (I'd probably suggest opening a 1-line PR to put in the dependency, which can land before this PR)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

It might be a bug indeed, I struggled a bit to set the core files

Copy link
Copy Markdown
Contributor Author

@KinzaQamar KinzaQamar Apr 15, 2026

Choose a reason for hiding this comment

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

Hi @rswarbrick,

I've created a PR for the GPIO dependency issue we discussed yesterday: 29769

This needs to go in first so that I'll vendor the stuff in mocha and then tweak this PR

files:
- top_chip_dv_env_pkg.sv
- mem_clear_util.sv: {is_include_file: true}
Expand All @@ -22,6 +23,7 @@ filesets:
- seq_lib/top_chip_dv_vseq_list.sv: {is_include_file: true}
- 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}
file_type: systemVerilogSource

targets:
Expand Down
5 changes: 5 additions & 0 deletions hw/top_chip/dv/env/top_chip_dv_env.sv
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,11 @@ function void top_chip_dv_env::build_phase(uvm_phase phase);
`uvm_fatal(`gfn, "failed to get sw_logger_vif from uvm_config_db")
end

// Get the GPIO VIF handle
if (!uvm_config_db#(virtual pins_if #(NUM_GPIOS))::get(this, "", "gpio_vif", cfg.gpio_vif)) begin
`uvm_fatal(`gfn, "Failed to retrieve gpio_vif from uvm_config_db")
end
Comment thread
KinzaQamar marked this conversation as resolved.

// Initialize the sw logger interface.
foreach (cfg.mem_image_files[i]) begin
if (i inside {ChipMemSRAM}) begin
Expand Down
4 changes: 4 additions & 0 deletions hw/top_chip/dv/env/top_chip_dv_env_cfg.sv
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,10 @@ class top_chip_dv_env_cfg extends uvm_object;
// External interfaces
virtual clk_rst_if sys_clk_vif;
virtual clk_rst_if peri_clk_vif;

// GPIO Pads interface
virtual pins_if #(NUM_GPIOS) gpio_vif;

// Software logging & status interfaces
virtual sw_logger_if sw_logger_vif;
virtual sw_test_status_if sw_test_status_vif;
Expand Down
1 change: 1 addition & 0 deletions hw/top_chip/dv/env/top_chip_dv_env_pkg.sv
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ package top_chip_dv_env_pkg;
import mem_bkdr_util_pkg::*;
import sw_test_status_pkg::*;
import uart_agent_pkg::*;
import gpio_env_pkg::NUM_GPIOS;

// Macro includes
`include "uvm_macros.svh"
Expand Down
21 changes: 21 additions & 0 deletions hw/top_chip/dv/tb/tb.sv
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ module tb;
import mem_bkdr_util_pkg::mem_bkdr_util;
import top_chip_dv_env_pkg::*;
import top_chip_dv_test_pkg::*;
import gpio_env_pkg::NUM_GPIOS;

import top_chip_dv_env_pkg::SW_DV_START_ADDR;
import top_chip_dv_env_pkg::SW_DV_TEST_STATUS_ADDR;
Expand All @@ -25,6 +26,9 @@ module tb;
wire rst_n;
wire peri_clk;
wire peri_rst_n;
wire [NUM_GPIOS-1:0] gpio_pads; // A wire connected to bidirectional pads in pins_if
logic [NUM_GPIOS-1:0] dut_gpio_o;
logic [NUM_GPIOS-1:0] dut_gpio_en_o;

logic [3:0] spi_host_sd;
logic [3:0] spi_host_sd_en;
Expand All @@ -33,6 +37,7 @@ module tb;
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_if (.pins(gpio_pads));
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

A bit confusing that gpio_if is the name of pins_if, maybe gpio_pins_if?


// ------ Mock DRAM ------
top_pkg::axi_dram_req_t dram_req;
Expand All @@ -52,6 +57,10 @@ module tb;
// Clock and reset.
.clk_i (clk ),
.rst_ni (rst_n ),
// GPIO inputs and outputs with output enable
.gpio_i (gpio_pads ),
.gpio_o (dut_gpio_o ),
.gpio_en_o (dut_gpio_en_o ),
// UART receive and transmit.
.uart_rx_i (uart_if.uart_rx ),
.uart_tx_o (uart_if.uart_tx ),
Expand Down Expand Up @@ -86,6 +95,12 @@ module tb;
.dram_resp_i (dram_resp )
);

// Assignment to the GPIO pads. If dut_gpio_en_o[i] is disabled, then let the gpio_pad[i] float so
// an external device/driver can drive it.
for (genvar i = 0; i < NUM_GPIOS; i++) begin : gen_gpio_pads
assign gpio_pads[i] = dut_gpio_en_o[i] ? dut_gpio_o[i] : 1'bz;
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

I just bumped into this when trying to make the bootrom boostrap pin to work with dvsim. Is it possible to make the pin 8 high if output enable high rathen then floating?

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

I guess it is possible, can you explain a bit more the reason in order to document this behavior with an explicit comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

The gpio 8 is now used by the bootrom to decide if it should enter spi bootstrap or jump to the next stage (test). For now we only want to enter spi bootstrap in the FPGA. In sumulation we would load both (rom and test) and skip bootstrap. For that to work we need the gpio 8 to be pulled high during boot.
Maybe it's easier to pull all pin high (that's is what I'm going to do for verilator)?

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Kinza showed me the pins_if.sv which already has a pull functionality. Hopefully we can use that and set all the pins to pull up.

Copy link
Copy Markdown
Contributor Author

@KinzaQamar KinzaQamar Apr 18, 2026

Choose a reason for hiding this comment

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

Hi @engdoreis,

I've done it for every pin in this commit: fdbe886

I can pull out that commit along with 2b54119 in a separate PR if your work is urgent?

end

// Signals to connect the sink
top_pkg::axi_req_t sim_sram_cpu_req;
top_pkg::axi_resp_t sim_sram_cpu_resp;
Expand Down Expand Up @@ -190,13 +205,19 @@ module tb;
`SIM_SRAM_IF.u_sw_test_status_if.sw_test_status_addr = SW_DV_TEST_STATUS_ADDR;
`SIM_SRAM_IF.u_sw_logger_if.sw_log_addr = SW_DV_LOG_ADDR;

// Set the pull ups on GPIO pins. This doesn't mean anything for DV. Rather a feature added for
// SW. GPIO pin 8 is going to be used by the bootrom to decide the booting process. To support
// SW booting process in simulation, pin 8 needs to be pulled up during booting. But instead of
// initializing a single pin as pulled high, we'll do the same for evrey pin.
gpio_if.set_pullup_en('1);
// Start clock and reset generators
sys_clk_if.set_active();
peri_clk_if.set_active();

uvm_config_db#(virtual clk_rst_if)::set(null, "*", "sys_clk_if", sys_clk_if);
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_if);

// SW logger and test status interfaces.
uvm_config_db#(virtual sw_test_status_if)::set(
Expand Down
1 change: 1 addition & 0 deletions hw/top_chip/dv/top_chip_sim.core
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ filesets:
- lowrisc:dv:xbar_macros
- lowrisc:dv_dpi_c:uartdpi:0.1
- lowrisc:dv_dpi_sv:uartdpi:0.1
- lowrisc:mocha_dv:gpio_if
files:
- tb/tb.sv
- tb/chip_hier_macros.svh: {is_include_file: true}
Expand Down
8 changes: 7 additions & 1 deletion hw/top_chip/dv/top_chip_sim_cfg.hjson
Original file line number Diff line number Diff line change
Expand Up @@ -142,10 +142,16 @@
}
{
name: gpio_smoke
uvm_test_seq: top_chip_dv_gpio_vseq
uvm_test_seq: top_chip_dv_gpio_smoke_vseq
sw_images: ["gpio_smoketest_vanilla_bare:5"]
run_opts: ["+ChipMemSRAM_image_file={run_dir}/gpio_smoketest_vanilla_bare.vmem"]
}
{
name: gpio_smoke_cheri
uvm_test_seq: top_chip_dv_gpio_smoke_vseq
sw_images: ["gpio_smoketest_cheri_bare:5"]
run_opts: ["+ChipMemSRAM_image_file={run_dir}/gpio_smoketest_cheri_bare.vmem"]
}
{
name: rom_ctrl_integrity_check
uvm_test_seq: top_chip_dv_rom_ctrl_integrity_check_vseq
Expand Down
3 changes: 3 additions & 0 deletions sw/device/tests/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,9 @@ mocha_add_test(NAME test_framework_exception_test SOURCES test_framework/excepti
mocha_add_test(NAME axi_sram_smoketest SOURCES axi_sram/smoketest.c LIBRARIES ${LIBS} FPGA)
mocha_add_test(NAME axi_sram_tag_test SOURCES axi_sram/tag_test.c LIBRARIES ${LIBS} FPGA)
mocha_add_test(NAME gpio_reg_access_test SOURCES gpio/reg_access_test.c LIBRARIES ${LIBS} FPGA)
# Can't run this test on FPGA's and verilator's tops and this test thinks that the GPIO inputs can
# be driven
mocha_add_test(NAME gpio_smoketest SOURCES gpio/smoketest.c LIBRARIES ${LIBS} SKIP_VERILATOR)
mocha_add_test(NAME i2c_smoketest SOURCES i2c/smoketest.c LIBRARIES ${LIBS} FPGA)
mocha_add_test(NAME mailbox_smoketest SOURCES mailbox/smoketest.c LIBRARIES ${LIBS} FPGA)
mocha_add_test(NAME plic_smoketest SOURCES plic/smoketest.c LIBRARIES ${LIBS} FPGA)
Expand Down
36 changes: 36 additions & 0 deletions sw/device/tests/gpio/smoketest.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
// 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/gpio.h"
#include "hal/mmio.h"
#include "hal/mocha.h"
#include <stdbool.h>
#include <stdint.h>

static bool gpio_test(gpio_t gpio)
{
// Enable the GPIOs in output mode
DEV_WRITE(gpio + GPIO_REG_DIRECT_OE, 0xFFFFFFFF);

// Set each pin in walking 1's fashion
for (int i = 0; i < GPIO_NUM_PINS; i++) {
DEV_WRITE(gpio + GPIO_REG_DIRECT_OUT, 1 << i);
}
Comment thread
engdoreis marked this conversation as resolved.

// When the SW is done driving walking 1's on the last GPIO pin, it should disable the
// output enables so that the GPIO pads can safely be driven as inputs.
DEV_WRITE(gpio + GPIO_REG_DIRECT_OE, 0x0);

// Wait for the pads to set high externally
while (DEV_READ(gpio + GPIO_REG_DATA_IN) != 0x55555555) {
}

return true;
}

bool test_main()
{
gpio_t gpio = mocha_system_gpio();
return gpio_test(gpio);
}