From 9c4a0f7f12486b381fe3dd43873576fdd34b9c94 Mon Sep 17 00:00:00 2001 From: Shashank V M Date: Fri, 3 Oct 2025 20:50:51 +0530 Subject: [PATCH] Create trace for each cover property --- .github/workflows/ebmc-release.yaml | 12 +- .github/workflows/pull-request-checks.yaml | 115 +- .github/workflows/syntax-checks.yaml | 11 +- CHANGELOG | 19 + Formula/ebmc@5.7.rb | 24 + Formula/ebmc@5.8.rb | 24 + lib/cbmc | 2 +- regression/ebmc-spot/ltl-buechi/implies3.desc | 8 + regression/ebmc-spot/ltl-buechi/implies3.smv | 14 + .../sva-buechi/cover_sequence1.bmc.desc | 4 +- .../sva-buechi/cover_sequence2.bmc.desc | 8 +- .../sva-buechi/disable_iff1.bdd.desc | 2 +- regression/ebmc-spot/sva-buechi/if1.k.desc | 2 +- .../ebmc-spot/sva-buechi/immediate2.desc | 11 + .../ebmc-spot/sva-buechi/immediate3.desc | 9 + .../ebmc-spot/sva-buechi/initial2.bmc.desc | 4 +- .../ebmc-spot/sva-buechi/initial2.k.desc | 4 +- .../sva-buechi/s_eventually2.bmc.desc | 3 +- .../ebmc-spot/sva-buechi/s_eventually4.desc | 8 + .../ebmc-spot/sva-buechi/sequence2.bmc.desc | 2 +- .../ebmc-spot/sva-buechi/sequence3.bmc.desc | 12 + .../sva-buechi/sequence_and1.bdd.desc | 13 + .../sva-buechi/sequence_and1.bmc.desc | 13 + .../sva-buechi/sequence_repetition1.bmc.desc | 8 +- .../sva-buechi/sequence_repetition2.bmc.desc | 17 + .../sva-buechi/sequence_repetition3.bdd.desc | 11 + .../sva-buechi/sequence_throughout1.desc | 9 +- .../sva-buechi/sequence_within1.desc | 13 +- regression/ebmc-spot/sva-buechi/strong1.desc | 2 +- .../sva-buechi/system_verilog_assertion1.desc | 8 + .../sva-buechi/system_verilog_assertion2.desc | 9 + .../sva-buechi/system_verilog_assertion4.desc | 8 + .../ebmc-spot/sva-buechi/unbounded1.desc | 4 +- regression/ebmc-spot/sva-buechi/weak1.desc | 9 + .../test.desc => CLI/reset1.desc} | 2 +- .../main.sv => CLI/reset1.sv} | 0 regression/ebmc/CLI/reset2.desc | 7 + regression/ebmc/CLI/reset2.sv | 15 + regression/ebmc/CLI/show-modules-smv.desc | 24 + regression/ebmc/CLI/show-modules-smv.smv | 15 + regression/ebmc/smv-netlist/s_until1.desc | 4 +- regression/ebmc/smv-netlist/smv1.desc | 2 + regression/ebmc/smv-netlist/smv1.smv | 1 + regression/ebmc/smv-netlist/verilog2.desc | 7 + regression/ebmc/smv-netlist/verilog2.sv | 4 + regression/ebmc/smv-netlist/verilog3.desc | 5 + regression/ebmc/smv-netlist/verilog3.sv | 5 + regression/ebmc/smv-word-level/verilog1.desc | 2 +- regression/ebmc/smv-word-level/verilog3.desc | 10 + regression/ebmc/smv-word-level/verilog3.sv | 8 + regression/ebmc/smv-word-level/verilog4.desc | 7 + regression/ebmc/smv-word-level/verilog4.sv | 12 + regression/ebmc/smv-word-level/verilog5.desc | 9 + regression/ebmc/smv-word-level/verilog5.sv | 5 + regression/ebmc/smv-word-level/verilog6.desc | 7 + regression/ebmc/smv-word-level/verilog6.sv | 6 + regression/smv/CTL/smv_ctlspec3.desc | 4 +- regression/smv/LTL/smv_ltlspec_X1.desc | 10 + regression/smv/LTL/smv_ltlspec_X1.smv | 11 + regression/smv/define/define2.desc | 4 +- regression/smv/define/define3.desc | 2 +- regression/smv/define/define4.desc | 2 +- regression/smv/define/define8.desc | 8 + regression/smv/define/define8.smv | 6 + regression/smv/define/define9.desc | 8 + regression/smv/define/define9.smv | 10 + regression/smv/enums/name_collision1.desc | 9 + regression/smv/enums/name_collision1.smv | 6 + regression/smv/enums/name_collision2.desc | 9 + regression/smv/enums/name_collision2.smv | 8 + regression/smv/enums/name_collision3.desc | 9 + regression/smv/enums/name_collision3.smv | 9 + regression/smv/expressions/div1.desc | 8 + regression/smv/expressions/div1.smv | 7 + regression/smv/expressions/mod1.desc | 8 + regression/smv/expressions/mod1.smv | 7 + .../smv/identifiers/complex_identifier1.desc | 7 + .../smv/identifiers/complex_identifier1.smv | 12 + regression/smv/ivar/ivar1.desc | 9 +- regression/smv/ivar/ivar1.smv | 6 + regression/smv/modules/module_argument1.desc | 8 + regression/smv/modules/module_argument1.smv | 15 + regression/smv/modules/module_with_enum1.desc | 3 +- regression/smv/modules/module_with_enum2.desc | 9 + regression/smv/modules/module_with_enum2.smv | 13 + regression/smv/modules/parameters1.desc | 12 + regression/smv/modules/parameters1.smv | 3 + regression/smv/modules/parameters2.desc | 8 + regression/smv/modules/parameters2.smv | 9 + regression/smv/modules/self1.desc | 9 + regression/smv/modules/self1.smv | 18 + regression/smv/modules/trace1.desc | 19 + regression/smv/modules/trace1.smv | 12 + .../smv/modules/use_before_declaration1.desc | 8 + .../smv/modules/use_before_declaration1.smv | 10 + regression/smv/next/assign_next1.desc | 7 + regression/smv/next/assign_next1.smv | 11 + regression/smv/process/process1.desc | 9 + regression/smv/process/process1.smv | 9 + regression/smv/var/already_declared1.desc | 2 +- regression/smv/var/already_declared2.desc | 2 +- regression/smv/var/already_declared3.desc | 2 +- regression/smv/var/already_declared4.desc | 3 +- regression/smv/var/already_declared5.desc | 4 +- regression/smv/word/bit_selection1.desc | 10 + regression/smv/word/bit_selection1.smv | 5 + regression/smv/word/bit_selection2.desc | 7 + .../{extractbits1.smv => bit_selection2.smv} | 0 regression/smv/word/bitwise1.desc | 5 +- regression/smv/word/bitwise1.smv | 6 +- regression/smv/word/div1.desc | 6 + regression/smv/word/div1.smv | 7 + regression/smv/word/mod1.desc | 6 + regression/smv/word/mod1.smv | 7 + regression/smv/word/word_constants1.desc | 7 + regression/smv/word/word_constants1.smv | 18 + regression/verilog/Makefile | 3 + regression/verilog/SVA/assert_else1.desc | 8 + regression/verilog/SVA/assert_else1.sv | 9 + regression/verilog/SVA/cover_sequence1.sv | 4 +- regression/verilog/SVA/cover_sequence2.sv | 8 +- regression/verilog/SVA/cover_sequence3.sv | 6 +- regression/verilog/SVA/cover_sequence4.sv | 6 +- regression/verilog/SVA/cover_sequence5.desc | 9 + regression/verilog/SVA/cover_sequence5.sv | 15 + regression/verilog/SVA/initial2.desc | 4 +- regression/verilog/SVA/initial2.sv | 4 +- regression/verilog/SVA/named_property1.sv | 2 + regression/verilog/SVA/property_and1.aig.desc | 9 + .../arrays/unpacked_array_concatenation1.desc | 8 + .../arrays/unpacked_array_concatenation1.sv | 11 + .../asic-world-operators/reduction.desc | 3 +- .../asic-world-operators/relational.desc | 3 +- .../asic-world-operators/replication.desc | 3 +- .../asic-world-operators/replication.sv | 4 +- .../assignments/assignment-context1.desc | 8 + .../assignments/assignment-context1.sv | 70 + .../assignments/assignment-context2.desc | 9 + .../assignments/assignment-context2.sv | 68 + .../assignments/assignment-pattern-lhs1.desc | 8 + .../assignments/assignment-pattern-lhs1.sv | 14 + .../assignment-with-function-call1.sv | 4 +- regression/verilog/case/case5.desc | 10 + regression/verilog/case/case5.sv | 30 + regression/verilog/class/new1.desc | 5 +- regression/verilog/config/basic_config1.desc | 8 + regression/verilog/config/basic_config1.sv | 13 + regression/verilog/data-types/time1.desc | 7 + regression/verilog/data-types/time1.sv | 12 + .../verilog/expressions/bitwise_and1.desc | 8 + .../verilog/expressions/bitwise_and1.sv | 8 + .../verilog/expressions/bitwise_or1.desc | 8 + regression/verilog/expressions/bitwise_or1.sv | 8 + .../verilog/expressions/bitwise_xor1.desc | 7 + .../verilog/expressions/bitwise_xor1.sv | 8 + .../verilog/expressions/concatenation5.desc | 2 +- regression/verilog/expressions/div1.desc | 9 + regression/verilog/expressions/div1.sv | 13 + regression/verilog/expressions/equality1.desc | 2 +- regression/verilog/expressions/equality2.desc | 2 +- regression/verilog/expressions/equality3.desc | 1 + regression/verilog/expressions/equality4.desc | 8 + regression/verilog/expressions/equality4.sv | 7 + regression/verilog/expressions/equality5.desc | 8 + regression/verilog/expressions/equality5.sv | 7 + .../expressions/integer_literals2.desc | 7 + .../verilog/expressions/integer_literals2.sv | 20 + .../expressions/integer_literals3.desc | 9 + .../verilog/expressions/integer_literals3.sv | 22 + regression/verilog/expressions/minus1.desc | 8 + regression/verilog/expressions/minus1.sv | 9 + regression/verilog/expressions/mod1.desc | 9 + regression/verilog/expressions/mod1.sv | 13 + regression/verilog/expressions/mod2.desc | 2 +- .../expressions/mult1.desc} | 3 +- regression/verilog/expressions/mult1.sv | 9 + regression/verilog/expressions/negation1.sv | 3 + regression/verilog/expressions/plus1.desc | 8 + regression/verilog/expressions/plus1.sv | 9 + regression/verilog/expressions/power3.desc | 8 + regression/verilog/expressions/power3.sv | 9 + .../verilog/expressions/reduction2.desc | 2 +- .../verilog/expressions/replication3.desc | 2 +- regression/verilog/expressions/shl4.desc | 3 +- regression/verilog/expressions/shl4.sv | 11 +- regression/verilog/expressions/shr2.desc | 2 +- regression/verilog/expressions/signed2.sv | 2 +- .../verilog/expressions/signing_cast1.sv | 5 + .../verilog/expressions/signing_cast2.desc | 9 + .../verilog/expressions/signing_cast2.sv | 11 + .../verilog/expressions/signing_cast3.desc | 8 + .../verilog/expressions/signing_cast3.sv | 9 + .../verilog/expressions/size_cast2.desc | 8 + regression/verilog/expressions/size_cast2.sv | 11 + .../verilog/expressions/size_cast3.desc | 8 + regression/verilog/expressions/size_cast3.sv | 9 + .../verilog/expressions/static_cast3.desc | 8 + .../verilog/expressions/static_cast3.sv | 15 + .../verilog/expressions/static_cast4.desc | 8 + .../verilog/expressions/static_cast4.sv | 17 + .../expressions/streaming_concatenation2.desc | 2 +- .../verilog/expressions/unary_minus1.desc | 8 + .../verilog/expressions/unary_minus1.sv | 9 + .../verilog/expressions/unary_plus1.desc | 9 + regression/verilog/expressions/unary_plus1.sv | 14 + .../expressions/wildcard_equality1.desc | 6 +- .../expressions/wildcard_equality2.desc | 4 +- ...card_equality2.v => wildcard_equality2.sv} | 2 +- .../verilog/functioncall/function_ports2.desc | 9 + .../verilog/functioncall/function_ports2.sv | 11 + .../verilog/functioncall/function_ports3.desc | 8 + .../verilog/functioncall/function_ports3.sv | 11 + .../named_parameter_assignment1.desc | 9 + .../named_parameter_assignment1.sv | 13 + regression/verilog/modules/interconnect1.desc | 6 +- regression/verilog/modules/localparam3.v | 4 + .../modules/named_port_connection1.desc | 8 + .../verilog/modules/named_port_connection1.sv | 10 + .../verilog/modules/parameter_ports4.desc | 8 - .../verilog/modules/parameter_ports5.desc | 6 + .../verilog/modules/parameter_ports5.sv | 12 + .../modules/parameter_without_default1.desc | 9 + .../modules/parameter_without_default1.sv | 11 + regression/verilog/modules/parameters11.desc | 7 + regression/verilog/modules/parameters11.sv | 21 + .../verilog/modules/port_connection1.desc | 8 + .../verilog/modules/port_connection1.sv | 16 + regression/verilog/modules/ports9.desc | 8 + regression/verilog/modules/ports9.sv | 15 + .../verilog/modules/type_parameter_port1.desc | 7 + ...eter_ports4.sv => type_parameter_port1.sv} | 0 .../verilog/modules/type_parameter_port2.desc | 7 + .../verilog/modules/type_parameter_port2.sv | 13 + .../verilog/modules/type_parameter_port3.desc | 7 + .../verilog/modules/type_parameter_port3.sv | 13 + .../verilog/modules/type_parameter_port4.desc | 7 + .../verilog/modules/type_parameter_port4.sv | 13 + .../verilog/modules/type_parameters1.desc | 4 +- .../verilog/modules/type_parameters2.desc | 7 + .../verilog/modules/type_parameters2.sv | 9 + .../verilog/modules/unconnected_ports1.desc | 8 + .../verilog/modules/unconnected_ports1.sv | 25 + .../preprocessor/unknown_directive.desc | 1 - regression/verilog/structs/structs4.sv | 2 +- .../verilog/structs/unpacked_struct1.desc | 7 + .../verilog/structs/unpacked_struct1.sv | 11 + .../verilog/structs/unpacked_struct2.desc | 7 + .../verilog/structs/unpacked_struct2.sv | 11 + .../verilog/synthesis/always_comb2.aig.desc | 12 + .../verilog/system-functions/error1.desc | 8 + regression/verilog/system-functions/error1.v | 8 + .../verilog/system-functions/past6.desc | 2 +- regression/verilog/unions/tagged_union1.desc | 8 + regression/verilog/unions/tagged_union1.sv | 11 + src/Makefile | 2 +- src/config.inc | 2 +- src/ebmc/Makefile | 5 +- src/ebmc/build_transition_system.cpp | 418 ++++++ src/ebmc/build_transition_system.h | 33 + src/ebmc/ebmc_base.cpp | 188 --- src/ebmc/ebmc_base.h | 61 - src/ebmc/ebmc_language.cpp | 13 + src/ebmc/ebmc_language.h | 42 + src/ebmc/ebmc_language_file.cpp | 298 +++++ src/ebmc/ebmc_language_file.h | 169 +++ src/ebmc/ebmc_parse_options.cpp | 96 +- src/ebmc/instrument_buechi.cpp | 125 +- src/ebmc/neural_liveness.cpp | 21 +- src/ebmc/neural_liveness.h | 10 +- src/ebmc/output_smv_word_level.cpp | 3 +- src/ebmc/random_traces.cpp | 18 +- src/ebmc/random_traces.h | 12 +- src/ebmc/ranking_function.cpp | 6 +- src/ebmc/ranking_function.h | 5 +- src/ebmc/report_results.cpp | 11 +- src/ebmc/show_modules.cpp | 97 ++ src/ebmc/show_modules.h | 51 + src/ebmc/show_trans.cpp | 1 - src/ebmc/transition_system.cpp | 323 +---- src/ebmc/transition_system.h | 11 - src/hw-cbmc/Makefile | 1 + src/hw-cbmc/hw_cbmc_parse_options.cpp | 5 +- src/hw_cbmc_irep_ids.h | 18 +- src/ic3/dnf_io.hh | 1 + src/ic3/m4y_aiger_print.cc | 16 +- src/ic3/m5y_aiger_print.cc | 16 +- src/smvlang/Makefile | 3 +- src/smvlang/expr2smv.cpp | 140 +- src/smvlang/expr2smv_class.h | 7 + src/smvlang/parser.y | 465 +++---- src/smvlang/scanner.l | 5 + src/smvlang/smv_ebmc_language.cpp | 127 ++ src/smvlang/smv_ebmc_language.h | 34 + src/smvlang/smv_expr.h | 67 + src/smvlang/smv_language.cpp | 70 +- src/smvlang/smv_parse_tree.cpp | 102 +- src/smvlang/smv_parse_tree.h | 211 +-- src/smvlang/smv_typecheck.cpp | 1107 ++++++++++------ src/smvlang/smv_types.h | 55 + src/temporal-logic/hoa.cpp | 24 +- src/temporal-logic/hoa.h | 5 +- src/temporal-logic/ltl_sva_to_string.cpp | 93 +- src/temporal-logic/ltl_sva_to_string.h | 9 +- src/temporal-logic/ltl_to_buechi.cpp | 27 +- src/temporal-logic/ltl_to_buechi.h | 10 + src/temporal-logic/sva_to_ltl.cpp | 3 +- src/temporal-logic/temporal_logic.cpp | 22 +- src/temporal-logic/temporal_logic.h | 4 - src/temporal-logic/trivial_sva.cpp | 8 + src/trans-netlist/aig.h | 46 +- src/trans-netlist/aig_prop.h | 5 +- src/trans-netlist/counterexample_netlist.cpp | 4 +- src/trans-netlist/ldg.cpp | 34 +- src/trans-netlist/ldg.h | 7 +- src/trans-netlist/netlist.cpp | 13 +- src/trans-netlist/smv_netlist.cpp | 22 +- src/trans-netlist/trans_to_netlist.cpp | 115 +- src/trans-netlist/trans_trace_netlist.cpp | 12 +- src/trans-netlist/unwind_netlist.cpp | 5 +- src/trans-netlist/var_map.cpp | 66 +- src/trans-netlist/var_map.h | 3 + src/trans-word-level/Makefile | 1 - src/trans-word-level/show_modules.cpp | 128 -- src/trans-word-level/show_modules.h | 20 - .../trans_trace_word_level.cpp | 9 +- src/util/ebmc_util.h | 12 - src/verilog/Makefile | 1 + src/verilog/aval_bval_encoding.cpp | 309 ++++- src/verilog/aval_bval_encoding.h | 21 +- src/verilog/expr2verilog.cpp | 89 +- src/verilog/expr2verilog_class.h | 10 +- src/verilog/parser.y | 233 +++- src/verilog/sva_expr.h | 127 ++ src/verilog/typename.cpp | 176 +++ src/verilog/typename.h | 25 + src/verilog/verilog_elaborate.cpp | 38 +- src/verilog/verilog_elaborate_type.cpp | 39 +- src/verilog/verilog_expr.cpp | 35 +- src/verilog/verilog_expr.h | 181 ++- src/verilog/verilog_generate.cpp | 5 +- src/verilog/verilog_interfaces.cpp | 10 +- src/verilog/verilog_lowering.cpp | 142 ++- src/verilog/verilog_parameterize_module.cpp | 59 +- src/verilog/verilog_parse_tree.cpp | 5 +- src/verilog/verilog_synthesis.cpp | 198 ++- src/verilog/verilog_synthesis_class.h | 5 +- src/verilog/verilog_typecheck.cpp | 193 +-- src/verilog/verilog_typecheck.h | 2 - src/verilog/verilog_typecheck_expr.cpp | 1127 +++++++---------- src/verilog/verilog_typecheck_expr.h | 17 +- src/verilog/verilog_typecheck_sva.cpp | 40 +- src/verilog/verilog_types.h | 32 +- unit/Makefile | 2 + unit/temporal-logic/sva_to_ltl.cpp | 25 + unit/verilog/typename.cpp | 30 + 355 files changed, 7549 insertions(+), 3111 deletions(-) create mode 100644 Formula/ebmc@5.7.rb create mode 100644 Formula/ebmc@5.8.rb create mode 100644 regression/ebmc-spot/ltl-buechi/implies3.desc create mode 100644 regression/ebmc-spot/ltl-buechi/implies3.smv create mode 100644 regression/ebmc-spot/sva-buechi/immediate2.desc create mode 100644 regression/ebmc-spot/sva-buechi/immediate3.desc create mode 100644 regression/ebmc-spot/sva-buechi/s_eventually4.desc create mode 100644 regression/ebmc-spot/sva-buechi/sequence3.bmc.desc create mode 100644 regression/ebmc-spot/sva-buechi/sequence_and1.bdd.desc create mode 100644 regression/ebmc-spot/sva-buechi/sequence_and1.bmc.desc create mode 100644 regression/ebmc-spot/sva-buechi/sequence_repetition2.bmc.desc create mode 100644 regression/ebmc-spot/sva-buechi/sequence_repetition3.bdd.desc create mode 100644 regression/ebmc-spot/sva-buechi/system_verilog_assertion1.desc create mode 100644 regression/ebmc-spot/sva-buechi/system_verilog_assertion2.desc create mode 100644 regression/ebmc-spot/sva-buechi/system_verilog_assertion4.desc create mode 100644 regression/ebmc-spot/sva-buechi/weak1.desc rename regression/ebmc/{reset-command-line-option1/test.desc => CLI/reset1.desc} (87%) rename regression/ebmc/{reset-command-line-option1/main.sv => CLI/reset1.sv} (100%) create mode 100644 regression/ebmc/CLI/reset2.desc create mode 100644 regression/ebmc/CLI/reset2.sv create mode 100644 regression/ebmc/CLI/show-modules-smv.desc create mode 100644 regression/ebmc/CLI/show-modules-smv.smv create mode 100644 regression/ebmc/smv-netlist/verilog2.desc create mode 100644 regression/ebmc/smv-netlist/verilog2.sv create mode 100644 regression/ebmc/smv-netlist/verilog3.desc create mode 100644 regression/ebmc/smv-netlist/verilog3.sv create mode 100644 regression/ebmc/smv-word-level/verilog3.desc create mode 100644 regression/ebmc/smv-word-level/verilog3.sv create mode 100644 regression/ebmc/smv-word-level/verilog4.desc create mode 100644 regression/ebmc/smv-word-level/verilog4.sv create mode 100644 regression/ebmc/smv-word-level/verilog5.desc create mode 100644 regression/ebmc/smv-word-level/verilog5.sv create mode 100644 regression/ebmc/smv-word-level/verilog6.desc create mode 100644 regression/ebmc/smv-word-level/verilog6.sv create mode 100644 regression/smv/LTL/smv_ltlspec_X1.desc create mode 100644 regression/smv/LTL/smv_ltlspec_X1.smv create mode 100644 regression/smv/define/define8.desc create mode 100644 regression/smv/define/define8.smv create mode 100644 regression/smv/define/define9.desc create mode 100644 regression/smv/define/define9.smv create mode 100644 regression/smv/enums/name_collision1.desc create mode 100644 regression/smv/enums/name_collision1.smv create mode 100644 regression/smv/enums/name_collision2.desc create mode 100644 regression/smv/enums/name_collision2.smv create mode 100644 regression/smv/enums/name_collision3.desc create mode 100644 regression/smv/enums/name_collision3.smv create mode 100644 regression/smv/expressions/div1.desc create mode 100644 regression/smv/expressions/div1.smv create mode 100644 regression/smv/expressions/mod1.desc create mode 100644 regression/smv/expressions/mod1.smv create mode 100644 regression/smv/identifiers/complex_identifier1.desc create mode 100644 regression/smv/identifiers/complex_identifier1.smv create mode 100644 regression/smv/modules/module_argument1.desc create mode 100644 regression/smv/modules/module_argument1.smv create mode 100644 regression/smv/modules/module_with_enum2.desc create mode 100644 regression/smv/modules/module_with_enum2.smv create mode 100644 regression/smv/modules/parameters1.desc create mode 100644 regression/smv/modules/parameters1.smv create mode 100644 regression/smv/modules/parameters2.desc create mode 100644 regression/smv/modules/parameters2.smv create mode 100644 regression/smv/modules/self1.desc create mode 100644 regression/smv/modules/self1.smv create mode 100644 regression/smv/modules/trace1.desc create mode 100644 regression/smv/modules/trace1.smv create mode 100644 regression/smv/modules/use_before_declaration1.desc create mode 100644 regression/smv/modules/use_before_declaration1.smv create mode 100644 regression/smv/next/assign_next1.desc create mode 100644 regression/smv/next/assign_next1.smv create mode 100644 regression/smv/process/process1.desc create mode 100644 regression/smv/process/process1.smv create mode 100644 regression/smv/word/bit_selection1.desc create mode 100644 regression/smv/word/bit_selection1.smv create mode 100644 regression/smv/word/bit_selection2.desc rename regression/smv/word/{extractbits1.smv => bit_selection2.smv} (100%) create mode 100644 regression/smv/word/div1.desc create mode 100644 regression/smv/word/div1.smv create mode 100644 regression/smv/word/mod1.desc create mode 100644 regression/smv/word/mod1.smv create mode 100644 regression/smv/word/word_constants1.desc create mode 100644 regression/smv/word/word_constants1.smv create mode 100644 regression/verilog/SVA/assert_else1.desc create mode 100644 regression/verilog/SVA/assert_else1.sv create mode 100644 regression/verilog/SVA/cover_sequence5.desc create mode 100644 regression/verilog/SVA/cover_sequence5.sv create mode 100644 regression/verilog/SVA/property_and1.aig.desc create mode 100644 regression/verilog/arrays/unpacked_array_concatenation1.desc create mode 100644 regression/verilog/arrays/unpacked_array_concatenation1.sv create mode 100644 regression/verilog/assignments/assignment-context1.desc create mode 100644 regression/verilog/assignments/assignment-context1.sv create mode 100644 regression/verilog/assignments/assignment-context2.desc create mode 100644 regression/verilog/assignments/assignment-context2.sv create mode 100644 regression/verilog/assignments/assignment-pattern-lhs1.desc create mode 100644 regression/verilog/assignments/assignment-pattern-lhs1.sv create mode 100644 regression/verilog/case/case5.desc create mode 100644 regression/verilog/case/case5.sv create mode 100644 regression/verilog/config/basic_config1.desc create mode 100644 regression/verilog/config/basic_config1.sv create mode 100644 regression/verilog/data-types/time1.desc create mode 100644 regression/verilog/data-types/time1.sv create mode 100644 regression/verilog/expressions/bitwise_and1.desc create mode 100644 regression/verilog/expressions/bitwise_and1.sv create mode 100644 regression/verilog/expressions/bitwise_or1.desc create mode 100644 regression/verilog/expressions/bitwise_or1.sv create mode 100644 regression/verilog/expressions/bitwise_xor1.desc create mode 100644 regression/verilog/expressions/bitwise_xor1.sv create mode 100644 regression/verilog/expressions/div1.desc create mode 100644 regression/verilog/expressions/div1.sv create mode 100644 regression/verilog/expressions/equality4.desc create mode 100644 regression/verilog/expressions/equality4.sv create mode 100644 regression/verilog/expressions/equality5.desc create mode 100644 regression/verilog/expressions/equality5.sv create mode 100644 regression/verilog/expressions/integer_literals2.desc create mode 100644 regression/verilog/expressions/integer_literals2.sv create mode 100644 regression/verilog/expressions/integer_literals3.desc create mode 100644 regression/verilog/expressions/integer_literals3.sv create mode 100644 regression/verilog/expressions/minus1.desc create mode 100644 regression/verilog/expressions/minus1.sv create mode 100644 regression/verilog/expressions/mod1.desc create mode 100644 regression/verilog/expressions/mod1.sv rename regression/{smv/word/extractbits1.desc => verilog/expressions/mult1.desc} (80%) create mode 100644 regression/verilog/expressions/mult1.sv create mode 100644 regression/verilog/expressions/plus1.desc create mode 100644 regression/verilog/expressions/plus1.sv create mode 100644 regression/verilog/expressions/power3.desc create mode 100644 regression/verilog/expressions/power3.sv create mode 100644 regression/verilog/expressions/signing_cast2.desc create mode 100644 regression/verilog/expressions/signing_cast2.sv create mode 100644 regression/verilog/expressions/signing_cast3.desc create mode 100644 regression/verilog/expressions/signing_cast3.sv create mode 100644 regression/verilog/expressions/size_cast2.desc create mode 100644 regression/verilog/expressions/size_cast2.sv create mode 100644 regression/verilog/expressions/size_cast3.desc create mode 100644 regression/verilog/expressions/size_cast3.sv create mode 100644 regression/verilog/expressions/static_cast3.desc create mode 100644 regression/verilog/expressions/static_cast3.sv create mode 100644 regression/verilog/expressions/static_cast4.desc create mode 100644 regression/verilog/expressions/static_cast4.sv create mode 100644 regression/verilog/expressions/unary_minus1.desc create mode 100644 regression/verilog/expressions/unary_minus1.sv create mode 100644 regression/verilog/expressions/unary_plus1.desc create mode 100644 regression/verilog/expressions/unary_plus1.sv rename regression/verilog/expressions/{wildcard_equality2.v => wildcard_equality2.sv} (71%) create mode 100644 regression/verilog/functioncall/function_ports2.desc create mode 100644 regression/verilog/functioncall/function_ports2.sv create mode 100644 regression/verilog/functioncall/function_ports3.desc create mode 100644 regression/verilog/functioncall/function_ports3.sv create mode 100644 regression/verilog/functioncall/named_parameter_assignment1.desc create mode 100644 regression/verilog/functioncall/named_parameter_assignment1.sv create mode 100644 regression/verilog/modules/named_port_connection1.desc create mode 100644 regression/verilog/modules/named_port_connection1.sv delete mode 100644 regression/verilog/modules/parameter_ports4.desc create mode 100644 regression/verilog/modules/parameter_ports5.desc create mode 100644 regression/verilog/modules/parameter_ports5.sv create mode 100644 regression/verilog/modules/parameter_without_default1.desc create mode 100644 regression/verilog/modules/parameter_without_default1.sv create mode 100644 regression/verilog/modules/parameters11.desc create mode 100644 regression/verilog/modules/parameters11.sv create mode 100644 regression/verilog/modules/port_connection1.desc create mode 100644 regression/verilog/modules/port_connection1.sv create mode 100644 regression/verilog/modules/ports9.desc create mode 100644 regression/verilog/modules/ports9.sv create mode 100644 regression/verilog/modules/type_parameter_port1.desc rename regression/verilog/modules/{parameter_ports4.sv => type_parameter_port1.sv} (100%) create mode 100644 regression/verilog/modules/type_parameter_port2.desc create mode 100644 regression/verilog/modules/type_parameter_port2.sv create mode 100644 regression/verilog/modules/type_parameter_port3.desc create mode 100644 regression/verilog/modules/type_parameter_port3.sv create mode 100644 regression/verilog/modules/type_parameter_port4.desc create mode 100644 regression/verilog/modules/type_parameter_port4.sv create mode 100644 regression/verilog/modules/type_parameters2.desc create mode 100644 regression/verilog/modules/type_parameters2.sv create mode 100644 regression/verilog/modules/unconnected_ports1.desc create mode 100644 regression/verilog/modules/unconnected_ports1.sv create mode 100644 regression/verilog/structs/unpacked_struct1.desc create mode 100644 regression/verilog/structs/unpacked_struct1.sv create mode 100644 regression/verilog/structs/unpacked_struct2.desc create mode 100644 regression/verilog/structs/unpacked_struct2.sv create mode 100644 regression/verilog/synthesis/always_comb2.aig.desc create mode 100644 regression/verilog/system-functions/error1.desc create mode 100644 regression/verilog/system-functions/error1.v create mode 100644 regression/verilog/unions/tagged_union1.desc create mode 100644 regression/verilog/unions/tagged_union1.sv create mode 100644 src/ebmc/build_transition_system.cpp create mode 100644 src/ebmc/build_transition_system.h delete mode 100644 src/ebmc/ebmc_base.cpp delete mode 100644 src/ebmc/ebmc_base.h create mode 100644 src/ebmc/ebmc_language.cpp create mode 100644 src/ebmc/ebmc_language.h create mode 100644 src/ebmc/ebmc_language_file.cpp create mode 100644 src/ebmc/ebmc_language_file.h create mode 100644 src/ebmc/show_modules.cpp create mode 100644 src/ebmc/show_modules.h create mode 100644 src/smvlang/smv_ebmc_language.cpp create mode 100644 src/smvlang/smv_ebmc_language.h delete mode 100644 src/trans-word-level/show_modules.cpp delete mode 100644 src/trans-word-level/show_modules.h create mode 100644 src/verilog/typename.cpp create mode 100644 src/verilog/typename.h create mode 100644 unit/temporal-logic/sva_to_ltl.cpp create mode 100644 unit/verilog/typename.cpp diff --git a/.github/workflows/ebmc-release.yaml b/.github/workflows/ebmc-release.yaml index 68683c621..63a8a5850 100644 --- a/.github/workflows/ebmc-release.yaml +++ b/.github/workflows/ebmc-release.yaml @@ -51,7 +51,7 @@ jobs: outputs: deb_package_name: ${{ steps.create_packages.outputs.deb_package_name }} steps: - - uses: actions/checkout@v5 + - uses: actions/checkout@v6 with: submodules: recursive - name: Fetch dependencies @@ -59,7 +59,7 @@ jobs: sudo apt-get update sudo apt-get install --no-install-recommends -yq gcc g++ jq flex bison libxml2-utils ccache - name: Prepare ccache - uses: actions/cache@v4 + uses: actions/cache@v5 with: save-always: true path: /home/runner/.cache @@ -135,13 +135,13 @@ jobs: tar xJf ccache-4.9.1-linux-x86_64.tar.xz cp ccache-4.9.1-linux-x86_64/ccache /usr/bin/ - name: cache for ccache - uses: actions/cache@v4 + uses: actions/cache@v5 with: path: /github/home/.cache/ccache save-always: true key: ${{ runner.os }}-centos8-make-gcc-${{ github.ref }}-${{ github.sha }}-PR restore-keys: ${{ runner.os }}-centos8-make-gcc- - - uses: actions/checkout@v5 + - uses: actions/checkout@v6 with: submodules: recursive - name: Zero ccache stats and limit in size @@ -222,7 +222,7 @@ jobs: outputs: wasm_package_name: ${{ steps.create_packages.outputs.wasm_package_name }} steps: - - uses: actions/checkout@v5 + - uses: actions/checkout@v6 with: submodules: recursive - name: Fetch dependencies @@ -244,7 +244,7 @@ jobs: source ./emsdk_env.sh emcc --version - name: Prepare ccache - uses: actions/cache@v4 + uses: actions/cache@v5 with: path: /home/runner/.cache save-always: true diff --git a/.github/workflows/pull-request-checks.yaml b/.github/workflows/pull-request-checks.yaml index 5c1a1d106..8bebfdc92 100644 --- a/.github/workflows/pull-request-checks.yaml +++ b/.github/workflows/pull-request-checks.yaml @@ -10,7 +10,7 @@ jobs: check-ubuntu-24_04-make-gcc: runs-on: ubuntu-24.04 steps: - - uses: actions/checkout@v5 + - uses: actions/checkout@v6 with: submodules: recursive - name: Fetch dependencies @@ -19,12 +19,19 @@ jobs: # user input DEBIAN_FRONTEND: noninteractive run: | - sudo apt-get update - sudo apt-get install --no-install-recommends -yq gcc gdb g++ jq flex bison libxml2-utils ccache cmake z3 + sudo apt-get remove --purge man-db + packages_to_install="ccache z3" + if ! sudo apt-get install --no-install-recommends -yq $packages_to_install ; then + # retry after updating package indices + sudo apt-get update + sudo apt-get install --no-install-recommends -yq $packages_to_install + fi - name: Confirm z3 solver is available and log the version installed run: z3 --version + - name: Log the version of gcc + run: gcc --version - name: Prepare ccache - uses: actions/cache@v4 + uses: actions/cache@v5 with: path: .ccache save-always: true @@ -68,7 +75,7 @@ jobs: CC: "ccache clang" CXX: "ccache clang++" steps: - - uses: actions/checkout@v5 + - uses: actions/checkout@v6 with: submodules: recursive - name: Fetch dependencies @@ -77,13 +84,18 @@ jobs: # user input DEBIAN_FRONTEND: noninteractive run: | - sudo apt-get update - sudo apt-get install --no-install-recommends -yq clang-19 clang++-19 gdb jq flex bison libxml2-utils cpanminus ccache z3 + sudo apt-get remove --purge man-db + packages_to_install="clang-19 clang++-19 gdb jq flex bison libxml2-utils cpanminus ccache z3" + if ! sudo apt-get install --no-install-recommends -yq $packages_to_install ; then + # retry after updating package indices + sudo apt-get update + sudo apt-get install --no-install-recommends -yq $packages_to_install + fi cpanm Thread::Pool::Simple - name: Confirm z3 solver is available and log the version installed run: z3 --version - name: Prepare ccache - uses: actions/cache@v4 + uses: actions/cache@v5 with: path: .ccache save-always: true @@ -120,19 +132,19 @@ jobs: - name: Print ccache stats run: ccache -s - name: Upload the ebmc binary - uses: actions/upload-artifact@v4 + uses: actions/upload-artifact@v6 with: name: ebmc-binary retention-days: 5 path: src/ebmc/ebmc - name: Upload the hw-cbmc binary - uses: actions/upload-artifact@v4 + uses: actions/upload-artifact@v6 with: name: hw-cbmc-binary retention-days: 5 path: src/hw-cbmc/hw-cbmc - name: Upload the vlindex binary - uses: actions/upload-artifact@v4 + uses: actions/upload-artifact@v6 with: name: vlindex-binary retention-days: 5 @@ -143,7 +155,7 @@ jobs: runs-on: ubuntu-24.04 needs: check-ubuntu-24_04-make-clang steps: - - uses: actions/checkout@v5 + - uses: actions/checkout@v6 with: submodules: recursive - name: Fetch dependencies @@ -152,12 +164,17 @@ jobs: # user input DEBIAN_FRONTEND: noninteractive run: | - sudo apt-get update - sudo apt-get install --no-install-recommends z3 + sudo apt-get remove --purge man-db + packages_to_install="z3" + if ! sudo apt-get install --no-install-recommends -yq $packages_to_install ; then + # retry after updating package indices + sudo apt-get update + sudo apt-get install --no-install-recommends -yq $packages_to_install + fi - name: Confirm z3 solver is available and log the version installed run: z3 --version - name: Get the ebmc binary - uses: actions/download-artifact@v5 + uses: actions/download-artifact@v7 with: name: ebmc-binary path: ebmc @@ -171,7 +188,7 @@ jobs: runs-on: ubuntu-24.04 needs: check-ubuntu-24_04-make-clang steps: - - uses: actions/checkout@v5 + - uses: actions/checkout@v6 with: submodules: recursive - name: Fetch dependencies @@ -181,17 +198,17 @@ jobs: DEBIAN_FRONTEND: noninteractive run: | # spot - SPOT_VERSION=2.14.2 - URL=https://download.opensuse.org/repositories/home:/adl/Debian_12/amd64 - wget ${URL}/libbddx0_${SPOT_VERSION}.0-1_amd64.deb - wget ${URL}/libspotgen0_${SPOT_VERSION}.0-1_amd64.deb - wget ${URL}/libspot0_${SPOT_VERSION}.0-1_amd64.deb - wget ${URL}/spot_${SPOT_VERSION}.0-1_amd64.deb - sudo dpkg -i libbddx0_${SPOT_VERSION}.0-1_amd64.deb libspotgen0_${SPOT_VERSION}.0-1_amd64.deb libspot0_${SPOT_VERSION}.0-1_amd64.deb spot_${SPOT_VERSION}.0-1_amd64.deb + SPOT_VERSION=2.14.3.16 + URL=https://www.lre.epita.fr/repo/debian/stable/ + wget ${URL}/libbddx0_${SPOT_VERSION}-1_amd64.deb + wget ${URL}/libspotgen0_${SPOT_VERSION}-1_amd64.deb + wget ${URL}/libspot0_${SPOT_VERSION}-1_amd64.deb + wget ${URL}/spot_${SPOT_VERSION}-1_amd64.deb + sudo dpkg -i libbddx0_${SPOT_VERSION}-1_amd64.deb libspotgen0_${SPOT_VERSION}-1_amd64.deb libspot0_${SPOT_VERSION}-1_amd64.deb spot_${SPOT_VERSION}-1_amd64.deb - name: Confirm ltl2tgba is available and log the version installed run: ltl2tgba --version - name: Get the ebmc binary - uses: actions/download-artifact@v5 + uses: actions/download-artifact@v7 with: name: ebmc-binary path: ebmc @@ -207,9 +224,9 @@ jobs: runs-on: ubuntu-24.04 needs: check-ubuntu-24_04-make-clang steps: - - uses: actions/checkout@v5 + - uses: actions/checkout@v6 - name: Get the ebmc binary - uses: actions/download-artifact@v5 + uses: actions/download-artifact@v7 with: name: ebmc-binary path: ebmc @@ -218,7 +235,7 @@ jobs: - name: ebmc on Hazard3 run: PATH=$PATH:$PWD/ebmc examples/Hazard3/Hazard3-ebmc.sh - name: Get the vlindex binary - uses: actions/download-artifact@v5 + uses: actions/download-artifact@v7 with: name: vlindex-binary path: vlindex @@ -245,13 +262,13 @@ jobs: # yum config-manager --set-enabled powertools # yum install glibc-static libstdc++-static - name: cache for ccache - uses: actions/cache@v4 + uses: actions/cache@v5 with: path: /github/home/.cache/ccache save-always: true key: ${{ runner.os }}-centos8-make-gcc-${{ github.ref }}-${{ github.sha }}-PR restore-keys: ${{ runner.os }}-centos8-make-gcc- - - uses: actions/checkout@v5 + - uses: actions/checkout@v6 with: submodules: recursive - name: Zero ccache stats and limit in size @@ -281,7 +298,7 @@ jobs: check-macos-15-make-clang: runs-on: macos-15 steps: - - uses: actions/checkout@v5 + - uses: actions/checkout@v6 with: submodules: recursive - name: Fetch dependencies @@ -289,7 +306,7 @@ jobs: - name: Confirm z3 solver is available and log the version installed run: z3 --version - name: Prepare ccache - uses: actions/cache@v4 + uses: actions/cache@v5 with: save-always: true path: .ccache @@ -331,7 +348,7 @@ jobs: name: Emscripten build runs-on: ubuntu-24.04 steps: - - uses: actions/checkout@v5 + - uses: actions/checkout@v6 with: submodules: recursive - name: Fetch dependencies @@ -340,10 +357,15 @@ jobs: # user input DEBIAN_FRONTEND: noninteractive run: | - sudo apt-get update - sudo apt-get install --no-install-recommends -yq emscripten flex bison libxml2-utils cpanminus ccache + sudo apt-get remove --purge man-db + packages_to_install="emscripten flex bison libxml2-utils cpanminus ccache" + if ! sudo apt-get install --no-install-recommends -yq $packages_to_install ; then + # retry after updating package indices + sudo apt-get update + sudo apt-get install --no-install-recommends -yq $packages_to_install + fi - name: Install node.js 23 - uses: actions/setup-node@v5 + uses: actions/setup-node@v6 with: node-version: 23 - name: Install emscripten @@ -357,7 +379,7 @@ jobs: source ./emsdk_env.sh emcc --version - name: Prepare ccache - uses: actions/cache@v4 + uses: actions/cache@v5 with: path: .ccache save-always: true @@ -409,7 +431,7 @@ jobs: env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} steps: - - uses: actions/checkout@v5 + - uses: actions/checkout@v6 with: submodules: recursive - name: Setup MSBuild @@ -433,7 +455,7 @@ jobs: - name: Initialise Developer Command Line uses: ilammy/msvc-dev-cmd@v1 - name: Prepare ccache - uses: actions/cache@v4 + uses: actions/cache@v5 with: save-always: true path: .ccache @@ -469,7 +491,7 @@ jobs: runs-on: ubuntu-24.04 needs: check-ubuntu-24_04-make-clang steps: - - uses: actions/checkout@v5 + - uses: actions/checkout@v6 with: submodules: recursive - name: Fetch dependencies @@ -478,22 +500,27 @@ jobs: # user input DEBIAN_FRONTEND: noninteractive run: | - sudo apt-get update - sudo apt-get install --no-install-recommends -yq z3 + sudo apt-get remove --purge man-db + packages_to_install="z3" + if ! sudo apt-get install --no-install-recommends -yq $packages_to_install ; then + # retry after updating package indices + sudo apt-get update + sudo apt-get install --no-install-recommends -yq $packages_to_install + fi - name: Confirm z3 solver is available and log the version installed run: z3 --version - name: Get the ebmc binary - uses: actions/download-artifact@v5 + uses: actions/download-artifact@v7 with: name: ebmc-binary path: bin - name: Get the hw-cbmc binary - uses: actions/download-artifact@v5 + uses: actions/download-artifact@v7 with: name: hw-cbmc-binary path: bin - name: Get the vlindex binary - uses: actions/download-artifact@v5 + uses: actions/download-artifact@v7 with: name: vlindex-binary path: bin diff --git a/.github/workflows/syntax-checks.yaml b/.github/workflows/syntax-checks.yaml index 08c86e462..b84ebdc38 100644 --- a/.github/workflows/syntax-checks.yaml +++ b/.github/workflows/syntax-checks.yaml @@ -8,7 +8,7 @@ jobs: check-clang-format: runs-on: ubuntu-24.04 steps: - - uses: actions/checkout@v5 + - uses: actions/checkout@v6 with: submodules: recursive fetch-depth: 0 @@ -18,8 +18,13 @@ jobs: # user input DEBIAN_FRONTEND: noninteractive run: | - sudo apt-get update - sudo apt-get install --no-install-recommends -yq clang-format-15 + sudo apt-get remove --purge man-db + packages_to_install="clang-format-15" + if ! sudo apt-get install --no-install-recommends -yq $packages_to_install ; then + # retry after updating package indices + sudo apt-get update + sudo apt-get install --no-install-recommends -yq $packages_to_install + fi - name: Check updated lines of code match clang-format-15 style env: BASE_BRANCH: ${{ github.base_ref }} diff --git a/CHANGELOG b/CHANGELOG index b137b209d..9895063dc 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,3 +1,21 @@ +# EBMC 5.9 + +* Verilog: fix for four-valued | and & +* Verilog: fix for typed parameter ports +* SystemVerilog: fix for type parameters +* SystemVerilog: type parameter ports +* SMV: word constants +* SMV: IVAR declarations +* SMV: bit selection operator + +# EBMC 5.8 + +* AIG/netlist engine: fix for conversion of extract bits operator +* Verilog: semantic fix for output register ports +* SystemVerilog: cover sequence +* SystemVerilog: labeled immediate assert/assume/cover statements +* SystemVerilog: semantics fix for explicit casts + # EBMC 5.7 * Verilog: --initial-zero changes the default value from nondet to zero @@ -5,6 +23,7 @@ * Verilog: fix for named generate blocks * Verilog: $onehot and $onehot0 are now elaboration-time constant * Verilog: $isunknown +* Verilog: fix for semantics of assignment contexts * SystemVerilog: fix for #-# and #=# for empty matches * SystemVerilog: fix for |-> and |=> for empty matches * SystemVerilog: ref module port direction diff --git a/Formula/ebmc@5.7.rb b/Formula/ebmc@5.7.rb new file mode 100644 index 000000000..4200eae3a --- /dev/null +++ b/Formula/ebmc@5.7.rb @@ -0,0 +1,24 @@ +class Ebmc < Formula + desc "Model Checker for SystemVerilog" + homepage "https://www.cprover.org/ebmc/" + url "https://github.com/diffblue/hw-cbmc.git", + tag: "ebmc-5.7", + revision: "953ccfa6092115594a28b43c87e27a6f22b2f192" + version "5.7" + license "BSD-3-Clause" + + uses_from_macos "flex" => :build + uses_from_macos "curl" => :build + depends_on "bison" => :build + + def install + system "make", "-C", "lib/cbmc/src", "minisat2-download" + system "make", "-C", "src" + system "mkdir", "-p", "#{prefix}/usr/bin" + system "cp", "src/ebmc/ebmc", "#{prefix}/usr/bin/" + end + + test do + system "make", "-C", "regression/ebmc", "test" + end +end diff --git a/Formula/ebmc@5.8.rb b/Formula/ebmc@5.8.rb new file mode 100644 index 000000000..995dfb6dd --- /dev/null +++ b/Formula/ebmc@5.8.rb @@ -0,0 +1,24 @@ +class Ebmc < Formula + desc "Model Checker for SystemVerilog" + homepage "https://www.cprover.org/ebmc/" + url "https://github.com/diffblue/hw-cbmc.git", + tag: "ebmc-5.8", + revision: "e67715256cd4ac967545bef1025410f676256f5d" + version "5.8" + license "BSD-3-Clause" + + uses_from_macos "flex" => :build + uses_from_macos "curl" => :build + depends_on "bison" => :build + + def install + system "make", "-C", "lib/cbmc/src", "minisat2-download" + system "make", "-C", "src" + system "mkdir", "-p", "#{prefix}/usr/bin" + system "cp", "src/ebmc/ebmc", "#{prefix}/usr/bin/" + end + + test do + system "make", "-C", "regression/ebmc", "test" + end +end diff --git a/lib/cbmc b/lib/cbmc index 5d1438a88..d148ae6e8 160000 --- a/lib/cbmc +++ b/lib/cbmc @@ -1 +1 @@ -Subproject commit 5d1438a883201a8983b1449eb2485df0821c819d +Subproject commit d148ae6e880a3ef167bb71e9ed28169578899dce diff --git a/regression/ebmc-spot/ltl-buechi/implies3.desc b/regression/ebmc-spot/ltl-buechi/implies3.desc new file mode 100644 index 000000000..ee311b162 --- /dev/null +++ b/regression/ebmc-spot/ltl-buechi/implies3.desc @@ -0,0 +1,8 @@ +CORE +implies3.smv +--buechi --bound 5 +^EXIT=0$ +^SIGNAL=0$ +-- +^warning: ignoring +-- diff --git a/regression/ebmc-spot/ltl-buechi/implies3.smv b/regression/ebmc-spot/ltl-buechi/implies3.smv new file mode 100644 index 000000000..f167e032e --- /dev/null +++ b/regression/ebmc-spot/ltl-buechi/implies3.smv @@ -0,0 +1,14 @@ +MODULE main + +VAR x : 0..3; + +ASSIGN + init(x) := 1; + + next(x) := + case + x=3 : 3; + TRUE: x+1; + esac; + +LTLSPEC ! (F x = 1 -> F x = 0) -- should pass diff --git a/regression/ebmc-spot/sva-buechi/cover_sequence1.bmc.desc b/regression/ebmc-spot/sva-buechi/cover_sequence1.bmc.desc index 09ded4191..a733cbc4d 100644 --- a/regression/ebmc-spot/sva-buechi/cover_sequence1.bmc.desc +++ b/regression/ebmc-spot/sva-buechi/cover_sequence1.bmc.desc @@ -1,8 +1,8 @@ CORE ../../verilog/SVA/cover_sequence1.sv --buechi --bound 10 --numbered-trace -^\[main\.p0\] cover \(main\.x == 2 ##1 main\.x == 3 ##1 main\.x == 4\): UNSUPPORTED: not convertible to Buechi$ -^\[main\.p1\] cover \(main\.x == 2 ##1 main\.x == 3 ##1 main\.x == 5\): UNSUPPORTED: not convertible to Buechi$ +^\[main\.p0\] cover \(main\.x == 2 ##1 main\.x == 3 ##1 main\.x == 4\): PROVED$ +^\[main\.p1\] cover \(main\.x == 2 ##1 main\.x == 3 ##1 main\.x == 5\): REFUTED up to bound 10$ ^EXIT=10$ ^SIGNAL=0$ -- diff --git a/regression/ebmc-spot/sva-buechi/cover_sequence2.bmc.desc b/regression/ebmc-spot/sva-buechi/cover_sequence2.bmc.desc index 0dda3d634..52b942489 100644 --- a/regression/ebmc-spot/sva-buechi/cover_sequence2.bmc.desc +++ b/regression/ebmc-spot/sva-buechi/cover_sequence2.bmc.desc @@ -1,10 +1,10 @@ CORE ../../verilog/SVA/cover_sequence2.sv --buechi --bound 5 -^\[main\.p0\] cover \(main\.x == 2 ##1 main\.x == 3 ##1 main\.x == 100\): UNSUPPORTED: not convertible to Buechi$ -^\[main\.p1\] cover \(main\.x == 98 ##1 main\.x == 99 ##1 main\.x == 100\): UNSUPPORTED: not convertible to Buechi$ -^\[main\.p2\] cover \(main\.x == 3 ##1 main\.x == 4 ##1 main\.x == 5\): UNSUPPORTED: not convertible to Buechi$ -^\[main\.p3\] cover \(main\.x == 4 ##1 main\.x == 5 ##1 main\.x == 6\): UNSUPPORTED: not convertible to Buechi$ +^\[main\.p0\] cover \(main\.x == 2 ##1 main\.x == 3 ##1 main\.x == 100\): REFUTED up to bound 5$ +^\[main\.p1\] cover \(main\.x == 98 ##1 main\.x == 99 ##1 main\.x == 100\): REFUTED up to bound 5$ +^\[main\.p2\] cover \(main\.x == 3 ##1 main\.x == 4 ##1 main\.x == 5\): PROVED$ +^\[main\.p3\] cover \(main\.x == 4 ##1 main\.x == 5 ##1 main\.x == 6\): REFUTED up to bound 5$ ^EXIT=10$ ^SIGNAL=0$ -- diff --git a/regression/ebmc-spot/sva-buechi/disable_iff1.bdd.desc b/regression/ebmc-spot/sva-buechi/disable_iff1.bdd.desc index fca389d5d..2cbb853be 100644 --- a/regression/ebmc-spot/sva-buechi/disable_iff1.bdd.desc +++ b/regression/ebmc-spot/sva-buechi/disable_iff1.bdd.desc @@ -1,4 +1,4 @@ -KNOWNBUG +CORE ../../verilog/SVA/disable_iff1.sv --buechi --module main --bdd --numbered-trace ^\[main\.p0\] always \(disable iff \(main.counter == 0\) main\.counter != 0\): PROVED$ diff --git a/regression/ebmc-spot/sva-buechi/if1.k.desc b/regression/ebmc-spot/sva-buechi/if1.k.desc index 2119fbeea..858c53c1d 100644 --- a/regression/ebmc-spot/sva-buechi/if1.k.desc +++ b/regression/ebmc-spot/sva-buechi/if1.k.desc @@ -1,6 +1,6 @@ CORE ../../verilog/SVA/if1.sv ---buechi --k-induction --bound 1 +--buechi --k-induction --bound 2 ^\[main\.p0\] always \(if\(main\.counter == 0\) nexttime main\.counter == 1\): PROVED$ ^\[main\.p1\] always \(if\(main\.counter == 0\) nexttime main\.counter == 1 else nexttime main\.counter == 3\): REFUTED$ ^EXIT=10$ diff --git a/regression/ebmc-spot/sva-buechi/immediate2.desc b/regression/ebmc-spot/sva-buechi/immediate2.desc new file mode 100644 index 000000000..195f6a27c --- /dev/null +++ b/regression/ebmc-spot/sva-buechi/immediate2.desc @@ -0,0 +1,11 @@ +CORE +../../verilog/SVA/immediate2.sv +--buechi +^\[main\.assume\.1\] assume always 0: ASSUMED$ +^\[main\.assert\.2\] always main\.index < 10: PROVED \(.*\)$ +^\[main\.assert\.3\] always 0: REFUTED$ +^EXIT=10$ +^SIGNAL=0$ +-- +^warning: ignoring +-- diff --git a/regression/ebmc-spot/sva-buechi/immediate3.desc b/regression/ebmc-spot/sva-buechi/immediate3.desc new file mode 100644 index 000000000..f3a799bf7 --- /dev/null +++ b/regression/ebmc-spot/sva-buechi/immediate3.desc @@ -0,0 +1,9 @@ +CORE +../../verilog/SVA/immediate3.sv +--buechi +^\[full_adder\.assert\.1\] always \{ full_adder\.carry, full_adder\.sum \} == \{ 1'b0, full_adder\.a \} \+ full_adder\.b \+ full_adder\.c: PROVED \(.*\)$ +^EXIT=0$ +^SIGNAL=0$ +-- +^warning: ignoring +-- diff --git a/regression/ebmc-spot/sva-buechi/initial2.bmc.desc b/regression/ebmc-spot/sva-buechi/initial2.bmc.desc index d7a98733e..dc5b85d87 100644 --- a/regression/ebmc-spot/sva-buechi/initial2.bmc.desc +++ b/regression/ebmc-spot/sva-buechi/initial2.bmc.desc @@ -1,8 +1,8 @@ CORE ../../verilog/SVA/initial2.sv --buechi --module main -^\[main\.assert\.1\] main\.counter == 1: PROVED \(1-induction\)$ -^\[main\.assert\.2\] main\.counter == 2: PROVED \(1-induction\)$ +^\[main\.p0\] main\.counter == 1: PROVED \(1-induction\)$ +^\[main\.p1\] main\.counter == 2: PROVED \(1-induction\)$ ^EXIT=0$ ^SIGNAL=0$ -- diff --git a/regression/ebmc-spot/sva-buechi/initial2.k.desc b/regression/ebmc-spot/sva-buechi/initial2.k.desc index fa0aeab7a..e975119ef 100644 --- a/regression/ebmc-spot/sva-buechi/initial2.k.desc +++ b/regression/ebmc-spot/sva-buechi/initial2.k.desc @@ -1,8 +1,8 @@ CORE ../../verilog/SVA/initial2.sv --buechi --k-induction --bound 1 --module main -^\[main\.assert\.1\] main\.counter == 1: PROVED$ -^\[main\.assert\.2\] main\.counter == 2: PROVED$ +^\[main\.p0\] main\.counter == 1: PROVED$ +^\[main\.p1\] main\.counter == 2: PROVED$ ^EXIT=0$ ^SIGNAL=0$ -- diff --git a/regression/ebmc-spot/sva-buechi/s_eventually2.bmc.desc b/regression/ebmc-spot/sva-buechi/s_eventually2.bmc.desc index 0503d5490..3709ae759 100644 --- a/regression/ebmc-spot/sva-buechi/s_eventually2.bmc.desc +++ b/regression/ebmc-spot/sva-buechi/s_eventually2.bmc.desc @@ -1,4 +1,4 @@ -KNOWNBUG +CORE ../../verilog/SVA/s_eventually2.sv --buechi --module main --bound 20 ^\[main\.p0\] always s_eventually main.reset \|\| main\.counter == 10: PROVED up to bound 20$ @@ -8,4 +8,3 @@ KNOWNBUG -- ^warning: ignoring -- -This gives the wrong answer for main.p0. diff --git a/regression/ebmc-spot/sva-buechi/s_eventually4.desc b/regression/ebmc-spot/sva-buechi/s_eventually4.desc new file mode 100644 index 000000000..c073188b3 --- /dev/null +++ b/regression/ebmc-spot/sva-buechi/s_eventually4.desc @@ -0,0 +1,8 @@ +CORE +../../verilog/SVA/s_eventually4.sv +--buechi --module main --bound 11 +^\[main\.p0\] always \(\(s_eventually main\.counter == 1\) or \(s_eventually main.counter == 10\)\): PROVED up to bound 11$ +^EXIT=0$ +^SIGNAL=0$ +-- +^warning: ignoring diff --git a/regression/ebmc-spot/sva-buechi/sequence2.bmc.desc b/regression/ebmc-spot/sva-buechi/sequence2.bmc.desc index 974f6c1ef..5f44b56c6 100644 --- a/regression/ebmc-spot/sva-buechi/sequence2.bmc.desc +++ b/regression/ebmc-spot/sva-buechi/sequence2.bmc.desc @@ -2,7 +2,7 @@ CORE ../../verilog/SVA/sequence2.sv --buechi --bound 10 ^\[main\.p0] weak\(##\[0:\$\] main\.x == 10\): PROVED up to bound 10$ -^\[main\.p1] strong\(##\[0:\$\] main\.x == 10\): UNSUPPORTED: not convertible to Buechi$ +^\[main\.p1] strong\(##\[0:\$\] main\.x == 10\): UNSUPPORTED: sva_cycle_delay not convertible to Buechi$ ^EXIT=10$ ^SIGNAL=0$ -- diff --git a/regression/ebmc-spot/sva-buechi/sequence3.bmc.desc b/regression/ebmc-spot/sva-buechi/sequence3.bmc.desc new file mode 100644 index 000000000..e09e8a230 --- /dev/null +++ b/regression/ebmc-spot/sva-buechi/sequence3.bmc.desc @@ -0,0 +1,12 @@ +CORE +../../verilog/SVA/sequence3.sv +--buechi --bound 20 --numbered-trace +^\[main\.p0\] strong\(##\[\*\] main\.x == 6\): UNSUPPORTED: sva_cycle_delay_star not convertible to Buechi$ +^\[main\.p1\] strong\(##\[\*\] main\.x == 5\): UNSUPPORTED: sva_cycle_delay_star not convertible to Buechi$ +^\[main\.p2\] strong\(##\[\+\] main\.x == 0\): UNSUPPORTED: sva_cycle_delay_plus not convertible to Buechi$ +^\[main\.p3\] strong\(##\[\+\] main\.x == 5\): UNSUPPORTED: sva_cycle_delay_plus not convertible to Buechi$ +^EXIT=10$ +^SIGNAL=0$ +-- +^warning: ignoring +-- diff --git a/regression/ebmc-spot/sva-buechi/sequence_and1.bdd.desc b/regression/ebmc-spot/sva-buechi/sequence_and1.bdd.desc new file mode 100644 index 000000000..43518554e --- /dev/null +++ b/regression/ebmc-spot/sva-buechi/sequence_and1.bdd.desc @@ -0,0 +1,13 @@ +CORE +../../verilog/SVA/sequence_and1.sv +--buechi --bdd +^\[main\.p0\] main\.x == 0 and main\.x == 1: REFUTED$ +^\[main\.p1\] strong\(main\.x == 0 and main\.x == 1\): REFUTED$ +^\[main\.p2\] main\.x == 0 and \(nexttime main\.x == 1\): PROVED$ +^\[main\.p3\] \(nexttime main\.x == 1\) and main\.x == 0: PROVED$ +^\[main\.p4\] \(main\.x == 0 and main\.x != 10\) |=> main\.x == 1: PROVED$ +^EXIT=10$ +^SIGNAL=0$ +-- +^warning: ignoring +-- diff --git a/regression/ebmc-spot/sva-buechi/sequence_and1.bmc.desc b/regression/ebmc-spot/sva-buechi/sequence_and1.bmc.desc new file mode 100644 index 000000000..0f866e2db --- /dev/null +++ b/regression/ebmc-spot/sva-buechi/sequence_and1.bmc.desc @@ -0,0 +1,13 @@ +CORE +../../verilog/SVA/sequence_and1.sv +--buechi --bound 5 +^\[main\.p0\] main\.x == 0 and main\.x == 1: REFUTED$ +^\[main\.p1\] strong\(main\.x == 0 and main\.x == 1\): REFUTED$ +^\[main\.p2\] main\.x == 0 and \(nexttime main\.x == 1\): PROVED up to bound \d+$ +^\[main\.p3\] \(nexttime main\.x == 1\) and main\.x == 0: PROVED up to bound \d+$ +^\[main\.p4\] \(main\.x == 0 and main\.x != 10\) |=> main\.x == 1: PROVED up to bound \d+$ +^EXIT=10$ +^SIGNAL=0$ +-- +^warning: ignoring +-- diff --git a/regression/ebmc-spot/sva-buechi/sequence_repetition1.bmc.desc b/regression/ebmc-spot/sva-buechi/sequence_repetition1.bmc.desc index 5b64f65ef..e9afa1219 100644 --- a/regression/ebmc-spot/sva-buechi/sequence_repetition1.bmc.desc +++ b/regression/ebmc-spot/sva-buechi/sequence_repetition1.bmc.desc @@ -2,11 +2,11 @@ CORE ../../verilog/SVA/sequence_repetition1.sv --buechi --bound 10 ^\[.*\] main\.half_x == 0 \[\*2\]: PROVED up to bound 10$ -^\[.*\] main\.half_x == 0 \[->2\]: UNSUPPORTED: not convertible to Buechi$ -^\[.*\] main\.half_x == 0 \[=2\]: UNSUPPORTED: not convertible to Buechi$ +^\[.*\] main\.half_x == 0 \[->2\]: UNSUPPORTED: sva_sequence_goto_repetition not convertible to Buechi$ +^\[.*\] main\.half_x == 0 \[=2\]: UNSUPPORTED: sva_sequence_non_consecutive_repetition not convertible to Buechi$ ^\[.*\] main\.x == 0 \[\*2\]: REFUTED$ -^\[.*\] main\.x == 0 \[->2\]: UNSUPPORTED: not convertible to Buechi$ -^\[.*\] main\.x == 0 \[=2\]: UNSUPPORTED: not convertible to Buechi$ +^\[.*\] main\.x == 0 \[->2\]: UNSUPPORTED: sva_sequence_goto_repetition not convertible to Buechi$ +^\[.*\] main\.x == 0 \[=2\]: UNSUPPORTED: sva_sequence_non_consecutive_repetition not convertible to Buechi$ ^EXIT=10$ ^SIGNAL=0$ -- diff --git a/regression/ebmc-spot/sva-buechi/sequence_repetition2.bmc.desc b/regression/ebmc-spot/sva-buechi/sequence_repetition2.bmc.desc new file mode 100644 index 000000000..5ab8f8552 --- /dev/null +++ b/regression/ebmc-spot/sva-buechi/sequence_repetition2.bmc.desc @@ -0,0 +1,17 @@ +CORE +../../verilog/SVA/sequence_repetition2.sv +--buechi --bound 10 +^\[main\.p0\] main\.x == 0 \[\*\]: PROVED up to bound 10$ +^\[main\.p1\] \(main\.x == 0 \[\+\]\) #=# main\.x == 1: PROVED up to bound 10$ +^\[main\.p2\] main\.x == 0 \[\+\]: PROVED up to bound 10$ +^\[main\.p3\] main\.half_x == 0 \[\*\]: PROVED up to bound 10$ +^\[main\.p4\] main\.x == 1 \[\*\]: REFUTED$ +^\[main\.p5\] 0 \[\*\]: REFUTED$ +^\[main\.p6\] main\.x == 1 \[\+\]: REFUTED$ +^\[main\.p7\] \(main\.x == 0 \[\+\]\) #-# main\.x == 1: REFUTED$ +^\[main\.p8\] 0 \[\+\]: REFUTED$ +^EXIT=10$ +^SIGNAL=0$ +-- +^warning: ignoring +-- diff --git a/regression/ebmc-spot/sva-buechi/sequence_repetition3.bdd.desc b/regression/ebmc-spot/sva-buechi/sequence_repetition3.bdd.desc new file mode 100644 index 000000000..3db6808b6 --- /dev/null +++ b/regression/ebmc-spot/sva-buechi/sequence_repetition3.bdd.desc @@ -0,0 +1,11 @@ +CORE +../../verilog/SVA/sequence_repetition3.sv +--buechi --bdd +^\[main\.p0\] \(main\.x == 0 \[\*1\]\) #=# \(main\.x == 1 \[\*1\]\): PROVED$ +^\[main\.p1\] \(main\.half_x == 0 \[\*2\]\) #=# \(main\.half_x == 1 \[\*2\]\): PROVED$ +^\[main\.p2\] main\.half_x == 0 \[\*3\]: REFUTED$ +^EXIT=10$ +^SIGNAL=0$ +-- +^warning: ignoring +-- diff --git a/regression/ebmc-spot/sva-buechi/sequence_throughout1.desc b/regression/ebmc-spot/sva-buechi/sequence_throughout1.desc index a40e404fe..11eed1555 100644 --- a/regression/ebmc-spot/sva-buechi/sequence_throughout1.desc +++ b/regression/ebmc-spot/sva-buechi/sequence_throughout1.desc @@ -1,12 +1,11 @@ CORE ../../verilog/SVA/sequence_throughout1.sv --buechi --bound 10 -^error: failed to convert sva_sequence_throughout$ -^EXIT=6$ +^\[main\.p0\] main\.x >= 0 throughout \(main\.x == 0 ##1 main\.x == 1 ##1 main\.x == 2\): UNSUPPORTED: sva_sequence_throughout not convertible to Buechi$ +^\[main\.p1\] main\.x <= 1 throughout \(main\.x == 0 ##1 main\.x == 1 ##1 main\.x == 2\): UNSUPPORTED: sva_sequence_throughout not convertible to Buechi$ +^\[main\.p2\] 1 throughout \(main\.x == 0 ##1 main\.x == 1 ##1 main\.x == 3\): UNSUPPORTED: sva_sequence_throughout not convertible to Buechi$ +^EXIT=10$ ^SIGNAL=0$ -- -^\[main\.p0\] main\.x >= 0 throughout \(main\.x == 0 ##1 main\.x == 1 ##1 main\.x == 2\): PROVED up to bound 10$ -^\[main\.p1\] main\.x <= 1 throughout \(main\.x == 0 ##1 main\.x == 1 ##1 main\.x == 2\): REFUTED$ -^\[main\.p2\] 1 throughout \(main\.x == 0 ##1 main\.x == 1 ##1 main\.x == 3\): REFUTED$ ^warning: ignoring -- diff --git a/regression/ebmc-spot/sva-buechi/sequence_within1.desc b/regression/ebmc-spot/sva-buechi/sequence_within1.desc index 7e842c87a..7b0a3af54 100644 --- a/regression/ebmc-spot/sva-buechi/sequence_within1.desc +++ b/regression/ebmc-spot/sva-buechi/sequence_within1.desc @@ -1,14 +1,13 @@ CORE ../../verilog/SVA/sequence_within1.sv --buechi --bound 20 -^error: failed to convert sva_sequence_within$ -^EXIT=6$ +^\[main\.p0\] main\.x == 0 within main\.x == 1: UNSUPPORTED: sva_sequence_within not convertible to Buechi$ +^\[main\.p1\] main\.x == 0 within \(##10 1\): UNSUPPORTED: sva_sequence_within not convertible to Buechi$ +^\[main\.p2\] main\.x == 5 within \(##10 1\): UNSUPPORTED: sva_sequence_within not convertible to Buechi$ +^\[main\.p3\] main\.x == 10 within \(##10 1\): UNSUPPORTED: sva_sequence_within not convertible to Buechi$ +^\[main\.p4\] main\.x == 11 within \(##10 1\): UNSUPPORTED: sva_sequence_within not convertible to Buechi$ +^EXIT=10$ ^SIGNAL=0$ -- -^\[main\.p0\] main\.x == 0 within main\.x == 1: REFUTED$ -^\[main\.p1\] main\.x == 0 within \(##10 1\): PROVED up to bound 20$ -^\[main\.p2\] main\.x == 5 within \(##10 1\): PROVED up to bound 20$ -^\[main\.p3\] main\.x == 10 within \(##10 1\): PROVED up to bound 20$ -^\[main\.p4\] main\.x == 11 within \(##10 1\): REFUTED$ ^warning: ignoring -- diff --git a/regression/ebmc-spot/sva-buechi/strong1.desc b/regression/ebmc-spot/sva-buechi/strong1.desc index aee695e79..4836a4e3b 100644 --- a/regression/ebmc-spot/sva-buechi/strong1.desc +++ b/regression/ebmc-spot/sva-buechi/strong1.desc @@ -1,7 +1,7 @@ CORE ../../verilog/SVA/strong1.sv --buechi --bound 4 -^\[main\.p0\] strong\(##\[0:9\] main\.x == 5\): UNSUPPORTED: not convertible to Buechi$ +^\[main\.p0\] strong\(##\[0:9\] main\.x == 5\): UNSUPPORTED: sva_cycle_delay not convertible to Buechi$ ^EXIT=10$ ^SIGNAL=0$ -- diff --git a/regression/ebmc-spot/sva-buechi/system_verilog_assertion1.desc b/regression/ebmc-spot/sva-buechi/system_verilog_assertion1.desc new file mode 100644 index 000000000..5cc37fc40 --- /dev/null +++ b/regression/ebmc-spot/sva-buechi/system_verilog_assertion1.desc @@ -0,0 +1,8 @@ +CORE +../../verilog/SVA/system_verilog_assertion1.sv +--buechi --module main --bound 20 --trace +^EXIT=10$ +^SIGNAL=0$ +^Counterexample:$ +-- +^warning: ignoring diff --git a/regression/ebmc-spot/sva-buechi/system_verilog_assertion2.desc b/regression/ebmc-spot/sva-buechi/system_verilog_assertion2.desc new file mode 100644 index 000000000..281dd6507 --- /dev/null +++ b/regression/ebmc-spot/sva-buechi/system_verilog_assertion2.desc @@ -0,0 +1,9 @@ +CORE +../../verilog/SVA/system_verilog_assertion2.sv +--buechi --module main --bound 20 --trace +^EXIT=10$ +^SIGNAL=0$ +^Counterexample:$ +^\[main\.my_label\] .* REFUTED$ +-- +^warning: ignoring diff --git a/regression/ebmc-spot/sva-buechi/system_verilog_assertion4.desc b/regression/ebmc-spot/sva-buechi/system_verilog_assertion4.desc new file mode 100644 index 000000000..8b1fab46a --- /dev/null +++ b/regression/ebmc-spot/sva-buechi/system_verilog_assertion4.desc @@ -0,0 +1,8 @@ +CORE +../../verilog/SVA/system_verilog_assertion4.sv +--buechi --module main --bound 10 +^\[main\.p11\] always \(main\.x == 0 \|-> \(\(##1 main\.x == 1\) and \(not \(##2 main\.x == 3\)\)\)\): PROVED up to bound 10$ +^EXIT=0$ +^SIGNAL=0$ +-- +^warning: ignoring diff --git a/regression/ebmc-spot/sva-buechi/unbounded1.desc b/regression/ebmc-spot/sva-buechi/unbounded1.desc index 0b0841f64..6fde0df12 100644 --- a/regression/ebmc-spot/sva-buechi/unbounded1.desc +++ b/regression/ebmc-spot/sva-buechi/unbounded1.desc @@ -1,7 +1,7 @@ CORE ../../verilog/SVA/unbounded1.sv --buechi --module main --bound 1 -^error: failed to convert sva_cycle_delay$ -^EXIT=6$ +^\[.*\] always \(main\.a ##\[0:main\.upper\] main\.b\): UNSUPPORTED: sva_cycle_delay not convertible to Buechi$ +^EXIT=10$ ^SIGNAL=0$ -- diff --git a/regression/ebmc-spot/sva-buechi/weak1.desc b/regression/ebmc-spot/sva-buechi/weak1.desc new file mode 100644 index 000000000..388b0fe8a --- /dev/null +++ b/regression/ebmc-spot/sva-buechi/weak1.desc @@ -0,0 +1,9 @@ +CORE +../../verilog/SVA/weak1.sv +--buechi --bound 20 +^\[main\.p0\] weak\(##\[0:9\] main\.x == 100\): REFUTED$ +^EXIT=10$ +^SIGNAL=0$ +-- +^warning: ignoring +-- diff --git a/regression/ebmc/reset-command-line-option1/test.desc b/regression/ebmc/CLI/reset1.desc similarity index 87% rename from regression/ebmc/reset-command-line-option1/test.desc rename to regression/ebmc/CLI/reset1.desc index b56303c9f..f7fd20981 100644 --- a/regression/ebmc/reset-command-line-option1/test.desc +++ b/regression/ebmc/CLI/reset1.desc @@ -1,5 +1,5 @@ CORE -main.sv +reset1.sv --module top --bound 10 --reset reset_n ^EXIT=0$ ^SIGNAL=0$ diff --git a/regression/ebmc/reset-command-line-option1/main.sv b/regression/ebmc/CLI/reset1.sv similarity index 100% rename from regression/ebmc/reset-command-line-option1/main.sv rename to regression/ebmc/CLI/reset1.sv diff --git a/regression/ebmc/CLI/reset2.desc b/regression/ebmc/CLI/reset2.desc new file mode 100644 index 000000000..fd8cd275b --- /dev/null +++ b/regression/ebmc/CLI/reset2.desc @@ -0,0 +1,7 @@ +CORE +reset2.sv +--module top --bound 10 --reset ~reset_n +^\[top\.p1\] always \(disable iff \(!top\.reset_n\) top\.data >= 0 && top\.data <= 10\): PROVED .*$ +^EXIT=0$ +^SIGNAL=0$ +-- diff --git a/regression/ebmc/CLI/reset2.sv b/regression/ebmc/CLI/reset2.sv new file mode 100644 index 000000000..7b1e27a5e --- /dev/null +++ b/regression/ebmc/CLI/reset2.sv @@ -0,0 +1,15 @@ +module top(input reset_n, clk); + + reg [7:0] data; + + always @(posedge clk) begin + if(!reset_n) + data = 0; + else if(data != 10) + data++; + end + + // the below holds if the design is reset properly + p1: assert property (disable iff (!reset_n) data >=0 && data <= 10); + +endmodule diff --git a/regression/ebmc/CLI/show-modules-smv.desc b/regression/ebmc/CLI/show-modules-smv.desc new file mode 100644 index 000000000..87703843d --- /dev/null +++ b/regression/ebmc/CLI/show-modules-smv.desc @@ -0,0 +1,24 @@ +CORE +show-modules-smv.smv +--show-modules +activate-multi-line-match +Module 1: + Location: file show-modules-smv\.smv line 3 + Mode: SMV + Identifier: smv::main + Name: main + +Module 2: + Location: file show-modules-smv\.smv line 8 + Mode: SMV + Identifier: smv::bar + Name: bar + +Module 3: + Location: file show-modules-smv\.smv line 13 + Mode: SMV + Identifier: smv::foo + Name: foo +^EXIT=0$ +^SIGNAL=0$ +-- diff --git a/regression/ebmc/CLI/show-modules-smv.smv b/regression/ebmc/CLI/show-modules-smv.smv new file mode 100644 index 000000000..e046990d9 --- /dev/null +++ b/regression/ebmc/CLI/show-modules-smv.smv @@ -0,0 +1,15 @@ +-- from the NuSMV 2.7 manual + +MODULE main + VAR + a : bar; + m : foo(a); + +MODULE bar + VAR + q : boolean; + p : boolean; + +MODULE foo(c) + DEFINE + flag := c.q | c.p; diff --git a/regression/ebmc/smv-netlist/s_until1.desc b/regression/ebmc/smv-netlist/s_until1.desc index b491f34dc..ad604fa01 100644 --- a/regression/ebmc/smv-netlist/s_until1.desc +++ b/regression/ebmc/smv-netlist/s_until1.desc @@ -1,8 +1,8 @@ CORE s_until1.sv --smv-netlist -^LTLSPEC \(\!node144\) U node151$ -^LTLSPEC \(TRUE\) U node158$ +^LTLSPEC \(\!node144\) U node51$ +^LTLSPEC TRUE U node151$ ^EXIT=0$ ^SIGNAL=0$ -- diff --git a/regression/ebmc/smv-netlist/smv1.desc b/regression/ebmc/smv-netlist/smv1.desc index caaa7e348..28e711724 100644 --- a/regression/ebmc/smv-netlist/smv1.desc +++ b/regression/ebmc/smv-netlist/smv1.desc @@ -5,6 +5,8 @@ smv1.smv ^VAR smv\.main\.var\.x: boolean;$ ^ASSIGN next\(smv\.main\.var\.x\):=\!smv\.main\.var\.x;$ ^INIT !smv\.main\.var\.x$ +^LTLSPEC G F smv\.main\.var\.x$ +^CTLSPEC smv\.main\.var\.x <-> \!AX smv\.main\.var\.x$ ^EXIT=0$ ^SIGNAL=0$ -- diff --git a/regression/ebmc/smv-netlist/smv1.smv b/regression/ebmc/smv-netlist/smv1.smv index de6109f2e..a37930340 100644 --- a/regression/ebmc/smv-netlist/smv1.smv +++ b/regression/ebmc/smv-netlist/smv1.smv @@ -7,3 +7,4 @@ ASSIGN init(x):=FALSE; LTLSPEC G F x +CTLSPEC x <-> ! AX x diff --git a/regression/ebmc/smv-netlist/verilog2.desc b/regression/ebmc/smv-netlist/verilog2.desc new file mode 100644 index 000000000..04061ef65 --- /dev/null +++ b/regression/ebmc/smv-netlist/verilog2.desc @@ -0,0 +1,7 @@ +CORE +verilog2.sv +--smv-netlist +^EXIT=0$ +^SIGNAL=0$ +-- +-- diff --git a/regression/ebmc/smv-netlist/verilog2.sv b/regression/ebmc/smv-netlist/verilog2.sv new file mode 100644 index 000000000..f4c7425cd --- /dev/null +++ b/regression/ebmc/smv-netlist/verilog2.sv @@ -0,0 +1,4 @@ +module main; + wire [7:0] some_wire; + assign some_wire[7:0] = 0; +endmodule diff --git a/regression/ebmc/smv-netlist/verilog3.desc b/regression/ebmc/smv-netlist/verilog3.desc new file mode 100644 index 000000000..37a0b22e7 --- /dev/null +++ b/regression/ebmc/smv-netlist/verilog3.desc @@ -0,0 +1,5 @@ +CORE +verilog3.sv +--smv-netlist +^EXIT=0$ +^SIGNAL=0$ diff --git a/regression/ebmc/smv-netlist/verilog3.sv b/regression/ebmc/smv-netlist/verilog3.sv new file mode 100644 index 000000000..514292ca5 --- /dev/null +++ b/regression/ebmc/smv-netlist/verilog3.sv @@ -0,0 +1,5 @@ +module main; + wire [7:0] some_wire; + wire [31:0] something_else; + assign something_else = some_wire[7:1]; +endmodule diff --git a/regression/ebmc/smv-word-level/verilog1.desc b/regression/ebmc/smv-word-level/verilog1.desc index d4dfef295..2c9a6ebca 100644 --- a/regression/ebmc/smv-word-level/verilog1.desc +++ b/regression/ebmc/smv-word-level/verilog1.desc @@ -4,7 +4,7 @@ verilog1.sv ^MODULE main$ ^VAR x : unsigned word\[32\];$ ^INIT main\.x = 0ud32_0$ -^INVAR Verilog::main\.x_aux0 = main\.x \+ 0ud32_1$ +^INVAR Verilog::main\.x_aux0 = main\.x \+ unsigned\(0sd32_1\)$ ^TRANS next\(main\.x\) = Verilog::main\.x_aux0$ ^LTLSPEC F main\.x = unsigned\(0sd32_10\)$ ^EXIT=0$ diff --git a/regression/ebmc/smv-word-level/verilog3.desc b/regression/ebmc/smv-word-level/verilog3.desc new file mode 100644 index 000000000..9bd845c25 --- /dev/null +++ b/regression/ebmc/smv-word-level/verilog3.desc @@ -0,0 +1,10 @@ +CORE +verilog3.sv +--smv-word-level +^MODULE main$ +^VAR some_array : array 0\.\.31 of unsigned word\[8\];$ +^TRANS next\(main\.some_array\) = main\.some_array$ +^LTLSPEC G main\.some_array\[resize\(unsigned\(0sd32_0\), 5\)\] = 0ud8_123$ +^EXIT=0$ +^SIGNAL=0$ +-- diff --git a/regression/ebmc/smv-word-level/verilog3.sv b/regression/ebmc/smv-word-level/verilog3.sv new file mode 100644 index 000000000..1deecbe93 --- /dev/null +++ b/regression/ebmc/smv-word-level/verilog3.sv @@ -0,0 +1,8 @@ +module main(input clk); + + // an array of bytes + reg [7:0] some_array [32]; + + assert property (@(posedge clk) some_array[0] == 8'd123); + +endmodule diff --git a/regression/ebmc/smv-word-level/verilog4.desc b/regression/ebmc/smv-word-level/verilog4.desc new file mode 100644 index 000000000..ddac5c5e2 --- /dev/null +++ b/regression/ebmc/smv-word-level/verilog4.desc @@ -0,0 +1,7 @@ +CORE +verilog4.sv +--smv-word-level +^LTLSPEC X X extend\(main\.x\[31:1\], 1\) = unsigned\(0sd32_1\)$ +^EXIT=0$ +^SIGNAL=0$ +-- diff --git a/regression/ebmc/smv-word-level/verilog4.sv b/regression/ebmc/smv-word-level/verilog4.sv new file mode 100644 index 000000000..176e31af0 --- /dev/null +++ b/regression/ebmc/smv-word-level/verilog4.sv @@ -0,0 +1,12 @@ +module main(input clk); + + reg [31:0] x; + + initial x = 0; + + always @(posedge clk) + x = x + 1; + + initial assert property (nexttime[2] x[31:1] == 1); + +endmodule diff --git a/regression/ebmc/smv-word-level/verilog5.desc b/regression/ebmc/smv-word-level/verilog5.desc new file mode 100644 index 000000000..b09fb8d96 --- /dev/null +++ b/regression/ebmc/smv-word-level/verilog5.desc @@ -0,0 +1,9 @@ +CORE +verilog5.sv +--smv-word-level +^INIT ebmc::\$past1@1 = FALSE$ +^TRANS next\(ebmc::\$past1@1\) = main\.in$ +^LTLSPEC G main\.in = \(X ebmc::\$past1@1\)$ +^EXIT=0$ +^SIGNAL=0$ +-- diff --git a/regression/ebmc/smv-word-level/verilog5.sv b/regression/ebmc/smv-word-level/verilog5.sv new file mode 100644 index 000000000..7de3d78ee --- /dev/null +++ b/regression/ebmc/smv-word-level/verilog5.sv @@ -0,0 +1,5 @@ +module main(input clk, input in); + + p1: assert property (in iff s_nexttime $past(in)); + +endmodule diff --git a/regression/ebmc/smv-word-level/verilog6.desc b/regression/ebmc/smv-word-level/verilog6.desc new file mode 100644 index 000000000..c250f58da --- /dev/null +++ b/regression/ebmc/smv-word-level/verilog6.desc @@ -0,0 +1,7 @@ +CORE +verilog6.sv +--smv-word-level +^CTLSPEC 0ud8_1 \+ 0ub6_000000 :: -0sd2_1 = 0ud8_4$ +^EXIT=0$ +^SIGNAL=0$ +-- diff --git a/regression/ebmc/smv-word-level/verilog6.sv b/regression/ebmc/smv-word-level/verilog6.sv new file mode 100644 index 000000000..7fef3bbb8 --- /dev/null +++ b/regression/ebmc/smv-word-level/verilog6.sv @@ -0,0 +1,6 @@ +module main(input clk, input in); + + // The RHS of the addition will be zero-extended + initial p1: assert property (8'b1 + 2'sb11 == 8'b100); + +endmodule diff --git a/regression/smv/CTL/smv_ctlspec3.desc b/regression/smv/CTL/smv_ctlspec3.desc index 47937f045..fb17825d0 100644 --- a/regression/smv/CTL/smv_ctlspec3.desc +++ b/regression/smv/CTL/smv_ctlspec3.desc @@ -1,7 +1,7 @@ -KNOWNBUG +CORE smv_ctlspec3.smv -^file .* line 5: next\(...\) is not allowed here$ +^file .* line 8: next\(...\) is not allowed here$ ^EXIT=2$ ^SIGNAL=0$ -- diff --git a/regression/smv/LTL/smv_ltlspec_X1.desc b/regression/smv/LTL/smv_ltlspec_X1.desc new file mode 100644 index 000000000..fd8f47f86 --- /dev/null +++ b/regression/smv/LTL/smv_ltlspec_X1.desc @@ -0,0 +1,10 @@ +CORE +smv_ltlspec_X1.smv + +^\[.*\] X x & x: REFUTED$ +^\[.*\] X x & x: REFUTED$ +^\[.*\] X \(x & x\): PROVED \(CT=1\)$ +^EXIT=10$ +^SIGNAL=0$ +-- +^warning: ignoring diff --git a/regression/smv/LTL/smv_ltlspec_X1.smv b/regression/smv/LTL/smv_ltlspec_X1.smv new file mode 100644 index 000000000..b389b86eb --- /dev/null +++ b/regression/smv/LTL/smv_ltlspec_X1.smv @@ -0,0 +1,11 @@ +MODULE main + +VAR x : boolean; + +ASSIGN next(x) := TRUE; + init(x) := FALSE; + +-- X binds stronger than & +LTLSPEC X x & x -- should parse as (X x) & x +LTLSPEC (X x) & x -- should fail +LTLSPEC X (x & x) -- should pass diff --git a/regression/smv/define/define2.desc b/regression/smv/define/define2.desc index 50db76004..dfb4457cf 100644 --- a/regression/smv/define/define2.desc +++ b/regression/smv/define/define2.desc @@ -1,8 +1,8 @@ CORE define2.smv -^file .* line 6: variable `x' already declared.*$ -^EXIT=1$ +^file .* line 6: identifier x already used as variable$ +^EXIT=2$ ^SIGNAL=0$ -- -- diff --git a/regression/smv/define/define3.desc b/regression/smv/define/define3.desc index a69176ac9..79214d15d 100644 --- a/regression/smv/define/define3.desc +++ b/regression/smv/define/define3.desc @@ -1,7 +1,7 @@ CORE define3.smv -^file .* line 6: variable x already declared, at file .* line 3$ +^file .* line 6: identifier x already used as define$ ^EXIT=2$ ^SIGNAL=0$ -- diff --git a/regression/smv/define/define4.desc b/regression/smv/define/define4.desc index fbc9008ff..99a900e11 100644 --- a/regression/smv/define/define4.desc +++ b/regression/smv/define/define4.desc @@ -2,7 +2,7 @@ CORE define4.smv ^file .* line 6: variable `x' already defined.*$ -^EXIT=1$ +^EXIT=2$ ^SIGNAL=0$ -- -- diff --git a/regression/smv/define/define8.desc b/regression/smv/define/define8.desc new file mode 100644 index 000000000..5acb877bd --- /dev/null +++ b/regression/smv/define/define8.desc @@ -0,0 +1,8 @@ +CORE +define8.smv + +^file .* line 6: identifier x already used as enum$ +^EXIT=2$ +^SIGNAL=0$ +-- +-- diff --git a/regression/smv/define/define8.smv b/regression/smv/define/define8.smv new file mode 100644 index 000000000..911e2bc37 --- /dev/null +++ b/regression/smv/define/define8.smv @@ -0,0 +1,6 @@ +MODULE main + +VAR some_enum : {x, y, z}; + +-- x is already defined as an enum +DEFINE x := 123; diff --git a/regression/smv/define/define9.desc b/regression/smv/define/define9.desc new file mode 100644 index 000000000..416ce95d3 --- /dev/null +++ b/regression/smv/define/define9.desc @@ -0,0 +1,8 @@ +CORE +define9.smv + +^file .* line 4: identifier x already used as a parameter$ +^EXIT=2$ +^SIGNAL=0$ +-- +-- diff --git a/regression/smv/define/define9.smv b/regression/smv/define/define9.smv new file mode 100644 index 000000000..763e54aad --- /dev/null +++ b/regression/smv/define/define9.smv @@ -0,0 +1,10 @@ +MODULE some-module(x) + +-- x is already declared as a parameter +DEFINE x := 123; + +INIT x = 123 + +MODULE main + +VAR instance : some-module(124); diff --git a/regression/smv/enums/name_collision1.desc b/regression/smv/enums/name_collision1.desc new file mode 100644 index 000000000..4537a9f2f --- /dev/null +++ b/regression/smv/enums/name_collision1.desc @@ -0,0 +1,9 @@ +CORE +name_collision1.smv + +^file .* line 6: identifier red already used as enum$ +^EXIT=2$ +^SIGNAL=0$ +-- +^warning: ignoring +-- diff --git a/regression/smv/enums/name_collision1.smv b/regression/smv/enums/name_collision1.smv new file mode 100644 index 000000000..e84e1c4a5 --- /dev/null +++ b/regression/smv/enums/name_collision1.smv @@ -0,0 +1,6 @@ +MODULE main + +VAR some_var: { red, green, yellow, off }; + +-- identifier already used +VAR red : boolean; diff --git a/regression/smv/enums/name_collision2.desc b/regression/smv/enums/name_collision2.desc new file mode 100644 index 000000000..7a2eb1393 --- /dev/null +++ b/regression/smv/enums/name_collision2.desc @@ -0,0 +1,9 @@ +CORE +name_collision2.smv + +^file .* line 8: identifier red already used as variable$ +^EXIT=2$ +^SIGNAL=0$ +-- +^warning: ignoring +-- diff --git a/regression/smv/enums/name_collision2.smv b/regression/smv/enums/name_collision2.smv new file mode 100644 index 000000000..44430726e --- /dev/null +++ b/regression/smv/enums/name_collision2.smv @@ -0,0 +1,8 @@ +MODULE main + +VAR red : boolean; + +-- The identifier "red" is already used. +-- NuSMV doesn't error this, but yields an error when attempting +-- to use the identifier. +VAR some_var: { red, green, yellow, off }; diff --git a/regression/smv/enums/name_collision3.desc b/regression/smv/enums/name_collision3.desc new file mode 100644 index 000000000..8ae3e5f34 --- /dev/null +++ b/regression/smv/enums/name_collision3.desc @@ -0,0 +1,9 @@ +CORE +name_collision3.smv + +^file .* line 8: identifier red already used as enum$ +^EXIT=2$ +^SIGNAL=0$ +-- +^warning: ignoring +-- diff --git a/regression/smv/enums/name_collision3.smv b/regression/smv/enums/name_collision3.smv new file mode 100644 index 000000000..566350d6b --- /dev/null +++ b/regression/smv/enums/name_collision3.smv @@ -0,0 +1,9 @@ +MODULE submodule + +MODULE main + +VAR some_var: { red, green, yellow, off }; + +-- identifier already used +VAR red : submodule; + diff --git a/regression/smv/expressions/div1.desc b/regression/smv/expressions/div1.desc new file mode 100644 index 000000000..a3e08692c --- /dev/null +++ b/regression/smv/expressions/div1.desc @@ -0,0 +1,8 @@ +CORE +div1.smv + +^file .* line 4: no support for / on integer operands$ +^EXIT=2$ +^SIGNAL=0$ +-- +-- diff --git a/regression/smv/expressions/div1.smv b/regression/smv/expressions/div1.smv new file mode 100644 index 000000000..19e759fe2 --- /dev/null +++ b/regression/smv/expressions/div1.smv @@ -0,0 +1,7 @@ +MODULE main + +-- NuSMV 2.7 manual page 16 +CTLSPEC 7/5 = 1 +CTLSPEC -7/5 = -1 +CTLSPEC 7/-5 = -1 +CTLSPEC -7/-5 = 1 diff --git a/regression/smv/expressions/mod1.desc b/regression/smv/expressions/mod1.desc new file mode 100644 index 000000000..13a26b69f --- /dev/null +++ b/regression/smv/expressions/mod1.desc @@ -0,0 +1,8 @@ +CORE +mod1.smv + +^file .* line 4: no support for % on integer operands$ +^EXIT=2$ +^SIGNAL=0$ +-- +-- diff --git a/regression/smv/expressions/mod1.smv b/regression/smv/expressions/mod1.smv new file mode 100644 index 000000000..5e18bf792 --- /dev/null +++ b/regression/smv/expressions/mod1.smv @@ -0,0 +1,7 @@ +MODULE main + +-- NuSMV 2.7 manual page 16 +CTLSPEC 7 mod 5 = 2 +CTLSPEC -7 mod 5 = -2 +CTLSPEC 7 mod -5 = 2 +CTLSPEC -7 mod -5 = -2 diff --git a/regression/smv/identifiers/complex_identifier1.desc b/regression/smv/identifiers/complex_identifier1.desc new file mode 100644 index 000000000..3d072e2a3 --- /dev/null +++ b/regression/smv/identifiers/complex_identifier1.desc @@ -0,0 +1,7 @@ +CORE +complex_identifier1.smv + +^EXIT=10$ +^SIGNAL=0$ +-- +-- diff --git a/regression/smv/identifiers/complex_identifier1.smv b/regression/smv/identifiers/complex_identifier1.smv new file mode 100644 index 000000000..348ca30f6 --- /dev/null +++ b/regression/smv/identifiers/complex_identifier1.smv @@ -0,0 +1,12 @@ +MODULE main + +-- complex identifiers can use '[...]' and '.' +VAR some_var : boolean; +VAR some_var[3] : boolean; +VAR some_var[4].whatnot : boolean; +VAR some_var[5][2].whatnot : boolean; + +INIT some_var[5][2].whatnot + +-- spaces are ok +INIT some_var [4] . whatnot diff --git a/regression/smv/ivar/ivar1.desc b/regression/smv/ivar/ivar1.desc index e6cb0032c..9eee67cbf 100644 --- a/regression/smv/ivar/ivar1.desc +++ b/regression/smv/ivar/ivar1.desc @@ -1,8 +1,11 @@ CORE ivar1.smv - -^file .* line 3: No support for IVAR declarations$ -^EXIT=1$ +--bound 1 +^\[.*\] some_input: REFUTED$ +^\[.*\] !some_input: REFUTED$ +^\[.*\] X some_input: REFUTED$ +^\[.*\] X !some_input: REFUTED$ +^EXIT=10$ ^SIGNAL=0$ -- -- diff --git a/regression/smv/ivar/ivar1.smv b/regression/smv/ivar/ivar1.smv index eb9ff90a8..f192a80f4 100644 --- a/regression/smv/ivar/ivar1.smv +++ b/regression/smv/ivar/ivar1.smv @@ -1,3 +1,9 @@ MODULE main IVAR some_input : boolean; + +-- these should all fail +LTLSPEC some_input +LTLSPEC !some_input +LTLSPEC X some_input +LTLSPEC X !some_input diff --git a/regression/smv/modules/module_argument1.desc b/regression/smv/modules/module_argument1.desc new file mode 100644 index 000000000..7e6baa5ac --- /dev/null +++ b/regression/smv/modules/module_argument1.desc @@ -0,0 +1,8 @@ +CORE +module_argument1.smv + +^EXIT=10$ +^SIGNAL=0$ +-- +^warning: ignoring +-- diff --git a/regression/smv/modules/module_argument1.smv b/regression/smv/modules/module_argument1.smv new file mode 100644 index 000000000..e046990d9 --- /dev/null +++ b/regression/smv/modules/module_argument1.smv @@ -0,0 +1,15 @@ +-- from the NuSMV 2.7 manual + +MODULE main + VAR + a : bar; + m : foo(a); + +MODULE bar + VAR + q : boolean; + p : boolean; + +MODULE foo(c) + DEFINE + flag := c.q | c.p; diff --git a/regression/smv/modules/module_with_enum1.desc b/regression/smv/modules/module_with_enum1.desc index 65c4a3a1e..c084046a6 100644 --- a/regression/smv/modules/module_with_enum1.desc +++ b/regression/smv/modules/module_with_enum1.desc @@ -1,4 +1,4 @@ -KNOWNBUG +CORE broken-smt-backend module_with_enum1.smv ^EXIT=0$ @@ -6,4 +6,3 @@ module_with_enum1.smv -- ^warning: ignoring -- -The enum literal is not found. diff --git a/regression/smv/modules/module_with_enum2.desc b/regression/smv/modules/module_with_enum2.desc new file mode 100644 index 000000000..adef84fe6 --- /dev/null +++ b/regression/smv/modules/module_with_enum2.desc @@ -0,0 +1,9 @@ +CORE +module_with_enum2.smv + +^file .* line 11: enum a already declared, at file .* line 7$ +^EXIT=2$ +^SIGNAL=0$ +-- +^warning: ignoring +-- diff --git a/regression/smv/modules/module_with_enum2.smv b/regression/smv/modules/module_with_enum2.smv new file mode 100644 index 000000000..31654c080 --- /dev/null +++ b/regression/smv/modules/module_with_enum2.smv @@ -0,0 +1,13 @@ +MODULE main + +VAR sub : my-module; + +-- There is an enum in another module with the same identifier, +-- which is an error! +VAR a : boolean; + +MODULE my-module + +VAR some_enum : { a, b }; + +ASSIGN some_enum := a; diff --git a/regression/smv/modules/parameters1.desc b/regression/smv/modules/parameters1.desc new file mode 100644 index 000000000..ff1cd5797 --- /dev/null +++ b/regression/smv/modules/parameters1.desc @@ -0,0 +1,12 @@ +CORE +parameters1.smv +--show-parse +^ PARAMETERS:$ +^ pa$ +^ pb$ +^ pc$ +^EXIT=0$ +^SIGNAL=0$ +-- +^warning: ignoring +-- diff --git a/regression/smv/modules/parameters1.smv b/regression/smv/modules/parameters1.smv new file mode 100644 index 000000000..cd5af252a --- /dev/null +++ b/regression/smv/modules/parameters1.smv @@ -0,0 +1,3 @@ +MODULE main + +MODULE my-module(pa, pb, pc) diff --git a/regression/smv/modules/parameters2.desc b/regression/smv/modules/parameters2.desc new file mode 100644 index 000000000..2288ee0fa --- /dev/null +++ b/regression/smv/modules/parameters2.desc @@ -0,0 +1,8 @@ +CORE +parameters2.smv + +^EXIT=10$ +^SIGNAL=0$ +-- +^warning: ignoring +-- diff --git a/regression/smv/modules/parameters2.smv b/regression/smv/modules/parameters2.smv new file mode 100644 index 000000000..c024deb9b --- /dev/null +++ b/regression/smv/modules/parameters2.smv @@ -0,0 +1,9 @@ +MODULE main + +MODULE my-module(x) + +-- this is tolerated when the module is not instantiated +CTLSPEC x + 1 + +-- this, too +CTLSPEC something_not_known_at_all diff --git a/regression/smv/modules/self1.desc b/regression/smv/modules/self1.desc new file mode 100644 index 000000000..de780717d --- /dev/null +++ b/regression/smv/modules/self1.desc @@ -0,0 +1,9 @@ +KNOWNBUG +self1.smv + +^EXIT=0$ +^SIGNAL=0$ +-- +^warning: ignoring +-- +This does not parse. diff --git a/regression/smv/modules/self1.smv b/regression/smv/modules/self1.smv new file mode 100644 index 000000000..1a6a715fe --- /dev/null +++ b/regression/smv/modules/self1.smv @@ -0,0 +1,18 @@ +-- from the NuSMV 2.7 manual + +MODULE container(init_value1, init_value2) + VAR c1 : counter(init_value1, self); + VAR c2 : counter(init_value2, self); + +MODULE counter(init_value, my_container) + VAR v: 1..100; + ASSIGN + init(v) := init_value; + DEFINE + greatestCounterInContainer := v >= my_container.c1.v & + v >= my_container.c2.v; + +MODULE main + VAR c : container(14, 7); + SPEC + c.c1.greatestCounterInContainer; diff --git a/regression/smv/modules/trace1.desc b/regression/smv/modules/trace1.desc new file mode 100644 index 000000000..70d04346d --- /dev/null +++ b/regression/smv/modules/trace1.desc @@ -0,0 +1,19 @@ +CORE +trace1.smv +--numbered-trace +^\[.*\] AG \!a\.c\.d: REFUTED$ +^Counterexample with 2 states:$ +^b\.d@0 = FALSE$ +^a\.c\.d@0 = FALSE$ +^a\.c\.d@1 = TRUE$ +^EXIT=10$ +^SIGNAL=0$ +-- +^warning: ignoring +^a@0 = .*$ +^b@0 = .*$ +^a.c@0 = .*$ +^a@1 = .*$ +^b@1 = .*$ +^a.c@1 = .*$ +-- diff --git a/regression/smv/modules/trace1.smv b/regression/smv/modules/trace1.smv new file mode 100644 index 000000000..601534f8d --- /dev/null +++ b/regression/smv/modules/trace1.smv @@ -0,0 +1,12 @@ +MODULE main + VAR a : foo; + VAR b : moo; + +SPEC AG !a.c.d + +MODULE foo + VAR c : moo; + +MODULE moo + VAR d : boolean; + INIT d = FALSE diff --git a/regression/smv/modules/use_before_declaration1.desc b/regression/smv/modules/use_before_declaration1.desc new file mode 100644 index 000000000..6ca5dc549 --- /dev/null +++ b/regression/smv/modules/use_before_declaration1.desc @@ -0,0 +1,8 @@ +CORE broken-smt-backend +use_before_declaration1.smv + +^EXIT=0$ +^SIGNAL=0$ +-- +^warning: ignoring +-- diff --git a/regression/smv/modules/use_before_declaration1.smv b/regression/smv/modules/use_before_declaration1.smv new file mode 100644 index 000000000..a0d3b443b --- /dev/null +++ b/regression/smv/modules/use_before_declaration1.smv @@ -0,0 +1,10 @@ +MODULE main + +-- you can use modules before they are declared +SPEC sub.something = 123 + +VAR sub : my-module; + +MODULE my-module + +DEFINE something := 123; diff --git a/regression/smv/next/assign_next1.desc b/regression/smv/next/assign_next1.desc new file mode 100644 index 000000000..3425a1c5b --- /dev/null +++ b/regression/smv/next/assign_next1.desc @@ -0,0 +1,7 @@ +CORE +assign_next1.smv + +^\[.*\] AG x = y: PROVED .*$ +^EXIT=0$ +^SIGNAL=0$ +-- diff --git a/regression/smv/next/assign_next1.smv b/regression/smv/next/assign_next1.smv new file mode 100644 index 000000000..6df0b75d8 --- /dev/null +++ b/regression/smv/next/assign_next1.smv @@ -0,0 +1,11 @@ +MODULE main + +VAR x : boolean; + y : boolean; + +-- The use of next in a 'next' assignment is allowed. +ASSIGN next(x) := next(y); + +ASSIGN init(x) := y; + +CTLSPEC AG x = y diff --git a/regression/smv/process/process1.desc b/regression/smv/process/process1.desc new file mode 100644 index 000000000..55a48b851 --- /dev/null +++ b/regression/smv/process/process1.desc @@ -0,0 +1,9 @@ +KNOWNBUG +process1.smv + +^EXIT=0$ +^SIGNAL=0$ +-- +^warning: ignoring +-- +This does not parse. diff --git a/regression/smv/process/process1.smv b/regression/smv/process/process1.smv new file mode 100644 index 000000000..bd99854ef --- /dev/null +++ b/regression/smv/process/process1.smv @@ -0,0 +1,9 @@ +-- from the NuSMV 2.7 manual + +MODULE my_module + -- my module definition... + +MODULE main + VAR + p1 : process my_module; + p2 : process my_module; diff --git a/regression/smv/var/already_declared1.desc b/regression/smv/var/already_declared1.desc index 0910f0f55..8d5b4a1c4 100644 --- a/regression/smv/var/already_declared1.desc +++ b/regression/smv/var/already_declared1.desc @@ -1,7 +1,7 @@ CORE already_declared1.smv -^file .* line 6: variable x already declared, at file .* line 3$ +^file .* line 6: identifier x already used as variable$ ^EXIT=2$ ^SIGNAL=0$ -- diff --git a/regression/smv/var/already_declared2.desc b/regression/smv/var/already_declared2.desc index cfacd32a3..51fdcee66 100644 --- a/regression/smv/var/already_declared2.desc +++ b/regression/smv/var/already_declared2.desc @@ -1,7 +1,7 @@ CORE already_declared2.smv -^file .* line 6: variable x already declared, at file .* line 3$ +^file .* line 6: identifier x already used as define$ ^EXIT=2$ ^SIGNAL=0$ -- diff --git a/regression/smv/var/already_declared3.desc b/regression/smv/var/already_declared3.desc index 22e8c3575..33afc32cb 100644 --- a/regression/smv/var/already_declared3.desc +++ b/regression/smv/var/already_declared3.desc @@ -1,7 +1,7 @@ CORE already_declared3.smv -^file .* line 8: variable x already declared, at file .* line 5$ +^file .* line 8: identifier x already used as variable$ ^EXIT=2$ ^SIGNAL=0$ -- diff --git a/regression/smv/var/already_declared4.desc b/regression/smv/var/already_declared4.desc index 9df5fac5c..e9831d8be 100644 --- a/regression/smv/var/already_declared4.desc +++ b/regression/smv/var/already_declared4.desc @@ -1,8 +1,7 @@ -KNOWNBUG +CORE already_declared4.smv ^EXIT=2$ ^SIGNAL=0$ -- -- -This should be errored. diff --git a/regression/smv/var/already_declared5.desc b/regression/smv/var/already_declared5.desc index be316c863..96e218534 100644 --- a/regression/smv/var/already_declared5.desc +++ b/regression/smv/var/already_declared5.desc @@ -1,8 +1,8 @@ -KNOWNBUG +CORE already_declared5.smv +^file .* line 6: identifier x already used as enum$ ^EXIT=2$ ^SIGNAL=0$ -- -- -This crashes. diff --git a/regression/smv/word/bit_selection1.desc b/regression/smv/word/bit_selection1.desc new file mode 100644 index 000000000..c54891e14 --- /dev/null +++ b/regression/smv/word/bit_selection1.desc @@ -0,0 +1,10 @@ +CORE +bit_selection1.smv +--bound 0 +^\[.*\] -0sd7_39\[4:1\] = 0ud4_12: PROVED .*$ +^\[.*\] 0ud3_5\[0:0\] = 0ud1_1: PROVED .*$ +^EXIT=0$ +^SIGNAL=0$ +-- +^warning: ignoring +-- diff --git a/regression/smv/word/bit_selection1.smv b/regression/smv/word/bit_selection1.smv new file mode 100644 index 000000000..d2b82917d --- /dev/null +++ b/regression/smv/word/bit_selection1.smv @@ -0,0 +1,5 @@ +MODULE main + +-- From the NuSMV manual +SPEC 0sb7_1011001[4:1] = 0ub4_1100 +SPEC 0ub3_101[0:0] = 0ub1_1 diff --git a/regression/smv/word/bit_selection2.desc b/regression/smv/word/bit_selection2.desc new file mode 100644 index 000000000..7a3395fcf --- /dev/null +++ b/regression/smv/word/bit_selection2.desc @@ -0,0 +1,7 @@ +CORE +bit_selection2.smv + +^EXIT=0$ +^SIGNAL=0$ +-- +^warning: ignoring diff --git a/regression/smv/word/extractbits1.smv b/regression/smv/word/bit_selection2.smv similarity index 100% rename from regression/smv/word/extractbits1.smv rename to regression/smv/word/bit_selection2.smv diff --git a/regression/smv/word/bitwise1.desc b/regression/smv/word/bitwise1.desc index 618cca9ff..cba35572a 100644 --- a/regression/smv/word/bitwise1.desc +++ b/regression/smv/word/bitwise1.desc @@ -1,12 +1,13 @@ CORE bitwise1.smv -^\[.*\] !\(0ud8_123 = 0ud8_132\): PROVED .*$ -^\[.*\] !\(0sd8_123 = -0sd8_124\): PROVED .*$ +^\[.*\] \(!0ud8_123\) = 0ud8_132: PROVED .*$ +^\[.*\] \(!0sd8_123\) = -0sd8_124: PROVED .*$ ^\[.*\] \(0ud8_123 \& 0ud8_7\) = 0ud8_3: PROVED .*$ ^\[.*\] \(0ud8_123 \| 0ud8_7\) = 0ud8_127: PROVED .*$ ^\[.*\] \(0ud8_123 xor 0ud8_7\) = 0ud8_124: PROVED .*$ ^\[.*\] \(0ud8_123 xnor 0ud8_7\) = 0ud8_131: PROVED .*$ +^\[.*\] \(0ud8_123 -> 0ud8_7\) = 0ud8_135: PROVED .*$ ^\[.*\] \(0ud8_123 <-> 0ud8_7\) = 0ud8_131: PROVED .*$ ^EXIT=0$ ^SIGNAL=0$ diff --git a/regression/smv/word/bitwise1.smv b/regression/smv/word/bitwise1.smv index 77c462b0b..d80dbc400 100644 --- a/regression/smv/word/bitwise1.smv +++ b/regression/smv/word/bitwise1.smv @@ -1,8 +1,8 @@ MODULE main -- negation -SPEC !uwconst(123, 8) = uwconst(132, 8) -SPEC !swconst(123, 8) = swconst(-124, 8) +SPEC (!uwconst(123, 8)) = uwconst(132, 8) +SPEC (!swconst(123, 8)) = swconst(-124, 8) -- and SPEC (uwconst(123, 8) & uwconst(7, 8)) = uwconst(3, 8) @@ -17,7 +17,7 @@ SPEC (uwconst(123, 8) xor uwconst(7, 8)) = uwconst(124, 8) SPEC (uwconst(123, 8) xnor uwconst(7, 8)) = uwconst(131, 8) -- implication ---SPEC (uwconst(123, 8) -> uwconst(7, 8)) = uwconst(135, 8) +SPEC (uwconst(123, 8) -> uwconst(7, 8)) = uwconst(135, 8) -- iff SPEC (uwconst(123, 8) <-> uwconst(7, 8)) = uwconst(131, 8) diff --git a/regression/smv/word/div1.desc b/regression/smv/word/div1.desc new file mode 100644 index 000000000..107e92db7 --- /dev/null +++ b/regression/smv/word/div1.desc @@ -0,0 +1,6 @@ +CORE +div1.smv + +^EXIT=0$ +^SIGNAL=0$ +-- diff --git a/regression/smv/word/div1.smv b/regression/smv/word/div1.smv new file mode 100644 index 000000000..38c49dbe3 --- /dev/null +++ b/regression/smv/word/div1.smv @@ -0,0 +1,7 @@ +MODULE main + +-- bit-vector version of NuSMV 2.7 manual page 16 +CTLSPEC swconst(7, 8)/swconst(5, 8) = swconst(1, 8) +CTLSPEC swconst(-7, 8)/swconst(5, 8) = swconst(-1, 8) +CTLSPEC swconst(7, 8)/swconst(-5, 8) = swconst(-1, 8) +CTLSPEC swconst(-7, 8)/swconst(-5, 8) = swconst(1, 8) diff --git a/regression/smv/word/mod1.desc b/regression/smv/word/mod1.desc new file mode 100644 index 000000000..de2c23ef3 --- /dev/null +++ b/regression/smv/word/mod1.desc @@ -0,0 +1,6 @@ +CORE +mod1.smv + +^EXIT=0$ +^SIGNAL=0$ +-- diff --git a/regression/smv/word/mod1.smv b/regression/smv/word/mod1.smv new file mode 100644 index 000000000..99990dffd --- /dev/null +++ b/regression/smv/word/mod1.smv @@ -0,0 +1,7 @@ +MODULE main + +-- bit-vector version of NuSMV 2.7 manual page 16 +CTLSPEC swconst(7, 8) mod swconst(5, 8) = swconst(2, 8) +CTLSPEC swconst(-7, 8) mod swconst(5, 8) = swconst(-2, 8) +CTLSPEC swconst(7, 8) mod swconst(-5, 8) = swconst(2, 8) +CTLSPEC swconst(-7, 8) mod swconst(-5, 8) = swconst(-2, 8) diff --git a/regression/smv/word/word_constants1.desc b/regression/smv/word/word_constants1.desc new file mode 100644 index 000000000..1313aeb6f --- /dev/null +++ b/regression/smv/word/word_constants1.desc @@ -0,0 +1,7 @@ +CORE +word_constants1.smv +--bound 0 +^EXIT=0$ +^SIGNAL=0$ +-- +^warning: ignoring diff --git a/regression/smv/word/word_constants1.smv b/regression/smv/word/word_constants1.smv new file mode 100644 index 000000000..26a48f971 --- /dev/null +++ b/regression/smv/word/word_constants1.smv @@ -0,0 +1,18 @@ +MODULE main + +SPEC uwconst(123, 8) = 0d8_123; +SPEC uwconst(123, 8) = 0ud8_123; +SPEC uwconst(123, 8) = 0h_7b; +SPEC uwconst(123, 8) = 0uh_7b; +SPEC uwconst(123, 8) = 0o8_173; +SPEC uwconst(123, 8) = 0uo8_173; +SPEC uwconst(123, 8) = 0b_01111011; +SPEC uwconst(123, 8) = 0ub_01111011; +SPEC uwconst(123, 8) = 0b8_1111011; +SPEC uwconst(123, 8) = 0ub8_1111011; + +SPEC swconst(123, 8) = 0sd8_123; +SPEC swconst(123, 8) = 0sh_7b; +SPEC swconst(123, 8) = 0so8_173; +SPEC swconst(123, 8) = 0sb_01111011; +SPEC swconst(123, 8) = 0sb8_1111011; diff --git a/regression/verilog/Makefile b/regression/verilog/Makefile index 68b2eefbf..369d98c6a 100644 --- a/regression/verilog/Makefile +++ b/regression/verilog/Makefile @@ -7,3 +7,6 @@ test: test-z3: @$(TEST_PL) -e -p -c "../../../src/ebmc/ebmc --z3" -X broken-smt-backend + +test-aig: + @$(TEST_PL) -e -p -c "../../../src/ebmc/ebmc --aig" diff --git a/regression/verilog/SVA/assert_else1.desc b/regression/verilog/SVA/assert_else1.desc new file mode 100644 index 000000000..ada76c19d --- /dev/null +++ b/regression/verilog/SVA/assert_else1.desc @@ -0,0 +1,8 @@ +CORE +assert_else1.sv +--module main +^EXIT=10$ +^SIGNAL=0$ +-- +^warning: ignoring +-- diff --git a/regression/verilog/SVA/assert_else1.sv b/regression/verilog/SVA/assert_else1.sv new file mode 100644 index 000000000..99485713c --- /dev/null +++ b/regression/verilog/SVA/assert_else1.sv @@ -0,0 +1,9 @@ +module main(input clk); + + task some_task; + $fatal("property failed"); + endtask; + + assert property (0) else some_task(); + +endmodule diff --git a/regression/verilog/SVA/cover_sequence1.sv b/regression/verilog/SVA/cover_sequence1.sv index 5fcbc9384..fcc2207f1 100644 --- a/regression/verilog/SVA/cover_sequence1.sv +++ b/regression/verilog/SVA/cover_sequence1.sv @@ -7,9 +7,9 @@ module main(input clk); x++; // expected to pass - p0: cover property (x==2 ##1 x==3 ##1 x==4); + p0: cover sequence (x==2 ##1 x==3 ##1 x==4); // expected to fail - p1: cover property (x==2 ##1 x==3 ##1 x==5); + p1: cover sequence (x==2 ##1 x==3 ##1 x==5); endmodule diff --git a/regression/verilog/SVA/cover_sequence2.sv b/regression/verilog/SVA/cover_sequence2.sv index 117316945..473572c2f 100644 --- a/regression/verilog/SVA/cover_sequence2.sv +++ b/regression/verilog/SVA/cover_sequence2.sv @@ -7,15 +7,15 @@ module main(input clk); x++; // expected to fail - p0: cover property (x==2 ##1 x==3 ##1 x==100); + p0: cover sequence (x==2 ##1 x==3 ##1 x==100); // expected to fail until x reaches 100 - p1: cover property (x==98 ##1 x==99 ##1 x==100); + p1: cover sequence (x==98 ##1 x==99 ##1 x==100); // expected to pass once x reaches 5 - p2: cover property (x==3 ##1 x==4 ##1 x==5); + p2: cover sequence (x==3 ##1 x==4 ##1 x==5); // expected to pass once x reaches 6 - p3: cover property (x==4 ##1 x==5 ##1 x==6); + p3: cover sequence (x==4 ##1 x==5 ##1 x==6); endmodule diff --git a/regression/verilog/SVA/cover_sequence3.sv b/regression/verilog/SVA/cover_sequence3.sv index 091240018..b0037fb2a 100644 --- a/regression/verilog/SVA/cover_sequence3.sv +++ b/regression/verilog/SVA/cover_sequence3.sv @@ -7,12 +7,12 @@ module main(input clk); x++; // passes with bound >=9 - p0: cover property (1[*10]); + p0: cover sequence (1[*10]); // passes with bound >=3 - p1: cover property (1[*4:10]); + p1: cover sequence (1[*4:10]); // passes with bound >=4 - p2: cover property (1[*5:10]); + p2: cover sequence (1[*5:10]); endmodule diff --git a/regression/verilog/SVA/cover_sequence4.sv b/regression/verilog/SVA/cover_sequence4.sv index 9c08ffb5a..24fa91fc4 100644 --- a/regression/verilog/SVA/cover_sequence4.sv +++ b/regression/verilog/SVA/cover_sequence4.sv @@ -7,12 +7,12 @@ module main(input clk); x++; // passes with bound >=9 - p0: cover property (1[=10]); + p0: cover sequence (1[=10]); // passes with bound >=3 - p1: cover property (1[=4:10]); + p1: cover sequence (1[=4:10]); // passes with bound >=4 - p2: cover property (1[=5:10]); + p2: cover sequence (1[=5:10]); endmodule diff --git a/regression/verilog/SVA/cover_sequence5.desc b/regression/verilog/SVA/cover_sequence5.desc new file mode 100644 index 000000000..0789e72bf --- /dev/null +++ b/regression/verilog/SVA/cover_sequence5.desc @@ -0,0 +1,9 @@ +KNOWNBUG +cover_sequence5.sv +--bound 10 +^EXIT=10$ +^SIGNAL=0$ +-- +^warning: ignoring +-- +This gives the wrong answer. diff --git a/regression/verilog/SVA/cover_sequence5.sv b/regression/verilog/SVA/cover_sequence5.sv new file mode 100644 index 000000000..38c09492e --- /dev/null +++ b/regression/verilog/SVA/cover_sequence5.sv @@ -0,0 +1,15 @@ +module main(input clk); + + // count up + int x = 0; + + always_ff @(posedge clk) + x++; + + // never passes, owing to disable iff + p0: cover sequence (disable iff (1) 1); + + // passes when reaching x=10 + p1: cover sequence (disable iff (x<10) 1); + +endmodule diff --git a/regression/verilog/SVA/initial2.desc b/regression/verilog/SVA/initial2.desc index 22b6a1662..cd4547272 100644 --- a/regression/verilog/SVA/initial2.desc +++ b/regression/verilog/SVA/initial2.desc @@ -1,8 +1,8 @@ CORE initial2.sv --module main -^\[main\.assert\.1\] main\.counter == 1: PROVED .*$ -^\[main\.assert\.2\] main\.counter == 2: PROVED .*$ +^\[main\.p0\] main\.counter == 1: PROVED .*$ +^\[main\.p1\] main\.counter == 2: PROVED .*$ ^EXIT=0$ ^SIGNAL=0$ -- diff --git a/regression/verilog/SVA/initial2.sv b/regression/verilog/SVA/initial2.sv index c47d12884..cf254b372 100644 --- a/regression/verilog/SVA/initial2.sv +++ b/regression/verilog/SVA/initial2.sv @@ -6,12 +6,12 @@ module main(input clk); initial begin counter = 1; // expected to pass - assert(counter == 1); + p0: assert(counter == 1); counter = 2; end // expected to pass - initial assert property (counter == 2); + initial p1: assert property (counter == 2); always_ff @(posedge clk) counter = counter + 1; diff --git a/regression/verilog/SVA/named_property1.sv b/regression/verilog/SVA/named_property1.sv index 489055b30..30db7d9fb 100644 --- a/regression/verilog/SVA/named_property1.sv +++ b/regression/verilog/SVA/named_property1.sv @@ -12,4 +12,6 @@ module main(input clk); x_is_ten endsequence + initial assert(some_sequence); + endmodule diff --git a/regression/verilog/SVA/property_and1.aig.desc b/regression/verilog/SVA/property_and1.aig.desc new file mode 100644 index 000000000..76dba32b9 --- /dev/null +++ b/regression/verilog/SVA/property_and1.aig.desc @@ -0,0 +1,9 @@ +CORE +property_and1.sv +--aig --bound 5 +^\[.*\] always \(main\.P1 and main\.P1\): PROVED up to bound 5$ +^EXIT=0$ +^SIGNAL=0$ +-- +^warning: ignoring +-- diff --git a/regression/verilog/arrays/unpacked_array_concatenation1.desc b/regression/verilog/arrays/unpacked_array_concatenation1.desc new file mode 100644 index 000000000..fb3c07002 --- /dev/null +++ b/regression/verilog/arrays/unpacked_array_concatenation1.desc @@ -0,0 +1,8 @@ +KNOWNBUG +unpacked_array_concatenation1.sv + +^EXIT=0$ +^SIGNAL=0$ +-- +-- +This yields a type checking error. diff --git a/regression/verilog/arrays/unpacked_array_concatenation1.sv b/regression/verilog/arrays/unpacked_array_concatenation1.sv new file mode 100644 index 000000000..147a8e278 --- /dev/null +++ b/regression/verilog/arrays/unpacked_array_concatenation1.sv @@ -0,0 +1,11 @@ +module main; + + // 1800-2017 10.10 Unpacked array concatenation + byte my_bytes [1:4] = { 1, 2, 3, 4 }; + + assert final(my_bytes[1] == 1); + assert final(my_bytes[2] == 2); + assert final(my_bytes[3] == 3); + assert final(my_bytes[4] == 4); + +endmodule diff --git a/regression/verilog/asic-world-operators/reduction.desc b/regression/verilog/asic-world-operators/reduction.desc index ecbd4fdc2..0187189ba 100644 --- a/regression/verilog/asic-world-operators/reduction.desc +++ b/regression/verilog/asic-world-operators/reduction.desc @@ -1,4 +1,4 @@ -KNOWNBUG +CORE broken-smt-backend reduction.sv --module main --bound 0 ^EXIT=0$ @@ -6,4 +6,3 @@ reduction.sv -- ^warning: ignoring -- -x-related tests fail diff --git a/regression/verilog/asic-world-operators/relational.desc b/regression/verilog/asic-world-operators/relational.desc index 988a8ab9e..c3f343774 100644 --- a/regression/verilog/asic-world-operators/relational.desc +++ b/regression/verilog/asic-world-operators/relational.desc @@ -1,4 +1,4 @@ -KNOWNBUG +CORE relational.sv --module main --bound 0 ^EXIT=0$ @@ -6,4 +6,3 @@ relational.sv -- ^warning: ignoring -- -x-related tests fail diff --git a/regression/verilog/asic-world-operators/replication.desc b/regression/verilog/asic-world-operators/replication.desc index 2f49cfc20..a38016a72 100644 --- a/regression/verilog/asic-world-operators/replication.desc +++ b/regression/verilog/asic-world-operators/replication.desc @@ -1,4 +1,4 @@ -KNOWNBUG +CORE replication.sv --module main --bound 0 ^EXIT=0$ @@ -6,4 +6,3 @@ replication.sv -- ^warning: ignoring -- -z-related tests fail diff --git a/regression/verilog/asic-world-operators/replication.sv b/regression/verilog/asic-world-operators/replication.sv index fb580eced..7d3d36809 100644 --- a/regression/verilog/asic-world-operators/replication.sv +++ b/regression/verilog/asic-world-operators/replication.sv @@ -4,7 +4,7 @@ module main(input[31:0] in1, in2, in3); // http://www.asic-world.com/verilog/operators2.html // replication - always assert repli_p1: {4{4'b1001}} == 'b1001100110011001; - always assert repli_p2: {4{4'b1001,1'bz}} == 'b1001z1001z1001z1001z; + initial repli_p1: assert({4{4'b1001}} === 'b1001100110011001); + initial repli_p2: assert({4{4'b1001,1'bz}} === 'b1001z1001z1001z1001z); endmodule diff --git a/regression/verilog/assignments/assignment-context1.desc b/regression/verilog/assignments/assignment-context1.desc new file mode 100644 index 000000000..0c6c7f0e0 --- /dev/null +++ b/regression/verilog/assignments/assignment-context1.desc @@ -0,0 +1,8 @@ +CORE +assignment-context1.sv + +^EXIT=0$ +^SIGNAL=0$ +-- +^warning: ignoring +-- diff --git a/regression/verilog/assignments/assignment-context1.sv b/regression/verilog/assignments/assignment-context1.sv new file mode 100644 index 000000000..21f5dd269 --- /dev/null +++ b/regression/verilog/assignments/assignment-context1.sv @@ -0,0 +1,70 @@ +module main; + +`define ui (8'd255+8'd2) +`define si (8'sd127+8'sd1) + + // enlarge + // The RHS is padded or sign extended. + wire signed [31:0] sw1 = `ui; // unsigned 8 to signed 32 + wire signed [31:0] sw2 = `si; // signed 8 to signed 32 + wire unsigned [31:0] uw1 = `ui; // unsigned 8 to unsigned 32 + wire unsigned [31:0] uw2 = `si; // signed 8 to unsigned 32 + + // shrink + wire signed [3:0] sn1 = `ui; // unsigned 8 to signed 4 + wire signed [3:0] sn2 = `si; // signed 8 to signed 4 + wire unsigned [3:0] un1 = `ui; // unsigned 8 to unsigned 4 + wire unsigned [3:0] un2 = `si; // signed 8 to unsigned 4 + + // same size + wire signed [7:0] sb1 = `ui; // unsigned 8 to signed 8 + wire signed [7:0] sb2 = `si; // signed 8 to signed 8 + wire unsigned [7:0] ub1 = `ui; // unsigned 8 to unsigned 8 + wire unsigned [7:0] ub2 = `si; // signed 8 to unsigned 8 + + // just one bit + wire signed sbit1 = `ui; // unsigned 8 to signed 1 + wire signed sbit2 = `si; // signed 8 to signed 1 + wire unsigned ubit1 = `ui; // unsigned 8 to unsigned 1 + wire unsigned ubit2 = `si; // signed 8 to unsigned 1 + + assert final(sw1 == 257); + assert final(sw2 == 128); + assert final(uw1 == 257); + assert final(uw2 == 128); + assert final(sn1 == 1); + assert final(sn2 == 0); + assert final(un1 == 1); + assert final(un2 == 0); + assert final(sb1 == 1); + assert final(sb2 == -128); + assert final(ub1 == 1); + assert final(ub2 == 128); + assert final(sbit1 == -1); + assert final(sbit2 == 0); + assert final(ubit1 == 1); + assert final(ubit2 == 0); + + initial begin + $display("sw1 == ", sw1); + $display("sw2 == ", sw2); + $display("uw1 == ", uw1); + $display("uw2 == ", uw2); + + $display("sn1 == ", sn1); + $display("sn2 == ", sn2); + $display("un1 == ", un1); + $display("un2 == ", un2); + + $display("sb1 == ", sb1); + $display("sb2 == ", sb2); + $display("ub1 == ", ub1); + $display("ub2 == ", ub2); + + $display("sbit1 == ", sbit1); + $display("sbit2 == ", sbit2); + $display("ubit1 == ", ubit1); + $display("ubit2 == ", ubit2); + end + +endmodule diff --git a/regression/verilog/assignments/assignment-context2.desc b/regression/verilog/assignments/assignment-context2.desc new file mode 100644 index 000000000..cb10432b2 --- /dev/null +++ b/regression/verilog/assignments/assignment-context2.desc @@ -0,0 +1,9 @@ +KNOWNBUG +assignment-context2.sv + +^EXIT=0$ +^SIGNAL=0$ +-- +^warning: ignoring +-- +The assertion main.v3 == 2'b10 gives the wrong answer. diff --git a/regression/verilog/assignments/assignment-context2.sv b/regression/verilog/assignments/assignment-context2.sv new file mode 100644 index 000000000..79a8dc19c --- /dev/null +++ b/regression/verilog/assignments/assignment-context2.sv @@ -0,0 +1,68 @@ +module submoduleA(input [2:0] some_input); +endmodule + +module submoduleB(output [2:0] some_output); + assign some_output = 1'd1+1'd1; +endmodule + +module main; + + // 1800-2017 10.8 Assignment-like contexts + + // continuous assignment + wire [1:0] v1; + assign v1 = 1'd1+1'd1; + assert final (v1 == 2'd2); + + // procedural assignment + reg [1:0] v2; + initial v2 = 1'd1+1'd1; + assert final (v2 == 2'd2); + + // parameter with explicit type declaration + parameter [1:0] v3 = 1'd1+1'd1; + assert final (v3 == 2'd2); + + // A port connection to an input port of a module + submoduleA subA(1'd1+1'd1); + assert final (subA.some_input == 2'd2); + + // A port connection to an output port of a module + submoduleB subB(); + assert final (subB.some_output == 2'd2); + + // The passing of a value to a subroutine input port + task my_task(input [1:0] some_input); + assert final (some_input == 2'd2); + endtask + + initial my_task(1'd1+1'd1); + + // A return statement in a function + function [1:0] my_fun; + return 1'd1+1'd1; + endfunction + + assert final (my_fun() == 2'd2); + + // A tagged union expression + union tagged { + bit [1:0] my_tag; + } some_union = tagged my_tag(1'd1+1'd1); + assert final (some_union.my_tag == 2'd2); + + // recursively, an expression within parentheses + wire [1:0] v4; + assign v4 = (1'd1+1'd1); + assert final (v4 == 2'd2); + + // recursively, the second and third operand of ?: + wire [1:0] v5; + assign v5 = 0 ? 1'b0 : 1'd1+1'd1; + assert final (v4 == 2'd2); + + // nondefault value in assignment pattern + struct { bit [1:0] field; } s = '{ field: 1'd1+1'd1 }; + assert final (s.field == 2'd2); + +endmodule diff --git a/regression/verilog/assignments/assignment-pattern-lhs1.desc b/regression/verilog/assignments/assignment-pattern-lhs1.desc new file mode 100644 index 000000000..f7f64cde7 --- /dev/null +++ b/regression/verilog/assignments/assignment-pattern-lhs1.desc @@ -0,0 +1,8 @@ +CORE +assignment-pattern-lhs1.sv + +^file .* line 9: no support for assignment patterns on LHS of an assignment$ +^EXIT=2$ +^SIGNAL=0$ +-- +-- diff --git a/regression/verilog/assignments/assignment-pattern-lhs1.sv b/regression/verilog/assignments/assignment-pattern-lhs1.sv new file mode 100644 index 000000000..27509c5be --- /dev/null +++ b/regression/verilog/assignments/assignment-pattern-lhs1.sv @@ -0,0 +1,14 @@ +module main; + + int x, y; + + initial begin + // Assignment pattern on LHS. + // Does not parse with Icarus Verilog, VCS, XCelium. + // Works with Riviera, Questa. + '{x, y} = '{1, 2}; + + assert(x == 1 && y == 2); + end + +endmodule diff --git a/regression/verilog/assignments/assignment-with-function-call1.sv b/regression/verilog/assignments/assignment-with-function-call1.sv index 5dd9a5857..2f8f431d9 100644 --- a/regression/verilog/assignments/assignment-with-function-call1.sv +++ b/regression/verilog/assignments/assignment-with-function-call1.sv @@ -10,8 +10,8 @@ module top(input [7:0] a, input [7:0] b); wire [7:0] sum_a_b = fn(a, b), sum_1_2 = fn(1, 2), sum_2_3 = fn(2, 3); - - assert property (sum_a_b==a[2:0]+b[2:0]); + + assert property (sum_a_b[2:0]==a[2:0]+b[2:0]); assert property (sum_1_2==3); diff --git a/regression/verilog/case/case5.desc b/regression/verilog/case/case5.desc new file mode 100644 index 000000000..b6eb351ca --- /dev/null +++ b/regression/verilog/case/case5.desc @@ -0,0 +1,10 @@ +KNOWNBUG +case5.sv +--module main --bound 0 +^EXIT=0$ +^SIGNAL=0$ +-- +^warning: ignoring +-- +This gives the wrong result. + diff --git a/regression/verilog/case/case5.sv b/regression/verilog/case/case5.sv new file mode 100644 index 000000000..bf6476d78 --- /dev/null +++ b/regression/verilog/case/case5.sv @@ -0,0 +1,30 @@ +module main; + + reg [31:0] resultA, resultB; + + // All case expressions are extended to the longest case + // or case item expression. + + initial begin + resultA = 10; + + case(1'b1 << 8) + 0: resultA = 0; // 32 bits! + 1'b1: resultA = 1; + endcase + + assert(resultA == 10); + end + + initial begin + resultB = 10; + + case(1'b1 << 8) + 1'b0: resultB = 0; // just 1 bit! + 1'b1: resultB = 1; + endcase + + assert(resultB == 0); + end + +endmodule diff --git a/regression/verilog/class/new1.desc b/regression/verilog/class/new1.desc index 7b532cf15..8682af3e5 100644 --- a/regression/verilog/class/new1.desc +++ b/regression/verilog/class/new1.desc @@ -1,8 +1,7 @@ -KNOWNBUG +CORE new1.sv -^EXIT=0$ +^EXIT=10$ ^SIGNAL=0$ -- -- -The class is not yet recognized as a type. diff --git a/regression/verilog/config/basic_config1.desc b/regression/verilog/config/basic_config1.desc new file mode 100644 index 000000000..aec2aedf7 --- /dev/null +++ b/regression/verilog/config/basic_config1.desc @@ -0,0 +1,8 @@ +CORE +basic_config1.sv +--module top +^EXIT=10$ +^SIGNAL=0$ +-- +^warning: ignoring +-- diff --git a/regression/verilog/config/basic_config1.sv b/regression/verilog/config/basic_config1.sv new file mode 100644 index 000000000..e63ae34ac --- /dev/null +++ b/regression/verilog/config/basic_config1.sv @@ -0,0 +1,13 @@ +module SUB; + parameter P = 1; +endmodule + +module top; + SUB sub(); +endmodule + +config some_config; + design top; + instance top.sub use #(.P(2)); +endconfig + diff --git a/regression/verilog/data-types/time1.desc b/regression/verilog/data-types/time1.desc new file mode 100644 index 000000000..18c3eae6b --- /dev/null +++ b/regression/verilog/data-types/time1.desc @@ -0,0 +1,7 @@ +CORE +time1.sv +--bound - +^EXIT=0$ +^SIGNAL=0$ +-- +^warning: ignoring diff --git a/regression/verilog/data-types/time1.sv b/regression/verilog/data-types/time1.sv new file mode 100644 index 000000000..76116eeeb --- /dev/null +++ b/regression/verilog/data-types/time1.sv @@ -0,0 +1,12 @@ +module main; + + initial begin : some_block + time some_time; + some_time = 1; + assert(some_time == 1); + some_time++; + assert(some_time == 2); + assert($bits(some_time) == 64); + end + +endmodule diff --git a/regression/verilog/expressions/bitwise_and1.desc b/regression/verilog/expressions/bitwise_and1.desc new file mode 100644 index 000000000..81fdb8779 --- /dev/null +++ b/regression/verilog/expressions/bitwise_and1.desc @@ -0,0 +1,8 @@ +CORE +bitwise_and1.sv +--bound 0 +^EXIT=0$ +^SIGNAL=0$ +-- +^warning: ignoring +-- diff --git a/regression/verilog/expressions/bitwise_and1.sv b/regression/verilog/expressions/bitwise_and1.sv new file mode 100644 index 000000000..58f036d22 --- /dev/null +++ b/regression/verilog/expressions/bitwise_and1.sv @@ -0,0 +1,8 @@ +module main; + + initial assert ((4'b0000 & 4'b01zx) === 4'b0000); + initial assert ((4'b1111 & 4'b01zx) === 4'b01xx); + initial assert ((4'bxxxx & 4'b01zx) === 4'b0xxx); + initial assert ((4'bzzzz & 4'b01zx) === 4'b0xxx); + +endmodule diff --git a/regression/verilog/expressions/bitwise_or1.desc b/regression/verilog/expressions/bitwise_or1.desc new file mode 100644 index 000000000..c9a4a8dd0 --- /dev/null +++ b/regression/verilog/expressions/bitwise_or1.desc @@ -0,0 +1,8 @@ +CORE +bitwise_or1.sv +--bound 0 +^EXIT=0$ +^SIGNAL=0$ +-- +^warning: ignoring +-- diff --git a/regression/verilog/expressions/bitwise_or1.sv b/regression/verilog/expressions/bitwise_or1.sv new file mode 100644 index 000000000..d24852e9e --- /dev/null +++ b/regression/verilog/expressions/bitwise_or1.sv @@ -0,0 +1,8 @@ +module main; + + initial assert ((4'b0000 | 4'b01zx) === 4'b01xx); + initial assert ((4'b1111 | 4'b01zx) === 4'b1111); + initial assert ((4'bxxxx | 4'b01zx) === 4'bx1xx); + initial assert ((4'bzzzz | 4'b01zx) === 4'bx1xx); + +endmodule diff --git a/regression/verilog/expressions/bitwise_xor1.desc b/regression/verilog/expressions/bitwise_xor1.desc new file mode 100644 index 000000000..a1068f936 --- /dev/null +++ b/regression/verilog/expressions/bitwise_xor1.desc @@ -0,0 +1,7 @@ +CORE +bitwise_xor1.sv +--bound 0 +^EXIT=0$ +^SIGNAL=0$ +-- +^warning: ignoring diff --git a/regression/verilog/expressions/bitwise_xor1.sv b/regression/verilog/expressions/bitwise_xor1.sv new file mode 100644 index 000000000..02a3016b5 --- /dev/null +++ b/regression/verilog/expressions/bitwise_xor1.sv @@ -0,0 +1,8 @@ +module main; + + initial assert ((4'b0000 ^ 4'b01zx) === 4'b01xx); + initial assert ((4'b1111 ^ 4'b01zx) === 4'b10xx); + initial assert ((4'bxxxx ^ 4'b01zx) === 4'bxxxx); + initial assert ((4'bzzzz ^ 4'b01zx) === 4'bxxxx); + +endmodule diff --git a/regression/verilog/expressions/concatenation5.desc b/regression/verilog/expressions/concatenation5.desc index 1c6799eeb..36995a0ff 100644 --- a/regression/verilog/expressions/concatenation5.desc +++ b/regression/verilog/expressions/concatenation5.desc @@ -1,7 +1,7 @@ CORE concatenation5.v -^file .* line 4: operand 1.1 must be integral$ +^file .* line 4: operand 1.1 must have a bit vector type$ ^EXIT=2$ ^SIGNAL=0$ -- diff --git a/regression/verilog/expressions/div1.desc b/regression/verilog/expressions/div1.desc new file mode 100644 index 000000000..50f479cdc --- /dev/null +++ b/regression/verilog/expressions/div1.desc @@ -0,0 +1,9 @@ +KNOWNBUG +div1.sv + +^EXIT=0$ +^SIGNAL=0$ +-- +^warning: ignoring +-- +The result is wrong. diff --git a/regression/verilog/expressions/div1.sv b/regression/verilog/expressions/div1.sv new file mode 100644 index 000000000..2b24bed2d --- /dev/null +++ b/regression/verilog/expressions/div1.sv @@ -0,0 +1,13 @@ +module main; + + // Any arithmetic with x or z returns x. + initial assert(32'bx / 1 === 32'hxxxx_xxxx); + initial assert(32'bz / 1 === 32'hxxxx_xxxx); + initial assert(1 / 32'bx === 32'hxxxx_xxxx); + initial assert(1 / 32'bz === 32'hxxxx_xxxx); + + // Division by zero returns x + initial assert(1 / 0 === 32'hxxxx_xxxx); + initial assert(1 / 0 === 32'hxxxx_xxxx); + +endmodule diff --git a/regression/verilog/expressions/equality1.desc b/regression/verilog/expressions/equality1.desc index e9fed273e..2418f3ee1 100644 --- a/regression/verilog/expressions/equality1.desc +++ b/regression/verilog/expressions/equality1.desc @@ -10,7 +10,7 @@ equality1.v ^\[.*\] always 32'b0000000000000000000000000000000x != 10 === 32'b0000000000000000000000000000000x: PROVED .*$ ^\[.*\] always 32'b0000000000000000000000000000000z != 20 === 32'b0000000000000000000000000000000x: PROVED .*$ ^\[.*\] always 1'sb1 == 2'b11 === 0: PROVED .*$ -^\[.*\] always 2'sb11 == 2'sb11 === 1: PROVED .*$ +^\[.*\] always 1'sb1 == 2'sb11 === 1: PROVED .*$ ^\[.*\] always 1\.1 == 1\.1 == 1: PROVED .*$ ^\[.*\] always 1\.1 == 1 == 0: PROVED .*$ ^EXIT=0$ diff --git a/regression/verilog/expressions/equality2.desc b/regression/verilog/expressions/equality2.desc index f70993dbe..179c844c4 100644 --- a/regression/verilog/expressions/equality2.desc +++ b/regression/verilog/expressions/equality2.desc @@ -12,7 +12,7 @@ equality2.v ^\[.*\] always 32'b0000000000000000000000000000000z === 1 == 0: PROVED .*$ ^\[.*\] always 1 === 1 == 1: PROVED .*$ ^\[.*\] always 3'b011 === 2'sb11 == 1: PROVED .*$ -^\[.*\] always 3'sb111 === 3'sb111 == 1: PROVED .*$ +^\[.*\] always 3'sb111 === 2'sb11 == 1: PROVED .*$ ^EXIT=0$ ^SIGNAL=0$ -- diff --git a/regression/verilog/expressions/equality3.desc b/regression/verilog/expressions/equality3.desc index 9b823fb06..6db629d90 100644 --- a/regression/verilog/expressions/equality3.desc +++ b/regression/verilog/expressions/equality3.desc @@ -1,6 +1,7 @@ CORE equality3.v +^file .* line 4: the case equality operator does not allow real or shortreal$ ^EXIT=2$ ^SIGNAL=0$ -- diff --git a/regression/verilog/expressions/equality4.desc b/regression/verilog/expressions/equality4.desc new file mode 100644 index 000000000..bc94403d6 --- /dev/null +++ b/regression/verilog/expressions/equality4.desc @@ -0,0 +1,8 @@ +CORE +equality4.sv + +^EXIT=0$ +^SIGNAL=0$ +-- +^warning: ignoring +-- diff --git a/regression/verilog/expressions/equality4.sv b/regression/verilog/expressions/equality4.sv new file mode 100644 index 000000000..07743c35c --- /dev/null +++ b/regression/verilog/expressions/equality4.sv @@ -0,0 +1,7 @@ +module main; + + // The two operands are zero-extended to 8 bits. + initial assert((2'b10 + 1'sbx) === 8'bxxxxxxxx); + initial assert((2'b10 | 1'sbx) === 8'b0000001x); + +endmodule diff --git a/regression/verilog/expressions/equality5.desc b/regression/verilog/expressions/equality5.desc new file mode 100644 index 000000000..c3c2e033d --- /dev/null +++ b/regression/verilog/expressions/equality5.desc @@ -0,0 +1,8 @@ +CORE +equality5.sv + +^EXIT=0$ +^SIGNAL=0$ +-- +^warning: ignoring +-- diff --git a/regression/verilog/expressions/equality5.sv b/regression/verilog/expressions/equality5.sv new file mode 100644 index 000000000..478ca6a82 --- /dev/null +++ b/regression/verilog/expressions/equality5.sv @@ -0,0 +1,7 @@ +module main; + + // The two operands are sign-extended to 8 bits. + initial assert((2'sb10 + 1'sbx) === 8'sbxxxxxxxx); + initial assert((2'sb10 | 1'sbx) === 8'sb1111111x); + +endmodule diff --git a/regression/verilog/expressions/integer_literals2.desc b/regression/verilog/expressions/integer_literals2.desc new file mode 100644 index 000000000..a5b43d679 --- /dev/null +++ b/regression/verilog/expressions/integer_literals2.desc @@ -0,0 +1,7 @@ +CORE +integer_literals2.sv + +^EXIT=0$ +^SIGNAL=0$ +-- +^warning: ignoring diff --git a/regression/verilog/expressions/integer_literals2.sv b/regression/verilog/expressions/integer_literals2.sv new file mode 100644 index 000000000..c2e771393 --- /dev/null +++ b/regression/verilog/expressions/integer_literals2.sv @@ -0,0 +1,20 @@ +module main; + + // 1800-2017 5.7.1 + + // "If the size of the unsigned number is smaller than the size specified + // for the literal constant, the unsigned number shall be padded to the + // left with zeros." + initial assert (4'b1 === 4'b0001); + + // "If the leftmost bit in the unsigned number is an x or a z, then + // an x or a z shall be used to pad to the left, respectively." + initial assert (4'bz1 === 4'bzzz1); + initial assert (4'bx1 === 4'bxxx1); + + // "If the size of the unsigned number is larger than the size specified + // for the literal constant, the unsigned number shall be truncated from + // the left." + initial assert (4'b1111_1111 === 4'b1111); + +endmodule diff --git a/regression/verilog/expressions/integer_literals3.desc b/regression/verilog/expressions/integer_literals3.desc new file mode 100644 index 000000000..761c08299 --- /dev/null +++ b/regression/verilog/expressions/integer_literals3.desc @@ -0,0 +1,9 @@ +KNOWNBUG +integer_literals3.sv + +^EXIT=0$ +^SIGNAL=0$ +-- +^warning: ignoring +-- +The context-dependent extension is not implemented. diff --git a/regression/verilog/expressions/integer_literals3.sv b/regression/verilog/expressions/integer_literals3.sv new file mode 100644 index 000000000..ed4d70bd4 --- /dev/null +++ b/regression/verilog/expressions/integer_literals3.sv @@ -0,0 +1,22 @@ +module main; + + // 1800-2017 5.7.1 + + // "Unsized unsigned literal constants where the high-order bit is unknown + // (X or x) or three-state (Z or z) shall be extended to the size of the + // expression containing the literal constant." + initial assert (('hx0 | 64'h0) === 64'hxxxx_xxx0); + + initial assert ((1 ? '0 : 16'h0) === 16'h0000); + initial assert ((1 ? '1 : 16'h0) === 16'hffff); + initial assert ((1 ? 'x : 16'h0) === 16'hxxxx); + initial assert ((1 ? 'z : 16'h0) === 16'hzzzz); + + // "All bits of the unsized value shall be set to the value of the specified + // bit." + initial assert ($bits(1 ? '0 : 16'h0) === 16); + initial assert ($bits(1 ? '1 : 16'h0) === 16); + initial assert ($bits(1 ? 'x : 16'h0) === 16); + initial assert ($bits(1 ? 'z : 16'h0) === 16); + +endmodule diff --git a/regression/verilog/expressions/minus1.desc b/regression/verilog/expressions/minus1.desc new file mode 100644 index 000000000..51fdb1242 --- /dev/null +++ b/regression/verilog/expressions/minus1.desc @@ -0,0 +1,8 @@ +CORE +minus1.sv + +^EXIT=0$ +^SIGNAL=0$ +-- +^warning: ignoring +-- diff --git a/regression/verilog/expressions/minus1.sv b/regression/verilog/expressions/minus1.sv new file mode 100644 index 000000000..7de5a8129 --- /dev/null +++ b/regression/verilog/expressions/minus1.sv @@ -0,0 +1,9 @@ +module main; + + // Any arithmetic with x or z returns x. + initial assert(32'bx - 1 === 32'hxxxx_xxxx); + initial assert(32'bz - 1 === 32'hxxxx_xxxx); + initial assert(1 - 32'bx === 32'hxxxx_xxxx); + initial assert(1 - 32'bz === 32'hxxxx_xxxx); + +endmodule diff --git a/regression/verilog/expressions/mod1.desc b/regression/verilog/expressions/mod1.desc new file mode 100644 index 000000000..1439e10ba --- /dev/null +++ b/regression/verilog/expressions/mod1.desc @@ -0,0 +1,9 @@ +KNOWNBUG +mod1.sv + +^EXIT=0$ +^SIGNAL=0$ +-- +^warning: ignoring +-- +The result is wrong. diff --git a/regression/verilog/expressions/mod1.sv b/regression/verilog/expressions/mod1.sv new file mode 100644 index 000000000..dc5b2b94c --- /dev/null +++ b/regression/verilog/expressions/mod1.sv @@ -0,0 +1,13 @@ +module main; + + // Any arithmetic with x or z returns x. + initial assert(32'bx % 1 === 32'hxxxx_xxxx); + initial assert(32'bz % 1 === 32'hxxxx_xxxx); + initial assert(1 % 32'bx === 32'hxxxx_xxxx); + initial assert(1 % 32'bz === 32'hxxxx_xxxx); + + // mod-by-zero returns x + initial assert(1 % 0 === 32'hxxxx_xxxx); + initial assert(1 % 0 === 32'hxxxx_xxxx); + +endmodule diff --git a/regression/verilog/expressions/mod2.desc b/regression/verilog/expressions/mod2.desc index 329be47ba..a2a7a4294 100644 --- a/regression/verilog/expressions/mod2.desc +++ b/regression/verilog/expressions/mod2.desc @@ -1,7 +1,7 @@ CORE mod2.v -^file .* line 4: operand 1\.1 must be integral$ +^file .* line 4: operand 1\.1 must have a bit vector type$ ^EXIT=2$ ^SIGNAL=0$ -- diff --git a/regression/smv/word/extractbits1.desc b/regression/verilog/expressions/mult1.desc similarity index 80% rename from regression/smv/word/extractbits1.desc rename to regression/verilog/expressions/mult1.desc index 106946ec4..57e745ac6 100644 --- a/regression/smv/word/extractbits1.desc +++ b/regression/verilog/expressions/mult1.desc @@ -1,7 +1,8 @@ CORE -shift1.smv +mult1.sv ^EXIT=0$ ^SIGNAL=0$ -- ^warning: ignoring +-- diff --git a/regression/verilog/expressions/mult1.sv b/regression/verilog/expressions/mult1.sv new file mode 100644 index 000000000..7d221d47a --- /dev/null +++ b/regression/verilog/expressions/mult1.sv @@ -0,0 +1,9 @@ +module main; + + // Any arithmetic with x or z returns x. + initial assert(32'bx * 0 === 32'hxxxx_xxxx); + initial assert(32'bz * 0 === 32'hxxxx_xxxx); + initial assert(0 * 32'bx === 32'hxxxx_xxxx); + initial assert(0 * 32'bz === 32'hxxxx_xxxx); + +endmodule diff --git a/regression/verilog/expressions/negation1.sv b/regression/verilog/expressions/negation1.sv index c7973a046..2cd4e4a14 100644 --- a/regression/verilog/expressions/negation1.sv +++ b/regression/verilog/expressions/negation1.sv @@ -8,4 +8,7 @@ module main; property06: assert final (!2'bxx===1'bx); property07: assert final (!1'bz===1'bx); + // expression type contexts do not pass through ! + initial assert(!(1'b1 + 1'b1) == 1); + endmodule diff --git a/regression/verilog/expressions/plus1.desc b/regression/verilog/expressions/plus1.desc new file mode 100644 index 000000000..73ad5068d --- /dev/null +++ b/regression/verilog/expressions/plus1.desc @@ -0,0 +1,8 @@ +CORE +plus1.sv + +^EXIT=0$ +^SIGNAL=0$ +-- +^warning: ignoring +-- diff --git a/regression/verilog/expressions/plus1.sv b/regression/verilog/expressions/plus1.sv new file mode 100644 index 000000000..c66564f7d --- /dev/null +++ b/regression/verilog/expressions/plus1.sv @@ -0,0 +1,9 @@ +module main; + + // Any arithmetic with x or z returns x. + initial assert(32'bx + 1 === 32'hxxxx_xxxx); + initial assert(32'bz + 1 === 32'hxxxx_xxxx); + initial assert(1 + 32'bx === 32'hxxxx_xxxx); + initial assert(1 + 32'bz === 32'hxxxx_xxxx); + +endmodule diff --git a/regression/verilog/expressions/power3.desc b/regression/verilog/expressions/power3.desc new file mode 100644 index 000000000..7a010c6a3 --- /dev/null +++ b/regression/verilog/expressions/power3.desc @@ -0,0 +1,8 @@ +CORE broken-smt-backend +power3.sv + +^EXIT=0$ +^SIGNAL=0$ +-- +^warning: ignoring +-- diff --git a/regression/verilog/expressions/power3.sv b/regression/verilog/expressions/power3.sv new file mode 100644 index 000000000..c1c976381 --- /dev/null +++ b/regression/verilog/expressions/power3.sv @@ -0,0 +1,9 @@ +module main; + + // Any arithmetic with x or z returns x. + initial assert('bx ** 1 === 32'hxxxx_xxxx); + initial assert('bz ** 1 === 32'hxxxx_xxxx); + initial assert(1 ** 'bx === 32'hxxxx_xxxx); + initial assert(1 ** 'bz === 32'hxxxx_xxxx); + +endmodule diff --git a/regression/verilog/expressions/reduction2.desc b/regression/verilog/expressions/reduction2.desc index 740909c3e..fea565df9 100644 --- a/regression/verilog/expressions/reduction2.desc +++ b/regression/verilog/expressions/reduction2.desc @@ -1,7 +1,7 @@ CORE reduction2.v -^file .* line 4: operand 1\.1 must be integral$ +^file .* line 4: operand 1\.1 must have a bit vector type$ ^EXIT=2$ ^SIGNAL=0$ -- diff --git a/regression/verilog/expressions/replication3.desc b/regression/verilog/expressions/replication3.desc index bdf6fde7e..35148a1bb 100644 --- a/regression/verilog/expressions/replication3.desc +++ b/regression/verilog/expressions/replication3.desc @@ -1,7 +1,7 @@ CORE replication3.v -^file .* line 3: operand 1\.1 must be integral$ +^file .* line 3: operand 1\.1 must have a bit vector type$ ^EXIT=2$ ^SIGNAL=0$ -- diff --git a/regression/verilog/expressions/shl4.desc b/regression/verilog/expressions/shl4.desc index c467a78ce..7b1140269 100644 --- a/regression/verilog/expressions/shl4.desc +++ b/regression/verilog/expressions/shl4.desc @@ -1,4 +1,4 @@ -KNOWNBUG +CORE broken-smt-backend shl4.sv --bound 0 ^EXIT=0$ @@ -6,4 +6,3 @@ shl4.sv -- ^warning: ignoring -- -This gives the wrong answer. diff --git a/regression/verilog/expressions/shl4.sv b/regression/verilog/expressions/shl4.sv index 9764a16dc..383d227eb 100644 --- a/regression/verilog/expressions/shl4.sv +++ b/regression/verilog/expressions/shl4.sv @@ -1,6 +1,15 @@ module main; + // The arguments of === are adjusted to the maximum of the + // self-determined widths of the lhs and rhs. + // Hence, 4'b1111 << 1 is equal both to 4'b1110 and 5'b11110. + assert final (4'b1111 << 1 === 4'b1110); assert final (4'b1111 << 1 === 5'b11110); - assert final (1 << 6 === 64); + + assert final (1'b1 << 6 === 64); + assert final (1'b1 << 6 === 1'b0); + + // The shift will have 16 bits! + initial assert(8'b0 + (1'sb1 << 15) === 16'b1000_0000_0000_0000); endmodule diff --git a/regression/verilog/expressions/shr2.desc b/regression/verilog/expressions/shr2.desc index e2957ddb1..48a6a5ac6 100644 --- a/regression/verilog/expressions/shr2.desc +++ b/regression/verilog/expressions/shr2.desc @@ -1,7 +1,7 @@ CORE shr2.v -^file .* line 4: operand 1\.1 must be integral$ +^file .* line 4: operand 1\.1 must have a bit vector type$ ^EXIT=2$ ^SIGNAL=0$ -- diff --git a/regression/verilog/expressions/signed2.sv b/regression/verilog/expressions/signed2.sv index aa186090e..068987c62 100644 --- a/regression/verilog/expressions/signed2.sv +++ b/regression/verilog/expressions/signed2.sv @@ -12,7 +12,7 @@ module main; // base 8 pB0: assert final ('so7 == -1); pB1: assert final ('so1 == 1); - pB2: assert final ('so7x === 'so3777777777x); + pB2: assert final ('so7x === 32'so3777777777x); pB3: assert final ($bits('so1) == 32); pB4: assert final ('so77 == -1); pB5: assert final (4'so7 == 7); diff --git a/regression/verilog/expressions/signing_cast1.sv b/regression/verilog/expressions/signing_cast1.sv index 900a57162..610680200 100644 --- a/regression/verilog/expressions/signing_cast1.sv +++ b/regression/verilog/expressions/signing_cast1.sv @@ -11,4 +11,9 @@ module main; // signing casts yield constants parameter Q = signed'(1); + // signing casts block downwards size/type propagation + initial assert (unsigned'(1'b1 + 1'b1) == 0); + initial assert (signed'(1'b1 + 1'b1) == 0); + initial assert ($bits(unsigned'(1'b1 + 1'b1)) == 1); + endmodule diff --git a/regression/verilog/expressions/signing_cast2.desc b/regression/verilog/expressions/signing_cast2.desc new file mode 100644 index 000000000..4e5e5cecf --- /dev/null +++ b/regression/verilog/expressions/signing_cast2.desc @@ -0,0 +1,9 @@ +KNOWNBUG +signing_cast2.sv +--module main +^EXIT=0$ +^SIGNAL=0$ +-- +^warning: ignoring +-- +This is not yet implemented. diff --git a/regression/verilog/expressions/signing_cast2.sv b/regression/verilog/expressions/signing_cast2.sv new file mode 100644 index 000000000..a3e76e461 --- /dev/null +++ b/regression/verilog/expressions/signing_cast2.sv @@ -0,0 +1,11 @@ +module main; + + // four-valued signing cast + initial assert (signed'(4'b11xx) === 8'sb1111_11xx); + initial assert (signed'(4'bx000) === 8'sbxxxx_x000); + + // four-valued signing cast + initial assert (unsigned'(4'sb11xx) === 8'b0000_11xx); + initial assert (unsigned'(4'sbx000) === 8'b0000_x000); + +endmodule diff --git a/regression/verilog/expressions/signing_cast3.desc b/regression/verilog/expressions/signing_cast3.desc new file mode 100644 index 000000000..2d382691d --- /dev/null +++ b/regression/verilog/expressions/signing_cast3.desc @@ -0,0 +1,8 @@ +CORE +signing_cast3.sv +--module main +^EXIT=0$ +^SIGNAL=0$ +-- +^warning: ignoring +-- diff --git a/regression/verilog/expressions/signing_cast3.sv b/regression/verilog/expressions/signing_cast3.sv new file mode 100644 index 000000000..f8362fab0 --- /dev/null +++ b/regression/verilog/expressions/signing_cast3.sv @@ -0,0 +1,9 @@ +module main; + + // 1800-2017 6.24.1 + // "the cast shall return the value that a variable of the casting type + // would hold after being assigned the expression." + // Hence, this is an assignment context with $bits width. + initial assert(signed'(1'b1 + 1'b1) == 0); + +endmodule diff --git a/regression/verilog/expressions/size_cast2.desc b/regression/verilog/expressions/size_cast2.desc new file mode 100644 index 000000000..3b5a443b0 --- /dev/null +++ b/regression/verilog/expressions/size_cast2.desc @@ -0,0 +1,8 @@ +CORE +size_cast2.sv +--module main +^EXIT=0$ +^SIGNAL=0$ +-- +^warning: ignoring +-- diff --git a/regression/verilog/expressions/size_cast2.sv b/regression/verilog/expressions/size_cast2.sv new file mode 100644 index 000000000..b1c5e90d1 --- /dev/null +++ b/regression/verilog/expressions/size_cast2.sv @@ -0,0 +1,11 @@ +module main; + + // four-valued zero extension + initial assert (8'(4'b11xx) === 8'b0000_11xx); + initial assert (8'(4'bx000) === 8'b0000_x000); + + // four-valued sign extension + initial assert (8'(4'sb11xx) === 8'sb1111_11xx); + initial assert (8'(4'sbx000) === 8'sbxxxx_x000); + +endmodule diff --git a/regression/verilog/expressions/size_cast3.desc b/regression/verilog/expressions/size_cast3.desc new file mode 100644 index 000000000..cf828778e --- /dev/null +++ b/regression/verilog/expressions/size_cast3.desc @@ -0,0 +1,8 @@ +CORE +size_cast3.sv +--module main +^EXIT=0$ +^SIGNAL=0$ +-- +^warning: ignoring +-- diff --git a/regression/verilog/expressions/size_cast3.sv b/regression/verilog/expressions/size_cast3.sv new file mode 100644 index 000000000..f3cb376e4 --- /dev/null +++ b/regression/verilog/expressions/size_cast3.sv @@ -0,0 +1,9 @@ +module main; + + // 1800-2017 6.24.1 + // "the cast shall return the value that a variable of the casting type + // would hold after being assigned the expression." + // Hence, this is an assignment context. + initial assert(8'(1'b1 + 1'b1) == 8'd2); + +endmodule diff --git a/regression/verilog/expressions/static_cast3.desc b/regression/verilog/expressions/static_cast3.desc new file mode 100644 index 000000000..f6c7f68c3 --- /dev/null +++ b/regression/verilog/expressions/static_cast3.desc @@ -0,0 +1,8 @@ +CORE +static_cast3.sv +--module main +^EXIT=0$ +^SIGNAL=0$ +-- +^warning: ignoring +-- diff --git a/regression/verilog/expressions/static_cast3.sv b/regression/verilog/expressions/static_cast3.sv new file mode 100644 index 000000000..33b01ff04 --- /dev/null +++ b/regression/verilog/expressions/static_cast3.sv @@ -0,0 +1,15 @@ +module main; + + typedef bit unsigned [7:0] unsigned_eight_bits; + typedef bit signed [7:0] signed_eight_bits; + + // 1800-2017 6.24.1 + // "the cast shall return the value that a variable of the casting type + // would hold after being assigned the expression." + // Hence, this is an assignment context. + initial assert(unsigned_eight_bits'(1'b1 + 1'b1) == 8'd2); + initial assert(unsigned_eight_bits'(1'sb1 + 1'sb1) == 8'b11111110); + initial assert(signed_eight_bits'(1'b1 + 1'b1) == 8'd2); + initial assert(signed_eight_bits'(1'sb1 + 1'sb1) == 8'sb11111110); + +endmodule diff --git a/regression/verilog/expressions/static_cast4.desc b/regression/verilog/expressions/static_cast4.desc new file mode 100644 index 000000000..8a353d973 --- /dev/null +++ b/regression/verilog/expressions/static_cast4.desc @@ -0,0 +1,8 @@ +CORE +static_cast4.sv +--module main +^EXIT=0$ +^SIGNAL=0$ +-- +^warning: ignoring +-- diff --git a/regression/verilog/expressions/static_cast4.sv b/regression/verilog/expressions/static_cast4.sv new file mode 100644 index 000000000..cd7fc02a2 --- /dev/null +++ b/regression/verilog/expressions/static_cast4.sv @@ -0,0 +1,17 @@ +module main; + + // The standard suggests that casts can be applied to assignment patterns. + // VCS, Icarus Verilog and Xcelium error this. + // Questa allows it. + // Riviera throws an internal error. + + typedef struct packed { int a, b; } S; + + initial begin + S some_struct; + some_struct.a = 1; + some_struct.b = 2; + assert ((S'('{a: 1, b: 2})) == some_struct); + end + +endmodule diff --git a/regression/verilog/expressions/streaming_concatenation2.desc b/regression/verilog/expressions/streaming_concatenation2.desc index ac3c6d7f1..c8a8006d0 100644 --- a/regression/verilog/expressions/streaming_concatenation2.desc +++ b/regression/verilog/expressions/streaming_concatenation2.desc @@ -1,7 +1,7 @@ CORE streaming_concatenation2.sv -^file .* line 4: operand 1\.1 must be integral$ +^file .* line 4: operand 1\.1 must have a bit vector type$ ^EXIT=2$ ^SIGNAL=0$ -- diff --git a/regression/verilog/expressions/unary_minus1.desc b/regression/verilog/expressions/unary_minus1.desc new file mode 100644 index 000000000..fb08c62ad --- /dev/null +++ b/regression/verilog/expressions/unary_minus1.desc @@ -0,0 +1,8 @@ +CORE +unary_minus1.sv + +^EXIT=0$ +^SIGNAL=0$ +-- +^warning: ignoring +-- diff --git a/regression/verilog/expressions/unary_minus1.sv b/regression/verilog/expressions/unary_minus1.sv new file mode 100644 index 000000000..14f054cad --- /dev/null +++ b/regression/verilog/expressions/unary_minus1.sv @@ -0,0 +1,9 @@ +module main; + + // Any arithmetic with x or z returns x. + initial assert(-32'bz === 32'hxxxx_xxxx); + + // Downwards type propagation passes through unary minus. + initial assert(-(1'sb1 + 1'sb1) == 2); + +endmodule diff --git a/regression/verilog/expressions/unary_plus1.desc b/regression/verilog/expressions/unary_plus1.desc new file mode 100644 index 000000000..6117179c4 --- /dev/null +++ b/regression/verilog/expressions/unary_plus1.desc @@ -0,0 +1,9 @@ +KNOWNBUG +unary_plus1.sv + +^EXIT=0$ +^SIGNAL=0$ +-- +^warning: ignoring +-- +The result is wrong. diff --git a/regression/verilog/expressions/unary_plus1.sv b/regression/verilog/expressions/unary_plus1.sv new file mode 100644 index 000000000..283135e01 --- /dev/null +++ b/regression/verilog/expressions/unary_plus1.sv @@ -0,0 +1,14 @@ +module main; + + // Any arithmetic with x or z normally returns x. + // IVerilog, VCS, Questa, Riviera say that +'bz is z. + // XCelium says it's 'x. + + // 1800-2017 11.4.3 says "For the arithmetic operators, if any operand bit + // value is the unknown value x or the high-impedance value z, then the + // entire result value shall be x." + // But it also says "Unary plus m (same as m)" in Table 11-5. + + initial assert(+32'bz === 32'hxxxx_xxxx); + +endmodule diff --git a/regression/verilog/expressions/wildcard_equality1.desc b/regression/verilog/expressions/wildcard_equality1.desc index 6d9359abc..e0457f8b1 100644 --- a/regression/verilog/expressions/wildcard_equality1.desc +++ b/regression/verilog/expressions/wildcard_equality1.desc @@ -9,9 +9,9 @@ wildcard_equality1.sv ^\[main\.property06\] always 2'b10 ==\? 2'b0x === 0: PROVED .*$ ^\[main\.property07\] always 2'b00 !=\? 2'b0x === 0: PROVED .*$ ^\[main\.property08\] always 2'b10 !=\? 2'b0x === 1: PROVED .*$ -^\[main\.property09\] always 2'b11 ==\? 2'b11 === 0: REFUTED$ -^\[main\.property10\] always 2'sb11 ==\? 2'sb11 === 1: PROVED .*$ -^EXIT=10$ +^\[main\.property09\] always 1'sb1 ==\? 2'b11 === 0: PROVED .*$ +^\[main\.property10\] always 1'sb1 ==\? 2'sb11 === 1: PROVED .*$ +^EXIT=0$ ^SIGNAL=0$ -- ^warning: ignoring diff --git a/regression/verilog/expressions/wildcard_equality2.desc b/regression/verilog/expressions/wildcard_equality2.desc index ecfe995c4..c653df5c9 100644 --- a/regression/verilog/expressions/wildcard_equality2.desc +++ b/regression/verilog/expressions/wildcard_equality2.desc @@ -1,7 +1,7 @@ CORE -wildcard_equality2.v +wildcard_equality2.sv -^file .* line 4: operand 1\.1 must be integral$ +^file .* line 4: operand 1\.1 must have a bit vector type$ ^EXIT=2$ ^SIGNAL=0$ -- diff --git a/regression/verilog/expressions/wildcard_equality2.v b/regression/verilog/expressions/wildcard_equality2.sv similarity index 71% rename from regression/verilog/expressions/wildcard_equality2.v rename to regression/verilog/expressions/wildcard_equality2.sv index aea237018..b0a3ebde2 100644 --- a/regression/verilog/expressions/wildcard_equality2.v +++ b/regression/verilog/expressions/wildcard_equality2.sv @@ -1,6 +1,6 @@ module main; // ==? only takes integral types - wire x = 1.1 === 1.2; + wire x = 1.1 ==? 1.2; endmodule diff --git a/regression/verilog/functioncall/function_ports2.desc b/regression/verilog/functioncall/function_ports2.desc new file mode 100644 index 000000000..2488697c2 --- /dev/null +++ b/regression/verilog/functioncall/function_ports2.desc @@ -0,0 +1,9 @@ +KNOWNBUG +function_ports2.sv +--module main +^EXIT=0$ +^SIGNAL=0$ +-- +^warning: ignoring +-- +This fails to type check. diff --git a/regression/verilog/functioncall/function_ports2.sv b/regression/verilog/functioncall/function_ports2.sv new file mode 100644 index 000000000..2438eebce --- /dev/null +++ b/regression/verilog/functioncall/function_ports2.sv @@ -0,0 +1,11 @@ +module main; + + function [31:0] incme; + input value; + integer value; + incme = value + 1; + endfunction + + initial assert(incme(10) == 11); + +endmodule diff --git a/regression/verilog/functioncall/function_ports3.desc b/regression/verilog/functioncall/function_ports3.desc new file mode 100644 index 000000000..17a2bfa83 --- /dev/null +++ b/regression/verilog/functioncall/function_ports3.desc @@ -0,0 +1,8 @@ +CORE +function_ports3.sv +--module main +^EXIT=0$ +^SIGNAL=0$ +-- +^warning: ignoring +-- diff --git a/regression/verilog/functioncall/function_ports3.sv b/regression/verilog/functioncall/function_ports3.sv new file mode 100644 index 000000000..ad35a41b9 --- /dev/null +++ b/regression/verilog/functioncall/function_ports3.sv @@ -0,0 +1,11 @@ +module main; + + function [7:0] identity(input [7:0] value); + identity = value; + endfunction + + // function ports are 'assignment-like contexts', 1800-2017 10.8, + // and hence, the signed argument is sign extended + assert final(identity(1'sb1) == 8'hff); + +endmodule diff --git a/regression/verilog/functioncall/named_parameter_assignment1.desc b/regression/verilog/functioncall/named_parameter_assignment1.desc new file mode 100644 index 000000000..dcdf9fe90 --- /dev/null +++ b/regression/verilog/functioncall/named_parameter_assignment1.desc @@ -0,0 +1,9 @@ +KNOWNBUG +named_parameter_assignment1.sv +--module main +^EXIT=0$ +^SIGNAL=0$ +-- +^warning: ignoring +-- +This does not parse. diff --git a/regression/verilog/functioncall/named_parameter_assignment1.sv b/regression/verilog/functioncall/named_parameter_assignment1.sv new file mode 100644 index 000000000..2f2bcfcfa --- /dev/null +++ b/regression/verilog/functioncall/named_parameter_assignment1.sv @@ -0,0 +1,13 @@ +module main; + + function [31:0] my_greater(int a, int b); + my_greater = a > b; + endfunction + + initial assert(my_greater(2, 1)); + initial assert(my_greater(.a(2), .b(1))); + initial assert(my_greater(2, .b(1))); + initial assert(!my_greater(.a(1), .b(2))); + initial assert(!my_greater(.b(2), .a(1))); + +endmodule diff --git a/regression/verilog/modules/interconnect1.desc b/regression/verilog/modules/interconnect1.desc index 65e4f27d2..8f5f9a52c 100644 --- a/regression/verilog/modules/interconnect1.desc +++ b/regression/verilog/modules/interconnect1.desc @@ -1,8 +1,8 @@ -KNOWNBUG +CORE interconnect1.sv -^EXIT=0$ +^file .* line 2: no support for interconnect nets$ +^EXIT=2$ ^SIGNAL=0$ -- -- -interconnect is not implemented. diff --git a/regression/verilog/modules/localparam3.v b/regression/verilog/modules/localparam3.v index af77c57af..46bec1cd6 100644 --- a/regression/verilog/modules/localparam3.v +++ b/regression/verilog/modules/localparam3.v @@ -3,7 +3,11 @@ module main; localparam [7:0] foo = 1; parameter [7:0] bar = 2; + // Parameters with type are "assignment contexts" + localparam [7:0] baz = 1'b1 + 1'b1; + always assert property1: $bits(foo) == 8; always assert property2: $bits(bar) == 8; + always assert property3: baz == 2; endmodule diff --git a/regression/verilog/modules/named_port_connection1.desc b/regression/verilog/modules/named_port_connection1.desc new file mode 100644 index 000000000..360ec7e69 --- /dev/null +++ b/regression/verilog/modules/named_port_connection1.desc @@ -0,0 +1,8 @@ +CORE +named_port_connection1.sv + +^file .* line 8: port name a assigned twice$ +^EXIT=2$ +^SIGNAL=0$ +-- +-- diff --git a/regression/verilog/modules/named_port_connection1.sv b/regression/verilog/modules/named_port_connection1.sv new file mode 100644 index 000000000..78c9a2d0f --- /dev/null +++ b/regression/verilog/modules/named_port_connection1.sv @@ -0,0 +1,10 @@ +module my_module(input a, b); + +endmodule + +module main(); + + // a is connected twice + my_module m1(.a(1), .a(1)); + +endmodule diff --git a/regression/verilog/modules/parameter_ports4.desc b/regression/verilog/modules/parameter_ports4.desc deleted file mode 100644 index 64ef929a0..000000000 --- a/regression/verilog/modules/parameter_ports4.desc +++ /dev/null @@ -1,8 +0,0 @@ -KNOWNBUG -parameter_ports4.sv - -^EXIT=0$ -^SIGNAL=0$ --- --- -The type parameter port needs to be parsed as a type. diff --git a/regression/verilog/modules/parameter_ports5.desc b/regression/verilog/modules/parameter_ports5.desc new file mode 100644 index 000000000..3775ae6ba --- /dev/null +++ b/regression/verilog/modules/parameter_ports5.desc @@ -0,0 +1,6 @@ +CORE +parameter_ports5.sv + +^EXIT=0$ +^SIGNAL=0$ +-- diff --git a/regression/verilog/modules/parameter_ports5.sv b/regression/verilog/modules/parameter_ports5.sv new file mode 100644 index 000000000..10b23ab48 --- /dev/null +++ b/regression/verilog/modules/parameter_ports5.sv @@ -0,0 +1,12 @@ +module sub #(parameter byte P = 0); + + initial assert($bits(P) == 8); + initial assert(P == 2); + +endmodule + +module main; + + sub #('h102) submodule(); + +endmodule // main diff --git a/regression/verilog/modules/parameter_without_default1.desc b/regression/verilog/modules/parameter_without_default1.desc new file mode 100644 index 000000000..b638875f0 --- /dev/null +++ b/regression/verilog/modules/parameter_without_default1.desc @@ -0,0 +1,9 @@ +KNOWNBUG +parameter_without_default1.sv + +^EXIT=2$ +^SIGNAL=0$ +-- +^warning: ignoring +-- +This does not parse. diff --git a/regression/verilog/modules/parameter_without_default1.sv b/regression/verilog/modules/parameter_without_default1.sv new file mode 100644 index 000000000..aa5f4dade --- /dev/null +++ b/regression/verilog/modules/parameter_without_default1.sv @@ -0,0 +1,11 @@ +// P has no default value; allowed by 1800-2017 6.20.1 +module my_module #(P); + +endmodule + +module main; + + // error: didn't give value for P + my_module m1(); + +endmodule diff --git a/regression/verilog/modules/parameters11.desc b/regression/verilog/modules/parameters11.desc new file mode 100644 index 000000000..671103ac9 --- /dev/null +++ b/regression/verilog/modules/parameters11.desc @@ -0,0 +1,7 @@ +CORE +parameters11.sv +--bound 0 +^EXIT=0$ +^SIGNAL=0$ +-- +^warning: ignoring diff --git a/regression/verilog/modules/parameters11.sv b/regression/verilog/modules/parameters11.sv new file mode 100644 index 000000000..6d577d5dc --- /dev/null +++ b/regression/verilog/modules/parameters11.sv @@ -0,0 +1,21 @@ +module my_module; + + parameter some_parameter = 8; + + // typedefs may depend on parameters + typedef bit [some_parameter-1:0] some_type; + wire some_type some_wire = -1; + +endmodule + +module main; + + my_module m8(); + my_module #(.some_parameter(4)) m4(); + my_module #(2) m2(); + + initial p1: assert (m8.some_wire==255); + initial p2: assert (m4.some_wire==15); + initial p3: assert (m2.some_wire==3); + +endmodule diff --git a/regression/verilog/modules/port_connection1.desc b/regression/verilog/modules/port_connection1.desc new file mode 100644 index 000000000..22fc74898 --- /dev/null +++ b/regression/verilog/modules/port_connection1.desc @@ -0,0 +1,8 @@ +CORE +port_connection1.sv + +^EXIT=0$ +^SIGNAL=0$ +-- +^warning: ignoring +-- diff --git a/regression/verilog/modules/port_connection1.sv b/regression/verilog/modules/port_connection1.sv new file mode 100644 index 000000000..d7a616191 --- /dev/null +++ b/regression/verilog/modules/port_connection1.sv @@ -0,0 +1,16 @@ +module M(input [31:0] some_name); + + initial assert (some_name == 123); + +endmodule + +module main; + + // typedef with the same name as a port + typedef bit [31:0] some_name; + + // This fails to parse with Icarus Verilog, + // but works with VCS, Questa, Xcelium, Riviera + M my_instance(.some_name(123)); + +endmodule diff --git a/regression/verilog/modules/ports9.desc b/regression/verilog/modules/ports9.desc new file mode 100644 index 000000000..eeaff0b10 --- /dev/null +++ b/regression/verilog/modules/ports9.desc @@ -0,0 +1,8 @@ +CORE +ports9.sv +--bound 1 +^EXIT=0$ +^SIGNAL=0$ +-- +^warning: ignoring +-- diff --git a/regression/verilog/modules/ports9.sv b/regression/verilog/modules/ports9.sv new file mode 100644 index 000000000..50fbad159 --- /dev/null +++ b/regression/verilog/modules/ports9.sv @@ -0,0 +1,15 @@ +module sub(input in, output logic data); + + assign data = in; + +endmodule + +module main; + logic subout; + + sub sub_inst(.data(subout)); + + // The value of the output needs to be able to change + cover property (##1 subout != $past(subout)); + +endmodule diff --git a/regression/verilog/modules/type_parameter_port1.desc b/regression/verilog/modules/type_parameter_port1.desc new file mode 100644 index 000000000..879db8eed --- /dev/null +++ b/regression/verilog/modules/type_parameter_port1.desc @@ -0,0 +1,7 @@ +CORE +type_parameter_port1.sv + +^EXIT=0$ +^SIGNAL=0$ +-- +-- diff --git a/regression/verilog/modules/parameter_ports4.sv b/regression/verilog/modules/type_parameter_port1.sv similarity index 100% rename from regression/verilog/modules/parameter_ports4.sv rename to regression/verilog/modules/type_parameter_port1.sv diff --git a/regression/verilog/modules/type_parameter_port2.desc b/regression/verilog/modules/type_parameter_port2.desc new file mode 100644 index 000000000..16da2d9a9 --- /dev/null +++ b/regression/verilog/modules/type_parameter_port2.desc @@ -0,0 +1,7 @@ +CORE +type_parameter_port2.sv + +^EXIT=0$ +^SIGNAL=0$ +-- +-- diff --git a/regression/verilog/modules/type_parameter_port2.sv b/regression/verilog/modules/type_parameter_port2.sv new file mode 100644 index 000000000..8ad2e02c3 --- /dev/null +++ b/regression/verilog/modules/type_parameter_port2.sv @@ -0,0 +1,13 @@ +module sub #(parameter type T = int)(); + + var T my_var; + +endmodule + +module main; + + sub #(.T(byte)) submodule(); + + p1: assert final ($bits(submodule.my_var) == 8); + +endmodule // main diff --git a/regression/verilog/modules/type_parameter_port3.desc b/regression/verilog/modules/type_parameter_port3.desc new file mode 100644 index 000000000..d4d8a3973 --- /dev/null +++ b/regression/verilog/modules/type_parameter_port3.desc @@ -0,0 +1,7 @@ +CORE +type_parameter_port3.sv + +^EXIT=0$ +^SIGNAL=0$ +-- +-- diff --git a/regression/verilog/modules/type_parameter_port3.sv b/regression/verilog/modules/type_parameter_port3.sv new file mode 100644 index 000000000..40b7d70ed --- /dev/null +++ b/regression/verilog/modules/type_parameter_port3.sv @@ -0,0 +1,13 @@ +module sub #(type T = int)(); + + var T my_var; + +endmodule + +module main; + + sub #(byte) submodule(); + + p1: assert final ($bits(submodule.my_var) == 8); + +endmodule // main diff --git a/regression/verilog/modules/type_parameter_port4.desc b/regression/verilog/modules/type_parameter_port4.desc new file mode 100644 index 000000000..8510ee8d7 --- /dev/null +++ b/regression/verilog/modules/type_parameter_port4.desc @@ -0,0 +1,7 @@ +CORE +type_parameter_port4.sv + +^EXIT=0$ +^SIGNAL=0$ +-- +-- diff --git a/regression/verilog/modules/type_parameter_port4.sv b/regression/verilog/modules/type_parameter_port4.sv new file mode 100644 index 000000000..aac370f92 --- /dev/null +++ b/regression/verilog/modules/type_parameter_port4.sv @@ -0,0 +1,13 @@ +module sub #(parameter N = 32, localparam type T = bit[N-1:0])(); + + var T my_var; + +endmodule + +module main; + + sub #(8) submodule(); + + p1: assert final ($bits(submodule.my_var) == 8); + +endmodule // main diff --git a/regression/verilog/modules/type_parameters1.desc b/regression/verilog/modules/type_parameters1.desc index c68a2b87d..f27f5d4ec 100644 --- a/regression/verilog/modules/type_parameters1.desc +++ b/regression/verilog/modules/type_parameters1.desc @@ -1,8 +1,8 @@ CORE type_parameters1.sv -^\[main\.p1\] always \$bits\(main\.T1\) == 1: PROVED .*$ -^\[main\.p2\] always \$bits\(main\.T2\) == 32: PROVED .*$ +^\[main\.p1\] always \$bits\(bool\) == 1: PROVED .*$ +^\[main\.p2\] always \$bits\(\[31:0\]\) == 32: PROVED .*$ ^EXIT=0$ ^SIGNAL=0$ -- diff --git a/regression/verilog/modules/type_parameters2.desc b/regression/verilog/modules/type_parameters2.desc new file mode 100644 index 000000000..cc2f80d27 --- /dev/null +++ b/regression/verilog/modules/type_parameters2.desc @@ -0,0 +1,7 @@ +CORE +type_parameters2.sv + +^EXIT=0$ +^SIGNAL=0$ +-- +^warning: ignoring diff --git a/regression/verilog/modules/type_parameters2.sv b/regression/verilog/modules/type_parameters2.sv new file mode 100644 index 000000000..7f93bff37 --- /dev/null +++ b/regression/verilog/modules/type_parameters2.sv @@ -0,0 +1,9 @@ +module main; + + parameter type T1 = bit [31:0]; + + T1 some_data; + + initial assert ($bits(some_data) == 32); + +endmodule diff --git a/regression/verilog/modules/unconnected_ports1.desc b/regression/verilog/modules/unconnected_ports1.desc new file mode 100644 index 000000000..e45992263 --- /dev/null +++ b/regression/verilog/modules/unconnected_ports1.desc @@ -0,0 +1,8 @@ +KNOWNBUG +unconnected_ports1.v +--bound 0 +^EXIT=0$ +^SIGNAL=0$ +-- +-- +This fails an assertion. diff --git a/regression/verilog/modules/unconnected_ports1.sv b/regression/verilog/modules/unconnected_ports1.sv new file mode 100644 index 000000000..27562a2e9 --- /dev/null +++ b/regression/verilog/modules/unconnected_ports1.sv @@ -0,0 +1,25 @@ +module my_module(input [31:0] x, y, z = 5); + +endmodule + +module main(); + + my_module m1(.x(1), .y(), .z()); + + // 1800-2017 23.3.3.2 says + // "If left unconnected, the port shall have the default + // initial value corresponding to the data type." + // This is 'x for logic types. + // However, Icarus Verilog, VCS, Questa, Xcelium use 'z. + + initial assert (m1.x == 1); + initial assert (m1.y === 'z); + initial assert (m1.z == 5); + + my_module m2(/* blank */, 1, /* blank */); + + initial assert (m2.x === 'z); + initial assert (m2.y == 1); + initial assert (m2.z == 5); + +endmodule diff --git a/regression/verilog/preprocessor/unknown_directive.desc b/regression/verilog/preprocessor/unknown_directive.desc index 1f6ce9b32..e718de61f 100644 --- a/regression/verilog/preprocessor/unknown_directive.desc +++ b/regression/verilog/preprocessor/unknown_directive.desc @@ -2,7 +2,6 @@ CORE unknown_directive.v --preprocess ^file unknown_directive\.v line 1: unknown preprocessor directive "something"$ -^PREPROCESSING FAILED$ ^EXIT=1$ ^SIGNAL=0$ -- diff --git a/regression/verilog/structs/structs4.sv b/regression/verilog/structs/structs4.sv index 0cb9c4441..af4887a73 100644 --- a/regression/verilog/structs/structs4.sv +++ b/regression/verilog/structs/structs4.sv @@ -12,7 +12,7 @@ module main; s.field3 = 'b1110011; end - // structs can be converted without cast to bit-vectors + // packed structs can be converted without cast to bit-vectors wire [8:0] w = s; // Expected to pass. diff --git a/regression/verilog/structs/unpacked_struct1.desc b/regression/verilog/structs/unpacked_struct1.desc new file mode 100644 index 000000000..0046665da --- /dev/null +++ b/regression/verilog/structs/unpacked_struct1.desc @@ -0,0 +1,7 @@ +CORE +unpacked_struct1.sv + +^file .* line 9: failed to convert `struct' to `\[8:0\]'$ +^EXIT=2$ +^SIGNAL=0$ +-- diff --git a/regression/verilog/structs/unpacked_struct1.sv b/regression/verilog/structs/unpacked_struct1.sv new file mode 100644 index 000000000..edc3d3ad8 --- /dev/null +++ b/regression/verilog/structs/unpacked_struct1.sv @@ -0,0 +1,11 @@ +module main; + + // an unpacked struct + struct { + bit field; + } s; + + // unpacked structs cannot be converted to bit-vectors + wire [8:0] w = s; + +endmodule diff --git a/regression/verilog/structs/unpacked_struct2.desc b/regression/verilog/structs/unpacked_struct2.desc new file mode 100644 index 000000000..f1c99907d --- /dev/null +++ b/regression/verilog/structs/unpacked_struct2.desc @@ -0,0 +1,7 @@ +CORE +unpacked_struct2.sv + +^file .* line 9: failed to convert `signed \[31:0\]' to `struct'$ +^EXIT=2$ +^SIGNAL=0$ +-- diff --git a/regression/verilog/structs/unpacked_struct2.sv b/regression/verilog/structs/unpacked_struct2.sv new file mode 100644 index 000000000..e267aa30f --- /dev/null +++ b/regression/verilog/structs/unpacked_struct2.sv @@ -0,0 +1,11 @@ +module main; + + // an unpacked struct type + typedef struct { + bit field; + } s_type; + + // bit-vectors cannot be assigned to unpacked structs + wire s_type w = 123; + +endmodule diff --git a/regression/verilog/synthesis/always_comb2.aig.desc b/regression/verilog/synthesis/always_comb2.aig.desc new file mode 100644 index 000000000..b206358cd --- /dev/null +++ b/regression/verilog/synthesis/always_comb2.aig.desc @@ -0,0 +1,12 @@ +KNOWNBUG +always_comb2.sv +--aig +^\[main\.p0\] always main\.data == 0 -> main\.decoded == 1: PROVED .*$ +^\[main\.p1\] always main\.data == 1 -> main\.decoded == 2: PROVED .*$ +^\[main\.p2\] always main\.data == 2 -> main\.decoded == 4: PROVED .*$ +^EXIT=0$ +^SIGNAL=0$ +-- +^warning: ignoring +-- +This segfaults. diff --git a/regression/verilog/system-functions/error1.desc b/regression/verilog/system-functions/error1.desc new file mode 100644 index 000000000..e2f68356f --- /dev/null +++ b/regression/verilog/system-functions/error1.desc @@ -0,0 +1,8 @@ +CORE +error1.v +--module main +^EXIT=10$ +^SIGNAL=0$ +-- +^warning: ignoring +-- diff --git a/regression/verilog/system-functions/error1.v b/regression/verilog/system-functions/error1.v new file mode 100644 index 000000000..7968fdcfb --- /dev/null +++ b/regression/verilog/system-functions/error1.v @@ -0,0 +1,8 @@ +module main; + + parameter P = 1; + + if(P==1) + $error("something is wrong"); + +endmodule diff --git a/regression/verilog/system-functions/past6.desc b/regression/verilog/system-functions/past6.desc index 79d8dc66c..3432b717a 100644 --- a/regression/verilog/system-functions/past6.desc +++ b/regression/verilog/system-functions/past6.desc @@ -1,4 +1,4 @@ -CORE +CORE broken-smt-backend past6.sv ^EXIT=10$ diff --git a/regression/verilog/unions/tagged_union1.desc b/regression/verilog/unions/tagged_union1.desc new file mode 100644 index 000000000..e32846731 --- /dev/null +++ b/regression/verilog/unions/tagged_union1.desc @@ -0,0 +1,8 @@ +CORE +tagged_union1.sv + +^file .* line 9: no support for tagged unions$ +^EXIT=2$ +^SIGNAL=0$ +-- +-- diff --git a/regression/verilog/unions/tagged_union1.sv b/regression/verilog/unions/tagged_union1.sv new file mode 100644 index 000000000..e79180035 --- /dev/null +++ b/regression/verilog/unions/tagged_union1.sv @@ -0,0 +1,11 @@ +module main; + typedef union tagged { + void Invalid; + int Valid; + } VInt; + + VInt v; + + initial v = tagged Invalid; + +endmodule diff --git a/src/Makefile b/src/Makefile index a1fc826b3..b5ded5f0f 100644 --- a/src/Makefile +++ b/src/Makefile @@ -21,7 +21,7 @@ ifneq ($(BUILD_ENV),MSVC) ebmc.dir: ic3.dir endif -hw-cbmc.dir: trans-word-level.dir trans-netlist.dir verilog.dir \ +hw-cbmc.dir: ebmc.dir trans-word-level.dir trans-netlist.dir verilog.dir \ vhdl.dir smvlang.dir cprover.dir temporal-logic.dir vlindex.dir: ebmc.dir cprover.dir verilog.dir diff --git a/src/config.inc b/src/config.inc index c54ee8987..435bdad5a 100644 --- a/src/config.inc +++ b/src/config.inc @@ -1 +1 @@ -EBMC_VERSION = 5.7 +EBMC_VERSION = 5.9 diff --git a/src/ebmc/Makefile b/src/ebmc/Makefile index 6dad84f45..de0fed92f 100644 --- a/src/ebmc/Makefile +++ b/src/ebmc/Makefile @@ -1,6 +1,7 @@ SRC = \ bdd_engine.cpp \ bmc.cpp \ + build_transition_system.cpp \ cegar/abstract.cpp \ cegar/bmc_cegar.cpp \ cegar/latch_ordering.cpp \ @@ -11,7 +12,8 @@ SRC = \ diameter.cpp \ diatest.cpp \ dimacs_writer.cpp \ - ebmc_base.cpp \ + ebmc_language.cpp \ + ebmc_language_file.cpp \ ebmc_languages.cpp \ ebmc_parse_options.cpp \ ebmc_properties.cpp \ @@ -34,6 +36,7 @@ SRC = \ ranking_function.cpp \ report_results.cpp \ show_formula_solver.cpp \ + show_modules.cpp \ show_properties.cpp \ show_trans.cpp \ tautology_check.cpp \ diff --git a/src/ebmc/build_transition_system.cpp b/src/ebmc/build_transition_system.cpp new file mode 100644 index 000000000..dbedc5e13 --- /dev/null +++ b/src/ebmc/build_transition_system.cpp @@ -0,0 +1,418 @@ +/*******************************************************************\ + +Module: Transition Systems for EBMC + +Author: Daniel Kroening, dkr@amazon.com + +\*******************************************************************/ + +#include "build_transition_system.h" + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include "ebmc_error.h" +#include "ebmc_language_file.h" +#include "ebmc_version.h" +#include "output_file.h" +#include "show_modules.h" +#include "transition_system.h" + +#include +#include + +void preprocess(const cmdlinet &cmdline, message_handlert &message_handler) +{ + messaget message(message_handler); + + if(cmdline.args.size() != 1) + throw ebmc_errort{}.with_exit_code(1) + << "please give exactly one file to preprocess"; + + const auto &filename = cmdline.args.front(); + std::ifstream infile(widen_if_needed(filename)); + + if(!infile) + throw ebmc_errort{}.with_exit_code(1) + << "failed to open input file `" << filename << "'"; + + auto language = get_language_from_filename(filename); + + if(language == nullptr) + { + source_locationt location; + location.set_file(filename); + throw ebmc_errort{}.with_location(location).with_exit_code(1) + << "failed to figure out type of file"; + } + + optionst options; + + // do -I + if(cmdline.isset('I')) + options.set_option("I", cmdline.get_values('I')); + + options.set_option("force-systemverilog", cmdline.isset("systemverilog")); + + // do -D + if(cmdline.isset('D')) + options.set_option("defines", cmdline.get_values('D')); + + language->set_language_options(options, message_handler); + + if(language->preprocess(infile, filename, std::cout, message_handler)) + throw ebmc_errort{}.with_exit_code(1); +} + +static bool parse( + const cmdlinet &cmdline, + const std::string &filename, + ebmc_language_filest &language_files, + message_handlert &message_handler) +{ + messaget message(message_handler); + + std::ifstream infile(widen_if_needed(filename)); + + if(!infile) + { + message.error() << "failed to open input file `" << filename << "'" + << messaget::eom; + return true; + } + + auto &lf = language_files.add_file(filename); + lf.filename = filename; + lf.language = get_language_from_filename(filename); + + if(lf.language == nullptr) + { + source_locationt location; + location.set_file(filename); + message.error().source_location = location; + message.error() << "failed to figure out type of file" << messaget::eom; + return true; + } + + languaget &language = *lf.language; + + optionst options; + + // do -I + if(cmdline.isset('I')) + options.set_option("I", cmdline.get_values('I')); + + options.set_option("force-systemverilog", cmdline.isset("systemverilog")); + options.set_option("vl2smv-extensions", cmdline.isset("vl2smv-extensions")); + options.set_option("warn-implicit-nets", cmdline.isset("warn-implicit-nets")); + + // do -D + if(cmdline.isset('D')) + options.set_option("defines", cmdline.get_values('D')); + + // do --ignore-initial + if(cmdline.isset("ignore-initial")) + options.set_option("ignore-initial", true); + + // do --initial-zero + if(cmdline.isset("initial-zero")) + options.set_option("initial-zero", true); + + language.set_language_options(options, message_handler); + + message.status() << "Parsing " << filename << messaget::eom; + + if(language.parse(infile, filename, message_handler)) + { + message.error() << "PARSING ERROR\n"; + return true; + } + + lf.get_modules(); + + return false; +} + +bool parse( + const cmdlinet &cmdline, + ebmc_language_filest &language_files, + message_handlert &message_handler) +{ + for(unsigned i = 0; i < cmdline.args.size(); i++) + { + if(parse(cmdline, cmdline.args[i], language_files, message_handler)) + return true; + } + return false; +} + +bool get_main( + const cmdlinet &cmdline, + message_handlert &message_handler, + transition_systemt &transition_system) +{ + std::string top_module; + + if(cmdline.isset("module")) + top_module = cmdline.get_value("module"); + else if(cmdline.isset("top")) + top_module = cmdline.get_value("top"); + + try + { + transition_system.main_symbol = + &get_module(transition_system.symbol_table, top_module, message_handler); + transition_system.trans_expr = + to_trans_expr(transition_system.main_symbol->value); + } + + catch(int e) + { + return true; + } + + return false; +} + +void make_next_state(exprt &expr) +{ + for(auto &sub_expression : expr.operands()) + make_next_state(sub_expression); + + if(expr.id() == ID_symbol) + expr.id(ID_next_symbol); +} + +int get_transition_system( + const cmdlinet &cmdline, + message_handlert &message_handler, + transition_systemt &transition_system) +{ + messaget message(message_handler); + + // + // parsing + // + ebmc_language_filest language_files; + + if(parse(cmdline, language_files, message_handler)) + return 1; + + if(cmdline.isset("show-parse")) + { + language_files.show_parse(std::cout, message_handler); + return 0; + } + + // + // type checking + // + + message.status() << "Converting" << messaget::eom; + + if(language_files.typecheck(transition_system.symbol_table, message_handler)) + { + message.error() << "CONVERSION ERROR" << messaget::eom; + return 2; + } + + if(cmdline.isset("show-modules")) + { + show_modulest::from_symbol_table(transition_system.symbol_table) + .plain_text(std::cout); + return 0; + } + + if(cmdline.isset("modules-xml")) + { + auto filename = cmdline.get_value("modules-xml"); + auto out_file = output_filet{filename}; + show_modulest::from_symbol_table(transition_system.symbol_table) + .xml(out_file.stream()); + return 0; + } + + if(cmdline.isset("json-modules")) + { + auto out_file = output_filet{cmdline.get_value("json-modules")}; + show_modulest::from_symbol_table(transition_system.symbol_table) + .json(out_file.stream()); + return 0; + } + + if(cmdline.isset("show-symbol-table")) + { + std::cout << transition_system.symbol_table; + return 0; + } + + // get module name + + if(get_main(cmdline, message_handler, transition_system)) + return 1; + + if(cmdline.isset("show-module-hierarchy")) + { + DATA_INVARIANT( + transition_system.main_symbol != nullptr, "must have main_symbol"); + show_module_hierarchy( + transition_system.symbol_table, + *transition_system.main_symbol, + std::cout); + return 0; + } + + // --reset given? + if(cmdline.isset("reset")) + { + namespacet ns(transition_system.symbol_table); + exprt reset_constraint = to_expr( + ns, transition_system.main_symbol->name, cmdline.get_value("reset")); + + // we want the constraint to be boolean + reset_constraint = + typecast_exprt::conditional_cast(reset_constraint, bool_typet{}); + + // true in initial state + transt new_trans_expr = transition_system.trans_expr; + new_trans_expr.init() = and_exprt(new_trans_expr.init(), reset_constraint); + + // and not anymore afterwards + exprt reset_next_state = reset_constraint; + make_next_state(reset_next_state); + + new_trans_expr.trans() = + and_exprt(new_trans_expr.trans(), not_exprt(reset_next_state)); + transition_system.trans_expr = new_trans_expr; + } + + return -1; // done with the transition system +} + +transition_systemt get_transition_system( + const cmdlinet &cmdline, + message_handlert &message_handler) +{ + transition_systemt transition_system; + auto exit_code = + get_transition_system(cmdline, message_handler, transition_system); + if(exit_code != -1) + throw ebmc_errort().with_exit_code(exit_code); + return transition_system; +} + +int show_parse(const cmdlinet &cmdline, message_handlert &message_handler) +{ + transition_systemt dummy_transition_system; + return get_transition_system( + cmdline, message_handler, dummy_transition_system); +} + +int show_modules(const cmdlinet &cmdline, message_handlert &message_handler) +{ + transition_systemt dummy_transition_system; + return get_transition_system( + cmdline, message_handler, dummy_transition_system); +} + +int show_module_hierarchy( + const cmdlinet &cmdline, + message_handlert &message_handler) +{ + transition_systemt dummy_transition_system; + return get_transition_system( + cmdline, message_handler, dummy_transition_system); +} + +int show_symbol_table( + const cmdlinet &cmdline, + message_handlert &message_handler) +{ + transition_systemt dummy_transition_system; + return get_transition_system( + cmdline, message_handler, dummy_transition_system); +} + +static std::set file_extensions(const cmdlinet::argst &args) +{ + std::set result; + + for(auto &arg : args) + { + std::size_t ext_pos = arg.rfind('.'); + + if(ext_pos != std::string::npos) + { + auto ext = std::string(arg, ext_pos + 1, std::string::npos); + result.insert(ext); + } + } + + return result; +} + +std::optional ebmc_languagest::transition_system() +{ + auto extensions = file_extensions(cmdline.args); + auto ext_used = [&extensions](const char *ext) + { return extensions.find(ext) != extensions.end(); }; + + bool have_smv = ext_used("smv"); + bool have_verilog = ext_used("v") || ext_used("sv"); + + if(have_smv && have_verilog) + { + throw ebmc_errort{} << "no support for mixed-language models"; + } + + if(have_smv) + { + return smv_ebmc_languaget{cmdline, message_handler}.transition_system(); + } + else + { + if(cmdline.isset("preprocess")) + { + preprocess(cmdline, message_handler); + return {}; + } + + if(cmdline.isset("show-parse")) + { + show_parse(cmdline, message_handler); + return {}; + } + + if( + cmdline.isset("show-modules") || cmdline.isset("modules-xml") || + cmdline.isset("json-modules")) + { + show_modules(cmdline, message_handler); + return {}; + } + + if(cmdline.isset("show-module-hierarchy")) + { + show_module_hierarchy(cmdline, message_handler); + return {}; + } + + if(cmdline.isset("show-symbol-table")) + { + show_symbol_table(cmdline, message_handler); + return {}; + } + + return get_transition_system(cmdline, message_handler); + } +} diff --git a/src/ebmc/build_transition_system.h b/src/ebmc/build_transition_system.h new file mode 100644 index 000000000..35c345a2f --- /dev/null +++ b/src/ebmc/build_transition_system.h @@ -0,0 +1,33 @@ +/*******************************************************************\ + +Module: Transition Systems for EBMC + +Author: Daniel Kroening, dkr@amazon.com + +\*******************************************************************/ + +#ifndef CPROVER_EBMC_BUILD_TRANSITION_SYSTEM_H +#define CPROVER_EBMC_BUILD_TRANSITION_SYSTEM_H + +#include "ebmc_language.h" + +transition_systemt get_transition_system(const cmdlinet &, message_handlert &); + +void preprocess(const cmdlinet &, message_handlert &); +int show_parse(const cmdlinet &, message_handlert &); +int show_modules(const cmdlinet &, message_handlert &); +int show_module_hierarchy(const cmdlinet &, message_handlert &); +int show_symbol_table(const cmdlinet &, message_handlert &); + +class ebmc_languagest : public ebmc_languaget +{ +public: + ebmc_languagest(cmdlinet &_cmdline, message_handlert &_message_handler) + : ebmc_languaget{_cmdline, _message_handler} + { + } + + std::optional transition_system() override; +}; + +#endif // CPROVER_EBMC_BUILD_TRANSITION_SYSTEM_H diff --git a/src/ebmc/ebmc_base.cpp b/src/ebmc/ebmc_base.cpp deleted file mode 100644 index 1dc8b596a..000000000 --- a/src/ebmc/ebmc_base.cpp +++ /dev/null @@ -1,188 +0,0 @@ -/*******************************************************************\ - -Module: Base for Verification Modules - -Author: Daniel Kroening, kroening@kroening.com - -\*******************************************************************/ - -#include "ebmc_base.h" - -#include -#include - -#include -#include - -#include "ebmc_error.h" -#include "ebmc_version.h" -#include "netlist.h" - -#include - -/*******************************************************************\ - -Function: ebmc_baset::ebmc_baset - - Inputs: - - Outputs: - - Purpose: - -\*******************************************************************/ - -ebmc_baset::ebmc_baset( - const cmdlinet &_cmdline, - ui_message_handlert &_ui_message_handler) - : message(_ui_message_handler), cmdline(_cmdline) -{ -} - -/*******************************************************************\ - -Function: ebmc_baset::get_properties - - Inputs: - - Outputs: - - Purpose: - -\*******************************************************************/ - -int ebmc_baset::get_properties() -{ - properties = ebmc_propertiest::from_command_line( - cmdline, transition_system, message.get_message_handler()); - - return -1; // done -} - -/*******************************************************************\ - -Function: ebmc_baset::show_ldg - - Inputs: - - Outputs: - - Purpose: - -\*******************************************************************/ - -void ebmc_baset::show_ldg(std::ostream &out) -{ - netlistt netlist; - - if(make_netlist(netlist)) - return; - - if(!netlist.transition.empty()) - out << "WARNING: transition constraint found!" << '\n' - << '\n'; - - ldgt ldg; - - ldg.compute(netlist); - - out << "Latch dependencies:" << '\n'; - - for(var_mapt::mapt::const_iterator - it=netlist.var_map.map.begin(); - it!=netlist.var_map.map.end(); - it++) - { - const var_mapt::vart &var=it->second; - - for(std::size_t i=0; ifirst - << "[" << i << "] = " << v << ":"; - - const ldg_nodet &node=ldg[v]; - - for(ldg_nodet::edgest::const_iterator - i_it=node.in.begin(); - i_it!=node.in.end(); - i_it++) - out << " " << i_it->first; - - out << '\n'; - } - } - } -} - -/*******************************************************************\ - -Function: ebmc_baset::make_netlist - - Inputs: - - Outputs: - - Purpose: - -\*******************************************************************/ - -bool ebmc_baset::make_netlist(netlistt &netlist) -{ - // make net-list - message.status() << "Generating Netlist" << messaget::eom; - - try - { - netlist = ::make_netlist( - transition_system, properties, message.get_message_handler()); - } - - catch(const std::string &error_str) - { - message.error() << error_str << messaget::eom; - return true; - } - - message.statistics() << "Latches: " << netlist.var_map.latches.size() - << ", nodes: " << netlist.number_of_nodes() - << messaget::eom; - - return false; -} - -/*******************************************************************\ - -Function: ebmc_baset::do_compute_ct - - Inputs: - - Outputs: - - Purpose: - -\*******************************************************************/ - -int ebmc_baset::do_compute_ct() -{ - // make net-list - message.status() << "Making Netlist" << messaget::eom; - - netlistt netlist; - if(make_netlist(netlist)) return 1; - - message.status() << "Latches: " << netlist.var_map.latches.size() - << ", nodes: " << netlist.number_of_nodes() << messaget::eom; - - message.status() << "Making LDG" << messaget::eom; - - ldgt ldg; - ldg.compute(netlist); - - std::cout << "CT = " << compute_ct(ldg) << '\n'; - - return 0; -} diff --git a/src/ebmc/ebmc_base.h b/src/ebmc/ebmc_base.h deleted file mode 100644 index dafd7db8f..000000000 --- a/src/ebmc/ebmc_base.h +++ /dev/null @@ -1,61 +0,0 @@ -/*******************************************************************\ - -Module: Base for Verification Modules - -Author: Daniel Kroening, kroening@kroening.com - -\*******************************************************************/ - -#ifndef CPROVER_EBMC_EBMC_BASE_H -#define CPROVER_EBMC_EBMC_BASE_H - -#include -#include -#include -#include - -#include -#include -#include -#include -#include - -#include "ebmc_properties.h" -#include "transition_system.h" - -#include - -class ebmc_baset -{ -public: - ebmc_baset(const cmdlinet &_cmdline, - ui_message_handlert &_ui_message_handler); - virtual ~ebmc_baset() { } - - int get_properties(); - void show_ldg(std::ostream &out); - bool make_netlist(netlistt &); - - transition_systemt transition_system; - - using propertyt = ebmc_propertiest::propertyt; - ebmc_propertiest properties; - -protected: - messaget message; - const cmdlinet &cmdline; - - bool parse_property(const std::string &property); - bool get_model_properties(); - - bool parse(); - bool parse(const std::string &filename); - bool typecheck(); - - std::size_t bound; - -public: - int do_compute_ct(); -}; - -#endif diff --git a/src/ebmc/ebmc_language.cpp b/src/ebmc/ebmc_language.cpp new file mode 100644 index 000000000..2eddf7e72 --- /dev/null +++ b/src/ebmc/ebmc_language.cpp @@ -0,0 +1,13 @@ +/*******************************************************************\ + +Module: Abstract interface to support a modeling language + +Author: Daniel Kroening, dkr@amazon.com + +\*******************************************************************/ + +#include "ebmc_language.h" + +ebmc_languaget::~ebmc_languaget() +{ +} diff --git a/src/ebmc/ebmc_language.h b/src/ebmc/ebmc_language.h new file mode 100644 index 000000000..d49f80917 --- /dev/null +++ b/src/ebmc/ebmc_language.h @@ -0,0 +1,42 @@ +/*******************************************************************\ + +Module: Abstract interface to support a modeling language + +Author: Daniel Kroening, dkr@amazon.com + +\*******************************************************************/ + +/// \file +/// Abstract interface to support a modeling language + +#ifndef EBMC_LANGUAGE_H +#define EBMC_LANGUAGE_H + +#include +#include + +class cmdlinet; +class message_handlert; +class transition_systemt; + +class ebmc_languaget +{ +public: + // constructor / destructor + ebmc_languaget(cmdlinet &_cmdline, message_handlert &_message_handler) + : cmdline(_cmdline), message_handler(_message_handler) + { + } + + virtual ~ebmc_languaget(); + + /// Produce the transition system, and return it; + /// returns {} when diagnostic output was produced instead. + virtual std::optional transition_system() = 0; + +protected: + cmdlinet &cmdline; + message_handlert &message_handler; +}; + +#endif // EBMC_LANGUAGE_H diff --git a/src/ebmc/ebmc_language_file.cpp b/src/ebmc/ebmc_language_file.cpp new file mode 100644 index 000000000..e4d8b8b6d --- /dev/null +++ b/src/ebmc/ebmc_language_file.cpp @@ -0,0 +1,298 @@ +/*******************************************************************\ + +Module: + +Author: Daniel Kroening, kroening@kroening.com + +\*******************************************************************/ + +#include "ebmc_language_file.h" + +#include + +#include + +#include + +ebmc_language_filet::ebmc_language_filet(const ebmc_language_filet &rhs) + : modules(rhs.modules), + language(rhs.language == nullptr ? nullptr : rhs.language->new_language()), + filename(rhs.filename) +{ +} + +/// To avoid compiler errors, the complete definition of a pointed-to type must +/// be visible at the point at which the unique_ptr destructor is created. In +/// this case, the pointed-to type is forward-declared, so we have to place the +/// destructor in the source file, where the full definition is availible. +ebmc_language_filet::~ebmc_language_filet() = default; + +ebmc_language_filet::ebmc_language_filet(const std::string &filename) + : filename(filename) +{ +} + +void ebmc_language_filet::get_modules() +{ + language->modules_provided(modules); +} + +void ebmc_language_filet::convert_lazy_method( + const irep_idt &id, + symbol_table_baset &symbol_table, + message_handlert &message_handler) +{ + language->convert_lazy_method(id, symbol_table, message_handler); +} + +void ebmc_language_filest::show_parse( + std::ostream &out, + message_handlert &message_handler) +{ + for(const auto &file : file_map) + file.second.language->show_parse(out, message_handler); +} + +bool ebmc_language_filest::parse(message_handlert &message_handler) +{ + messaget log(message_handler); + + for(auto &file : file_map) + { + // open file + + std::ifstream infile(file.first); + + if(!infile) + { + log.error() << "Failed to open " << file.first << messaget::eom; + return true; + } + + // parse it + + languaget &language = *(file.second.language); + + if(language.parse(infile, file.first, message_handler)) + { + log.error() << "Parsing of " << file.first << " failed" << messaget::eom; + return true; + } + + // what is provided? + + file.second.get_modules(); + } + + return false; +} + +bool ebmc_language_filest::typecheck( + symbol_table_baset &symbol_table, + const bool keep_file_local, + message_handlert &message_handler) +{ + // typecheck interfaces + + for(auto &file : file_map) + { + if(file.second.language->interfaces(symbol_table, message_handler)) + return true; + } + + // build module map + + unsigned collision_counter = 0; + + for(auto &file : file_map) + { + const ebmc_language_filet::modulest &modules = file.second.modules; + + for(ebmc_language_filet::modulest::const_iterator mo_it = modules.begin(); + mo_it != modules.end(); + mo_it++) + { + // these may collide, and then get renamed + std::string module_name = *mo_it; + + while(module_map.find(module_name) != module_map.end()) + { + module_name = *mo_it + "#" + std::to_string(collision_counter); + collision_counter++; + } + + ebmc_language_modulet module; + module.file = &file.second; + module.name = module_name; + module_map.insert( + std::pair(module.name, module)); + } + } + + // typecheck files + + for(auto &file : file_map) + { + if(file.second.modules.empty()) + { + if(file.second.language->can_keep_file_local()) + { + if(file.second.language->typecheck( + symbol_table, "", message_handler, keep_file_local)) + return true; + } + else + { + if(file.second.language->typecheck(symbol_table, "", message_handler)) + return true; + } + // register lazy methods. + // TODO: learn about modules and generalise this + // to module-providing languages if required. + std::unordered_set lazy_method_ids; + file.second.language->methods_provided(lazy_method_ids); + for(const auto &id : lazy_method_ids) + lazy_method_map[id] = &file.second; + } + } + + // typecheck modules + + for(auto &module : module_map) + { + if(typecheck_module( + symbol_table, module.second, keep_file_local, message_handler)) + return true; + } + + return false; +} + +bool ebmc_language_filest::generate_support_functions( + symbol_table_baset &symbol_table, + message_handlert &message_handler) +{ + std::set languages; + + for(auto &file : file_map) + { + if(languages.insert(file.second.language->id()).second) + if(file.second.language->generate_support_functions( + symbol_table, message_handler)) + return true; + } + + return false; +} + +bool ebmc_language_filest::final(symbol_table_baset &symbol_table) +{ + std::set languages; + + for(auto &file : file_map) + { + if(languages.insert(file.second.language->id()).second) + if(file.second.language->final(symbol_table)) + return true; + } + + return false; +} + +bool ebmc_language_filest::interfaces( + symbol_table_baset &symbol_table, + message_handlert &message_handler) +{ + for(auto &file : file_map) + { + if(file.second.language->interfaces(symbol_table, message_handler)) + return true; + } + + return false; +} + +bool ebmc_language_filest::typecheck_module( + symbol_table_baset &symbol_table, + const std::string &module, + const bool keep_file_local, + message_handlert &message_handler) +{ + // check module map + + module_mapt::iterator it = module_map.find(module); + + if(it == module_map.end()) + { + messaget log(message_handler); + log.error() << "found no file that provides module " << module + << messaget::eom; + return true; + } + + return typecheck_module( + symbol_table, it->second, keep_file_local, message_handler); +} + +bool ebmc_language_filest::typecheck_module( + symbol_table_baset &symbol_table, + ebmc_language_modulet &module, + const bool keep_file_local, + message_handlert &message_handler) +{ + // already typechecked? + + if(module.type_checked) + return false; + + messaget log(message_handler); + + // already in progress? + + if(module.in_progress) + { + log.error() << "circular dependency in " << module.name << messaget::eom; + return true; + } + + module.in_progress = true; + + // first get dependencies of current module + + std::set dependency_set; + + module.file->language->dependencies(module.name, dependency_set); + + for(std::set::const_iterator it = dependency_set.begin(); + it != dependency_set.end(); + it++) + { + module.in_progress = + !typecheck_module(symbol_table, *it, keep_file_local, message_handler); + if(module.in_progress == false) + return true; + } + + // type check it + + log.status() << "Type-checking " << module.name << messaget::eom; + + if(module.file->language->can_keep_file_local()) + { + module.in_progress = !module.file->language->typecheck( + symbol_table, module.name, message_handler, keep_file_local); + } + else + { + module.in_progress = !module.file->language->typecheck( + symbol_table, module.name, message_handler); + } + + if(!module.in_progress) + return true; + + module.type_checked = true; + module.in_progress = false; + + return false; +} diff --git a/src/ebmc/ebmc_language_file.h b/src/ebmc/ebmc_language_file.h new file mode 100644 index 000000000..cf904c2c1 --- /dev/null +++ b/src/ebmc/ebmc_language_file.h @@ -0,0 +1,169 @@ +/*******************************************************************\ + +Module: + +Author: Daniel Kroening, kroening@kroening.com + +\*******************************************************************/ + +#ifndef CPROVER_LANGAPI_LANGUAGE_FILE_H +#define CPROVER_LANGAPI_LANGUAGE_FILE_H + +#include + +#include +#include +#include // unique_ptr +#include +#include +#include + +class message_handlert; +class ebmc_language_filet; +class languaget; + +class ebmc_language_modulet final +{ +public: + std::string name; + bool type_checked, in_progress; + ebmc_language_filet *file; + + ebmc_language_modulet() + : type_checked(false), in_progress(false), file(nullptr) + { + } +}; + +class ebmc_language_filet final +{ +public: + typedef std::set modulest; + modulest modules; + + std::unique_ptr language; + std::string filename; + + void get_modules(); + + void convert_lazy_method( + const irep_idt &id, + symbol_table_baset &symbol_table, + message_handlert &message_handler); + + explicit ebmc_language_filet(const std::string &filename); + ebmc_language_filet(const ebmc_language_filet &rhs); + + ~ebmc_language_filet(); +}; + +class ebmc_language_filest +{ +private: + typedef std::map file_mapt; + file_mapt file_map; + + typedef std::map module_mapt; + module_mapt module_map; + + // Contains pointers into file_map! + // This is safe-ish as long as this is std::map. + typedef std::map lazy_method_mapt; + lazy_method_mapt lazy_method_map; + +public: + ebmc_language_filet &add_file(const std::string &filename) + { + ebmc_language_filet language_file(filename); + return file_map.emplace(filename, std::move(language_file)).first->second; + } + + void remove_file(const std::string &filename) + { + // Clear relevant entries from lazy_method_map + ebmc_language_filet *language_file = &file_map.at(filename); + std::unordered_set files_methods; + for(auto const &method : lazy_method_map) + { + if(method.second == language_file) + files_methods.insert(method.first); + } + for(const irep_idt &method_name : files_methods) + lazy_method_map.erase(method_name); + + file_map.erase(filename); + } + + void clear_files() + { + lazy_method_map.clear(); + file_map.clear(); + } + + bool parse(message_handlert &message_handler); + + void show_parse(std::ostream &out, message_handlert &message_handler); + + bool generate_support_functions( + symbol_table_baset &symbol_table, + message_handlert &message_handler); + + bool + + typecheck( + symbol_table_baset &symbol_table, + const bool keep_file_local, + message_handlert &message_handler); + bool + typecheck(symbol_table_baset &symbol_table, message_handlert &message_handler) + { + return typecheck(symbol_table, false, message_handler); + } + + bool final(symbol_table_baset &symbol_table); + + bool interfaces( + symbol_table_baset &symbol_table, + message_handlert &message_handler); + + // The method must have been added to the symbol table and registered + // in lazy_method_map (currently always in language_filest::typecheck) + // for this to be legal. + void convert_lazy_method( + const irep_idt &id, + symbol_table_baset &symbol_table, + message_handlert &message_handler) + { + PRECONDITION(symbol_table.has_symbol(id)); + lazy_method_mapt::iterator it = lazy_method_map.find(id); + if(it != lazy_method_map.end()) + it->second->convert_lazy_method(id, symbol_table, message_handler); + } + + bool can_convert_lazy_method(const irep_idt &id) const + { + return lazy_method_map.count(id) != 0; + } + + void clear() + { + file_map.clear(); + module_map.clear(); + lazy_method_map.clear(); + } + +protected: + bool typecheck_module( + symbol_table_baset &symbol_table, + ebmc_language_modulet &module, + const bool keep_file_local, + message_handlert &message_handler); + + bool typecheck_module( + symbol_table_baset &symbol_table, + const std::string &module, + const bool keep_file_local, + message_handlert &message_handler); +}; + +#endif // CPROVER_UTIL_LANGUAGE_FILE_H diff --git a/src/ebmc/ebmc_parse_options.cpp b/src/ebmc/ebmc_parse_options.cpp index ec0bfc6b1..d377a06ba 100644 --- a/src/ebmc/ebmc_parse_options.cpp +++ b/src/ebmc/ebmc_parse_options.cpp @@ -13,14 +13,18 @@ Author: Daniel Kroening, kroening@kroening.com #include #include +#include +#include #include +#include "build_transition_system.h" #include "diatest.h" -#include "ebmc_base.h" #include "ebmc_error.h" +#include "ebmc_language.h" #include "ebmc_version.h" #include "format_hooks.h" #include "instrument_buechi.h" +#include "instrument_past.h" #include "liveness_to_safety.h" #include "netlist.h" #include "neural_liveness.h" @@ -106,23 +110,6 @@ int ebmc_parse_optionst::doit() return 0; } - if(cmdline.isset("preprocess")) - return preprocess(cmdline, ui_message_handler); - - if(cmdline.isset("show-parse")) - return show_parse(cmdline, ui_message_handler); - - if( - cmdline.isset("show-modules") || cmdline.isset("modules-xml") || - cmdline.isset("json-modules")) - return show_modules(cmdline, ui_message_handler); - - if(cmdline.isset("show-module-hierarchy")) - return show_module_hierarchy(cmdline, ui_message_handler); - - if(cmdline.isset("show-symbol-table")) - return show_symbol_table(cmdline, ui_message_handler); - if(cmdline.isset("coverage")) { throw ebmc_errort() << "This option is currently disabled"; @@ -138,18 +125,6 @@ int ebmc_parse_optionst::doit() #endif } - if(cmdline.isset("random-traces")) - return random_traces(cmdline, ui_message_handler); - - if(cmdline.isset("random-trace") || cmdline.isset("random-waveform")) - return random_trace(cmdline, ui_message_handler); - - if(cmdline.isset("neural-liveness")) - return do_neural_liveness(cmdline, ui_message_handler); - - if(cmdline.isset("ranking-function")) - return do_ranking_function(cmdline, ui_message_handler); - if(cmdline.isset("interpolation-word")) { throw ebmc_errort() << "This option is currently disabled"; @@ -206,7 +181,28 @@ int ebmc_parse_optionst::doit() } // get the transition system - auto transition_system = get_transition_system(cmdline, ui_message_handler); + ebmc_languagest ebmc_languages{cmdline, ui_message_handler}; + + auto transition_system_opt = ebmc_languages.transition_system(); + + // Did we produce diagnostics instead? + if(!transition_system_opt.has_value()) + return 0; + + auto &transition_system = transition_system_opt.value(); + + if(cmdline.isset("random-traces")) + return random_traces(transition_system, cmdline, ui_message_handler); + + if(cmdline.isset("random-trace") || cmdline.isset("random-waveform")) + return random_trace(transition_system, cmdline, ui_message_handler); + + if(cmdline.isset("neural-liveness")) + return do_neural_liveness(transition_system, cmdline, ui_message_handler); + + if(cmdline.isset("ranking-function")) + return do_ranking_function( + transition_system, cmdline, ui_message_handler); // get the properties auto properties = ebmc_propertiest::from_command_line( @@ -234,6 +230,8 @@ int ebmc_parse_optionst::doit() if(cmdline.isset("smv-word-level")) { + // There is no $past in SMV. + instrument_past(transition_system, properties); auto filename = cmdline.value_opt("outfile").value_or("-"); output_filet output_file{filename}; output_smv_word_level( @@ -273,10 +271,19 @@ int ebmc_parse_optionst::doit() if(cmdline.isset("show-ldg")) { - ebmc_baset ebmc_base(cmdline, ui_message_handler); - ebmc_base.transition_system = std::move(transition_system); - ebmc_base.properties = std::move(properties); - ebmc_base.show_ldg(std::cout); + auto netlist = + make_netlist(transition_system, properties, ui_message_handler); + + if(!netlist.transition.empty()) + { + messaget message(ui_message_handler); + message.warning() << "transition constraint found!" << messaget::eom; + } + + ldgt ldg; + ldg.compute(netlist); + std::cout << "Latch dependencies:" << '\n'; + ldg.output(netlist, std::cout); return 0; } @@ -324,10 +331,21 @@ int ebmc_parse_optionst::doit() if(cmdline.isset("compute-ct")) { - ebmc_baset ebmc_base(cmdline, ui_message_handler); - ebmc_base.transition_system = std::move(transition_system); - ebmc_base.properties = std::move(properties); - return ebmc_base.do_compute_ct(); + auto netlist = + make_netlist(transition_system, properties, ui_message_handler); + + messaget message{ui_message_handler}; + + message.status() << "Latches: " << netlist.var_map.latches.size() + << ", nodes: " << netlist.number_of_nodes() + << messaget::eom; + + message.status() << "Making LDG" << messaget::eom; + + ldgt ldg; + ldg.compute(netlist); + std::cout << "CT = " << compute_ct(ldg) << '\n'; + return 0; } auto checker_result = property_checker( diff --git a/src/ebmc/instrument_buechi.cpp b/src/ebmc/instrument_buechi.cpp index b17db5b10..7604429d2 100644 --- a/src/ebmc/instrument_buechi.cpp +++ b/src/ebmc/instrument_buechi.cpp @@ -25,9 +25,7 @@ void instrument_buechi( continue; // This is for LTL and some fragment of SVA only. - if( - !is_LTL(property.normalized_expr) && - !is_Buechi_SVA(property.normalized_expr)) + if(!is_LTL(property.normalized_expr) && !is_SVA(property.normalized_expr)) { property.unsupported("not convertible to Buechi"); continue; @@ -37,65 +35,74 @@ void instrument_buechi( message.debug() << "Translating " << property.description << " to Buechi" << messaget::eom; - // make the automaton for the negation of the property - auto buechi = - ltl_to_buechi(not_exprt{property.normalized_expr}, message_handler); - - // make a fresh symbol for the state of the automaton - namespacet ns(transition_system.symbol_table); - auto property_symbol = ns.lookup(property.identifier); - - auxiliary_symbolt new_state_symbol{ - id2string(property_symbol.name) + "::buechi_state", - buechi.state_symbol.type(), - property_symbol.mode}; - new_state_symbol.is_state_var = true; - new_state_symbol.module = property_symbol.module; - - buechi.rename_state_symbol(new_state_symbol.symbol_expr()); - - // add the new symbol to the symbol table - transition_system.symbol_table.add(std::move(new_state_symbol)); - - // add the automaton to the transition system - transition_system.trans_expr.init() = - and_exprt{transition_system.trans_expr.init(), buechi.init}; - - transition_system.trans_expr.trans() = - and_exprt{transition_system.trans_expr.trans(), buechi.trans}; - - // Replace the normalized property expression - // by the Buechi acceptance condition. - exprt::operandst property_conjuncts; - - bool have_liveness = false, have_safety = false; - - if(!buechi.liveness_signal.is_false()) + try { - // Note that we have negated the property, - // so this is the negation of the Buechi acceptance condition. - property_conjuncts.push_back( - F_exprt{G_exprt{not_exprt{buechi.liveness_signal}}}); - have_liveness = true; + // make the automaton for the negation of the property + auto buechi = + ltl_to_buechi(not_exprt{property.normalized_expr}, message_handler); + + // make a fresh symbol for the state of the automaton + namespacet ns(transition_system.symbol_table); + auto property_symbol = ns.lookup(property.identifier); + + auxiliary_symbolt new_state_symbol{ + id2string(property_symbol.name) + "::buechi_state", + buechi.state_symbol.type(), + property_symbol.mode}; + new_state_symbol.is_state_var = true; + new_state_symbol.module = property_symbol.module; + + buechi.rename_state_symbol(new_state_symbol.symbol_expr()); + + // add the new symbol to the symbol table + transition_system.symbol_table.add(std::move(new_state_symbol)); + + // add the automaton to the transition system + transition_system.trans_expr.init() = + and_exprt{transition_system.trans_expr.init(), buechi.init}; + + transition_system.trans_expr.trans() = + and_exprt{transition_system.trans_expr.trans(), buechi.trans}; + + // Replace the normalized property expression + // by the Buechi acceptance condition. + exprt::operandst property_conjuncts; + + bool have_liveness = false, have_safety = false; + + if(!buechi.liveness_signal.is_false()) + { + // Note that we have negated the property, + // so this is the negation of the Buechi acceptance condition. + property_conjuncts.push_back( + F_exprt{G_exprt{not_exprt{buechi.liveness_signal}}}); + have_liveness = true; + } + + if(!buechi.error_signal.is_true()) + { + property_conjuncts.push_back(G_exprt{not_exprt{buechi.error_signal}}); + have_safety = true; + } + + if(have_liveness && have_safety) + message.debug() << "Buechi automaton has liveness and safety components" + << messaget::eom; + else if(have_liveness) + message.debug() << "Buechi automaton is liveness only" << messaget::eom; + else if(have_safety) + message.debug() << "Buechi automaton is safety only" << messaget::eom; + + property.normalized_expr = conjunction(property_conjuncts); + + message.debug() << "New property: " << format(property.normalized_expr) + << messaget::eom; } - - if(!buechi.error_signal.is_true()) + catch(ltl_to_buechi_unsupportedt error) { - property_conjuncts.push_back(G_exprt{not_exprt{buechi.error_signal}}); - have_safety = true; + property.unsupported( + error.expr.id_string() + " not convertible to Buechi"); + continue; } - - if(have_liveness && have_safety) - message.debug() << "Buechi automaton has liveness and safety components" - << messaget::eom; - else if(have_liveness) - message.debug() << "Buechi automaton is liveness only" << messaget::eom; - else if(have_safety) - message.debug() << "Buechi automaton is safety only" << messaget::eom; - - property.normalized_expr = conjunction(property_conjuncts); - - message.debug() << "New property: " << format(property.normalized_expr) - << messaget::eom; } } diff --git a/src/ebmc/neural_liveness.cpp b/src/ebmc/neural_liveness.cpp index 13aac05a3..5188f92cc 100644 --- a/src/ebmc/neural_liveness.cpp +++ b/src/ebmc/neural_liveness.cpp @@ -41,10 +41,14 @@ Author: Daniel Kroening, dkr@amazon.com class neural_livenesst { public: - neural_livenesst(const cmdlinet &_cmdline, message_handlert &_message_handler) + neural_livenesst( + transition_systemt &_transition_system, + const cmdlinet &_cmdline, + message_handlert &_message_handler) : cmdline(_cmdline), message(_message_handler), - solver_factory(ebmc_solver_factory(_cmdline)) + solver_factory(ebmc_solver_factory(_cmdline)), + transition_system(_transition_system) { } @@ -54,7 +58,7 @@ class neural_livenesst const cmdlinet &cmdline; messaget message; ebmc_solver_factoryt solver_factory; - transition_systemt transition_system; + transition_systemt &transition_system; ebmc_propertiest properties; int show_traces(); @@ -74,9 +78,6 @@ int neural_livenesst::operator()() if(!cmdline.isset("neural-engine")) throw ebmc_errort() << "give a neural engine"; - transition_system = - get_transition_system(cmdline, message.get_message_handler()); - // Get the properties properties = ebmc_propertiest::from_command_line( cmdline, transition_system, message.get_message_handler()); @@ -126,9 +127,6 @@ int neural_livenesst::operator()() int neural_livenesst::show_traces() { - transition_system = - get_transition_system(cmdline, message.get_message_handler()); - properties = ebmc_propertiest::from_command_line( cmdline, transition_system, message.get_message_handler()); @@ -316,8 +314,9 @@ tvt neural_livenesst::verify( } int do_neural_liveness( + transition_systemt &transition_system, const cmdlinet &cmdline, - ui_message_handlert &ui_message_handler) + message_handlert &message_handler) { - return neural_livenesst(cmdline, ui_message_handler)(); + return neural_livenesst{transition_system, cmdline, message_handler}(); } diff --git a/src/ebmc/neural_liveness.h b/src/ebmc/neural_liveness.h index 159f38208..ed47bb555 100644 --- a/src/ebmc/neural_liveness.h +++ b/src/ebmc/neural_liveness.h @@ -9,9 +9,13 @@ Author: Daniel Kroening, dkr@amazon.com #ifndef EBMC_NEURAL_LIVENESS_H #define EBMC_NEURAL_LIVENESS_H -#include -#include +class cmdlinet; +class message_handlert; +class transition_systemt; -int do_neural_liveness(const cmdlinet &, ui_message_handlert &); +int do_neural_liveness( + transition_systemt &, + const cmdlinet &, + message_handlert &); #endif // EBMC_NEURAL_LIVENESS_H diff --git a/src/ebmc/output_smv_word_level.cpp b/src/ebmc/output_smv_word_level.cpp index 2e0f96ddf..ba7081074 100644 --- a/src/ebmc/output_smv_word_level.cpp +++ b/src/ebmc/output_smv_word_level.cpp @@ -45,7 +45,8 @@ operator<<(std::ostream &out, const smv_type_printert &type_printer) if( type.id() == ID_bool || type.id() == ID_signedbv || - type.id() == ID_unsignedbv || type.id() == ID_range) + type.id() == ID_unsignedbv || type.id() == ID_range || + type.id() == ID_array) { return out << type2smv(type, ns); } diff --git a/src/ebmc/random_traces.cpp b/src/ebmc/random_traces.cpp index 68ef7b420..978a11d60 100644 --- a/src/ebmc/random_traces.cpp +++ b/src/ebmc/random_traces.cpp @@ -20,9 +20,9 @@ Author: Daniel Kroening, kroening@kroening.com #include #include -#include "ebmc_base.h" #include "ebmc_error.h" #include "output_file.h" +#include "transition_system.h" #include "waveform.h" #include @@ -112,7 +112,10 @@ Function: random_traces \*******************************************************************/ -int random_traces(const cmdlinet &cmdline, message_handlert &message_handler) +int random_traces( + const transition_systemt &transition_system, + const cmdlinet &cmdline, + message_handlert &message_handler) { const auto number_of_traces = [&cmdline]() -> std::size_t { if(cmdline.isset("traces")) @@ -171,9 +174,6 @@ int random_traces(const cmdlinet &cmdline, message_handlert &message_handler) return {}; }(); - transition_systemt transition_system = - get_transition_system(cmdline, message_handler); - if(cmdline.isset("waveform") && cmdline.isset("vcd")) throw ebmc_errort() << "cannot do VCD and ASCII waveform simultaneously"; @@ -231,7 +231,10 @@ Function: random_trace \*******************************************************************/ -int random_trace(const cmdlinet &cmdline, message_handlert &message_handler) +int random_trace( + const transition_systemt &transition_system, + const cmdlinet &cmdline, + message_handlert &message_handler) { if(cmdline.isset("traces")) throw ebmc_errort() << "must not give number of traces"; @@ -275,9 +278,6 @@ int random_trace(const cmdlinet &cmdline, message_handlert &message_handler) return 10; // default }(); - transition_systemt transition_system = - get_transition_system(cmdline, message_handler); - auto consumer = [&](trans_tracet trace) -> void { namespacet ns(transition_system.symbol_table); if(cmdline.isset("random-waveform") || cmdline.isset("waveform")) diff --git a/src/ebmc/random_traces.h b/src/ebmc/random_traces.h index ccb03b584..92ba55645 100644 --- a/src/ebmc/random_traces.h +++ b/src/ebmc/random_traces.h @@ -16,14 +16,20 @@ Author: Daniel Kroening, kroening@kroening.com class cmdlinet; class message_handlert; +class transition_systemt; // many traces -int random_traces(const cmdlinet &, message_handlert &); +int random_traces( + const transition_systemt &, + const cmdlinet &, + message_handlert &); // just one trace -int random_trace(const cmdlinet &, message_handlert &); +int random_trace( + const transition_systemt &, + const cmdlinet &, + message_handlert &); -class transition_systemt; class trans_tracet; // many traces, VCD diff --git a/src/ebmc/ranking_function.cpp b/src/ebmc/ranking_function.cpp index 2e7ad5ed3..9a5602f5b 100644 --- a/src/ebmc/ranking_function.cpp +++ b/src/ebmc/ranking_function.cpp @@ -21,7 +21,6 @@ Author: Daniel Kroening, dkr@amazon.com #include #include -#include "ebmc_base.h" #include "ebmc_error.h" #include "ebmc_solver_factory.h" #include "property_checker.h" @@ -86,13 +85,10 @@ ebmc_propertiest::propertyt &find_property(ebmc_propertiest &properties) } int do_ranking_function( + const transition_systemt &transition_system, const cmdlinet &cmdline, message_handlert &message_handler) { - // get the transition system - transition_systemt transition_system = - get_transition_system(cmdline, message_handler); - // parse the ranking function if(!cmdline.isset("ranking-function")) throw ebmc_errort() << "no candidate ranking function given"; diff --git a/src/ebmc/ranking_function.h b/src/ebmc/ranking_function.h index d705705a0..bcd360efe 100644 --- a/src/ebmc/ranking_function.h +++ b/src/ebmc/ranking_function.h @@ -20,7 +20,10 @@ class exprt; class transition_systemt; class trans_tracet; -int do_ranking_function(const cmdlinet &, message_handlert &); +int do_ranking_function( + const transition_systemt &, + const cmdlinet &, + message_handlert &); exprt parse_ranking_function( const std::string &, diff --git a/src/ebmc/report_results.cpp b/src/ebmc/report_results.cpp index 8c1fd92b4..0896b5e5f 100644 --- a/src/ebmc/report_results.cpp +++ b/src/ebmc/report_results.cpp @@ -176,18 +176,19 @@ void report_results( if(cmdline.isset("vcd")) { + const auto outfile_prefix = cmdline.get_value("vcd") + '.'; for(const auto &property : result.properties) { if(property.has_witness_trace()) { - std::string vcdfile = cmdline.get_value("vcd"); - auto outfile = output_filet{vcdfile}; - + const auto filename = + outfile_prefix + id2string(property.name) + "_witness.vcd"; + auto outfile = output_filet{filename}; messaget message(message_handler); + message.status() << "Writing witness trace VCD file to " << filename + << messaget::eom; show_trans_trace_vcd( property.witness_trace.value(), message, ns, outfile.stream()); - - break; } } } diff --git a/src/ebmc/show_modules.cpp b/src/ebmc/show_modules.cpp new file mode 100644 index 000000000..635b06004 --- /dev/null +++ b/src/ebmc/show_modules.cpp @@ -0,0 +1,97 @@ +/*******************************************************************\ + +Module: Show Modules + +Author: Daniel Kroening, kroening@kroening.com + +\*******************************************************************/ + +#include "show_modules.h" + +#include +#include +#include + +void show_modulest::xml(std::ostream &out) const +{ + std::size_t count = 0; + + for(const auto &module : modules) + { + count++; + + xmlt xml("module"); + xml.new_element("number").data = std::to_string(count); // will go away + xml.set_attribute("number", std::to_string(count)); + + xmlt &l = xml.new_element(); + convert(module.source_location, l); + l.name = "location"; + + // these go away + xml.new_element("identifier").data = id2string(module.identifier); + xml.new_element("mode").data = id2string(module.mode); + xml.new_element("name").data = id2string(module.display_name); + + // these stay + xml.set_attribute("identifier", id2string(module.identifier)); + xml.set_attribute("mode", id2string(module.mode)); + xml.set_attribute("name", id2string(module.display_name)); + + out << xml; + } +} + +void show_modulest::plain_text(std::ostream &out) const +{ + std::size_t count = 0; + + for(const auto &module : modules) + { + count++; + + out << "Module " << count << ":" << '\n'; + + out << " Location: " << module.source_location << '\n'; + out << " Mode: " << module.mode << '\n'; + out << " Identifier: " << module.identifier << '\n'; + out << " Name: " << module.display_name << '\n' << '\n'; + } +} + +void show_modulest::json(std::ostream &out) const +{ + json_arrayt json_modules; + + for(const auto &module : modules) + { + json_objectt json_module; + json_module["location"] = ::json(module.source_location); + json_module["identifier"] = json_stringt{id2string(module.identifier)}; + json_module["mode"] = json_stringt{id2string(module.mode)}; + json_module["name"] = json_stringt{id2string(module.display_name)}; + + json_modules.push_back(std::move(json_module)); + } + + out << json_modules; +} + +show_modulest +show_modulest::from_symbol_table(const symbol_table_baset &symbol_table) +{ + show_modulest show_modules; + + for(const auto &s : symbol_table.symbols) + { + const symbolt &symbol = s.second; + + if(symbol.type.id() == ID_module) + { + show_modules.modules.emplace_back( + symbol.name, symbol.display_name(), symbol.mode, symbol.location); + } + } + + return show_modules; +} diff --git a/src/ebmc/show_modules.h b/src/ebmc/show_modules.h new file mode 100644 index 000000000..cf2b24b24 --- /dev/null +++ b/src/ebmc/show_modules.h @@ -0,0 +1,51 @@ +/*******************************************************************\ + +Module: Show Modules + +Author: Daniel Kroening, kroening@kroening.com + +\*******************************************************************/ + +#ifndef CPROVER_EBMC_SHOW_MODULES_H +#define CPROVER_EBMC_SHOW_MODULES_H + +#include + +#include +#include +#include + +class symbol_table_baset; + +class show_modulest +{ +public: + struct modulet + { + modulet( + irep_idt _identifier, + irep_idt _display_name, + irep_idt _mode, + source_locationt _source_location) + : identifier(_identifier), + display_name(_display_name), + mode(_mode), + source_location(std::move(_source_location)) + { + } + + irep_idt identifier, display_name, mode; + source_locationt source_location; + }; + + using modulest = std::list; + modulest modules; + + void plain_text(std::ostream &) const; + void xml(std::ostream &) const; + void json(std::ostream &) const; + + static show_modulest from_symbol_table(const symbol_table_baset &); +}; + +#endif diff --git a/src/ebmc/show_trans.cpp b/src/ebmc/show_trans.cpp index 3e2c0aa94..a46076240 100644 --- a/src/ebmc/show_trans.cpp +++ b/src/ebmc/show_trans.cpp @@ -12,7 +12,6 @@ Author: Daniel Kroening, kroening@kroening.com #include -#include "ebmc_base.h" #include "ebmc_version.h" #include "output_file.h" #include "output_verilog.h" diff --git a/src/ebmc/transition_system.cpp b/src/ebmc/transition_system.cpp index 1157912fb..5cee19308 100644 --- a/src/ebmc/transition_system.cpp +++ b/src/ebmc/transition_system.cpp @@ -17,14 +17,13 @@ Author: Daniel Kroening, dkr@amazon.com #include #include -#include #include #include #include -#include #include #include "ebmc_error.h" +#include "ebmc_language_file.h" #include "ebmc_version.h" #include "output_file.h" @@ -74,326 +73,6 @@ void transition_systemt::output(std::ostream &out) const ::output(trans_expr.trans(), out, *language, ns); } -int preprocess(const cmdlinet &cmdline, message_handlert &message_handler) -{ - messaget message(message_handler); - - if(cmdline.args.size() != 1) - { - message.error() << "please give exactly one file to preprocess" - << messaget::eom; - return 1; - } - - const auto &filename = cmdline.args.front(); - std::ifstream infile(widen_if_needed(filename)); - - if(!infile) - { - message.error() << "failed to open input file `" << filename << "'" - << messaget::eom; - return 1; - } - - auto language = get_language_from_filename(filename); - - if(language == nullptr) - { - source_locationt location; - location.set_file(filename); - message.error().source_location = location; - message.error() << "failed to figure out type of file" << messaget::eom; - return 1; - } - - optionst options; - - // do -I - if(cmdline.isset('I')) - options.set_option("I", cmdline.get_values('I')); - - options.set_option("force-systemverilog", cmdline.isset("systemverilog")); - - // do -D - if(cmdline.isset('D')) - options.set_option("defines", cmdline.get_values('D')); - - language->set_language_options(options, message_handler); - - if(language->preprocess(infile, filename, std::cout, message_handler)) - { - message.error() << "PREPROCESSING FAILED" << messaget::eom; - return 1; - } - - return 0; -} - -static bool parse( - const cmdlinet &cmdline, - const std::string &filename, - language_filest &language_files, - message_handlert &message_handler) -{ - messaget message(message_handler); - - std::ifstream infile(widen_if_needed(filename)); - - if(!infile) - { - message.error() << "failed to open input file `" << filename << "'" - << messaget::eom; - return true; - } - - auto &lf = language_files.add_file(filename); - lf.filename = filename; - lf.language = get_language_from_filename(filename); - - if(lf.language == nullptr) - { - source_locationt location; - location.set_file(filename); - message.error().source_location = location; - message.error() << "failed to figure out type of file" << messaget::eom; - return true; - } - - languaget &language = *lf.language; - - optionst options; - - // do -I - if(cmdline.isset('I')) - options.set_option("I", cmdline.get_values('I')); - - options.set_option("force-systemverilog", cmdline.isset("systemverilog")); - options.set_option("vl2smv-extensions", cmdline.isset("vl2smv-extensions")); - options.set_option("warn-implicit-nets", cmdline.isset("warn-implicit-nets")); - - // do -D - if(cmdline.isset('D')) - options.set_option("defines", cmdline.get_values('D')); - - // do --ignore-initial - if(cmdline.isset("ignore-initial")) - options.set_option("ignore-initial", true); - - // do --initial-zero - if(cmdline.isset("initial-zero")) - options.set_option("initial-zero", true); - - language.set_language_options(options, message_handler); - - message.status() << "Parsing " << filename << messaget::eom; - - if(language.parse(infile, filename, message_handler)) - { - message.error() << "PARSING ERROR\n"; - return true; - } - - lf.get_modules(); - - return false; -} - -bool parse( - const cmdlinet &cmdline, - language_filest &language_files, - message_handlert &message_handler) -{ - for(unsigned i = 0; i < cmdline.args.size(); i++) - { - if(parse(cmdline, cmdline.args[i], language_files, message_handler)) - return true; - } - return false; -} - -bool get_main( - const cmdlinet &cmdline, - message_handlert &message_handler, - transition_systemt &transition_system) -{ - std::string top_module; - - if(cmdline.isset("module")) - top_module = cmdline.get_value("module"); - else if(cmdline.isset("top")) - top_module = cmdline.get_value("top"); - - try - { - transition_system.main_symbol = - &get_module(transition_system.symbol_table, top_module, message_handler); - transition_system.trans_expr = - to_trans_expr(transition_system.main_symbol->value); - } - - catch(int e) - { - return true; - } - - return false; -} - -void make_next_state(exprt &expr) -{ - for(auto &sub_expression : expr.operands()) - make_next_state(sub_expression); - - if(expr.id() == ID_symbol) - expr.id(ID_next_symbol); -} - -int get_transition_system( - const cmdlinet &cmdline, - message_handlert &message_handler, - transition_systemt &transition_system) -{ - messaget message(message_handler); - - if(cmdline.isset("preprocess")) - return preprocess(cmdline, message_handler); - - // - // parsing - // - language_filest language_files; - - if(parse(cmdline, language_files, message_handler)) - return 1; - - if(cmdline.isset("show-parse")) - { - language_files.show_parse(std::cout, message_handler); - return 0; - } - - // - // type checking - // - - message.status() << "Converting" << messaget::eom; - - if(language_files.typecheck(transition_system.symbol_table, message_handler)) - { - message.error() << "CONVERSION ERROR" << messaget::eom; - return 2; - } - - if(cmdline.isset("show-modules")) - { - show_modules(transition_system.symbol_table, std::cout); - return 0; - } - - if(cmdline.isset("modules-xml")) - { - auto filename = cmdline.get_value("modules-xml"); - auto outfile = output_filet{filename}; - show_modules_xml(transition_system.symbol_table, outfile.stream()); - return 0; - } - - if(cmdline.isset("json-modules")) - { - auto out_file = output_filet{cmdline.get_value("json-modules")}; - json_modules(transition_system.symbol_table, out_file.stream()); - return 0; - } - - if(cmdline.isset("show-symbol-table")) - { - std::cout << transition_system.symbol_table; - return 0; - } - - // get module name - - if(get_main(cmdline, message_handler, transition_system)) - return 1; - - if(cmdline.isset("show-module-hierarchy")) - { - DATA_INVARIANT( - transition_system.main_symbol != nullptr, "must have main_symbol"); - show_module_hierarchy( - transition_system.symbol_table, - *transition_system.main_symbol, - std::cout); - return 0; - } - - // --reset given? - if(cmdline.isset("reset")) - { - namespacet ns(transition_system.symbol_table); - exprt reset_constraint = to_expr( - ns, transition_system.main_symbol->name, cmdline.get_value("reset")); - - // true in initial state - transt new_trans_expr = transition_system.trans_expr; - new_trans_expr.init() = and_exprt(new_trans_expr.init(), reset_constraint); - - // and not anymore afterwards - exprt reset_next_state = reset_constraint; - make_next_state(reset_next_state); - - new_trans_expr.trans() = - and_exprt(new_trans_expr.trans(), not_exprt(reset_next_state)); - transition_system.trans_expr = new_trans_expr; - } - - return -1; // done with the transition system -} - -transition_systemt get_transition_system( - const cmdlinet &cmdline, - message_handlert &message_handler) -{ - transition_systemt transition_system; - auto exit_code = - get_transition_system(cmdline, message_handler, transition_system); - if(exit_code != -1) - throw ebmc_errort().with_exit_code(exit_code); - return transition_system; -} - -int show_parse(const cmdlinet &cmdline, message_handlert &message_handler) -{ - transition_systemt dummy_transition_system; - return get_transition_system( - cmdline, message_handler, dummy_transition_system); -} - -int show_modules(const cmdlinet &cmdline, message_handlert &message_handler) -{ - transition_systemt dummy_transition_system; - return get_transition_system( - cmdline, message_handler, dummy_transition_system); -} - -int show_module_hierarchy( - const cmdlinet &cmdline, - message_handlert &message_handler) -{ - transition_systemt dummy_transition_system; - return get_transition_system( - cmdline, message_handler, dummy_transition_system); -} - -int show_symbol_table( - const cmdlinet &cmdline, - message_handlert &message_handler) -{ - transition_systemt dummy_transition_system; - return get_transition_system( - cmdline, message_handler, dummy_transition_system); -} - std::vector transition_systemt::state_variables() const { std::vector state_variables; diff --git a/src/ebmc/transition_system.h b/src/ebmc/transition_system.h index a2451632e..7056dccb9 100644 --- a/src/ebmc/transition_system.h +++ b/src/ebmc/transition_system.h @@ -13,9 +13,6 @@ Author: Daniel Kroening, dkr@amazon.com #include #include -class cmdlinet; -class message_handlert; - class transition_systemt { public: @@ -34,12 +31,4 @@ class transition_systemt std::vector inputs() const; }; -transition_systemt get_transition_system(const cmdlinet &, message_handlert &); - -int preprocess(const cmdlinet &, message_handlert &); -int show_parse(const cmdlinet &, message_handlert &); -int show_modules(const cmdlinet &, message_handlert &); -int show_module_hierarchy(const cmdlinet &, message_handlert &); -int show_symbol_table(const cmdlinet &, message_handlert &); - #endif // CPROVER_EBMC_TRANSITION_SYSTEM_H diff --git a/src/hw-cbmc/Makefile b/src/hw-cbmc/Makefile index 7634c69de..e86cbb900 100644 --- a/src/hw-cbmc/Makefile +++ b/src/hw-cbmc/Makefile @@ -34,6 +34,7 @@ OBJ+= $(CPROVER_DIR)/goto-checker/goto-checker$(LIBEXT) \ $(CPROVER_DIR)/solvers/solvers$(LIBEXT) \ $(CPROVER_DIR)/util/util$(LIBEXT) \ $(CPROVER_DIR)/json/json$(LIBEXT) \ + ../ebmc/show_modules$(OBJEXT) \ ../temporal-logic/temporal-logic$(LIBEXT) \ ../trans-netlist/trans_trace$(OBJEXT) \ ../trans-word-level/trans-word-level$(LIBEXT) diff --git a/src/hw-cbmc/hw_cbmc_parse_options.cpp b/src/hw-cbmc/hw_cbmc_parse_options.cpp index 4c68ae063..9d41f6429 100644 --- a/src/hw-cbmc/hw_cbmc_parse_options.cpp +++ b/src/hw-cbmc/hw_cbmc_parse_options.cpp @@ -19,12 +19,12 @@ Author: Daniel Kroening, kroening@kroening.com #include #include +#include #include #include #include #include #include -#include #include #include @@ -246,7 +246,8 @@ int hw_cbmc_parse_optionst::get_modules(std::list &bmc_constraints) { } else if(cmdline.isset("show-modules")) { - show_modules(goto_model.symbol_table, std::cout); + show_modulest::from_symbol_table(goto_model.symbol_table) + .plain_text(std::cout); return 0; // done } diff --git a/src/hw_cbmc_irep_ids.h b/src/hw_cbmc_irep_ids.h index 0dc8b8301..3478822e9 100644 --- a/src/hw_cbmc_irep_ids.h +++ b/src/hw_cbmc_irep_ids.h @@ -19,13 +19,16 @@ IREP_ID_ONE(G) IREP_ID_ONE(X) IREP_ID_ONE(smv_abs) IREP_ID_ONE(smv_bitimplies) +IREP_ID_ONE(smv_bit_selection) IREP_ID_ONE(smv_bool) +IREP_ID_ONE(smv_cases) IREP_ID_ONE(smv_count) IREP_ID_ONE(smv_enumeration) IREP_ID_ONE(smv_extend) IREP_ID_ONE(smv_max) IREP_ID_ONE(smv_min) IREP_ID_ONE(smv_next) +IREP_ID_ONE(smv_identifier) IREP_ID_ONE(smv_iff) IREP_ID_TWO(C_smv_iff, "#smv_iff") IREP_ID_ONE(smv_resize) @@ -35,11 +38,13 @@ IREP_ID_ONE(smv_setin) IREP_ID_ONE(smv_setnotin) IREP_ID_ONE(smv_signed_cast) IREP_ID_ONE(smv_sizeof) +IREP_ID_ONE(smv_module_instance) IREP_ID_ONE(smv_swconst) IREP_ID_ONE(smv_union) IREP_ID_ONE(smv_unsigned_cast) IREP_ID_ONE(smv_uwconst) IREP_ID_ONE(smv_word1) +IREP_ID_ONE(smv_word_constant) IREP_ID_ONE(smv_H) IREP_ID_ONE(smv_bounded_H) IREP_ID_ONE(smv_O) @@ -69,11 +74,13 @@ IREP_ID_ONE(sva_cycle_delay) IREP_ID_ONE(sva_cycle_delay_star) IREP_ID_ONE(sva_cycle_delay_plus) IREP_ID_ONE(sva_disable_iff) +IREP_ID_ONE(sva_sequence_disable_iff) IREP_ID_ONE(sva_sequence_first_match) IREP_ID_ONE(sva_sequence_goto_repetition) IREP_ID_ONE(sva_sequence_intersect) IREP_ID_ONE(sva_sequence_non_consecutive_repetition) IREP_ID_ONE(sva_sequence_property) +IREP_ID_ONE(sva_sequence_property_instance) IREP_ID_ONE(sva_sequence_repetition_star) IREP_ID_ONE(sva_sequence_repetition_plus) IREP_ID_ONE(sva_sequence_throughout) @@ -111,12 +118,17 @@ IREP_ID_ONE(direction) IREP_ID_ONE(ports) IREP_ID_ONE(inst) IREP_ID_ONE(Verilog) +IREP_ID_ONE(verilog_action_else) +IREP_ID_ONE(verilog_action_then) +IREP_ID_ONE(verilog_action_then_else) IREP_ID_ONE(verilog_array_range) IREP_ID_ONE(verilog_assignment_pattern) IREP_ID_ONE(verilog_associative_array) IREP_ID_ONE(verilog_declarations) IREP_ID_ONE(verilog_default_clocking) IREP_ID_ONE(verilog_default_disable) +IREP_ID_ONE(verilog_identifier) +IREP_ID_ONE(verilog_interconnect) IREP_ID_ONE(verilog_lifetime) IREP_ID_ONE(verilog_logical_equality) IREP_ID_ONE(verilog_logical_inequality) @@ -140,6 +152,7 @@ IREP_ID_ONE(verilog_past) IREP_ID_ONE(verilog_property_declaration) IREP_ID_ONE(verilog_sequence_declaration) IREP_ID_ONE(verilog_sequence) +IREP_ID_ONE(verilog_tagged_union) IREP_ID_ONE(verilog_value_range) IREP_ID_ONE(verilog_void) IREP_ID_ONE(verilog_streaming_concatenation_left_to_right) @@ -206,6 +219,7 @@ IREP_ID_ONE(verilog_immediate_cover) IREP_ID_ONE(verilog_assert_property) IREP_ID_ONE(verilog_assume_property) IREP_ID_ONE(verilog_cover_property) +IREP_ID_ONE(verilog_cover_sequence) IREP_ID_ONE(verilog_covergroup) IREP_ID_ONE(verilog_restrict_property) IREP_ID_ONE(verilog_expect_property) @@ -215,6 +229,8 @@ IREP_ID_ONE(verilog_always) IREP_ID_ONE(verilog_always_comb) IREP_ID_ONE(verilog_always_ff) IREP_ID_ONE(verilog_always_latch) +IREP_ID_ONE(verilog_sva_named_property) +IREP_ID_ONE(verilog_sva_named_sequence) IREP_ID_ONE(named_port_connection) IREP_ID_ONE(verilog_final) IREP_ID_ONE(initial) @@ -299,11 +315,11 @@ IREP_ID_ONE(verilog_module) IREP_ID_ONE(verilog_package) IREP_ID_ONE(verilog_package_import) IREP_ID_ONE(verilog_package_scope) +IREP_ID_ONE(verilog_parameter_port_decls) IREP_ID_ONE(verilog_program) IREP_ID_ONE(verilog_udp) IREP_ID_ONE(module_source) IREP_ID_ONE(module_items) -IREP_ID_ONE(parameter_port_list) IREP_ID_ONE(named_block) IREP_ID_ONE(primitive_module_instance) IREP_ID_ONE(all) diff --git a/src/ic3/dnf_io.hh b/src/ic3/dnf_io.hh index 25065f8e7..07e65a92e 100644 --- a/src/ic3/dnf_io.hh +++ b/src/ic3/dnf_io.hh @@ -10,6 +10,7 @@ Author: Eugene Goldberg, eu.goldberg@gmail.com #ifndef DNF_IO_HH #define DNF_IO_HH +#include #include #include #include diff --git a/src/ic3/m4y_aiger_print.cc b/src/ic3/m4y_aiger_print.cc index be2b2f660..7170b705f 100644 --- a/src/ic3/m4y_aiger_print.cc +++ b/src/ic3/m4y_aiger_print.cc @@ -6,21 +6,19 @@ Module: Printing circuit in text version of aiger format Author: Eugene Goldberg, eu.goldberg@gmail.com ******************************************************/ -#include -#include -#include +#include "ccircuit.hh" +#include "dnf_io.hh" +#include "m0ic3.hh" + #include #include - -#include +#include +#include +#include #include "minisat/core/Solver.h" #include "minisat/simp/SimpSolver.h" -#include "dnf_io.hh" -#include "ccircuit.hh" -#include "m0ic3.hh" - /*==================================== P R I N T _ A I G E R _ F O R M A T diff --git a/src/ic3/m5y_aiger_print.cc b/src/ic3/m5y_aiger_print.cc index 1387f7cef..705c5cc74 100644 --- a/src/ic3/m5y_aiger_print.cc +++ b/src/ic3/m5y_aiger_print.cc @@ -6,21 +6,19 @@ Module: Printing circuit in text version of aiger format Author: Eugene Goldberg, eu.goldberg@gmail.com ******************************************************/ -#include -#include -#include +#include "ccircuit.hh" +#include "dnf_io.hh" +#include "m0ic3.hh" + #include #include - -#include +#include +#include +#include #include "minisat/core/Solver.h" #include "minisat/simp/SimpSolver.h" -#include "dnf_io.hh" -#include "ccircuit.hh" -#include "m0ic3.hh" - /*=========================================== P R I N T _ A I G E R _ C O N S T R S diff --git a/src/smvlang/Makefile b/src/smvlang/Makefile index 248dced76..30b6e6505 100644 --- a/src/smvlang/Makefile +++ b/src/smvlang/Makefile @@ -1,4 +1,5 @@ -SRC = smv_expr.cpp \ +SRC = smv_ebmc_language.cpp \ + smv_expr.cpp \ smv_language.cpp \ smv_parser.cpp \ smv_typecheck.cpp \ diff --git a/src/smvlang/expr2smv.cpp b/src/smvlang/expr2smv.cpp index 13aab16c9..a45ee3f9f 100644 --- a/src/smvlang/expr2smv.cpp +++ b/src/smvlang/expr2smv.cpp @@ -350,6 +350,25 @@ expr2smvt::resultt expr2smvt::convert_typecast(const typecast_exprt &expr) /*******************************************************************\ +Function: expr2smvt::convert_zero_extend + + Inputs: + + Outputs: + + Purpose: + +\*******************************************************************/ + +expr2smvt::resultt expr2smvt::convert_zero_extend(const zero_extend_exprt &expr) +{ + // Both "extend" and "resize" do sign extension. + // Hence, use lowering. + return convert_rec(expr.lower()); +} + +/*******************************************************************\ + Function: expr2smvt::convert_rtctl Inputs: @@ -479,6 +498,87 @@ expr2smvt::convert_index(const index_exprt &src, precedencet precedence) /*******************************************************************\ +Function: expr2smvt::convert_extractbits + + Inputs: + + Outputs: + + Purpose: + +\*******************************************************************/ + +expr2smvt::resultt expr2smvt::convert_extractbits(const extractbits_exprt &expr) +{ + const precedencet precedence = precedencet::INDEX; + auto op_rec = convert_rec(expr.src()); + + std::string dest; + + if(precedence >= op_rec.p) + dest += '('; + dest += op_rec.s; + if(precedence >= op_rec.p) + dest += ')'; + + dest += '['; + + // We can only do constant indices. + if(expr.index().is_constant()) + { + auto index_int = numeric_cast_v(to_constant_expr(expr.index())); + auto width = to_unsignedbv_type(expr.type()).get_width(); + dest += integer2string(index_int + width - 1); + dest += ':'; + dest += integer2string(index_int); + } + else + { + dest += "?:?"; + } + + dest += ']'; + + return {precedence, std::move(dest)}; +} + +/*******************************************************************\ + +Function: expr2smvt::convert_smv_bit_select + + Inputs: + + Outputs: + + Purpose: + +\*******************************************************************/ + +expr2smvt::resultt +expr2smvt::convert_smv_bit_selection(const ternary_exprt &expr) +{ + const precedencet precedence = precedencet::INDEX; + auto op_rec = convert_rec(expr.op0()); + + std::string dest; + + if(precedence >= op_rec.p) + dest += '('; + dest += op_rec.s; + if(precedence >= op_rec.p) + dest += ')'; + + dest += '['; + dest += convert_rec(expr.op1()).s; + dest += ':'; + dest += convert_rec(expr.op2()).s; + dest += ']'; + + return {precedence, std::move(dest)}; +} + +/*******************************************************************\ + Function: expr2smvt::convert_if Inputs: @@ -616,6 +716,20 @@ expr2smvt::resultt expr2smvt::convert_constant(const constant_exprt &src) dest = minus + std::string("0") + sign_specifier + 'd' + std::to_string(word_width) + '_' + integer2string(value_abs); } + else if(type.id() == ID_bv) + { + auto &bv_type = to_bv_type(type); + auto width = bv_type.width(); + auto &src_value = src.get_value(); + dest = std::string("0ub"); + dest += std::to_string(width); + dest += '_'; + for(std::size_t i = 0; i < width; i++) + { + bool bit = get_bvrep_bit(src_value, width, width - i - 1); + dest += bit ? '1' : '0'; + } + } else return convert_norep(src); @@ -692,8 +806,8 @@ expr2smvt::resultt expr2smvt::convert_rec(const exprt &src) else if(src.id()==ID_notequal) return convert_binary(to_notequal_expr(src), "!=", precedencet::REL); - else if(src.id()==ID_not) - return convert_unary(to_not_expr(src), "!", precedencet::NOT); + else if(src.id() == ID_not || src.id() == ID_bitnot) + return convert_unary(to_unary_expr(src), "!", precedencet::NOT); else if(src.id() == ID_and || src.id() == ID_bitand) return convert_binary_associative(src, "&", precedencet::AND); @@ -825,6 +939,12 @@ expr2smvt::resultt expr2smvt::convert_rec(const exprt &src) return convert_binary(to_binary_expr(src), ">>", precedencet::SHIFT); } + else if(src.id() == ID_extractbits) + return convert_extractbits(to_extractbits_expr(src)); + + else if(src.id() == ID_smv_bit_selection) + return convert_smv_bit_selection(to_ternary_expr(src)); + else if(src.id() == ID_smv_extend) return convert_function_application("extend", src); @@ -863,6 +983,9 @@ expr2smvt::resultt expr2smvt::convert_rec(const exprt &src) return convert_typecast(to_typecast_expr(src)); } + else if(src.id() == ID_zero_extend) + return convert_zero_extend(to_zero_extend_expr(src)); + else // no SMV language expression for internal representation return convert_norep(src); } @@ -903,10 +1026,15 @@ std::string type2smv(const typet &type, const namespacet &ns) return "boolean"; else if(type.id()==ID_array) { + auto &array_type = to_array_type(type); + auto size_const = to_constant_expr(array_type.size()); + auto size_int = numeric_cast_v(size_const); std::string code = "array "; - code+=".."; + // The index type cannot be any type, but must be a range low..high + code += "0.."; + code += integer2string(size_int - 1); code+=" of "; - code += type2smv(to_array_type(type).element_type(), ns); + code += type2smv(array_type.element_type(), ns); return code; } else if(type.id() == ID_smv_enumeration) @@ -930,9 +1058,9 @@ std::string type2smv(const typet &type, const namespacet &ns) { return "set"; } - else if(type.id()=="submodule") + else if(type.id() == ID_smv_module_instance) { - auto code = type.get_string(ID_identifier); + auto code = id2string(to_smv_module_instance_type(type).identifier()); const exprt &e=(exprt &)type; if(e.has_operands()) { diff --git a/src/smvlang/expr2smv_class.h b/src/smvlang/expr2smv_class.h index caed6efde..7ee44c563 100644 --- a/src/smvlang/expr2smv_class.h +++ b/src/smvlang/expr2smv_class.h @@ -10,6 +10,7 @@ Author: Daniel Kroening, dkr@amazon.com #define CPROVER_SMV_EXPR2SMV_CLASS_H #include +#include #include #include #include @@ -111,6 +112,10 @@ class expr2smvt resultt convert_unary(const unary_exprt &, const std::string &symbol, precedencet); + resultt convert_extractbits(const extractbits_exprt &); + + resultt convert_smv_bit_selection(const ternary_exprt &); + resultt convert_index(const index_exprt &, precedencet); resultt convert_if(const if_exprt &, precedencet); @@ -128,6 +133,8 @@ class expr2smvt resultt convert_typecast(const typecast_exprt &); + resultt convert_zero_extend(const zero_extend_exprt &); + resultt convert_norep(const exprt &); }; diff --git a/src/smvlang/parser.y b/src/smvlang/parser.y index 43eb16e81..f7745c8b5 100644 --- a/src/smvlang/parser.y +++ b/src/smvlang/parser.y @@ -2,8 +2,10 @@ %define parse.error verbose %{ +#include "smv_expr.h" #include "smv_parser.h" #include "smv_typecheck.h" +#include "smv_types.h" #include #include @@ -130,41 +132,6 @@ static void j_binary(YYSTYPE & dest, YYSTYPE & op1, const irep_idt &id, YYSTYPE /*******************************************************************\ -Function: merge_complex_identifier - - Inputs: - - Outputs: - - Purpose: - -\*******************************************************************/ - -irep_idt merge_complex_identifier(const exprt &expr) -{ - if(expr.id() == ID_symbol) - return to_symbol_expr(expr).get_identifier(); - else if(expr.id() == ID_member) - { - auto &member_expr = to_member_expr(expr); - return id2string(merge_complex_identifier(member_expr.compound())) + '.' + id2string(member_expr.get_component_name()); - } - else if(expr.id() == ID_index) - { - auto &index_expr = to_index_expr(expr); - auto &index = index_expr.index(); - PRECONDITION(index.is_constant()); - auto index_string = id2string(to_constant_expr(index).get_value()); - return id2string(merge_complex_identifier(index_expr.array())) + '.' + index_string; - } - else - { - DATA_INVARIANT_WITH_DIAGNOSTICS(false, "unexpected complex_identifier", expr.pretty()); - } -} - -/*******************************************************************\ - Function: new_module Inputs: @@ -175,12 +142,18 @@ Function: new_module \*******************************************************************/ -static void new_module(YYSTYPE &module) +static smv_parse_treet::modulet &new_module(YYSTYPE &location, YYSTYPE &module_name) { - const std::string name=smv_module_symbol(stack_expr(module).id_string()); - PARSER.module=&PARSER.parse_tree.modules[name]; - PARSER.module->name=name; - PARSER.module->base_name=stack_expr(module).id_string(); + auto base_name = stack_expr(module_name).id_string(); + const std::string identifier=smv_module_symbol(base_name); + PARSER.parse_tree.module_list.push_back(smv_parse_treet::modulet{}); + auto &module=PARSER.parse_tree.module_list.back(); + PARSER.parse_tree.module_map[identifier] = --PARSER.parse_tree.module_list.end(); + module.name = identifier; + module.base_name = base_name; + module.source_location = stack_expr(location).source_location(); + PARSER.module = &module; + return module; } /*------------------------------------------------------------------------*/ @@ -316,8 +289,9 @@ static void new_module(YYSTYPE &module) %token IDENTIFIER_Token "identifier" %token QIDENTIFIER_Token "quoted identifier" -%token STRING_Token "quoted string" +%token STRING_Token "quoted string" %token NUMBER_Token "number" +%token WORD_CONSTANT_Token "word constant" /* operator precedence, low to high */ %right IMPLIES_Token @@ -337,7 +311,7 @@ static void new_module(YYSTYPE &module) %left TIMES_Token DIVIDE_Token %left COLONCOLON_Token %left UMINUS /* supplies precedence for unary minus */ -%left DOT_Token +%left DOT_Token '[' '(' %% @@ -355,8 +329,12 @@ module_name: IDENTIFIER_Token | STRING_Token ; -module_head: MODULE_Token module_name { new_module($2); } - | MODULE_Token module_name { new_module($2); } '(' module_parameters_opt ')' +module_keyword: MODULE_Token { init($$); /* for the location */ } + ; + +module_head: module_keyword module_name { new_module($1, $2); } + | module_keyword module_name { new_module($1, $2); } + '(' module_parameters_opt ')' ; module_body: /* optional */ @@ -393,10 +371,19 @@ var_declaration: ; ivar_declaration: - IVAR_Token simple_var_list + IVAR_Token ivar_simple_var_list + ; + +ivar_simple_var_list: + identifier ':' simple_type_specifier ';' { - yyerror("No support for IVAR declarations"); - YYERROR; + smv_identifier_exprt identifier{stack_expr($1).id(), PARSER.source_location()}; + PARSER.module->add_ivar(std::move(identifier), stack_type($3)); + } + | ivar_simple_var_list identifier ':' simple_type_specifier ';' + { + smv_identifier_exprt identifier{stack_expr($2).id(), PARSER.source_location()}; + PARSER.module->add_ivar(std::move(identifier), stack_type($4)); } ; @@ -537,18 +524,6 @@ ltl_specification: ; extern_var : variable_identifier EQUAL_Token STRING_Token - { - const irep_idt &identifier=stack_expr($1).get(ID_identifier); - smv_parse_treet::mc_vart &var=PARSER.module->vars[identifier]; - - if(var.identifier!=irep_idt()) - { - yyerror("variable `"+id2string(identifier)+"' already declared extern"); - YYERROR; - } - else - var.identifier=stack_expr($3).id_string(); - } ; var_list : var_decl @@ -557,10 +532,8 @@ var_list : var_decl module_parameter: identifier { - const irep_idt &identifier=stack_expr($1).get(ID_identifier); - smv_parse_treet::mc_vart &var=PARSER.module->vars[identifier]; - var.var_class=smv_parse_treet::mc_vart::ARGUMENT; - PARSER.module->ports.push_back(identifier); + const irep_idt &identifier=stack_expr($1).id(); + PARSER.module->parameters.push_back(identifier); } ; @@ -569,7 +542,11 @@ module_parameters: | module_parameters ',' module_parameter ; -module_parameters_opt: /* empty */ +module_parameters_opt: + /* empty */ + { + init($$); + } | module_parameters ; @@ -623,14 +600,14 @@ simple_type_specifier: module_type_specifier: module_name { - init($$, "submodule"); - stack_expr($$).set(ID_identifier, + init($$, ID_smv_module_instance); + to_smv_module_instance_type(stack_type($$)).identifier( smv_module_symbol(stack_expr($1).id_string())); } | module_name '(' parameter_list ')' { - init($$, "submodule"); - stack_expr($$).set(ID_identifier, + init($$, ID_smv_module_instance); + to_smv_module_instance_type(stack_type($$)).identifier( smv_module_symbol(stack_expr($1).id_string())); stack_expr($$).operands().swap(stack_expr($3).operands()); } @@ -656,35 +633,14 @@ enum_list : enum_element enum_element: IDENTIFIER_Token { $$=$1; - PARSER.module->enum_set.insert(stack_expr($1).id_string()); + PARSER.parse_tree.enum_set.insert(stack_expr($1).id_string()); + PARSER.module->add_enum( + smv_identifier_exprt{stack_expr($1).id(), PARSER.source_location()}); } ; var_decl : variable_identifier ':' type_specifier ';' { - const irep_idt &identifier=stack_expr($1).get(ID_identifier); - smv_parse_treet::mc_vart &var=PARSER.module->vars[identifier]; - - switch(var.var_class) - { - case smv_parse_treet::mc_vart::UNKNOWN: - var.type=stack_type($3); - var.var_class=smv_parse_treet::mc_vart::DECLARED; - break; - - case smv_parse_treet::mc_vart::DEFINED: - case smv_parse_treet::mc_vart::DECLARED: - break; - - case smv_parse_treet::mc_vart::ARGUMENT: - yyerror("variable `"+id2string(identifier)+"' already declared as argument"); - YYERROR; - break; - - default: - DATA_INVARIANT(false, "unexpected variable class"); - } - PARSER.module->add_var(stack_expr($1), stack_type($3)); } ; @@ -706,34 +662,6 @@ assignment : assignment_head '(' assignment_var ')' BECOMES_Token formula ';' } | assignment_var BECOMES_Token formula ';' { - const irep_idt &identifier=stack_expr($1).get(ID_identifier); - smv_parse_treet::mc_vart &var=PARSER.module->vars[identifier]; - - switch(var.var_class) - { - case smv_parse_treet::mc_vart::UNKNOWN: - var.type.make_nil(); - var.var_class=smv_parse_treet::mc_vart::DEFINED; - break; - - case smv_parse_treet::mc_vart::DECLARED: - var.var_class=smv_parse_treet::mc_vart::DEFINED; - break; - - case smv_parse_treet::mc_vart::DEFINED: - yyerror("variable `"+id2string(identifier)+"' already defined"); - YYERROR; - break; - - case smv_parse_treet::mc_vart::ARGUMENT: - yyerror("variable `"+id2string(identifier)+"' already declared as argument"); - YYERROR; - break; - - default: - DATA_INVARIANT(false, "unexpected variable class"); - } - PARSER.module->add_assign_current(std::move(stack_expr($1)), std::move(stack_expr($3))); } ; @@ -752,133 +680,155 @@ defines: define define : assignment_var BECOMES_Token formula ';' { - const irep_idt &identifier=stack_expr($1).get(ID_identifier); - smv_parse_treet::mc_vart &var=PARSER.module->vars[identifier]; - - switch(var.var_class) - { - case smv_parse_treet::mc_vart::UNKNOWN: - var.type.make_nil(); - var.var_class=smv_parse_treet::mc_vart::DEFINED; - break; - - case smv_parse_treet::mc_vart::DECLARED: - yyerror("variable `"+id2string(identifier)+"' already declared"); - YYERROR; - break; - - case smv_parse_treet::mc_vart::DEFINED: - yyerror("variable `"+id2string(identifier)+"' already defined"); - YYERROR; - break; + PARSER.module->add_define(std::move(stack_expr($1)), std::move(stack_expr($3))); + } + ; - case smv_parse_treet::mc_vart::ARGUMENT: - yyerror("variable `"+id2string(identifier)+"' already declared as argument"); - YYERROR; - break; +formula : basic_expr + ; - default: - DATA_INVARIANT(false, "unexpected variable class"); - } +constant : boolean_constant + | integer_constant + | word_constant + ; - PARSER.module->add_define(std::move(stack_expr($1)), std::move(stack_expr($3))); +boolean_constant: + TRUE_Token + { + init($$, ID_constant); + stack_expr($$).set(ID_value, ID_true); + stack_expr($$).type()=typet{ID_bool}; + } + | FALSE_Token + { + init($$, ID_constant); + stack_expr($$).set(ID_value, ID_false); + stack_expr($$).type()=typet{ID_bool}; } ; -formula : term +integer_constant: + NUMBER_Token + { + init($$, ID_constant); + stack_expr($$).set(ID_value, stack_expr($1).id()); + stack_expr($$).type()=integer_typet{}; + } ; -constant : NUMBER_Token { init($$, ID_constant); stack_expr($$).set(ID_value, stack_expr($1).id()); stack_expr($$).type()=integer_typet(); } - | TRUE_Token { init($$, ID_constant); stack_expr($$).set(ID_value, ID_true); stack_expr($$).type()=typet(ID_bool); } - | FALSE_Token { init($$, ID_constant); stack_expr($$).set(ID_value, ID_false); stack_expr($$).type()=typet(ID_bool); } +word_constant: + WORD_CONSTANT_Token + { + init($$, ID_constant); + stack_expr($$).set(ID_value, stack_expr($1).id()); + stack_expr($$).type() = typet{ID_smv_word_constant}; + } ; -term : constant - | variable_identifier - | '(' formula ')' { $$=$2; } - | NOT_Token term { init($$, ID_not); mto($$, $2); } - | "abs" '(' term ')' { unary($$, ID_smv_abs, $3); } - | "max" '(' term ',' term ')' { binary($$, $3, ID_smv_max, $5); } - | "min" '(' term ',' term ')' { binary($$, $3, ID_smv_min, $5); } - | term AND_Token term { j_binary($$, $1, ID_and, $3); } - | term OR_Token term { j_binary($$, $1, ID_or, $3); } - | term xor_Token term { j_binary($$, $1, ID_xor, $3); } - | term xnor_Token term { binary($$, $1, ID_xnor, $3); } - | term IMPLIES_Token term { binary($$, $1, ID_implies, $3); } - | term EQUIV_Token term { binary($$, $1, ID_smv_iff, $3); } - | term EQUAL_Token term { binary($$, $1, ID_equal, $3); } - | term NOTEQUAL_Token term { binary($$, $1, ID_notequal, $3); } - | term LT_Token term { binary($$, $1, ID_lt, $3); } - | term LE_Token term { binary($$, $1, ID_le, $3); } - | term GT_Token term { binary($$, $1, ID_gt, $3); } - | term GE_Token term { binary($$, $1, ID_ge, $3); } - | MINUS_Token term %prec UMINUS - { init($$, ID_unary_minus); mto($$, $2); } - | term PLUS_Token term { binary($$, $1, ID_plus, $3); } - | term MINUS_Token term { binary($$, $1, ID_minus, $3); } - | term TIMES_Token term { binary($$, $1, ID_mult, $3); } - | term DIVIDE_Token term { binary($$, $1, ID_div, $3); } - | term mod_Token term { binary($$, $1, ID_mod, $3); } - | term GTGT_Token term { binary($$, $1, ID_shr, $3); } - | term LTLT_Token term { binary($$, $1, ID_shl, $3); } - | term COLONCOLON_Token term { binary($$, $1, ID_concatenation, $3); } - | "word1" '(' term ')' { unary($$, ID_smv_word1, $3); } - | "bool" '(' term ')' { unary($$, ID_smv_bool, $3); } - | "toint" '(' term ')' { unary($$, ID_smv_toint, $3); } - | "count" '(' term_list ')' { $$=$3; stack_expr($$).id(ID_smv_count); } - | swconst_Token '(' term ',' term ')' { binary($$, $3, ID_smv_swconst, $5); } - | uwconst_Token '(' term ',' term ')' { binary($$, $3, ID_smv_uwconst, $5); } - | signed_Token '(' term ')' { unary($$, ID_smv_signed_cast, $3); } - | unsigned_Token '(' term ')' { unary($$, ID_smv_unsigned_cast, $3); } - | sizeof_Token '(' term ')' { unary($$, ID_smv_sizeof, $3); } - | extend_Token '(' term ',' term ')' { binary($$, $3, ID_smv_extend, $5); } - | resize_Token '(' term ',' term ')' { binary($$, $3, ID_smv_resize, $5); } - | term union_Token term { binary($$, $1, ID_smv_union, $3); } - | '{' set_body_expr '}' { $$=$2; stack_expr($$).id(ID_smv_set); } - | term in_Token term { binary($$, $1, ID_smv_setin, $3); } - | term IF_Token term ':' term %prec IF_Token - { init($$, ID_if); mto($$, $1); mto($$, $3); mto($$, $5); } - | case_Token cases esac_Token { $$=$2; } - | next_Token '(' term ')' { init($$, ID_smv_next); mto($$, $3); } +basic_expr : constant + | identifier + { + // This rule is part of "complex_identifier" in the NuSMV manual. + $$ = $1; + irep_idt identifier = stack_expr($$).id(); + stack_expr($$) = smv_identifier_exprt{identifier, PARSER.source_location()}; + } + | basic_expr DOT_Token IDENTIFIER_Token + { + // This rule is part of "complex_identifier" in the NuSMV manual. + unary($$, ID_member, $1); + stack_expr($$).set(ID_component_name, stack_expr($3).id()); + } + | basic_expr '(' basic_expr ')' + { + // Not in the NuSMV grammar. + binary($$, $1, ID_index, $3); + } + | '(' formula ')' { $$=$2; } + | NOT_Token basic_expr { init($$, ID_not); mto($$, $2); } + | "abs" '(' basic_expr ')' { unary($$, ID_smv_abs, $3); } + | "max" '(' basic_expr ',' basic_expr ')' { binary($$, $3, ID_smv_max, $5); } + | "min" '(' basic_expr ',' basic_expr ')' { binary($$, $3, ID_smv_min, $5); } + | basic_expr AND_Token basic_expr { j_binary($$, $1, ID_and, $3); } + | basic_expr OR_Token basic_expr { j_binary($$, $1, ID_or, $3); } + | basic_expr xor_Token basic_expr { j_binary($$, $1, ID_xor, $3); } + | basic_expr xnor_Token basic_expr { binary($$, $1, ID_xnor, $3); } + | basic_expr IMPLIES_Token basic_expr { binary($$, $1, ID_implies, $3); } + | basic_expr EQUIV_Token basic_expr { binary($$, $1, ID_smv_iff, $3); } + | basic_expr EQUAL_Token basic_expr { binary($$, $1, ID_equal, $3); } + | basic_expr NOTEQUAL_Token basic_expr { binary($$, $1, ID_notequal, $3); } + | basic_expr LT_Token basic_expr { binary($$, $1, ID_lt, $3); } + | basic_expr LE_Token basic_expr { binary($$, $1, ID_le, $3); } + | basic_expr GT_Token basic_expr { binary($$, $1, ID_gt, $3); } + | basic_expr GE_Token basic_expr { binary($$, $1, ID_ge, $3); } + | MINUS_Token basic_expr %prec UMINUS { init($$, ID_unary_minus); mto($$, $2); } + | basic_expr PLUS_Token basic_expr { binary($$, $1, ID_plus, $3); } + | basic_expr MINUS_Token basic_expr { binary($$, $1, ID_minus, $3); } + | basic_expr TIMES_Token basic_expr { binary($$, $1, ID_mult, $3); } + | basic_expr DIVIDE_Token basic_expr { binary($$, $1, ID_div, $3); } + | basic_expr mod_Token basic_expr { binary($$, $1, ID_mod, $3); } + | basic_expr GTGT_Token basic_expr { binary($$, $1, ID_shr, $3); } + | basic_expr LTLT_Token basic_expr { binary($$, $1, ID_shl, $3); } + | basic_expr '[' basic_expr ']' { binary($$, $1, ID_index, $3); } + | basic_expr '[' basic_expr ':' basic_expr ']' { init($$, ID_smv_bit_selection); mto($$, $1); mto($$, $3); mto($$, $5); } + | basic_expr COLONCOLON_Token basic_expr { binary($$, $1, ID_concatenation, $3); } + | "word1" '(' basic_expr ')' { unary($$, ID_smv_word1, $3); } + | "bool" '(' basic_expr ')' { unary($$, ID_smv_bool, $3); } + | "toint" '(' basic_expr ')' { unary($$, ID_smv_toint, $3); } + | "count" '(' basic_expr_list ')' { $$=$3; stack_expr($$).id(ID_smv_count); } + | swconst_Token '(' basic_expr ',' basic_expr ')' { binary($$, $3, ID_smv_swconst, $5); } + | uwconst_Token '(' basic_expr ',' basic_expr ')' { binary($$, $3, ID_smv_uwconst, $5); } + | signed_Token '(' basic_expr ')' { unary($$, ID_smv_signed_cast, $3); } + | unsigned_Token '(' basic_expr ')' { unary($$, ID_smv_unsigned_cast, $3); } + | sizeof_Token '(' basic_expr ')' { unary($$, ID_smv_sizeof, $3); } + | extend_Token '(' basic_expr ',' basic_expr ')' { binary($$, $3, ID_smv_extend, $5); } + | resize_Token '(' basic_expr ',' basic_expr ')' { binary($$, $3, ID_smv_resize, $5); } + | basic_expr union_Token basic_expr { binary($$, $1, ID_smv_union, $3); } + | '{' set_body_expr '}' { $$=$2; stack_expr($$).id(ID_smv_set); } + | basic_expr in_Token basic_expr { binary($$, $1, ID_smv_setin, $3); } + | basic_expr IF_Token basic_expr ':' basic_expr %prec IF_Token + { init($$, ID_if); mto($$, $1); mto($$, $3); mto($$, $5); } + | case_Token cases esac_Token { $$=$2; } + | next_Token '(' basic_expr ')' { init($$, ID_smv_next); mto($$, $3); } /* Not in NuSMV manual */ - | INC_Token '(' term ')' { init($$, "inc"); mto($$, $3); } - | DEC_Token '(' term ')' { init($$, "dec"); mto($$, $3); } - | ADD_Token '(' term ',' term ')' { j_binary($$, $3, ID_plus, $5); } - | SUB_Token '(' term ',' term ')' { init($$, ID_minus); mto($$, $3); mto($$, $5); } + | INC_Token '(' basic_expr ')' { init($$, "inc"); mto($$, $3); } + | DEC_Token '(' basic_expr ')' { init($$, "dec"); mto($$, $3); } + | ADD_Token '(' basic_expr ',' basic_expr ')' { j_binary($$, $3, ID_plus, $5); } + | SUB_Token '(' basic_expr ',' basic_expr ')' { init($$, ID_minus); mto($$, $3); mto($$, $5); } | switch_Token '(' variable_identifier ')' '{' switches '}' { init($$, ID_switch); mto($$, $3); mto($$, $6); } /* CTL */ - | AX_Token term { init($$, ID_AX); mto($$, $2); } - | AF_Token term { init($$, ID_AF); mto($$, $2); } - | AG_Token term { init($$, ID_AG); mto($$, $2); } - | EX_Token term { init($$, ID_EX); mto($$, $2); } - | EF_Token term { init($$, ID_EF); mto($$, $2); } - | EG_Token term { init($$, ID_EG); mto($$, $2); } - | A_Token '[' term U_Token term ']' { binary($$, $3, ID_AU, $5); } - | A_Token '[' term R_Token term ']' { binary($$, $3, ID_AR, $5); } - | E_Token '[' term U_Token term ']' { binary($$, $3, ID_EU, $5); } - | E_Token '[' term R_Token term ']' { binary($$, $3, ID_ER, $5); } + | AX_Token basic_expr { init($$, ID_AX); mto($$, $2); } + | AF_Token basic_expr { init($$, ID_AF); mto($$, $2); } + | AG_Token basic_expr { init($$, ID_AG); mto($$, $2); } + | EX_Token basic_expr { init($$, ID_EX); mto($$, $2); } + | EF_Token basic_expr { init($$, ID_EF); mto($$, $2); } + | EG_Token basic_expr { init($$, ID_EG); mto($$, $2); } + | A_Token '[' basic_expr U_Token basic_expr ']' { binary($$, $3, ID_AU, $5); } + | A_Token '[' basic_expr R_Token basic_expr ']' { binary($$, $3, ID_AR, $5); } + | E_Token '[' basic_expr U_Token basic_expr ']' { binary($$, $3, ID_EU, $5); } + | E_Token '[' basic_expr R_Token basic_expr ']' { binary($$, $3, ID_ER, $5); } /* LTL */ - | F_Token term { init($$, ID_F); mto($$, $2); } - | G_Token term { init($$, ID_G); mto($$, $2); } - | X_Token term { init($$, ID_X); mto($$, $2); } - | term U_Token term { binary($$, $1, ID_U, $3); } - | term R_Token term { binary($$, $1, ID_R, $3); } - | term V_Token term { binary($$, $1, ID_R, $3); } + | F_Token basic_expr { init($$, ID_F); mto($$, $2); } + | G_Token basic_expr { init($$, ID_G); mto($$, $2); } + | X_Token basic_expr { init($$, ID_X); mto($$, $2); } + | basic_expr U_Token basic_expr { binary($$, $1, ID_U, $3); } + | basic_expr R_Token basic_expr { binary($$, $1, ID_R, $3); } + | basic_expr V_Token basic_expr { binary($$, $1, ID_R, $3); } /* LTL PAST */ - | Y_Token term { $$ = $1; stack_expr($$).id(ID_smv_Y); mto($$, $2); } - | Z_Token term { $$ = $1; stack_expr($$).id(ID_smv_Z); mto($$, $2); } - | H_Token term { $$ = $1; stack_expr($$).id(ID_smv_H); mto($$, $2); } - | H_Token bound term { $$ = $1; stack_expr($$).id(ID_smv_bounded_H); mto($$, $3); } - | O_Token term { $$ = $1; stack_expr($$).id(ID_smv_O); mto($$, $2); } - | O_Token bound term { $$ = $1; stack_expr($$).id(ID_smv_bounded_O); mto($$, $3); } - | term S_Token term { $$ = $2; stack_expr($$).id(ID_smv_S); mto($$, $1); mto($$, $3); } - | term T_Token term { $$ = $2; stack_expr($$).id(ID_smv_T); mto($$, $1); mto($$, $3); } + | Y_Token basic_expr { $$ = $1; stack_expr($$).id(ID_smv_Y); mto($$, $2); } + | Z_Token basic_expr { $$ = $1; stack_expr($$).id(ID_smv_Z); mto($$, $2); } + | H_Token basic_expr { $$ = $1; stack_expr($$).id(ID_smv_H); mto($$, $2); } + | H_Token bound basic_expr { $$ = $1; stack_expr($$).id(ID_smv_bounded_H); mto($$, $3); } + | O_Token basic_expr { $$ = $1; stack_expr($$).id(ID_smv_O); mto($$, $2); } + | O_Token bound basic_expr { $$ = $1; stack_expr($$).id(ID_smv_bounded_O); mto($$, $3); } + | basic_expr S_Token basic_expr { $$ = $2; stack_expr($$).id(ID_smv_S); mto($$, $1); mto($$, $3); } + | basic_expr T_Token basic_expr { $$ = $2; stack_expr($$).id(ID_smv_T); mto($$, $1); mto($$, $3); } /* Real-time CTL */ - | EBF_Token range term { $$ = $1; stack_expr($$).id(ID_smv_EBF); stack_expr($$).operands().swap(stack_expr($2).operands()); mto($$, $3); } - | ABF_Token range term { $$ = $1; stack_expr($$).id(ID_smv_ABF); stack_expr($$).operands().swap(stack_expr($2).operands()); mto($$, $3); } - | EBG_Token range term { $$ = $1; stack_expr($$).id(ID_smv_EBG); stack_expr($$).operands().swap(stack_expr($2).operands()); mto($$, $3); } - | ABG_Token range term { $$ = $1; stack_expr($$).id(ID_smv_ABG); stack_expr($$).operands().swap(stack_expr($2).operands()); mto($$, $3); } - | A_Token '[' term BU_Token range term ']' + | EBF_Token range basic_expr { $$ = $1; stack_expr($$).id(ID_smv_EBF); stack_expr($$).operands().swap(stack_expr($2).operands()); mto($$, $3); } + | ABF_Token range basic_expr { $$ = $1; stack_expr($$).id(ID_smv_ABF); stack_expr($$).operands().swap(stack_expr($2).operands()); mto($$, $3); } + | EBG_Token range basic_expr { $$ = $1; stack_expr($$).id(ID_smv_EBG); stack_expr($$).operands().swap(stack_expr($2).operands()); mto($$, $3); } + | ABG_Token range basic_expr { $$ = $1; stack_expr($$).id(ID_smv_ABG); stack_expr($$).operands().swap(stack_expr($2).operands()); mto($$, $3); } + | A_Token '[' basic_expr BU_Token range basic_expr ']' { $$ = $1; stack_expr($$).id(ID_smv_ABU); @@ -887,7 +837,7 @@ term : constant stack_expr($$).add_to_operands(stack_expr($5).operands()[1]); mto($$, $6); } - | E_Token '[' term BU_Token range term ']' + | E_Token '[' basic_expr BU_Token range basic_expr ']' { $$ = $1; stack_expr($$).id(ID_smv_EBU); @@ -911,9 +861,9 @@ set_body_expr: | set_body_expr ',' formula { $$=$1; mto($$, $3); } ; -term_list: - term { init($$); mto($$, $1); } - | term_list ',' term { $$=$1; mto($$, $3); } +basic_expr_list: + basic_expr { init($$); mto($$, $1); } + | basic_expr_list ',' basic_expr { $$=$1; mto($$, $3); } ; identifier : IDENTIFIER_Token @@ -925,43 +875,13 @@ identifier : IDENTIFIER_Token ; variable_identifier: complex_identifier - { - auto id = merge_complex_identifier(stack_expr($1)); - - bool is_enum=(PARSER.module->enum_set.find(id)!= - PARSER.module->enum_set.end()); - bool is_var=(PARSER.module->vars.find(id)!= - PARSER.module->vars.end()); - - if(is_var && is_enum) - { - yyerror("identifier `"+id2string(id)+"' is ambiguous"); - YYERROR; - } - else if(is_enum) - { - init($$, ID_constant); - stack_expr($$).type()=typet(ID_smv_enumeration); - stack_expr($$).set(ID_value, id); - } - else // not an enum, probably a variable - { - init($$, ID_symbol); - stack_expr($$).set(ID_identifier, id); - auto var_it = PARSER.module->vars.find(id); - if(var_it!= PARSER.module->vars.end()) - stack_expr($$).type()=var_it->second.type; - //PARSER.module->vars[stack_expr($1).id()]; - } - } | STRING_Token { // Not in the NuSMV grammar. const irep_idt &id=stack_expr($1).id(); - init($$, ID_symbol); + init($$, ID_smv_identifier); stack_expr($$).set(ID_identifier, id); - PARSER.module->vars[id]; } ; @@ -969,9 +889,8 @@ complex_identifier: identifier { $$ = $1; - irep_idt identifier = stack_expr($$).id(); - stack_expr($$).id(ID_symbol); - stack_expr($$).set(ID_identifier, identifier); + auto identifier = stack_expr($$).id(); + stack_expr($$) = smv_identifier_exprt{identifier, PARSER.source_location()}; } | complex_identifier DOT_Token QIDENTIFIER_Token { @@ -984,11 +903,11 @@ complex_identifier: unary($$, ID_member, $1); stack_expr($$).set(ID_component_name, stack_expr($3).id()); } - | complex_identifier '[' term ']' + | complex_identifier '[' basic_expr ']' { binary($$, $1, ID_index, $3); } - | complex_identifier '(' term ')' + | complex_identifier '(' basic_expr ')' { // Not in the NuSMV grammar. binary($$, $1, ID_index, $3); @@ -996,7 +915,7 @@ complex_identifier: ; cases : - { init($$, "smv_cases"); } + { init($$, ID_smv_cases); } | cases case { $$=$1; mto($$, $2); } ; @@ -1011,7 +930,7 @@ switches : { $$=$1; mto($$, $2); } ; -switch : NUMBER_Token ':' term ';' +switch : NUMBER_Token ':' basic_expr ';' { init($$, ID_switch); mto($$, $1); mto($$, $3); } ; diff --git a/src/smvlang/scanner.l b/src/smvlang/scanner.l index 289115877..e3281493a 100644 --- a/src/smvlang/scanner.l +++ b/src/smvlang/scanner.l @@ -188,6 +188,11 @@ void newlocation(YYSTYPE &x) stack_expr(yysmvlval).id(yytext); return NUMBER_Token; } +0[us]?[bBoOdDhH][0-9]*_[0-9a-fA-F][_0-9a-fA-F]* { + newstack(yysmvlval); + stack_expr(yysmvlval).id(yytext); + return WORD_CONSTANT_Token; + } \"[^\"]*\" { newstack(yysmvlval); std::string tmp(yytext); diff --git a/src/smvlang/smv_ebmc_language.cpp b/src/smvlang/smv_ebmc_language.cpp new file mode 100644 index 000000000..77a576e7a --- /dev/null +++ b/src/smvlang/smv_ebmc_language.cpp @@ -0,0 +1,127 @@ +/*******************************************************************\ + +Module: SMV Language Interface + +Author: Daniel Kroening, dkr@amazon.com + +\*******************************************************************/ + +/// \file +/// SMV Language Interface + +#include "smv_ebmc_language.h" + +#include +#include +#include + +#include +#include +#include +#include + +#include "smv_parser.h" +#include "smv_typecheck.h" + +#include +#include + +std::string smv_file_name(const cmdlinet &cmdline) +{ + if(cmdline.args.size() == 0) + throw ebmc_errort{} << "no file name given"; + + if(cmdline.args.size() >= 2) + throw ebmc_errort{}.with_exit_code(1) << "SMV only uses a single file"; + + return cmdline.args.front(); +} + +smv_parse_treet smv_ebmc_languaget::parse() +{ + smv_parsert smv_parser{message_handler}; + + auto file_name = smv_file_name(cmdline); + + std::ifstream infile{widen_if_needed(file_name)}; + + if(!infile) + throw ebmc_errort{}.with_exit_code(1) << "failed to open " << file_name; + + smv_parser.set_file(file_name); + smv_parser.in = &infile; + + if(smv_parser.parse()) + throw ebmc_errort{}.with_exit_code(1); + + return std::move(smv_parser.parse_tree); +} + +std::optional smv_ebmc_languaget::transition_system() +{ + if(cmdline.isset("preprocess")) + { + throw ebmc_errort{}.with_exit_code(1) << "SMV does not use preprocessing"; + } + + auto parse_tree = parse(); + + if(cmdline.isset("show-parse")) + { + parse_tree.show(std::cout); + return {}; + } + + if( + cmdline.isset("show-modules") || cmdline.isset("modules-xml") || + cmdline.isset("json-modules")) + { + show_modulest show_modules; + + for(const auto &module : parse_tree.module_list) + show_modules.modules.emplace_back( + module.name, module.base_name, "SMV", module.source_location); + + auto filename = cmdline.value_opt("outfile").value_or("-"); + output_filet output_file{filename}; + auto &out = output_file.stream(); + + if(cmdline.isset("show-modules")) + show_modules.plain_text(out); + else if(cmdline.isset("modules-xml")) + show_modules.xml(out); + else if(cmdline.isset("json-modules")) + show_modules.json(out); + + return {}; + } + + if(cmdline.isset("show-module-hierarchy")) + { + //show_module_hierarchy(cmdline, message_handler); + return {}; + } + + transition_systemt result; + + if(smv_typecheck( + parse_tree, result.symbol_table, "smv::main", message_handler)) + { + messaget message{message_handler}; + message.error() << "CONVERSION ERROR" << messaget::eom; + throw ebmc_errort{}.with_exit_code(2); + } + + if(cmdline.isset("show-symbol-table")) + { + std::cout << result.symbol_table; + return {}; + } + + result.main_symbol = + &get_module(result.symbol_table, "main", message_handler); + + result.trans_expr = to_trans_expr(result.main_symbol->value); + + return result; +} diff --git a/src/smvlang/smv_ebmc_language.h b/src/smvlang/smv_ebmc_language.h new file mode 100644 index 000000000..72ab3ef35 --- /dev/null +++ b/src/smvlang/smv_ebmc_language.h @@ -0,0 +1,34 @@ +/*******************************************************************\ + +Module: SMV Language Interface + +Author: Daniel Kroening, dkr@amazon.com + +\*******************************************************************/ + +/// \file +/// SMV Language Interface + +#ifndef EBMC_SMV_LANGUAGE_H +#define EBMC_SMV_LANGUAGE_H + +#include + +class smv_parse_treet; + +class smv_ebmc_languaget : public ebmc_languaget +{ +public: + smv_ebmc_languaget(cmdlinet &_cmdline, message_handlert &_message_handler) + : ebmc_languaget(_cmdline, _message_handler) + { + } + + // produce the transition system, and return it + std::optional transition_system() override; + +protected: + smv_parse_treet parse(); +}; + +#endif // EBMC_SMV_LANGUAGE_H diff --git a/src/smvlang/smv_expr.h b/src/smvlang/smv_expr.h index 293e76809..6261e4368 100644 --- a/src/smvlang/smv_expr.h +++ b/src/smvlang/smv_expr.h @@ -209,6 +209,30 @@ inline smv_min_exprt &to_smv_min_expr(exprt &expr) return static_cast(expr); } +// -> +class smv_bitimplies_exprt : public binary_exprt +{ +public: + smv_bitimplies_exprt(exprt __lhs, exprt __rhs) + : binary_exprt{std::move(__lhs), ID_smv_bitimplies, std::move(__rhs)} + { + } +}; + +inline const smv_bitimplies_exprt &to_smv_bitimplies_expr(const exprt &expr) +{ + PRECONDITION(expr.id() == ID_smv_bitimplies); + smv_bitimplies_exprt::check(expr); + return static_cast(expr); +} + +inline smv_bitimplies_exprt &to_smv_bitimplies_expr(exprt &expr) +{ + PRECONDITION(expr.id() == ID_smv_bitimplies); + smv_bitimplies_exprt::check(expr); + return static_cast(expr); +} + class smv_unsigned_cast_exprt : public unary_exprt { public: @@ -302,4 +326,47 @@ inline smv_word1_exprt &to_smv_word1_expr(exprt &expr) return static_cast(expr); } +// parse tree only -- used for identifiers, which may turn into +// symbols or enums +class smv_identifier_exprt : public nullary_exprt +{ +public: + explicit smv_identifier_exprt(irep_idt _identifier) + : nullary_exprt{ID_smv_identifier, typet{}} + { + identifier(_identifier); + } + + smv_identifier_exprt(irep_idt _identifier, source_locationt _location) + : smv_identifier_exprt{_identifier} + { + if(_location.is_not_nil()) + add_source_location() = _location; + } + + irep_idt identifier() const + { + return get(ID_identifier); + } + + void identifier(irep_idt _identifier) + { + set(ID_identifier, _identifier); + } +}; + +inline const smv_identifier_exprt &to_smv_identifier_expr(const exprt &expr) +{ + PRECONDITION(expr.id() == ID_smv_identifier); + smv_identifier_exprt::check(expr); + return static_cast(expr); +} + +inline smv_identifier_exprt &to_smv_identifier_expr(exprt &expr) +{ + PRECONDITION(expr.id() == ID_smv_identifier); + smv_identifier_exprt::check(expr); + return static_cast(expr); +} + #endif // CPROVER_SMV_EXPR_H diff --git a/src/smvlang/smv_language.cpp b/src/smvlang/smv_language.cpp index c401449dd..4ba5f722f 100644 --- a/src/smvlang/smv_language.cpp +++ b/src/smvlang/smv_language.cpp @@ -12,8 +12,10 @@ Author: Daniel Kroening, kroening@kroening.com #include #include "expr2smv.h" +#include "smv_expr.h" #include "smv_parser.h" #include "smv_typecheck.h" +#include "smv_types.h" /*******************************************************************\ @@ -60,17 +62,17 @@ void smv_languaget::dependencies( const std::string &module, std::set &module_set) { - smv_parse_treet::modulest::const_iterator - m_it=smv_parse_tree.modules.find(module); + auto m_it = smv_parse_tree.module_map.find(module); - if(m_it==smv_parse_tree.modules.end()) return; + if(m_it == smv_parse_tree.module_map.end()) + return; - const smv_parse_treet::modulet &smv_module=m_it->second; + const smv_parse_treet::modulet &smv_module = *m_it->second; - for(smv_parse_treet::mc_varst::const_iterator it=smv_module.vars.begin(); - it!=smv_module.vars.end(); it++) - if(it->second.type.id()=="submodule") - module_set.insert(it->second.type.get_string("identifier")); + for(auto &element : smv_module.elements) + if(element.is_var() && element.expr.type().id() == ID_smv_module_instance) + module_set.insert(id2string( + to_smv_module_instance_type(element.expr.type()).identifier())); } /*******************************************************************\ @@ -87,10 +89,8 @@ Function: smv_languaget::modules_provided void smv_languaget::modules_provided(std::set &module_set) { - for(smv_parse_treet::modulest::const_iterator - it=smv_parse_tree.modules.begin(); - it!=smv_parse_tree.modules.end(); it++) - module_set.insert(id2string(it->second.name)); + for(const auto &module : smv_parse_tree.module_list) + module_set.insert(id2string(module.name)); } /*******************************************************************\ @@ -127,51 +127,7 @@ Function: smv_languaget::show_parse void smv_languaget::show_parse(std::ostream &out, message_handlert &) { - for(smv_parse_treet::modulest::const_iterator - it=smv_parse_tree.modules.begin(); - it!=smv_parse_tree.modules.end(); it++) - { - const smv_parse_treet::modulet &module=it->second; - out << "Module: " << module.name << std::endl << std::endl; - - out << " VARIABLES:" << std::endl; - - for(smv_parse_treet::mc_varst::const_iterator it=module.vars.begin(); - it!=module.vars.end(); it++) - if(it->second.type.id()!="submodule") - { - symbol_tablet symbol_table; - namespacet ns{symbol_table}; - auto msg = type2smv(it->second.type, ns); - out << " " << it->first << ": " << msg << ";\n"; - } - - out << std::endl; - - out << " SUBMODULES:" << std::endl; - - for(smv_parse_treet::mc_varst::const_iterator - it=module.vars.begin(); - it!=module.vars.end(); it++) - if(it->second.type.id()=="submodule") - { - symbol_tablet symbol_table; - namespacet ns(symbol_table); - auto msg = type2smv(it->second.type, ns); - out << " " << it->first << ": " << msg << ";\n"; - } - - out << std::endl; - - out << " ITEMS:" << std::endl; - - forall_item_list(it, module.items) - { - out << " TYPE: " << to_string(it->item_type) << std::endl; - out << " EXPR: " << it->expr.pretty() << std::endl; - out << std::endl; - } - } + smv_parse_tree.show(out); } /*******************************************************************\ diff --git a/src/smvlang/smv_parse_tree.cpp b/src/smvlang/smv_parse_tree.cpp index ad780c5f8..c2de28e46 100644 --- a/src/smvlang/smv_parse_tree.cpp +++ b/src/smvlang/smv_parse_tree.cpp @@ -8,6 +8,12 @@ Author: Daniel Kroening, kroening@kroening.com #include "smv_parse_tree.h" +#include +#include + +#include "expr2smv.h" +#include "smv_expr.h" + /*******************************************************************\ Function: smv_parse_treet::swap @@ -22,7 +28,9 @@ Function: smv_parse_treet::swap void smv_parse_treet::swap(smv_parse_treet &smv_parse_tree) { - smv_parse_tree.modules.swap(modules); + smv_parse_tree.module_list.swap(module_list); + smv_parse_tree.module_map.swap(module_map); + smv_parse_tree.enum_set.swap(enum_set); } /*******************************************************************\ @@ -39,7 +47,8 @@ Function: smv_parse_treet::clear void smv_parse_treet::clear() { - modules.clear(); + module_map.clear(); + module_list.clear(); } /*******************************************************************\ @@ -54,27 +63,35 @@ Function: operator << \*******************************************************************/ -std::string to_string(smv_parse_treet::modulet::itemt::item_typet i) +std::string to_string(smv_parse_treet::modulet::elementt::element_typet i) { switch(i) { - case smv_parse_treet::modulet::itemt::ASSIGN_CURRENT: + case smv_parse_treet::modulet::elementt::ASSIGN_CURRENT: return "ASSIGN CURRENT"; - case smv_parse_treet::modulet::itemt::ASSIGN_INIT: + case smv_parse_treet::modulet::elementt::ASSIGN_INIT: return "ASSIGN INIT"; - case smv_parse_treet::modulet::itemt::ASSIGN_NEXT: + case smv_parse_treet::modulet::elementt::ASSIGN_NEXT: return "ASSIGN NEXT"; - case smv_parse_treet::modulet::itemt::INVAR: return "INVAR"; - case smv_parse_treet::modulet::itemt::TRANS: return "TRANS"; - case smv_parse_treet::modulet::itemt::INIT: return "INIT"; - case smv_parse_treet::modulet::itemt::CTLSPEC: + case smv_parse_treet::modulet::elementt::INVAR: + return "INVAR"; + case smv_parse_treet::modulet::elementt::TRANS: + return "TRANS"; + case smv_parse_treet::modulet::elementt::INIT: + return "INIT"; + case smv_parse_treet::modulet::elementt::CTLSPEC: return "SPEC"; - case smv_parse_treet::modulet::itemt::LTLSPEC: + case smv_parse_treet::modulet::elementt::LTLSPEC: return "LTLSPEC"; - case smv_parse_treet::modulet::itemt::FAIRNESS: return "FAIRNESS"; - case smv_parse_treet::modulet::itemt::DEFINE: + case smv_parse_treet::modulet::elementt::FAIRNESS: + return "FAIRNESS"; + case smv_parse_treet::modulet::elementt::DEFINE: return "DEFINE"; - case smv_parse_treet::modulet::itemt::VAR: + case smv_parse_treet::modulet::elementt::ENUM: + return "ENUM"; + case smv_parse_treet::modulet::elementt::IVAR: + return "IVAR"; + case smv_parse_treet::modulet::elementt::VAR: return "VAR"; default:; @@ -82,3 +99,60 @@ std::string to_string(smv_parse_treet::modulet::itemt::item_typet i) return ""; } + +void smv_parse_treet::modulet::elementt::show(std::ostream &out) const +{ + out << " TYPE: " << to_string(element_type) << '\n'; + out << " EXPR: " << expr.pretty() << '\n'; +} + +void smv_parse_treet::show(std::ostream &out) const +{ + for(auto &module : module_list) + { + out << "Module: " << module.base_name << '\n' << '\n'; + + out << " PARAMETERS:\n"; + + for(auto ¶meter : module.parameters) + out << " " << parameter << '\n'; + + out << '\n'; + + out << " VARIABLES:" << std::endl; + + for(auto &element : module.elements) + if(element.is_var() && element.expr.type().id() != ID_smv_module_instance) + { + symbol_tablet symbol_table; + namespacet ns{symbol_table}; + auto identifier = to_smv_identifier_expr(element.expr).identifier(); + auto msg = type2smv(element.expr.type(), ns); + out << " " << identifier << ": " << msg << ";\n"; + } + + out << std::endl; + + out << " SUBMODULES:" << std::endl; + + for(auto &element : module.elements) + if(element.is_var() && element.expr.type().id() == ID_smv_module_instance) + { + symbol_tablet symbol_table; + namespacet ns(symbol_table); + auto identifier = to_smv_identifier_expr(element.expr).identifier(); + auto msg = type2smv(element.expr.type(), ns); + out << " " << identifier << ": " << msg << ";\n"; + } + + out << std::endl; + + out << " ITEMS:" << std::endl; + + for(auto &element : module.elements) + { + element.show(out); + out << '\n'; + } + } +} diff --git a/src/smvlang/smv_parse_tree.h b/src/smvlang/smv_parse_tree.h index 3c04b63d3..f5d211e36 100644 --- a/src/smvlang/smv_parse_tree.h +++ b/src/smvlang/smv_parse_tree.h @@ -12,269 +12,320 @@ Author: Daniel Kroening, kroening@kroening.com #include #include +#include #include #include class smv_parse_treet { public: + smv_parse_treet() = default; + smv_parse_treet(smv_parse_treet &&) = default; + + // don't copy, contains pointers + smv_parse_treet(const smv_parse_treet &) = delete; - struct mc_vart - { - typedef enum { UNKNOWN, DECLARED, DEFINED, ARGUMENT } var_classt; - var_classt var_class; - typet type; - irep_idt identifier; - - mc_vart():var_class(UNKNOWN), type(typet(ID_bool)) - { - } - }; - - typedef std::unordered_map mc_varst; typedef std::unordered_set enum_sett; struct modulet { + source_locationt source_location; irep_idt name, base_name; - - struct itemt + std::vector parameters; + + struct elementt { - enum item_typet + enum element_typet { ASSIGN_CURRENT, ASSIGN_INIT, ASSIGN_NEXT, CTLSPEC, DEFINE, + ENUM, FAIRNESS, INIT, INVAR, + IVAR, LTLSPEC, TRANS, VAR }; - itemt(item_typet __item_type, exprt __expr, source_locationt __location) - : item_type(__item_type), + elementt( + element_typet __element_type, + exprt __expr, + source_locationt __location) + : element_type(__element_type), expr(std::move(__expr)), location(std::move(__location)) { } - itemt( - item_typet __item_type, + elementt( + element_typet __element_type, irep_idt __name, exprt __expr, source_locationt __location) - : item_type(__item_type), + : element_type(__element_type), name(__name), expr(std::move(__expr)), location(std::move(__location)) { } - friend std::string to_string(item_typet i); - - item_typet item_type; + friend std::string to_string(element_typet i); + + element_typet element_type; std::optional name; exprt expr; source_locationt location; bool is_assign_current() const { - return item_type == ASSIGN_CURRENT; + return element_type == ASSIGN_CURRENT; } bool is_assign_init() const { - return item_type == ASSIGN_INIT; + return element_type == ASSIGN_INIT; } bool is_assign_next() const { - return item_type == ASSIGN_NEXT; + return element_type == ASSIGN_NEXT; } bool is_ctlspec() const { - return item_type == CTLSPEC; + return element_type == CTLSPEC; } bool is_ltlspec() const { - return item_type == LTLSPEC; + return element_type == LTLSPEC; } bool is_define() const { - return item_type==DEFINE; + return element_type == DEFINE; } bool is_invar() const { - return item_type==INVAR; + return element_type == INVAR; } bool is_trans() const { - return item_type==TRANS; + return element_type == TRANS; } bool is_init() const { - return item_type==INIT; + return element_type == INIT; + } + + bool is_enum() const + { + return element_type == ENUM; + } + + bool is_ivar() const + { + return element_type == IVAR; } bool is_var() const { - return item_type == VAR; + return element_type == VAR; } // for ASSIGN_CURRENT, ASSIGN_INIT, ASSIGN_NEXT, DEFINE - const equal_exprt &equal_expr() const + const exprt &lhs() const { PRECONDITION( is_assign_current() || is_assign_init() || is_assign_next() || is_define()); - return to_equal_expr(expr); + return to_equal_expr(expr).lhs(); } - equal_exprt &equal_expr() + exprt &lhs() + { + PRECONDITION( + is_assign_current() || is_assign_init() || is_assign_next() || + is_define()); + return to_equal_expr(expr).lhs(); + } + + // for ASSIGN_CURRENT, ASSIGN_INIT, ASSIGN_NEXT, DEFINE + const exprt &rhs() const { PRECONDITION( is_assign_current() || is_assign_init() || is_assign_next() || is_define()); - return to_equal_expr(expr); + return to_equal_expr(expr).rhs(); } + + exprt &rhs() + { + PRECONDITION( + is_assign_current() || is_assign_init() || is_assign_next() || + is_define()); + return to_equal_expr(expr).rhs(); + } + + void show(std::ostream &) const; }; - - typedef std::list item_listt; - item_listt items; + + typedef std::list element_listt; + element_listt elements; void add_assign_current(exprt lhs, exprt rhs) { - items.emplace_back( - itemt::ASSIGN_CURRENT, + elements.emplace_back( + elementt::ASSIGN_CURRENT, binary_exprt{std::move(lhs), ID_equal, std::move(rhs)}, source_locationt::nil()); } void add_assign_init(exprt lhs, exprt rhs) { - items.emplace_back( - itemt::ASSIGN_INIT, + elements.emplace_back( + elementt::ASSIGN_INIT, binary_exprt{std::move(lhs), ID_equal, std::move(rhs)}, source_locationt::nil()); } void add_assign_next(exprt lhs, exprt rhs) { - items.emplace_back( - itemt::ASSIGN_NEXT, + elements.emplace_back( + elementt::ASSIGN_NEXT, binary_exprt{std::move(lhs), ID_equal, std::move(rhs)}, source_locationt::nil()); } void add_invar(exprt expr) { - items.emplace_back( - itemt::INVAR, std::move(expr), source_locationt::nil()); + elements.emplace_back( + elementt::INVAR, std::move(expr), source_locationt::nil()); } void add_define(exprt lhs, exprt rhs) { - items.emplace_back( - itemt::DEFINE, + elements.emplace_back( + elementt::DEFINE, binary_exprt{std::move(lhs), ID_equal, std::move(rhs)}, source_locationt::nil()); } void add_fairness(exprt expr) { - items.emplace_back( - itemt::FAIRNESS, std::move(expr), source_locationt::nil()); + elements.emplace_back( + elementt::FAIRNESS, std::move(expr), source_locationt::nil()); } void add_init(exprt expr) { - items.emplace_back(itemt::INIT, std::move(expr), source_locationt::nil()); + elements.emplace_back( + elementt::INIT, std::move(expr), source_locationt::nil()); } void add_trans(exprt expr) { - items.emplace_back( - itemt::TRANS, std::move(expr), source_locationt::nil()); + elements.emplace_back( + elementt::TRANS, std::move(expr), source_locationt::nil()); } void add_invar(exprt expr, source_locationt location) { - items.emplace_back(itemt::INVAR, std::move(expr), location); + elements.emplace_back(elementt::INVAR, std::move(expr), location); } void add_ctlspec(exprt expr, source_locationt location) { - items.emplace_back(itemt::CTLSPEC, std::move(expr), std::move(location)); + elements.emplace_back( + elementt::CTLSPEC, std::move(expr), std::move(location)); } void add_ctlspec(irep_idt name, exprt expr, source_locationt location) { - items.emplace_back( - itemt::CTLSPEC, name, std::move(expr), std::move(location)); + elements.emplace_back( + elementt::CTLSPEC, name, std::move(expr), std::move(location)); } void add_ltlspec(exprt expr, source_locationt location) { - items.emplace_back(itemt::LTLSPEC, std::move(expr), location); + elements.emplace_back(elementt::LTLSPEC, std::move(expr), location); } void add_ltlspec(irep_idt name, exprt expr, source_locationt location) { - items.emplace_back(itemt::LTLSPEC, name, std::move(expr), location); + elements.emplace_back(elementt::LTLSPEC, name, std::move(expr), location); } void add_define(exprt expr, source_locationt location) { - items.emplace_back(itemt::DEFINE, std::move(expr), std::move(location)); + elements.emplace_back( + elementt::DEFINE, std::move(expr), std::move(location)); } void add_fairness(exprt expr, source_locationt location) { - items.emplace_back(itemt::FAIRNESS, std::move(expr), std::move(location)); + elements.emplace_back( + elementt::FAIRNESS, std::move(expr), std::move(location)); } void add_init(exprt expr, source_locationt location) { - items.emplace_back(itemt::INIT, std::move(expr), std::move(location)); + elements.emplace_back( + elementt::INIT, std::move(expr), std::move(location)); } void add_trans(exprt expr, source_locationt location) { - items.emplace_back(itemt::TRANS, std::move(expr), std::move(location)); + elements.emplace_back( + elementt::TRANS, std::move(expr), std::move(location)); } - void add_var(exprt expr, typet type) + void add_ivar(exprt expr, typet type) { expr.type() = std::move(type); auto location = expr.source_location(); - items.emplace_back(itemt::VAR, std::move(expr), std::move(location)); + elements.emplace_back( + elementt::IVAR, std::move(expr), std::move(location)); } - mc_varst vars; - enum_sett enum_set; + void add_var(exprt expr, typet type) + { + expr.type() = std::move(type); + auto location = expr.source_location(); + elements.emplace_back( + elementt::VAR, std::move(expr), std::move(location)); + } - std::list ports; + void add_enum(exprt expr) + { + auto location = expr.source_location(); + elements.emplace_back( + elementt::ENUM, std::move(expr), std::move(location)); + } }; - - typedef std::unordered_map modulest; - - modulest modules; - - void swap(smv_parse_treet &smv_parse_tree); + + using module_listt = std::list; + module_listt module_list; + + using module_mapt = + std::unordered_map; + module_mapt module_map; + + // enums are global + enum_sett enum_set; + + void swap(smv_parse_treet &); void clear(); + + void show(std::ostream &) const; }; -#define forall_item_list(it, expr) \ - for(smv_parse_treet::modulet::item_listt::const_iterator it=(expr).begin(); \ - it!=(expr).end(); it++) #endif diff --git a/src/smvlang/smv_typecheck.cpp b/src/smvlang/smv_typecheck.cpp index 5c8f1dc39..92f3c7cfe 100644 --- a/src/smvlang/smv_typecheck.cpp +++ b/src/smvlang/smv_typecheck.cpp @@ -9,6 +9,7 @@ Author: Daniel Kroening, kroening@kroening.com #include "smv_typecheck.h" #include +#include #include #include #include @@ -58,14 +59,14 @@ class smv_typecheckt:public typecheckt } modet; void convert(smv_parse_treet::modulet &); - void create_var_symbols(const smv_parse_treet::modulet::item_listt &); - void collect_define(const equal_exprt &); + void create_var_symbols(const smv_parse_treet::modulet::element_listt &); + + void collect_define(const exprt &lhs, const exprt &rhs); void convert_defines(exprt::operandst &invar); void convert_define(const irep_idt &identifier); - typedef enum { NORMAL, NEXT } expr_modet; - void convert(exprt &, expr_modet); + void convert(exprt &); void typecheck(exprt &, modet); void typecheck_op(exprt &, const typet &, modet); @@ -85,10 +86,15 @@ class smv_typecheckt:public typecheckt void check_type(typet &); smv_ranget convert_type(const typet &); - void convert(smv_parse_treet::modulet::itemt &); - void typecheck(smv_parse_treet::modulet::itemt &); - void typecheck_expr_rec(exprt &, modet); + void variable_checks(const smv_parse_treet::modulet &); + bool uses_next(const exprt &expr) const; + void no_next_allowed(const exprt &expr) const; + + void convert(smv_parse_treet::modulet::elementt &); + void typecheck(smv_parse_treet::modulet::elementt &); + void typecheck_expr_rec(exprt &, modet, bool next); void convert_expr_to(exprt &, const typet &dest); + exprt convert_word_constant(const constant_exprt &); smv_parse_treet::modulet *modulep; @@ -100,7 +106,7 @@ class smv_typecheckt:public typecheckt smv_parse_treet::modulet &, const irep_idt &identifier, const irep_idt &instance, - const exprt::operandst &operands, + const exprt::operandst &arguments, const source_locationt &); typet @@ -108,8 +114,6 @@ class smv_typecheckt:public typecheckt typedef std::map rename_mapt; - void instantiate_rename(exprt &, const rename_mapt &rename_map); - void convert_ports(smv_parse_treet::modulet &, typet &dest); // for defines @@ -117,13 +121,13 @@ class smv_typecheckt:public typecheckt { public: exprt value; - bool typechecked, in_progress; - - explicit definet(const exprt &_v):value(_v), typechecked(false), in_progress(false) + bool typechecked = false, in_progress = false, uses_next = false; + + explicit definet(const exprt &_v) : value(_v) { } - definet():typechecked(false), in_progress(false) + definet() { } }; @@ -151,6 +155,44 @@ class smv_typecheckt:public typecheckt /*******************************************************************\ +Function: merge_complex_identifier + + Inputs: + + Outputs: + + Purpose: + +\*******************************************************************/ + +irep_idt merge_complex_identifier(const exprt &expr) +{ + if(expr.id() == ID_smv_identifier) + return to_smv_identifier_expr(expr).identifier(); + else if(expr.id() == ID_member) + { + auto &member_expr = to_member_expr(expr); + return id2string(merge_complex_identifier(member_expr.compound())) + '.' + + id2string(member_expr.get_component_name()); + } + else if(expr.id() == ID_index) + { + auto &index_expr = to_index_expr(expr); + auto &index = index_expr.index(); + PRECONDITION(index.is_constant()); + auto index_string = id2string(to_constant_expr(index).get_value()); + return id2string(merge_complex_identifier(index_expr.array())) + '.' + + index_string; + } + else + { + DATA_INVARIANT_WITH_DIAGNOSTICS( + false, "unexpected complex_identifier", expr.pretty()); + } +} + +/*******************************************************************\ + Function: smv_typecheckt::convert_ports Inputs: @@ -167,9 +209,9 @@ void smv_typecheckt::convert_ports( { irept::subt &ports=dest.add(ID_ports).get_sub(); - ports.reserve(smv_module.ports.size()); + ports.reserve(smv_module.parameters.size()); - for(const auto &port_name : smv_module.ports) + for(const auto &port_name : smv_module.parameters) { ports.push_back(exprt(ID_symbol)); ports.back().set( @@ -192,24 +234,30 @@ Function: smv_typecheckt::flatten_hierarchy void smv_typecheckt::flatten_hierarchy(smv_parse_treet::modulet &smv_module) { - for(auto &item : smv_module.items) + // Not using ranged for since we will append to the list we are + // iterating over! This avoids recursion. + for(auto element_it = smv_module.elements.begin(); + element_it != smv_module.elements.end(); + ++element_it) { - if(item.is_var() && item.expr.type().id() == "submodule") + auto &element = *element_it; + + if(element.is_var() && element.expr.type().id() == ID_smv_module_instance) { - exprt &inst = - static_cast(static_cast(item.expr.type())); + auto &instance = to_smv_module_instance_type(element.expr.type()); - for(auto &op : inst.operands()) - convert(op, NORMAL); + for(auto &argument : instance.arguments()) + convert(argument); - auto instance_base_name = to_symbol_expr(item.expr).get_identifier(); + auto instance_base_name = + to_smv_identifier_expr(element.expr).identifier(); instantiate( smv_module, - inst.get(ID_identifier), + instance.identifier(), instance_base_name, - inst.operands(), - inst.find_source_location()); + instance.arguments(), + instance.source_location()); } } } @@ -230,195 +278,76 @@ void smv_typecheckt::instantiate( smv_parse_treet::modulet &smv_module, const irep_idt &identifier, const irep_idt &instance, - const exprt::operandst &operands, + const exprt::operandst &arguments, const source_locationt &location) { - symbol_table_baset::symbolst::const_iterator s_it = - symbol_table.symbols.find(identifier); + // Find the module + auto module_it = smv_parse_tree.module_map.find(identifier); - if(s_it==symbol_table.symbols.end()) + if(module_it == smv_parse_tree.module_map.end()) { throw errort().with_location(location) << "submodule `" << identifier << "' not found"; } - if(s_it->second.type.id()!=ID_module) - { - throw errort().with_location(location) - << "submodule `" << identifier << "' not a module"; - } - - const irept::subt &ports=s_it->second.type.find(ID_ports).get_sub(); - - // do the arguments/ports + const auto &instantiated_module = *module_it->second; + const auto ¶meters = instantiated_module.parameters; - if(ports.size()!=operands.size()) + // map the arguments to parameters + if(parameters.size() != arguments.size()) { throw errort().with_location(location) << "submodule `" << identifier << "' has wrong number of arguments"; } - std::set port_identifiers; - rename_mapt rename_map; + rename_mapt parameter_map; - for(std::size_t i = 0; i < ports.size(); i++) + for(std::size_t i = 0; i < parameters.size(); i++) { - const irep_idt &identifier=ports[i].get(ID_identifier); - rename_map.insert(std::pair(identifier, operands[i])); - port_identifiers.insert(identifier); + parameter_map.emplace(parameters[i], arguments[i]); } - // do the variables - - std::string new_prefix= - id2string(smv_module.name)+"::var::"+id2string(instance)+"."; - - std::set var_identifiers; + // We add a prefix to all identifiers in the instantiated + // module -- this prefix is called "context" in Sec. 2.3.16 in + // the NuSMV 2.7 manual. + const std::string context = id2string(instance) + '.'; - for(auto v_it=symbol_table.symbol_module_map.lower_bound(identifier); - v_it!=symbol_table.symbol_module_map.upper_bound(identifier); - v_it++) + // copy the parse tree elements + for(auto &src_element : instantiated_module.elements) { - symbol_table_baset::symbolst::const_iterator s_it2 = - symbol_table.symbols.find(v_it->second); - - if(s_it2==symbol_table.symbols.end()) - { - throw errort() << "symbol `" << v_it->second << "' not found"; - } - - if(port_identifiers.find(s_it2->first) != port_identifiers.end()) - { - } - else if(s_it2->second.type.id() == ID_module) - { - } - else - { - symbolt symbol(s_it2->second); + auto copy = src_element; - symbol.name=new_prefix+id2string(symbol.base_name); - symbol.module=smv_module.name; - - if(smv_module.name == "smv::main") - { - symbol.pretty_name = - id2string(instance) + '.' + id2string(symbol.base_name); - } - else + // replace the parameter identifiers, + // and add the context prefix to non-parameter, non-enum identifiers + copy.expr.visit_post( + [¶meter_map, &context, this](exprt &expr) { - symbol.pretty_name = strip_smv_prefix(symbol.name); - } - - rename_map.insert( - std::pair(s_it2->first, symbol.symbol_expr())); - - var_identifiers.insert(symbol.name); - - symbol_table.add(symbol); - } - } - - // fix values (macros) - - for(const auto &v_id : var_identifiers) - { - auto s_it2 = symbol_table.get_writeable(v_id); - - if(s_it2==nullptr) - { - throw errort() << "symbol `" << v_id << "' not found"; - } - - symbolt &symbol=*s_it2; - - if(!symbol.value.is_nil()) - { - instantiate_rename(symbol.value, rename_map); - typecheck(symbol.value, OTHER); - convert_expr_to(symbol.value, symbol.type); - } - } - - // get the transition system - - const transt &trans=to_trans_expr(s_it->second.value); - - std::string old_prefix=id2string(s_it->first)+"::var::"; - - // do the transition system - - if(!trans.invar().is_true()) - { - exprt tmp(trans.invar()); - instantiate_rename(tmp, rename_map); - smv_module.add_invar(tmp); - } - - if(!trans.init().is_true()) - { - exprt tmp(trans.init()); - instantiate_rename(tmp, rename_map); - smv_module.add_init(tmp); - } - - if(!trans.trans().is_true()) - { - exprt tmp(trans.trans()); - instantiate_rename(tmp, rename_map); - smv_module.add_trans(tmp); - } - -} - -/*******************************************************************\ - -Function: smv_typecheckt::instantiate_rename - - Inputs: - - Outputs: - - Purpose: - -\*******************************************************************/ - -void smv_typecheckt::instantiate_rename( - exprt &expr, - const rename_mapt &rename_map) -{ - for(auto &op : expr.operands()) - instantiate_rename(op, rename_map); - - if(expr.id()==ID_symbol || expr.id()==ID_next_symbol) - { - const irep_idt &old_identifier=expr.get(ID_identifier); - bool next=expr.id()==ID_next_symbol; - - rename_mapt::const_iterator it= - rename_map.find(old_identifier); - - if(it!=rename_map.end()) - { - expr=it->second; - - if(next) - { - if(expr.id()==ID_symbol) - { - expr=it->second; - expr.id(ID_next_symbol); - } - else + if(expr.id() == ID_smv_identifier) { - throw errort().with_location(expr.find_source_location()) - << "expected symbol expression here, but got " - << to_string(it->second); + auto identifier = to_smv_identifier_expr(expr).identifier(); + auto parameter_it = parameter_map.find(identifier); + if(parameter_it != parameter_map.end()) + { + // It's a parameter + expr = parameter_it->second; + } + else if( + smv_parse_tree.enum_set.find(identifier) != + smv_parse_tree.enum_set.end()) + { + // It's an enum, leave as is + } + else + { + // add the context prefix + to_smv_identifier_expr(expr).identifier( + context + id2string(identifier)); + } } - } - else - expr=it->second; - } + }); + + // add to main parse tree + smv_module.elements.push_back(copy); } } @@ -576,7 +505,124 @@ Function: smv_typecheckt::typecheck void smv_typecheckt::typecheck(exprt &expr, modet mode) { - typecheck_expr_rec(expr, mode); + typecheck_expr_rec(expr, mode, false); +} + +/*******************************************************************\ + +Function: convert_word_constant + + Inputs: + + Outputs: + + Purpose: + +\*******************************************************************/ + +exprt smv_typecheckt::convert_word_constant(const constant_exprt &src_expr) +{ + auto &src = id2string(src_expr.get_value()); + + DATA_INVARIANT(src[0] == '0', "word constant grammar"); + + std::size_t index = 1; + bool is_signed = false; + + DATA_INVARIANT(index < src.size(), "word constant length"); + + switch(src[index]) + { + case 's': + case 'S': + is_signed = true; + index++; + break; + + case 'u': + case 'U': + // this is the default + index++; + break; + + default:; + } + + DATA_INVARIANT(index < src.size(), "word constant length"); + + unsigned base; + switch(src[index]) + { + case 'd': + case 'D': + base = 10; + break; + + case 'h': + case 'H': + base = 16; + break; + + case 'b': + case 'B': + base = 2; + break; + + case 'o': + case 'O': + base = 8; + break; + + default: + DATA_INVARIANT(false, "word constant base"); + } + + index++; + + DATA_INVARIANT(index < src.size(), "word constant length"); + + std::optional bits = {}; + + // optional number of bits + if(isdigit(src[index])) + { + std::string bits_str; + for(; index < src.size() && isdigit(src[index]); index++) + { + bits_str += src[index]; + } + + bits = string2integer(bits_str); + } + + std::string digits; + digits.reserve(src.size()); + + for(; index < src.size(); index++) + { + if(src[index] != '_') + digits.push_back(src[index]); + } + + if(!bits.has_value()) + { + if(base == 10) + throw errort{}.with_location(src_expr.source_location()) + << "decimal word constant without width"; + else if(base == 2) + bits = digits.size(); + else if(base == 8) + bits = digits.size() * 3; + else if(base == 16) + bits = digits.size() * 4; + } + + auto digits_int = string2integer(digits, base); + + auto type = + bitvector_typet{is_signed ? ID_signedbv : ID_unsignedbv, bits.value()}; + + return from_integer(digits_int, type).with_source_location(src_expr); } /*******************************************************************\ @@ -591,19 +637,24 @@ Function: smv_typecheckt::typecheck_expr_rec \*******************************************************************/ -void smv_typecheckt::typecheck_expr_rec(exprt &expr, modet mode) +void smv_typecheckt::typecheck_expr_rec(exprt &expr, modet mode, bool next) { - if(expr.id()==ID_symbol || - expr.id()==ID_next_symbol) + if(expr.id() == ID_smv_next) { - // next_symbol is only allowed in TRANS mode - if(expr.id() == ID_next_symbol && mode != TRANS && mode != OTHER) + if(next) + { throw errort().with_location(expr.find_source_location()) - << "next(...) is not allowed here"; + << "next(next(...)) encountered"; + } + + expr = to_unary_expr(expr).op(); + + typecheck_expr_rec(expr, mode, true); + } + else if(expr.id() == ID_symbol || expr.id() == ID_next_symbol) + { + const irep_idt &identifier = expr.get(ID_identifier); - const irep_idt &identifier=expr.get(ID_identifier); - bool next=expr.id()==ID_next_symbol; - if(define_map.find(identifier)!=define_map.end()) convert_define(identifier); @@ -615,12 +666,15 @@ void smv_typecheckt::typecheck_expr_rec(exprt &expr, modet mode) << "variable `" << identifier << "' not found"; } + if(next) + expr.id(ID_next_symbol); + symbolt &symbol=*s_it; assert(symbol.type.is_not_nil()); expr.type()=symbol.type; - if(mode==INIT || (mode==TRANS && next)) + if(mode == INIT || next) { if(symbol.module==module) { @@ -636,7 +690,7 @@ void smv_typecheckt::typecheck_expr_rec(exprt &expr, modet mode) PRECONDITION(!expr.operands().empty()); for(auto &op : expr.operands()) - typecheck_expr_rec(op, mode); + typecheck_expr_rec(op, mode, next); auto &op0_type = to_multi_ary_expr(expr).op0().type(); @@ -675,8 +729,8 @@ void smv_typecheckt::typecheck_expr_rec(exprt &expr, modet mode) else if(expr.id() == ID_smv_iff) { auto &binary_expr = to_binary_expr(expr); - typecheck_expr_rec(binary_expr.lhs(), mode); - typecheck_expr_rec(binary_expr.rhs(), mode); + typecheck_expr_rec(binary_expr.lhs(), mode, next); + typecheck_expr_rec(binary_expr.rhs(), mode, next); auto &op0_type = binary_expr.op0().type(); @@ -699,7 +753,7 @@ void smv_typecheckt::typecheck_expr_rec(exprt &expr, modet mode) else if(expr.id()==ID_constraint_select_one) { for(auto &op : expr.operands()) - typecheck_expr_rec(op, mode); + typecheck_expr_rec(op, mode, next); typet op_type; op_type.make_nil(); @@ -724,8 +778,8 @@ void smv_typecheckt::typecheck_expr_rec(exprt &expr, modet mode) exprt &op0 = to_binary_expr(expr).op0(); exprt &op1 = to_binary_expr(expr).op1(); - typecheck_expr_rec(op0, mode); - typecheck_expr_rec(op1, mode); + typecheck_expr_rec(op0, mode, next); + typecheck_expr_rec(op1, mode, next); typet op_type = type_union(op0.type(), op1.type(), expr.source_location()); @@ -751,10 +805,10 @@ void smv_typecheckt::typecheck_expr_rec(exprt &expr, modet mode) auto &if_expr = to_if_expr(expr); auto &true_case = if_expr.true_case(); auto &false_case = if_expr.false_case(); - typecheck_expr_rec(if_expr.cond(), mode); + typecheck_expr_rec(if_expr.cond(), mode, next); convert_expr_to(if_expr.cond(), bool_typet{}); - typecheck_expr_rec(true_case, mode); - typecheck_expr_rec(false_case, mode); + typecheck_expr_rec(true_case, mode, next); + typecheck_expr_rec(false_case, mode, next); expr.type() = type_union(true_case.type(), false_case.type(), expr.source_location()); convert_expr_to(true_case, expr.type()); @@ -767,8 +821,8 @@ void smv_typecheckt::typecheck_expr_rec(exprt &expr, modet mode) auto &op0 = to_binary_expr(expr).op0(); auto &op1 = to_binary_expr(expr).op1(); - typecheck_expr_rec(op0, mode); - typecheck_expr_rec(op1, mode); + typecheck_expr_rec(op0, mode, next); + typecheck_expr_rec(op1, mode, next); if(op0.type().id() == ID_range || op0.type().id() == ID_bool) { @@ -785,9 +839,15 @@ void smv_typecheckt::typecheck_expr_rec(exprt &expr, modet mode) else if(expr.id() == ID_mult) new_range = smv_range0 * smv_range1; else if(expr.id() == ID_div) - new_range = smv_range0; + { + throw errort().with_location(expr.source_location()) + << "no support for / on integer operands"; + } else if(expr.id() == ID_mod) - new_range = smv_range1; + { + throw errort().with_location(expr.source_location()) + << "no support for % on integer operands"; + } else assert(false); @@ -831,6 +891,11 @@ void smv_typecheckt::typecheck_expr_rec(exprt &expr, modet mode) { // good as is } + else if(type.id() == ID_smv_word_constant) + { + // turn into signedbv/unsignedbv + expr = convert_word_constant(to_constant_expr(expr)); + } else { PRECONDITION(false); @@ -840,7 +905,7 @@ void smv_typecheckt::typecheck_expr_rec(exprt &expr, modet mode) { // case ... esac for(auto &op : expr.operands()) - typecheck_expr_rec(op, mode); + typecheck_expr_rec(op, mode, next); bool condition = true; @@ -877,7 +942,7 @@ void smv_typecheckt::typecheck_expr_rec(exprt &expr, modet mode) << "CTL operator not permitted here"; expr.type() = bool_typet(); auto &op = to_unary_expr(expr).op(); - typecheck_expr_rec(op, mode); + typecheck_expr_rec(op, mode, next); convert_expr_to(op, expr.type()); } else if( @@ -889,7 +954,7 @@ void smv_typecheckt::typecheck_expr_rec(exprt &expr, modet mode) << "CTL operator not permitted here"; expr.type() = bool_typet(); auto &op2 = to_ternary_expr(expr).op2(); - typecheck_expr_rec(op2, mode); + typecheck_expr_rec(op2, mode, next); convert_expr_to(op2, expr.type()); } else if(expr.id() == ID_smv_ABU || expr.id() == ID_smv_EBU) @@ -900,7 +965,7 @@ void smv_typecheckt::typecheck_expr_rec(exprt &expr, modet mode) expr.type() = bool_typet(); for(std::size_t i = 0; i < expr.operands().size(); i++) { - typecheck_expr_rec(expr.operands()[i], mode); + typecheck_expr_rec(expr.operands()[i], mode, next); if(i == 0 || i == 3) convert_expr_to(expr.operands()[i], expr.type()); } @@ -915,7 +980,7 @@ void smv_typecheckt::typecheck_expr_rec(exprt &expr, modet mode) << "LTL operator not permitted here"; expr.type() = bool_typet{}; auto &op = to_unary_expr(expr).op(); - typecheck_expr_rec(op, mode); + typecheck_expr_rec(op, mode, next); convert_expr_to(op, expr.type()); } else if( @@ -927,8 +992,8 @@ void smv_typecheckt::typecheck_expr_rec(exprt &expr, modet mode) << "CTL operator not permitted here"; auto &binary_expr = to_binary_expr(expr); expr.type() = bool_typet{}; - typecheck_expr_rec(binary_expr.lhs(), mode); - typecheck_expr_rec(binary_expr.rhs(), mode); + typecheck_expr_rec(binary_expr.lhs(), mode, next); + typecheck_expr_rec(binary_expr.rhs(), mode, next); convert_expr_to(binary_expr.lhs(), expr.type()); convert_expr_to(binary_expr.rhs(), expr.type()); } @@ -941,8 +1006,8 @@ void smv_typecheckt::typecheck_expr_rec(exprt &expr, modet mode) << "LTL operator not permitted here"; auto &binary_expr = to_binary_expr(expr); expr.type() = bool_typet{}; - typecheck_expr_rec(binary_expr.lhs(), mode); - typecheck_expr_rec(binary_expr.rhs(), mode); + typecheck_expr_rec(binary_expr.lhs(), mode, next); + typecheck_expr_rec(binary_expr.rhs(), mode, next); convert_expr_to(binary_expr.lhs(), expr.type()); convert_expr_to(binary_expr.rhs(), expr.type()); } @@ -956,8 +1021,8 @@ void smv_typecheckt::typecheck_expr_rec(exprt &expr, modet mode) auto &lhs = to_binary_expr(expr).lhs(); auto &rhs = to_binary_expr(expr).rhs(); - typecheck_expr_rec(lhs, mode); - typecheck_expr_rec(rhs, mode); + typecheck_expr_rec(lhs, mode, next); + typecheck_expr_rec(rhs, mode, next); // The RHS can be a set or a singleton if(rhs.type().id() == ID_smv_set) @@ -990,7 +1055,7 @@ void smv_typecheckt::typecheck_expr_rec(exprt &expr, modet mode) else if(expr.id() == ID_unary_minus) { auto &uminus_expr = to_unary_minus_expr(expr); - typecheck_expr_rec(uminus_expr.op(), mode); + typecheck_expr_rec(uminus_expr.op(), mode, next); auto &op_type = uminus_expr.op().type(); if(op_type.id() == ID_range) @@ -1018,8 +1083,8 @@ void smv_typecheckt::typecheck_expr_rec(exprt &expr, modet mode) else if(expr.id() == ID_smv_swconst) { auto &binary_expr = to_binary_expr(expr); - typecheck_expr_rec(binary_expr.lhs(), mode); - typecheck_expr_rec(binary_expr.rhs(), mode); + typecheck_expr_rec(binary_expr.lhs(), mode, next); + typecheck_expr_rec(binary_expr.rhs(), mode, next); PRECONDITION(binary_expr.lhs().is_constant()); PRECONDITION(binary_expr.rhs().is_constant()); auto bits = numeric_cast_v(to_constant_expr(binary_expr.rhs())); @@ -1032,8 +1097,8 @@ void smv_typecheckt::typecheck_expr_rec(exprt &expr, modet mode) else if(expr.id() == ID_smv_uwconst) { auto &binary_expr = to_binary_expr(expr); - typecheck_expr_rec(binary_expr.lhs(), mode); - typecheck_expr_rec(binary_expr.rhs(), mode); + typecheck_expr_rec(binary_expr.lhs(), mode, next); + typecheck_expr_rec(binary_expr.rhs(), mode, next); PRECONDITION(binary_expr.lhs().is_constant()); PRECONDITION(binary_expr.rhs().is_constant()); auto bits = numeric_cast_v(to_constant_expr(binary_expr.rhs())); @@ -1046,7 +1111,7 @@ void smv_typecheckt::typecheck_expr_rec(exprt &expr, modet mode) else if(expr.id() == ID_smv_abs) { auto &op = to_unary_expr(expr).op(); - typecheck_expr_rec(op, mode); + typecheck_expr_rec(op, mode, next); if(op.type().id() == ID_range) { // ok @@ -1066,10 +1131,66 @@ void smv_typecheckt::typecheck_expr_rec(exprt &expr, modet mode) << "abs expects integer"; } } + else if(expr.id() == ID_smv_bit_selection) // word[high:low] + { + auto &op = to_ternary_expr(expr).op0(); + + typecheck_expr_rec(op, mode, next); + + if(op.type().id() != ID_unsignedbv && op.type().id() != ID_signedbv) + { + throw errort().with_location(op.source_location()) + << "bit selection expects word"; + } + + auto &high = to_ternary_expr(expr).op1(); + + typecheck_expr_rec(high, OTHER, next); + + // high must be an integer constant + if(high.type().id() != ID_range && high.type().id() != ID_natural) + { + throw errort().with_location(expr.find_source_location()) + << "bit-select high must be integer, but got " + << to_string(high.type()); + } + + if(high.id() != ID_constant) + throw errort().with_location(expr.find_source_location()) + << "bit-select high must be constant"; + + auto high_int = numeric_cast_v(to_constant_expr(high)); + + auto &low = to_ternary_expr(expr).op2(); + + typecheck_expr_rec(low, OTHER, next); + + // low must be an integer constant + if(low.type().id() != ID_range && low.type().id() != ID_natural) + { + throw errort().with_location(expr.find_source_location()) + << "bit-select low must be integer, but got " << to_string(low.type()); + } + + if(low.id() != ID_constant) + throw errort().with_location(expr.find_source_location()) + << "bit-select low must be constant"; + + auto low_int = numeric_cast_v(to_constant_expr(low)); + + if(low_int > high_int) + throw errort().with_location(expr.find_source_location()) + << "bit-select high must not be smaller than low"; + + auto width = numeric_cast_v(high_int - low_int + 1); + + // always unsigned, even if op is signed + expr.type() = unsignedbv_typet{width}; + } else if(expr.id() == ID_smv_bool) { auto &op = to_unary_expr(expr).op(); - typecheck_expr_rec(op, mode); + typecheck_expr_rec(op, mode, next); if( op.type().id() == ID_bool || op.type().id() == ID_unsignedbv || op.type().id() == ID_signedbv || op.type().id() == ID_range) @@ -1087,7 +1208,7 @@ void smv_typecheckt::typecheck_expr_rec(exprt &expr, modet mode) auto &multi_ary_expr = to_multi_ary_expr(expr); for(auto &op : multi_ary_expr.operands()) { - typecheck_expr_rec(op, mode); + typecheck_expr_rec(op, mode, next); if(op.type().id() != ID_bool) throw errort().with_location(op.source_location()) << "count expects boolean arguments"; @@ -1098,8 +1219,8 @@ void smv_typecheckt::typecheck_expr_rec(exprt &expr, modet mode) { auto &binary_expr = to_binary_expr(expr); - typecheck_expr_rec(binary_expr.lhs(), mode); - typecheck_expr_rec(binary_expr.rhs(), mode); + typecheck_expr_rec(binary_expr.lhs(), mode, next); + typecheck_expr_rec(binary_expr.rhs(), mode, next); binary_expr.type() = type_union( binary_expr.lhs().type(), @@ -1120,7 +1241,7 @@ void smv_typecheckt::typecheck_expr_rec(exprt &expr, modet mode) else if(expr.id() == ID_smv_toint) { auto &op = to_unary_expr(expr).op(); - typecheck_expr_rec(op, mode); + typecheck_expr_rec(op, mode, next); if(op.type().id() == ID_bool) { expr.type() = range_typet{0, 1}; @@ -1142,7 +1263,7 @@ void smv_typecheckt::typecheck_expr_rec(exprt &expr, modet mode) else if(expr.id() == ID_smv_word1) { auto &op = to_unary_expr(expr).op(); - typecheck_expr_rec(op, mode); + typecheck_expr_rec(op, mode, next); if(op.type().id() != ID_bool) throw errort().with_location(op.source_location()) << "word1 expects boolean argument"; @@ -1155,7 +1276,7 @@ void smv_typecheckt::typecheck_expr_rec(exprt &expr, modet mode) auto &binary_expr = to_binary_expr(expr); // The LHS must be a word type. - typecheck_expr_rec(binary_expr.lhs(), mode); + typecheck_expr_rec(binary_expr.lhs(), mode, next); binary_expr.type() = binary_expr.lhs().type(); @@ -1176,7 +1297,7 @@ void smv_typecheckt::typecheck_expr_rec(exprt &expr, modet mode) } // The RHS must be an integer constant - typecheck_expr_rec(binary_expr.rhs(), mode); + typecheck_expr_rec(binary_expr.rhs(), mode, next); if( binary_expr.rhs().type().id() != ID_range && @@ -1211,8 +1332,8 @@ void smv_typecheckt::typecheck_expr_rec(exprt &expr, modet mode) { auto &binary_expr = to_binary_expr(expr); - typecheck_expr_rec(binary_expr.lhs(), mode); - typecheck_expr_rec(binary_expr.rhs(), mode); + typecheck_expr_rec(binary_expr.lhs(), mode, next); + typecheck_expr_rec(binary_expr.rhs(), mode, next); if( binary_expr.lhs().type().id() != ID_signedbv && @@ -1238,7 +1359,7 @@ void smv_typecheckt::typecheck_expr_rec(exprt &expr, modet mode) else if(expr.id() == ID_smv_sizeof) { auto &op = to_unary_expr(expr).op(); - typecheck_expr_rec(op, mode); + typecheck_expr_rec(op, mode, next); if(op.type().id() == ID_signedbv || op.type().id() == ID_unsignedbv) { auto bits = to_bitvector_type(op.type()).get_width(); @@ -1253,8 +1374,8 @@ void smv_typecheckt::typecheck_expr_rec(exprt &expr, modet mode) else if(expr.id() == ID_smv_resize) { auto &binary_expr = to_binary_expr(expr); - typecheck_expr_rec(binary_expr.lhs(), mode); - typecheck_expr_rec(binary_expr.rhs(), mode); + typecheck_expr_rec(binary_expr.lhs(), mode, next); + typecheck_expr_rec(binary_expr.rhs(), mode, next); PRECONDITION(binary_expr.rhs().is_constant()); auto &lhs_type = binary_expr.lhs().type(); auto new_bits = @@ -1273,8 +1394,8 @@ void smv_typecheckt::typecheck_expr_rec(exprt &expr, modet mode) else if(expr.id() == ID_smv_extend) { auto &binary_expr = to_binary_expr(expr); - typecheck_expr_rec(binary_expr.lhs(), mode); - typecheck_expr_rec(binary_expr.rhs(), mode); + typecheck_expr_rec(binary_expr.lhs(), mode, next); + typecheck_expr_rec(binary_expr.rhs(), mode, next); PRECONDITION(binary_expr.rhs().is_constant()); auto &lhs_type = binary_expr.lhs().type(); auto old_bits = to_bitvector_type(lhs_type).get_width(); @@ -1295,7 +1416,7 @@ void smv_typecheckt::typecheck_expr_rec(exprt &expr, modet mode) { // a reinterpret cast auto &op = to_smv_unsigned_cast_expr(expr).op(); - typecheck_expr_rec(op, mode); + typecheck_expr_rec(op, mode, next); if(op.type().id() == ID_signedbv) expr.type() = unsignedbv_typet{to_signedbv_type(op.type()).get_width()}; else @@ -1308,7 +1429,7 @@ void smv_typecheckt::typecheck_expr_rec(exprt &expr, modet mode) { // a reinterpret cast auto &op = to_smv_signed_cast_expr(expr).op(); - typecheck_expr_rec(op, mode); + typecheck_expr_rec(op, mode, next); if(op.type().id() == ID_unsignedbv) expr.type() = signedbv_typet{to_unsignedbv_type(op.type()).get_width()}; else @@ -1323,7 +1444,7 @@ void smv_typecheckt::typecheck_expr_rec(exprt &expr, modet mode) expr.type() = typet{ID_smv_set}; for(auto &op : expr.operands()) - typecheck_expr_rec(op, mode); + typecheck_expr_rec(op, mode, next); } else { @@ -1480,6 +1601,19 @@ void smv_typecheckt::lower_node(exprt &expr) const auto one = from_integer(1, expr.type()); expr = if_exprt{op, std::move(one), std::move(zero)}; } + else if(expr.id() == ID_smv_bitimplies) + { + // we'll lower a->b to !a|b + auto &implies = to_smv_bitimplies_expr(expr); + expr = bitor_exprt{bitnot_exprt{implies.op0()}, implies.op1()}; + } + else if(expr.id() == ID_smv_bit_selection) + { + // we'll lower to extractbits + auto &bit_selection = to_ternary_expr(expr); + expr = extractbits_exprt{ + bit_selection.op0(), bit_selection.op2(), bit_selection.type()}; + } // lower the type lower(expr.type()); @@ -1676,42 +1810,62 @@ Function: smv_typecheckt::convert \*******************************************************************/ -void smv_typecheckt::convert(exprt &expr, expr_modet expr_mode) +void smv_typecheckt::convert(exprt &expr) { - if(expr.id() == ID_smv_next) - { - if(expr_mode!=NORMAL) - { - throw errort().with_location(expr.find_source_location()) - << "next(next(...)) encountered"; - } - - assert(expr.operands().size()==1); - - exprt tmp; - tmp.swap(to_unary_expr(expr).op()); - expr.swap(tmp); - - convert(expr, NEXT); - return; - } - for(auto &op : expr.operands()) - convert(op, expr_mode); + convert(op); - if(expr.id()==ID_symbol) + if(expr.id() == ID_smv_identifier) { const std::string &identifier=expr.get_string(ID_identifier); DATA_INVARIANT( identifier.find("::") == std::string::npos, "conversion is done once"); - std::string id = module + "::var::" + identifier; + // enum or variable? + if( + smv_parse_tree.enum_set.find(identifier) == smv_parse_tree.enum_set.end()) + { + std::string id = module + "::var::" + identifier; - expr.set(ID_identifier, id); + expr.set(ID_identifier, id); + expr.id(ID_symbol); + } + else + { + expr.id(ID_constant); + expr.type() = typet(ID_smv_enumeration); + expr.set(ID_value, identifier); + expr.remove(ID_identifier); + } + } + else if(expr.id() == ID_member) + { + auto &member_expr = to_member_expr(expr); + DATA_INVARIANT_WITH_DIAGNOSTICS( + member_expr.compound().id() == ID_symbol, + "unexpected complex_identifier", + expr.pretty()); - if(expr_mode == NEXT) - expr.id(ID_next_symbol); + auto tmp = to_symbol_expr(member_expr.compound()); + tmp.set_identifier( + id2string(tmp.get_identifier()) + '.' + + id2string(member_expr.get_component_name())); + expr = tmp; + } + else if(expr.id() == ID_index) + { + auto &index_expr = to_index_expr(expr); + DATA_INVARIANT_WITH_DIAGNOSTICS( + index_expr.array().id() == ID_symbol, + "unexpected complex_identifier", + expr.pretty()); + auto &index = index_expr.index(); + PRECONDITION(index.is_constant()); + auto index_string = id2string(to_constant_expr(index).get_value()); + auto tmp = to_symbol_expr(index_expr.array()); + tmp.set_identifier(id2string(tmp.get_identifier()) + '.' + index_string); + expr = tmp; } else if(expr.id()=="smv_nondet_choice" || expr.id()=="smv_union") @@ -1730,7 +1884,7 @@ void smv_typecheckt::convert(exprt &expr, expr_modet expr_mode) expr.id(ID_constraint_select_one); } - else if(expr.id()=="smv_cases") // cases + else if(expr.id() == ID_smv_cases) // cases { if(expr.operands().size()<1) { @@ -1809,68 +1963,75 @@ Function: smv_typecheckt::typecheck \*******************************************************************/ -void smv_typecheckt::typecheck( - smv_parse_treet::modulet::itemt &item) +void smv_typecheckt::typecheck(smv_parse_treet::modulet::elementt &element) { - switch(item.item_type) + switch(element.element_type) { - case smv_parse_treet::modulet::itemt::INIT: - typecheck(item.expr, INIT); - convert_expr_to(item.expr, bool_typet{}); + case smv_parse_treet::modulet::elementt::INIT: + typecheck(element.expr, INIT); + convert_expr_to(element.expr, bool_typet{}); + no_next_allowed(element.expr); return; - case smv_parse_treet::modulet::itemt::TRANS: - typecheck(item.expr, TRANS); - convert_expr_to(item.expr, bool_typet{}); + case smv_parse_treet::modulet::elementt::TRANS: + typecheck(element.expr, TRANS); + convert_expr_to(element.expr, bool_typet{}); return; - case smv_parse_treet::modulet::itemt::CTLSPEC: - typecheck(item.expr, CTL); - convert_expr_to(item.expr, bool_typet{}); + case smv_parse_treet::modulet::elementt::CTLSPEC: + typecheck(element.expr, CTL); + convert_expr_to(element.expr, bool_typet{}); + no_next_allowed(element.expr); return; - case smv_parse_treet::modulet::itemt::LTLSPEC: - typecheck(item.expr, LTL); - convert_expr_to(item.expr, bool_typet{}); + case smv_parse_treet::modulet::elementt::LTLSPEC: + typecheck(element.expr, LTL); + convert_expr_to(element.expr, bool_typet{}); + no_next_allowed(element.expr); return; - case smv_parse_treet::modulet::itemt::INVAR: - typecheck(item.expr, INVAR); - convert_expr_to(item.expr, bool_typet{}); + case smv_parse_treet::modulet::elementt::INVAR: + typecheck(element.expr, INVAR); + convert_expr_to(element.expr, bool_typet{}); + no_next_allowed(element.expr); return; - case smv_parse_treet::modulet::itemt::FAIRNESS: - typecheck(item.expr, OTHER); - convert_expr_to(item.expr, bool_typet{}); + case smv_parse_treet::modulet::elementt::FAIRNESS: + typecheck(element.expr, OTHER); + convert_expr_to(element.expr, bool_typet{}); + no_next_allowed(element.expr); return; - case smv_parse_treet::modulet::itemt::ASSIGN_CURRENT: - typecheck(item.equal_expr().lhs(), OTHER); - typecheck(item.equal_expr().rhs(), OTHER); - convert_expr_to(item.equal_expr().rhs(), item.equal_expr().lhs().type()); - item.equal_expr().type() = bool_typet{}; + case smv_parse_treet::modulet::elementt::ASSIGN_CURRENT: + typecheck(element.lhs(), OTHER); + typecheck(element.rhs(), OTHER); + convert_expr_to(element.rhs(), element.lhs().type()); + element.expr.type() = bool_typet{}; return; - case smv_parse_treet::modulet::itemt::ASSIGN_INIT: - typecheck(item.equal_expr().lhs(), INIT); - typecheck(item.equal_expr().rhs(), INIT); - convert_expr_to(item.equal_expr().rhs(), item.equal_expr().lhs().type()); - item.equal_expr().type() = bool_typet{}; + case smv_parse_treet::modulet::elementt::ASSIGN_INIT: + typecheck(element.lhs(), INIT); + typecheck(element.rhs(), INIT); + convert_expr_to(element.rhs(), element.lhs().type()); + no_next_allowed(element.rhs()); + element.expr.type() = bool_typet{}; return; - case smv_parse_treet::modulet::itemt::ASSIGN_NEXT: - typecheck(item.equal_expr().lhs(), TRANS); - typecheck(item.equal_expr().rhs(), TRANS); - convert_expr_to(item.equal_expr().rhs(), item.equal_expr().lhs().type()); - item.equal_expr().type() = bool_typet{}; + case smv_parse_treet::modulet::elementt::ASSIGN_NEXT: + typecheck(element.lhs(), TRANS); + typecheck(element.rhs(), TRANS); + convert_expr_to(element.rhs(), element.lhs().type()); + element.expr.type() = bool_typet{}; return; - case smv_parse_treet::modulet::itemt::DEFINE: - typecheck(item.expr, OTHER); - item.equal_expr().type() = bool_typet{}; + case smv_parse_treet::modulet::elementt::DEFINE: + typecheck(element.expr, OTHER); + element.expr.type() = bool_typet{}; return; - case smv_parse_treet::modulet::itemt::VAR: + case smv_parse_treet::modulet::elementt::ENUM: + case smv_parse_treet::modulet::elementt::IVAR: + case smv_parse_treet::modulet::elementt::VAR: return; } } @@ -1887,10 +2048,131 @@ Function: smv_typecheckt::convert \*******************************************************************/ -void smv_typecheckt::convert( - smv_parse_treet::modulet::itemt &item) +void smv_typecheckt::convert(smv_parse_treet::modulet::elementt &element) { - convert(item.expr, NORMAL); + convert(element.expr); +} + +/*******************************************************************\ + +Function: smv_typecheckt::variable_checks + + Inputs: + + Outputs: + + Purpose: + +\*******************************************************************/ + +void smv_typecheckt::variable_checks(const smv_parse_treet::modulet &module) +{ + std::unordered_set enums, defines, vars, parameters; + + for(const auto ¶meter : module.parameters) + parameters.insert(parameter); + + for(const auto &element : module.elements) + { + if(element.is_var() || element.is_ivar()) + { + irep_idt base_name = merge_complex_identifier(element.expr); + auto location = element.expr.source_location(); + + // already used as enum? + if(enums.find(base_name) != enums.end()) + { + throw errort{}.with_location(location) + << "identifier " << base_name << " already used as enum"; + } + + // already used as a parameter? + if(parameters.find(base_name) != parameters.end()) + { + throw errort{}.with_location(location) + << "identifier " << base_name << " already used as a parameter"; + } + + // already used as variable? + if(vars.find(base_name) != vars.end()) + { + throw errort{}.with_location(location) + << "identifier " << base_name << " already used as variable"; + } + + // already used as define? + if(defines.find(base_name) != defines.end()) + { + throw errort{}.with_location(location) + << "identifier " << base_name << " already used as define"; + } + + vars.insert(base_name); + } + else if(element.is_define()) + { + irep_idt base_name = merge_complex_identifier(element.lhs()); + auto location = to_equal_expr(element.expr).lhs().source_location(); + + // already used as enum? + if(enums.find(base_name) != enums.end()) + { + throw errort{}.with_location(location) + << "identifier " << base_name << " already used as enum"; + } + + // already used as a parameter? + if(parameters.find(base_name) != parameters.end()) + { + throw errort{}.with_location(location) + << "identifier " << base_name << " already used as a parameter"; + } + + // already used as variable? + if(vars.find(base_name) != vars.end()) + { + throw errort{}.with_location(location) + << "identifier " << base_name << " already used as variable"; + } + + // already used as define? + if(defines.find(base_name) != defines.end()) + { + throw errort{}.with_location(location) + << "identifier " << base_name << " already used as define"; + } + + defines.insert(base_name); + } + else if(element.is_enum()) + { + const auto &identifier_expr = to_smv_identifier_expr(element.expr); + irep_idt base_name = identifier_expr.identifier(); + + // already used as a parameter? + if(parameters.find(base_name) != parameters.end()) + { + throw errort{}.with_location(identifier_expr.source_location()) + << "identifier " << base_name << " already used as a parameter"; + } + + // already used as variable? + if(vars.find(base_name) != vars.end()) + { + throw errort{}.with_location(identifier_expr.source_location()) + << "identifier " << base_name << " already used as variable"; + } + + // already used as define? + if(defines.find(base_name) != defines.end()) + { + throw errort{}.with_location(identifier_expr.source_location()) + << "identifier " << base_name << " already used as define"; + } + + enums.insert(base_name); + } + } } /*******************************************************************\ @@ -1906,26 +2188,27 @@ Function: smv_typecheckt::create_var_symbols \*******************************************************************/ void smv_typecheckt::create_var_symbols( - const smv_parse_treet::modulet::item_listt &items) + const smv_parse_treet::modulet::element_listt &elements) { const irep_idt mode = "SMV"; - for(const auto &item : items) + for(const auto &element : elements) { - if(item.is_var()) + if(element.is_var() || element.is_ivar()) { - irep_idt base_name = to_symbol_expr(item.expr).get_identifier(); + irep_idt base_name = merge_complex_identifier(element.expr); + auto location = element.expr.source_location(); irep_idt identifier = module + "::var::" + id2string(base_name); auto symbol_ptr = symbol_table.lookup(identifier); if(symbol_ptr != nullptr) { - throw errort{}.with_location(item.expr.source_location()) + throw errort{}.with_location(location) << "variable " << base_name << " already declared, at " << symbol_ptr->location; } - typet type = item.expr.type(); + typet type = element.expr.type(); // check the type check_type(type); @@ -1940,22 +2223,31 @@ void smv_typecheckt::create_var_symbols( else symbol.pretty_name = strip_smv_prefix(symbol.name); - if(symbol.type.id() == "submodule") + if(symbol.type.id() == ID_smv_module_instance) symbol.is_input = false; else symbol.is_input = true; symbol.is_state_var = false; symbol.value = nil_exprt{}; - symbol.location = item.expr.source_location(); + symbol.location = location; symbol_table.insert(std::move(symbol)); } - else if(item.is_define()) + else if(element.is_define()) { - const auto &symbol_expr = to_symbol_expr(to_equal_expr(item.expr).lhs()); - irep_idt base_name = symbol_expr.get_identifier(); + irep_idt base_name = merge_complex_identifier(element.lhs()); + auto location = to_equal_expr(element.expr).lhs().source_location(); irep_idt identifier = module + "::var::" + id2string(base_name); + + auto symbol_ptr = symbol_table.lookup(identifier); + if(symbol_ptr != nullptr) + { + throw errort{}.with_location(location) + << "variable `" << base_name << "' already declared, at " + << symbol_ptr->location; + } + typet type; type.make_nil(); @@ -1973,10 +2265,23 @@ void smv_typecheckt::create_var_symbols( symbol.value = nil_exprt{}; symbol.is_input = true; symbol.is_state_var = false; - symbol.location = symbol_expr.source_location(); + symbol.location = location; symbol_table.insert(std::move(symbol)); } + else if(element.is_enum()) + { + irep_idt base_name = to_smv_identifier_expr(element.expr).identifier(); + irep_idt identifier = module + "::var::" + id2string(base_name); + + auto symbol_ptr = symbol_table.lookup(identifier); + if(symbol_ptr != nullptr) + { + throw errort{}.with_location(element.expr.source_location()) + << "enum " << base_name << " already declared, at " + << symbol_ptr->location; + } + } } } @@ -1992,11 +2297,8 @@ Function: smv_typecheckt::collect_define \*******************************************************************/ -void smv_typecheckt::collect_define(const equal_exprt &expr) +void smv_typecheckt::collect_define(const exprt &lhs, const exprt &rhs) { - const exprt &lhs = expr.lhs(); - const exprt &rhs = expr.rhs(); - if(lhs.id() != ID_symbol) throw errort() << "collect_define expects symbol on left hand side"; @@ -2022,9 +2324,59 @@ void smv_typecheckt::collect_define(const equal_exprt &expr) if(!result.second) { + throw errort().with_location(lhs.source_location()) + << "variable `" << symbol.display_name() << "' already defined"; + } +} + +/*******************************************************************\ + +Function: smv_typecheckt::uses_next + + Inputs: + + Outputs: + + Purpose: + +\*******************************************************************/ + +bool smv_typecheckt::uses_next(const exprt &expr) const +{ + if(expr.id() == ID_next_symbol) + return true; + + if(expr.id() == ID_symbol) + { + auto d_it = define_map.find(to_symbol_expr(expr).get_identifier()); + if(d_it != define_map.end()) + return d_it->second.uses_next; + } + + for(auto &op : expr.operands()) + if(uses_next(op)) + return true; + + return false; +} + +/*******************************************************************\ + +Function: smv_typecheckt::no_next_allowed + + Inputs: + + Outputs: + + Purpose: + +\*******************************************************************/ + +void smv_typecheckt::no_next_allowed(const exprt &expr) const +{ + if(uses_next(expr)) throw errort().with_location(expr.find_source_location()) - << "symbol `" << identifier << "' defined twice"; - } + << "next(...) is not allowed here"; } /*******************************************************************\ @@ -2069,6 +2421,7 @@ void smv_typecheckt::convert_define(const irep_idt &identifier) d.in_progress=false; d.typechecked=true; + d.uses_next = uses_next(d.value); // VAR x : type; ASSIGN x := ... does come with a type. // DEFINE x := ... doesn't come with a type. @@ -2120,8 +2473,11 @@ void smv_typecheckt::convert(smv_parse_treet::modulet &smv_module) define_map.clear(); - // variables/defines first, can be used before their declaration - create_var_symbols(smv_module.items); + // expand the module hierarchy + flatten_hierarchy(smv_module); + + // Now do variables/defines, which can be used before their declaration + create_var_symbols(smv_module.elements); // transition relation @@ -2139,41 +2495,41 @@ void smv_typecheckt::convert(smv_parse_treet::modulet &smv_module) convert_ports(smv_module, module_symbol.type); - // non-variable items - for(auto &item : smv_module.items) - if(!item.is_var()) - convert(item); - - flatten_hierarchy(smv_module); + // non-variable elements + for(auto &element : smv_module.elements) + if(!element.is_var() && !element.is_ivar()) + convert(element); // we first need to collect all the defines - for (auto &item : smv_module.items) { - if(item.is_define() || item.is_assign_current()) - collect_define(item.equal_expr()); + for(auto &element : smv_module.elements) + { + if(element.is_define() || element.is_assign_current()) + collect_define(element.lhs(), element.rhs()); } // now turn them into INVARs convert_defines(trans_invar); // do the rest now: typecheck - for (auto &item : smv_module.items) { - if(!item.is_define() && !item.is_assign_current()) - typecheck(item); + for(auto &element : smv_module.elements) + { + if(!element.is_define() && !element.is_assign_current()) + typecheck(element); } // copy to transition system - for(const auto &item : smv_module.items) + for(const auto &element : smv_module.elements) { - if (item.is_invar()) - trans_invar.push_back(item.expr); - else if (item.is_init()) - trans_init.push_back(item.expr); - else if(item.is_assign_init()) - trans_init.push_back(item.expr); - else if(item.is_assign_next()) - trans_trans.push_back(item.expr); - else if (item.is_trans()) - trans_trans.push_back(item.expr); + if(element.is_invar()) + trans_invar.push_back(element.expr); + else if(element.is_init()) + trans_init.push_back(element.expr); + else if(element.is_assign_init()) + trans_init.push_back(element.expr); + else if(element.is_assign_next()) + trans_trans.push_back(element.expr); + else if(element.is_trans()) + trans_trans.push_back(element.expr); } module_symbol.value = @@ -2191,14 +2547,14 @@ void smv_typecheckt::convert(smv_parse_treet::modulet &smv_module) { unsigned nr=1; - forall_item_list(it, smv_module.items) + for(auto &element : smv_module.elements) { - if(it->is_ctlspec() || it->is_ltlspec()) + if(element.is_ctlspec() || element.is_ltlspec()) { symbolt spec_symbol; - if(it->name.has_value()) - spec_symbol.base_name = it->name.value(); + if(element.name.has_value()) + spec_symbol.base_name = element.name.value(); else spec_symbol.base_name = "spec" + std::to_string(nr++); @@ -2208,9 +2564,9 @@ void smv_typecheckt::convert(smv_parse_treet::modulet &smv_module) spec_symbol.type = bool_typet(); spec_symbol.is_property = true; spec_symbol.mode = "SMV"; - spec_symbol.value = it->expr; - spec_symbol.location = it->location; - spec_symbol.location.set_comment(to_string(it->expr)); + spec_symbol.value = element.expr; + spec_symbol.location = element.location; + spec_symbol.location.set_comment(to_string(element.expr)); if(smv_module.name == "smv::main") spec_symbol.pretty_name = spec_symbol.base_name; @@ -2249,14 +2605,21 @@ Function: smv_typecheckt::typecheck void smv_typecheckt::typecheck() { - smv_parse_treet::modulest::iterator it=smv_parse_tree.modules.find(module); + if(module != "smv::main") + return; + + // check all modules for duplicate identifiers + for(auto &module : smv_parse_tree.module_list) + variable_checks(module); + + auto it = smv_parse_tree.module_map.find(module); - if(it==smv_parse_tree.modules.end()) + if(it == smv_parse_tree.module_map.end()) { throw errort() << "failed to find module " << module; } - convert(it->second); + convert(*it->second); } /*******************************************************************\ diff --git a/src/smvlang/smv_types.h b/src/smvlang/smv_types.h index b32330958..868b80c12 100644 --- a/src/smvlang/smv_types.h +++ b/src/smvlang/smv_types.h @@ -9,6 +9,7 @@ Author: Daniel Kroening, dkr@amazon.com #ifndef CPROVER_SMV_TYPES_H #define CPROVER_SMV_TYPES_H +#include #include #include @@ -71,4 +72,58 @@ inline smv_enumeration_typet &to_smv_enumeration_type(typet &type) return static_cast(type); } +/// The type used for VAR declarations that are in fact module instantiations +class smv_module_instance_typet : public typet +{ +public: + explicit smv_module_instance_typet(irep_idt _identifier) + : typet{ID_smv_module_instance} + { + identifier(_identifier); + } + + irep_idt identifier() const + { + return get(ID_identifier); + } + + void identifier(irep_idt _identifier) + { + set(ID_identifier, _identifier); + } + + const exprt::operandst &arguments() const + { + return (const exprt::operandst &)get_sub(); + } + + exprt::operandst &arguments() + { + return (exprt::operandst &)get_sub(); + } +}; + +/*! \brief Cast a generic typet to a \ref smv_module_instance_typet + * + * This is an unchecked conversion. \a type must be known to be \ref + * smv_module_instance_typet. + * + * \param type Source type + * \return Object of type \ref smv_module_instance_typet + * + * \ingroup gr_std_types +*/ +inline const smv_module_instance_typet & +to_smv_module_instance_type(const typet &type) +{ + PRECONDITION(type.id() == ID_smv_module_instance); + return static_cast(type); +} + +inline smv_module_instance_typet &to_smv_module_instance_type(typet &type) +{ + PRECONDITION(type.id() == ID_smv_module_instance); + return static_cast(type); +} + #endif // CPROVER_SMV_TYPES_H diff --git a/src/temporal-logic/hoa.cpp b/src/temporal-logic/hoa.cpp index 68d6a6987..902d4d36d 100644 --- a/src/temporal-logic/hoa.cpp +++ b/src/temporal-logic/hoa.cpp @@ -266,6 +266,28 @@ hoat::headert hoa_parsert::parse_header() return header; } +hoat::ap_mapt hoat::parse_AP() const +{ + for(auto &item : header) + { + if(item.first == "AP:") + { + hoat::ap_mapt result; + std::size_t index = 0; + for(auto &name : item.second) + { + if(index != 0) + result[index - 1] = name; + index++; + } + return result; + } + } + + // header not found + return {}; +} + hoat::bodyt hoa_parsert::parse_body() { if(!tokenizer.consume().is_body()) @@ -323,8 +345,6 @@ hoat::edgest hoa_parsert::parse_edges() return edges; } -#include - hoat::edget hoa_parsert::parse_edge() { edget edge; diff --git a/src/temporal-logic/hoa.h b/src/temporal-logic/hoa.h index c532522d1..e140e0adc 100644 --- a/src/temporal-logic/hoa.h +++ b/src/temporal-logic/hoa.h @@ -68,7 +68,10 @@ class hoat intt max_state_number() const; // atomic propositions - std::map ap_map; + using ap_mapt = std::map; + + // parses the AP header + ap_mapt parse_AP() const; // convert into a graph struct graph_edget diff --git a/src/temporal-logic/ltl_sva_to_string.cpp b/src/temporal-logic/ltl_sva_to_string.cpp index d5d288703..32dd9f048 100644 --- a/src/temporal-logic/ltl_sva_to_string.cpp +++ b/src/temporal-logic/ltl_sva_to_string.cpp @@ -11,6 +11,7 @@ Author: Daniel Kroening, dkr@amazon.com #include #include +#include #include #include "ltl.h" @@ -21,8 +22,11 @@ Author: Daniel Kroening, dkr@amazon.com exprt ltl_sva_to_stringt::atom(const std::string &string) const { + if(string.empty() || string[0] != 'a') + throw ebmc_errort{} << "got unexpected atom '" << string << "'"; + // map back to number - auto number = safe_string2size_t(string); + auto number = safe_string2size_t(string.substr(1, std::string::npos)); PRECONDITION(number < atoms.size()); @@ -297,44 +301,58 @@ ltl_sva_to_stringt::rec(const exprt &expr, modet mode) auto new_expr = R_exprt{until_with.rhs(), until_with.lhs()}; // swapped return infix(" R ", new_expr, mode); } - else if( - expr.id() == ID_sva_weak || expr.id() == ID_sva_strong || - expr.id() == ID_sva_implicit_weak || expr.id() == ID_sva_implicit_strong) + else if(expr.id() == ID_sva_weak || expr.id() == ID_sva_implicit_weak) { PRECONDITION(mode == PROPERTY); auto &sequence = to_sva_sequence_property_expr_base(expr).sequence(); - auto op_rec = rec(sequence, SVA_SEQUENCE); + auto op_rec = rec(sequence, SVA_SEQUENCE_WEAK); // weak closure return resultt{precedencet::ATOM, '{' + op_rec.s + '}'}; } + else if(expr.id() == ID_sva_strong || expr.id() == ID_sva_implicit_strong) + { + PRECONDITION(mode == PROPERTY); + auto &sequence = to_sva_sequence_property_expr_base(expr).sequence(); + auto op_rec = rec(sequence, SVA_SEQUENCE_STRONG); + + // we use the weak closure, and reject cases where this does not work + return resultt{precedencet::ATOM, '{' + op_rec.s + '}'}; + } else if(expr.id() == ID_sva_or) { // can be sequence or property - PRECONDITION(mode == PROPERTY || mode == SVA_SEQUENCE); + PRECONDITION( + mode == PROPERTY || mode == SVA_SEQUENCE_STRONG || + mode == SVA_SEQUENCE_WEAK); return infix("|", expr, mode); } else if(expr.id() == ID_sva_and) { // can be sequence or property - PRECONDITION(mode == PROPERTY || mode == SVA_SEQUENCE); + PRECONDITION( + mode == PROPERTY || mode == SVA_SEQUENCE_STRONG || + mode == SVA_SEQUENCE_WEAK); // NLM intersection return infix("&", expr, mode); } else if(expr.id() == ID_sva_sequence_intersect) { - PRECONDITION(mode == SVA_SEQUENCE); + PRECONDITION(mode == SVA_SEQUENCE_STRONG || mode == SVA_SEQUENCE_WEAK); return infix("&&", expr, mode); } else if(expr.id() == ID_sva_boolean) { // can be sequence or property - PRECONDITION(mode == PROPERTY || mode == SVA_SEQUENCE); + PRECONDITION( + mode == PROPERTY || mode == SVA_SEQUENCE_STRONG || + mode == SVA_SEQUENCE_WEAK); return rec(to_sva_boolean_expr(expr).op(), BOOLEAN); } else if(expr.id() == ID_sva_cycle_delay) { - PRECONDITION(mode == SVA_SEQUENCE); + PRECONDITION(mode == SVA_SEQUENCE_STRONG || mode == SVA_SEQUENCE_WEAK); + auto &delay = to_sva_cycle_delay_expr(expr); if(delay.lhs().is_nil()) @@ -343,6 +361,9 @@ ltl_sva_to_stringt::rec(const exprt &expr, modet mode) if(delay.is_range()) // ##[from:to] rhs { + if(mode == SVA_SEQUENCE_STRONG) + throw ltl_sva_to_string_unsupportedt{expr}; + auto from = numeric_cast_v(delay.from()); if(delay.is_unbounded()) // ##[n:$] rhs @@ -378,6 +399,9 @@ ltl_sva_to_stringt::rec(const exprt &expr, modet mode) if(delay.is_range()) { + if(mode == SVA_SEQUENCE_STRONG) + throw ltl_sva_to_string_unsupportedt{expr}; + auto from = numeric_cast_v(delay.from()); if(from == 0) @@ -387,6 +411,9 @@ ltl_sva_to_stringt::rec(const exprt &expr, modet mode) } else if(delay.is_unbounded()) // f ##[n:$] g { + if(mode == SVA_SEQUENCE_STRONG) + throw ltl_sva_to_string_unsupportedt{expr}; + return infix( " ; 1[*" + integer2string(from - 1) + "..] ; ", new_expr, mode); } @@ -421,7 +448,11 @@ ltl_sva_to_stringt::rec(const exprt &expr, modet mode) { // ##[*] x ---> 1[*] ; x // w ##[*] x ---> w : 1[*] ; x - PRECONDITION(mode == SVA_SEQUENCE); + PRECONDITION(mode == SVA_SEQUENCE_STRONG || mode == SVA_SEQUENCE_WEAK); + + if(mode == SVA_SEQUENCE_STRONG) + throw ltl_sva_to_string_unsupportedt{expr}; + auto &cycle_delay_expr = to_sva_cycle_delay_star_expr(expr); if(cycle_delay_expr.has_lhs()) { @@ -442,7 +473,11 @@ ltl_sva_to_stringt::rec(const exprt &expr, modet mode) { // ##[+] x ---> 1[+] ; x // w ##[+] x ---> w : 1[+] ; x - PRECONDITION(mode == SVA_SEQUENCE); + PRECONDITION(mode == SVA_SEQUENCE_STRONG || mode == SVA_SEQUENCE_WEAK); + + if(mode == SVA_SEQUENCE_STRONG) + throw ltl_sva_to_string_unsupportedt{expr}; + auto &cycle_delay_expr = to_sva_cycle_delay_plus_expr(expr); if(cycle_delay_expr.has_lhs()) { @@ -471,11 +506,14 @@ ltl_sva_to_stringt::rec(const exprt &expr, modet mode) expr.id() == ID_sva_sequence_repetition_star) // [*] or [*n] or [*x:y] or [*x:$] { - PRECONDITION(mode == SVA_SEQUENCE); + PRECONDITION(mode == SVA_SEQUENCE_STRONG || mode == SVA_SEQUENCE_WEAK); auto &repetition = to_sva_sequence_repetition_star_expr(expr); unary_exprt new_expr{ID_sva_sequence_repetition_star, repetition.op()}; if(!repetition.repetitions_given()) { + if(mode == SVA_SEQUENCE_STRONG) + throw ltl_sva_to_string_unsupportedt{expr}; + return suffix("[*]", new_expr, mode); } else if(repetition.is_empty_match()) @@ -498,6 +536,9 @@ ltl_sva_to_stringt::rec(const exprt &expr, modet mode) } else if(repetition.is_unbounded()) { + if(mode == SVA_SEQUENCE_STRONG) + throw ltl_sva_to_string_unsupportedt{expr}; + auto from = numeric_cast_v(repetition.from()); return suffix("[*" + integer2string(from) + "..]", new_expr, mode); } @@ -506,7 +547,11 @@ ltl_sva_to_stringt::rec(const exprt &expr, modet mode) } else if(expr.id() == ID_sva_sequence_repetition_plus) // something[+] { - PRECONDITION(mode == SVA_SEQUENCE); + PRECONDITION(mode == SVA_SEQUENCE_STRONG || mode == SVA_SEQUENCE_WEAK); + + if(mode == SVA_SEQUENCE_STRONG) + throw ltl_sva_to_string_unsupportedt{expr}; + auto new_expr = unary_exprt{ ID_sva_sequence_repetition_plus, to_sva_sequence_repetition_plus_expr(expr).op()}; @@ -514,7 +559,10 @@ ltl_sva_to_stringt::rec(const exprt &expr, modet mode) } else if(expr.id() == ID_sva_sequence_goto_repetition) // something[->n] { - PRECONDITION(mode == SVA_SEQUENCE); + // ltl2tgba produces the wrong anser for [->n] and [=n] + throw ltl_sva_to_string_unsupportedt{expr}; + + PRECONDITION(mode == SVA_SEQUENCE_STRONG || mode == SVA_SEQUENCE_WEAK); auto &repetition = to_sva_sequence_goto_repetition_expr(expr); unary_exprt new_expr{ID_sva_sequence_goto_repetition, repetition.op()}; if(repetition.is_singleton()) @@ -533,6 +581,9 @@ ltl_sva_to_stringt::rec(const exprt &expr, modet mode) } else if(repetition.is_unbounded()) { + if(mode == SVA_SEQUENCE_STRONG) + throw ltl_sva_to_string_unsupportedt{expr}; + auto from = numeric_cast_v(repetition.from()); return suffix("[->" + integer2string(from) + "..]", new_expr, mode); } @@ -542,7 +593,10 @@ ltl_sva_to_stringt::rec(const exprt &expr, modet mode) else if( expr.id() == ID_sva_sequence_non_consecutive_repetition) // something[=n] { - PRECONDITION(mode == SVA_SEQUENCE); + // ltl2tgba produces the wrong anser for [->n] and [=n] + throw ltl_sva_to_string_unsupportedt{expr}; + + PRECONDITION(mode == SVA_SEQUENCE_STRONG || mode == SVA_SEQUENCE_WEAK); auto &repetition = to_sva_sequence_non_consecutive_repetition_expr(expr); unary_exprt new_expr{ ID_sva_sequence_non_consecutive_repetition, repetition.op()}; @@ -562,6 +616,9 @@ ltl_sva_to_stringt::rec(const exprt &expr, modet mode) } else if(repetition.is_unbounded()) { + if(mode == SVA_SEQUENCE_STRONG) + throw ltl_sva_to_string_unsupportedt{expr}; + auto from = numeric_cast_v(repetition.from()); return suffix("[=" + integer2string(from) + "..]", new_expr, mode); } @@ -571,9 +628,9 @@ ltl_sva_to_stringt::rec(const exprt &expr, modet mode) } else if(expr.id() == ID_sva_sequence_first_match) // first_match(...) { - PRECONDITION(mode == SVA_SEQUENCE); + PRECONDITION(mode == SVA_SEQUENCE_STRONG || mode == SVA_SEQUENCE_WEAK); auto &sequence = to_sva_sequence_first_match_expr(expr).sequence(); - auto op_rec = rec(sequence, SVA_SEQUENCE); + auto op_rec = rec(sequence, mode); return resultt{precedencet::ATOM, "first_match(" + op_rec.s + ')'}; } else if(!is_temporal_operator(expr)) diff --git a/src/temporal-logic/ltl_sva_to_string.h b/src/temporal-logic/ltl_sva_to_string.h index 02cb9c6e3..e1bdea976 100644 --- a/src/temporal-logic/ltl_sva_to_string.h +++ b/src/temporal-logic/ltl_sva_to_string.h @@ -53,9 +53,16 @@ class ltl_sva_to_stringt std::string s; }; + // This maps our expressions to a number. + // Spot may or may not use the same numbering in the AP header. numberingt atoms; - using modet = enum { PROPERTY, SVA_SEQUENCE, BOOLEAN }; + using modet = enum { + PROPERTY, + SVA_SEQUENCE_STRONG, + SVA_SEQUENCE_WEAK, + BOOLEAN + }; resultt prefix(std::string s, const unary_exprt &, modet); resultt suffix(std::string s, const unary_exprt &, modet); diff --git a/src/temporal-logic/ltl_to_buechi.cpp b/src/temporal-logic/ltl_to_buechi.cpp index 2e119b99b..e67de4523 100644 --- a/src/temporal-logic/ltl_to_buechi.cpp +++ b/src/temporal-logic/ltl_to_buechi.cpp @@ -16,6 +16,7 @@ Author: Daniel Kroening, dkr@amazon.com #include #include #include +#include #include #include @@ -46,12 +47,13 @@ void buechi_transt::rename_state_symbol(const symbol_exprt &new_state_symbol) exprt hoa_label_to_expr( const hoat::labelt &label, - const ltl_sva_to_stringt <l_sva_to_string) + const ltl_sva_to_stringt <l_sva_to_string, + const hoat::ap_mapt &ap_map) { std::vector operands; operands.reserve(label.get_sub().size()); for(auto &sub : label.get_sub()) - operands.push_back(hoa_label_to_expr(sub, ltl_sva_to_string)); + operands.push_back(hoa_label_to_expr(sub, ltl_sva_to_string, ap_map)); if(label.id() == "t") { @@ -78,8 +80,17 @@ exprt hoa_label_to_expr( } else { - // atomic proposition, given as number - return ltl_sva_to_string.atom(label.id_string()); + // Atomic proposition, given as number. This is the numbering + // from the "AP" header, which then maps to a string "aX", which + // is our atom number. These may or may not match. + auto spot_ap_number = safe_string2size_t(label.id_string()); + + auto ap_map_it = ap_map.find(spot_ap_number); + if(ap_map_it == ap_map.end()) + throw ebmc_errort{} << "failed to find atom " << label.id() + << " in AP header"; + + return ltl_sva_to_string.atom(ap_map_it->second); } } @@ -150,6 +161,7 @@ ltl_to_buechi(const exprt &property, message_handlert &message_handler) hoa.buechi_acceptance_cleanup(); auto max_state_number = hoa.max_state_number(); + auto ap_map = hoa.parse_AP(); auto state_type = range_typet{0, max_state_number}; const auto buechi_state = symbol_exprt{"buechi::state", state_type}; const auto buechi_next_state = @@ -220,7 +232,7 @@ ltl_to_buechi(const exprt &property, message_handlert &message_handler) { auto pre = equal_exprt{ buechi_state, from_integer(state.first.number, state_type)}; - auto cond = hoa_label_to_expr(edge.label, ltl_sva_to_string); + auto cond = hoa_label_to_expr(edge.label, ltl_sva_to_string, ap_map); error_disjuncts.push_back(and_exprt{pre, cond}); } } @@ -242,7 +254,7 @@ ltl_to_buechi(const exprt &property, message_handlert &message_handler) { if(edge.dest_states.size() != 1) throw ebmc_errort() << "edge must have one destination state"; - auto cond = hoa_label_to_expr(edge.label, ltl_sva_to_string); + auto cond = hoa_label_to_expr(edge.label, ltl_sva_to_string, ap_map); auto post = equal_exprt{ buechi_next_state, from_integer(edge.dest_states.front(), state_type)}; @@ -264,6 +276,7 @@ ltl_to_buechi(const exprt &property, message_handlert &message_handler) } catch(ltl_sva_to_string_unsupportedt error) { - throw ebmc_errort{} << "failed to convert " << error.expr.id(); + // re-throw + throw ltl_to_buechi_unsupportedt{error.expr}; } } diff --git a/src/temporal-logic/ltl_to_buechi.h b/src/temporal-logic/ltl_to_buechi.h index d842302ac..28efe4991 100644 --- a/src/temporal-logic/ltl_to_buechi.h +++ b/src/temporal-logic/ltl_to_buechi.h @@ -37,6 +37,16 @@ struct buechi_transt void rename_state_symbol(const symbol_exprt &new_state_symbol); }; +class ltl_to_buechi_unsupportedt +{ +public: + explicit ltl_to_buechi_unsupportedt(exprt __expr) : expr(std::move(__expr)) + { + } + + exprt expr; +}; + class message_handlert; buechi_transt ltl_to_buechi(const exprt &formula, message_handlert &); diff --git a/src/temporal-logic/sva_to_ltl.cpp b/src/temporal-logic/sva_to_ltl.cpp index 00e4cbb9f..4830aabfe 100644 --- a/src/temporal-logic/sva_to_ltl.cpp +++ b/src/temporal-logic/sva_to_ltl.cpp @@ -272,7 +272,8 @@ exprt SVA_to_LTL(exprt expr) } else if( expr.id() == ID_and || expr.id() == ID_implies || expr.id() == ID_or || - expr.id() == ID_not) + expr.id() == ID_not || + (expr.id() == ID_equal && to_equal_expr(expr).lhs().type().id() == ID_bool)) { for(auto &op : expr.operands()) { diff --git a/src/temporal-logic/temporal_logic.cpp b/src/temporal-logic/temporal_logic.cpp index 2ae4155f1..cb01a8216 100644 --- a/src/temporal-logic/temporal_logic.cpp +++ b/src/temporal-logic/temporal_logic.cpp @@ -112,7 +112,8 @@ bool is_SVA_sequence_operator(const exprt &expr) id == ID_sva_sequence_goto_repetition || id == ID_sva_sequence_non_consecutive_repetition || id == ID_sva_sequence_repetition_star || - id == ID_sva_sequence_repetition_plus || id == ID_sva_boolean; + id == ID_sva_sequence_repetition_plus || id == ID_sva_boolean || + id == ID_sva_sequence_disable_iff; } bool is_SVA_operator(const exprt &expr) @@ -213,22 +214,3 @@ std::optional LTL_to_CTL(exprt expr) else return {}; } - -bool is_Buechi_SVA(const exprt &expr) -{ - auto unsupported_operator = [](const exprt &expr) - { - // ltl2tgba produces the wrong anser for [->n] and [=n] - if( - expr.id() == ID_sva_implicit_strong || expr.id() == ID_sva_strong || - expr.id() == ID_sva_sequence_goto_repetition || - expr.id() == ID_sva_sequence_non_consecutive_repetition) - { - return true; - } - else - return is_temporal_operator(expr) && !is_SVA_operator(expr); - }; - - return !has_subexpr(expr, unsupported_operator); -} diff --git a/src/temporal-logic/temporal_logic.h b/src/temporal-logic/temporal_logic.h index 0192122a1..e799a3624 100644 --- a/src/temporal-logic/temporal_logic.h +++ b/src/temporal-logic/temporal_logic.h @@ -81,8 +81,4 @@ bool is_SVA_always_s_eventually_p(const exprt &); /// returns {} if not possible std::optional LTL_to_CTL(exprt); -/// Returns true iff the given expression is an SVA expression that -/// we can convert into a Buechi automaton -bool is_Buechi_SVA(const exprt &); - #endif diff --git a/src/temporal-logic/trivial_sva.cpp b/src/temporal-logic/trivial_sva.cpp index 6eadfdc17..be055bc1a 100644 --- a/src/temporal-logic/trivial_sva.cpp +++ b/src/temporal-logic/trivial_sva.cpp @@ -110,6 +110,14 @@ exprt trivial_sva(exprt expr) auto &disable_iff_expr = to_sva_disable_iff_expr(expr); expr = or_exprt{disable_iff_expr.lhs(), disable_iff_expr.rhs()}; } + else if(expr.id() == ID_sva_sequence_disable_iff) + { + auto &disable_iff_expr = to_sva_sequence_disable_iff_expr(expr); + expr = sva_or_exprt{ + sva_boolean_exprt{disable_iff_expr.lhs(), verilog_sva_sequence_typet{}}, + disable_iff_expr.rhs(), + verilog_sva_sequence_typet{}}; + } else if(expr.id() == ID_sva_accept_on || expr.id() == ID_sva_sync_accept_on) { auto &sva_abort_expr = to_sva_abort_expr(expr); diff --git a/src/trans-netlist/aig.h b/src/trans-netlist/aig.h index 51f1048a5..1a2593b1e 100644 --- a/src/trans-netlist/aig.h +++ b/src/trans-netlist/aig.h @@ -22,18 +22,30 @@ class aig_nodet { public: literalt a, b; - aig_nodet() {} + explicit aig_nodet(literalt::var_not var_no) + : a{literalt::unused_var_no(), false}, b{var_no, false} + { + } - bool is_and() const { return a.var_no() != literalt::unused_var_no(); } + aig_nodet(literalt _a, literalt _b) : a(_a), b(_b) + { + } - bool is_var() const { return a.var_no() == literalt::unused_var_no(); } + bool is_and() const + { + return a.var_no() != literalt::unused_var_no(); + } - void make_and(literalt _a, literalt _b) { - a = _a; - b = _b; + bool is_var() const + { + return a.var_no() == literalt::unused_var_no(); } - void make_var() { a.set(literalt::unused_var_no(), false); } + literalt::var_not var_no() const + { + PRECONDITION(is_var()); + return b.var_no(); + } }; class aigt { @@ -56,23 +68,15 @@ class aigt { void swap(aigt &g) { nodes.swap(g.nodes); } - literalt new_node() { - nodes.push_back(aig_nodet()); - literalt l; - l.set(nodes.size() - 1, false); - return l; - } - - literalt new_var_node() { - literalt l = new_node(); - nodes.back().make_var(); - return l; + literalt new_var_node(literalt::var_not var_no = literalt::unused_var_no()) + { + nodes.emplace_back(var_no); + return {narrow_cast(nodes.size() - 1), false}; } literalt new_and_node(literalt a, literalt b) { - literalt l = new_node(); - nodes.back().make_and(a, b); - return l; + nodes.emplace_back(a, b); + return {narrow_cast(nodes.size() - 1), false}; } bool empty() const { return nodes.empty(); } diff --git a/src/trans-netlist/aig_prop.h b/src/trans-netlist/aig_prop.h index 1d18be4d3..cc2aa4949 100644 --- a/src/trans-netlist/aig_prop.h +++ b/src/trans-netlist/aig_prop.h @@ -46,7 +46,10 @@ class aig_prop_baset : public propt { PRECONDITION(false); } - literalt new_variable() override { return dest.new_node(); } + literalt new_variable() override + { + return dest.new_var_node(); + } size_t no_variables() const override { return dest.number_of_nodes(); } diff --git a/src/trans-netlist/counterexample_netlist.cpp b/src/trans-netlist/counterexample_netlist.cpp index c8bcbcb90..421534e95 100644 --- a/src/trans-netlist/counterexample_netlist.cpp +++ b/src/trans-netlist/counterexample_netlist.cpp @@ -39,9 +39,7 @@ void show_state( std::cout << "Transition system state " << timeframe << "\n"; std::cout << "----------------------------------------------------\n"; - for(var_mapt::mapt::const_iterator - it=map.var_map.map.begin(); - it!=map.var_map.map.end(); it++) + for(auto it : map.var_map.sorted()) { const var_mapt::vart &var=it->second; diff --git a/src/trans-netlist/ldg.cpp b/src/trans-netlist/ldg.cpp index 6c17cda7d..2bcffa1ba 100644 --- a/src/trans-netlist/ldg.cpp +++ b/src/trans-netlist/ldg.cpp @@ -59,11 +59,8 @@ void ldgt::compute( nodes[*l_it].is_source_latch=true; // get the next state nodes - - for(var_mapt::mapt::const_iterator - m_it=netlist.var_map.map.begin(); - m_it!=netlist.var_map.map.end(); - m_it++) + + for(auto m_it : netlist.var_map.sorted()) { const var_mapt::vart &var=m_it->second; if(var.is_latch()) @@ -101,3 +98,30 @@ void ldgt::compute( } } } + +void ldgt::output(const netlistt &netlist, std::ostream &out) const +{ + for(auto var_it : netlist.var_map.sorted()) + { + auto &var = var_it->second; + + for(std::size_t i = 0; i < var.bits.size(); i++) + { + if(var.is_latch()) + { + literalt::var_not v = var.bits[i].current.var_no(); + + out << " " << var_it->first << "[" << i << "] = " << v << ":"; + + const ldg_nodet &node = (*this)[v]; + + for(ldg_nodet::edgest::const_iterator i_it = node.in.begin(); + i_it != node.in.end(); + i_it++) + out << " " << i_it->first; + + out << '\n'; + } + } + } +} diff --git a/src/trans-netlist/ldg.h b/src/trans-netlist/ldg.h index 267a6f108..e6d38894e 100644 --- a/src/trans-netlist/ldg.h +++ b/src/trans-netlist/ldg.h @@ -9,12 +9,13 @@ Author: Daniel Kroening, kroening@kroening.com #ifndef CPROVER_TRANS_LDG_H #define CPROVER_TRANS_LDG_H -#include - #include #include "netlist.h" +#include +#include + struct ldg_nodet:public graph_nodet<> { public: @@ -35,6 +36,8 @@ class ldgt:public grapht // latches that are to be considered void compute(const netlistt &netlist, const latchest &localization); + + void output(const netlistt &, std::ostream &) const; }; #endif diff --git a/src/trans-netlist/netlist.cpp b/src/trans-netlist/netlist.cpp index 4ecccb931..0ea7fe2ba 100644 --- a/src/trans-netlist/netlist.cpp +++ b/src/trans-netlist/netlist.cpp @@ -32,9 +32,8 @@ void netlistt::print(std::ostream &out) const out << '\n'; out << "Next state functions:" << '\n'; - for(var_mapt::mapt::const_iterator - it=var_map.map.begin(); - it!=var_map.map.end(); it++) + // use a sorted var_map to get determistic output + for(auto it : var_map.sorted()) { const var_mapt::vart &var=it->second; @@ -190,11 +189,9 @@ void netlistt::output_dot(std::ostream &out) const { aigt::output_dot(out); - // add the sinks - for(var_mapt::mapt::const_iterator - it=var_map.map.begin(); - it!=var_map.map.end(); - it++) + // Add the sinks. + // Use a sorted var_map to get deterministic results. + for(auto it : var_map.sorted()) { const var_mapt::vart &var=it->second; diff --git a/src/trans-netlist/smv_netlist.cpp b/src/trans-netlist/smv_netlist.cpp index 61244e9d0..2d5a5b6dd 100644 --- a/src/trans-netlist/smv_netlist.cpp +++ b/src/trans-netlist/smv_netlist.cpp @@ -106,7 +106,7 @@ void print_smv(const netlistt &netlist, std::ostream &out, const exprt &expr) std::ostringstream buffer; auto l = to_literal_expr(expr).get_literal(); print_smv(netlist, buffer, l); - if(l.sign()) + if(l.sign() && !l.is_constant()) return {precedencet::NOT, buffer.str()}; else return {precedencet::MAX, buffer.str()}; @@ -127,17 +127,19 @@ void smv_netlist(const netlistt &netlist, std::ostream &out) out << "-- Variables" << '\n'; out << '\n'; + // We use the sorted var map to get deterministic output auto &var_map = netlist.var_map; + const auto sorted_var_map = var_map.sorted(); - for(auto &var_it : var_map.map) + for(auto var_it : sorted_var_map) { - const var_mapt::vart &var = var_it.second; + const var_mapt::vart &var = var_it->second; for(std::size_t i = 0; i < var.bits.size(); i++) { if(var.is_latch()) { - out << "VAR " << id2smv(var_it.first); + out << "VAR " << id2smv(var_it->first); if(var.bits.size() != 1) out << "[" << i << "]"; out << ": boolean;" << '\n'; @@ -149,15 +151,15 @@ void smv_netlist(const netlistt &netlist, std::ostream &out) out << "-- Inputs" << '\n'; out << '\n'; - for(auto &var_it : var_map.map) + for(auto var_it : sorted_var_map) { - const var_mapt::vart &var = var_it.second; + const var_mapt::vart &var = var_it->second; for(std::size_t i = 0; i < var.bits.size(); i++) { if(var.is_input()) { - out << "VAR " << id2smv(var_it.first); + out << "VAR " << id2smv(var_it->first); if(var.bits.size() != 1) out << "[" << i << "]"; out << ": boolean;" << '\n'; @@ -189,15 +191,15 @@ void smv_netlist(const netlistt &netlist, std::ostream &out) out << "-- Next state functions" << '\n'; out << '\n'; - for(auto &var_it : var_map.map) + for(auto var_it : sorted_var_map) { - const var_mapt::vart &var = var_it.second; + const var_mapt::vart &var = var_it->second; for(std::size_t i = 0; i < var.bits.size(); i++) { if(var.is_latch()) { - out << "ASSIGN next(" << id2smv(var_it.first); + out << "ASSIGN next(" << id2smv(var_it->first); if(var.bits.size() != 1) out << "[" << i << "]"; out << "):="; diff --git a/src/trans-netlist/trans_to_netlist.cpp b/src/trans-netlist/trans_to_netlist.cpp index 44948e7d7..9dd84fc26 100644 --- a/src/trans-netlist/trans_to_netlist.cpp +++ b/src/trans-netlist/trans_to_netlist.cpp @@ -16,6 +16,7 @@ Author: Daniel Kroening, kroening@kroening.com #include #include +#include #include #include #include @@ -148,9 +149,9 @@ class convert_trans_to_netlistt:public messaget std::optional convert_property(const exprt &); - void map_vars( - const irep_idt &module, - netlistt &dest); + var_mapt build_var_map(const irep_idt &module); + + void allocate_state_variables(netlistt &); }; /*******************************************************************\ @@ -189,7 +190,7 @@ literalt convert_trans_to_netlistt::new_input() /*******************************************************************\ -Function: convert_trans_to_netlistt::map_vars +Function: convert_trans_to_netlistt::build_var_map Inputs: @@ -199,23 +200,40 @@ Function: convert_trans_to_netlistt::map_vars \*******************************************************************/ -void convert_trans_to_netlistt::map_vars( - const irep_idt &module, - netlistt &dest) +var_mapt convert_trans_to_netlistt::build_var_map(const irep_idt &module) { boolbv_widtht boolbv_width(ns); + var_mapt var_map; - auto update_dest_var_map = [&dest, &boolbv_width](const symbolt &symbol) { + auto update_dest_var_map = [&var_map, &boolbv_width](const symbolt &symbol) + { var_mapt::vart::vartypet vartype; if (symbol.is_property) return; // ignore properties + else if( + symbol.type.id() == ID_verilog_sva_named_sequence || + symbol.type.id() == ID_verilog_sva_named_property) + { + return; // ignore sequence/property declarations + } + else if( + symbol.type.id() == ID_natural || symbol.type.id() == ID_integer || + symbol.type.id() == ID_verilog_genvar) + { + return; // ignore + } else if( symbol.type.id() == ID_module || symbol.type.id() == ID_module_instance || - symbol.type.id() == ID_primitive_module_instance) + symbol.type.id() == ID_primitive_module_instance || + symbol.type.id() == ID_smv_module_instance) { return; // ignore modules } + else if(symbol.type.id() == ID_named_block) + { + return; // ignore Verilog named blocks + } else if(symbol.is_type) return; // ignore types else if (symbol.is_input) @@ -230,24 +248,51 @@ void convert_trans_to_netlistt::map_vars( if (size == 0) return; - var_mapt::vart &var = dest.var_map.map[symbol.name]; + var_mapt::vart &var = var_map.map[symbol.name]; var.vartype = vartype; var.type = symbol.type; var.mode = symbol.mode; var.bits.resize(size); + }; + + for(const auto &symbol_it : symbol_table.symbols) + if(symbol_it.second.module == module) + update_dest_var_map(symbol_it.second); + + return var_map; +} + +/*******************************************************************\ + +Function: convert_trans_to_netlistt::allocate_state_variables + + Inputs: + + Outputs: - for (std::size_t bit = 0; bit < size; bit++) { + Purpose: + +\*******************************************************************/ + +void convert_trans_to_netlistt::allocate_state_variables(netlistt &dest) +{ + // we work with the sorted var_map to get a deterministic + // allocation for the latches and inputs + + for(auto var_map_it : dest.var_map.sorted()) + { + auto &var = var_map_it->second; + + for(auto &bit : var.bits) + { // just initialize with something - var.bits[bit].current = const_literal(false); - var.bits[bit].next = const_literal(false); + bit.current = const_literal(false); + bit.next = const_literal(false); - // we already know the numbers of inputs and latches - if (var.is_input() || var.is_latch()) - var.bits[bit].current = dest.new_var_node(); + if(var.is_input() || var.is_latch()) + bit.current = dest.new_var_node(); } - }; - - for_all_module_symbols(symbol_table, module, update_dest_var_map); + } } /*******************************************************************\ @@ -271,9 +316,10 @@ void convert_trans_to_netlistt::operator()( lhs_map.clear(); rhs_list.clear(); constraint_list.clear(); - - map_vars(module, dest); - + + dest.var_map = build_var_map(module); + allocate_state_variables(dest); + // setup lhs_map for(var_mapt::mapt::iterator @@ -411,7 +457,8 @@ convert_trans_to_netlistt::convert_property(const exprt &expr) } else if( expr.id() == ID_and || expr.id() == ID_or || expr.id() == ID_not || - expr.id() == ID_implies || expr.id() == ID_xor || expr.id() == ID_xnor) + expr.id() == ID_implies || expr.id() == ID_xor || expr.id() == ID_xnor || + (expr.id() == ID_equal && to_equal_expr(expr).lhs().type().id() == ID_bool)) { exprt copy = expr; for(auto &op : copy.operands()) @@ -564,8 +611,9 @@ void convert_trans_to_netlistt::convert_lhs_rec( lhs_mapt::iterator it=lhs_map.find(bv_varid); if(it==lhs_map.end()) - throw "lhs_rec: failed to find `"+bv_varid.as_string()+"' in lhs_map"; - + throw ebmc_errort{} << "lhs_rec: failed to find `" + << bv_varid.as_string() << "' in lhs_map"; + // we only need to do wires if(!it->second.var->is_wire()) return; @@ -592,7 +640,10 @@ void convert_trans_to_netlistt::convert_lhs_rec( if(!to_integer_non_constant(to_extractbits_expr(expr).index(), new_from)) { boolbv_widtht boolbv_width(ns); - mp_integer new_to = new_from + boolbv_width(expr.type()); + const auto width = boolbv_width(expr.type()); + DATA_INVARIANT( + width != 0, "trans_to_netlist got extractbits with zero-width operand"); + mp_integer new_to = new_from + width - 1; from = new_from.to_ulong(); to = new_to.to_ulong(); @@ -720,7 +771,7 @@ void convert_trans_to_netlistt::add_equality_rec( bv_varidt bv_varid; bv_varid.id=lhs.get(ID_identifier); - + for(bv_varid.bit_nr=lhs_from; bv_varid.bit_nr!=(lhs_to+1); bv_varid.bit_nr++) @@ -729,7 +780,8 @@ void convert_trans_to_netlistt::add_equality_rec( lhs_map.find(bv_varid); if(it==lhs_map.end()) - throw "add_equality_rec: failed to find `"+bv_varid.as_string()+"' in lhs_map"; + throw ebmc_errort{} << "add_equality_rec: failed to find `" + << bv_varid.as_string() << "' in lhs_map"; lhs_entryt &lhs_entry=it->second; const var_mapt::vart &var=*lhs_entry.var; @@ -767,9 +819,12 @@ void convert_trans_to_netlistt::add_equality_rec( boolbv_widtht boolbv_width(ns); + const auto width = boolbv_width(lhs.type()); + + DATA_INVARIANT(width != 0, "add_equality_rec got zero-width bit-vector"); + std::size_t new_lhs_from = lhs_from + index.to_ulong(); - std::size_t new_lhs_to = - lhs_from + index.to_ulong() + boolbv_width(lhs.type()); + std::size_t new_lhs_to = lhs_from + index.to_ulong() + width - 1; add_equality_rec( src, to_extractbits_expr(lhs).src(), new_lhs_from, new_lhs_to, rhs_entry); diff --git a/src/trans-netlist/trans_trace_netlist.cpp b/src/trans-netlist/trans_trace_netlist.cpp index 9c279a144..1e1d7826f 100644 --- a/src/trans-netlist/trans_trace_netlist.cpp +++ b/src/trans-netlist/trans_trace_netlist.cpp @@ -106,16 +106,16 @@ trans_tracet compute_trans_trace( trans_tracet dest; dest.states.reserve(bmc_map.get_no_timeframes()); - + + // use a sorted var_map to get deterministic results + const auto sorted_var_map = bmc_map.var_map.sorted(); + for(unsigned t=0; tsecond; diff --git a/src/trans-netlist/unwind_netlist.cpp b/src/trans-netlist/unwind_netlist.cpp index 342828fac..03476d436 100644 --- a/src/trans-netlist/unwind_netlist.cpp +++ b/src/trans-netlist/unwind_netlist.cpp @@ -83,10 +83,7 @@ void unwind( if(!last) { // joining the latches between timeframe and timeframe+1 - for(var_mapt::mapt::const_iterator - v_it=netlist.var_map.map.begin(); - v_it!=netlist.var_map.map.end(); - v_it++) + for(auto v_it : netlist.var_map.sorted()) { const var_mapt::vart &var=v_it->second; if(var.is_latch()) diff --git a/src/trans-netlist/var_map.cpp b/src/trans-netlist/var_map.cpp index 3e78230af..7bbdfb990 100644 --- a/src/trans-netlist/var_map.cpp +++ b/src/trans-netlist/var_map.cpp @@ -179,6 +179,64 @@ const bv_varidt &var_mapt::reverse(unsigned v) const /*******************************************************************\ +Function: var_mapt::sorted + + Inputs: + + Outputs: + + Purpose: + +\*******************************************************************/ + +std::vector var_mapt::sorted() const +{ + using iteratort = mapt::const_iterator; + std::vector iterators; + iterators.reserve(map.size()); + + for(auto it = map.begin(); it != map.end(); it++) + iterators.push_back(it); + + std::sort( + iterators.begin(), + iterators.end(), + [](iteratort a, iteratort b) { return a->first.compare(b->first) < 0; }); + + return iterators; +} + +/*******************************************************************\ + +Function: var_mapt::sorted + + Inputs: + + Outputs: + + Purpose: + +\*******************************************************************/ + +std::vector var_mapt::sorted() +{ + using iteratort = mapt::iterator; + std::vector iterators; + iterators.reserve(map.size()); + + for(auto it = map.begin(); it != map.end(); it++) + iterators.push_back(it); + + std::sort( + iterators.begin(), + iterators.end(), + [](iteratort a, iteratort b) { return a->first.compare(b->first) < 0; }); + + return iterators; +} + +/*******************************************************************\ + Function: var_mapt::output Inputs: @@ -193,14 +251,14 @@ void var_mapt::output(std::ostream &out) const { out << "Variable map:" << '\n'; - for(mapt::const_iterator it=map.begin(); - it!=map.end(); it++) + // sort by identifier to get stable output + for(auto map_it : sorted()) { - const vart &var=it->second; + const vart &var = map_it->second; for(std::size_t i=0; ifirst; + out << " " << map_it->first; if(var.bits.size()!=1) out << "[" << i << "]"; out << "="; diff --git a/src/trans-netlist/var_map.h b/src/trans-netlist/var_map.h index f5e912d69..4b79a6d68 100644 --- a/src/trans-netlist/var_map.h +++ b/src/trans-netlist/var_map.h @@ -128,6 +128,9 @@ class var_mapt wires.clear(); map.clear(); } + + std::vector sorted() const; + std::vector sorted(); }; #endif diff --git a/src/trans-word-level/Makefile b/src/trans-word-level/Makefile index 3e5b7a769..ebdfc4381 100644 --- a/src/trans-word-level/Makefile +++ b/src/trans-word-level/Makefile @@ -6,7 +6,6 @@ SRC = counterexample_word_level.cpp \ trans_trace_word_level.cpp \ instantiate_word_level.cpp \ sequence.cpp \ - show_modules.cpp \ show_module_hierarchy.cpp \ unwind.cpp \ word_level_trans.cpp diff --git a/src/trans-word-level/show_modules.cpp b/src/trans-word-level/show_modules.cpp deleted file mode 100644 index 4bea6ef05..000000000 --- a/src/trans-word-level/show_modules.cpp +++ /dev/null @@ -1,128 +0,0 @@ -/*******************************************************************\ - -Module: Show Modules - -Author: Daniel Kroening, kroening@kroening.com - -\*******************************************************************/ - -#include "show_modules.h" - -#include -#include - -/*******************************************************************\ - -Function: show_modules_xml - - Inputs: - - Outputs: - - Purpose: - -\*******************************************************************/ - -void show_modules_xml(const symbol_table_baset &symbol_table, std::ostream &out) -{ - std::size_t count = 0; - - for(const auto &s : symbol_table.symbols) - { - const symbolt &symbol = s.second; - - if(symbol.type.id() == ID_module) - { - count++; - - xmlt xml("module"); - xml.new_element("number").data = std::to_string(count); // will go away - xml.set_attribute("number", std::to_string(count)); - - xmlt &l = xml.new_element(); - convert(symbol.location, l); - l.name = "location"; - - // these go away - xml.new_element("identifier").data = id2string(symbol.name); - xml.new_element("mode").data = id2string(symbol.mode); - xml.new_element("name").data = id2string(symbol.display_name()); - - // these stay - xml.set_attribute("identifier", id2string(symbol.name)); - xml.set_attribute("mode", id2string(symbol.mode)); - xml.set_attribute("name", id2string(symbol.display_name())); - - out << xml; - } - } -} - -/*******************************************************************\ - -Function: show_modules - - Inputs: - - Outputs: - - Purpose: - -\*******************************************************************/ - -void show_modules(const symbol_table_baset &symbol_table, std::ostream &out) -{ - std::size_t count = 0; - - for(const auto &s : symbol_table.symbols) - { - const symbolt &symbol=s.second; - - if(symbol.type.id()==ID_module) - { - count++; - - out << "Module " << count << ":" << '\n'; - - out << " Location: " << symbol.location << '\n'; - out << " Mode: " << symbol.mode << '\n'; - out << " Identifier: " << symbol.name << '\n'; - out << " Name: " << symbol.display_name() << '\n' << '\n'; - } - } -} - -/*******************************************************************\ - -Function: json_modules - - Inputs: - - Outputs: - - Purpose: - -\*******************************************************************/ - -void json_modules(const symbol_table_baset &symbol_table, std::ostream &out) -{ - json_arrayt json_modules; - - for(const auto &s : symbol_table.symbols) - { - const symbolt &symbol = s.second; - - if(symbol.type.id() == ID_module) - { - json_objectt json_module; - json_module["location"] = json(symbol.location); - json_module["identifier"] = json_stringt{id2string(symbol.name)}; - json_module["mode"] = json_stringt{id2string(symbol.mode)}; - json_module["name"] = json_stringt{id2string(symbol.display_name())}; - - json_modules.push_back(std::move(json_module)); - } - } - - out << json_modules; -} diff --git a/src/trans-word-level/show_modules.h b/src/trans-word-level/show_modules.h deleted file mode 100644 index caa8fe307..000000000 --- a/src/trans-word-level/show_modules.h +++ /dev/null @@ -1,20 +0,0 @@ -/*******************************************************************\ - -Module: Show Modules - -Author: Daniel Kroening, kroening@kroening.com - -\*******************************************************************/ - -#ifndef CPROVER_TRANS_SHOW_MODULES_H -#define CPROVER_TRANS_SHOW_MODULES_H - -#include - -void show_modules(const symbol_table_baset &, std::ostream &); - -void show_modules_xml(const symbol_table_baset &, std::ostream &); - -void json_modules(const symbol_table_baset &, std::ostream &); - -#endif diff --git a/src/trans-word-level/trans_trace_word_level.cpp b/src/trans-word-level/trans_trace_word_level.cpp index 57fb2a0fc..14280657a 100644 --- a/src/trans-word-level/trans_trace_word_level.cpp +++ b/src/trans-word-level/trans_trace_word_level.cpp @@ -53,10 +53,11 @@ trans_tracet compute_trans_trace( { const symbolt &symbol=ns.lookup(it->second); - if(!symbol.is_type && - !symbol.is_property && - symbol.type.id()!=ID_module && - symbol.type.id()!=ID_module_instance) + if( + !symbol.is_type && !symbol.is_property && + symbol.type.id() != ID_module && + symbol.type.id() != ID_module_instance && + symbol.type.id() != ID_smv_module_instance) { if(symbol.is_macro) { diff --git a/src/util/ebmc_util.h b/src/util/ebmc_util.h index 6321f7445..d9c1e45e8 100644 --- a/src/util/ebmc_util.h +++ b/src/util/ebmc_util.h @@ -15,18 +15,6 @@ #include -template -void for_all_module_symbols(const symbol_tablet &symbol_table, - const irep_idt &module_name, F &&f) { - using symbol_pairt = typename symbol_tablet::iteratort::value_type; - std::for_each(symbol_table.begin(), symbol_table.end(), - [&module_name, &f](const symbol_pairt &symbol_pair) { - const auto &symbol = symbol_pair.second; - if (symbol.module == module_name) - f(symbol); - }); -} - // This function is legacy, and will be gradually removed. // Consider to_integer(constant_exprt, mp_integer &) or numerical_cast(...). inline bool to_integer_non_constant(const exprt &expr, mp_integer &int_value) diff --git a/src/verilog/Makefile b/src/verilog/Makefile index 9f5932b50..cfa50473c 100644 --- a/src/verilog/Makefile +++ b/src/verilog/Makefile @@ -2,6 +2,7 @@ SRC = aval_bval_encoding.cpp \ convert_literals.cpp \ expr2verilog.cpp \ sva_expr.cpp \ + typename.cpp \ verilog_bits.cpp \ verilog_elaborate.cpp \ verilog_elaborate_type.cpp \ diff --git a/src/verilog/aval_bval_encoding.cpp b/src/verilog/aval_bval_encoding.cpp index 78167552c..fe99296d1 100644 --- a/src/verilog/aval_bval_encoding.cpp +++ b/src/verilog/aval_bval_encoding.cpp @@ -36,8 +36,7 @@ bv_typet aval_bval_type(std::size_t width, irep_idt source_type) bv_typet lower_to_aval_bval(const typet &src) { - PRECONDITION( - src.id() == ID_verilog_unsignedbv || src.id() == ID_verilog_signedbv); + PRECONDITION(is_four_valued(src)); return aval_bval_type(to_bitvector_type(src).get_width(), src.id()); } @@ -75,9 +74,7 @@ typet aval_bval_underlying(const typet &src) constant_exprt lower_to_aval_bval(const constant_exprt &src) { - PRECONDITION( - src.type().id() == ID_verilog_signedbv || - src.type().id() == ID_verilog_unsignedbv); + PRECONDITION(is_four_valued(src.type())); auto new_type = lower_to_aval_bval(src.type()); auto width = aval_bval_width(new_type); @@ -191,6 +188,7 @@ exprt aval_bval_conversion(const exprt &src, const typet &dest) if(is_aval_bval(src.type())) { + // four-valued to four-valued auto src_width = aval_bval_width(src.type()); if(src_width == dest_width) @@ -198,15 +196,43 @@ exprt aval_bval_conversion(const exprt &src, const typet &dest) // same size return typecast_exprt{src, dest}; } - else + else if(src_width > dest_width) { + // shrink auto new_aval = adjust_size(aval(src), dest_width); auto new_bval = adjust_size(bval(src), dest_width); return combine_aval_bval(new_aval, new_bval, dest); } + else + { + // extend + auto underlying_src = aval_bval_underlying(src.type()); + auto underlying_dest = aval_bval_underlying(dest); + + if(underlying_src.id() == ID_signedbv) + { + // sign extend both aval and bval + auto new_aval = typecast_exprt{ + typecast_exprt{ + typecast_exprt{aval(src), underlying_src}, underlying_dest}, + bv_typet{dest_width}}; + auto new_bval = typecast_exprt{ + typecast_exprt{ + typecast_exprt{bval(src), underlying_src}, underlying_dest}, + bv_typet{dest_width}}; + return combine_aval_bval(new_aval, new_bval, dest); + } + else + { + auto new_aval = adjust_size(aval(src), dest_width); + auto new_bval = adjust_size(bval(src), dest_width); + return combine_aval_bval(new_aval, new_bval, dest); + } + } } else { + // two-valued to four-valued const bv_typet bv_type{dest_width}; auto aval = typecast_exprt{typecast_exprt{src, aval_bval_underlying(dest)}, bv_type}; @@ -256,7 +282,7 @@ exprt has_xz(const exprt &expr) return false_exprt{}; // it's two-valued } -/// return 'x', one bit, in aval_bval encoding +/// return 'x' exprt make_x(const typet &type) { PRECONDITION(is_four_valued(type)); @@ -337,6 +363,75 @@ exprt aval_bval(const not_exprt &expr) return if_exprt{has_xz, x, aval_bval_conversion(not_expr, x.type())}; } +exprt aval_bval_reduction(const unary_exprt &expr) +{ + auto &type = expr.type(); + auto type_aval_bval = lower_to_aval_bval(type); + PRECONDITION(is_four_valued(type)); + PRECONDITION(is_aval_bval(expr.op())); + + auto has_xz = ::has_xz(expr.op()); + auto x = make_x(type); + auto op_aval = aval(expr.op()); + auto op_bval = bval(expr.op()); + + if(expr.id() == ID_reduction_xor || expr.id() == ID_reduction_xnor) + { + auto reduction_expr = unary_exprt{expr.id(), op_aval, bool_typet{}}; + return if_exprt{has_xz, x, aval_bval_conversion(reduction_expr, x.type())}; + } + else if(expr.id() == ID_reduction_and || expr.id() == ID_reduction_nand) + { + auto has_zero = notequal_exprt{ + bitor_exprt{op_aval, op_bval}, + to_bv_type(op_aval.type()).all_ones_expr()}; + + auto one = combine_aval_bval( + bv_typet{1}.all_ones_expr(), + bv_typet{1}.all_zeros_expr(), + type_aval_bval); + auto zero = combine_aval_bval( + bv_typet{1}.all_zeros_expr(), + bv_typet{1}.all_zeros_expr(), + type_aval_bval); + + if(expr.id() == ID_reduction_and) + { + return if_exprt{has_zero, zero, if_exprt{has_xz, x, one}}; + } + else // nand + { + return if_exprt{has_zero, one, if_exprt{has_xz, x, zero}}; + } + } + else if(expr.id() == ID_reduction_or || expr.id() == ID_reduction_nor) + { + auto has_one = notequal_exprt{ + bitand_exprt{op_aval, bitnot_exprt{op_bval}}, + to_bv_type(op_aval.type()).all_zeros_expr()}; + + auto one = combine_aval_bval( + bv_typet{1}.all_ones_expr(), + bv_typet{1}.all_zeros_expr(), + type_aval_bval); + auto zero = combine_aval_bval( + bv_typet{1}.all_zeros_expr(), + bv_typet{1}.all_zeros_expr(), + type_aval_bval); + + if(expr.id() == ID_reduction_or) + { + return if_exprt{has_one, one, if_exprt{has_xz, x, zero}}; + } + else // nor + { + return if_exprt{has_one, zero, if_exprt{has_xz, x, one}}; + } + } + else + PRECONDITION(false); +} + exprt aval_bval(const bitnot_exprt &expr) { auto &type = expr.type(); @@ -355,7 +450,85 @@ exprt aval_bval(const bitnot_exprt &expr) return combine_aval_bval(aval, op_bval, lower_to_aval_bval(expr.type())); } -exprt aval_bval_bitwise(const multi_ary_exprt &expr) +exprt aval_bval_bitand(const bitand_exprt &expr) +{ + auto &type = expr.type(); + PRECONDITION(is_four_valued(type)); + PRECONDITION(!expr.operands().empty()); + + for(auto &op : expr.operands()) + PRECONDITION(is_aval_bval(op)); + + // All result bits are computed bit-wise. + // 0 is the dominating value. + // Otherwise, any bit involving x/z is x. + + // A bit is zero of both aval and bval bits are zero. + exprt::operandst bit_is_zero_disjuncts; + + for(auto &op : expr.operands()) + bit_is_zero_disjuncts.push_back( + bitand_exprt{bitnot_exprt{aval(op)}, bitnot_exprt{bval(op)}}); + + auto bit_is_zero = + bitor_exprt{bit_is_zero_disjuncts, bit_is_zero_disjuncts.front().type()}; + + // bval: one if not bit_is_zero, and any bval bit is one + exprt::operandst bval_disjuncts; + + for(auto &op : expr.operands()) + bval_disjuncts.push_back(bval(op)); + + auto bval = bitand_exprt{ + bitor_exprt{bval_disjuncts, bval_disjuncts.front().type()}, + bitnot_exprt{bit_is_zero}}; + + // aval: one if not bit_is_zero and bval is zero + auto aval = bitand_exprt{bitnot_exprt{bit_is_zero}, bitnot_exprt{bval}}; + + return combine_aval_bval(aval, bval, lower_to_aval_bval(expr.type())); +} + +exprt aval_bval_bitor(const bitor_exprt &expr) +{ + auto &type = expr.type(); + PRECONDITION(is_four_valued(type)); + PRECONDITION(!expr.operands().empty()); + + for(auto &op : expr.operands()) + PRECONDITION(is_aval_bval(op)); + + // All result bits are computed bit-wise. + // 1 is the dominating value. + // Otherwise, any bit involving x/z is x. + + // A bit is one if the aval bit is one and the bval bit is zero. + exprt::operandst bit_is_one_disjuncts; + + for(auto &op : expr.operands()) + bit_is_one_disjuncts.push_back( + bitand_exprt{aval(op), bitnot_exprt{bval(op)}}); + + auto bit_is_one = + bitor_exprt{bit_is_one_disjuncts, bit_is_one_disjuncts.front().type()}; + + // bval: one if not bit_is_one, and any bval bit is one + exprt::operandst bval_disjuncts; + + for(auto &op : expr.operands()) + bval_disjuncts.push_back(bval(op)); + + auto bval = bitand_exprt{ + bitor_exprt{bval_disjuncts, bval_disjuncts.front().type()}, + bitnot_exprt{bit_is_one}}; + + // aval: one if bit_is_one + auto aval = bit_is_one; + + return combine_aval_bval(aval, bval, lower_to_aval_bval(expr.type())); +} + +exprt aval_bval_xor_xnor(const multi_ary_exprt &expr) { auto &type = expr.type(); PRECONDITION(is_four_valued(type)); @@ -388,6 +561,30 @@ exprt aval_bval_bitwise(const multi_ary_exprt &expr) return combine_aval_bval(aval, bval, lower_to_aval_bval(expr.type())); } +exprt aval_bval_replication(const replication_exprt &expr) +{ + auto &type = expr.type(); + PRECONDITION(is_four_valued(type)); + PRECONDITION(!is_four_valued(expr.times())); + + auto times_int = numeric_cast_v(expr.times()); + + // separately replicate aval and bval + auto op_aval = aval(expr.op()); + auto op_bval = bval(expr.op()); + + auto replication_type = bv_typet{numeric_cast_v( + to_bitvector_type(op_aval.type()).width() * times_int)}; + + auto aval_replicated = + replication_exprt{expr.times(), op_aval, replication_type}; + auto bval_replicated = + replication_exprt{expr.times(), op_bval, replication_type}; + + return combine_aval_bval( + aval_replicated, bval_replicated, lower_to_aval_bval(type)); +} + exprt aval_bval(const power_exprt &expr) { PRECONDITION(is_four_valued(expr.type())); @@ -435,14 +632,34 @@ exprt aval_bval(const verilog_implies_exprt &expr) exprt aval_bval(const typecast_exprt &expr) { - // 'true' is defined as a "nonzero known value" (1800-2017 12.4). + auto &dest_type = expr.type(); + PRECONDITION(is_aval_bval(expr.op())); - PRECONDITION(expr.type().id() == ID_bool); - auto op_has_xz = ::has_xz(expr.op()); - auto op_aval = aval(expr.op()); - auto op_aval_zero = to_bv_type(op_aval.type()).all_zeros_expr(); - return and_exprt{not_exprt{op_has_xz}, notequal_exprt{op_aval, op_aval_zero}}; + if(dest_type.id() == ID_bool) + { + // 'true' is defined as a "nonzero known value" (1800-2017 12.4). + auto op_has_xz = ::has_xz(expr.op()); + auto op_aval = aval(expr.op()); + auto op_aval_zero = to_bv_type(op_aval.type()).all_zeros_expr(); + return and_exprt{ + not_exprt{op_has_xz}, notequal_exprt{op_aval, op_aval_zero}}; + } + else if( + dest_type.id() == ID_verilog_unsignedbv || + dest_type.id() == ID_verilog_signedbv) + { + // four-valued to four-valued + auto aval_bval_type = lower_to_aval_bval(dest_type); + return aval_bval_conversion(expr.op(), aval_bval_type); + } + else if(dest_type.id() == ID_unsignedbv || dest_type.id() == ID_signedbv) + { + // four-valued to two-valued + return typecast_exprt{aval(expr.op()), dest_type}; + } + else + PRECONDITION(false); } exprt aval_bval(const shift_exprt &expr) @@ -470,3 +687,67 @@ exprt aval_bval(const shift_exprt &expr) auto x = make_x(expr.type()); return if_exprt{distance_has_xz, x, combined}; } + +exprt aval_bval(const binary_relation_exprt &expr) +{ + auto &type = expr.type(); + + PRECONDITION(type.id() == ID_verilog_unsignedbv); + + auto has_xz = or_exprt{::has_xz(expr.lhs()), ::has_xz(expr.rhs())}; + + exprt two_valued_expr = binary_predicate_exprt{ + aval_underlying(expr.lhs()), expr.id(), aval_underlying(expr.rhs())}; + + return if_exprt{ + has_xz, + make_x(type), + aval_bval_conversion(two_valued_expr, lower_to_aval_bval(type))}; +} + +exprt aval_bval(const zero_extend_exprt &expr) +{ + PRECONDITION(is_four_valued(expr.type())); + + // extend aval and bval separately + auto op_aval = aval(expr.op()); + auto op_bval = bval(expr.op()); + + auto result_type = lower_to_aval_bval(expr.type()); + auto extended_type = bv_typet{aval_bval_width(result_type)}; + + auto aval_extended = zero_extend_exprt{op_aval, extended_type}; + auto bval_extended = zero_extend_exprt{op_bval, extended_type}; + + return combine_aval_bval(aval_extended, bval_extended, result_type); +} + +exprt default_aval_bval_lowering(const exprt &expr) +{ + auto &type = expr.type(); + + PRECONDITION(is_four_valued(type)); + + exprt::operandst disjuncts; + for(auto &op : expr.operands()) + disjuncts.push_back(has_xz(op)); + + auto has_xz = disjunction(disjuncts); + + exprt two_valued_expr = expr; // copy + + for(auto &op : two_valued_expr.operands()) + op = aval_underlying(op); // replace by aval + + if(type.id() == ID_verilog_unsignedbv) + two_valued_expr.type() = unsignedbv_typet{to_bitvector_type(type).width()}; + else if(type.id() == ID_verilog_signedbv) + two_valued_expr.type() = signedbv_typet{to_bitvector_type(type).width()}; + else + PRECONDITION(false); + + return if_exprt{ + has_xz, + make_x(type), + aval_bval_conversion(two_valued_expr, lower_to_aval_bval(type))}; +} diff --git a/src/verilog/aval_bval_encoding.h b/src/verilog/aval_bval_encoding.h index 5b29d238a..63f3ea3ef 100644 --- a/src/verilog/aval_bval_encoding.h +++ b/src/verilog/aval_bval_encoding.h @@ -49,8 +49,16 @@ exprt aval_bval(const verilog_logical_inequality_exprt &); exprt aval_bval(const not_exprt &); /// lowering for ~ exprt aval_bval(const bitnot_exprt &); -/// lowering for &, |, ^, ^~ -exprt aval_bval_bitwise(const multi_ary_exprt &); +/// lowering for & +exprt aval_bval_bitand(const bitand_exprt &); +/// lowering for | +exprt aval_bval_bitor(const bitor_exprt &); +/// lowering for ^, ^~ +exprt aval_bval_xor_xnor(const multi_ary_exprt &); +/// lowering for reduction operators +exprt aval_bval_reduction(const unary_exprt &); +/// lowering for replication +exprt aval_bval_replication(const replication_exprt &); /// lowering for ==? exprt aval_bval(const verilog_wildcard_equality_exprt &); /// lowering for !=? @@ -65,5 +73,14 @@ exprt aval_bval(const verilog_implies_exprt &); exprt aval_bval(const typecast_exprt &); /// lowering for shifts exprt aval_bval(const shift_exprt &); +/// lowering for <=, <, etc. +exprt aval_bval(const binary_relation_exprt &); +/// lowering for zero extension +exprt aval_bval(const zero_extend_exprt &); + +/// If any operand has x/z, then the result is 'x'. +/// Otherwise, the result is the expression applied to the aval +/// of the operands. +exprt default_aval_bval_lowering(const exprt &); #endif diff --git a/src/verilog/expr2verilog.cpp b/src/verilog/expr2verilog.cpp index b44888715..8674feba9 100644 --- a/src/verilog/expr2verilog.cpp +++ b/src/verilog/expr2verilog.cpp @@ -680,10 +680,10 @@ Function: expr2verilogt::convert_sva_abort expr2verilogt::resultt expr2verilogt::convert_sva_abort( const std::string &text, - const sva_abort_exprt &expr) + const binary_exprt &expr) { - auto op0 = convert_rec(expr.condition()); - auto op1 = convert_rec(expr.property()); + auto op0 = convert_rec(expr.op0()); + auto op1 = convert_rec(expr.op1()); return {verilog_precedencet::MIN, text + " (" + op0.s + ") " + op1.s}; } @@ -1178,6 +1178,24 @@ expr2verilogt::resultt expr2verilogt::convert_symbol(const exprt &src) /*******************************************************************\ +Function: expr2verilogt::convert_verilog_identifier + + Inputs: + + Outputs: + + Purpose: + +\*******************************************************************/ + +expr2verilogt::resultt +expr2verilogt::convert_verilog_identifier(const verilog_identifier_exprt &src) +{ + return {verilog_precedencet::MAX, id2string(src.base_name())}; +} + +/*******************************************************************\ + Function: expr2verilogt::convert_nondet_symbol Inputs: @@ -1348,6 +1366,10 @@ expr2verilogt::convert_constant(const constant_exprt &src) else return convert_norep(src); } + else if(type.id() == ID_verilog_null) + { + dest = "null"; + } else return convert_norep(src); @@ -1479,6 +1501,45 @@ expr2verilogt::convert_inside(const verilog_inside_exprt &src) /*******************************************************************\ +Function: expr2verilogt::convert_sequence_property_instance + + Inputs: + + Outputs: + + Purpose: + +\*******************************************************************/ + +expr2verilogt::resultt expr2verilogt::convert_sequence_property_instance( + const sva_sequence_property_instance_exprt &src) +{ + if(src.arguments().empty()) + return convert_rec(src.symbol()); + + auto fkt = convert_rec(src.symbol()); + + std::string dest = fkt.s; + bool first = true; + dest += "("; + + for(const auto &op : src.arguments()) + { + if(first) + first = false; + else + dest += ", "; + + dest += convert_rec(op).s; + } + + dest += ")"; + + return {verilog_precedencet::MEMBER, dest}; +} + +/*******************************************************************\ + Function: expr2verilogt::convert_value_range Inputs: @@ -1766,6 +1827,9 @@ expr2verilogt::resultt expr2verilogt::convert_rec(const exprt &src) else if(src.id()==ID_symbol) return convert_symbol(src); + else if(src.id() == ID_verilog_identifier) + return convert_symbol(to_verilog_identifier_expr(src)); + else if(src.id()==ID_nondet_symbol) return convert_nondet_symbol(src); @@ -1933,6 +1997,11 @@ expr2verilogt::resultt expr2verilogt::convert_rec(const exprt &src) return precedence = verilog_precedencet::MIN, convert_sva_abort("disable iff", to_sva_abort_expr(src)); + else if(src.id() == ID_sva_sequence_disable_iff) + return precedence = verilog_precedencet::MIN, + convert_sva_abort( + "disable iff", to_sva_sequence_disable_iff_expr(src)); + else if(src.id()==ID_sva_eventually) { return precedence = verilog_precedencet::MIN, @@ -2003,6 +2072,15 @@ expr2verilogt::resultt expr2verilogt::convert_rec(const exprt &src) return convert_function(src.id_string(), src); } + else if(src.id() == ID_zero_extend) + return convert_rec(to_zero_extend_expr(src).op()); + + else if(src.id() == ID_sva_sequence_property_instance) + { + return convert_sequence_property_instance( + to_sva_sequence_property_instance_expr(src)); + } + // no VERILOG language expression for internal representation return convert_norep(src); } @@ -2145,7 +2223,10 @@ std::string expr2verilogt::convert(const typet &type) } else if(type.id() == ID_struct) { - return "struct"; + if(type.get_bool(ID_packed)) + return "struct packed"; + else + return "struct"; } else if(type.id() == ID_union) { diff --git a/src/verilog/expr2verilog_class.h b/src/verilog/expr2verilog_class.h index 1a1a96693..f06989bf6 100644 --- a/src/verilog/expr2verilog_class.h +++ b/src/verilog/expr2verilog_class.h @@ -12,13 +12,14 @@ Author: Daniel Kroening, kroening@kroening.com #include #include -class sva_abort_exprt; class sva_case_exprt; class sva_if_exprt; class sva_ranged_predicate_exprt; class sva_cycle_delay_exprt; class sva_sequence_first_match_exprt; +class sva_sequence_property_instance_exprt; class sva_sequence_repetition_exprt; +class verilog_identifier_exprt; // Precedences (higher means binds more strongly). // Follows Table 11-2 in IEEE 1800-2017. @@ -98,6 +99,8 @@ class expr2verilogt resultt convert_symbol(const exprt &); + resultt convert_verilog_identifier(const verilog_identifier_exprt &); + resultt convert_hierarchical_identifier(const class hierarchical_identifier_exprt &); @@ -145,7 +148,7 @@ class expr2verilogt const std::string &name, const sva_sequence_repetition_exprt &); - resultt convert_sva_abort(const std::string &name, const sva_abort_exprt &); + resultt convert_sva_abort(const std::string &name, const binary_exprt &); resultt convert_sva_indexed_binary(const std::string &name, const binary_exprt &); @@ -181,6 +184,9 @@ class expr2verilogt resultt convert_value_range(const class verilog_value_range_exprt &); + resultt convert_sequence_property_instance( + const class sva_sequence_property_instance_exprt &); + protected: const namespacet &ns; }; diff --git a/src/verilog/parser.y b/src/verilog/parser.y index 1c8763280..31ef9bb56 100644 --- a/src/verilog/parser.y +++ b/src/verilog/parser.y @@ -28,6 +28,7 @@ Author: Daniel Kroening, kroening@cs.cmu.edu //#define YYDEBUG 1 #define mto(x, y) stack_expr(x).add_to_operands(std::move(stack_expr(y))) +#define mto2(x, y, z) stack_expr(x).add_to_operands(std::move(stack_expr(y)), std::move(stack_expr(z))) #define mts(x, y) stack_expr(x).move_to_sub((irept &)stack_expr(y)) #define swapop(x, y) stack_expr(x).operands().swap(stack_expr(y).operands()) #define addswap(x, y, z) stack_expr(x).add(y).swap(stack_expr(z)) @@ -111,7 +112,7 @@ inline static void init(YYSTYPE &expr, const irep_idt &id) /*******************************************************************\ -Function: new_symbol +Function: new_identifier Inputs: @@ -122,9 +123,9 @@ Function: new_symbol \*******************************************************************/ -inline static void new_symbol(YYSTYPE &dest, YYSTYPE &src) +inline static void new_identifier(YYSTYPE &dest, YYSTYPE &src) { - init(dest, ID_symbol); + init(dest, ID_verilog_identifier); const auto base_name = stack_expr(src).id(); stack_expr(dest).set(ID_identifier, base_name); stack_expr(dest).set(ID_base_name, base_name); @@ -580,6 +581,8 @@ int yyverilogerror(const char *error) // following System Verilog 1800-2017 Table 11-2. // Bison expects these in order of increasing precedence, // whereas the table gives them in decreasing order. +%nonassoc '{' +%nonassoc '=' "+=" "-=" "*=" "/=" "%=" "&=" "^=" "|=" "<<=" ">>=" "<<<=" ">>>=" ":=" ":/" %right "->" "<->" %right "?" ":" %left "||" @@ -1023,6 +1026,9 @@ module_or_generate_item: { add_attributes($2, $1); $$=$2; } | attribute_instance_brace module_common_item { add_attributes($2, $1); $$=$2; } + // The next rule is not in 1800-2017, but is a vendor extension. + | attribute_instance_brace system_tf_call ';' + { add_attributes($2, $1); $$ = $2; } ; module_or_generate_item_declaration: @@ -1049,8 +1055,79 @@ non_port_module_item: // A.1.5 Configuration source text config_declaration: - TOK_CONFIG TOK_ENDCONFIG - ; + TOK_CONFIG config_identifier ';' + local_parameter_declaration_opt + design_statement + config_rule_statement_opt + TOK_ENDCONFIG config_identifier_opt + ; + +local_parameter_declaration_opt: + /* Optional */ + | local_parameter_declaration ';' + ; + +design_statement: + TOK_DESIGN design_identifier ';' + ; + +design_identifier: + cell_identifier + | library_identifier '.' cell_identifier + ; + +config_rule_statement_opt: + /* Optional */ + | config_rule_statement + ; + +config_rule_statement: + default_clause liblist_clause ';' + | inst_clause liblist_clause ';' + | inst_clause use_clause ';' + | cell_clause liblist_clause ';' + | cell_clause use_clause ';' + ; + +default_clause: TOK_DEFAULT; + +inst_clause: TOK_INSTANCE inst_name; + +inst_name: topmodule_identifier dot_instance_identifier_brace; + +dot_instance_identifier_brace: + /* Optional */ + | dot_instance_identifier_brace '.' instance_identifier + ; + +cell_clause: + TOK_CELL cell_identifier + | TOK_CELL library_identifier cell_identifier + ; + +liblist_clause: TOK_LIBLIST library_identifier_brace; + +library_identifier_brace: + /* Optional */ + | library_identifier_brace library_identifier + ; + +use_clause: + TOK_USE cell_identifier colon_config_opt + | TOK_USE library_identifier '.' cell_identifier colon_config_opt + | TOK_USE '#' '(' named_parameter_assignment_brace ')' colon_config_opt + | TOK_USE library_identifier '.' cell_identifier '#' '(' named_parameter_assignment_brace ')' colon_config_opt + ; + +colon_config_opt: + /* Optional */ + | TOK_COLON TOK_CONFIG + ; + +config_identifier_opt: + /* Optional */ + | TOK_COLON config_identifier + ; bind_directive: TOK_BIND @@ -1428,11 +1505,11 @@ package_import_item: package_identifier "::" identifier { init($$, ID_verilog_import_item); stack_expr($$).set(ID_verilog_package, stack_expr($1).id()); - stack_expr($$).set(ID_identifier, stack_expr($3).id()); } + stack_expr($$).set(ID_base_name, stack_expr($3).id()); } | package_identifier "::" "*" { init($$, ID_verilog_import_item); stack_expr($$).set(ID_verilog_package, stack_expr($1).id()); - stack_expr($$).set(ID_identifier, "*"); } + stack_expr($$).set(ID_base_name, "*"); } ; genvar_declaration: @@ -1446,6 +1523,10 @@ net_declaration: addswap($$, ID_class, $1); addswap($$, ID_type, $4); swapop($$, $6); } + | TOK_INTERCONNECT delay3_opt list_of_net_decl_assignments ';' + { init($$, ID_decl); + stack_expr($$).set(ID_class, ID_verilog_interconnect); + swapop($$, $3); } ; // Note that the identifier that is defined using the typedef may be @@ -1552,6 +1633,8 @@ data_type: | struct_union packed_opt signing_opt '{' struct_union_member_brace '}' packed_dimension_brace { $$=$1; + if(stack_expr($2).id() == ID_packed) + stack_type($1).set(ID_packed, true); addswap($$, ID_declaration_list, $5); } | TOK_ENUM enum_base_type_opt '{' enum_name_declaration_list '}' { // Like in C, these do _not_ create a scope. @@ -1713,14 +1796,19 @@ net_type_opt: | net_type ; -net_port_type: net_type_opt signing_opt packed_dimension_brace - { - // The net type is a subtype of the signing. - add_as_subtype(stack_type($2), stack_type($1)); - // That becomes a subtype of the packed dimension. - add_as_subtype(stack_type($3), stack_type($2)); - $$ = $3; - } +net_port_type: + net_type_opt signing_opt packed_dimension_brace + { + // The net type is a subtype of the signing. + add_as_subtype(stack_type($2), stack_type($1)); + // That becomes a subtype of the packed dimension. + add_as_subtype(stack_type($3), stack_type($2)); + $$ = $3; + } + | TOK_INTERCONNECT + { + init($$, ID_verilog_interconnect); + } ; variable_port_type: var_data_type ; @@ -1896,12 +1984,19 @@ list_of_variable_identifiers: // to cover list_of_param_assignments. parameter_port_declaration: TOK_PARAMETER data_type_or_implicit param_assignment - { $$ = $3; } + { init($$, ID_decl); stack_expr($$).type() = std::move(stack_type($2)); mto($$, $3); } + | TOK_PARAMETER TOK_TYPE type_assignment + { init($$, ID_decl); stack_expr($$).type() = typet{ID_type}; mto($$, $3); } | TOK_LOCALPARAM data_type_or_implicit param_assignment - { $$ = $3; } + { init($$, ID_decl); stack_expr($$).type() = std::move(stack_type($2)); mto($$, $3); } + | TOK_LOCALPARAM TOK_TYPE type_assignment + { init($$, ID_decl); stack_expr($$).type() = typet{ID_type}; mto($$, $3); } | data_type param_assignment - { $$ = $2; } + { init($$, ID_decl); stack_expr($$).type() = std::move(stack_type($1)); mto($$, $2); } | param_assignment + { init($$, ID_decl); mto($$, $1); } + | TOK_TYPE type_assignment + { init($$, ID_decl); stack_expr($$).type() = typet{ID_type}; mto($$, $2); } ; list_of_defparam_assignments: @@ -1926,7 +2021,6 @@ list_of_param_assignments: param_assignment: param_identifier '=' constant_param_expression { init($$, ID_parameter); auto base_name = stack_expr($1).id(); - stack_expr($$).set(ID_identifier, base_name); stack_expr($$).set(ID_base_name, base_name); addswap($$, ID_value, $3); } ; @@ -1939,11 +2033,15 @@ list_of_type_assignments: ; type_assignment: param_identifier '=' data_type - { init($$, ID_parameter); + { init($$, ID_declarator); auto base_name = stack_expr($1).id(); - stack_expr($$).set(ID_identifier, base_name); stack_expr($$).set(ID_base_name, base_name); - addswap($$, ID_type, $3); } + stack_expr($$).set(ID_value, type_exprt{stack_type($3)}); + stack_expr($$).type() = typet{ID_type}; + + // add to the scope as a type name + PARSER.scopes.add_name(base_name, "", verilog_scopet::TYPEDEF); + } ; data_type_or_implicit: @@ -2161,6 +2259,7 @@ unsized_dimension: '[' ']' struct_union: TOK_STRUCT { init($$, ID_struct); } | TOK_UNION { init($$, ID_union); } + | TOK_UNION TOK_TAGGED { init($$, ID_union); } ; // System Verilog standard 1800-2017 @@ -2322,7 +2421,7 @@ concurrent_assertion_item: | block_identifier TOK_COLON concurrent_assertion_statement { $$=$3; - stack_expr($$).set(ID_identifier, stack_expr($1).id()); + stack_expr($$).set(ID_base_name, stack_expr($1).id()); } ; @@ -2330,6 +2429,7 @@ concurrent_assertion_statement: assert_property_statement | assume_property_statement | cover_property_statement + | cover_sequence_statement | restrict_property_statement ; @@ -2339,13 +2439,13 @@ smv_assertion_statement: { init($$, ID_verilog_smv_assert); stack_expr($$).operands().resize(2); to_binary_expr(stack_expr($$)).op0().swap(stack_expr($4)); to_binary_expr(stack_expr($$)).op1().make_nil(); - stack_expr($$).set(ID_identifier, stack_expr($2).id()); + stack_expr($$).set(ID_base_name, stack_expr($2).id()); } | TOK_ASSUME property_identifier TOK_COLON smv_property ';' { init($$, ID_verilog_smv_assume); stack_expr($$).operands().resize(2); to_binary_expr(stack_expr($$)).op0().swap(stack_expr($4)); to_binary_expr(stack_expr($$)).op1().make_nil(); - stack_expr($$).set(ID_identifier, stack_expr($2).id()); + stack_expr($$).set(ID_base_name, stack_expr($2).id()); } ; @@ -2392,6 +2492,15 @@ cover_property_statement: TOK_COVER TOK_PROPERTY '(' property_spec ')' action_bl { init($$, ID_verilog_cover_property); mto($$, $4); mto($$, $6); } ; +cover_sequence_statement: + TOK_COVER TOK_SEQUENCE '(' sequence_expr ')' action_block + { init($$, ID_verilog_cover_sequence); mto2($$, $4, $6); } + | TOK_COVER TOK_SEQUENCE '(' clocking_event TOK_DISABLE TOK_IFF '(' expression ')' sequence_expr ')' action_block + { init($5, ID_sva_sequence_disable_iff); mto2($5, $8, $10); init($$, ID_verilog_cover_sequence); mto2($$, $5, $12); } + | TOK_COVER TOK_SEQUENCE '(' TOK_DISABLE TOK_IFF '(' expression ')' sequence_expr ')' action_block + { init($4, ID_sva_sequence_disable_iff); mto2($4, $7, $9); init($$, ID_verilog_cover_sequence); mto2($$, $4, $11); } + ; + restrict_property_statement: TOK_RESTRICT TOK_PROPERTY '(' property_spec ')' ';' { init($$, ID_verilog_restrict_property); mto($$, $4); mto($$, $6); } ; @@ -3057,11 +3166,23 @@ named_parameter_assignment_brace: { $$=$1; mto($$, $3); } ; -ordered_parameter_assignment: - expression; +ordered_parameter_assignment: param_expression + ; + +param_expression: + expression + | data_type + { init($$, ID_type); stack_expr($$).type() = stack_type($1); } + ; + +param_expression_opt: + /* empty */ + { init($$, ID_nil); } + | param_expression + ; named_parameter_assignment: - '.' parameter_identifier '(' expression_opt ')' + '.' parameter_identifier '(' param_expression_opt ')' { init($$, ID_named_parameter_assignment); stack_expr($$).add(ID_parameter).swap(stack_expr($2)); stack_expr($$).add(ID_value).swap(stack_expr($4)); @@ -3115,10 +3236,13 @@ named_port_connection_brace: ; named_port_connection: - '.' port_identifier '(' expression_opt ')' + // This needs to be 'any_identifier' to allow identifiers that + // are typedefs in the local scope. + '.' any_identifier '(' expression_opt ')' { init($$, ID_named_port_connection); - mto($$, $2); - mto($$, $4); } + stack_expr($2).id(ID_verilog_identifier); + mto($$, $2); + mto($$, $4); } ; // System Verilog standard 1800-2017 @@ -3493,10 +3617,11 @@ subroutine_call_statement: action_block: statement_or_null %prec LT_TOK_ELSE + { init($$, ID_verilog_action_then); mto($$, $1); } + | TOK_ELSE statement + { init($$, ID_verilog_action_else); mto($$, $2); } | statement_or_null TOK_ELSE statement - { init($$, "action-else"); stack_expr($$).operands().resize(2); - to_binary_expr(stack_expr($$)).op0().swap(stack_expr($0)); - to_binary_expr(stack_expr($$)).op1().swap(stack_expr($2)); } + { init($$, ID_verilog_action_then_else); mto2($$, $1, $3); } ; // The 1800-2017 grammar specifies this to be @@ -3572,7 +3697,18 @@ statement: attribute_instance_brace block_identifier TOK_COLON attribute_instance_brace statement_item { init($$, ID_verilog_label_statement); stack_expr($$).set(ID_base_name, stack_expr($2).id()); - mto($$, $5); } + + // We'll stick the label onto any assertion + auto statement = stack_expr($5).id(); + if(statement == ID_verilog_immediate_assert || + statement == ID_verilog_immediate_assume || + statement == ID_verilog_immediate_cover) + { + stack_expr($5).set(ID_base_name, stack_expr($2).id()); + } + + mto($$, $5); + } | attribute_instance_brace statement_item { $$=$2; } ; @@ -3601,7 +3737,7 @@ function_statement: statement ; system_task_name: TOK_SYSIDENT - { new_symbol($$, $1); } + { new_identifier($$, $1); } ; // System Verilog standard 1800-2017 @@ -3838,7 +3974,7 @@ deferred_immediate_assertion_item: } | block_identifier TOK_COLON deferred_immediate_assertion_statement { /* wrap the statement into an item */ - stack_expr($3).set(ID_identifier, stack_expr($1).id()); + stack_expr($3).set(ID_base_name, stack_expr($1).id()); init($$, ID_verilog_assertion_item); mto($$, $3); } @@ -4341,6 +4477,12 @@ expression: | TOK_QSTRING { init($$, ID_constant); stack_expr($$).type()=typet(ID_string); addswap($$, ID_value, $1); } | inside_expression + | tagged_union_expression + ; + +tagged_union_expression: + TOK_TAGGED member_identifier + { init($$, ID_verilog_tagged_union); mto($$, $2); } ; inside_expression: @@ -4443,6 +4585,7 @@ variable_lvalue: | '{' variable_concatenation_lvalue_brace '}' { init($$, ID_concatenation); swapop($$, $2); } */ + | assignment_pattern ; variable_concatenation_lvalue_brace: @@ -4522,16 +4665,19 @@ attr_name: identifier // even if they are already used for a different kind of identifier // in a higher scope. any_identifier: - type_identifier + TOK_TYPE_IDENTIFIER + { new_identifier($$, $1); } | non_type_identifier ; non_type_identifier: TOK_NON_TYPE_IDENTIFIER - { new_symbol($$, $1); } + { new_identifier($$, $1); } ; block_identifier: TOK_NON_TYPE_IDENTIFIER; +cell_identifier: TOK_NON_TYPE_IDENTIFIER; + class_identifier: TOK_CLASS_IDENTIFIER { init($$, ID_verilog_class_type); @@ -4541,6 +4687,8 @@ class_identifier: TOK_CLASS_IDENTIFIER } ; +config_identifier: TOK_NON_TYPE_IDENTIFIER; + constraint_identifier: TOK_NON_TYPE_IDENTIFIER; edge_identifier: identifier; @@ -4552,10 +4700,14 @@ genvar_identifier: identifier; hierarchical_parameter_identifier: hierarchical_identifier ; +instance_identifier: TOK_NON_TYPE_IDENTIFIER; + interface_identifier: TOK_NON_TYPE_IDENTIFIER; module_identifier: TOK_NON_TYPE_IDENTIFIER; +topmodule_identifier: TOK_NON_TYPE_IDENTIFIER; + endmodule_identifier_opt: /* Optional */ | TOK_COLON module_identifier @@ -4585,6 +4737,8 @@ port_identifier: identifier; ps_covergroup_identifier: ; +library_identifier: TOK_NON_TYPE_IDENTIFIER; + memory_identifier: identifier; member_identifier: identifier; @@ -4598,7 +4752,6 @@ type_identifier: TOK_TYPE_IDENTIFIER init($$, ID_typedef_type); auto base_name = stack_expr($1).id(); stack_expr($$).set(ID_base_name, base_name); - stack_expr($$).set(ID_identifier, PARSER.scopes.current_scope().prefix+id2string(base_name)); } ; diff --git a/src/verilog/sva_expr.h b/src/verilog/sva_expr.h index 6282c7804..2c4414a62 100644 --- a/src/verilog/sva_expr.h +++ b/src/verilog/sva_expr.h @@ -11,6 +11,7 @@ Author: Daniel Kroening, kroening@kroening.com #include +#include "verilog_expr.h" #include "verilog_types.h" /// 1800-2017 16.6 Boolean expressions @@ -36,6 +37,58 @@ static inline sva_boolean_exprt &to_sva_boolean_expr(exprt &expr) return static_cast(expr); } +/// disable_iff for cover sequence +class sva_sequence_disable_iff_exprt : public binary_exprt +{ +public: + sva_sequence_disable_iff_exprt(exprt condition, exprt sequence) + : binary_exprt( + std::move(condition), + ID_sva_sequence_disable_iff, + std::move(sequence), + verilog_sva_sequence_typet{}) + { + } + + const exprt &condition() const + { + return op0(); + } + + exprt &condition() + { + return op0(); + } + + const exprt &sequence() const + { + return op1(); + } + + exprt &sequence() + { + return op1(); + } + +protected: + using binary_exprt::op0; + using binary_exprt::op1; +}; + +static inline const sva_sequence_disable_iff_exprt & +to_sva_sequence_disable_iff_expr(const exprt &expr) +{ + sva_sequence_disable_iff_exprt::check(expr, validation_modet::INVARIANT); + return static_cast(expr); +} + +static inline sva_sequence_disable_iff_exprt & +to_sva_sequence_disable_iff_expr(exprt &expr) +{ + sva_sequence_disable_iff_exprt::check(expr, validation_modet::INVARIANT); + return static_cast(expr); +} + /// accept_on, reject_on, sync_accept_on, sync_reject_on, disable_iff class sva_abort_exprt : public binary_exprt { @@ -1995,4 +2048,78 @@ enum class sva_sequence_semanticst STRONG }; +/// a base class for both sequence and property instance expressions +class sva_sequence_property_instance_exprt : public ternary_exprt +{ +public: + sva_sequence_property_instance_exprt( + symbol_exprt _symbol, + exprt::operandst _arguments, + verilog_sequence_property_declaration_baset _declaration) + : ternary_exprt{ + ID_sva_sequence_property_instance, + std::move(_symbol), + multi_ary_exprt{ID_arguments, std::move(_arguments), typet{}}, + std::move(_declaration), + typet{}} + { + } + + const symbol_exprt &symbol() const + { + return static_cast(op0()); + } + + symbol_exprt &symbol() + { + return static_cast(op0()); + } + + exprt::operandst &arguments() + { + return op1().operands(); + } + + const exprt::operandst &arguments() const + { + return op1().operands(); + } + + verilog_sequence_property_declaration_baset &declaration() + { + return static_cast(op2()); + } + + const verilog_sequence_property_declaration_baset &declaration() const + { + return static_cast( + op2()); + } + + /// Add the source location from \p other, if it has any. + sva_sequence_property_instance_exprt && + with_source_location(const exprt &other) && + { + if(other.source_location().is_not_nil()) + add_source_location() = other.source_location(); + return std::move(*this); + } +}; + +inline const sva_sequence_property_instance_exprt & +to_sva_sequence_property_instance_expr(const exprt &expr) +{ + PRECONDITION(expr.id() == ID_sva_sequence_property_instance); + sva_sequence_property_instance_exprt::check(expr); + return static_cast(expr); +} + +inline sva_sequence_property_instance_exprt & +to_sva_sequence_property_instance_expr(exprt &expr) +{ + PRECONDITION(expr.id() == ID_sva_sequence_property_instance); + sva_sequence_property_instance_exprt::check(expr); + return static_cast(expr); +} + #endif diff --git a/src/verilog/typename.cpp b/src/verilog/typename.cpp new file mode 100644 index 000000000..1fb330144 --- /dev/null +++ b/src/verilog/typename.cpp @@ -0,0 +1,176 @@ +/*******************************************************************\ + +Module: $typename + +Author: Daniel Kroening, dkr@amazon.com + +\*******************************************************************/ + +#include "typename.h" + +#include + +#include "verilog_bits.h" + +// unpacked array: left bound +// packed array: index of most significant element +// 0 otherwise +mp_integer verilog_left(const typet &type) +{ + if( + type.id() == ID_unsignedbv || type.id() == ID_signedbv || + type.id() == ID_verilog_unsignedbv || type.id() == ID_verilog_signedbv || + type.id() == ID_bool) + { + auto offset = type.get_int(ID_C_offset); + if(type.get_bool(ID_C_increasing)) + return offset; + else + return offset + verilog_bits(type) - 1; + } + else if(type.id() == ID_array) + { + auto offset = numeric_cast_v( + to_constant_expr(static_cast(type.find(ID_offset)))); + if(type.get_bool(ID_C_increasing)) + return offset; + else + { + return offset + + numeric_cast_v( + to_constant_expr(to_array_type(type).size())) - + 1; + } + } + else + return 0; +} + +// unpacked array: right bound +// packed array: index of least significant element +// 0 otherwise +mp_integer verilog_right(const typet &type) +{ + if( + type.id() == ID_unsignedbv || type.id() == ID_signedbv || + type.id() == ID_verilog_unsignedbv || type.id() == ID_verilog_signedbv || + type.id() == ID_bool) + { + auto offset = type.get_int(ID_C_offset); + if(type.get_bool(ID_C_increasing)) + return offset + verilog_bits(type) - 1; + else + return offset; + } + else if(type.id() == ID_array) + { + auto offset = numeric_cast_v( + to_constant_expr(static_cast(type.find(ID_offset)))); + if(type.get_bool(ID_C_increasing)) + { + return offset + + numeric_cast_v( + to_constant_expr(to_array_type(type).size())) - + 1; + } + else + return offset; + } + else + return 0; +} + +std::string verilog_typename(const typet &type) +{ + const auto verilog_type = type.get(ID_C_verilog_type); + + auto left = [](const typet &type) + { return integer2string(verilog_left(type)); }; + auto right = [](const typet &type) + { return integer2string(verilog_right(type)); }; + + if(type.id() == ID_unsignedbv) + { + if(verilog_type == ID_verilog_byte) + return "byte unsigned"; + else if(verilog_type == ID_verilog_int) + return "int unsigned"; + else if(verilog_type == ID_verilog_longint) + return "longint unsigned"; + else if(verilog_type == ID_verilog_shortint) + return "shortint unsigned"; + else + return "bit[" + left(type) + ":" + right(type) + "]"; + } + else if(type.id() == ID_verilog_unsignedbv) + { + return "logic[" + left(type) + ":" + right(type) + "]"; + } + else if(type.id() == ID_bool) + { + return "bit"; + } + else if(type.id() == ID_signedbv) + { + if(verilog_type == ID_verilog_byte) + return "byte"; + else if(verilog_type == ID_verilog_int) + return "int"; + else if(verilog_type == ID_verilog_longint) + return "longint"; + else if(verilog_type == ID_verilog_shortint) + return "shortint"; + else + return "bit signed[" + left(type) + ":" + right(type) + "]"; + } + else if(type.id() == ID_verilog_byte) + { + return "byte"; + } + else if(type.id() == ID_verilog_int) + { + return "int"; + } + else if(type.id() == ID_verilog_integer) + { + return "integer"; + } + else if(type.id() == ID_verilog_longint) + { + return "longint"; + } + else if(type.id() == ID_verilog_shortint) + { + return "shortint"; + } + else if(type.id() == ID_verilog_signedbv) + { + return "logic signed[" + left(type) + ":" + right(type) + "]"; + } + else if(type.id() == ID_verilog_realtime) + { + return "realtime"; + } + else if(type.id() == ID_verilog_real) + { + return "real"; + } + else if(type.id() == ID_verilog_shortreal) + { + return "shortreal"; + } + else if(type.id() == ID_verilog_chandle) + { + return "chandle"; + } + else if(type.id() == ID_verilog_event) + { + return "event"; + } + else if(type.id() == ID_verilog_string) + { + return "string"; + } + else + return "?"; +} diff --git a/src/verilog/typename.h b/src/verilog/typename.h new file mode 100644 index 000000000..9f8ec01c4 --- /dev/null +++ b/src/verilog/typename.h @@ -0,0 +1,25 @@ +/*******************************************************************\ + +Module: $typename + +Author: Daniel Kroening, dkr@amazon.com + +\*******************************************************************/ + +#ifndef CPROVER_VERILOG_TYPENAME_H +#define CPROVER_VERILOG_TYPENAME_H + +#include + +class typet; + +/// Verilog's $left +mp_integer verilog_left(const typet &); + +/// Verilog's $right +mp_integer verilog_right(const typet &); + +/// Verilog's $typename +std::string verilog_typename(const typet &); + +#endif diff --git a/src/verilog/verilog_elaborate.cpp b/src/verilog/verilog_elaborate.cpp index 8df68d742..514cbddc3 100644 --- a/src/verilog/verilog_elaborate.cpp +++ b/src/verilog/verilog_elaborate.cpp @@ -102,7 +102,8 @@ void verilog_typecheckt::collect_symbols( if(type.id() == ID_type) { // much like a typedef - auto symbol_type = to_be_elaborated_typet{declarator.type()}; + auto symbol_type = + to_be_elaborated_typet{to_type_expr(declarator.value()).type()}; type_symbolt symbol{full_identifier, symbol_type, mode}; @@ -492,8 +493,14 @@ void verilog_typecheckt::collect_symbols(const verilog_declt &decl) symbols_added.push_back(symbol.name); } } - else if(decl_class == ID_reg || decl_class == ID_var) + else if( + decl_class == ID_reg || decl_class == ID_var || + decl_class == ID_verilog_interconnect) { + if(decl_class == ID_verilog_interconnect) + throw errort().with_location(decl.source_location()) + << "no support for interconnect nets"; + symbolt symbol; symbol.mode = mode; @@ -671,6 +678,7 @@ void verilog_typecheckt::collect_symbols(const verilog_statementt &statement) statement.id() == ID_verilog_assume_property || statement.id() == ID_verilog_restrict_property || statement.id() == ID_verilog_cover_property || + statement.id() == ID_verilog_cover_sequence || statement.id() == ID_verilog_expect_property) { } @@ -797,15 +805,15 @@ void verilog_typecheckt::collect_symbols( { auto ¶meter_decl = to_verilog_parameter_decl(module_item); collect_symbols(parameter_decl.type()); - for(auto &decl : parameter_decl.declarations()) - collect_symbols(parameter_decl.type(), decl); + for(auto &declarator : parameter_decl.declarators()) + collect_symbols(parameter_decl.type(), declarator); } else if(module_item.id() == ID_local_parameter_decl) { auto &localparam_decl = to_verilog_local_parameter_decl(module_item); collect_symbols(localparam_decl.type()); - for(auto &decl : localparam_decl.declarations()) - collect_symbols(localparam_decl.type(), decl); + for(auto &declarator : localparam_decl.declarators()) + collect_symbols(localparam_decl.type(), declarator); } else if(module_item.id() == ID_decl) { @@ -850,7 +858,8 @@ void verilog_typecheckt::collect_symbols( module_item.id() == ID_verilog_assert_property || module_item.id() == ID_verilog_assume_property || module_item.id() == ID_verilog_restrict_property || - module_item.id() == ID_verilog_cover_property) + module_item.id() == ID_verilog_cover_property || + module_item.id() == ID_verilog_cover_sequence) { } else if(module_item.id() == ID_verilog_assertion_item) @@ -902,6 +911,10 @@ void verilog_typecheckt::collect_symbols( { collect_symbols(to_verilog_sequence_declaration(module_item)); } + else if(module_item.id() == ID_function_call) + { + // e.g., $error + } else DATA_INVARIANT(false, "unexpected module item: " + module_item.id_string()); } @@ -975,8 +988,9 @@ verilog_typecheckt::elaborate(const verilog_module_sourcet &module_source) // and the expansion of generate blocks. // At the top level of the module, include the parameter ports. - for(auto ¶meter_port_decl : module_source.parameter_port_list()) - collect_symbols(typet(ID_nil), parameter_port_decl); + for(auto &declaration : module_source.parameter_port_decls()) + for(auto &declarator : declaration.declarators()) + collect_symbols(declaration.type(), declarator); // At the top level of the module, include the non-parameter module port // module items. @@ -1026,11 +1040,11 @@ void verilog_typecheckt::elaborate_symbol_rec(irep_idt identifier) { convert_expr(symbol.value); + // Convert to the given type. These are assignment contexts. + assignment_conversion(symbol.value, symbol.type); + if(!is_let) symbol.value = elaborate_constant_expression_check(symbol.value); - - // Cast to the given type. - propagate_type(symbol.value, symbol.type); } } } diff --git a/src/verilog/verilog_elaborate_type.cpp b/src/verilog/verilog_elaborate_type.cpp index 26452e8f5..a96b97955 100644 --- a/src/verilog/verilog_elaborate_type.cpp +++ b/src/verilog/verilog_elaborate_type.cpp @@ -172,18 +172,26 @@ typet verilog_typecheck_exprt::elaborate_package_scope_typedef( << "verilog_package_scope expects typedef_type on the rhs"; auto package_base_name = src.subtypes()[0].id(); - auto typedef_base_name = src.subtypes()[1].get(ID_base_name); + auto typedef_base_name = + to_verilog_typedef_type(src.subtypes()[1]).base_name(); // stitch together irep_idt full_identifier = id2string(verilog_package_identifier(package_base_name)) + '.' + id2string(typedef_base_name); - // recursive call - verilog_typedef_typet full_typedef_type(full_identifier); - full_typedef_type.set(ID_identifier, full_identifier); + // look it up + const symbolt *symbol_ptr; - return elaborate_type(full_typedef_type); + if(ns.lookup(full_identifier, symbol_ptr)) + throw errort().with_location(location) + << "symbol " << typedef_base_name << " not found in package"; + + // must be type + if(!symbol_ptr->is_type) + throw errort().with_location(location) << "expected a type identifier"; + + return symbol_ptr->type; } /*******************************************************************\ @@ -334,18 +342,17 @@ typet verilog_typecheck_exprt::elaborate_type(const typet &src) else if(src.id() == ID_typedef_type) { // Look it up! - const symbolt *symbol_ptr; + auto base_name = to_verilog_typedef_type(src).base_name(); + const auto *symbol_ptr = resolve(base_name); - auto identifier = to_verilog_typedef_type(src).identifier(); - - if(ns.lookup(identifier, symbol_ptr)) + if(symbol_ptr == nullptr) throw errort().with_location(source_location) - << "type symbol " << identifier << " not found"; + << "type symbol " << base_name << " not found"; DATA_INVARIANT(symbol_ptr->is_type, "typedef symbols must be types"); // elaborate that typedef symbol, recursively, if needed - elaborate_symbol_rec(identifier); + elaborate_symbol_rec(symbol_ptr->name); auto result = symbol_ptr->type; // copy return result.with_source_location(source_location); @@ -425,8 +432,14 @@ typet verilog_typecheck_exprt::elaborate_type(const typet &src) } } - return struct_union_typet{src.id(), std::move(components)} - .with_source_location(src.source_location()); + auto result = + struct_union_typet{src.id(), std::move(components)}.with_source_location( + src.source_location()); + + if(src.get_bool(ID_packed)) + result.set(ID_packed, true); + + return result; } else if(src.id() == ID_verilog_string) { diff --git a/src/verilog/verilog_expr.cpp b/src/verilog/verilog_expr.cpp index 3a359986a..c85d92c56 100644 --- a/src/verilog/verilog_expr.cpp +++ b/src/verilog/verilog_expr.cpp @@ -50,20 +50,30 @@ typet verilog_declaratort::merged_type(const typet &declaration_type) const return result; } -bool function_call_exprt::is_system_function_call() const +static bool is_system_function_identifier(const exprt &function) { - return function().id() == ID_symbol && + return function.id() == ID_verilog_identifier && has_prefix( - id2string(to_symbol_expr(function()).get_identifier()), "$"); + id2string(to_verilog_identifier_expr(function).base_name()), "$"); +} + +bool function_call_exprt::is_system_function_call() const +{ + return is_system_function_identifier(function()); +} + +bool verilog_function_callt::is_system_function_call() const +{ + return is_system_function_identifier(function()); } void verilog_module_sourcet::show(std::ostream &out) const { out << "Module: " << base_name() << '\n'; - out << " Parameters:\n"; + out << " Parameter ports:\n"; - for(auto ¶meter : parameter_port_list()) + for(auto ¶meter : parameter_port_decls()) out << " " << parameter.pretty() << '\n'; out << '\n'; @@ -146,19 +156,19 @@ static void dependencies_rec( else if(module_item.id() == ID_parameter_decl) { auto ¶meter_decl = to_verilog_parameter_decl(module_item); - for(auto &decl : parameter_decl.declarations()) + for(auto &declarator : parameter_decl.declarators()) { - dependencies_rec(decl.type(), dest); - dependencies_rec(decl.value(), dest); + dependencies_rec(declarator.type(), dest); + dependencies_rec(declarator.value(), dest); } } else if(module_item.id() == ID_local_parameter_decl) { auto &localparam_decl = to_verilog_local_parameter_decl(module_item); - for(auto &decl : localparam_decl.declarations()) + for(auto &declarator : localparam_decl.declarators()) { - dependencies_rec(decl.type(), dest); - dependencies_rec(decl.value(), dest); + dependencies_rec(declarator.type(), dest); + dependencies_rec(declarator.value(), dest); } } else if(module_item.id() == ID_decl) @@ -201,7 +211,8 @@ static void dependencies_rec( module_item.id() == ID_verilog_assert_property || module_item.id() == ID_verilog_assume_property || module_item.id() == ID_verilog_restrict_property || - module_item.id() == ID_verilog_cover_property) + module_item.id() == ID_verilog_cover_property || + module_item.id() == ID_verilog_cover_sequence) { } else if(module_item.id() == ID_verilog_assertion_item) diff --git a/src/verilog/verilog_expr.h b/src/verilog/verilog_expr.h index 9f7b197c3..b04681c33 100644 --- a/src/verilog/verilog_expr.h +++ b/src/verilog/verilog_expr.h @@ -11,6 +11,36 @@ Author: Daniel Kroening, kroening@kroening.com #include +/// A simple Verilog identifier, unqualified +class verilog_identifier_exprt : public nullary_exprt +{ +public: + const irep_idt &base_name() const + { + return get(ID_base_name); + } + + void identifier(irep_idt _base_name) + { + set(ID_base_name, _base_name); + } +}; + +inline const verilog_identifier_exprt & +to_verilog_identifier_expr(const exprt &expr) +{ + PRECONDITION(expr.id() == ID_verilog_identifier); + verilog_identifier_exprt::check(expr); + return static_cast(expr); +} + +inline verilog_identifier_exprt &to_verilog_identifier_expr(exprt &expr) +{ + PRECONDITION(expr.id() == ID_verilog_identifier); + verilog_identifier_exprt::check(expr); + return static_cast(expr); +} + /// The syntax for these A.B, where A is a module identifier and B /// is an identifier within that module. B is given als symbol_exprt. class hierarchical_identifier_exprt : public binary_exprt @@ -21,12 +51,12 @@ class hierarchical_identifier_exprt : public binary_exprt return op0(); } - const symbol_exprt &item() const + const verilog_identifier_exprt &item() const { - return static_cast(binary_exprt::op1()); + return static_cast(binary_exprt::op1()); } - const symbol_exprt &rhs() const + const verilog_identifier_exprt &rhs() const { return item(); } @@ -393,6 +423,12 @@ class verilog_module_itemt:public exprt inline verilog_module_itemt() { } + + static void + check(const exprt &expr, validation_modet vm = validation_modet::INVARIANT) + { + exprt::check(expr, vm); + } }; inline const verilog_module_itemt &to_verilog_module_item(const irept &irep) @@ -680,6 +716,7 @@ class verilog_declaratort : public exprt using verilog_declaratorst = std::vector; +/// a SystemVerilog parameter declaration class verilog_parameter_declt : public verilog_module_itemt { public: @@ -690,12 +727,12 @@ class verilog_parameter_declt : public verilog_module_itemt using declaratort = verilog_declaratort; using declaratorst = verilog_declaratorst; - const declaratorst &declarations() const + const declaratorst &declarators() const { return (const declaratorst &)operands(); } - declaratorst &declarations() + declaratorst &declarators() { return (declaratorst &)operands(); } @@ -725,12 +762,12 @@ class verilog_local_parameter_declt : public verilog_module_itemt using declaratort = verilog_declaratort; using declaratorst = verilog_declaratorst; - const declaratorst &declarations() const + const declaratorst &declarators() const { return (const declaratorst &)operands(); } - declaratorst &declarations() + declaratorst &declarators() { return (declaratorst &)operands(); } @@ -1406,6 +1443,7 @@ inline verilog_ift &to_verilog_if(exprt &expr) return static_cast(expr); } +/// task or function enable class verilog_function_callt:public verilog_statementt { public: @@ -1423,7 +1461,9 @@ class verilog_function_callt:public verilog_statementt { return op0(); } - + + bool is_system_function_call() const; + exprt::operandst &arguments() { return op1().operands(); @@ -2042,6 +2082,7 @@ class verilog_assert_assume_cover_module_itemt : public verilog_module_itemt return op1(); } + // The full identifier created by the type checker const irep_idt &identifier() const { return get(ID_identifier); @@ -2051,6 +2092,11 @@ class verilog_assert_assume_cover_module_itemt : public verilog_module_itemt { set(ID_identifier, identifier); } + + const irep_idt &base_name() const + { + return get(ID_base_name); + } }; inline const verilog_assert_assume_cover_module_itemt & @@ -2061,7 +2107,8 @@ to_verilog_assert_assume_cover_module_item( module_item.id() == ID_verilog_assert_property || module_item.id() == ID_verilog_assume_property || module_item.id() == ID_verilog_restrict_property || - module_item.id() == ID_verilog_cover_property); + module_item.id() == ID_verilog_cover_property || + module_item.id() == ID_verilog_cover_sequence); binary_exprt::check(module_item); return static_cast( module_item); @@ -2074,7 +2121,8 @@ to_verilog_assert_assume_cover_module_item(verilog_module_itemt &module_item) module_item.id() == ID_verilog_assert_property || module_item.id() == ID_verilog_assume_property || module_item.id() == ID_verilog_restrict_property || - module_item.id() == ID_verilog_cover_property); + module_item.id() == ID_verilog_cover_property || + module_item.id() == ID_verilog_cover_sequence); binary_exprt::check(module_item); return static_cast(module_item); } @@ -2110,6 +2158,16 @@ class verilog_assert_assume_cover_statementt : public verilog_statementt { set(ID_identifier, _identifier); } + + const irep_idt &base_name() const + { + return get(ID_base_name); + } + + void base_name(irep_idt _base_name) + { + set(ID_base_name, _base_name); + } }; inline const verilog_assert_assume_cover_statementt & @@ -2124,7 +2182,8 @@ to_verilog_assert_assume_cover_statement(const verilog_statementt &statement) statement.id() == ID_verilog_restrict_property || statement.id() == ID_verilog_smv_assume || statement.id() == ID_verilog_immediate_cover || - statement.id() == ID_verilog_cover_property); + statement.id() == ID_verilog_cover_property || + statement.id() == ID_verilog_cover_sequence); binary_exprt::check(statement); return static_cast(statement); } @@ -2141,7 +2200,8 @@ to_verilog_assert_assume_cover_statement(verilog_statementt &statement) statement.id() == ID_verilog_restrict_property || statement.id() == ID_verilog_smv_assume || statement.id() == ID_verilog_immediate_cover || - statement.id() == ID_verilog_cover_property); + statement.id() == ID_verilog_cover_property || + statement.id() == ID_verilog_cover_sequence); binary_exprt::check(statement); return static_cast(statement); } @@ -2350,17 +2410,18 @@ class verilog_module_sourcet : public verilog_item_containert { } - using parameter_port_listt = verilog_parameter_declt::declaratorst; + using parameter_port_declst = std::vector; - const parameter_port_listt ¶meter_port_list() const + const parameter_port_declst ¶meter_port_decls() const { - return ( - const parameter_port_listt &)(find(ID_parameter_port_list).get_sub()); + return (const parameter_port_declst &)(find(ID_verilog_parameter_port_decls) + .get_sub()); } - parameter_port_listt ¶meter_port_list() + parameter_port_declst ¶meter_port_decls() { - return (parameter_port_listt &)(add(ID_parameter_port_list).get_sub()); + return ( + parameter_port_declst &)(add(ID_verilog_parameter_port_decls).get_sub()); } using port_listt = std::vector; @@ -2554,12 +2615,6 @@ class verilog_explicit_size_cast_exprt : public binary_exprt { return op1(); } - - // lower to typecast - exprt lower() const - { - return typecast_exprt{op(), type()}; - } }; inline const verilog_explicit_size_cast_exprt & @@ -2655,11 +2710,6 @@ class verilog_explicit_type_cast_exprt : public unary_exprt std::move(__type)) { } - - exprt lower() const - { - return typecast_exprt{op(), type()}; - } }; inline const verilog_explicit_type_cast_exprt & @@ -2887,9 +2937,16 @@ to_verilog_indexed_part_select_plus_or_minus_expr(exprt &expr) return static_cast(expr); } -class verilog_property_declarationt : public verilog_module_itemt +/// a base class for both sequence and property declarations +class verilog_sequence_property_declaration_baset : public verilog_module_itemt { public: + verilog_sequence_property_declaration_baset(irep_idt _id, exprt _cond) + : verilog_module_itemt{_id} + { + add_to_operands(std::move(_cond)); + } + const irep_idt &base_name() const { return get(ID_base_name); @@ -2906,10 +2963,53 @@ class verilog_property_declarationt : public verilog_module_itemt } }; +inline const verilog_sequence_property_declaration_baset & +to_verilog_sequence_property_declaration_base(const exprt &expr) +{ + PRECONDITION( + expr.id() == ID_verilog_sequence_declaration || + expr.id() == ID_verilog_property_declaration); + verilog_sequence_property_declaration_baset::check(expr); + return static_cast(expr); +} + +inline verilog_sequence_property_declaration_baset & +to_verilog_sequence_property_declaration_base(exprt &expr) +{ + PRECONDITION( + expr.id() == ID_verilog_sequence_declaration || + expr.id() == ID_verilog_property_declaration); + verilog_sequence_property_declaration_baset::check(expr); + return static_cast(expr); +} + +class verilog_property_declarationt + : public verilog_sequence_property_declaration_baset +{ +public: + explicit verilog_property_declarationt(exprt property) + : verilog_sequence_property_declaration_baset{ + ID_verilog_property_declaration, + std::move(property)} + { + } + + const exprt &property() const + { + return cond(); + } + + exprt &property() + { + return cond(); + } +}; + inline const verilog_property_declarationt & to_verilog_property_declaration(const exprt &expr) { PRECONDITION(expr.id() == ID_verilog_property_declaration); + verilog_property_declarationt::check(expr); return static_cast(expr); } @@ -2917,30 +3017,29 @@ inline verilog_property_declarationt & to_verilog_property_declaration(exprt &expr) { PRECONDITION(expr.id() == ID_verilog_property_declaration); + verilog_property_declarationt::check(expr); return static_cast(expr); } -class verilog_sequence_declarationt : public verilog_module_itemt +class verilog_sequence_declarationt + : public verilog_sequence_property_declaration_baset { public: - explicit verilog_sequence_declarationt(exprt sequence) - { - add_to_operands(std::move(sequence)); - } - - const irep_idt &base_name() const + explicit verilog_sequence_declarationt(exprt _sequence) + : verilog_sequence_property_declaration_baset{ + ID_verilog_sequence_declaration, + std::move(_sequence)} { - return get(ID_base_name); } const exprt &sequence() const { - return op0(); + return cond(); } exprt &sequence() { - return op0(); + return cond(); } }; @@ -2948,6 +3047,7 @@ inline const verilog_sequence_declarationt & to_verilog_sequence_declaration(const exprt &expr) { PRECONDITION(expr.id() == ID_verilog_sequence_declaration); + verilog_sequence_declarationt::check(expr); return static_cast(expr); } @@ -2955,6 +3055,7 @@ inline verilog_sequence_declarationt & to_verilog_sequence_declaration(exprt &expr) { PRECONDITION(expr.id() == ID_verilog_sequence_declaration); + verilog_sequence_declarationt::check(expr); return static_cast(expr); } diff --git a/src/verilog/verilog_generate.cpp b/src/verilog/verilog_generate.cpp index a010e3bb7..40260c0f7 100644 --- a/src/verilog/verilog_generate.cpp +++ b/src/verilog/verilog_generate.cpp @@ -170,13 +170,14 @@ void verilog_typecheckt::elaborate_generate_assign( const verilog_generate_assignt &statement, module_itemst &dest) { - if(statement.lhs().id() != ID_symbol) + if(statement.lhs().id() != ID_verilog_identifier) { throw errort().with_location(statement.lhs().source_location()) << "expected symbol on left hand side of assignment"; } - const irep_idt &identifier = to_symbol_expr(statement.lhs()).get_identifier(); + const irep_idt &identifier = + to_verilog_identifier_expr(statement.lhs()).base_name(); genvarst::iterator it=genvars.find(identifier); diff --git a/src/verilog/verilog_interfaces.cpp b/src/verilog/verilog_interfaces.cpp index 535832ecb..47169a64f 100644 --- a/src/verilog/verilog_interfaces.cpp +++ b/src/verilog/verilog_interfaces.cpp @@ -108,6 +108,10 @@ void verilog_typecheckt::check_module_ports( else direction = ID_inout; } + else if(direction == ID_output_register) + { + direction = ID_output; + } ports.emplace_back(identifier, port_symbol->type, direction); @@ -285,7 +289,8 @@ void verilog_typecheckt::interface_module_item( module_item.id() == ID_verilog_assert_property || module_item.id() == ID_verilog_assume_property || module_item.id() == ID_verilog_restrict_property || - module_item.id() == ID_verilog_cover_property) + module_item.id() == ID_verilog_cover_property || + module_item.id() == ID_verilog_cover_sequence) { // done later } @@ -335,6 +340,9 @@ void verilog_typecheckt::interface_module_item( else if(module_item.id() == ID_verilog_sequence_declaration) { } + else if(module_item.id() == ID_function_call) + { + } else { DATA_INVARIANT(false, "unexpected module item: " + module_item.id_string()); diff --git a/src/verilog/verilog_lowering.cpp b/src/verilog/verilog_lowering.cpp index 465869999..f8b624481 100644 --- a/src/verilog/verilog_lowering.cpp +++ b/src/verilog/verilog_lowering.cpp @@ -176,20 +176,20 @@ exprt to_bitvector(const exprt &src) exprt verilog_lowering_system_function(const function_call_exprt &call) { - auto identifier = to_symbol_expr(call.function()).get_identifier(); + auto base_name = to_verilog_identifier_expr(call.function()).base_name(); auto &arguments = call.arguments(); - if(identifier == "$signed" || identifier == "$unsigned") + if(base_name == "$signed" || base_name == "$unsigned") { // lower to typecast DATA_INVARIANT( - arguments.size() == 1, id2string(identifier) + " takes one argument"); + arguments.size() == 1, id2string(base_name) + " takes one argument"); return typecast_exprt{arguments[0], call.type()}; } - else if(identifier == "$rtoi") + else if(base_name == "$rtoi") { DATA_INVARIANT( - arguments.size(), id2string(identifier) + " takes one argument"); + arguments.size(), id2string(base_name) + " takes one argument"); // These truncate, and do not round. return floatbv_typecast_exprt{ arguments[0], @@ -197,10 +197,10 @@ exprt verilog_lowering_system_function(const function_call_exprt &call) ieee_floatt::rounding_modet::ROUND_TO_ZERO), verilog_lowering(call.type())}; } - else if(identifier == "$itor") + else if(base_name == "$itor") { DATA_INVARIANT( - arguments.size(), id2string(identifier) + " takes one argument"); + arguments.size(), id2string(base_name) + " takes one argument"); // No rounding required, any 32-bit integer will fit into double. return floatbv_typecast_exprt{ arguments[0], @@ -208,36 +208,36 @@ exprt verilog_lowering_system_function(const function_call_exprt &call) ieee_floatt::rounding_modet::ROUND_TO_ZERO), verilog_lowering(call.type())}; } - else if(identifier == "$bitstoreal") + else if(base_name == "$bitstoreal") { DATA_INVARIANT( - arguments.size(), id2string(identifier) + " takes one argument"); + arguments.size(), id2string(base_name) + " takes one argument"); // not a conversion -- this returns the given bit-pattern as a real return typecast_exprt{ zero_extend_exprt{arguments[0], bv_typet{64}}, verilog_lowering(call.type())}; } - else if(identifier == "$bitstoshortreal") + else if(base_name == "$bitstoshortreal") { DATA_INVARIANT( - arguments.size(), id2string(identifier) + " takes one argument"); + arguments.size(), id2string(base_name) + " takes one argument"); // not a conversion -- this returns the given bit-pattern as a real return typecast_exprt{ zero_extend_exprt{arguments[0], bv_typet{32}}, verilog_lowering(call.type())}; } - else if(identifier == "$realtobits") + else if(base_name == "$realtobits") { DATA_INVARIANT( - arguments.size(), id2string(identifier) + " takes one argument"); + arguments.size(), id2string(base_name) + " takes one argument"); // not a conversion -- this returns the given floating-point bit-pattern as [63:0] return zero_extend_exprt{ typecast_exprt{arguments[0], bv_typet{64}}, call.type()}; } - else if(identifier == "$shortrealtobits") + else if(base_name == "$shortrealtobits") { DATA_INVARIANT( - arguments.size(), id2string(identifier) + " takes one argument"); + arguments.size(), id2string(base_name) + " takes one argument"); // not a conversion -- this returns the given floating-point bit-pattern as [31:0] return zero_extend_exprt{ typecast_exprt{arguments[0], bv_typet{32}}, call.type()}; @@ -251,6 +251,16 @@ exprt verilog_lowering_cast(typecast_exprt expr) auto &src_type = expr.op().type(); auto &dest_type = expr.type(); + if(src_type.id() == ID_verilog_null && dest_type.id() == ID_verilog_chandle) + { + return to_verilog_chandle_type(dest_type).null_expr(); + } + + if(src_type.id() == ID_verilog_null && dest_type.id() == ID_verilog_event) + { + return to_verilog_event_type(dest_type).null_expr(); + } + // float to int if( (src_type.id() == ID_verilog_real || @@ -293,7 +303,7 @@ exprt verilog_lowering_cast(typecast_exprt expr) return std::move(new_cast); } - if(is_aval_bval(src_type) && dest_type.id() == ID_bool) + if(is_aval_bval(src_type)) { // When casting a four-valued scalar to bool, // 'true' is defined as a "nonzero known value" (1800-2017 12.4). @@ -340,8 +350,8 @@ exprt verilog_lowering(exprt expr) auto &call = to_function_call_expr(expr); if(call.is_system_function_call()) { - auto identifier = to_symbol_expr(call.function()).get_identifier(); - if(identifier == "$typename") + auto base_name = to_verilog_identifier_expr(call.function()).base_name(); + if(base_name == "$typename") { // Don't touch. // Will be expanded by elaborate_constant_system_function_call, @@ -411,6 +421,17 @@ exprt verilog_lowering(exprt expr) else return expr; } + else if( + expr.id() == ID_le || expr.id() == ID_ge || expr.id() == ID_lt || + expr.id() == ID_ge) + { + if(is_four_valued(expr)) + { + return aval_bval(to_binary_relation_expr(expr)); + } + else + return expr; + } else if(expr.id() == ID_concatenation) { if( @@ -461,8 +482,13 @@ exprt verilog_lowering(exprt expr) } else if(expr.id() == ID_verilog_explicit_type_cast) { - return verilog_lowering_cast( - to_typecast_expr(to_verilog_explicit_type_cast_expr(expr).lower())); + // These act like an assignment, and hence, the type checker + // has already converted the argument to the target type. + auto &type_cast = to_verilog_explicit_type_cast_expr(expr); + expr.type() = verilog_lowering(expr.type()); + DATA_INVARIANT( + type_cast.op().type() == type_cast.type(), "type cast type consistency"); + return type_cast.op(); } else if(expr.id() == ID_verilog_explicit_signing_cast) { @@ -470,7 +496,13 @@ exprt verilog_lowering(exprt expr) } else if(expr.id() == ID_verilog_explicit_size_cast) { - return to_verilog_explicit_size_cast_expr(expr).lower(); + // These act like an assignment, and hence, the type checker + // has already converted the argument to the target type. + auto &size_cast = to_verilog_explicit_size_cast_expr(expr); + expr.type() = verilog_lowering(expr.type()); + DATA_INVARIANT( + size_cast.op().type() == size_cast.type(), "size cast type consistency"); + return size_cast.op(); } else if( expr.id() == ID_verilog_streaming_concatenation_left_to_right || @@ -538,15 +570,48 @@ exprt verilog_lowering(exprt expr) else return expr; // leave as is } - else if( - expr.id() == ID_bitand || expr.id() == ID_bitor || expr.id() == ID_bitxor || - expr.id() == ID_bitxnor) + else if(expr.id() == ID_bitand) + { + // encode into aval/bval + if(is_four_valued(expr.type())) + return aval_bval_bitand(to_bitand_expr(expr)); + else + return expr; // leave as is + } + else if(expr.id() == ID_bitor) + { + // encode into aval/bval + if(is_four_valued(expr.type())) + return aval_bval_bitor(to_bitor_expr(expr)); + else + return expr; // leave as is + } + else if(expr.id() == ID_bitxor || expr.id() == ID_bitxnor) + { + // encode into aval/bval + if(is_four_valued(expr.type())) + return aval_bval_xor_xnor(to_multi_ary_expr(expr)); + else + return expr; // leave as is + } + else if(expr.id() == ID_replication) { - auto &multi_ary_expr = to_multi_ary_expr(expr); + auto &replication_expr = to_replication_expr(expr); // encode into aval/bval if(is_four_valued(expr.type())) - return aval_bval_bitwise(multi_ary_expr); + return aval_bval_replication(replication_expr); + else + return expr; // leave as is + } + else if( + expr.id() == ID_reduction_or || expr.id() == ID_reduction_and || + expr.id() == ID_reduction_nor || expr.id() == ID_reduction_nand || + expr.id() == ID_reduction_xor || expr.id() == ID_reduction_xnor) + { + // encode into aval/bval + if(is_four_valued(expr.type())) + return aval_bval_reduction(to_unary_expr(expr)); else return expr; // leave as is } @@ -604,9 +669,23 @@ exprt verilog_lowering(exprt expr) { // turn into floatbv expr.type() = verilog_lowering(expr.type()); + return expr; } - - return expr; + else if(is_four_valued(expr)) + { + return default_aval_bval_lowering(expr); + } + else + return expr; + } + else if( + expr.id() == ID_plus || expr.id() == ID_minus || expr.id() == ID_mult || + expr.id() == ID_div || expr.id() == ID_mod) + { + if(is_four_valued(expr)) + return default_aval_bval_lowering(expr); + else + return expr; } else if(expr.id() == ID_lshr || expr.id() == ID_ashr || expr.id() == ID_shl) { @@ -615,6 +694,13 @@ exprt verilog_lowering(exprt expr) else return expr; } + else if(expr.id() == ID_zero_extend) + { + if(is_four_valued(expr.type())) + return aval_bval(to_zero_extend_expr(expr)); + else + return expr; + } else return expr; // leave as is diff --git a/src/verilog/verilog_parameterize_module.cpp b/src/verilog/verilog_parameterize_module.cpp index 21d101db1..9afb4a0b7 100644 --- a/src/verilog/verilog_parameterize_module.cpp +++ b/src/verilog/verilog_parameterize_module.cpp @@ -10,9 +10,9 @@ Author: Daniel Kroening, kroening@kroening.com #include #include -#include "verilog_typecheck.h" - +#include "typename.h" #include "verilog_expr.h" +#include "verilog_typecheck.h" /*******************************************************************\ @@ -33,18 +33,19 @@ verilog_typecheckt::get_parameter_declarators( std::vector declarators; // We do the parameter ports first. - const auto ¶meter_port_list = module_source.parameter_port_list(); + const auto ¶meter_port_decls = module_source.parameter_port_decls(); - for(auto &decl : parameter_port_list) - declarators.push_back(decl); + for(auto &declaration : parameter_port_decls) + for(auto &declarator : declaration.declarators()) + declarators.push_back(declarator); // We do the module item ports second. const auto &module_items = module_source.module_items(); for(auto &item : module_items) if(item.id() == ID_parameter_decl) - for(auto &decl : to_verilog_parameter_decl(item).declarations()) - declarators.push_back(decl); + for(auto &declarator : to_verilog_parameter_decl(item).declarators()) + declarators.push_back(declarator); return declarators; } @@ -119,8 +120,8 @@ std::list verilog_typecheckt::get_parameter_values( } // Is there a defparam that overrides this parameter? - auto &identifier = decl.identifier(); - auto def_param_it = instance_defparams.find(identifier); + auto &base_name = decl.base_name(); + auto def_param_it = instance_defparams.find(base_name); if(def_param_it != instance_defparams.end()) value = def_param_it->second; @@ -155,25 +156,28 @@ void verilog_typecheckt::set_parameter_values( { auto p_it=parameter_values.begin(); - auto ¶meter_port_list = module_source.parameter_port_list(); + auto ¶meter_port_decls = module_source.parameter_port_decls(); - for(auto &declarator : parameter_port_list) - { - DATA_INVARIANT(p_it != parameter_values.end(), "have enough parameter values"); + for(auto &declaration : parameter_port_decls) + for(auto &declarator : declaration.declarators()) + { + DATA_INVARIANT( + p_it != parameter_values.end(), "have enough parameter values"); - // only overwrite when actually assigned - if(p_it->is_not_nil()) - declarator.value() = *p_it; + // only overwrite when actually assigned + if(p_it->is_not_nil()) + declarator.value() = *p_it; - p_it++; - } + p_it++; + } auto &module_items = module_source.module_items(); for(auto &module_item : module_items) if(module_item.id() == ID_parameter_decl) { - for(auto &decl : to_verilog_parameter_decl(module_item).declarations()) + for(auto &declarator : + to_verilog_parameter_decl(module_item).declarators()) { if(p_it!=parameter_values.end()) { @@ -181,7 +185,7 @@ void verilog_typecheckt::set_parameter_values( // only overwrite when actually assigned if(p_it->is_not_nil()) - decl.value() = *p_it; + declarator.value() = *p_it; p_it++; } @@ -241,15 +245,18 @@ irep_idt verilog_typecheckt::parameterize_module( if(pv.is_not_nil()) { - mp_integer i; - if(to_integer_non_constant(pv, i)) + if(pv.id() == ID_type) { - throw errort().with_location(pv.source_location()) - << "parameter value expected to be constant, but got `" - << to_string(pv) << "'"; + suffix += verilog_typename(to_type_expr(pv).type()); } - else + else if(pv.id() == ID_constant) + { + mp_integer i = numeric_cast_v(to_constant_expr(pv)); suffix += integer2string(i); + } + else + DATA_INVARIANT( + false, "parameter value expected to be type or constant"); } } diff --git a/src/verilog/verilog_parse_tree.cpp b/src/verilog/verilog_parse_tree.cpp index f796bd512..61655f0c1 100644 --- a/src/verilog/verilog_parse_tree.cpp +++ b/src/verilog/verilog_parse_tree.cpp @@ -25,7 +25,7 @@ exprt verilog_parse_treet::create_module( irept &attributes, irept &module_keyword, exprt &name, - exprt ¶meter_port_list, + exprt ¶meter_port_decls, exprt &ports, exprt &module_items) { @@ -35,7 +35,8 @@ exprt verilog_parse_treet::create_module( verilog_module_sourcet new_module{name.id()}; - new_module.add(ID_parameter_port_list) = std::move(parameter_port_list); + new_module.add(ID_verilog_parameter_port_decls) = + std::move(parameter_port_decls); new_module.add(ID_ports) = std::move(ports); new_module.add_source_location() = ((const exprt &)module_keyword).source_location(); diff --git a/src/verilog/verilog_synthesis.cpp b/src/verilog/verilog_synthesis.cpp index ce4c34b03..5b694dbab 100644 --- a/src/verilog/verilog_synthesis.cpp +++ b/src/verilog/verilog_synthesis.cpp @@ -71,6 +71,11 @@ exprt verilog_synthesist::synth_expr_rec(exprt expr, symbol_statet symbol_state) { return expand_function_call(to_function_call_expr(expr), symbol_state); } + else if(expr.id() == ID_sva_sequence_property_instance) + { + auto &instance = to_sva_sequence_property_instance_expr(expr); + return synth_expr(instance.declaration().cond(), symbol_state); + } else if(expr.id() == ID_hierarchical_identifier) { expand_hierarchical_identifier( @@ -337,8 +342,8 @@ exprt verilog_synthesist::expand_function_call( // Is it a 'system function call'? if(call.is_system_function_call()) { - auto identifier = to_symbol_expr(call.function()).get_identifier(); - if(identifier == "$ND") + auto base_name = to_verilog_identifier_expr(call.function()).base_name(); + if(base_name == "$ND") { std::string identifier = id2string(module) + "::nondet::" + std::to_string(nondet_count++); @@ -349,7 +354,7 @@ exprt verilog_synthesist::expand_function_call( select_one.set(ID_identifier, identifier); return select_one.with_source_location(call); } - else if(identifier == "$past") + else if(base_name == "$past") { auto what = call.arguments()[0]; auto ticks = call.arguments().size() < 2 @@ -358,8 +363,8 @@ exprt verilog_synthesist::expand_function_call( return verilog_past_exprt{what, ticks}.with_source_location(call); } else if( - identifier == "$stable" || identifier == "$rose" || - identifier == "$fell" || identifier == "$changed") + base_name == "$stable" || base_name == "$rose" || base_name == "$fell" || + base_name == "$changed") { DATA_INVARIANT(call.arguments().size() >= 1, "must have argument"); auto what = call.arguments()[0]; @@ -371,18 +376,18 @@ exprt verilog_synthesist::expand_function_call( std::move(expr), from_integer(0, integer_typet{})}; }; - if(identifier == "$stable") + if(base_name == "$stable") return equal_exprt{what, past}; - else if(identifier == "$changed") + else if(base_name == "$changed") return notequal_exprt{what, past}; - else if(identifier == "$rose") + else if(base_name == "$rose") return and_exprt{not_exprt{lsb(past)}, lsb(what)}; - else if(identifier == "$fell") + else if(base_name == "$fell") return and_exprt{lsb(past), not_exprt{lsb(what)}}; else DATA_INVARIANT(false, "all cases covered"); } - else if(identifier == "$countones") + else if(base_name == "$countones") { // lower to popcount DATA_INVARIANT( @@ -505,12 +510,12 @@ void verilog_synthesist::expand_hierarchical_identifier( const irep_idt &lhs_identifier = expr.lhs().get(ID_identifier); // rhs - const irep_idt &rhs_identifier = expr.rhs().get_identifier(); + const irep_idt &rhs_base_name = expr.rhs().base_name(); // just patch together irep_idt full_identifier = - id2string(lhs_identifier) + '.' + id2string(rhs_identifier); + id2string(lhs_identifier) + '.' + id2string(rhs_base_name); // Note: the instance copy may not yet be in symbol table, // as the inst module item may be later. @@ -555,9 +560,7 @@ void verilog_synthesist::assignment_rec( if(it->type().id()==ID_bool) { - exprt bit_extract(ID_extractbit, it->type()); - bit_extract.add_to_operands(rhs); - bit_extract.add_to_operands(offset_constant); + exprt bit_extract = extractbit_exprt{rhs, offset_constant}; ++offset; assignment_rec(*it, bit_extract, blocking); @@ -649,8 +652,7 @@ void verilog_synthesist::assignment_rec( { assert(value_map!=NULL); - exprt new_rhs(rhs), new_value; - assignment_rec(lhs, new_rhs, new_value); // start of recursion + auto new_value = assignment_rec(lhs, rhs); // start of recursion if(new_value.is_not_nil()) { @@ -683,15 +685,11 @@ Function: verilog_synthesist::assignment_rec \*******************************************************************/ -void verilog_synthesist::assignment_rec( - const exprt &lhs, - exprt &rhs, - exprt &new_value) +exprt verilog_synthesist::assignment_rec(const exprt &lhs, const exprt &rhs) { if(lhs.id()==ID_symbol) { - new_value.swap(rhs); - rhs.clear(); + return rhs; } else if(lhs.id()==ID_index || lhs.id()==ID_extractbit) @@ -718,7 +716,7 @@ void verilog_synthesist::assignment_rec( new_rhs.where() = synth_expr(new_rhs.where(), symbol_statet::CURRENT); // do the value - assignment_rec(lhs_array, new_rhs, new_value); // recursive call + return assignment_rec(lhs_array, new_rhs); // recursive call } else if(lhs.id() == ID_verilog_non_indexed_part_select) { @@ -749,8 +747,7 @@ void verilog_synthesist::assignment_rec( // redundant? if(from == 0 && to == get_width(lhs_src.type()) - 1) { - assignment_rec(lhs_src, rhs, new_value); // recursive call - return; + return assignment_rec(lhs_src, rhs); // recursive call } // turn @@ -777,39 +774,26 @@ void verilog_synthesist::assignment_rec( { exprt offset = from_integer(i - from, integer_typet()); - exprt rhs_extractbit(ID_extractbit, bool_typet()); - rhs_extractbit.reserve_operands(2); - rhs_extractbit.add_to_operands(rhs); - rhs_extractbit.add_to_operands(std::move(offset)); + exprt rhs_extractbit = extractbit_exprt{rhs, std::move(offset)}; exprt count = from_integer(i, integer_typet()); - exprt new_rhs(ID_with, lhs_src.type()); - new_rhs.reserve_operands(3); - new_rhs.add_to_operands(synth_lhs_src); - new_rhs.add_to_operands(std::move(count)); - new_rhs.add_to_operands(std::move(rhs_extractbit)); + exprt new_rhs = + with_exprt{synth_lhs_src, std::move(count), std::move(rhs_extractbit)}; // do the value - assignment_rec(lhs_src, new_rhs, new_value); // recursive call + exprt new_value = assignment_rec(lhs_src, new_rhs); // recursive call - if(last_value.is_nil()) - last_value.swap(new_value); - else + if(last_value.is_not_nil()) { - // merge the withs - assert(new_value.id() == ID_with); - assert(new_value.operands().size() == 3); - assert(last_value.id() == ID_with); - assert(last_value.operands().size() >= 3); - - last_value.add_to_operands(std::move(to_with_expr(new_value).where())); - last_value.add_to_operands( - std::move(to_with_expr(new_value).new_value())); + // chain the withs + to_with_expr(new_value).old() = std::move(last_value); } + + last_value = std::move(new_value); } - new_value.swap(last_value); + return last_value; } else if( lhs.id() == ID_verilog_indexed_part_select_plus || @@ -864,39 +848,26 @@ void verilog_synthesist::assignment_rec( { exprt offset = from_integer(i - index, integer_typet()); - exprt rhs_extractbit(ID_extractbit, bool_typet()); - rhs_extractbit.reserve_operands(2); - rhs_extractbit.add_to_operands(rhs); - rhs_extractbit.add_to_operands(std::move(offset)); + exprt rhs_extractbit = extractbit_exprt{rhs, std::move(offset)}; exprt count = from_integer(i, integer_typet()); - exprt new_rhs(ID_with, lhs_src.type()); - new_rhs.reserve_operands(3); - new_rhs.add_to_operands(synth_lhs_src); - new_rhs.add_to_operands(std::move(count)); - new_rhs.add_to_operands(std::move(rhs_extractbit)); + exprt new_rhs = + with_exprt{synth_lhs_src, std::move(count), std::move(rhs_extractbit)}; // do the value - assignment_rec(lhs_src, new_rhs, new_value); // recursive call + exprt new_value = assignment_rec(lhs_src, new_rhs); // recursive call - if(last_value.is_nil()) - last_value.swap(new_value); - else + if(last_value.is_not_nil()) { - // merge the withs - assert(new_value.id() == ID_with); - assert(new_value.operands().size() == 3); - assert(last_value.id() == ID_with); - assert(last_value.operands().size() >= 3); - - last_value.add_to_operands(std::move(to_with_expr(new_value).where())); - last_value.add_to_operands( - std::move(to_with_expr(new_value).new_value())); + // chain the withs + to_with_expr(new_value).old() = std::move(last_value); } + + last_value = std::move(new_value); } - new_value.swap(last_value); + return last_value; } else if(lhs.id() == ID_member) { @@ -918,7 +889,7 @@ void verilog_synthesist::assignment_rec( synth_compound, member_designatort{component_name}, rhs}; // recursive call - assignment_rec(lhs_compound, new_rhs, new_value); // recursive call + return assignment_rec(lhs_compound, new_rhs); // recursive call } else { @@ -929,24 +900,6 @@ void verilog_synthesist::assignment_rec( { throw errort() << "unexpected lhs: " << lhs.id(); } - - #if 0 - // do "with" merging - - if(new_value.id()==ID_with && - new_value.op0().id()==ID_with) - { - exprt tmp; - - tmp.swap(new_value.op0()); - - tmp.reserve_operands(tmp.operands().size()+2); - tmp.add_to_operands(std::move(new_value.op1())); - tmp.add_to_operands(std::move(new_value.op2())); - - new_value.swap(tmp); - } - #endif } /*******************************************************************\ @@ -2337,6 +2290,7 @@ void verilog_synthesist::synth_assert_assume_cover( // one of the 'always' variants -- assertions and assumptions have an implicit 'always' if( statement.id() != ID_verilog_cover_property && + statement.id() != ID_verilog_cover_sequence && statement.id() != ID_verilog_immediate_cover) { if(cond_for_comment.id() != ID_sva_always) @@ -2353,7 +2307,9 @@ void verilog_synthesist::synth_assert_assume_cover( { cond_for_comment = sva_assume_exprt(cond_for_comment); } - else if(statement.id() == ID_verilog_cover_property) + else if( + statement.id() == ID_verilog_cover_property || + statement.id() == ID_verilog_cover_sequence) { // 'cover' properties are existential cond_for_comment = sva_cover_exprt(cond_for_comment); @@ -2393,6 +2349,7 @@ void verilog_synthesist::synth_assert_assume_cover( // assertions and assumptions have an implicit 'always' if( statement.id() != ID_verilog_cover_property && + statement.id() != ID_verilog_cover_sequence && statement.id() != ID_verilog_immediate_cover) { if(cond.id() != ID_sva_always) @@ -2412,14 +2369,25 @@ void verilog_synthesist::synth_assert_assume_cover( else if(statement.id() == ID_verilog_cover_property) { // 'cover' properties are existential - cond = sva_cover_exprt(cond); + cond = sva_cover_exprt{cond}; + } + else if(statement.id() == ID_verilog_cover_sequence) + { + // 'cover' properties are existential + cond = sva_cover_exprt{sva_sequence_property_exprt{cond}}; } // 1800-2017 16.12.2 Sequence property - if(statement.id() == ID_verilog_cover_property) + if( + statement.id() == ID_verilog_cover_property || + statement.id() == ID_verilog_cover_sequence) + { set_default_sequence_semantics(cond, sva_sequence_semanticst::STRONG); + } else + { set_default_sequence_semantics(cond, sva_sequence_semanticst::WEAK); + } symbol.value = std::move(cond); } @@ -2456,7 +2424,9 @@ void verilog_synthesist::synth_assert_assume_cover( if(cond_for_comment.id() != ID_sva_always) cond_for_comment = sva_always_exprt{cond_for_comment}; } - else if(module_item.id() == ID_verilog_cover_property) + else if( + module_item.id() == ID_verilog_cover_property || + module_item.id() == ID_verilog_cover_sequence) { // 'cover' requirements are existential. cond_for_comment = sva_cover_exprt{cond_for_comment}; @@ -2493,14 +2463,25 @@ void verilog_synthesist::synth_assert_assume_cover( // 'cover' requirements are existential. cond = sva_cover_exprt{cond}; } + else if(module_item.id() == ID_verilog_cover_sequence) + { + // 'cover' requirements are existential. + cond = sva_cover_exprt{sva_sequence_property_exprt{cond}}; + } else PRECONDITION(false); // 1800-2017 16.12.2 Sequence property - if(module_item.id() == ID_verilog_cover_property) + if( + module_item.id() == ID_verilog_cover_property || + module_item.id() == ID_verilog_cover_sequence) + { set_default_sequence_semantics(cond, sva_sequence_semanticst::STRONG); + } else + { set_default_sequence_semantics(cond, sva_sequence_semanticst::WEAK); + } symbol.value = std::move(cond); } @@ -3113,21 +3094,15 @@ Function: verilog_synthesist::synth_function_call_or_task_enable void verilog_synthesist::synth_function_call_or_task_enable( const verilog_function_callt &statement) { - // this is essentially inlined - const symbol_exprt &function=to_symbol_expr(statement.function()); - - irep_idt identifier=function.get_identifier(); - - // We ignore everyting that starts with a '$', - // e.g., $display etc - - if(!identifier.empty() && identifier[0]=='$') + if(statement.is_system_function_call()) { - // ignore + // ignore system functions } else { - const symbolt &symbol=ns.lookup(identifier); + // this is essentially inlined + const symbol_exprt &function = to_symbol_expr(statement.function()); + const symbolt &symbol = ns.lookup(function); if(symbol.type.id()!=ID_code) { @@ -3233,7 +3208,8 @@ void verilog_synthesist::synth_statement( statement.id() == ID_verilog_immediate_assert || statement.id() == ID_verilog_assert_property || statement.id() == ID_verilog_smv_assert || - statement.id() == ID_verilog_cover_property) + statement.id() == ID_verilog_cover_property || + statement.id() == ID_verilog_cover_sequence) { synth_assert_assume_cover( to_verilog_assert_assume_cover_statement(statement)); @@ -3369,7 +3345,8 @@ void verilog_synthesist::synth_module_item( } else if( module_item.id() == ID_verilog_assert_property || - module_item.id() == ID_verilog_cover_property) + module_item.id() == ID_verilog_cover_property || + module_item.id() == ID_verilog_cover_sequence) { synth_assert_assume_cover( to_verilog_assert_assume_cover_module_item(module_item)); @@ -3424,6 +3401,9 @@ void verilog_synthesist::synth_module_item( else if(module_item.id() == ID_verilog_sequence_declaration) { } + else if(module_item.id() == ID_function_call) + { + } else { throw errort().with_location(module_item.source_location()) diff --git a/src/verilog/verilog_synthesis_class.h b/src/verilog/verilog_synthesis_class.h index 7f411bfd7..d332f2c6b 100644 --- a/src/verilog/verilog_synthesis_class.h +++ b/src/verilog/verilog_synthesis_class.h @@ -222,10 +222,7 @@ class verilog_synthesist: void assignment_rec(const exprt &lhs, const exprt &rhs, bool blocking); - void assignment_rec( - const exprt &lhs, - exprt &rhs, - exprt &new_value); + exprt assignment_rec(const exprt &lhs, const exprt &rhs); const symbolt &assignment_symbol(const exprt &lhs); diff --git a/src/verilog/verilog_typecheck.cpp b/src/verilog/verilog_typecheck.cpp index b328b2f37..1bb902c52 100644 --- a/src/verilog/verilog_typecheck.cpp +++ b/src/verilog/verilog_typecheck.cpp @@ -27,34 +27,6 @@ Author: Daniel Kroening, kroening@kroening.com /*******************************************************************\ -Function: verilog_typecheckt::assignment_conversion - - Inputs: - - Outputs: - - Purpose: - -\*******************************************************************/ - -void verilog_typecheckt::assignment_conversion( - exprt &rhs, - const typet &lhs_type) -{ - // Implements 1800-2017 10.7 - // If the RHS is smaller than the LHS: - // * if the RHS is unsigned, it is zero-padded - // * if the RHS is signed, it is sign-extended - // If the RHS is larger than the LHS, it is truncated. - - // This matches our typecast, but differs from the steps taken - // when evaluating binary expressions (11.8.2), where sign - // extension only happens when the propagated type is signed. - implicit_typecast(rhs, lhs_type); -} - -/*******************************************************************\ - Function: verilog_typecheckt::typecheck_port_connection Inputs: @@ -88,11 +60,12 @@ void verilog_typecheckt::typecheck_port_connection( { // IEEE 1800 2017 6.10 allows implicit declarations of nets when // used in a port connection. - if(op.id() == ID_symbol) + if(op.id() == ID_verilog_identifier) { // The type of the implicit net is _not_ the type of the port, // but an "implicit scalar net of default net type". - op = convert_symbol(to_symbol_expr(op), bool_typet{}); + op = convert_verilog_identifier( + to_verilog_identifier_expr(op), bool_typet{}); } else { @@ -161,25 +134,27 @@ void verilog_typecheckt::typecheck_port_connections( to_verilog_named_port_connection(connection); exprt &value = named_port_connection.value(); - const irep_idt &name = named_port_connection.port().get(ID_identifier); + const irep_idt &base_name = + to_verilog_identifier_expr(named_port_connection.port()).base_name(); bool found=false; - std::string identifier= - id2string(symbol.module)+"."+id2string(name); + std::string full_identifier = + id2string(symbol.module) + "." + id2string(base_name); - named_port_connection.port().set(ID_identifier, identifier); + named_port_connection.port() = + symbol_exprt{full_identifier, typet{}}.with_source_location( + named_port_connection.port()); - if(assigned_ports.find(name)!= - assigned_ports.end()) + if(assigned_ports.find(base_name) != assigned_ports.end()) { throw errort().with_location(connection.source_location()) - << "port name " << name << " assigned twice"; + << "port name " << base_name << " assigned twice"; } for(auto &port : ports) { - if(port.get(ID_identifier) == identifier) + if(port.identifier() == full_identifier) { found=true; typecheck_port_connection(value, port); @@ -191,10 +166,10 @@ void verilog_typecheckt::typecheck_port_connections( if(!found) { throw errort().with_location(connection.source_location()) - << "port name " << identifier << " not found"; + << "port name " << base_name << " not found"; } - assigned_ports.insert(identifier); + assigned_ports.insert(base_name); } } else // just a list without names @@ -259,11 +234,12 @@ void verilog_typecheckt::typecheck_builtin_port_connections( { // IEEE 1800 2017 6.10 allows implicit declarations of nets when // used in a port connection. - if(connection.id() == ID_symbol) + if(connection.id() == ID_verilog_identifier) { // The type of the implicit net is _not_ the type of the port, // but an "implicit scalar net of default net type". - connection = convert_symbol(to_symbol_expr(connection), bool_typet{}); + connection = convert_verilog_identifier( + to_verilog_identifier_expr(connection), bool_typet{}); } else { @@ -494,13 +470,27 @@ void verilog_typecheckt::convert_inst(verilog_instt &inst) if(it->id()==ID_named_parameter_assignment) { auto &value = static_cast(it->add(ID_value)); - mp_integer v_int = convert_integer_constant_expression(value); - value = from_integer(v_int, integer_typet()).with_source_location(*it); + if(value.id() == ID_type) + { + // leave as is + } + else + { + mp_integer v_int = convert_integer_constant_expression(value); + value = from_integer(v_int, integer_typet()).with_source_location(*it); + } } else { - mp_integer v_int = convert_integer_constant_expression(*it); - *it = from_integer(v_int, integer_typet()).with_source_location(*it); + if(it->id() == ID_type) + { + // leave as is + } + else + { + mp_integer v_int = convert_integer_constant_expression(*it); + *it = from_integer(v_int, integer_typet()).with_source_location(*it); + } } } @@ -788,6 +778,11 @@ void verilog_typecheckt::check_lhs( { check_lhs(to_member_expr(lhs).struct_op(), vassign); } + else if(lhs.id() == ID_verilog_assignment_pattern) + { + throw errort().with_location(lhs.source_location()) + << "no support for assignment patterns on LHS of an assignment"; + } else { throw errort() << "typechecking: failed to get identifier on LHS " @@ -866,8 +861,9 @@ void verilog_typecheckt::convert_continuous_assign( // from the RHS, and hence, we convert that first. convert_expr(rhs); - if(lhs.id() == ID_symbol) - lhs = convert_symbol(to_symbol_expr(lhs), rhs.type()); + if(lhs.id() == ID_verilog_identifier) + lhs = + convert_verilog_identifier(to_verilog_identifier_expr(lhs), rhs.type()); else convert_expr(lhs); @@ -892,17 +888,15 @@ Function: verilog_typecheckt::convert_function_call_or_task_enable void verilog_typecheckt::convert_function_call_or_task_enable( verilog_function_callt &statement) { - irep_idt base_name= - to_symbol_expr(statement.function()).get_identifier(); - - // We ignore everyting that starts with a '$', - // e.g., $display etc - - if(!base_name.empty() && base_name[0]=='$') + if(statement.is_system_function_call()) { + // we ignore all of these } else { + irep_idt base_name = + to_verilog_identifier_expr(statement.function()).base_name(); + // look it up const irep_idt full_identifier = id2string(module_identifier) + "." + id2string(base_name); @@ -938,8 +932,8 @@ void verilog_typecheckt::convert_function_call_or_task_enable( assignment_conversion(arguments[i], parameter_types[i].type()); } - statement.function().type() = symbol->type; - statement.function().set(ID_identifier, symbol->name); + statement.function() = + symbol->symbol_expr().with_source_location(statement.function()); } } @@ -985,14 +979,14 @@ void verilog_typecheckt::convert_parameter_override( auto module_instance = to_symbol_expr(hierarchical_identifier.module()).get_identifier(); - auto parameter_name = hierarchical_identifier.item().get_identifier(); + auto parameter_base_name = hierarchical_identifier.item().base_name(); // The rhs must be a constant at this point. auto rhs_value = from_integer(convert_integer_constant_expression(rhs), integer_typet()); - // store the assignment - defparams[module_instance][parameter_name] = rhs_value; + // store the assignment. + defparams[module_instance][parameter_base_name] = rhs_value; } } @@ -1047,8 +1041,8 @@ void verilog_typecheckt::convert_assign( convert_expr(lhs); convert_expr(rhs); - assignment_conversion(rhs, lhs.type()); check_lhs(lhs, blocking?A_BLOCKING:A_NON_BLOCKING); + assignment_conversion(rhs, lhs.type()); } /*******************************************************************\ @@ -1069,28 +1063,29 @@ void verilog_typecheckt::convert_assert_assume_cover( exprt &cond = module_item.condition(); convert_sva(cond); - require_sva_property(cond); + + if(module_item.id() == ID_verilog_cover_sequence) + require_sva_sequence(cond); + else + require_sva_property(cond); // We create a symbol for the property. // The 'value' of the symbol is set by synthesis. - const irep_idt &identifier = module_item.identifier(); - - irep_idt base_name; + irep_idt base_name = module_item.base_name(); // The label is optional. - if(identifier == irep_idt()) + if(base_name == irep_idt{}) { std::string kind = module_item.id() == ID_verilog_assert_property ? "assert" : module_item.id() == ID_verilog_assume_property ? "assume" : module_item.id() == ID_verilog_cover_property ? "cover" + : module_item.id() == ID_verilog_cover_sequence ? "cover" : ""; assertion_counter++; - base_name = kind + "." + std::to_string(assertion_counter); + base_name = kind + '.' + std::to_string(assertion_counter); } - else - base_name = identifier; // The assert/assume/cover module items use the module name space std::string full_identifier = @@ -1134,20 +1129,23 @@ void verilog_typecheckt::convert_assert_assume_cover( exprt &cond = statement.condition(); convert_sva(cond); - require_sva_property(cond); + + if(statement.id() == ID_verilog_cover_sequence) + require_sva_sequence(cond); + else + require_sva_property(cond); // We create a symbol for the property. // The 'value' is set by synthesis. - const irep_idt &identifier = statement.identifier(); + irep_idt base_name = statement.base_name(); - irep_idt base_name; - - if(identifier == irep_idt()) + if(base_name == irep_idt{}) { std::string kind = statement.id() == ID_verilog_immediate_assert ? "assert" : statement.id() == ID_verilog_assert_property ? "assert" : statement.id() == ID_verilog_smv_assert ? "assert" : statement.id() == ID_verilog_cover_property ? "cover" + : statement.id() == ID_verilog_cover_sequence ? "cover" : statement.id() == ID_verilog_immediate_assume ? "assume" : statement.id() == ID_verilog_assume_property ? "assume" @@ -1155,10 +1153,8 @@ void verilog_typecheckt::convert_assert_assume_cover( : ""; assertion_counter++; - base_name = kind + "." + std::to_string(assertion_counter); + base_name = kind + '.' + std::to_string(assertion_counter); } - else - base_name = identifier; // We produce a full hierarchical identifier for the SystemVerilog immediate // and concurrent assertion statements. @@ -1235,7 +1231,7 @@ void verilog_typecheckt::convert_case_values( // This works like a relational operator, not like an assignment typet t=max_type(it->type(), case_operand.type()); - propagate_type(*it, t); + downwards_type_propagation(*it, t); } } @@ -1553,7 +1549,8 @@ void verilog_typecheckt::convert_statement( statement.id() == ID_verilog_immediate_assert || statement.id() == ID_verilog_assert_property || statement.id() == ID_verilog_smv_assert || - statement.id() == ID_verilog_cover_property) + statement.id() == ID_verilog_cover_property || + statement.id() == ID_verilog_cover_sequence) { convert_assert_assume_cover( to_verilog_assert_assume_cover_statement(statement)); @@ -1569,9 +1566,6 @@ void verilog_typecheckt::convert_statement( { convert_assert_assume_cover(to_verilog_assume_statement(statement)); } - else if(statement.id() == ID_verilog_cover_property) - { - } else if(statement.id() == ID_verilog_non_blocking_assign) convert_assign(to_verilog_assign(statement), false); else if(statement.id()==ID_if) @@ -1613,9 +1607,10 @@ void verilog_typecheckt::convert_statement( sub_statement.id() == ID_verilog_assert_property || sub_statement.id() == ID_verilog_assume_property || sub_statement.id() == ID_verilog_restrict_property || + sub_statement.id() == ID_verilog_cover_sequence || sub_statement.id() == ID_verilog_cover_property) { - sub_statement.set(ID_identifier, label_statement.label()); + sub_statement.set(ID_base_name, label_statement.label()); } convert_statement(sub_statement); @@ -1692,7 +1687,8 @@ void verilog_typecheckt::convert_module_item( module_item.id() == ID_verilog_assert_property || module_item.id() == ID_verilog_assume_property || module_item.id() == ID_verilog_restrict_property || - module_item.id() == ID_verilog_cover_property) + module_item.id() == ID_verilog_cover_property || + module_item.id() == ID_verilog_cover_sequence) { convert_assert_assume_cover( to_verilog_assert_assume_cover_module_item(module_item)); @@ -1787,6 +1783,9 @@ void verilog_typecheckt::convert_module_item( { convert_sequence_declaration(to_verilog_sequence_declaration(module_item)); } + else if(module_item.id() == ID_function_call) + { + } else { throw errort().with_location(module_item.source_location()) @@ -1812,17 +1811,19 @@ void verilog_typecheckt::convert_property_declaration( auto base_name = declaration.base_name(); auto full_identifier = hierarchical_identifier(base_name); - convert_sva(declaration.cond()); - require_sva_property(declaration.cond()); + // 1800-2017 F.4.1 + // Typechecking of the property expression has to be delayed + // until the instance is known, owing to untyped ports. + declaration.type() = verilog_sva_named_property_typet{}; - auto type = verilog_sva_property_typet{}; + // The symbol uses the full declaration as value + auto type = verilog_sva_named_property_typet{}; symbolt symbol{full_identifier, type, mode}; symbol.module = module_identifier; symbol.base_name = base_name; symbol.pretty_name = strip_verilog_prefix(symbol.name); - symbol.is_macro = true; - symbol.value = declaration.cond(); + symbol.value = declaration; symbol.location = declaration.source_location(); add_symbol(std::move(symbol)); @@ -1846,17 +1847,19 @@ void verilog_typecheckt::convert_sequence_declaration( auto base_name = declaration.base_name(); auto full_identifier = hierarchical_identifier(base_name); - auto &sequence = declaration.sequence(); - convert_sva(sequence); - require_sva_sequence(sequence); + // 1800-2017 F.4.1 + // Typechecking of the sequence expression has to be delayed + // until the instance is known, owing to untyped ports. + declaration.type() = verilog_sva_named_sequence_typet{}; - symbolt symbol{full_identifier, sequence.type(), mode}; + // The symbol uses the full declaration as value + auto type = verilog_sva_named_sequence_typet{}; + symbolt symbol{full_identifier, type, mode}; symbol.module = module_identifier; symbol.base_name = base_name; symbol.pretty_name = strip_verilog_prefix(symbol.name); - symbol.is_macro = true; - symbol.value = declaration.sequence(); + symbol.value = declaration; symbol.location = declaration.source_location(); add_symbol(std::move(symbol)); diff --git a/src/verilog/verilog_typecheck.h b/src/verilog/verilog_typecheck.h index ffa6cd276..4d0ce747b 100644 --- a/src/verilog/verilog_typecheck.h +++ b/src/verilog/verilog_typecheck.h @@ -168,8 +168,6 @@ class verilog_typecheckt: void convert_assert_assume_cover(verilog_assert_assume_cover_statementt &); void convert_assume(verilog_assume_statementt &); - void assignment_conversion(exprt &rhs, const typet &lhs_type); - // module items void convert_decl(class verilog_declt &); void convert_function_or_task(class verilog_function_or_task_declt &); diff --git a/src/verilog/verilog_typecheck_expr.cpp b/src/verilog/verilog_typecheck_expr.cpp index 9d470554b..015e1b961 100644 --- a/src/verilog/verilog_typecheck_expr.cpp +++ b/src/verilog/verilog_typecheck_expr.cpp @@ -23,6 +23,7 @@ Author: Daniel Kroening, kroening@kroening.com #include "aval_bval_encoding.h" #include "convert_literals.h" #include "expr2verilog.h" +#include "typename.h" #include "verilog_bits.h" #include "verilog_expr.h" #include "verilog_lowering.h" @@ -89,7 +90,7 @@ void verilog_typecheck_exprt::enter_named_block(const irep_idt &name) /*******************************************************************\ -Function: verilog_typecheck_exprt::propagate_type +Function: verilog_typecheck_exprt::assignment_conversion Inputs: @@ -99,125 +100,222 @@ Function: verilog_typecheck_exprt::propagate_type \*******************************************************************/ -void verilog_typecheck_exprt::propagate_type( - exprt &expr, - const typet &type) +void verilog_typecheck_exprt::assignment_conversion( + exprt &rhs, + const typet &lhs_type) { - auto &verilog_dest_type = type.get(ID_C_verilog_type); + // 1800-2017 10.9 + if(rhs.type().id() == ID_verilog_assignment_pattern) + { + DATA_INVARIANT( + rhs.id() == ID_verilog_assignment_pattern, + "verilog_assignment_pattern expression expected"); + + if(lhs_type.id() == ID_struct) + { + auto &struct_type = to_struct_type(lhs_type); + auto &components = struct_type.components(); + + if( + !rhs.operands().empty() && + rhs.operands().front().id() == ID_member_initializer) + { + exprt::operandst initializers{components.size(), nil_exprt{}}; + + for(auto &op : rhs.operands()) + { + PRECONDITION(op.id() == ID_member_initializer); + auto member_name = op.get(ID_member_name); + if(!struct_type.has_component(member_name)) + { + throw errort().with_location(op.source_location()) + << "struct does not have a member `" << member_name << "'"; + } + auto nr = struct_type.component_number(member_name); + auto value = to_unary_expr(op).op(); + // rec. call + assignment_conversion(value, components[nr].type()); + initializers[nr] = std::move(value); + } + + // Is every member covered? + for(std::size_t i = 0; i < components.size(); i++) + if(initializers[i].is_nil()) + { + throw errort().with_location(rhs.source_location()) + << "assignment pattern does not assign member `" + << components[i].get_name() << "'"; + } + + rhs = struct_exprt{std::move(initializers), struct_type} + .with_source_location(rhs.source_location()); + } + else + { + if(rhs.operands().size() != components.size()) + { + throw errort().with_location(rhs.source_location()) + << "number of expressions does not match number of struct members"; + } + + for(std::size_t i = 0; i < components.size(); i++) + { + // rec. call + assignment_conversion(rhs.operands()[i], components[i].type()); + } + + // turn into struct expression + rhs.id(ID_struct); + rhs.type() = lhs_type; + } + + return; + } + else if(lhs_type.id() == ID_array) + { + auto &array_type = to_array_type(lhs_type); + auto &element_type = array_type.element_type(); + auto array_size = + numeric_cast_v(to_constant_expr(array_type.size())); + + if(array_size != rhs.operands().size()) + { + throw errort().with_location(rhs.source_location()) + << "number of expressions does not match number of array elements"; + } + + for(std::size_t i = 0; i < array_size; i++) + { + // rec. call + assignment_conversion(rhs.operands()[i], element_type); + } + + // turn into array expression + rhs.id(ID_array); + rhs.type() = lhs_type; + return; + } + else + { + throw errort().with_location(rhs.source_location()) + << "cannot convert assignment pattern to '" << to_string(lhs_type) + << '\''; + } + } + + auto original_rhs_type = rhs.type(); // copy + + auto &verilog_dest_type = lhs_type.get(ID_C_verilog_type); if(verilog_dest_type == ID_verilog_enum) { // IEEE 1800-2017 6.19.3: "a variable of type enum cannot be directly // assigned a value that lies outside the enumeration set unless an // explicit cast is used" if( - expr.type().get(ID_C_verilog_type) != ID_verilog_enum || - expr.type().get(ID_C_identifier) != type.get(ID_C_identifier)) + rhs.type().get(ID_C_verilog_type) != ID_verilog_enum || + rhs.type().get(ID_C_identifier) != lhs_type.get(ID_C_identifier)) { - throw errort().with_location(expr.source_location()) + throw errort().with_location(rhs.source_location()) << "assignment to enum requires enum of the same type, but got " - << to_string(expr.type()); + << to_string(rhs.type()); } } - if(expr.type()==type) + if(lhs_type == rhs.type()) return; - if(expr.type().id() == ID_verilog_sva_sequence) + if(lhs_type.id() == ID_struct && !lhs_type.get_bool(ID_packed)) { - throw errort{}.with_location(expr.source_location()) - << "cannot use SVA sequence as an expression"; + // assignment of a non-matching type to unpacked struct + throw errort().with_location(rhs.source_location()) + << "failed to convert `" << to_string(original_rhs_type) << "' to `" + << to_string(lhs_type) << "'"; } - else if(expr.type().id() == ID_verilog_sva_property) + + // do enum, union and struct decay + enum_decay(rhs); + struct_decay(rhs); + union_decay(rhs); + + if(rhs.type().id() == ID_struct || rhs.type().id() == ID_union) { - throw errort{}.with_location(expr.source_location()) - << "cannot use SVA property as an expression"; + // not decayed, not equal + throw errort().with_location(rhs.source_location()) + << "failed to convert `" << to_string(original_rhs_type) << "' to `" + << to_string(lhs_type) << "'"; } - vtypet vt_from=vtypet(expr.type()); - vtypet vt_to =vtypet(type); + // Implements 1800-2017 10.7 and 1800-2017 11.8.3. - if(!vt_from.is_other() && !vt_to.is_other() && - expr.has_operands()) + if( + lhs_type.id() == ID_verilog_real || lhs_type.id() == ID_verilog_shortreal || + lhs_type.id() == ID_verilog_realtime || + rhs.type().id() == ID_verilog_real || + rhs.type().id() == ID_verilog_shortreal) { - // arithmetic + // from/to real is just a cast + rhs = typecast_exprt::conditional_cast(rhs, lhs_type); + return; + } + if(rhs.type().id() == ID_verilog_null) + { if( - expr.id() == ID_plus || expr.id() == ID_minus || expr.id() == ID_mult || - expr.id() == ID_div || expr.id() == ID_unary_minus || - expr.id() == ID_unary_plus) + lhs_type.id() == ID_verilog_chandle || + lhs_type.id() == ID_verilog_class_type || + lhs_type.id() == ID_verilog_event) { - if(type.id()!=ID_bool) - { - Forall_operands(it, expr) - propagate_type(*it, type); - - expr.type()=type; - - return; - } + rhs = typecast_exprt{rhs, lhs_type}; + return; } - else if(expr.id()==ID_bitand || - expr.id()==ID_bitor || - expr.id()==ID_bitnand || - expr.id()==ID_bitnor || - expr.id()==ID_bitxor || - expr.id()==ID_bitxnor || - expr.id()==ID_bitnot) + } + + if(rhs.type().id() == ID_verilog_new) + { + if(lhs_type.id() == ID_verilog_class_type) { - Forall_operands(it, expr) - propagate_type(*it, type); + rhs = typecast_exprt{rhs, lhs_type}; + return; + } + } - expr.type()=type; + // "The size of the left-hand side of an assignment forms + // the context for the right-hand expression." - if(type.id()==ID_bool) - { - if(expr.id()==ID_bitand) - expr.id(ID_and); - else if(expr.id()==ID_bitor) - expr.id(ID_or); - else if(expr.id()==ID_bitnand) - expr.id(ID_nand); - else if(expr.id()==ID_bitnor) - expr.id(ID_nor); - else if(expr.id()==ID_bitxor) - expr.id(ID_xor); - else if(expr.id()==ID_bitxnor) - expr.id(ID_xnor); - else if(expr.id()==ID_bitnot) - expr.id(ID_not); - } + // Get the width of LHS and RHS + auto lhs_width = get_width(lhs_type); + auto rhs_width = get_width(rhs.type()); - return; - } - else if(expr.id()==ID_if) + if(lhs_width > rhs_width) + { + // Need to enlarge the RHS. + // + // "If needed, extend the size of the right-hand side, + // performing sign extension if, and only if, the type + // of the right-hand side is signed. + if( + (rhs.type().id() == ID_signedbv || + rhs.type().id() == ID_verilog_signedbv) && + (lhs_type.id() == ID_unsignedbv || + lhs_type.id() == ID_verilog_unsignedbv)) { - if(expr.operands().size()==3) - { - propagate_type(to_if_expr(expr).true_case(), type); - propagate_type(to_if_expr(expr).false_case(), type); + // LHS is unsigned, RHS is signed. Must sign-extend. + auto new_rhs_type = to_bitvector_type(rhs.type()); + new_rhs_type.set_width(numeric_cast_v(lhs_width)); - expr.type()=type; - return; - } - } - else if(expr.id()==ID_shl) // does not work with shr - { - // does not work with boolean - if(type.id()!=ID_bool) - { - if(expr.operands().size()==2) - { - propagate_type(to_binary_expr(expr).op0(), type); - // not applicable to second operand + downwards_type_propagation(rhs, new_rhs_type); - expr.type()=type; - return; - } - } + // then cast + rhs = typecast_exprt::conditional_cast(rhs, lhs_type); } + else + downwards_type_propagation(rhs, lhs_type); + } + else + { + // no need to enlarge + rhs = typecast_exprt::conditional_cast(rhs, lhs_type); } - - implicit_typecast(expr, type); } /*******************************************************************\ @@ -241,95 +339,69 @@ void verilog_typecheck_exprt::downwards_type_propagation( // Any context-determined operand of an operator shall be the // same type and size as the result of the operator. - // Exceptions: - // * result type real -- just cast - // * relational operators are always 1 bit unsigned + // As an exception, if the result type is real, the operands + // are just casted. if(expr.type() == type) return; - vtypet vt_from = vtypet(expr.type()); - vtypet vt_to = vtypet(type); - - if(!vt_from.is_other() && !vt_to.is_other() && expr.has_operands()) + if(type.id() == ID_verilog_real || type.id() == ID_verilog_shortreal) { - // arithmetic - - if( - expr.id() == ID_plus || expr.id() == ID_minus || expr.id() == ID_mult || - expr.id() == ID_div || expr.id() == ID_unary_minus || - expr.id() == ID_unary_plus) - { - if(type.id() != ID_bool) - { - Forall_operands(it, expr) - propagate_type(*it, type); - - expr.type() = type; - - return; - } - } - else if( - expr.id() == ID_bitand || expr.id() == ID_bitor || - expr.id() == ID_bitnand || expr.id() == ID_bitnor || - expr.id() == ID_bitxor || expr.id() == ID_bitxnor || - expr.id() == ID_bitnot) - { - Forall_operands(it, expr) - propagate_type(*it, type); - - expr.type() = type; - - if(type.id() == ID_bool) - { - if(expr.id() == ID_bitand) - expr.id(ID_and); - else if(expr.id() == ID_bitor) - expr.id(ID_or); - else if(expr.id() == ID_bitnand) - expr.id(ID_nand); - else if(expr.id() == ID_bitnor) - expr.id(ID_nor); - else if(expr.id() == ID_bitxor) - expr.id(ID_xor); - else if(expr.id() == ID_bitxnor) - expr.id(ID_xnor); - else if(expr.id() == ID_bitnot) - expr.id(ID_not); - } - - return; - } - else if(expr.id() == ID_if) - { - if(expr.operands().size() == 3) - { - propagate_type(to_if_expr(expr).true_case(), type); - propagate_type(to_if_expr(expr).false_case(), type); - - expr.type() = type; - return; - } - } - else if(expr.id() == ID_shl) // does not work with shr - { - // does not work with boolean - if(type.id() != ID_bool) - { - if(expr.operands().size() == 2) - { - propagate_type(to_binary_expr(expr).op0(), type); - // not applicable to second operand + expr = typecast_exprt{expr, type}; + return; + } - expr.type() = type; - return; - } - } - } + // expressions with context-determined width, following + // 1800-2017 Table 11-21 + if( + expr.id() == ID_plus || expr.id() == ID_minus || expr.id() == ID_mult || + expr.id() == ID_div || expr.id() == ID_mod || expr.id() == ID_bitand || + expr.id() == ID_bitor || expr.id() == ID_bitxor || + expr.id() == ID_bitxnor || expr.id() == ID_unary_plus || + expr.id() == ID_unary_minus || expr.id() == ID_bitnot) + { + // All operands are context-determined. + for(auto &op : expr.operands()) + downwards_type_propagation(op, type); + expr.type() = type; + return; + } + else if( + expr.id() == ID_shl || expr.id() == ID_ashr || expr.id() == ID_lshr || + expr.id() == ID_power) + { + // The LHS is context-determined, the RHS is self-determined + auto &binary_expr = to_binary_expr(expr); + downwards_type_propagation(binary_expr.lhs(), type); + expr.type() = type; + return; + } + else if(expr.id() == ID_if) + { + // The first operand is self-determined, the others are context-determined + auto &if_expr = to_if_expr(expr); + downwards_type_propagation(if_expr.op1(), type); + downwards_type_propagation(if_expr.op2(), type); + expr.type() = type; + return; } - implicit_typecast(expr, type); + // Just cast the expression, leave any operands as they are. + if( + (expr.type().id() == ID_signedbv || + expr.type().id() == ID_verilog_signedbv) && + (type.id() == ID_unsignedbv || type.id() == ID_verilog_unsignedbv) && + get_width(expr.type()) < get_width(type)) + { + // "If the operand shall be extended, then it shall be sign-extended only + // if the propagated type is signed." + // A typecast from signed to a larger unsigned would sign extend. + expr = zero_extend_exprt{expr, type}; + } + else + { + expr = typecast_exprt{expr, type}; + } } /*******************************************************************\ @@ -354,7 +426,7 @@ void verilog_typecheck_exprt::no_bool_ops(exprt &expr) /*******************************************************************\ -Function: verilog_typecheck_exprt::must_be_integral +Function: verilog_typecheck_exprt::must_be_bit_vector Inputs: @@ -364,9 +436,9 @@ Function: verilog_typecheck_exprt::must_be_integral \*******************************************************************/ -void verilog_typecheck_exprt::must_be_integral(const exprt &expr) +void verilog_typecheck_exprt::must_be_bit_vector(exprt &expr) { - // Throw an error if the given expression doesn't have an integral type. + // Throw an error if the given expression doesn't have a bitvector type. const auto &type = expr.type(); if(type.id() == ID_bool) { @@ -380,7 +452,7 @@ void verilog_typecheck_exprt::must_be_integral(const exprt &expr) } else throw errort().with_location(expr.source_location()) - << "operand " << to_string(expr) << " must be integral"; + << "operand " << to_string(expr) << " must have a bit vector type"; } /*******************************************************************\ @@ -418,7 +490,7 @@ exprt verilog_typecheck_exprt::convert_expr_concatenation( << "unsized literals are not allowed in concatenations"; } - must_be_integral(*it); + must_be_bit_vector(*it); const typet &type = it->type(); @@ -552,29 +624,29 @@ exprt verilog_typecheck_exprt::convert_expr_function_call( Forall_expr(it, arguments) convert_expr(*it); - - if(expr.function().id()!=ID_symbol) + + // built-in functions + if(expr.is_system_function_call()) + return convert_system_function(expr); + + if(expr.function().id() != ID_verilog_identifier) { throw errort().with_location(expr.source_location()) - << "expected symbol as function argument"; + << "expected identifier as function"; } - - // built-in functions - symbol_exprt &f_op=to_symbol_expr(expr.function()); - - const irep_idt &identifier=f_op.get_identifier(); - - if(expr.is_system_function_call()) - return convert_system_function(identifier, expr); - std::string full_identifier= - id2string(module_identifier)+"."+id2string(identifier); + exprt &f_op = expr.function(); + + const irep_idt &base_name = to_verilog_identifier_expr(f_op).base_name(); + + std::string full_identifier = + id2string(module_identifier) + "." + id2string(base_name); const symbolt *symbol; if(ns.lookup(full_identifier, symbol)) { throw errort().with_location(f_op.source_location()) - << "unknown function `" << identifier << "'"; + << "unknown function `" << base_name << "'"; } if(symbol->type.id()!=ID_code) @@ -584,9 +656,8 @@ exprt verilog_typecheck_exprt::convert_expr_function_call( } const code_typet &code_type=to_code_type(symbol->type); - - f_op.type()=code_type; - f_op.set(ID_identifier, full_identifier); + + f_op = symbol->symbol_expr().with_source_location(f_op); expr.type()=code_type.return_type(); if(code_type.return_type().id()==ID_empty) @@ -605,7 +676,7 @@ exprt verilog_typecheck_exprt::convert_expr_function_call( } for(unsigned i=0; i mp_integer { - if( - type.id() == ID_unsignedbv || type.id() == ID_signedbv || - type.id() == ID_verilog_unsignedbv || type.id() == ID_verilog_signedbv || - type.id() == ID_bool) - { - auto offset = type.get_int(ID_C_offset); - if(type.get_bool(ID_C_increasing)) - return offset; - else - return offset + get_width(type) - 1; - } - else if(type.id() == ID_array) - { - auto offset = numeric_cast_v( - to_constant_expr(static_cast(type.find(ID_offset)))); - if(type.get_bool(ID_C_increasing)) - return offset; - else - { - return offset + - numeric_cast_v( - to_constant_expr(to_array_type(type).size())) - - 1; - } - } - else - return 0; - }; - - return from_integer(left(expr.type()), integer_typet{}); + return from_integer(verilog_left(expr.type()), integer_typet{}); } /*******************************************************************\ @@ -725,40 +763,7 @@ Function: verilog_typecheck_exprt::right constant_exprt verilog_typecheck_exprt::right(const exprt &expr) { - // unpacked array: right bound - // packed array: index of least significant element - // 0 otherwise - auto right = [](const typet &type) -> mp_integer { - if( - type.id() == ID_unsignedbv || type.id() == ID_signedbv || - type.id() == ID_verilog_unsignedbv || type.id() == ID_verilog_signedbv || - type.id() == ID_bool) - { - auto offset = type.get_int(ID_C_offset); - if(type.get_bool(ID_C_increasing)) - return offset + get_width(type) - 1; - else - return offset; - } - else if(type.id() == ID_array) - { - auto offset = numeric_cast_v( - to_constant_expr(static_cast(type.find(ID_offset)))); - if(type.get_bool(ID_C_increasing)) - { - return offset + - numeric_cast_v( - to_constant_expr(to_array_type(type).size())) - - 1; - } - else - return offset; - } - else - return 0; - }; - - return from_integer(right(expr.type()), integer_typet{}); + return from_integer(verilog_right(expr.type()), integer_typet{}); } /*******************************************************************\ @@ -879,84 +884,8 @@ Function: verilog_typecheck_exprt::typename_string exprt verilog_typecheck_exprt::typename_string(const exprt &expr) { - auto &type = expr.type(); - - auto left = this->left(expr); - auto right = this->right(expr); - - const auto verilog_type = type.get(ID_C_verilog_type); - - std::string s; - - if(type.id() == ID_unsignedbv) - { - if(verilog_type == ID_verilog_byte) - s = "byte unsigned"; - else if(verilog_type == ID_verilog_int) - s = "int unsigned"; - else if(verilog_type == ID_verilog_longint) - s = "longint unsigned"; - else if(verilog_type == ID_verilog_shortint) - s = "shortint unsigned"; - else - s = "bit[" + to_string(left) + ":" + to_string(right) + "]"; - } - else if(type.id() == ID_verilog_unsignedbv) - { - s = "logic[" + to_string(left) + ":" + to_string(right) + "]"; - } - else if(type.id() == ID_bool) - { - s = "bit"; - } - else if(type.id() == ID_signedbv) - { - if(verilog_type == ID_verilog_byte) - s = "byte"; - else if(verilog_type == ID_verilog_int) - s = "int"; - else if(verilog_type == ID_verilog_longint) - s = "longint"; - else if(verilog_type == ID_verilog_shortint) - s = "shortint"; - else - s = "bit signed[" + to_string(left) + ":" + to_string(right) + "]"; - } - else if(type.id() == ID_verilog_signedbv) - { - s = "logic signed[" + to_string(left) + ":" + to_string(right) + "]"; - } - else if(type.id() == ID_verilog_realtime) - { - s = "realtime"; - } - else if(type.id() == ID_verilog_real) - { - s = "real"; - } - else if(type.id() == ID_verilog_shortreal) - { - s = "shortreal"; - } - else if(type.id() == ID_verilog_chandle) - { - s = "chandle"; - } - else if(type.id() == ID_verilog_event) - { - s = "event"; - } - else if(type.id() == ID_verilog_string) - { - s = "string"; - } - else - s = "?"; - - auto result = convert_string_literal(s); - result.add_source_location() = expr.source_location(); - - return std::move(result); + auto s = verilog_typename(expr.type()); + return convert_string_literal(s).with_source_location(expr); } /*******************************************************************\ @@ -971,13 +900,13 @@ Function: verilog_typecheck_exprt::convert_system_function \*******************************************************************/ -exprt verilog_typecheck_exprt::convert_system_function( - const irep_idt &identifier, - function_call_exprt expr) +exprt verilog_typecheck_exprt::convert_system_function(function_call_exprt expr) { + auto base_name = to_verilog_identifier_expr(expr.function()).base_name(); + exprt::operandst &arguments=expr.arguments(); - if(identifier=="$signed") + if(base_name == "$signed") { // this is an explicit type cast if(arguments.size()!=1) @@ -1012,7 +941,7 @@ exprt verilog_typecheck_exprt::convert_system_function( << to_string(argument.type()) << '\''; } } - else if(identifier=="$unsigned") + else if(base_name == "$unsigned") { // this is an explicit type cast if(arguments.size()!=1) @@ -1047,7 +976,7 @@ exprt verilog_typecheck_exprt::convert_system_function( << to_string(argument.type()) << '\''; } } - else if(identifier=="$ND") + else if(base_name == "$ND") { // this is something from VIS @@ -1061,13 +990,13 @@ exprt verilog_typecheck_exprt::convert_system_function( return std::move(expr); } else if( - identifier == "$bits" || identifier == "$left" || identifier == "$right" || - identifier == "$increment" || identifier == "$low" || identifier == "$high") + base_name == "$bits" || base_name == "$left" || base_name == "$right" || + base_name == "$increment" || base_name == "$low" || base_name == "$high") { if(arguments.size() != 1) { throw errort().with_location(expr.source_location()) - << identifier << " takes one argument"; + << base_name << " takes one argument"; } // The return type is integer. @@ -1075,7 +1004,7 @@ exprt verilog_typecheck_exprt::convert_system_function( return std::move(expr); } - else if(identifier == "$countones") // SystemVerilog + else if(base_name == "$countones") // SystemVerilog { if(arguments.size() != 1) { @@ -1088,7 +1017,7 @@ exprt verilog_typecheck_exprt::convert_system_function( return std::move(expr); } - else if(identifier=="$onehot") // SystemVerilog + else if(base_name == "$onehot") // SystemVerilog { if(arguments.size()!=1) { @@ -1102,7 +1031,7 @@ exprt verilog_typecheck_exprt::convert_system_function( return std::move(onehot); } - else if(identifier=="$onehot0") // SystemVerilog + else if(base_name == "$onehot0") // SystemVerilog { if(arguments.size()!=1) { @@ -1116,7 +1045,7 @@ exprt verilog_typecheck_exprt::convert_system_function( return std::move(onehot0); } - else if(identifier == "$clog2") // Verilog-2005 + else if(base_name == "$clog2") // Verilog-2005 { if(arguments.size() != 1) { @@ -1128,7 +1057,7 @@ exprt verilog_typecheck_exprt::convert_system_function( return std::move(expr); } - else if(identifier == "$isunknown") + else if(base_name == "$isunknown") { if(arguments.size() != 1) { @@ -1140,7 +1069,7 @@ exprt verilog_typecheck_exprt::convert_system_function( return std::move(expr); } - else if(identifier == "$past") + else if(base_name == "$past") { if(arguments.size() == 0 || arguments.size() >= 4) { @@ -1159,73 +1088,73 @@ exprt verilog_typecheck_exprt::convert_system_function( return std::move(expr); } else if( - identifier == "$stable" || identifier == "$rose" || identifier == "$fell" || - identifier == "$changed") + base_name == "$stable" || base_name == "$rose" || base_name == "$fell" || + base_name == "$changed") { if(arguments.size() != 1 && arguments.size() != 2) { throw errort().with_location(expr.source_location()) - << identifier << " takes one or two arguments"; + << base_name << " takes one or two arguments"; } expr.type() = bool_typet(); return std::move(expr); } - else if(identifier == "$rtoi") + else if(base_name == "$rtoi") { if(arguments.size() != 1) { throw errort().with_location(expr.source_location()) - << identifier << " takes one argument"; + << base_name << " takes one argument"; } expr.type() = verilog_integer_typet(); return std::move(expr); } - else if(identifier == "$itor") + else if(base_name == "$itor") { if(arguments.size() != 1) { throw errort().with_location(expr.source_location()) - << identifier << " takes one argument"; + << base_name << " takes one argument"; } expr.type() = verilog_real_typet(); return std::move(expr); } - else if(identifier == "$bitstoreal") + else if(base_name == "$bitstoreal") { if(arguments.size() != 1) { throw errort().with_location(expr.source_location()) - << identifier << " takes one argument"; + << base_name << " takes one argument"; } expr.type() = verilog_real_typet(); return std::move(expr); } - else if(identifier == "$bitstoshortreal") + else if(base_name == "$bitstoshortreal") { if(arguments.size() != 1) { throw errort().with_location(expr.source_location()) - << identifier << " takes one argument"; + << base_name << " takes one argument"; } expr.type() = verilog_shortreal_typet(); return std::move(expr); } - else if(identifier == "$realtobits") + else if(base_name == "$realtobits") { if(arguments.size() != 1) { throw errort().with_location(expr.source_location()) - << identifier << " takes one argument"; + << base_name << " takes one argument"; } arguments[0] = @@ -1235,12 +1164,12 @@ exprt verilog_typecheck_exprt::convert_system_function( return std::move(expr); } - else if(identifier == "$shortrealtobits") + else if(base_name == "$shortrealtobits") { if(arguments.size() != 1) { throw errort().with_location(expr.source_location()) - << identifier << " takes one argument"; + << base_name << " takes one argument"; } arguments[0] = @@ -1250,7 +1179,7 @@ exprt verilog_typecheck_exprt::convert_system_function( return std::move(expr); } - else if(identifier == "$typename") + else if(base_name == "$typename") { if(arguments.size() != 1) { @@ -1268,7 +1197,7 @@ exprt verilog_typecheck_exprt::convert_system_function( else { throw errort().with_location(expr.function().source_location()) - << "unknown system function `" << identifier << "'"; + << "unknown system function `" << base_name << "'"; } } @@ -1290,9 +1219,10 @@ exprt verilog_typecheck_exprt::convert_nullary_expr(nullary_exprt expr) { return convert_constant(to_constant_expr(std::move(expr))); } - else if(expr.id()==ID_symbol) + else if(expr.id() == ID_verilog_identifier) { - return convert_symbol(to_symbol_expr(std::move(expr)), {}); + return convert_verilog_identifier( + to_verilog_identifier_expr(std::move(expr)), {}); } else if(expr.id()==ID_verilog_star_event) { @@ -1330,7 +1260,7 @@ exprt verilog_typecheck_exprt::convert_nullary_expr(nullary_exprt expr) /*******************************************************************\ -Function: verilog_typecheck_exprt::convert_symbol +Function: verilog_typecheck_exprt::resolve Inputs: @@ -1340,58 +1270,64 @@ Function: verilog_typecheck_exprt::convert_symbol \*******************************************************************/ -exprt verilog_typecheck_exprt::convert_symbol( - symbol_exprt expr, - const std::optional &implicit_net_type) +const symbolt *verilog_typecheck_exprt::resolve(const irep_idt base_name) { - const irep_idt &identifier = expr.get_identifier(); - - std::string full_identifier; - // in a task or function? Try local ones first if(function_or_task_name!="") { - full_identifier= - id2string(function_or_task_name)+ - "."+id2string(identifier); - + auto full_identifier = + id2string(function_or_task_name) + "." + id2string(base_name); + const symbolt *symbol; if(!ns.lookup(full_identifier, symbol)) - { // found! - expr.type()=symbol->type; - expr.set_identifier(full_identifier); - return std::move(expr); - } + return symbol; // found! } - - std::string named_block; - + // try named blocks, beginning with inner one for(named_blockst::const_reverse_iterator it=named_blocks.rbegin(); it!=named_blocks.rend(); it++) { - full_identifier= - id2string(module_identifier)+"."+ - id2string(*it)+ - id2string(identifier); - + auto full_identifier = id2string(module_identifier) + "." + id2string(*it) + + id2string(base_name); + const symbolt *symbol; if(!ns.lookup(full_identifier, symbol)) - { // found! - named_block=*it; - break; - } + return symbol; // found! } - - full_identifier= - id2string(module_identifier)+"."+ - named_block+ - id2string(identifier); + + auto full_identifier = + id2string(module_identifier) + "." + id2string(base_name); const symbolt *symbol; if(!ns.lookup(full_identifier, symbol)) + return symbol; // found! + + // give up + return nullptr; +} + +/*******************************************************************\ + +Function: verilog_typecheck_exprt::convert_symbol + + Inputs: + + Outputs: + + Purpose: + +\*******************************************************************/ + +exprt verilog_typecheck_exprt::convert_verilog_identifier( + verilog_identifier_exprt expr, + const std::optional &implicit_net_type) +{ + auto base_name = expr.base_name(); + auto symbol = resolve(base_name); + + if(symbol != nullptr) { // found! if( @@ -1400,14 +1336,12 @@ exprt verilog_typecheck_exprt::convert_symbol( { // A parameter, or enum. The type is elaborated recursively. elaborate_symbol_rec(symbol->name); - expr.type() = symbol->type; - expr.set_identifier(full_identifier); - return std::move(expr); + return symbol->symbol_expr().with_source_location(expr); } else if(symbol->type.id() == ID_verilog_genvar) { // This must be a constant. - mp_integer int_value = genvar_value(identifier); + mp_integer int_value = genvar_value(base_name); if(int_value<0) { @@ -1422,31 +1356,41 @@ exprt verilog_typecheck_exprt::convert_symbol( result.add_source_location()=source_location; return result; } + else if( + symbol->type.id() == ID_verilog_sva_named_sequence || + symbol->type.id() == ID_verilog_sva_named_property) + { + // A named sequence or property. Create an instance expression, + // and then flatten it. + auto symbol_expr = symbol->symbol_expr().with_source_location(expr); + auto &declaration = + to_verilog_sequence_property_declaration_base(symbol->value); + auto instance = + sva_sequence_property_instance_exprt{symbol_expr, {}, declaration} + .with_source_location(expr); + return flatten_named_sequence_property(instance); + } else { - expr.type()=symbol->type; - expr.set_identifier(full_identifier); - return std::move(expr); + return symbol->symbol_expr().with_source_location(expr); } } else { if(implicit_net_type.has_value()) { - implicit_wire(identifier, symbol, implicit_net_type.value()); + implicit_wire(base_name, symbol, implicit_net_type.value()); if(warn_implicit_nets) { warning().source_location = expr.source_location(); warning() << "implicit wire " << symbol->display_name() << eom; } - expr.type() = symbol->type; - expr.set_identifier(symbol->name); - return std::move(expr); + return symbol->symbol_expr().with_source_location(expr); } else { throw errort().with_location(expr.source_location()) - << "unknown identifier " << identifier; + << "unknown identifier " << base_name; } } } @@ -1468,19 +1412,21 @@ exprt verilog_typecheck_exprt::convert_hierarchical_identifier( { convert_expr(expr.lhs()); - DATA_INVARIANT(expr.rhs().id() == ID_symbol, "expected symbol on rhs of `.'"); + DATA_INVARIANT( + expr.rhs().id() == ID_verilog_identifier, + "expected verilog_identifier as rhs of `.'"); - const irep_idt &rhs_identifier = expr.rhs().get_identifier(); + const irep_idt &rhs_base_name = expr.rhs().base_name(); if(expr.lhs().type().id() == ID_struct || expr.lhs().type().id() == ID_union) { // look up the component auto &compound_type = to_struct_union_type(expr.lhs().type()); - auto &component = compound_type.get_component(rhs_identifier); + auto &component = compound_type.get_component(rhs_base_name); if(component.is_nil()) throw errort().with_location(expr.source_location()) << compound_type.id() << " does not have a member named " - << rhs_identifier; + << rhs_base_name; // create the member expression return member_exprt{expr.lhs(), component.get_name(), component.type()} @@ -1514,7 +1460,7 @@ exprt verilog_typecheck_exprt::convert_hierarchical_identifier( // the identifier in the module const irep_idt full_identifier = - id2string(module) + "." + id2string(rhs_identifier); + id2string(module) + "." + id2string(rhs_base_name); const symbolt *symbol; if(!ns.lookup(full_identifier, symbol)) @@ -1532,7 +1478,7 @@ exprt verilog_typecheck_exprt::convert_hierarchical_identifier( else { throw errort().with_location(expr.source_location()) - << "identifier `" << rhs_identifier << "' not found in module `" + << "identifier `" << rhs_base_name << "' not found in module `" << module_instance_symbol->pretty_name << "'"; } @@ -1544,7 +1490,7 @@ exprt verilog_typecheck_exprt::convert_hierarchical_identifier( else if(expr.lhs().type().id() == ID_named_block) { const irep_idt full_identifier = - id2string(lhs_identifier) + "." + id2string(rhs_identifier); + id2string(lhs_identifier) + "." + id2string(rhs_base_name); const symbolt *symbol; if(!ns.lookup(full_identifier, symbol)) @@ -1566,7 +1512,7 @@ exprt verilog_typecheck_exprt::convert_hierarchical_identifier( else { throw errort().with_location(expr.source_location()) - << "identifier `" << rhs_identifier << "' not found in named block"; + << "identifier `" << rhs_base_name << "' not found in named block"; } } else @@ -1610,7 +1556,7 @@ exprt verilog_typecheck_exprt::convert_constant(constant_exprt expr) const std::string &value = id2string(expr.get_value()); - // real or integral? + // real or integer? if( value.find('.') != std::string::npos || (value.find('h') == std::string::npos && @@ -1866,44 +1812,41 @@ exprt verilog_typecheck_exprt::elaborate_constant_system_function_call( // This performs constant-folding on a type-checked function // call expression according to Section 11.2.1 IEEE 1800-2017. auto &function = expr.function(); - if(function.id() != ID_symbol) - return std::move(expr); // give up - - auto &identifier = to_symbol_expr(function).get_identifier(); - + PRECONDITION(function.id() == ID_verilog_identifier); + auto &base_name = to_verilog_identifier_expr(function).base_name(); auto &arguments = expr.arguments(); - if(identifier == "$bits") + if(base_name == "$bits") { DATA_INVARIANT(arguments.size() == 1, "$bits has one argument"); return bits(arguments[0]); } - else if(identifier == "$low") + else if(base_name == "$low") { DATA_INVARIANT(arguments.size() == 1, "$low has one argument"); return low(arguments[0]); } - else if(identifier == "$high") + else if(base_name == "$high") { DATA_INVARIANT(arguments.size() == 1, "$high has one argument"); return high(arguments[0]); } - else if(identifier == "$left") + else if(base_name == "$left") { DATA_INVARIANT(arguments.size() == 1, "$left has one argument"); return left(arguments[0]); } - else if(identifier == "$right") + else if(base_name == "$right") { DATA_INVARIANT(arguments.size() == 1, "$right has one argument"); return right(arguments[0]); } - else if(identifier == "$increment") + else if(base_name == "$increment") { DATA_INVARIANT(arguments.size() == 1, "$increment has one argument"); return increment(arguments[0]); } - else if(identifier == "$countones") + else if(base_name == "$countones") { DATA_INVARIANT(arguments.size() == 1, "$countones has one argument"); @@ -1914,7 +1857,7 @@ exprt verilog_typecheck_exprt::elaborate_constant_system_function_call( return countones(to_constant_expr(op)); } - else if(identifier == "$clog2") + else if(base_name == "$clog2") { // the ceiling of the log with base 2 of the argument DATA_INVARIANT(arguments.size() == 1, "$clog2 has one argument"); @@ -1940,12 +1883,12 @@ exprt verilog_typecheck_exprt::elaborate_constant_system_function_call( return from_integer(result, integer_typet()); } } - else if(identifier == "$typename") + else if(base_name == "$typename") { DATA_INVARIANT(arguments.size() == 1, "$typename takes one argument"); return typename_string(arguments[0]); } - else if(identifier == "$isunknown") + else if(base_name == "$isunknown") { DATA_INVARIANT(arguments.size() == 1, "$isunknown takes one argument"); @@ -2191,102 +2134,6 @@ void verilog_typecheck_exprt::implicit_typecast( return; } } - else if(src_type.id() == ID_verilog_assignment_pattern) - { - DATA_INVARIANT( - expr.id() == ID_verilog_assignment_pattern, - "verilog_assignment_pattern expression expected"); - if(dest_type.id() == ID_struct) - { - auto &struct_type = to_struct_type(dest_type); - auto &components = struct_type.components(); - - if( - !expr.operands().empty() && - expr.operands().front().id() == ID_member_initializer) - { - exprt::operandst initializers{components.size(), nil_exprt{}}; - - for(auto &op : expr.operands()) - { - PRECONDITION(op.id() == ID_member_initializer); - auto member_name = op.get(ID_member_name); - if(!struct_type.has_component(member_name)) - { - throw errort().with_location(op.source_location()) - << "struct does not have a member `" << member_name << "'"; - } - auto nr = struct_type.component_number(member_name); - auto value = to_unary_expr(op).op(); - // rec. call - implicit_typecast(value, components[nr].type()); - initializers[nr] = std::move(value); - } - - // Is every member covered? - for(std::size_t i = 0; i < components.size(); i++) - if(initializers[i].is_nil()) - { - throw errort().with_location(expr.source_location()) - << "assignment pattern does not assign member `" - << components[i].get_name() << "'"; - } - - expr = struct_exprt{std::move(initializers), struct_type} - .with_source_location(expr.source_location()); - } - else - { - if(expr.operands().size() != components.size()) - { - throw errort().with_location(expr.source_location()) - << "number of expressions does not match number of struct members"; - } - - for(std::size_t i = 0; i < components.size(); i++) - { - // rec. call - implicit_typecast(expr.operands()[i], components[i].type()); - } - - // turn into struct expression - expr.id(ID_struct); - expr.type() = dest_type; - } - - return; - } - else if(dest_type.id() == ID_array) - { - auto &array_type = to_array_type(dest_type); - auto &element_type = array_type.element_type(); - auto array_size = - numeric_cast_v(to_constant_expr(array_type.size())); - - if(array_size != expr.operands().size()) - { - throw errort().with_location(expr.source_location()) - << "number of expressions does not match number of array elements"; - } - - for(std::size_t i = 0; i < array_size; i++) - { - // rec. call - implicit_typecast(expr.operands()[i], element_type); - } - - // turn into array expression - expr.id(ID_array); - expr.type() = dest_type; - return; - } - else - { - throw errort().with_location(expr.source_location()) - << "cannot convert assignment pattern to '" << to_string(dest_type) - << '\''; - } - } else if(src_type.id() == ID_verilog_real) { if( @@ -2313,11 +2160,8 @@ void verilog_typecheck_exprt::implicit_typecast( dest_type.id() == ID_verilog_class_type || dest_type.id() == ID_verilog_event) { - if(expr.id() == ID_constant) - { - expr.type() = dest_type; - return; - } + expr = typecast_exprt{expr, dest_type}; + return; } } @@ -2484,7 +2328,7 @@ void verilog_typecheck_exprt::struct_decay(exprt &expr) const // Verilog packed struct types decay to a vector type [$bits(t)-1:0] // when used in relational or arithmetic expressions. auto &type = expr.type(); - if(type.id() == ID_struct) + if(type.id() == ID_struct && type.get_bool(ID_packed)) { auto new_type = unsignedbv_typet{numeric_cast_v(get_width(type))}; @@ -2538,39 +2382,6 @@ void verilog_typecheck_exprt::tc_binary_expr( /*******************************************************************\ -Function: zero_extend - - Inputs: - - Outputs: - - Purpose: - -\*******************************************************************/ - -static exprt zero_extend(const exprt &expr, const typet &type) -{ - auto old_width = expr.type().id() == ID_bool ? 1 - : expr.type().id() == ID_integer - ? 32 - : to_bitvector_type(expr.type()).get_width(); - - // first make unsigned - typet tmp_type; - - if(type.id() == ID_unsignedbv) - tmp_type = unsignedbv_typet{old_width}; - else if(type.id() == ID_verilog_unsignedbv) - tmp_type = verilog_unsignedbv_typet{old_width}; - else - PRECONDITION(false); - - return typecast_exprt::conditional_cast( - typecast_exprt::conditional_cast(expr, tmp_type), type); -} - -/*******************************************************************\ - Function: verilog_typecheck_exprt::convert_relation Inputs: @@ -2583,43 +2394,11 @@ Function: verilog_typecheck_exprt::convert_relation void verilog_typecheck_exprt::convert_relation(binary_exprt &expr) { - auto &lhs = expr.lhs(); - auto &rhs = expr.rhs(); - - convert_expr(lhs); - convert_expr(rhs); - - union_decay(lhs); - union_decay(rhs); - - // Relations are special-cased in 1800-2017 11.8.2. - const typet new_type = - max_type(enum_decay(lhs.type()), enum_decay(rhs.type())); - - if(new_type.is_nil()) - { - throw errort().with_location(expr.source_location()) - << "expected operands of compatible type but got:\n" - << " " << to_string(lhs.type()) << '\n' - << " " << to_string(rhs.type()); - } + convert_expr(expr.lhs()); + convert_expr(expr.rhs()); - // If both operands are signed, both are sign-extended to the max width. - // Otherwise, both are zero-extended to the max width. - // In particular, signed operands are then _not_ sign extended, - // which a typecast would do. - if(new_type.id() == ID_verilog_unsignedbv || new_type.id() == ID_unsignedbv) - { - // zero extend both operands - lhs = zero_extend(lhs, new_type); - rhs = zero_extend(rhs, new_type); - } - else - { - // convert - implicit_typecast(lhs, new_type); - implicit_typecast(rhs, new_type); - } + // determine the max of the operand types and propagate it downwards + tc_binary_expr(expr); } /*******************************************************************\ @@ -2727,15 +2506,9 @@ Function: verilog_typecheck_exprt::tc_binary_expr \*******************************************************************/ -void verilog_typecheck_exprt::tc_binary_expr(exprt &expr) +void verilog_typecheck_exprt::tc_binary_expr(binary_exprt &expr) { - if(expr.operands().size()!=2) - { - throw errort().with_location(expr.source_location()) - << "operator " << expr.id_string() << " takes two operands"; - } - - tc_binary_expr(expr, to_binary_expr(expr).op0(), to_binary_expr(expr).op1()); + tc_binary_expr(expr, expr.op0(), expr.op1()); } /*******************************************************************\ @@ -2775,10 +2548,11 @@ exprt verilog_typecheck_exprt::convert_unary_expr(unary_exprt expr) { // these may produce an 'x' if the operand is a verilog_bv convert_expr(expr.op()); - must_be_integral(expr.op()); + must_be_bit_vector(expr.op()); - if (expr.op().type().id() == ID_verilog_signedbv || - expr.op().type().id() == ID_verilog_unsignedbv) + if( + expr.op().type().id() == ID_verilog_signedbv || + expr.op().type().id() == ID_verilog_unsignedbv) { expr.type()=verilog_unsignedbv_typet(1); } @@ -2802,9 +2576,22 @@ exprt verilog_typecheck_exprt::convert_unary_expr(unary_exprt expr) else if(expr.id() == ID_verilog_explicit_type_cast) { // SystemVerilog has got type'(expr). This is an explicit - // type cast. + // type cast. These are assignment contexts. convert_expr(expr.op()); expr.type() = elaborate_type(expr.type()); + + // In contrast to assignments, these can turn integers into enums + // (1800-2017 6.19.3). + if(expr.type().get(ID_C_verilog_type) == ID_verilog_enum) + { + expr.op() = typecast_exprt::conditional_cast(expr.op(), expr.type()); + } + else + { + assignment_conversion(expr.op(), expr.type()); + } + + CHECK_RETURN(expr.op().type() == expr.type()); } else if(expr.id() == ID_verilog_explicit_signing_cast) { @@ -2872,7 +2659,7 @@ exprt verilog_typecheck_exprt::convert_unary_expr(unary_exprt expr) // slice_size is defaulted to 1 PRECONDITION(expr.op().operands().size() == 1); convert_expr(expr.op().operands()[0]); - must_be_integral(expr.op().operands()[0]); + must_be_bit_vector(expr.op().operands()[0]); expr.type() = expr.op().operands()[0].type(); return std::move(expr); } @@ -2924,6 +2711,11 @@ exprt verilog_typecheck_exprt::convert_unary_expr(unary_exprt expr) // assignment patterns, 1800 2017 10.9 convert_expr(expr.op()); } + else if(expr.id() == ID_verilog_tagged_union) + { + throw errort{}.with_location(expr.source_location()) + << "no support for tagged unions"; + } else { throw errort() << "no conversion for unary expression " << expr.id(); @@ -3038,7 +2830,7 @@ exprt verilog_typecheck_exprt::convert_replication_expr(replication_exprt expr) exprt &op1=expr.op1(); convert_expr(op1); - must_be_integral(op1); + must_be_bit_vector(op1); if(op1.type().id()==ID_bool) op1 = typecast_exprt{op1, unsignedbv_typet{1}}; @@ -3165,12 +2957,13 @@ exprt verilog_typecheck_exprt::convert_binary_expr(binary_exprt expr) auto location = expr.source_location(); auto &package_scope = to_verilog_package_scope_expr(expr); - if(package_scope.identifier().id() != ID_symbol) + if(package_scope.identifier().id() != ID_verilog_identifier) throw errort().with_location(location) - << expr.id() << " expects symbol on the rhs"; + << expr.id() << " expects verilog_identifier on the rhs"; auto package_base = package_scope.package_base_name(); - auto rhs_base = package_scope.identifier().get(ID_base_name); + auto rhs_base = + to_verilog_identifier_expr(package_scope.identifier()).base_name(); // stitch together irep_idt full_identifier = @@ -3268,12 +3061,15 @@ exprt verilog_typecheck_exprt::convert_binary_expr(binary_exprt expr) expr.id() == ID_verilog_wildcard_inequality) { // ==? and !=? - Forall_operands(it, expr) - convert_expr(*it); + // 1800-2017 Table 11-1 says that any integral operands are allowed; + // however, it is unclear how these would apply to types that do not have + // a bit-encoding. + convert_relation(expr); - tc_binary_expr(expr); + must_be_bit_vector(expr.lhs()); + must_be_bit_vector(expr.rhs()); - expr.type() = verilog_unsignedbv_typet(1); + expr.type() = verilog_unsignedbv_typet{1}; return std::move(expr); } @@ -3281,26 +3077,39 @@ exprt verilog_typecheck_exprt::convert_binary_expr(binary_exprt expr) expr.id()==ID_verilog_case_inequality) { // === and !== + // Take any operand types except real and shortreal (1800-2017 Table 11-1). // The result is always Boolean, and semantically // a proper equality is performed. - expr.type()=bool_typet(); + expr.type() = bool_typet{}; convert_relation(expr); - // integral operands only - must_be_integral(expr.lhs()); - must_be_integral(expr.rhs()); + if( + expr.lhs().type().id() == ID_verilog_real || + expr.lhs().type().id() == ID_verilog_shortreal) + { + throw errort().with_location(expr.source_location()) + << "the case equality operator does not allow real or shortreal"; + } return std::move(expr); } else if(expr.id()==ID_lt || expr.id()==ID_gt || expr.id()==ID_le || expr.id()==ID_ge) { - expr.type()=bool_typet(); - convert_relation(expr); no_bool_ops(expr); + // This returns 'x' if either of the operands contains x or z. + if(is_four_valued(expr.lhs().type()) || is_four_valued(expr.rhs().type())) + { + expr.type() = verilog_unsignedbv_typet(1); + } + else + { + expr.type() = bool_typet{}; + } + return std::move(expr); } else if(expr.id() == ID_power) @@ -3314,8 +3123,8 @@ exprt verilog_typecheck_exprt::convert_binary_expr(binary_exprt expr) convert_expr(expr.lhs()); convert_expr(expr.rhs()); - must_be_integral(expr.lhs()); - must_be_integral(expr.rhs()); + must_be_bit_vector(expr.lhs()); + must_be_bit_vector(expr.rhs()); no_bool_ops(expr); const typet &lhs_type = expr.lhs().type(); @@ -3351,9 +3160,8 @@ exprt verilog_typecheck_exprt::convert_binary_expr(binary_exprt expr) // logical right shift >> convert_expr(expr.lhs()); convert_expr(expr.rhs()); - must_be_integral(expr.lhs()); - must_be_integral(expr.rhs()); - no_bool_ops(expr); + must_be_bit_vector(expr.lhs()); + must_be_bit_vector(expr.rhs()); const typet &lhs_type = expr.lhs().type(); const typet &rhs_type = expr.rhs().type(); @@ -3385,12 +3193,13 @@ exprt verilog_typecheck_exprt::convert_binary_expr(binary_exprt expr) { convert_expr(expr.lhs()); convert_expr(expr.rhs()); - must_be_integral(expr.lhs()); - must_be_integral(expr.rhs()); tc_binary_expr(expr); no_bool_ops(expr); + must_be_bit_vector(expr.lhs()); + must_be_bit_vector(expr.rhs()); + expr.type() = expr.lhs().type(); return std::move(expr); @@ -3415,16 +3224,29 @@ exprt verilog_typecheck_exprt::convert_binary_expr(binary_exprt expr) { expr.type() = signedbv_typet{new_size_int}; } + else if(op_type.id() == ID_verilog_signedbv) + { + expr.type() = verilog_signedbv_typet{new_size_int}; + } else if(op_type.id() == ID_unsignedbv || op_type.id() == ID_bool) { expr.type() = unsignedbv_typet{new_size_int}; } + else if(op_type.id() == ID_verilog_unsignedbv) + { + expr.type() = verilog_unsignedbv_typet{new_size_int}; + } else { throw errort().with_location(expr.source_location()) << "cannot perform size cast on " << to_string(op_type); } + // These act like an assignment (1800-2017 6.24.1) + assignment_conversion(expr.rhs(), expr.type()); + + CHECK_RETURN(expr.rhs().type() == expr.type()); + return std::move(expr); } else if( @@ -3469,9 +3291,7 @@ exprt verilog_typecheck_exprt::convert_binary_expr(binary_exprt expr) expr.type() = bool_typet{}; return std::move(expr); } - else if( - expr.id() == ID_plus || expr.id() == ID_minus || expr.id() == ID_mult || - expr.id() == ID_power) + else if(expr.id() == ID_plus || expr.id() == ID_minus || expr.id() == ID_mult) { for(auto &op : expr.operands()) convert_expr(op); @@ -3514,9 +3334,7 @@ exprt verilog_typecheck_exprt::convert_binary_expr(binary_exprt expr) return std::move(expr); } - else if( - expr.id() == ID_and || expr.id() == ID_or || expr.id() == ID_xor || - expr.id() == ID_xnor || expr.id() == ID_nand || expr.id() == ID_nor) + else if(expr.id() == ID_and || expr.id() == ID_or) { for(auto &op : expr.operands()) { @@ -3530,6 +3348,13 @@ exprt verilog_typecheck_exprt::convert_binary_expr(binary_exprt expr) return std::move(expr); } + else if( + expr.id() == ID_xor || expr.id() == ID_xnor || expr.id() == ID_nand || + expr.id() == ID_nor) + { + // should not occur -- only generated by the typechecker + PRECONDITION(false); + } else if(expr.id() == ID_verilog_value_range) { for(auto &op : expr.operands()) diff --git a/src/verilog/verilog_typecheck_expr.h b/src/verilog/verilog_typecheck_expr.h index eaf70e07f..1d909cfa9 100644 --- a/src/verilog/verilog_typecheck_expr.h +++ b/src/verilog/verilog_typecheck_expr.h @@ -65,7 +65,7 @@ class verilog_typecheck_exprt:public verilog_typecheck_baset void make_boolean(exprt &expr); - void propagate_type(exprt &expr, const typet &type); + void assignment_conversion(exprt &expr, const typet &type); void downwards_type_propagation(exprt &, const typet &); [[nodiscard]] typet elaborate_type(const typet &); @@ -174,8 +174,10 @@ class verilog_typecheck_exprt:public verilog_typecheck_baset protected: [[nodiscard]] exprt convert_expr_rec(exprt expr); [[nodiscard]] exprt convert_constant(constant_exprt); - [[nodiscard]] exprt - convert_symbol(symbol_exprt, const std::optional &implicit_net_type); + [[nodiscard]] const symbolt *resolve(irep_idt base_name); + [[nodiscard]] exprt convert_verilog_identifier( + verilog_identifier_exprt, + const std::optional &implicit_net_type); [[nodiscard]] exprt convert_hierarchical_identifier(class hierarchical_identifier_exprt); [[nodiscard]] exprt convert_nullary_expr(nullary_exprt); @@ -184,18 +186,17 @@ class verilog_typecheck_exprt:public verilog_typecheck_baset [[nodiscard]] exprt convert_trinary_expr(ternary_exprt); [[nodiscard]] exprt convert_expr_concatenation(concatenation_exprt); [[nodiscard]] exprt convert_expr_function_call(function_call_exprt); - [[nodiscard]] exprt - convert_system_function(const irep_idt &identifier, function_call_exprt); + [[nodiscard]] exprt convert_system_function(function_call_exprt); [[nodiscard]] exprt convert_bit_select_expr(binary_exprt); [[nodiscard]] exprt convert_replication_expr(replication_exprt); [[nodiscard]] exprt convert_power_expr(power_exprt); [[nodiscard]] exprt convert_shl_expr(shl_exprt); void implicit_typecast(exprt &, const typet &type); - void tc_binary_expr(exprt &); + void tc_binary_expr(binary_exprt &); void tc_binary_expr(const exprt &expr, exprt &op0, exprt &op1); void convert_relation(binary_exprt &); void no_bool_ops(exprt &); - void must_be_integral(const exprt &); + void must_be_bit_vector(exprt &); // SVA void convert_sva(exprt &expr) @@ -211,6 +212,8 @@ class verilog_typecheck_exprt:public verilog_typecheck_baset [[nodiscard]] exprt convert_binary_sva(binary_exprt); [[nodiscard]] exprt convert_ternary_sva(ternary_exprt); [[nodiscard]] exprt convert_other_sva(exprt); + [[nodiscard]] exprt + flatten_named_sequence_property(sva_sequence_property_instance_exprt); // system functions exprt bits(const exprt &); diff --git a/src/verilog/verilog_typecheck_sva.cpp b/src/verilog/verilog_typecheck_sva.cpp index a2a1acaa3..fe11ef692 100644 --- a/src/verilog/verilog_typecheck_sva.cpp +++ b/src/verilog/verilog_typecheck_sva.cpp @@ -167,6 +167,21 @@ exprt verilog_typecheck_exprt::convert_binary_sva(binary_exprt expr) return std::move(expr); } + else if(expr.id() == ID_sva_sequence_disable_iff) + { + auto &disable_iff = to_sva_sequence_disable_iff_expr(expr); + + // The condition of these is special: They are not sampled, + // but evaluated directly (1800-2017 16.6). + convert_expr(disable_iff.condition()); + make_boolean(disable_iff.condition()); + + convert_sva(disable_iff.sequence()); + require_sva_sequence(disable_iff.sequence()); + expr.type() = verilog_sva_sequence_typet{}; + + return std::move(expr); + } else if( expr.id() == ID_sva_cycle_delay_plus || // ##[+] expr.id() == ID_sva_cycle_delay_star) // ##[*] @@ -295,7 +310,7 @@ exprt verilog_typecheck_exprt::convert_binary_sva(binary_exprt expr) { convert_expr(pattern); typet t = max_type(pattern.type(), case_expr.case_op().type()); - propagate_type(pattern, t); + downwards_type_propagation(pattern, t); } convert_sva(case_item.result()); @@ -478,3 +493,26 @@ exprt verilog_typecheck_exprt::convert_sva_rec(exprt expr) return convert_other_sva(expr); } } + +/// 1800-2017 F.4.1 +exprt verilog_typecheck_exprt::flatten_named_sequence_property( + sva_sequence_property_instance_exprt instance) +{ + auto &cond = instance.declaration().cond(); + convert_sva(cond); + + if(instance.symbol().type().id() == ID_verilog_sva_named_sequence) + { + require_sva_sequence(cond); + instance.type() = verilog_sva_sequence_typet{}; + } + else if(instance.symbol().type().id() == ID_verilog_sva_named_property) + { + require_sva_property(cond); + instance.type() = verilog_sva_property_typet{}; + } + else + PRECONDITION(false); + + return instance; +} diff --git a/src/verilog/verilog_types.h b/src/verilog/verilog_types.h index 08940b284..803a6d536 100644 --- a/src/verilog/verilog_types.h +++ b/src/verilog/verilog_types.h @@ -777,20 +777,20 @@ inline verilog_event_typet &to_verilog_event_type(typet &type) class verilog_typedef_typet : public typet { public: - explicit verilog_typedef_typet(const irep_idt &_identifier) + explicit verilog_typedef_typet(const irep_idt &_base_name) : typet(ID_typedef_type) { - identifier(_identifier); + base_name(_base_name); } - void identifier(const irep_idt &identifier) + void base_name(const irep_idt &base_name) { - set(ID_identifier, identifier); + set(ID_base_name, base_name); } - const irep_idt &identifier() const + const irep_idt &base_name() const { - return get(ID_identifier); + return get(ID_base_name); } }; @@ -867,4 +867,24 @@ class verilog_sva_sequence_typet : public typet } }; +/// SVA named properties +class verilog_sva_named_property_typet : public typet +{ +public: + explicit verilog_sva_named_property_typet() + : typet{ID_verilog_sva_named_property} + { + } +}; + +/// SVA named sequences +class verilog_sva_named_sequence_typet : public typet +{ +public: + explicit verilog_sva_named_sequence_typet() + : typet{ID_verilog_sva_named_sequence} + { + } +}; + #endif diff --git a/unit/Makefile b/unit/Makefile index c2876e01e..c9ccd4416 100644 --- a/unit/Makefile +++ b/unit/Makefile @@ -8,8 +8,10 @@ SRC += smvlang/expr2smv.cpp \ temporal-logic/hoa.cpp \ temporal-logic/ltl_sva_to_string.cpp \ temporal-logic/sva_sequence_match.cpp \ + temporal-logic/sva_to_ltl.cpp \ temporal-logic/nnf.cpp \ temporal-logic/trivial_sva.cpp \ + verilog/typename.cpp \ # Empty last line INCLUDES= -I ../src/ -I . -I $(CPROVER_DIR)/unit -I $(CPROVER_DIR)/src diff --git a/unit/temporal-logic/sva_to_ltl.cpp b/unit/temporal-logic/sva_to_ltl.cpp new file mode 100644 index 000000000..ba1a9cff1 --- /dev/null +++ b/unit/temporal-logic/sva_to_ltl.cpp @@ -0,0 +1,25 @@ +/*******************************************************************\ + +Module: SVA to LTL + +Author: Daniel Kroening, dkr@amazon.com + +\*******************************************************************/ + +#include + +#include +#include + +SCENARIO("Generating LTL from SVA") +{ + GIVEN("A boolean formula") + { + auto p = symbol_exprt{"p", bool_typet{}}; + auto q = symbol_exprt{"q", bool_typet{}}; + + REQUIRE(SVA_to_LTL(true_exprt{}) == true_exprt{}); + REQUIRE(SVA_to_LTL(p) == p); + REQUIRE(SVA_to_LTL(equal_exprt{p, q}) == equal_exprt{p, q}); + } +} diff --git a/unit/verilog/typename.cpp b/unit/verilog/typename.cpp new file mode 100644 index 000000000..43e30d4e8 --- /dev/null +++ b/unit/verilog/typename.cpp @@ -0,0 +1,30 @@ +/*******************************************************************\ + +Module: $typename Unit Tests + +Author: Daniel Kroening, Amazon, dkr@amazon.com + +\*******************************************************************/ + +#include +#include +#include + +SCENARIO("$typename(...)") +{ + GIVEN("various Verilog types") + { + REQUIRE(verilog_typename(verilog_byte_typet{}) == "byte"); + REQUIRE(verilog_typename(verilog_chandle_typet{}) == "chandle"); + REQUIRE(verilog_typename(verilog_event_typet{}) == "event"); + REQUIRE(verilog_typename(verilog_int_typet{}) == "int"); + REQUIRE(verilog_typename(verilog_integer_typet{}) == "integer"); + REQUIRE(verilog_typename(verilog_longint_typet{}) == "longint"); + REQUIRE(verilog_typename(verilog_real_typet{}) == "real"); + REQUIRE(verilog_typename(verilog_realtime_typet{}) == "realtime"); + REQUIRE(verilog_typename(verilog_shortint_typet{}) == "shortint"); + REQUIRE(verilog_typename(verilog_shortreal_typet{}) == "shortreal"); + REQUIRE( + verilog_typename(verilog_signedbv_typet{10}) == "logic signed[9:0]"); + } +}