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 17, 2025
1 parent 29d7b87 commit 913c3a4
Show file tree
Hide file tree
Showing 17 changed files with 289 additions and 43 deletions.
10 changes: 9 additions & 1 deletion hw/ip/gpio/data/gpio.hjson
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,7 @@
package: "",
desc: '''
This signal is pulsed high by the power manager after reset in order to sample the HW straps.
It can only be pulsed high one-time after reset. The following pulses will not be taken into consideration.
''',
default: "1'b0"
},
Expand Down Expand Up @@ -390,7 +391,14 @@
],
},
{ name: "HW_STRAPS_DATA_IN",
desc: "GPIO Input data sampled as straps during cold boot read value",
desc: '''
GPIO input data that was sampled as straps as the block came out of reset.

This register depends on the GpioAsHwStrapsEn parameter.
- If the parameter is false then the register reads as zero.
- If the parameter is true then GPIO input data is sampled on the first cycle after reset
where the strap_en_i input is high. That sampled data is stored in this register.
''',
swaccess: "ro",
hwaccess: "hrw",
tags: [// Value in the register is determined by GPIO pin values that are sampled
Expand Down
15 changes: 15 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,20 @@
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 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_o 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_o.
- Apply reset and make sure the strap registers are clean.
- Read straps registers after reset.
- Iterate again the same flow, with new random values.'''
stage: V3
tests: ["gpio_rand_straps"]
}
]
}
1 change: 1 addition & 0 deletions hw/ip/gpio/doc/registers.md
Original file line number Diff line number Diff line change
Expand Up @@ -359,6 +359,7 @@ Indicates whether the data in [`HW_STRAPS_DATA_IN`](#hw_straps_data_in) is valid

## HW_STRAPS_DATA_IN
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.
- Offset: `0x44`
- Reset default: `0x0`
- Reset mask: `0xffffffff`
Expand Down
34 changes: 0 additions & 34 deletions hw/ip/gpio/dv/cov/gpio_cov_excl.el

This file was deleted.

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
10 changes: 9 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 All @@ -27,6 +32,9 @@ class gpio_env_cfg extends cip_base_env_cfg #(

// only support 1 outstanding TL item
m_tl_agent_cfg.max_outstanding_req = 1;

// Used to allow reset operation during a stress all tests and check the CSR after that.
can_reset_with_csr_accesses = 1'b1;
endfunction : initialize

endclass
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
52 changes: 51 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 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 +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,8 @@ class gpio_scoreboard extends cip_base_scoreboard #(.CFG_T (gpio_env_cfg),
fork
monitor_gpio_i();
monitor_gpio_interrupt_pins();
monitor_gpio_straps();
handle_reset();
join_none
endtask

Expand Down Expand Up @@ -360,6 +366,48 @@ 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)
if(!cfg.under_reset) begin
if (|gpio_i_driven === 1'b1) begin
@(negedge cfg.straps_vif_inst.strap_en) 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 valid 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
end
endtask : monitor_gpio_straps

virtual protected task handle_reset();
forever begin
@(negedge cfg.clk_rst_vif.rst_n);
cfg.under_reset = 1;
@(posedge cfg.clk_rst_vif.rst_n);
cfg.under_reset = 0;
end
endtask

// 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.data)
// Check the register hw_straps_data_in_valid
`DV_CHECK_CASE_EQ('b1, cfg.straps_vif_inst.sampled_straps.valid)
// Turn-off the checker after the first strap trigger.
first_strap_trigged = 1;
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 @@ -561,6 +609,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 +853,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_trigged = 0;
endfunction

// Function: check_phase
Expand Down
134 changes: 134 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,134 @@
// 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);

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

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

// 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;)
cfg.clk_rst_vif.wait_clks(delay);

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

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

// Stop driving gpio_i
undrive_gpio_in();

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

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

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

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

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

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

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

// Apply reset and make sure the strap registers are clean
apply_reset();

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

// Step-8 Read the straps registers after reset
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
Loading

0 comments on commit 913c3a4

Please sign in to comment.