3 # yosys -- Yosys Open SYnthesis Suite
5 # Copyright (C) 2012 Claire Xenia Wolf <claire@yosyshq.com>
7 # Permission to use, copy, modify, and/or distribute this software for any
8 # purpose with or without fee is hereby granted, provided that the above
9 # copyright notice and this permission notice appear in all copies.
11 # THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
12 # WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
13 # MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
14 # ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
15 # WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
16 # ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
17 # OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
20 import os
, sys
, getopt
, re
22 from smtio
import SmtIo
, SmtOpts
, MkVcd
23 from collections
import defaultdict
57 print(os
.path
.basename(sys
.argv
[0]) + """ [options] <yosys_smt2_output>
60 -t <skip_steps>:<num_steps>
61 -t <skip_steps>:<step_size>:<num_steps>
62 default: skip_steps=0, step_size=1, num_steps=20
65 generate an arbitrary trace that satisfies
66 all assertions and assumptions.
69 instead of BMC run temporal induction
72 instead of regular BMC run cover analysis
75 name of the top module
77 --smtc <constr_filename>
81 read cex file as written by ABC's "write_cex -n"
84 read AIGER map file (as written by Yosys' "write_aiger -map")
85 and AIGER witness file. The file names are <prefix>.aim for
86 the map file and <prefix>.aiw for the witness file.
88 --aig <aim_filename>:<aiw_filename>
89 like above, but for map files and witness files that do not
90 share a filename prefix (or use different file extensions).
93 the AIGER witness file does not include the status and
96 --btorwit <btor_witness_filename>
100 only run the core proof, do not collect and print any
101 additional information (e.g. which assert failed)
104 check if the design with assumptions but without assertions
105 is SAT before checking if assertions are UNSAT. This will
106 detect if there are contradicting assumptions. In some cases
107 this will also help to "warm up" the solver, potentially
111 only check final constraints, assume base case
113 --assume-skipped <start_step>
114 assume asserts in skipped steps in BMC.
115 no assumptions are created for skipped steps
118 --dump-vcd <vcd_filename>
119 write trace to this VCD file
120 (hint: use 'write_smt2 -wires' for maximum
121 coverage of signals in generated VCD file)
123 --dump-vlogtb <verilog_filename>
124 write trace as Verilog test bench
126 --vlogtb-top <hierarchical_name>
127 use the given entity as top module for the generated
128 Verilog test bench. The <hierarchical_name> is relative
129 to the design top module without the top module name.
131 --dump-smtc <constr_filename>
132 write trace as constraints file
135 write just the last state as initial constraint to smtc file
137 --smtc-top <old>[:<new>]
138 replace <old> with <new> in constraints dumped to smtc
139 file and only dump object below <old> in design hierarchy.
142 do not assume initial conditions in state 0
145 when using -g or -i, create a dump file for each
146 step. The character '%' is replaces in all dump
147 filenames with the step number.
150 add <num_steps> time steps at the end of the trace
151 when creating a counter example (this additional time
152 steps will still be constrained by assumptions)
155 dump anyconst values as raw bit strings
161 opts
, args
= getopt
.getopt(sys
.argv
[1:], so
.shortopts
+ "t:igcm:", so
.longopts
+
162 ["final-only", "assume-skipped=", "smtc=", "cex=", "aig=", "aig-noheader", "btorwit=", "presat",
163 "dump-vcd=", "dump-vlogtb=", "vlogtb-top=", "dump-smtc=", "dump-all", "noinfo", "append=",
164 "smtc-init", "smtc-top=", "noinit", "binary"])
173 num_steps
= int(a
[0])
175 skip_steps
= int(a
[0])
176 num_steps
= int(a
[1])
178 skip_steps
= int(a
[0])
179 step_size
= int(a
[1])
180 num_steps
= int(a
[2])
183 elif o
== "--assume-skipped":
184 assume_skipped
= int(a
)
185 elif o
== "--final-only":
193 aimfile
, aiwfile
= a
.split(":")
197 elif o
== "--aig-noheader":
199 elif o
== "--btorwit":
201 elif o
== "--dump-vcd":
203 elif o
== "--dump-vlogtb":
205 elif o
== "--vlogtb-top":
207 elif o
== "--dump-smtc":
209 elif o
== "--smtc-init":
211 elif o
== "--smtc-top":
212 smtctop
= a
.split(":")
213 if len(smtctop
) == 1:
215 assert len(smtctop
) == 2
216 smtctop
= tuple(smtctop
)
217 elif o
== "--dump-all":
219 elif o
== "--presat":
221 elif o
== "--noinfo":
223 elif o
== "--noinit":
225 elif o
== "--append":
226 append_steps
= int(a
)
235 elif o
== "--binary":
237 elif so
.handle(o
, a
):
245 if sum([tempind
, gentrace
, covermode
]) > 1:
248 constr_final_start
= None
249 constr_asserts
= defaultdict(list)
250 constr_assumes
= defaultdict(list)
251 constr_write
= list()
254 current_states
= None
257 with
open(fn
, "r") as f
:
261 if line
.startswith("#"):
264 tokens
= line
.split()
269 if tokens
[0] == "initial":
270 current_states
= set()
272 current_states
.add(0)
275 if tokens
[0] == "final":
278 current_states
= set(["final-%d" % i
for i
in range(0, num_steps
+1)])
279 constr_final_start
= 0
280 elif len(tokens
) == 2:
281 arg
= abs(int(tokens
[1]))
282 current_states
= set(["final-%d" % i
for i
in range(arg
, num_steps
+1)])
283 constr_final_start
= arg
if constr_final_start
is None else min(constr_final_start
, arg
)
288 if tokens
[0] == "state":
289 current_states
= set()
291 for token
in tokens
[1:]:
292 tok
= token
.split(":")
294 current_states
.add(int(token
))
301 for i
in range(lower
, upper
+1):
302 current_states
.add(i
)
307 if tokens
[0] == "always":
309 current_states
= set(range(0, num_steps
+1))
310 elif len(tokens
) == 2:
311 arg
= abs(int(tokens
[1]))
312 current_states
= set(range(arg
, num_steps
+1))
317 if tokens
[0] == "assert":
318 assert current_states
is not None
320 for state
in current_states
:
321 constr_asserts
[state
].append(("%s:%d" % (fn
, current_line
), " ".join(tokens
[1:])))
325 if tokens
[0] == "assume":
326 assert current_states
is not None
328 for state
in current_states
:
329 constr_assumes
[state
].append(("%s:%d" % (fn
, current_line
), " ".join(tokens
[1:])))
333 if tokens
[0] == "write":
334 constr_write
.append(" ".join(tokens
[1:]))
337 if tokens
[0] == "logic":
338 so
.logic
= " ".join(tokens
[1:])
344 def get_constr_expr(db
, state
, final
=False, getvalues
=False):
346 if ("final-%d" % state
) not in db
:
347 return ([], [], []) if getvalues
else "true"
350 return ([], [], []) if getvalues
else "true"
352 netref_regex
= re
.compile(r
'(^|[( ])\[(-?[0-9]+:|)([^\]]*|\S*)\](?=[ )]|$)')
354 def replace_netref(match
):
355 state_sel
= match
.group(2)
359 elif state_sel
[0] == "-":
360 st
= state
+ int(state_sel
[:-1])
362 st
= int(state_sel
[:-1])
364 expr
= smt
.net_expr(topmod
, "s%d" % st
, smt
.get_path(topmod
, match
.group(3)))
366 return match
.group(1) + expr
369 for loc
, expr
in db
[("final-%d" % state
) if final
else state
]:
370 actual_expr
= netref_regex
.sub(replace_netref
, expr
)
372 expr_list
.append((loc
, expr
, actual_expr
))
374 expr_list
.append(actual_expr
)
377 loc_list
, expr_list
, acual_expr_list
= zip(*expr_list
)
378 value_list
= smt
.get_list(acual_expr_list
)
379 return loc_list
, expr_list
, value_list
381 if len(expr_list
) == 0:
384 if len(expr_list
) == 1:
387 return "(and %s)" % " ".join(expr_list
)
392 if noinfo
and vcdfile
is None and vlogtbfile
is None and outconstr
is None:
393 smt
.produce_models
= False
396 print("%s %s" % (smt
.timestamp(), msg
))
399 print_msg("Solver: %s" % (so
.solver
))
401 with
open(args
[0], "r") as f
:
405 for line
in constr_write
:
411 assert topmod
is not None
412 assert topmod
in smt
.modinfo
414 if cexfile
is not None:
420 with
open(cexfile
, "r") as f
:
421 cex_regex
= re
.compile(r
'([^\[@=]+)(\[\d+\])?([^@=]*)(@\d+)=([01])')
422 for entry
in f
.read().split():
423 match
= cex_regex
.match(entry
)
426 name
, bit
, extra_name
, step
, val
= match
.group(1), match
.group(2), match
.group(3), match
.group(4), match
.group(5)
431 if name
not in smt
.modinfo
[topmod
].inputs
:
442 if smt
.modinfo
[topmod
].wsize
[name
] == 1:
444 smtexpr
= "(= [%s] %s)" % (name
, "true" if val
else "false")
446 smtexpr
= "(= ((_ extract %d %d) [%s]) #b%d)" % (bit
, bit
, name
, val
)
448 # print("cex@%d: %s" % (step, smtexpr))
449 constr_assumes
[step
].append((cexfile
, smtexpr
))
452 skip_steps
= max(skip_steps
, step
)
453 num_steps
= max(num_steps
, step
+1)
455 if aimfile
is not None:
465 with
open(aimfile
, "r") as f
:
466 for entry
in f
.read().splitlines():
467 entry
= entry
.split()
469 if entry
[0] == "input":
470 input_map
[int(entry
[1])] = (entry
[3], int(entry
[2]))
473 if entry
[0] == "init":
474 init_map
[int(entry
[1])] = (entry
[3], int(entry
[2]))
477 if entry
[0] in ["latch", "invlatch"]:
478 latch_map
[int(entry
[1])] = (entry
[3], int(entry
[2]), entry
[0] == "invlatch")
481 if entry
[0] in ["output", "wire"]:
486 with
open(aiwfile
, "r") as f
:
494 for entry
in f
.read().splitlines():
495 if len(entry
) == 0 or entry
[0] in "bcjfu.":
505 if len(init_map
) == 0:
506 for i
in range(len(entry
)):
511 value
= int(entry
[i
])
512 name
= latch_map
[i
][0]
513 bitidx
= latch_map
[i
][1]
514 invert
= latch_map
[i
][2]
519 path
= smt
.get_path(topmod
, name
)
520 width
= smt
.net_width(topmod
, path
)
524 smtexpr
= "(= [%s] %s)" % (name
, "true" if value
else "false")
526 smtexpr
= "(= ((_ extract %d %d) [%s]) #b%d)" % (bitidx
, bitidx
, name
, value
)
528 constr_assumes
[0].append((cexfile
, smtexpr
))
531 for i
in range(len(entry
)):
535 if (step
== 0) and (i
in init_map
):
536 value
= int(entry
[i
])
537 name
= init_map
[i
][0]
538 bitidx
= init_map
[i
][1]
540 path
= smt
.get_path(topmod
, name
)
542 if not smt
.net_exists(topmod
, path
):
543 match
= re
.match(r
"(.*)\[(\d+)\]$", path
[-1])
545 path
[-1] = match
.group(1)
546 addr
= int(match
.group(2))
548 if not match
or not smt
.mem_exists(topmod
, path
):
549 print_msg("Ignoring init value for unknown net: %s" % (name
))
552 meminfo
= smt
.mem_info(topmod
, path
)
553 smtexpr
= "(select [%s] #b%s)" % (".".join(path
), bin(addr
)[2:].zfill(meminfo
[0]))
557 smtexpr
= "[%s]" % name
558 width
= smt
.net_width(topmod
, path
)
562 smtexpr
= "(= %s %s)" % (smtexpr
, "true" if value
else "false")
564 smtexpr
= "(= ((_ extract %d %d) %s) #b%d)" % (bitidx
, bitidx
, smtexpr
, value
)
566 constr_assumes
[0].append((cexfile
, smtexpr
))
569 value
= int(entry
[i
])
570 name
= input_map
[i
][0]
571 bitidx
= input_map
[i
][1]
573 path
= smt
.get_path(topmod
, name
)
574 width
= smt
.net_width(topmod
, path
)
578 smtexpr
= "(= [%s] %s)" % (name
, "true" if value
else "false")
580 smtexpr
= "(= ((_ extract %d %d) [%s]) #b%d)" % (bitidx
, bitidx
, name
, value
)
582 constr_assumes
[step
].append((cexfile
, smtexpr
))
585 skip_steps
= max(skip_steps
, step
)
586 num_steps
= max(num_steps
, step
+1)
589 if btorwitfile
is not None:
590 with
open(btorwitfile
, "r") as f
:
606 if line
== "" or line
[0] == "b" or line
[0] == "j":
612 if line
[0] == '#' or line
[0] == '@':
617 altsuffix
= "#" + suffix
[1:]
619 altsuffix
= "@" + suffix
[1:]
627 if line
[-1].endswith(suffix
):
628 line
[-1] = line
[-1][0:len(line
[-1]) - len(suffix
)]
630 if line
[-1].endswith(altsuffix
):
631 line
[-1] = line
[-1][0:len(line
[-1]) - len(altsuffix
)]
633 if line
[-1][0] == "$":
637 if len(line
) == 3 and line
[1][0] != "[":
641 path
= smt
.get_path(topmod
, name
)
643 if not smt
.net_exists(topmod
, path
):
646 width
= smt
.net_width(topmod
, path
)
649 assert value
in ["0", "1"]
650 value
= "true" if value
== "1" else "false"
654 smtexpr
= "(= [%s] %s)" % (name
, value
)
655 constr_assumes
[step
].append((btorwitfile
, smtexpr
))
658 if len(line
) == 4 and line
[1][0] == "[":
663 path
= smt
.get_path(topmod
, name
)
665 if not smt
.mem_exists(topmod
, path
):
668 meminfo
= smt
.mem_info(topmod
, path
)
671 assert value
in ["0", "1"]
672 value
= "true" if value
== "1" else "false"
676 assert index
[0] == "["
677 assert index
[-1] == "]"
678 index
= "#b" + index
[1:-1]
680 smtexpr
= "(= (select [%s] %s) %s)" % (name
, index
, value
)
681 constr_assumes
[step
].append((btorwitfile
, smtexpr
))
686 def write_vcd_trace(steps_start
, steps_stop
, index
):
687 filename
= vcdfile
.replace("%", index
)
688 print_msg("Writing trace to VCD file: %s" % (filename
))
690 with
open(filename
, "w") as vcd_file
:
691 vcd
= MkVcd(vcd_file
)
694 for netpath
in sorted(smt
.hiernets(topmod
)):
697 if n
.startswith("$"):
700 edge
= smt
.net_clock(topmod
, netpath
)
702 vcd
.add_net([topmod
] + netpath
, smt
.net_width(topmod
, netpath
))
704 vcd
.add_clock([topmod
] + netpath
, edge
)
705 path_list
.append(netpath
)
707 mem_trace_data
= dict()
708 for mempath
in sorted(smt
.hiermems(topmod
)):
709 abits
, width
, rports
, wports
, asyncwr
= smt
.mem_info(topmod
, mempath
)
713 for i
in range(steps_start
, steps_stop
):
714 for j
in range(rports
):
715 expr_id
.append(('R', i
-steps_start
, j
, 'A'))
716 expr_id
.append(('R', i
-steps_start
, j
, 'D'))
717 expr_list
.append(smt
.mem_expr(topmod
, "s%d" % i
, mempath
, "R%dA" % j
))
718 expr_list
.append(smt
.mem_expr(topmod
, "s%d" % i
, mempath
, "R%dD" % j
))
719 for j
in range(wports
):
720 expr_id
.append(('W', i
-steps_start
, j
, 'A'))
721 expr_id
.append(('W', i
-steps_start
, j
, 'D'))
722 expr_id
.append(('W', i
-steps_start
, j
, 'M'))
723 expr_list
.append(smt
.mem_expr(topmod
, "s%d" % i
, mempath
, "W%dA" % j
))
724 expr_list
.append(smt
.mem_expr(topmod
, "s%d" % i
, mempath
, "W%dD" % j
))
725 expr_list
.append(smt
.mem_expr(topmod
, "s%d" % i
, mempath
, "W%dM" % j
))
731 for eid
, edat
in zip(expr_id
, smt
.get_list(expr_list
)):
749 c
[f
] = smt
.bv2bin(edat
)
759 if len(wdata
) == 0 and len(rdata
) != 0:
760 wdata
= [[]] * len(rdata
)
762 assert len(rdata
) == len(wdata
)
764 for i
in range(len(wdata
)):
766 for j_data
in rdata
[i
]:
767 if j_data
["A"] == addr
:
768 data
= list(j_data
["D"])
774 for ii
in reversed(range(len(tdata
))):
775 for k
in range(width
):
776 if tdata
[ii
][k
] == "x":
777 tdata
[ii
][k
] = buf
[k
]
779 buf
[k
] = tdata
[ii
][k
]
782 tdata
.append(data
[:])
784 for j_data
in wdata
[i
]:
785 if j_data
["A"] != addr
:
791 for k
in range(width
):
796 tdata
.append(data
[:])
798 assert len(tdata
) == len(rdata
)
801 netpath
[-1] += "<%0*x>" % ((len(addr
)+3) // 4, int(addr
, 2))
802 vcd
.add_net([topmod
] + netpath
, width
)
804 for i
in range(steps_start
, steps_stop
):
805 if i
not in mem_trace_data
:
806 mem_trace_data
[i
] = list()
807 mem_trace_data
[i
].append((netpath
, "".join(tdata
[i
-steps_start
])))
809 for i
in range(steps_start
, steps_stop
):
811 value_list
= smt
.get_net_bin_list(topmod
, path_list
, "s%d" % i
)
812 for path
, value
in zip(path_list
, value_list
):
813 vcd
.set_net([topmod
] + path
, value
)
814 if i
in mem_trace_data
:
815 for path
, value
in mem_trace_data
[i
]:
816 vcd
.set_net([topmod
] + path
, value
)
818 vcd
.set_time(steps_stop
)
820 def char_ok_in_verilog(c
,i
):
821 if ('A' <= c
<= 'Z'): return True
822 if ('a' <= c
<= 'z'): return True
823 if ('0' <= c
<= '9' and i
>0): return True
824 if (c
== '_'): return True
825 if (c
== '$'): return True
828 def escape_identifier(identifier
):
829 if type(identifier
) is list:
830 return map(escape_identifier
, identifier
)
831 if "." in identifier
:
832 return ".".join(escape_identifier(identifier
.split(".")))
833 if (all(char_ok_in_verilog(identifier
[i
],i
) for i
in range(0, len(identifier
)))):
835 return "\\"+identifier
+" "
839 def write_vlogtb_trace(steps_start
, steps_stop
, index
):
840 filename
= vlogtbfile
.replace("%", index
)
841 print_msg("Writing trace to Verilog testbench: %s" % (filename
))
843 vlogtb_topmod
= topmod
844 vlogtb_state
= "s@@step_idx@@"
846 if vlogtbtop
is not None:
847 for item
in vlogtbtop
.split("."):
848 if item
in smt
.modinfo
[vlogtb_topmod
].cells
:
849 vlogtb_state
= "(|%s_h %s| %s)" % (vlogtb_topmod
, item
, vlogtb_state
)
850 vlogtb_topmod
= smt
.modinfo
[vlogtb_topmod
].cells
[item
]
852 print_msg("Vlog top module '%s' not found: no cell '%s' in module '%s'" % (vlogtbtop
, item
, vlogtb_topmod
))
855 with
open(filename
, "w") as f
:
856 print("`ifndef VERILATOR", file=f
)
857 print("module testbench;", file=f
)
858 print(" reg [4095:0] vcdfile;", file=f
)
859 print(" reg clock;", file=f
)
860 print("`else", file=f
)
861 print("module testbench(input clock, output reg genclock);", file=f
)
862 print(" initial genclock = 1;", file=f
)
863 print("`endif", file=f
)
865 print(" reg genclock = 1;", file=f
)
866 print(" reg [31:0] cycle = 0;", file=f
)
868 primary_inputs
= list()
871 for name
in smt
.modinfo
[vlogtb_topmod
].inputs
:
872 if name
in ["clk", "clock", "CLK", "CLOCK"]:
873 clock_inputs
.add(name
)
874 width
= smt
.modinfo
[vlogtb_topmod
].wsize
[name
]
875 primary_inputs
.append((name
, width
))
877 for name
, width
in primary_inputs
:
878 if name
in clock_inputs
:
879 print(" wire [%d:0] %s = clock;" % (width
-1, escape_identifier("PI_"+name
)), file=f
)
881 print(" reg [%d:0] %s;" % (width
-1, escape_identifier("PI_"+name
)), file=f
)
883 print(" %s UUT (" % escape_identifier(vlogtb_topmod
), file=f
)
884 print(",\n".join(" .%s(%s)" % (escape_identifier(name
), escape_identifier("PI_"+name
)) for name
, _
in primary_inputs
), file=f
)
887 print("`ifndef VERILATOR", file=f
)
888 print(" initial begin", file=f
)
889 print(" if ($value$plusargs(\"vcd=%s\", vcdfile)) begin", file=f
)
890 print(" $dumpfile(vcdfile);", file=f
)
891 print(" $dumpvars(0, testbench);", file=f
)
892 print(" end", file=f
)
893 print(" #5 clock = 0;", file=f
)
894 print(" while (genclock) begin", file=f
)
895 print(" #5 clock = 0;", file=f
)
896 print(" #5 clock = 1;", file=f
)
897 print(" end", file=f
)
898 print(" end", file=f
)
899 print("`endif", file=f
)
901 print(" initial begin", file=f
)
903 regs
= sorted(smt
.hiernets(vlogtb_topmod
, regs_only
=True))
904 regvals
= smt
.get_net_bin_list(vlogtb_topmod
, regs
, vlogtb_state
.replace("@@step_idx@@", str(steps_start
)))
906 print("`ifndef VERILATOR", file=f
)
907 print(" #1;", file=f
)
908 print("`endif", file=f
)
909 for reg
, val
in zip(regs
, regvals
):
912 if n
.startswith("$"):
914 print(" %sUUT.%s = %d'b%s;" % ("// " if hidden_net
else "", ".".join(escape_identifier(reg
)), len(val
), val
), file=f
)
916 anyconsts
= sorted(smt
.hieranyconsts(vlogtb_topmod
))
917 for info
in anyconsts
:
918 if info
[3] is not None:
919 modstate
= smt
.net_expr(vlogtb_topmod
, vlogtb_state
.replace("@@step_idx@@", str(steps_start
)), info
[0])
920 value
= smt
.bv2bin(smt
.get("(|%s| %s)" % (info
[1], modstate
)))
921 print(" UUT.%s = %d'b%s;" % (".".join(escape_identifier(info
[0] + [info
[3]])), len(value
), value
), file=f
);
923 mems
= sorted(smt
.hiermems(vlogtb_topmod
))
925 abits
, width
, rports
, wports
, asyncwr
= smt
.mem_info(vlogtb_topmod
, mempath
)
927 addr_expr_list
= list()
928 data_expr_list
= list()
929 for i
in range(steps_start
, steps_stop
):
930 for j
in range(rports
):
931 addr_expr_list
.append(smt
.mem_expr(vlogtb_topmod
, vlogtb_state
.replace("@@step_idx@@", str(i
)), mempath
, "R%dA" % j
))
932 data_expr_list
.append(smt
.mem_expr(vlogtb_topmod
, vlogtb_state
.replace("@@step_idx@@", str(i
)), mempath
, "R%dD" % j
))
934 addr_list
= smt
.get_list(addr_expr_list
)
935 data_list
= smt
.get_list(data_expr_list
)
938 for addr
, data
in zip(addr_list
, data_list
):
939 addr
= smt
.bv2bin(addr
)
940 data
= smt
.bv2bin(data
)
941 if addr
not in addr_data
:
942 addr_data
[addr
] = data
944 for addr
, data
in addr_data
.items():
945 print(" UUT.%s[%d'b%s] = %d'b%s;" % (".".join(escape_identifier(mempath
)), len(addr
), addr
, len(data
), data
), file=f
)
948 anyseqs
= sorted(smt
.hieranyseqs(vlogtb_topmod
))
950 for i
in range(steps_start
, steps_stop
):
951 pi_names
= [[name
] for name
, _
in primary_inputs
if name
not in clock_inputs
]
952 pi_values
= smt
.get_net_bin_list(vlogtb_topmod
, pi_names
, vlogtb_state
.replace("@@step_idx@@", str(i
)))
954 print(" // state %d" % i
, file=f
)
957 print(" if (cycle == %d) begin" % (i
-1), file=f
)
959 for name
, val
in zip(pi_names
, pi_values
):
961 print(" %s <= %d'b%s;" % (escape_identifier("PI_"+".".join(name
)), len(val
), val
), file=f
)
963 print(" %s = %d'b%s;" % (escape_identifier("PI_"+".".join(name
)), len(val
), val
), file=f
)
966 if info
[3] is not None:
967 modstate
= smt
.net_expr(vlogtb_topmod
, vlogtb_state
.replace("@@step_idx@@", str(i
)), info
[0])
968 value
= smt
.bv2bin(smt
.get("(|%s| %s)" % (info
[1], modstate
)))
970 print(" UUT.%s <= %d'b%s;" % (".".join(escape_identifier(info
[0] + [info
[3]])), len(value
), value
), file=f
);
972 print(" UUT.%s = %d'b%s;" % (".".join(escape_identifier(info
[0] + [info
[3]])), len(value
), value
), file=f
);
975 print(" end", file=f
)
979 print(" end", file=f
)
980 print(" always @(posedge clock) begin", file=f
)
982 print(" genclock <= cycle < %d;" % (steps_stop
-1), file=f
)
983 print(" cycle <= cycle + 1;", file=f
)
984 print(" end", file=f
)
986 print("endmodule", file=f
)
989 def write_constr_trace(steps_start
, steps_stop
, index
):
990 filename
= outconstr
.replace("%", index
)
991 print_msg("Writing trace to constraints file: %s" % (filename
))
993 constr_topmod
= topmod
994 constr_state
= "s@@step_idx@@"
997 if smtctop
is not None:
998 for item
in smtctop
[0].split("."):
999 assert item
in smt
.modinfo
[constr_topmod
].cells
1000 constr_state
= "(|%s_h %s| %s)" % (constr_topmod
, item
, constr_state
)
1001 constr_topmod
= smt
.modinfo
[constr_topmod
].cells
[item
]
1002 if smtctop
[1] != "":
1003 constr_prefix
= smtctop
[1] + "."
1006 steps_start
= steps_stop
- 1
1008 with
open(filename
, "w") as f
:
1009 primary_inputs
= list()
1011 for name
in smt
.modinfo
[constr_topmod
].inputs
:
1012 width
= smt
.modinfo
[constr_topmod
].wsize
[name
]
1013 primary_inputs
.append((name
, width
))
1015 if steps_start
== 0 or smtcinit
:
1016 print("initial", file=f
)
1018 print("state %d" % steps_start
, file=f
)
1020 regnames
= sorted(smt
.hiernets(constr_topmod
, regs_only
=True))
1021 regvals
= smt
.get_net_list(constr_topmod
, regnames
, constr_state
.replace("@@step_idx@@", str(steps_start
)))
1023 for name
, val
in zip(regnames
, regvals
):
1024 print("assume (= [%s%s] %s)" % (constr_prefix
, ".".join(name
), val
), file=f
)
1026 mems
= sorted(smt
.hiermems(constr_topmod
))
1027 for mempath
in mems
:
1028 abits
, width
, rports
, wports
, asyncwr
= smt
.mem_info(constr_topmod
, mempath
)
1030 addr_expr_list
= list()
1031 data_expr_list
= list()
1032 for i
in range(steps_start
, steps_stop
):
1033 for j
in range(rports
):
1034 addr_expr_list
.append(smt
.mem_expr(constr_topmod
, constr_state
.replace("@@step_idx@@", str(i
)), mempath
, "R%dA" % j
))
1035 data_expr_list
.append(smt
.mem_expr(constr_topmod
, constr_state
.replace("@@step_idx@@", str(i
)), mempath
, "R%dD" % j
))
1037 addr_list
= smt
.get_list(addr_expr_list
)
1038 data_list
= smt
.get_list(data_expr_list
)
1041 for addr
, data
in zip(addr_list
, data_list
):
1042 if addr
not in addr_data
:
1043 addr_data
[addr
] = data
1045 for addr
, data
in addr_data
.items():
1046 print("assume (= (select [%s%s] %s) %s)" % (constr_prefix
, ".".join(mempath
), addr
, data
), file=f
)
1048 for k
in range(steps_start
, steps_stop
):
1051 print("state %d" % k
, file=f
)
1053 pi_names
= [[name
] for name
, _
in sorted(primary_inputs
)]
1054 pi_values
= smt
.get_net_list(constr_topmod
, pi_names
, constr_state
.replace("@@step_idx@@", str(k
)))
1056 for name
, val
in zip(pi_names
, pi_values
):
1057 print("assume (= [%s%s] %s)" % (constr_prefix
, ".".join(name
), val
), file=f
)
1060 def write_trace(steps_start
, steps_stop
, index
):
1061 if vcdfile
is not None:
1062 write_vcd_trace(steps_start
, steps_stop
, index
)
1064 if vlogtbfile
is not None:
1065 write_vlogtb_trace(steps_start
, steps_stop
, index
)
1067 if outconstr
is not None:
1068 write_constr_trace(steps_start
, steps_stop
, index
)
1071 def print_failed_asserts_worker(mod
, state
, path
, extrainfo
):
1072 assert mod
in smt
.modinfo
1073 found_failed_assert
= False
1075 if smt
.get("(|%s_a| %s)" % (mod
, state
)) in ["true", "#b1"]:
1078 for cellname
, celltype
in smt
.modinfo
[mod
].cells
.items():
1079 if print_failed_asserts_worker(celltype
, "(|%s_h %s| %s)" % (mod
, cellname
, state
), path
+ "." + cellname
, extrainfo
):
1080 found_failed_assert
= True
1082 for assertfun
, assertinfo
in smt
.modinfo
[mod
].asserts
.items():
1083 if smt
.get("(|%s| %s)" % (assertfun
, state
)) in ["false", "#b0"]:
1084 print_msg("Assert failed in %s: %s%s" % (path
, assertinfo
, extrainfo
))
1085 found_failed_assert
= True
1087 return found_failed_assert
1090 def print_failed_asserts(state
, final
=False, extrainfo
=""):
1092 loc_list
, expr_list
, value_list
= get_constr_expr(constr_asserts
, state
, final
=final
, getvalues
=True)
1093 found_failed_assert
= False
1095 for loc
, expr
, value
in zip(loc_list
, expr_list
, value_list
):
1096 if smt
.bv2int(value
) == 0:
1097 print_msg("Assert %s failed: %s%s" % (loc
, expr
, extrainfo
))
1098 found_failed_assert
= True
1101 if print_failed_asserts_worker(topmod
, "s%d" % state
, topmod
, extrainfo
):
1102 found_failed_assert
= True
1104 return found_failed_assert
1107 def print_anyconsts_worker(mod
, state
, path
):
1108 assert mod
in smt
.modinfo
1110 for cellname
, celltype
in smt
.modinfo
[mod
].cells
.items():
1111 print_anyconsts_worker(celltype
, "(|%s_h %s| %s)" % (mod
, cellname
, state
), path
+ "." + cellname
)
1113 for fun
, info
in smt
.modinfo
[mod
].anyconsts
.items():
1116 print_msg("Value for anyconst in %s (%s): %d" % (path
, info
[0], smt
.bv2int(smt
.get("(|%s| %s)" % (fun
, state
)))))
1118 print_msg("Value for anyconst in %s (%s): %s" % (path
, info
[0], smt
.bv2bin(smt
.get("(|%s| %s)" % (fun
, state
)))))
1121 print_msg("Value for anyconst %s.%s (%s): %d" % (path
, info
[1], info
[0], smt
.bv2int(smt
.get("(|%s| %s)" % (fun
, state
)))))
1123 print_msg("Value for anyconst %s.%s (%s): %s" % (path
, info
[1], info
[0], smt
.bv2bin(smt
.get("(|%s| %s)" % (fun
, state
)))))
1126 def print_anyconsts(state
):
1128 print_anyconsts_worker(topmod
, "s%d" % state
, topmod
)
1131 def get_cover_list(mod
, base
):
1132 assert mod
in smt
.modinfo
1137 for expr
, desc
in smt
.modinfo
[mod
].covers
.items():
1138 cover_expr
.append("(ite (|%s| %s) #b1 #b0)" % (expr
, base
))
1139 cover_desc
.append(desc
)
1141 for cell
, submod
in smt
.modinfo
[mod
].cells
.items():
1142 e
, d
= get_cover_list(submod
, "(|%s_h %s| %s)" % (mod
, cell
, base
))
1146 return cover_expr
, cover_desc
1149 asserts_antecedent_cache
= [list()]
1150 asserts_consequent_cache
= [list()]
1151 asserts_cache_dirty
= False
1153 def smt_state(step
):
1154 smt
.write("(declare-fun s%d () |%s_s|)" % (step
, topmod
))
1155 states
.append("s%d" % step
)
1157 def smt_assert(expr
):
1161 smt
.write("(assert %s)" % expr
)
1163 def smt_assert_antecedent(expr
):
1167 smt
.write("(assert %s)" % expr
)
1169 global asserts_cache_dirty
1170 asserts_cache_dirty
= True
1171 asserts_antecedent_cache
[-1].append(expr
)
1173 def smt_assert_consequent(expr
):
1177 smt
.write("(assert %s)" % expr
)
1179 global asserts_cache_dirty
1180 asserts_cache_dirty
= True
1181 asserts_consequent_cache
[-1].append(expr
)
1183 def smt_forall_assert():
1187 global asserts_cache_dirty
1188 asserts_cache_dirty
= False
1190 assert (len(smt
.modinfo
[topmod
].maximize
) + len(smt
.modinfo
[topmod
].minimize
) <= 1)
1192 def make_assert_expr(asserts_cache
):
1194 for lst
in asserts_cache
:
1197 assert len(expr
) != 0
1202 expr
= "(and %s)" % (" ".join(expr
))
1205 antecedent_expr
= make_assert_expr(asserts_antecedent_cache
)
1206 consequent_expr
= make_assert_expr(asserts_consequent_cache
)
1208 states_db
= set(states
)
1209 used_states_db
= set()
1210 new_antecedent_expr
= list()
1211 new_consequent_expr
= list()
1212 assert_expr
= list()
1214 def make_new_expr(new_expr
, expr
):
1216 while cursor
< len(expr
):
1218 if expr
[cursor
] in '|"':
1219 while cursor
+l
+1 < len(expr
) and expr
[cursor
] != expr
[cursor
+l
]:
1222 elif expr
[cursor
] not in '() ':
1223 while cursor
+l
< len(expr
) and expr
[cursor
+l
] not in '|"() ':
1226 word
= expr
[cursor
:cursor
+l
]
1227 if word
in states_db
:
1228 used_states_db
.add(word
)
1231 new_expr
.append(word
)
1234 make_new_expr(new_antecedent_expr
, antecedent_expr
)
1235 make_new_expr(new_consequent_expr
, consequent_expr
)
1237 new_antecedent_expr
= ["".join(new_antecedent_expr
)]
1238 new_consequent_expr
= ["".join(new_consequent_expr
)]
1240 if states
[0] in used_states_db
:
1241 new_antecedent_expr
.append("(|%s_ex_state_eq| %s %s_)" % (topmod
, states
[0], states
[0]))
1243 if s
in used_states_db
:
1244 new_antecedent_expr
.append("(|%s_ex_input_eq| %s %s_)" % (topmod
, s
, s
))
1246 if len(new_antecedent_expr
) == 0:
1247 new_antecedent_expr
= "true"
1248 elif len(new_antecedent_expr
) == 1:
1249 new_antecedent_expr
= new_antecedent_expr
[0]
1251 new_antecedent_expr
= "(and %s)" % (" ".join(new_antecedent_expr
))
1253 if len(new_consequent_expr
) == 0:
1254 new_consequent_expr
= "true"
1255 elif len(new_consequent_expr
) == 1:
1256 new_consequent_expr
= new_consequent_expr
[0]
1258 new_consequent_expr
= "(and %s)" % (" ".join(new_consequent_expr
))
1260 assert_expr
.append("(assert (forall (")
1263 if s
in used_states_db
:
1264 assert_expr
.append("%s(%s_ |%s_s|)" % ("" if first_state
else " ", s
, topmod
))
1266 assert_expr
.append(") (=> %s %s)))" % (new_antecedent_expr
, new_consequent_expr
))
1268 smt
.write("".join(assert_expr
))
1270 if len(smt
.modinfo
[topmod
].maximize
) > 0:
1272 if s
in used_states_db
:
1273 smt
.write("(maximize (|%s| %s))\n" % (smt
.modinfo
[topmod
].maximize
.copy().pop(), s
))
1276 if len(smt
.modinfo
[topmod
].minimize
) > 0:
1278 if s
in used_states_db
:
1279 smt
.write("(minimize (|%s| %s))\n" % (smt
.modinfo
[topmod
].minimize
.copy().pop(), s
))
1283 global asserts_cache_dirty
1284 asserts_cache_dirty
= True
1285 asserts_antecedent_cache
.append(list())
1286 asserts_consequent_cache
.append(list())
1287 smt
.write("(push 1)")
1290 global asserts_cache_dirty
1291 asserts_cache_dirty
= True
1292 asserts_antecedent_cache
.pop()
1293 asserts_consequent_cache
.pop()
1294 smt
.write("(pop 1)")
1296 def smt_check_sat(expected
=["sat", "unsat"]):
1297 if asserts_cache_dirty
:
1299 return smt
.check_sat(expected
=expected
)
1302 retstatus
= "FAILED"
1303 skip_counter
= step_size
1304 for step
in range(num_steps
, -1, -1):
1306 print_msg("Temporal induction not supported for exists-forall problems.")
1310 smt_assert_consequent("(|%s_u| s%d)" % (topmod
, step
))
1311 smt_assert_antecedent("(|%s_h| s%d)" % (topmod
, step
))
1312 smt_assert_antecedent("(not (|%s_is| s%d))" % (topmod
, step
))
1313 smt_assert_consequent(get_constr_expr(constr_assumes
, step
))
1315 if step
== num_steps
:
1316 smt_assert("(not (and (|%s_a| s%d) %s))" % (topmod
, step
, get_constr_expr(constr_asserts
, step
)))
1319 smt_assert_antecedent("(|%s_t| s%d s%d)" % (topmod
, step
, step
+1))
1320 smt_assert("(|%s_a| s%d)" % (topmod
, step
))
1321 smt_assert(get_constr_expr(constr_asserts
, step
))
1323 if step
> num_steps
-skip_steps
:
1324 print_msg("Skipping induction in step %d.." % (step
))
1328 if skip_counter
< step_size
:
1329 print_msg("Skipping induction in step %d.." % (step
))
1333 print_msg("Trying induction in step %d.." % (step
))
1335 if smt_check_sat() == "sat":
1337 print_msg("Temporal induction failed!")
1338 print_anyconsts(num_steps
)
1339 print_failed_asserts(num_steps
)
1340 write_trace(step
, num_steps
+1, '%')
1343 print_anyconsts(num_steps
)
1344 print_failed_asserts(num_steps
)
1345 write_trace(step
, num_steps
+1, "%d" % step
)
1348 print_msg("Temporal induction successful.")
1349 retstatus
= "PASSED"
1353 cover_expr
, cover_desc
= get_cover_list(topmod
, "state")
1354 cover_mask
= "1" * len(cover_desc
)
1356 if len(cover_expr
) > 1:
1357 cover_expr
= "(concat %s)" % " ".join(cover_expr
)
1358 elif len(cover_expr
) == 1:
1359 cover_expr
= cover_expr
[0]
1364 smt
.write("(define-fun covers_0 ((state |%s_s|)) (_ BitVec %d) %s)" % (topmod
, len(cover_desc
), cover_expr
))
1367 retstatus
= "FAILED"
1368 found_failed_assert
= False
1370 assert step_size
== 1
1372 while step
< num_steps
:
1374 smt_assert_consequent("(|%s_u| s%d)" % (topmod
, step
))
1375 smt_assert_antecedent("(|%s_h| s%d)" % (topmod
, step
))
1376 smt_assert_consequent(get_constr_expr(constr_assumes
, step
))
1380 smt_assert_antecedent("(not (|%s_is| s%d))" % (topmod
, step
))
1382 smt_assert_antecedent("(|%s_i| s0)" % (topmod
))
1383 smt_assert_antecedent("(|%s_is| s0)" % (topmod
))
1386 smt_assert_antecedent("(|%s_t| s%d s%d)" % (topmod
, step
-1, step
))
1387 smt_assert_antecedent("(not (|%s_is| s%d))" % (topmod
, step
))
1389 while "1" in cover_mask
:
1390 print_msg("Checking cover reachability in step %d.." % (step
))
1392 smt_assert("(distinct (covers_%d s%d) #b%s)" % (coveridx
, step
, "0" * len(cover_desc
)))
1394 if smt_check_sat() == "unsat":
1398 if append_steps
> 0:
1399 for i
in range(step
+1, step
+1+append_steps
):
1400 print_msg("Appending additional step %d." % i
)
1402 smt_assert_antecedent("(not (|%s_is| s%d))" % (topmod
, i
))
1403 smt_assert_consequent("(|%s_u| s%d)" % (topmod
, i
))
1404 smt_assert_antecedent("(|%s_h| s%d)" % (topmod
, i
))
1405 smt_assert_antecedent("(|%s_t| s%d s%d)" % (topmod
, i
-1, i
))
1406 smt_assert_consequent(get_constr_expr(constr_assumes
, i
))
1407 print_msg("Re-solving with appended steps..")
1408 if smt_check_sat() == "unsat":
1409 print("%s Cannot appended steps without violating assumptions!" % smt
.timestamp())
1410 found_failed_assert
= True
1411 retstatus
= "FAILED"
1414 reached_covers
= smt
.bv2bin(smt
.get("(covers_%d s%d)" % (coveridx
, step
)))
1415 assert len(reached_covers
) == len(cover_desc
)
1419 for i
in range(len(reached_covers
)):
1420 if reached_covers
[i
] == "0":
1421 new_cover_mask
.append(cover_mask
[i
])
1424 print_msg("Reached cover statement at %s in step %d." % (cover_desc
[i
], step
))
1425 new_cover_mask
.append("0")
1427 cover_mask
= "".join(new_cover_mask
)
1429 for i
in range(step
+1+append_steps
):
1430 if print_failed_asserts(i
, extrainfo
=" (step %d)" % i
):
1431 found_failed_assert
= True
1433 write_trace(0, step
+1+append_steps
, "%d" % coveridx
)
1435 if found_failed_assert
:
1440 smt
.write("(define-fun covers_%d ((state |%s_s|)) (_ BitVec %d) (bvand (covers_%d state) #b%s))" % (coveridx
, topmod
, len(cover_desc
), coveridx
-1, cover_mask
))
1442 if found_failed_assert
:
1445 if "1" not in cover_mask
:
1446 retstatus
= "PASSED"
1451 if "1" in cover_mask
:
1452 for i
in range(len(cover_mask
)):
1453 if cover_mask
[i
] == "1":
1454 print_msg("Unreached cover statement at %s." % cover_desc
[i
])
1456 else: # not tempind, covermode
1458 retstatus
= "PASSED"
1459 while step
< num_steps
:
1461 smt_assert_consequent("(|%s_u| s%d)" % (topmod
, step
))
1462 smt_assert_antecedent("(|%s_h| s%d)" % (topmod
, step
))
1463 smt_assert_consequent(get_constr_expr(constr_assumes
, step
))
1467 smt_assert_antecedent("(not (|%s_is| s%d))" % (topmod
, step
))
1469 smt_assert_antecedent("(|%s_i| s0)" % (topmod
))
1470 smt_assert_antecedent("(|%s_is| s0)" % (topmod
))
1473 smt_assert_antecedent("(|%s_t| s%d s%d)" % (topmod
, step
-1, step
))
1474 smt_assert_antecedent("(not (|%s_is| s%d))" % (topmod
, step
))
1476 if step
< skip_steps
:
1477 if assume_skipped
is not None and step
>= assume_skipped
:
1478 print_msg("Skipping step %d (and assuming pass).." % (step
))
1479 smt_assert("(|%s_a| s%d)" % (topmod
, step
))
1480 smt_assert(get_constr_expr(constr_asserts
, step
))
1482 print_msg("Skipping step %d.." % (step
))
1486 last_check_step
= step
1487 for i
in range(1, step_size
):
1488 if step
+i
< num_steps
:
1490 smt_assert_antecedent("(not (|%s_is| s%d))" % (topmod
, step
+i
))
1491 smt_assert_consequent("(|%s_u| s%d)" % (topmod
, step
+i
))
1492 smt_assert_antecedent("(|%s_h| s%d)" % (topmod
, step
+i
))
1493 smt_assert_antecedent("(|%s_t| s%d s%d)" % (topmod
, step
+i
-1, step
+i
))
1494 smt_assert_consequent(get_constr_expr(constr_assumes
, step
+i
))
1495 last_check_step
= step
+i
1499 if last_check_step
== step
:
1500 print_msg("Checking assumptions in step %d.." % (step
))
1502 print_msg("Checking assumptions in steps %d to %d.." % (step
, last_check_step
))
1504 if smt_check_sat() == "unsat":
1505 print("%s Assumptions are unsatisfiable!" % smt
.timestamp())
1506 retstatus
= "PREUNSAT"
1510 if last_check_step
== step
:
1511 print_msg("Checking assertions in step %d.." % (step
))
1513 print_msg("Checking assertions in steps %d to %d.." % (step
, last_check_step
))
1516 smt_assert("(not (and %s))" % " ".join(["(|%s_a| s%d)" % (topmod
, i
) for i
in range(step
, last_check_step
+1)] +
1517 [get_constr_expr(constr_asserts
, i
) for i
in range(step
, last_check_step
+1)]))
1519 if smt_check_sat() == "sat":
1520 print("%s BMC failed!" % smt
.timestamp())
1521 if append_steps
> 0:
1522 for i
in range(last_check_step
+1, last_check_step
+1+append_steps
):
1523 print_msg("Appending additional step %d." % i
)
1525 smt_assert_antecedent("(not (|%s_is| s%d))" % (topmod
, i
))
1526 smt_assert_consequent("(|%s_u| s%d)" % (topmod
, i
))
1527 smt_assert_antecedent("(|%s_h| s%d)" % (topmod
, i
))
1528 smt_assert_antecedent("(|%s_t| s%d s%d)" % (topmod
, i
-1, i
))
1529 smt_assert_consequent(get_constr_expr(constr_assumes
, i
))
1530 print_msg("Re-solving with appended steps..")
1531 if smt_check_sat() == "unsat":
1532 print("%s Cannot append steps without violating assumptions!" % smt
.timestamp())
1533 retstatus
= "FAILED"
1535 print_anyconsts(step
)
1536 for i
in range(step
, last_check_step
+1):
1537 print_failed_asserts(i
)
1538 write_trace(0, last_check_step
+1+append_steps
, '%')
1539 retstatus
= "FAILED"
1544 if (constr_final_start
is not None) or (last_check_step
+1 != num_steps
):
1545 for i
in range(step
, last_check_step
+1):
1546 smt_assert("(|%s_a| s%d)" % (topmod
, i
))
1547 smt_assert(get_constr_expr(constr_asserts
, i
))
1549 if constr_final_start
is not None:
1550 for i
in range(step
, last_check_step
+1):
1551 if i
< constr_final_start
:
1554 print_msg("Checking final constraints in step %d.." % (i
))
1557 smt_assert_consequent(get_constr_expr(constr_assumes
, i
, final
=True))
1558 smt_assert("(not %s)" % get_constr_expr(constr_asserts
, i
, final
=True))
1560 if smt_check_sat() == "sat":
1561 print("%s BMC failed!" % smt
.timestamp())
1563 print_failed_asserts(i
, final
=True)
1564 write_trace(0, i
+1, '%')
1565 retstatus
= "FAILED"
1569 if retstatus
== "FAILED" or retstatus
== "PREUNSAT":
1573 for i
in range(step
, last_check_step
+1):
1574 smt_assert("(|%s_a| s%d)" % (topmod
, i
))
1575 smt_assert(get_constr_expr(constr_asserts
, i
))
1577 print_msg("Solving for step %d.." % (last_check_step
))
1578 status
= smt_check_sat()
1580 print("%s No solution found! (%s)" % (smt
.timestamp(), status
))
1581 retstatus
= "FAILED"
1586 write_trace(0, last_check_step
+1, "%d" % step
)
1590 if gentrace
and retstatus
== "PASSED":
1592 write_trace(0, num_steps
, '%')
1598 print_msg("Status: %s" % retstatus
)
1599 sys
.exit(0 if retstatus
== "PASSED" else 1)