Skip to content

Commit f06d73b

Browse files
committed
[chip, gpio, dv] Added W1's, W0's, T1's and T0's testing for GPIOs
The smoketest.c and top_chip_dv_gpio_base_vseq works in pairs in a way that C drives W1's and W0's pattern on the outputs and vseq drives all 1's and all 0's pattern on the inputs. Both C and vseq waits for an expected pattern to arrive in order to drive the next pattern. Signed-off-by: Kinza Qamar <kqzaman@lowrisc.org>
1 parent bf63dfa commit f06d73b

File tree

3 files changed

+221
-28
lines changed

3 files changed

+221
-28
lines changed

hw/top_chip/dv/env/seq_lib/top_chip_dv_gpio_base_vseq.sv

Lines changed: 105 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,17 @@ class top_chip_dv_gpio_base_vseq extends top_chip_dv_base_vseq;
88
// Standard SV/UVM methods
99
extern function new(string name="");
1010
extern task body();
11+
12+
// Class specific methods
13+
//
14+
// Waits for the pattern to appear on the GPIOs
15+
extern virtual task wait_for_pattern(logic [NUM_GPIOS-1:0] exp_val);
16+
17+
// Drives a pattern on the quarter GPIOs pins in input mode
18+
extern virtual task drive_pattern(int unsigned wait_num_clks,
19+
int unsigned pins_starting_quarter,
20+
int unsigned pins_next_quarter,
21+
bit state);
1122
endclass : top_chip_dv_gpio_base_vseq
1223

