@@ -33,14 +33,14 @@ Author: Daniel Kroening, kroening@kroening.com
3333#include < ebmc/show_modules.h>
3434#include < ebmc/transition_system.h>
3535#include < goto-checker/all_properties_verifier_with_trace_storage.h>
36+ #include < goto-checker/goto_trace_storage.h>
3637#include < goto-checker/goto_verifier.h>
3738#include < goto-checker/multi_path_symex_checker.h>
3839#include < langapi/language_file.h>
3940#include < langapi/mode.h>
4041#include < linking/static_lifetime_init.h>
42+ #include < trans-netlist/trans_trace.h>
4143#include < trans-word-level/instantiate_word_level.h>
42- #include < trans-word-level/trans_trace_word_level.h>
43- #include < trans-word-level/unwind.h>
4444#include < verilog/verilog_ebmc_language.h>
4545
4646#include " gen_interface.h"
@@ -422,8 +422,14 @@ int hw_cbmc_parse_optionst::doit()
422422 messaget::M_STATISTICS , ui_message_handler);
423423
424424 if (cmdline.isset (" vcd" ))
425+ {
425426 options.set_option (" vcd" , cmdline.get_value (" vcd" ));
426427
428+ // the verifier only stores the traces needed for the
429+ // VCD output when the trace option is set
430+ options.set_option (" trace" , true );
431+ }
432+
427433 //
428434 // Print a banner
429435 //
@@ -567,14 +573,17 @@ int hw_cbmc_parse_optionst::doit()
567573 if (set_properties ())
568574 return 7 ;
569575
570- std::unique_ptr<goto_verifiert> verifier = std::make_unique<
576+ auto verifier = std::make_unique<
571577 all_properties_verifier_with_trace_storaget<multi_path_symex_checkert>>(
572578 options, ui_message_handler, goto_model);
573579
574580 // do actual BMC
575581 const resultt result = (*verifier)();
576582 verifier->report ();
577583
584+ if (result == resultt::FAIL && options.get_option (" vcd" ) != " " )
585+ show_unwind_trace (options, verifier->get_traces ());
586+
578587 return result_to_exit_code (result);
579588}
580589
@@ -728,54 +737,142 @@ void hw_cbmc_parse_optionst::help()
728737 " \n " ;
729738}
730739
731- void hw_cbmc_parse_optionst::do_unwind_module (prop_convt &prop_conv) {
732- if (unwind_module == " " || unwind_no_timeframes == 0 )
733- return ;
740+ /* ******************************************************************\
741+
742+ Function: compute_trans_trace
743+
744+ Inputs:
745+
746+ Outputs:
747+
748+ Purpose: build a hardware trace from a goto trace, using the
749+ values of the timeframe-instantiated hardware symbols
750+
751+ \*******************************************************************/
752+
753+ static trans_tracet compute_trans_trace (
754+ const goto_tracet &goto_trace,
755+ std::size_t no_timeframes,
756+ const namespacet &ns,
757+ const irep_idt &module )
758+ {
759+ // The hardware signals show up in the goto trace as assignments
760+ // to the timeframe-instantiated symbols (identifier@t). Collect
761+ // their values, per signal and timeframe.
762+ std::map<irep_idt, std::vector<exprt>> values;
763+
764+ for (const auto &step : goto_trace.steps )
765+ {
766+ if (!step.is_assignment () && !step.is_decl ())
767+ continue ;
768+
769+ if (step.full_lhs .id () != ID_symbol)
770+ continue ;
771+
772+ const std::string identifier =
773+ id2string (to_symbol_expr (step.full_lhs ).get_identifier ());
774+
775+ const auto separator_pos = identifier.rfind (' @' );
776+ if (separator_pos == std::string::npos)
777+ continue ;
778+
779+ const auto timeframe_string = identifier.substr (separator_pos + 1 );
780+ if (
781+ timeframe_string.empty () ||
782+ timeframe_string.find_first_not_of (" 0123456789" ) != std::string::npos)
783+ {
784+ continue ;
785+ }
786+
787+ const auto timeframe = unsafe_string2size_t (timeframe_string);
788+ if (timeframe >= no_timeframes)
789+ continue ;
790+
791+ // the base identifier must be a hardware signal
792+ const irep_idt base_identifier = identifier.substr (0 , separator_pos);
793+ const symbolt *symbol;
794+ if (ns.lookup (base_identifier, symbol))
795+ continue ;
734796
735- namespacet ns{goto_model. symbol_table };
736- const symbolt &symbol = ns. lookup (unwind_module) ;
797+ if (symbol-> is_type || symbol-> is_property || symbol-> is_macro )
798+ continue ;
737799
738- log.status () << " Unwinding transition system `" << symbol.name << " ' with "
739- << unwind_no_timeframes << " time frames" << messaget::eom;
800+ auto &signal_values = values[base_identifier];
801+ signal_values.resize (no_timeframes, nil_exprt ());
802+ signal_values[timeframe] = step.full_lhs_value ;
803+ }
740804
741- // auto dp= get_decision_procedure() ;
805+ trans_tracet dest ;
742806
743- ::unwind (to_trans_expr(symbol.value), ui_message_handler, prop_conv,
744- unwind_no_timeframes, ns, true);
807+ dest.mode = id2string (ns.lookup (module ).mode );
808+ dest.states .resize (no_timeframes);
809+
810+ for (std::size_t t = 0 ; t < no_timeframes; t++)
811+ {
812+ trans_tracet::statet &state = dest.states [t];
813+
814+ for (const auto &[identifier, signal_values] : values)
815+ {
816+ const symbolt &symbol = ns.lookup (identifier);
817+ state.assignments .emplace_back (symbol.symbol_expr (), signal_values[t]);
818+ }
819+ }
745820
746- log. status () << " Unwinding transition system done " << messaget::eom ;
821+ return dest ;
747822}
748823
749- void hw_cbmc_parse_optionst::show_unwind_trace (const optionst &options,
750- const prop_convt &prop_conv) {
751- if (unwind_module == " " || unwind_no_timeframes == 0 )
824+ /* ******************************************************************\
825+
826+ Function: hw_cbmc_parse_optionst::show_unwind_trace
827+
828+ Inputs:
829+
830+ Outputs:
831+
832+ Purpose: write the hardware signals of the counterexample
833+ as a VCD file
834+
835+ \*******************************************************************/
836+
837+ void hw_cbmc_parse_optionst::show_unwind_trace (
838+ const optionst &options,
839+ const goto_trace_storaget &traces)
840+ {
841+ if (unwind_module.empty () || unwind_no_timeframes == 0 )
752842 return ;
753843
754- namespacet ns{goto_model.symbol_table };
755- auto trans_trace =
756- compute_trans_trace (prop_conv, unwind_no_timeframes, ns, unwind_module);
844+ if (traces.all ().empty ())
845+ return ;
757846
758- if (options.get_option (" vcd" ) != " " ) {
759- if (options.get_option (" vcd" ) == " -" )
760- show_trans_trace_vcd (trans_trace, log, ns, std::cout);
761- else {
762- std::ofstream out (widen_if_needed (options.get_option (" vcd" )));
763- show_trans_trace_vcd (trans_trace, log, ns, out);
764- }
847+ const namespacet ns{goto_model.symbol_table };
848+
849+ auto trans_trace = compute_trans_trace (
850+ traces.all ().front (), unwind_no_timeframes, ns, unwind_module);
851+
852+ if (
853+ trans_trace.states .empty () ||
854+ trans_trace.states .front ().assignments .empty ())
855+ {
856+ log.warning () << " no hardware signals in counterexample, "
857+ << " not generating VCD" << messaget::eom;
858+ return ;
765859 }
766860
767- switch (ui_message_handler.get_ui ())
861+ const auto &vcd_file = options.get_option (" vcd" );
862+
863+ if (vcd_file == " -" )
864+ show_trans_trace_vcd (trans_trace, log, ns, std::cout);
865+ else
768866 {
769- case ui_message_handlert::uit::PLAIN :
770- show_trans_trace (trans_trace, log, ns, std::cout);
771- break ;
867+ std::ofstream out (widen_if_needed (vcd_file));
772868
773- case ui_message_handlert::uit::XML_UI :
774- show_trans_trace_xml (trans_trace, log, ns, std::cout);
775- break ;
869+ if (!out)
870+ {
871+ log.error () << " failed to open VCD file `" << vcd_file << " '"
872+ << messaget::eom;
873+ return ;
874+ }
776875
777- case ui_message_handlert::uit::JSON_UI :
778- show_trans_trace_json (trans_trace, log, ns, std::cout);
779- break ;
876+ show_trans_trace_vcd (trans_trace, log, ns, out);
780877 }
781878}
0 commit comments