Skip to content

Commit 5ade54b

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 T1's and T0'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 471f518 commit 5ade54b

2 files changed

Lines changed: 209 additions & 2 deletions

File tree

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

Lines changed: 112 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,11 @@ 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);
1116
endclass : top_chip_dv_gpio_base_vseq
1217

1318
function top_chip_dv_gpio_base_vseq::new (string name = "");
@@ -17,5 +22,111 @@ endfunction : new
1722
task top_chip_dv_gpio_base_vseq::body();
1823
super.body();
1924
`DV_WAIT(cfg.sw_test_status_vif.sw_test_status == SwTestStatusInTest);
20-
// TODO
25+
26+
// Checks the GPIOs in both input and output mode. A smoketest.c writes walking 0's and walking
27+
// 1's pattern on the first and third of direct_out register and body() waits (for a reasonable
28+
// amount of timeout) for that pattern to appear on the pads to drive 1's and 0's in temperature
29+
// sequence fashion.
30+
//
31+
// Enable the pulldowns so that the pads are driving 0's rather than Z's when no external driver
32+
// is connected
33+
cfg.gpio_vif.set_pulldown_en('1);
34+
35+
// Current Current GPIOs pads state state : 'h0
36+
37+
`uvm_info(`gfn, "Starting GPIOs outputs test", UVM_LOW)
38+
39+
// The C code first sets the first and third quater of GPIOs to 0's in order to walk 1's on them.
40+
//
41+
// Wait and check for all 0s.
42+
wait_for_pattern({NUM_GPIOS{1'b0}});
43+
44+
// Check for walking 1's pattern on the first quater of pins.
45+
for (int i = 0; i < NUM_GPIOS/4; i++) begin
46+
wait_for_pattern({24'h0, 1 << i});
47+
end
48+
49+
// Wait for a cycle so that the pads can transition from the current pin state to the next pin
50+
// state
51+
cfg.peri_clk_vif.wait_clks(1);
52+
53+
// Current GPIOs pads state : 'h00000080
54+
//
55+
// Drive 1's in temperature pattern on the second quater of pins.
56+
for (int i = NUM_GPIOS/4; i < (NUM_GPIOS/4) * 2; i++) begin
57+
cfg.gpio_vif.drive_pin(i, 1);
58+
end
59+
60+
// Current GPIOs pads state : 'h0000FF80
61+
//
62+
// Check for walking 1's pattern on the third quater of pins.
63+
for (int i = 0; i < NUM_GPIOS/4; i++) begin
64+
wait_for_pattern({8'h?, 1 << i, 16'h????});
65+
end
66+
67+
// Wait for a cycle so that the pads can transition from the current pin state to the next pin
68+
// state
69+
cfg.peri_clk_vif.wait_clks(1);
70+
71+
// Current GPIOs pads state : 'h0080FF80
72+
//
73+
// Drive 1's in temperature pattern on the fourth quater of pins.
74+
for (int i = (NUM_GPIOS/4) * 3; i < NUM_GPIOS; i++) begin
75+
cfg.gpio_vif.drive_pin(i, 1);
76+
end
77+
78+
// Current GPIOs pads state : 'hFF80FF80
79+
//
80+
// The C code first sets the first and third quater of GPIOs to 1's in order to walk 0's on them.
81+
// The second and fourth quater of pads should contain all 1's by now.
82+
//
83+
//
84+
// Wait and check for all 1s.
85+
wait_for_pattern({NUM_GPIOS{1'b1}});
86+
87+
// Current GPIOs pads state : 'hFFFFFFFF
88+
//
89+
// Check for walking 0's pattern on the first quater of pins.
90+
for (int i = 0; i < NUM_GPIOS/4; i++) begin
91+
wait_for_pattern({24'h?, ~(1 << i)});
92+
end
93+
94+
// Wait for a cycle so that the pads can transition from the current pin state to the next pin
95+
// state
96+
cfg.peri_clk_vif.wait_clks(1);
97+
98+
// Current GPIOs pads state : 'hFFFFFF7F
99+
//
100+
// Drive 0's in temperature pattern on the second quater of pins.
101+
for (int i = NUM_GPIOS/4; i < (NUM_GPIOS/4) * 2; i++) begin
102+
cfg.gpio_vif.drive_pin(i, 0);
103+
end
104+
105+
// Current GPIOs pads state : 'hFFFF007F
106+
//
107+
// Check for walking 0's pattern on on the third quater of pins.
108+
for (int i = 0; i < NUM_GPIOS/4; i++) begin
109+
wait_for_pattern({8'h?, ~(1 << i), 16'h?});
110+
end
111+
112+
// Wait for a cycle so that the pads can transition from the current pin state to the next pin
113+
// state
114+
cfg.peri_clk_vif.wait_clks(1);
115+
116+
// Current GPIOs pads state : 'hFF00007F
117+
//
118+
// Drive 0's in temperature pattern on the fourth quater of pins.
119+
for (int i = (NUM_GPIOS/4) * 3; i < NUM_GPIOS; i++) begin
120+
cfg.gpio_vif.drive_pin(i, 0);
121+
end
122+
123+
// Current GPIOs pads state : 'h7F00007F
124+
21125
endtask : body
126+
127+
task top_chip_dv_gpio_base_vseq::wait_for_pattern(logic [NUM_GPIOS-1:0] exp_val);
128+
`DV_SPINWAIT(wait(cfg.gpio_vif.pins ==? exp_val);,
129+
$sformatf("Timed out waiting for GPIOs == %0h", exp_val),
130+
/*use default_spinwait_timeout_ns*/,
131+
`gfn)
132+
endtask : wait_for_pattern

sw/device/tests/gpio/smoketest.c

Lines changed: 97 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -49,8 +49,104 @@ static bool reg_test(gpio_t gpio)
4949
return true;
5050
}
5151

52+
// Drive a pattern (val)
53+
static void drive(gpio_t gpio, uint32_t masked_reg, uint32_t val) {
54+
gpio_write(gpio, masked_reg, 0XFFFF0000 | val);
55+
}
56+
57+
// Wait for an expected pattern (compare_val).
58+
static void wait(gpio_t gpio, uint32_t compare_val) {
59+
while(DEV_READ(gpio + GPIO_REG_DATA_IN) != compare_val){
60+
}
61+
}
62+
63+
// Verifies GPIOs in partially output and input direction. The test distributes GPIOs as four equal
64+
// quaters. The idea is to drive first quater of GPIOs as outputs and wait for a pattern to appear
65+
// on the second quater of pins as inputs. Next, drive a pattern on the third quater and waits for a
66+
// pattern to appear on the fourth quater as inputs. Repeat the same process second time but with a
67+
// different pattern.
68+
//
69+
// The pattern driven on the outputs is going to be walking 1's (1, 10, 0100, 1000, ...) first and
70+
// then walking 0's (1110, 1101, 1011, 0111, ...) whereas it is a temperature 1's (1, 11, 111, 1111,
71+
// ...) then a temperature 0's (1110, 1100, 1000, 0000, ...) sequence for the inputs.
72+
//
73+
// 1- First, drive 0's on the first and third quater of GPIOs.
74+
// 2- Walk 1's on the first quater of GPIOs in output mode.
75+
// 3- top_chip_dv_gpio_base_vseq will wait for walking 1's pattern to appear on the pads. Once it
76+
// sees that pattern, it will drive 1's in temperature sequence on to the second quater.
77+
// 4- gpio_test waits for the pattern 0x0000T1W1 on the GPIO pads by reading DATA_IN register. Then
78+
// it will walk 1's on the third quater of pins and waits for pattern 0xT1W1T1W1.
79+
// 5- On the other side, the vseq waits for the walking 1's pattern on the third quater of pins and
80+
// drive 1's in temperature sequence on the fourth quater.
81+
// 6- After all that, gpio_test start to write 1's to the first and third quater of pins in order to
82+
// drive walking 0's. Everything beyond that is similar but the expected driven sequence is going
83+
// to be temperature 0's and walking 0's.
84+
static bool gpio_test(gpio_t gpio)
85+
{
86+
// Enable the first and third quater of pins in output mode
87+
gpio_set_all_oe(gpio, 0x00FF00FF);
88+
89+
// Set the gpios to all 0's in order to walk 1's on first and third quater,
90+
gpio_write(gpio, GPIO_REG_DIRECT_OUT, 0x0);
91+
92+
// Current GPIOs pads state : 0x00000000
93+
//
94+
// Walk 1's on the first quater. vseq drives the second quater as temperature 1's. Hence, the
95+
// expected value to wait for is 0xFF80,
96+
for (int i = 0; i < GPIO_NUM_PINS / 4; i++) {
97+
drive(gpio, GPIO_REG_MASKED_OUT_LOWER, 1 << i);
98+
if (i == ((GPIO_NUM_PINS / 4) - 1)) {
99+
wait(gpio, 0xFF80);
100+
}
101+
}
102+
103+
// Current GPIOs pads state : 0x0000FF80
104+
//
105+
// Walk 1's on the third quater. vseq drives the fourth quater as temperature 1's. Additionally,
106+
// the pads contains 0xFF80 by now on the first two quaters. Hence, the expected value to wait
107+
// for is 0xFF80FF80,
108+
for (int i = 0; i < GPIO_NUM_PINS / 4; i++) {
109+
drive(gpio, GPIO_REG_MASKED_OUT_UPPER, 1 << i);
110+
if (i == ((GPIO_NUM_PINS / 4) - 1)) {
111+
wait(gpio, 0xFF80FF80);
112+
}
113+
}
114+
115+
// Current GPIOs pads state : 0xFF80FF80
116+
//
117+
// Now, set the first and third quater (which are enabled as outputs) to all 1's in order to
118+
// walk 0's on them.
119+
gpio_write(gpio, GPIO_REG_DIRECT_OUT, 0x00FF00FF);
120+
121+
// Current GPIOs pads state : 0xFFFFFFFF
122+
//
123+
// Walk 0's on the first quater of pins. vseq drives the second quater as temperature 0's.
124+
// Hence, the expected value to wait for is 0xFFFF007F.
125+
for (int i = 0; i < GPIO_NUM_PINS / 4; i++) {
126+
drive(gpio, GPIO_REG_MASKED_OUT_LOWER, ~(1 << i));
127+
if (i == ((GPIO_NUM_PINS / 4) - 1)) {
128+
wait(gpio, 0xFFFF007F);
129+
}
130+
}
131+
132+
// Current GPIOs pads state : 0xFFFF007F
133+
//
134+
// Walk 0's on the third quater of pins. vseq drives the fourth quater as temperature 0's.
135+
// Hence, the expected value to wait for is 0x007F007F.
136+
for (int i = 0; i < GPIO_NUM_PINS / 4; i++) {
137+
drive(gpio, GPIO_REG_MASKED_OUT_UPPER, ~(1 << i));
138+
if (i == ((GPIO_NUM_PINS / 4) - 1)) {
139+
wait(gpio, 0x007F007F);
140+
}
141+
}
142+
143+
// Current GPIOs pads state : 0x007F007F
144+
145+
return true;
146+
}
147+
52148
bool test_main()
53149
{
54150
gpio_t gpio = mocha_system_gpio();
55-
return reg_test(gpio);
151+
return gpio_test(gpio);
56152
}

0 commit comments

Comments
 (0)