Skip to content

Commit

Permalink
New testcase for the GPIO feature straps
Browse files Browse the repository at this point in the history
- Fix the gpio_stress_all with random reset PR:25657 was taking into this
  commit.

Signed-off-by: Marcelo Carvalho Faleiro de Almeida <[email protected]>
  • Loading branch information
marcelocarvalhoLowRisc committed Feb 24, 2025
1 parent 29d7b87 commit 0017d95
Show file tree
Hide file tree
Showing 15 changed files with 319 additions and 10 deletions.
16 changes: 16 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,21 @@
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:
- Drive gpio_i input with random values.
- Set strap_en high for at least one clock cycle.
- Read the registers hw_straps_data_in and hw_straps_data_in_valid.
- Check the data read and sampled_straps_o in the scoreboard.
- Drive gpio_o to make sure that has no impact on straps registers.
- Verify that driving gpio_o does not affect the straps registers.
- Apply a reset and ensure the strap registers are cleared.
- Read straps registers after reset.
- Iterate through the same flow again with new random values.
'''
stage: V3
tests: ["gpio_rand_straps"]
}
]
}
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
56 changes: 55 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,8 @@ 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;
// Flag to indicate that the strap was triggered
bit first_strap_triggered;

// mask are WO, store the values in scb
uvm_reg_data_t masked_out_lower_mask;
Expand All @@ -40,7 +42,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 +58,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 +365,53 @@ class gpio_scoreboard extends cip_base_scoreboard #(.CFG_T (gpio_env_cfg),
end
endtask : monitor_gpio_interrupt_pins

virtual task update_gpio_straps_regs();
// Update data_in and data_in_valid ral register value based on result of input
`DV_CHECK_FATAL(ral.hw_straps_data_in.predict(.value(gpio_i_driven),
.kind(UVM_PREDICT_READ)));
`DV_CHECK_FATAL(ral.hw_straps_data_in_valid.predict(.value('b1),
.kind(UVM_PREDICT_READ)));
endtask : update_gpio_straps_regs

// Task: monitor_gpio_straps
// The task monitors the gpio straps enable signal
// and checks the straps output signal after the first strap trigger
virtual task monitor_gpio_straps();
forever begin : monitor_gpio_straps
wait(!cfg.under_reset);
fork begin : isolation_fork
fork begin
wait(cfg.under_reset);
forever begin
@(posedge cfg.clk_rst_vif.clk)
if(cfg.straps_vif_inst.tb_if.strap_en &&
!cfg.straps_vif_inst.strap_en_q &&
!cfg.straps_vif_inst.strap_en_qq) begin
// Wait for at least 1 clock cycle after strap_en is asserted,
// to allow the straps to be
// ready for sampling.
cfg.clk_rst_vif.wait_clks(1);
update_gpio_straps_regs();

if (!first_strap_triggered) begin
// 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.tb_if.sampled_straps.data)
// Check the register hw_straps_data_in_valid
`DV_CHECK_CASE_EQ('b1, cfg.straps_vif_inst.tb_if.sampled_straps.valid)
// Turn-off the checker after the first strap trigger.
first_strap_triggered = 1;
end
end
end
end
join_any
disable fork;
end
join
end
endtask : monitor_gpio_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 @@ -561,6 +613,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 Expand Up @@ -804,6 +857,7 @@ class gpio_scoreboard extends cip_base_scoreboard #(.CFG_T (gpio_env_cfg),
last_intr_update_except_clearing = '0;
last_intr_test_event = '0;
cleared_intr_bits = '0;
first_strap_triggered = 0;
endfunction

// Function: check_phase
Expand Down
11 changes: 11 additions & 0 deletions hw/ip/gpio/dv/env/seq_lib/gpio_base_vseq.sv
Original file line number Diff line number Diff line change
Expand Up @@ -124,4 +124,15 @@ class gpio_base_vseq extends cip_base_vseq #(
end
endtask : pgm_intr_regs

// Wait a few cycles. If force_positive is true, Wait at least one clock cycle.
task short_wait(bit force_positive);
int unsigned delay;
`DV_CHECK_FATAL(std::randomize(delay) with
{
delay dist {0 :/ 20, [1:5] :/ 40, [6:15] :/ 30, [20:25] :/ 10};
force_positive -> delay > 0;
})
cfg.clk_rst_vif.wait_clks(delay);
endtask

endclass : gpio_base_vseq
144 changes: 144 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,144 @@
// Copyright lowRISC contributors (OpenTitan project).
// Licensed under the Apache License, Version 2.0, see LICENSE for details.
// SPDX-License-Identifier: Apache-2.0
//
// Verify the straps data/valid ouput expected values based on the strap_en and gpio_in inputs:
// - Drive gpio_in input with random values.
// - Set the strap_en high for at least one clock cycle.
// - Read the registers hw_straps_data_in and hw_straps_data_in_valid.
// - The data read and sampled_straps_o will be checked in the scoreboard.
// - Drive the gpio_out to make sure that has no impact on straps registers.
// - Read to make sure that if does not affect the straps registers after drive the gpio_out.
// - Apply reset and make sure the strap registers are clean.
// - Read straps registers after reset.
// - Iterate again the same flow, with new random values.
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_in;
// gpio output to program in register
rand bit [NUM_GPIOS-1:0] gpio_out;
// gpio output enable to program in register
rand bit [NUM_GPIOS-1:0] gpio_oe;

constraint num_trans_c {
num_trans inside {[1:3]};
}

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

// Read hw_straps_data_in and hw_straps_data_in_valid and
// check they match the expected value in
// the scoreboard
task csr_strap_read();
fork
begin
uvm_status_e status;
ral.hw_straps_data_in.mirror(status, UVM_CHECK);
`DV_CHECK_EQ(status, UVM_IS_OK)
end
begin
uvm_status_e status;
ral.hw_straps_data_in_valid.mirror(status, UVM_CHECK);
`DV_CHECK_EQ(status, UVM_IS_OK)
end
join
endtask : csr_strap_read

task test_straps_gpio_in();
// Drive the gpio_in
drive_gpio_in(gpio_in);

// Wait at least one clock cycle to drive the strap_en
// Required because is required one clock cycle to update the gpio_in registers.
short_wait(1);

// Trigger the snapshot of gpio_in to be stored in the straps registers
cfg.straps_vif_inst.tb_if.strap_en = 1;
short_wait(1);

// Read the hw_straps_data_in and check the expected value in the scoreboard
csr_strap_read();

// Random wait
short_wait(0);

// Stop driving gpio_in
undrive_gpio_in();

// Random wait
short_wait(0);

// Read to make sure that if does not affect the straps registers after undrive the gpio_in
csr_strap_read();

endtask : test_straps_gpio_in

task test_straps_gpio_out();

// Additional verification
// Drive the gpio_out to make sure that has no impact on straps registers.
// then read the gpio strap registers again
cfg.gpio_vif.drive_en('0);

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

// Random wait
short_wait(0);

// Read to make sure that if does not affect the straps registers after drive the gpio_out
csr_strap_read();

endtask : test_straps_gpio_out

task check_transaction(string txn_desc, bit is_first);
string msg_id = {`gfn, txn_desc};

`DV_CHECK_MEMBER_RANDOMIZE_FATAL(gpio_in)
`DV_CHECK_MEMBER_RANDOMIZE_FATAL(gpio_out)
`DV_CHECK_MEMBER_RANDOMIZE_FATAL(gpio_oe)

// User case to test the straps output, with gpio_in data randomised
test_straps_gpio_in();

// User case to test the straps output/registers, with gpio_out data randomised
// The gpio_out should not affect the straps output/registers.
test_straps_gpio_out();

// Random wait
short_wait(0);

// Disable the straps.
cfg.straps_vif_inst.tb_if.strap_en = 0;
// Apply reset and make sure the strap registers are clean
apply_reset();

// Random wait
short_wait(1);

// Read the straps registers after reset
csr_strap_read();

endtask : check_transaction

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)};

short_wait(1);
check_transaction(msg_id, tr_num == 0);
`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
Loading

0 comments on commit 0017d95

Please sign in to comment.