1324
function top_chip_dv_gpio_base_vseq::new (string name = "");
@@ -17,5 +28,98 @@ endfunction : new
1728
task top_chip_dv_gpio_base_vseq::body();
1829
super.body();
1930
`DV_WAIT(cfg.sw_test_status_vif.sw_test_status == SwTestStatusInTest);
20-
// TODO
31+
32+
// Checks the GPIOs in both input and output mode. SW writes walking 0's and walking 1's pattern
33+
// on the first and third quarter of direct_out register and body() waits (for a reasonable
34+
// amount of timeout) for that pattern to appear on the pads. Then it drives all 1's and all 0's
35+
// on the other even quaters.
36+
//
37+
// Enable the pulldowns so that the pads are driving 0's rather than Z's when no external driver
38+
// is connected
39+
cfg.gpio_vif.set_pulldown_en('1);
40+
41+
// Current Current GPIOs pads state : 'h0
42+
43+
`uvm_info(`gfn, "Starting GPIOs outputs test", UVM_LOW)
44+
45+
// Check for walking 1's pattern on the first quarter of pins.
46+
for (int i = 0; i < NUM_GPIOS/4; i++) begin
47+
wait_for_pattern({24'h0, 1 << i});
48+
end
49+
50+
// Current GPIOs pads state : 'h00000080
51+
//
52+
// Drive all 1's on the second quarter of pins.
53+
drive_pattern(2, 1, 2, 1);
54+
55+
// Current GPIOs pads state : 'h0000FF80
56+
//
57+
// Check for walking 1's pattern on the third quarter of pins.
58+
for (int i = 0; i < NUM_GPIOS/4; i++) begin
59+
wait_for_pattern({8'h0, 1 << i, 16'hFF80});
60+
end
61+
62+
// Current GPIOs pads state : 'h0080FF80
63+
//
64+
// Drive all 1's on the fourth quarter of pins.
65+
drive_pattern(2, 3, 4, 1);
66+
67+
// Current GPIOs pads state : 'hFF80FF80
68+
//
69+
// The SW first sets the first and third quarter of GPIOs to 1's in order to walk 0's on them.
70+
// The second and fourth quarter of pads should contain all 1's by now.
71+
//
72+
// Wait and check for all 1s.
73+
wait_for_pattern({NUM_GPIOS{1'b1}});
74+
75+
// Current GPIOs pads state : 'hFFFFFFFF
76+
//
77+
// Check for walking 0's pattern on the first quarter of pins.
78+
for (int i = 0; i < NUM_GPIOS/4; i++) begin
79+
wait_for_pattern({24'hFF_FFFF, ~(1 << i)});
80+
end
81+
82+
// Current GPIOs pads state : 'hFFFFFF7F
83+
//
84+
// Drive all 0's on the second quarter of pins.
85+
drive_pattern(2, 1, 2, 0);
86+
87+
// Current GPIOs pads state : 'hFFFF007F
88+
//
89+
// Check for walking 0's pattern on on the third quarter of pins.
90+
for (int i = 0; i < NUM_GPIOS/4; i++) begin
91+
wait_for_pattern({8'hFF, ~(1 << i), 16'h007F});
92+
end
93+
94+
// Current GPIOs pads state : 'hFF7F007F
95+
//
96+
// Drive all 0's on the fourth quarter of pins.
97+
drive_pattern(2, 3, 4, 0);
98+
99+
// Current GPIOs pads state : 'h007F007F
21100
endtask : body
101+
102+
task top_chip_dv_gpio_base_vseq::wait_for_pattern(logic [NUM_GPIOS-1:0] exp_val);
103+
`DV_SPINWAIT(wait(cfg.gpio_vif.pins === exp_val);,
104+
$sformatf("Timed out waiting for GPIOs == %0h", exp_val),
105+
/*use default_spinwait_timeout_ns*/,
106+
`gfn)
107+
endtask : wait_for_pattern
108+
109+
task top_chip_dv_gpio_base_vseq::drive_pattern(int unsigned wait_num_clks,
110+
int unsigned pins_starting_quarter,
111+
int unsigned pins_next_quarter,
112+
bit state);
113+
114+
int unsigned quarter_start = (NUM_GPIOS/4) * pins_starting_quarter;
115+
int unsigned quarter_end = (NUM_GPIOS/4) * pins_next_quarter;
116+
117+
// Wait for some cycles so that the pads can transition from the current pin state to the next pin
118+
// state
119+
cfg.sys_clk_vif.wait_clks(wait_num_clks);
120+
121+
// Drive state on the quarter of pins
122+
for (int i = quarter_start; i < quarter_end; i++) begin
123+
cfg.gpio_vif.drive_pin(i, state);
124+
end
125+
endtask : drive_pattern

signals.svwf

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
2+
#
3+
# Mnemonic Maps
4+
#
5+
mmap new -reuse -name {Boolean as Logic} -radix %b -contents {{%c=FALSE -edgepriority 1 -shape low}
6+
{%c=TRUE -edgepriority 1 -shape high}}
7+
mmap new -reuse -name {Example Map} -radix %x -contents {{%b=11???? -bgcolor orange -label REG:%x -linecolor yellow -shape bus}
8+
{%x=1F -bgcolor red -label ERROR -linecolor white -shape EVENT}
9+
{%x=2C -bgcolor red -label ERROR -linecolor white -shape EVENT}
10+
{%x=* -label %x -linecolor gray -shape bus}}
11+
12+
array unset createdGroup
13+
array set createdGroup {}
14+
set id [waveform add -signals [subst {
15+
{[format {tb.dut.u_gpio.clk_i}]}
16+
} ]]
17+
set id [waveform add -signals [subst {
18+
{[format {tb.dut.u_gpio.rst_ni}]}
19+
} ]]
20+
set id [waveform add -signals [subst {
21+
{[format {tb.dut.u_gpio.cio_gpio_i[31:0]}]}
22+
} ]]
23+
set id [waveform add -signals [subst {
24+
{[format {tb.dut.u_gpio.cio_gpio_en_o[31:0]}]}
25+
} ]]
26+
set id [waveform add -signals [subst {
27+
{[format {tb.dut.u_gpio.cio_gpio_o[31:0]}]}
28+
} ]]
29+
set id [waveform add -signals [subst {
30+
{[format {tb.dut.u_gpio.tl_i}]}
31+
} ]]
32+
set id [waveform add -signals [subst {
33+
{[format {tb.dut.u_gpio.tl_o}]}
34+
} ]]
35+
36+
waveform xview limits 0 501700.823ns

sw/device/tests/gpio/smoketest.c

Lines changed: 80 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -8,49 +8,102 @@
88
#include <stdbool.h>
99
#include <stdint.h>
1010

11-
// Check that we can write and read some GPIO registers
12-
static bool reg_test(gpio_t gpio)
11+
// Drive a pattern (val)
12+
static void drive(gpio_t gpio, uint32_t masked_reg, uint32_t val)
1313
{
14-
uint32_t hal_val;
14+
gpio_write(gpio, masked_reg, 0XFFFF0000 | val);
15+
}
1516

16-
// Inputs
17-
hal_val = 0;
18-
for (int ii = 0; ii < GPIO_NUM_PINS; ii++) {
19-
hal_val |= (gpio_read_pin(gpio, ii) << ii);
20-
}
21-
if (hal_val != DEV_READ(gpio + GPIO_REG_DATA_IN)) {
22-
return false;
17+
// Wait for an expected pattern (compare_val).
18+
static void wait(gpio_t gpio, uint32_t compare_val)
19+
{
20+
while (DEV_READ(gpio + GPIO_REG_DATA_IN) != compare_val) {
2321
}
22+
}
23+
24+
// Verifies GPIOs in partially output and input direction. The test distributes GPIOs as four equal
25+
// quarters. The idea is to drive first quarter of GPIOs as outputs and wait for a pattern to appear
26+
// on the second quarter of pins as inputs. Next, drive a pattern on the third quarter and waits for a
27+
// pattern to appear on the fourth quarter as inputs. Repeat the same process second time but with a
28+
// different pattern.
29+
//
30+
// The pattern driven on the outputs is going to be walking 1's (1, 10, 0100, 1000, ...) first and
31+
// then walking 0's (1110, 1101, 1011, 0111, ...) whereas it is all 1's then all 0's sequence for
32+
// the inputs.
33+
//
34+
// 1- Walk 1's on the first quarter of GPIOs in output mode.
35+
// 2- top_chip_dv_gpio_base_vseq will wait for walking 1's pattern to appear on the pads. Once it
36+
// sees that pattern, it will drive all 1's on to the second quarter.
37+
// 4- gpio_test waits for the pattern 0x0000FF80 on the GPIO pads by reading DATA_IN register. Then
38+
// it will walk 1's on the third quarter of pins and waits for pattern 0xFF80FF80.
39+
// 5- On the other side, the vseq waits for the walking 1's pattern on the third quarter of pins and
40+
// drive all 1's on the fourth quarter.
41+
// 6- After all that, gpio_test start to write 1's to the first and third quarter of pins in order to
42+
// drive walking 0's. Everything beyond that is similar but the expected driven sequence is going
43+
// to be 0's on the inputs and walking 0's on the outputs.
44+
static bool gpio_test(gpio_t gpio)
45+
{
46+
// Enable the first and third quarter of pins in output mode
47+
gpio_set_all_oe(gpio, 0x00FF00FF);
2448

25-
// Outputs
26-
hal_val = 0xC1A0; // Ciao!
27-
for (int nn = 0; nn < 2; nn++) {
28-
for (int ii = 0; ii < GPIO_NUM_PINS; ii++) {
29-
gpio_write_pin(gpio, ii, ((hal_val >> ii) & 0x1));
49+
// Current GPIOs pads state : 0x00000000
50+
//
51+
// Walk 1's on the first quarter. vseq drives the second quarter with all 1's. Hence, the
52+
// expected value to wait for is 0xFF80,
53+
for (int i = 0; i < GPIO_NUM_PINS / 4; i++) {
54+
drive(gpio, GPIO_REG_MASKED_OUT_LOWER, 1 << i);
55+
if (i == ((GPIO_NUM_PINS / 4) - 1)) {
56+
wait(gpio, 0xFF80);
3057
}
31-
if (hal_val != DEV_READ(gpio + GPIO_REG_DIRECT_OUT)) {
32-
return false;
58+
}
59+
60+
// Current GPIOs pads state : 0x0000FF80
61+
//
62+
// Walk 1's on the third quarter. vseq drives the fourth quarter with all 1's. Additionally, the
63+
// pads contains 0xFF80 by now on the first two quarters. Hence, the expected value to wait for
64+
// is 0xFF80FF80,
65+
for (int i = 0; i < GPIO_NUM_PINS / 4; i++) {
66+
drive(gpio, GPIO_REG_MASKED_OUT_UPPER, 1 << i);
67+
if (i == ((GPIO_NUM_PINS / 4) - 1)) {
68+
wait(gpio, 0xFF80FF80);
3369
}
34-
hal_val = ~hal_val; // invert to check for constant bits
3570
}
3671

37-
// Output enables
38-
hal_val = 0xB7EE; // Byee!
39-
for (int nn = 0; nn < 2; nn++) {
40-
for (int ii = 0; ii < GPIO_NUM_PINS; ii++) {
41-
gpio_set_oe_pin(gpio, ii, ((hal_val >> ii) & 0x1));
72+
// Current GPIOs pads state : 0xFF80FF80
73+
//
74+
// Now, set the first and third quarter (which are enabled as outputs) to all 1's in order to
75+
// walk 0's on them.
76+
gpio_write(gpio, GPIO_REG_DIRECT_OUT, 0x00FF00FF);
77+
78+
// Current GPIOs pads state : 0xFFFFFFFF
79+
//
80+
// Walk 0's on the first quarter of pins. vseq drives the second quarter with all 0's.
81+
// Hence, the expected value to wait for is 0xFFFF007F.
82+
for (int i = 0; i < GPIO_NUM_PINS / 4; i++) {
83+
drive(gpio, GPIO_REG_MASKED_OUT_LOWER, ~(1 << i));
84+
if (i == ((GPIO_NUM_PINS / 4) - 1)) {
85+
wait(gpio, 0xFFFF007F);
4286
}
43-
if (hal_val != DEV_READ(gpio + GPIO_REG_DIRECT_OE)) {
44-
return false;
87+
}
88+
89+
// Current GPIOs pads state : 0xFFFF007F
90+
//
91+
// Walk 0's on the third quarter of pins. vseq drives the fourth quarter with all 0's.
92+
// Hence, the expected value to wait for is 0x007F007F.
93+
for (int i = 0; i < GPIO_NUM_PINS / 4; i++) {
94+
drive(gpio, GPIO_REG_MASKED_OUT_UPPER, ~(1 << i));
95+
if (i == ((GPIO_NUM_PINS / 4) - 1)) {
96+
wait(gpio, 0x007F007F);
4597
}
46-
hal_val = ~hal_val; // invert to check for constant bits
4798
}
4899

100+
// Current GPIOs pads state : 0x007F007F
101+
49102
return true;
50103
}
51104

52105
bool test_main()
53106
{
54107
gpio_t gpio = mocha_system_gpio();
55-
return reg_test(gpio);
108+
return gpio_test(gpio);
56109
}

0 commit comments

Comments
 (0)