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

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

// Class specific methods
//
// Waits for the pattern to appear on the GPIOs
extern virtual task wait_for_pattern(logic [NUM_GPIOS-1:0] exp_val);

// Drives a pattern on the quarter GPIOs pins in input mode
extern virtual task drive_pattern(int unsigned wait_num_clks,
int unsigned pins_starting_quarter,
int unsigned pins_next_quarter,
bit state);
endclass : top_chip_dv_gpio_base_vseq

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

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

// Checks the GPIOs in both input and output mode. SW writes walking 0's and walking 1's pattern
// on the first and third quarter of direct_out register and body() waits (for a reasonable
// amount of timeout) for that pattern to appear on the pads. Then it drives all 1's and all 0's
// on the other even quaters.
//
// Enable the pulldowns so that the pads are driving 0's rather than Z's when no external driver
// is connected
cfg.gpio_vif.set_pulldown_en('1);

// Current Current GPIOs pads state : 'h0

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

// Check for walking 1's pattern on the first quarter of pins.
for (int i = 0; i < NUM_GPIOS/4; i++) begin
wait_for_pattern({24'h0, 1 << i});
end

// Current GPIOs pads state : 'h00000080
//
// Drive all 1's on the second quarter of pins.
drive_pattern(2, 1, 2, 1);

// Current GPIOs pads state : 'h0000FF80
//
// Check for walking 1's pattern on the third quarter of pins.
for (int i = 0; i < NUM_GPIOS/4; i++) begin
wait_for_pattern({8'h0, 1 << i, 16'hFF80});
end

// Current GPIOs pads state : 'h0080FF80
//
// Drive all 1's on the fourth quarter of pins.
drive_pattern(2, 3, 4, 1);

// Current GPIOs pads state : 'hFF80FF80
//
// The SW first sets the first and third quarter of GPIOs to 1's in order to walk 0's on them.
// The second and fourth quarter of pads should contain all 1's by now.
//
// Wait and check for all 1s.
wait_for_pattern({NUM_GPIOS{1'b1}});

// Current GPIOs pads state : 'hFFFFFFFF
//
// Check for walking 0's pattern on the first quarter of pins.
for (int i = 0; i < NUM_GPIOS/4; i++) begin
wait_for_pattern({24'hFF_FFFF, ~(1 << i)});
end

// Current GPIOs pads state : 'hFFFFFF7F
//
// Drive all 0's on the second quarter of pins.
drive_pattern(2, 1, 2, 0);

// Current GPIOs pads state : 'hFFFF007F
//
// Check for walking 0's pattern on on the third quarter of pins.
for (int i = 0; i < NUM_GPIOS/4; i++) begin
wait_for_pattern({8'hFF, ~(1 << i), 16'h007F});
end

// Current GPIOs pads state : 'hFF7F007F
//
// Drive all 0's on the fourth quarter of pins.
drive_pattern(2, 3, 4, 0);

// Current GPIOs pads state : 'h007F007F
endtask : body

task top_chip_dv_gpio_base_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),
/*use default_spinwait_timeout_ns*/,
`gfn)
endtask : wait_for_pattern

task top_chip_dv_gpio_base_vseq::drive_pattern(int unsigned wait_num_clks,
int unsigned pins_starting_quarter,
int unsigned pins_next_quarter,
bit state);

int unsigned quarter_start = (NUM_GPIOS/4) * pins_starting_quarter;
int unsigned quarter_end = (NUM_GPIOS/4) * pins_next_quarter;

// Wait for some cycles so that the pads can transition from the current pin state to the next pin
// state
cfg.sys_clk_vif.wait_clks(wait_num_clks);

// Drive state on the quarter of pins
for (int i = quarter_start; i < quarter_end; i++) begin
cfg.gpio_vif.drive_pin(i, state);
end
endtask : drive_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_base_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
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_base_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

// 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
16 changes: 16 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,11 +26,15 @@ 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;

// ------ 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_if (.pins(gpio_pads));

// ------ Mock DRAM ------
top_pkg::axi_dram_req_t dram_req;
Expand All @@ -49,6 +54,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 All @@ -69,6 +78,12 @@ module tb;
.dram_resp_i (dram_resp )
);

// Assignment to the GPIO pads. If dut_gpio_en_o[i] is disabled, the let the gpio_pad[i] floating
// 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;
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 @@ -180,6 +195,7 @@ module tb;
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
2 changes: 2 additions & 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,8 @@ filesets:
- lowrisc:dv:xbar_macros
- lowrisc:dv_dpi_c:uartdpi:0.1
- lowrisc:dv_dpi_sv:uartdpi:0.1
- lowrisc:mocha_dv:gpio_if:0.1
- lowrisc:mocha_dv:gpio_env
files:
- tb/tb.sv
- tb/chip_hier_macros.svh: {is_include_file: true}
Expand Down
2 changes: 1 addition & 1 deletion hw/top_chip/dv/top_chip_sim_cfg.hjson
Original file line number Diff line number Diff line change
Expand Up @@ -130,7 +130,7 @@
}
{
name: gpio_smoke
uvm_test_seq: top_chip_dv_gpio_vseq
uvm_test_seq: top_chip_dv_gpio_base_vseq
sw_images: ["gpio_smoketest_vanilla_bare:5"]
run_opts: ["+ChipMemSRAM_image_file={run_dir}/gpio_smoketest_vanilla_bare.vmem"]
}
Expand Down
36 changes: 36 additions & 0 deletions signals.svwf
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@

#
# Mnemonic Maps
#
mmap new -reuse -name {Boolean as Logic} -radix %b -contents {{%c=FALSE -edgepriority 1 -shape low}
{%c=TRUE -edgepriority 1 -shape high}}
mmap new -reuse -name {Example Map} -radix %x -contents {{%b=11???? -bgcolor orange -label REG:%x -linecolor yellow -shape bus}
{%x=1F -bgcolor red -label ERROR -linecolor white -shape EVENT}
{%x=2C -bgcolor red -label ERROR -linecolor white -shape EVENT}
{%x=* -label %x -linecolor gray -shape bus}}

array unset createdGroup
array set createdGroup {}
set id [waveform add -signals [subst {
{[format {tb.dut.u_gpio.clk_i}]}
} ]]
set id [waveform add -signals [subst {
{[format {tb.dut.u_gpio.rst_ni}]}
} ]]
set id [waveform add -signals [subst {
{[format {tb.dut.u_gpio.cio_gpio_i[31:0]}]}
} ]]
set id [waveform add -signals [subst {
{[format {tb.dut.u_gpio.cio_gpio_en_o[31:0]}]}
} ]]
set id [waveform add -signals [subst {
{[format {tb.dut.u_gpio.cio_gpio_o[31:0]}]}
} ]]
set id [waveform add -signals [subst {
{[format {tb.dut.u_gpio.tl_i}]}
} ]]
set id [waveform add -signals [subst {
{[format {tb.dut.u_gpio.tl_o}]}
} ]]

waveform xview limits 0 501700.823ns
10 changes: 10 additions & 0 deletions sw/device/lib/hal/gpio.c
Original file line number Diff line number Diff line change
Expand Up @@ -30,3 +30,13 @@ void gpio_set_oe_pin(gpio_t gpio, uint32_t pin, bool output)
uint32_t mask = 1u << (pin & 0xFu);
DEV_WRITE(gpio + reg, (mask << 16) | (output ? mask : 0u));
}

void gpio_write(gpio_t gpio, uint32_t output_reg_addr, uint32_t value)
{
DEV_WRITE(gpio + output_reg_addr, value);
}

void gpio_set_all_oe(gpio_t gpio, uint32_t value)
{
DEV_WRITE(gpio + GPIO_REG_DIRECT_OE, value);
}
6 changes: 6 additions & 0 deletions sw/device/lib/hal/gpio.h
Original file line number Diff line number Diff line change
Expand Up @@ -25,5 +25,11 @@ bool gpio_read_pin(gpio_t gpio, uint32_t pin);
// Set the value of one output pin
void gpio_write_pin(gpio_t gpio, uint32_t pin, bool state);

// Set the value of all output pins
void gpio_write(gpio_t gpio, uint32_t output_reg_addr, uint32_t value);

// Set the output enable state of one pin
void gpio_set_oe_pin(gpio_t gpio, uint32_t pin, bool output);

// Set the output enable state of all pins
void gpio_set_all_oe(gpio_t gpio, uint32_t value);
Loading
Loading