1
1
#!/usr/bin/env python3
2
2
3
- # Copyright (c) 2023-2024 Rivos, Inc.
3
+ # Copyright (c) 2023-2025 Rivos, Inc.
4
4
# SPDX-License-Identifier: Apache2
5
5
6
6
"""OpenTitan QEMU unit test sequencer.
@@ -229,6 +229,9 @@ def run(self, tdef: EasyDict[str, Any]) -> tuple[int, ExecTime, str]:
229
229
- trigger, a string to match on the QEMU virtual comm port
230
230
output to trigger the context execution. It may be
231
231
defined as a regular expression.
232
+ - validate, a string to match on the QEMU virtual comm port
233
+ output to early exit. It may be defined as a regular
234
+ expression.
232
235
- start_delay, the delay to wait before starting the execution
233
236
of the context once QEMU command has been started.
234
237
:return: a 3-uple of exit code, execution time, and last guest error
@@ -237,23 +240,25 @@ def run(self, tdef: EasyDict[str, Any]) -> tuple[int, ExecTime, str]:
237
240
# OT's UART0 is redirected to a TCP stream that can be accessed through
238
241
# self._device. The VM pauses till the TCP socket is connected
239
242
xre = re .compile (self .EXIT_ON )
243
+ sync_event = None
240
244
if tdef .trigger :
241
245
sync_event = Event ()
242
- if tdef .trigger .startswith ("r'" ) and tdef .trigger .endswith ("'" ):
246
+ match_pattern = tdef .trigger or tdef .validate
247
+ if match_pattern :
248
+ if match_pattern .startswith ("r'" ) and match_pattern .endswith ("'" ):
243
249
try :
244
- tmo = re .compile (tdef . trigger [2 :- 1 ].encode ())
250
+ tmo = re .compile (match_pattern [2 :- 1 ].encode ())
245
251
except re .error as exc :
246
- raise ValueError ('Invalid trigger regex: {exc}' ) from exc
252
+ raise ValueError ('Invalid regex: {exc}' ) from exc
247
253
248
254
def trig_match (bline ):
249
255
return tmo .match (bline )
250
256
else :
251
- btrigger = tdef . trigger .encode ()
257
+ btrigger = match_pattern .encode ()
252
258
253
259
def trig_match (bline ):
254
260
return bline .find (btrigger ) >= 0
255
261
else :
256
- sync_event = None
257
262
trig_match = None
258
263
ret = None
259
264
proc = None
@@ -401,10 +406,15 @@ def trig_match(bline):
401
406
if trig_match and trig_match (line ):
402
407
# reset timeout from this event
403
408
abstimeout = float (tdef .timeout ) + now ()
404
- log .info ('Trigger pattern detected, resuming for '
405
- '%.0f secs' , tdef .timeout )
406
- sync_event .set ()
407
409
trig_match = None
410
+ if sync_event :
411
+ log .info ('Trigger pattern detected, resuming '
412
+ 'for %.0f secs' , tdef .timeout )
413
+ sync_event .set ()
414
+ else :
415
+ log .info ('Validation pattern detected, exiting' )
416
+ ret = 0
417
+ break
408
418
xmo = xre .search (line )
409
419
if xmo :
410
420
xend = now ()
@@ -1573,14 +1583,18 @@ def _build_qemu_command(self, args: Namespace,
1573
1583
from exc
1574
1584
start_delay *= args .timeout_factor
1575
1585
trigger = getattr (args , 'trigger' , '' )
1586
+ validate = getattr (args , 'validate' , '' )
1587
+ if trigger and validate :
1588
+ raise ValueError (f"{ getattr (args , 'exec' , '?' )} : 'trigger' and "
1589
+ f"'validate' are mutually exclusive" )
1576
1590
vcp_args , vcp_map = self ._build_qemu_vcp_args (args )
1577
1591
qemu_args .extend (vcp_args )
1578
1592
qemu_args .extend (args .global_opts or [])
1579
1593
if opts :
1580
1594
qemu_args .extend ((str (o ) for o in opts ))
1581
1595
return EasyDict (command = qemu_args , vcp_map = vcp_map ,
1582
1596
tmpfiles = temp_files , start_delay = start_delay ,
1583
- trigger = trigger )
1597
+ trigger = trigger , validate = validate )
1584
1598
1585
1599
def _build_qemu_test_command (self , filename : str ) -> EasyDict [str , Any ]:
1586
1600
test_name = self .get_test_radix (filename )
0 commit comments