Skip to content

Commit

Permalink
New testcase for the GPIO feature straps
Browse files Browse the repository at this point in the history
Signed-off-by: Marcelo Carvalho Faleiro de Almeida <[email protected]>
  • Loading branch information
marcelocarvalhoLowRisc committed Jan 15, 2025
1 parent 29d7b87 commit 05e6443
Show file tree
Hide file tree
Showing 16 changed files with 400 additions and 89 deletions.
4 changes: 3 additions & 1 deletion hw/ip/gpio/data/gpio.hjson
Original file line number Diff line number Diff line change
Expand Up @@ -390,7 +390,9 @@
],
},
{ name: "HW_STRAPS_DATA_IN",
desc: "GPIO Input data sampled as straps during cold boot read value",
desc: '''GPIO Input data sampled as straps during cold boot read value
The GPIO input data is sampled after the first one pulse cycle of straps_en input after reset.
''',
swaccess: "ro",
hwaccess: "hrw",
tags: [// Value in the register is determined by GPIO pin values that are sampled
Expand Down
12 changes: 12 additions & 0 deletions hw/ip/gpio/data/gpio_testplan.hjson
Original file line number Diff line number Diff line change
Expand Up @@ -145,5 +145,17 @@
stage: V2
tests: ["gpio_stress_all"]
}
{
name: straps_data
desc: '''Verify the straps data/valid ouput expected values based on the strap_en and gpio_i inputs:
- Drives gpio_i input with random values
- Set the expected strap_data_in based on the condition if is the first triggered strap_en or not
- Updates the RAL model with the expected strap_data_in and strap_data_in_valid
- Trigger the strap_en with one clock cycle
- Read the registers hw_straps_data_in and hw_straps_data_in_valid
- Check the expected behavior in the scoreboard and also on csr checks'''
stage: V3
tests: ["gpio_rand_straps"]
}
]
}
215 changes: 135 additions & 80 deletions hw/ip/gpio/doc/registers.md

Large diffs are not rendered by default.

1 change: 1 addition & 0 deletions hw/ip/gpio/dv/env/gpio_env.core
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ filesets:
- seq_lib/gpio_stress_all_vseq.sv: {is_include_file: true}
- seq_lib/gpio_intr_rand_pgm_vseq.sv: {is_include_file: true}
- seq_lib/gpio_intr_with_filter_rand_intr_event_vseq.sv: {is_include_file: true}
- seq_lib/gpio_rand_straps_vseq.sv : {is_include_file: true}
file_type: systemVerilogSource

generate:
Expand Down
3 changes: 3 additions & 0 deletions hw/ip/gpio/dv/env/gpio_env.sv
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,9 @@ class gpio_env extends cip_base_env #(
if (!uvm_config_db#(gpio_vif)::get(this, "", "gpio_vif", cfg.gpio_vif)) begin
`uvm_fatal(get_full_name(), "failed to get gpio_vif from uvm_config_db")
end
if (!uvm_config_db#(straps_vif)::get(this, "", "straps_vif", cfg.straps_vif_inst)) begin
`uvm_fatal(get_full_name(), "Virtual interface straps_vif_inst is not set")
end
endfunction

endclass
7 changes: 6 additions & 1 deletion hw/ip/gpio/dv/env/gpio_env_cfg.sv
Original file line number Diff line number Diff line change
Expand Up @@ -13,11 +13,16 @@ class gpio_env_cfg extends cip_base_env_cfg #(
rand bit pulldown_en;
// gpio virtual interface
gpio_vif gpio_vif;
// gpio straps interface
straps_vif straps_vif_inst;

constraint pullup_pulldown_en_c {pullup_en ^ pulldown_en;}

`uvm_object_utils(gpio_env_cfg)
`uvm_object_new

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

virtual function void initialize(bit [TL_AW-1:0] csr_base_addr = '1);
list_of_alerts = gpio_env_pkg::LIST_OF_ALERTS;
Expand Down
1 change: 1 addition & 0 deletions hw/ip/gpio/dv/env/gpio_env_pkg.sv
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ package gpio_env_pkg;
parameter string LIST_OF_ALERTS[] = {"fatal_fault"};

typedef virtual pins_if #(NUM_GPIOS) gpio_vif;
typedef virtual gpio_straps_if straps_vif;
typedef class gpio_env_cfg;
typedef class gpio_env_cov;
typedef cip_base_virtual_sequencer #(gpio_env_cfg, gpio_env_cov) gpio_virtual_sequencer;
Expand Down
54 changes: 53 additions & 1 deletion hw/ip/gpio/dv/env/gpio_scoreboard.sv
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,12 @@ class gpio_scoreboard extends cip_base_scoreboard #(.CFG_T (gpio_env_cfg),
// (i) indicate that write to INTR_STATE register just happened, and
// (ii) store information of which all interupt bits were cleared
bit [TL_DW-1:0] cleared_intr_bits;
// hw straps_data_in_valid register
bit straps_data_in_valid;
// hw straps_data_in register
bit [NUM_GPIOS-1:0] straps_data_in;
// Flag to indicate that the strap was trigered
bit first_strap_trigged;

// mask are WO, store the values in scb
uvm_reg_data_t masked_out_lower_mask;
Expand All @@ -40,7 +46,9 @@ class gpio_scoreboard extends cip_base_scoreboard #(.CFG_T (gpio_env_cfg),

`uvm_component_utils(gpio_scoreboard)

`uvm_component_new
function new (string name = "gpio_scoreboard", uvm_component parent = null);
super.new (name, parent);
endfunction

// Function: build_phase
function void build_phase(uvm_phase phase);
Expand All @@ -54,6 +62,7 @@ class gpio_scoreboard extends cip_base_scoreboard #(.CFG_T (gpio_env_cfg),
fork
monitor_gpio_i();
monitor_gpio_interrupt_pins();
monitor_gpio_straps();
join_none
endtask

Expand Down Expand Up @@ -360,6 +369,38 @@ class gpio_scoreboard extends cip_base_scoreboard #(.CFG_T (gpio_env_cfg),
end
endtask : monitor_gpio_interrupt_pins

// Task: monitor_gpio_straps
virtual task monitor_gpio_straps();
forever begin : monitor_gpio_intr
@(posedge cfg.clk_rst_vif.clk)
`uvm_info(`gfn, "Monitor gpio_straps on!", UVM_HIGH)
if (|gpio_i_driven === 1'b1) begin
@(negedge cfg.straps_vif_inst.strap_en_i) begin
if (first_strap_trigged == 0) begin
// Update data_in ral register value based on result of input
void'(ral.hw_straps_data_in.predict(.value(gpio_i_driven), .kind(UVM_PREDICT_DIRECT)));
// Update data_in register value based on result of input
void'(ral.hw_straps_data_in_valid.predict(.value('b1), .kind(UVM_PREDICT_DIRECT)));
check_straps();
end
end
end
end
endtask : monitor_gpio_straps

// Function: check_straps
// Used to check the behavior of the straps register data.
// Based on strap_en input value, the straps register data should contains the snapshot of the data_in pins
function void check_straps();
// Checker: Compare actual values of gpio pins with straps register.
// Check the register hw_straps_data_in against gpio_i pins
`DV_CHECK_CASE_EQ(gpio_i_driven, cfg.straps_vif_inst.sampled_straps_o.data)
// Check the register hw_straps_data_in_valid
`DV_CHECK_CASE_EQ('b1, cfg.straps_vif_inst.sampled_straps_o.valid)
// Turn-off the checker after the first strap trigger.
first_strap_trigged = 'b1;
endfunction : check_straps

// Function: actual_gpio_i_activity
function bit actual_gpio_i_activity();
return ~((prv_gpio_i_pins_o === cfg.gpio_vif.pins_o) &&
Expand Down Expand Up @@ -478,6 +519,16 @@ class gpio_scoreboard extends cip_base_scoreboard #(.CFG_T (gpio_env_cfg),
end
"ctrl_en_input_filter": begin
end
"hw_straps_data_in_valid": begin
straps_data_in_valid = csr.get_mirrored_value();
`uvm_info(`gfn, $sformatf("straps_data_in_valid updated to 0x%0h", straps_data_in_valid),
UVM_HIGH)
end
"hw_straps_data_in": begin
straps_data_in = csr.get_mirrored_value();
`uvm_info(`gfn, $sformatf("straps_data_in updated to 0x%0h", straps_data_in),
UVM_HIGH)
end
default: begin
`uvm_fatal(`gfn, $sformatf("invalid csr: %0s", csr.get_full_name()))
end
Expand Down Expand Up @@ -561,6 +612,7 @@ class gpio_scoreboard extends cip_base_scoreboard #(.CFG_T (gpio_env_cfg),
((|gpio_i_driven === 1'b1) && (actual_gpio_i_activity() == 1))) begin
`DV_CHECK_CASE_EQ(pred_val_gpio_pins, cfg.gpio_vif.pins)
end

end

endfunction : gpio_predict_and_compare
Expand Down
121 changes: 121 additions & 0 deletions hw/ip/gpio/dv/env/seq_lib/gpio_rand_straps_vseq.sv
Original file line number Diff line number Diff line change
@@ -0,0 +1,121 @@
// Copyright lowRISC contributors (OpenTitan project).
// Licensed under the Apache License, Version 2.0, see LICENSE for details.
// SPDX-License-Identifier: Apache-2.0

// class : gpio_rand_straps_vseq
// This gpio random test sequence performs following in each of multiple iterations:
// - Drives gpio_i input with random values
// - Set the expected strap_data_in based on the condition if is the first triggered strap_en or not
// - Updates the RAL model with the expected strap_data_in and strap_data_in_valid
// - Trigger the strap_en with one clock cycles
// - Read the registers hw_straps_data_in and hw_straps_data_in_valid
// - Check the expected behavior in the scoreboard and also on csr checks
class gpio_rand_straps_vseq extends gpio_base_vseq;

`uvm_object_utils(gpio_rand_straps_vseq)

// gpio input to drive
rand bit [NUM_GPIOS-1:0] gpio_i;
// gpio output to program in register
rand bit [NUM_GPIOS-1:0] gpio_o;
// gpio output enable to program in register
rand bit [NUM_GPIOS-1:0] gpio_oe;
// Flag to indicate that the first trigger straps happened
bit straps_triggered;
// Read straps_data_in
bit [NUM_GPIOS-1:0] rd_hw_straps_data_in;
// Read straps_data_in valid
bit rd_hw_straps_data_in_valid;
// Expected strap data_in
bit [NUM_GPIOS-1:0] exp_strap_data_in;

constraint num_trans_c {
num_trans inside {[20:200]};
}

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

task body();
`uvm_info(`gfn, $sformatf("num_trans = %0d", num_trans), UVM_HIGH)

for (uint tr_num = 0; tr_num < num_trans; tr_num++) begin
string msg_id = {`gfn, $sformatf(" Transaction-%0d", tr_num)};
`DV_CHECK_MEMBER_RANDOMIZE_FATAL(delay)
`DV_CHECK_MEMBER_RANDOMIZE_FATAL(gpio_i)
`DV_CHECK_MEMBER_RANDOMIZE_FATAL(gpio_o)
`DV_CHECK_MEMBER_RANDOMIZE_FATAL(gpio_oe)

cfg.clk_rst_vif.wait_clks(delay);
`uvm_info(msg_id, $sformatf("delay = %0d", delay), UVM_HIGH)
// Step-1 Drive the gpio_i
drive_gpio_in(gpio_i);

// If is not the first strap triggered, it should be the gpio_i input (that is the first one after reset),
// for the following interations keep the same value as the first strap already happened.
// No more updates in gpio_i should be taken
// into consideration for the strap_data_in register.
if(straps_triggered) begin
exp_strap_data_in = rd_hw_straps_data_in;
end else begin
exp_strap_data_in = gpio_i;
end

// Wait at least one clock cycle
`DV_CHECK_MEMBER_RANDOMIZE_WITH_FATAL(delay, delay >= 1;)

// Step-2 Trigger the snapshot of gpio_i to be stored in the straps registers
cfg.straps_vif_inst.strap_en = 1;
cfg.clk_rst_vif.wait_clks(1);
cfg.straps_vif_inst.strap_en = 0;
straps_triggered = 'b1;

// Step-3 Read the HW_STRAPS_DATA_IN register
// Reading straps data_in will trigger a check inside scoreboard

// Wait at least one clock cycle
`DV_CHECK_MEMBER_RANDOMIZE_WITH_FATAL(delay, delay >= 1;)

// Step-4 Read the hw_straps_data_in and check the expected value in the scoreboard
csr_rd(.ptr(ral.hw_straps_data_in), .value(rd_hw_straps_data_in));
// Read the hw_straps_data_in_valid and check the expected value in the scoreboard
csr_rd(.ptr(ral.hw_straps_data_in_valid), .value(rd_hw_straps_data_in_valid));

// Stop driving gpio_i
undrive_gpio_in();

// Step-5 Read to make sure that if does not affect the straps registers after undrive the gpio_in
csr_rd(.ptr(ral.hw_straps_data_in), .value(rd_hw_straps_data_in));
csr_rd(.ptr(ral.hw_straps_data_in_valid), .value(rd_hw_straps_data_in_valid));

// Additional verification
// Drive the gpio_o to make sure that has no impact on straps registers.
// test gpio outputs
cfg.gpio_vif.drive_en('0);

ral.direct_out.set(gpio_o);
ral.direct_oe.set(gpio_oe);
csr_update(.csr(ral.direct_out));
csr_update(.csr(ral.direct_oe));

`DV_CHECK_MEMBER_RANDOMIZE_WITH_FATAL(delay, delay >= 1;)

// Step-6 Drive again the strap_en
cfg.straps_vif_inst.strap_en = 1;
cfg.clk_rst_vif.wait_clks(1);
cfg.straps_vif_inst.strap_en = 0;

`DV_CHECK_MEMBER_RANDOMIZE_WITH_FATAL(delay, delay >= 1;)

// Step-7 Read to make sure that if does not affect the straps registers after drive the gpio_o
csr_rd(.ptr(ral.hw_straps_data_in), .value(rd_hw_straps_data_in));
csr_rd(.ptr(ral.hw_straps_data_in_valid), .value(rd_hw_straps_data_in_valid));

`uvm_info(msg_id, "End of Transaction", UVM_HIGH)

end // end for

endtask : body

endclass : gpio_rand_straps_vseq
1 change: 1 addition & 0 deletions hw/ip/gpio/dv/env/seq_lib/gpio_vseq_list.sv
Original file line number Diff line number Diff line change
Expand Up @@ -14,3 +14,4 @@
`include "gpio_random_long_reg_writes_reg_reads_vseq.sv"
`include "gpio_full_random_vseq.sv"
`include "gpio_stress_all_vseq.sv"
`include "gpio_rand_straps_vseq.sv"
1 change: 1 addition & 0 deletions hw/ip/gpio/dv/gpio_sim.core
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ filesets:
depend:
- lowrisc:dv:gpio_test
- lowrisc:dv:gpio_sva
- lowrisc:dv:gpio_if
files:
- tb/tb.sv
file_type: systemVerilogSource
Expand Down
4 changes: 4 additions & 0 deletions hw/ip/gpio/dv/gpio_sim_cfg.hjson
Original file line number Diff line number Diff line change
Expand Up @@ -180,6 +180,10 @@
build_mode: en_cdc_prims
run_opts: ["+no_pullup_pulldown=1"]
}
{
name: gpio_rand_straps
uvm_test_seq: gpio_rand_straps_vseq
}
]

// List of regressions.
Expand Down
18 changes: 18 additions & 0 deletions hw/ip/gpio/dv/interfaces/gpio_if.core
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
CAPI=2:
# Copyright lowRISC contributors (OpenTitan project).
# Licensed under the Apache License, Version 2.0, see LICENSE for details.
# SPDX-License-Identifier: Apache-2.0
name: "lowrisc:dv:gpio_if:0.1"
description: "GPIO Interfaces"
filesets:
files_dv:
depend:
- lowrisc:ip:gpio:0.1
files:
- gpio_straps_if.sv
file_type: systemVerilogSource

targets:
default:
filesets:
- files_dv
21 changes: 21 additions & 0 deletions hw/ip/gpio/dv/interfaces/gpio_straps_if.sv
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
// Copyright lowRISC contributors (OpenTitan project).
// Licensed under the Apache License, Version 2.0, see LICENSE for details.
// SPDX-License-Identifier: Apache-2.0
// interface : gpio_straps_if
`ifndef GPIO_STRAPS_IF_SV
`define GPIO_STRAPS_IF_SV

import gpio_pkg::*;

// Interface definition
interface gpio_straps_if (
inout strap_en_i, // Input signal to enable straps
input gpio_straps_t sampled_straps_o // Output signal of type gpio_straps_t
);

logic strap_en;
assign strap_en_i = strap_en;

endinterface

`endif // GPIO_STRAPS_IF_SV
Loading

0 comments on commit 05e6443

Please sign in to comment.