diff --git a/.github/workflows/cmake.yml b/.github/workflows/cmake.yml index 9e7372839..a89fb00e4 100644 --- a/.github/workflows/cmake.yml +++ b/.github/workflows/cmake.yml @@ -13,7 +13,7 @@ jobs: - uses: actions/checkout@v2 - name: Install Dependent Packages - run: sudo apt install bison flex z3 libz3-dev + run: sudo apt install bison flex z3 libz3-dev libfl-dev - name: Create Build Environment run: cmake -E make_directory ${{runner.workspace}}/build diff --git a/.gitmodules b/.gitmodules index f2f3e286e..ae0b41cc0 100644 --- a/.gitmodules +++ b/.gitmodules @@ -7,3 +7,6 @@ [submodule "extern/smt-switch"] path = extern/smt-switch url = https://github.com/makaimann/smt-switch.git +[submodule "extern/vexpparser"] + path = extern/vexpparser + url = https://github.com/zhanghongce/vexpparser.git diff --git a/.travis.yml b/.travis.yml index 7fe7ddba3..b26f06d09 100644 --- a/.travis.yml +++ b/.travis.yml @@ -57,6 +57,7 @@ jobs: - bison - z3 - libz3-dev + - libfl-dev - g++-7 before_install: - echo -n | openssl s_client -connect https://scan.coverity.com:443 | sed -ne '/-BEGIN CERTIFICATE-/,/-END CERTIFICATE-/p' | sudo tee -a /etc/ssl/certs/ca- @@ -77,6 +78,7 @@ addons: - bison - z3 - libz3-dev + - libfl-dev - g++-7 notifications: diff --git a/appveyor.yml b/appveyor.yml index d189fb8bf..ace79576d 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -8,7 +8,7 @@ configuration: install: - sudo apt update --yes -- sudo apt install --yes z3 libz3-dev bison flex gcc g++ +- sudo apt install --yes z3 libz3-dev bison libfl-dev flex gcc g++ build_script: - cd $APPVEYOR_BUILD_FOLDER diff --git a/azure-pipelines.yml b/azure-pipelines.yml index c2efac903..948ba2b78 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -55,27 +55,6 @@ jobs: ./test/unit_tests displayName: 'build' -- job: Ubuntu_1604_LTS - pool: - vmImage: 'ubuntu-16.04' - steps: - - script: | - sudo apt-get update - sudo apt-get install bison - sudo apt-get install flex - sudo apt-get install z3 - sudo apt-get install libz3-dev - sudo apt-get install g++-7 - displayName: 'package' - - script: | - mkdir -p build - cd build - cmake .. -DCMAKE_BUILD_TYPE=Release -DCMAKE_CXX_COMPILER=g++-7 - cmake --build . - sudo cmake --build . --target install - cmake --build . --target test - displayName: 'build' - - job: Ubuntu_1804_LTS pool: vmImage: 'ubuntu-18.04' @@ -86,6 +65,7 @@ jobs: sudo apt-get install flex sudo apt-get install z3 sudo apt-get install libz3-dev + sudo apt-get install libfl-dev sudo apt-get install g++-8 displayName: 'package' - script: | @@ -118,7 +98,7 @@ jobs: cd glog md build cd build - cmake .. + cmake .. -DFLEXLEXER_INCLUDE_PATH=c:\ProgramData\chocolatey\lib\winflexbison3\tools\ cmake --build . --target install displayName: 'glog' @@ -140,11 +120,20 @@ jobs: cmake --build . --target install displayName: 'vlog-parser' + - script: | + cd extern + cd vexpparser + md build + cd build + cmake .. -DFLEXLEXER_INCLUDE_PATH=c:\ProgramData\chocolatey\lib\winflexbison3\tools\ + cmake --build . --target install + displayName: 'vexpparser' + - script: | md build cd build # For building the test, we need CMAKE_MSVC_RUNTIME_LIBRARY (which will be supported in CMake 3.15+) - cmake .. -DILANG_BUILD_TEST=OFF -DBUILD_SHARED_LIBS=OFF -DILANG_BUILD_INVSYN=OFF -DZ3_INCLUDE_DIR=$(Build.Repository.LocalPath)/z3/include -DZ3_LIBRARY=$(Build.Repository.LocalPath)/z3/bin/libz3.lib -DZ3_EXEC=$(Build.Repository.LocalPath)/z3/bin/z3.exe + cmake .. -DILANG_BUILD_TEST=OFF -DBUILD_SHARED_LIBS=OFF -DILANG_BUILD_INVSYN=OFF -DZ3_INCLUDE_DIR=$(Build.Repository.LocalPath)/z3/include -DZ3_LIBRARY=$(Build.Repository.LocalPath)/z3/bin/libz3.lib -DZ3_EXEC=$(Build.Repository.LocalPath)/z3/bin/z3.exe -DFLEXLEXER_INCLUDE_PATH=c:\ProgramData\chocolatey\lib\winflexbison3\tools\ cmake --build . cmake --build . --target install displayName: 'build' @@ -153,7 +142,7 @@ jobs: cd starter md build cd build - cmake .. -DZ3_INCLUDE_DIR=$(Build.Repository.LocalPath)/z3/include -DZ3_LIBRARY=$(Build.Repository.LocalPath)/z3/bin/libz3.lib -DZ3_EXEC=$(Build.Repository.LocalPath)/z3/bin/z3.exe + cmake .. -DZ3_INCLUDE_DIR=$(Build.Repository.LocalPath)/z3/include -DZ3_LIBRARY=$(Build.Repository.LocalPath)/z3/bin/libz3.lib -DZ3_EXEC=$(Build.Repository.LocalPath)/z3/bin/z3.exe -DFLEXLEXER_INCLUDE_PATH=c:\ProgramData\chocolatey\lib\winflexbison3\tools\ cmake --build . displayName: 'starter' diff --git a/cmake/config.cmake.in b/cmake/config.cmake.in index 5a30fc266..12b2e5a56 100644 --- a/cmake/config.cmake.in +++ b/cmake/config.cmake.in @@ -6,6 +6,7 @@ find_dependency(glog REQUIRED) find_dependency(nlohmann_json REQUIRED) find_dependency(verilogparser REQUIRED) find_dependency(vcdparser REQUIRED) +find_dependency(vexpparser REQUIRED) find_dependency(smtparser REQUIRED) find_dependency(fmt REQUIRED) find_dependency(Z3 REQUIRED) diff --git a/extern/CMakeLists.txt b/extern/CMakeLists.txt index c1aea656f..96ed94c94 100644 --- a/extern/CMakeLists.txt +++ b/extern/CMakeLists.txt @@ -126,6 +126,39 @@ if(NOT VERILOGPARSER_FOUND) endif() # VERILOGPARSER_FOUND +# ---------------------------------------------------------------------------- # +# Verilog Expression Parser +# +# TARGET vexpparser::vexpparser +# SOURCE https://github.com/zhanghongce/vexpparser.git +# PATH extern/vexpparser +# ---------------------------------------------------------------------------- # +# find installed package +find_package(vexpparser 1.1.0 QUIET) + +# embed to build tree if not installed +if(NOT VEXP_PARSER_FOUND) + + # fetch from git + if(${ILANG_FETCH_DEPS}) + + execute_process( + COMMAND ${GIT_EXECUTABLE} submodule update --init vexpparser + WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} + RESULT_VARIABLE GIT_SUBMOD_RESULT + ) + + if(NOT GIT_SUBMOD_RESULT EQUAL "0") + message(FATAL_ERROR "Submodule update failed with ${GIT_SUBMOD_RESULT}") + endif() + + endif() # ILANG_FETCH_DEPS + + # embedded build + add_subdirectory(vexpparser) + +endif() # VERILOGPARSER_FOUND + # ---------------------------------------------------------------------------- # # Template-based ILA Synthesis # diff --git a/extern/vexpparser b/extern/vexpparser new file mode 160000 index 000000000..4b6131e7b --- /dev/null +++ b/extern/vexpparser @@ -0,0 +1 @@ +Subproject commit 4b6131e7be72a962c2e75e884dbb5a9424b7703d diff --git a/include/ilang/ilang++.h b/include/ilang/ilang++.h index 09f7d6616..4e85ead30 100644 --- a/include/ilang/ilang++.h +++ b/include/ilang/ilang++.h @@ -16,6 +16,7 @@ #endif // SMTSWITCH_INTERFACE #include +#include /// \namespace ilang /// Defines the core data structure and APIs for constructing and storing ILA. @@ -745,6 +746,28 @@ class IlaZ3Unroller { }; // class IlaZ3Unroller + +/// \brief The wrapper of Rtl verification target generator +class IlaVerilogRefinementChecker { + +public: + // ------------------------- CONSTRUCTOR/DESTRUCTOR ----------------------- // + /// Default constructor + IlaVerilogRefinementChecker( + const Ila& ila, + const std::vector& implementation_include_path, + const std::vector& implementation_srcs, + const std::string& implementation_top_module, + const std::string& refinement_variable_mapping, + const std::string& refinement_conditions, + const std::string& output_path, + ModelCheckerSelection backend, + const RtlVerifyConfig& vtg_config = RtlVerifyConfig() ); + /// Default virtual destructor. + ~IlaVerilogRefinementChecker() {}; + +}; // class RtlVerifier + #ifdef SMTSWITCH_INTERFACE /// \brief Reset the solver and generate the SMT Term (for smt-switch). diff --git a/include/ilang/rfmap-in/rfexpr_shortcut.h b/include/ilang/rfmap-in/rfexpr_shortcut.h new file mode 100644 index 000000000..10fab0090 --- /dev/null +++ b/include/ilang/rfmap-in/rfexpr_shortcut.h @@ -0,0 +1,38 @@ +/// \file rfexpr_shortcut.h Refinement map expression +/// construction +/// Hongce Zhang (zhanghongce@126.com) + +#ifndef ILANG_RFEXPR_SHORTCUT_H__ +#define ILANG_RFEXPR_SHORTCUT_H__ + +#include + +namespace ilang { + +rfmap::RfExpr rfmap_reduce_or(const rfmap::RfExpr& in); +rfmap::RfExpr rfmap_imply(const rfmap::RfExpr& l, const rfmap::RfExpr& r); +rfmap::RfExpr rfmap_and(const rfmap::RfExpr& l, const rfmap::RfExpr& r); +rfmap::RfExpr rfmap_or(const rfmap::RfExpr& l, const rfmap::RfExpr& r); +rfmap::RfExpr rfmap_and(const std::vector& v); +rfmap::RfExpr rfmap_or(const std::vector& v); + +rfmap::RfExpr rfmap_ite(const rfmap::RfExpr& c, const rfmap::RfExpr& l, + const rfmap::RfExpr& r); + +rfmap::RfExpr rfmap_eq(const rfmap::RfExpr& l, const rfmap::RfExpr& r); +rfmap::RfExpr rfmap_le(const rfmap::RfExpr& l, const rfmap::RfExpr& r); + +rfmap::RfExpr rfmap_not(const rfmap::RfExpr& l); + +rfmap::RfExpr rfmap_true(); +rfmap::RfExpr rfmap_false(); +rfmap::RfExpr rfmap_const(unsigned b, unsigned w, unsigned v); +/// if it is RTL. or ILA. then will use MakeVar +/// otherwise will use MakeSpecial +/// will not determine its type +/// ReplExpr will determine the type +rfmap::RfExpr rfmap_var(const std::string& v); + +} // namespace ilang + +#endif // ILANG_RFEXPR_SHORTCUT_H__ diff --git a/include/ilang/rfmap-in/rfexpr_to_smt.h b/include/ilang/rfmap-in/rfexpr_to_smt.h new file mode 100644 index 000000000..0495f552b --- /dev/null +++ b/include/ilang/rfmap-in/rfexpr_to_smt.h @@ -0,0 +1,58 @@ +/// \file rfexpr_to_smt.cc Refinement map to smt-lib2 +/// Hongce Zhang (hongcez@princeton.edu) + +#ifndef ILANG_RFEXPR_TO_SMT_H__ +#define ILANG_RFEXPR_TO_SMT_H__ + +#include + +namespace ilang { +namespace rfmap { + +struct SmtType : public RfMapVarType { + bool bool_or_bv; + + SmtType() : RfMapVarType(1), bool_or_bv(true) {} + SmtType(unsigned w) : RfMapVarType(w), bool_or_bv(false) {} + SmtType(unsigned a, unsigned d) : RfMapVarType(a, d), bool_or_bv(false) {} + SmtType(const RfMapVarType& r, bool request_bool) + : RfMapVarType(r), bool_or_bv(request_bool) {} + + bool is_bool() const { return bool_or_bv && (RfMapVarType::is_bv()); } + bool is_bv() const { return (!bool_or_bv) && (RfMapVarType::is_bv()); } + bool operator==(const SmtType& r) const { + if (bool_or_bv != r.bool_or_bv) + return false; + if (type != r.type) + return false; + if (type == TYPE::BV) + return width == r.width; + if (type == TYPE::MEM) + return data_width == r.data_width && addr_width == r.addr_width; + return false; // unknown type , unknown + } // operator= + + std::string type_to_smt2() const; + +}; // SmtType + +struct RfExpr2Smt { + +public: + static std::string to_smt2(const RfExpr& in, SmtType expected_type); + +protected: + // helper function + static std::string + to_smt2_const(const std::shared_ptr& in, + SmtType expected_type); + static std::string + to_smt2_var(const std::shared_ptr& in, + SmtType expected_type); + +}; // struct RfExpr2Smt + +} // namespace rfmap +} // namespace ilang + +#endif // ILANG_RFEXPR_TO_SMT_H__ diff --git a/include/ilang/rfmap-in/rfmap_typecheck.h b/include/ilang/rfmap-in/rfmap_typecheck.h new file mode 100644 index 000000000..ee669988c --- /dev/null +++ b/include/ilang/rfmap-in/rfmap_typecheck.h @@ -0,0 +1,255 @@ +/// \file Verilog Verification Refinement Map Interface Class +/// Type checker +/// --- Hongce Zhang (hongcez@princeton.edu) + +#ifndef ILANG_RFMAP_TYPECHECK_H__ +#define ILANG_RFMAP_TYPECHECK_H__ + +#include +#include + +#include + +// define annotation + +namespace ilang { +namespace rfmap { + +class TypeAnnotation : public ::verilog_expr::AbstractInternalInfo, + public ::ilang::rfmap::RfVarTypeOrig { + +public: + // allow instantiation + virtual void should_not_instantiate() override {} + + TypeAnnotation() {} + TypeAnnotation(const ::ilang::rfmap::RfVarTypeOrig& r) + : ::ilang::rfmap::RfVarTypeOrig(r) {} +}; // TypeAnnotation + +/// \class structure for recording variable replacement +struct VarReplacement { + RfExpr origvar; // this is certainly a var + RfExpr newvar; // this is certainly a var + + VarReplacement(const RfExpr& o, const RfExpr& n); + + // returns v, there would not be `v[range]` at all + std::string get_orig_name() const { + return std::dynamic_pointer_cast(origvar) + ->get_name() + .first; + } + + std::string get_new_name() const { + return std::dynamic_pointer_cast(newvar) + ->get_name() + .first; + } + + RfVarTypeOrig get_type_new() const { return get_type_orig(); } + + RfVarTypeOrig get_type_orig() const { + auto annotation_ptr = newvar->get_annotation(); + return annotation_ptr ? *annotation_ptr : RfVarTypeOrig(); + } + + bool is_orig_rtlv() const { + return get_type_orig().var_ref_type == RfVarTypeOrig::VARTYPE::RTLV; + } + bool is_orig_ila_state() const { + return get_type_orig().var_ref_type == RfVarTypeOrig::VARTYPE::ILAS; + } + bool is_orig_ila_input() const { + return get_type_orig().var_ref_type == RfVarTypeOrig::VARTYPE::ILAI; + } + + bool is_orig_var_array() const { return get_type_orig().type.is_array(); } +}; + +// convert RfExpr constant -> out +bool _compute_const(const RfExpr& in, unsigned& out); + +// type infer rules +// + +// provide function: + +// try_find_ila_type -> TypeAnnotation +// try find_rtl_type -> TypeAnnotation +// type annotation & checking & replacing : all-together + +class TypeAnalysisUtility { + +public: + typedef std::function var_typecheck_t; + +public: + /// Annotate the type of a refinement expression + /// and this process will be recursive + static void AnnotateType(const RfExpr& inout, + const std::map & quantified_var_type); + +protected: + // internal use only, does not do recursion itself + // therefore, an order of invocation is needed + static void infer_type_based_on_op_child(const RfExpr& inout); + +}; // struct TypeAnalysisUtility + +class RfExprAstUtility { +private: + /// will only replace the free var, so we need to keep track + /// if some var inside are quantified, in that case, should not mask + static RfExpr ReplaceQuantifiedVar(const std::string &n, + const RfExpr & in, const RfExpr & newexpr, + const std::set & quantified_var); + + /// expand the current one, should be invoked from the leaf node + static RfExpr QuantifierInstantiation(const RfExpr& in); + +public: + /// determine if a rf expr has array variable in it + static bool HasArrayVar(const RfExpr& in); + /// determine if a rf expr has quantifier in it + static bool HasQuantifier(const RfExpr& in); + /// for pono, this will cause to use text + /// FORALL -> /\ /\ /\ ... (JasperGold) + /// EXISTS -> \/ \/ \/ ... + static RfExpr FindExpandQuantifier(const RfExpr& in); + + + /// determine if a rf expr is a boolean expr + static bool IsLastLevelBooleanOp(const RfExpr& in); + /// get the variables from a expression + static void GetVars(const RfExpr& in, + std::unordered_map& vars_out); + static RfVarTypeOrig GetType(const RfExpr& in); + /// will modify where the pointer is pointing to + /// because we will be creating new rfexpr + static RfExpr TraverseRfExpr(const RfExpr& inout, + std::function func); + /// will modify where the pointer is pointing to + /// because we will be creating new rfexpr + static void TraverseRfExprNoModify(const RfExpr& inout, + std::function func); + /// check to make sure no null ptr + static void RfMapNoNullNode(const RfExpr& in); +}; + +struct RfExprVarReplUtility { + +public: + /// used by vtarget_gen to replace rtl/ila vars + RfExpr ReplacingRtlIlaVar(const RfExpr& in, const std::set & quantified_vars); + + /// Register internal variables and also the mapping + void RegisterInternalVariableWithMapping(const std::string& n, + const VarReplacement& in) { + var_replacement.emplace(n, in); + } + + VarReplacement* CheckReplacement(const std::string& origname) { + auto pos = var_replacement.find(origname); + if (pos != var_replacement.end()) + return &(var_replacement.at(origname)); + return NULL; + } + + const std::map& GetVarReplacement() const { + return var_replacement; + } + +protected: + /// the replacement used for creating new wires + std::map + var_replacement; // including rtl/ilas/ilav +}; + +struct TypedVerilogRefinementMap : public VerilogRefinementMap, + public TypeAnalysisUtility, + public RfExprAstUtility, + public RfExprVarReplUtility { + + // type definitions + using var_typecheck_t = TypeAnalysisUtility::var_typecheck_t; + using VarDef = GeneralVerilogMonitor::VarDef; + + // constructor + // typechecker is only used in TypeInferTraverseRfExpr + TypedVerilogRefinementMap(const std::string& varmap_json_file, + const std::string& instcond_json_file, + var_typecheck_t type_checker); + + TypedVerilogRefinementMap(const VerilogRefinementMap& refinement, + var_typecheck_t type_checker); + + // references + // - named defined vars with type + // - named stages with type bit 1 + + // additional delayed + std::map aux_delays; + // additional value_recoder added to value_recorder + + // defined vars + // 1. first round : only explict ones + // this is to collect information before running the + // the AST type checks + std::map all_var_def_types; + // the above is only used in the first round + // 2. second round : AST type check + // so this is NOT used in creating vars? + // Var creating stage should deal with separate ones + + // this should include phase-tracker (m,v,alias) + // ... ? + void TraverseAllRfExpr(std::function func); + + // this function is used in + // (1) value holder/delay : width determination + // will use all_var_def_types & typechecker + // (2) vlg-monitor replace-var + RfMapVarType TypeInferTravserRfExpr(const RfExpr& in, const std::map local_var_def); + +protected: + // used in TypedVerilogRefinementMap::TypeInferTravserRfExpr + // this is only used in the first stage : aux var width determination + var_typecheck_t typechecker; + + void initialize(); + /// this function will not collect implicity vars + /// or those with 0/auto width + /// for the explicity vars + /// it will add them to the `all_var_def_types` + /// for the implicit ones, ComputeDelayValueHolderWidth will + /// compute the width and add them to `all_var_def_types` + + /// this will also create `all_var_def_types` + /// for 4 virtual vars: decode, commit, $decode, $valid + /// those replacement are added separately + void CollectInternallyDefinedVars(); + + /// deal with condition map + void TraverseCondMap(SingleVarMap& inout, + std::function func); + +private: + // help with naming + unsigned counter; + std::string new_id(); + + // helper for AST traversal + RfExpr collect_inline_value_recorder_func(const RfExpr& inout); + RfExpr collect_inline_delay_func(const RfExpr& inout); + // this function uses the above two and the + void CollectInlineDelayValueHolder(); + + void ComputeDelayValueHolderWidth(); + +}; // TypedVerilogRefinementMap + +} // namespace rfmap +} // namespace ilang + +#endif // ILANG_RFMAP_TYPECHECK_H__ diff --git a/include/ilang/rfmap-in/rfvar_type.h b/include/ilang/rfmap-in/rfvar_type.h new file mode 100644 index 000000000..20e069550 --- /dev/null +++ b/include/ilang/rfmap-in/rfvar_type.h @@ -0,0 +1,72 @@ +/// \file Verilog Verification Refinement Map Interface Class +/// Variable Types +/// --- Hongce Zhang (hongcez@princeton.edu) + +#ifndef ILANG_RFMAP_VARTYPE_H__ +#define ILANG_RFMAP_VARTYPE_H__ + +#include + +namespace ilang { +namespace rfmap { + +// define type +struct RfMapVarType { + enum class TYPE { BV, MEM, UNKNOWN } type; + unsigned width; + unsigned addr_width; + unsigned data_width; + + bool is_unknown() const { return type == TYPE::UNKNOWN; } + bool is_bv() const { return type == TYPE::BV; } + bool is_array() const { return type == TYPE::MEM; } + + /// for unknown type + RfMapVarType() : type(TYPE::UNKNOWN) {} + /// for bit-vector type + RfMapVarType(unsigned w) : type(TYPE::BV), width(w) {} + /// for array type + RfMapVarType(unsigned a, unsigned d) + : type(TYPE::MEM), addr_width(a), data_width(d) {} + unsigned unified_width() const { + return type == RfMapVarType::TYPE::BV ? width : data_width; + } + + std::string to_string() const { + if (is_unknown()) + return "(unknown)"; + if (is_bv()) + return "(_ BitVec " + std::to_string(width) + ")"; + return "(Array (_ BitVec " + std::to_string(addr_width) + ") (_ BitVec " + + std::to_string(data_width) + "))"; + } +}; + +class RfVarTypeOrig { +public: + enum class VARTYPE { + NOTVAR, /*also unknown type*/ + ILAS, /*state var*/ + ILAI, /*ila input*/ + RTLV, /*rtl signal*/ + DEFINE_VAR, /*defined vars*/ + INTERNAL /* those already translated: + like __CYCLE_CNT__, __START__*/ + }; + + VARTYPE var_ref_type; + RfMapVarType type; + + // constructur + RfVarTypeOrig() : var_ref_type(VARTYPE::NOTVAR) {} + RfVarTypeOrig(const RfVarTypeOrig& r) + : var_ref_type(r.var_ref_type), type(r.type) {} + + RfVarTypeOrig& operator=(const RfVarTypeOrig&) = default; + +}; // class RfVarType + +} // namespace rfmap +} // namespace ilang + +#endif // ILANG_RFMAP_VARTYPE_H__ diff --git a/include/ilang/rfmap-in/verilog_rfmap.h b/include/ilang/rfmap-in/verilog_rfmap.h new file mode 100644 index 000000000..412cd0a61 --- /dev/null +++ b/include/ilang/rfmap-in/verilog_rfmap.h @@ -0,0 +1,254 @@ +/// \file Verilog Verification Refinement Map Interface Class +/// External Refinement Map Interface Class +/// --- Hongce Zhang (hongcez@princeton.edu) + +#ifndef ILANG_VERILOG_RFMAP_H__ +#define ILANG_VERILOG_RFMAP_H__ + +#include +#include +#include +#include +#include +#include + +namespace ilang { +namespace rfmap { + +// ---------------------- varmap ------------------------------- // + +/* +"model names" : { + "ILA" : "SomeNameHere", + "RTL" : "SomeNameHere" +} +*/ + +typedef verilog_expr::VExprAst::VExprAstPtr RfExpr; +typedef verilog_expr::VExprAstVar::VExprAstVarPtr RfVar; + +/* +"ILA_mem_state_var_2" : { // case 4 : external RTL +memory "wen" : "", "waddr" : "", + "wdata" : "", + "ren" : "", + "raddr" : "", + "rdata" : "" +}, +*/ + +struct SingleVarMap { + /// a single refinement string, will be initialized to NULL + RfExpr single_map; + /// a list of pair of string + std::vector> cond_map; +}; + +struct ExternalMemPortMap { + bool wport_mapped; + bool rport_mapped; + SingleVarMap wen_map; + SingleVarMap waddr_map; + SingleVarMap wdata_map; + SingleVarMap ren_map; + SingleVarMap raddr_map; + SingleVarMap rdata_map; + ExternalMemPortMap() : wport_mapped(false), rport_mapped(false) {} +}; // struct ExternalMemPortMap + +struct IlaVarMapping { + enum class StateVarMapType { SINGLE, CONDITIONAL, EXTERNMEM } type; + /// a single refinement string + SingleVarMap single_map; + /// the standard 6-port map + std::vector externmem_map; +}; // struct IlaVarMapping + +struct RtlInterfaceMapping { + /// "CLOCK" : { "clkA" : "wclk", "clkB" : ["rclk", "clk"] } + // name of the clock domain -> list of clock pins + std::map> clock_domain_defs; + + // "RESET" : "reset", // you can have a list of signals here + std::set reset_pins; + // "NRESET" : ["nreset1", "nreset2"], // like this + std::set nreset_pins; + // "CUSTOMRESET" : {"name" : "input-pin", ...} + std::map> custom_reset_domain_defs; + // "INPUT/INPUTs/INPUT-ports", + std::map input_port_connection; +}; // struct RtlInterfaceMapping + +typedef std::vector OneBitSignalSequence; + +struct ResetSpecification { + // rtl state var -> value map + std::map initial_state; + // reset cycle : unsigned int + unsigned reset_cycle; + // customized reset sequence + std::map custom_reset_sequence; + // default constructor + ResetSpecification() : reset_cycle(1) {} +}; // ResetSpecification + +struct ClockSpecification { + struct factor { + unsigned high; + unsigned low; + unsigned offset; + }; + + unsigned gcm_period; + // per-clock domain specification, name -> sequence + std::map custom_clock_sequence; + // specified by the factor + std::map custom_clock_factor; +}; // ClockSpecification + +struct UninterpretedFunctionApplication { + struct Apply { + RfExpr result_map; + std::vector arg_map; + }; + std::vector func_applications; +}; // UninterpretedFunctionApplication + +struct GeneralVerilogMonitor { + struct VarDef { + enum class var_type { REG, WIRE } type; + unsigned width; + }; // VarDef + + std::string verilog_inline; // handle concatnation/load from file etc + std::string verilog_append; // + std::map var_defs; + std::set var_uses; + bool keep_for_invariant; + + GeneralVerilogMonitor() : keep_for_invariant(false) {} +}; // GeneralVerilogMonitor + +struct ValueRecorder { + RfExpr condition; + RfExpr value; + unsigned width; + + ValueRecorder() : condition(nullptr), value(nullptr), width(0) {} +}; + +// this is not directly used +struct SignalDelay { + + SignalDelay(const RfExpr& _signal, unsigned n_cycle) + : delay_type(delay_typeT::SINGLE), signal(_signal), num_cycle(n_cycle), + width(0), upper_bnd(0) {} + + SignalDelay(const RfExpr& _signal, unsigned n_cycle, unsigned u_bnd) + : delay_type(u_bnd == 0 ? delay_typeT::TO_INFINITE : delay_typeT::RANGE), + signal(_signal), num_cycle(n_cycle), width(0), upper_bnd(u_bnd) {} + + enum class delay_typeT { SINGLE, RANGE, TO_INFINITE } delay_type; + RfExpr signal; + unsigned num_cycle; + unsigned width; + + unsigned upper_bnd; +}; + +struct AuxVar { + std::string name; + RfExpr val; + unsigned width; + AuxVar(const std::string & n) : name(n), width(0) {} +}; + +struct PhaseTracker { + struct Assignment { + std::string LHS; // a state name + RfExpr RHS; // a rhs expression + }; + typedef std::vector Action; + struct Rule { + std::string stage_name; + RfExpr enter_rule; // this is not using Verilog signals + RfExpr exit_rule; + Action enter_action; + Action exit_action; + }; + + using VarDef = GeneralVerilogMonitor::VarDef; + // name to defs + std::map var_defs; + std::map event_alias; + std::vector rules; +}; + +// ---------------------- inst-cond ------------------------------- // + +struct InstructionCompleteCondition { + std::string instruction_name; + enum class ConditionType { BOUND, SIGNAL } type; + unsigned ready_bound; + unsigned max_bound; + std::vector start_condition; + RfExpr ready_signal; + + InstructionCompleteCondition() + : ready_bound(0), max_bound(0), ready_signal(nullptr) {} + bool is_readybound() const { return type == ConditionType::BOUND; } + bool is_readysignal() const { return type == ConditionType::SIGNAL; } +}; // + +struct VerilogRefinementMap { + // ---------------------- varmap ------------------------------- // + /// State mapping section + std::map ila_state_var_map; + /// State mapping section + std::map ila_input_var_map; + /// RTL interface connection specification + RtlInterfaceMapping rtl_interface_connection; + /// reset section + ResetSpecification reset_specification; + /// clock section + ClockSpecification clock_specification; + /// Uninterpreted function map : func-name -> applications + std::map uf_application; + /// "additional mapping" section + std::vector additional_mapping; + /// "assumptions" section + std::vector assumptions; + /// Customized Verilog Monitor + std::map phase_tracker; + std::map value_recorder; + std::map customized_monitor; + std::map direct_aux_vars; + + // ---------------------- inst-cond ------------------------------- // + std::map inst_complete_cond; + bool global_inst_complete_set; + InstructionCompleteCondition global_inst_complete_cond; + std::vector global_invariants; + + // ---------------------- supplementary_info ------------------------------- + // // + std::map + width_info; // this is needed in case our width inference failed + std::map + range_info; // this is needed in case our width inference failed + + // member function : return true if checking passed + bool SelfCheckField() const; + + // from JSON + VerilogRefinementMap(const std::string& varmap_json_file, + const std::string& instcond_json_file); + + static RfExpr ParseRfExprFromString(const std::string& in); + +}; // VerilogRefinementMap + +} // namespace rfmap +} // namespace ilang + +#endif // ILANG_VERILOG_RFMAP_H__ diff --git a/include/ilang/rtl_verify.h b/include/ilang/rtl_verify.h new file mode 100644 index 000000000..364fcb8c9 --- /dev/null +++ b/include/ilang/rtl_verify.h @@ -0,0 +1,265 @@ +/// \file +/// The header for the c++ API. + +#ifndef ILANG_RTL_VERIFY_CONFIG_H__ +#define ILANG_RTL_VERIFY_CONFIG_H__ + +#include +#include +#include +#include + + +/// \namespace ilang +/// Defines the configurations for Verilog refinement checking +namespace ilang { + + + // ----------- Verification Settings -------------- // + /// Type of the backend: + /// Pono, JasperGold + /// YOSYS is for generic btor generation + enum class ModelCheckerSelection { + NONE = 0, + JASPERGOLD = 2, + YOSYS = 128, // 10000000 + // CHC = YOSYS + 8, // 10001000 + // Z3PDR = CHC + 1, // 10001001 + // ELD_CEGAR = CHC + 2, // 10001010 + // GRAIN_SYGUS = CHC + 4, // 10001100 + // ABCPDR = YOSYS + 16, // 10010000 + PONO = YOSYS + 32, // 10100000 + RELCHC = YOSYS + 64 // 11000000 + }; // enum class ModelCheckerSelection + +/// Verilog Target Generation Configuration + typedef struct _vtg_config { + /// Preheader Content : will use in all targets + std::string WrapperPreheader; + /// Set the targets: instructions/invariants/both + enum { INST, INV, BOTH } target_select; + /// If not an empty string, then only check for that instruction + std::string CheckThisInstructionOnly; + /// Ensure the instruction will not be reseted while + /// in the whole execution of checking instruction + /// from reseted --> to forever + bool InstructionNoReset; // true + /// Ensure the design will not be reseted + /// from reseted --> to forever + bool InvariantCheckNoReset; // true + /// Does not insert assertions of variable mapping + /// if an instruction does not update that var + bool OnlyCheckInstUpdatedVars; // true + /// Whether to pass Verilog node name in reference + /// generation + bool VerilogGenPassNodeName; + /// if false : assume (cond |-> reg == value) + /// if true : assume ((START || STARTED) && cond && not_triggered) + /// |-> reg == value + bool EnforcingValueRecorderForOnlyOneCycle; + + + /// Configure the behavior of INV target, if false, + /// will not check synthesized invariants by default (unless call + /// generateInvariantVerificationTarget) if true, will check by default + enum class _validate_synthesized_inv { + NOINV, + CANDIDATE, + CONFIRMED, + ALL + } ValidateSynthesizedInvariant; + + // ----------- Options for Pono settings -------------- // + /// Whether to force the instruction check to start from reset state + bool ForceInstCheckReset; + /// Whether to always instiantiate quantifers in refinement + bool ForceQuantifierInstantiationInRfExpr; + /// If true, will generate a separate check that cover the + /// the commit condition + bool CheckInstrCommitSatisfiable; + /// For Pono target generator : whether to force NEW/OLD port declaration + enum class PortDeclStyleT { AUTO = 0, NEW = 1, OLD = 2 } PortDeclStyle; + + /// Pono VCD output + std::string PonoVcdOutputName; + /// Binary location of Pono + std::string PonoPath; + /// For Pono backend: do we add (* keep *)? default true, however, it can be + /// buggy, so you can disable it if you want + bool PonoAddKeep; + /// For Pono backend: the default engine (ind by default) + /// other options: like bmc, bmc-sp, ind, interp, mbic3, + /// ic3bits, ic3ia, msat-ic3ia, ic3sa, sygus-pdr + std::string PonoEngine; + /// For Pono backend: what more options to add + std::string PonoOtherOptions; + /// whether to force dot reference check in the generation + /// if you expect to use Pono on the it, yes, you need to + /// use the default setting : NOTIFY_PANIC + /// in some rare cases, you may want to use JasperGold after it + /// in that case, it is okay to just ignore it + enum class PonoDotReferenceNotify_t { + NOTIFY_PANIC = 0, + NOTIFY_WARNING = 1, + NOTIFY_IGNORE = 2 + } PonoDotReferenceNotify; + /// whether to generator a script to be used with JG as well + bool PonoGenJgScript; + // The bound of BMC, default 127 + unsigned MaxBound; + /// Only enforce var eq on updated vars, should not be used + bool OnlyAssumeUpdatedVarsEq; // should be false + + // ----------- Options for Yosys SMT-LIB2 Generator -------------- // + /// The path to yosys, if yosys is not in the PATH, default empty + std::string YosysPath; + /// whether to explicitly turn the undriven net to input + /// for smt-backend, the top level undriven net seems always turned into + /// inputs, but the lower level may not + bool YosysUndrivenNetAsInput; + /// Whether to flatten the module hierarchy + bool YosysSmtFlattenHierarchy; + /// Whether to flatten the datatypes + bool YosysSmtFlattenDatatype; + /// Whether to word-blast array or use SMT Array + /// By default will word-blast + bool YosysSmtArrayForRegFile; + /// How to encode Verilog state + /// DataSort seems to use PDR engine + enum class YosysStateSortT { + UnintepretedFunc /*not supported*/, + Datatypes, /*by default*/ + BitVec /*optional for property check, not inv-syn*/ + } YosysSmtStateSort; + /// for invariant synthesis do we keep memory abstraction in Verilog + /// you can keep it true, untill the invariant refers to some memory there + bool InvariantSynthesisKeepMemory; + /// for invariant check, do we keep memory abstraction in Verilog + bool InvariantCheckKeepMemory; + /// Whether to assume the old invariants when check for reachability + /// It seems for Z3, setting this to be false is faster (I don't know why) + /// For grain-enhance, this will be (internally) overwritten to be true + bool InvariantSynthesisReachableCheckKeepOldInvariant; + /// Whether to set undriven net in yosys as 0. In general this should not + /// be needed, but for some reason, PONO is unhappy sometimes. + bool YosysSetUndrivenZero; + + // ----------- Options for CHC Solver -------------- // + /// CHC, whether to turn array into individual registers + bool ChcWordBlastArray; + /// CHC, whether to force assumption on the init + bool ChcAssumptionsReset; + /// CHC, whether to force assumption on the next T + bool ChcAssumptionNextState; + /// CHC, whether to force assumption on the end T + bool ChcAssumptionEnd; + + // ----------- Options for Btor Output -------------- // + /// in the format of "xxxx [options] %btorfile% [options]" + /// will replace %btorfile% with the file + std::string BtorGenericCmdline; + /// CHC, whether to turn array into individual registers + bool BtorSingleProperty; + /// CHC, whether to force assumption on the init + bool BtorAddCommentsInOutputs; + + /* TODO: future work: + bool YosysAssumptionOverlyConstrainedCheck; + */ + + // ----------- Options for Z3/Grain/ABC Solver -------------- // + /// The path to Z3, if "z3" is not in the PATH, default empty + std::string Z3Path; + /// The path to Grain, if "grain" is not in the PATH, default empty + std::string GrainPath; + /// Grain Configuration Options + std::vector GrainOptions; + /// FreqHorn style (cocistyple, cnfstyle) + bool GrainHintsUseCnfStyle; + /// The path to ABC, if "abc" is not in the PATH, default empty + std::string AbcPath; + + // ----------- Extended Options for ABC Solver -------------- // + /// ABC option : whether to use gate-level abstraction + bool AbcUseGla; + /// ABC option : gate-level abstraction time limit + unsigned AbcGlaTimeLimit; + /// ABC option : gate-level abstraction frame limit + unsigned AbcGlaFrameLimit; + /// ABC option : whether to use correlation analysis + bool AbcUseCorr; + /// ABC option : whether to pass aiger to ABC + bool AbcUseAiger; + /// ABC option : whether to minimize invariant + bool AbcMinimizeInv; + /// ABC option : the way to handle assumptions + enum class AbcAssumptionStyle_t { + AigMiterExtraOutput = + 0, // Use AIG's extra output to represent, cannot use with GLA + AssumptionRegister = + 1 // Use extra register, may have issues in interpreting the invariant + } AbcAssumptionStyle; + + // ----------- Refinement Sanity Check Options-------------- // + /// if true: will check if the value recorder is triggered multiple times + bool SanityCheck_ValueRecorderOverlyConstrained; + /// if true: will check if the value recorder is not triggered before commit + bool SanityCheck_ValueRecorderTriggeredBeforeCommit; + + /// The default constructor for default values + _vtg_config() + : target_select(BOTH), CheckThisInstructionOnly(""), + InstructionNoReset(true), InvariantCheckNoReset(false), + OnlyCheckInstUpdatedVars(true), VerilogGenPassNodeName(false), + EnforcingValueRecorderForOnlyOneCycle(true), + ValidateSynthesizedInvariant(_validate_synthesized_inv::ALL), + + // ----------- Options for Pono settings -------------- // + ForceInstCheckReset(false), + ForceQuantifierInstantiationInRfExpr(false), + CheckInstrCommitSatisfiable(false), + PortDeclStyle(PortDeclStyleT::AUTO), + PonoVcdOutputName("cex.vcd"), PonoAddKeep(false), PonoEngine("ind"), + PonoOtherOptions(""), + PonoDotReferenceNotify(PonoDotReferenceNotify_t::NOTIFY_PANIC), + PonoGenJgScript(false), + MaxBound(127), OnlyAssumeUpdatedVarsEq(false), + + // ----------- Options for Pono script -------------- // + // PonoAssumptionOverlyConstrainedCheck(false), + + // ----------- Options for Yosys SMT-LIB2 Generator -------------- // + YosysUndrivenNetAsInput(true), YosysSmtFlattenHierarchy(true), + YosysSmtFlattenDatatype(false), + YosysSmtArrayForRegFile(true), + YosysSmtStateSort(YosysStateSortT::Datatypes), + InvariantSynthesisKeepMemory(true), InvariantCheckKeepMemory(true), + InvariantSynthesisReachableCheckKeepOldInvariant(false), + YosysSetUndrivenZero(false), + + // ----------- Options for CHCs -------------- // + ChcWordBlastArray(true), ChcAssumptionsReset(false), + ChcAssumptionNextState(false), ChcAssumptionEnd(false), + + // ----------- Options for Btor Output -------------- // + /// CHC, whether to turn array into individual registers + BtorSingleProperty(true), + /// CHC, whether to force assumption on the init + BtorAddCommentsInOutputs(false), + + // ----------- Options for Z3/Grain/ABC Solver -------------- // + GrainHintsUseCnfStyle(true), + + // ----------- Options for ABC -------------- // + AbcUseGla(false), AbcGlaTimeLimit(500), AbcGlaFrameLimit(200), + AbcUseCorr(false), AbcUseAiger(true), AbcMinimizeInv(false), + AbcAssumptionStyle(AbcAssumptionStyle_t::AigMiterExtraOutput), + + // ----------- Options for Refinement Sanity Checks -------------- // + SanityCheck_ValueRecorderOverlyConstrained(true), + SanityCheck_ValueRecorderTriggeredBeforeCommit(true) {} + } RtlVerifyConfig; + +} // namespace ilang + +#endif // ILANG_RTL_VERIFY_CONFIG_H__ diff --git a/include/ilang/verilog-in/verilog_analysis.h b/include/ilang/verilog-in/verilog_analysis.h index 7915a2117..1267ed6b5 100644 --- a/include/ilang/verilog-in/verilog_analysis.h +++ b/include/ilang/verilog-in/verilog_analysis.h @@ -63,7 +63,8 @@ class SignalInfoReg : public SignalInfoBase { SignalInfoReg(ast_reg_declaration* def, const std::string& full_name, VerilogAnalyzerBase::hierarchical_name_type tp, const std::map* const width_info, - const VerilogAnalyzer* _ana); + const VerilogAnalyzer* _ana, + const std::map* const range_info); /// Return its definition ast_reg_declaration* get_def() { return _def; } }; // class SignalInfoPort @@ -187,7 +188,8 @@ class VerilogAnalyzer : public VerilogAnalyzerBase { /// Find a signal SignalInfoBase get_signal(const std::string& net_name, - const std::map* const width_info = NULL) const; + const std::map* const width_info = NULL, + const std::map* const range_info = NULL) const; /// Return the location of a module's endmodule statement vlg_loc_t get_endmodule_loc(const std::string& inst_name) const; /// Return the module name of a net --- will check if the module names are diff --git a/include/ilang/verilog-in/verilog_analysis_wrapper.h b/include/ilang/verilog-in/verilog_analysis_wrapper.h index 11d5f52c3..3ba79903b 100644 --- a/include/ilang/verilog-in/verilog_analysis_wrapper.h +++ b/include/ilang/verilog-in/verilog_analysis_wrapper.h @@ -122,11 +122,15 @@ class SignalInfoBase { const VerilogAnalyzerBase::hierarchical_name_type _type; /// its location of definition const VerilogAnalyzerBase::vlg_loc_t _loc; + /// addr range size of the array, 0 if not array + const unsigned _addr_range_size; public: /// --------------------- ACCESSORS ------------------- /// /// Return the width of the signal virtual unsigned get_width() const { return _width; } + /// Return the addrwidth of the signal + virtual unsigned get_addr_range_size() const {return _addr_range_size; } /// Whether is a IO signal virtual bool is_io_sig() const { return VerilogAnalyzerBase::is_io_sig(_type); @@ -164,8 +168,9 @@ class SignalInfoBase { /// --------------------- ACCESSORS ------------------- /// SignalInfoBase(const std::string& n, const std::string& h, unsigned w, const VerilogAnalyzerBase::hierarchical_name_type& typ, - const VerilogAnalyzerBase::vlg_loc_t& loc) - : _name(n), _hierarchical_name(h), _width(w), _type(typ), _loc(loc) {} + const VerilogAnalyzerBase::vlg_loc_t& loc, + unsigned aw) + : _name(n), _hierarchical_name(h), _width(w), _type(typ), _loc(loc), _addr_range_size(aw) {} /// implicit copy constructor }; // class SignalInfoBase @@ -242,7 +247,8 @@ class VerilogInfo { SignalInfoBase get_signal(const std::string& net_name) const; /// Find a signal (and use the width info, if width is unknown) SignalInfoBase get_signal(const std::string& net_name, - const std::map& width_info) const; + const std::map& width_info, + const std::map& range_info) const; /// whether this analyzer is in bad state bool in_bad_state() const; diff --git a/include/ilang/verilog-out/verilog_gen.h b/include/ilang/verilog-out/verilog_gen.h index 3005506eb..28c181e2c 100644 --- a/include/ilang/verilog-out/verilog_gen.h +++ b/include/ilang/verilog-out/verilog_gen.h @@ -164,22 +164,20 @@ class VerilogGeneratorBase { bool expand_mem; /// whether to collect the ite(c, v, unknown) thing bool collect_ite_unknown_update; + /// add (* keep *) before the internal mem? + bool add_keep_for_internal_mem; /// Constructor, set default value, ExternalMem : false, function: internal /// module VlgGenConfig( // provide the default settings bool ExternalMem = true, funcOption funcOpt = funcOption::Internal, bool gen_start = false, bool pass_name = false, bool rand_init = false, - bool ExpandMem = false, bool CollectIteUnknownUpdate = false) + bool ExpandMem = false, bool CollectIteUnknownUpdate = false, + bool AddKeepForInternalMem = true) : extMem(ExternalMem), fcOpt(funcOpt), start_signal(gen_start), pass_node_name(pass_name), reg_random_init(rand_init), - expand_mem(ExpandMem), collect_ite_unknown_update(CollectIteUnknownUpdate) {} - /// Overwrite configuration, used by vtarget gen - VlgGenConfig(const VlgGenConfig& c, bool ExternalMem, funcOption funcOpt, - bool gen_start, bool rand_init, bool ExpandMem, bool CollectIteUnknownUpdate) - : extMem(ExternalMem), fcOpt(funcOpt), start_signal(gen_start), - pass_node_name(c.pass_node_name), reg_random_init(rand_init), - expand_mem(ExpandMem), collect_ite_unknown_update(CollectIteUnknownUpdate) {} + expand_mem(ExpandMem), collect_ite_unknown_update(CollectIteUnknownUpdate), + add_keep_for_internal_mem(AddKeepForInternalMem) {} // set other fields if there are such need (?) }; // end of struct VlgGenConfig @@ -483,6 +481,13 @@ class VerilogGenerator : public VerilogGeneratorBase { void ExportIla(const InstrLvlAbsPtr& ila_ptr_); /// Parse an instruction void ExportTopLevelInstr(const InstrPtr& instr_ptr_); + + /// for VerilogVerificationTargetGen + // get valid signal name in advace + std::string GetValidSignalName(const InstrPtr& instr_ptr_) const; + // get decode signal name in advace + std::string GetDecodeSignalName(const InstrPtr& instr_ptr_) const; + }; // class VerilogGenerator }; // namespace ilang diff --git a/include/ilang/vtarget-out/.gitignore b/include/ilang/vtarget-out/.gitignore new file mode 100644 index 000000000..0b255b650 --- /dev/null +++ b/include/ilang/vtarget-out/.gitignore @@ -0,0 +1,2 @@ +deprecated/* + diff --git a/include/ilang/vtarget-out/absmem.h b/include/ilang/vtarget-out/absmem.h deleted file mode 100644 index 7211d41bd..000000000 --- a/include/ilang/vtarget-out/absmem.h +++ /dev/null @@ -1,85 +0,0 @@ -/// \file Header for generating abstract memory -// --- Hongce Zhang - -#ifndef ILANG_VTARGET_OUT_ABS_MEM_H__ -#define ILANG_VTARGET_OUT_ABS_MEM_H__ - -#include -#include -#include -#include -#include - -#include -#include - -namespace ilang { - -/// \brief a struct to store abstract memory -struct VlgAbsMem { - // ---------------------- TYPES --------------- // - /// type of read port - using rport_t = VerilogGeneratorBase::rport_t; - /// type of write port - using wport_t = VerilogGeneratorBase::wport_t; - - // ---------------------- MEMBERS --------------- // - /// verilog read ports - std::map vlg_rports; - /// verilog write ports - std::map vlg_wports; - /// ila read ports - std::map ila_rports; - /// ila write ports - std::map ila_wports; - - /// whether to abstract the memory read - bool read_abstract; - /// how many are considered to be concrete - unsigned concrete_level; - /// widths , 0 stands for unknown - unsigned data_width; - /// widths , 0 stands for unknown - unsigned addr_width; - /// which ila state it is mapped to - std::string ila_map_name; - /// the name in rfmap - std::string mem_name; - /// the assumptions it has - std::vector assumpts; - -private: - /// Whether the module is checked to be okay - bool checked; - /// track what kind of memory need to export, positive for w-abs, negative for - /// r-w-abs - static std::set concrete_level_encountered; - -public: - // ------------------CONSTRUCTOR ----------- // - /// do nothing - VlgAbsMem(); - // ------------------ MEMBERS ------------- // - /// SetAddrWidth, if already set, and different -> error - void SetAddrWidth(unsigned w); - /// SetDataWidth - void SetDataWidth(unsigned w); - /// Get the memeq signal name - std::string MemEQSignalName() const; - /// Get the memory module instantiation string, it will also - /// add signals when necessary - std::string - GeneratingMemModuleSignalsInstantiation(VerilogGeneratorBase& gen, - const std::string& endCond); - /// Output the memory module to the stream - static void OutputMemFile(std::ostream& os, bool avoid_issue_stage); - /// Return true if there are abs mem used (strategy : ALL -> AUTO) - static bool hasAbsMem(); - /// reset concrete_level (per-target). - static void ClearAbsMemRecord(); - -}; // class VlgAbsMem - -}; // namespace ilang - -#endif // ILANG_VTARGET_OUT_ABS_MEM_H__ diff --git a/include/ilang/vtarget-out/directive.h b/include/ilang/vtarget-out/directive.h index 03b42fd94..418a52203 100644 --- a/include/ilang/vtarget-out/directive.h +++ b/include/ilang/vtarget-out/directive.h @@ -12,7 +12,6 @@ #include #include -#include namespace ilang { @@ -65,13 +64,6 @@ class IntefaceDirectiveRecorder { using wport_t = VerilogGeneratorBase::wport_t; public: - /// Return if a string 'c' begins with string 's' - static bool beginsWith(const std::string& c, const std::string& s); - /// Return true if 'c' is special input directive - static bool isSpecialInputDir(const std::string& c); - /// Check for compatibility - static bool isSpecialInputDirCompatibleWith(const std::string& c, - const SignalInfoBase& vlg_sig); /// Check if an interface needs to be declare as top module I/O // static bool interfaceDeclareTop(const std::string & c); // --- more to added @@ -89,44 +81,10 @@ class IntefaceDirectiveRecorder { void VlgAddTopInteface(VerilogGeneratorBase& gen) const; /// Used to tell this module about the refinement relations void RegisterInterface(const SignalInfoBase& vlg_sig, - const std::string& refstr, ila_input_checker_t chk, - ila_mem_checker_t mget); + const std::string& refstr); /// Register the extra wire to connect (for extra wire) void RegisterExtraWire(const std::string& io_name, const std::string& outside_name); - /// Register the connection of signals related to a memory - std::string ConnectMemory(const std::string& directive, - const std::string& ila_state_name, - const std::map& rports, - const std::map& wports, - int ila_addr_width, int ila_data_width, - bool abs_read); - /// Insert memory abstractions' assumptions - void InsertAbsMemAssmpt(assmpt_inserter_t inserter); - - /// Setting the memory abstraction name, but does not enforce any equality - /// there - void SetMemName(const std::string& directive, - const std::string& ila_state_name, bool abs_read); - - /// Setting the memory abstraction name, and width... - /// but does not enforce any equality - /// there - void SetMemNameAndWidth(const std::string& directive, - const std::string& ila_state_name, bool abs_read, int, - int); - - /// Return the memory instantiation string - std::string GetAbsMemInstString(VerilogGeneratorBase& gen, - const std::string& endCond); - /// Check if some port has been connected, - /// if not, connect it to the wire_name (will not create wire!) - /// if connected, will warn and refuse to connect - /// should be called before GetAbsMemInstString - /// return the wire name to create (but no need to create if it is empty) - std::pair - KeepMemoryPorts(const std::string& mem_name, const std::string& port_name, - bool caller_build_wire); protected: /// a sanity check for module instantiation string gen, check if all the vlg @@ -148,8 +106,6 @@ class IntefaceDirectiveRecorder { vlg_sig_vec_t output_wires; /// wires to be declared as just wire vlg_sig_vec_t internal_wires; - /// ila-mem-name -> abs - std::map abs_mems; /// whether to reset this vlg (reset to rst or dummy_reset) bool _reset_vlg; @@ -159,22 +115,6 @@ class IntefaceDirectiveRecorder { **MEM**.? */ -/// \brief a class to handle state-mapping directives in the refinement -/// relations -class StateMappingDirectiveRecorder { -public: - // ------------------------------ HELPER - // ------------------------------------// - /// a function to determine if a state map refstr is special directie (**???) - static bool isSpecialStateDir(const std::string& c); - /// a function to determine if a state map refstr is special directie (**???) - static bool isSpecialStateDirMem(const std::string& c); - /// a function to determine if a function name is an unknown special directive - static bool isSpecialUnknownFunctionName(const std::string &funcname); - /// a function to determine if a function (no arg) is an unknown special directive - static bool isSpecialUnknownFunction(const FuncPtr &func_ptr); -}; // class StateMappingDirectiveRecorder - }; // namespace ilang #endif // ILANG_VTARGET_OUT_DIRECTIVE_H__ diff --git a/include/ilang/vtarget-out/inv-syn/grain_inv_parse.h b/include/ilang/vtarget-out/inv-syn/grain_inv_parse.h index c4dddefa3..0493b7f1a 100644 --- a/include/ilang/vtarget-out/inv-syn/grain_inv_parse.h +++ b/include/ilang/vtarget-out/inv-syn/grain_inv_parse.h @@ -56,9 +56,9 @@ class GrainInvariantParser : public SmtlibInvariantParser { // -------------- CALLBACK FNs ------------------- // - /// this is actually declare variables - virtual void declare_function(const std::string& name, SortPtrT sort) override; + virtual void declare_function(const std::string& name, + SortPtrT sort) override; /// this function receives the final assert result // virtual void assert_formula(SmtTermInfoVlgPtr result) override; -- use the @@ -75,10 +75,9 @@ class GrainInvariantParser : public SmtlibInvariantParser { SortPtrT sort) override; /// call back function to apply an uninterpreted function /// fall-through case if it is not an defined op, if failed, return NULL - virtual TermPtrT - mk_function(const std::string& name, SortPtrT sort, - const std::vector& idx, - const std::vector& args) override; + virtual TermPtrT mk_function(const std::string& name, SortPtrT sort, + const std::vector& idx, + const std::vector& args) override; /// call back function to make a number term // virtual SmtTermInfoVlgPtr mk_number(const std::string & rep, int width, int @@ -87,8 +86,7 @@ class GrainInvariantParser : public SmtlibInvariantParser { /// this function receives the final result virtual void define_function(const std::string& func_name, const std::vector& args, - SortPtrT ret_type, - TermPtrT func_body) override; + SortPtrT ret_type, TermPtrT func_body) override; }; // class GrainInvariantParser diff --git a/include/ilang/vtarget-out/inv-syn/inv_syn_cegar.h b/include/ilang/vtarget-out/inv-syn/inv_syn_cegar.h deleted file mode 100644 index bde891143..000000000 --- a/include/ilang/vtarget-out/inv-syn/inv_syn_cegar.h +++ /dev/null @@ -1,240 +0,0 @@ -/// \file The header for invariant synthesis --- using CEGAR loop -// ---Hongce Zhang - -#ifndef ILANG_VTARGET_OUT_INV_SYN_CEGAR_H__ -#define ILANG_VTARGET_OUT_INV_SYN_CEGAR_H__ - -#include -#ifdef INVSYN_INTERFACE - -#include -#include -#include - -#include -#include - -namespace ilang { - -/// \brief the implementation of the synthesizer class -class InvariantSynthesizerCegar { - -public: - // -------------------- TYPES ------------------ // - /// Type of the verification backend - using verify_backend_selector = VlgVerifTgtGenBase::backend_selector; - /// Type of configuration - using vtg_config_t = VlgVerifTgtGenBase::vtg_config_t; - /// Type of invariant synthesis backend - using synthesis_backend_selector = - VlgVerifTgtGenBase::synthesis_backend_selector; - /// Type of the cegar loop status - /// next to verify, wait_for_verify_result - /// next to synthesis, wait_for_synthesis_result - typedef enum { NEXT_V, V_RES, NEXT_S, S_RES, DONE, FAILED } cegar_status; - /// Type of advanced parameter - using advanced_parameters_t = VlgVerifTgtGenBase::advanced_parameters_t; - /// the type of invariant check result - enum _inv_check_res_t { INV_PROVED, INV_INVALID, INV_UNKNOWN }; - /// additional width info - typedef std::map additional_width_info_t; - -public: - // -------------------- CONSTRUCTOR ------------------ // - /// to create an inv-syn target - InvariantSynthesizerCegar( - const std::vector& implementation_include_path, - const std::vector& implementation_srcs, - const std::string& implementation_top_module, - const std::string& refinement_variable_mapping, - const std::string& refinement_conditions, const std::string& output_path, - const InstrLvlAbsPtr& ila_ptr, verify_backend_selector vbackend, - synthesis_backend_selector sbackend, - const vtg_config_t& vtg_config = vtg_config_t(), - const VerilogGenerator::VlgGenConfig& config = - VerilogGenerator::VlgGenConfig()); - /// no copy constructor, please. - InvariantSynthesizerCegar(const InvariantSynthesizerCegar&) = delete; - /// no assignment, please. - InvariantSynthesizerCegar& - operator=(const InvariantSynthesizerCegar&) = delete; - -public: - // -------------------- HELPERs ------------------ // - // to do things separately, you can provide the run function your self - // or even do it step by step - /// to generate targets using the current invariants - void GenerateVerificationTarget(); - /// to generate targets using the provided invariants - void GenerateVerificationTarget(const std::vector& invs); - /// to generate a target to validate the given and synthesize invariants - void GenerateInvariantVerificationTarget(); - /// to extract verification result - void ExtractVerificationResult(bool autodet = true, bool pass = true, - const std::string& res_file = "", - const std::string& mod_inst_name = ""); - - /// genenate a target to extract smt - void GenerateTargetAndExtractSmt(); - /// get the width of a certain state - unsigned QueryRtlStateWidth(const std::string& name) const; - - /// remove some states from cex - void CexGeneralizeRemoveStates(const std::vector&); - /// to generate synthesis target - void GenerateSynthesisTarget(); - /// to extract reachability test result - void ExtractSynthesisResult(bool autodet = true, bool reachable = true, - const std::string& res_file = ""); - /// to extract reachability test result, this will extract to candidate - /// invariant - void ExtractAbcSynthesisResultForEnhancement(InvariantInCnf& incremental_cnf, - bool autodet = true, - bool reachable = true); - - /// run Verification : returns eq true/false - bool virtual RunVerifAuto(const std::string& script_selection, - const std::string& pid_fname = "", - bool run_test = false, - unsigned timeout = 0); - /// run Synthesis : returns reachable/not - bool virtual RunSynAuto(bool run_test = false); - - /// Forcing to accept all the candidate invariants - void AcceptAllCandidateInvariant(); - /// Remove potentially failing candidate invariants (conservative approach - /// remove all candidates) - void PruneCandidateInvariant(); - /// Supply Verilog candidate invariants - void SupplyCandidateInvariant(const std::string& vlg); - /// Clear all the candidate invariants - void ClearAllCandidateInvariants(); - - // -------------------- GrainChc ------------------ // - void ChangeGrainSyntax(const std::vector& syn); - /// generate enhancement target and run it - /// return false, if grain fails - bool WordLevelEnhancement(const InvariantInCnf& incremental_cnf, - bool run_test = false); - /// get the current inv in cnf - const InvariantInCnf& GetCurrentCnfEnhance() const; - /// merge cnfs - void MergeCnf(const InvariantInCnf& incremental_cnf); - /// extra variable for enhancement, so not really a cnf - void ExtractInvariantVarForEnhance( - size_t inv_idx, InvariantInCnf& incremental_cnf, bool per_clause, - const std::set& vars_to_remove = {}); - - // -------------------- ACCESSOR ------------------ // - /// return back state - bool in_bad_state() const { return bad_state; } - /// check state - bool check_in_bad_state() const; - /// load the smt_design file - void LoadDesignSmtInfo(const std::string& fn); - /// Here we directly expose the runnable script names (They will never be used - /// as inputs) - const std::vector& GetRunnableTargetScriptName() const; - /// Here you can restore the design information - void LoadPrevStatisticsState(const std::string& fn); - /// Here you can get the design information - DesignStatistics GetDesignStatistics() const; - /// Here you can extract the invariants and export them if needed - const InvariantObject& GetInvariants() const; - /// remove a confirmed invariant - void RemoveInvariantsByIdx(size_t idx); - /// Here you can extract the invariants and export them if needed - const InvariantObject& GetCandidateInvariants() const; - /// load confirmed invariants from file - void LoadInvariantsFromFile(const std::string& fn); - /// load invariants as candidates from file - void LoadCandidateInvariantsFromFile(const std::string& fn); - -protected: - // -------------------- MEMBERS ------------------ // - /// the found invariants, in Verilog expression - InvariantObject inv_obj; - /// the found invariants, in CNF (only for ABC), will be merged to - InvariantInCnf inv_cnf; - /// the temporary invariants (that might not be inductive) - InvariantObject inv_candidate; - /// the pointer to a cegar object - std::unique_ptr cex_extract; - /// vlg-module instance name; - std::string vlg_mod_inst_name; - /// the status of the loop - cegar_status status; - /// the SMT-LIB2 information of the design - std::shared_ptr design_smt_info; - /// the supplementary information - additional_width_info_t additional_width_info; - /// is in back state? - bool bad_state; - /// the round id - unsigned round_id; - /// the runnable script name after each target gen - std::vector runnable_script_name; - /// verification result - bool verification_pass; - /// verification result -- the vcd full name/path - std::string vcd_file_name; - /// synthesis result - bool cex_reachable; - /// the synthesis result file - std::string synthesis_result_fn; - /// the invariant type - enum cur_inv_tp { NONE, GRAIN_CHC, CHC, CEGAR_ABC } current_inv_type; - - // -------------------------------------------------- - // for book-keeping purpose - // -------------------------------------------------- - /// path for verilog includes - std::vector implementation_incl_path; - /// path for verilog sources - std::vector implementation_srcs_path; - /// the top module name - std::string implementation_top_module_name; - /// path to the variable mapping file - std::string refinement_variable_mapping_path; - /// path to the conditions - std::string refinement_condition_path; - /// the output path (must exists) - std::string _output_path; - /// the pointer to ILA - InstrLvlAbsPtr _host; - /// the verification backend - verify_backend_selector v_backend; - /// the synthesis backend selection - synthesis_backend_selector s_backend; - /// the target generator configuration - vtg_config_t _vtg_config; - /// the verilog gnerator configuration - VerilogGenerator::VlgGenConfig _vlg_config; - - // -------------------------------------------------- - // for statistics purpose - // -------------------------------------------------- - /// time for equivalence checking - double eqcheck_time; - /// time for validation of invariants - double inv_validate_time; - /// time for z3 proving attempt - double inv_proof_attempt_time; - /// the synthesis time of invariants : chc/sygus-chc/sygus-dp - double inv_syn_time; - /// the enhance ment time - double inv_enhance_time; - /// the series of synthesis time - std::vector inv_syn_time_series; - -public: - /// total cands there are - long long total_grain_cand; - -}; // class InvariantSynthesizerCegar - -}; // namespace ilang - -#endif // INVSYN_INTERFACE - -#endif // ILANG_VTARGET_OUT_INV_SYN_CEGAR_H__ diff --git a/include/ilang/vtarget-out/inv-syn/vtarget_gen_inv_abc.h b/include/ilang/vtarget-out/inv-syn/vtarget_gen_inv_abc.h deleted file mode 100644 index 99f951e67..000000000 --- a/include/ilang/vtarget-out/inv-syn/vtarget_gen_inv_abc.h +++ /dev/null @@ -1,179 +0,0 @@ -/// \file Verilog Verification Target Generator -- generating Abc target -/// (design-only, same as the invariant target) -/// We use Abc to convert Verilog to smt-lib2, and then -/// it will be parsed and re-format by smt-io -/// and use that information, it will create horn clauses -/// This file should not be included, as it requires the impl. -// ---Hongce Zhang - -#ifndef VTARGET_GEN_INV_ABC_H__ -#define VTARGET_GEN_INV_ABC_H__ - -#include -#ifdef INVSYN_INTERFACE - -#include -#include -#include -#include -#include -#include -#include - -namespace ilang { - -class VlgSglTgtGen_Abc; - -/// \brief a class to store (and generate) the problem for Abc -class Abc_problem { - friend class VlgSglTgtGen_Abc; - /// Type of assertions and assumptions - typedef std::vector prop_t; - /// Type of a problem --- we can handle multiple several problems (may not - /// needed) - typedef struct { - // the name in [??] - // std::string problem_name; - /// will be conjuncted and put in the question - prop_t exprs; - } problem_t; - /// set of problems - typedef std::map problemset_t; - -protected: - /// assumptions are not shared (unlike CoSA) - problemset_t assumptions; - /// problems are splitted into items - problemset_t assertions; - -}; // Abc_problem - -/// \brief a class to interface w. Abc -class VlgSglTgtGen_Abc : public VlgSglTgtGen { - -public: - /// using the target type - using target_type_t = VlgSglTgtGen::target_type_t; - /// a tuple to store all related info for modification - using info_t = VerilogModifier::info_t; - /// filename -> (lineno, varname, is_port_sig) vec - using fn_l_map_t = VerilogModifier::fn_l_map_t; - /// Type of advanced parameter - using advanced_parameters_t = VlgVerifTgtGenBase::advanced_parameters_t; - /// Type of Abc target - using _chc_target_t = VlgVerifTgtGenBase::_chc_target_t; - -public: - // --------------------- CONSTRUCTOR ---------------------------- // - /// - /// \param[in] output path (ila-verilog, wrapper-verilog, problem.txt, - /// run-verify-by-???, modify-impl, it there is ) \param[in] pointer to the - /// instruction \param[in] the default configuration for outputing verilog - /// \param[in] the variable map - /// \param[in] the conditions - /// \param[in] pointer to verify info class - /// \param[in] verilog module name - /// \param[in] ila module name, - /// \param[in] all implementation sources - /// \param[in] all include paths - /// \param[in] which backend to use, it needs this info to gen proper - /// properties - VlgSglTgtGen_Abc( - const std::string& output_path, // will be a sub directory of the - // output_path of its parent - const InstrPtr& instr_ptr, // which could be an empty pointer, and it will - // be used to verify invariants - const InstrLvlAbsPtr& ila_ptr, - const VerilogGenerator::VlgGenConfig& config, nlohmann::json& _rf_vmap, - nlohmann::json& _rf_cond, VlgTgtSupplementaryInfo& _sup_info, - VerilogInfo* _vlg_info_ptr, const std::string& vlg_mod_inst_name, - const std::string& ila_mod_inst_name, const std::string& wrapper_name, - const std::vector& implementation_srcs, - const std::vector& include_dirs, - const vtg_config_t& vtg_config, backend_selector vbackend, - synthesis_backend_selector sbackend, const target_type_t& target_tp, - advanced_parameters_t* adv_ptr, bool generate_proof, - _chc_target_t Abc_target, bool useGLA, bool useCORR, bool useAIGER); - - // --------------------- Destructor ---------------------------- // - /// do nothing - virtual ~VlgSglTgtGen_Abc(); - -protected: - /// Abc problem generate - Abc_problem _problems; - /// Abc problem file name - std::string blif_fname; - /// Abc problem file name (aiger file), if aiger_fname is not empty, it will - /// be do aiger - std::string aiger_fname; - /// Abc script 'run.sh' name - std::string abc_run_script_name; - /// the invariants on the design - std::vector vlg_mod_inv_vec; - /// the synthesis backend - synthesis_backend_selector s_backend; - /// whether to require a proof - bool generate_proof; - /// whether a cex is provided - bool has_cex; - /// what are the targets - _chc_target_t chc_target; - /// Use abc gla? - const bool useGla; - /// Use abc corr - const bool useCorr; - /// send abc aiger - const bool useAiger; - /// disallow GLA if use extra output as assumptions - bool disallowGla; - -protected: - /// Add a direct assumption -- needed by base class - virtual void add_a_direct_assumption(const std::string& aspt, - const std::string& dspt) override; - /// Add a direct assertion -- needed by base class - virtual void add_a_direct_assertion(const std::string& asst, - const std::string& dspt) override; - - /// Pre export work : add assume and asssert to the top level - void virtual PreExportProcess() override; - /// export the script to run the verification - virtual void Export_script(const std::string& script_name) override; - /// export extra things: the Abc script, the smt template - virtual void Export_problem(const std::string& extra_name) override; - /// export the memory abstraction (implementation) - /// Yes, this is also implementation specific, (jasper may use a different - /// one) - virtual void Export_mem(const std::string& mem_name) override; - /// For jasper, this means do nothing, for Abc, you need to add (*keep*) - virtual void Export_modify_verilog() override; - -private: - /// generate the wrapper's smt first - void generate_blif(const std::string& blif_name, - const std::string& ys_script_name); - /// generate the wrapper's aig first - void generate_aiger(const std::string& blif_name, - const std::string& aiger_name, - const std::string& map_name, - const std::string& ys_script_name); - -public: - /// overwrite the Export - void virtual ExportAll(const std::string& wrapper_name, - const std::string& ila_vlg_name, - const std::string& script_name, - const std::string& extra_name, - const std::string& mem_name) override; - - /// It is okay to instantiation - virtual void do_not_instantiate(void) override{}; - -}; // class VlgVerifTgtGenAbc - -}; // namespace ilang - -#endif // INVSYN_INTERFACE - -#endif // VTARGET_GEN_INV_ABC_H__ diff --git a/include/ilang/vtarget-out/inv-syn/vtarget_gen_inv_chc.h b/include/ilang/vtarget-out/inv-syn/vtarget_gen_inv_chc.h deleted file mode 100644 index 5d8df9320..000000000 --- a/include/ilang/vtarget-out/inv-syn/vtarget_gen_inv_chc.h +++ /dev/null @@ -1,174 +0,0 @@ -/// \file Verilog Verification Target Generator -- generating CHC target -/// (design-only, same as the invariant target) -/// We use chc to convert Verilog to smt-lib2, and then -/// it will be parsed and re-format by smt-io -/// and use that information, it will create horn clauses -/// This file should not be included, as it requires the impl. -// ---Hongce Zhang - -#ifndef VTARGET_GEN_INV_CHC_H__ -#define VTARGET_GEN_INV_CHC_H__ - -#include -#ifdef INVSYN_INTERFACE - -#include -#include -#include -#include -#include -#include -#include -#include - -namespace ilang { - -class VlgSglTgtGen_Chc; - -/// \brief a class to store (and generate) the problem for Chc -class Chc_problem { - friend class VlgSglTgtGen_Chc; - /// Type of assertions and assumptions - typedef std::vector prop_t; - /// Type of a problem --- we can handle multiple several problems (may not - /// needed) - typedef struct { - // the name in [??] - // std::string problem_name; - /// will be conjuncted and put in the question - prop_t exprs; - } problem_t; - /// set of problems - typedef std::map problemset_t; - -protected: - /// assumptions are not shared (unlike CoSA) - problemset_t assumptions; - /// problems are splitted into items - problemset_t assertions; - -}; // Chc_problem - -/// \brief a class to interface w. Chc -class VlgSglTgtGen_Chc : public VlgSglTgtGen { - -public: - /// using the target type - using target_type_t = VlgSglTgtGen::target_type_t; - /// a tuple to store all related info for modification - using info_t = VerilogModifier::info_t; - /// filename -> (lineno, varname, is_port_sig) vec - using fn_l_map_t = VerilogModifier::fn_l_map_t; - /// Type of advanced parameter - using advanced_parameters_t = VlgVerifTgtGenBase::advanced_parameters_t; - /// Type of chc target - using _chc_target_t = VlgVerifTgtGenBase::_chc_target_t; - -public: - // --------------------- CONSTRUCTOR ---------------------------- // - /// - /// \param[in] output path (ila-verilog, wrapper-verilog, problem.txt, - /// run-verify-by-???, modify-impl, it there is ) \param[in] pointer to the - /// instruction \param[in] the default configuration for outputing verilog - /// \param[in] the variable map - /// \param[in] the conditions - /// \param[in] pointer to verify info class - /// \param[in] verilog module name - /// \param[in] ila module name, - /// \param[in] all implementation sources - /// \param[in] all include paths - /// \param[in] which backend to use, it needs this info to gen proper - /// properties - VlgSglTgtGen_Chc( - const std::string& output_path, // will be a sub directory of the - // output_path of its parent - const InstrPtr& instr_ptr, // which could be an empty pointer, and it will - // be used to verify invariants - const InstrLvlAbsPtr& ila_ptr, - const VerilogGenerator::VlgGenConfig& config, nlohmann::json& _rf_vmap, - nlohmann::json& _rf_cond, VlgTgtSupplementaryInfo& _sup_info, - VerilogInfo* _vlg_info_ptr, const std::string& vlg_mod_inst_name, - const std::string& ila_mod_inst_name, const std::string& wrapper_name, - const std::vector& implementation_srcs, - const std::vector& include_dirs, - const vtg_config_t& vtg_config, backend_selector vbackend, - synthesis_backend_selector sbackend, const target_type_t& target_tp, - advanced_parameters_t* adv_ptr, bool generate_proof, - _chc_target_t chc_target); - - // --------------------- Destructor ---------------------------- // - /// do nothing - virtual ~VlgSglTgtGen_Chc(); - -protected: - /// Chc problem generate - Chc_problem _problems; - /// Chc problem file name - std::string chc_prob_fname; - /// Chc script 'run.sh' name - std::string chc_run_script_name; - /// the invariants on the design - std::vector vlg_mod_inv_vec; - /// the synthesis backend - synthesis_backend_selector s_backend; - /// the smt info of the design - std::shared_ptr design_smt_info; - /// whether to require a proof - bool generate_proof; - /// whether a cex is provided - bool has_cex; - /// what are the targets - _chc_target_t chc_target; - -protected: - /// Add a direct assumption -- needed by base class - virtual void add_a_direct_assumption(const std::string& aspt, - const std::string& dspt) override; - /// Add a direct assertion -- needed by base class - virtual void add_a_direct_assertion(const std::string& asst, - const std::string& dspt) override; - - /// Pre export work : add assume and asssert to the top level - void virtual PreExportProcess() override; - /// export the script to run the verification - virtual void Export_script(const std::string& script_name) override; - /// export extra things: the chc script, the smt template - virtual void Export_problem(const std::string& extra_name) override; - /// export the memory abstraction (implementation) - /// Yes, this is also implementation specific, (jasper may use a different - /// one) - virtual void Export_mem(const std::string& mem_name) override; - /// For jasper, this means do nothing, for chc, you need to add (*keep*) - virtual void Export_modify_verilog() override; - -private: - /// Convert the smt file to CHC -- datatype encoding - void convert_smt_to_chc_datatype(const std::string& smt_fname, - const std::string& chc_fname); - /// Convert the smt file to CHC -- bitvector encoding - void convert_smt_to_chc_bitvec(const std::string& smt_fname, - const std::string& chc_fname, - const std::string& wrapper_mod_name); - /// generate the wrapper's smt first - void design_only_gen_smt(const std::string& smt_name, - const std::string& ys_script_name); - -public: - /// overwrite the Export - void virtual ExportAll(const std::string& wrapper_name, - const std::string& ila_vlg_name, - const std::string& script_name, - const std::string& extra_name, - const std::string& mem_name) override; - /// accessor of the design info - std::shared_ptr GetDesignSmtInfo() const; - /// It is okay to instantiation - virtual void do_not_instantiate(void) override{}; - -}; // class VlgVerifTgtGenChc - -}; // namespace ilang - -#endif // INVSYN_INTERFACE - -#endif // VTARGET_GEN_INV_CHC_H__ diff --git a/include/ilang/vtarget-out/inv-syn/vtarget_gen_inv_enhance.h b/include/ilang/vtarget-out/inv-syn/vtarget_gen_inv_enhance.h deleted file mode 100644 index 76c4c78f8..000000000 --- a/include/ilang/vtarget-out/inv-syn/vtarget_gen_inv_enhance.h +++ /dev/null @@ -1,187 +0,0 @@ -/// \file Verilog Verification Target Generator -- generating CHC target to -/// enhance invariant (design-only, same as the invariant target) We use yosys -/// to convert Verilog to smt-lib2, and then it will be parsed and re-format by -/// smt-io and use that information, it will create horn clauses This file -/// should not be included by the user code, as it requires the impl. - -/// This is for Grain only invariant enhancements/strengthening by syntax -// ---Hongce Zhang - -#ifndef VTARGET_GEN_INV_ENHANCE_H__ -#define VTARGET_GEN_INV_ENHANCE_H__ - -#include -#ifdef INVSYN_INTERFACE - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -namespace ilang { - -class VlgSglTgtGen_Chc_wCNF; - -/// \brief a class to store (and generate) the problem for Chc -class Chc_enhance_problem { - friend class VlgSglTgtGen_Chc_wCNF; - /// Type of assertions and assumptions - typedef std::vector prop_t; - /// Type of a problem --- we can handle multiple several problems (may not - /// needed) - typedef struct { - // the name in [??] - // std::string problem_name; - /// will be conjuncted and put in the question - prop_t exprs; - } problem_t; - /// set of problems - typedef std::map problemset_t; - -protected: - /// assumptions are not shared (unlike CoSA) - problemset_t assumptions; - /// problems are splitted into items - problemset_t assertions; - -}; // Chc_enhance_problem - -/// \brief a class to interface w. Chc -class VlgSglTgtGen_Chc_wCNF : public VlgSglTgtGen { - -public: - /// using the target type - using target_type_t = VlgSglTgtGen::target_type_t; - /// a tuple to store all related info for modification - using info_t = VerilogModifier::info_t; - /// filename -> (lineno, varname, is_port_sig) vec - using fn_l_map_t = VerilogModifier::fn_l_map_t; - /// Type of advanced parameter - using advanced_parameters_t = VlgVerifTgtGenBase::advanced_parameters_t; - /// Type of chc target - using _chc_target_t = VlgVerifTgtGenBase::_chc_target_t; - -public: - // --------------------- CONSTRUCTOR ---------------------------- // - /// - /// \param[in] output path (ila-verilog, wrapper-verilog, problem.txt, - /// run-verify-by-???, modify-impl, it there is ) \param[in] pointer to the - /// instruction \param[in] the default configuration for outputing verilog - /// \param[in] the variable map - /// \param[in] the conditions - /// \param[in] pointer to verify info class - /// \param[in] verilog module name - /// \param[in] ila module name, - /// \param[in] all implementation sources - /// \param[in] all include paths - /// \param[in] which backend to use, it needs this info to gen proper - /// properties - VlgSglTgtGen_Chc_wCNF( - const std::string& output_path, // will be a sub directory of the - // output_path of its parent - const InstrPtr& instr_ptr, // which could be an empty pointer, and it will - // be used to verify invariants - const InstrLvlAbsPtr& ila_ptr, - const VerilogGenerator::VlgGenConfig& config, nlohmann::json& _rf_vmap, - nlohmann::json& _rf_cond, VlgTgtSupplementaryInfo& _sup_info, - VerilogInfo* _vlg_info_ptr, const std::string& vlg_mod_inst_name, - const std::string& ila_mod_inst_name, const std::string& wrapper_name, - const std::vector& implementation_srcs, - const std::vector& include_dirs, - const vtg_config_t& vtg_config, backend_selector vbackend, - synthesis_backend_selector sbackend, const target_type_t& target_tp, - advanced_parameters_t* adv_ptr, bool generate_proof, - _chc_target_t chc_target); - - // --------------------- Destructor ---------------------------- // - /// do nothing - virtual ~VlgSglTgtGen_Chc_wCNF(); - -protected: - /// Chc problem generate - Chc_enhance_problem _problems; - /// Chc problem file name - std::string chc_prob_fname; - /// Chc script 'run.sh' name - std::string chc_run_script_name; - /// the invariants on the design - std::vector vlg_mod_inv_vec; - /// the synthesis backend - synthesis_backend_selector s_backend; - /// the smt info of the design - std::shared_ptr design_smt_info; - /// whether to require a proof - bool generate_proof; - /// whether a cex is provided - bool has_cex; - /// what are the targets - _chc_target_t chc_target; - -protected: - /// Add a direct assumption -- needed by base class - virtual void add_a_direct_assumption(const std::string& aspt, - const std::string& dspt) override; - /// Add a direct assertion -- needed by base class - virtual void add_a_direct_assertion(const std::string& asst, - const std::string& dspt) override; - - /// Pre export work : add assume and asssert to the top level - void virtual PreExportProcess() override; - /// export the script to run the verification - virtual void Export_script(const std::string& script_name) - override; // do nothing - should not be used - virtual void Export_script(const std::string& script_name, - const std::string& cnf_fn); - /// export extra things: the chc script, the smt template - virtual void Export_problem(const std::string& extra_name) override; - /// export the memory abstraction (implementation) - /// Yes, this is also implementation specific, (jasper may use a different - /// one) - virtual void Export_mem(const std::string& mem_name) override; - /// For jasper, this means do nothing, for chc, you need to add (*keep*) - virtual void Export_modify_verilog() override; - /// Export the cnf for Grain's reference - void Export_cnf(const InvariantInCnf& cnf, const std::string& cnf_fn) const; - /// Export the cnf for wky's Grain's reference - void Export_coci(const InvariantInCnf& cnf, const std::string& cnf_fn) const; - -private: - /// Convert the smt file to CHC -- datatype encoding - void convert_smt_to_chc_datatype(const std::string& smt_fname, - const std::string& chc_fname); - /// generate the wrapper's smt first - void design_only_gen_smt(const std::string& smt_name, - const std::string& ys_script_name); - -public: - /// do nothing - should not be used - void virtual ExportAll(const std::string& wrapper_name, - const std::string& ila_vlg_name, - const std::string& script_name, - const std::string& extra_name, - const std::string& mem_name) override; - /// overwrite the Export, use this one: - void virtual ExportAll(const std::string& wrapper_name, - const std::string& ila_vlg_name, - const std::string& script_name, - const std::string& extra_name, - const std::string& mem_name, - const std::string& cnf_name, - const InvariantInCnf& cnf); - /// accessor of the design info - std::shared_ptr GetDesignSmtInfo() const; - /// It is okay to instantiation - virtual void do_not_instantiate(void) override{}; - -}; // class VlgVerifTgtGenChc - -}; // namespace ilang - -#endif // INVSYN_INTERFACE - -#endif // VTARGET_GEN_INV_ENHANCE_H__ diff --git a/include/ilang/vtarget-out/supplementary_info.h b/include/ilang/vtarget-out/supplementary_info.h deleted file mode 100644 index b832ffd5f..000000000 --- a/include/ilang/vtarget-out/supplementary_info.h +++ /dev/null @@ -1,60 +0,0 @@ -/// \file Header for Verilog Verification Supplementary Information -/// this is useful to provide our tool information that it cannot -/// or may not be able to figure out itself - -#ifndef SUPPLEMENTARY_INFO_H__ -#define SUPPLEMENTARY_INFO_H__ - -#include "nlohmann/json.hpp" - -#include -#include - -namespace ilang { - -/// \brief the class to hold supplementary information -struct VlgTgtSupplementaryInfo { - - // ----------------------- TYPE ------------------------ // - struct reset_config_t { - /// whether to enforce no reset constraint - bool no_reset_after_starting_state; - /// how many cycles should reset signal holds - unsigned reset_cycles; - /// the reset sequence: list of (signal name -> value) map (not supported - /// yet) - // we anticipate in the reset sequence, you don't need a wide signal - std::vector> reset_sequence; - /// Future work: reset state: signame -> signal value (valid vlog expr) (not - /// supported yet) - std::map reset_state; - /// Constructor, set default parameters - reset_config_t() : no_reset_after_starting_state(false), reset_cycles(1) {} - }; // struct reset_config_t - - // ----------------------- MEMBERS ------------------------ // - /// the width info - std::map width_info; - /// how to treat a memory , the reason of using bool instead of enum is - /// because I don't want the verilog-out part to include this file, so its - /// type should be a generic type - typedef bool memory_export_type; -#define memory_export_type_internal false -#define memory_export_type_external true - /// the map of memory - std::map memory_export; - /// the port to keep : memory_name -> (port and its connector) - std::map> memory_ports; - /// The reset annotation for CoSA & Yosys (Jasper should be fine...) - reset_config_t cosa_yosys_reset_config; - - // ----------------------- METHODS ------------------------ // - /// Constructor - default - VlgTgtSupplementaryInfo(); - /// Parse annotations from Json - void FromJson(nlohmann::json& vmap); -}; // struct VlgTgtSupplementaryInfo - -}; // namespace ilang - -#endif // SUPPLEMENTARY_INFO_H__ diff --git a/include/ilang/vtarget-out/var_extract.h b/include/ilang/vtarget-out/var_extract.h deleted file mode 100644 index b8e4ec89c..000000000 --- a/include/ilang/vtarget-out/var_extract.h +++ /dev/null @@ -1,68 +0,0 @@ -/// \file Header of variable extractor -/// This is use to extract variable from expression (string) -/// See whether it is ila-state(I/O) / vlg-state and ... -/// and change their name if needed and generate a string -// --- Hongce Zhang - -#ifndef ILANG_VTARGET_OUT_VAR_EXTRACT_H__ -#define ILANG_VTARGET_OUT_VAR_EXTRACT_H__ - -#include -#include -#include - -namespace ilang { - -class VarExtractor { - -public: - /// Type of tokens - typedef enum { KEEP = 0, ILA_S, ILA_IN, VLG_S, UNKN_S, NUM } token_type; - /// Tokens - typedef std::pair token; - /// Type of function pointer of string judger - typedef std::function str_j; - /// Type of function pointer of string replacer - typedef std::function str_r; - -protected: - /// token from parsed string - std::vector _tokens; - /// a pointer to string judger (is ila state?) - str_j _is_ila_state; - /// a pointer to string judge (is ila input?) - str_j _is_ila_input; - /// a pointer to string judger (is vlg signal?) - str_j _is_vlg_sig; - -public: - // ---------------------- CONSTRUCTOR ----------------- // - VarExtractor(str_j is_ila_state, str_j is_ila_input, str_j is_vlg_sig); - // ---------------------- METHODS ----------------- // - /// Parse a string and populate the token vector, will clear the _tokens - /// storage - void - ParseToExtract(const std::string& in, - bool force_vlg_statename = - false); // the later is only used in dealing w. invariants - /// Traverse the tokens, see if replace is needed - void ForEachTokenReplace( - str_r replacer); // you can return the same so it will not be replaced - /// Get back string - std::string GenString() const; - /// A shortcut to do all at once - std::string Replace(const std::string& in, bool force_vlg_statename, - str_r replacer) { - ParseToExtract(in, force_vlg_statename); - ForEachTokenReplace(replacer); - return GenString(); - } - // ---------------------- HELPERS ----------------- // - static bool contains_mod_inst_name(const std::string& s, - const std::string& mi); - -}; // class VarExtractor - -}; // namespace ilang - -#endif // ILANG_VTARGET_OUT_VAR_EXTRACT_H__ diff --git a/include/ilang/vtarget-out/vlg_mod.h b/include/ilang/vtarget-out/vlg_mod.h index 04a6de47f..403e5944c 100644 --- a/include/ilang/vtarget-out/vlg_mod.h +++ b/include/ilang/vtarget-out/vlg_mod.h @@ -89,7 +89,8 @@ class VerilogModifier { /// \param[in] the style: 0 auto deteremined, 1 Old, 2 New VerilogModifier(VerilogInfo* _vlg_info_ptr, port_decl_style_t port_decl_style, bool add_keep_or_not, - const std::map& _sup_width_info); // + const std::map& _sup_width_info, + const std::map& _sup_range_info); // /// Destructor: ~VerilogModifier(); /// do the work : read from fin and append to fout, fout needs to be open with @@ -101,8 +102,10 @@ class VerilogModifier { /// record the name to add a keep there void RecordKeepSignalName(const std::string& vname); /// record the name to add related wires - vlg_sig_t RecordConnectSigName(const std::string& vlg_sig_name, - const std::string& suffix = ""); + void RecordConnectSigName(const std::string& vname, // wirename + const std::string& hierarchy, // + const std::string& last_level_name, unsigned width); + /// record the stmt to be added to a module void RecordAdditionalVlgModuleStmt(const std::string& stmt, const std::string& mod_instance_name); @@ -127,6 +130,8 @@ class VerilogModifier { bool _add_keep_or_not; /// the supplementary width info const std::map& sup_width_info; + /// the supplementary range info + const std::map& sup_range_info; protected: // --------------- HELPERS --------------------------- // diff --git a/include/ilang/vtarget-out/vtarget_gen.h b/include/ilang/vtarget-out/vtarget_gen.h index f67548cfe..2428fd155 100644 --- a/include/ilang/vtarget-out/vtarget_gen.h +++ b/include/ilang/vtarget-out/vtarget_gen.h @@ -6,6 +6,7 @@ #define ILANG_VTARGET_OUT_VTARGET_GEN_H__ #include +#include #include #include #include @@ -24,249 +25,25 @@ class VlgVerifTgtGenBase { ex_info_t(const std::string& r) : range(r) {} }; - // ----------- Verification Settings -------------- // - /// Type of the backend: - /// CoSA, JasperGold, CHC for chc solver, AIGER for abc - // YOSYS is for invariant synthesis use - typedef enum { - NONE = 0, - COSA = 1, - JASPERGOLD = 2, - YOSYS = 128, // 10000000 - CHC = YOSYS + 8, // 10001000 - Z3PDR = CHC + 1, // 10001001 - ELD_CEGAR = CHC + 2, // 10001010 - GRAIN_SYGUS = CHC + 4, // 10001100 - ABCPDR = YOSYS + 16, // 10010000 - BTOR_GENERIC = YOSYS + 32,// 10100000 - RELCHC = YOSYS + 64 // 11000000 - } backend_selector; - /// Type of invariant synthesis backend - typedef enum { - Z3 = Z3PDR ^ YOSYS, - GRAIN = GRAIN_SYGUS ^ YOSYS, - ABC = ABCPDR ^ YOSYS, - ELDERICA = ELD_CEGAR ^ YOSYS,// 0001010 - NOSYN = BTOR_GENERIC ^ YOSYS // 1000000 - } synthesis_backend_selector; - /// Type of the chc target - enum _chc_target_t { CEX, INVCANDIDATE, GENERAL_PROPERTY }; - /// Verilog Target Generation Configuration - typedef struct _vtg_config { - /// Preheader Content : will use in all targets - std::string WrapperPreheader; - /// Set the targets: instructions/invariants/both - enum { INST, INV, BOTH } target_select; - /// If not an empty string, then only check for that instruction - std::string CheckThisInstructionOnly; - /// Ensure the instruction will not be reseted while - /// in the whole execution of checking instruction - /// from reseted --> to forever - bool InstructionNoReset; // true - /// Does not insert assertions of variable mapping - /// if an instruction does not update that var - bool OnlyCheckInstUpdatedVars; // true - /// A shortcut for SetUpdate(s, Ite(c, v, __unknown__() )) - /// will only gnerate map like : ( ila.c => ila.v == vlg.v ) - /// In this case, you don't need to deal with unknown in func map - /// nor do you need to create a special refinement map - /// function has to be defined as __unknown__X - bool IteUnknownAutoIgnore; // false - /// whether to remove the extra issue cycle and starts from reset - bool VerificationSettingAvoidIssueStage; - /// Configure the behavior of INV target, if false, - /// will not check synthesized invariants by default (unless call - /// generateInvariantVerificationTarget) if true, will check by default - enum _validate_synthesized_inv { - NOINV, - CANDIDATE, - CONFIRMED, - ALL - } ValidateSynthesizedInvariant; - - // ----------- Options for CoSA settings -------------- // - /// Do we set separate problems for different var map (CoSA only) - bool PerVariableProblemCosa; // true - /// Whether to abstract the memory read - bool MemAbsReadAbstraction; // false - /// Whether to force the instruction check to start from reset state - bool ForceInstCheckReset; - /// For COSA target generator : whether to force NEW/OLD port declaration - enum { AUTO = 0, NEW = 1, OLD = 2 } PortDeclStyle; - /// Generate a jg script to help validate cosa? - bool CosaGenJgTesterScript; - /// generate the trace for all variables? or just the relevent variables - bool CosaFullTrace; - /// For CoSA backend: do we add (* keep *)? default true, however, it can be - /// buggy, so you can disable it if you want - bool CosaAddKeep; - /// whether to force dot reference check in the generation - /// if you expect to use cosa on the it, yes, you need to - /// use the default setting : NOTIFY_PANIC - /// in some rare cases, you may want to use JasperGold after it - /// in that case, it is okay to just ignore it - enum CosaDotReferenceNotify_t { - NOTIFY_PANIC = 0, - NOTIFY_WARNING = 1, - NOTIFY_IGNORE = 2 - } CosaDotReferenceNotify; - // The bound of BMC, default 127 - unsigned MaxBound; - /// Only enforce var eq on updated vars, should not be used - bool OnlyAssumeUpdatedVarsEq; // should be false - - - // ----------- Options for CoSA script -------------- // - /// If not empty, the generated script will include the path of Cosa - std::string CosaPath; - /// If not empty, the generated script will include sourcing a script - std::string CosaPyEnvironment; - /// A choice of solver (in the script) - std::string CosaSolver; - /// Whether the Solver should generate vcd trace - bool CosaGenTraceVcd; - /// Assumption overly constrained check - bool CosaAssumptionOverlyConstrainedCheck; - /// other CoSA options - std::string CosaOtherSolverOptions; - - // ----------- Options for Yosys SMT-LIB2 Generator -------------- // - /// The path to yosys, if yosys is not in the PATH, default empty - std::string YosysPath; - /// whether to explicitly turn the undriven net to input - /// for smt-backend, the top level undriven net seems always turned into - /// inputs, but the lower level may not - bool YosysUndrivenNetAsInput; - /// Whether to flatten the module hierarchy - bool YosysSmtFlattenHierarchy; - /// Whether to flatten the datatypes - bool YosysSmtFlattenDatatype; - /// when used in property verification, show prove? - bool YosysPropertyCheckShowProof; - /// Whether to word-blast array or use SMT Array - /// By default will word-blast - bool YosysSmtArrayForRegFile; - /// How to encode Verilog state - /// DataSort seems to use PDR engine - typedef enum { - UnintepretedFunc /*not supported*/, - Datatypes, /*by default*/ - BitVec /*optional for property check, not inv-syn*/ - } _state_sort_t; - _state_sort_t YosysSmtStateSort; - /// for invariant synthesis do we keep memory abstraction in Verilog - /// you can keep it true, untill the invariant refers to some memory there - bool InvariantSynthesisKeepMemory; - /// for invariant check, do we keep memory abstraction in Verilog - bool InvariantCheckKeepMemory; - /// Whether to assume the old invariants when check for reachability - /// It seems for Z3, setting this to be false is faster (I don't know why) - /// For grain-enhance, this will be (internally) overwritten to be true - bool InvariantSynthesisReachableCheckKeepOldInvariant; - - // ----------- Options for CHC Solver -------------- // - /// CHC, whether to turn array into individual registers - bool ChcWordBlastArray; - /// CHC, whether to force assumption on the init - bool ChcAssumptionsReset; - /// CHC, whether to force assumption on the next T - bool ChcAssumptionNextState; - /// CHC, whether to force assumption on the end T - bool ChcAssumptionEnd; - - // ----------- Options for Btor Output -------------- // - /// in the format of "xxxx [options] %btorfile% [options]" - /// will replace %btorfile% with the file - std::string BtorGenericCmdline; - /// CHC, whether to turn array into individual registers - bool BtorSingleProperty; - /// CHC, whether to force assumption on the init - bool BtorAddCommentsInOutputs; - - // ----------- Options for Z3/Grain/ABC Solver -------------- // - /// The path to Z3, if "z3" is not in the PATH, default empty - std::string Z3Path; - /// The path to Grain, if "grain" is not in the PATH, default empty - std::string GrainPath; - /// Grain Configuration Options - std::vector GrainOptions; - /// FreqHorn style (cocistyple, cnfstyle) - bool GrainHintsUseCnfStyle; - /// The path to ABC, if "abc" is not in the PATH, default empty - std::string AbcPath; - - // ----------- Extended Options for ABC Solver -------------- // - /// ABC option : whether to use gate-level abstraction - bool AbcUseGla; - /// ABC option : gate-level abstraction time limit - unsigned AbcGlaTimeLimit; - /// ABC option : gate-level abstraction frame limit - unsigned AbcGlaFrameLimit; - /// ABC option : whether to use correlation analysis - bool AbcUseCorr; - /// ABC option : whether to pass aiger to ABC - bool AbcUseAiger; - /// ABC option : whether to minimize invariant - bool AbcMinimizeInv; - /// ABC option : the way to handle assumptions - typedef enum _abc_assumption_style_t { - AigMiterExtraOutput = - 0, // Use AIG's extra output to represent, cannot use with GLA - AssumptionRegister = - 1 // Use extra register, may have issues in interpreting the invariant - } AbcAssumptionStyle_t; - AbcAssumptionStyle_t AbcAssumptionStyle; - - // ----------- Extended Options for Grain -------------- // - /// The default constructor for default values - _vtg_config() - : target_select(BOTH), CheckThisInstructionOnly(""), - InstructionNoReset(true), OnlyCheckInstUpdatedVars(true), - IteUnknownAutoIgnore(false), - VerificationSettingAvoidIssueStage(false), - ValidateSynthesizedInvariant(ALL), - - // ----------- Options for CoSA settings -------------- // - PerVariableProblemCosa(false), MemAbsReadAbstraction(false), - ForceInstCheckReset(false), PortDeclStyle(AUTO), - CosaGenJgTesterScript(false), CosaFullTrace(false), CosaAddKeep(true), - CosaDotReferenceNotify(CosaDotReferenceNotify_t::NOTIFY_PANIC), - MaxBound(127), OnlyAssumeUpdatedVarsEq(false), - - // ----------- Options for CoSA script -------------- // - CosaPath(""), CosaPyEnvironment(""), CosaSolver(""), - CosaGenTraceVcd(true), CosaAssumptionOverlyConstrainedCheck(false), - CosaOtherSolverOptions(""), - - // ----------- Options for Yosys SMT-LIB2 Generator -------------- // - YosysUndrivenNetAsInput(true), YosysSmtFlattenHierarchy(true), - YosysSmtFlattenDatatype(false), YosysPropertyCheckShowProof(false), - YosysSmtArrayForRegFile(false), - YosysSmtStateSort(Datatypes), InvariantSynthesisKeepMemory(true), - InvariantCheckKeepMemory(true), - InvariantSynthesisReachableCheckKeepOldInvariant(false), - - // ----------- Options for CHCs -------------- // - ChcWordBlastArray(true), ChcAssumptionsReset(false), - ChcAssumptionNextState(false), ChcAssumptionEnd(false), - - // ----------- Options for Btor Output -------------- // - /// CHC, whether to turn array into individual registers - BtorSingleProperty(true), - /// CHC, whether to force assumption on the init - BtorAddCommentsInOutputs(false), + /// decide if a backend needs Yosys + static bool backend_needs_yosys(ModelCheckerSelection b) { + return (int(b) & int(ModelCheckerSelection::YOSYS)) == + int(ModelCheckerSelection::YOSYS); + } - // ----------- Options for Z3/Grain/ABC Solver -------------- // - GrainHintsUseCnfStyle(true), - - // ----------- Options for ABC -------------- // - AbcUseGla(false), AbcGlaTimeLimit(500), AbcGlaFrameLimit(200), - AbcUseCorr(false), AbcUseAiger(true), AbcMinimizeInv(false), - AbcAssumptionStyle(_abc_assumption_style_t::AigMiterExtraOutput) - - {} - } vtg_config_t; + /// Type of invariant synthesis backend + /*enum class synthesis_backend_selector { + // Z3 = int(ModelCheckerSelection::Z3PDR) ^ + int(ModelCheckerSelection::YOSYS), // 01001 GRAIN = + int(ModelCheckerSelection::GRAIN_SYGUS) ^ int(ModelCheckerSelection::YOSYS), // 01100 + ABC = int(ModelCheckerSelection::ABCPDR) ^ + int(ModelCheckerSelection::YOSYS), // 10000 ELDERICA = + int(ModelCheckerSelection::ELD_CEGAR) ^ int(ModelCheckerSelection::YOSYS), // 01010 + NOSYN = int(ModelCheckerSelection::YOSYS) // 1000000 } ;*/ + /// Type of the chc target + enum class _chc_target_t { CEX, INVCANDIDATE, GENERAL_PROPERTY }; + /// Advanced parameters used for invariant synthesizer /// should not be used by generat @@ -293,7 +70,7 @@ class VlgVerifTgtGenBase { // destructor : do nothing (make it virtual !!!) virtual ~VlgVerifTgtGenBase() {} /// check if a backend selector is valid - static bool isValidVerifBackend(backend_selector vbackend); + static bool isValidVerifBackend(ModelCheckerSelection vbackend); private: // avoid instantiation @@ -301,35 +78,31 @@ class VlgVerifTgtGenBase { }; // class VlgVerifTgtGenBase class VerilogVerificationTargetGenerator { -public: - /// Type of the backend - using backend_selector = VlgVerifTgtGenBase::backend_selector; - /// Type of the synthesis backend - using synthesis_backend_selector = - VlgVerifTgtGenBase::synthesis_backend_selector; - /// Type of configuration - using vtg_config_t = VlgVerifTgtGenBase::vtg_config_t; public: // --------------------- CONSTRUCTOR ---------------------------- // /// /// \param[in] implementation's include path (if it uses `include) /// \param[in] verilog's path, currently we only handle situation where all in - /// the same folder \param[in] name of the top module of the implementation, - /// leave "" to allow auto analysis \param[in] where to get variable mapping + /// the same folder + /// \param[in] name of the top module of the implementation, + /// leave "" to allow auto analysis + /// \param[in] where to get variable mapping /// \param[in] where to get refinement relation /// \param[in] output path (ila-verilog, wrapper-verilog, problem.txt, - /// run-verify-by-???, modify-impl, it there is ) \param[in] pointer to the - /// ila \param[in] the backend selector \param[in] (optional) the default - /// configuration for outputing verilog + /// run-verify-by-???, modify-impl, it there is ) + /// \param[in] pointer to the ila + /// \param[in] the backend selector + /// \param[in] (optional) the default + /// configuration for outputing verilog VerilogVerificationTargetGenerator( const std::vector& implementation_include_path, const std::vector& implementation_srcs, const std::string& implementation_top_module, const std::string& refinement_variable_mapping, const std::string& refinement_conditions, const std::string& output_path, - const InstrLvlAbsPtr& ila_ptr, backend_selector backend, - const vtg_config_t& vtg_config = vtg_config_t(), + const InstrLvlAbsPtr& ila_ptr, ModelCheckerSelection backend, + const RtlVerifyConfig& vtg_config = RtlVerifyConfig(), const VerilogGenerator::VlgGenConfig& config = VerilogGenerator::VlgGenConfig()); // --------------------- DECONSTRUCTOR ---------------------------- // diff --git a/include/ilang/vtarget-out/vtarget_gen_impl.h b/include/ilang/vtarget-out/vtarget_gen_impl.h index 461e7da94..e8c9a7140 100644 --- a/include/ilang/vtarget-out/vtarget_gen_impl.h +++ b/include/ilang/vtarget-out/vtarget_gen_impl.h @@ -22,38 +22,40 @@ #include "nlohmann/json.hpp" #include #include +#include #include #include #include #include -#include -#include #include namespace ilang { +/// \brief What internal signal to pull out +/// for yosys +struct RtlExtraWire { + std::string wire_name; + std::string hierarchy; + std::string internal_name; + unsigned width; + RtlExtraWire(const std::string& wn, const std::string& h, + const std::string& i, unsigned _width) + : wire_name(wn), hierarchy(h), internal_name(i), width(_width) {} + // for example: + // RTL.a.b.c[3] + // wire_name : RTL__DOT__a__DOT__b__DOT__c_3_ + // hierarchy RTL.a.b + // internal name c[3] +}; // end of struct RtlExtraWire + /// \brief Generating a target (just the invairant or for an instruction) class VlgSglTgtGen { public: // --------------------- TYPE DEFINITION ------------------------ // /// Type of the target typedef enum { INVARIANTS, INSTRUCTIONS, INV_SYN_DESIGN_ONLY } target_type_t; - /// Type of the ready condition - typedef enum { - NA = 0, - READY_SIGNAL = 1, - READY_BOUND = 2, - BOTH = 3 - } ready_type_t; /// Per func apply counter typedef std::map func_app_cnt_t; - /// Type of the verification backend - using backend_selector = VlgVerifTgtGenBase::backend_selector; - /// Type of the synthesis backend - using synthesis_backend_selector = - VlgVerifTgtGenBase::synthesis_backend_selector; - /// Type of configuration - using vtg_config_t = VlgVerifTgtGenBase::vtg_config_t; /// Type of record of extra info of a signal using ex_info_t = VlgVerifTgtGenBase::ex_info_t; /// Type of advanced parameter @@ -78,13 +80,11 @@ class VlgSglTgtGen { const InstrPtr& instr_ptr, // which could be an empty pointer, and it will // be used to verify invariants const InstrLvlAbsPtr& ila_ptr, - const VerilogGenerator::VlgGenConfig& config, nlohmann::json& _rf_vmap, - nlohmann::json& _rf_cond, VlgTgtSupplementaryInfo& _supplementary_info, - VerilogInfo* _vlg_info_ptr, const std::string& vlg_mod_inst_name, - const std::string& ila_mod_inst_name, const std::string& wrapper_name, + const rfmap::VerilogRefinementMap& refinement, VerilogInfo* _vlg_info_ptr, + const std::string& wrapper_name, const std::vector& implementation_srcs, const std::vector& implementation_include_path, - const vtg_config_t& vtg_config, backend_selector backend, + const RtlVerifyConfig& vtg_config, ModelCheckerSelection backend, const target_type_t& target_tp, advanced_parameters_t* adv_ptr); /// Destructor: do nothing , most importantly it is virtual @@ -109,32 +109,17 @@ class VlgSglTgtGen { VerilogGeneratorBase vlg_wrapper; /// Generator for the ila verilog VerilogGenerator vlg_ila; - /// inteface directive recorder + /// Verilog module connection IntefaceDirectiveRecorder _idr; - /// state directive recorder - StateMappingDirectiveRecorder _sdr; + /// Analyzer for the implementation // we don't know the module name, before analyzing the rfmap. so we cannot // initialize in the beginning VerilogInfo* vlg_info_ptr; - /// variable extractor to handle property expressions - VarExtractor _vext; - /// refinement relation variable mapping - nlohmann::json& rf_vmap; - /// refinement relation instruction conditions - nlohmann::json& rf_cond; - /// An empty json for default fallthrough cases - nlohmann::json empty_json; - /// The supplementary information - const VlgTgtSupplementaryInfo& supplementary_info; - /// record all the referred vlg names, so you can add (*keep*) if needed - std::map _all_referred_vlg_names; + /// The refinement map with type checked + rfmap::TypedVerilogRefinementMap refinement_map; /// target type target_type_t target_type; - /// a shortcut of whether rf has flush condition set - bool has_flush; - /// ready type - ready_type_t ready_type; /// func apply counter func_app_cnt_t func_cnt; /// max bound , default 127 @@ -168,7 +153,6 @@ class VlgSglTgtGen { const ExprPtr IlaGetInput(const std::string& sname) const; /// Get (a,d) width of a memory, if not existing, (0,0) std::pair - GetMemInfo(const std::string& ila_mem_name) const; /// Test if a string represents an ila state name bool TryFindIlaState(const std::string& sname); @@ -178,32 +162,80 @@ class VlgSglTgtGen { bool TryFindVlgState(const std::string& sname); /// Try to find a ILA var according to a name ExprPtr TryFindIlaVarName(const std::string& sname); - /// Modify a token and record its use - std::string ModifyCondExprAndRecordVlgName(const VarExtractor::token& t); + /// return the type of a variable when its name is given + rfmap::RfVarTypeOrig VarTypeCheckForRfExprParsing(const std::string&); + /// Check if ila name and vlg name are type compatible (not including special /// directives) static unsigned TypeMatched(const ExprPtr& ila_var, const SignalInfoBase& vlg_var); /// get width of an ila node static unsigned get_width(const ExprPtr& n); - /// Parse and modify a condition string - std::string ReplExpr(const std::string& expr, bool force_vlg_sts = false); - /// handle a single string map (s-name/equ-string) - std::string PerStateMap(const std::string& ila_state_name_or_equ, - const std::string& vlg_st_name); + + // ----------------------------------------------------------------------- + // Refinement map handling + // ----------------------------------------------------------------------- + /// Create a variable replacement for var + /// RTL_var/ ILA_IN/ ILA_SO/ INTERNL-DEFVAR + /// a new var is always typed + /// otherwise, will not + /// this function get type information from + /// VarTypeCheckForRfExprParsing and + /// refinement_map.all_var_def_type + rfmap::VarReplacement CreateVarReplacement(const rfmap::RfVar& var, + bool replace_internal_names); + /// replace var for assumptions/assertions + /// (should only be used inside assumptions/assertions) + /// 1. GetVar 2. Check Replacement 3. add replacement using the above + /// function 4. do replacement for var 5. annotate type + rfmap::RfExpr ReplExpr(const rfmap::RfExpr& in); + + /// treat `in` as var map, if it is not a Boolean, add `==` + /// this function is not used in `_bv` version below + rfmap::RfExpr TranslateMap(const rfmap::RfExpr& in, + const std::string& ila_vn); + + /// translate a conditional map to rf expression + rfmap::RfExpr condition_map_to_rfexpr( + const std::vector>& cond_map, + const std::string& ila_state_name); + /// difference from condition_map_to_rfexpr is that + /// this will not create (v == ...) , this expects bv + rfmap::RfExpr condition_map_bv_to_rfexpr( + const std::vector>& cond_map); + + /// translate a single map to rfexpr + rfmap::RfExpr singlemap_to_rfexpr(const rfmap::SingleVarMap& single_map, + const std::string& ila_state_name); + /// translate a single map to rfexpr (expect bit-vector) + rfmap::RfExpr singlemap_bv_to_rfexpr(const rfmap::SingleVarMap& single_map); + + /// register a reg in refinement_map.all_var_def_type + void rfmap_add_internal_reg(const std::string& n, unsigned width); + /// register a wire in refinement_map.all_var_def_type + void rfmap_add_internal_wire(const std::string& n, unsigned width); + /// register a replacement in refinement_map + /// this will affect ReplExpr's behavior + /// (Note 1: ReplExpr will also create replacement, but it will not use + /// this function. 2: will require that the new one has been registered + /// in refinement_map.all_var_def_type) + void rfmap_add_replacement(const std::string& old, const std::string& n); + /// handle a var map - /// will create new variables "m?" and return it - /// 1. "ila-state":"**MEM**.?" - /// 2a. "ila-state":"statename" --> PerStateMap - /// 2b. "ila-state":"(cond)&map" --> PerStateMap - /// 3. "ila-state":[ "cond&map" ] - /// 4. "ila-state":[ {"cond":,"map":}, ] - std::string GetStateVarMapExpr(const std::string& ila_state_name, - nlohmann::json& m, bool is_assert = false); + void Gen_varmap_assumpt_assert(const std::string& ila_state_name, + const rfmap::IlaVarMapping& vmap, + const std::string& problem_name, + bool true_for_assumpt_false_for_assert); + + // handle an input map + void Gen_input_map_assumpt(const std::string& ila_input_name, + const rfmap::IlaVarMapping& imap, + const std::string& problem_name); + /// add a start condition if it is given - void handle_start_condition(nlohmann::json& dc); + void handle_start_condition(const std::vector& dc); /// Find the current instruction-mapping - nlohmann::json& get_current_instruction_rf(); + const rfmap::InstructionCompleteCondition& get_current_instruction_rf(); protected: // --------------- STEPS OF GENERATION ------------------------// @@ -217,6 +249,8 @@ class VlgSglTgtGen { void ConstructWrapper_add_cycle_count_moniter(); /// generate the `define TRUE 1 void ConstructWrapper_generate_header(); + /// add input equ assumptions + void ConstructWrapper_add_inputmap_assumptions(); /// add state equ assumptions void ConstructWrapper_add_varmap_assumptions(); /// add state equ assertions @@ -236,26 +270,40 @@ class VlgSglTgtGen { void ConstructWrapper_register_extra_io_wire(); /// Add instantiation statement of the two modules void ConstructWrapper_add_module_instantiation(); - /// Add instantiation of the memory and put the needed mem implementation in - /// extra export This also include the assertions - void ConstructWrapper_add_helper_memory(); /// Add buffers and assumption/assertions about the void ConstructWrapper_add_uf_constraints(); /// Add post value holder (val @ cond == ...) void ConstructWrapper_add_post_value_holder(); - /// A sub function of the above post-value-holder hanlder - int ConstructWrapper_add_post_value_holder_handle_obj( - nlohmann::json& pv_cond_val, const std::string& pv_name, int width, - bool create_reg); + /// Add delay unit + void ConstructWrapper_add_delay_unit(); + /// Add stage tracker unit + void ConstructWrapper_add_stage_tracker(); /// Add Verilog inline monitor void ConstructWrapper_add_vlg_monitor(); + /// Add direct aux vars + void ConstructWrapper_add_direct_aux_vars(); + /// handle all_assumption/all_assertion + /// ReplExpr all assertion/assumptions + /// ReplExpr will know whether to create + /// `__DOT__`, but will anyway + // do the other replacement, and non-repl + /// for yosys: + /// 1. use var_replacement to create + /// extra wire + /// 2. check if contains array[const] + /// add extra wire and replacement + /// 3. if it still contain array + /// use add_smt_assumption/assertion + /// for the others, use add_a_direct ... + /// for jg: + /// 1. use add_a_direct_assertion/assumption ... + void ConstructWrapper_translate_property_and_collect_all_rtl_connection_var(); // ------------------------------------------------------------------------- /// Add invariants as assumption/assertion when target is inv_syn_design_only void ConstructWrapper_add_inv_assumption_or_assertion_target_inv_syn_design_only(); - /// Connect the memory even we don't care a lot about them - void ConstructWrapper_inv_syn_connect_mem(); + /// Sometimes you need to add some signals that only appeared in Instruction /// target void ConstructWrapper_inv_syn_cond_signals(); @@ -285,11 +333,34 @@ class VlgSglTgtGen { /// include paths std::vector vlg_include_files_path; /// Store the configuration - vtg_config_t _vtg_config; - /// Store the vlg configurations - const VerilogGenerator::VlgGenConfig& _vlg_cfg; + RtlVerifyConfig _vtg_config; /// Store the selection of backend - backend_selector _backend; + ModelCheckerSelection _backend; + +protected: + // ----------------------- MEMBERS for storing assumptions/assertions + // ------------------- // + /// assumptions : written by add_an_assumption, + /// consumed by + /// ConstructWrapper_translate_property_and_collect_all_rtl_connection_var + std::map> all_assumptions; + /// assertions : written by add_an_assertion, + /// consumed by + /// ConstructWrapper_translate_property_and_collect_all_rtl_connection_var + std::map> all_assertions; + /// assumptions : written by add_a_cover, + /// consumed by + /// ConstructWrapper_translate_property_and_collect_all_rtl_connection_var + std::map> all_covers; + /// consumed by + /// ConstructWrapper_translate_property_and_collect_all_rtl_connection_var + std::map> all_sanity_assertions; + /// assign or assumptions : vector of (dspt, wire_name, rhs, wn == rhs) + std::vector< + std::tuple> + assign_or_assumptions; + /// map: wire_name -> (wire_name, hierarchy, internal name) + std::unordered_map rtl_extra_wire; public: /// Call the separate construct functions to make a wrapper (not yet export @@ -297,9 +368,9 @@ class VlgSglTgtGen { void virtual ConstructWrapper(); /// PreExportWork (modification and etc.) void virtual PreExportProcess() = 0; - /// create the wrapper file + /// create the wrapper file: set top_file_name void virtual Export_wrapper(const std::string& wrapper_name); - /// export the ila verilog + /// export the ila verilog, may use top_file_name if backend needs yosys void virtual Export_ila_vlg(const std::string& ila_vlg_name); /// export the script to run the verification void virtual Export_script(const std::string& script_name) = 0; @@ -309,15 +380,14 @@ class VlgSglTgtGen { /// export the memory abstraction (implementation) /// Yes, this is also implementation specific, (jasper may use a different /// one) - void virtual Export_mem(const std::string& mem_name) = 0; + // void virtual Export_mem(const std::string& mem_name) = 0; /// For jasper, this means do nothing, for yosys, you need to add (*keep*) void virtual Export_modify_verilog() = 0; /// Take care of exporting all of a single target void virtual ExportAll(const std::string& wrapper_name, const std::string& ila_vlg_name, const std::string& script_name, - const std::string& extra_name, - const std::string& mem_name); + const std::string& extra_name); protected: // helper function to be implemented by COSA/JASPER @@ -325,27 +395,63 @@ class VlgSglTgtGen { virtual void add_a_direct_assumption(const std::string& aspt, const std::string& dspt) = 0; /// Add an assertion - virtual void add_a_direct_assertion(const std::string& asst, + virtual void add_a_direct_assertion(const std::string& aspt, const std::string& dspt) = 0; - - // helper function to be implemented by COSA, Yosys, invsyn, jasper is not - /// Add an assumption -- JasperGold will override this - virtual void add_an_assumption(const std::string& aspt, + /// Add a sanity assertion + virtual void add_a_direct_sanity_assertion(const std::string& aspt, + const std::string& dspt) = 0; +/// Add a sanity assertion + virtual void add_a_direct_cover_check(const std::string& cvr, + const std::string& dspt) = 0; + + /// Add SMT-lib2 assumption + virtual void add_a_direct_smt_assumption(const std::string& arg, + const std::string& ret, + const std::string& body, + const std::string& dspt) = 0; + /// Add SMT-lib2 assertion + virtual void add_a_direct_smt_assertion(const std::string& arg, + const std::string& ret, + const std::string& body, + const std::string& dspt) = 0; + + // helper function to add assumption/assertions to internal data-strcture + virtual void add_an_assumption(const rfmap::RfExpr& aspt, const std::string& dspt); - /// Add an assertion -- JasperGold will override this - virtual void add_an_assertion(const std::string& asst, + + /// Add an assertion -- simply put in record + virtual void add_an_assertion(const rfmap::RfExpr& asst, const std::string& dspt); - /// Add an assignment which in JasperGold could be an assignment, but in CoSA - /// has to be an assumption + /// Add a cover -- simply put in record + virtual void add_a_cover(const rfmap::RfExpr& asst, + const std::string& dspt); + + /// Add an assertion for sanity checking -- simply put in record + void add_a_santiy_assertion(const rfmap::RfExpr& aspt, + const std::string& dspt); + + // Add SMT assumption (using rfexpr) + // - will use add_a_direct_smt_assumption/assertion + virtual void add_smt_assumption(const rfmap::RfExpr& body, + const std::string& dspt); + + // Add SMT assertion (using rfexpr) + virtual void add_smt_assertion(const rfmap::RfExpr& body, + const std::string& dspt); + + /// Add an assignment which in JasperGold could be an assignment, but in + /// Yosys-based solution has to be an assumption virtual void add_wire_assign_assumption(const std::string& varname, - const std::string& expression, + const rfmap::RfExpr& aspt, const std::string& dspt); - /// Add an assignment to a register which in JasperGold could be an - /// assignment, but in CoSA has to be an assumption + + /// Add an assignment, will always be an assumption + /// will use add_an_assumption, and it is up to + /// the derived class to determine whether to add as vlg/smt assumption virtual void add_reg_cassign_assumption(const std::string& varname, - const std::string& expression, - int width, const std::string& cond, + const rfmap::RfExpr& expression, + int width, const rfmap::RfExpr& cond, const std::string& dspt); public: @@ -360,6 +466,9 @@ class VlgSglTgtGen { protected: /// If it is bad state, return true and display a message bool bad_state_return(void); + /// this function make sure ila.input and ila.sv are all mapped + /// in the refinement map and no more vars are mapped + void RfmapIlaStateSanityCheck(); private: /// If it is in a bad state @@ -371,10 +480,6 @@ class VlgSglTgtGen { /// outside class VlgVerifTgtGen : public VlgVerifTgtGenBase { // --------------------- TYPE DEFINITIONS ---------------------------- // - /// tell us which backend to use - using backend_selector = VlgVerifTgtGenBase::backend_selector; - /// Type of configuration - using vtg_config_t = VlgVerifTgtGenBase::vtg_config_t; /// Type of a target using target_type_t = VlgSglTgtGen::target_type_t; /// Type of advanced parameter @@ -396,12 +501,9 @@ class VlgVerifTgtGen : public VlgVerifTgtGenBase { VlgVerifTgtGen(const std::vector& implementation_include_path, const std::vector& implementation_srcs, const std::string& implementation_top_module, - const std::string& refinement_variable_mapping, - const std::string& refinement_conditions, + const rfmap::VerilogRefinementMap& refinement, const std::string& output_path, const InstrLvlAbsPtr& ila_ptr, - backend_selector backend, const vtg_config_t& vtg_config, - const VerilogGenerator::VlgGenConfig& config = - VerilogGenerator::VlgGenConfig(), + ModelCheckerSelection backend, const RtlVerifyConfig& vtg_config, advanced_parameters_t* adv_ptr = NULL); /// no copy constructor, please @@ -422,39 +524,25 @@ class VlgVerifTgtGen : public VlgVerifTgtGenBase { /// implementation top module name const std::string _vlg_impl_top_name; /// refinement relation - variable mapping path - const std::string _rf_var_map_name; - /// refinement relation - condition path - const std::string _rf_cond_name; + rfmap::VerilogRefinementMap _refinement; /// output path, output the ila-verilog, wrapper-verilog, problem.txt, /// run-verify-by-??? const std::string _output_path; /// The pointer to the instruction that is going to export const InstrLvlAbsPtr& _ila_ptr; - /// The name of verilog top module instance in the wrapper - std::string _vlg_mod_inst_name; - /// The name of ila-verilog top module instance in the wrapper - std::string _ila_mod_inst_name; /// A pointer to create verilog analyzer VerilogInfo* vlg_info_ptr; /// to store the backend - backend_selector _backend; + ModelCheckerSelection _backend; /// to store the verilog configuration VerilogGenerator::VlgGenConfig _cfg; /// to store the configuration - vtg_config_t _vtg_config; + RtlVerifyConfig _vtg_config; /// to store the advanced parameter configurations advanced_parameters_t* _advanced_param_ptr; /// to store the generate script name std::vector runnable_script_name; -protected: - /// store the vmap info - nlohmann::json rf_vmap; - /// store the condition - nlohmann::json rf_cond; - /// The supplementary information - VlgTgtSupplementaryInfo supplementary_info; - public: // --------------------- METHODS ---------------------------- // /// Generate everything @@ -463,9 +551,9 @@ class VlgVerifTgtGen : public VlgVerifTgtGenBase { /// Return true if it is in bad state bool in_bad_state(void) const { return _bad_state; } /// get vlg-module instance name - std::string GetVlgModuleInstanceName() const { return _vlg_mod_inst_name; } + std::string GetVlgModuleInstanceName() const { return "RTL"; } -#ifdef INVSYN_INTERFACE +#if 0 /// generate invariant synthesis target void GenerateInvSynTargetsAbc(bool useGla, bool useCorr, bool useAiger); /// generate inv-syn target @@ -480,20 +568,10 @@ class VlgVerifTgtGen : public VlgVerifTgtGenBase { /// generate the runable script name const std::vector& GetRunnableScriptName() const; - /// return the result from parsing supplymentary information - const VlgTgtSupplementaryInfo& GetSupplementaryInfo() const; - -protected: - // --------------------- METHODS ---------------------------- // - /// subroutine for generating synthesis using chc targets protected: /// If it is bad state, return true and display a message bool bad_state_return(void); - /// load json from a file name to the given j - void load_json(const std::string& fname, nlohmann::json& j); - /// Get instance name from rfmap - void set_module_instantiation_name(); private: /// If it is in a bad state diff --git a/include/ilang/vtarget-out/vtarget_gen_jasper.h b/include/ilang/vtarget-out/vtarget_gen_jasper.h index 52da17b71..0952cdc4a 100644 --- a/include/ilang/vtarget-out/vtarget_gen_jasper.h +++ b/include/ilang/vtarget-out/vtarget_gen_jasper.h @@ -38,46 +38,38 @@ class VlgSglTgtGen_Jasper : public VlgSglTgtGen { const InstrPtr& instr_ptr, // which could be an empty pointer, and it will // be used to verify invariants const InstrLvlAbsPtr& ila_ptr, - const VerilogGenerator::VlgGenConfig& config, nlohmann::json& _rf_vmap, - nlohmann::json& _rf_cond, VlgTgtSupplementaryInfo& _supplementary_info, - VerilogInfo* _vlg_info_ptr, const std::string& vlg_mod_inst_name, - const std::string& ila_mod_inst_name, const std::string& wrapper_name, + const rfmap::VerilogRefinementMap& refinement, VerilogInfo* _vlg_info_ptr, + const std::string& wrapper_name, const std::vector& implementation_srcs, const std::vector& include_dirs, - const vtg_config_t& vtg_config, backend_selector backend, + const RtlVerifyConfig& vtg_config, ModelCheckerSelection backend, const target_type_t& target_tp, advanced_parameters_t* adv_ptr); - /// if you have signals that are controled by assumptions to be equal as - /// the outer clock, you need to put them here, - /// because the assumptions do not work in the jaspergold reset step - /// (unlike COSA) - void add_addition_clock_info(const std::string& expr); - void add_addition_reset_info(const std::string& expr); - protected: /// internal storage of problems /// vector of pairs of std::vector> assumptions; /// vector of pairs of std::vector> assertions; + /// vector of pairs of + std::vector> covers; /// vector of clock signals that need to be taken care of - std::vector - additional_clock_expr; // we don't put the "clk" here, as by default it - // will be there - /// vector of clock signals that need to be taken care of - std::vector additional_reset_expr; + /// Name of the problem file std::string jg_script_name; - /// Name of the problem file - std::string abs_mem_name; protected: - /// Add an assumption - virtual void add_an_assumption(const std::string& aspt, - const std::string& dspt) override; - /// Add an assertion - virtual void add_an_assertion(const std::string& asst, - const std::string& dspt) override; + /// Add SMT-lib2 assumption + virtual void add_a_direct_smt_assumption(const std::string& arg, + const std::string& ret, + const std::string& body, + const std::string& dspt) override; + /// Add SMT-lib2 assertion + virtual void add_a_direct_smt_assertion(const std::string& arg, + const std::string& ret, + const std::string& body, + const std::string& dspt) override; + /// Add a direct assumption virtual void add_a_direct_assumption(const std::string& aspt, const std::string& dspt) override; @@ -85,17 +77,14 @@ class VlgSglTgtGen_Jasper : public VlgSglTgtGen { virtual void add_a_direct_assertion(const std::string& asst, const std::string& dspt) override; - /// Add an assignment which in JasperGold could be an assignment, but in CoSA - /// has to be an assumption - virtual void add_wire_assign_assumption(const std::string& varname, - const std::string& expression, - const std::string& dspt) override; - /// Add an assignment to a register which in JasperGold could be an - /// assignment, but in CoSA has to be an assumption - virtual void add_reg_cassign_assumption(const std::string& varname, - const std::string& expression, - int width, const std::string& cond, - const std::string& dspt) override; + /// Add a direct cover check + virtual void add_a_direct_cover_check(const std::string& cvr, + const std::string& dspt) override; + /// Add a direct assertion + virtual void add_a_direct_sanity_assertion(const std::string& asst, + const std::string& dspt) override { + add_a_direct_assertion(asst, dspt); + } /// Pre export work : nothing for cosa void virtual PreExportProcess() override {} @@ -104,10 +93,6 @@ class VlgSglTgtGen_Jasper : public VlgSglTgtGen { /// export extra things (problem) virtual void Export_problem(const std::string& extra_name) override; // only for cosa - /// export the memory abstraction (implementation) - /// Yes, this is also implementation specific, (jasper may use a different - /// one) - virtual void Export_mem(const std::string& mem_name) override; /// For jasper, this means do nothing, for yosys, you need to add (*keep*) virtual void Export_modify_verilog() override; diff --git a/include/ilang/vtarget-out/vtarget_gen_cosa.h b/include/ilang/vtarget-out/vtarget_gen_pono.h similarity index 52% rename from include/ilang/vtarget-out/vtarget_gen_cosa.h rename to include/ilang/vtarget-out/vtarget_gen_pono.h index 1902d6b02..65221c4cd 100644 --- a/include/ilang/vtarget-out/vtarget_gen_cosa.h +++ b/include/ilang/vtarget-out/vtarget_gen_pono.h @@ -1,9 +1,9 @@ -/// \file Verilog Verification Target Generator -- for CoSA +/// \file Verilog Verification Target Generator -- for Pono /// This file should not be included, as it requires the impl. // ---Hongce Zhang -#ifndef ILANG_VTARGET_OUT_VTARGET_GEN_COSA_H__ -#define ILANG_VTARGET_OUT_VTARGET_GEN_COSA_H__ +#ifndef ILANG_VTARGET_OUT_VTARGET_GEN_PONO_H__ +#define ILANG_VTARGET_OUT_VTARGET_GEN_PONO_H__ #include #include @@ -17,11 +17,11 @@ namespace ilang { -class VlgSglTgtGen_Cosa; +class VlgSglTgtGen_Pono; -/// \brief a class to store (and generate) the problem for cosa -class Cosa_problem { - friend class VlgSglTgtGen_Cosa; +/// \brief a class to store (and generate) the problem for pono +class Pono_problem { + friend class VlgSglTgtGen_Pono; /// Type of assertions and assumptions typedef std::vector prop_t; /// Type of a problem --- we can handle multiple several problems (may not @@ -30,21 +30,31 @@ class Cosa_problem { // the name in [??] // std::string problem_name; /// will be conjuncted and put in the question - prop_t assertions; + prop_t exprs; } problem_t; /// set of problems typedef std::map problemset_t; protected: - /// assumptions are shared - prop_t assumptions; + /// assumptions are not shared + problemset_t assumptions; /// problems are splitted into items - problemset_t probitem; + problemset_t assertions; + /// problems are splitted into items + problemset_t sanity_assertions; + /// problems are splitted into items + problemset_t cover_checks; + + /// SMT-LIB2 assumptions + prop_t smt_assumptions; + /// SMT-LIB2 assertions + prop_t smt_assertions; -}; // Cosa_problem +}; // Pono_problem -/// \brief a class to interface w. COSA -class VlgSglTgtGen_Cosa : public VlgSglTgtGen { +/// \brief a class to interface w. PONO +class VlgSglTgtGen_Pono : public VlgSglTgtGen { +public: /// using the target type using target_type_t = VlgSglTgtGen::target_type_t; /// a tuple to store all related info for modification @@ -58,10 +68,9 @@ class VlgSglTgtGen_Cosa : public VlgSglTgtGen { // --------------------- CONSTRUCTOR ---------------------------- // /// /// \param[in] output path (ila-verilog, wrapper-verilog, problem.txt, - /// run-verify-by-???, modify-impl, it there is ) \param[in] pointer to the - /// instruction \param[in] the default configuration for outputing verilog - /// \param[in] the variable map - /// \param[in] the conditions + /// run-verify-by-???, modify-impl, it there is ) + /// \param[in] pointer to the instruction + /// \param[in] the refinement map /// \param[in] pointer to verify info class /// \param[in] verilog module name /// \param[in] ila module name, @@ -69,26 +78,26 @@ class VlgSglTgtGen_Cosa : public VlgSglTgtGen { /// \param[in] all include paths /// \param[in] which backend to use, it needs this info to gen proper /// properties - VlgSglTgtGen_Cosa( + VlgSglTgtGen_Pono( const std::string& output_path, // will be a sub directory of the // output_path of its parent const InstrPtr& instr_ptr, // which could be an empty pointer, and it will // be used to verify invariants const InstrLvlAbsPtr& ila_ptr, - const VerilogGenerator::VlgGenConfig& config, nlohmann::json& _rf_vmap, - nlohmann::json& _rf_cond, VlgTgtSupplementaryInfo& _supplementary_info, - VerilogInfo* _vlg_info_ptr, const std::string& vlg_mod_inst_name, - const std::string& ila_mod_inst_name, const std::string& wrapper_name, + const rfmap::VerilogRefinementMap& refinement, VerilogInfo* _vlg_info_ptr, + const std::string& wrapper_name, const std::vector& implementation_srcs, const std::vector& include_dirs, - const vtg_config_t& vtg_config, backend_selector backend, + const RtlVerifyConfig& vtg_config, ModelCheckerSelection backend, const target_type_t& target_tp, advanced_parameters_t* adv_ptr); protected: - /// Cosa problem generate - Cosa_problem _problems; - /// Cosa problem file name - std::string cosa_prob_fname; + /// Pono problem generate + Pono_problem _problems; + /// Pono problem file name + std::string ys_script_name; + /// all cover assert property names + std::vector all_cover_assert_property_names; protected: /// Add a direct assumption @@ -97,21 +106,39 @@ class VlgSglTgtGen_Cosa : public VlgSglTgtGen { /// Add a direct assertion virtual void add_a_direct_assertion(const std::string& asst, const std::string& dspt) override; + /// Add a direct sanity assertion + virtual void add_a_direct_sanity_assertion(const std::string& asst, + const std::string& dspt) override; + /// Add a direct cover check + virtual void add_a_direct_cover_check(const std::string& asst, + const std::string& dspt) override; + + /// Add SMT-lib2 assumption + virtual void add_a_direct_smt_assumption(const std::string& arg, + const std::string& ret, + const std::string& body, + const std::string& dspt) override; + /// Add SMT-lib2 assertion + virtual void add_a_direct_smt_assertion(const std::string& arg, + const std::string& ret, + const std::string& body, + const std::string& dspt) override; + + /// Pre export work : nothing for pono + void virtual PreExportProcess() override; + + // A helper function to generate Yosys script + void GenYosysScript( + const std::string& ys_script_name_path, + const std::string& property_selection_cmd, + const std::string& generated_btor_name ); - /// Pre export work : nothing for cosa - void virtual PreExportProcess() override {} /// export the script to run the verification virtual void Export_script(const std::string& script_name) override; /// export extra things (problem) virtual void - Export_problem(const std::string& extra_name) override; // only for cosa - /// generate along-side a jg script that you can use in JasperGold - virtual void Export_jg_tester_script(const std::string& extra_name); - - /// export the memory abstraction (implementation) - /// Yes, this is also implementation specific, (jasper may use a different - /// one) - virtual void Export_mem(const std::string& mem_name) override; + Export_problem(const std::string& extra_name) override; // only for pono + /// For jasper, this means do nothing, for yosys, you need to add (*keep*) virtual void Export_modify_verilog() override; @@ -119,8 +146,8 @@ class VlgSglTgtGen_Cosa : public VlgSglTgtGen { /// It is okay to instantiation virtual void do_not_instantiate(void) override{}; -}; // class VlgVerifTgtGenCosa +}; // class VlgVerifTgtGenPono }; // namespace ilang -#endif // ILANG_VTARGET_OUT_VTARGET_GEN_COSA_H__ +#endif // ILANG_VTARGET_OUT_VTARGET_GEN_PONO_H__ diff --git a/include/ilang/vtarget-out/vtarget_gen_relchc.h b/include/ilang/vtarget-out/vtarget_gen_relchc.h deleted file mode 100644 index 377dd77e3..000000000 --- a/include/ilang/vtarget-out/vtarget_gen_relchc.h +++ /dev/null @@ -1,165 +0,0 @@ -/// \file Verilog Verification Target Generator -- for Relchc -/// We use yosys to convert Verilog to smt-lib2, and then -/// it will be converted to horn clause -/// This file should not be included, as it requires the impl. -/// Internally, we use the -// ---Hongce Zhang - -#ifndef VTARGET_GEN_RELCHC_H__ -#define VTARGET_GEN_RELCHC_H__ - -#include - -#include -#include -#include -#include -#include -#include - -namespace ilang { - -class VlgSglTgtGen_Relchc; - -/// \brief a class to store (and generate) the problem for Relchc (Z3) -class Relchc_problem { - friend class VlgSglTgtGen_Relchc; - /// Type of assertions and assumptions - typedef std::vector prop_t; - /// Type of a problem --- we can handle multiple several problems (may not - /// needed) - typedef struct { - // the name in [??] - // std::string problem_name; - /// will be conjuncted and put in the question - prop_t exprs; - } problem_t; - /// set of problems - typedef std::map problemset_t; - -protected: - /// assumptions are not shared (unlike CoSA) - problemset_t assumptions; - /// problems are splitted into items - problemset_t assertions; - -}; // Relchc_problem - - -/// \brief a class to interface w. Relchc Z3 -class VlgSglTgtGen_Relchc : public VlgSglTgtGen { - /// using the target type - using target_type_t = VlgSglTgtGen::target_type_t; - /// a tuple to store all related info for modification - using info_t = VerilogModifier::info_t; - /// filename -> (lineno, varname, is_port_sig) vec - using fn_l_map_t = VerilogModifier::fn_l_map_t; - /// Type of advanced parameter - using advanced_parameters_t = VlgVerifTgtGenBase::advanced_parameters_t; - -public: - // --------------------- CONSTRUCTOR ---------------------------- // - /// - /// \param[in] output path (ila-verilog, wrapper-verilog, problem.txt, - /// run-verify-by-???, modify-impl, it there is ) \param[in] pointer to the - /// instruction \param[in] the default configuration for outputing verilog - /// \param[in] the variable map - /// \param[in] the conditions - /// \param[in] pointer to verify info class - /// \param[in] verilog module name - /// \param[in] ila module name, - /// \param[in] all implementation sources - /// \param[in] all include paths - /// \param[in] which backend to use, it needs this info to gen proper - /// properties - VlgSglTgtGen_Relchc( - const std::string& output_path, // will be a sub directory of the - // output_path of its parent - const InstrPtr& instr_ptr, // which could be an empty pointer, and it will - // be used to verify invariants - const InstrLvlAbsPtr& ila_ptr, - const VerilogGenerator::VlgGenConfig& config, nlohmann::json& _rf_vmap, - nlohmann::json& _rf_cond, VlgTgtSupplementaryInfo & _sup_info, VerilogInfo* _vlg_info_ptr, - const std::string& vlg_mod_inst_name, - const std::string& ila_mod_inst_name, const std::string& wrapper_name, - const std::vector& implementation_srcs, - const std::vector& include_dirs, - const vtg_config_t& vtg_config, backend_selector backend, - const target_type_t& target_tp, - advanced_parameters_t * adv_ptr); - - /// Destructor: do nothing , most importantly it is virtual - virtual ~VlgSglTgtGen_Relchc() {} - -protected: - /// Relchc problem generate - Relchc_problem _problems; - /// Relchc problem file name - std::string relchc_prob_fname; - /// Relchc script 'run.sh' name - std::string relchc_run_script_name; - /// the invariants on the design - std::vector vlg_mod_inv_vec; - -protected: - /// Add a direct assumption -- needed by base class - virtual void add_a_direct_assumption(const std::string& aspt, - const std::string& dspt) override; - /// Add a direct assertion -- needed by base class - virtual void add_a_direct_assertion(const std::string& asst, - const std::string& dspt) override; - - /// Pre export work : add assume and asssert to the top level - void virtual PreExportProcess() override; - /// export the script to run the verification - virtual void Export_script(const std::string& script_name) override; - /// export extra things: the relchc script, the smt template - virtual void - Export_problem(const std::string& extra_name) override; - /// export the memory abstraction (implementation) - /// Yes, this is also implementation specific, (jasper may use a different - /// one) - virtual void Export_mem(const std::string& mem_name) override; - /// For jasper, this means do nothing, for relchc, you need to add (*keep*) - virtual void Export_modify_verilog() override; - -private: - // Here begins the specific functions - // single_inv_problem() : gensmt.ys - // dual_inv_problem() : gensmt.ys - // single_inv_script() : same run.sh - // dual_inv_script() - // single_inv_tpl() : - // dual_inv_tpl() : - - /// generate the Relchc script for dual invariant - void dual_inv_problem(const std::string& ys_script_name); - - /// generate the template file - void dual_inv_tpl(const std::string & tpl_name, const std::string & smt_info); - - /// generate the wrapper's smt first - std::string dual_inv_gen_smt( - const std::string & smt_name, - const std::string & ys_script_name); - - -public: - - /// Deprecation of the one without smt info - void virtual ExportAll(const std::string& wrapper_name, - const std::string& ila_vlg_name, - const std::string& script_name, - const std::string& extra_name, - const std::string& mem_name) override; - - - /// It is okay to instantiation - virtual void do_not_instantiate(void) override { }; - -}; // class VlgVerifTgtGenRelchc - - -}; // namespace ilang - -#endif // VTARGET_GEN_RELCHC_H__ diff --git a/include/ilang/vtarget-out/vtarget_gen_yosys.h b/include/ilang/vtarget-out/vtarget_gen_yosys.h deleted file mode 100644 index ff1f1183a..000000000 --- a/include/ilang/vtarget-out/vtarget_gen_yosys.h +++ /dev/null @@ -1,174 +0,0 @@ -/// \file Verilog Verification Target Generator -- generating CHC target -/// (design-only, same as the invariant target) -/// We use chc to convert Verilog to smt-lib2, and then -/// it will be parsed and re-format by smt-io -/// and use that information, it will create horn clauses -/// This file should not be included, as it requires the impl. -// ---Hongce Zhang - -#ifndef VTARGET_GEN_YOSYS_H__ -#define VTARGET_GEN_YOSYS_H__ - -#include - -#include -#include -#include -#include -#include -#include -#include -#include - -namespace ilang { - -class VlgSglTgtGen_Yosys; - -/// \brief a class to store (and generate) the problem for Yosys -class Yosys_problem { - friend class VlgSglTgtGen_Yosys; - /// Type of assertions and assumptions - typedef std::vector prop_t; - /// Type of a problem --- we can handle multiple several problems (may not - /// needed) - typedef struct { - // the name in [??] - // std::string problem_name; - /// will be conjuncted and put in the question - prop_t exprs; - } problem_t; - /// set of problems - typedef std::map problemset_t; - -protected: - /// assumptions are not shared (unlike CoSA) - problemset_t assumptions; - /// problems are splitted into items - problemset_t assertions; - -}; // Yosys_problem - -/// \brief a class to interface w. Yosys -class VlgSglTgtGen_Yosys : public VlgSglTgtGen { - -public: - /// using the target type - using target_type_t = VlgSglTgtGen::target_type_t; - /// a tuple to store all related info for modification - using info_t = VerilogModifier::info_t; - /// filename -> (lineno, varname, is_port_sig) vec - using fn_l_map_t = VerilogModifier::fn_l_map_t; - /// Type of advanced parameter - using advanced_parameters_t = VlgVerifTgtGenBase::advanced_parameters_t; - /// Type of yosys target - using _chc_target_t = VlgVerifTgtGenBase::_chc_target_t; - -public: - // --------------------- CONSTRUCTOR ---------------------------- // - /// - /// \param[in] output path (ila-verilog, wrapper-verilog, problem.txt, - /// run-verify-by-???, modify-impl, it there is ) \param[in] pointer to the - /// instruction \param[in] the default configuration for outputing verilog - /// \param[in] the variable map - /// \param[in] the conditions - /// \param[in] pointer to verify info class - /// \param[in] verilog module name - /// \param[in] ila module name, - /// \param[in] all implementation sources - /// \param[in] all include paths - /// \param[in] which backend to use, it needs this info to gen proper - /// properties - VlgSglTgtGen_Yosys( - const std::string& output_path, // will be a sub directory of the - // output_path of its parent - const InstrPtr& instr_ptr, // which could be an empty pointer, and it will - // be used to verify invariants - const InstrLvlAbsPtr& ila_ptr, - const VerilogGenerator::VlgGenConfig& config, nlohmann::json& _rf_vmap, - nlohmann::json& _rf_cond, VlgTgtSupplementaryInfo& _sup_info, - VerilogInfo* _vlg_info_ptr, const std::string& vlg_mod_inst_name, - const std::string& ila_mod_inst_name, const std::string& wrapper_name, - const std::vector& implementation_srcs, - const std::vector& include_dirs, - const vtg_config_t& vtg_config, backend_selector vbackend, - const target_type_t& target_tp, advanced_parameters_t* adv_ptr, - _chc_target_t chc_target); - - // --------------------- Destructor ---------------------------- // - /// do nothing - virtual ~VlgSglTgtGen_Yosys(); - -protected: - /// Yosys problem generate - Yosys_problem _problems; - /// Yosys problem file name - std::string prob_fname; - /// Yosys script 'run.sh' name - std::string run_script_name; - /// the synthesis backend - synthesis_backend_selector s_backend; - /// the smt info of the design - std::shared_ptr design_smt_info; - /// whether to require a proof - bool generate_proof; - /// what are the targets - _chc_target_t chc_target; - -protected: - /// Add a direct assumption -- needed by base class - virtual void add_a_direct_assumption(const std::string& aspt, - const std::string& dspt) override; - /// Add a direct assertion -- needed by base class - virtual void add_a_direct_assertion(const std::string& asst, - const std::string& dspt) override; - - /// Pre export work : add assume and asssert to the top level - void virtual PreExportProcess() override; - /// export the script to run the verification - virtual void Export_script(const std::string& script_name) override; - /// export extra things: the chc script, the smt template - virtual void Export_problem(const std::string& extra_name) override; - /// export the memory abstraction (implementation) - /// Yes, this is also implementation specific, (jasper may use a different - /// one) - virtual void Export_mem(const std::string& mem_name) override; - /// For jasper, this means do nothing, for chc, you need to add (*keep*) - virtual void Export_modify_verilog() override; - -private: - /// Convert the smt file to CHC -- datatype encoding - void convert_smt_to_chc_datatype(const std::string& smt_fname, - const std::string& chc_fname); - /// Convert the smt file to CHC -- bitvector encoding - void convert_smt_to_chc_bitvec(const std::string& smt_fname, - const std::string& chc_fname, - const std::string& wrapper_mod_name); - /// generate the wrapper's smt first - void design_only_gen_smt(const std::string& smt_name, - const std::string& ys_script_name); - /// generate the wrapper's btor - void design_only_gen_btor(const std::string& btor_name, - const std::string& ys_script_name); - /// generate the aiger file - void generate_aiger(const std::string& blif_name, - const std::string& aiger_name, - const std::string& map_name, - const std::string& ys_script_name); - -public: - /// overwrite the Export - void virtual ExportAll(const std::string& wrapper_name, - const std::string& ila_vlg_name, - const std::string& script_name, - const std::string& extra_name, - const std::string& mem_name) override; - /// accessor of the design info - std::shared_ptr GetDesignSmtInfo() const; - /// It is okay to instantiation - virtual void do_not_instantiate(void) override{}; - -}; // class VlgVerifTgtGenYosys - -}; // namespace ilang - -#endif // VTARGET_GEN_YOSYS_H__ diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index b80acf95a..49cafb343 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -19,6 +19,7 @@ add_subdirectory(verilog-in) add_subdirectory(verilog-out) add_subdirectory(vtarget-out) add_subdirectory(smt-inout) +add_subdirectory(rfmap-in) if(${ILANG_BUILD_SYNTH}) add_subdirectory(target-itsy) @@ -143,6 +144,24 @@ else() target_link_libraries(${ILANG_LIB_NAME} PRIVATE verilogparser::verilogparser) endif() +## +## refinement parser +## +if(NOT TARGET vexpparser::vexpparser) + find_package(vexpparser REQUIRED) +endif() + +if (${ILANG_BUILD_TEST} OR ${ILANG_INSTALL_DEV}) + target_link_libraries(${ILANG_LIB_NAME} PUBLIC vexpparser::vexpparser) +else() + target_link_libraries(${ILANG_LIB_NAME} PRIVATE vexpparser::vexpparser) +endif() + +if(DEFINED FLEXLEXER_INCLUDE_PATH) + message(STATUS "Flex include path: ${FLEXLEXER_INCLUDE_PATH}") + include_directories(${FLEXLEXER_INCLUDE_PATH}) +endif() + ## ## vcd parser ## @@ -269,6 +288,11 @@ else() DESTINATION ${ILANG_INCLUDE_INSTALL_DIR}/ilang ) + install( + FILES ${ILANG_INCLUDE_BUILD_DIR}/ilang/rtl_verify.h + DESTINATION ${ILANG_INCLUDE_INSTALL_DIR}/ilang + ) + install( FILES ${ILANG_INCLUDE_BUILD_DIR}/ilang/config.h DESTINATION ${ILANG_INCLUDE_INSTALL_DIR}/ilang diff --git a/src/ilang++.cc b/src/ilang++.cc index 6091c964e..94b454ddb 100644 --- a/src/ilang++.cc +++ b/src/ilang++.cc @@ -14,6 +14,7 @@ #include #include #include +#include #ifdef SMTSWITCH_INTERFACE #include @@ -868,4 +869,30 @@ smt::Term ResetAndGetSmtTerm(smt::SmtSolver& solver, const ExprRef& expr, } #endif // SMTSWITCH_INTERFACE +IlaVerilogRefinementChecker::IlaVerilogRefinementChecker( + const Ila& ila, + const std::vector& implementation_include_path, + const std::vector& implementation_srcs, + const std::string& implementation_top_module, + const std::string& refinement_variable_mapping, + const std::string& refinement_conditions, + const std::string& output_path, + ModelCheckerSelection backend, + const RtlVerifyConfig& vtg_config ) { + + VerilogVerificationTargetGenerator checker( + implementation_include_path, + implementation_srcs, + implementation_top_module, + refinement_variable_mapping, + refinement_conditions, + output_path, + ila.get(), + backend, + vtg_config + ); + + checker.GenerateTargets(); +} + } // namespace ilang diff --git a/src/mcm/ast_helper.cc b/src/mcm/ast_helper.cc index ea98f6801..0ed1c1bae 100644 --- a/src/mcm/ast_helper.cc +++ b/src/mcm/ast_helper.cc @@ -8,6 +8,7 @@ #include #include #include +#include namespace ilang { @@ -170,6 +171,10 @@ FunctionApplicationFinder::GetReferredFunc() const { } +bool isSpecialUnknownFunction(const ExprOpAppFunc::FuncPtr & func) { + return StrStartsWith(func->name().str(), "__unknown__"); +} + bool getIteUnknownCondVal(const ExprPtr & e, ExprPtr & c, ExprPtr & v) { if (!e->is_op()) @@ -183,7 +188,7 @@ bool getIteUnknownCondVal(const ExprPtr & e, ExprPtr & c, ExprPtr & v) { if ( (arg1 && arg1->op_name() == "APP") ) { std::shared_ptr apply_op_arg1 = std::dynamic_pointer_cast(arg1); - if ( StateMappingDirectiveRecorder::isSpecialUnknownFunction(apply_op_arg1->func())) { + if ( isSpecialUnknownFunction(apply_op_arg1->func())) { c = eop->arg(0); v = eop->arg(2); return true; @@ -196,7 +201,7 @@ bool getIteUnknownCondVal(const ExprPtr & e, ExprPtr & c, ExprPtr & v) { if ( (arg2 && arg2->op_name() == "APP") ) { std::shared_ptr apply_op_arg2 = std::dynamic_pointer_cast(arg2); - if ( StateMappingDirectiveRecorder::isSpecialUnknownFunction(apply_op_arg2->func())) { + if ( isSpecialUnknownFunction(apply_op_arg2->func())) { c = eop->arg(0); v = eop->arg(1); return true; diff --git a/src/rfmap-in/CMakeLists.txt b/src/rfmap-in/CMakeLists.txt new file mode 100644 index 000000000..927431f9f --- /dev/null +++ b/src/rfmap-in/CMakeLists.txt @@ -0,0 +1,10 @@ +# ---------------------------------------------------------------------------- # +# source +# ---------------------------------------------------------------------------- # +target_sources(${ILANG_LIB_NAME} PRIVATE + ${CMAKE_CURRENT_SOURCE_DIR}/verilog_rfmap.cc + ${CMAKE_CURRENT_SOURCE_DIR}/rfmap_typecheck.cc + ${CMAKE_CURRENT_SOURCE_DIR}/rfexpr_to_smt.cc + ${CMAKE_CURRENT_SOURCE_DIR}/rfexpr_shortcut.cc +) + diff --git a/src/rfmap-in/rfexpr_shortcut.cc b/src/rfmap-in/rfexpr_shortcut.cc new file mode 100644 index 000000000..00c1a0b60 --- /dev/null +++ b/src/rfmap-in/rfexpr_shortcut.cc @@ -0,0 +1,90 @@ +/// \file rfexpr_to_smt.cc Refinement map to smt-lib2 +/// Hongce Zhang (zhanghongce@126.com) + +#include +#include +#include + +namespace ilang { + +rfmap::RfExpr rfmap_reduce_or(const rfmap::RfExpr& in) { + return verilog_expr::VExprAst::MakeUnaryAst(verilog_expr::voperator::B_OR, + in); +} + +rfmap::RfExpr rfmap_imply(const rfmap::RfExpr& l, const rfmap::RfExpr& r) { + return rfmap_or(rfmap_not(l), r); +} + +rfmap::RfExpr rfmap_and(const rfmap::RfExpr& l, const rfmap::RfExpr& r) { + return verilog_expr::VExprAst::MakeBinaryAst(verilog_expr::voperator::L_AND, + l, r); +} + +rfmap::RfExpr rfmap_or(const rfmap::RfExpr& l, const rfmap::RfExpr& r) { + return verilog_expr::VExprAst::MakeBinaryAst(verilog_expr::voperator::L_OR, l, + r); +} + +rfmap::RfExpr rfmap_and(const std::vector& v) { + ILA_ERROR_IF(v.empty()) << "rfmap_and([])"; + + auto ret = v.at(0); + for (size_t idx = 1; idx < v.size(); ++idx) + ret = rfmap_and(ret, v.at(idx)); + return ret; +} + +rfmap::RfExpr rfmap_or(const std::vector& v) { + ILA_ERROR_IF(v.empty()) << "rfmap_or([])"; + + auto ret = v.at(0); + for (size_t idx = 1; idx < v.size(); ++idx) + ret = rfmap_or(ret, v.at(idx)); + return ret; +} + +rfmap::RfExpr rfmap_ite(const rfmap::RfExpr& c, const rfmap::RfExpr& l, + const rfmap::RfExpr& r) { + return verilog_expr::VExprAst::MakeTernaryAst( + verilog_expr::voperator::TERNARY, c, l, r); +} + +rfmap::RfExpr rfmap_eq(const rfmap::RfExpr& l, const rfmap::RfExpr& r) { + return verilog_expr::VExprAst::MakeBinaryAst(verilog_expr::voperator::L_EQ, l, + r); +} + +rfmap::RfExpr rfmap_le(const rfmap::RfExpr& l, const rfmap::RfExpr& r) { + return verilog_expr::VExprAst::MakeBinaryAst(verilog_expr::voperator::LTE, l, + r); +} + +rfmap::RfExpr rfmap_not(const rfmap::RfExpr& l) { + return verilog_expr::VExprAst::MakeUnaryAst(verilog_expr::voperator::L_NEG, + l); +} + +rfmap::RfExpr rfmap_true() { + return verilog_expr::VExprAst::MakeConstant(2, 1, "1"); +} + +rfmap::RfExpr rfmap_false() { + return verilog_expr::VExprAst::MakeConstant(2, 1, "0"); +} + +rfmap::RfExpr rfmap_const(unsigned b, unsigned w, unsigned v) { + return verilog_expr::VExprAst::MakeConstant(b, w, + IntToStrCustomBase(v, b, false)); +} +/// if it is RTL. or ILA. then will use MakeVar +/// otherwise will use MakeSpecial +/// will not determine its type +/// ReplExpr will determine the type +rfmap::RfExpr rfmap_var(const std::string& v) { + if (StrStartsWith(v, "RTL.") || StrStartsWith(v, "ILA.")) + return verilog_expr::VExprAst::MakeVar(v); + return verilog_expr::VExprAst::MakeSpecialName(v); +} + +} // namespace ilang diff --git a/src/rfmap-in/rfexpr_to_smt.cc b/src/rfmap-in/rfexpr_to_smt.cc new file mode 100644 index 000000000..0c3af4e36 --- /dev/null +++ b/src/rfmap-in/rfexpr_to_smt.cc @@ -0,0 +1,463 @@ +/// \file rfexpr_to_smt.cc Refinement map to smt-lib2 +/// Hongce Zhang (hongcez@princeton.edu) + +#include +#include +#include + +#include + +namespace ilang { +namespace rfmap { + +std::string SmtType::type_to_smt2() const { + if (is_bool()) + return "Bool"; + if (is_bv()) + return "(_ BitVec " + std::to_string(unified_width()) + ")"; + ILA_ERROR_IF(!is_array()) << "Does not know how to translate unknown type"; + return "(Array (_ BitVec " + std::to_string(addr_width) + ") (_ BitVec " + + std::to_string(data_width) + "))"; +} + +static std::vector voperator_str_smt = { + "bvmul", // STAR + "bvadd", "bvsub", "bvshl", "bvashr", "bvshl", "bvlshr", "bvudiv", + "#notsupported", // POW ** + "bvurem", "bvuge", "bvule", "bvugt", "bvult", "not", "and", "or", "=", "=", + "#special", "#special", "bvnot", "bvand", "bvor", "bvxor", "bvxnor", + "bvnand", + "bvnor", // B_NOR + "#special", // select/extract [idx] operator A[i1][i2] -> + // index(index(A,i1),i2) A[i1[i2]] index(A, index(i1,i2)) + "#special", // extract [i1:i2] ternary + "#special", // extract [i1:+i2] ternary + "#special", // extract [i1:-i2] ternary + "store", // store A:<3>:5:<4>:6:<5>:7 (not supported yet) + "#notsupported", // AT + "ite", // ternary + /*special ops*/ + "#special", // function app + "concat", + "#special", // REPEAT if it is const we can handle + /*Placeholder*/ + "MK_CONST", "MK_VAR", + + "#notsupported", // delay + "#special", "#special" // forall and exist +}; + +static RfMapVarType get_type(const RfExpr& in) { + auto tp = in->get_annotation(); + if (tp == nullptr) + return RfMapVarType(); + return tp->type; +} + +static std::string smt_const(unsigned value, unsigned width) { + auto ret = IntToStrCustomBase(value, 2, false); + if (ret.length() > width) { + ILA_ERROR << "Creating SMT constant with value " << value + << " width: " << width; + throw verilog_expr::VexpException( + verilog_expr::ExceptionCause::UnknownNumberSmtTranslation); + } + + std::string zero; + if (width > ret.length()) + for (unsigned idx = 0; idx < width - ret.length(); ++idx) + zero += "0"; + return "#b" + zero + ret; +} // smt_const + +static std::string split_bit(const std::string& opstr, unsigned width, + const std::string& childstr) { + if (width <= 1) + return childstr; + + std::vector child; + for (unsigned idx = 0; idx < width; ++idx) { + auto ext = + "(_ extract " + std::to_string(idx) + " " + std::to_string(idx) + ")"; + child.push_back("(" + ext + " " + childstr + ")"); + } + + std::string ret = "(" + opstr + " " + child.at(0) + " " + child.at(1) + ")"; + for (unsigned idx = 2; idx < child.size(); ++idx) + ret = "(" + opstr + " " + ret + " " + child.at(idx) + ")"; + return ret; +} + +static SmtType common_type(RfMapVarType tp1, RfMapVarType tp2) { + if (tp1.is_array() || tp2.is_array()) { + ILA_CHECK(tp2.is_array() && tp1.is_array() && + tp2.addr_width == tp1.addr_width && + tp2.data_width == tp1.data_width); + return SmtType(tp1, false); + } + + if (tp1.is_bv() && tp2.is_bv()) { + return SmtType(std::max(tp1.unified_width(), tp2.unified_width())); + } + + if (tp1.is_unknown() || tp2.is_unknown()) { + if (!tp1.is_unknown()) + return SmtType(tp1, false); + if (!tp2.is_unknown()) + return SmtType(tp2, false); + } + ILA_CHECK(false) << "unable to determine common type"; + return SmtType(); // should not be reachable +} + +static std::string extend_width(const std::string& in, unsigned inw, + unsigned outw) { + ILA_CHECK(outw > inw); + return "(concat " + smt_const(0, outw - inw) + " " + in + ")"; +} +// make sure in_bool -> out_bool +static std::string type_convert(SmtType out_tp, SmtType in_tp, + const std::string& in) { + if (out_tp == in_tp) + return in; + + if (out_tp.is_bool() && in_tp.is_bv()) { + return "(not (= " + in + " " + smt_const(0, in_tp.unified_width()) + "))"; + } + + if (in_tp.is_bool() && out_tp.is_bv()) { + auto retstr = "(ite " + in + " #b1 #b0)"; + ILA_CHECK(out_tp.unified_width() > 0); + if(out_tp.unified_width() == 1) + return retstr; + return extend_width("(ite " + in + " #b1 #b0)", 1, out_tp.unified_width()); + } + + if (in_tp.is_bv() && out_tp.is_bv() && + in_tp.unified_width() != out_tp.unified_width()) { + ILA_ASSERT(out_tp.unified_width() > in_tp.unified_width()) + << "[Convert to SMT] cutting input bit-vector, not allowed."; + return extend_width(in, in_tp.unified_width(), out_tp.unified_width()); + } + + if (in_tp.is_array() || out_tp.is_array()) { + ILA_CHECK(false) << "Unable to convert array of different sizes"; + } + ILA_CHECK(false) << "Unable to convert types"; + return "|ERROR|"; +} + +// typeconvert +// intype == outtype +// bv_n -> bool +// bool -> bv_n +// bv_n -> bv_(n+m) +// E: truncate +// E: array -> ? +// E: ? -> array + +std::string RfExpr2Smt::to_smt2_const( + const std::shared_ptr& in, + SmtType expected_type) { + unsigned out; + bool succ = _compute_const(in, out); + if (!succ) + throw verilog_expr::VexpException( + verilog_expr::ExceptionCause::UnknownNumberSmtTranslation); + + auto b_w_l = in->get_constant(); + auto width = std::get<1>(b_w_l); + if (width == 0) + width = expected_type.unified_width(); + return type_convert(expected_type, SmtType(width), smt_const(out, width)); + +} // to_smt2_const + +std::string +RfExpr2Smt::to_smt2_var(const std::shared_ptr& in, + SmtType expected_type) { + RfMapVarType tp = get_type(in); + auto ret = "|" + in->get_name().first + "|"; + if (!tp.is_array()) + ret = type_convert(expected_type, SmtType(tp.unified_width()), ret); + else + ILA_ASSERT(expected_type == SmtType(tp, false)); + return ret; +} // to_smt2_var + +std::string RfExpr2Smt::to_smt2(const RfExpr& in, SmtType expected_type) { + if (in->is_var()) { + auto ptr = std::dynamic_pointer_cast(in); + ILA_NOT_NULL(ptr); + return to_smt2_var(ptr, expected_type); + } + if (in->is_constant()) { + auto ptr = std::dynamic_pointer_cast(in); + ILA_NOT_NULL(ptr); + return to_smt2_const(ptr, expected_type); + } + + auto op_ = in->get_op(); + const auto& child_ = in->get_child(); + + ILA_ASSERT(op_ != verilog_expr::voperator::MK_CONST && + op_ != verilog_expr::voperator::MK_CONST); + + unsigned idx = static_cast(op_); + ILA_ASSERT(idx < voperator_str_smt.size()); + auto opstr = voperator_str_smt.at(idx); + if (opstr == "#notsupported") + throw verilog_expr::VexpException( + verilog_expr::ExceptionCause::UntranslatedSmtlib2, opstr); + // TODO: + + if (child_.size() == 1 && (op_ == verilog_expr::voperator::L_NEG)) { + + RfMapVarType tp = get_type(child_.at(0)); + return type_convert(expected_type, SmtType(tp, true), + "(" + opstr + " " + + to_smt2(child_.at(0), SmtType(tp, true)) + ")"); + } + + if (child_.size() == 1 && (op_ == verilog_expr::voperator::B_NEG)) { + + RfMapVarType tp = get_type(child_.at(0)); + return type_convert(expected_type, SmtType(tp, false), + "(" + opstr + " " + + to_smt2(child_.at(0), SmtType(tp, false)) + ")"); + } + + if (child_.size() == 1 && op_ == verilog_expr::voperator::PLUS) { + + RfMapVarType tp = get_type(in); + return type_convert(expected_type, SmtType(tp, false), + to_smt2(child_.at(0), SmtType(tp, false))); + } + + if (child_.size() == 1 && op_ == verilog_expr::voperator::MINUS) { + + RfMapVarType tp = get_type(in); + return type_convert(expected_type, SmtType(tp, false), + "(bvsub " + smt_const(0, tp.unified_width()) + " " + + to_smt2(child_.at(0), SmtType(tp, false))); + } + + if (child_.size() == 1 && (op_ == verilog_expr::voperator::B_AND || + op_ == verilog_expr::voperator::B_NAND || + op_ == verilog_expr::voperator::B_OR || + op_ == verilog_expr::voperator::B_NOR || + op_ == verilog_expr::voperator::B_XOR || + op_ == verilog_expr::voperator::B_EQU)) { + + RfMapVarType tp = get_type(in); + + return type_convert(expected_type, SmtType(tp, false), + split_bit(opstr, tp.unified_width(), + to_smt2(child_.at(0), SmtType(tp, false)))); + } + + RfMapVarType parent_tp = get_type(in); + + // binary or more + switch (op_) { + case verilog_expr::voperator::STAR: // mul + case verilog_expr::voperator::PLUS: + case verilog_expr::voperator::MINUS: + case verilog_expr::voperator::ASL: + case verilog_expr::voperator::ASR: + case verilog_expr::voperator::LSL: + case verilog_expr::voperator::LSR: + case verilog_expr::voperator::DIV: + case verilog_expr::voperator::MOD: + ILA_ASSERT(child_.size() == 2); + return type_convert( + expected_type, SmtType(parent_tp, false), + "(" + opstr + " " + to_smt2(child_.at(0), SmtType(parent_tp, false)) + + " " + to_smt2(child_.at(1), SmtType(parent_tp, false)) + ")"); + break; + + case verilog_expr::voperator::GTE: + case verilog_expr::voperator::LTE: + case verilog_expr::voperator::GT: + case verilog_expr::voperator::LT: + case verilog_expr::voperator::C_EQ: + case verilog_expr::voperator::L_EQ: + ILA_ASSERT(child_.size() == 2); + { + SmtType common_tp = + common_type(get_type(child_.at(0)), get_type(child_.at(1))); + return type_convert(expected_type, SmtType(parent_tp, true), + "(" + opstr + " " + to_smt2(child_.at(0), common_tp) + + " " + to_smt2(child_.at(1), common_tp) + ")"); + } + break; + + case verilog_expr::voperator::C_NEQ: + case verilog_expr::voperator::L_NEQ: + ILA_ASSERT(child_.size() == 2); + { // expect common_type to make bool false? + SmtType common_tp = + common_type(get_type(child_.at(0)), get_type(child_.at(1))); + return type_convert(expected_type, SmtType(parent_tp, true), + "(not (= " + to_smt2(child_.at(0), common_tp) + " " + + to_smt2(child_.at(1), common_tp) + "))"); + break; + } + + case verilog_expr::voperator::L_AND: + case verilog_expr::voperator::L_OR: + ILA_ASSERT(child_.size() == 2); + return type_convert( + expected_type, SmtType(parent_tp, true), + "(" + opstr + " " + + to_smt2(child_.at(0), SmtType(get_type(child_.at(0)), true)) + " " + + to_smt2(child_.at(1), SmtType(get_type(child_.at(1)), true)) + ")"); + break; + + case verilog_expr::voperator::B_AND: + case verilog_expr::voperator::B_OR: + case verilog_expr::voperator::B_XOR: + case verilog_expr::voperator::B_EQU: + case verilog_expr::voperator::B_NAND: + case verilog_expr::voperator::B_NOR: { + SmtType common_tp = + common_type(get_type(child_.at(0)), get_type(child_.at(1))); + + ILA_ASSERT(child_.size() == 2); + return type_convert(expected_type, SmtType(parent_tp, false), + "(" + opstr + " " + to_smt2(child_.at(0), common_tp) + + " " + to_smt2(child_.at(1), common_tp) + ")"); + break; + } + + default: + break; + } // end switch + + if (op_ == verilog_expr::voperator::INDEX) { + RfMapVarType tp = get_type(child_.at(0)); + if (tp.is_array()) { + return type_convert( + expected_type, SmtType(tp.unified_width()), + "(select " + to_smt2(child_.at(0), SmtType(tp, false)) + " " + + to_smt2(child_.at(1), SmtType(tp.addr_width)) + ")"); + } // else is bv + // request to index to be constant + unsigned bitidx; + bool succ = _compute_const(child_.at(1), bitidx); + if (!succ) + throw verilog_expr::VexpException( + verilog_expr::ExceptionCause::UnknownNumberSmtTranslation); + auto bitidxstr = std::to_string(bitidx); + return type_convert(expected_type, SmtType(1) /* (_ BitVec 1) */, + "((_ extract " + bitidxstr + " " + bitidxstr + ") " + + to_smt2(child_.at(0), SmtType(tp, false)) + ")"); + } // end if INDEX + + if (op_ == verilog_expr::voperator::IDX_PRT_SEL_PLUS || + op_ == verilog_expr::voperator::IDX_PRT_SEL_MINUS || + op_ == verilog_expr::voperator::RANGE_INDEX) { + + unsigned l, r; + bool succ = _compute_const(child_.at(1), l); + succ = succ && _compute_const(child_.at(2), r); + if (!succ) + throw verilog_expr::VexpException( + verilog_expr::ExceptionCause::UnknownNumberSmtTranslation); + + if (op_ == verilog_expr::voperator::IDX_PRT_SEL_PLUS) + r = l + r - 1; + else if (op_ == verilog_expr::voperator::IDX_PRT_SEL_MINUS) + r = l - r + 1; + auto lstr = std::to_string(l); + auto rstr = std::to_string(r); + RfMapVarType tp = get_type(child_.at(0)); + return type_convert(expected_type, SmtType(l - r + 1), + "((_ extract " + lstr + " " + rstr + ") " + + to_smt2(child_.at(0), SmtType(tp, false)) + ")"); + } // IDX_PRT_SEL_PLUS, IDX_PRT_SEL_MINUS, RANGE_INDEX + + if (op_ == verilog_expr::voperator::STORE_OP) { + SmtType tp0(get_type(child_.at(0)), false); + SmtType tp1(get_type(child_.at(1)), false); + // no need to convert + ILA_ASSERT(expected_type == tp0); + return "(store " + to_smt2(child_.at(0), tp0) + " " + + to_smt2(child_.at(1), tp1) + ")"; + // do not convert as we are unable to do so + } // STORE_OP + + if (op_ == verilog_expr::voperator::TERNARY) { + RfMapVarType parent_tp = get_type(in); + // you need to handle the case of array + SmtType common_tp = + common_type(get_type(child_.at(1)), get_type(child_.at(2))); + + if (parent_tp.is_array()) { + // do not convert as we are unable to do so + return "(ite " + to_smt2(child_.at(0), SmtType()) + " " + + to_smt2(child_.at(1), common_tp) + " " + + to_smt2(child_.at(2), common_tp) + ")"; + } // else + + return type_convert(expected_type, common_tp, + "(ite " + to_smt2(child_.at(0), SmtType()) + " " + + to_smt2(child_.at(1), common_tp) + " " + + to_smt2(child_.at(2), common_tp) + ")"); + } + + if (op_ == verilog_expr::voperator::FUNCTION_APP) + throw verilog_expr::VexpException( + verilog_expr::ExceptionCause::UntranslatedSmtlib2); + + if (op_ == verilog_expr::voperator::CONCAT) { + ILA_ASSERT(in->get_child_cnt() == 2); + return type_convert( + expected_type, SmtType(parent_tp, false), + "(concat " + + to_smt2(child_.at(0), SmtType(get_type(child_.at(0)), false)) + + " " + + to_smt2(child_.at(1), SmtType(get_type(child_.at(1)), false)) + + ")"); + } // CONCAT + + if (op_ == verilog_expr::voperator::REPEAT) { + ILA_ASSERT(in->get_child_cnt() == 2); + unsigned ntimes; + if (!_compute_const(in->get_child().at(0), ntimes)) + throw verilog_expr::VexpException( + verilog_expr::ExceptionCause::UnknownNumberSmtTranslation); + ILA_ASSERT(ntimes > 0); + std::string c1 = + to_smt2(child_.at(1), SmtType(get_type(child_.at(1)), false)); + std::string ret = "(concat " + c1 + " " + c1 + ")"; + + for (unsigned idx = 2; idx < ntimes; ++idx) + ret = "(concat " + ret + " " + c1 + ")"; + + return type_convert(expected_type, SmtType(parent_tp, false), ret); + } + + if(op_ == verilog_expr::voperator::FORALL || op_ == verilog_expr::voperator::EXIST) { + ILA_ASSERT(in->get_child_cnt() == 1); + ILA_ASSERT(in->get_str_parameter().size() == 1); + ILA_ASSERT(in->get_parameter().size() == 1); + const std::string & qvar = in->get_str_parameter().at(0); + auto width = in->get_parameter().at(0); + + std::string c1 = + to_smt2(child_.at(0), SmtType(get_type(child_.at(0)), true)); + std::string quantifier = op_ == verilog_expr::voperator::FORALL ? "forall" : "exists"; + std::string ret = "(" + quantifier + " ((" + qvar + " (_ BitVec " + std::to_string(width) + "))) " + c1 + ")"; + return type_convert(expected_type, SmtType(), ret); // convert bool : SmtType() to expected type + } + + throw verilog_expr::VexpException( + verilog_expr::ExceptionCause::UntranslatedSmtlib2); + + return ""; + +} // end to_smt + +} // namespace rfmap +} // namespace ilang diff --git a/src/rfmap-in/rfmap_typecheck.cc b/src/rfmap-in/rfmap_typecheck.cc new file mode 100644 index 000000000..e9a4a0451 --- /dev/null +++ b/src/rfmap-in/rfmap_typecheck.cc @@ -0,0 +1,1176 @@ +/// \file rfmap_typecheck.cc Refinement map typecheck +/// Second pass : rfexpr typecheck + +#include +#include +#include + +#include +#include +#include +#include + +namespace ilang { +namespace rfmap { + +using namespace verilog_expr; + +std::string TypedVerilogRefinementMap::new_id() { + return "__auxvar" + std::to_string(counter++) + "__"; +} + +TypedVerilogRefinementMap::TypedVerilogRefinementMap( + const VerilogRefinementMap& refinement, var_typecheck_t type_checker) + : VerilogRefinementMap(refinement), typechecker(type_checker), counter(0) { + initialize(); +} + +TypedVerilogRefinementMap::TypedVerilogRefinementMap( + const std::string& varmap_json_file, const std::string& instcond_json_file, + var_typecheck_t type_checker) + : VerilogRefinementMap(varmap_json_file, instcond_json_file), + typechecker(type_checker), counter(0) { + initialize(); +} // TypedVerilogRefinementMap::TypedVerilogRefinementMap + +void TypedVerilogRefinementMap::initialize() { + // collect those with unknown types + // a. delay + // b. value holder + CollectInlineDelayValueHolder(); + + // put existing internal vars in + // all_var_def_types + CollectInternallyDefinedVars(); + + // determine the types of delay and value holder + // and add them to all_var_def_types + // will use current all_var_def_types + ComputeDelayValueHolderWidth(); + +} // initialize + +// this function will iteratively make a new copy of the whole AST. +RfExpr RfExprVarReplUtility::ReplacingRtlIlaVar(const RfExpr& in, const std::set & quantified_vars) { + + // skip state memory mapped + // provide a function to ReplExpr... + auto tp_annotate = in->get_annotation(); + + if (in->is_var()) { + auto var_ptr = std::dynamic_pointer_cast(in); + ILA_NOT_NULL(var_ptr); + auto n = var_ptr->get_name(); + if(quantified_vars.find(n.first) != quantified_vars.end()) + return in; // will not replace a quantified variable + + ILA_CHECK(var_replacement.find(n.first) != var_replacement.end()) + << "variable " << n.first << " has no replacement"; + + return var_replacement.at(n.first).newvar; + } else if (in->is_constant()) { + return in; + } + // else is op + std::vector retchild; + bool has_quantifier = + in->get_op() == verilog_expr::voperator::EXIST || + in->get_op() == verilog_expr::voperator::FORALL; + if(has_quantifier) { + std::set new_quantified_vars(quantified_vars); + ILA_ASSERT(in->get_child_cnt() == 1 && in->get_str_parameter().size() == 1); + new_quantified_vars.insert(in->get_str_parameter().at(0)); // the quantified var + retchild.push_back(ReplacingRtlIlaVar(in->get_child().at(0), new_quantified_vars)); + } else { + for (size_t idx = 0; idx < in->get_child_cnt(); ++idx) { + retchild.push_back(ReplacingRtlIlaVar(in->get_child().at(idx), quantified_vars)); + } + } + auto ret = in->MakeCopyWithNewChild(retchild); + ret->set_annotation(in->get_annotation()); + return ret; +} // AnnotateSignalsAndCollectRtlVars + +RfExpr TypedVerilogRefinementMap::collect_inline_value_recorder_func( + const RfExpr& in) { + if (in->get_op() != verilog_expr::voperator::AT) + return in; + + auto recorder_name = new_id() + "recorder"; + auto new_node = verilog_expr::VExprAst::MakeVar(recorder_name); + + verilog_expr::VExprAst::VExprAstPtrVec child(in->get_child()); + ValueRecorder tmp_value_recorder; + tmp_value_recorder.width = 0; + tmp_value_recorder.value = child.at(0); + // TODO: deal with value@CLK.n + if (child.at(1)->is_constant()) { + // deal with value@0 + auto new_cond = verilog_expr::VExprAst::MakeBinaryAst( + verilog_expr::voperator::L_EQ, + verilog_expr::VExprAst::MakeVar("__CYCLE_CNT__"), child.at(1)); + tmp_value_recorder.condition = new_cond; + } else + tmp_value_recorder.condition = child.at(1); + value_recorder.emplace(recorder_name, tmp_value_recorder); + return new_node; // rewrite the node +} // collect_inline_value_recorder_func + +RfExpr TypedVerilogRefinementMap::collect_inline_delay_func(const RfExpr& in) { + if (in->get_op() != voperator::DELAY) + return in; + // else + assert(in->get_parameter().size() == in->get_str_parameter().size()); + assert(in->get_child().size() == 1 || in->get_child().size() == 2); + assert(in->get_parameter().size() == 1 || in->get_parameter().size() == 2); + + auto delay_name = new_id() + "delay"; + auto new_node = VExprAst::MakeVar(delay_name); + + if (in->get_parameter().size() == 1) { + // Single a ##n + int delay = in->get_parameter().at(0); + aux_delays.emplace(delay_name, SignalDelay(in->get_child().at(0), delay)); + // std::cout << "SingleDelay:" <get_child().at(0) <get_parameter().size() == 2 + // RANGE/INF a ##[n,m] / ##[n,0] 0 represents $ + int delay = in->get_parameter().at(0); + int delay_upper = in->get_parameter().at(1); + aux_delays.emplace(delay_name, + SignalDelay(in->get_child().at(0), delay, delay_upper)); + // std::cout << "2Delay:" <get_child().at(0) <get_child().size() == 1) { + ret = new_node; + } else { + assert(in->get_child().size() == 2); + auto tmp_node = VExprAst::MakeBinaryAst(voperator::L_AND, new_node, + in->get_child().at(1)); + ret = tmp_node; + } + // std::cout << "-->:" << ret < RfExpr { + return this->collect_inline_delay_func(in); + }); + TraverseAllRfExpr([this](const RfExpr& in) -> RfExpr { + return this->collect_inline_value_recorder_func(in); + }); +} + +// internal datastructure like +// phase_tracker, value_recorder, customized_monitor, aux_delay -> +// all_var_def_types +// +void TypedVerilogRefinementMap::CollectInternallyDefinedVars() { + for (const auto& n_st : phase_tracker) { + for (const auto& var_def : n_st.second.event_alias) { + VarDef tmp; + tmp.type = VarDef::var_type::WIRE; + tmp.width = 1; + all_var_def_types.emplace(var_def.first, tmp); + } + for (const auto& var_def : n_st.second.var_defs) { + all_var_def_types.emplace(var_def.first, var_def.second); + } + for (const auto& stage : n_st.second.rules) { + VarDef tmp; + tmp.type = VarDef::var_type::REG; + tmp.width = 1; + all_var_def_types.emplace(stage.stage_name, tmp); + } + } + for (const auto& n_st : value_recorder) { + VarDef tmp; + if (n_st.second.width != 0) { + tmp.width = n_st.second.width; + tmp.type = VarDef::var_type::REG; + all_var_def_types.emplace(n_st.first, tmp); + } + } // value recorder + + for (const auto& n_expr : direct_aux_vars) { + ILA_CHECK(n_expr.second.width == 0); + } // direct aux vars + + for (const auto& n_st : customized_monitor) { + for (const auto& var_def : n_st.second.var_defs) { + all_var_def_types.emplace(var_def.first, var_def.second); + } + } + + // add internal signals + { // add decode,commit, $decode, $valid + VarDef tmp; + tmp.width = 1; + tmp.type = VarDef::var_type::WIRE; + + all_var_def_types.emplace("decode", tmp); // these are the stage info + all_var_def_types.emplace("afterdecode", tmp); // these are the stage info + all_var_def_types.emplace("commit", tmp); + + + all_var_def_types.emplace("start", tmp); // these are the stage info + all_var_def_types.emplace("afterstart", tmp); // these are the stage info + all_var_def_types.emplace("end", tmp); + + all_var_def_types.emplace("$decode", + tmp); // these are the ila.decode/ila.valid info + all_var_def_types.emplace("$valid", tmp); + + } // end of add decode,commit, $decode, $valid + +} // CollectInternallyDefinedVars + +void TypedVerilogRefinementMap::TraverseCondMap( + SingleVarMap& inout, std::function func) { + if (inout.single_map) + inout.single_map = TraverseRfExpr(inout.single_map, func); + else + for (auto& c : inout.cond_map) { + c.first = TraverseRfExpr(c.first, func); + c.second = TraverseRfExpr(c.second, func); + } +} // TraverseCondMap + +void TypedVerilogRefinementMap::TraverseAllRfExpr( + std::function func) { + for (auto& sv : ila_state_var_map) { + if (sv.second.type == IlaVarMapping::StateVarMapType::SINGLE) + sv.second.single_map.single_map = + TraverseRfExpr(sv.second.single_map.single_map, func); + else if (sv.second.type == IlaVarMapping::StateVarMapType::CONDITIONAL) { + for (auto& c : sv.second.single_map.cond_map) { + c.first = TraverseRfExpr(c.first, func); + c.second = TraverseRfExpr(c.second, func); + } + } else { // extern map + for (auto& m : sv.second.externmem_map) { + TraverseCondMap(m.raddr_map, func); + TraverseCondMap(m.rdata_map, func); + TraverseCondMap(m.ren_map, func); + TraverseCondMap(m.waddr_map, func); + TraverseCondMap(m.wdata_map, func); + TraverseCondMap(m.wen_map, func); + } + } + } // sv map + + for (auto& sv : ila_input_var_map) { + if (sv.second.type == IlaVarMapping::StateVarMapType::SINGLE) + sv.second.single_map.single_map = + TraverseRfExpr(sv.second.single_map.single_map, func); + else /* if(sv.second.type == IlaVarMapping::StateVarMapType::CONDITIONAL) */ + { + for (auto& c : sv.second.single_map.cond_map) { + c.first = TraverseRfExpr(c.first, func); + c.second = TraverseRfExpr(c.second, func); + } + } + } // input var + + for (auto& ufa : uf_application) { + for (auto& fapp : ufa.second.func_applications) { + fapp.result_map = TraverseRfExpr(fapp.result_map, func); + for (auto& a : fapp.arg_map) + a = TraverseRfExpr(a, func); + } + } // uf application + for (auto& a : assumptions) + a = TraverseRfExpr(a, func); + for (auto& a : additional_mapping) + a = TraverseRfExpr(a, func); + + for (auto& ptracker : phase_tracker) { + for (auto& a : ptracker.second.event_alias) + a.second = TraverseRfExpr(a.second, func); + for (auto& r : ptracker.second.rules) { + r.enter_rule = TraverseRfExpr(r.enter_rule, func); + if (r.exit_rule) + r.exit_rule = TraverseRfExpr(r.exit_rule, func); + for (auto& act : r.enter_action) + act.RHS = TraverseRfExpr(act.RHS, func); + for (auto& act : r.exit_action) + act.RHS = TraverseRfExpr(act.RHS, func); + } + } // phase tracker + for (auto& pv : value_recorder) { + pv.second.condition = TraverseRfExpr(pv.second.condition, func); + pv.second.value = TraverseRfExpr(pv.second.value, func); + } + for (auto& n_expr : direct_aux_vars) { + n_expr.second.val = TraverseRfExpr(n_expr.second.val, func); + } + + // ALERT: NOT handle customized_monitor in TraverseRfExpr + + for (auto& instcond : inst_complete_cond) { + if (instcond.second.type == + InstructionCompleteCondition::ConditionType::SIGNAL) + instcond.second.ready_signal = + TraverseRfExpr(instcond.second.ready_signal, func); + for (auto& cond : instcond.second.start_condition) + cond = TraverseRfExpr(cond, func); + } + if (global_inst_complete_set) { + if ( global_inst_complete_cond.type == InstructionCompleteCondition::ConditionType::SIGNAL) + global_inst_complete_cond.ready_signal = TraverseRfExpr(global_inst_complete_cond.ready_signal, func); + } + + for (auto& a : global_invariants) + a = TraverseRfExpr(a, func); + + for (auto& p_rf : rtl_interface_connection.input_port_connection) { + p_rf.second = TraverseRfExpr(p_rf.second, func); + } + +} // TraverseAllRfExpr + +// ------------------------------------------------------------------------------ + +// helper for type inference +bool _compute_const(const RfExpr& in, unsigned& out) { + if (!in->is_constant()) + return false; + std::shared_ptr cst_ast_ptr = + std::dynamic_pointer_cast(in); + if (cst_ast_ptr == nullptr) + return false; + auto bws = cst_ast_ptr->get_constant(); + auto base = std::get<0>(bws); + if (base == 0) + base = 10; + // auto width = std::get<1>(bws); + out = StrToLong(std::get<2>(bws), base); + return true; +} + +// this does not rely on type annotation +// relies on TypeInferTravserRfExpr +// and therefore, all_var_def_types +void TypedVerilogRefinementMap::ComputeDelayValueHolderWidth() { + + + unsigned failed_cnt = 0; + unsigned prev_failed_cnt = 0; + unsigned iter = 0; + do { + prev_failed_cnt = failed_cnt; + failed_cnt = 0; + for (auto& name_delay_pair : aux_delays) { + if (name_delay_pair.second.width == 0) { + auto tp = TypeInferTravserRfExpr(name_delay_pair.second.signal, {}); + ILA_CHECK(!tp.is_array()) + << "Currently does not support to delay a memory variable"; + + if (tp.is_array() || tp.is_unknown() || tp.unified_width() == 0) { + failed_cnt ++; + continue; + } + + name_delay_pair.second.width = tp.unified_width(); + + // replendish all_var_def_types + VarDef internal_var_def; + internal_var_def.width = tp.unified_width(); + internal_var_def.type = VarDef::var_type::REG; + + all_var_def_types.emplace(name_delay_pair.first, internal_var_def); + } + } + for (auto& name_vr : value_recorder) { + if (name_vr.second.width == 0) { + auto tp = TypeInferTravserRfExpr(name_vr.second.value, {}); + ILA_CHECK(!tp.is_array()) + << "Currently does not support to delay a memory variable"; + + if (tp.is_array() || tp.is_unknown() || tp.unified_width() == 0) { + failed_cnt ++; + continue; + } + + name_vr.second.width = tp.unified_width(); + + // replendish all_var_def_types + VarDef internal_var_def; + internal_var_def.width = tp.unified_width(); + internal_var_def.type = VarDef::var_type::REG; + + all_var_def_types.emplace(name_vr.first, internal_var_def); + } + } // replendish internal defined vars + + for (auto& n_expr : direct_aux_vars) { + if (n_expr.second.width == 0) { + + auto tp = TypeInferTravserRfExpr(n_expr.second.val, {}); + ILA_CHECK(!tp.is_array()) + << "Currently does not support to delay a memory variable"; + + if (tp.is_array() || tp.is_unknown() || tp.unified_width() == 0 ) { + failed_cnt ++; + continue; + } + n_expr.second.width = tp.unified_width(); + + VarDef internal_var_def; + internal_var_def.width = tp.unified_width(); + internal_var_def.type = VarDef::var_type::WIRE; + all_var_def_types.emplace(n_expr.first, internal_var_def); + } + } // end of for (auto& n_expr : direct_aux_vars) + ILA_ASSERT(prev_failed_cnt >= failed_cnt || prev_failed_cnt == 0); + ILA_INFO_IF(failed_cnt > 0) << "Rf Expr Type Resolution: iter " + << (iter++) << " remaining: " << failed_cnt; + }while(prev_failed_cnt != failed_cnt && failed_cnt != 0); + // the last round : report failed ones + ILA_INFO_IF(prev_failed_cnt > 0) << "Rf Expr Type Resolution: iter " + << (iter++) << " remaining: " << failed_cnt; + + for (auto& name_delay_pair : aux_delays) { + ILA_ERROR_IF (name_delay_pair.second.width == 0) + << "Type inference failed on: " + << name_delay_pair.second.signal->to_verilog(); + } + + for (auto& name_vr : value_recorder) { + ILA_ERROR_IF (name_vr.second.width == 0) + << "Type inference failed on: " << name_vr.second.value->to_verilog(); + } + + for (auto& n_expr : direct_aux_vars) { + ILA_ERROR_IF(n_expr.second.width == 0) + << "Type inference failed on: " << n_expr.second.val->to_verilog(); + } +} // ComputeDelayValueHolderWidth + +// relies on typechecker and all_var_def_types +RfMapVarType TypedVerilogRefinementMap::TypeInferTravserRfExpr( + const RfExpr& in, const std::map local_var_def) { + + ILA_CHECK(local_var_def.empty()); + // I believe we will never need to go into + // a forall/exists case because it is boolean! + + if (in->is_constant()) { + auto c = std::dynamic_pointer_cast(in) + ->get_constant(); + return RfMapVarType(std::get<1>(c)); + } else if (in->is_var()) { + auto n = + std::dynamic_pointer_cast(in)->get_name(); + + auto local_var_pos = local_var_def.find(n.first); + if (local_var_pos != local_var_def.end()) { + ILA_WARN_IF(n.second) << n.first + << " is regarded as quantified variable, which " + "should not be a special name"; + return RfMapVarType(local_var_pos->second); + } + + auto pos_def_var = all_var_def_types.find(n.first); + + if (n.second) { // is a special name + // check special name first + if (pos_def_var != all_var_def_types.end()) { + ILA_WARN_IF(pos_def_var->second.width == 0) + << "Using width of not yet" + << " determined var " << n.first; + return RfMapVarType(pos_def_var->second.width); + } + + RfVarTypeOrig rtl_ila_vartype = typechecker(n.first); + if (!rtl_ila_vartype.type.is_unknown()) + return rtl_ila_vartype.type; + // then rtl ila name + } else { + // check rtl ila name first + // then special name + RfVarTypeOrig rtl_ila_vartype = typechecker(n.first); + if (!rtl_ila_vartype.type.is_unknown()) + return rtl_ila_vartype.type; + if (pos_def_var != all_var_def_types.end()) { + ILA_WARN_IF(pos_def_var->second.width == 0) + << "Using width of not yet" + << " determined var " << n.first; + return RfMapVarType(pos_def_var->second.width); + } + } // if # ... # else not + return RfMapVarType(); // unknown type + } else { // has op + + if (in->get_child_cnt() == 1 && + (in->get_op() == voperator::B_AND || // & a + in->get_op() == voperator::B_NAND || // ~& a + in->get_op() == voperator::B_OR || // | a + in->get_op() == voperator::B_NOR || // ~| a + in->get_op() == voperator::B_XOR || // ^ a + in->get_op() == voperator::B_EQU // "^~"|"~^" + )) { + return RfMapVarType(1); + } + + if (in->get_op() == verilog_expr::voperator::STAR || + in->get_op() == verilog_expr::voperator::PLUS || + in->get_op() == verilog_expr::voperator::MINUS || + in->get_op() == verilog_expr::voperator::DIV || + in->get_op() == verilog_expr::voperator::POW || + in->get_op() == verilog_expr::voperator::MOD || + in->get_op() == verilog_expr::voperator::B_NEG || + in->get_op() == verilog_expr::voperator::B_AND || + in->get_op() == verilog_expr::voperator::B_OR || + in->get_op() == verilog_expr::voperator::B_XOR || + in->get_op() == verilog_expr::voperator::B_NAND || + in->get_op() == verilog_expr::voperator::B_NOR) { + // the max of the args + unsigned nchild = in->get_child_cnt(); + unsigned maxw = 0; + for (size_t idx = 0; idx < nchild; idx++) { + RfMapVarType t = + TypeInferTravserRfExpr(in->get_child().at(idx), local_var_def); + if (t.is_bv()) + maxw = std::max(maxw, t.unified_width()); + } + return RfMapVarType(maxw); + } else if (in->get_op() == verilog_expr::voperator::ASL || + in->get_op() == verilog_expr::voperator::ASR || + in->get_op() == verilog_expr::voperator::LSL || + in->get_op() == verilog_expr::voperator::LSR || + in->get_op() == verilog_expr::voperator::AT) { // the left type + assert(in->get_child_cnt() == 2); + return TypeInferTravserRfExpr(in->get_child().at(0), local_var_def); + } else if (in->get_op() == verilog_expr::voperator::DELAY) { + // arg 1: width of first + // arg 2: width is 1 !!! + assert(in->get_child_cnt() == 1 || in->get_child_cnt() == 2); + if (in->get_child_cnt() == 2) + return RfMapVarType(1); + + // set return type to be the same as the first one + return TypeInferTravserRfExpr(in->get_child().at(0), local_var_def); + } else if (in->get_op() == verilog_expr::voperator::GTE || + in->get_op() == verilog_expr::voperator::LTE || + in->get_op() == verilog_expr::voperator::GT || + in->get_op() == verilog_expr::voperator::LT || + in->get_op() == verilog_expr::voperator::C_EQ || + in->get_op() == verilog_expr::voperator::L_EQ || + in->get_op() == verilog_expr::voperator::C_NEQ || + in->get_op() == verilog_expr::voperator::L_NEQ || + in->get_op() == verilog_expr::voperator::L_NEG || + in->get_op() == verilog_expr::voperator::L_AND || + in->get_op() == verilog_expr::voperator::L_OR) { + return RfMapVarType(1); + } else if (in->get_op() == verilog_expr::voperator::INDEX) { + RfMapVarType child_type = + TypeInferTravserRfExpr(in->get_child().at(0), local_var_def); + if (child_type.is_array()) + return RfMapVarType(child_type.unified_width()); // data width + // TODO: check index within ? + if (child_type.is_bv()) + return RfMapVarType(1); + return RfMapVarType(); // UNKNOWN type + } else if (in->get_op() == verilog_expr::voperator::IDX_PRT_SEL_PLUS || + in->get_op() == verilog_expr::voperator::IDX_PRT_SEL_MINUS) { + assert(in->get_child().size() == 3); + unsigned diff; + bool succ = _compute_const(in->get_child().at(2), diff /*ref*/); + // TODO: check index within ? + if (succ) + return RfMapVarType(diff); + return RfMapVarType(); + } else if (in->get_op() == verilog_expr::voperator::RANGE_INDEX) { + assert(in->get_child_cnt() == 3); + unsigned l, r; + + bool succ = _compute_const(in->get_child().at(1), l /*ref*/); + succ = succ && _compute_const(in->get_child().at(2), r /*ref*/); + if (!succ) + return RfMapVarType(); + // TODO: check width! + return RfMapVarType(std::max(l, r) - std::min(l, r) + 1); + } else if (in->get_op() == verilog_expr::voperator::STORE_OP) { + // TODO: check width! + // actually not implemented + return TypeInferTravserRfExpr(in->get_child().at(0), local_var_def); + } else if (in->get_op() == verilog_expr::voperator::TERNARY) { + auto left = TypeInferTravserRfExpr(in->get_child().at(1), local_var_def); + auto right = TypeInferTravserRfExpr(in->get_child().at(2), local_var_def); + if (left.is_unknown() && right.is_unknown()) + return RfMapVarType(); // unknown + if (left.is_unknown()) + return right; + if (right.is_unknown()) + return left; + + if (left.is_array() || right.is_array()) + return left; // TODO: check compatibility + + return RfMapVarType( + std::max(left.unified_width(), right.unified_width())); + } else if (in->get_op() == verilog_expr::voperator::FUNCTION_APP) { + return RfMapVarType(); + } else if (in->get_op() == verilog_expr::voperator::CONCAT) { + unsigned nchild = in->get_child_cnt(); + unsigned sumw = 0; + for (size_t idx = 0; idx < nchild; idx++) { + RfMapVarType t = + TypeInferTravserRfExpr(in->get_child().at(idx), local_var_def); + if (t.is_bv()) + sumw += t.unified_width(); + else + return RfMapVarType(); // cannot decide + } + return RfMapVarType(sumw); + } else if (in->get_op() == verilog_expr::voperator::REPEAT) { + assert(in->get_child_cnt() == 2); + unsigned ntimes; + if (!_compute_const(in->get_child().at(0), ntimes)) + return RfMapVarType(); + auto tp = TypeInferTravserRfExpr(in->get_child().at(1), local_var_def); + if (tp.is_unknown()) + return RfMapVarType(); // unknown + return RfMapVarType(tp.unified_width() * ntimes); + } else if (in->get_op() == verilog_expr::voperator::FORALL || + in->get_op() == verilog_expr::voperator::EXIST) { + + return RfMapVarType(1); + // std::map new_var_def; + // const auto& sparam = in->get_str_parameter(); + // const auto& param = in->get_parameter(); + // ILA_CHECK(sparam.size() == 1 && param.size() == 1); + // new_var_def.emplace(sparam.at(0), param.at(0)); + // return TypeInferTravserRfExpr(in->get_child().at(0), new_var_def); + } + ILA_ASSERT(false) << "BUG: Operator " << int(in->get_op()) + << " is not handled"; + } // end of else has op + return RfMapVarType(); +} // TypeInferTravserRfExpr + +// -------------------------------------------------------- +// RfExprAstUtility +// -------------------------------------------------------- + +RfVarTypeOrig RfExprAstUtility::GetType(const RfExpr& in) { + auto anno = in->get_annotation(); + ILA_NOT_NULL(anno); + return *anno; +} + +void RfExprAstUtility::GetVars( + const RfExpr& in, std::unordered_map& vars_out) { + // bfs walk + std::vector> stack; + std::vector> quantified_vars; + stack.push_back(std::make_pair(in, false)); + quantified_vars.push_back({}); + while (!stack.empty()) { + auto& back = stack.back(); + const auto &curr_quantified_var = quantified_vars.back(); + + auto backvar = back.first; + if (back.second) { + quantified_vars.pop_back(); + stack.pop_back(); + continue; + } + // back.second == false + back.second = true; + if (backvar->is_var()) { + ILA_ASSERT(backvar->get_child().size() == 0); + verilog_expr::VExprAstVar::VExprAstVarPtr varptr = + std::dynamic_pointer_cast(backvar); + ILA_NOT_NULL(varptr); + const auto name = varptr->get_name().first; + if(curr_quantified_var.find(name) == curr_quantified_var.end()) + vars_out.emplace(name, varptr); // only add it if not quantified + } // end of is_var + else { + auto new_quantified_var(curr_quantified_var); // this is necessary + // because reference could become invalid when you start to push + if(backvar->get_op() == verilog_expr::voperator::FORALL || + backvar->get_op() == verilog_expr::voperator::EXIST) { + new_quantified_var.insert(backvar->get_str_parameter().at(0)); + } + + for (const auto& c : backvar->get_child()) { + stack.push_back(std::make_pair(c, false)); + quantified_vars.push_back(new_quantified_var); + } // end - for each child + } // end of else + } // end while (stack is not empty) +} // end of GetVars + + +/// will only replace the free var, so we need to keep track +/// if some var inside are quantified, in that case, should not mask +/// EXPECT: newexpr has annnotation !!! +RfExpr RfExprAstUtility::ReplaceQuantifiedVar(const std::string &name, + const RfExpr & in, const RfExpr & newexpr, + const std::set & quantified_var) { + // traverse the tree + if (in->is_var()) { + auto var_ptr = std::dynamic_pointer_cast(in); + ILA_NOT_NULL(var_ptr); + auto n = var_ptr->get_name(); + // will only replace free var + if(quantified_var.find(n.first) != quantified_var.end()) + return in; + if (n.first == name) + return newexpr; + return in; + } else if (in->is_constant()) { + return in; + } + // else is op + std::set p_quantified_var(quantified_var); + if(in->get_op() == verilog_expr::voperator::FORALL || + in->get_op() == verilog_expr::voperator::EXIST) { + ILA_ASSERT(in->get_str_parameter().size() == 1); + p_quantified_var.insert(in->get_str_parameter().at(0)); + } + + std::vector retchild; + for (size_t idx = 0; idx < in->get_child_cnt(); ++idx) { + retchild.push_back( + ReplaceQuantifiedVar( + name, + in->get_child().at(idx), + newexpr, + p_quantified_var + )); + } + auto ret = in->MakeCopyWithNewChild(retchild); + ret->set_annotation(in->get_annotation()); + return ret; +} // END of ReplaceQuantifiedVar + +/// expand the current one, should be invoked from the leaf node +RfExpr RfExprAstUtility::QuantifierInstantiation(const RfExpr& in) { + ILA_CHECK(in->get_op() == verilog_expr::voperator::FORALL || + in->get_op() == verilog_expr::voperator::EXIST); + ILA_ASSERT(in->get_str_parameter().size() == 1); + ILA_ASSERT(in->get_parameter().size() == 1); + ILA_ASSERT(in->get_child_cnt() == 1); + + auto child = in->get_child().at(0); + bool use_and = in->get_op() == verilog_expr::voperator::FORALL; + auto anno = in->get_annotation(); + ILA_WARN_IF(anno && anno->type.unified_width() != 1) + << "FORALL/EXIST has non-Boolean Formula as child"; + + const std::string quantified_var_name = in->get_str_parameter().at(0); + const int quantified_var_width = in->get_parameter().at(0); + ILA_CHECK(quantified_var_width <= 32) + << "Quantifier instantiation for width > 32 is strongly discouraged"; + long long range = std::pow(2,quantified_var_width); + RfExpr ret = nullptr; + for(long long idx = 0; idx < range; ++idx) { + auto new_const = verilog_expr::VExprAst::MakeConstant(10, quantified_var_width, std::to_string(idx)); + + RfVarTypeOrig tp; + tp.type = + RfMapVarType(quantified_var_width); // base, width,... + new_const->set_annotation(std::make_shared(tp)); + RfExpr repl = ReplaceQuantifiedVar(quantified_var_name, child, new_const, {}); + if(ret == nullptr) + ret = repl; + else + ret = verilog_expr::VExprAst::MakeBinaryAst( + use_and ? verilog_expr::voperator::L_AND : verilog_expr::voperator::L_OR, + repl, ret); + ret->set_annotation(anno); + } + return ret; +} // END of QuantifierInstantiation + + +/// determine if a rf expr has quantifier in it +bool RfExprAstUtility::HasQuantifier(const RfExpr& in) { + bool ret = false; + TraverseRfExprNoModify(in, [&ret](const RfExpr &e) -> void { + if(e->get_op() == verilog_expr::voperator::EXIST || + e->get_op() == verilog_expr::voperator::FORALL) + ret = true; + } ); + return ret; +} +/// for pono, this will cause to use text +/// FORALL -> /\ /\ /\ ... (JasperGold) +/// EXISTS -> \/ \/ \/ ... +RfExpr RfExprAstUtility::FindExpandQuantifier(const RfExpr& in) { + return TraverseRfExpr(in, [](const RfExpr &e) -> RfExpr{ + if(e->get_op() == verilog_expr::voperator::EXIST || + e->get_op() == verilog_expr::voperator::FORALL) + return QuantifierInstantiation(e); + // else + return e; + }); +} + +bool RfExprAstUtility::HasArrayVar(const RfExpr& in) { + if (in->is_var()) { + auto anno = in->get_annotation(); + ILA_NOT_NULL(anno); + auto memvar = std::dynamic_pointer_cast(in); + ILA_NOT_NULL(memvar); + if (anno->type.is_array()) { + // array_var.emplace(std::get<0>(memvar->get_name()), memvar); + return true; + } + return false; + } else if (in->is_constant()) { + return false; + } + bool has_array = false; + for (size_t idx = 0; idx < in->get_child_cnt(); idx++) { + has_array = has_array || HasArrayVar(in->get_child().at(idx)); + if (has_array) + break; + } + return has_array; +} + +void RfExprAstUtility::RfMapNoNullNode(const RfExpr& in) { + ILA_NOT_NULL(in); + size_t cnt = in->get_child_cnt(); + for (size_t idx = 0; idx < cnt; ++idx) + RfMapNoNullNode(in->get_child().at(idx)); +} + +void RfExprAstUtility::TraverseRfExprNoModify(const RfExpr& in, + std::function func) { + ILA_NOT_NULL(in); + std::vector> parent_stack; + while (!parent_stack.empty()) { + auto& lastlv = parent_stack.back(); + auto cnt = lastlv.first->get_child_cnt(); + auto& idx = lastlv.second; + if (idx >= cnt) { // also cnt could be 0 (leaf) + func(lastlv.first); + parent_stack.pop_back(); + if (!parent_stack.empty()) + ++parent_stack.back().second; + continue; + } + ILA_ASSERT(lastlv.first->get_child_cnt() != 0); + parent_stack.push_back( + std::make_pair(lastlv.first->get_child().at(idx), 0U)); + } +} + +RfExpr RfExprAstUtility::TraverseRfExpr( + const RfExpr& in, std::function func) { + ILA_NOT_NULL(in); + std::vector> child_stack; + child_stack.push_back({}); + child_stack.push_back({}); // Yes, do it twice! + std::vector> parent_stack; + parent_stack.push_back(std::make_pair(in, 0U)); + while (!parent_stack.empty()) { + auto& lastlv = parent_stack.back(); + auto cnt = lastlv.first->get_child_cnt(); + auto& idx = lastlv.second; + if (idx >= cnt) { + auto new_c = lastlv.first->MakeCopyWithNewChild(child_stack.back()); + auto new_node = func(new_c); + new_node->set_annotation(lastlv.first->get_annotation()); + child_stack.pop_back(); + child_stack.back().push_back(new_node); + parent_stack.pop_back(); + if (!parent_stack.empty()) + ++parent_stack.back().second; + continue; + } // else + ILA_CHECK(lastlv.first->get_child_cnt() != 0); + parent_stack.push_back( + std::make_pair(lastlv.first->get_child().at(idx), 0U)); + child_stack.push_back({}); + } // end of while + ILA_CHECK(child_stack.size() == 1); + ILA_CHECK(child_stack.at(0).size() == 1); + return child_stack.at(0).at(0); +} // TraverseRfExpr + +bool RfExprAstUtility::IsLastLevelBooleanOp(const RfExpr& in) { + std::set boolean_op = { + verilog_expr::voperator::GTE, verilog_expr::voperator::LTE, + verilog_expr::voperator::GT, verilog_expr::voperator::LT, + verilog_expr::voperator::C_EQ, verilog_expr::voperator::L_EQ, + verilog_expr::voperator::C_NEQ, verilog_expr::voperator::L_NEQ, + verilog_expr::voperator::L_NEG, verilog_expr::voperator::L_AND, + verilog_expr::voperator::L_OR, verilog_expr::voperator::FORALL, + verilog_expr::voperator::EXIST}; + + if (in->is_constant() || in->is_var()) + return false; + auto op = in->get_op(); + return (boolean_op.find(op) != boolean_op.end()); +} + +// -------------------------------------------------------- +// TypeAnalysisUtility +// -------------------------------------------------------- + +// type inference rules +// differences from TypedVerilogRefinementMap::ReplacingRtlIlaVar +// 1. no var replacement (__ILA_I_, __ILA_SO_, __DOT__), array[idx] +// 2. no special name handling +void TypeAnalysisUtility::AnnotateType(const RfExpr& inout, + const std::map & quantified_var_type) +{ + auto tp_annotate = inout->get_annotation(); + + if (inout->is_var()) { + auto ptr = std::dynamic_pointer_cast(inout); + const auto & n = ptr->get_name().first; + if(tp_annotate == nullptr || tp_annotate->type.is_unknown()) { + // if it is a quantified var, then we can annotate its type + auto type_pos = quantified_var_type.find(n); + if(type_pos != quantified_var_type.end()) { + auto width = type_pos->second; + RfVarTypeOrig tp; + tp.type = RfMapVarType(width); // base, width,... + tp_annotate = std::make_shared(tp); + inout->set_annotation(tp_annotate); + } + } + ILA_CHECK(tp_annotate != nullptr && !tp_annotate->type.is_unknown()) + << n << " has no type annotation"; + } else if (inout->is_constant()) { + if (tp_annotate == nullptr || tp_annotate->type.is_unknown()) { + RfVarTypeOrig tp; + auto cptr = + std::dynamic_pointer_cast(inout); + ILA_NOT_NULL(cptr); + tp.type = + RfMapVarType(std::get<1>(cptr->get_constant())); // base, width,... + inout->set_annotation(std::make_shared(tp)); + } // end if no annotation + } else { // op + bool has_quantifier = + inout->get_op() == verilog_expr::voperator::EXIST || + inout->get_op() == verilog_expr::voperator::FORALL; + if(has_quantifier) { + ILA_ASSERT(inout->get_child_cnt() == 1 && + inout->get_str_parameter().size() == 1 && + inout->get_parameter().size() == 1 + ); + std::map new_quantified_dict (quantified_var_type); + new_quantified_dict.emplace(inout->get_str_parameter().at(0), + inout->get_parameter().at(0)); + AnnotateType(inout->get_child().at(0), new_quantified_dict); + } else + for (size_t idx = 0; idx < inout->get_child_cnt(); ++idx) + AnnotateType(inout->get_child().at(idx), quantified_var_type); + infer_type_based_on_op_child(inout); + // for each child + } // end if-else- op +} // TypeAnalysisUtility::AnnotateType + +void TypeAnalysisUtility::infer_type_based_on_op_child(const RfExpr& inout) { + assert(inout->get_op() != verilog_expr::voperator::MK_CONST && + inout->get_op() != verilog_expr::voperator::MK_VAR); + + if (inout->get_child_cnt() == 1 && + (inout->get_op() == voperator::B_AND || + inout->get_op() == voperator::B_NAND || + inout->get_op() == voperator::B_OR || + inout->get_op() == voperator::B_NOR || + inout->get_op() == voperator::B_XOR || + inout->get_op() == voperator::B_EQU // "^~"|"~^" + )) { + auto new_annotation = std::make_shared(); + new_annotation->type = RfMapVarType(1); + inout->set_annotation(new_annotation); + return; + } + + if (inout->get_op() == verilog_expr::voperator::STAR || + inout->get_op() == verilog_expr::voperator::PLUS || + inout->get_op() == verilog_expr::voperator::MINUS || + inout->get_op() == verilog_expr::voperator::DIV || + inout->get_op() == verilog_expr::voperator::POW || + inout->get_op() == verilog_expr::voperator::MOD || + inout->get_op() == verilog_expr::voperator::B_NEG || + inout->get_op() == verilog_expr::voperator::B_AND || + inout->get_op() == verilog_expr::voperator::B_OR || + inout->get_op() == verilog_expr::voperator::B_XOR || + inout->get_op() == verilog_expr::voperator::B_NAND || + inout->get_op() == verilog_expr::voperator::B_NOR) { + // the max of the args + unsigned nchild = inout->get_child_cnt(); + unsigned maxw = 0; + for (size_t idx = 0; idx < nchild; idx++) { + RfMapVarType t = + inout->get_child().at(idx)->get_annotation()->type; + if (t.is_bv()) + maxw = std::max(maxw, t.unified_width()); + } + auto new_annotation = std::make_shared(); + new_annotation->type = RfMapVarType(maxw); + inout->set_annotation(new_annotation); + return; + } + + if (inout->get_op() == verilog_expr::voperator::ASL || + inout->get_op() == verilog_expr::voperator::ASR || + inout->get_op() == verilog_expr::voperator::LSL || + inout->get_op() == verilog_expr::voperator::LSR || + inout->get_op() == verilog_expr::voperator::AT) { // the left type + assert(inout->get_child_cnt() == 2); + inout->set_annotation( + inout->get_child().at(0)->get_annotation()); + return; + } else if (inout->get_op() == verilog_expr::voperator::DELAY) { + // arg 1: width of first + // arg 2: width is 1 !!! + assert(inout->get_child_cnt() == 1 || inout->get_child_cnt() == 2); + if (inout->get_child_cnt() == 2) { + auto new_annotation = std::make_shared(); + new_annotation->type = RfMapVarType(1); + inout->set_annotation(new_annotation); + return; + } + + // set return type to be the same as the first one + inout->set_annotation( + inout->get_child().at(0)->get_annotation()); + return; + + } else if (inout->get_op() == verilog_expr::voperator::GTE || + inout->get_op() == verilog_expr::voperator::LTE || + inout->get_op() == verilog_expr::voperator::GT || + inout->get_op() == verilog_expr::voperator::LT || + inout->get_op() == verilog_expr::voperator::C_EQ || + inout->get_op() == verilog_expr::voperator::L_EQ || + inout->get_op() == verilog_expr::voperator::C_NEQ || + inout->get_op() == verilog_expr::voperator::L_NEQ || + inout->get_op() == verilog_expr::voperator::L_NEG || + inout->get_op() == verilog_expr::voperator::L_AND || + inout->get_op() == verilog_expr::voperator::L_OR) { + auto new_annotation = std::make_shared(); + new_annotation->type = RfMapVarType(1); + inout->set_annotation(new_annotation); + return; + } else if (inout->get_op() == verilog_expr::voperator::INDEX) { + RfMapVarType child_type = + inout->get_child().at(0)->get_annotation()->type; + + auto new_annotation = std::make_shared(); + if (child_type.is_array()) + new_annotation->type = RfMapVarType(child_type.unified_width()); + // TODO: check index within ? + else + new_annotation->type = RfMapVarType(1); + inout->set_annotation(new_annotation); + return; + } else if (inout->get_op() == verilog_expr::voperator::IDX_PRT_SEL_PLUS || + inout->get_op() == verilog_expr::voperator::IDX_PRT_SEL_MINUS) { + assert(inout->get_child().size() == 3); + unsigned diff = 0; + bool succ = _compute_const(inout->get_child().at(2), diff /*ref*/); + ILA_ASSERT(succ); + + auto new_annotation = std::make_shared(); + new_annotation->type = RfMapVarType(diff); + inout->set_annotation(new_annotation); + + // TODO: check index within ? + return; + + } else if (inout->get_op() == verilog_expr::voperator::RANGE_INDEX) { + assert(inout->get_child_cnt() == 3); + unsigned l, r; + + bool succ = _compute_const(inout->get_child().at(1), l /*ref*/); + succ = succ && _compute_const(inout->get_child().at(2), r /*ref*/); + ILA_ASSERT(succ); + + auto new_annotation = std::make_shared(); + new_annotation->type = RfMapVarType(std::max(l, r) - std::min(l, r) + 1); + inout->set_annotation(new_annotation); + + return; + } else if (inout->get_op() == verilog_expr::voperator::STORE_OP) { + inout->set_annotation( + inout->get_child().at(0)->get_annotation()); + return; + + } else if (inout->get_op() == verilog_expr::voperator::TERNARY) { + inout->set_annotation( + inout->get_child().at(1)->get_annotation()); + return; + } else if (inout->get_op() == verilog_expr::voperator::FUNCTION_APP) { + ILA_ASSERT(false); + auto new_annotation = std::make_shared(); + new_annotation->type = RfMapVarType(0); + inout->set_annotation(new_annotation); + return; + } else if (inout->get_op() == verilog_expr::voperator::CONCAT) { + unsigned nchild = inout->get_child_cnt(); + unsigned sumw = 0; + for (size_t idx = 0; idx < nchild; idx++) { + RfMapVarType t = + (inout->get_child().at(idx)->get_annotation()->type); + sumw += t.unified_width(); + } + auto new_annotation = std::make_shared(); + new_annotation->type = RfMapVarType(sumw); + inout->set_annotation(new_annotation); + return; + } else if (inout->get_op() == verilog_expr::voperator::REPEAT) { + assert(inout->get_child_cnt() == 2); + unsigned ntimes = 0; + if (!_compute_const(inout->get_child().at(0), ntimes)) + ILA_ASSERT(false); + auto tp = + (inout->get_child().at(1)->get_annotation()->type); + + auto new_annotation = std::make_shared(); + new_annotation->type = RfMapVarType(tp.unified_width() * ntimes); + inout->set_annotation(new_annotation); + + return; + } else if (inout->get_op() == verilog_expr::voperator::FORALL || + inout->get_op() == verilog_expr::voperator::EXIST) { + assert(inout->get_child_cnt() == 1); + auto child_anno = inout->get_child().at(0)->get_annotation(); + ILA_ERROR_IF(child_anno == nullptr || + !child_anno->type.is_bv() || + child_anno->type.unified_width() != 1) << "type-check: FORALL/EXIST requires Boolean sub-formula"; + + auto new_annotation = std::make_shared(); + new_annotation->type = RfMapVarType(1); + inout->set_annotation(new_annotation); + + return; + } + ILA_ASSERT(false) << "BUG: Operator " << int(inout->get_op()) + << " is not handled"; + + auto new_annotation = std::make_shared(); + new_annotation->type = RfMapVarType(0); + inout->set_annotation(new_annotation); +} // infer_type_op + +VarReplacement::VarReplacement(const RfExpr& o, const RfExpr& n) + : origvar(o), newvar(n) { + auto annotation_ptr = newvar->get_annotation(); + ILA_NOT_NULL(annotation_ptr); + ILA_CHECK(!annotation_ptr->type.is_unknown()) + << "new var is not typed: " << newvar->to_verilog(); +} + +} // namespace rfmap +} // namespace ilang diff --git a/src/rfmap-in/verilog_rfmap.cc b/src/rfmap-in/verilog_rfmap.cc new file mode 100644 index 000000000..561d5d8c7 --- /dev/null +++ b/src/rfmap-in/verilog_rfmap.cc @@ -0,0 +1,1394 @@ +/// \file verilog_rfmap.cc Verilog Refinement Map Handling +/// First pass : JSON -> rfmap object + +#include +#include +#include +#include + +#include + +#include "vexpparser/interpreter.h" +#include "nlohmann/json.hpp" + +namespace ilang { +namespace rfmap { + +// return npos if no comments in +static size_t find_comments(const std::string& line) { + enum state_t { PLAIN, STR, LEFT } state, next_state; + state = PLAIN; + size_t ret = 0; + for (const auto& c : line) { + if (state == PLAIN) { + if (c == '/') + next_state = LEFT; + else if (c == '"') + next_state = STR; + else + next_state = PLAIN; + } else if (state == STR) { + if (c == '"' || c == '\n') + next_state = PLAIN; + // the '\n' case is in case we encounter some issue to find + // the ending of a string + else + next_state = STR; + } else if (state == LEFT) { + if (c == '/') { + ILA_CHECK(ret > 0); + return ret - 1; + } else + next_state = PLAIN; + } + state = next_state; + ++ret; + } + return std::string::npos; +} + +// load_json and remove the comment, if succeed return true +static bool load_json(const std::string& fname, nlohmann::json& j) { + std::ifstream fin(fname); + + if (!fin.is_open()) { + ILA_ERROR << "Cannot read from file:" << fname; + return false; + } + + // remove the comments + std::string contents; + std::string line; + while (std::getline(fin, line)) { + auto comment_begin = find_comments(line); + if (comment_begin != std::string::npos) + contents += line.substr(0, comment_begin); + else + contents += line; + contents += "\n"; + } + j = nlohmann::json::parse(contents); + return true; +} // load_json + +static bool ParseRfExprErrFlag = false; + +RfExpr VerilogRefinementMap::ParseRfExprFromString(const std::string& in) { + Vexp::Interpreter intp; + std::stringstream ss; + ss << in; + intp.switchInputStream(&ss); + try { + intp.parse(); + } catch (verilog_expr::VexpException& e) { + return nullptr; + } + + if (intp.HasError()) + return nullptr; + return intp.GetAstRoot(); +} + +RfExpr ParseRfMapExpr(const std::string& in) { + // TODO + auto ret = VerilogRefinementMap::ParseRfExprFromString(in); + ILA_ERROR_IF(ret == nullptr) << "Parsing string: `" << in << "` failed."; + if (ret == nullptr) + ParseRfExprErrFlag = true; + return ret; +} + +RfExpr ParseRfMapExprJson(nlohmann::json& in) { + if(in.is_null()) + return ParseRfMapExpr("1'b1 == 1'b1"); // true + return ParseRfMapExpr(in.get()); +} + +bool JsonRfmapParseCond(SingleVarMap& cond_map, nlohmann::json& json_array) { + assert(json_array.is_array()); + bool succ = true; + for (const auto& idx_array_pair : json_array.items()) { + succ = succ && idx_array_pair.value().is_array() && + idx_array_pair.value().size() == 2; + if (!idx_array_pair.value().is_array() || + idx_array_pair.value().size() != 2) + continue; + + RfExpr cond, mapping; + for (const auto& index_map_pair : idx_array_pair.value().items()) { + if (index_map_pair.key() == "0") { + cond = ParseRfMapExprJson(index_map_pair.value()); + } else if (index_map_pair.key() == "1") { + mapping = ParseRfMapExprJson(index_map_pair.value()); + } + } + assert(cond.get() != nullptr && mapping.get() != nullptr); + cond_map.cond_map.push_back(std::make_pair(cond, mapping)); + } // for each array_element + return succ; +} // JsonRfmapParseCond + +bool JsonRfmapParseSingleOrCond(SingleVarMap& sc_map, + nlohmann::json& json_single_or_array) { + if (json_single_or_array.is_array()) + return JsonRfmapParseCond(sc_map, json_single_or_array); + assert(json_single_or_array.is_string()); + sc_map.single_map = ParseRfMapExprJson(json_single_or_array); + return sc_map.single_map != nullptr; +} + +bool JsonRfmapParseMem(ExternalMemPortMap& mem_rfmap, + nlohmann::json& json_obj) { + assert(json_obj.is_object()); + + bool succ = true; + + if (json_obj.contains("wen")) + succ = + succ && JsonRfmapParseSingleOrCond(mem_rfmap.wen_map, json_obj["wen"]); + if (json_obj.contains("waddr")) + succ = succ && + JsonRfmapParseSingleOrCond(mem_rfmap.waddr_map, json_obj["waddr"]); + if (json_obj.contains("wdata")) + succ = succ && + JsonRfmapParseSingleOrCond(mem_rfmap.wdata_map, json_obj["wdata"]); + if (json_obj.contains("ren")) + succ = + succ && JsonRfmapParseSingleOrCond(mem_rfmap.ren_map, json_obj["ren"]); + if (json_obj.contains("raddr")) + succ = succ && + JsonRfmapParseSingleOrCond(mem_rfmap.raddr_map, json_obj["raddr"]); + if (json_obj.contains("rdata")) + succ = succ && + JsonRfmapParseSingleOrCond(mem_rfmap.rdata_map, json_obj["rdata"]); + + mem_rfmap.rport_mapped = json_obj.contains("ren"); + mem_rfmap.wport_mapped = json_obj.contains("wen"); + if (mem_rfmap.rport_mapped) + succ = succ && json_obj.contains("raddr") && json_obj.contains("rdata"); + if (mem_rfmap.wport_mapped) + succ = succ && json_obj.contains("waddr") && json_obj.contains("wdata"); + + return (succ && (json_obj.contains("ren") || json_obj.contains("wen"))); +} // JsonRfmapParseMem + +char inline to_space(char in) { return ((in == '-' || in == '_') ? ' ' : in); } + +bool SectionNameRelaxedMatch(const std::string& in1, const std::string& in2) { + if (in1.length() != in2.length()) + return false; + for (size_t idx = 0; idx < in1.length(); ++idx) { + if (tolower(in1.at(idx)) != tolower(in2.at(idx)) && + (to_space(in1.at(idx)) != to_space(in2.at(idx)))) + return false; + } + return true; +} // SectionNameRelaxedMatch + +nlohmann::json* GetJsonSection(nlohmann::json& in, + const std::set& sec_names, + bool allow_dup = false) { + nlohmann::json* ret = NULL; + if (!in.is_object()) + return NULL; + for (const auto& n : sec_names) { + for (const auto& n_v : in.items()) { + if (SectionNameRelaxedMatch(n_v.key(), n)) { + + ILA_ERROR_IF(ret) << "Section " << n << " is duplicated."; + if (ret && !allow_dup) + return NULL; + + ret = &(in.at(n_v.key())); + } + } + } + return ret; +} // GetJsonSection + +bool JsonRfmapParseSingleSequence(OneBitSignalSequence& out, + nlohmann::json& seq) { + + auto get_multipler = [](const std::string& in) -> unsigned { + if (in.length() < 2) + return 0; + if (in.at(0) != '*') + return 0; + auto sub = in.substr(1); + return StrToInt(sub, 10); + }; + + if (!seq.is_array()) + return false; + OneBitSignalSequence tmp_seq; + bool the_last_encountered = false; + for (auto& elem : seq.items()) { + if (the_last_encountered) + return false; + auto& e = elem.value(); + if (!(e.is_number_unsigned() || e.is_array() || e.is_string())) + return false; + if (e.is_number_unsigned()) + tmp_seq.push_back(e.get()); + else if (e.is_array()) { + if (!JsonRfmapParseSingleSequence(tmp_seq, e)) + return false; + } else if (e.is_string()) { + // duplicate the tmp_sequence + auto mult = e.get(); + unsigned n_count = get_multipler(mult); + unsigned length = tmp_seq.size(); + if (length == 0 || n_count == 0) + return false; + for (unsigned iter = 0; iter < n_count; ++iter) { + for (unsigned idx = 0; idx < length; ++idx) { + tmp_seq.push_back(tmp_seq.at(idx)); + } + } + the_last_encountered = true; + } // if mult + } // end of for + out.insert(out.end(), tmp_seq.begin(), tmp_seq.end()); + return true; +} // JsonRfmapParseSingleSequence + +bool JsonRfmapParseSequence(std::map& out, + nlohmann::json& in) { + if (!in.is_object()) + return false; + + for (const auto& n_seq_pair : in.items()) { + const auto& name = n_seq_pair.key(); + auto& seq = n_seq_pair.value(); + if (!seq.is_array()) + return false; + if (IN(name, out)) + return false; + auto insert_ret = out.insert(std::make_pair(name, OneBitSignalSequence())); + // [pos (name, seq) , bool] + auto& seq_ref = insert_ret.first->second; + bool succ = JsonRfmapParseSingleSequence(seq_ref, seq); + if (!succ) + return false; + } + return true; +} // JsonRfmapParseSequence + +bool JsonRfmapParseClockFactor( + std::map& out, + nlohmann::json& in) { + if (!in.is_object()) + return false; + for (const auto& n_obj_pair : in.items()) { + const auto& n = n_obj_pair.key(); + auto& obj = n_obj_pair.value(); + if (IN(n, out)) + return false; + if (!obj.is_object()) + return false; + ClockSpecification::factor f; + auto* high = GetJsonSection(obj, {"high"}); + auto* low = GetJsonSection(obj, {"low"}); + auto* offset = GetJsonSection(obj, {"offset"}); + if (!(high && low)) + return false; + + if (high) { + if (!high->is_number_unsigned()) + return false; + f.high = high->get(); + } + + if (low) { + if (!low->is_number_unsigned()) + return false; + f.low = low->get(); + } + + if (offset) { + if (!offset->is_number_unsigned()) + return false; + f.offset = offset->get(); + } + out[n] = f; + } // end for + return true; +} // JsonRfmapParseClockFactor + +unsigned gcd(unsigned a, unsigned b) { + if (b == 0) + return a; + return gcd(b, a % b); +} + +// least common multiplier +unsigned lcm(const std::vector& in) { + unsigned ans = in.at(0); + for (size_t i = 1; i < in.size(); ++i) { + ans = ((in.at(i) * ans) / gcd(in.at(i), ans)); + } + return ans; +} + +bool JsonRfmapConvertFactorToSeq( + const std::map& in, + std::map& out) { + if (in.size() == 0) + return false; + std::map seq_no_dup; + std::vector cycles; + for (const auto& n_factor_pair : in) { + const auto& n = n_factor_pair.first; + const auto& factor_obj = n_factor_pair.second; + auto n_cycle = factor_obj.high + factor_obj.low; + cycles.push_back(n_cycle); + seq_no_dup[n].resize(factor_obj.high, true); + seq_no_dup[n].insert(seq_no_dup.at(n).end(), factor_obj.low, false); + } // for each factor + + auto len = lcm(cycles); + for (const auto& n_factor_pair : in) { + const auto& n = n_factor_pair.first; + const auto& factor_obj = n_factor_pair.second; + auto n_cycle = factor_obj.high + factor_obj.low; + assert(len % n_cycle == 0); + auto n_copy = len / n_cycle; + auto offset = factor_obj.offset; + + unsigned idx = offset; + unsigned idx_copy = 0; + while (!(idx == offset && idx_copy == n_copy)) { + + out[n].push_back(seq_no_dup[n][idx]); + + if (idx + 1 == n_cycle) + ++idx_copy; + idx = (idx + 1) % n_cycle; + } + assert(out[n].size() == len); + } + return true; +} // JsonRfmapConvertFactorToSeq + +#define ERRIF(cond, s) \ + do { \ + if (cond) \ + return (s); \ + } while (0) +#define ENSURE(cond, s) ERRIF(!(cond), (s)) +std::string JsonRfMapParseVarDefs( + std::map& var_defs, + nlohmann::json& def_field) { + + ENSURE(def_field.is_array(), + "`defs` field should be list of [[name, width, type], ...]"); + for (auto& one_def : def_field) { + ENSURE(one_def.is_array(), + "`defs` field should be list of [[name, width, type], ...]"); + auto pos = one_def.begin(); + + ENSURE(pos != one_def.end() && pos->is_string(), + "`defs` field should be list of [[name, width, type], ...]"); + auto var_name = pos->get(); + ENSURE(!IN(var_name, var_defs), "var " + var_name + " has been defined"); + + ++pos; + ENSURE(pos != one_def.end() && pos->is_number_unsigned(), + "`defs` field should be list of [[name, width, type], ...]"); + var_defs[var_name].width = pos->get(); + ERRIF(var_defs[var_name].width == 0, + "Definition of " + var_name + " has 0 width"); + + ++pos; + ENSURE(pos != one_def.end() && pos->is_string(), + "`defs` field should be list of [[name, width, type], ...]"); + auto tp = pos->get(); + ENSURE(SectionNameRelaxedMatch(tp, "reg") || + SectionNameRelaxedMatch(tp, "wire"), + "`defs` field should be list of [name, width, type (wire/reg)]"); + + var_defs[var_name].type = + SectionNameRelaxedMatch(tp, "reg") + ? GeneralVerilogMonitor::VarDef::var_type::REG + : GeneralVerilogMonitor::VarDef::var_type::WIRE; + ++pos; + ENSURE(pos == one_def.end(), "`defs` expects 3-element tuple"); + } + return ""; +} + +std::string JsonRfmapParsePhaseTracker(PhaseTracker& tracker, + nlohmann::json& monitor, + const std::string& tracker_name) { + auto* event_alias = GetJsonSection(monitor, {"event-alias", "signal-alias"}); + auto* rules = GetJsonSection(monitor, {"rules","rule", "phase", "phases", "stage", "stages"}); + auto* aux_var = GetJsonSection(monitor, {"aux-var", "def", "defs", "var-def", "var-defs"}); + ERRIF(rules == NULL, "`phase tracker` needs `rules` field"); + if (event_alias) { + ERRIF(!event_alias->is_object(), "`event-alias` expects map:name->expr"); + for (auto& name_val_pair : event_alias->items()) { + const auto& vn = name_val_pair.key(); + ERRIF(IN(vn, tracker.event_alias), "`" + vn + "` is already defined."); + ERRIF(!name_val_pair.value().is_string(), + "expecting string in event-alias"); + tracker.event_alias.emplace(vn, + ParseRfMapExprJson(name_val_pair.value())); + } + } + + if (aux_var) { + auto errmsg = JsonRfMapParseVarDefs(tracker.var_defs, *aux_var); + ENSURE(errmsg.empty(), errmsg); + } + + assert(rules); + ENSURE(rules->is_array(), "`rules` field should be list of objects"); + size_t sidx = 0; + for (auto& stage : *rules) { + ENSURE(stage.is_object(), "`rules` field should be list of objects"); + auto* enter = GetJsonSection(stage, {"enter"}); + auto* exit = GetJsonSection(stage, {"exit"}); + auto* stage_name = GetJsonSection(stage, {"name"}); + ENSURE(enter || exit, + "`rules` object must contain `enter` or `exit` events"); + if(enter) { + ENSURE(enter->is_object() || enter->is_string(), + "`enter` should contain `event` and (optional) `action`"); + } + if(exit) { + ENSURE(exit->is_object() || exit->is_string(), + "`exit` should contain `event` and (optional) `action`"); + } + + nlohmann::json* enter_event = NULL; + nlohmann::json* enter_action = NULL; + nlohmann::json* exit_event = NULL; + nlohmann::json* exit_action = NULL; + + if (enter) { + if(enter->is_object()) { + enter_event = GetJsonSection(*enter, {"event"}); + enter_action = GetJsonSection(*enter, {"action"}); + } else { // is string + enter_event = enter; + } + } + if (exit) { + if(exit->is_object()) { + exit_event = GetJsonSection(*exit, {"event"}); + exit_action = GetJsonSection(*exit, {"action"}); + } else + exit_event = exit; + } + + ERRIF( enter_event == NULL , "the current stage has no `entering` event, please check!" ); + ERRIF( (enter_event == NULL && enter_action != NULL), "if you specify `enter->action`, you must provide `enter->event`." ); + ERRIF( (exit_event == NULL && exit_action != NULL), "if you specify `exit->action`, you must provide `exit->event`." ); + + ENSURE(enter_event, + "`enter` should contain `event` and (optional) `action`"); + ENSURE(enter_event->is_string(), "`enter` -> `event` should be a string"); + if(exit) { + ENSURE(exit_event, "`exit` should contain `event` and (optional) `action`"); + ENSURE(exit_event->is_string(), "`exit` -> `event` should be a string"); + } + + tracker.rules.push_back(PhaseTracker::Rule()); + auto& ws = tracker.rules.back(); + if (stage_name) { + ENSURE(stage_name->is_string(), "`name` of a phase should be string"); + ws.stage_name = tracker_name + "_" + stage_name->get(); + } else { + ws.stage_name = tracker_name + "_stage" + std::to_string(sidx++); + } + + ws.enter_rule = ParseRfMapExprJson(*enter_event); + if(exit_event) { + ws.exit_rule = ParseRfMapExprJson(*exit_event); + } + + if (enter_action) { + ENSURE(enter_action->is_string(), "`action` should be a string"); + auto action_str = enter_action->get(); + auto actions = Split(action_str, ";"); + for (auto& a : actions) { + StrTrim(a); + if (a.empty()) + continue; + auto pos = a.find("<="); + ERRIF(pos == std::string::npos, + "`action` should be `LHS <= RHS ; ...`"); + auto LHS = a.substr(0, pos); + auto RHS = a.substr(pos + 2); + PhaseTracker::Assignment assign; + StrTrim(LHS); // you don't need to trim RHS (parsing will help) + assign.LHS = LHS; + assign.RHS = ParseRfMapExpr(RHS); + ws.enter_action.push_back(assign); + } // for each action + } // if (enter_action) + + if (exit_action) { + ENSURE(exit_action->is_string(), "`action` should be a string"); + auto action_str = exit_action->get(); + auto actions = Split(action_str, ";"); + for (auto& a : actions) { + StrTrim(a); + if (a.empty()) + continue; + auto pos = a.find("<="); + ERRIF(pos == std::string::npos, + "`action` should be `LHS <= RHS ; ...`"); + auto LHS = a.substr(0, pos); + auto RHS = a.substr(pos + 2); + PhaseTracker::Assignment assign; + StrTrim(LHS); + assign.LHS = LHS; + assign.RHS = ParseRfMapExpr(RHS); + ws.exit_action.push_back(assign); + } // for each action + } // exit_action + } // for each stage + + return ""; +} + +std::string JsonRfmapParseValueRecorder(ValueRecorder& tracker, + nlohmann::json& monitor) { + auto* cond = GetJsonSection(monitor, {"condition", "cond"}); + auto* val = GetJsonSection(monitor, {"value", "val"}); + auto* width = GetJsonSection(monitor, {"width", "w"}); + ENSURE(cond && cond->is_string(), "`cond` field should be a string"); + ENSURE(val && val->is_string(), "`val` field should be a string"); + tracker.condition = ParseRfMapExprJson(*cond); + tracker.value = ParseRfMapExprJson(*val); + if (width && width->is_number_unsigned()) { + tracker.width = width->get(); + } // if you don't write width or use a string then it is 0 + else + tracker.width = 0; + return ""; +} + +#undef ENSURE +#undef ERRIF + +// ------------------------------------------------------------------------------ + +#define ERRIF(cond, str) \ + do { \ + ILA_ERROR_IF(cond) << str; \ + if (cond) \ + return; \ + } while (false) +#define ENSURE(cond, str) ERRIF(!(cond), str) + +VerilogRefinementMap::VerilogRefinementMap( + const std::string& varmap_json_file, + const std::string& instcond_json_file) { + + ParseRfExprErrFlag = false; + + // this is the first pass + nlohmann::json rf_vmap; + nlohmann::json rf_cond; + load_json(varmap_json_file, rf_vmap); + load_json(instcond_json_file, rf_cond); + { // deprecated warning messages + nlohmann::json* model_name = GetJsonSection( + rf_vmap, {"model", "models", "model name", "model names"}); + ERRIF(model_name != NULL, + "model names are not supported. Use `ILA` and `RTL`."); + nlohmann::json* instmap = + GetJsonSection(rf_vmap, {"instruction mapping", "instruction map"}); + ERRIF(instmap != NULL, "instruction mapping is no longer supported"); + nlohmann::json* interface = + GetJsonSection(rf_vmap, {"interface mapping", "interface map"}); + ERRIF(interface != NULL, "interface mapping is no longer supported. Use " + "`input mapping` and `RTL interface connection`"); + } + + // now json to -> Rfmap + { // state mapping + nlohmann::json* state_mapping = + GetJsonSection(rf_vmap, {"state mapping", "state map"}); + ERRIF(state_mapping == NULL, "state var mapping is duplicated or missing"); + for (auto& i : state_mapping->items()) { + IlaVarMapping svmp; + auto sname = i.key(); // ila state name + if (i.value().is_null()) { + svmp.type = IlaVarMapping::StateVarMapType::SINGLE; + svmp.single_map.single_map = ParseRfMapExprJson(i.value()); // 1'b1 == 1'b1 + } + else if (i.value().is_string()) { + svmp.type = IlaVarMapping::StateVarMapType::SINGLE; + svmp.single_map.single_map = ParseRfMapExprJson(i.value()); + } else if (i.value().is_object()) { + // External Mem + svmp.type = IlaVarMapping::StateVarMapType::EXTERNMEM; + svmp.externmem_map.push_back(ExternalMemPortMap()); + + auto& extmem_ports = i.value(); + bool succ = JsonRfmapParseMem(svmp.externmem_map.back(), extmem_ports); + ENSURE(succ, "fail to parse external memory map"); + + } else if (i.value().is_array()) { + ERRIF(i.value().empty(), ("Empty list for " + sname)); + bool are_memports = false; + if (i.value().begin()->is_object()) { + are_memports = true; + } else if (i.value().begin()->is_array()) { + are_memports = false; + } else + ERRIF(true, "Expecting array of list or objects for " + sname); + + if (are_memports) { + svmp.type = IlaVarMapping::StateVarMapType::EXTERNMEM; + for (const auto& idx_obj_pair : i.value().items()) { + ENSURE(idx_obj_pair.value().is_object(), + "Expecting array of objects for " + sname); + + svmp.externmem_map.push_back(ExternalMemPortMap()); + + auto& extmem_ports = idx_obj_pair.value(); + bool succ = + JsonRfmapParseMem(svmp.externmem_map.back(), extmem_ports); + ENSURE(succ, "fail to parse external memory map"); + } + } else { + svmp.type = IlaVarMapping::StateVarMapType::CONDITIONAL; + JsonRfmapParseCond(svmp.single_map, i.value()); + } + + } // if array of array / array of object + ILA_ERROR_IF(IN(sname, ila_state_var_map)) + << "ILA state var : " << sname << " has duplicated mapping"; + ila_state_var_map.emplace(sname, svmp); + } // for each state + } // state mapping + + { // input mapping + // TODO: add things here + nlohmann::json* input_mapping = + GetJsonSection(rf_vmap, {"input mapping", "input map"}); + if (input_mapping) { + for (auto& i : input_mapping->items()) { + IlaVarMapping ivmp; + auto sname = i.key(); // ila state name + ERRIF(i.value().is_object(), "input array is not supported"); + if (i.value().is_string()) { + ivmp.type = IlaVarMapping::StateVarMapType::SINGLE; + ivmp.single_map.single_map = ParseRfMapExprJson(i.value()); + } else if (i.value().is_array()) { + ERRIF(i.value().empty(), ("Empty list for " + sname)); + ENSURE(i.value().begin()->is_array(), "Expect array of array"); + ivmp.type = IlaVarMapping::StateVarMapType::CONDITIONAL; + JsonRfmapParseCond(ivmp.single_map, i.value()); + + } // if array of array / array of object + ILA_ERROR_IF(IN(sname, ila_input_var_map)) + << "ILA state var : " << sname << " has duplicated mapping"; + ila_input_var_map.emplace(sname, ivmp); + } // for each input var + } + } // input mapping + + { // interface map + nlohmann::json* rtl_if_map = GetJsonSection( + rf_vmap, {"RTL interface connection", "RTL interface connect"}); + ERRIF(rtl_if_map == nullptr, + "`RTL interface connection` is duplicated or missing"); + nlohmann::json* clock_domains = + GetJsonSection(*rtl_if_map, {"CLOCK"}, true); + nlohmann::json* reset_list = GetJsonSection(*rtl_if_map, {"RESET"}, true); + nlohmann::json* nreset_list = GetJsonSection(*rtl_if_map, {"NRESET"}, true); + nlohmann::json* reset_domains = + GetJsonSection(*rtl_if_map, {"CUSTOMRESET"}, true); + nlohmann::json* input_ports = GetJsonSection(*rtl_if_map, + {"INPUT", "INPORT", "INPUTS", "INPORTS", "INPUT-PORT", "INPUT-PORTS"}, false); + if (clock_domains) { + ENSURE(clock_domains->is_array() || clock_domains->is_string() || + clock_domains->is_object(), + "clock specification in RTL interface connection should be " + "string/list of string/map:string->list(string)"); + if (clock_domains->is_string()) + rtl_interface_connection.clock_domain_defs["default"].insert( + clock_domains->get()); + else if (clock_domains->is_array()) { + auto clk_pins = clock_domains->get>(); + for (const auto& clk_pin : clk_pins) + rtl_interface_connection.clock_domain_defs["default"].insert(clk_pin); + } else { // is_object + for (const auto& n_l_pair : clock_domains->items()) { + const auto& domain_name = n_l_pair.key(); + std::set pins; + ENSURE(n_l_pair.value().is_string() || n_l_pair.value().is_array(), + "expect string/array in RTL interface connection"); + if (n_l_pair.value().is_string()) { + pins.insert(n_l_pair.value().get()); + } else { + auto pin_vec = n_l_pair.value().get>(); + pins = std::set(pin_vec.begin(), pin_vec.end()); + } + rtl_interface_connection.clock_domain_defs.emplace(domain_name, pins); + } + } // if is_object + } // if (clock_domain) + + if (reset_list) { + if (reset_list->is_string()) + rtl_interface_connection.reset_pins.insert( + reset_list->get()); + else if (reset_list->is_array()) { + auto reset_pins = reset_list->get>(); + for (const auto& pin : reset_pins) + rtl_interface_connection.reset_pins.insert(pin); + } + } + + if (nreset_list) { + if (nreset_list->is_string()) + rtl_interface_connection.nreset_pins.insert( + nreset_list->get()); + else if (nreset_list->is_array()) { + auto nreset_pins = nreset_list->get>(); + for (const auto& pin : nreset_pins) + rtl_interface_connection.nreset_pins.insert(pin); + } + } + if (reset_domains) { + ENSURE(reset_domains->is_array() || reset_domains->is_string() || + reset_domains->is_object(), + "clock specification in RTL interface connection should be " + "string/list of string/map:string->list(string)"); + if (reset_domains->is_string()) + rtl_interface_connection.custom_reset_domain_defs["default"].push_back( + reset_domains->get()); + else if (reset_domains->is_array()) { + rtl_interface_connection.custom_reset_domain_defs.insert( + std::make_pair(std::string("default"), + reset_domains->get>())); + } else { // is_object + for (const auto& n_l_pair : reset_domains->items()) { + const auto& domain_name = n_l_pair.key(); + std::vector pins; + ENSURE(n_l_pair.value().is_string() || n_l_pair.value().is_array(), + "expect string/array in RTL interface connection"); + if (n_l_pair.value().is_string()) { + pins.push_back(n_l_pair.value().get()); + } else { + pins = n_l_pair.value().get>(); + } + rtl_interface_connection.custom_reset_domain_defs.emplace(domain_name, + pins); + } + } // if is_object + } // if reset custom domain + if(input_ports) { + ENSURE(input_ports->is_object(), "Expecting `input-port` to be a map of string->string"); + for (const auto& n_l_pair : input_ports->items()) { + ENSURE(n_l_pair.value().is_string(), "Expecting `input-port` to be a map of string->string"); + auto rfe = ParseRfMapExprJson( n_l_pair.value() ); + auto port_name = n_l_pair.key(); + ENSURE(rtl_interface_connection.input_port_connection.find(port_name) == rtl_interface_connection.input_port_connection.end(), + ("Error: port name " + port_name + " has been assigned already") ); + rtl_interface_connection.input_port_connection.emplace(port_name, rfe); + } + } + } // interface map + + { // reset section parsing + nlohmann::json* reset_section = GetJsonSection(rf_vmap, {"reset"}); + if (reset_section) { + nlohmann::json* initial_state = + GetJsonSection(*reset_section, {"initial-state"}); + nlohmann::json* cycle = GetJsonSection(*reset_section, {"cycles"}); + nlohmann::json* customreset = + GetJsonSection(*reset_section, {"custom-seq"}); + if (initial_state) { + ENSURE(initial_state->is_object(), + "initial state should be map:name->value"); + for (const auto& n_v_pair : initial_state->items()) { + const auto& sn = n_v_pair.key(); + RfExpr val = ParseRfMapExprJson(n_v_pair.value()); + ERRIF(IN(sn, reset_specification.initial_state), + "duplicated sname for initial-state in reset"); + reset_specification.initial_state[sn] = val; + } + } // initial state + + if (cycle) { + ENSURE(cycle->is_number_unsigned(), + "cycles in reset should be unsigned integer"); + reset_specification.reset_cycle = cycle->get(); + } else + reset_specification.reset_cycle = 1; + + if (customreset) { + bool succ = JsonRfmapParseSequence( + reset_specification.custom_reset_sequence, *customreset); + ENSURE(succ, "Custom Reset Sequence error!"); + } + + } // if reset_section + } // reset + + { // clock section + nlohmann::json* clock_section = GetJsonSection(rf_vmap, {"clock"}); + if (clock_section) { + nlohmann::json* factor_section = + GetJsonSection(*clock_section, {"factor"}, true); + nlohmann::json* custom_section = + GetJsonSection(*clock_section, {"custom"}, true); + ENSURE(factor_section || custom_section, + "clock section must contain factor/custom field"); + ERRIF(factor_section && custom_section, + "Cannot have both `factor` and `custom` section"); + if (custom_section) { + nlohmann::json* length = GetJsonSection(*custom_section, {"length"}); + ENSURE(length, "`length` field is needed for custom section"); + ENSURE(length->is_number_unsigned(), + "length field must be unsigned integer"); + clock_specification.gcm_period = length->get(); + nlohmann::json* clocks = GetJsonSection(*custom_section, {"clocks"}); + ENSURE(clocks, "`clocks` field is needed for custom section"); + bool succ = JsonRfmapParseSequence( + clock_specification.custom_clock_sequence, *clocks); + ENSURE(succ, "Custom Clock error!"); + } else { + // factor_section + bool succ = JsonRfmapParseClockFactor( + clock_specification.custom_clock_factor, *factor_section); + succ = succ && JsonRfmapConvertFactorToSeq( + clock_specification.custom_clock_factor, + clock_specification.custom_clock_sequence); + ENSURE(succ, "Custom clock sequence error"); + } + } // if clock section + } // clock + + { // uf section + nlohmann::json* func_section = GetJsonSection( + rf_vmap, {"functions", "function", "uf", "ufs", + "uninterpreted function", "uninterpreted functions"}); + if (func_section) { + ENSURE(func_section->is_object(), + "Expect `functions` to be map:name->list of invocation "); + for (auto& n_invocation_pair : func_section->items()) { + const auto& n = n_invocation_pair.key(); + auto& invocations = n_invocation_pair.value(); + auto ret = uf_application.insert( + std::make_pair(n, UninterpretedFunctionApplication())); + auto& apply_obj = + ret.first->second; // point to the UninterpretedFunctionApplication + // object + ENSURE(invocations.is_array(), + "Expect `functions` to be map:name->list of invocation"); + for (auto& elem : invocations) { + ENSURE( + elem.is_object(), + "Expect `functions` to be map:name->list of invocation(object)"); + auto* result = GetJsonSection(elem, {"result"}); + auto* arg = GetJsonSection(elem, {"arg", "args"}); + ENSURE(result, + "Expect invocation object has `result` and `arg` field"); + ENSURE(result->is_string(), + "Expect type string in `result` field of invocation object"); + if(arg) { + ENSURE( + arg->is_array(), + "Expect type list(string) in `arg` field of invocation object"); + } + apply_obj.func_applications.push_back( + UninterpretedFunctionApplication::Apply()); + auto& curr_invocation = apply_obj.func_applications.back(); + curr_invocation.result_map = ParseRfMapExprJson(*result); + if(arg) { + std::vector argList = + arg->get>(); + for (const auto& arg : argList) + curr_invocation.arg_map.push_back(ParseRfMapExpr(arg)); + } + } + } // for each invocation + } // if func_section + } // uf section + { // additional mapping & assumptions + { + nlohmann::json* mapping_control = + GetJsonSection(rf_vmap, {"mapping control"}); + ERRIF(mapping_control != NULL, + "please rename `mapping control` to `additional mapping`"); + } + + nlohmann::json* additonal_section = + GetJsonSection(rf_vmap, {"additional mapping"}); + if (additonal_section) { + ENSURE(additonal_section->is_array(), + "`additional mapping` section should be a list of string"); + for (auto& pstr : *additonal_section) { + ENSURE(pstr.is_string(), + "`additional mapping` section should be a list of string"); + additional_mapping.push_back(ParseRfMapExprJson(pstr)); + } + } // if additional mapping + + nlohmann::json* assumption_section = + GetJsonSection(rf_vmap, {"assumptions"}); + if (assumption_section) { + ENSURE(assumption_section->is_array(), + "`assumptions` section should be a list of string"); + for (auto& pstr : *assumption_section) { + ENSURE(pstr.is_string(), + "`assumptions` section should be a list of string"); + assumptions.push_back(ParseRfMapExprJson(pstr)); + } + } + } // additional mapping & assumptions + + { // phase tracker, value recorder, customized ones + nlohmann::json* monitor_section = GetJsonSection(rf_vmap, {"monitor", "monitors"}); + if (monitor_section) { + ENSURE(monitor_section->is_object(), "`monitor` section should be a map"); + for (auto& name_monitor_pair : monitor_section->items()) { + auto name = name_monitor_pair.key(); + + ERRIF(IN(name, customized_monitor), + "monitor `" + name + "` has been defined."); + ERRIF(IN(name, phase_tracker), + "monitor `" + name + "` has been defined."); + ERRIF(IN(name, value_recorder), + "monitor `" + name + "` has been defined."); + ERRIF(IN(name, direct_aux_vars), + "monitor `" + name + "` has been defined."); + + auto& monitor = name_monitor_pair.value(); + if (monitor.is_string()) { + direct_aux_vars.emplace(name, AuxVar(name)); + auto ret = ParseRfMapExpr(monitor.get()); + ILA_NOT_NULL(ret); + direct_aux_vars.at(name).val = ret; + } else { + auto* template_field = GetJsonSection(monitor, {"template"}); + if (template_field) { + ENSURE(template_field->is_string(), + "`template` field should be string"); + auto template_name = template_field->get(); + if (SectionNameRelaxedMatch(template_name, "phase tracker") || + SectionNameRelaxedMatch(template_name, "stage tracker") ) { + phase_tracker.emplace(name, PhaseTracker()); + std::string errmsg = JsonRfmapParsePhaseTracker( + phase_tracker.at(name), monitor, name); + ENSURE(errmsg.empty(), errmsg); + } else if (SectionNameRelaxedMatch(template_name, "value recorder")) { + value_recorder.emplace(name, ValueRecorder()); + std::string errmsg = + JsonRfmapParseValueRecorder(value_recorder.at(name), monitor); + ENSURE(errmsg.empty(), errmsg); + } else { + ERRIF(true, + "template name `" + template_name + "` is not recognized."); + } + // end if has template field + } else { + customized_monitor.emplace(name, GeneralVerilogMonitor()); + auto& mnt_ref = customized_monitor.at(name); + { // inline verilog + // has no template + auto* verilog_field = GetJsonSection(monitor, {"verilog"}); + auto* verilog_file_field = + GetJsonSection(monitor, {"verilog-from-file"}); + auto* keep_inv = GetJsonSection( + monitor, {"keep-for-invariant", "keep-for-invariants"}); + + ERRIF( + verilog_field && verilog_file_field, + "`verilog` or `verilog-from-file` fields are mutual exclusive"); + if (keep_inv) { + ENSURE(keep_inv->is_boolean(), + "`keep-for-invariant` should be Boolean"); + mnt_ref.keep_for_invariant = keep_inv->get(); + } + + if (verilog_field) { + if (verilog_field->is_string()) { + mnt_ref.verilog_inline = verilog_field->get(); + } else { + ENSURE(verilog_field->is_array(), + "`verilog` field should be a list of string"); + for (auto& ps : *verilog_field) { + ENSURE(ps.is_string(), + "`verilog` field should be a list of string"); + mnt_ref.verilog_inline += ps.get() + "\n"; + } + } + } else if (verilog_file_field) { + ENSURE(verilog_file_field->is_string(), + "`verilog-from-file` expects a string (file name)"); + auto fname = verilog_file_field->get(); + std::ifstream fin(fname); + ENSURE(fin.is_open(), "Cannot read from " + fname); + { + std::stringstream buffer; + buffer << fin.rdbuf(); + mnt_ref.verilog_inline = buffer.str(); + } + } // verilog_file_field : from file + } // inline verilog + + { // append verilog outside the module + // has no template + auto* verilog_field = GetJsonSection(monitor, {"append-verilog"}); + auto* verilog_file_field = + GetJsonSection(monitor, {"append-verilog-from-file"}); + + ERRIF(verilog_field && verilog_file_field, + "`append-verilog` or `append-verilog-from-file` fields are " + "mutual exclusive"); + + if (verilog_field) { + if (verilog_field->is_string()) { + mnt_ref.verilog_append = + verilog_field->get() + "\n"; + } else { + ENSURE(verilog_field->is_array(), + "`append-verilog` field should be a list of string"); + for (auto& ps : *verilog_field) { + ENSURE(ps.is_string(), + "`append-verilog` field should be a list of string"); + mnt_ref.verilog_append += ps.get() + "\n"; + } + } + } else if (verilog_file_field) { + ENSURE(verilog_file_field->is_string(), + "`append-verilog-from-file` expects a string (file name)"); + auto fname = verilog_file_field->get(); + std::ifstream fin(fname); + ENSURE(fin.is_open(), "Cannot read from " + fname); + { + std::stringstream buffer; + buffer << fin.rdbuf(); + mnt_ref.verilog_append = buffer.str() + "\n"; + } + } // append-verilog_file_field : from file + } // verilog_append verilog + + auto* ref_field = GetJsonSection(monitor, {"refs"}); + if (ref_field) { // refs + ENSURE(ref_field->is_array(), + "`refs` field should be a list of string"); + for (auto& p : *ref_field) { + ENSURE(p.is_string(), "`refs` field should be a list of string"); + auto var_name = p.get(); + ILA_WARN_IF(IN(var_name, mnt_ref.var_uses)) + << "`" + var_name + "` has been declared already in `refs`"; + mnt_ref.var_uses.insert(p.get()); + } + } // if ref_field + + auto* def_field = GetJsonSection(monitor, {"defs"}); + if (def_field) { // defs + auto err_msg = JsonRfMapParseVarDefs(mnt_ref.var_defs, *def_field); + ENSURE(err_msg.empty(), err_msg); + } // if def_field + } // else if it is verilog monitor (general) + } // end of if is_string()--else + } // for each monitor + } // if has monitor field + } // monitor block + + // ---------------- inst_cond ------------------------ // + { + auto* instrs = GetJsonSection(rf_cond, {"instructions"}); + auto* invariants = GetJsonSection(rf_cond, {"global invariants"}); + auto* glb_ready_bound = GetJsonSection(rf_cond, {"ready-bound"}); + auto* glb_ready_signal = GetJsonSection(rf_cond, {"ready-signal"}); + ERRIF(glb_ready_bound && glb_ready_signal, + "`ready bound` and `ready signal` are mutual exclusive"); + global_inst_complete_set = glb_ready_bound || glb_ready_signal; + + if (glb_ready_bound) { + ENSURE(glb_ready_bound->is_number_unsigned(), + "`ready-bound` should be an unsigned number"); + global_inst_complete_cond.ready_bound = glb_ready_bound->get(); + global_inst_complete_cond.type = InstructionCompleteCondition::ConditionType::BOUND; + } else if (glb_ready_signal) { + ENSURE(glb_ready_signal->is_string(), + "`ready-signal` should be a string"); + global_inst_complete_cond.ready_signal = ParseRfMapExprJson(*glb_ready_signal); + global_inst_complete_cond.type = InstructionCompleteCondition::ConditionType::SIGNAL; + } + + if (instrs) { + ENSURE(instrs->is_array(), "`instructions` should be array of object"); + for (auto& instr : *instrs) { + ENSURE(instr.is_object(), "`instructions` should be array of object"); + auto* instr_name = GetJsonSection(instr, {"instruction"}); + auto* ready_bnd = GetJsonSection(instr, {"ready-bound"}); + auto* ready_signal = GetJsonSection(instr, {"ready-signal"}); + auto* max_bound = GetJsonSection(instr, {"max-bound"}); + auto* start_condition = GetJsonSection(instr, {"start-condition"}); + ENSURE(instr_name && instr_name->is_string(), + "`instruction` field should be a string"); + ERRIF(ready_bnd && ready_signal, + "`ready bound` and `ready signal` are mutual exclusive"); + ENSURE(ready_bnd || ready_signal, + "You must specify one of `ready bound` and `ready signal`"); + auto iname = instr_name->get(); + inst_complete_cond.emplace(iname, InstructionCompleteCondition()); + auto& ws = inst_complete_cond.at(iname); + + ws.instruction_name = iname; + if (ready_bnd) { + ENSURE(ready_bnd->is_number_unsigned(), + "`ready-bound` should be an unsigned number"); + ws.ready_bound = ready_bnd->get(); + ws.type = InstructionCompleteCondition::ConditionType::BOUND; + } else { // ready_signal + ENSURE(ready_signal->is_string(), + "`ready-signal` should be a string"); + ws.ready_signal = ParseRfMapExprJson(*ready_signal); + ws.type = InstructionCompleteCondition::ConditionType::SIGNAL; + } + + if (max_bound) { + ENSURE(max_bound->is_number_unsigned(), + "`max_bound` should be an unsigned number"); + ws.max_bound = max_bound->get(); + } else + ws.max_bound = 0; + + if (start_condition) { + if (start_condition->is_string()) { + ws.start_condition.push_back(ParseRfMapExprJson(*start_condition)); + } else { + ENSURE(start_condition->is_array(), + "`start_condition` should be a string or array of strings"); + for (auto& cond : *start_condition) { + ENSURE( + cond.is_string(), + "`start_condition` should be a string or array of strings"); + ws.start_condition.push_back(ParseRfMapExprJson(cond)); + } + } // end if start condition is string + } // end if start condition + } // for each instr` + } // if instrs + + if (invariants) { + ENSURE(invariants->is_array(), + "`global-invariants` should be an array of strings"); + for (auto& inv : *invariants) { + ENSURE(inv.is_string(), + "`global-invariants` should be an array of strings"); + global_invariants.push_back(ParseRfMapExprJson(inv)); + } + } // if invariant + } // inst cond + + // ---------------- supplementary_info ------------------------ // + { + auto* annotation = GetJsonSection(rf_vmap, {"annotation", "annotations"}); + if (annotation) { + auto* width_anno = GetJsonSection(*annotation, {"width"}); + if (width_anno && width_anno->is_object()) { + for (auto&& nw : width_anno->items()) { + width_info.insert(std::make_pair(nw.key(), nw.value().get())); + ERRIF(nw.value().get() <= 0 , (nw.key() + "'s width <=0")); + } + } + auto* range_anno = GetJsonSection(*annotation, {"range"}); + if (range_anno && range_anno->is_object()) { + for (auto&& nw : range_anno->items()) { + range_info.insert(std::make_pair(nw.key(), nw.value().get())); + ERRIF(nw.value().get() <= 0 , (nw.key() + "'s range <=0")); + } + } + } // end of annotation + } // end of supplementary_info + + ERRIF(ParseRfExprErrFlag, "error occur in refinement expression parsing"); + +} // VerilogRefinementMap::VerilogRefinementMap + +bool is_valid_id_name(const std::string& in) { + if (in.empty()) + return false; + if (!isalpha(in.at(0)) && in.at(0) != '_') + return false; + for (size_t idx = 1; idx < in.size(); ++idx) + if (!isalnum(in.at(idx))) + return false; + return true; +} + +#undef ERRIF +#undef ENSURE +#define ERRIF(cond, str) \ + do { \ + ILA_ERROR_IF(cond) << str; \ + if (cond) \ + return false; \ + } while (false) +#define ENSURE(cond, str) ERRIF(!(cond), str) + +bool VerilogRefinementMap::SelfCheckField() const { + // check module name + ERRIF(ParseRfExprErrFlag, "Error in parsing refinement expressions"); + + for (const auto& n_map : ila_state_var_map) { + ENSURE(!(n_map.second.externmem_map.empty()) || + (n_map.second.single_map.single_map.get() != nullptr) || + !(n_map.second.single_map.cond_map.empty()), + "state var map cannot be empty for " + n_map.first); + ERRIF(!(n_map.second.externmem_map.empty()) && + (n_map.second.single_map.single_map.get() != nullptr), + "duplicate state var map for " + n_map.first); + ERRIF(!(n_map.second.single_map.cond_map.empty()) && + (n_map.second.single_map.single_map.get() != nullptr), + "duplicate state var map for " + n_map.first); + ERRIF(!(n_map.second.externmem_map.empty()) && + (!n_map.second.single_map.cond_map.empty()), + "duplicate state var map for " + n_map.first); + } + + std::set custom_reset_seq_name; + std::set custom_clock_seq_name; + { // for reset, valid name, domain names are defs + unsigned seq_len = 0; + for (const auto& n_seq : reset_specification.custom_reset_sequence) { + ERRIF(!is_valid_id_name(n_seq.first), + "Custom reset sequence name " << n_seq.first << " is not valid"); + ERRIF(IN(n_seq.first, custom_reset_seq_name), + "reset sequence name " + n_seq.first + + "has been used multiple times"); + + custom_reset_seq_name.insert(n_seq.first); + + ERRIF(n_seq.second.size() == 0, + "Empty reset sequence for " + n_seq.first); + if (seq_len == 0) + seq_len = n_seq.second.size(); + ERRIF(seq_len != reset_specification.reset_cycle, + "Customized reset sequence does not match the cycle count"); + + ERRIF(seq_len != n_seq.second.size(), + "Reset sequence should be of same length"); + } + } + + { // for clock, valid name, check no empty sequence, sequence of the same + // length + unsigned seq_len = 0; + for (const auto& n_seq : clock_specification.custom_clock_sequence) { + ERRIF(!is_valid_id_name(n_seq.first), + "Custom clock sequence name " << n_seq.first << " is not valid"); + ERRIF(IN(n_seq.first, custom_clock_seq_name), + "clock sequence name " + n_seq.first + + "has been used multiple times"); + + custom_clock_seq_name.insert(n_seq.first); + + ERRIF(n_seq.second.size() == 0, + "Empty clock sequence for " + n_seq.first); + if (seq_len == 0) + seq_len = n_seq.second.size(); + ERRIF(seq_len != clock_specification.gcm_period, + "Customized clock does not match the specified length requirement"); + + ERRIF(seq_len != n_seq.second.size(), + "Clock sequence should be of same length"); + } + } + + { + for (const auto& clkd : custom_clock_seq_name) { + ERRIF(IN(clkd, custom_reset_seq_name), + "Name " + clkd + " has been used multiple times"); + } + for (const auto& rstd : custom_reset_seq_name) { + ERRIF(IN(rstd, custom_clock_seq_name), + "Name " + rstd + " has been used multiple times"); + } + } + + { // for each interface check domain names are good + for (const auto& n_clks : rtl_interface_connection.clock_domain_defs) { + ERRIF(!IN(n_clks.first, custom_clock_seq_name), + "clock domain " + n_clks.first + " is not found"); + } + for (const auto& n_rsts : + rtl_interface_connection.custom_reset_domain_defs) { + ERRIF(!IN(n_rsts.first, custom_reset_seq_name), + "reset domain " + n_rsts.first + " is not found"); + } + } + + // check trackers, recorders, monitor names are okay + + { // GeneralVerilogMonitor, for ids are okay, no bad names + std::set var_def_names; + for (const auto& n_st : phase_tracker) { + // const auto & phase_tracker_name = n_st.first; + for (const auto& var_def : n_st.second.event_alias) { + ERRIF(!is_valid_id_name(var_def.first), + "Monitor name " + var_def.first + " is not valid"); + ERRIF(IN(var_def.first, var_def_names), + "Variable " + n_st.first + " has been defined already"); + var_def_names.insert(var_def.first); + } + for (const auto& var_def : n_st.second.var_defs) { + ERRIF(!is_valid_id_name(var_def.first), + "Monitor name " + var_def.first + " is not valid"); + ERRIF(IN(var_def.first, var_def_names), + "Variable " + n_st.first + " has been defined already"); + var_def_names.insert(var_def.first); + } + for (const auto& st : n_st.second.rules) { + ERRIF(!is_valid_id_name(st.stage_name), + "stage name " + st.stage_name + " is not valid"); + + ERRIF(IN(st.stage_name, var_def_names), + "Variable " + n_st.first + " has been defined already"); + var_def_names.insert(st.stage_name); + } + } + + for (const auto& n_expr : direct_aux_vars) { + ERRIF(!is_valid_id_name(n_expr.first), + "Monitor name " + n_expr.first + " is not valid"); + ERRIF(IN(n_expr.first, var_def_names), + "Monitor name " + n_expr.first + " has been used"); + var_def_names.insert(n_expr.first); + } + + for (const auto& n_st : value_recorder) { + ERRIF(!is_valid_id_name(n_st.first), + "Monitor name " + n_st.first + " is not valid"); + ERRIF(IN(n_st.first, var_def_names), + "Monitor name " + n_st.first + " has been used"); + var_def_names.insert(n_st.first); + } + for (const auto& n_st : customized_monitor) { + ERRIF(!is_valid_id_name(n_st.first), + "Monitor name " + n_st.first + " is not valid"); + ERRIF(IN(n_st.first, var_def_names), + "Monitor name " + n_st.first + " has been used"); + var_def_names.insert(n_st.first); + + for (const auto& var_def : n_st.second.var_defs) { + ERRIF(IN(var_def.first, var_def_names), + "Variable " + n_st.first + " has been defined already"); + var_def_names.insert(var_def.first); + } + } + } + return true; + // no need to check for inst_cond +} // bool VerilogRefinementMap::SelfCheck() const + +#undef ERRIF +#undef ENSURE + +} // namespace rfmap +} // namespace ilang diff --git a/src/util/str_util.cc b/src/util/str_util.cc index ac732b1ee..049d33913 100644 --- a/src/util/str_util.cc +++ b/src/util/str_util.cc @@ -63,7 +63,8 @@ long long StrToLong(const std::string& str, int base) { try { return std::stoll(str, NULL, base); } catch (const std::exception& e) { - ILA_ERROR << "Converting non-numeric value " << str << " to long int."; + ILA_ERROR << "Cannot converting value " << str << " to long int." + << " base : " << base; return 0; } } @@ -72,8 +73,8 @@ unsigned long long StrToULongLong(const std::string& str, int base) { try { return std::stoull(str, NULL, base); } catch (const std::exception& e) { - ILA_ERROR << "Converting non-numeric value " << str - << " to unsigned long long"; + ILA_ERROR << "Cannot converting value " << str << " to unsigned long long." + << " base : " << base; return 0; } } diff --git a/src/verilog-in/verilog_analysis.cc b/src/verilog-in/verilog_analysis.cc index d1d5ba604..c6767d0a0 100644 --- a/src/verilog-in/verilog_analysis.cc +++ b/src/verilog-in/verilog_analysis.cc @@ -633,9 +633,10 @@ VerilogAnalyzer::name2loc(const std::string& net_name) const { /// Find a signal SignalInfoBase VerilogAnalyzer::get_signal( const std::string& net_name, - const std::map* const width_info) const { + const std::map* const width_info, + const std::map* const range_info) const { SignalInfoBase bad_signal("", "", 0, hierarchical_name_type::NONE, - vlg_loc_t()); + vlg_loc_t(), 0); if (_bad_state_return()) return bad_signal; @@ -670,7 +671,7 @@ SignalInfoBase VerilogAnalyzer::get_signal( case O_REG_w_INTERNAL_DEF: case REG: return SignalInfoReg((ast_reg_declaration*)ast_ptr, net_name, tp_, - width_info, this); + width_info, this, range_info); case MODULE: ILA_ERROR << "Module instance:" << net_name << " is not a signal."; return bad_signal; @@ -756,7 +757,7 @@ VerilogAnalyzer::module_io_vec_t VerilogAnalyzer::get_top_module_io( case O_REG_w_INTERNAL_DEF: retIoVec.insert( {short_name, SignalInfoReg((ast_reg_declaration*)ast_ptr, port_name, - tp_, width_info, this)}); + tp_, width_info, this, NULL)}); break; default: ILA_ASSERT(false) << "Implementation bug."; @@ -838,6 +839,9 @@ unsigned range_to_width(ast_range* range, const std::string& full_name, const VerilogAnalyzer* _ana, int width = -1) { if (range == NULL) return 1; + if(width > 0) + return width; + ast_expression* left = range->upper; ast_expression* right = range->lower; @@ -854,18 +858,28 @@ unsigned range_to_width(ast_range* range, const std::string& full_name, unsigned rr = (unsigned)eval.Eval(right); unsigned analyzed_width = std::max(lr, rr) - std::min(lr, rr) + 1; - // this will provide width when we cannot get width - // or there is error, o.w. we will trust the width from - if (width > 0) { - ILA_WARN_IF(!eval.error()) - << "Overwriting width of signal: " << full_name << " to " << width - << "(w=" << analyzed_width << " by analysis)"; - return width; - } + // overwriting will end this procedure first. + // if (width > 0) { + // ILA_WARN_IF(!eval.error()) + // << "Overwriting width of signal: " << full_name << " to " << width + // << "(w=" << analyzed_width << " by analysis)"; + // return width; + //} return analyzed_width; } +// this returns: from [0:15] 15-0+1 == 16 +unsigned addr_range_to_width(ast_identifier id, const std::string& full_name, + const VerilogAnalyzer* _ana, int width) { + if(id->range_or_idx == ID_HAS_RANGES && id->ranges && id->ranges->items > 0) { + ast_range * range = (ast_range *) id->ranges->head->data; + return range_to_width(range, full_name, _ana, width); + } + return 0; +} + + SignalInfoPort::SignalInfoPort( ast_port_declaration* def, const std::string& full_name, VerilogAnalyzerBase::hierarchical_name_type tp, @@ -878,7 +892,9 @@ SignalInfoPort::SignalInfoPort( : (IN_p(full_name, width_info) ? width_info->at(full_name) : -1)), - tp, VerilogAnalyzer::Meta2Loc(def->meta)), + tp, VerilogAnalyzer::Meta2Loc(def->meta), + 0 // not an array + ), _def(def) { // ILA_WARN_IF( def->range == NULL ) << "Verilog Analyzer: // signal "<< full_name <<" has no range."; ILA_WARN_IF(_width == 0) @@ -890,7 +906,8 @@ SignalInfoReg::SignalInfoReg(ast_reg_declaration* def, const std::string& full_name, VerilogAnalyzerBase::hierarchical_name_type tp, const std::map* const width_info, - const VerilogAnalyzer* _ana) + const VerilogAnalyzer* _ana, + const std::map* const range_info) : SignalInfoBase(Split(full_name, ".").back(), full_name, range_to_width(def->range, full_name, _ana, width_info == NULL @@ -898,7 +915,10 @@ SignalInfoReg::SignalInfoReg(ast_reg_declaration* def, : (IN_p(full_name, width_info) ? width_info->at(full_name) : -1)), - tp, VerilogAnalyzer::Meta2Loc(def->meta)), + tp, VerilogAnalyzer::Meta2Loc(def->meta), + addr_range_to_width(def->identifier, full_name, _ana, + range_info == NULL ? -1 : (IN_p(full_name, range_info) ? range_info->at(full_name) : -1) ) + ), _def(def) { ILA_WARN_IF(_width == 0) << "Verilog Analyzer is not able to determine the width of signal:" @@ -917,7 +937,9 @@ SignalInfoWire::SignalInfoWire( : (IN_p(full_name, width_info) ? width_info->at(full_name) : -1)), - tp, VerilogAnalyzer::Meta2Loc(def->meta)), + tp, VerilogAnalyzer::Meta2Loc(def->meta), + 0 // not an array + ), _def(def) { ILA_WARN_IF(_width == 0) << "Verilog Analyzer is not able to determine the width of signal:" diff --git a/src/verilog-in/verilog_analysis_wrapper.cc b/src/verilog-in/verilog_analysis_wrapper.cc index 37a83b5a2..8b2abdd18 100644 --- a/src/verilog-in/verilog_analysis_wrapper.cc +++ b/src/verilog-in/verilog_analysis_wrapper.cc @@ -82,10 +82,11 @@ SignalInfoBase VerilogInfo::get_signal(const std::string& net_name) const { /// Find a signal (and use the width info, if width is unknown) SignalInfoBase VerilogInfo::get_signal(const std::string& net_name, - const std::map& width_info) const { + const std::map& width_info, + const std::map& range_info) const { const VerilogAnalyzer* _ptr = dynamic_cast(_analyzer); ILA_NOT_NULL(_ptr); - return _ptr->get_signal(net_name, &width_info); + return _ptr->get_signal(net_name, &width_info, &range_info); } bool VerilogInfo::in_bad_state() const { diff --git a/src/verilog-out/verilog_gen.cc b/src/verilog-out/verilog_gen.cc index e56b90c35..3c317cd02 100644 --- a/src/verilog-out/verilog_gen.cc +++ b/src/verilog-out/verilog_gen.cc @@ -213,6 +213,7 @@ int VerilogGeneratorBase::get_width(const ExprPtr& n) { } /// convert a widith to a verilog string std::string VerilogGeneratorBase::WidthToRange(int w) { + ILA_ERROR_IF(w==0) << "Width should be > 0 !"; if (w > 1) return std::string("[") + toStr(w - 1) + ":0]"; return ""; @@ -388,6 +389,8 @@ void VerilogGeneratorBase::DumpToFile(std::ostream& fout) const { << "the maximum allowed entry count: " << n_elem_allowed; if (entry_num_specified != 0 && entry_num_specified <= n_elem_allowed) n_elem = entry_num_specified; + if(cfg_.add_keep_for_internal_mem) + fout << "(* keep *) "; // sometimes these regs will be optimized always fout << "reg " << std::setw(10) << WidthToRange(data_width) << " " << (std::get<0>(mem.second)) << WidthToRange(n_elem) << ";\n"; } @@ -1301,6 +1304,23 @@ void VerilogGenerator::ExportIla(const InstrLvlAbsPtr& ila_ptr_) { ExportFuncDefs(); } + +// get valid signal name in advace +std::string VerilogGenerator::GetValidSignalName(const InstrPtr& instr_ptr_) const { + + auto ila_ptr_ = instr_ptr_->host(); + return "__ILA_" + sanitizeName(ila_ptr_->name().str()) + "_valid__"; +} + +// get decode signal name in advace +std::string VerilogGenerator::GetDecodeSignalName(const InstrPtr& instr_ptr_) const { + + auto ila_ptr_ = instr_ptr_->host(); + return "__ILA_" + sanitizeName(ila_ptr_->name().str()) + + "_decode_of_" + sanitizeName(instr_ptr_->name().str()) + + "__"; +} + // here we will add all updates, those not touched will be update to itself // add inputs / states / functions // do remember to export its parents' state (hierarchically collect its parents) @@ -1341,7 +1361,7 @@ void VerilogGenerator::ExportTopLevelInstr(const InstrPtr& instr_ptr_) { ParseNonMemUpdateExpr(valid_ptr); vlg_name_t valid_sig_name = getVlgFromExpr(valid_ptr); if (validName == "") - validName = "__ILA_" + sanitizeName(ila_ptr_->name().str()) + "_valid__"; + validName = GetValidSignalName(instr_ptr_); add_wire(validName, 1); add_output(validName, 1); add_assign_stmt(validName, valid_sig_name); @@ -1354,9 +1374,7 @@ void VerilogGenerator::ExportTopLevelInstr(const InstrPtr& instr_ptr_) { } ParseNonMemUpdateExpr(decode_ptr); vlg_name_t decode_sig_name = getVlgFromExpr(decode_ptr); - auto decodeName = "__ILA_" + sanitizeName(ila_ptr_->name().str()) + - "_decode_of_" + sanitizeName(instr_ptr_->name().str()) + - "__"; + auto decodeName = GetDecodeSignalName(instr_ptr_); decodeNames.push_back(decodeName); add_wire(decodeName, 1); add_output(decodeName, 1); diff --git a/src/vtarget-out/.gitignore b/src/vtarget-out/.gitignore new file mode 100644 index 000000000..d8f4c5a86 --- /dev/null +++ b/src/vtarget-out/.gitignore @@ -0,0 +1,2 @@ +NOTE.txt +deprecated/* diff --git a/src/vtarget-out/CMakeLists.txt b/src/vtarget-out/CMakeLists.txt index 14134d4db..6ad93c1f9 100644 --- a/src/vtarget-out/CMakeLists.txt +++ b/src/vtarget-out/CMakeLists.txt @@ -7,7 +7,6 @@ add_subdirectory(inv-syn) target_sources(${ILANG_LIB_NAME} PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/directive.cc ${CMAKE_CURRENT_SOURCE_DIR}/gen_util.cc - ${CMAKE_CURRENT_SOURCE_DIR}/var_extract.cc ${CMAKE_CURRENT_SOURCE_DIR}/vtarget_gen_impl.cc ${CMAKE_CURRENT_SOURCE_DIR}/single_target.cc ${CMAKE_CURRENT_SOURCE_DIR}/single_target_as.cc @@ -15,14 +14,10 @@ target_sources(${ILANG_LIB_NAME} PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/single_target_misc.cc ${CMAKE_CURRENT_SOURCE_DIR}/single_target_cond.cc ${CMAKE_CURRENT_SOURCE_DIR}/single_target_inv_syn_support.cc - ${CMAKE_CURRENT_SOURCE_DIR}/vtarget_gen_cosa.cc + ${CMAKE_CURRENT_SOURCE_DIR}/vtarget_gen_pono.cc ${CMAKE_CURRENT_SOURCE_DIR}/vtarget_gen_jasper.cc - ${CMAKE_CURRENT_SOURCE_DIR}/vtarget_gen_yosys.cc - ${CMAKE_CURRENT_SOURCE_DIR}/vtarget_gen_relchc.cc ${CMAKE_CURRENT_SOURCE_DIR}/vtarget_gen.cc ${CMAKE_CURRENT_SOURCE_DIR}/vlg_mod.cc - ${CMAKE_CURRENT_SOURCE_DIR}/absmem.cc ${CMAKE_CURRENT_SOURCE_DIR}/design_stat.cc - ${CMAKE_CURRENT_SOURCE_DIR}/supplementary_info.cc ) diff --git a/src/vtarget-out/absmem.cc b/src/vtarget-out/absmem.cc deleted file mode 100644 index 3fba7e41c..000000000 --- a/src/vtarget-out/absmem.cc +++ /dev/null @@ -1,636 +0,0 @@ -/// \file Source for generating abstract memory -// --- Hongce Zhang - -#include - -#include -#include - -#include -#include -#include - -namespace ilang { - -unsigned mem_count = 0; -std::string get_m_inst_name() { - return std::string("mi") + std::to_string(mem_count++); -} - -// ---------------------- class VlgAbsMem ------------------------------- // -VlgAbsMem::VlgAbsMem() - : read_abstract(false), concrete_level(1), data_width(0), addr_width(0), - checked(false) {} - -/// SetAddrWidth -void VlgAbsMem::SetAddrWidth(unsigned w) { - if (addr_width != 0 && addr_width != w) { - ILA_ERROR << "Address width incompatible!"; - return; - } - addr_width = w; -} -/// SetDataWidth -void VlgAbsMem::SetDataWidth(unsigned w) { - if (data_width != 0 && data_width != w) { - ILA_ERROR << "Data width incompatible!"; - return; - } - data_width = w; -} - -std::string VlgAbsMem::MemEQSignalName() const { return mem_name + "_EQ_"; } - -// add signals and add instantiation statement; -std::string -VlgAbsMem::GeneratingMemModuleSignalsInstantiation(VerilogGeneratorBase& gen, - const std::string& endCond) { - // eq ? signal - // if not given, use a name it self - if (addr_width == 0 || data_width == 0) { - ILA_ERROR << "Unknown addr/data width for absmem : " << ila_map_name; - return ""; - } - if (vlg_rports.size() > 1 || vlg_wports.size() > 1 || ila_rports.size() > 1 || - ila_wports.size() > 1) { - ILA_ERROR << "Not implemented for support for abs mem w. more than 1 rport " - "and 1 wport"; - return ""; - } - - std::stringstream ret; - std::string moduleName; - auto inst_name = get_m_inst_name(); - if (concrete_level == 1) - moduleName = "absmem"; - else - moduleName = "absmemD" + std::to_string(concrete_level); - if (read_abstract) - moduleName += "_ra"; - ret << moduleName << " #( \n .AW(" << addr_width << "),\n"; - if (read_abstract) { - ret << " .DW(" << data_width << ") )\n"; - // will not have TTS, because not used - // and will create problem for jg - } else { - ret << " .DW(" << data_width << "),\n"; - ret << " .TTS(" << (long long)(std::pow(2, addr_width)) << ") )\n"; - } - ret << inst_name << "(\n"; - ret << " .clk(clk),\n"; - ret << " .rst(rst),\n"; - - auto vlg_rand_input_name = inst_name + "_vlg_r_rand_input"; - auto ila_rand_input_name = inst_name + "_ila_r_rand_input"; - auto read_assume_true = inst_name + "_read_assume_true"; - gen.add_input(vlg_rand_input_name, data_width); - gen.add_input(ila_rand_input_name, data_width); - gen.add_output(read_assume_true, 1); - - if (read_abstract) - assumpts.push_back(read_assume_true + "==1'b1"); - - ret << " .vlg_r_rand_input( " << vlg_rand_input_name << "),\n"; - ret << " .ila_r_rand_input( " << ila_rand_input_name << "),\n"; - ret << " .equal(" << MemEQSignalName() << "),\n"; - ret << " .issue( __ISSUE__ ),\n"; - if (read_abstract) - ret << " .read_assume_true(" << read_assume_true << "),\n"; - ret << " .compare(" << endCond // "__IEND__ || __ENDED__" - << ")"; - - gen.add_wire(MemEQSignalName(), 1, true); - if (ila_map_name == "") - ILA_WARN_IF(ila_map_name == "") - << "Empty mem abs name for (" << mem_name << ")"; - - // connect ports, create - // treat unconnected wire? -#define CONNECT(e, s, w, i) \ - do { \ - std::string wn = (e); \ - if ((wn).size() == 0) { \ - (wn) = base_name + (s); \ - gen.add_wire((wn), (w), true); \ - if (i) \ - gen.add_input((wn), (w)); \ - else \ - gen.add_output((wn), (w)); \ - } \ - ret << ",\n .vlg" s "(" << (wn) << ")"; \ - } while (false) - - for (auto&& np : vlg_wports) { - auto n = np.first; - auto& p = np.second; - auto base_name = "__MEM_" + - VerilogGeneratorBase::sanitizeName(ila_map_name) + "_" + - std::to_string(n); - - CONNECT(p.waddr, "_waddr", addr_width, true); - CONNECT(p.wdata, "_wdata", data_width, false); - CONNECT(p.wen, "_wen", 1, true); - } // the else case: - if (vlg_wports.size() == 0) { // avoid write arbitrarily - ret << ",\n .vlg_wen(1'b0)"; - int n = 0; - auto base_name = "__MEM_" + - VerilogGeneratorBase::sanitizeName(ila_map_name) + "_" + - std::to_string(n); - CONNECT("", "_waddr", addr_width, true); - CONNECT("", "_wdata", data_width, false); - } - - for (auto&& np : vlg_rports) { - auto n = np.first; - auto& p = np.second; - auto base_name = "__MEM_" + - VerilogGeneratorBase::sanitizeName(ila_map_name) + "_" + - std::to_string(n); - - CONNECT(p.raddr, "_raddr", addr_width, true); - CONNECT(p.rdata, "_rdata", data_width, false); - CONNECT(p.ren, "_ren", 1, true); - } // else case - if (vlg_rports.size() == 0) { - ret << ",\n .vlg_ren(1'b0)"; - int n = 0; - auto base_name = "__MEM_" + - VerilogGeneratorBase::sanitizeName(ila_map_name) + "_" + - std::to_string(n); - CONNECT("", "_raddr", addr_width, true); - CONNECT("", "_rdata", data_width, false); - } - - // ila ports should have been fully connected - // NOTE: in multi inst - for (auto&& np : ila_wports) { - auto n = np.first; - auto& p = np.second; - auto base_name = "__IMEM_" + - VerilogGeneratorBase::sanitizeName(ila_map_name) + "_" + - std::to_string(n); - - ret << ",\n .ila_waddr(" << base_name + "_waddr" - << ")"; - ret << ",\n .ila_wdata(" << base_name + "_wdata" - << ")"; - ret << ",\n .ila_wen (" << base_name + "_wen" - << ")"; - - ILA_DLOG("VtargetGen.AbsMem") - << ".ila_waddr(" << p.waddr << " or " << base_name + "_waddr" - << ")"; - ILA_DLOG("VtargetGen.AbsMem") - << ".ila_wdata(" << p.wdata << " or " << base_name + "_wdata" - << ")"; - ILA_DLOG("VtargetGen.AbsMem") - << ".ila_wen (" << p.wen << " or " << base_name + "_wen" - << ")"; - } - if (ila_wports.size() == 0) - ret << ",\n .ila_wen ( 1'b0 )"; // make sure we don't do any writes if - // no write - - for (auto&& np : ila_rports) { - auto n = np.first; - auto& p = np.second; - - auto base_name = "__IMEM_" + - VerilogGeneratorBase::sanitizeName(ila_map_name) + "_" + - std::to_string(n); - - ret << ",\n .ila_raddr(" << base_name + "_raddr" - << ")"; - ret << ",\n .ila_rdata(" << base_name + "_rdata" - << ")"; - ret << ",\n .ila_ren (" << p.ren << ")"; // this is the start? - } - - ret << " );\n\n"; - - checked = true; - // here negative means abstract its read - concrete_level_encountered.insert(read_abstract ? -concrete_level - : concrete_level); - - return (ret.str()); -} - -bool VlgAbsMem::hasAbsMem() { return concrete_level_encountered.size() > 0; } - -void VlgAbsMem::ClearAbsMemRecord() { - mem_count = 0; - concrete_level_encountered.clear(); -} - -// the parameters are : -// %%%AVOID_ISSUE%%% -// -// - -std::string d1model = R"**##**( - -// 1R 1W (x2) d=1 AW(V=I) DW(V=I) absmem -// only work for CoSA -// Hongce Zhang (hongcez@princeton.edu) - -module absmem( - clk, - rst, - vlg_raddr, - vlg_rdata, - vlg_ren, - vlg_waddr, - vlg_wdata, - vlg_wen, - - vlg_r_rand_input, - - ila_raddr, - ila_rdata, - ila_ren, - ila_waddr, - ila_wdata, - ila_wen, - - ila_r_rand_input, - - compare, - equal, - issue - ); - - -parameter AW = 16; -parameter DW = 8; -parameter TTS = 65536; - -input clk; -input rst; - -input [AW-1:0] vlg_raddr; -output [DW-1:0] vlg_rdata; -input vlg_ren; -input [AW-1:0] vlg_waddr; -input [DW-1:0] vlg_wdata; -input vlg_wen; -input [DW-1:0] vlg_r_rand_input; - - -input [AW-1:0] ila_raddr; -output [DW-1:0] ila_rdata; -input ila_ren; -input [AW-1:0] ila_waddr; -input [DW-1:0] ila_wdata; -input ila_wen; -input [DW-1:0] ila_r_rand_input; - -input compare; -output equal; -input issue; - -(* keep *) reg start_and_on; -(* keep *) reg [DW-1:0] mem[0:TTS-1]; - -wire vlg_ren_real; -wire vlg_wen_real; -wire ila_ren_real; -wire ila_wen_real; - -(* keep *) reg vlg_m_e0; -(* keep *) reg [AW-1:0] vlg_m_a0; -(* keep *) reg [DW-1:0] vlg_m_d0; - - -(* keep *) reg ila_m_e0; -(* keep *) reg [AW-1:0] ila_m_a0; -(* keep *) reg [DW-1:0] ila_m_d0; - -(* keep *) reg vlg_match_ila; -(* keep *) reg ila_match_vlg; - -always @(posedge clk) begin - if(rst) - start_and_on <= 1'b%%%AVOID_ISSUE%%%; - else if(issue) - start_and_on <= 1'b1; -end - -assign vlg_ren_real = vlg_ren & ~compare & start_and_on; -assign vlg_wen_real = vlg_wen & ~compare & start_and_on; -assign ila_ren_real = ila_ren & ~compare & start_and_on; -assign ila_wen_real = ila_wen & ~compare & start_and_on; - - -assign vlg_rdata = vlg_ren_real ? - vlg_m_e0 && vlg_m_a0 == vlg_raddr ? vlg_m_d0 - : - mem[vlg_raddr] : vlg_r_rand_input; - -assign ila_rdata = ila_ren_real ? - ila_m_e0 && ila_m_a0 == ila_raddr ? ila_m_d0 - : - mem[ila_raddr] : ila_r_rand_input; - -always @(posedge clk) begin - if( rst ) begin - vlg_m_e0 <= 1'b0; - end - else begin - if( vlg_m_e0 == 0 && vlg_wen_real) begin - vlg_m_e0 <= 1'b1; - vlg_m_a0 <= vlg_waddr; - vlg_m_d0 <= vlg_wdata; - end - end -end - -always @(posedge clk) begin - if( rst ) begin - ila_m_e0 <= 1'b0; - end - else begin - if( ila_m_e0 == 0 && ila_wen_real) begin - ila_m_e0 <= 1'b1; - ila_m_a0 <= ila_waddr; - ila_m_d0 <= ila_wdata; - end - end -end - -always @(*) begin - vlg_match_ila = 0; - if( vlg_m_e0 ) begin - if(ila_m_e0 == 1 && ila_m_a0 == vlg_m_a0) - vlg_match_ila = ila_m_d0 == vlg_m_d0; - else if(vlg_m_d0 == mem[vlg_m_a0]) - vlg_match_ila = 1; - else - vlg_match_ila = 0; - end - else - vlg_match_ila = 1; -end - -always @(*) begin - ila_match_vlg = 0; - if( ila_m_e0 ) begin - if(vlg_m_e0 == 1 && ila_m_a0 == vlg_m_a0) - ila_match_vlg = ila_m_d0 == vlg_m_d0; - else if(ila_m_d0 == mem[ila_m_a0]) - ila_match_vlg = 1; - else - ila_match_vlg = 0; - end - else - ila_match_vlg = 1; -end - -assign equal = compare && ila_match_vlg && vlg_match_ila; - -endmodule - - )**##**"; - -std::string d1ra = R"**##**( - -// 1R 1W (x2) d=1 AW(V=I) DW(V=I) absmem -// CoSA & Jasper -// --- ra : read abstraction (depth = 1) -// -// Hongce Zhang (hongcez@princeton.edu) - -module absmem_ra( - clk, - rst, - vlg_raddr, - vlg_rdata, - vlg_ren, - vlg_waddr, - vlg_wdata, - vlg_wen, - - vlg_r_rand_input, - - ila_raddr, - ila_rdata, - ila_ren, - ila_waddr, - ila_wdata, - ila_wen, - - ila_r_rand_input, - - compare, - equal, - issue, - read_assume_true - ); - - -parameter AW = 16; -parameter DW = 8; -parameter TTS = 65536; - -input clk; -input rst; - -input [AW-1:0] vlg_raddr; -output [DW-1:0] vlg_rdata; -input vlg_ren; -input [AW-1:0] vlg_waddr; -input [DW-1:0] vlg_wdata; -input vlg_wen; -input [DW-1:0] vlg_r_rand_input; - - -input [AW-1:0] ila_raddr; -output [DW-1:0] ila_rdata; -input ila_ren; -input [AW-1:0] ila_waddr; -input [DW-1:0] ila_wdata; -input ila_wen; -input [DW-1:0] ila_r_rand_input; - -input compare; -output equal; -input issue; -(* keep *) output read_assume_true; - -(* keep *) reg start_and_on; - -wire vlg_ren_real; -wire vlg_wen_real; -wire ila_ren_real; -wire ila_wen_real; - -(* keep *) reg vlg_r_e0; -(* keep *) reg [AW-1:0] vlg_r_a0; -(* keep *) reg [DW-1:0] vlg_r_d0; - - -(* keep *) reg ila_r_e0; -(* keep *) reg [AW-1:0] ila_r_a0; -(* keep *) reg [DW-1:0] ila_r_d0; - -(* keep *) reg vlg_m_e0; -(* keep *) reg [AW-1:0] vlg_m_a0; -(* keep *) reg [DW-1:0] vlg_m_d0; - - -(* keep *) reg ila_m_e0; -(* keep *) reg [AW-1:0] ila_m_a0; -(* keep *) reg [DW-1:0] ila_m_d0; - -(* keep *) reg vlg_match_ila; -(* keep *) reg ila_match_vlg; - -always @(posedge clk) begin - if(rst) - start_and_on <= 1'b%%%AVOID_ISSUE%%%; - else if(issue) - start_and_on <= 1'b1; -end - -assign vlg_ren_real = vlg_ren & ~compare & start_and_on; -assign vlg_wen_real = vlg_wen & ~compare & start_and_on; -assign ila_ren_real = ila_ren & ~compare & start_and_on; -assign ila_wen_real = ila_wen & ~compare & start_and_on; - - -assign vlg_rdata = vlg_ren_real ? ( - (vlg_m_e0 && vlg_m_a0 == vlg_raddr) ? vlg_m_d0 - : vlg_r_rand_input ) : vlg_r_rand_input; - -assign ila_rdata = ila_ren_real ? ( - (ila_m_e0 && ila_m_a0 == ila_raddr) ? ila_m_d0 - : ila_r_rand_input) : ila_r_rand_input; - -always @(posedge clk) begin - if( rst ) begin - vlg_r_e0 <= 1'b0; - end - else begin - //if( vlg_ren_real && ( vlg_r_e0 == 0 || (vlg_r_e0 == 1 && vlg_r_a0 == vlg_raddr) ) ) begin - if( vlg_ren_real && ( vlg_r_e0 == 0) ) begin - vlg_r_e0 <= 1'b1; - vlg_r_a0 <= vlg_raddr; - vlg_r_d0 <= vlg_r_rand_input; // vlg_rdata; - end - end -end - -always @(posedge clk) begin - if( rst ) begin - ila_r_e0 <= 1'b0; - end - else begin - // if( ( ila_ren_real && ( ila_r_e0 == 0 || (ila_r_e0 == 1 && ila_r_a0 == ila_raddr ) ) ) ) - if( ila_ren_real && ( ila_r_e0 == 0) ) begin - ila_r_e0 <= 1'b1; - ila_r_a0 <= ila_raddr; - ila_r_d0 <= ila_r_rand_input; // ila_rdata; - end - /* - else if ( ila_wen_real && ila_r_e0 && ila_r_a0 == ila_waddr ) begin - ila_r_e0 <= ila_r_e0; - ila_r_a0 <= ila_r_a0; - ila_r_d0 <= ila_wdata; - end*/ - end -end - -// we only ensure that the initial read matches, not the read involve the new data (changed by write) -// if you change it, we guarantee nothing - -assign read_assume_true = - (vlg_r_e0 && ila_r_e0 && vlg_r_a0 == ila_r_a0) == 0 || (vlg_r_d0 == ila_r_d0); - -// ------------- WRITE LOGIC ---------------- // - -always @(posedge clk) begin - if( rst ) begin - vlg_m_e0 <= 1'b0; - end - else begin - if( vlg_wen_real && ( vlg_m_e0 == 0 || (vlg_m_e0 == 1'b1 && vlg_m_a0 == vlg_waddr) ) ) begin - vlg_m_e0 <= 1'b1; - vlg_m_a0 <= vlg_waddr; - vlg_m_d0 <= vlg_wdata; - end - end -end - -always @(posedge clk) begin - if( rst ) begin - ila_m_e0 <= 1'b0; - end - else begin - if( ila_wen_real && ( ila_m_e0 == 0 || (ila_m_e0 == 1'b1 && ila_m_a0 == ila_waddr) ) ) begin - ila_m_e0 <= 1'b1; - ila_m_a0 <= ila_waddr; - ila_m_d0 <= ila_wdata; - end - end -end - - -always @(*) begin - vlg_match_ila = 0; - if( vlg_m_e0 ) begin - if(ila_m_e0 == 1 && ila_m_a0 == vlg_m_a0) - vlg_match_ila = ila_m_d0 == vlg_m_d0; - else if(ila_r_e0 == 1 && ila_r_a0 == vlg_m_a0) - vlg_match_ila = ila_r_d0 == vlg_m_d0; - //else if(vlg_m_d0 == mem[vlg_m_a0]) - // vlg_match_ila = 1; - //below is an over-approximation - else - vlg_match_ila = 0; - end - else - vlg_match_ila = 1; -end - -always @(*) begin - ila_match_vlg = 0; - if( ila_m_e0 ) begin - if(vlg_m_e0 == 1 && ila_m_a0 == vlg_m_a0) - ila_match_vlg = ila_m_d0 == vlg_m_d0; - else if(vlg_r_e0 == 1 && vlg_r_a0 == ila_m_a0) - ila_match_vlg = ila_m_d0 == vlg_r_d0; - //else if(ila_m_d0 == mem[ila_m_a0]) - // ila_match_vlg = 1; - else - ila_match_vlg = 0; - end - else - ila_match_vlg = 1; -end - -assign equal = compare && ila_match_vlg && vlg_match_ila; - -endmodule - - - )**##**"; - -void VlgAbsMem::OutputMemFile(std::ostream& os, bool avoid_issue_stage) { - - for (auto&& cl : concrete_level_encountered) { - if (cl == 1) - os << ReplaceAll(d1model, "%%%AVOID_ISSUE%%%", - avoid_issue_stage ? "1" : "0"); - else if (cl == -1) - os << ReplaceAll(d1ra, "%%%AVOID_ISSUE%%%", - avoid_issue_stage ? "1" : "0"); - else - ILA_ASSERT(false) << "depth :" << cl - << " abs mem model is not developed. Future work."; - } -} - -std::set VlgAbsMem::concrete_level_encountered; - -}; // namespace ilang diff --git a/src/vtarget-out/directive.cc b/src/vtarget-out/directive.cc index cdbbe3f04..6e11f2631 100644 --- a/src/vtarget-out/directive.cc +++ b/src/vtarget-out/directive.cc @@ -13,67 +13,7 @@ namespace ilang { #define VLG_TRUE "`true" // ---------------------- class IntefaceDirectiveRecorder -// ------------------------------- // static function -bool IntefaceDirectiveRecorder::beginsWith(const std::string& c, - const std::string& s) { - return StrStartsWith(c, s); -} - -// static function -bool IntefaceDirectiveRecorder::isSpecialInputDir(const std::string& c) { - return beginsWith(c, "**"); -} - -// static function -bool IntefaceDirectiveRecorder::isSpecialInputDirCompatibleWith( - const std::string& c, const SignalInfoBase& vlg_sig) { - ILA_CHECK(isSpecialInputDir(c)); - if (c == "**KEEP**") - return true; - if (c == "**NC**") - return true; - if (c == "**SO**") - return vlg_sig.is_output(); - if (c == "**RESET**" || c == "**NRESET**" || c == "**CLOCK**" || - c == "**START**") - return (vlg_sig.is_input() && vlg_sig.get_width() == 1); - if (beginsWith(c, "**MEM**")) { - auto first_dot_loc = c.find("."); - auto port_name = c.substr(first_dot_loc + 1); - if (beginsWith(port_name, "waddr") || beginsWith(port_name, "wdata") || - beginsWith(port_name, "wen") || beginsWith(port_name, "raddr") || - beginsWith(port_name, "ren")) - return vlg_sig.is_output(); - if (beginsWith(port_name, "rdata")) - return vlg_sig.is_input(); - ILA_ERROR << "Unknown IO directive in refinement relations:" << c; - return false; - } - ILA_ERROR << "Unknown IO directive in refinement relations:" << c; - return false; -} - -// static function -/* -bool IntefaceDirectiveRecorder::interfaceDeclareTop(const std::string & c) { - ILA_CHECK(isSpecialInputDir(c)); - if(c == "**KEEP**") return true; - if(c == "**NC**") return false; - if(c == "**SO**") return true; - if(c == "**RESET**" || c == "**CLOCK**") return false; - if(beginsWith(c, "**MEM**")) { - auto first_dot_loc = c.find("."); - auto port_name = c.substr(first_dot_loc + 1); - if( beginsWith(port_name,"waddr") || beginsWith(port_name,"wdata") || -beginsWith(port_name,"wen") || beginsWith(port_name,"raddr") || -beginsWith(port_name,"ren") ) return false; if( beginsWith(port_name,"rdata") ) - return false; // - ILA_ERROR<<"Unknown IO directive in refinement relations:"< 3) { - ILA_ERROR << "Bad mem directive:" << refstr; - return; - } - if (dirv.size() == 2) - dirv.push_back("0"); // refer to 0 by default - const auto& ila_mem_name = dirv[0]; - const auto& port_name = dirv[1]; - unsigned port_no = StrToInt(dirv[2]); - // add internal wire __MEM_ilaname_no_..._ - // - - auto ila_minfo = mget(ila_mem_name); - if (ila_minfo.first == 0 || ila_minfo.second == 0) { - ILA_ERROR << "No such memory in ila:" << ila_mem_name - << " refered by refinement relation."; - return; - } - auto addr_w = ila_minfo.first; - auto data_w = ila_minfo.second; - - auto new_wire_name = "__MEM_" + - VerilogGeneratorBase::sanitizeName(ila_mem_name) + - "_" + dirv[2] + "_" + port_name; - -#define ADD_PORT_WIRE(name, w, INFO1, INFO2, io, assign, inf_d) \ - do { \ - ILA_ERROR_IF(width != (w)) \ - << INFO1 " width does not match: vlg:" << short_name << "(" << width \ - << ") " \ - << " ila: " << ila_mem_name << "." INFO2 " (" << (w) << ")"; \ - ILA_ERROR_IF(!io) << name " should be an input to the verilog module."; \ - (assign) = new_wire_name; \ - mod_inst_rec.insert({short_name, {(inf_d), new_wire_name}}); \ - internal_wires.push_back({new_wire_name, (w)}); \ - } while (0); - - abs_mems[ila_mem_name].SetDataWidth(data_w); - abs_mems[ila_mem_name].SetAddrWidth(addr_w); - - if (port_name == "rdata") { - ADD_PORT_WIRE("rdata", data_w, "Data", "data", is_input, - abs_mems[ila_mem_name].vlg_rports[port_no].rdata, - inf_dir_t::MEM_R_D); - } else if (port_name == "raddr") { - ADD_PORT_WIRE("raddr", addr_w, "Addr", "addr", is_output, - abs_mems[ila_mem_name].vlg_rports[port_no].raddr, - inf_dir_t::MEM_R_A); - } else if (port_name == "ren") { - ADD_PORT_WIRE("ren", 1, "Enable signal", "en", is_output, - abs_mems[ila_mem_name].vlg_rports[port_no].ren, - inf_dir_t::MEM_R_EN); - } else if (port_name == "wdata") { - ADD_PORT_WIRE("wdata", data_w, "Data", "data", is_output, - abs_mems[ila_mem_name].vlg_wports[port_no].wdata, - inf_dir_t::MEM_W_D); - } else if (port_name == "waddr") { - ADD_PORT_WIRE("waddr", addr_w, "Addr", "addr", is_output, - abs_mems[ila_mem_name].vlg_wports[port_no].waddr, - inf_dir_t::MEM_W_A); - } else if (port_name == "wen") { - ADD_PORT_WIRE("wen", 1, "Enable signal", "en", is_output, - abs_mems[ila_mem_name].vlg_wports[port_no].wen, - inf_dir_t::MEM_W_EN); - } else { - ILA_ERROR << "no such port:" << port_name - << " on built-in mem abstraction for " << ila_mem_name; - } - return; - } else - ILA_ERROR << "Ignoring unknown verilog interface directive:" << refstr; - - // decide how to connect and signals to create - return; - } // end of isSpecialInputDir - - // exists and not special input directive, connected the name they are given. - // this name should be an ila-input, maybe we can check - - if (is_input) { - // TODO: FIXME: NEED TO CHECK w. ILA - // ILA_ERROR_IF( refstr is not an ila input ) - ILA_ERROR_IF(!chk(refstr, vlg_sig)) - << "Uncompatible input refinement:" << refstr << " for " << short_name - << ". Connect anyway. Please check."; - - mod_inst_rec.insert({short_name, {inf_dir_t::INPUT, "__ILA_I_" + refstr}}); - } - if (is_output) { - ILA_ERROR << "Cannot map output signals to ILA input for :" << refstr - << ", left unconnected."; - mod_inst_rec.insert({short_name, inf_connector_t({inf_dir_t::NC, ""})}); - } // ignoring it - // okay we are done now + {short_name, inf_connector_t({inf_dir_t::RESET, "dummy_reset"})}); + } else if (refstr == "**NRESET**") { + ILA_ERROR_IF(!is_input || width != 1) + << "Expecting `" << short_name << "` to be input of width 1"; + if (_reset_vlg) + mod_inst_rec.insert( + {short_name, inf_connector_t({inf_dir_t::RESET, "~rst"})}); + else + mod_inst_rec.insert( + {short_name, inf_connector_t({inf_dir_t::RESET, "~dummy_reset"})}); + } else if (refstr == "**CLOCK**") { + ILA_ERROR_IF(!is_input || width != 1) + << "Expecting `" << short_name << "` to be input of width 1"; + mod_inst_rec.insert( + {short_name, inf_connector_t({inf_dir_t::CLOCK, "clk"})}); + } else if (refstr == "**CUSTOM_INPUT**") { + ILA_CHECK(is_input) << "Cannot assign to output port : " << short_name; + ILA_ERROR_IF(IN(short_name, mod_inst_rec)) << short_name << " has already been connected"; + internal_wires.push_back({"__VLG_II_" + short_name, width}); + mod_inst_rec.insert( + {short_name, + inf_connector_t({inf_dir_t::INPUT, "__VLG_II_" + short_name})}); + } else { + ILA_ASSERT(false) << "Implementation error. Should not be reachable."; + } // decide how to connect and signals to create + return; } // IntefaceDirectiveRecorder::RegisterInterface void IntefaceDirectiveRecorder::Clear(bool reset_vlg) { @@ -378,219 +206,8 @@ void IntefaceDirectiveRecorder::Clear(bool reset_vlg) { input_wires.clear(); internal_wires.clear(); output_wires.clear(); - abs_mems.clear(); - _reset_vlg = reset_vlg; -} -void IntefaceDirectiveRecorder::SetMemName(const std::string& directive, - const std::string& ila_state_name, - bool abs_read) { - - ILA_CHECK(beginsWith(directive, "**")); - if (!beginsWith(directive, "**MEM**")) { - ILA_ERROR << directive << " is not a recognized directive!"; - return; - } - - auto mem_name = directive.substr(7); - auto pos = abs_mems.find(mem_name); - if (pos == abs_mems.end()) { - ILA_INFO << directive << " refers to a new memory!"; - abs_mems.insert(std::make_pair(mem_name, VlgAbsMem())); - pos = abs_mems.find(mem_name); - // return; - } - - pos->second.read_abstract = abs_read; - - if (pos->second.mem_name == "") - pos->second.mem_name = mem_name; - if (pos->second.ila_map_name == "") - pos->second.ila_map_name = ila_state_name; - - // check no duplicate settings - ILA_ERROR_IF(pos->second.mem_name != mem_name) - << "Implementation bug," - << " setting memory abstraction with a different name" - << " old:" << pos->second.mem_name << ", new:" << mem_name; - ILA_ERROR_IF(pos->second.ila_map_name != ila_state_name) - << "Implementation bug," - << " setting memory abstraction with a different name" - << " old:" << pos->second.ila_map_name << ", new:" << ila_state_name; -} - -void IntefaceDirectiveRecorder::SetMemNameAndWidth( - const std::string& directive, const std::string& ila_state_name, - bool abs_read, int ila_addr_width, int ila_data_width) { - - ILA_CHECK(beginsWith(directive, "**")); - if (!beginsWith(directive, "**MEM**")) { - ILA_ERROR << directive << " is not a recognized directive!"; - return; - } - - auto mem_name = directive.substr(7); - auto pos = abs_mems.find(mem_name); - if (pos == abs_mems.end()) { - ILA_INFO << directive << " refers to a new memory!"; - abs_mems.insert(std::make_pair(mem_name, VlgAbsMem())); - pos = abs_mems.find(mem_name); - // return; - } - - pos->second.read_abstract = abs_read; - - if (pos->second.mem_name == "") - pos->second.mem_name = mem_name; - if (pos->second.ila_map_name == "") - pos->second.ila_map_name = ila_state_name; - - // check no duplicate settings - ILA_ERROR_IF(pos->second.mem_name != mem_name) - << "Implementation bug," - << " setting memory abstraction with a different name" - << " old:" << pos->second.mem_name << ", new:" << mem_name; - ILA_ERROR_IF(pos->second.ila_map_name != ila_state_name) - << "Implementation bug," - << " setting memory abstraction with a different name" - << " old:" << pos->second.ila_map_name << ", new:" << ila_state_name; - - ILA_CHECK(ila_addr_width > 0 && ila_data_width > 0); - pos->second.SetAddrWidth(ila_addr_width); - pos->second.SetDataWidth(ila_data_width); -} - -std::string IntefaceDirectiveRecorder::ConnectMemory( - const std::string& directive, const std::string& ila_state_name, - const std::map& rports, - const std::map& wports, int ila_addr_width, - int ila_data_width, bool abs_read) { - ILA_CHECK(beginsWith(directive, "**")); - if (!beginsWith(directive, "**MEM**")) { - ILA_ERROR << directive << " is not a recognized directive!"; - return VLG_TRUE; - } - - auto mem_name = directive.substr(7); - auto pos = abs_mems.find(mem_name); - if (pos == abs_mems.end()) { - ILA_ERROR << directive << " refers to a nonexisting memory!"; - return VLG_TRUE; - } - - // pos->second.read_abstract = abs_read; - SetMemNameAndWidth(directive, ila_state_name, abs_read, ila_addr_width, - ila_data_width); - - // copy the ports - ILA_ERROR_IF(pos->second.ila_rports.size() != 0 || - pos->second.ila_wports.size() != 0) - << mem_name << " seems to have been connected."; - // pos->second.ila_rports = rports; - pos->second.ila_rports.insert(rports.begin(), rports.end()); - // pos->second.ila_wports = wports; - pos->second.ila_wports.insert(wports.begin(), wports.end()); - - return pos->second.MemEQSignalName(); -} // ConnectMemory - -/// Check if some verilog port has been connected, -/// if not, connect it to the wire_name (will not create wire!) -/// if connected, will warn and refuse to connect -/// should be called before GetAbsMemInstString -std::pair -IntefaceDirectiveRecorder::KeepMemoryPorts(const std::string& mem_name, - const std::string& port_name, - bool caller_build_wire) { - -#define check_connect_port(p) \ - if (!(p).empty()) \ - ILA_ERROR << port_name << " has been connected"; \ - else \ - (p) = caller_build_wire ? wire_name : ""; - // set to empty here will cause absmem:CONNECT macro to add wire for it - - auto pos = abs_mems.find(mem_name); - if (pos == abs_mems.end()) { - ILA_ERROR << "No memory named: " << mem_name; - return std::pair( - "KeepMemoryPortsERROR_no_mem_name_" + mem_name, 0); - } - std::string wire_name = - "__MEM_" + VerilogGeneratorBase::sanitizeName(pos->second.ila_map_name) + - "_" + std::to_string(0) + "_" + port_name; - - if (port_name == "raddr") { - check_connect_port(pos->second.vlg_rports[0].raddr); - return std::make_pair(wire_name, pos->second.addr_width); - } else if (port_name == "rdata") { - check_connect_port(pos->second.vlg_rports[0].rdata); - return std::make_pair(wire_name, pos->second.data_width); - } else if (port_name == "ren") { - check_connect_port(pos->second.vlg_rports[0].ren); - return std::make_pair(wire_name, 1); - } else if (port_name == "waddr") { - check_connect_port(pos->second.vlg_wports[0].waddr); - return std::make_pair(wire_name, pos->second.addr_width); - } else if (port_name == "wdata") { - check_connect_port(pos->second.vlg_wports[0].wdata); - return std::make_pair(wire_name, pos->second.data_width); - } else if (port_name == "wen") { - check_connect_port(pos->second.vlg_wports[0].wen); - return std::make_pair(wire_name, 1); - } else - ILA_ERROR << "Unknown port:" << port_name; - return std::pair( - "KeepMemoryPortsERROR_no_port_name_" + port_name, 0); -} - -std::string -IntefaceDirectiveRecorder::GetAbsMemInstString(VerilogGeneratorBase& gen, - const std::string& endCond) { - std::string ret; - for (auto&& m : abs_mems) { - ret += "/*" + m.first + "*/\n"; - ret += m.second.GeneratingMemModuleSignalsInstantiation(gen, endCond); - } - return ret; -} - -void IntefaceDirectiveRecorder::InsertAbsMemAssmpt(assmpt_inserter_t inserter) { - for (auto&& nm_pair : abs_mems) { - for (auto&& assumpt : nm_pair.second.assumpts) - inserter(assumpt); - } -} - -// ------------------------------------------------------------------------ - -// static function -bool StateMappingDirectiveRecorder::isSpecialStateDir(const std::string& c) { - return IntefaceDirectiveRecorder::beginsWith(c, "**"); -} - -/// a function to determine if a state map refstr is special directie (**???) -bool StateMappingDirectiveRecorder::isSpecialStateDirMem(const std::string& c) { - return IntefaceDirectiveRecorder::beginsWith(c, "**MEM**"); -} - -bool StateMappingDirectiveRecorder::isSpecialUnknownFunctionName(const std::string &funcname) { - if (funcname.length() < 11) - return false; - if (!StrStartsWith(funcname, "__unknown__")) - return false; - if (funcname == "__unknown__") - return true; - for (size_t idx = 11; idx < funcname.length(); ++ idx) - if (!isdigit(funcname.at(idx))) - return false; - return true; -} - -bool StateMappingDirectiveRecorder::isSpecialUnknownFunction(const FuncPtr &func_ptr) { - if (func_ptr->arg_num() > 0) - return false; - return isSpecialUnknownFunctionName(func_ptr->name().str()); + _reset_vlg = reset_vlg; } } // namespace ilang diff --git a/src/vtarget-out/gen_util.cc b/src/vtarget-out/gen_util.cc index e2d5b2a54..1cc212c7a 100644 --- a/src/vtarget-out/gen_util.cc +++ b/src/vtarget-out/gen_util.cc @@ -8,11 +8,14 @@ #include +#include #include #include #include #include +#include + namespace ilang { #define VLG_TRUE "`true" @@ -108,166 +111,6 @@ bool VlgSglTgtGen::TryFindVlgState(const std::string& sname) { return false; } -#define SIN(sub, s) (s.find(sub) != std::string::npos) - -/// signals generated in the wrapper, -/// it is normal that you cannot find -/// them in the verilog -std::set wrapper_signals = { - "__START__", "__IEND__", "__ISSUE__", - "__STARTED__", "__RESETED__", "__ENDED__", - "__ENDFLUSH__", "__FLUSHENDED__", "__CYCLE_CNT__"}; - -// for ila state: add __ILA_SO_ -// for verilog signal: keep as it is should be fine -// btw, record all referred vlg name -std::string -VlgSglTgtGen::ModifyCondExprAndRecordVlgName(const VarExtractor::token& t) { - // modify name and ... - const auto& token_tp = t.first; - const auto& sname = t.second; - - if (token_tp == VarExtractor::token_type::UNKN_S) { - ILA_WARN_IF(!IN(sname, wrapper_signals) && !IN(sname, vlg_wrapper.wires)) - << "In refinement relations: unknown reference to name:" << sname - << " keep unchanged."; - return sname; - } else if (token_tp == VarExtractor::token_type::KEEP) - return sname; // NC - else if (token_tp == VarExtractor::token_type::NUM) { - /* - if (_backend == backend_selector::COSA) { - if (SIN("'", sname)) { - auto l = Split(sname, "'"); - - auto& num_l = l.back(); - auto num = num_l.substr(1); // [1:] - int base = 16; - if (num_l[0] == 'd') - base = 10; - else if (num_l[0] == 'h') - base = 16; - else if (num_l[0] == 'b') - base = 2; - else if (num_l[0] == 'o') - base = 8; - else - ILA_ERROR << "unknown base in " << sname << ", assuming 16"; - - unsigned n = StrToInt(num, base); - unsigned int w; - if (l.size() == 2) { - w = StrToInt(l[0]); - } else { - w = ((unsigned int)std::floor(std::log2(n))) + 1; - ILA_WARN << sname << " is considered to be of width " << w; - } - return IntToStr(n) + "_" + IntToStr(w); - } else { - if (SIN("_", sname)) - return sname; // already changed to 0_1 - else { - auto n = StrToInt(sname); - unsigned int w = ((unsigned int)std::floor(std::log2(n))) + 1; - ILA_WARN << sname << " is considered to be of width " << w; - return IntToStr(n) + "_" + IntToStr(w); - } - } - } else if (_backend == backend_selector::JASPERGOLD) { - if (SIN("'", sname)) - return sname; - else { - if (SIN("_", sname)) { - return Split(sname, "_") - .front(); // remove the bitwidth, let jaspergold itself decide - } else - return sname; - } - }*/ - // else -- only leave it here - return sname; // NC - } else if (token_tp == VarExtractor::token_type::ILA_S) { - std::string quote = ""; - auto left_p = sname.find('['); - auto check_s = sname.substr(0, left_p); - auto range_s = left_p != std::string::npos ? sname.substr(left_p) : ""; - // if (_backend == backend_selector::COSA) - // quote = "'"; - // if it refers to ILA state - if (_host->state(check_s)) - return quote + "__ILA_SO_" + check_s + quote + range_s; - // if it uses the reference it self - auto hierName = Split(check_s, "."); - if (hierName.size() == 2) // maybe it contains an unnecessary head - if ((hierName[0] == _ila_mod_inst_name || hierName[0] == "ILA") && - _host->state(hierName[1])) - return quote + "__ILA_SO_" + hierName[1] + quote + range_s; - // should not reachable - ILA_CHECK(false) - << "Implementation bug: should not be reachable. token_tp: ILA_S"; - return sname; - } else if (token_tp == VarExtractor::token_type::ILA_IN) { - auto left_p = sname.find('['); - auto check_s = sname.substr(0, left_p); - auto range_s = left_p != std::string::npos ? sname.substr(left_p) : ""; - - std::string quote = ""; - // if (_backend == backend_selector::COSA) - // quote = "'"; - // if it refers to ILA state - if (_host->input(check_s)) - return quote + "__ILA_I_" + check_s + quote + range_s; - // if it uses the reference it self - auto hierName = Split(check_s, "."); - if (hierName.size() == 2) // maybe it contains an unnecessary head - if ((hierName[0] == _ila_mod_inst_name || hierName[0] == "ILA") && - _host->input(hierName[1])) - return quote + "__ILA_I_" + hierName[1] + quote + range_s; - // should not reachable - ILA_CHECK(false) - << "Implementation bug: should not be reachable. token_tp: ILA_IN"; - return sname; - } else if (token_tp == VarExtractor::token_type::VLG_S) { - - // do nothing for JasperGold - // will not add to the all_referred name, so will not modify verilog - if (_backend == backend_selector::JASPERGOLD) - return sname; - - std::string quote = ""; - auto left_p = sname.find('['); - auto check_s = sname.substr(0, left_p); - auto range_s = left_p != std::string::npos ? sname.substr(left_p) : ""; - auto range_underscore = ReplaceAll(ReplaceAll(range_s, "[", "_"), "]", "_"); - // if (_backend == backend_selector::COSA) - // quote = "'"; - - if (vlg_info_ptr->check_hierarchical_name_type(check_s) != - VerilogInfo::hierarchical_name_type::NONE) { - _all_referred_vlg_names.insert({check_s + range_s, ex_info_t(range_s)}); - auto remove_dot_name = ReplaceAll(check_s, ".", "__DOT__"); - // Convert the check_s to - return quote + remove_dot_name + quote + range_underscore; - } - if (vlg_info_ptr->check_hierarchical_name_type(_vlg_mod_inst_name + "." + - check_s) != - VerilogInfo::hierarchical_name_type::NONE) { - _all_referred_vlg_names.insert( - {_vlg_mod_inst_name + "." + check_s + range_s, ex_info_t(range_s)}); - auto remove_dot_name = ReplaceAll(check_s, ".", "__DOT__"); - return quote + _vlg_mod_inst_name + "__DOT__" + remove_dot_name + quote + - range_underscore; - } - ILA_CHECK(false) - << "Implementation bug: should not be reachable. token_type: VLG_S"; - return sname; - } - ILA_CHECK(false) - << "Implementation bug: should not reachable. Caused by token_type:" - << token_tp; - return sname; -} - // static function unsigned VlgSglTgtGen::TypeMatched(const ExprPtr& ila_var, const SignalInfoBase& vlg_var) { @@ -313,287 +156,440 @@ unsigned VlgSglTgtGen::get_width(const ExprPtr& n) { return VerilogGeneratorBase::get_width(n); } -// static function -bool isEqu(const std::string& c) { return (c.find("=") != std::string::npos); } - -// will create new variables "m?" and return it -// 1. "ila-state":"**MEM**.?" -// 2a. "ila-state":"statename" --> PerStateMap -// 2b. "ila-state":"(cond)&map" --> PerStateMap -// 3. "ila-state":[ "cond&map" ] -// 4. "ila-state":[ {"cond":,"map":}, ] - -// Replace an expr's variable name -std::string VlgSglTgtGen::ReplExpr(const std::string& expr, - bool force_vlg_sts) { - return _vext.Replace(expr, force_vlg_sts, - [this](const VarExtractor::token& t) { - return ModifyCondExprAndRecordVlgName(t); - }); -} - -std::string VlgSglTgtGen::PerStateMap(const std::string& ila_state_name, - const std::string& vlg_st_name) { - if (vlg_st_name.size() == 0) { - ILA_INFO << "Skip mapping ila state:" << ila_state_name; - return VLG_TRUE; +rfmap::RfVarTypeOrig +VlgSglTgtGen::VarTypeCheckForRfExprParsing(const std::string& vname) { + + if (StrStartsWith(vname, "ILA.")) { + rfmap::RfVarTypeOrig ret; + if (TryFindIlaInput(vname)) { + const ExprPtr ila_input_ptr = IlaGetInput(vname.substr(4)); + ret.var_ref_type = rfmap::RfVarTypeOrig::VARTYPE::ILAI; + + ret.type = rfmap::RfMapVarType( + ila_input_ptr->is_bool() ? 1 : ila_input_ptr->sort()->bit_width()); + return ret; + } else if (TryFindIlaState(vname)) { + const ExprPtr ila_sv_ptr = IlaGetState(vname.substr(4)); + ret.var_ref_type = rfmap::RfVarTypeOrig::VARTYPE::ILAS; + if (ila_sv_ptr->is_bool()) + ret.type = rfmap::RfMapVarType(1); + else if (ila_sv_ptr->is_bv()) + ret.type = rfmap::RfMapVarType(ila_sv_ptr->sort()->bit_width()); + else { + ILA_ASSERT(ila_sv_ptr->is_mem()); + ret.type = rfmap::RfMapVarType(ila_sv_ptr->sort()->addr_width(), + ila_sv_ptr->sort()->data_width()); + } + return ret; + } + ILA_ERROR << "Cannot find ila var: " << vname; + return ret; + } // else if + if (StrStartsWith(vname, "RTL.")) { + ILA_ERROR_IF(!TryFindVlgState(vname)) << "Cannot find rtl var: " << vname; + auto sig_info = vlg_info_ptr->get_signal(vname, + refinement_map.width_info, + refinement_map.range_info); + auto aw_range = sig_info.get_addr_range_size(); + auto dw = sig_info.get_width(); + + rfmap::RfVarTypeOrig ret; + ret.var_ref_type = rfmap::RfVarTypeOrig::VARTYPE::RTLV; + if (aw_range == 0) // not an array + ret.type = rfmap::RfMapVarType(dw); + else { + unsigned aw = (unsigned)(std::ceil(std::log2(aw_range))); + // [15:0] -> aw_range == 16 -> 4 -> ceil (4) == 4 + ret.type = rfmap::RfMapVarType(aw, dw); + } + return ret; } - if (isEqu(vlg_st_name)) { // is equ - // not using re here - auto new_expr = ReplExpr(vlg_st_name); + // if(!StrStartsWith(vname,"ILA.") && !StrStartsWith(vname,"RTL.")) + return rfmap::RfVarTypeOrig(); // unknown +} // VarTypeCheckForRfExprParsing - if (_backend == backend_selector::JASPERGOLD and - new_expr.find('[') != new_expr.npos) { - // this is a jasper gold bug - return new_expr; - } +rfmap::VarReplacement +VlgSglTgtGen::CreateVarReplacement(const rfmap::RfVar& var, + bool replace_internal_names) { + const auto n = var->get_name(); - std::string map_sig = new_mapping_id(); - vlg_wrapper.add_wire(map_sig, 1, true); - vlg_wrapper.add_output(map_sig, 1); - add_wire_assign_assumption(map_sig, new_expr, "vmap"); - return map_sig; + rfmap::RfVarTypeOrig tp; + { // retrieve its old type + auto anno = var->get_annotation(); + if (anno) + tp = *anno; } - // else it is a vlg signal name - auto ila_state = TryFindIlaVarName(ila_state_name); - if (!ila_state) - return VLG_TRUE; - if (ila_state->sort()->is_mem()) { - // we need to decide if this memory is internal/external; - bool external = _vlg_cfg.extMem; - if (IN(ila_state_name, supplementary_info.memory_export)) - external = supplementary_info.memory_export.at(ila_state_name); - - if (!external) { // if internal - // if you choose to expand the array then we are able to handle with out - // MEM directive - int addr_range = std::pow(2, ila_state->sort()->addr_width()); // 2^N - int specify_range = asthub::GetMemSize(ila_state); - ILA_ERROR_IF(specify_range > addr_range) - << "For memory state: " << ila_state_name << ", its address width is" - << ila_state->sort()->addr_width() << " which can hold " << addr_range - << " addrs" - << ", but range: " << specify_range - << " is specified with SetEntryNum"; - if (specify_range != 0) - addr_range = specify_range; - // construct expansion expression - std::string map_expr; - for (int idx = 0; idx < addr_range; ++idx) { - if (!map_expr.empty()) - map_expr += "&&"; - map_expr += - "( __ILA_SO_" + ila_state_name + "_" + std::to_string(idx) + - " == " + - ReplExpr(vlg_st_name + "[" + std::to_string(idx) + "]", true) + ")"; - } - std::string map_sig = new_mapping_id(); - vlg_wrapper.add_wire(map_sig, 1, true); - vlg_wrapper.add_output(map_sig, 1); - add_wire_assign_assumption(map_sig, map_expr, "vmap"); - return map_sig; + auto pos_def_var = refinement_map.all_var_def_types.find(n.first); + + if (n.second) { // if it is special name + if (pos_def_var != refinement_map.all_var_def_types.end()) { + tp.var_ref_type = rfmap::RfVarTypeOrig::VARTYPE::DEFINE_VAR; + tp.type = rfmap::RfMapVarType(pos_def_var->second.width); } else { - ILA_ERROR - << "Please use **MEM**.? directive for memory state matching of " - << ila_state_name; - return VLG_TRUE; + auto rtl_ila_tp = VarTypeCheckForRfExprParsing(n.first); + tp = rtl_ila_tp; } - } - // check for state match -- (no '=' inside at this step) - std::string vlg_state_name = vlg_st_name; - if (vlg_state_name.find(".") == std::string::npos && - vlg_state_name.find("#") == std::string::npos) { - vlg_state_name = _vlg_mod_inst_name + "." + vlg_state_name; - } // auto-add module name - - { // handle [] - auto pos = vlg_state_name.find('['); - auto vlg_state_name_wo_idx = vlg_state_name; - if (pos != vlg_state_name.npos) - vlg_state_name_wo_idx = vlg_state_name_wo_idx.substr(0, pos); - - if (vlg_info_ptr->check_hierarchical_name_type(vlg_state_name_wo_idx) != - VerilogInfo::hierarchical_name_type::NONE) { - // if this is truly a state name - auto vlg_sig_info = vlg_info_ptr->get_signal( - vlg_state_name_wo_idx, supplementary_info.width_info); - ILA_ERROR_IF(!TypeMatched(ila_state, vlg_sig_info)) - << "ila state:" << ila_state_name - << " has mismatched type w. verilog signal:" << vlg_state_name_wo_idx; - } else { - ILA_INFO_IF(!S_IN('#', vlg_state_name_wo_idx)) - << "rfmap: treating: " << vlg_state_name_wo_idx - << " as an expression."; + } else { // if it is not special name + auto rtl_ila_tp = VarTypeCheckForRfExprParsing(n.first); + if (!rtl_ila_tp.type.is_unknown()) + tp = rtl_ila_tp; + else if (pos_def_var != refinement_map.all_var_def_types.end()) { + tp.var_ref_type = rfmap::RfVarTypeOrig::VARTYPE::DEFINE_VAR; + tp.type = rfmap::RfMapVarType(pos_def_var->second.width); } } + ILA_WARN_IF(tp.type.is_unknown()) << "type of var: " << (n.second ? "#" : "") + << n.first << " is still unknown."; - // add signal -- account for jg's bug - if (_backend == backend_selector::JASPERGOLD && - vlg_state_name.find('[') != vlg_state_name.npos) - return ReplExpr(vlg_state_name, true) + " == __ILA_SO_" + - ila_state->name().str(); - - std::string map_sig = new_mapping_id(); - vlg_wrapper.add_wire(map_sig, 1, true); - vlg_wrapper.add_output(map_sig, 1); - add_wire_assign_assumption(map_sig, - ReplExpr(vlg_state_name, true) + " == __ILA_SO_" + - ila_state->name().str(), - "vmap"); - return map_sig; -} // PerStateMap - -// ila-state -> ref (json) -// return a verilog verilog, that should be asserted to be true for this purpose -std::string VlgSglTgtGen::GetStateVarMapExpr(const std::string& ila_state_name, - nlohmann::json& m, - bool is_assert) { - if (m.is_null()) - return VLG_TRUE; - if (m.is_string()) { - std::string rfm = m.get(); - if (_sdr.isSpecialStateDir(rfm)) { - // currently we only support **MEM** as state directive - if (!_sdr.isSpecialStateDirMem(rfm)) { - ILA_ERROR << "Unsupported state directive:" << rfm; - return VLG_TRUE; - } - ILA_DLOG("VlgSglTgtGen.GetStateVarMapExpr") - << "map mem:" << ila_state_name; - - bool external = _vlg_cfg.extMem; - if (IN(ila_state_name, supplementary_info.memory_export)) - external = supplementary_info.memory_export.at(ila_state_name); - - ILA_ERROR_IF(!external) - << "Should not use MEM directive since this memory is internal:" - << ila_state_name; - // may be we need to log them here - if (is_assert == false) { - _idr.SetMemName(rfm, ila_state_name, _vtg_config.MemAbsReadAbstraction); - return VLG_TRUE; // no need for assumptions on memory - } - // handle memory: map vlg_ila.ila_wports && vlg_ila.ila_rports with - // _idr.abs_mems + if (tp.var_ref_type == rfmap::RfVarTypeOrig::VARTYPE::RTLV) { - auto ila_state = TryFindIlaVarName(ila_state_name); - if (!ila_state) { - ILA_ERROR << ila_state_name << " does not exist in ILA."; - return VLG_TRUE; - } - if (!ila_state->sort()->is_mem()) { - ILA_ERROR << ila_state_name << " is not memory, not compatible w. " - << rfm; - return VLG_TRUE; - } - // if expand memory, it will not reach this point - // but will on the per_state_map branch - auto mem_eq_assert = _idr.ConnectMemory( - rfm, ila_state_name, vlg_ila.ila_rports[ila_state_name], - vlg_ila.ila_wports[ila_state_name], ila_state->sort()->addr_width(), - ila_state->sort()->data_width(), _vtg_config.MemAbsReadAbstraction); - // wire will be added by the absmem - return mem_eq_assert; - } else { - // return the mapping variable - return PerStateMap(ila_state_name, rfm); + bool is_array = tp.type.is_array(); // you can never connect an array out + if (!replace_internal_names || is_array) { + auto ret_copy = std::make_shared(*var); + ret_copy->set_annotation(std::make_shared(tp)); + return rfmap::VarReplacement(var, ret_copy); } - } /* else */ - if (m.is_array()) { // array of string or array of object/array - std::vector all_mappings; - std::string prev_neg; // make sure it is a priority condition lists - - for (auto& num_item_pair : m.items()) { - auto& item = num_item_pair.value(); - if (item.is_string()) { - auto mapping = ReplExpr(item.get()); - all_mappings.push_back(mapping); - } else if (item.is_array() || - item.is_object()) { // it should only by size of 2 - std::string cond(VLG_TRUE), vmap(VLG_TRUE); - for (const auto& i : (item).items()) { - if (i.key() == "0" || i.key() == "cond") { - if (i.value().is_null()) - continue; - else if (i.value().is_string()) { - cond = ReplExpr(i.value().get()); // set the condtion - continue; - } else { - ILA_ERROR - << "Expecting the first element/`cond` to be a string/null"; - continue; - } - } - if (i.key() == "1" || i.key() == "map") { - if (i.value().is_null()) - continue; - else if (i.value().is_string()) { - vmap = PerStateMap(ila_state_name, i.value().get()); - continue; // set the mapping - } else { - ILA_ERROR - << "Expecting the second element/`map` to be a string/null"; - continue; - } - } - ILA_ERROR << "mapping for statename:" << ila_state_name - << " contains unsupported construct."; - break; - } - // cond ==> vmap i.e. ~cond || vmap - all_mappings.push_back("~ (" + prev_neg + "(" + cond + ") ) || (" + - vmap + ")"); - prev_neg += "~(" + cond + ")&&"; - } else { - ILA_ERROR << "Unable to handle this piece of JSON input:" << item; - return VLG_TRUE; - } - } // for (item in m) - if (all_mappings.size() == 0) { - ILA_ERROR << "Variable mapping for " << ila_state_name << " is empty!"; - return VLG_TRUE; + auto new_name = ReplaceAll(n.first, ".", "__DOT__"); + auto new_node = verilog_expr::VExprAst::MakeSpecialName(new_name); + new_node->set_annotation(std::make_shared(tp)); + return rfmap::VarReplacement(var, new_node); + + } else if (tp.var_ref_type == rfmap::RfVarTypeOrig::VARTYPE::ILAI) { + const auto& ila_sn = n.first; + auto dotpos = ila_sn.find('.'); + ILA_ASSERT(ila_sn.substr(0, dotpos + 1) == "ILA."); + + bool is_array = tp.type.is_array(); // you can never connect an array out + ILA_CHECK(!is_array) + << "Implementation bug: currently does not support array as input"; + + auto new_name = "__ILA_I_" + ila_sn.substr(dotpos + 1); + auto new_node = verilog_expr::VExprAst::MakeSpecialName(new_name); + new_node->set_annotation(std::make_shared(tp)); + return rfmap::VarReplacement(var, new_node); + } else if (tp.var_ref_type == rfmap::RfVarTypeOrig::VARTYPE::ILAS) { + const auto& ila_sn = n.first; + auto dotpos = ila_sn.find('.'); + ILA_ASSERT(ila_sn.substr(0, dotpos + 1) == "ILA."); + + bool is_array = tp.type.is_array(); // you can never connect an array out + // so there should not be such things like: __ILA_SO_array + if (is_array) { // basically no replacement + auto ret_copy = std::make_shared(*var); + ret_copy->set_annotation(std::make_shared(tp)); + return rfmap::VarReplacement(var, ret_copy); } - return "(" + Join(all_mappings, " )&&( ") + ")"; - } // if it is an array + auto new_name = "__ILA_SO_" + ila_sn.substr(dotpos + 1); + auto new_node = verilog_expr::VExprAst::MakeSpecialName(new_name); + new_node->set_annotation(std::make_shared(tp)); + return rfmap::VarReplacement(var, new_node); + } else if (tp.var_ref_type == rfmap::RfVarTypeOrig::VARTYPE::INTERNAL || + tp.var_ref_type == rfmap::RfVarTypeOrig::VARTYPE::DEFINE_VAR) { + ILA_ERROR_IF(StrStartsWith(n.first, "$")) + << "Creating non replace-able var " << n.first; + if (var->get_annotation() == nullptr) { + var->set_annotation(std::make_shared(tp)); + } + return rfmap::VarReplacement(var, var); + } - // fall-through case - ILA_ERROR << "Unable to handle this piece of JSON input:" << m; - return VLG_TRUE; -} // GetStateVarMapExpr + ILA_ERROR << "Unknown how to replace var: " << n.first << " will keep it"; + auto ret_copy = std::make_shared(*var); + ret_copy->set_annotation(std::make_shared(tp)); + return rfmap::VarReplacement(var, ret_copy); +} -void VlgSglTgtGen::handle_start_condition(nlohmann::json& dc) { - if (!dc.is_array()) { - ILA_ERROR << " not enforcing start condition: expect an array of strings."; - return; - } - for (auto&& pr : dc.items()) { - if (!pr.value().is_string()) { - ILA_ERROR - << " not enforcing start condition: expect an array of strings."; - continue; +rfmap::RfExpr VlgSglTgtGen::ReplExpr(const rfmap::RfExpr& in) { + bool replace_dot = _backend != ModelCheckerSelection::JASPERGOLD; + bool expand_quantifier = _backend != ModelCheckerSelection::PONO || + _vtg_config.ForceQuantifierInstantiationInRfExpr; + + rfmap::RfExpr rfin (in); + if(expand_quantifier) + rfin = rfmap::RfExprAstUtility::FindExpandQuantifier(in); + + std::unordered_map vars; + refinement_map.GetVars(rfin, vars); + for (const auto& v : vars) { + rfmap::VarReplacement* repl = refinement_map.CheckReplacement(v.first); + if (repl == NULL) { + rfmap::VarReplacement new_repl = + CreateVarReplacement(v.second, replace_dot); + + ILA_DLOG("gen_util.create_var_replacement") + << new_repl.origvar->to_verilog() << " --> " + << new_repl.newvar->to_verilog(); + + refinement_map.RegisterInternalVariableWithMapping(v.first, new_repl); + repl = refinement_map.CheckReplacement(v.first); } - auto cond = pr.value().get(); - cond = ReplaceAll(ReplaceAll(cond, "$decode$", vlg_ila.decodeNames[0]), - "$valid$", vlg_ila.validName); - add_an_assumption("(~ __START__) || " + ReplExpr(cond), "start_condition"); - // ReplExpr: Yes, you need to translate it to the vlg names + ILA_NOT_NULL(repl); + ILA_DLOG("gen_util.use_var_replacement") + << repl->origvar->to_verilog() << " --> " << repl->newvar->to_verilog(); } -} // handle_start_condition -// use instruction pointer and the rf_cond to get it (no need to provide) -nlohmann::json& VlgSglTgtGen::get_current_instruction_rf() { - if (_instr_ptr == nullptr) - return empty_json; - auto& instrs = rf_cond["instructions"]; - for (auto&& instr : instrs) { - if (instr["instruction"] == _instr_ptr->name().str()) - return instr; + auto new_node = refinement_map.ReplacingRtlIlaVar(rfin, {}); + // AnnotateType requires all + refinement_map.AnnotateType(new_node, {}); + return new_node; +} + +rfmap::RfExpr VlgSglTgtGen::TranslateMap(const rfmap::RfExpr& in, + const std::string& ila_vn) { + if (refinement_map.IsLastLevelBooleanOp(in)) + return in; + auto vnode = rfmap_var("ILA." + ila_vn); + auto eq_node = rfmap_eq(vnode, in); + return eq_node; +} + +rfmap::RfExpr VlgSglTgtGen::condition_map_to_rfexpr( + const std::vector>& cond_map, + const std::string& ila_state_name) { + std::vector all_mappings; + rfmap::RfExpr prev_neg; // make sure it is a priority condition lists + for (const auto& cond_map_pair : cond_map) { + rfmap::RfExpr cond = cond_map_pair.first; + if (prev_neg != nullptr) + cond = rfmap_and(prev_neg, cond); + rfmap::RfExpr single_map = + TranslateMap(cond_map_pair.second, ila_state_name); + all_mappings.push_back(rfmap_imply(cond, single_map)); + if (prev_neg == nullptr) + prev_neg = rfmap_not(cond); + else + prev_neg = rfmap_and(prev_neg, rfmap_not(cond)); + } // end of for each cond_map pair + ILA_CHECK(!all_mappings.empty()); + return rfmap_and(all_mappings); +} // end of condition_map_to_str + +rfmap::RfExpr VlgSglTgtGen::condition_map_bv_to_rfexpr( + const std::vector>& cond_map) { + rfmap::RfExpr ret; + for (auto pos = cond_map.rbegin(); pos != cond_map.rend(); ++pos) { + if (ret == nullptr) + ret = pos->second; + else + ret = rfmap_ite(pos->first, pos->second, ret); } - return empty_json; + return ret; +} // end of condition_map_to_str + +rfmap::RfExpr +VlgSglTgtGen::singlemap_bv_to_rfexpr(const rfmap::SingleVarMap& single_map) { + if (single_map.single_map != nullptr) { + return single_map.single_map; + } else { + return condition_map_bv_to_rfexpr(single_map.cond_map); + } // end map type } +rfmap::RfExpr +VlgSglTgtGen::singlemap_to_rfexpr(const rfmap::SingleVarMap& single_map, + const std::string& ila_state_name) { + if (single_map.single_map != nullptr) { + return (TranslateMap(single_map.single_map, ila_state_name)); + } else { + auto map_str = condition_map_to_rfexpr(single_map.cond_map, ila_state_name); + return (map_str); + } // end map type +} // non_mem_map_to_str + +// compared to Gen_varmap_assumpt_assert +// problem_name, true_for_assumpt_false_for_assert +// prefix, suffix are all fixed +void VlgSglTgtGen::Gen_input_map_assumpt(const std::string& ila_input_name, + const rfmap::IlaVarMapping& imap, + const std::string& problem_name) { + + bool is_mem = _host->input(ila_input_name)->is_mem(); + ILA_ERROR_IF(is_mem) << "Mem as input is not supported yet"; + + ILA_ERROR_IF(imap.type == rfmap::IlaVarMapping::StateVarMapType::EXTERNMEM) + << "ila sv " << ila_input_name << " cannot be mapped as external mem!"; + // NOTE: non_mem_map_to_str will use translate map + // but it should be able to distinguish input from state var + auto map_rfexpr = singlemap_to_rfexpr(imap.single_map, ila_input_name); + add_an_assumption(rfmap_imply(rfmap_var("decode"), map_rfexpr), problem_name); +} + +void VlgSglTgtGen::Gen_varmap_assumpt_assert( + const std::string& ila_state_name, const rfmap::IlaVarMapping& vmap, + const std::string& problem_name, bool true_for_assumpt_false_for_assert) { + // NOTE: prefix has ( ~ __START__ || ... + // and suffix has .. ) + +#define ADD_CONSTR(p1) \ + do { \ + if (true_for_assumpt_false_for_assert) \ + add_an_assumption(rfmap_imply(rfmap_var("decode"), (p1)), problem_name); \ + else \ + add_an_assertion(rfmap_imply(rfmap_var("commit"), (p1)), problem_name); \ + } while (0) + + bool is_mem = _host->state(ila_state_name)->is_mem(); + if (vmap.type != rfmap::IlaVarMapping::StateVarMapType::EXTERNMEM) { + auto map_str = singlemap_to_rfexpr(vmap.single_map, ila_state_name); + ADD_CONSTR(map_str); + } else { + // if(vmap.type == rfmap::IlaVarMapping::StateVarMapType::EXTERNMEM) { + // TODO: (note: multiple ports!) + // assume : START |-> + // ( ila.ren && rtl.renexpr && (ila.raddr == rtl.raddrexpr) |-> + // (ila.rdata === rtl.rdataexpr) ) + + ILA_ERROR_IF(!is_mem) << "ila sv " << ila_state_name << " is not memory!"; + + if (true_for_assumpt_false_for_assert) { + // mem read assumption + if (vlg_ila.ila_rports.find(ila_state_name) != vlg_ila.ila_rports.end()) { + const auto& read_ports = vlg_ila.ila_rports.at(ila_state_name); + unsigned rfmap_node_idx = 0; + + for (const auto& rport : read_ports) { + size_t no = rport.first; + + auto ila_raddr = rfmap_var("__IMEM_" + ila_state_name + "_" + + IntToStr(no) + "_raddr"); + auto ila_rdata = rfmap_var("__IMEM_" + ila_state_name + "_" + + IntToStr(no) + "_rdata"); + + while (!(vmap.externmem_map.at(rfmap_node_idx).rport_mapped) && + rfmap_node_idx < vmap.externmem_map.size()) + ++rfmap_node_idx; + + ILA_ERROR_IF(rfmap_node_idx >= vmap.externmem_map.size()) + << "#ila.read-port=" << read_ports.size() + << " does not match #rfmap.read-port" + << ", and this is a mismatch for sname:" << ila_state_name; + + const auto& rfmap_rport = vmap.externmem_map.at(rfmap_node_idx); + + // expect bit-vector rather than booleans + auto rtl_ren = singlemap_bv_to_rfexpr(rfmap_rport.ren_map); + auto rtl_raddr = singlemap_bv_to_rfexpr(rfmap_rport.raddr_map); + auto rtl_rdata = singlemap_bv_to_rfexpr(rfmap_rport.rdata_map); + + auto constr = + rfmap_imply(rfmap_and({rtl_ren, rfmap_eq(ila_raddr, rtl_raddr)}), + rfmap_eq(ila_rdata, rtl_rdata)); + + ADD_CONSTR(constr); + + ++rfmap_node_idx; + + } // for each read port + } // if there is such port + } else { + // assert : IEND |-> + // ( ila.wen_d1 == rtl.wenexpr && ( ila.wen |-> + // (ila.wdata_d1 == rtl.wdataexpr) && (ila.waddr_d1 == + // rtl.waddrexpr) ) ) + + // mem write assertion + // vlg_ila.ila_wports + if (vlg_ila.ila_wports.find(ila_state_name) != vlg_ila.ila_wports.end()) { + const auto& write_ports = vlg_ila.ila_wports.at(ila_state_name); + unsigned rfmap_node_idx = 0; + + for (const auto& wport : write_ports) { + // the reason for _d1: see ConstructWrapper_get_ila_module_inst + // in single_target_connect.cc + size_t no = wport.first; + auto ila_wen = rfmap_var("__IMEM_" + ila_state_name + "_" + + IntToStr(no) + "_wen" + "_d1"); + auto ila_waddr = rfmap_var("__IMEM_" + ila_state_name + "_" + + IntToStr(no) + "_waddr" + "_d1"); + auto ila_wdata = rfmap_var("__IMEM_" + ila_state_name + "_" + + IntToStr(no) + "_wdata" + "_d1"); + + while (!(vmap.externmem_map.at(rfmap_node_idx).wport_mapped) && + rfmap_node_idx < vmap.externmem_map.size()) + ++rfmap_node_idx; + + ILA_ERROR_IF(rfmap_node_idx >= vmap.externmem_map.size()) + << "#ila.write-port=" << write_ports.size() + << " does not match #rfmap.write-port" + << ", and this is a mismatch for sname:" << ila_state_name; + + const auto& rfmap_wport = vmap.externmem_map.at(rfmap_node_idx); + + auto rtl_wen = singlemap_bv_to_rfexpr(rfmap_wport.wen_map); + auto rtl_waddr = singlemap_bv_to_rfexpr(rfmap_wport.waddr_map); + auto rtl_wdata = singlemap_bv_to_rfexpr(rfmap_wport.wdata_map); + + auto constr = rfmap_and( + rfmap_eq(ila_wen, rtl_wen), + rfmap_imply(ila_wen, rfmap_and(rfmap_eq(ila_waddr, rtl_waddr), + rfmap_eq(ila_wdata, rtl_wdata)))); + + ADD_CONSTR(constr); + + ++rfmap_node_idx; + } // for each write port + } // end of if wport found + } // end of if assume else assert + } +#undef ADD_CONSTR +} // end of Gen_varmap_assumpt_assert + +void VlgSglTgtGen::handle_start_condition( + const std::vector& dc) { + for (const auto& c : dc) { + // cond = ReplaceAll(ReplaceAll(cond, "$decode", vlg_ila.decodeNames[0]), + // "$valid", vlg_ila.validName); + add_an_assumption(rfmap_imply(rfmap_var("__START__"), c), + "start_condition"); + } +} // handle_start_condition + +/// register a reg in refinement_map.all_var_def_type +void VlgSglTgtGen::rfmap_add_internal_reg(const std::string& n, + unsigned width) { + rfmap::TypedVerilogRefinementMap::VarDef def; + def.type = rfmap::TypedVerilogRefinementMap::VarDef::var_type::REG; + def.width = width; + refinement_map.all_var_def_types.emplace(n, def); +} + +/// register a wire in refinement_map.all_var_def_type +void VlgSglTgtGen::rfmap_add_internal_wire(const std::string& n, + unsigned width) { + rfmap::TypedVerilogRefinementMap::VarDef def; + def.type = rfmap::TypedVerilogRefinementMap::VarDef::var_type::WIRE; + def.width = width; + refinement_map.all_var_def_types.emplace(n, def); +} + +/// register a replacement in refinement_map +/// this will affect ReplExpr's behavior +/// (Note 1: ReplExpr will also create replacement, but it will not use +/// this function. 2: will require that the new one has been registered +/// in refinement_map.all_var_def_type) +/// !!! should only be used to add +/// decode -> __START__ +/// commit -> __IEND__ +/// $decode -> vlg_ila.decode_signal +/// $valid -> vlg_ila.valid_signal +/// !!! whose var_def are include in refinement_map + +void VlgSglTgtGen::rfmap_add_replacement(const std::string& old, + const std::string& n) { + auto def_pos = refinement_map.all_var_def_types.find(n); + ILA_CHECK(def_pos != refinement_map.all_var_def_types.end()); + auto oldexpr = rfmap_var(old); + auto newexpr = rfmap_var(n); + auto tp = std::make_shared(); + tp->type = rfmap::RfMapVarType(def_pos->second.width); + tp->var_ref_type = rfmap::RfVarTypeOrig::VARTYPE::INTERNAL; + newexpr->set_annotation(tp); + refinement_map.RegisterInternalVariableWithMapping( + old, rfmap::VarReplacement(oldexpr, newexpr)); +} // rfmap_add_replacement + }; // namespace ilang diff --git a/src/vtarget-out/inv-syn/CMakeLists.txt b/src/vtarget-out/inv-syn/CMakeLists.txt index 7afb999ae..55f6b41ca 100644 --- a/src/vtarget-out/inv-syn/CMakeLists.txt +++ b/src/vtarget-out/inv-syn/CMakeLists.txt @@ -5,15 +5,10 @@ target_sources(${ILANG_LIB_NAME} PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/cex_extract.cc - ${CMAKE_CURRENT_SOURCE_DIR}/rel_chc.cc ${CMAKE_CURRENT_SOURCE_DIR}/inv_obj.cc ${CMAKE_CURRENT_SOURCE_DIR}/inv_cnf.cc ${CMAKE_CURRENT_SOURCE_DIR}/inv_abc_parse.cc - ${CMAKE_CURRENT_SOURCE_DIR}/inv_syn_cegar.cc ${CMAKE_CURRENT_SOURCE_DIR}/grain_inv_parse.cc - ${CMAKE_CURRENT_SOURCE_DIR}/vtarget_gen_inv_chc.cc - ${CMAKE_CURRENT_SOURCE_DIR}/vtarget_gen_inv_abc.cc - ${CMAKE_CURRENT_SOURCE_DIR}/vtarget_gen_inv_enhance.cc ) diff --git a/src/vtarget-out/inv-syn/cex_extract.cc b/src/vtarget-out/inv-syn/cex_extract.cc index e4396335e..336a79a19 100644 --- a/src/vtarget-out/inv-syn/cex_extract.cc +++ b/src/vtarget-out/inv-syn/cex_extract.cc @@ -172,7 +172,7 @@ CexExtractor::CexExtractor(const std::string& vcd_file_name, parse_from(vcd_file_name, scope, is_reg, reg_only); } -/// create from a existing file +/// create from an existing file CexExtractor::CexExtractor(const std::string& fn) { std::ifstream fin(fn); if (!fin.is_open()) { @@ -200,10 +200,9 @@ CexExtractor::CexExtractor(const std::string& fn) { std::string CexExtractor::GenInvAssert(const std::string& prefix, const std::set& focus_name) const { - - std::string ret = "(1'b1 == 1'b1)"; // true + std::string ret; for (auto&& nv : cex) { - if (!cex_is_reg.at(nv.first)) + if (!cex_is_reg.at(nv.first)) // skipping those that are not registers continue; auto fullname = prepend(prefix, ReplaceAll(nv.first, "[0:0]", "")); auto check_name = fullname; // remove further of [][:] @@ -212,7 +211,10 @@ CexExtractor::GenInvAssert(const std::string& prefix, check_name = check_name.substr(0, pos); if (!focus_name.empty() && !IN(check_name, focus_name)) continue; - ret += "\n&& (" + fullname + " == " + nv.second + ")"; + if (ret.empty()) + ret = "(" + fullname + " == " + nv.second + ")"; + else + ret += "\n&& (" + fullname + " == " + nv.second + ")"; } return ret; } diff --git a/src/vtarget-out/inv-syn/grain_inv_parse.cc b/src/vtarget-out/inv-syn/grain_inv_parse.cc index fd4c2b264..15bcb5fc1 100644 --- a/src/vtarget-out/inv-syn/grain_inv_parse.cc +++ b/src/vtarget-out/inv-syn/grain_inv_parse.cc @@ -71,7 +71,6 @@ bool GrainInvariantParser::ParseInvResultFromFile(const std::string& fname) { // -------------------------CALL BACK // FUNS-------------------------------------------------------------------- - /// this is actually declare variables void GrainInvariantParser::declare_function(const std::string& name, SortPtrT sort) { @@ -104,27 +103,26 @@ void GrainInvariantParser::declare_function(const std::string& name, } else { converted_name = "__TOP_dot_" + vlg_name + "__"; } - free_vars.insert(std::make_pair(converted_name, get_sort(sort).GetBoolBvWidth())); + free_vars.insert( + std::make_pair(converted_name, get_sort(sort).GetBoolBvWidth())); } else // else do not convert converted_name = vlg_name; } // save it term_pool.push_back(SmtTermInfoVerilog(converted_name, get_sort(sort), this)); - quantifier_def_stack.back().emplace(name, term_pool.size()-1); + quantifier_def_stack.back().emplace(name, term_pool.size() - 1); } // declare_function // --------------------- DISABLE THESE FUNCTIONS ------------------------ // /// call back function to handle (forall -GrainInvariantParser::TermPtrT -GrainInvariantParser::push_quantifier_scope() { +GrainInvariantParser::TermPtrT GrainInvariantParser::push_quantifier_scope() { ILA_CHECK(false) << "push_quantifier_scope should not appear in Grain CHC result"; return 0; } /// call back function to handle ) of forall -GrainInvariantParser::TermPtrT -GrainInvariantParser::pop_quantifier_scope() { +GrainInvariantParser::TermPtrT GrainInvariantParser::pop_quantifier_scope() { ILA_CHECK(false) << "pop_quantifier_scope should not appear in Grain CHC result"; return 0; @@ -145,10 +143,9 @@ void GrainInvariantParser::declare_quantified_variable(const std::string& name, /// or (pred (pred state)) ... you need to pass the right instance name allow /// side GrainInvariantParser::TermPtrT -GrainInvariantParser::mk_function( - const std::string& name, SortPtrT sort, - const std::vector& idx, - const std::vector& args) { +GrainInvariantParser::mk_function(const std::string& name, SortPtrT sort, + const std::vector& idx, + const std::vector& args) { // we don't really rely on the sort here: actually it should be NULL ILA_DLOG("GrainInvariantParser.mk_function") << "make func:" << name << ", #arg" << args.size() << std::endl; @@ -165,11 +162,10 @@ GrainInvariantParser::mk_function( return 0; // should not be reachable } // mk_function -void GrainInvariantParser::define_function( - const std::string& func_name, - const std::vector& args, - SortPtrT ret_type, - TermPtrT func_body) { +void GrainInvariantParser::define_function(const std::string& func_name, + const std::vector& args, + SortPtrT ret_type, + TermPtrT func_body) { ILA_CHECK(false) << "define_function should not appear in Grain CHC result, func:" << func_name; diff --git a/src/vtarget-out/inv-syn/inv_abc_parse.cc b/src/vtarget-out/inv-syn/inv_abc_parse.cc index 0d3193b59..f3f8801ad 100644 --- a/src/vtarget-out/inv-syn/inv_abc_parse.cc +++ b/src/vtarget-out/inv-syn/inv_abc_parse.cc @@ -64,12 +64,12 @@ void AbcInvariantParser::parseAigerResultWoGLA( const auto new_name = vec.at(3) + "[" + bit_no + ":" + bit_no + "]"; const auto blif_ref_name = vec.at(3) + "[" + bit_no + "]"; ILA_CHECK(aig_state_order.size() == latch_no || - aig_state_order.size() == latch_no + 1) + aig_state_order.size() == latch_no + 1) << new_name << " " << latch_no << " " << aig_state_order.size(); if (IN(blif_ref_name, blif_valid_state_names) || (IN(vec.at(3), blif_valid_state_names) && bit_no == "0")) { ILA_CHECK(aig_state_order.size() == - latch_no); // insert to the right index + latch_no); // insert to the right index aig_state_order.push_back(new_name); aig_literal.push_back(std::make_pair(vec.at(3), StrToInt(bit_no))); } @@ -102,7 +102,7 @@ void AbcInvariantParser::parseAigerResultWoGLA( unsigned long long flopno = flop >> 1; std::string literal; ILA_CHECK(aig_state_order.size() >= - flopno) // remeber : the last one should be one + flopno) // remeber : the last one should be one << "Referring #" << flopno << " flop, while size of blifstates:" << aig_state_order.size(); @@ -155,7 +155,7 @@ void AbcInvariantParser::parseAigerResultWoGLA( // void the cube if abnormal if (remove_this_cube) // cube_has_abnormal_var || cube = "1'b0"; // cube = "1'b0"; // under-approximate it : total - // under-approximate + // under-approximate else { // if at least the cube has a normal var, it is a normal cube has_a_normal_cube = true; // only if this cube is not removed, we will add it @@ -223,12 +223,12 @@ void AbcInvariantParser::parseAigerResultWithGLA( const auto new_name = vec.at(3) + "[" + bit_no + ":" + bit_no + "]"; const auto blif_ref_name = vec.at(3) + "[" + bit_no + "]"; ILA_CHECK(aig_state_order.size() == latch_no || - aig_state_order.size() == latch_no + 1) + aig_state_order.size() == latch_no + 1) << new_name << " " << latch_no << " " << aig_state_order.size(); if (IN(blif_ref_name, blif_valid_state_names) || (IN(vec.at(3), blif_valid_state_names) && bit_no == "0")) { ILA_CHECK(aig_state_order.size() == - latch_no); // insert to the right index + latch_no); // insert to the right index aig_state_order.push_back(new_name); aig_literal.push_back(std::make_pair(vec.at(3), StrToInt(bit_no))); } @@ -336,7 +336,7 @@ void AbcInvariantParser::parseAigerResultWithGLA( // void the cube if abnormal if (remove_this_cube) // cube_has_abnormal_var || cube = "1'b0"; // cube = "1'b0"; // under-approximate it : total - // under-approximate + // under-approximate else { // if at least the cube has a normal var, it is a normal cube has_a_normal_cube = true; // only if this cube is not removed, we will add it @@ -469,7 +469,7 @@ void AbcInvariantParser::parse(const std::string& blif_name, // void the cube if abnormal if (remove_this_cube) // cube_has_abnormal_var || cube = "1'b0"; // cube = "1'b0"; // under-approximate it : total - // under-approximate + // under-approximate else { // if at least the cube has a normal var, it is a normal cube has_a_normal_cube = true; // only if this cube is not removed, we will add it @@ -610,7 +610,7 @@ void AbcInvariantParser::parse(const std::string& blif_name, // void the cube if abnormal if (remove_this_cube) // cube_has_abnormal_var || cube = "1'b0"; // cube = "1'b0"; // under-approximate it : total - // under-approximate + // under-approximate else { has_a_normal_cube = true; if (parse_result.empty()) diff --git a/src/vtarget-out/inv-syn/inv_obj.cc b/src/vtarget-out/inv-syn/inv_obj.cc index 7734c69b7..a0cebf209 100644 --- a/src/vtarget-out/inv-syn/inv_obj.cc +++ b/src/vtarget-out/inv-syn/inv_obj.cc @@ -113,10 +113,9 @@ bool InvariantObject::AddInvariantFromChcResultFile( smt_formula_vec.push_back(raw_smt); for (auto&& name_vlg_pair : parser.GetLocalVarDefs()) { - const auto & t = parser.get_term(name_vlg_pair.second); - inv_extra_vlg_vars.push_back( - std::make_tuple(name_vlg_pair.first, t._translate, - t._type.GetBoolBvWidth())); + const auto& t = parser.get_term(name_vlg_pair.second); + inv_extra_vlg_vars.push_back(std::make_tuple( + name_vlg_pair.first, t._translate, t._type.GetBoolBvWidth())); } for (auto&& name_w_pair : parser.GetFreeVarDefs()) { if (IN(name_w_pair.first, inv_extra_free_vars)) @@ -155,10 +154,9 @@ void InvariantObject::AddInvariantFromGrainResultFile( smt_formula_vec.push_back(""); // although we get it, we remove it here for (auto&& name_vlg_pair : parser.GetLocalVarDefs()) { - const auto & t = parser.get_term(name_vlg_pair.second); - inv_extra_vlg_vars.push_back( - std::make_tuple(name_vlg_pair.first, t._translate, - t._type.GetBoolBvWidth())); + const auto& t = parser.get_term(name_vlg_pair.second); + inv_extra_vlg_vars.push_back(std::make_tuple( + name_vlg_pair.first, t._translate, t._type.GetBoolBvWidth())); } for (auto&& name_w_pair : parser.GetFreeVarDefs()) { if (IN(name_w_pair.first, inv_extra_free_vars)) diff --git a/src/vtarget-out/inv-syn/inv_syn_cegar.cc b/src/vtarget-out/inv-syn/inv_syn_cegar.cc deleted file mode 100644 index 10387a241..000000000 --- a/src/vtarget-out/inv-syn/inv_syn_cegar.cc +++ /dev/null @@ -1,936 +0,0 @@ -/// \file Source for invariant synthesis --- using CEGAR loop -// Hongce Zhang - -#include -#ifdef INVSYN_INTERFACE - -#include -#include -#include -#include -#include -#include -#include - -#include - -namespace ilang { - -static std::string select_script_to_run(const std::vector& scripts, - const std::string& sel) { - ILA_CHECK(!sel.empty()) << "no selection is provided in RunVerifAuto"; - std::vector sels; - for (auto&& sc : scripts) - if (S_IN(sel, sc)) - sels.push_back(sc); - ILA_CHECK(!sels.empty()) << "Auto run: no selection!"; - if (sels.size() > 1) { - ILA_ERROR << "Multi scripts selected!"; - for (auto&& sc : sels) - ILA_ERROR << sc; - ILA_CHECK(false); - } - return sels[0]; -} - -// problem: you cannot create and keep the objs -// so you need to keep the infos -InvariantSynthesizerCegar::InvariantSynthesizerCegar( - const std::vector& implementation_include_path, - const std::vector& implementation_srcs, - const std::string& implementation_top_module, - const std::string& refinement_variable_mapping, - const std::string& refinement_conditions, const std::string& output_path, - const InstrLvlAbsPtr& ila_ptr, verify_backend_selector vbackend, - synthesis_backend_selector sbackend, const vtg_config_t& vtg_config, - const VerilogGenerator::VlgGenConfig& config) - : status(cegar_status::NEXT_V), bad_state(false), round_id(0), - // book-keeping - implementation_incl_path(implementation_include_path), - implementation_srcs_path(implementation_srcs), - implementation_top_module_name(implementation_top_module), - refinement_variable_mapping_path(refinement_variable_mapping), - refinement_condition_path(refinement_conditions), - _output_path(output_path), _host(ila_ptr), v_backend(vbackend), - s_backend(sbackend), _vtg_config(vtg_config), _vlg_config(config), - // ------------ statistics bookkeeping --------------- // - eqcheck_time(0), inv_validate_time(0), inv_proof_attempt_time(0), - inv_syn_time(0), inv_enhance_time(0), total_grain_cand(0) { - // detect some wrong settings here - if (vbackend != verify_backend_selector::COSA) { - ILA_ERROR << "Implementation bug: currently only support COSA."; - bad_state = true; - return; - } - // BUG: should also consider Yosys single inv? - - // we need to have the vcd generated - _vtg_config.CosaGenTraceVcd = true; - // for other backend, enable similar options - - current_inv_type = cur_inv_tp::NONE; - -} // end of constructor - -bool InvariantSynthesizerCegar::check_in_bad_state() const { - ILA_ERROR_IF(bad_state) << "In bad state, cannot proceed."; - return bad_state; -} - -// -------------------------------- VERIFICATION TARGETS -// ------------------------------------------- // - -/// to generate a target to validate the given and synthesize invariants and -/// guessed ones -void InvariantSynthesizerCegar::GenerateInvariantVerificationTarget() { - if (check_in_bad_state()) - return; - - // to send in the invariants - advanced_parameters_t adv_param; - adv_param._inv_obj_ptr = &inv_obj; - adv_param._candidate_inv_ptr = &inv_candidate; - - auto inv_gen_vtg_config = _vtg_config; - inv_gen_vtg_config.target_select = inv_gen_vtg_config.INV; - // no overwite - // inv_gen_vtg_config.ValidateSynthesizedInvariant = - // vtg_config_t::_validate_synthesized_inv::ALL; // overwrite - - VlgVerifTgtGen vg(implementation_incl_path, // include - implementation_srcs_path, // sources - implementation_top_module_name, // top_module_name - refinement_variable_mapping_path, // variable mapping - refinement_condition_path, // conditions - _output_path, // output path - _host, // ILA - v_backend, // verification backend setting - inv_gen_vtg_config, // target configuration - _vlg_config, // verilog generator configuration - &adv_param // advanced parameter - ); - - vg.GenerateTargets(); -} - -// the reason we need to do this is that we need to know -// in the verilog design, which is (true)reg, which is not (true)reg -void InvariantSynthesizerCegar::GenerateTargetAndExtractSmt() { - // generate a target -- based on selection - if (check_in_bad_state()) - return; - - // to send in the invariants - advanced_parameters_t adv_param; - adv_param._inv_obj_ptr = NULL; - adv_param._candidate_inv_ptr = NULL; - - VlgVerifTgtGen vg( - implementation_incl_path, // include - implementation_srcs_path, // sources - implementation_top_module_name, // top_module_name - refinement_variable_mapping_path, // variable mapping - refinement_condition_path, // conditions - _output_path, // output path - _host, // ILA - verify_backend_selector::YOSYS, // verification backend setting - _vtg_config, // target configuration - _vlg_config, // verilog generator configuration - &adv_param // advanced parameter - ); - - // design_smt_info = vg.GenerateSmtTargets(); -} - -unsigned -InvariantSynthesizerCegar::QueryRtlStateWidth(const std::string& name) const { - if (design_smt_info == nullptr) - return 0; - const auto& sts = design_smt_info->get_var_idx(); - auto pos = sts.find(name); - if (pos == sts.end()) - return 0; - return pos->second->_type.GetBoolBvWidth(); -} - -// to do things separately, you can provide the run function yourself -// or even do it step by step -/// to generate targets using the current invariants -void InvariantSynthesizerCegar::GenerateVerificationTarget() { - // generate a target -- based on selection - if (check_in_bad_state()) - return; - ILA_WARN_IF(status != cegar_status::NEXT_V) - << "CEGAR-loop: repeated verification step."; - - // to send in the invariants - advanced_parameters_t adv_param; - adv_param._inv_obj_ptr = &inv_obj; - adv_param._candidate_inv_ptr = &inv_candidate; - - VlgVerifTgtGen vg(implementation_incl_path, // include - implementation_srcs_path, // sources - implementation_top_module_name, // top_module_name - refinement_variable_mapping_path, // variable mapping - refinement_condition_path, // conditions - _output_path, // output path - _host, // ILA - v_backend, // verification backend setting - _vtg_config, // target configuration - _vlg_config, // verilog generator configuration - &adv_param // advanced parameter - ); - - vg.GenerateTargets(); - - vlg_mod_inst_name = vg.GetVlgModuleInstanceName(); - inv_obj.set_dut_inst_name(vlg_mod_inst_name); - inv_candidate.set_dut_inst_name(vlg_mod_inst_name); - - runnable_script_name = vg.GetRunnableScriptName(); - if (additional_width_info.empty()) - additional_width_info = vg.GetSupplementaryInfo().width_info; - - status = cegar_status::V_RES; -} - -/// to generate targets using the provided invariants -void InvariantSynthesizerCegar::GenerateVerificationTarget( - const std::vector& invs) { - for (auto&& inv : invs) - inv_obj.AddInvariantFromVerilogExpr(std::to_string(round_id), inv); - GenerateVerificationTarget(); -} // to generate targets using the provided invariants - -// -------------------------------- CHC SYNTHESIS TARGETS -// ------------------------------------------- // - -/// to generate synthesis target -void InvariantSynthesizerCegar::GenerateSynthesisTarget() { - // generate a target -- based on selection - if (check_in_bad_state()) - return; - ILA_WARN_IF(status != cegar_status::NEXT_S) - << "CEGAR-loop: not expecting synthesis step."; - - // to send in the invariants - advanced_parameters_t adv_param; - adv_param._inv_obj_ptr = &inv_obj; - adv_param._candidate_inv_ptr = NULL; - adv_param._cex_obj_ptr = cex_extract.get(); - - VlgVerifTgtGen vg( - implementation_incl_path, // include - implementation_srcs_path, // sources - implementation_top_module_name, // top_module_name - refinement_variable_mapping_path, // variable mapping - refinement_condition_path, // conditions - _output_path, // output path - _host, // ILA - verify_backend_selector::YOSYS, // verification backend setting - _vtg_config, // target configuration - _vlg_config, // verilog generator configuration - &adv_param // advanced parameter - ); - - if (s_backend == synthesis_backend_selector::ABC) { - vg.GenerateInvSynTargetsAbc(_vtg_config.AbcUseGla, _vtg_config.AbcUseCorr, - _vtg_config.AbcUseAiger); - current_inv_type = cur_inv_tp::CEGAR_ABC; - } else { - design_smt_info = vg.GenerateInvSynTargets(s_backend); // general chc - current_inv_type = s_backend == synthesis_backend_selector::GRAIN - ? cur_inv_tp::GRAIN_CHC - : cur_inv_tp::CHC; - } - - runnable_script_name = vg.GetRunnableScriptName(); - - status = cegar_status::S_RES; - -} // GenerateSynthesisTarget - -static int inline retrieveColonEol(const std::string& msg, - const std::string& label) { - size_t pos_1, endl_1; - pos_1 = msg.find(label); - endl_1 = msg.find('\n', pos_1); - return StrToInt(msg.substr(pos_1 + label.length(), endl_1)); -} - -const InvariantInCnf& InvariantSynthesizerCegar::GetCurrentCnfEnhance() const { - return inv_cnf; -} -/// merge cnfs -void InvariantSynthesizerCegar::MergeCnf( - const InvariantInCnf& incremental_cnf) { - inv_cnf.InsertClauseIncremental(incremental_cnf); -} - -/// extra variable for enhancement, so not really a cnf -void InvariantSynthesizerCegar::ExtractInvariantVarForEnhance( - size_t inv_idx, InvariantInCnf& incremental_cnf, bool per_clause, - const std::set& vars_to_remove) { - ILA_CHECK(inv_idx < inv_obj.NumInvariant()); - const auto& inv_vlg = inv_obj.GetVlgConstraints().at(inv_idx); - VarExtractor vext( - [](const std::string& s) -> bool { return false; }, // not ila input - [](const std::string& s) -> bool { return false; }, // not ila state - [](const std::string& scalbln) -> bool { - return true; - } // but verilog state - ); - vext.ParseToExtract(inv_vlg, true); // force verilog state - - InvariantInCnf::clause cl; - std::set v_in_this_cl; - vext.ForEachTokenReplace( - [&cl, &incremental_cnf, &v_in_this_cl, per_clause, - &vars_to_remove](const VarExtractor::token& t) -> std::string { - if (per_clause && t.second.find("&&") != t.second.npos) { - incremental_cnf.InsertClause(cl); - cl.clear(); - v_in_this_cl.clear(); - } - if (t.first != VarExtractor::token_type::VLG_S) - return t.second; - const auto& vname = t.second; - auto pos = vname.rfind('['); - std::string vn = vname; - if (pos != vname.npos) - vn = vname.substr(0, pos); - if (!IN(vn, v_in_this_cl) && !(IN(vn, vars_to_remove))) { - cl.push_back(std::make_tuple(false, vn, 0U)); - v_in_this_cl.insert(vn); - } - return t.second; - }); - incremental_cnf.InsertClause(cl); -} - -bool InvariantSynthesizerCegar::WordLevelEnhancement( - const InvariantInCnf& incremental_cnf, bool under_test) { - if (check_in_bad_state()) - return false; - // to send in the invariants - advanced_parameters_t adv_param; - adv_param._inv_obj_ptr = &inv_obj; - adv_param._candidate_inv_ptr = NULL; - adv_param._cex_obj_ptr = cex_extract.get(); - // TODO: - // generate grain (enhance) target - // run the script - // extract the result - std::vector runnable_scripts; - { // generate grain target - VlgVerifTgtGen vg( - implementation_incl_path, // include - implementation_srcs_path, // sources - implementation_top_module_name, // top_module_name - refinement_variable_mapping_path, // variable mapping - refinement_condition_path, // conditions - _output_path, // output path - _host, // ILA - verify_backend_selector::YOSYS, // verification backend setting - _vtg_config, // target configuration - _vlg_config, // verilog generator configuration - &adv_param // advanced parameter - ); - - design_smt_info = vg.GenerateInvSynEnhanceTargets(incremental_cnf); - runnable_scripts = vg.GetRunnableScriptName(); - } // generate grain target - - // merge the cnfs - // incremental_cnf.Clear(); - - ILA_CHECK(runnable_scripts.size() == 1) - << "BUG: GenerateInvSynEnhanceTargets should create only 1 target " - "script "; - auto synthesis_result_fn = - os_portable_append_dir(_output_path, "__enhance_result.txt"); - auto redirect_fn = os_portable_append_dir("../", "__enhance_result.txt"); - - auto cwd = os_portable_getcwd(); - auto new_wd = os_portable_path_from_path(runnable_scripts[0]); - ILA_ERROR_IF(!os_portable_chdir(new_wd)) - << "WordLevelEnhancement: cannot change dir to:" << new_wd; - ILA_INFO << "Executing script:" << runnable_scripts[0]; - execute_result res; - - if (under_test) { - res.subexit_normal = true; - res.seconds = 0; - res.ret = 0; - res.failure = res.NONE; - res.timeout = false; - } else - res = os_portable_execute_shell( - {"bash", os_portable_file_name_from_path(runnable_scripts[0])}, - redirect_fn, redirect_t::BOTH); - - ILA_ERROR_IF(res.failure != execute_result::NONE) - << "Running synthesis script " << runnable_scripts[0] - << " results in error."; - ILA_CHECK(os_portable_chdir(cwd)); - - inv_enhance_time += res.seconds; - // inv_syn_time_series.push_back(res.seconds); - - bool freq_enhance_okay = false; - { // run grain - std::stringstream sbuf; - std::ifstream fin(synthesis_result_fn); - if (!fin.is_open()) { - ILA_ERROR << "Unable to read the synthesis result file:" - << synthesis_result_fn; - freq_enhance_okay = false; - } else { - sbuf << fin.rdbuf(); - freq_enhance_okay = - S_IN("proved", sbuf.str()) || S_IN("proven", sbuf.str()); - if (S_IN("unknown", sbuf.str())) - freq_enhance_okay = false; - if (freq_enhance_okay) { - ILA_INFO << "Enhance Info: Lemma/Gen/Spec = " - << retrieveColonEol(sbuf.str(), "learned lemmas:") << " " - << retrieveColonEol(sbuf.str(), "TotalGen:") << " " - << retrieveColonEol(sbuf.str(), "TotalSpec:") << " " - << retrieveColonEol(sbuf.str(), "TotalCand:"); - total_grain_cand += retrieveColonEol(sbuf.str(), "TotalCand:"); - } - } - } // end of grain chc result - // else reachable - if (!freq_enhance_okay) - return false; - - if (design_smt_info == nullptr) { - ILA_ERROR << "BUG: Design SMT-LIB2 info is not available. "; - return false; - } - inv_obj.AddInvariantFromGrainResultFile( - *(design_smt_info.get()), "", - os_portable_append_dir(_output_path, "grain.result"), true, true); - - // you also need to merge CNF - status = cegar_status::NEXT_V; - return true; -} - -// -------------------------------- EXTRACTIONS -// ------------------------------------------- // - -/// to extract result -void InvariantSynthesizerCegar::ExtractVerificationResult( - bool autodet, bool pass, const std::string& vcd_file, - const std::string& mod_inst_name) { - if (check_in_bad_state()) - return; - - std::string res_file = vcd_file; - if (autodet) { - res_file = vcd_file_name; - pass = verification_pass; - } - ILA_WARN_IF(status != cegar_status::V_RES) - << "CEGAR-loop: repeated verification step."; - - vlg_mod_inst_name = - vlg_mod_inst_name.empty() ? mod_inst_name : vlg_mod_inst_name; - if (vlg_mod_inst_name.empty()) { - ILA_ERROR << "Instance name in vcd is unknown and not specified"; - bad_state = true; - return; - } - - if (pass) { - ILA_INFO << "No counterexample has been found. CEGAR loop finishes."; - status = cegar_status::DONE; - return; - } - - // we still need to create a verilog info analyzer - VerilogAnalyzer va(implementation_incl_path, implementation_srcs_path, - vlg_mod_inst_name, implementation_top_module_name); - - auto is_reg = [&](const std::string& n) -> bool { - if (!VerilogAnalyzerBase::is_reg(va.check_hierarchical_name_type(n))) - return false; - if (design_smt_info) // if available we will use it - return design_smt_info->is_state_name(n); - return true; // if not available - }; - - // not passing - cex_extract = std::unique_ptr(new CexExtractor( - res_file, vlg_mod_inst_name, is_reg, !_vtg_config.CosaFullTrace)); - // advance to synthesis stage - status = cegar_status::NEXT_S; -} // extract result - -/// a helper function (only locally available) -/// to extract vcd file name from the output -std::string extract_vcd_name_from_cex(const std::string& fn) { - std::ifstream fin(fn); - if (!fin.is_open()) { - ILA_ERROR << "Unable to read from:" << fn; - return ""; - } - std::string line; - while (std::getline(fin, line)) { - if (S_IN("*** TRACES ***", line)) - break; - } - if (fin.eof()) { - ILA_ERROR << "Cannot extract vcd filename, incorrect format, expecting *** " - "TRACES ***"; - return ""; - } - std::string fname; - fin >> fname; - fin >> fname; // the first is garbage; - ILA_ERROR_IF(!S_IN(".vcd", fname)) - << "Expecting vcd file name, get " << fname; - return fname; -} // extract_vcd_name_from_cex - -void InvariantSynthesizerCegar::CexGeneralizeRemoveStates( - const std::vector& n) { - cex_extract->DropStates(n); -} - -void InvariantSynthesizerCegar::ExtractAbcSynthesisResultForEnhancement( - InvariantInCnf& incremental_cnf, bool autodet, bool reachable) { - - if (check_in_bad_state()) - return; - - if (autodet) { - reachable = cex_reachable; - } - - ILA_WARN_IF(status != cegar_status::S_RES) - << "CEGAR-loop: expecting synthesis result."; - - if (reachable) { - ILA_ERROR << "Verification failed with true counterexample!"; - status = cegar_status::FAILED; - return; - } - ILA_CHECK(current_inv_type == cur_inv_tp::CEGAR_ABC) - << "Can only work with CEGAR ABC!"; - // the incremental CNF here - ILA_CHECK(inv_candidate.AddInvariantFromAbcResultFile( - _vtg_config.AbcUseAiger - ? os_portable_append_dir( - os_portable_path_from_path(runnable_script_name[0]), - "__aiger_prepare.blif") - : os_portable_append_dir( - os_portable_path_from_path(runnable_script_name[0]), - "wrapper.blif"), - os_portable_append_dir( - os_portable_path_from_path(runnable_script_name[0]), "ffmap.info"), - true, true, - _vtg_config.AbcUseGla - ? os_portable_append_dir( - os_portable_path_from_path(runnable_script_name[0]), - "glamap.info") - : "", - _vtg_config.AbcUseAiger, - _vtg_config.AbcUseAiger - ? os_portable_append_dir( - os_portable_path_from_path(runnable_script_name[0]), - "wrapper.aig.map") - : "", - incremental_cnf, inv_cnf) // incrementally add cnf - ) - << "Extracting of invariant failed!"; - - current_inv_type = cur_inv_tp::NONE; // we have extracted, reset this marker -} // ExtractAbcSynthesisResultForEnhancement - -void InvariantSynthesizerCegar::ExtractSynthesisResult( - bool autodet, bool reachable, const std::string& given_smt_chc_result_txt) { - - if (check_in_bad_state()) - return; - - std::string res_file = given_smt_chc_result_txt; - if (autodet) { - reachable = cex_reachable; - res_file = synthesis_result_fn; - } - - ILA_WARN_IF(status != cegar_status::S_RES) - << "CEGAR-loop: expecting synthesis result."; - - if (reachable) { - ILA_ERROR << "Verification failed with true counterexample!"; - status = cegar_status::FAILED; - return; - } - - if (current_inv_type == cur_inv_tp::CHC) { - if (design_smt_info == nullptr) { - ILA_ERROR << "Design SMT-LIB2 info is not available. " - << "You need to run `GenerateSynthesisTarget` or Parse a " - "design smt first first."; - return; - } - ILA_CHECK(inv_obj.AddInvariantFromChcResultFile - (*(design_smt_info.get()), "", - res_file, - _vtg_config.YosysSmtFlattenDatatype, - _vtg_config.YosysSmtFlattenHierarchy)); - } else if (current_inv_type == cur_inv_tp::GRAIN_CHC) { - if (design_smt_info == nullptr) { - ILA_ERROR << "Design SMT-LIB2 info is not available. " - << "You need to run `GenerateSynthesisTarget` or Parse a " - "design smt first first."; - return; - } - inv_obj.AddInvariantFromGrainResultFile( - *(design_smt_info.get()), "", - os_portable_append_dir(_output_path, "grain.result"), true, true); - } else if (current_inv_type == cur_inv_tp::CEGAR_ABC) { - ILA_CHECK(inv_obj.AddInvariantFromAbcResultFile( - _vtg_config.AbcUseAiger - ? os_portable_append_dir( - os_portable_path_from_path(runnable_script_name[0]), - "__aiger_prepare.blif") - : os_portable_append_dir( - os_portable_path_from_path(runnable_script_name[0]), - "wrapper.blif"), - os_portable_append_dir( - os_portable_path_from_path(runnable_script_name[0]), "ffmap.info"), - true, true, - _vtg_config.AbcUseGla - ? os_portable_append_dir( - os_portable_path_from_path(runnable_script_name[0]), - "glamap.info") - : "", - _vtg_config.AbcUseAiger, - _vtg_config.AbcUseAiger - ? os_portable_append_dir( - os_portable_path_from_path(runnable_script_name[0]), - "wrapper.aig.map") - : "", - inv_cnf, InvariantInCnf())) - << "Extracting of invariant failed!"; - } else - ILA_ERROR << "Inv type unknown:" << current_inv_type; - - std::cout << "Confirmed synthesized invariants:" << std::endl; - for (auto&& v : inv_obj.GetVlgConstraints()) - std::cout << v << std::endl; - - status = cegar_status::NEXT_V; - current_inv_type = cur_inv_tp::NONE; // we have extracted, reset this marker - -} // ExtractSynthesisResult - -// -------------------------------- AUTO RUNS -// ------------------------------------------- // - -/// a helper function (only locally available) -/// to detect tool error (e.g., verilog parsing error) -bool static has_verify_tool_error_cosa(const std::string& fn) { - std::ifstream fin(fn); - if (!fin.is_open()) { - ILA_ERROR << "Unable to read from:" << fn; - return true; - } - - std::string line; - while (std::getline(fin, line)) { - if (S_IN("See yosys-err.log for more info.", line)) - return true; - } - return false; -} // has_verify_tool_error_cosa - -/// a helper function (only locally available) -/// to detect tool error (e.g., verilog parsing error) -bool static has_verify_tool_unknown_cosa(const std::string& fn) { - std::ifstream fin(fn); - if (!fin.is_open()) { - ILA_ERROR << "Unable to read from:" << fn; - return true; - } - - std::string line; - while (std::getline(fin, line)) { - if (S_IN("UNKNOWN != TRUE <<<---------| ERROR", line)) - return true; - } - return false; -} // has_verify_tool_error_cosa -/// run Verification -bool InvariantSynthesizerCegar::RunVerifAuto( - const std::string& script_selection, const std::string& pid_fname, - bool under_test, unsigned timeout) { - auto script_sel = - select_script_to_run(runnable_script_name, script_selection); - if (check_in_bad_state()) - return true; - // Not implemented - auto result_fn = - os_portable_append_dir(_output_path, "__verification_result.txt"); - auto redirect_fn = os_portable_append_dir("..", "__verification_result.txt"); - auto cwd = os_portable_getcwd(); - auto new_wd = os_portable_path_from_path(script_sel); - ILA_ERROR_IF(!os_portable_chdir(new_wd)) - << "RunVerifAuto: cannot change dir to:" << new_wd; - ILA_INFO << "Executing verify script:" << script_sel; - - execute_result res; - if (under_test) { - res.subexit_normal = true; - res.seconds = 0; - res.ret = 0; - res.failure = res.NONE; - res.timeout = false; - } else { - res = os_portable_execute_shell( - {"bash", os_portable_file_name_from_path(script_sel)}, redirect_fn, - redirect_t::BOTH, timeout, pid_fname); - } - - ILA_ERROR_IF(res.failure != execute_result::NONE) - << "Running verification script " << script_sel << " results in error."; - ILA_CHECK(os_portable_chdir(cwd)); - // the last line contains the result - // above it you should have *** TRACES *** - // the vcd file resides within the new dir - ILA_ERROR_IF(has_verify_tool_error_cosa(result_fn)) - << "----------- Verification tool reported error! Please check the log " - "output!"; - ILA_ERROR_IF(has_verify_tool_unknown_cosa(result_fn)) - << "UNKNOWN Verif result"; - - eqcheck_time += res.seconds; - - auto lastLine = os_portable_read_last_line(result_fn); - ILA_ERROR_IF(lastLine.empty()) << "Unable to extract verification result."; - if (S_IN("Verifications with unexpected result", lastLine)) { - ILA_INFO << "Counterexample found."; - - vcd_file_name = extract_vcd_name_from_cex(result_fn); - vcd_file_name = os_portable_append_dir(new_wd, vcd_file_name); - - verification_pass = false; - return false; - } - verification_pass = true; - status = cegar_status::DONE; - ILA_INFO << "No counterexample has been found. CEGAR loop finishes."; - return true; -} - -/// run Synthesis -bool InvariantSynthesizerCegar::RunSynAuto(bool under_test) { - if (check_in_bad_state()) - return true; - - ILA_CHECK(runnable_script_name.size() == 1) - << "Please run GenerateInvSynTargets function first"; - synthesis_result_fn = - os_portable_append_dir(_output_path, "__synthesis_result.txt"); - auto redirect_fn = os_portable_append_dir("..", "__synthesis_result.txt"); - - auto cwd = os_portable_getcwd(); - auto new_wd = os_portable_path_from_path(runnable_script_name[0]); - ILA_ERROR_IF(!os_portable_chdir(new_wd)) - << "RunSynAuto: cannot change dir to:" << new_wd; - ILA_INFO << "Executing synthesis script:" << runnable_script_name[0]; - - execute_result res; - if (under_test) { - res.subexit_normal = true; - res.seconds = 0; - res.ret = 0; - res.failure = res.NONE; - res.timeout = false; - } else { - res = os_portable_execute_shell( - {"bash", os_portable_file_name_from_path(runnable_script_name[0])}, - redirect_fn, redirect_t::BOTH); - } - - ILA_ERROR_IF(res.failure != execute_result::NONE) - << "Running synthesis script " << runnable_script_name[0] - << " results in error."; - ILA_CHECK(os_portable_chdir(cwd)); - - inv_syn_time += res.seconds; - inv_syn_time_series.push_back(res.seconds); - - if (current_inv_type == CEGAR_ABC) { - std::stringstream sbuf; - std::ifstream fin(synthesis_result_fn); - if (!fin.is_open()) { - ILA_ERROR << "Unable to read the synthesis result file:" - << synthesis_result_fn; - status = cegar_status::FAILED; - bad_state = true; - return true; // reachable - } - sbuf << fin.rdbuf(); - cex_reachable = !(S_IN("Property proved.", sbuf.str()) && - S_IN("Invariant contains ", sbuf.str())); - } else if (current_inv_type == GRAIN_CHC) { - std::stringstream sbuf; - std::ifstream fin(synthesis_result_fn); - if (!fin.is_open()) { - ILA_ERROR << "Unable to read the synthesis result file:" - << synthesis_result_fn; - status = cegar_status::FAILED; - bad_state = true; - return true; // reachable - } - sbuf << fin.rdbuf(); - cex_reachable = !(S_IN("proved", sbuf.str())); - if (S_IN("unknown", sbuf.str())) - cex_reachable = true; - // count cands - total_grain_cand += retrieveColonEol(sbuf.str(), "TotalCand:"); - } else { - std::string line; - { // read the result - std::ifstream fin(synthesis_result_fn); - if (!fin.is_open()) { - ILA_ERROR << "Unable to read the synthesis result file:" - << synthesis_result_fn; - status = cegar_status::FAILED; - bad_state = true; - return true; // reachable - } - std::getline(fin, line); - } // finish file reading - cex_reachable = true; - if (S_IN("unsat", line)) - cex_reachable = false; // not reachable - } - // else reachable - return cex_reachable; -} - -// -------------------------------- MISCS -// ------------------------------------------- // - -void InvariantSynthesizerCegar::LoadDesignSmtInfo(const std::string& fn) { - std::ifstream fin(fn); - if (!fin.is_open()) { - ILA_ERROR << "Unable to read from : " << fn; - return; - } - std::stringstream sbuf; - sbuf << fin.rdbuf(); - design_smt_info = std::make_shared(sbuf.str()); -} - -const std::vector& -InvariantSynthesizerCegar::GetRunnableTargetScriptName() const { - return runnable_script_name; -} - -void InvariantSynthesizerCegar::LoadPrevStatisticsState(const std::string& fn) { - DesignStatistics local_info; - local_info.LoadFromFile(fn); - if (eqcheck_time != 0 || inv_proof_attempt_time != 0 || inv_syn_time != 0 || - inv_validate_time != 0 || inv_enhance_time != 0 || - !inv_syn_time_series.empty()) { - ILA_ERROR << "Not loading the statistics state from initial time!"; - } - eqcheck_time += local_info.TimeOfEqCheck; - inv_proof_attempt_time += local_info.TimeOfInvProof; - inv_syn_time += local_info.TimeOfInvSyn; - inv_enhance_time += local_info.TimeOfInvSynEnhance; - inv_validate_time += local_info.TimeOfInvValidate; - inv_syn_time_series.insert(inv_syn_time_series.end(), - local_info.TimeOfInvSynSeries.begin(), - local_info.TimeOfInvSynSeries.end()); -} - -DesignStatistics InvariantSynthesizerCegar::GetDesignStatistics() const { - DesignStatistics ret; - - ret.TimeOfEqCheck = eqcheck_time; - ret.TimeOfInvProof = inv_proof_attempt_time; - ret.TimeOfInvSyn = inv_syn_time; - ret.TimeOfInvSynEnhance = inv_enhance_time; - ret.TimeOfInvValidate = inv_validate_time; - ret.TimeOfInvSynSeries = inv_syn_time_series; - - if (design_smt_info == nullptr) { - ILA_ERROR << "Design information not available!"; - return ret; - } - - ILA_ERROR_IF(vlg_mod_inst_name.empty()) - << "vlg_mod_inst_name is empty, will not distinguish in/out module state"; - - for (auto&& st : design_smt_info->get_module_flatten_dt("wrapper")) { - - if (StrStartsWith(st.verilog_name, vlg_mod_inst_name + ".")) { - ret.NumOfDesignStateBits += st._type.GetBoolBvWidth(); - ret.NumOfDesignStateVars++; - } else { - ret.NumOfExtraStateBits += st._type.GetBoolBvWidth(); - ret.NumOfExtraStateVars++; - } - } - return ret; -} - -const InvariantObject& InvariantSynthesizerCegar::GetInvariants() const { - return inv_obj; -} - -void InvariantSynthesizerCegar::RemoveInvariantsByIdx(size_t idx) { - inv_obj.RemoveInvByIdx(idx); -} - -/// Here you can extract the invariants and export them if needed -const InvariantObject& -InvariantSynthesizerCegar::GetCandidateInvariants() const { - return inv_candidate; -} - -void InvariantSynthesizerCegar::ClearAllCandidateInvariants() { - inv_candidate.ClearAllInvariants(); -} - -void InvariantSynthesizerCegar::LoadInvariantsFromFile(const std::string& fn) { - inv_obj.ImportFromFile(fn); -} -void InvariantSynthesizerCegar::LoadCandidateInvariantsFromFile( - const std::string& fn) { - inv_candidate.ImportFromFile(fn); -} - -void InvariantSynthesizerCegar::AcceptAllCandidateInvariant() { - if (inv_candidate.NumInvariant() != 0) { - inv_obj.InsertFromAnotherInvObj(inv_candidate); - inv_candidate.ClearAllInvariants(); - } else - ILA_INFO << "All candidate invariants have been accepted."; -} - -/// Supply Verilog candidate invariants -void InvariantSynthesizerCegar::SupplyCandidateInvariant( - const std::string& vlg_expr) { - ILA_WARN << "Verilog invariant cannot be pruned"; - inv_candidate.AddInvariantFromVerilogExpr("", vlg_expr); -} - -// -------------------- GrainChc ------------------ // -void InvariantSynthesizerCegar::ChangeGrainSyntax( - const std::vector& syn) { - _vtg_config.GrainOptions = syn; -} - -}; // namespace ilang - -#endif // INVSYN_INTERFACE diff --git a/src/vtarget-out/inv-syn/rel_chc.cc b/src/vtarget-out/inv-syn/rel_chc.cc deleted file mode 100644 index 2dcb52940..000000000 --- a/src/vtarget-out/inv-syn/rel_chc.cc +++ /dev/null @@ -1,611 +0,0 @@ -/// \file Source of initial constraint synthesis utility -// --- Hongce Zhang - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -namespace ilang { - -// o.w. we need to find two ind-inv -static std::string dual_ind_inv_reset_start_tmpl = R"***( -;---------------------------------------- -; Dual Inductive Invariant Synthesis -; Generated from ILAng -;---------------------------------------- - -; wrapper smt -%wrapperSmt% - -; customized bv2bool -(define-fun zbv2bool ((bv1b (_ BitVec 1))) Bool (= bv1b #b1)) - -; additional mapping control -; |__AMC__design| is actually the invariants -; -(define-fun |__AMC__design| ((|__Sv__| |%d%_s|)) Bool %amcFunc_design%) -(define-fun |__AMC__wrapper| ((|__Sw__| |%w%_s|)) Bool %amcFunc_wrapper%) - -; includes the start_condition, issue_decode, issue_valid -(define-fun |__ASPT__| ((|__Sw__| |%w%_s|)) Bool %ASPT%) - -; includes the variable_map_assert -(define-fun |__ASST__| ((|__Sw__| |%w%_s|)) Bool %ASST%) - -(declare-rel INV1 (|%d%_s|)) ; inv1 is on design -(declare-rel INV2 (|%w%_s|)) ; inv2 is on wrapper -(declare-rel fail ()) - -%BIn% - -(declare-var |__SvI__| |%d%_s|) ; design -(declare-var |__Sv__| |%d%_s|) ; design -(declare-var |__Sv'__| |%d%_s|) ; design - -; (declare-var |__Swst__| |%w%_s|) ; wrapper : starting -- __START__ signal is true -(declare-var |__Sw__| |%w%_s|) ; wrapper : generic state -(declare-var |__Sw'__| |%w%_s|) ; wrapper : new state -;(declare-var |__Svst__| |%d%_s|) ; design : starting -- __START__ signal is true here - - -; init => inv1 -(rule (=> - (and - %rstseq% - ; (not (|%d%_n rst| |__SvI__|)) ; why not removed? - (|%d%_h| |__SvI__|) - (|__AMC__design| |__SvI__|) - ) (INV1 |__SvI__|))) - -; inv1 /\ T => inv1 -(rule (=> - (and - (INV1 |__Sv__|) - (|%d%_t| |__Sv__| |__Sv'__|) - (|%d%_h| |__Sv__|) - (|%d%_h| |__Sv'__|) - (|__AMC__design| |__Sv__|) - (|__AMC__design| |__Sv'__|)) - (INV1 |__Sv'__|))) - - -; init /\ inv1 => inv2 -(rule (=> - (and - (not (|%w%_n rst| |__Sw__|)) ; why not removed? - (|%w%_h| |__Sw__|) - (|%w%_i| |__Sw__|) - (|__AMC__wrapper| |__Sw__|) - (|__ASPT__| |__Sw__|) - (INV1 (|%w%_h %subi%| |__Sw__|)) - ) - (INV2 |__Sw__|) - ) -) - -; inv2 /\ T => inv2 -(rule - (=> - (and - (INV2 |__Sw__|) - (|%w%_t| |__Sw__| |__Sw'__|) - (|__AMC__wrapper| |__Sw__|) - (|__AMC__wrapper| |__Sw'__|) - (not (|%w%_n rst| |__Sw__|)) ; why not removed? - (not (|%w%_n rst| |__Sw'__|)) ; why not removed? - (|%w%_h| |__Sw__|) - (|%w%_h| |__Sw'__|) - ) - (INV2 |__Sw'__|) - ) -) - - -; inv2 /\ ~ assert => fail -(rule - (=> - (and - (INV2 |__Sw__|) - (|__AMC__wrapper| |__Sw__|) - (|%w%_h| |__Sw__|) - (not (|__ASST__| |__Sw__|)) - ) - fail) -) - -(query fail :print-certificate true) - -)***"; - - -// o.w. we need to find two ind-inv -static std::string dual_ind_inv_tmpl = R"***( -;---------------------------------------- -; Dual Inductive Invariant Synthesis -; Generated from ILAng -;---------------------------------------- - -; wrapper smt -%wrapperSmt% - -; customized bv2bool -(define-fun zbv2bool ((bv1b (_ BitVec 1))) Bool (= bv1b #b1)) - -; additional mapping control -; |__AMC__design| is actually the invariants -; -(define-fun |__AMC__design| ((|__Sv__| |%d%_s|)) Bool %amcFunc_design%) -(define-fun |__AMC__wrapper| ((|__Sw__| |%w%_s|)) Bool %amcFunc_wrapper%) - -; includes the start_condition, issue_decode, issue_valid -(define-fun |__ASPT__| ((|__Sw__| |%w%_s|)) Bool %ASPT%) - -; includes the variable_map_assert -(define-fun |__ASST__| ((|__Sw__| |%w%_s|)) Bool %ASST%) - -(declare-rel INV1 (|%d%_s|)) ; inv1 is on design -(declare-rel INV2 (|%w%_s|)) ; inv2 is on wrapper -(declare-rel fail ()) - -%BIn% -(declare-var |__SvI__| |%d%_s|) ; design -(declare-var |__Sv__| |%d%_s|) ; design -(declare-var |__Sv'__| |%d%_s|) ; design - -(declare-var |__SwI__| |%w%_s|) ; wrapper : init state -(declare-var |__Swst__| |%w%_s|) ; wrapper : starting -- __START__ signal is true -(declare-var |__Sw__| |%w%_s|) ; wrapper : generic state -(declare-var |__Sw'__| |%w%_s|) ; wrapper : new state -;(declare-var |__Svst__| |%d%_s|) ; design : starting -- __START__ signal is true here - - -; init => inv1 -(rule (=> - (and - %rstseq% - ;(not (|%d%_n rst| |__SvI__|)) ; why not removed? - (|%d%_h| |__SvI__|) - (|__AMC__design| |__SvI__|) - ) (INV1 |__SvI__|))) - -; inv1 /\ T => inv1 -(rule (=> - (and - (INV1 |__Sv__|) - (|%d%_t| |__Sv__| |__Sv'__|) - (|%d%_h| |__Sv__|) - (|%d%_h| |__Sv'__|) - (|__AMC__design| |__Sv__|) - (|__AMC__design| |__Sv'__|)) - (INV1 |__Sv'__|))) - - -; init /\ inv1 => inv2 -(rule (=> - (and - (|%w%_i| |__SwI__|) - (not (|%w%_n rst| |__SwI__|)) ; why not removed? - (not (|%w%_n rst| |__Swst__|)) ; why not removed? - (|%w%_h| |__SwI__|) - (|%w%_h| |__Swst__|) - (|__AMC__wrapper| |__SwI__|) - (|%w%_t| |__SwI__| |__Swst__|) - (|__AMC__wrapper| |__Swst__|) - (|__ASPT__| |__Swst__|) - (INV1 (|%w%_h %subi%| |__Swst__|)) - ) - (INV2 |__Swst__|) - ) -) - -; inv2 /\ T => inv2 -(rule - (=> - (and - (INV2 |__Sw__|) - (|%w%_t| |__Sw__| |__Sw'__|) - (|__AMC__wrapper| |__Sw__|) - (|__AMC__wrapper| |__Sw'__|) - (not (|%w%_n rst| |__Sw__|)) ; why not removed? - (not (|%w%_n rst| |__Sw'__|)) ; why not removed? - (|%w%_h| |__Sw__|) - (|%w%_h| |__Sw'__|) - ) - (INV2 |__Sw'__|) - ) -) - - -; inv2 /\ ~ assert => fail -(rule - (=> - (and - (INV2 |__Sw__|) - (|__AMC__wrapper| |__Sw__|) - (|%w%_h| |__Sw__|) - (not (|__ASST__| |__Sw__|)) - ) - fail) -) - -(query fail :print-certificate true) - -)***"; - -// a local helper function to produce a list of and -std::string static JoinListWithAnd(const std::vector & l) { - if (l.size() == 0) - return "true"; - else if(l.size() == 1) - return l[0]; - return "(and " + Join(l, " ")+")"; -} - -size_t static skipArgs(const std::string & stmt, size_t start) { - // need to fit - auto pos = start; - ILA_ASSERT(stmt.at(pos) == '(') << "Expecting '('"; - unsigned level = 0; - do { - if (stmt.at(pos) == '(') - level ++; - else if (stmt.at(pos) == ')') - level --; - pos ++; - } while(level != 0); - return pos; -} - -// a local helper function to return the type of a smt (define-fun ) stmt -bool static is_returntype_bool(const std::string & stmt) { - std::string beginning("(define-fun |"); - ILA_ASSERT (stmt.find(beginning) == 0) << "Not a `(define-fun |` stmt"; - auto pos = beginning.length()+1; - auto end_func_name_pos = stmt.find('|',pos); - auto start_arg_list = stmt.find('(', end_func_name_pos); - auto end_arg_list = skipArgs(stmt, start_arg_list); - auto Bool_pos = stmt.find("Bool", end_arg_list); - auto Bitvec_pos = stmt.find("(_ BitVec", end_arg_list); - if (Bool_pos < Bitvec_pos) - return true; - return false; -} - - -// extract -bool static extractSigDefFromLine( - const std::string & mod_name, - const std::string & line, - std::set & s, - std::vector> & v) { - // list of (name, is bool?) - bool found_match_state = false; - std::string search_target_wire_num = "(define-fun |" + mod_name + "#"; - std::string search_target_n = "(define-fun |" + mod_name + "_n "; - // bool returnBool; - if (line.find(search_target_wire_num) == 0) { // begins with it - auto mark = line.find("; \\"); - if (mark != line.npos) { - auto signame = line.substr(mark+strlen("; \\")); - // it should not contain EOL - //signame = ReplaceAll(ReplaceAll(signame, "\n",""),"\r",""); - if( IN(signame, s ) ) { - s.erase(signame); // remove it from the set - - auto num_start = line.substr(search_target_wire_num.size()); - auto end = num_start.find('|'); - auto num = num_start.substr(0,end); - auto smt_expr = "|" + mod_name + "#" + num + "|"; - - v.push_back(std::make_pair(smt_expr,is_returntype_bool(line))); // |mod#n| - - found_match_state = true; - } - } // found "; \\" - } // end of exists signal definition type 1 - else if (line.find(search_target_n) == 0) { // begins with it - auto len = search_target_n.size(); - auto mark = line.find('|',len); - auto signame = line.substr(len, mark-len); - - if( IN(signame, s) ) { - s.erase(signame); // remove it from the set - - auto smt_expr = "|" + mod_name + "_n " + signame + "|"; - - v.push_back(std::make_pair(smt_expr,is_returntype_bool(line))); // |mod_n signal| - found_match_state = true; - } - } - - return found_match_state; -} - - /// generate the Yosys script for dual invariant - void VlgSglTgtGen_Relchc::dual_inv_problem(const std::string& ys_script_name) { - // this is the yosys script for ? what? - return; // do nothing - } - - -// ------------------------------------------- -// Summary of the assertions/assumptions we need to handle -// -// assert: variable_map_assert -// invariant_assert -- should no be here -// -// assmpt: noreset (AMC) -// funcmap (AMC) -// absmem (AMC) -// additional_mapping_control_assume (AMC) -// invariant_assume (AMC_design) -// issue_decode (START -- ASPT) -// issue_valid (START -- ASPT) -// start_condition (START -- ASPT) -// -// (AMC means should always be true) -// -// ------------------------------------------- - - /// generate the template file - void VlgSglTgtGen_Relchc::dual_inv_tpl(const std::string & tpl_name, const std::string & all_smt) { - // get a local copy of the stringstream - std::stringstream smt_stream; - smt_stream << all_smt; - // std::string all_smt = smt_info.full_smt.str(); - // the Verilog top module - auto vlg_top_module_name = vlg_info_ptr->get_top_module_name(); - - // define amc(d/w)/asst/aspt funcs - std::string amc_design; - std::string amc_wrapper; - std::string asst; - std::string aspt; - { // Construct the above four - std::set wn_amc_design_item; // wn stands for wire name - std::set wn_amc_wrapper_item; - std::set wn_asst_item; // assertions - std::set wn_aspt_item; // assumptions - - { // find the verilog signal name - for (auto&& pbname_prob_pair : _problems.assertions) { - const auto & dspt = pbname_prob_pair.first; - const auto & exprs = pbname_prob_pair.second; - - if (dspt == "invariant_assert") { - ILA_ASSERT(false) << "Unanticipated dspt: " << dspt; - } - else if(dspt == "variable_map_assert") { - // - for (const auto & expr : exprs.exprs) { - ILA_ASSERT( expr.find("=") == expr.npos ) - << "Bug: should be pure name." - << "but get: " << expr; - - wn_asst_item.insert(expr); - } - } - else - ILA_ASSERT(false) << "Unknown dspt:" << dspt; - - - } // end of parsing asserts - - for (auto && pbname_prob_pair : _problems.assumptions) { - const auto & dspt = pbname_prob_pair.first; - const auto & exprs = pbname_prob_pair.second; - for (const auto &expr : exprs.exprs) { - ILA_ASSERT( expr.find("=") == expr.npos ) // no "=" - << "Bug: should be pure name." - << " but get: " << expr - << " dspt: " << dspt; - - if(dspt == "invariant_assume") - wn_amc_design_item.insert(expr); - else if( - dspt == "noreset" || - dspt == "funcmap" || - dspt == "absmem" || - dspt == "additional_mapping_control_assume" || - dspt == "func_arg" || - dspt == "func_result" || - dspt == "post_value_holder" || - dspt == "rfassumptions" - ) - wn_amc_wrapper_item.insert(expr); - else if( - dspt == "issue_decode" || - dspt == "issue_valid" || - dspt == "start_condition" || - dspt == "variable_map_assume" || - dspt == "variable_map_assume_" - ) - wn_aspt_item.insert(expr); - else - ILA_ASSERT(false) << "Unknown dspt : " << dspt; - } // for expr - } // for assumptions - - } // gen wire name - - std::vector> amc_design_item; // no wn here : in the submodule - std::vector> amc_wrapper_item; // in the top module - std::vector> asst_item; // assertions - std::vector> aspt_item; // assumptions - { // find number name --- smt name - // algo : go line by line, check in "wn_" or not, if so, add ow ignored - enum {BEFORE, SUBMODULE, TOPMODULE} state = BEFORE; - for (std::string line; std::getline(smt_stream, line);) { - if ( state == BEFORE && - line.find("; yosys-smt2-module ") == 0) { // starts with it - // new module - auto modname = line.substr(strlen("; yosys-smt2-module ")); - if (modname == vlg_top_module_name) - state = SUBMODULE; // go to next state - } // find vlg module - else if (state == SUBMODULE) { - if ( extractSigDefFromLine( - vlg_top_module_name, line, wn_amc_design_item, - amc_design_item) ) { /* do nothing */ } - else if(line.find("; yosys-smt2-module ") == 0) { - auto modname = line.substr(strlen("; yosys-smt2-module ")); - if (modname == top_mod_name) - state = TOPMODULE; // go to next state - } // end of go to next module - // else do nothing - } // deal with submodule (verilog top) -- continue to the wrapper - else if (state == TOPMODULE) { - if ( extractSigDefFromLine( top_mod_name, line, - wn_amc_wrapper_item, amc_wrapper_item ) ) { /* do nothing */ } - else if ( extractSigDefFromLine( top_mod_name, line, - wn_asst_item, asst_item ) ) { /* do nothing */ } - else if ( extractSigDefFromLine( top_mod_name, line, - wn_aspt_item, aspt_item ) ) { /* do nothing */ } - else { /* do nothing */ } - } - } // end of for readline - ILA_ASSERT (state == TOPMODULE) - << "BUG: Error in parsing smt-lib2 file! " - << "Not reaching the top module."; - // sanity check -- if all sigs are found - - ILA_ASSERT ( - wn_amc_design_item.empty() && - wn_amc_wrapper_item.empty() && - wn_asst_item.empty() && - wn_aspt_item.empty() - ) << "Missing signals in SMT parsing, HC gen will be incorrect"; - } // find number name --- smt name - - { // construct expressions - // (signame |%d%_s|) or (signame |%w%_s|), use " " to join and add "(and" ")" - std::vector items; - items.clear(); - for (auto && name_bool_pair: amc_design_item) { - if (name_bool_pair.second) - items.push_back("("+name_bool_pair.first+" |__Sv__|)"); - else - items.push_back("(zbv2bool ("+name_bool_pair.first+" |__Sv__|))"); - } - amc_design = JoinListWithAnd(items); - - - items.clear(); - for (auto && name_bool_pair: amc_wrapper_item) { - if (name_bool_pair.second) - items.push_back("("+name_bool_pair.first+" |__Sw__|)"); - else - items.push_back("(zbv2bool ("+name_bool_pair.first+" |__Sw__|))"); - } - amc_wrapper = JoinListWithAnd(items); - - items.clear(); - for (auto && name_bool_pair: aspt_item) { - if (name_bool_pair.second) - items.push_back("("+name_bool_pair.first+" |__Sw__|)"); - else - items.push_back("(zbv2bool ("+name_bool_pair.first+" |__Sw__|))"); - } - aspt = JoinListWithAnd(items); - - items.clear(); - for (auto && name_bool_pair: asst_item) { - if (name_bool_pair.second) - items.push_back("("+name_bool_pair.first+" |__Sw__|)"); - else - items.push_back("(zbv2bool ("+name_bool_pair.first+" |__Sw__|))"); - } - asst = JoinListWithAnd(items); - - /* - for_each(aspt_item.begin(), aspt_item.end(), - [](std::string & s) -> void {s = "("+s+" |__Sw__|)";} ); - aspt = JoinListWithAnd(aspt_item); - - for_each(asst_item.begin(), asst_item.end(), - [](std::string & s) -> void {s = "("+s+" |__Sw__|)";} ); - asst = JoinListWithAnd(asst_item);*/ - - } // construct expressions - } // Construct exprs done - - // %BIn% - // %rstseq% - std::string BIn; - std::string rstseq; - { // set BIn and rstseq - unsigned rstcycles = supplementary_info.cosa_yosys_reset_config.reset_cycles; - std::string rst_sig = "rst"; - bool rst_neg = false; - - // decide reset signal - if(IN("interface mapping", rf_vmap) || IN("interface-mapping", rf_vmap)) { - nlohmann::json & ifmap = IN("interface mapping", rf_vmap) ? rf_vmap["interface mapping"] : rf_vmap["interface-mapping"]; - ILA_CHECK(ifmap.is_object()); - for (auto&& item : ifmap.items()) { - if (item.value() == "**RESET**") { - rst_sig = item.key(); - rst_neg = false; - } else if (item.value() == "**NRESET**") { - rst_sig = item.key(); - rst_neg = true; - } - } - } // finish deciding reset signal - - - for (unsigned idx = 0; idx < rstcycles; ++ idx) { - std::string st_name = "|__SvBI" + std::to_string(idx) +"__|"; - std::string next_st_name = idx < rstcycles -1 ? - "|__SvBI" + std::to_string(idx+1) +"__|" : - "|__SvI__|"; - BIn += "(declare-var " + st_name + " |%d%_s|)\n"; - - if (rst_neg) - rstseq += "(not (|%d%_n "+ rst_sig +"| " + st_name + "))\n"; - else - rstseq += "(|%d%_n "+ rst_sig +"| " + st_name + ")\n"; - rstseq += "(|%d%_t| " + st_name + " " + next_st_name + ")\n"; - rstseq += "(|%d%_h| " + st_name + ")\n"; - } - } // end of setting BIn and rstseq - - - std::string ret_tpl_smt; - if (_vtg_config.VerificationSettingAvoidIssueStage) - ret_tpl_smt = dual_ind_inv_reset_start_tmpl; - else - ret_tpl_smt = dual_ind_inv_tmpl; - { // replacing the init sequence - ret_tpl_smt = ReplaceAll(ReplaceAll(ret_tpl_smt, "%BIn%", BIn), "%rstseq%", rstseq); - } - - { // now create the template - // 1. func sub - ret_tpl_smt = ReplaceAll(ret_tpl_smt, "%wrapperSmt%", all_smt); - ret_tpl_smt = ReplaceAll(ret_tpl_smt, "%amcFunc_design%", amc_design); - ret_tpl_smt = ReplaceAll(ret_tpl_smt, "%amcFunc_wrapper%", amc_wrapper); - ret_tpl_smt = ReplaceAll(ret_tpl_smt, "%ASST%", asst); - ret_tpl_smt = ReplaceAll(ret_tpl_smt, "%ASPT%", aspt); - // 2. name sub - ret_tpl_smt = ReplaceAll(ret_tpl_smt, "%subi%", _vlg_mod_inst_name); - ret_tpl_smt = ReplaceAll(ret_tpl_smt, "%d%", vlg_top_module_name); - ret_tpl_smt = ReplaceAll(ret_tpl_smt, "%w%", top_mod_name); - } - - { // output the tpl - std::ofstream tpl_fout(tpl_name); - tpl_fout << ret_tpl_smt; - } // finish output - - } // dual_inv_tpl - - - -}; // namespace ilang diff --git a/src/vtarget-out/inv-syn/vtarget_gen_inv_abc.cc b/src/vtarget-out/inv-syn/vtarget_gen_inv_abc.cc deleted file mode 100644 index 30e3c2cda..000000000 --- a/src/vtarget-out/inv-syn/vtarget_gen_inv_abc.cc +++ /dev/null @@ -1,575 +0,0 @@ -/// \file Source of generating Yosys accepted problem, vlg, mem, script -/// the inv-syn related HC generation is located in inv_syn.cc -// --- Hongce Zhang - -#include -#ifdef INVSYN_INTERFACE - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -namespace ilang { - -#define VLG_TRUE "`true" -#define VLG_FALSE "`false" - -// initialize templates -static std::string abcGenerateSmtScript_wo_Array = R"***( -read_verilog -formal %topfile% -prep -top %module% -flatten -sim -clock clk -reset rst -rstlen %rstlen% -n %cycle% -w %module% -miter -assert %module% -%setundef -undriven -init -expose% -memory -nordff -techmap; opt -fast -write_blif %blifname% -)***"; - -// flatten before sim to avoid sim's none unique issue -// yosys template -static std::string abcGenerateAigerWInit_wo_Array = R"***( -read_verilog -formal %topfile% -prep -top %module% -flatten -sim -clock clk -reset rst -rstlen %rstlen% -n %cycle% -w %module% -miter -assert %module% -%setundef -undriven -init -expose% -memory -nordff -opt_clean -techmap -abc -fast -g AND -write_aiger -zinit -map %mapname% %aigname% -write_blif %blifname% -)***"; - -static std::string abcAigCmdNoGLA = R"***( - &read %aigname% - &put - fold - pdr - {inv_min} - inv_print -v -)***"; - -static std::string abcAigCmdGLA = R"***( - &read %aigname% - &gla -T 500 -F 200 -v - &gla_derive - &put - dc2 -v - dc2 -v - dc2 -v - dc2 -v - dc2 -v - dc2 -v - dc2 -v - dc2 -v - {scorr} - dc2 -v - dc2 -v - dc2 -v - dc2 -v - {lcorr} - dc2 -v - dc2 -v - dc2 -v - dc2 -v - pdr - {inv_min} - inv_print -v -)***"; - -static std::string abcCmdNoGLA = R"***( - read_blif %blifname% - strash - pdr - {inv_min} - inv_print -v -)***"; - -static std::string abcCmdGLA = R"***( - read_blif %blifname% - &get -n - &gla -T 500 -F 200 -v - &gla_derive - &put - dc2 -v - dc2 -v - dc2 -v - dc2 -v - dc2 -v - dc2 -v - dc2 -v - dc2 -v - {scorr} - dc2 -v - dc2 -v - dc2 -v - dc2 -v - {lcorr} - dc2 -v - dc2 -v - dc2 -v - dc2 -v - pdr - {inv_min} - inv_print -v -)***"; - -VlgSglTgtGen_Abc::~VlgSglTgtGen_Abc() {} - -VlgSglTgtGen_Abc::VlgSglTgtGen_Abc( - const std::string& - output_path, // will be a sub directory of the output_path of its parent - const InstrPtr& instr_ptr, // which could be an empty pointer, and it will - // be used to verify invariants - const InstrLvlAbsPtr& ila_ptr, const VerilogGenerator::VlgGenConfig& config, - nlohmann::json& _rf_vmap, nlohmann::json& _rf_cond, - VlgTgtSupplementaryInfo& _sup_info, VerilogInfo* _vlg_info_ptr, - const std::string& vlg_mod_inst_name, const std::string& ila_mod_inst_name, - const std::string& wrapper_name, - const std::vector& implementation_srcs, - const std::vector& implementation_include_path, - const vtg_config_t& vtg_config, backend_selector vbackend, - synthesis_backend_selector sbackend, const target_type_t& target_tp, - advanced_parameters_t* adv_ptr, bool GenerateProof, _chc_target_t chctarget, - bool useGLA, bool useCORR, bool useAIGER) - : VlgSglTgtGen(output_path, instr_ptr, ila_ptr, config, _rf_vmap, _rf_cond, - _sup_info, _vlg_info_ptr, vlg_mod_inst_name, - ila_mod_inst_name, wrapper_name, implementation_srcs, - implementation_include_path, vtg_config, vbackend, target_tp, - adv_ptr), - s_backend(sbackend), generate_proof(GenerateProof), - has_cex(adv_ptr && adv_ptr->_cex_obj_ptr), chc_target(chctarget), - useGla(useGLA), useCorr(useCORR), useAiger(useAIGER), disallowGla(false) { - - ILA_CHECK(vbackend == backend_selector::YOSYS) - << "Only support using yosys for chc target"; - - ILA_CHECK(chctarget == _chc_target_t::CEX) << "Target must be cex"; - ILA_CHECK(target_tp == target_type_t::INV_SYN_DESIGN_ONLY) - << "for cex chc, target type must be INV_SYN_DESIGN_ONLY: " << target_tp; - ILA_CHECK(has_cex) << "for cex chc, cex must be provided!"; - - ILA_CHECK(sbackend == synthesis_backend_selector::ABC) - << "Unknown synthesis backend:" << sbackend; - - ILA_CHECK(_vtg_config.YosysSmtFlattenHierarchy) - << "For ABC, hierarchy must be flattened!"; -} - -/// Add an assumption -void VlgSglTgtGen_Abc::add_a_direct_assumption(const std::string& aspt, - const std::string& dspt) { - _problems.assumptions[dspt].exprs.push_back(aspt); -} -/// Add an assertion -void VlgSglTgtGen_Abc::add_a_direct_assertion(const std::string& asst, - const std::string& dspt) { - _problems.assertions[dspt].exprs.push_back(asst); -} - -void VlgSglTgtGen_Abc::PreExportProcess() { - - std::string all_assert_wire_content; - std::string all_assume_wire_content; - - ILA_CHECK(target_type == target_type_t::INV_SYN_DESIGN_ONLY); - ILA_ERROR_IF(_problems.assertions.size() != 1) << "BUG in cex extract"; - - // you need to add assumptions as well - for (auto&& pbname_prob_pair : _problems.assumptions) { - const auto& prbname = pbname_prob_pair.first; - const auto& prob = pbname_prob_pair.second; - ILA_DLOG("VlgSglTgtGen_Abc.PreExportProcess") - << "Adding assumption:" << prbname; - - for (auto&& p : prob.exprs) { - if (all_assume_wire_content.empty()) - all_assume_wire_content = "(" + p + ")"; - else - all_assume_wire_content += "&& (" + p + ")"; - } // for prob.exprs - } // for _problems.assumption - - bool first = true; - // this is to check given invariants - for (auto&& pbname_prob_pair : _problems.assertions) { - // const auto& prbname = pbname_prob_pair.first; - const auto& prob = pbname_prob_pair.second; - - // ILA_CHECK(prbname == "cex_nonreachable_assert") - // << "BUG: assertion can only be cex reachability queries."; - // sanity check, should only be invariant's related asserts - - for (auto&& p : prob.exprs) { - // there should be only one expression (for cex target) - // ILA_CHECK(all_assert_wire_content.empty()); - if (first) - all_assert_wire_content = p; - else - all_assert_wire_content += " && " + p; - - first = false; - } // for expr - } // for problem - // add assert wire (though no use : make sure will not optimized away) - ILA_CHECK(!all_assert_wire_content.empty()) << "no property to check!"; - - vlg_wrapper.add_wire("__all_assert_wire__", 1, true); - vlg_wrapper.add_output("__all_assert_wire__", 1); - vlg_wrapper.add_assign_stmt("__all_assert_wire__", all_assert_wire_content); - - std::string precond; - disallowGla = false; - if (!all_assume_wire_content.empty()) { - ILA_CHECK( - !(_vtg_config.AbcUseAiger == false && - _vtg_config.AbcAssumptionStyle == _vtg_config.AigMiterExtraOutput)) - << "If you don't use aiger, and has assumptions, there is no way to " - "pass the extra output. (Will have an additional latch, but " - "currently we cannot interprete.)"; - if (_vtg_config.AbcAssumptionStyle == _vtg_config.AigMiterExtraOutput) { - disallowGla = true; - vlg_wrapper.add_wire("__all_assume_wire__", 1, true); - vlg_wrapper.add_output("__all_assume_wire__", 1); - vlg_wrapper.add_assign_stmt("__all_assume_wire__", - all_assume_wire_content); - vlg_wrapper.add_stmt("assume property (__all_assume_wire__);\n"); - } else { - vlg_wrapper.add_reg("__all_assumed_reg__", 1); - vlg_wrapper.add_stmt("always @(posedge clk) begin"); - vlg_wrapper.add_stmt("if (rst) __all_assumed_reg__ <= 0;"); - vlg_wrapper.add_stmt( - "else if (!__all_assume_wire__) __all_assumed_reg__ <= 1; end"); - - vlg_wrapper.add_wire("__all_assume_wire__", 1, true); - vlg_wrapper.add_output("__all_assume_wire__", 1); - vlg_wrapper.add_assign_stmt("__all_assume_wire__", - all_assume_wire_content); - precond = "!( __all_assume_wire__ && !__all_assumed_reg__) || "; - } - } // handle assumptions - - vlg_wrapper.add_stmt("assert property (" + precond + - " __all_assert_wire__ ); // the only assertion \n"); -} // PreExportProcess - -/// export the script to run the verification : -/// like "yosys gemsmt.ys" -void VlgSglTgtGen_Abc::Export_script(const std::string& script_name) { - abc_run_script_name = script_name; - /// TODO: BUG: modify this : use z3/freqHorn - - auto fname = os_portable_append_dir(_output_path, script_name); - std::ofstream fout(fname); - if (!fout.is_open()) { - ILA_ERROR << "Error writing to file:" << fname; - return; - } - fout << "#!/bin/bash" << std::endl; - // fout << "trap \"trap - SIGTERM && kill -- -$$\" SIGINT SIGTERM"< lineno - // open, read, count and write - // if it is a port name, we will ask user to specify its upper level - // signal name - VerilogModifier vlg_mod(vlg_info_ptr, - static_cast( - _vtg_config.PortDeclStyle), - _vtg_config.CosaAddKeep, - supplementary_info.width_info); - - for (auto&& refered_vlg_item : _all_referred_vlg_names) { - auto idx = refered_vlg_item.first.find("["); - auto removed_range_name = refered_vlg_item.first.substr(0, idx); - vlg_mod.RecordKeepSignalName(removed_range_name); - // auto sig = // no use, this is too late, vlg_wrapper already exported - vlg_mod.RecordConnectSigName(removed_range_name, - refered_vlg_item.second.range); - // vlg_wrapper.add_output(sig.first, sig.second); - } - vlg_mod.FinishRecording(); - - // auto tmp_fn = os_portable_append_dir(_output_path, tmp_design_file); - auto tmp_fn = os_portable_append_dir(_output_path, top_file_name); - // now let's do the job - for (auto&& fn : vlg_design_files) { - std::ifstream fin(fn); - std::ofstream fout(tmp_fn, std::ios_base::app); // append to a temp file - if (!fin.is_open()) { - ILA_ERROR << "Cannot read file:" << fn; - continue; - } - if (!fout.is_open()) { - ILA_ERROR << "Cannot open file for write:" << tmp_fn; - continue; - } - vlg_mod.ReadModifyWrite(fn, fin, fout); - } // for (auto && fn : vlg_design_files) - - // handles the includes - // .. (copy all the verilog file in the folder), this has to be os independent - if (vlg_include_files_path.size() != 0) { - // copy the files and specify the -I commandline to the run.sh - for (auto&& include_path : vlg_include_files_path) - os_portable_copy_dir(include_path, _output_path); - } - -} // Export_modify_verilog - -/// export the memory abstraction (implementation) -/// Yes, this is also implementation specific, (jasper may use a different one) -void VlgSglTgtGen_Abc::Export_mem(const std::string& mem_name) { - // we will ignore the mem_name - - auto outfn = os_portable_append_dir(_output_path, top_file_name); - std::ofstream fout(outfn, std::ios_base::app); // append - - VlgAbsMem::OutputMemFile(fout, - _vtg_config.VerificationSettingAvoidIssueStage); -} - -static void correct_blif_remove_non_init(const std::string& fn, - const std::string& fo) { - std::ifstream fin(fn); - std::ofstream fout(fo); - if (!fin.is_open()) { - ILA_ERROR << "Unable to read " << fn; - return; - } - if (!fout.is_open()) { - ILA_ERROR << "Unable to write " << fo; - return; - } - std::string line; - while (std::getline(fin, line)) { - if (StrStartsWith(line, ".latch ")) { - auto st_def = SplitSpaceTabEnter(line); - if (st_def.back() == "2") { - st_def.back() = "0"; - ILA_WARN << "Force state to be 0: " << st_def.at(2); - line = Join(st_def, " "); - } - } - // always write back - fout << line << "\n"; - } -} // correct_blif_remove_non_init - -// export the chc file -void VlgSglTgtGen_Abc::Export_problem(const std::string& extra_name) { - // used by export script! - - if (!useAiger) { - blif_fname = extra_name; - - // first generate a temporary smt - // and extract from it the necessary info - // "yosys --> blif " - generate_blif(os_portable_append_dir(_output_path, "__blif_prepare.blif"), - os_portable_append_dir(_output_path, "__gen_blif_script.ys")); - - correct_blif_remove_non_init( - os_portable_append_dir(_output_path, "__blif_prepare.blif"), - os_portable_append_dir(_output_path, blif_fname)); - } else { - aiger_fname = extra_name; - - generate_aiger( - os_portable_append_dir(_output_path, "__aiger_prepare.blif"), - os_portable_append_dir(_output_path, aiger_fname), - os_portable_append_dir(_output_path, aiger_fname + ".map"), - os_portable_append_dir(_output_path, "__gen_blif_script.ys")); - } -} // Export_problem - -void VlgSglTgtGen_Abc::ExportAll(const std::string& wrapper_name, // wrapper.v - const std::string& ila_vlg_name, // no use - const std::string& script_name, // the run.sh - const std::string& extra_name, // the chc - const std::string& mem_name) { // no use - - PreExportProcess(); - - if (os_portable_mkdir(_output_path) == false) - ILA_WARN << "Cannot create output directory:" << _output_path; - - // you don't need to worry about the path and names - Export_wrapper(wrapper_name); - // design only - // if (target_type == target_type_t::INSTRUCTIONS) - // Export_ila_vlg(ila_vlg_name); // this has to be after Export_wrapper - - // for Jasper, this will be put to multiple files - // for CoSA & Yosys, this will be put after the wrapper file (wrapper.v) - Export_modify_verilog(); // this must be after Export_wrapper - Export_mem(mem_name); - - // you need to create the map function -- - Export_problem(extra_name); // the gensmt.ys - - Export_script(script_name); -} - -/// generate the wrapper's smt first -void VlgSglTgtGen_Abc::generate_blif(const std::string& blif_name, - const std::string& ys_script_name) { - - auto ys_output_full_name = - os_portable_append_dir(_output_path, "__yosys_exec_result.txt"); - { // export to ys_script_name - std::ofstream ys_script_fout(ys_script_name); - - ys_script_fout << ReplaceAll( - ReplaceAll( - ReplaceAll( - ReplaceAll( - ReplaceAll( - ReplaceAll(abcGenerateSmtScript_wo_Array, "%topfile%", - os_portable_append_dir(_output_path, - top_file_name)), - "%module%", top_mod_name), - "%blifname%", blif_name), - "%setundef -undriven -init -expose%", - _vtg_config.YosysUndrivenNetAsInput - ? "setundef -undriven -init -expose" - : ""), - "%rstlen%", - std::to_string( - supplementary_info.cosa_yosys_reset_config.reset_cycles)), - "%cycle%", - std::to_string( - supplementary_info.cosa_yosys_reset_config.reset_cycles)); - } // finish writing - - std::string yosys = "yosys"; - - if (!_vtg_config.YosysPath.empty()) - yosys = os_portable_append_dir(_vtg_config.YosysPath, yosys); - - // execute it - std::vector cmd; - cmd.push_back(yosys); - cmd.push_back("-s"); - cmd.push_back(ys_script_name); - auto res = os_portable_execute_shell(cmd, ys_output_full_name); - ILA_ERROR_IF(res.failure != res.NONE) << "Executing Yosys failed!"; - ILA_ERROR_IF(res.failure == res.NONE && res.ret != 0) - << "Yosys returns error code:" << res.ret; -} // design_only_gen_smt - -/// generate the wrapper's smt first -void VlgSglTgtGen_Abc::generate_aiger(const std::string& blif_name, - const std::string& aiger_name, - const std::string& map_name, - const std::string& ys_script_name) { - - auto ys_output_full_name = - os_portable_append_dir(_output_path, "__yosys_exec_result.txt"); - { // export to ys_script_name - std::ofstream ys_script_fout(ys_script_name); - - ys_script_fout << ReplaceAll( - ReplaceAll( - ReplaceAll( - ReplaceAll( - ReplaceAll( - ReplaceAll( - ReplaceAll( - ReplaceAll(abcGenerateAigerWInit_wo_Array, - "%topfile%", - os_portable_append_dir( - _output_path, top_file_name)), - "%module%", top_mod_name), - "%blifname%", blif_name), - "%aigname%", aiger_name), - "%mapname%", map_name), - "%setundef -undriven -init -expose%", - _vtg_config.YosysUndrivenNetAsInput - ? "setundef -undriven -init -expose" - : ""), - "%rstlen%", - std::to_string( - supplementary_info.cosa_yosys_reset_config.reset_cycles)), - "%cycle%", - std::to_string( - supplementary_info.cosa_yosys_reset_config.reset_cycles)); - } // finish writing - - std::string yosys = "yosys"; - - if (!_vtg_config.YosysPath.empty()) - yosys = os_portable_append_dir(_vtg_config.YosysPath, yosys); - - // execute it - std::vector cmd; - cmd.push_back(yosys); - cmd.push_back("-s"); - cmd.push_back(ys_script_name); - auto res = os_portable_execute_shell(cmd, ys_output_full_name); - ILA_ERROR_IF(res.failure != res.NONE) << "Executing Yosys failed!"; - ILA_ERROR_IF(res.failure == res.NONE && res.ret != 0) - << "Yosys returns error code:" << res.ret; -} // generate_aiger - -}; // namespace ilang - -#endif // INVSYN_INTERFACE diff --git a/src/vtarget-out/inv-syn/vtarget_gen_inv_chc.cc b/src/vtarget-out/inv-syn/vtarget_gen_inv_chc.cc deleted file mode 100644 index af6bc8672..000000000 --- a/src/vtarget-out/inv-syn/vtarget_gen_inv_chc.cc +++ /dev/null @@ -1,782 +0,0 @@ -/// \file Source of generating Yosys accepted problem, vlg, mem, script -/// the inv-syn related HC generation is located in inv_syn.cc -// --- Hongce Zhang - -#include -#ifdef INVSYN_INTERFACE - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -namespace ilang { - -#define VLG_TRUE "`true" -#define VLG_FALSE "`false" - -// hierarchy --> opt may not be useful -// mux undef may be useful? - -// initialize templates -static std::string chcGenerateSmtScript_wo_Array = R"***( -hierarchy -check -proc -opt -opt_expr -mux_undef -opt -opt -%flatten% -%setundef -undriven -init -expose% -sim -clock clk -reset rst -rstlen %rstlen% -n %cycle% -w %module% -memory -nordff -proc -opt;; -)***"; - -// should not be used -static std::string chcGenerateSmtScript_w_Array = R"***( -hierarchy -check -proc -opt -opt_expr -mux_undef -opt -opt -%flatten% -%setundef -undriven -init -expose% -sim -clock clk -reset rst -rstlen %rstlen% -n %cycle% -w %module% -memory_dff -wr_only -memory_collect; -memory_unpack -splitnets -driver -opt;; -memory_collect; -pmuxtree -proc -opt;; -)***"; - -static std::string inv_syn_tmpl_datatypes = R"***( -;---------------------------------------- -; Single Inductive Invariant Synthesis -; Generated from ILAng -;---------------------------------------- -%(set-option :fp.engine spacer)% - -%% - -(declare-rel INV (|%1%_s|)) -(declare-rel fail ()) - -(declare-var |__S__| |%1%_s|) -(declare-var |__S'__| |%1%_s|) - -; -------------------------------- -; note if you want it a bit faster -; if can try removing wrapper-u in rule 1 -; or remove the assume previous invariants -; -------------------------------- - -; init => inv -(rule (=> - (and - (|%1%_i| |__S__|) - (|%1%_u| |__S__|) - (|%1%_h| |__S__|) - ) - (INV |__S__|))) - -; inv /\ T => inv -(rule (=> (and - (INV |__S__|) - (|%1%_u| |__S__|) - (|%1%_u| |__S'__|) - (|%1%_h| |__S__|) - (|%1%_h| |__S'__|) - (|%1%_t| |__S__| |__S'__|)) - (INV |__S'__|))) - -; inv /\ ~p => \bot -(rule (=> (and - (INV |__S__|) - (|%1%_u| |__S__|) - (|%1%_h| |__S__|) - (not (|%1%_a| |__S__|))) - fail)) - -; (query fail :print-certificate true) - -)***"; - -static std::string inv_syn_tmpl_wo_datatypes = R"***( -;---------------------------------------- -; Single Inductive Invariant Synthesis -; Generated from ILAng -;---------------------------------------- -%(set-option :fp.engine spacer)% - -%% - -(declare-rel INV %WrapperDataType%) -(declare-rel fail ()) - - -%State% -%StatePrime% -;(declare-var |__S__state| Type) -;(declare-var |__S'__state| Type) - -; same for flattened - -; init => inv -(rule (=> - (and - (|%WrapperName%_i| %Ss%) - (|%WrapperName%_u| %Ss%) - (|%WrapperName%_h| %Ss%) - ) - (INV %Ss%))) - -; inv /\ T => inv -(rule (=> (and - (INV %Ss%) - (|%WrapperName%_u| %Ss%) - (|%WrapperName%_u| %Sps%) - (|%WrapperName%_h| %Ss%) - (|%WrapperName%_h| %Sps%) - (|%WrapperName%_t| %Ss% %Sps%)) - (INV %Sps%))) - -; inv /\ ~p => \bot -(rule (=> (and - (INV %Ss%) - (|%WrapperName%_u| %Ss%) - (|%WrapperName%_h| %Ss%) - (not (|%WrapperName%_a| %Ss%))) - fail)) - -; (query fail :print-certificate true) - -)***"; - -static std::string RewriteDatatypeChc(const std::string& tmpl, - const std::vector& dt, - const std::string& wrapper_mod_name); - -VlgSglTgtGen_Chc::~VlgSglTgtGen_Chc() {} - -VlgSglTgtGen_Chc::VlgSglTgtGen_Chc( - const std::string& - output_path, // will be a sub directory of the output_path of its parent - const InstrPtr& instr_ptr, // which could be an empty pointer, and it will - // be used to verify invariants - const InstrLvlAbsPtr& ila_ptr, const VerilogGenerator::VlgGenConfig& config, - nlohmann::json& _rf_vmap, nlohmann::json& _rf_cond, - VlgTgtSupplementaryInfo& _sup_info, VerilogInfo* _vlg_info_ptr, - const std::string& vlg_mod_inst_name, const std::string& ila_mod_inst_name, - const std::string& wrapper_name, - const std::vector& implementation_srcs, - const std::vector& implementation_include_path, - const vtg_config_t& vtg_config, backend_selector vbackend, - synthesis_backend_selector sbackend, const target_type_t& target_tp, - advanced_parameters_t* adv_ptr, bool GenerateProof, _chc_target_t chctarget) - : VlgSglTgtGen(output_path, instr_ptr, ila_ptr, config, _rf_vmap, _rf_cond, - _sup_info, _vlg_info_ptr, vlg_mod_inst_name, - ila_mod_inst_name, wrapper_name, implementation_srcs, - implementation_include_path, vtg_config, vbackend, target_tp, - adv_ptr), - s_backend(sbackend), generate_proof(GenerateProof), - has_cex(adv_ptr && adv_ptr->_cex_obj_ptr), chc_target(chctarget) { - - ILA_CHECK(vbackend == backend_selector::YOSYS) - << "Only support using yosys for chc target"; - - ILA_CHECK(chctarget == _chc_target_t::CEX) - << "Bug: VlgSglTgtGen_Chc should only be used for CEX"; - - ILA_CHECK(target_tp == target_type_t::INV_SYN_DESIGN_ONLY) - << "for cex chc, target type must be INV_SYN_DESIGN_ONLY: " << target_tp; - ILA_CHECK(has_cex) << "for cex chc, cex must be provided!"; - ILA_CHECK(_vtg_config.YosysSmtStateSort == _vtg_config.Datatypes) - << "invariant synthesis only supports datatypes state encoding."; - - ILA_CHECK(sbackend == synthesis_backend_selector::GRAIN or - sbackend == synthesis_backend_selector::Z3) - << "Unknown synthesis backend:" << sbackend; - - if (sbackend == synthesis_backend_selector::GRAIN) - ILA_CHECK(vtg_config.YosysSmtFlattenDatatype) - << "For Grain, datatype must be flattened!"; - - ILA_CHECK(_vtg_config.YosysSmtFlattenHierarchy) - << "Currently implementation only supports extract invariants from " - "flattened hierarchy."; -} - -/// Add an assumption -void VlgSglTgtGen_Chc::add_a_direct_assumption(const std::string& aspt, - const std::string& dspt) { - _problems.assumptions[dspt].exprs.push_back(aspt); -} -/// Add an assertion -void VlgSglTgtGen_Chc::add_a_direct_assertion(const std::string& asst, - const std::string& dspt) { - _problems.assertions[dspt].exprs.push_back(asst); -} - -void VlgSglTgtGen_Chc::PreExportProcess() { - - std::string all_assert_wire_content; - std::string all_assume_wire_content; - - ILA_CHECK(target_type == target_type_t::INV_SYN_DESIGN_ONLY); - ILA_ERROR_IF(_problems.assertions.size() != 1) << "BUG in cex extract"; - - // you need to add assumptions as well - for (auto&& pbname_prob_pair : _problems.assumptions) { - const auto& prbname = pbname_prob_pair.first; - const auto& prob = pbname_prob_pair.second; - ILA_DLOG("VlgSglTgtGen_Chc.PreExportProcess") - << "Adding assumption:" << prbname; - - for (auto&& p : prob.exprs) { - vlg_wrapper.add_stmt("assume property (" + p + "); //" + prbname + "\n"); - if (all_assume_wire_content.empty()) - all_assume_wire_content = "(" + p + ")"; - else - all_assume_wire_content += "&& (" + p + ")"; - } // for prob.exprs - } // for _problems.assumption - - bool first = true; - // this is to check given invariants - for (auto&& pbname_prob_pair : _problems.assertions) { - const auto& prbname = pbname_prob_pair.first; - const auto& prob = pbname_prob_pair.second; - - // ILA_CHECK(prbname == "cex_nonreachable_assert") - // << "BUG: assertion can only be cex reachability queries."; - // sanity check, should only be invariant's related asserts - - for (auto&& p : prob.exprs) { - vlg_wrapper.add_stmt("assert property (" + p + "); //" + prbname + "\n"); - // there should be only one expression (for cex target) - // ILA_CHECK(all_assert_wire_content.empty()); - if (first) - all_assert_wire_content = p; - else - all_assert_wire_content += " && " + p; - - first = false; - } // for expr - } // for problem - // add assert wire (though no use : make sure will not optimized away) - ILA_CHECK(!all_assert_wire_content.empty()) << "no property to check!"; - - vlg_wrapper.add_wire("__all_assert_wire__", 1, true); - vlg_wrapper.add_output("__all_assert_wire__", 1); - vlg_wrapper.add_assign_stmt("__all_assert_wire__", all_assert_wire_content); - - if (!all_assume_wire_content.empty()) { - vlg_wrapper.add_wire("__all_assume_wire__", 1, true); - vlg_wrapper.add_output("__all_assume_wire__", 1); - vlg_wrapper.add_assign_stmt("__all_assume_wire__", all_assume_wire_content); - } -} // PreExportProcess - -/// export the script to run the verification : -/// like "yosys gemsmt.ys" -void VlgSglTgtGen_Chc::Export_script(const std::string& script_name) { - chc_run_script_name = script_name; - /// TODO: BUG: modify this : use z3/freqHorn - - auto fname = os_portable_append_dir(_output_path, script_name); - std::ofstream fout(fname); - if (!fout.is_open()) { - ILA_ERROR << "Error writing to file:" << fname; - return; - } - fout << "#!/bin/bash" << std::endl; - // fout << "trap \"trap - SIGTERM && kill -- -$$\" SIGINT SIGTERM"< lineno - // open, read, count and write - // if it is a port name, we will ask user to specify its upper level - // signal name - VerilogModifier vlg_mod(vlg_info_ptr, - static_cast( - _vtg_config.PortDeclStyle), - _vtg_config.CosaAddKeep, - supplementary_info.width_info); - - for (auto&& refered_vlg_item : _all_referred_vlg_names) { - auto idx = refered_vlg_item.first.find("["); - auto removed_range_name = refered_vlg_item.first.substr(0, idx); - vlg_mod.RecordKeepSignalName(removed_range_name); - // auto sig = // no use, this is too late, vlg_wrapper already exported - vlg_mod.RecordConnectSigName(removed_range_name, - refered_vlg_item.second.range); - // vlg_wrapper.add_output(sig.first, sig.second); - } - vlg_mod.FinishRecording(); - - // auto tmp_fn = os_portable_append_dir(_output_path, tmp_design_file); - auto tmp_fn = os_portable_append_dir(_output_path, top_file_name); - // now let's do the job - for (auto&& fn : vlg_design_files) { - std::ifstream fin(fn); - std::ofstream fout(tmp_fn, std::ios_base::app); // append to a temp file - if (!fin.is_open()) { - ILA_ERROR << "Cannot read file:" << fn; - continue; - } - if (!fout.is_open()) { - ILA_ERROR << "Cannot open file for write:" << tmp_fn; - continue; - } - vlg_mod.ReadModifyWrite(fn, fin, fout); - } // for (auto && fn : vlg_design_files) - - // handles the includes - // .. (copy all the verilog file in the folder), this has to be os independent - if (vlg_include_files_path.size() != 0) { - // copy the files and specify the -I commandline to the run.sh - for (auto&& include_path : vlg_include_files_path) - os_portable_copy_dir(include_path, _output_path); - } - -} // Export_modify_verilog - -/// export the memory abstraction (implementation) -/// Yes, this is also implementation specific, (jasper may use a different one) -void VlgSglTgtGen_Chc::Export_mem(const std::string& mem_name) { - // we will ignore the mem_name - - auto outfn = os_portable_append_dir(_output_path, top_file_name); - std::ofstream fout(outfn, std::ios_base::app); // append - - VlgAbsMem::OutputMemFile(fout, - _vtg_config.VerificationSettingAvoidIssueStage); -} - -// export the chc file -void VlgSglTgtGen_Chc::Export_problem(const std::string& extra_name) { - // used by export script! - chc_prob_fname = extra_name; - - // first generate a temporary smt - // and extract from it the necessary info - - // first generate a temporary smt - // and extract from it the necessary info - // this is the CHC-style thing - design_only_gen_smt( - os_portable_append_dir(_output_path, "__design_smt.smt2"), - os_portable_append_dir(_output_path, "__gen_smt_script.ys")); - // if (_vtg_config.YosysSmtStateSort == _vtg_config.DataSort) - convert_smt_to_chc_datatype( - os_portable_append_dir(_output_path, "__design_smt.smt2"), - os_portable_append_dir(_output_path, - s_backend == synthesis_backend_selector::GRAIN - ? "grain_prep.txt" - : extra_name)); - - // for grain : convert wrapper# --> w wrapper_ --> w - if (s_backend == synthesis_backend_selector::GRAIN) { - std::ifstream fin(os_portable_append_dir(_output_path, "grain_prep.txt")); - std::ofstream fout(os_portable_append_dir(_output_path, extra_name)); - if (!fin.is_open()) { - ILA_ERROR << "Cannot read from : " - << os_portable_append_dir(_output_path, "grain_prep.txt"); - return; - } - if (!fout.is_open()) { - ILA_ERROR << "Cannot write to : " - << os_portable_append_dir(_output_path, extra_name); - return; - } - std::string line; - while (std::getline(fin, line)) { - fout << ReplaceAll(ReplaceAll(line, "wrapper#", "w"), "wrapper_", "w_") - << "\n"; - } - } - -} // Export_problem - -std::shared_ptr -VlgSglTgtGen_Chc::GetDesignSmtInfo() const { - return design_smt_info; -} - -void VlgSglTgtGen_Chc::ExportAll(const std::string& wrapper_name, // wrapper.v - const std::string& ila_vlg_name, // no use - const std::string& script_name, // the run.sh - const std::string& extra_name, // the chc - const std::string& mem_name) { // no use - - PreExportProcess(); - - if (os_portable_mkdir(_output_path) == false) - ILA_WARN << "Cannot create output directory:" << _output_path; - - // you don't need to worry about the path and names - Export_wrapper(wrapper_name); - // design only - // if (target_type == target_type_t::INSTRUCTIONS) - // Export_ila_vlg(ila_vlg_name); // this has to be after Export_wrapper - - // for Jasper, this will be put to multiple files - // for CoSA & Yosys, this will be put after the wrapper file (wrapper.v) - Export_modify_verilog(); // this must be after Export_wrapper - Export_mem(mem_name); - - // you need to create the map function -- - Export_problem(extra_name); // the gensmt.ys - - Export_script(script_name); -} - -/// generate the wrapper's smt first -void VlgSglTgtGen_Chc::design_only_gen_smt(const std::string& smt_name, - const std::string& ys_script_name) { - - auto ys_output_full_name = - os_portable_append_dir(_output_path, "__yosys_exec_result.txt"); - { // export to ys_script_name - std::ofstream ys_script_fout(ys_script_name); - - std::string write_smt2_options = - " -mem -bv "; // future work : -stbv, or nothing - // if (_vtg_config.YosysSmtStateSort == _vtg_config.DataSort) - write_smt2_options += "-stdt "; - // else if (_vtg_config.YosysSmtStateSort == _vtg_config.BitVec) - // write_smt2_options += "-stbv "; - // else - // ILA_CHECK(false) << "Unsupported smt state sort encoding:" << - // _vtg_config.YosysSmtStateSort; - - ys_script_fout << "read_verilog -sv " - << os_portable_append_dir(_output_path, top_file_name) - << std::endl; - ys_script_fout << "prep -top " << top_mod_name << std::endl; - - auto chcGenSmtTemplate = _vtg_config.ChcWordBlastArray - ? chcGenerateSmtScript_wo_Array - : chcGenerateSmtScript_w_Array; - - ys_script_fout << ReplaceAll( - ReplaceAll( - ReplaceAll( - ReplaceAll(ReplaceAll(chcGenSmtTemplate, "%flatten%", - _vtg_config.YosysSmtFlattenHierarchy - ? "flatten;" - : ""), - "%setundef -undriven -init -expose%", - _vtg_config.YosysUndrivenNetAsInput - ? "setundef -undriven -init -expose" - : ""), - "%rstlen%", - std::to_string( - supplementary_info.cosa_yosys_reset_config.reset_cycles)), - "%cycle%", - std::to_string( - supplementary_info.cosa_yosys_reset_config.reset_cycles)), - "%module%", top_mod_name); - - ys_script_fout << "write_smt2" << write_smt2_options << smt_name; - } // finish writing - - std::string yosys = "yosys"; - - if (!_vtg_config.YosysPath.empty()) - yosys = os_portable_append_dir(_vtg_config.YosysPath, yosys); - - // execute it - std::vector cmd; - cmd.push_back(yosys); - cmd.push_back("-s"); - cmd.push_back(ys_script_name); - auto res = os_portable_execute_shell(cmd, ys_output_full_name); - ILA_ERROR_IF(res.failure != res.NONE) << "Executing Yosys failed!"; - ILA_ERROR_IF(res.failure == res.NONE && res.ret != 0) - << "Yosys returns error code:" << res.ret; -} // design_only_gen_smt - -// currently we don't support prepresenting state using a bit vector -#if 0 -void VlgSglTgtGen_Chc::convert_smt_to_chc_bitvec( - const std::string & smt_fname, const std::string & chc_fname, - const std::string & wrapper_mod_name) { - - std::stringstream ibuf; - { // read file - std::ifstream smt_fin( smt_fname ); - if(! smt_fin.is_open()) { - ILA_ERROR << "Cannot read from " << smt_fname; - return; - } - ibuf << smt_fin.rdbuf(); - } // end read file - - std::string smt_converted; - smt_converted = ibuf.str(); - - std::string chc; - - chc = ReplaceAll(inv_syn_tmpl_datatypes, - "%(set-option :fp.engine spacer)%" , - s_backend == synthesis_backend_selector::GRAIN ? "" : "(set-option :fp.engine spacer)"); - chc = ReplaceAll(chc, "(|%1%_h| |__BI__|)", _vtg_config.YosysSmtFlattenHierarchy ? "" : "(|%1%_h| |__BI__|)"); - chc = ReplaceAll(chc, "(|%1%_h| |__I__|)" , _vtg_config.YosysSmtFlattenHierarchy ? "" : "(|%1%_h| |__I__|)"); - chc = ReplaceAll(chc, "(|%1%_h| |__S__|)" , _vtg_config.YosysSmtFlattenHierarchy ? "" : "(|%1%_h| |__S__|)"); - chc = ReplaceAll(chc, "(|%1%_h| |__S'__|)", _vtg_config.YosysSmtFlattenHierarchy ? "" : "(|%1%_h| |__S'__|)"); - chc = ReplaceAll(chc,"%1%", wrapper_mod_name); - chc = ReplaceAll(chc, "%%", smt_converted ); - - { // (query fail :print-certificate true) - if (generate_proof) - chc += "\n(query fail :print-certificate true)\n"; - else - chc += "\n(query fail)\n"; - } - - { // write file - std::ofstream chc_fout(chc_fname); - if (! chc_fout.is_open()) { - ILA_ERROR << "Error writing to : "<< chc_fname; - return; - } - chc_fout << chc; - } // end write file -} -#endif - -void VlgSglTgtGen_Chc::convert_smt_to_chc_datatype( - const std::string& smt_fname, const std::string& chc_fname) { - - std::stringstream ibuf; - { // read file - std::ifstream smt_fin(smt_fname); - if (!smt_fin.is_open()) { - ILA_ERROR << "Cannot read from " << smt_fname; - return; - } - ibuf << smt_fin.rdbuf(); - } // end read file - - std::string smt_converted; - design_smt_info = std::make_shared(ibuf.str()); - if (_vtg_config.YosysSmtFlattenDatatype) { - design_smt_info->BreakDatatypes(); - // smt_rewriter.AddNoChangeStateUpdateFunction(); - smt_converted = design_smt_info->Export(); - } else { - smt_converted = ibuf.str(); - } - - std::string wrapper_mod_name = - design_smt_info->get_module_def_orders().back(); - // construct the template - - std::string chc; - if (_vtg_config.YosysSmtFlattenDatatype) { - const auto& datatype_top_mod = - design_smt_info->get_module_flatten_dt(wrapper_mod_name); - auto tmpl = ReplaceAll(inv_syn_tmpl_wo_datatypes, - "%(set-option :fp.engine spacer)%", - s_backend == synthesis_backend_selector::GRAIN - ? "" - : "(set-option :fp.engine spacer)"); - - tmpl = ReplaceAll( - tmpl, "(|%WrapperName%_u| %Ss%)", - _vtg_config.ChcAssumptionsReset ? "(|%WrapperName%_u| %Ss%)" : ""); - tmpl = ReplaceAll( - tmpl, "(|%WrapperName%_u| %Sps%)", - _vtg_config.ChcAssumptionNextState ? "(|%WrapperName%_u| %Sps%)" : ""); - tmpl = ReplaceAll(tmpl, "(|%WrapperName%_u| %Ss%)", - _vtg_config.ChcAssumptionEnd ? "(|%WrapperName%_u| %Ss%)" - : ""); - tmpl = ReplaceAll( - tmpl, "(|%WrapperName%_h| %Ss%)", - _vtg_config.YosysSmtFlattenHierarchy ? "" : "(|%WrapperName%_h| %Ss%)"); - tmpl = ReplaceAll(tmpl, "(|%WrapperName%_h| %Sps%)", - _vtg_config.YosysSmtFlattenHierarchy - ? "" - : "(|%WrapperName%_h| %Sps%)"); - tmpl = ReplaceAll(tmpl, "(and", - !_vtg_config.ChcAssumptionsReset && - _vtg_config.YosysSmtFlattenHierarchy - ? "" - : "(and"); - tmpl = ReplaceAll(tmpl, ")", - !_vtg_config.ChcAssumptionsReset && - _vtg_config.YosysSmtFlattenHierarchy - ? "" - : ")"); - - chc = RewriteDatatypeChc(tmpl, datatype_top_mod, wrapper_mod_name); - - chc = ReplaceAll(chc, "%%", smt_converted); - - } else { - chc = ReplaceAll(inv_syn_tmpl_datatypes, "%(set-option :fp.engine spacer)%", - s_backend == synthesis_backend_selector::GRAIN - ? "" - : "(set-option :fp.engine spacer)"); - - chc = - ReplaceAll(chc, "(|%1%_u| |__S__|)", - _vtg_config.ChcAssumptionsReset ? "(|%1%_u| |__S__|)" : ""); - chc = ReplaceAll(chc, "(|%1%_u| |__S'__|)", - _vtg_config.ChcAssumptionNextState ? "(|%1%_u| |__S'__|)" - : ""); - chc = ReplaceAll(chc, "(|%1%_u| |__S__|)", - _vtg_config.ChcAssumptionEnd ? "(|%1%_u| |__S__|)" : ""); - chc = ReplaceAll( - chc, "(|%1%_h| |__S__|)", - _vtg_config.YosysSmtFlattenHierarchy ? "" : "(|%1%_h| |__S__|)"); - chc = ReplaceAll( - chc, "(|%1%_h| |__S'__|)", - _vtg_config.YosysSmtFlattenHierarchy ? "" : "(|%1%_h| |__S'__|)"); - chc = ReplaceAll(chc, "(and", - !_vtg_config.ChcAssumptionsReset && - _vtg_config.YosysSmtFlattenHierarchy - ? "" - : "(and"); - chc = ReplaceAll(chc, ")", - !_vtg_config.ChcAssumptionsReset && - _vtg_config.YosysSmtFlattenHierarchy - ? "" - : ")"); - chc = ReplaceAll(chc, "%1%", wrapper_mod_name); - chc = ReplaceAll(chc, "%%", smt_converted); - } // end of ~_vtg_config.YosysSmtFlattenDatatype -- no convert - - { // (query fail :print-certificate true) - if (generate_proof) - chc += "\n(query fail :print-certificate true)\n"; - else - chc += "\n(query fail)\n"; - } - - { // write file - std::ofstream chc_fout(chc_fname); - if (!chc_fout.is_open()) { - ILA_ERROR << "Error writing to : " << chc_fname; - return; - } - chc_fout << chc; - } // end write file - -} // convert_smt_to_chc_datatype - -// %WrapperName% -// %WrapperDataType% -// %BeforeInitVar% -// %InitVar% -// %State% -// %StatePrime% -// %BIs% %Is% %Ss% %Sps% -static std::string RewriteDatatypeChc(const std::string& tmpl, - const std::vector& dt, - const std::string& wrapper_mod_name) { - - std::string chc = tmpl; - - std::vector inv_tps; - smt::YosysSmtParser::convert_datatype_to_type_vec(dt, inv_tps); - auto WrapperDataType = smt::var_type::toString(inv_tps); - - // %State% - // %StatePrime% - // declare-var s ... - std::string State; - std::string StatePrime; - // %Ss% %Sps% - std::string Ss; - std::string Sps; - bool first = true; - - std::set name_set; // avoid repetition - for (auto&& st : dt) { - auto st_name = st.verilog_name.back() == '.' || st.verilog_name.empty() - ? st.internal_name - : st.verilog_name; - st_name = ReplaceAll(st_name, "|", ""); // remove its || - // check no repetition is very important! - ILA_CHECK(!IN(st_name, name_set)) << "Bug: name repetition!"; - ILA_CHECK(!st._type.is_datatype()); - name_set.insert(st_name); - auto type_string = st._type.toString(); - State += "(declare-var |S_" + st_name + "| " + type_string + ")\n"; - StatePrime += "(declare-var |S'_" + st_name + "| " + type_string + ")\n"; - - if (!first) { - Ss += " "; - Sps += " "; - } - first = false; - Ss += "|S_" + st_name + "|"; - Sps += "|S'_" + st_name + "|"; - } - // Replacement - chc = ReplaceAll(chc, "%WrapperName%", wrapper_mod_name); - chc = ReplaceAll(chc, "%WrapperDataType%", WrapperDataType); - chc = ReplaceAll(chc, "%State%", State); - chc = ReplaceAll(chc, "%StatePrime%", StatePrime); - chc = ReplaceAll(chc, "%Ss%", Ss); - chc = ReplaceAll(chc, "%Sps%", Sps); - - return chc; -} // RewriteDatatypeChc - -}; // namespace ilang - -#endif // INVSYN_INTERFACE \ No newline at end of file diff --git a/src/vtarget-out/inv-syn/vtarget_gen_inv_enhance.cc b/src/vtarget-out/inv-syn/vtarget_gen_inv_enhance.cc deleted file mode 100644 index 9991937d3..000000000 --- a/src/vtarget-out/inv-syn/vtarget_gen_inv_enhance.cc +++ /dev/null @@ -1,680 +0,0 @@ -/// \file Verilog Verification Target Generator -- generating CHC target to -/// enhance invariant (design-only, same as the invariant target) We use yosys -/// to convert Verilog to smt-lib2, and then it will be parsed and re-format by -/// smt-io and use that information, it will create horn clauses This file -/// should not be included by the user code, as it requires the impl. - -/// This is for Grain only invariant enhancements/strengthening by syntax -// ---Hongce Zhang - -/// the monolithic CHC generation is located in inv_syn.cc - -#include -#ifdef INVSYN_INTERFACE - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -namespace ilang { - -#define VLG_TRUE "`true" -#define VLG_FALSE "`false" - -// initialize templates -std::string chcEnhanceGenerateSmtScript_wo_Array = R"***( -hierarchy -check -proc -opt -opt_expr -mux_undef -opt -opt -%flatten% -sim -clock clk -reset rst -n 1 -w %topmodule% -memory -nordff -proc -opt;; -)***"; - -std::string inv_enhance_tmpl_datatypes = R"***( -;---------------------------------------- -; Single Inductive Invariant Synthesis -; Generated from ILAng -;---------------------------------------- -(set-option :fp.engine spacer) - - -%% - -;(declare-rel INIT (|%1%_s|)) -;(declare-rel T (|%1%_s|) (|%1%_s|)) -(declare-rel INV (|%1%_s|)) -(declare-rel fail ()) - - -(declare-var |__I__| |%1%_s|) - -(declare-var |__S__| |%1%_s|) -(declare-var |__S'__| |%1%_s|) - -; -------------------------------- -; note if you want it a bit faster -; if can try removing wrapper-u in rule 1 -; or remove the assume previous invariants -; -------------------------------- - -; init => inv -(rule (=> (and - (|%1%_i| |__I__|) - (|%1%_h| |__I__|) - (|%1%_u| |__I__|)) - (INV |__I__|))) - -; inv /\ T => inv -(rule (=> (and - (INV |__S__|) - (|%1%_u| |__S__|) - (|%1%_u| |__S'__|) - (|%1%_h| |__S__|) - (|%1%_h| |__S'__|) - (|%1%_t| |__S__| |__S'__|)) - (INV |__S'__|))) - -; inv /\ ~p => \bot -(rule (=> (and - (INV |__S__|) - (|%1%_u| |__S__|) - (|%1%_h| |__S__|) - (not (|%1%_a| |__S__|))) - fail)) - -; (query fail :print-certificate true) - -)***"; - -std::string inv_enhance_tmpl_wo_datatypes = R"***( -;---------------------------------------- -; Single Inductive Invariant Synthesis -; Generated from ILAng -;---------------------------------------- - -%% - -(declare-rel INV %WrapperDataType%) -(declare-rel fail ()) - -%InitVar% -;(declare-var |__I__state| Type) - -%State% -%StatePrime% -;(declare-var |__S__state| Type) -;(declare-var |__S'__state| Type) - -; same for flattened - -; init => inv -(rule (=> (and - (|%WrapperName%_i| %Is%) - (|%WrapperName%_h| %Is%) - (|%WrapperName%_u| %Is%)) - (INV %Is%))) - -; inv /\ T => inv -(rule (=> (and - (INV %Ss%) - (|%WrapperName%_u| %Ss%) - (|%WrapperName%_u| %Sps%) - (|%WrapperName%_h| %Ss%) - (|%WrapperName%_h| %Sps%) - (|%WrapperName%_t| %Ss% %Sps%)) - (INV %Sps%))) - -; inv /\ ~p => \bot -(rule (=> (and - (INV %Ss%) - (|%WrapperName%_u| %Ss%) - (|%WrapperName%_h| %Ss%) - (not (|%WrapperName%_a| %Ss%))) - fail)) - -; (query fail :print-certificate true) - -)***"; - -static std::string RewriteDatatypeChc(const std::string& tmpl, - const std::vector& dt, - const std::string& wrapper_mod_name); - -VlgSglTgtGen_Chc_wCNF::~VlgSglTgtGen_Chc_wCNF() {} - -VlgSglTgtGen_Chc_wCNF::VlgSglTgtGen_Chc_wCNF( - const std::string& - output_path, // will be a sub directory of the output_path of its parent - const InstrPtr& instr_ptr, // which could be an empty pointer, and it will - // be used to verify invariants - const InstrLvlAbsPtr& ila_ptr, const VerilogGenerator::VlgGenConfig& config, - nlohmann::json& _rf_vmap, nlohmann::json& _rf_cond, - VlgTgtSupplementaryInfo& _sup_info, VerilogInfo* _vlg_info_ptr, - const std::string& vlg_mod_inst_name, const std::string& ila_mod_inst_name, - const std::string& wrapper_name, - const std::vector& implementation_srcs, - const std::vector& implementation_include_path, - const vtg_config_t& vtg_config, backend_selector vbackend, - synthesis_backend_selector sbackend, const target_type_t& target_tp, - advanced_parameters_t* adv_ptr, bool GenerateProof, _chc_target_t chctarget) - : VlgSglTgtGen(output_path, instr_ptr, ila_ptr, config, _rf_vmap, _rf_cond, - _sup_info, _vlg_info_ptr, vlg_mod_inst_name, - ila_mod_inst_name, wrapper_name, implementation_srcs, - implementation_include_path, vtg_config, vbackend, target_tp, - adv_ptr), - s_backend(sbackend), generate_proof(GenerateProof), - has_cex(adv_ptr && adv_ptr->_cex_obj_ptr), chc_target(chctarget) { - - ILA_CHECK(vbackend == backend_selector::YOSYS) - << "Only support using yosys for chc target"; - - ILA_CHECK(chctarget == _chc_target_t::CEX) << "Target type must be chc"; - ILA_CHECK(target_tp == target_type_t::INV_SYN_DESIGN_ONLY) - << "for cex chc, target type must be INV_SYN_DESIGN_ONLY: " << target_tp; - ILA_CHECK(has_cex) << "for cex chc, cex must be provided!"; - ILA_ERROR_IF(_vtg_config.YosysSmtStateSort != _vtg_config.Datatypes) - << "will ignore smt non-datatype encoding option"; - - ILA_CHECK(sbackend == synthesis_backend_selector::GRAIN) - << "Only support grain backend" << sbackend; - - if (sbackend == synthesis_backend_selector::GRAIN) - ILA_CHECK(vtg_config.YosysSmtFlattenDatatype) - << "For Grain, datatype must be flattened!"; -} - -/// Add an assumption -void VlgSglTgtGen_Chc_wCNF::add_a_direct_assumption(const std::string& aspt, - const std::string& dspt) { - _problems.assumptions[dspt].exprs.push_back(aspt); -} -/// Add an assertion -void VlgSglTgtGen_Chc_wCNF::add_a_direct_assertion(const std::string& asst, - const std::string& dspt) { - _problems.assertions[dspt].exprs.push_back(asst); -} - -void VlgSglTgtGen_Chc_wCNF::PreExportProcess() { - - std::string all_assert_wire_content; - std::string all_assume_wire_content; - - ILA_CHECK(target_type == target_type_t::INV_SYN_DESIGN_ONLY); - ILA_ERROR_IF(_problems.assertions.size() != 1) << "BUG in cex extract"; - - // you need to add assumptions as well - for (auto&& pbname_prob_pair : _problems.assumptions) { - const auto& prbname = pbname_prob_pair.first; - const auto& prob = pbname_prob_pair.second; - ILA_DLOG("VlgSglTgtGen_Chc_wCNF.PreExportProcess") - << "Adding assumption:" << prbname; - - for (auto&& p : prob.exprs) { - vlg_wrapper.add_stmt("assume property (" + p + "); //" + prbname + "\n"); - if (all_assume_wire_content.empty()) - all_assume_wire_content = "(" + p + ")"; - else - all_assume_wire_content += "&& (" + p + ")"; - } // for prob.exprs - } // for _problems.assumption - - bool first = true; - // this is to check given invariants - for (auto&& pbname_prob_pair : _problems.assertions) { - const auto& prbname = pbname_prob_pair.first; - const auto& prob = pbname_prob_pair.second; - - // ILA_CHECK(prbname == "cex_nonreachable_assert") - // << "BUG: assertion can only be cex reachability queries."; - // sanity check, should only be invariant's related asserts - - for (auto&& p : prob.exprs) { - vlg_wrapper.add_stmt("assert property (" + p + "); //" + prbname + "\n"); - // there should be only one expression (for cex target) - // ILA_CHECK(all_assert_wire_content.empty()); - if (first) - all_assert_wire_content = p; - else - all_assert_wire_content += " && " + p; - - first = false; - } // for expr - } // for problem - // add assert wire (though no use : make sure will not optimized away) - ILA_CHECK(!all_assert_wire_content.empty()) << "no property to check!"; - - vlg_wrapper.add_wire("__all_assert_wire__", 1, true); - vlg_wrapper.add_output("__all_assert_wire__", 1); - vlg_wrapper.add_assign_stmt("__all_assert_wire__", all_assert_wire_content); - - if (!all_assume_wire_content.empty()) { - vlg_wrapper.add_wire("__all_assume_wire__", 1, true); - vlg_wrapper.add_output("__all_assume_wire__", 1); - vlg_wrapper.add_assign_stmt("__all_assume_wire__", all_assume_wire_content); - } -} // PreExportProcess - -/// export the script to run the verification : -/// like "yosys gemsmt.ys" -void VlgSglTgtGen_Chc_wCNF::Export_script(const std::string& script_name, - const std::string& cnf_name) { - chc_run_script_name = script_name; - /// TODO: BUG: modify this : use z3/freqHorn - - auto fname = os_portable_append_dir(_output_path, script_name); - std::ofstream fout(fname); - if (!fout.is_open()) { - ILA_ERROR << "Error writing to file:" << fname; - return; - } - fout << "#!/bin/bash" << std::endl; - // fout << "trap \"trap - SIGTERM && kill -- -$$\" SIGINT SIGTERM"< lineno - // open, read, count and write - // if it is a port name, we will ask user to specify its upper level - // signal name - VerilogModifier vlg_mod(vlg_info_ptr, - static_cast( - _vtg_config.PortDeclStyle), - _vtg_config.CosaAddKeep, - supplementary_info.width_info); - - for (auto&& refered_vlg_item : _all_referred_vlg_names) { - auto idx = refered_vlg_item.first.find("["); - auto removed_range_name = refered_vlg_item.first.substr(0, idx); - vlg_mod.RecordKeepSignalName(removed_range_name); - // auto sig = // no use, this is too late, vlg_wrapper already exported - vlg_mod.RecordConnectSigName(removed_range_name, - refered_vlg_item.second.range); - // vlg_wrapper.add_output(sig.first, sig.second); - } - vlg_mod.FinishRecording(); - - // auto tmp_fn = os_portable_append_dir(_output_path, tmp_design_file); - auto tmp_fn = os_portable_append_dir(_output_path, top_file_name); - // now let's do the job - for (auto&& fn : vlg_design_files) { - std::ifstream fin(fn); - std::ofstream fout(tmp_fn, std::ios_base::app); // append to a temp file - if (!fin.is_open()) { - ILA_ERROR << "Cannot read file:" << fn; - continue; - } - if (!fout.is_open()) { - ILA_ERROR << "Cannot open file for write:" << tmp_fn; - continue; - } - vlg_mod.ReadModifyWrite(fn, fin, fout); - } // for (auto && fn : vlg_design_files) - - // handles the includes - // .. (copy all the verilog file in the folder), this has to be os independent - if (vlg_include_files_path.size() != 0) { - // copy the files and specify the -I commandline to the run.sh - for (auto&& include_path : vlg_include_files_path) - os_portable_copy_dir(include_path, _output_path); - } - -} // Export_modify_verilog - -/// export the memory abstraction (implementation) -/// Yes, this is also implementation specific, (jasper may use a different one) -void VlgSglTgtGen_Chc_wCNF::Export_mem(const std::string& mem_name) { - // we will ignore the mem_name - - auto outfn = os_portable_append_dir(_output_path, top_file_name); - std::ofstream fout(outfn, std::ios_base::app); // append - - VlgAbsMem::OutputMemFile(fout, - _vtg_config.VerificationSettingAvoidIssueStage); -} - -// export the chc file -void VlgSglTgtGen_Chc_wCNF::Export_problem(const std::string& extra_name) { - // used by export script! - chc_prob_fname = extra_name; - - // first generate a temporary smt - // and extract from it the necessary info - - // first generate a temporary smt - // and extract from it the necessary info - // this is the CHC-style thing - design_only_gen_smt( - os_portable_append_dir(_output_path, "__design_smt.smt2"), - os_portable_append_dir(_output_path, "__gen_smt_script.ys")); - - convert_smt_to_chc_datatype( - os_portable_append_dir(_output_path, "__design_smt.smt2"), - os_portable_append_dir(_output_path, - s_backend == synthesis_backend_selector::GRAIN - ? "grain_prep.txt" - : extra_name)); - - // for grain : convert wrapper# --> w wrapper_ --> w - if (s_backend == synthesis_backend_selector::GRAIN) { - std::ifstream fin(os_portable_append_dir(_output_path, "grain_prep.txt")); - std::ofstream fout(os_portable_append_dir(_output_path, extra_name)); - if (!fin.is_open()) { - ILA_ERROR << "Cannot read from : " - << os_portable_append_dir(_output_path, "grain_prep.txt"); - return; - } - if (!fout.is_open()) { - ILA_ERROR << "Cannot write to : " - << os_portable_append_dir(_output_path, extra_name); - return; - } - std::string line; - while (std::getline(fin, line)) { - fout << ReplaceAll(ReplaceAll(line, "wrapper#", "w"), "wrapper_", "w_") - << "\n"; - } - } - -} // Export_problem - -std::shared_ptr -VlgSglTgtGen_Chc_wCNF::GetDesignSmtInfo() const { - return design_smt_info; -} - -void VlgSglTgtGen_Chc_wCNF::ExportAll( - const std::string& wrapper_name, // wrapper.v - const std::string& ila_vlg_name, // no use - const std::string& script_name, // the run.sh - const std::string& extra_name, // the chc - const std::string& mem_name, const std::string& cnf_name, - const InvariantInCnf& cnf) { // no use - - PreExportProcess(); - - if (os_portable_mkdir(_output_path) == false) - ILA_WARN << "Cannot create output directory:" << _output_path; - - // you don't need to worry about the path and names - Export_wrapper(wrapper_name); - // design only - // if (target_type == target_type_t::INSTRUCTIONS) - // Export_ila_vlg(ila_vlg_name); // this has to be after Export_wrapper - - // for Jasper, this will be put to multiple files - // for CoSA & Yosys, this will be put after the wrapper file (wrapper.v) - Export_modify_verilog(); // this must be after Export_wrapper - Export_mem(mem_name); - - // you need to create the map function -- - Export_problem(extra_name); // the gensmt.ys - if (_vtg_config.GrainHintsUseCnfStyle) - Export_cnf(cnf, cnf_name); - else - Export_coci(cnf, cnf_name); - Export_script(script_name, cnf_name); -} - -void VlgSglTgtGen_Chc_wCNF::Export_coci(const InvariantInCnf& cnf, - const std::string& cnf_fn) const { - auto fn = os_portable_append_dir(_output_path, cnf_fn); - std::ofstream fout(fn); - if (!fout.is_open()) { - ILA_ERROR << "Unable to open " << fn << " for write."; - return; - } - cnf.ExportInCociFormat(fout); -} - -void VlgSglTgtGen_Chc_wCNF::Export_cnf(const InvariantInCnf& cnf, - const std::string& cnf_fn) const { - auto fn = os_portable_append_dir(_output_path, cnf_fn); - std::ofstream fout(fn); - if (!fout.is_open()) { - ILA_ERROR << "Unable to open " << fn << " for write."; - return; - } - cnf.ExportInCnfFormat(fout); -} - -void VlgSglTgtGen_Chc_wCNF::Export_script(const std::string& script_name) { - ILA_CHECK(false) << "Deprecated. Should not be used!"; -} -void VlgSglTgtGen_Chc_wCNF::ExportAll(const std::string& wrapper_name, - const std::string& ila_vlg_name, - const std::string& script_name, - const std::string& extra_name, - const std::string& mem_name) { - ILA_CHECK(false) << "Deprecated. Should not be used!"; -} - -/// generate the wrapper's smt first -void VlgSglTgtGen_Chc_wCNF::design_only_gen_smt( - const std::string& smt_name, const std::string& ys_script_name) { - - auto ys_output_full_name = - os_portable_append_dir(_output_path, "__yosys_exec_result.txt"); - { // export to ys_script_name - std::ofstream ys_script_fout(ys_script_name); - - std::string write_smt2_options = - " -mem -bv "; // future work : -stbv, or nothing - write_smt2_options += "-stdt "; - - ys_script_fout << "read_verilog -sv " - << os_portable_append_dir(_output_path, top_file_name) - << std::endl; - ys_script_fout << "prep -top " << top_mod_name << std::endl; - ys_script_fout << ReplaceAll( - ReplaceAll(chcEnhanceGenerateSmtScript_wo_Array, "%flatten%", - _vtg_config.YosysSmtFlattenHierarchy ? "flatten;" : ""), - "%topmodule%", top_mod_name); - ys_script_fout << "write_smt2" << write_smt2_options << smt_name; - } // finish writing - - std::string yosys = "yosys"; - - if (!_vtg_config.YosysPath.empty()) - yosys = os_portable_append_dir(_vtg_config.YosysPath, yosys); - - // execute it - std::vector cmd; - cmd.push_back(yosys); - cmd.push_back("-s"); - cmd.push_back(ys_script_name); - auto res = os_portable_execute_shell(cmd, ys_output_full_name); - ILA_ERROR_IF(res.failure != res.NONE) << "Executing Yosys failed!"; - ILA_ERROR_IF(res.failure == res.NONE && res.ret != 0) - << "Yosys returns error code:" << res.ret; -} // design_only_gen_smt - -void VlgSglTgtGen_Chc_wCNF::convert_smt_to_chc_datatype( - const std::string& smt_fname, const std::string& chc_fname) { - - std::stringstream ibuf; - { // read file - std::ifstream smt_fin(smt_fname); - if (!smt_fin.is_open()) { - ILA_ERROR << "Cannot read from " << smt_fname; - return; - } - ibuf << smt_fin.rdbuf(); - } // end read file - - std::string smt_converted; - design_smt_info = std::make_shared(ibuf.str()); - // if (_vtg_config.YosysSmtFlattenDatatype) { - design_smt_info->BreakDatatypes(); - // smt_rewriter.AddNoChangeStateUpdateFunction(); - smt_converted = design_smt_info->Export(); - //} else { - // smt_converted = ibuf.str(); - //} - - std::string wrapper_mod_name = - design_smt_info->get_module_def_orders().back(); - // construct the template - - std::string chc; - // if (_vtg_config.YosysSmtFlattenDatatype) { - const auto& datatype_top_mod = - design_smt_info->get_module_flatten_dt(wrapper_mod_name); - auto tmpl = inv_enhance_tmpl_wo_datatypes; - tmpl = ReplaceAll( - tmpl, "(|%WrapperName%_h| %Ss%)", - _vtg_config.YosysSmtFlattenHierarchy ? "" : "(|%WrapperName%_h| %Ss%)"); - tmpl = ReplaceAll( - tmpl, "(|%WrapperName%_h| %Sps%)", - _vtg_config.YosysSmtFlattenHierarchy ? "" : "(|%WrapperName%_h| %Sps%)"); - tmpl = ReplaceAll( - tmpl, "(|%WrapperName%_h| %BIs%)", - _vtg_config.YosysSmtFlattenHierarchy ? "" : "(|%WrapperName%_h| %BIs%)"); - tmpl = ReplaceAll( - tmpl, "(|%WrapperName%_h| %Is%)", - _vtg_config.YosysSmtFlattenHierarchy ? "" : "(|%WrapperName%_h| %Is%)"); - chc = RewriteDatatypeChc(tmpl, datatype_top_mod, wrapper_mod_name); - chc = ReplaceAll(chc, "%%", smt_converted); - //} else { - // chc = inv_enhance_tmpl_datatypes; - // chc = ReplaceAll(chc, "(|%1%_h| |__BI__|)", - // _vtg_config.YosysSmtFlattenHierarchy ? "" : "(|%1%_h| |__BI__|)"); chc = - // ReplaceAll(chc, "(|%1%_h| |__I__|)" , - // _vtg_config.YosysSmtFlattenHierarchy ? "" : "(|%1%_h| |__I__|)"); chc = - // ReplaceAll(chc, "(|%1%_h| |__S__|)" , - // _vtg_config.YosysSmtFlattenHierarchy ? "" : "(|%1%_h| |__S__|)"); chc = - // ReplaceAll(chc, "(|%1%_h| |__S'__|)", - // _vtg_config.YosysSmtFlattenHierarchy ? "" : "(|%1%_h| |__S'__|)"); chc = - // ReplaceAll(chc,"%1%", wrapper_mod_name); chc = ReplaceAll(chc, "%%", - // smt_converted ); - //} // end of ~_vtg_config.YosysSmtFlattenDatatype -- no convert - - { // (query fail :print-certificate true) - if (generate_proof) - chc += "\n(query fail :print-certificate true)\n"; - else - chc += "\n(query fail)\n"; - } - - { // write file - std::ofstream chc_fout(chc_fname); - if (!chc_fout.is_open()) { - ILA_ERROR << "Error writing to : " << chc_fname; - return; - } - chc_fout << chc; - } // end write file - -} // convert_smt_to_chc_datatype - -// %WrapperName% -// %WrapperDataType% -// %InitVar% -// %State% -// %StatePrime% -// %BIs% %Is% %Ss% %Sps% -static std::string RewriteDatatypeChc(const std::string& tmpl, - const std::vector& dt, - const std::string& wrapper_mod_name) { - - std::string chc = tmpl; - - std::vector inv_tps; - smt::YosysSmtParser::convert_datatype_to_type_vec(dt, inv_tps); - auto WrapperDataType = smt::var_type::toString(inv_tps); - - // %InitVar% - // %State% - // %StatePrime% - // declare-var s ... - std::string InitVar; - std::string State; - std::string StatePrime; - // %BIs% %Is% %Ss% %Sps% - std::string BIs; - std::string Is; - std::string Ss; - std::string Sps; - bool first = true; - - std::set name_set; // avoid repetition - for (auto&& st : dt) { - auto st_name = st.verilog_name.back() == '.' || st.verilog_name.empty() - ? st.internal_name - : st.verilog_name; - st_name = ReplaceAll(st_name, "|", ""); // remove its || - // check no repetition is very important! - ILA_CHECK(!IN(st_name, name_set)) << "Bug: name repetition!"; - ILA_CHECK(!st._type.is_datatype()); - name_set.insert(st_name); - auto type_string = st._type.toString(); - InitVar += "(declare-var |I_" + st_name + "| " + type_string + ")\n"; - State += "(declare-var |S_" + st_name + "| " + type_string + ")\n"; - StatePrime += "(declare-var |S'_" + st_name + "| " + type_string + ")\n"; - - if (!first) { - Is += " "; - Ss += " "; - Sps += " "; - } - first = false; - Is += "|I_" + st_name + "|"; - Ss += "|S_" + st_name + "|"; - Sps += "|S'_" + st_name + "|"; - } - // Replacement - chc = ReplaceAll(chc, "%WrapperName%", wrapper_mod_name); - chc = ReplaceAll(chc, "%WrapperDataType%", WrapperDataType); - chc = ReplaceAll(chc, "%InitVar%", InitVar); - chc = ReplaceAll(chc, "%State%", State); - chc = ReplaceAll(chc, "%StatePrime%", StatePrime); - chc = ReplaceAll(chc, "%Is%", Is); - chc = ReplaceAll(chc, "%Ss%", Ss); - chc = ReplaceAll(chc, "%Sps%", Sps); - - return chc; -} // RewriteDatatypeChc - -}; // namespace ilang - -#endif // INVSYN_INTERFACE diff --git a/src/vtarget-out/single_target.cc b/src/vtarget-out/single_target.cc index 8bf4857db..b6e64134d 100644 --- a/src/vtarget-out/single_target.cc +++ b/src/vtarget-out/single_target.cc @@ -32,41 +32,36 @@ VlgSglTgtGen::VlgSglTgtGen( output_path, // will be a sub directory of the output_path of its parent const InstrPtr& instr_ptr, // which could be an empty pointer, and it will // be used to verify invariants - const InstrLvlAbsPtr& ila_ptr, const VerilogGenerator::VlgGenConfig& config, - nlohmann::json& _rf_vmap, nlohmann::json& _rf_cond, - VlgTgtSupplementaryInfo& _supplementary_info, VerilogInfo* _vlg_info_ptr, - const std::string& vlg_mod_inst_name, const std::string& ila_mod_inst_name, + const InstrLvlAbsPtr& ila_ptr, + const rfmap::VerilogRefinementMap& refinement, VerilogInfo* _vlg_info_ptr, const std::string& wrapper_name, const std::vector& implementation_srcs, const std::vector& implementation_include_path, - const vtg_config_t& vtg_config, backend_selector backend, + const RtlVerifyConfig& vtg_config, ModelCheckerSelection backend, const target_type_t& target_tp, advanced_parameters_t* adv_ptr) : _output_path(output_path), _instr_ptr(instr_ptr), _host(ila_ptr), - _vlg_mod_inst_name(vlg_mod_inst_name), - _ila_mod_inst_name(ila_mod_inst_name), + _vlg_mod_inst_name("RTL"), _ila_mod_inst_name("ILA"), // default option on wrapper vlg_wrapper( - VerilogGenerator::VlgGenConfig(config, // use default configuration - true, + VerilogGenerator::VlgGenConfig(true, // ExternalMem VerilogGeneratorBase::VlgGenConfig:: funcOption::External, // function false, // no start signal + false, // no pass node name false, // no rand init false, // no expand memory false), // no collect ITE unknown wrapper_name), // use given, except for core options vlg_ila(VerilogGeneratorBase::VlgGenConfig( - config, - // except overwriting these: external memory - // if expand memory, then the ila's memory must be internal - config - .extMem, // this depends on the given configuration (default case) - VerilogGeneratorBase::VlgGenConfig::funcOption::External, true, - true, // rand init - true, // for internal should always expand (probe) memory - vtg_config - .IteUnknownAutoIgnore // may collect depends on configuration + false, // default case: internal memory + VerilogGeneratorBase::VlgGenConfig::funcOption::External, // external + // function + true, // w. start signal + vtg_config.VerilogGenPassNodeName, // pass node name + true, // has rand init + false, // no expand memory + false // no collecte ITE unknown )), // interface mapping directive // -------- CONTROLLING THE RESET CONNECTION ------------- // @@ -78,37 +73,34 @@ VlgSglTgtGen::VlgSglTgtGen( // but if forced, we do; For the design only thing // we do ensure reset also - // state-mapping directive - _sdr(), // currently no // verilog info vlg_info_ptr(_vlg_info_ptr), // variable extractor - _vext( - [this](const std::string& n) -> bool { return TryFindIlaState(n); }, - [this](const std::string& n) -> bool { return TryFindIlaInput(n); }, - [this](const std::string& n) -> bool { return TryFindVlgState(n); }), + //_vext( + // [this](const std::string& n) -> bool { return TryFindIlaState(n); }, + // [this](const std::string& n) -> bool { return TryFindIlaInput(n); }, + // [this](const std::string& n) -> bool { return TryFindVlgState(n); + // }), // ref to refmaps - rf_vmap(_rf_vmap), rf_cond(_rf_cond), empty_json(nullptr), - supplementary_info(_supplementary_info), + refinement_map(refinement, /*type checker*/ + [this](const std::string& n) -> rfmap::RfVarTypeOrig { + return this->VarTypeCheckForRfExprParsing(n); + }), + target_type(target_tp), // whether it is // invariant/instructions - has_flush(false), ready_type(ready_type_t::NA), max_bound(127), - cnt_width(1), _advanced_param_ptr(adv_ptr), + max_bound(127), cnt_width(1), _advanced_param_ptr(adv_ptr), has_gussed_synthesized_invariant( adv_ptr && adv_ptr->_candidate_inv_ptr && !adv_ptr->_candidate_inv_ptr->GetVlgConstraints().empty()), has_confirmed_synthesized_invariant( adv_ptr && adv_ptr->_inv_obj_ptr && !adv_ptr->_inv_obj_ptr->GetVlgConstraints().empty()), - has_rf_invariant((IN("global invariants", _rf_cond) && - rf_cond["global invariants"].size() != 0) || - (IN("global-invariants", _rf_cond) && - rf_cond["global-invariants"].size() != 0)), + has_rf_invariant(!refinement_map.global_invariants.empty()), mapping_counter(0), property_counter(0), top_mod_name(wrapper_name), vlg_design_files(implementation_srcs), vlg_include_files_path(implementation_include_path), - _vtg_config(vtg_config), _vlg_cfg(config), _backend(backend), - _bad_state(false) { + _vtg_config(vtg_config), _backend(backend), _bad_state(false) { ILA_NOT_NULL(_host); @@ -117,33 +109,28 @@ VlgSglTgtGen::VlgSglTgtGen( target_type == target_type_t::INV_SYN_DESIGN_ONLY) << "Implementation bug: unrecognized target type!"; - // reset absmem's counter - VlgAbsMem::ClearAbsMemRecord(); - - if (has_rf_invariant) { - if (IN("global invariants", rf_cond) && - !rf_cond["global invariants"].is_array()) { - ILA_ERROR - << "'global invariants' field in refinement relation has to be a " - "JSON array."; - _bad_state = true; - return; - } - if (IN("global-invariants", rf_cond) && - !rf_cond["global-invariants"].is_array()) { - ILA_ERROR - << "'global-invariants' field in refinement relation has to be a " - "JSON array."; - _bad_state = true; - return; - } - } - if (target_type == target_type_t::INSTRUCTIONS) { ILA_NOT_NULL(instr_ptr); + RfmapIlaStateSanityCheck(); + // TODO: insert the memory export directive - vlg_ila.AnnotateMemory(supplementary_info.memory_export); + VerilogGeneratorBase::memory_export_annotation_t mem_annotation; + for (unsigned sidx = 0; sidx < _host->state_num(); ++sidx) { + const auto& s = _host->state(sidx); + if (!s->is_mem()) + continue; + const auto& n = s->name().str(); + auto pos = refinement_map.ila_state_var_map.find(n); + if (pos == refinement_map.ila_state_var_map.end()) + continue; + if (pos->second.type == rfmap::IlaVarMapping::StateVarMapType::EXTERNMEM) + mem_annotation.emplace(n, true); + else + mem_annotation.emplace(n, false); + } // end - for each mem state + + vlg_ila.AnnotateMemory(mem_annotation); // need to change this vlg_ila.ExportTopLevelInstr(instr_ptr); @@ -152,81 +139,19 @@ VlgSglTgtGen::VlgSglTgtGen( _bad_state = true; } - auto& instr = get_current_instruction_rf(); - if (instr.is_null()) { - ILA_ERROR << "No refinement relation is defined for current instruction:" - << instr_ptr->name().str(); - _bad_state = true; - } - // check for fields in - if (!IN("instruction", instr) || !instr["instruction"].is_string()) { - ILA_ERROR << "RF: `instruction` field must be a string for " - << instr_ptr->name().str(); - _bad_state = true; - } + // vlg_ila.ila_rports/ila_wports -> internal wire + // register_ila_memory_wires(); + // no this is not needed + // the ports are connected to wires with names like + // __IMEM_xxx_... + // this is in single_target_connect.cc - if (IN("flush constraint", instr) && - not instr["flush constraint"].is_array()) { - ILA_ERROR - << "RF: 'flush constraint' filed must be an array of string for " - << instr_ptr->name().str(); - _bad_state = true; - } - - if (IN("pre-flush end", instr) && !instr["pre-flush end"].is_string()) { - ILA_ERROR << "RF: 'pre-flush end' field must be a string for " - << instr_ptr->name().str(); - _bad_state = true; - } - - if (IN("post-flush end", instr) && - not instr["post-flush end"].is_string()) { - ILA_ERROR << "RF: 'post-flush end' filed must be a string for " - << instr_ptr->name().str(); - _bad_state = true; - } - - if (IN("flush constraint", instr) && - instr["flush constraint"].size() != 0) { - if (IN("pre-flush end", instr) && instr["pre-flush end"].size() != 0 && - IN("post-flush end", instr) && instr["post-flush end"].size() != 0) - has_flush = true; // requiring three items - else { - ILA_ERROR - << "When using flushing, 'pre-flush end' and 'post-flush end' " - << "must be specify"; - _bad_state = true; - } - } - - if (IN("ready signal", instr) && - instr["ready signal"].size() != - 0) // whether a none-empty string or array... - ready_type = (ready_type_t)(ready_type | ready_type_t::READY_SIGNAL); - if (IN("ready bound", instr) && instr["ready bound"].is_number_integer()) - ready_type = (ready_type_t)(ready_type | ready_type_t::READY_BOUND); - if (ready_type == ready_type_t::NA) { - ILA_ERROR << "refinement relation for:" << instr_ptr->name().str() - << " has to specify a ready condition"; - _bad_state = true; - } } // END of target_type == INSTRUCTION else if (target_type == target_type_t::INVARIANTS) { ILA_WARN_IF(instr_ptr != nullptr) << "Provide an instruction " << "when verifying invariants. The instruction will not be used"; } - // if you supply additional invariant in the invariant synthesis - // they will still be a target for invariant generated. - // you can use it to verify the invariants if you like - ILA_CHECK(!(has_flush && - (backend & backend_selector::YOSYS) == backend_selector::YOSYS)) - << "Currently does not support flushing in invariant synthesis." - << "Future work."; - - ILA_CHECK(!(has_flush && vtg_config.VerificationSettingAvoidIssueStage)) - << "it is impossible to avoid issue stage for flushing refinement map, " - << "ignore this configuration option."; } // END of constructor void VlgSglTgtGen::ConstructWrapper_generate_header() { @@ -235,6 +160,31 @@ void VlgSglTgtGen::ConstructWrapper_generate_header() { vlg_wrapper.add_preheader("\n" + _vtg_config.WrapperPreheader + "\n"); } // ConstructWrapper_generate_header +void VlgSglTgtGen::ConstructWrapper_add_inputmap_assumptions() { + + std::set ila_input_names; + + for (size_t input_idx = 0; input_idx < _host->input_num(); ++input_idx) + ila_input_names.insert(_host->input(input_idx)->name().str()); + + for (const auto& iv_rfmap : refinement_map.ila_input_var_map) { + const auto& iname = iv_rfmap.first; + if (ila_input_names.find(iname) == ila_input_names.end()) { + ILA_ERROR << "Cannot find ILA input with name: " << iname; + continue; + } + ila_input_names.erase(iname); + + Gen_input_map_assumpt(iname, iv_rfmap.second, "input_map_assume_"); + } + + if (!ila_input_names.empty()) { + ILA_ERROR << "Lack input var map for the following variables:"; + for (const auto& in : ila_input_names) + ILA_ERROR << in; + } +} + // for special memory, we don't need to do anything? void VlgSglTgtGen::ConstructWrapper_add_varmap_assumptions() { ILA_CHECK(target_type == target_type_t::INSTRUCTIONS) @@ -245,44 +195,28 @@ void VlgSglTgtGen::ConstructWrapper_add_varmap_assumptions() { for (size_t state_idx = 0; state_idx < _host->state_num(); ++state_idx) ila_state_names.insert(_host->state(state_idx)->name().str()); - nlohmann::json& state_mapping = IN("state mapping", rf_vmap) - ? rf_vmap["state mapping"] - : rf_vmap["state-mapping"]; - for (auto& i : state_mapping.items()) { - auto sname = i.key(); + for (const auto& sv_rfmap : refinement_map.ila_state_var_map) { + const auto& sname = sv_rfmap.first; if (!IN(sname, ila_state_names)) { ILA_ERROR << sname << " is not a state of the ILA:" << _host->name().str(); continue; } + if (_vtg_config.OnlyAssumeUpdatedVarsEq && _instr_ptr->update(sname) == nullptr) { ILA_DLOG("VtargetGen") << "Skip assume EQ on variable:" << sname << " for instruction:" << _instr_ptr->name().str(); continue; } - ila_state_names.erase(sname); - // __START__ ==> vmap ILA_DLOG("VtargetGen.ConstructWrapper_add_varmap_assumptions") << sname; std::string problem_name = "variable_map_assume_"; - if (_vtg_config.PerVariableProblemCosa && - _backend != backend_selector::RELCHC) - problem_name += "_" + sname; - // if we are targeting yosys, we should make sure they have the same - // problem_name so the it knowns these are the assumptions for varmap - - if (_backend == backend_selector::RELCHC) { - - add_an_assumption(GetStateVarMapExpr(sname, i.value()), problem_name); - // its signal reference will be replaced, but this should be fine - // because the names on any level is the same! - } else - add_an_assumption("(~ __START__ )|| (" + - GetStateVarMapExpr(sname, i.value()) + ")", - problem_name); - } + + Gen_varmap_assumpt_assert(sname, sv_rfmap.second, problem_name, true); + } // end for each state variable + ILA_DLOG("VtargetGen") << "STEP:" << "5.2.2"; // check for unmapped states @@ -307,60 +241,34 @@ void VlgSglTgtGen::ConstructWrapper_add_varmap_assertions() { for (size_t state_idx = 0; state_idx < _host->state_num(); ++state_idx) ila_state_names.insert(_host->state(state_idx)->name().str()); - nlohmann::json& state_mapping = IN("state mapping", rf_vmap) - ? rf_vmap["state mapping"] - : rf_vmap["state-mapping"]; - for (auto& i : state_mapping.items()) { - auto sname = i.key(); + for (const auto& sv_rfmap : refinement_map.ila_state_var_map) { + const auto& sname = sv_rfmap.first; if (!IN(sname, ila_state_names)) { ILA_ERROR << sname << " is not a state of the ILA:" << _host->name().str(); continue; } + ila_state_names.erase(sname); + if (_vtg_config.OnlyCheckInstUpdatedVars && _instr_ptr->update(sname) == nullptr) { - - // do not skip memory, though we don't use the eq signal it returns - if (_host->state(sname)->is_mem()) - GetStateVarMapExpr(sname, i.value(), true); - - ILA_DLOG("VtargetGen") << "Skip checking variable:" << sname + ILA_DLOG("VtargetGen") << "Skip assume EQ on variable:" << sname << " for instruction:" << _instr_ptr->name().str(); continue; } - - ila_state_names.erase(sname); - - // report the need of refinement map - if (_instr_ptr->update(sname)) { - FunctionApplicationFinder func_app_finder(_instr_ptr->update(sname)); - for (auto&& func_ptr : func_app_finder.GetReferredFunc()) { - // handle the IteUnknown function case - if (_vtg_config.IteUnknownAutoIgnore && - _sdr.isSpecialUnknownFunction(func_ptr)) - continue; - ILA_ERROR_IF(!(IN("functions", rf_vmap) && - rf_vmap["functions"].is_object() && - IN(func_ptr->name().str(), rf_vmap["functions"]))) - << "uf: " << func_ptr->name().str() << " in " - << _instr_ptr->name().str() << " updating state:" << sname - << " is not provided in rfmap!"; - } - } - - // ISSUE ==> vmap - std::string precondition = - has_flush ? "(~ __ENDFLUSH__) || " : "(~ __IEND__) || "; - - if (IN(sname, vlg_ila.state_update_ite_unknown)) { - auto pos = vlg_ila.state_update_ite_unknown.find(sname); - precondition += "(~ " + pos->second.condition + ") ||"; + ILA_DLOG("VtargetGen.ConstructWrapper_add_varmap_assertions") << sname; + + // just check if we miss any function in uf section + FunctionApplicationFinder func_app_finder(_instr_ptr->update(sname)); + for (auto&& func_ptr : func_app_finder.GetReferredFunc()) { + // handle the IteUnknown function case + ILA_ERROR_IF(!IN(func_ptr->name().str(), refinement_map.uf_application)) + << "uf: " << func_ptr->name().str() << " in " + << _instr_ptr->name().str() << " updating state:" << sname + << " is not provided in rfmap!"; } std::string problem_name = "variable_map_assert"; - if (_vtg_config.PerVariableProblemCosa && - (_backend & backend_selector::YOSYS) != backend_selector::YOSYS) - problem_name += "_" + sname; // for Yosys, we must keep the name the same // so it knows these are for variable map assertions @@ -370,10 +278,9 @@ void VlgSglTgtGen::ConstructWrapper_add_varmap_assertions() { // for Yosys inv-synthesis, we don't mind the precondition // that's part the assertions, so it should be fine - add_an_assertion(precondition + "(" + - GetStateVarMapExpr(sname, i.value(), true) + ")", - problem_name); - } + + Gen_varmap_assumpt_assert(sname, sv_rfmap.second, problem_name, false); + } // end - for each state var } // ConstructWrapper_add_varmap_assertions // NON-FLUSH case @@ -386,22 +293,6 @@ void VlgSglTgtGen::ConstructWrapper_add_varmap_assertions() { // 6 IEND ---> check varmap // 7 ENDED -// FLUSH case -// 1 RESET -// 2 RESETED ---> assume flush & preflush cond -// ... ---> assume flush & preflush cond -// n ISSUE = pre-flush end ---> assume flush & preflush cond -// n+1 START ---> assume varmap ---> assume inv -// (maybe globally?) n+2 STARTED n+3 STARTED -// ... ... (forever) -// m IEND -// m+1 ENDED ---> assume flush & postflush cond -// ... ENDED (forever) ---> assume flush & postflush cond -// l ENDFLUSH = post-flush end ---> assume flush & postflush cond -// ---> assert varmap l+1 FLUSHENDED ---> assume flush -// & postflush cond -// - // for invariants or for instruction void VlgSglTgtGen::ConstructWrapper() { ILA_CHECK(target_type == target_type_t::INVARIANTS || @@ -415,8 +306,20 @@ void VlgSglTgtGen::ConstructWrapper() { ConstructWrapper_generate_header(); ILA_DLOG("VtargetGen") << "STEP:" << 2; + if (target_type != target_type_t::INSTRUCTIONS) + max_bound = _vtg_config.MaxBound; + + // if invariants, will do nothing + if (target_type == target_type_t::INSTRUCTIONS) { + // __CYCLE_CNT__, START RESETED and etc. + ConstructWrapper_add_cycle_count_moniter(); + // IEND ENDCOND and etc. (will use cycle count) + ConstructWrapper_add_condition_signals(); + } else + ConstructWrapper_inv_syn_cond_signals(); + // 1. dealing with reset - ConstructWrapper_reset_setup(); + ConstructWrapper_reset_setup(); // will use __RESETED__ ILA_DLOG("VtargetGen") << "STEP:" << 3; // -- find out the inputs @@ -425,12 +328,9 @@ void VlgSglTgtGen::ConstructWrapper() { ConstructWrapper_add_ila_input(); ILA_DLOG("VtargetGen") << "STEP:" << 5; - // 2. add some monitors (bound cnt) - // 3. add assumptions & assertions if (target_type == target_type_t::INSTRUCTIONS) { - ILA_DLOG("VtargetGen") << "STEP:" << 5.1; - ConstructWrapper_add_cycle_count_moniter(); + ConstructWrapper_add_inputmap_assumptions(); ILA_DLOG("VtargetGen") << "STEP:" << 5.2; ConstructWrapper_add_varmap_assumptions(); ILA_DLOG("VtargetGen") << "STEP:" << 5.3; @@ -438,13 +338,8 @@ void VlgSglTgtGen::ConstructWrapper() { ILA_DLOG("VtargetGen") << "STEP:" << 5.4; ConstructWrapper_add_inv_assumption_or_assertion_target_instruction(); } else if (target_type == target_type_t::INVARIANTS) { - ConstructWrapper_inv_syn_connect_mem(); // the same as inv-syn so I add it - // here ConstructWrapper_add_inv_assumption_or_assertion_target_invariant(); - max_bound = _vtg_config.MaxBound; } else if (target_type == target_type_t::INV_SYN_DESIGN_ONLY) { - ConstructWrapper_inv_syn_cond_signals(); - ConstructWrapper_inv_syn_connect_mem(); ConstructWrapper_add_inv_assumption_or_assertion_target_inv_syn_design_only(); } @@ -455,38 +350,55 @@ void VlgSglTgtGen::ConstructWrapper() { ConstructWrapper_add_rf_assumptions(); - ILA_DLOG("VtargetGen") << "STEP:" << 7; - // if invariants, will do nothing - if (target_type == target_type_t::INSTRUCTIONS) - ConstructWrapper_add_condition_signals(); - ILA_DLOG("VtargetGen") << "STEP:" << 8; - // 7. uni-functions - if (target_type == target_type_t::INSTRUCTIONS) - ConstructWrapper_add_uf_constraints(); - // post value holder --- ABC cannot work on this if (target_type == target_type_t::INSTRUCTIONS) { + // the vars defined here are already + // presented in refinement_map.all_var_def_type ConstructWrapper_add_post_value_holder(); + ConstructWrapper_add_delay_unit(); + ConstructWrapper_add_stage_tracker(); + // you cannot always add aux vars + // because it may refer to other aux vars (like post value holder) + // unless we have a way to check hierarchically + // the dependency + ConstructWrapper_add_direct_aux_vars(); } + ConstructWrapper_add_vlg_monitor(); // add monitor -- inside the monitor, there will be // disable logic if it is for invariant type target - // 6. helper memory - ConstructWrapper_add_helper_memory(); // need to decide what is the target - // type + // 7. uni-functions + if (target_type == target_type_t::INSTRUCTIONS) + ConstructWrapper_add_uf_constraints(); + + // instantiate ila module + if (target_type == target_type_t::INSTRUCTIONS) { + auto ila_mod_inst = ConstructWrapper_get_ila_module_inst(); + vlg_wrapper.add_stmt(ila_mod_inst); + } + + // read assumption/assertion, decide where to put them rtl/smt + // perform the reg[n] optimize + // populate the RtlExtraWire data structure + ConstructWrapper_translate_property_and_collect_all_rtl_connection_var(); + // 1. varname 2. hierarchy 3. what to connect inside // 5.0 add the extra wires to the top module wrapper - if (_backend == backend_selector::COSA || - (_backend & backend_selector::YOSYS) == backend_selector::YOSYS) + // will use var_replacement, and will set _idr + if (VlgVerifTgtGenBase::backend_needs_yosys(_backend)) ConstructWrapper_register_extra_io_wire(); ILA_DLOG("VtargetGen") << "STEP:" << 9; // 5. module instantiation + // for the vlg inst: will use _idr ConstructWrapper_add_module_instantiation(); -} + + // 2. add some monitors (bound cnt) + // 3. add assumptions & assertions +} // Construct_wrapper /// create the wrapper file void VlgSglTgtGen::Export_wrapper(const std::string& wrapper_name) { @@ -498,7 +410,21 @@ void VlgSglTgtGen::Export_wrapper(const std::string& wrapper_name) { return; } vlg_wrapper.DumpToFile(fout); + + // for append verilog + for (const auto& vlg_monitor : refinement_map.customized_monitor) { + if (vlg_monitor.second.verilog_append.empty()) + continue; + if (!vlg_monitor.second.keep_for_invariant && + target_type != target_type_t::INSTRUCTIONS) + continue; + + fout << "/***** BEGIN of Monitor for " << vlg_monitor.first << " *****/\n"; + fout << vlg_monitor.second.verilog_append; + fout << "/***** END of Monitor for " << vlg_monitor.first << " *****/\n"; + } } + /// export the ila verilog void VlgSglTgtGen::Export_ila_vlg(const std::string& ila_vlg_name) { @@ -511,12 +437,10 @@ void VlgSglTgtGen::Export_ila_vlg(const std::string& ila_vlg_name) { ila_file_name = ila_vlg_name; std::ofstream fout; std::string fn; - if (_backend == backend_selector::COSA || - (_backend & backend_selector::YOSYS) == backend_selector::YOSYS || - (_backend == backend_selector::RELCHC)) { + if (VlgVerifTgtGenBase::backend_needs_yosys(_backend)) { fn = os_portable_append_dir(_output_path, top_file_name); fout.open(fn, std::ios_base::app); - } else if (_backend == backend_selector::JASPERGOLD) { + } else if (_backend == ModelCheckerSelection::JASPERGOLD) { fn = os_portable_append_dir(_output_path, ila_vlg_name); fout.open(fn); } @@ -525,13 +449,12 @@ void VlgSglTgtGen::Export_ila_vlg(const std::string& ila_vlg_name) { return; } vlg_ila.DumpToFile(fout); -} +} // end of Export_ila_vlg void VlgSglTgtGen::ExportAll(const std::string& wrapper_name, const std::string& ila_vlg_name, const std::string& script_name, - const std::string& extra_name, - const std::string& mem_name) { + const std::string& extra_name) { PreExportProcess(); if (os_portable_mkdir(_output_path) == false) ILA_WARN << "Cannot create output directory:" << _output_path; @@ -543,10 +466,10 @@ void VlgSglTgtGen::ExportAll(const std::string& wrapper_name, // for Jasper, this will be put to multiple files // for CoSA & Yosys, this will be put after the wrapper file (wrapper.v) Export_modify_verilog(); // this must be after Export_wrapper - Export_mem(mem_name); - Export_problem(extra_name); + Export_problem(extra_name); // for JG this is do.tcl + // for Pono: this is the yosys.script and Export_script(script_name); -} +} // end of ExportAll } // namespace ilang diff --git a/src/vtarget-out/single_target_as.cc b/src/vtarget-out/single_target_as.cc index da0091cc7..2290d3673 100644 --- a/src/vtarget-out/single_target_as.cc +++ b/src/vtarget-out/single_target_as.cc @@ -11,6 +11,8 @@ #include #include +#include +#include #include #include #include @@ -18,101 +20,384 @@ namespace ilang { -void VlgSglTgtGen::add_wire_assign_assumption(const std::string& varname, - const std::string& expression, - const std::string& dspt) { - //_problems.assumptions.push_back(varname + " = " + - // convert_expr_to_cosa(expression)); - vlg_wrapper.add_assign_stmt(varname, expression); - ILA_CHECK(_vtg_config.CosaDotReferenceNotify != - vtg_config_t::CosaDotReferenceNotify_t::NOTIFY_PANIC || - expression.find(".") == std::string::npos) - << "expression:" << expression << " contains unfriendly dot."; - ILA_WARN_IF(_vtg_config.CosaDotReferenceNotify == - vtg_config_t::CosaDotReferenceNotify_t::NOTIFY_WARNING && - expression.find(".") != std::string::npos) - << "expression:" << expression << " contains unfriendly dot."; -} +// NOTE: add_an_assumption, add_an_assertion are not defined in base class void VlgSglTgtGen::add_reg_cassign_assumption(const std::string& varname, - const std::string& expression, + const rfmap::RfExpr& expression, int width, - const std::string& cond, + const rfmap::RfExpr& cond, const std::string& dspt) { - // vlg_wrapper.add_always_stmt(varname + " <= " + varname + ";"); - // _problems.assumptions.push_back("(!( " + convert_expr_to_cosa(cond) + - // " ) | (" + varname + " = " + - // convert_expr_to_cosa(expression) + "))"); - - ILA_CHECK(_vtg_config.CosaDotReferenceNotify != - vtg_config_t::CosaDotReferenceNotify_t::NOTIFY_PANIC || - expression.find(".") == std::string::npos) - << "expression:" << expression << " contains unfriendly dot."; - - ILA_WARN_IF(_vtg_config.CosaDotReferenceNotify == - vtg_config_t::CosaDotReferenceNotify_t::NOTIFY_WARNING && - expression.find(".") != std::string::npos) - << "expression:" << expression << " contains unfriendly dot."; - - // vlg_wrapper.add_always_stmt("if (" + cond + ") " + varname + - // " <= " + expression + "; //" + dspt); - // we prefer the following way, as we get the value instantaneously + rfmap::RfExprAstUtility::RfMapNoNullNode(expression); + rfmap::RfExprAstUtility::RfMapNoNullNode(cond); + std::string rand_in_name = "__" + varname + "_init__"; vlg_wrapper.add_input(rand_in_name, width); vlg_wrapper.add_wire(rand_in_name, width); vlg_wrapper.add_init_stmt(varname + " <= " + rand_in_name + ";"); vlg_wrapper.add_always_stmt(varname + " <= " + varname + ";"); - add_an_assumption( - "(~(" + cond + ") || ((" + varname + ") == (" + expression + ")))", dspt); + add_an_assumption(rfmap_imply(cond, rfmap_eq(rfmap_var(varname), expression)), + dspt); +} // add_reg_cassign_assumption + +void VlgSglTgtGen::add_smt_assumption(const rfmap::RfExpr& body, + const std::string& dspt) { + rfmap::RfExprAstUtility::RfMapNoNullNode(body); + + std::unordered_map vars; + rfmap::RfExprAstUtility::GetVars(body, vars); + + std::string body_smt2 = + rfmap::RfExpr2Smt::to_smt2(body, rfmap::SmtType() /*Bool type*/); + std::vector arg; + for (const auto& n_expr_pair : vars) { + auto tp = refinement_map.GetType(n_expr_pair.second); + auto smt_tp = rfmap::SmtType(tp.type, false); + const auto& n = n_expr_pair.first; + arg.push_back("(|" + n + "| " + smt_tp.type_to_smt2() + ")"); + } + add_a_direct_smt_assumption("(" + Join(arg, " ") + ")", "Bool", body_smt2, + dspt); } -/// Add an assumption -void VlgSglTgtGen::add_an_assumption(const std::string& aspt, +// Add SMT assertion (using rfexpr) +void VlgSglTgtGen::add_smt_assertion(const rfmap::RfExpr& body, const std::string& dspt) { - auto assumption_wire_name = vlg_wrapper.sanitizeName(dspt) + new_mapping_id(); - vlg_wrapper.add_wire(assumption_wire_name, 1, true); - vlg_wrapper.add_output(assumption_wire_name, - 1); // I find it is necessary to connect to the output - - ILA_CHECK(_vtg_config.CosaDotReferenceNotify != - vtg_config_t::CosaDotReferenceNotify_t::NOTIFY_PANIC || - aspt.find(".") == std::string::npos) - << "aspt:" << aspt << " contains unfriendly dot."; - - ILA_WARN_IF(_vtg_config.CosaDotReferenceNotify == - vtg_config_t::CosaDotReferenceNotify_t::NOTIFY_WARNING && - aspt.find(".") != std::string::npos) - << "aspt:" << aspt << " contains unfriendly dot."; - - vlg_wrapper.add_assign_stmt(assumption_wire_name, aspt); - add_a_direct_assumption( - assumption_wire_name + - (_backend == backend_selector::COSA ? " = 1_1" : ""), - dspt); -} // add_an_assumption - -/// Add an assertion -void VlgSglTgtGen::add_an_assertion(const std::string& asst, + rfmap::RfExprAstUtility::RfMapNoNullNode(body); + + std::unordered_map vars; + rfmap::RfExprAstUtility::GetVars(body, vars); + + std::string body_smt2 = + rfmap::RfExpr2Smt::to_smt2(body, rfmap::SmtType() /*Bool type*/); + std::vector arg; + for (const auto& n_expr_pair : vars) { + auto tp = refinement_map.GetType(n_expr_pair.second); + auto smt_tp = rfmap::SmtType(tp.type, false); + const auto& n = n_expr_pair.first; + arg.push_back("(|" + n + "| " + smt_tp.type_to_smt2() + ")"); + } + add_a_direct_smt_assertion("(" + Join(arg, " ") + ")", "Bool", body_smt2, + dspt); +} + +void VlgSglTgtGen::add_an_assumption(const rfmap::RfExpr& aspt, + const std::string& dspt) { + + rfmap::RfExprAstUtility::RfMapNoNullNode(aspt); + all_assumptions[dspt].push_back(aspt); +} + +void VlgSglTgtGen::add_an_assertion(const rfmap::RfExpr& asst, + const std::string& dspt) { + rfmap::RfExprAstUtility::RfMapNoNullNode(asst); + all_assertions[dspt].push_back(asst); +} + +void VlgSglTgtGen::add_a_cover(const rfmap::RfExpr& asst, const std::string& dspt) { - auto assrt_wire_name = vlg_wrapper.sanitizeName(dspt) + new_property_id(); - vlg_wrapper.add_wire(assrt_wire_name, 1, true); - vlg_wrapper.add_output(assrt_wire_name, - 1); // I find it is necessary to connect to the output - vlg_wrapper.add_assign_stmt(assrt_wire_name, asst); - add_a_direct_assertion( - assrt_wire_name + (_backend == backend_selector::COSA ? " = 1_1" : ""), - dspt); - ILA_CHECK(_vtg_config.CosaDotReferenceNotify != - vtg_config_t::CosaDotReferenceNotify_t::NOTIFY_PANIC || - asst.find(".") == std::string::npos) - << "asst:" << asst << " contains unfriendly dot."; - ILA_WARN_IF(_vtg_config.CosaDotReferenceNotify == - vtg_config_t::CosaDotReferenceNotify_t::NOTIFY_WARNING && - asst.find(".") != std::string::npos) - << "asst:" << asst << " contains unfriendly dot."; - - //_problems.probitem[dspt].assertions.push_back(convert_expr_to_cosa(asst)); + rfmap::RfExprAstUtility::RfMapNoNullNode(asst); + all_covers[dspt].push_back(asst); } +void VlgSglTgtGen::add_a_santiy_assertion(const rfmap::RfExpr& asst, + const std::string& dspt) { + if (dspt == "post_value_holder_overly_constrained" && + !_vtg_config.SanityCheck_ValueRecorderOverlyConstrained) + return; + if (dspt == "post_value_holder_triggered" && + !_vtg_config.SanityCheck_ValueRecorderTriggeredBeforeCommit) + return; + + rfmap::RfExprAstUtility::RfMapNoNullNode(asst); + all_sanity_assertions[dspt].push_back(asst); +} + +static std::string const_to_unified_str(const rfmap::RfExpr& in) { + auto cnst = verilog_expr::VExprAstConstant::cast_ptr(in); + ILA_NOT_NULL(cnst); + auto b_w_lit = cnst->get_constant(); + auto base = std::get<0>(b_w_lit); + auto lit = std::get<2>(b_w_lit); + if (base == 10 || base == 0) + return lit; + // else other base + auto n = StrToULongLong(lit, base); + if (lit != "0" && n == 0) + return "error"; + return IntToStrCustomBase(n, 10, false); +} + +static std::string GetVlg(const rfmap::RfExpr & e) { + try { + return e->to_verilog(); + } catch (...) { + ILA_ERROR<< "Cannot convert r-expr : " << e; + } + return "(error)"; +} + +static rfmap::RfExpr find_and_replace_array_const( + const rfmap::RfExpr& expr, + std::map& array_const_set, // RTL.a.b.c[const] + std::unordered_map& extra_wire) { + auto fd_rp_array_const_func = [&array_const_set, + &extra_wire](const rfmap::RfExpr& in) -> rfmap::RfExpr { + if (in->get_op() == verilog_expr::voperator::INDEX && + in->get_child_cnt() == 2 && in->get_child().at(0)->is_var() && + in->get_child().at(1)->is_constant() && + rfmap::RfExprAstUtility::GetType(in->get_child().at(0)).type.is_array()) { + auto hier_name = GetVlg(in->get_child().at(0)); + auto cnst = const_to_unified_str(in->get_child().at(1)); + if (cnst == "error") // if cannot convert + return in; + + auto new_name = ReplaceAll(hier_name, ".", "__DOT__"); + new_name += "_" + cnst + "_"; + rfmap::RfExpr ret; + if (array_const_set.find(new_name) != array_const_set.end()) { + ret = array_const_set.at(new_name); + return ret; + } + + const auto last_dot_pos = hier_name.rfind("."); + ILA_CHECK(last_dot_pos != std::string::npos); + const auto hierarchy = hier_name.substr(0, last_dot_pos); + const auto internal = + hier_name.substr(last_dot_pos + 1) + "[" + cnst + "]"; + ILA_CHECK(!IN(new_name, extra_wire)); + + auto tp = rfmap::RfExprAstUtility::GetType(in->get_child().at(0)).type; + auto w = tp.unified_width(); + + extra_wire.emplace(new_name, + RtlExtraWire(new_name, hierarchy, internal, w)); + // new_name is the wire name + + // replace var + auto repl = verilog_expr::VExprAst::MakeSpecialName(new_name); + auto new_tp = std::make_shared(); + new_tp->var_ref_type = rfmap::TypeAnnotation::VARTYPE::INTERNAL; + new_tp->type = rfmap::RfMapVarType(w); + repl->set_annotation(new_tp); + ret = repl; + + array_const_set.emplace(new_name, repl); + return ret; + } // else + return in; + }; + return rfmap::RfExprAstUtility::TraverseRfExpr(expr, fd_rp_array_const_func); +} // find_and_replace_array_const + +void VlgSglTgtGen::add_wire_assign_assumption(const std::string& varname, + const rfmap::RfExpr& aspt, + const std::string& dspt) { + + rfmap::RfExprAstUtility::RfMapNoNullNode(aspt); + assign_or_assumptions.push_back( + std::make_tuple(dspt, varname, aspt, nullptr)); +} + +// read assumption/assertion, decide where to put them rtl/smt +// perform the reg[n] optimize +// populate the RtlExtraWire data structure +void VlgSglTgtGen:: + ConstructWrapper_translate_property_and_collect_all_rtl_connection_var() { + bool is_jg = _backend == ModelCheckerSelection::JASPERGOLD; + + for (auto& dspt_vn_rfexpr_eq : assign_or_assumptions) { + const auto& vn = std::get<1>(dspt_vn_rfexpr_eq); + const auto& rfe = std::get<2>(dspt_vn_rfexpr_eq); + + ILA_DLOG("VTG.ReplWireEq") << vn << " := " << GetVlg(rfe); + std::get<3>(dspt_vn_rfexpr_eq) = ReplExpr(rfmap_eq(rfmap_var(vn), rfe)); + } // for each assign/assumption + + for (auto& dspt_aspt : all_assumptions) { + for (auto& aspt : dspt_aspt.second) { + ILA_DLOG("VTG.ReplAssume") << GetVlg(aspt); + aspt = ReplExpr(aspt); + } + } + + for (auto& dspt_asst : all_assertions) { + for (auto& asst : dspt_asst.second) { + ILA_DLOG("VTG.ReplAssert") << GetVlg(asst); + asst = ReplExpr(asst); + } + } + + for (auto& dspt_asst : all_sanity_assertions) { + for (auto& asst : dspt_asst.second) { + ILA_DLOG("VTG.ReplAssert") << GetVlg(asst); + asst = ReplExpr(asst); + } + } + + for (auto& dspt_cvrs : all_covers) { + for (auto& cvrs : dspt_cvrs.second) { + ILA_DLOG("VTG.ReplAssert") << GetVlg(cvrs); + cvrs = ReplExpr(cvrs); + } + } + + if (is_jg) { + for (auto& dspt_aspt : all_assumptions) { + for (auto& aspt : dspt_aspt.second) { + ILA_ASSERT(!rfmap::RfExprAstUtility::HasQuantifier(aspt)); + add_a_direct_assumption(GetVlg(aspt), dspt_aspt.first); + } + } + for (auto& dspt_asst : all_assertions) { + for (auto& asst : dspt_asst.second) { + ILA_ASSERT(!rfmap::RfExprAstUtility::HasQuantifier(asst)); + add_a_direct_assertion(GetVlg(asst), dspt_asst.first); + } + } + for (auto& dspt_asst : all_sanity_assertions) { + for (auto& asst : dspt_asst.second) { + ILA_ASSERT(!rfmap::RfExprAstUtility::HasQuantifier(asst)); + add_a_direct_sanity_assertion(GetVlg(asst), dspt_asst.first); + } + } + for (auto& dspt_cvrs : all_covers) { + for (auto& cvr : dspt_cvrs.second) { + ILA_ASSERT(!rfmap::RfExprAstUtility::HasQuantifier(cvr)); + add_a_direct_cover_check(GetVlg(cvr), dspt_cvrs.first); + } + } + + + for (auto& dspt_vn_rfexpr_eq : assign_or_assumptions) { + const auto& vn = std::get<1>(dspt_vn_rfexpr_eq); + const auto& eq = std::get<3>(dspt_vn_rfexpr_eq); + // we know it is eq(vn, rhs); + ILA_ASSERT(!rfmap::RfExprAstUtility::HasQuantifier(eq)); + vlg_wrapper.add_assign_stmt(vn, GetVlg(eq->get_child().at(1))); + } + return; + } // end of is_jg (will not continue if using jg) + + for (const auto& repl : refinement_map.GetVarReplacement()) { + ILA_CHECK(StrStartsWith(repl.second.get_orig_name(), "RTL.") == + repl.second.is_orig_rtlv()); + + if (!repl.second.is_orig_rtlv()) + continue; + + if (repl.second.is_orig_var_array()) + continue; // do not connect array + + ILA_CHECK(StrStartsWith(repl.second.get_new_name(), "RTL__DOT__")) + << repl.second.get_new_name() << "is not replaced"; + // jaspergold should not reach here + + const auto full_name = repl.second.get_orig_name(); + const auto last_dot_pos = full_name.rfind("."); + const auto hierarchy = full_name.substr(0, last_dot_pos); + const auto internal = full_name.substr(last_dot_pos + 1); + unsigned width = repl.second.get_type_orig().type.unified_width(); + + rtl_extra_wire.emplace( + repl.second.get_new_name(), + RtlExtraWire(repl.second.get_new_name(), hierarchy, internal, width)); + } + + std::map array_const_set; + // below will also update `rtl_extra_wire` + for (auto& dspt_aspt : all_assumptions) { + for (auto& aspt : dspt_aspt.second) { + aspt = find_and_replace_array_const(aspt, array_const_set, rtl_extra_wire); + // this will find array[const] and replace as a word reference + } + } + + for (auto& dspt_asst : all_assertions) { + for (auto& asst : dspt_asst.second) { + asst = find_and_replace_array_const(asst, array_const_set, rtl_extra_wire); + } + } + + for (auto& dspt_vn_rfexpr_eq : assign_or_assumptions) { + auto& eq = std::get<3>(dspt_vn_rfexpr_eq); + eq = find_and_replace_array_const(eq, array_const_set, rtl_extra_wire); + } + + // last step + // if a=b[c] contains array not handled, then we need to have + // smt assumptions + // otherwise, we can add it as an assign + for (const auto& dspt_vn_rfexpr_eq : assign_or_assumptions) { + const auto& eq = std::get<3>(dspt_vn_rfexpr_eq); + const auto& dspt = std::get<0>(dspt_vn_rfexpr_eq); + const auto& wn = std::get<1>(dspt_vn_rfexpr_eq); + + ILA_DLOG("VTG.AddWireEq") << GetVlg(eq); + + if (rfmap::RfExprAstUtility::HasArrayVar(eq) || + rfmap::RfExprAstUtility::HasQuantifier(eq) ) { + ILA_ERROR_IF(!_vtg_config.YosysSmtArrayForRegFile) + << "Requiring array sort in Yosys when generating" + << " properties, please enable YosysSmtArrayForRegFile"; + add_smt_assumption(eq, dspt); + } else + vlg_wrapper.add_assign_stmt( + wn, GetVlg(eq->get_child().at(1))); + } + + for (const auto& dspt_aspt : all_assumptions) { + for (const auto& aspt : dspt_aspt.second) { + ILA_DLOG("VTG.AddAssume") << GetVlg(aspt); + + if (rfmap::RfExprAstUtility::HasArrayVar(aspt) || + rfmap::RfExprAstUtility::HasQuantifier(aspt) ) { + ILA_ERROR_IF(!_vtg_config.YosysSmtArrayForRegFile) + << "Requiring array sort in Yosys when generating" + << " properties, please enable YosysSmtArrayForRegFile"; + add_smt_assumption(aspt, dspt_aspt.first); + } else + add_a_direct_assumption(GetVlg(aspt), dspt_aspt.first); + } + } + + for (const auto& dspt_asst : all_assertions) { + for (const auto& asst : dspt_asst.second) { + ILA_DLOG("VTG.AddAssert") << GetVlg(asst); + + if (rfmap::RfExprAstUtility::HasArrayVar(asst) || + rfmap::RfExprAstUtility::HasQuantifier(asst)) + add_smt_assertion(asst, dspt_asst.first); + else + add_a_direct_assertion(GetVlg(asst), dspt_asst.first); + } + } + + for (const auto& dspt_asst : all_sanity_assertions) { + for (const auto& asst : dspt_asst.second) { + ILA_CHECK(!rfmap::RfExprAstUtility::HasArrayVar(asst)) + << "Implementation bug: sanity checking assertion should not contain " + "arrays"; + ILA_CHECK(!rfmap::RfExprAstUtility::HasQuantifier(asst)) + << "Implementation bug: sanity checking assertion should not contain " + "quantifier"; + + add_a_direct_sanity_assertion(GetVlg(asst), dspt_asst.first); + } + } + for (const auto& dspt_cvrs : all_covers) { + for (const auto& cvr : dspt_cvrs.second) { + ILA_CHECK(!rfmap::RfExprAstUtility::HasArrayVar(cvr)) + << "Implementation bug: cover checks should not contain " + "arrays"; + ILA_CHECK(!rfmap::RfExprAstUtility::HasQuantifier(cvr)) + << "Implementation bug: cover checks should not contain " + "quantifier"; + + add_a_direct_cover_check(GetVlg(cvr), dspt_cvrs.first); + } + } + +} // ConstructWrapper_translate_property_and_collect_all_rtl_connection_var + }; // namespace ilang diff --git a/src/vtarget-out/single_target_cond.cc b/src/vtarget-out/single_target_cond.cc index b1ea955fb..80b16d11c 100644 --- a/src/vtarget-out/single_target_cond.cc +++ b/src/vtarget-out/single_target_cond.cc @@ -14,6 +14,8 @@ #include #include +#include + namespace ilang { // ------------- CONFIGURATIONS -------------------- // @@ -35,48 +37,26 @@ namespace ilang { // 6 IEND ---> check varmap // 7 ENDED -// FLUSH case -// 1 RESET -// 2 RESETED ---> assume flush & preflush cond -// ... ---> assume flush & preflush cond -// n ISSUE = pre-flush end ---> assume flush & preflush cond -// n+1 START ---> assume varmap ---> assume inv -// (maybe globally?) n+2 STARTED n+3 STARTED -// ... ... (forever) -// m IEND -// m+1 ENDED ---> assume flush & postflush cond -// ... ENDED (forever) ---> assume flush & postflush cond -// l ENDFLUSH = post-flush end ---> assume flush & postflush cond -// ---> assert varmap l+1 FLUSHENDED ---> assume flush -// & postflush cond -// - /// setup reset, add assumptions if necessary void VlgSglTgtGen::ConstructWrapper_reset_setup() { if (target_type == target_type_t::INSTRUCTIONS) { vlg_wrapper.add_input("dummy_reset", 1); vlg_wrapper.add_wire("dummy_reset", 1, true); - if (_vtg_config.InstructionNoReset || - supplementary_info.cosa_yosys_reset_config - .no_reset_after_starting_state) - add_an_assumption(" (~__RESETED__) || (dummy_reset == 0) ", "noreset"); + rfmap_add_internal_wire("dummy_reset", 1); + if (_vtg_config.InstructionNoReset) { + add_an_assumption(rfmap_imply(rfmap_var("__RESETED__"), + rfmap_not(rfmap_var("dummy_reset"))), + "noreset"); + } } else if (target_type == target_type_t::INVARIANTS || target_type == target_type_t::INV_SYN_DESIGN_ONLY) { - if (supplementary_info.cosa_yosys_reset_config - .no_reset_after_starting_state) { - if (_backend == backend_selector::COSA) { - add_a_direct_assumption("reset_done = 1_1 -> rst = 0_1", - "noresetagain"); - add_a_direct_assumption("reset_done = 1_1 -> next( reset_done ) = 1_1", - "noresetnextdone"); - } else if (_backend == backend_selector::JASPERGOLD) { + if (_vtg_config.InvariantCheckNoReset) { + if (_backend == ModelCheckerSelection::JASPERGOLD) { // no need to any thing - } else if ((_backend & backend_selector::YOSYS) == - backend_selector::YOSYS) { + } else if (VlgVerifTgtGenBase::backend_needs_yosys(_backend)) { add_a_direct_assumption("rst == 0", "noreset"); } } - // COSA : direct assumption // JasperGold will not mess with it // yosys : abc needs assumptions but not all of them } @@ -86,38 +66,46 @@ void VlgSglTgtGen::ConstructWrapper_add_cycle_count_moniter() { // find in rf_cond, how many cycles will be needed max_bound = 0; - auto& instr = get_current_instruction_rf(); + const auto& instr = get_current_instruction_rf(); - if (!instr.is_null() && IN("ready bound", instr) && - instr["ready bound"].is_number_integer()) - max_bound = instr["ready bound"].get(); + if (instr.is_readybound()) + max_bound = instr.ready_bound; else max_bound = _vtg_config.MaxBound; + if (instr.max_bound > max_bound) + max_bound = instr.max_bound; - cnt_width = (int)std::ceil(std::log2(max_bound + 10)); + cnt_width = (int)std::ceil(std::log2(max_bound + 20)); vlg_wrapper.add_reg("__CYCLE_CNT__", cnt_width); // by default it will be an output reg + rfmap_add_internal_reg("__CYCLE_CNT__", cnt_width); + vlg_wrapper.add_stmt("always @(posedge clk) begin"); vlg_wrapper.add_stmt("if (rst) __CYCLE_CNT__ <= 0;"); vlg_wrapper.add_stmt( "else if ( ( __START__ || __STARTED__ ) && __CYCLE_CNT__ < " + - IntToStr(max_bound + 5) + ") __CYCLE_CNT__ <= __CYCLE_CNT__ + 1;"); + IntToStr(max_bound + 10) + ") __CYCLE_CNT__ <= __CYCLE_CNT__ + 1;"); vlg_wrapper.add_stmt("end"); vlg_wrapper.add_reg("__START__", 1); + rfmap_add_internal_reg("__START__", 1); + rfmap_add_replacement("decode", "__START__"); + rfmap_add_replacement("start", "__START__"); vlg_wrapper.add_stmt("always @(posedge clk) begin"); // how start is triggered - if (_vtg_config.VerificationSettingAvoidIssueStage) { - vlg_wrapper.add_stmt("if (rst) __START__ <= 1;"); - vlg_wrapper.add_stmt("else if (__START__ || __STARTED__) __START__ <= 0;"); + if(_vtg_config.ForceInstCheckReset) { + vlg_wrapper.add_stmt("if (__ISSUE__ && !__START__ && !__STARTED__) __START__ <= 1;"); } else { - vlg_wrapper.add_stmt("if (rst) __START__ <= 0;"); - vlg_wrapper.add_stmt("else if (__START__ || __STARTED__) __START__ <= 0;"); - vlg_wrapper.add_stmt("else if (__ISSUE__) __START__ <= 1;"); + vlg_wrapper.add_stmt("if (rst) __START__ <= 1;"); } + vlg_wrapper.add_stmt("else if (__START__ || __STARTED__) __START__ <= 0;"); + vlg_wrapper.add_stmt("end"); vlg_wrapper.add_reg("__STARTED__", 1); + rfmap_add_internal_reg("__STARTED__", 1); + rfmap_add_replacement("afterdecode", "__STARTED__"); + rfmap_add_replacement("afterstart", "__STARTED__"); vlg_wrapper.add_stmt("always @(posedge clk) begin"); vlg_wrapper.add_stmt("if (rst) __STARTED__ <= 0;"); vlg_wrapper.add_stmt( @@ -125,6 +113,7 @@ void VlgSglTgtGen::ConstructWrapper_add_cycle_count_moniter() { vlg_wrapper.add_stmt("end"); vlg_wrapper.add_reg("__ENDED__", 1); + rfmap_add_internal_reg("__ENDED__", 1); vlg_wrapper.add_stmt("always @(posedge clk) begin"); vlg_wrapper.add_stmt("if (rst) __ENDED__ <= 0;"); vlg_wrapper.add_stmt( @@ -132,6 +121,7 @@ void VlgSglTgtGen::ConstructWrapper_add_cycle_count_moniter() { vlg_wrapper.add_stmt("end"); vlg_wrapper.add_reg("__2ndENDED__", 1); + rfmap_add_internal_reg("__2ndENDED__", 1); vlg_wrapper.add_stmt("always @(posedge clk) begin"); vlg_wrapper.add_stmt("if (rst) __2ndENDED__ <= 1'b0;"); vlg_wrapper.add_stmt("else if (__ENDED__ && __EDCOND__ && ~__2ndENDED__) " @@ -142,6 +132,7 @@ void VlgSglTgtGen::ConstructWrapper_add_cycle_count_moniter() { "__ENDED__ && __EDCOND__ && ~__2ndENDED__"); vlg_wrapper.add_reg("__RESETED__", 1); + rfmap_add_internal_reg("__RESETED__", 1); vlg_wrapper.add_stmt("always @(posedge clk) begin"); vlg_wrapper.add_stmt("if (rst) __RESETED__ <= 1;"); vlg_wrapper.add_stmt("end"); @@ -166,160 +157,78 @@ void VlgSglTgtGen::ConstructWrapper_add_condition_signals() { // we don't need additional signals, just make reset drives the design // find the instruction - auto& instr = get_current_instruction_rf(); - ILA_CHECK(!instr.is_null()); + const auto& instr = get_current_instruction_rf(); // __IEND__ - std::string iend_cond = VLG_FALSE; + rfmap::RfExpr iend_cond; // bool no_started_signal = false; - if (ready_type & ready_type_t::READY_SIGNAL) { - if (instr["ready signal"].is_string()) { - iend_cond += "|| (" + - ReplExpr(instr["ready signal"].get(), true) + - ")"; // force vlg - } else if (instr["ready signal"].is_array()) { - for (auto&& cond : instr["ready signal"]) - if (cond.is_string()) - iend_cond += " || (" + ReplExpr(cond.get()) + ")"; - else - ILA_ERROR << "ready signal field of instruction: " - << _instr_ptr->name().str() - << " has to be string or array or string"; - } else - ILA_ERROR << "ready signal field of instruction: " - << _instr_ptr->name().str() - << " has to be string or array or string"; + if (instr.is_readysignal()) { + iend_cond = instr.ready_signal; + } else { + ILA_ASSERT(instr.is_readybound()); + unsigned bound = instr.ready_bound; + ILA_ERROR_IF(bound == 0) + << "Does not support bound : 0, please use a buffer to hold " + "the signal."; + iend_cond = + rfmap_eq(rfmap_var("__CYCLE_CNT__"), rfmap_const(10, cnt_width, bound)); + // "( __CYCLE_CNT__ == " + IntToStr(cnt_width) + "'d" + // + IntToStr(bound) + ")"; } - if (ready_type & ready_type_t::READY_BOUND) { // can be both applied - if (instr["ready bound"].is_number_integer()) { - int bound = instr["ready bound"].get(); - if (bound > 0) { - // okay now we enforce the bound - iend_cond += "|| ( __CYCLE_CNT__ == " + - ReplExpr(IntToStr(cnt_width) + "'d" + IntToStr(bound)) + - ")"; - } else if (bound == 0) { - // iend_cond += "|| (__START__)"; - // no_started_signal = true; // please don't use && STARTED - ILA_ERROR << "Does not support bound : 0, please use a buffer to hold " - "the signal."; - } else - ILA_ERROR << "ready bound field of instruction: " - << _instr_ptr->name().str() - << " has to a non negative integer"; - } else - ILA_ERROR << "ready bound field of instruction: " - << _instr_ptr->name().str() << " has to a non negative integer"; - } // end of ready bound/condition // max bound for max checking range - std::string max_bound_constr; - if (IN("max bound", instr)) { - if (instr["max bound"].is_number_integer()) { - max_bound_constr = - "&& ( __CYCLE_CNT__ <= " + IntToStr(instr["max bound"].get()) + - ")"; - } + rfmap::RfExpr max_bound_constr = rfmap_true(); + if (instr.max_bound != 0) { + max_bound_constr = rfmap_le(rfmap_var("__CYCLE_CNT__"), + rfmap_const(10, cnt_width, instr.max_bound)); + // "&& ( __CYCLE_CNT__ <= " + IntToStr(instr.max_bound) + ")"; } vlg_wrapper.add_wire("__IEND__", 1, true); vlg_wrapper.add_wire("__EDCOND__", 1, true); - // if(no_started_signal) - // add_wire_assign_assumption("__IEND__", "(" + iend_cond + ")", - // "IEND"); - // else - auto end_no_recur = has_flush ? "(~ __FLUSHENDED__ )" : "(~ __ENDED__)"; - - add_wire_assign_assumption("__EDCOND__", - "(" + iend_cond + ") && __STARTED__ ", "EDCOND"); - - add_wire_assign_assumption("__IEND__", - "(" + iend_cond + - ") && __STARTED__ && __RESETED__ && " + - end_no_recur + max_bound_constr, - "IEND"); + vlg_wrapper.add_output("__IEND__", 1); + vlg_wrapper.add_output("__EDCOND__", 1); + + rfmap_add_internal_wire("__IEND__", 1); + rfmap_add_internal_wire("__EDCOND__", 1); + rfmap_add_replacement("commit", "__IEND__"); + rfmap_add_replacement("end", "__IEND__"); + + auto end_no_recur = rfmap_not(rfmap_var("__ENDED__")); + + add_wire_assign_assumption( + "__EDCOND__", rfmap_and(iend_cond, rfmap_var("__STARTED__")), "EDCOND"); + + add_wire_assign_assumption( + "__IEND__", + rfmap_and({iend_cond, rfmap_var("__STARTED__"), rfmap_var("__RESETED__"), + end_no_recur, max_bound_constr}), + "IEND"); + + if(_vtg_config.CheckInstrCommitSatisfiable) { + add_a_cover(rfmap_var("commit"), "inst_will_commit"); + } + // handle start decode - ILA_ERROR_IF(IN("start decode", instr)) - << "'start decode' is replaced by start condition!"; - if (IN("start condition", instr)) { - handle_start_condition(instr["start condition"]); + + if (!instr.start_condition.empty()) { + handle_start_condition(instr.start_condition); } else { - add_an_assumption("(~ __START__) || (" + vlg_ila.decodeNames[0] + ")", - "issue_decode"); // __ISSUE__ |=> decode - add_an_assumption("(~ __START__) || (" + vlg_ila.validName + ")", - "issue_valid"); // __ISSUE__ |=> decode + add_an_assumption(rfmap_imply(rfmap_var("__START__"), rfmap_var("$decode")), + "issue_decode"); // __ISSUE__ |-> decode + add_an_assumption(rfmap_imply(rfmap_var("__START__"), rfmap_var("$valid")), + "issue_valid"); // __ISSUE__ |-> valid } - if (has_flush) { - ILA_CHECK(IN("pre-flush end", instr) && - IN("post-flush end", instr)); // there has to be something - - std::string issue_cond; - if (instr["pre-flush end"].is_string()) - issue_cond = "(" + ReplExpr(instr["pre-flush end"].get()) + - ") && __RESETED__"; - else { - issue_cond = "1"; - ILA_ERROR << "pre-flush end field should be a string!"; - } - vlg_wrapper.add_wire("__ISSUE__", 1, true); - add_wire_assign_assumption("__ISSUE__", issue_cond, "ISSUE"); - - std::string finish_cond; - if (instr["post-flush end"].is_string()) - finish_cond = "(" + ReplExpr(instr["post-flush end"].get()) + - ") && __ENDED__"; - else { - finish_cond = "1"; - ILA_ERROR << "post-flush end field should be a string!"; - } - vlg_wrapper.add_wire("__ENDFLUSH__", 1, true); - add_wire_assign_assumption("__ENDFLUSH__", finish_cond, "ENDFLUSH"); - - vlg_wrapper.add_reg("__FLUSHENDED__", 1); - vlg_wrapper.add_stmt( - "always @(posedge clk) begin\n" - "if(rst) __FLUSHENDED__ <= 0;\n" - "else if( __ENDFLUSH__ && __ENDED__ ) __FLUSHENDED__ <= 1;\n end"); - - // enforcing flush constraints - std::string flush_enforcement = VLG_TRUE; - if (instr["flush constraints"].is_null()) { - // do nothing. we are good - } else if (instr["flush constraints"].is_string()) { - flush_enforcement += - "&& (" + ReplExpr(instr["flush constraints"].get()) + - ")"; - } else if (instr["flush constraints"].is_array()) { - for (auto&& c : instr["flush constraints"]) - if (c.is_string()) - flush_enforcement += "&& (" + ReplExpr(c.get()) + ")"; - else - ILA_ERROR << "flush constraint field of instruction:" - << _instr_ptr->name().str() - << " must be a string or an array of string."; - } else - ILA_ERROR << "flush constraint field of instruction:" - << _instr_ptr->name().str() - << " must be string or array of string."; - - // TODO: preflush and postflush - - add_an_assumption( - "(~ ( __RESETED__ && ~ ( __START__ || __STARTED__ ) ) ) || (" + - flush_enforcement + ")", - "flush_enforce_pre"); - add_an_assumption("(~ ( __ENDED__ )) || (" + flush_enforcement + ")", - "flush_enforce_post"); + vlg_wrapper.add_wire("__ISSUE__", 1, true); + rfmap_add_internal_wire("__ISSUE__", 1); + + if (_vtg_config.ForceInstCheckReset) { + vlg_wrapper.add_input("__ISSUE__", 1); + } else + vlg_wrapper.add_assign_stmt("__ISSUE__", "1"); + // start decode -- issue enforce (e.g. valid, input) - } else { - vlg_wrapper.add_wire("__ISSUE__", 1, true); - if (_vtg_config.ForceInstCheckReset) { - vlg_wrapper.add_input("__ISSUE__", 1); - } else - add_wire_assign_assumption("__ISSUE__", "1", "ISSUE"); // issue ASAP - // start decode -- issue enforce (e.g. valid, input) - } // end of no flush } // ConstructWrapper_add_condition_signals } // namespace ilang diff --git a/src/vtarget-out/single_target_connect.cc b/src/vtarget-out/single_target_connect.cc index 7511d0644..0272e6d9c 100644 --- a/src/vtarget-out/single_target_connect.cc +++ b/src/vtarget-out/single_target_connect.cc @@ -57,15 +57,17 @@ std::string VlgSglTgtGen::ConstructWrapper_get_ila_module_inst() { target_type == target_type_t::INV_SYN_DESIGN_ONLY) return ""; - ILA_CHECK(vlg_ila.decodeNames.size() == 1) - << "Implementation bug: decode condition."; - vlg_wrapper.add_wire(vlg_ila.validName, 1, true); - vlg_wrapper.add_wire(vlg_ila.decodeNames[0], 1, true); + vlg_wrapper.add_wire(vlg_ila.GetValidSignalName(_instr_ptr), 1, true); + vlg_wrapper.add_wire(vlg_ila.GetDecodeSignalName(_instr_ptr), 1, true); + + rfmap_add_internal_wire(vlg_ila.GetValidSignalName(_instr_ptr), 1); + rfmap_add_internal_wire(vlg_ila.GetDecodeSignalName(_instr_ptr), 1); + rfmap_add_replacement("$decode", vlg_ila.GetDecodeSignalName(_instr_ptr)); + rfmap_add_replacement("$valid", vlg_ila.GetValidSignalName(_instr_ptr)); // TODO: check whether all ports have been dealt with // TODO: check whether there are any extra ports we create std::set port_connected; // store the name of ila port - std::set port_of_ila; // store the name of ila port also // .. record function @@ -81,6 +83,7 @@ std::string VlgSglTgtGen::ConstructWrapper_get_ila_module_inst() { port_connected.insert(port_name); vlg_wrapper.add_wire(port_name, 1, true); vlg_wrapper.add_output(port_name, 1); + rfmap_add_internal_wire(port_name, 1); retStr += " ." + port_name + "(" + port_name + "),\n"; } @@ -95,18 +98,12 @@ std::string VlgSglTgtGen::ConstructWrapper_get_ila_module_inst() { std::string func_reg_w = func_app.func_name + "_" + IntToStr(func_no) + "_result_wire"; - std::string func_reg = - func_app.func_name + "_" + IntToStr(func_no) + "_result_reg"; - vlg_wrapper.add_reg(func_reg, func_app.result.second); + vlg_wrapper.add_wire(func_reg_w, func_app.result.second, true); + rfmap_add_internal_wire(func_reg_w, func_app.result.second); // add as a module input, also vlg_wrapper.add_input(func_reg_w, func_app.result.second); - add_reg_cassign_assumption(func_reg, func_reg_w, func_app.result.second, - "__START__", "func_result"); - // vlg_wrapper.add_always_stmt( "if( __START__ ) " + func_reg + " <= " + - // func_reg_w + ";" ); - retStr += " ." + func_app.result.first + "(" + func_reg_w + "),\n"; unsigned argNo = 0; @@ -116,12 +113,10 @@ std::string VlgSglTgtGen::ConstructWrapper_get_ila_module_inst() { std::string func_arg_w = func_app.func_name + "_" + IntToStr(func_no) + "_arg" + IntToStr(argNo) + "_wire"; - std::string func_arg = func_app.func_name + "_" + IntToStr(func_no) + - "_arg" + IntToStr(argNo) + "_reg"; - vlg_wrapper.add_reg(func_arg, arg.second); + // this should be module output vlg_wrapper.add_wire(func_arg_w, arg.second, true); - add_reg_cassign_assumption(func_arg, func_arg_w, arg.second, "__START__", - "func_arg"); + rfmap_add_internal_wire(func_arg_w, arg.second); + // vlg_wrapper.add_always_stmt( "if( __START__ ) " + func_arg + " <= " + // func_arg_w + ";" ); @@ -199,6 +194,9 @@ std::string VlgSglTgtGen::ConstructWrapper_get_ila_module_inst() { // auto rew = "__IMEM_" + ila_name + "_" + IntToStr(no) + "_ren"; no need, // r_en is the start signal + rfmap_add_internal_wire(rdw, dw); + rfmap_add_internal_wire(raw, aw); + vlg_wrapper.add_wire(rdw, dw, true); vlg_wrapper.add_wire(raw, aw, true); @@ -228,10 +226,30 @@ std::string VlgSglTgtGen::ConstructWrapper_get_ila_module_inst() { auto wdw = "__IMEM_" + ila_name + "_" + IntToStr(no) + "_wdata"; auto waw = "__IMEM_" + ila_name + "_" + IntToStr(no) + "_waddr"; auto wew = "__IMEM_" + ila_name + "_" + IntToStr(no) + "_wen"; + auto wdw_delay = wdw + "_d1"; + auto waw_delay = waw + "_d1"; + auto wew_delay = wew + "_d1"; vlg_wrapper.add_wire(wdw, dw, true); vlg_wrapper.add_wire(waw, aw, true); vlg_wrapper.add_wire(wew, 1, true); + rfmap_add_internal_wire(wdw, dw); + rfmap_add_internal_wire(waw, aw); + rfmap_add_internal_wire(wew, 1); + + // latch the write signal + vlg_wrapper.add_reg(wdw_delay, dw); + vlg_wrapper.add_reg(waw_delay, aw); + vlg_wrapper.add_reg(wew_delay, 1); + rfmap_add_internal_reg(wdw_delay, dw); + rfmap_add_internal_reg(waw_delay, aw); + rfmap_add_internal_reg(wew_delay, 1); + vlg_wrapper.add_always_stmt("if (__START__) " + wdw_delay + " <= " + wdw + + ";"); + vlg_wrapper.add_always_stmt("if (__START__) " + waw_delay + " <= " + waw + + ";"); + vlg_wrapper.add_always_stmt("if (__START__) " + wew_delay + " <= " + wew + + ";"); retStr += " ." + port.wdata + "(" + wdw + "),\n"; retStr += " ." + port.waddr + "(" + waw + "),\n"; @@ -272,41 +290,46 @@ std::string VlgSglTgtGen::ConstructWrapper_get_ila_module_inst() { void VlgSglTgtGen::ConstructWrapper_add_vlg_input_output() { - auto vlg_inputs = - vlg_info_ptr->get_top_module_io(supplementary_info.width_info); - auto& io_map = IN("interface mapping", rf_vmap) - ? rf_vmap["interface mapping"] - : rf_vmap["interface-mapping"]; + auto vlg_inputs = vlg_info_ptr->get_top_module_io(refinement_map.width_info); + + ILA_CHECK( + refinement_map.rtl_interface_connection.clock_domain_defs.size() == 1 && + IN("default", refinement_map.rtl_interface_connection.clock_domain_defs)) + << "Not implemented. Cannot handle multi-clock."; + + ILA_CHECK( + refinement_map.rtl_interface_connection.custom_reset_domain_defs.empty()) + << "Not implemented. Cannot handle customized reset."; + + const auto& clock_pins = + refinement_map.rtl_interface_connection.clock_domain_defs.at("default"); + const auto& reset_pins = refinement_map.rtl_interface_connection.reset_pins; + const auto& nreset_pins = refinement_map.rtl_interface_connection.nreset_pins; + const auto& custom_input = refinement_map.rtl_interface_connection.input_port_connection; for (auto&& name_siginfo_pair : vlg_inputs) { - std::string refstr = - IN(name_siginfo_pair.first, io_map) - ? io_map[name_siginfo_pair.first].get() - : ""; - _idr.RegisterInterface( - name_siginfo_pair.second, refstr, - // Verifier_compatible_w_ila_input - [this](const std::string& ila_name, - const SignalInfoBase& vlg_sig_info) -> bool { - return TypeMatched(IlaGetInput(ila_name), vlg_sig_info) != 0; - }, - // no need to worry about the nullptr in IlaGetInput, TypeMatched will - // be able to handle. - // Verifier_get_ila_mem_info - [this]( - const std::string& ila_mem_name) -> std::pair { - return GetMemInfo(ila_mem_name); - }); // end of function call: RegisterInterface + std::string refstr = "**KEEP**"; + if (IN(name_siginfo_pair.first, clock_pins)) + refstr = "**CLOCK**"; + else if (IN(name_siginfo_pair.first, reset_pins)) + refstr = "**RESET**"; + else if (IN(name_siginfo_pair.first, nreset_pins)) + refstr = "**NRESET**"; + else if (IN(name_siginfo_pair.first, custom_input)) { + auto short_name = name_siginfo_pair.first; + auto wname = "__VLG_II_" + short_name; + add_wire_assign_assumption( wname, custom_input.at(name_siginfo_pair.first), + "vlg_input_wire"); + rfmap_add_internal_wire(wname, + name_siginfo_pair.second.get_width() ); + refstr = "**CUSTOM_INPUT**"; + } + + _idr.RegisterInterface(name_siginfo_pair.second, refstr); } } // ConstructWrapper_add_vlg_input_output // ------------------------ ALL instantiation ----------------------------- // void VlgSglTgtGen::ConstructWrapper_add_module_instantiation() { - // instantiate ila module - if (target_type == target_type_t::INSTRUCTIONS) { - auto ila_mod_inst = ConstructWrapper_get_ila_module_inst(); - vlg_wrapper.add_stmt(ila_mod_inst); - } - // instantiate verilog module std::string verilog_inst_str = vlg_info_ptr->get_top_module_name() + " " + _vlg_mod_inst_name + "(\n"; @@ -321,26 +344,13 @@ void VlgSglTgtGen::ConstructWrapper_add_module_instantiation() { // ------------------------ OTERHS (refs) ----------------------------- // void VlgSglTgtGen::ConstructWrapper_register_extra_io_wire() { - for (auto&& refered_vlg_item : _all_referred_vlg_names) { - - auto idx = refered_vlg_item.first.find("["); - auto removed_range_name = refered_vlg_item.first.substr(0, idx); - auto vlg_sig_info = vlg_info_ptr->get_signal(removed_range_name, - supplementary_info.width_info); - - auto vname = ReplaceAll( - ReplaceAll(ReplaceAll(refered_vlg_item.first, ".", "__DOT__"), "[", - "_"), - "]", "_"); - // + ReplaceAll(ReplaceAll(refered_vlg_item.second.range, "[","_"),"]","_"); - // // name for verilog - auto width = vlg_sig_info.get_width(); - - vlg_wrapper.add_wire(vname, width, 1); // keep - vlg_wrapper.add_output(vname, width); // add as output of the wrapper - _idr.RegisterExtraWire(vname, vname); - // these will be connected to the verilog module, so register as extra wires - // so, later they will be connected + for (auto&& extra_wire : rtl_extra_wire) { + const auto& wire_name = extra_wire.first; + unsigned width = extra_wire.second.width; + + vlg_wrapper.add_wire(wire_name, width, 1); // keep + vlg_wrapper.add_output(wire_name, width); // add as output of the wrapper + _idr.RegisterExtraWire(wire_name, wire_name); } } // ConstructWrapper_register_extra_io_wire diff --git a/src/vtarget-out/single_target_inv_syn_support.cc b/src/vtarget-out/single_target_inv_syn_support.cc index f34e222fc..b5c2ea93b 100644 --- a/src/vtarget-out/single_target_inv_syn_support.cc +++ b/src/vtarget-out/single_target_inv_syn_support.cc @@ -15,6 +15,8 @@ #include #include +#include + namespace ilang { // ------------- CONFIGURATIONS -------------------- // @@ -72,17 +74,21 @@ void VlgSglTgtGen::add_inv_obj_as_assertion(InvariantObject* inv_obj) { for (auto&& name_expr_pair : inv_obj->GetExtraVarDefs()) { vlg_wrapper.add_wire(std::get<0>(name_expr_pair), std::get<2>(name_expr_pair), true); - vlg_wrapper.add_assign_stmt(std::get<0>(name_expr_pair), - ReplExpr(std::get<1>(name_expr_pair), true)); + vlg_wrapper.add_output(std::get<0>(name_expr_pair), + std::get<2>(name_expr_pair)); + rfmap_add_internal_wire(std::get<0>(name_expr_pair), + std::get<2>(name_expr_pair)); + add_wire_assign_assumption( + std::get<0>(name_expr_pair), + refinement_map.ParseRfExprFromString(std::get<1>(name_expr_pair)), + "invariant_aux_var"); } for (auto&& name_w_pair : inv_obj->GetExtraFreeVarDefs()) { vlg_wrapper.add_wire(name_w_pair.first, name_w_pair.second, true); vlg_wrapper.add_input(name_w_pair.first, name_w_pair.second); } for (auto&& inv_expr : inv_obj->GetVlgConstraints()) { - auto new_cond = ReplExpr(inv_expr, true); - ILA_CHECK(!S_IN("][", new_cond)) - << "Inv translate error: ][ found in:" << new_cond; + auto new_cond = refinement_map.ParseRfExprFromString(inv_expr); add_an_assertion(new_cond, "invariant_assert"); } } // add_inv_obj_as_assertion @@ -92,29 +98,29 @@ void VlgSglTgtGen::add_inv_obj_as_assumption(InvariantObject* inv_obj) { for (auto&& name_expr_pair : inv_obj->GetExtraVarDefs()) { vlg_wrapper.add_wire(std::get<0>(name_expr_pair), std::get<2>(name_expr_pair), true); - vlg_wrapper.add_assign_stmt(std::get<0>(name_expr_pair), - ReplExpr(std::get<1>(name_expr_pair), true)); + vlg_wrapper.add_output(std::get<0>(name_expr_pair), + std::get<2>(name_expr_pair)); + rfmap_add_internal_wire(std::get<0>(name_expr_pair), + std::get<2>(name_expr_pair)); + add_wire_assign_assumption( + std::get<0>(name_expr_pair), + refinement_map.ParseRfExprFromString(std::get<1>(name_expr_pair)), + "invariant_aux_var"); } for (auto&& name_w_pair : inv_obj->GetExtraFreeVarDefs()) { vlg_wrapper.add_wire(name_w_pair.first, name_w_pair.second, true); vlg_wrapper.add_input(name_w_pair.first, name_w_pair.second); } for (auto&& inv_expr : inv_obj->GetVlgConstraints()) { - auto new_cond = ReplExpr(inv_expr, true); - ILA_CHECK(!S_IN("][", new_cond)) - << "Inv translate error: ][ found in:" << new_cond; + auto new_cond = refinement_map.ParseRfExprFromString(inv_expr); add_an_assumption(new_cond, "invariant_assume"); } } // add_inv_obj_as_assumption void VlgSglTgtGen::add_rf_inv_as_assumption() { if (has_rf_invariant) { - nlohmann::json& inv = IN("global invariants", rf_cond) - ? rf_cond["global invariants"] - : rf_cond["global-invariants"]; - for (auto& cond : inv) { - auto new_cond = ReplExpr(cond.get(), true); - add_an_assumption(new_cond, "invariant_assume"); // without new var added + for (auto&& cond : refinement_map.global_invariants) { + add_an_assumption(cond, "invariant_assume"); // without new var added } // for inv in global invariants field } } // add_rf_inv_as_assumption @@ -122,13 +128,8 @@ void VlgSglTgtGen::add_rf_inv_as_assumption() { void VlgSglTgtGen::add_rf_inv_as_assertion() { // the provided invariants if (has_rf_invariant) { - nlohmann::json& inv = IN("global invariants", rf_cond) - ? rf_cond["global invariants"] - : rf_cond["global-invariants"]; - for (auto& cond : inv) { - auto new_cond = - ReplExpr(cond.get(), true); // force vlg state - add_an_assertion("(" + new_cond + ")", "invariant_assert"); + for (auto& cond : refinement_map.global_invariants) { + add_an_assertion(cond, "invariant_assert"); } } // has_rf_invariant } // add_rf_inv_as_assertion @@ -138,14 +139,14 @@ void VlgSglTgtGen:: ConstructWrapper_add_inv_assumption_or_assertion_target_invariant() { ILA_CHECK(target_type == target_type_t::INVARIANTS); if (_vtg_config.ValidateSynthesizedInvariant == - vtg_config_t::_validate_synthesized_inv::NOINV && + RtlVerifyConfig::_validate_synthesized_inv::NOINV && !has_rf_invariant) { ILA_CHECK(false) << "No invariant to handle for INVARIANT target, this is a bug!"; } if (_vtg_config.ValidateSynthesizedInvariant == - vtg_config_t::_validate_synthesized_inv::ALL) { + RtlVerifyConfig::_validate_synthesized_inv::ALL) { ILA_CHECK(has_confirmed_synthesized_invariant || has_gussed_synthesized_invariant || has_rf_invariant) << "No invariant to handle for INVARIANT target, this is a bug!"; @@ -156,7 +157,7 @@ void VlgSglTgtGen:: add_rf_inv_as_assertion(); } else if (_vtg_config.ValidateSynthesizedInvariant == - vtg_config_t::_validate_synthesized_inv::CANDIDATE) { + RtlVerifyConfig::_validate_synthesized_inv::CANDIDATE) { ILA_CHECK(has_gussed_synthesized_invariant) << "No invariant to handle for INVARIANT target, need candidate " "invariant!"; @@ -168,7 +169,7 @@ void VlgSglTgtGen:: add_rf_inv_as_assumption(); } else if (_vtg_config.ValidateSynthesizedInvariant == - vtg_config_t::_validate_synthesized_inv::CONFIRMED) { + RtlVerifyConfig::_validate_synthesized_inv::CONFIRMED) { ILA_INFO_IF(has_confirmed_synthesized_invariant) << "Will ignore candidate invariants when checking confirmed " "invariants"; @@ -180,7 +181,7 @@ void VlgSglTgtGen:: // assume rf add_rf_inv_as_assumption(); } else if (_vtg_config.ValidateSynthesizedInvariant == - vtg_config_t::_validate_synthesized_inv::NOINV) { + RtlVerifyConfig::_validate_synthesized_inv::NOINV) { // assert rf add_rf_inv_as_assertion(); } @@ -210,10 +211,9 @@ void VlgSglTgtGen:: if (_advanced_param_ptr && _advanced_param_ptr->_cex_obj_ptr) { // this is cex reachability checking // -- assertions -- // - auto new_cond = - ReplExpr(_advanced_param_ptr->_cex_obj_ptr->GenInvAssert(""), - true); // force vlg state - add_an_assertion("~(" + new_cond + ")", "cex_nonreachable_assert"); + auto new_cond = refinement_map.ParseRfExprFromString( + _advanced_param_ptr->_cex_obj_ptr->GenInvAssert("")); // force vlg state + add_an_assertion(rfmap_not(new_cond), "cex_nonreachable_assert"); // -- assumption -- // if (_vtg_config.InvariantSynthesisReachableCheckKeepOldInvariant) { add_rf_inv_as_assumption(); @@ -247,47 +247,13 @@ void VlgSglTgtGen::ConstructWrapper_inv_syn_cond_signals() { target_type == target_type_t::INVARIANTS); vlg_wrapper.add_input("__START__", 1); vlg_wrapper.add_input("__STARTED__", 1); -} - -void VlgSglTgtGen::ConstructWrapper_inv_syn_connect_mem() { - ILA_CHECK(target_type == target_type_t::INV_SYN_DESIGN_ONLY || - target_type == target_type_t::INVARIANTS); - - std::map> ila_mem_state_names; - for (size_t state_idx = 0; state_idx < _host->state_num(); ++state_idx) { - if (_host->state(state_idx)->is_mem()) - ila_mem_state_names.insert( - std::make_pair(_host->state(state_idx)->name().str(), - std::make_pair( - _host->state(state_idx)->sort()->addr_width(), - _host->state(state_idx)->sort()->data_width()))); - } - nlohmann::json& state_mapping = IN("state mapping", rf_vmap) - ? rf_vmap["state mapping"] - : rf_vmap["state-mapping"]; - for (auto& i : state_mapping.items()) { - auto sname = i.key(); // ila state name - if (!IN(sname, ila_mem_state_names)) - continue; // we only care about the mem states - if (i.value().is_null()) { - ILA_ERROR << "Ignore mapping memory: " << sname; - continue; - } - // ILA_INFO << i.key() << i.value(); - // Connect memory here - if (i.value().is_string() && - StrStartsWith(i.value().get(), "**")) { - _idr.SetMemNameAndWidth( - i.value(), sname, _vtg_config.MemAbsReadAbstraction, - ila_mem_state_names[sname].first, ila_mem_state_names[sname].second); - ila_mem_state_names.erase(sname); - } - } - - // check for unmapped memory - for (auto&& m : ila_mem_state_names) - ILA_ERROR << "No mapping exists for memory : " << m.first; -} // ConstructWrapper_inv_syn_connect_mem + rfmap_add_internal_wire("__START__", 1); + rfmap_add_replacement("decode", "__START__"); + rfmap_add_replacement("start", "__START__"); + rfmap_add_internal_wire("__STARTED__", 1); + rfmap_add_replacement("afterdecode", "__STARTED__"); + rfmap_add_replacement("afterstart", "__STARTED__"); +} } // namespace ilang diff --git a/src/vtarget-out/single_target_misc.cc b/src/vtarget-out/single_target_misc.cc index fd0f78341..4031e46db 100644 --- a/src/vtarget-out/single_target_misc.cc +++ b/src/vtarget-out/single_target_misc.cc @@ -9,6 +9,7 @@ #include #include +#include #include #include #include @@ -30,104 +31,69 @@ bool VlgSglTgtGen::bad_state_return(void) { return _bad_state; } // bad_state_return -void VlgSglTgtGen::ConstructWrapper_add_additional_mapping_control() { - if (IN("mapping control", rf_vmap)) { - if (!rf_vmap["mapping control"].is_array()) - ILA_ERROR << "mapping control field must be an array of string"; - for (auto&& c : rf_vmap["mapping control"]) { - if (!c.is_string()) { - ILA_ERROR << "mapping control field must be an array of string"; - continue; - } - add_an_assumption(ReplExpr(c.get()), - "additional_mapping_control_assume"); - } +void VlgSglTgtGen::RfmapIlaStateSanityCheck() { +#define ERR_IF(cond, s) \ + do { \ + ILA_ERROR_IF(cond) << (s); \ + if (cond) { \ + _bad_state = true; \ + return; \ + } \ + } while (0) + + for (unsigned sidx = 0; sidx < _host->state_num(); ++sidx) { + const auto& s = _host->state(sidx); + const auto& n = s->name().str(); + ERR_IF(!IN(n, refinement_map.ila_state_var_map), + "state `" + n + "` not in refinement map"); } -} // ConstructWrapper_add_additional_mapping_control -void VlgSglTgtGen::ConstructWrapper_add_rf_assumptions() { - if (IN("assumptions", rf_vmap)) { - if (!rf_vmap["assumptions"].is_array()) - ILA_ERROR << "`assumptions` field must be an array of string"; - for (auto&& c : rf_vmap["assumptions"]) { - if (!c.is_string()) { - ILA_ERROR << "`assumptions` field must be an array of string"; - continue; - } - add_an_assumption(ReplExpr(c.get()), "rfassumptions"); - } + for (unsigned sidx = 0; sidx < _host->input_num(); ++sidx) { + const auto& s = _host->input(sidx); + const auto& n = s->name().str(); + ERR_IF(!IN(n, refinement_map.ila_input_var_map), + "input `" + n + "` not in refinement map"); } -} // ConstructWrapper_add_rf_assumptions -void VlgSglTgtGen::ConstructWrapper_add_helper_memory() { - auto endCond = - has_flush ? "__ENDFLUSH__ || __FLUSHENDED__" : "__IEND__ || __ENDED__"; - - // here we insert the memory ports - for (auto&& memname_ports_pair : supplementary_info.memory_ports) { - // add wire - for (auto&& port_expr_port : memname_ports_pair.second) { - if (RemoveWhiteSpace(port_expr_port.second).empty()) - _idr.KeepMemoryPorts(memname_ports_pair.first, port_expr_port.first, - false); - // does not need to create extra wires - else { - // create wire as abs_mem_will not - auto wn = _idr.KeepMemoryPorts(memname_ports_pair.first, - port_expr_port.first, true); - vlg_wrapper.add_wire(wn.first, wn.second, true); - vlg_wrapper.add_assign_stmt(wn.first, ReplExpr(port_expr_port.second)); - } - } + for (const auto& n_map_pair : refinement_map.ila_state_var_map) { + ERR_IF(_host->find_state(n_map_pair.first) == nullptr, + "state `" + n_map_pair.first + "` not defined in ILA"); } - auto stmt = _idr.GetAbsMemInstString(vlg_wrapper, endCond); + for (const auto& n_map_pair : refinement_map.ila_input_var_map) { + ERR_IF(_host->find_input(n_map_pair.first) == nullptr, + "input `" + n_map_pair.first + "` not defined in ILA"); + } + +#undef ERR_IF +} - if (!((target_type == target_type_t::INV_SYN_DESIGN_ONLY && - !_vtg_config.InvariantSynthesisKeepMemory) || - (target_type == target_type_t::INVARIANTS && - !_vtg_config.InvariantCheckKeepMemory))) - vlg_wrapper.add_stmt(stmt); +void VlgSglTgtGen::ConstructWrapper_add_additional_mapping_control() { + for (const auto& mapc : refinement_map.additional_mapping) { + add_an_assumption(mapc, "additional_mapping_control_assume"); + } +} // ConstructWrapper_add_additional_mapping_control - // check if we need to insert any assumptions - auto inserter = [this](const std::string& p) -> void { - if (target_type == target_type_t::INSTRUCTIONS) - add_an_assumption(p, "absmem"); - }; - _idr.InsertAbsMemAssmpt(inserter); -} // ConstructWrapper_add_helper_memory +void VlgSglTgtGen::ConstructWrapper_add_rf_assumptions() { + for (const auto& assumpt : refinement_map.assumptions) { + add_an_assumption(assumpt, "rfassumptions"); + } +} // ConstructWrapper_add_rf_assumptions void VlgSglTgtGen::ConstructWrapper_add_uf_constraints() { - if (!IN("functions", rf_vmap)) - return; // do nothing - auto& fm = rf_vmap["functions"]; - if (!fm.is_object()) { - ILA_ERROR << "expect functions field to be funcName -> list of list of " - "pair of (cond,val)."; + if (refinement_map.uf_application.empty()) return; - } // convert vlg_ila.ila_func_app to name->list of func_app std::map name_to_fnapp_vec; for (auto&& func_app : vlg_ila.ila_func_app) { - if (_vtg_config.IteUnknownAutoIgnore) { - if (func_app.args.empty() && - _sdr.isSpecialUnknownFunctionName(func_app.func_name)) - continue; - } name_to_fnapp_vec[func_app.func_name].push_back(func_app); } - for (auto&& it : fm.items()) { - const auto& funcName = it.key(); - const auto& list_of_time_of_apply = it.value(); - if (!list_of_time_of_apply.is_array()) { - ILA_ERROR << funcName - << ": expect functions field to be funcName -> list of list of " - "pair of (cond,val)."; - continue; - } + for (const auto& uf_app : refinement_map.uf_application) { + const auto& funcName = uf_app.first; + const auto& list_of_time_of_apply = uf_app.second.func_applications; if (!IN(funcName, name_to_fnapp_vec)) { // ILA_WARN << "uninterpreted function mapping:" << funcName // << " does not exist. Skipped."; @@ -140,263 +106,383 @@ void VlgSglTgtGen::ConstructWrapper_add_uf_constraints() { << " not matched. Skipped."; continue; } - auto& ila_app_list = name_to_fnapp_vec[funcName]; - size_t idx = 0; - for (auto&& each_apply : list_of_time_of_apply.items()) { - if (!each_apply.value().is_array()) { - ILA_ERROR << funcName - << ": expecting mapping to be list of pair of (cond,val)."; - idx++; - continue; - } + for (auto&& each_apply : list_of_time_of_apply) { + auto& ila_app_item = ila_app_list[idx]; idx++; - if (each_apply.value().size() != (ila_app_item.args.size() + 1) * 2) { - ILA_ERROR << "ila func app expect: (1(retval) + " - << ila_app_item.args.size() << "(args) )*2" - << " items. Given:" << each_apply.value().size() + if (each_apply.arg_map.size() != ila_app_item.args.size()) { + ILA_ERROR << "ila func app expect: " << ila_app_item.args.size() + << " (args)." + << " Given:" << each_apply.arg_map.size() << " items, for func: " << funcName; continue; } - auto val_arg_map_str_vec = - each_apply.value().get>(); - - std::string func_reg = funcName + "_" + IntToStr(idx - 1) + "_result_reg"; - // okay now get the chance - auto val_cond = ReplExpr(val_arg_map_str_vec[0]); - auto val_map = ReplExpr(val_arg_map_str_vec[1], - true); // force vlg name on the mapping - auto res_map = "~(" + val_cond + ")||(" + func_reg + "==" + val_map + ")"; - - std::string prep = VLG_TRUE; - for (size_t arg_idx = 2; arg_idx < val_arg_map_str_vec.size(); - arg_idx += 2) { - const auto& cond = ReplExpr(val_arg_map_str_vec[arg_idx]); - const auto& map = ReplExpr(val_arg_map_str_vec[arg_idx + 1], true); + const auto& arg_apply = each_apply.arg_map; + const auto& result_apply = each_apply.result_map; + std::string func_result_wire = + funcName + "_" + IntToStr(idx - 1) + "_result_wire"; - std::string func_arg = funcName + "_" + IntToStr(idx - 1) + "_arg" + - IntToStr(arg_idx / 2 - 1) + "_reg"; + auto res_map = + rfmap_imply(rfmap_var("decode"), + rfmap_eq(rfmap_var(func_result_wire), result_apply)); - prep += "&&(~(" + cond + ")||((" + func_arg + ") == (" + map + ")))"; - } + std::vector prep; + size_t arg_idx = 0; + for (const auto& each_arg : arg_apply) { - add_an_assumption("~(" + prep + ") || (" + res_map + ")", "funcmap"); + std::string func_arg = funcName + "_" + IntToStr(idx - 1) + "_arg" + + IntToStr(arg_idx++) + "_wire"; + prep.push_back(rfmap_imply(rfmap_var("decode"), + rfmap_eq(rfmap_var(func_arg), each_arg))); + } + // ( + // (decode |-> arg0_output == ??@?? ) && (decode |-> arg1_output == + // ??@?? ) + // && ... + // ) |-> ( + // (decode |-> result_input == ??@??) + // ) + auto pre_cond = prep.empty() ? rfmap_true() : rfmap_and(prep); + add_an_assumption(rfmap_imply(pre_cond, res_map), "funcmap"); } // for each apply in the list of apply name_to_fnapp_vec.erase(funcName); // remove from it } + // check for unmapped func for (auto&& nf : name_to_fnapp_vec) ILA_ERROR << "lacking function map for func:" << nf.first; } // ConstructWrapper_add_uf_constraints -int VlgSglTgtGen::ConstructWrapper_add_post_value_holder_handle_obj( - nlohmann::json& pv_cond_val, const std::string& pv_name, int width, - bool create_reg) { - - std::string cond = VLG_TRUE; - std::string val = "'hx"; - std::string original_val_field; - - for (auto&& cond_val_pair : pv_cond_val.items()) { - if (cond_val_pair.key() == "cond") - cond = ReplExpr(cond_val_pair.value(), true); - else if (cond_val_pair.key() == "val") { - original_val_field = cond_val_pair.value(); - StrTrim(original_val_field); - val = ReplExpr(original_val_field, true); - } else if (cond_val_pair.key() == "width") { - if (cond_val_pair.value().is_string()) { - ILA_CHECK(cond_val_pair.value().get() == "auto") - << "Expecting width to be unsigned int / auto"; - ILA_CHECK(!original_val_field.empty()) - << "You must first provide `val` field before auto"; - if (original_val_field.find("[") != original_val_field.npos) - original_val_field = - original_val_field.substr(0, original_val_field.find("[")); - if (S_IN("=", original_val_field)) { - ILA_WARN << "Creating value-holder for conditions"; - width = 1; - } else if (vlg_info_ptr->check_hierarchical_name_type( - original_val_field) != - VerilogInfo::hierarchical_name_type::NONE) { - auto vlg_sig_info = vlg_info_ptr->get_signal( - original_val_field, supplementary_info.width_info); - width = vlg_sig_info.get_width(); - } else if (vlg_info_ptr->check_hierarchical_name_type( - _vlg_mod_inst_name + "." + original_val_field) != - VerilogInfo::hierarchical_name_type::NONE) { - auto vlg_sig_info = vlg_info_ptr->get_signal( - _vlg_mod_inst_name + "." + original_val_field, - supplementary_info.width_info); - width = vlg_sig_info.get_width(); - } else { - ILA_ERROR << "Cannot auto-determine value-holder width for val:" - << original_val_field; - width = 0; - } - } else - width = cond_val_pair.value().get(); - } else - ILA_ERROR << "Unexpected key: " << cond_val_pair.key() - << " in post-value-holder, expecting 0-2 or cond/val/width"; - } - ILA_WARN_IF(val == "'hx") << "val field is not provided for " << pv_name; - ILA_WARN_IF(cond == VLG_TRUE) << "cond field is not provided for " << pv_name; - ILA_ERROR_IF(width <= 0 && create_reg) - << "Cannot create signal for " << pv_name << " : unknown width!"; - if (width >= 0 && create_reg) { // error - // ILA_ERROR << "width of post-value-holder `" << pv_name << "` is - // unknown!"; - vlg_wrapper.add_reg(pv_name, width); - } - add_reg_cassign_assumption(pv_name, val, width, cond, "post_value_holder"); - - return width; -} +void VlgSglTgtGen::ConstructWrapper_add_delay_unit() { + // for (const auto& delay_unit : refinement_map.aux_delays) { + // std::cout << delay_unit.first << " : expr = " + // << (delay_unit.second.signal) << std::endl; + // } + + for (const auto& delay_unit : refinement_map.aux_delays) { + const auto& name = delay_unit.first; + const auto& du = delay_unit.second; + unsigned width = du.width; + auto rhs = du.signal; + if (du.delay_type != rfmap::SignalDelay::delay_typeT::SINGLE && + du.width > 1) { + width = 1; + rhs = rfmap_reduce_or(rhs); + } -void VlgSglTgtGen::ConstructWrapper_add_post_value_holder() { - if (!IN("post-value-holder", rf_vmap) && !IN("value-holder", rf_vmap)) - return; // no need for it - ILA_WARN_IF(IN("post-value-holder", rf_vmap)) - << "The name `post-value-holder` will be deprecated in the future, " - << "please use `value-holder` instead"; - auto& post_val_rec = IN("value-holder", rf_vmap) - ? rf_vmap["value-holder"] - : rf_vmap["post-value-holder"]; - if (!post_val_rec.is_object()) { - ILA_ERROR << "Expect (post-)value-holder to be map-type"; - return; - } - for (auto&& item : post_val_rec.items()) { - const auto& pv_name = item.key(); - auto& pv_cond_val = item.value(); - ILA_ERROR_IF(!(pv_cond_val.is_array() || pv_cond_val.is_object())) - << "Expecting (post-)value-holder's content to be list or map type"; - if (pv_cond_val.is_array() && - (!pv_cond_val.empty() && - (pv_cond_val.begin()->is_array() || - pv_cond_val.begin()->is_object()))) { // multiple condition - int w = 0; - bool first = true; - for (auto ptr = pv_cond_val.begin(); ptr != pv_cond_val.end(); ++ptr) { - w = ConstructWrapper_add_post_value_holder_handle_obj(*ptr, pv_name, w, - first); - first = false; + ILA_ERROR_IF(du.num_cycle == 0) << "Cannot delay 0 cycle"; + std::string last_reg; + for (size_t didx = 1; didx <= du.num_cycle; ++didx) { + auto curr_name = name + "_d_" + std::to_string(didx); + auto prev_name = name + "_d_" + std::to_string(didx - 1); + vlg_wrapper.add_reg(curr_name, width); + if (didx == 1) { + // delay from signal + vlg_wrapper.add_wire(prev_name, width, true); + vlg_wrapper.add_output(prev_name, width); + rfmap_add_internal_wire(prev_name, width); + add_wire_assign_assumption(prev_name, rhs, "delay_unit"); } - } else { // it is just a single line - ConstructWrapper_add_post_value_holder_handle_obj(pv_cond_val, pv_name, 0, - true); + vlg_wrapper.add_always_stmt(curr_name + " <= " + prev_name + " ;"); + vlg_wrapper.add_init_stmt(curr_name + "<= 0;"); + if (didx == du.num_cycle) + last_reg = curr_name; + } // end - for each delay + if (du.delay_type == rfmap::SignalDelay::delay_typeT::SINGLE) { + vlg_wrapper.add_wire(name, width); + vlg_wrapper.add_assign_stmt(name, last_reg); + continue; + } // else + if (du.delay_type == rfmap::SignalDelay::delay_typeT::TO_INFINITE) { + auto summary_var = name + "_inf_"; + vlg_wrapper.add_reg(summary_var, 1); + vlg_wrapper.add_init_stmt(summary_var + "<= 1'b0;"); + vlg_wrapper.add_always_stmt("if( " + last_reg + ") " + summary_var + + " <= 1'b1;"); + vlg_wrapper.add_wire(name, 1); + vlg_wrapper.add_assign_stmt(name, summary_var + " || " + last_reg); + continue; + } + // finally the range + // if (du.delay_type == rfmap::SignalDelay::delay_typeT::RANGE) + ILA_ERROR_IF(du.upper_bnd <= du.num_cycle) + << "in `##[l:u]`, we need `l < u` "; + std::string or_reduce = last_reg; + for (size_t didx = du.num_cycle + 1; didx <= du.upper_bnd; ++didx) { + auto curr_name = name + "_d_" + std::to_string(didx); + auto prev_name = name + "_d_" + std::to_string(didx - 1); + vlg_wrapper.add_reg(curr_name, 1); + vlg_wrapper.add_init_stmt(curr_name + " <= 0;"); + vlg_wrapper.add_always_stmt(curr_name + " <= " + prev_name + " ;"); + + or_reduce += " || " + curr_name; + } + vlg_wrapper.add_wire(name, 1); + vlg_wrapper.add_assign_stmt(name, or_reduce); + } // end for each delay unit +} // end ConstructWrapper_add_delay_unit + +void VlgSglTgtGen::ConstructWrapper_add_stage_tracker() { + for (const auto& n_tracker : refinement_map.phase_tracker) { + const auto& tracker_name = n_tracker.first; + const auto& tracker = n_tracker.second; + + for (const auto& vardef : tracker.var_defs) { + // already in refinement_map.all_var_def_types + const auto& vn = vardef.first; + if (vardef.second.type == + rfmap::GeneralVerilogMonitor::VarDef::var_type::REG) + vlg_wrapper.add_reg(vn, vardef.second.width); + else + vlg_wrapper.add_wire(vn, vardef.second.width); } - } // for item + for (const auto& event_alias : tracker.event_alias) { + vlg_wrapper.add_wire(event_alias.first, 1); + vlg_wrapper.add_output(event_alias.first, 1); + rfmap_add_internal_wire(event_alias.first, 1); + // add_wire_assign_assumption + add_wire_assign_assumption(event_alias.first, event_alias.second, + "stage_tracker"); + } + unsigned sidx = 0; + for (const auto& stage : tracker.rules) { + const std::string& stage_name = stage.stage_name; + ILA_CHECK(!stage_name.empty()) + << "stage name is empty for " << tracker_name; + vlg_wrapper.add_reg(stage_name, 1); + + std::string enter_cond_wire_name = stage_name + "_enter_cond"; + std::string exit_cond_wire_name = stage_name + "_exit_cond"; + std::string enter_action_wire_name = stage_name + "_enter_action"; + std::string exit_action_wire_name = stage_name + "_exit_action"; + + vlg_wrapper.add_init_stmt(stage_name + "<= 1'b0;"); + vlg_wrapper.add_always_stmt("if(" + enter_cond_wire_name + ") begin " + + stage_name + " <= 1'b1;"); + vlg_wrapper.add_wire(enter_cond_wire_name, 1, true); + vlg_wrapper.add_output(enter_cond_wire_name, 1); + rfmap_add_internal_wire(enter_cond_wire_name, 1); + ILA_NOT_NULL(stage.enter_rule); + add_wire_assign_assumption(enter_cond_wire_name, stage.enter_rule, + "phase_tracker"); + + unsigned idx = 0; + for (const auto& action : stage.enter_action) { + auto pos_def_var = refinement_map.all_var_def_types.find(action.LHS); + ILA_ERROR_IF(pos_def_var == refinement_map.all_var_def_types.end()) + << "Cannot find var def for " << action.LHS + << " used in LHS of phase tracker " << tracker_name; + + std::string action_name = + enter_action_wire_name + std::to_string(idx++); + vlg_wrapper.add_always_stmt(action.LHS + " <= " + action_name + ";"); + + vlg_wrapper.add_wire(action_name, pos_def_var->second.width, true); + vlg_wrapper.add_output(action_name, pos_def_var->second.width); + rfmap_add_internal_wire(action_name, pos_def_var->second.width); + add_wire_assign_assumption(action_name, action.RHS, "phase_tracker"); + } + + vlg_wrapper.add_always_stmt("end"); + vlg_wrapper.add_always_stmt("else if(" + exit_cond_wire_name + + ") begin " + stage_name + " <= 1'b0;"); + + vlg_wrapper.add_wire(exit_cond_wire_name, 1, true); + vlg_wrapper.add_output(exit_cond_wire_name, 1); + rfmap_add_internal_wire(exit_cond_wire_name, 1); + if (stage.exit_rule == nullptr) + vlg_wrapper.add_assign_stmt(exit_cond_wire_name, "1'b0"); + else + add_wire_assign_assumption(exit_cond_wire_name, stage.exit_rule, + "phase_tracker"); + + idx = 0; + for (const auto& action : stage.exit_action) { + auto pos_def_var = refinement_map.all_var_def_types.find(action.LHS); + ILA_ERROR_IF(pos_def_var == refinement_map.all_var_def_types.end()) + << "Cannot find var def for " << action.LHS + << " used in LHS of phase tracker " << tracker_name; + + std::string action_name = exit_action_wire_name + std::to_string(idx++); + vlg_wrapper.add_always_stmt(action.LHS + " <= " + action_name + ";"); + vlg_wrapper.add_wire(action_name, pos_def_var->second.width, true); + vlg_wrapper.add_output(action_name, pos_def_var->second.width); + rfmap_add_internal_wire(action_name, pos_def_var->second.width); + add_wire_assign_assumption(action_name, action.RHS, "phase_tracker"); + } + + vlg_wrapper.add_always_stmt("end"); + + sidx++; + } // for each stage + } // for each tracker +} // ConstructWrapper_add_stage_tracker + +void VlgSglTgtGen::ConstructWrapper_add_post_value_holder() { + for (const auto& post_val_holder : refinement_map.value_recorder) { + const auto& pv_name = post_val_holder.first; + vlg_wrapper.add_reg(pv_name, post_val_holder.second.width); + rfmap_add_internal_reg(pv_name, post_val_holder.second.width); + + auto eq_cond = + _vtg_config.EnforcingValueRecorderForOnlyOneCycle + ? rfmap_and( + {rfmap_or(rfmap_var("__START__"), rfmap_var("__STARTED__")), + rfmap_not(rfmap_var(pv_name + "_sn_condmet")), + post_val_holder.second.condition}) + : post_val_holder.second.condition; + + add_reg_cassign_assumption(pv_name, post_val_holder.second.value, + post_val_holder.second.width, eq_cond, + "post_value_holder"); + + // for sanity check + vlg_wrapper.add_reg(pv_name + "_sn_vhold", post_val_holder.second.width); + rfmap_add_internal_reg(pv_name + "_sn_vhold", post_val_holder.second.width); + vlg_wrapper.add_wire(pv_name + "_sn_value", post_val_holder.second.width); + rfmap_add_internal_wire(pv_name + "_sn_value", + post_val_holder.second.width); + + vlg_wrapper.add_reg(pv_name + "_sn_condmet", 1); + rfmap_add_internal_reg(pv_name + "_sn_condmet", 1); + vlg_wrapper.add_wire(pv_name + "_sn_cond", 1); + rfmap_add_internal_wire(pv_name + "_sn_cond", 1); + vlg_wrapper.add_init_stmt(pv_name + "_sn_condmet <= 1'b0;"); + vlg_wrapper.add_always_stmt("if (" + pv_name + "_sn_cond ) begin " + + pv_name + "_sn_condmet <= 1'b1; " + pv_name + + "_sn_vhold <= " + pv_name + "_sn_value; end"); + + // pv_sn_cond = && ( __START__ || __STARTED__ ) + add_wire_assign_assumption( + pv_name + "_sn_cond", + rfmap_and({post_val_holder.second.condition, + rfmap_or(rfmap_var("__START__"), rfmap_var("__STARTED__")), + rfmap_not(rfmap_var("__ENDED__")) + }), + "pvholder_cond_assign"); + + // pv_sn_value = + add_wire_assign_assumption(pv_name + "_sn_value", + post_val_holder.second.value, + "pvholder_cond_assign"); + + add_a_santiy_assertion( + // cond && cond_met |-> value == value_stored + rfmap_imply(rfmap_and(rfmap_var(pv_name + "_sn_condmet"), + rfmap_var(pv_name + "_sn_cond")), + rfmap_eq(rfmap_var(pv_name + "_sn_value"), + rfmap_var(pv_name + "_sn_vhold"))), + "post_value_holder_overly_constrained"); + + // check : commit -> _cond_met + add_a_santiy_assertion( + rfmap_imply(rfmap_var("commit"), + rfmap_or( + rfmap_var(pv_name + "_sn_condmet"), + rfmap_var(pv_name + "_sn_cond") + )), + "post_value_holder_triggered"); + + } // for each value recorder } // ConstructWrapper_add_post_value_holder -void VlgSglTgtGen::ConstructWrapper_add_vlg_monitor() { - if (!IN("verilog-inline-monitors", rf_vmap)) - return; // no need for it +/// Add direct aux vars +void VlgSglTgtGen::ConstructWrapper_add_direct_aux_vars() { + for (const auto & n_expr : refinement_map.direct_aux_vars) { + const auto & n = n_expr.first; + auto w = n_expr.second.width; + ILA_CHECK(w!=0); // aux var should have its width + vlg_wrapper.add_wire(n,w,true); + vlg_wrapper.add_output(n,w); + add_wire_assign_assumption(n, n_expr.second.val, "direct_aux_var"); + } +} - auto& monitor_rec = rf_vmap["verilog-inline-monitors"]; - if (!monitor_rec.is_object()) { - ILA_ERROR << "Expect verilog-inline-monitors to be map-type"; +void VlgSglTgtGen::ConstructWrapper_add_vlg_monitor() { + if (refinement_map.customized_monitor.empty()) return; - } - for (auto&& m_rec : monitor_rec.items()) { - const auto& mname = m_rec.key(); // actually no use - auto& mdef = m_rec.value(); - ILA_ERROR_IF(!(mdef.is_object())) - << "Expect verilog-inline-monitors's element to be map type"; + const auto& monitor_rec = refinement_map.customized_monitor; + + for (auto&& m_rec : monitor_rec) { + + const auto& mname = m_rec.first; + const auto& mdef = m_rec.second; // generalMonitor + std::string vlg_expr; std::vector repl_list; - bool keep_for_non_instruction_target = false; - if (IN("keep-for-invariants", mdef) && - mdef["keep-for-invariants"].get()) - keep_for_non_instruction_target = true; + bool keep_for_non_instruction_target = mdef.keep_for_invariant; + if (target_type != target_type_t::INSTRUCTIONS && !keep_for_non_instruction_target) continue; - for (auto&& vlg_inp_pair : mdef.items()) { - if (vlg_inp_pair.key() == "verilog") { - auto& vlg_field = vlg_inp_pair.value(); - if (vlg_field.is_string()) { - vlg_expr = vlg_field.get(); - } else if (vlg_field.is_array() or vlg_field.is_object()) { - for (auto&& line : vlg_field.items()) { - if (!line.value().is_string()) { - ILA_ERROR << "Expecting string/list-of-string in `verilog` field " - "of `verilog-inline-monitors`"; - continue; - } - vlg_expr += line.value().get() + "\n"; - } - } else - ILA_ERROR << "Expecting string/list-of-string in `verilog` field of " - "`verilog-inline-monitors`"; - } else if (vlg_inp_pair.key() == "refs") { - auto& ref_field = vlg_inp_pair.value(); - if (ref_field.is_string()) - repl_list.push_back(vlg_inp_pair.value().get()); - else if (ref_field.is_array()) { - for (auto&& vlg_name : ref_field.items()) { - if (!vlg_name.value().is_string()) { - ILA_ERROR << "Expecting string/list-of-string in `refs` field of " - "`verilog-inline-monitors`"; - continue; - } - repl_list.push_back(vlg_name.value().get()); - } - } else - ILA_ERROR << "Expecting string/list-of-string in `refs` field of " - "`verilog-inline-monitors`"; - } else if (vlg_inp_pair.key() == "defs") { - if (vlg_inp_pair.value().is_array()) { - auto& defs = vlg_inp_pair.value(); - for (auto&& def : defs.items()) { - std::string defname; - int width = 0; - std::string type; - - for (auto&& nwt : def.value().items()) { - // name , width , type - if (nwt.key() == "0" || nwt.key() == "name") { - defname = nwt.value().get(); - } else if (nwt.key() == "1" || nwt.key() == "width") { - width = nwt.value().get(); - } else if (nwt.key() == "2" || nwt.key() == "type") { - type = nwt.value().get(); - } else - ILA_ERROR << "Expecting key in [0,2] or [name,width,type]"; - } - - if (defname.empty() || width == 0 || - (type != "reg" && type != "wire")) - ILA_ERROR << "Cannot create monitor for " << mname; - else { - if (type == "reg") - vlg_wrapper.add_reg(defname, width); - else - vlg_wrapper.add_wire(defname, width, true); - } - } // for each def in the array - } else - ILA_ERROR << "Expecting list-of-map in `defs` field of " - "`verilog-inline-monitors`"; - } else if (vlg_inp_pair.key() == "keep-for-invariants") { - ILA_ASSERT(vlg_inp_pair.value().get() == - keep_for_non_instruction_target); - } else - ILA_ERROR << "Unexpected key: " << vlg_inp_pair.key() - << " in verilog-inline-monitors, expecting " - "verilog/refs/defs/keep-for-invariants"; - } // for vlg_inp_pair - for (const auto& w : repl_list) { - const std::string repl = ReplExpr(w, true); - vlg_expr = ReplaceAll(vlg_expr, w, repl); + + for (const auto& n_def : mdef.var_defs) { + // already in refinement_map.all_var_def + if (n_def.second.type == + rfmap::GeneralVerilogMonitor::VarDef::var_type::REG) + vlg_wrapper.add_reg(n_def.first, n_def.second.width); + else + vlg_wrapper.add_wire(n_def.first, n_def.second.width); + } + + unsigned idx = 0; + std::vector> replace_list; + for (auto pos1 = mdef.var_uses.begin(); pos1 != mdef.var_uses.end(); ++pos1) { + for (auto pos2 = mdef.var_uses.begin(); pos2 != mdef.var_uses.end(); ++pos2) { + if(pos1 == pos2) continue; + ILA_ERROR_IF( (*pos1).find(*pos2) != std::string::npos) << *pos2 << " is part of " << *pos1; + } + } + + for (const auto& vref : mdef.var_uses) { + + auto vref_node = rfmap::VerilogRefinementMap::ParseRfExprFromString(vref); + auto new_name = mname + "_auxvar" + std::to_string(idx++); + + auto tp = refinement_map.TypeInferTravserRfExpr(vref_node, {}); + + ILA_ERROR_IF(tp.is_unknown()) + << "Cannot determine width of " << vref << " in monitor " << mname; + + auto width = tp.unified_width(); + vlg_wrapper.add_wire(new_name, width, true); + vlg_wrapper.add_output(new_name, width); + rfmap_add_internal_wire(new_name, width); + add_wire_assign_assumption(new_name, vref_node, "monitor_auxvar"); + + replace_list.push_back(std::make_pair(vref, new_name)); + } + + auto vlog_inline = mdef.verilog_inline; + for (const auto& old_new_pair : replace_list) { + // std::cout << vlog_inline << std::endl; + vlog_inline = + ReplaceAll(vlog_inline, old_new_pair.first, old_new_pair.second); + // std::cout << old_new_pair.first << std::endl; + // std::cout << old_new_pair.second << std::endl; + // std::cout << vlog_inline << std::endl; } - vlg_wrapper.add_stmt(vlg_expr); + vlg_wrapper.add_stmt(vlog_inline); + } // for monitor_rec.items() } // ConstructWrapper_add_vlg_monitor +const rfmap::InstructionCompleteCondition& +VlgSglTgtGen::get_current_instruction_rf() { + ILA_NOT_NULL(_instr_ptr); + const auto& inst_name = _instr_ptr->name().str(); + auto pos = refinement_map.inst_complete_cond.find(inst_name); + if(pos == refinement_map.inst_complete_cond.end() && + refinement_map.global_inst_complete_set) + return refinement_map.global_inst_complete_cond; + ILA_ERROR_IF(pos == refinement_map.inst_complete_cond.end() && + !refinement_map.global_inst_complete_set) + << "Cannot find the completion condition for " << inst_name; + return pos->second; +} // get_current_instruction_rf + } // namespace ilang diff --git a/src/vtarget-out/supplementary_info.cc b/src/vtarget-out/supplementary_info.cc deleted file mode 100644 index 55f347838..000000000 --- a/src/vtarget-out/supplementary_info.cc +++ /dev/null @@ -1,103 +0,0 @@ -/// \file Source for Verilog Verification Supplementary Information -/// this is useful to provide our tool information that it cannot -/// or may not be able to figure out itself - -#include -#include -#include -#include - -namespace ilang { - -VlgTgtSupplementaryInfo::VlgTgtSupplementaryInfo() {} - -void VlgTgtSupplementaryInfo::FromJson(nlohmann::json& vmap) { - if (!IN("annotation", vmap)) - return; - const auto& supplementary_info = vmap["annotation"]; - if (!supplementary_info.is_object()) { - ILA_ERROR << "Unable to parse `annotation` field, expect a map."; - return; - } - if (IN("width", supplementary_info) && - supplementary_info["width"].is_object()) { - for (auto&& nw : supplementary_info["width"].items()) { - width_info.insert(std::make_pair(nw.key(), nw.value().get())); - } - } - - if (IN("memory-ports", supplementary_info) && - supplementary_info["memory-ports"].is_object()) { - std::set ports = {"ren", "wen", "raddr", - "waddr", "rdata", "wdata"}; - for (auto&& p : supplementary_info["memory-ports"].items()) { - std::string port = p.key(); - auto pos = port.find('.'); - - ILA_ERROR_IF(pos == port.npos) - << "memory-ports should follow NAME.PORT format"; - if (pos == port.npos) - continue; - - if (!p.value().is_string()) { - ILA_ERROR << "memory-ports's must be string->string map"; - continue; - } - - auto port_expr = p.value().get(); - auto mem_name = port.substr(0, pos); - auto port_name = port.substr(pos + 1); - if (!IN(port_name, ports)) { - ILA_ERROR << "port name : " << port_name - << " should be one of ren/wen/raddr/waddr/rdata/wdata"; - continue; - } - memory_ports[mem_name].insert(std::make_pair(port_name, port_expr)); - } - } - - if (IN("memory", supplementary_info) && - supplementary_info["memory"].is_object()) { - for (auto&& nw : supplementary_info["memory"].items()) { - std::string memory_export_directive = nw.value().get(); - memory_export_type directive = memory_export_type_external; - if (memory_export_directive == "internal") - directive = memory_export_type_internal; - else if (memory_export_directive == "external") - directive = memory_export_type_external; - else - ILA_ERROR << "Unsupported memory export directive:" - << memory_export_directive << ", expect internal/external"; - memory_export.insert(std::make_pair(nw.key(), directive)); - } - } - - // reset sequence annotation - if (IN("reset", supplementary_info) && - supplementary_info["reset"].is_object()) { - if (IN("cycle", supplementary_info["reset"])) { - if (supplementary_info["reset"]["cycle"].is_number_unsigned()) { - unsigned cycle = supplementary_info["reset"]["cycle"].get(); - ILA_ERROR_IF(cycle == 0) << "reset cycle must >= 1"; - cosa_yosys_reset_config.reset_cycles = cycle; - } else - ILA_ERROR - << "`cycle` field in `reset` annotation must be unsigned integer"; - } - if (IN("no-reset-after", supplementary_info["reset"])) { - if (supplementary_info["reset"]["no-reset-after"].is_boolean()) { - cosa_yosys_reset_config.no_reset_after_starting_state = - supplementary_info["reset"]["no-reset-after"].get(); - } else - ILA_ERROR - << "`no-reset-after` field in `reset` annotation must be boolean"; - } - ILA_ERROR_IF(IN("reset-state", supplementary_info["reset"])) - << "reset-state is not implemented yet."; - ILA_ERROR_IF(IN("reset-sequence", supplementary_info["reset"])) - << "reset-sequence is not implemented yet."; - } - -} // VlgTgtSupplementaryInfo - -}; // namespace ilang diff --git a/src/vtarget-out/var_extract.cc b/src/vtarget-out/var_extract.cc deleted file mode 100644 index 2efaaaebb..000000000 --- a/src/vtarget-out/var_extract.cc +++ /dev/null @@ -1,196 +0,0 @@ -/// \file Source of variable extractor -/// This is use to extract variable from expression (string) -/// See whether it is ila-state(I/O) / vlg-state and ... -/// and change their name if needed and generate a string -// --- Hongce Zhang - -#include - -#include - -#include -#include - -namespace ilang { - -VarExtractor::VarExtractor(str_j is_ila_state, str_j is_ila_input, - str_j is_vlg_sig) - : _is_ila_state(is_ila_state), _is_ila_input(is_ila_input), - _is_vlg_sig(is_vlg_sig) {} - -// mi == ila_inst_name / vlg_inst_name -bool VarExtractor::contains_mod_inst_name(const std::string& s, - const std::string& mi) { - ILA_ERROR_IF(mi == "") - << "Implementation bug: set the module instances name first"; - return Split(s, ".").front() == mi; -} - -std::string VarExtractor::GenString() const { - std::string ret; - for (auto&& t_s_pair : _tokens) - ret += t_s_pair.second; - return ret; -} - -bool isStateBegin(unsigned char c) { - return std::isalpha(c) || c == '#' || c == '_' || c == '$' ; -} - -bool isStateCont(unsigned char c, size_t idx, const std::string& s) { - if (std::isalpha(c) || std::isdigit(c) || c == '.' || c == '_' || c == ']' || c == '$') - return true; - if (!s.empty() && s.front() == '#' && c == '#') - return true; - else if (c == '[') { - auto rp = s.find(']', idx); - auto rc = s.find(':', idx); - if (rc < rp) - return false; - // s[a:b], for this type, we make sure the whole of s is connected - // basically, it assumes that the rf will not refer to multiple elements - // but actually we need to check - return true; - // we are not sure of it actually - } - return false; -} - -bool isNumBegin(unsigned char c) { return isdigit(c) || c == '\''; } - -bool isNumCont(unsigned char c) { - return isdigit(c) || isalpha(c) || c == '\''; -} - -// [A-Za-z_][A-Za-z0-9\.]+ ==> state -// ['0-9][A-Za-z0-9']+ ==> num -void VarExtractor::ParseToExtract(const std::string& in, - bool force_vlg_statename) { - _tokens.clear(); - if (in.empty()) { - ILA_ERROR << "Parsing an empty refinement string!"; - return; - } - - auto l = in.length(); - - bool is_num = isNumBegin(in.at(0)); - bool is_state = isStateBegin(in.at(0)); - ILA_CHECK(!(is_num && is_state)) << "Implementation bug"; - - size_t left = 0; - size_t idx = 1; - - for (; idx < l; ++idx) { - bool is_num_new = - (is_num && isNumCont(in.at(idx))) || isNumBegin(in.at(idx)); - bool is_state_new = (is_state && isStateCont(in.at(idx), idx, in)) || - isStateBegin(in.at(idx)); - - if (is_num && is_state) { - ILA_CHECK(false) << "This should not be possible"; - } else if (is_num && !is_state) { // in the num matching - if (!is_num_new) { // leave matching - is_num = false; - _tokens.push_back({token_type::NUM, in.substr(left, idx - left)}); - left = idx; - if (is_state_new) - is_state = true; - } - } else if (is_state && !is_num) { // in the state matching - if (!is_state_new) { // leave matching - is_state = false; - auto subs = in.substr(left, idx - left); - token_type tp; - if (!subs.empty() && subs.front() == '#' && - subs.find('#', 1) != subs.npos) { - _tokens.push_back({KEEP, ReplaceAll(subs, "#", "")}); - left = idx; - if (is_num_new) - is_num = true; - } // if # # [2:3] .. like this , will not convert at all - else { // else normal ones - // deal with [] - auto left_p = subs.find('['); - auto check_s = - subs.substr(0, left_p); // the string use to check no [] - - if (_is_ila_state(check_s) && !force_vlg_statename) - tp = ILA_S; - else if (_is_ila_input(check_s) && !force_vlg_statename) - tp = ILA_IN; - else if (_is_vlg_sig(check_s)) - tp = VLG_S; - else - tp = UNKN_S; - _tokens.push_back({tp, subs}); - left = idx; - if (is_num_new) - is_num = true; - } // when no ## - } - } else if (!is_state && !is_num) { // not in the matching - // see if we need to start matching - ILA_CHECK(!(is_num_new && is_state_new)) - << "This should not be possible"; - if (is_num_new || is_state_new) { - _tokens.push_back({token_type::KEEP, in.substr(left, idx - left)}); - left = idx; - } - if (is_num_new) { - // copy [left, idx (not including) ] to KEEP - is_num = true; - is_state = false; - } else if (is_state_new) { - // copy [left, idx (not including) ] to KEEP - is_num = false; - is_state = true; - } - - } else - ILA_CHECK(false) << "Implementation bug, should not be reachable!"; - } - ILA_CHECK(!(is_num && is_state)) << "Implementation bug"; - // copy the last if necessary - if (left < idx) { - auto subs = in.substr(left, idx - left); - if (is_num) - _tokens.push_back({token_type::NUM, subs}); - else if (is_state) { - if (!subs.empty() && subs.front() == '#' && - subs.find('#', 1) != subs.npos) - _tokens.push_back({KEEP, ReplaceAll(subs, "#", "")}); - else { - token_type tp; - auto left_p = subs.find('['); - auto check_s = subs.substr(0, left_p); // the string use to check no [] - if (_is_ila_state(check_s) && !force_vlg_statename) - tp = ILA_S; - else if (_is_ila_input(check_s) && !force_vlg_statename) - tp = ILA_IN; - else if (_is_vlg_sig(check_s)) - tp = VLG_S; - else - tp = UNKN_S; - _tokens.push_back({tp, subs}); - } // no # - } else { - _tokens.push_back({token_type::KEEP, subs}); - } - } -} - -void VarExtractor::ForEachTokenReplace(str_r replacer) { - size_t idx = -1; - for (auto&& p : _tokens) { - idx++; - auto rep = replacer(p); - if (rep == p.second) - continue; - _tokens[idx] = std::make_pair(p.first, rep); - } -} - -// Find the strings like this : - -}; // namespace ilang diff --git a/src/vtarget-out/vlg_mod.cc b/src/vtarget-out/vlg_mod.cc index 0dc1bedc6..b3078f0cd 100644 --- a/src/vtarget-out/vlg_mod.cc +++ b/src/vtarget-out/vlg_mod.cc @@ -14,9 +14,11 @@ namespace ilang { /// Constructor: do nothing VerilogModifier::VerilogModifier( VerilogInfo* _vlg_info_ptr, port_decl_style_t port_decl_style, - bool add_keep_or_not, const std::map& _sup_width_info) + bool add_keep_or_not, const std::map& _sup_width_info, + const std::map& _sup_range_info) : vlg_info_ptr(_vlg_info_ptr), _port_decl_style(port_decl_style), - _add_keep_or_not(add_keep_or_not), sup_width_info(_sup_width_info) {} + _add_keep_or_not(add_keep_or_not), sup_width_info(_sup_width_info), + sup_range_info(_sup_range_info) {} /// Destructor: do nothing VerilogModifier::~VerilogModifier() {} @@ -150,7 +152,7 @@ void VerilogModifier::FinishRecording() { /// record the name to add a keep there void VerilogModifier::RecordKeepSignalName(const std::string& vlg_sig_name) { - auto vlg_sig_info = vlg_info_ptr->get_signal(vlg_sig_name); + auto vlg_sig_info = vlg_info_ptr->get_signal(vlg_sig_name,sup_width_info,sup_range_info ); auto loc = vlg_info_ptr->name2loc(vlg_sig_name); // check for repetition: @@ -268,6 +270,55 @@ void VerilogModifier::RecordAdditionalVlgModuleStmt( add_stmt_map[loc.first].push_back(add_stmt_t(loc.second, stmt)); } +// RTL.a.b.c[3] +// vname : RTL__DOT__a__DOT__b__DOT__c_3_ +// hiearchy RTL.a.b +// last_level_name c[3] +void VerilogModifier::RecordConnectSigName(const std::string& vname, // wirename + const std::string& hierarchy, // + const std::string& last_level_name, + unsigned width) { + ILA_CHECK(width != 0); + + auto mod_hier_name = Split(hierarchy, "."); + auto hier = mod_hier_name.size(); + ILA_CHECK(hier >= 1); + + // add module decl mod + std::string inst_name = mod_hier_name[0]; + // add topmodule: + auto loc = vlg_info_ptr->name2loc(inst_name); + ILA_CHECK(loc.first != ""); // should be found + mod_decl_map[loc.first].push_back(mod_decl_item_t(loc.second, vname, width)); + + for (unsigned idx = 1; idx < hier; ++idx) { // exclude the last level name + inst_name += "." + mod_hier_name[idx]; + + auto loc = vlg_info_ptr->name2loc(inst_name); + ILA_CHECK(loc.first != ""); // should be found + mod_decl_map[loc.first].push_back( + mod_decl_item_t(loc.second, vname, width)); + } + + // add module inst mod: a.b.signal + inst_name = mod_hier_name[0]; + for (unsigned idx = 1; idx < hier; ++idx) { + inst_name += "." + mod_hier_name[idx]; + auto loc = vlg_info_ptr->get_module_inst_loc(inst_name); + ILA_CHECK(loc.first != ""); // should be found + mod_inst_map[loc.first].push_back( + mod_inst_item_t(loc.second, vname, width)); + } + + // use the special location (mod_decl to add wires and ...) + loc = + vlg_info_ptr->get_endmodule_loc(inst_name); // this the endmodule location + assign_map[loc.first].push_back( + assign_item_t(loc.second, vname, width, last_level_name)); + +} // RecordConnectSigName + +#if 0 // the old implementation /// record the name to add a keep there VerilogModifier::vlg_sig_t VerilogModifier::RecordConnectSigName(const std::string& vlg_sig_name, @@ -289,7 +340,8 @@ VerilogModifier::RecordConnectSigName(const std::string& vlg_sig_name, auto vname = ReplaceAll(vlg_sig_name, ".", "__DOT__") + - ReplaceAll(ReplaceAll(suffix, "[", "_"), "]", "_"); // name for verilog + (suffix.empty() ? "" : ( + "_"+ ReplaceAll(suffix,"'","") +"_")); // name for verilog auto mod_hier_name = Split(vlg_sig_name, "."); auto hier = mod_hier_name.size(); auto last_level_name = mod_hier_name[hier - 1]; @@ -325,11 +377,13 @@ VerilogModifier::RecordConnectSigName(const std::string& vlg_sig_name, // use the special location (mod_decl to add wires and ...) loc = vlg_info_ptr->get_endmodule_loc(inst_name); // this the endmodule location + auto last_lv_signal_name = suffix.empty() ? short_name : (short_name + "["+ suffix+"]"); assign_map[loc.first].push_back( - assign_item_t(loc.second, vname, width, short_name + suffix)); + assign_item_t(loc.second, vname, width, last_lv_signal_name)); return vlg_sig_t({vname, width}); } // RecordConnectSigName +#endif // end of the old implementation std::string WidthToRange(unsigned w) { if (w > 1) diff --git a/src/vtarget-out/vtarget_gen.cc b/src/vtarget-out/vtarget_gen.cc index 24cdbba30..e81a58af3 100644 --- a/src/vtarget-out/vtarget_gen.cc +++ b/src/vtarget-out/vtarget_gen.cc @@ -9,25 +9,26 @@ namespace ilang { -bool VlgVerifTgtGenBase::isValidVerifBackend(backend_selector vbackend) { - if (vbackend == backend_selector::COSA) +bool VlgVerifTgtGenBase::isValidVerifBackend(ModelCheckerSelection vbackend) { + if (vbackend == ModelCheckerSelection::PONO) return true; - if (vbackend == backend_selector::JASPERGOLD) + if (vbackend == ModelCheckerSelection::JASPERGOLD) return true; - if (vbackend == backend_selector::RELCHC) + /* + if (vbackend == ModelCheckerSelection::RELCHC) return true; - if ((vbackend & backend_selector::YOSYS) == backend_selector::YOSYS) { - if (vbackend == backend_selector::ABCPDR) + if ((vbackend & ModelCheckerSelection::YOSYS) == ModelCheckerSelection::YOSYS) { + if (vbackend == ModelCheckerSelection::ABCPDR) return true; - if (vbackend == backend_selector::BTOR_GENERIC) + if (vbackend == ModelCheckerSelection::BTOR_GENERIC) return true; - if ((vbackend & backend_selector::CHC) == backend_selector::CHC) { - if (vbackend == backend_selector::ELD_CEGAR || - vbackend == backend_selector::GRAIN_SYGUS || - vbackend == backend_selector::Z3PDR) + if ((vbackend & ModelCheckerSelection::CHC) == ModelCheckerSelection::CHC) { + if (vbackend == ModelCheckerSelection::ELD_CEGAR || + vbackend == ModelCheckerSelection::GRAIN_SYGUS || + vbackend == ModelCheckerSelection::Z3PDR) return true; } - } + }*/ return false; } @@ -37,14 +38,15 @@ VerilogVerificationTargetGenerator::VerilogVerificationTargetGenerator( const std::string& implementation_top_module, const std::string& refinement_variable_mapping, const std::string& refinement_conditions, const std::string& output_path, - const InstrLvlAbsPtr& ila_ptr, backend_selector backend, - const vtg_config_t& vtg_config, - const VerilogGenerator::VlgGenConfig& config) + const InstrLvlAbsPtr& ila_ptr, ModelCheckerSelection backend, + const RtlVerifyConfig& vtg_config, + const VerilogGenerator::VlgGenConfig& notused) : _generator(new VlgVerifTgtGen( implementation_include_path, implementation_srcs, - implementation_top_module, refinement_variable_mapping, - refinement_conditions, output_path, ila_ptr, backend, vtg_config, - config, NULL)) {} + implementation_top_module, + rfmap::VerilogRefinementMap(refinement_variable_mapping, + refinement_conditions), + output_path, ila_ptr, backend, vtg_config, NULL)) {} VerilogVerificationTargetGenerator::~VerilogVerificationTargetGenerator() { if (_generator) diff --git a/src/vtarget-out/vtarget_gen_cosa.cc b/src/vtarget-out/vtarget_gen_cosa.cc deleted file mode 100644 index ee116d963..000000000 --- a/src/vtarget-out/vtarget_gen_cosa.cc +++ /dev/null @@ -1,291 +0,0 @@ -/// \file Source of generating CoSA accepted problem, vlg, mem, script -// --- Hongce Zhang - -#include - -#include -#include -#include - -#include -#include -#include -#include -#include - -namespace ilang { - -#define VLG_TRUE "`true" -#define VLG_FALSE "`false" - -VlgSglTgtGen_Cosa::VlgSglTgtGen_Cosa( - const std::string& - output_path, // will be a sub directory of the output_path of its parent - const InstrPtr& instr_ptr, // which could be an empty pointer, and it will - // be used to verify invariants - const InstrLvlAbsPtr& ila_ptr, const VerilogGenerator::VlgGenConfig& config, - nlohmann::json& _rf_vmap, nlohmann::json& _rf_cond, - VlgTgtSupplementaryInfo& _supplementary_info, VerilogInfo* _vlg_info_ptr, - const std::string& vlg_mod_inst_name, const std::string& ila_mod_inst_name, - const std::string& wrapper_name, - const std::vector& implementation_srcs, - const std::vector& implementation_include_path, - const vtg_config_t& vtg_config, backend_selector backend, - const target_type_t& target_tp, advanced_parameters_t* adv_ptr) - : VlgSglTgtGen(output_path, instr_ptr, ila_ptr, config, _rf_vmap, _rf_cond, - _supplementary_info, _vlg_info_ptr, vlg_mod_inst_name, - ila_mod_inst_name, wrapper_name, implementation_srcs, - implementation_include_path, vtg_config, backend, target_tp, - adv_ptr) {} - -#if 0 -// currently this function has no use -std::string convert_expr_to_cosa(const std::string& in) { - return ReplaceAll( - ReplaceAll(ReplaceAll(ReplaceAll(ReplaceAll(ReplaceAll(in, "&&", "&"), - "||", "|"), - "~", "!"), - "==", "="), - VLG_TRUE, "True"), - VLG_FALSE, "False"); -} -#endif - -/// Add an assumption -void VlgSglTgtGen_Cosa::add_a_direct_assumption(const std::string& aspt, - const std::string& dspt) { - _problems.assumptions.push_back(aspt); -} -/// Add an assertion -void VlgSglTgtGen_Cosa::add_a_direct_assertion(const std::string& asst, - const std::string& dspt) { - _problems.probitem[dspt].assertions.push_back(asst); -} - -/// export the script to run the verification -void VlgSglTgtGen_Cosa::Export_script(const std::string& script_name) { - auto fname = os_portable_append_dir(_output_path, script_name); - std::ofstream fout(fname); - if (!fout.is_open()) { - ILA_ERROR << "Error writing to file:" << fname; - return; - } - fout << "#!/bin/bash" << std::endl; - if (!_vtg_config.CosaPyEnvironment.empty()) - fout << "source " << _vtg_config.CosaPyEnvironment << std::endl; - - std::string cosa = "CoSA"; - std::string options; - - if (!_vtg_config.CosaSolver.empty()) - options += " --solver-name=" + _vtg_config.CosaSolver; - if (_vtg_config.CosaGenTraceVcd) - options += " --vcd"; - if (_vtg_config.CosaFullTrace) - options += " --full-trace"; - options += " " + _vtg_config.CosaOtherSolverOptions; - - // no need, copy is good enough - // if(vlg_include_files_path.size() != 0) - // options += " -I./"; - - if (!_vtg_config.CosaPath.empty()) { - cosa = os_portable_append_dir(_vtg_config.CosaPath, cosa) + ".py"; - } - - if (cosa_prob_fname != "") - fout << cosa << " --problem " << cosa_prob_fname << options << std::endl; - else - fout << "echo 'Nothing to check!'" << std::endl; -} - -void VlgSglTgtGen_Cosa::Export_jg_tester_script(const std::string& extra_name) { - if (_problems.probitem.size() == 0) - return; - - std::ofstream fout(os_portable_append_dir(_output_path, extra_name)); - if (!fout.is_open()) { - ILA_ERROR << "Error writing file: " - << os_portable_append_dir(_output_path, extra_name); - return; - } - fout << "analyze -sva " << top_file_name << std::endl; - fout << "elaborate -top " << top_mod_name << std::endl; - fout << "clock clk" << std::endl; - fout << "reset rst" << std::endl; - - decltype(_problems.assumptions) local_assumpt; - for (auto&& p : _problems.assumptions) { - if (p == "reset_done = 1_1 -> rst = 0_1") - continue ; // must match with single_target_cond.cc - if (p == "reset_done = 1_1 -> next( reset_done ) = 1_1") - continue ; // must match with single_target_cond.cc - auto eq_idx = p.find('='); - auto rm_eq_p = p.substr(0, eq_idx); - local_assumpt.push_back(rm_eq_p); - - fout << "assume { " << rm_eq_p << " }" << std::endl; - } - // separate assumptions - // std::string assmpt = "(" + Join(local_assumpt, ") && (") + ")"; - - for (auto&& pbname_prob_pair : _problems.probitem) { - const auto& prob = pbname_prob_pair.second; - - decltype(prob.assertions) local_asst; - for (auto&& p : prob.assertions) { - auto eq_idx = p.find('='); - auto rm_eq_p = p.substr(0, eq_idx); - local_asst.push_back(rm_eq_p); - } - - auto asst = "(" + Join(local_asst, ") && (") + ")"; - fout << "assert { " << asst << " }" << std::endl; - } -} - -/// export extra things (problem) -void VlgSglTgtGen_Cosa::Export_problem(const std::string& extra_name) { - if (_problems.probitem.size() == 0) { - ILA_ERROR << "Nothing to prove, no assertions inserted!"; - return; - } - - cosa_prob_fname = extra_name; - - std::ofstream rstf(os_portable_append_dir(_output_path, "rst.ets")); - if (!rstf.is_open()) { - ILA_ERROR << "Error writing file: " - << os_portable_append_dir(_output_path, "rst.ets"); - return; - } - - rstf << "I: rst = 1_1" << std::endl; - rstf << "I: reset_done = 0_1" << std::endl; - - unsigned cycle_after_i = 1; - unsigned reset_cycle_needed = - (target_type == target_type_t::INSTRUCTIONS) && (!_vtg_config.ForceInstCheckReset )? 1: - supplementary_info.cosa_yosys_reset_config.reset_cycles; - - for (; cycle_after_i < reset_cycle_needed; ++cycle_after_i) { - rstf << "S" << cycle_after_i << ": rst = 1_1" << std::endl; - rstf << "S" << cycle_after_i << ": reset_done = 0_1" << std::endl; - } - rstf << "S" << cycle_after_i << ": rst = 0_1" << std::endl; - rstf << "S" << cycle_after_i << ": reset_done = 1_1" << std::endl; - rstf << "# TRANS" << std::endl; - rstf << "I -> S1" << std::endl; - for (cycle_after_i = 1; cycle_after_i < reset_cycle_needed; ++cycle_after_i) - rstf << "S" << cycle_after_i << " -> S" << (cycle_after_i + 1) << std::endl; - rstf << "S" << cycle_after_i << " -> S" << cycle_after_i << std::endl; - - std::ofstream fout(os_portable_append_dir(_output_path, extra_name)); - if (!fout.is_open()) { - ILA_ERROR << "Error writing file: " - << os_portable_append_dir(_output_path, extra_name); - return; - } - - fout << "[GENERAL]" << std::endl; - fout << "model_files:"; // - fout << top_file_name << "[" << top_mod_name << "],"; - // if(target_type != target_type_t::INVARIANTS ) - // fout << ila_file_name<<","; // will be combined - fout << "rst.ets"; - // for(auto && fn : vlg_design_files) // will be combined - // fout << "," << os_portable_file_name_from_path(fn); - fout << std::endl; - - fout << "assume_if_true: True" << std::endl; - fout << "abstract_clock: True" << std::endl; - fout << "[DEFAULT]" << std::endl; - fout << "bmc_length: " << std::to_string(max_bound + 5) << std::endl; - fout << "precondition: reset_done = 1_1" << std::endl; - fout << std::endl; - - std::string assmpt = "(" + Join(_problems.assumptions, ") & (") + ")"; - for (auto&& pbname_prob_pair : _problems.probitem) { - const auto& prbname = pbname_prob_pair.first; - const auto& prob = pbname_prob_pair.second; - auto asst = "(" + Join(prob.assertions, ") & (") + ")"; - auto prob_name = vlg_wrapper.sanitizeName(prbname); - fout << "[" << prob_name << "]" << std::endl; - fout << "description:\"" << prbname << "\"" << std::endl; - fout << "properties:" << asst << std::endl; - if (assmpt != "()") - fout << "assumptions:" << assmpt << std::endl; - fout << "prove: True" << std::endl; - fout << "verification: safety" << std::endl; - if (VlgAbsMem::hasAbsMem()) - fout << "strategy: AUTO" << std::endl; - else - fout << "strategy: ALL" << std::endl; - fout << "expected: True" << std::endl; - } - - if (_vtg_config.CosaGenJgTesterScript) - Export_jg_tester_script("jg.tcl"); - -} // only for cosa - -/// export the memory abstraction (implementation) -/// Yes, this is also implementation specific, (jasper may use a different one) -void VlgSglTgtGen_Cosa::Export_mem(const std::string& mem_name) { - // we will ignore the mem_name - - auto outfn = os_portable_append_dir(_output_path, top_file_name); - std::ofstream fout(outfn, std::ios_base::app); // append - - VlgAbsMem::OutputMemFile(fout, - _vtg_config.VerificationSettingAvoidIssueStage); -} - -/// For jasper, this means do nothing, for yosys, you need to add (*keep*) -void VlgSglTgtGen_Cosa::Export_modify_verilog() { - // collect all locations: filename -> lineno - // open, read, count and write - // if it is a port name, we will ask user to specify its upper level - // signal name - VerilogModifier vlg_mod(vlg_info_ptr, - static_cast( - _vtg_config.PortDeclStyle), - _vtg_config.CosaAddKeep, - supplementary_info.width_info); - - for (auto&& refered_vlg_item : _all_referred_vlg_names) { - auto idx = refered_vlg_item.first.find("["); - auto removed_range_name = refered_vlg_item.first.substr(0, idx); - vlg_mod.RecordKeepSignalName(removed_range_name); - // auto sig = // no use, this is too late, vlg_wrapper already exported - vlg_mod.RecordConnectSigName(removed_range_name, - refered_vlg_item.second.range); - // vlg_wrapper.add_output(sig.first, sig.second); - } - vlg_mod.FinishRecording(); - - // now let's do the job - for (auto&& fn : vlg_design_files) { - auto outfn = os_portable_append_dir(_output_path, top_file_name); - std::ifstream fin(fn); - std::ofstream fout(outfn, std::ios_base::app); // append - if (!fin.is_open()) { - ILA_ERROR << "Cannot read file:" << fn; - continue; - } - if (!fout.is_open()) { - ILA_ERROR << "Cannot open file for write:" << outfn; - continue; - } - vlg_mod.ReadModifyWrite(fn, fin, fout); - } // for (auto && fn : vlg_design_files) - // .. (copy all the verilog file in the folder), this has to be os dependent - if (vlg_include_files_path.size() != 0) { - // copy the files and specify the -I commandline to the run.sh - for (auto&& include_path : vlg_include_files_path) - os_portable_copy_dir(include_path, _output_path); - } - -} // Export_modify_verilog - -}; // namespace ilang diff --git a/src/vtarget-out/vtarget_gen_impl.cc b/src/vtarget-out/vtarget_gen_impl.cc index 7517f7768..8e4ede034 100644 --- a/src/vtarget-out/vtarget_gen_impl.cc +++ b/src/vtarget-out/vtarget_gen_impl.cc @@ -12,14 +12,14 @@ #include #include #include -#include #include -#include -#include +#include +// #include +// #include // for invariant synthesis -#include -#include -#include +// #include +// #include +// #include namespace ilang { @@ -29,100 +29,25 @@ VlgVerifTgtGen::VlgVerifTgtGen( const std::vector& implementation_include_path, const std::vector& implementation_srcs, const std::string& implementation_top_module, - const std::string& refinement_variable_mapping, - const std::string& refinement_conditions, const std::string& output_path, - const InstrLvlAbsPtr& ila_ptr, backend_selector backend, - const vtg_config_t& vtg_config, - const VerilogGenerator::VlgGenConfig& vlg_gen_config, + const rfmap::VerilogRefinementMap& refinement, + const std::string& output_path, const InstrLvlAbsPtr& ila_ptr, + ModelCheckerSelection backend, const RtlVerifyConfig& vtg_config, advanced_parameters_t* adv_ptr) : _vlg_impl_include_path(implementation_include_path), _vlg_impl_srcs(implementation_srcs), - _vlg_impl_top_name(implementation_top_module), - _rf_var_map_name(refinement_variable_mapping), - _rf_cond_name(refinement_conditions), _output_path(output_path), - _ila_ptr(ila_ptr), + _vlg_impl_top_name(implementation_top_module), _refinement(refinement), + _output_path(output_path), _ila_ptr(ila_ptr), // configure is only for ila, generate the start signal vlg_info_ptr( NULL), // not creating it now, because we don't have the info to do so - _backend(backend), _cfg(vlg_gen_config), _vtg_config(vtg_config), - _advanced_param_ptr(adv_ptr), _bad_state(false) { - load_json(_rf_var_map_name, rf_vmap); - supplementary_info.FromJson(rf_vmap); - load_json(_rf_cond_name, rf_cond); - set_module_instantiation_name(); + _backend(backend), _vtg_config(vtg_config), _advanced_param_ptr(adv_ptr), + _bad_state(false) { + if (_ila_ptr == nullptr) { ILA_ERROR << "ILA should not be none"; _bad_state = true; } - // check for json file -- global-invariants - if (!IN("global invariants", rf_cond) && !IN("global-invariants", rf_cond)) { - ILA_ERROR << "'global-invariants' must exist, can be an empty array"; - _bad_state = true; - } else if (IN("global invariants", rf_cond) && - !rf_cond["global invariants"].is_array()) { - ILA_ERROR << "'global invariants' must be an array of string"; - _bad_state = true; - } else if (IN("global-invariants", rf_cond) && - !rf_cond["global-invariants"].is_array()) { - ILA_ERROR << "'global-invariants' must be an array of string"; - _bad_state = true; - } else if (IN("global invariants", rf_cond) && - rf_cond["global invariants"].size() != 0) { - if (!rf_cond["global invariants"][0].is_string()) { - ILA_ERROR << "'global invariants' must be an array of string"; - _bad_state = true; - } - } else if (IN("global-invariants", rf_cond) && - rf_cond["global-invariants"].size() != 0) { - if (!rf_cond["global-invariants"][0].is_string()) { - ILA_ERROR << "'global-invariants' must be an array of string"; - _bad_state = true; - } - } - // check for json file -- instructions - if (!IN("instructions", rf_cond)) { - ILA_ERROR << "'instructions' must exist."; - _bad_state = true; - } else if (!rf_cond["instructions"].is_array()) { - ILA_ERROR << "'instructions' must be an array of objects."; - _bad_state = true; - } else if (rf_cond["instructions"].size() == 0) { - ILA_WARN << "No instruction in the rf specification"; - } else { - for (auto&& it : rf_cond["instructions"].items()) { - if (!it.value().is_object()) { - ILA_ERROR << "'instructions' must be an array of objects."; - _bad_state = true; - break; - } else { - if (!IN("instruction", it.value())) { - ILA_ERROR << "'instruction' field must exist in the rf object."; - _bad_state = true; - break; - } else if (!it.value()["instruction"].is_string()) { - ILA_ERROR - << "'instruction' field must be a string of instruction name."; - _bad_state = true; - break; - } - } - } - } - // check vmap - if (!IN("models", rf_vmap) || !rf_vmap["models"].is_object()) { - ILA_ERROR << "'model' field must exist in vmap and be a map of ILA/VERILOG " - "-> 'instance name' "; - _bad_state = true; - } - if (!((IN("state mapping", rf_vmap) && - rf_vmap["state mapping"].is_object()) || - (IN("state-mapping", rf_vmap) && - rf_vmap["state-mapping"].is_object()))) { - ILA_ERROR << "'state-mapping' field must exist in vmap and be a map : " - "ila_var -> impl_var"; - _bad_state = true; - } // TODO: check more } @@ -135,18 +60,14 @@ const std::vector& VlgVerifTgtGen::GetRunnableScriptName() const { return runnable_script_name; } -const VlgTgtSupplementaryInfo& VlgVerifTgtGen::GetSupplementaryInfo() const { - return supplementary_info; -} - void VlgVerifTgtGen::GenerateTargets(void) { if (bad_state_return()) return; runnable_script_name.clear(); - vlg_info_ptr = new VerilogInfo(_vlg_impl_include_path, _vlg_impl_srcs, - _vlg_mod_inst_name, _vlg_impl_top_name); + vlg_info_ptr = new VerilogInfo(_vlg_impl_include_path, _vlg_impl_srcs, "RTL", + _vlg_impl_top_name); if (vlg_info_ptr == NULL || vlg_info_ptr->in_bad_state()) { ILA_ERROR << "Unable to generate targets. Verilog parser failed."; @@ -154,97 +75,89 @@ void VlgVerifTgtGen::GenerateTargets(void) { } if (!isValidVerifBackend(_backend)) { - ILA_ERROR << "Unknown backend specification:" << _backend << ", quit."; + ILA_ERROR << "Unknown backend specification:" << int(_backend) << ", quit."; return; } - if (_vtg_config.target_select == vtg_config_t::BOTH || - _vtg_config.target_select == vtg_config_t::INV) { + if (_vtg_config.target_select == RtlVerifyConfig::BOTH || + _vtg_config.target_select == RtlVerifyConfig::INV) { // check if there are really invariants: bool invariantExists = false; - if (IN("global invariants", rf_cond) || IN("global-invariants", rf_cond)) { - nlohmann::json& inv = IN("global invariants", rf_cond) - ? rf_cond["global invariants"] - : rf_cond["global-invariants"]; - if (inv.is_array() && inv.size() != 0) - invariantExists = true; - else if (inv.is_string() && inv.get() != "") - invariantExists = true; - else if ((_vtg_config.ValidateSynthesizedInvariant == - vtg_config_t::_validate_synthesized_inv::ALL || - _vtg_config.ValidateSynthesizedInvariant == - vtg_config_t::_validate_synthesized_inv::CONFIRMED) && - (_advanced_param_ptr && - _advanced_param_ptr->_inv_obj_ptr != NULL && - !_advanced_param_ptr->_inv_obj_ptr->GetVlgConstraints() - .empty())) - invariantExists = true; - else if ((_vtg_config.ValidateSynthesizedInvariant == - vtg_config_t::_validate_synthesized_inv::ALL || - _vtg_config.ValidateSynthesizedInvariant == - vtg_config_t::_validate_synthesized_inv::CANDIDATE) && - (_advanced_param_ptr && - _advanced_param_ptr->_candidate_inv_ptr != NULL && - !_advanced_param_ptr->_candidate_inv_ptr->GetVlgConstraints() - .empty())) - invariantExists = true; - } + if (!_refinement.global_invariants.empty()) + invariantExists = true; + + if ((_vtg_config.ValidateSynthesizedInvariant == + RtlVerifyConfig::_validate_synthesized_inv::ALL || + _vtg_config.ValidateSynthesizedInvariant == + RtlVerifyConfig::_validate_synthesized_inv::CONFIRMED) && + (_advanced_param_ptr && _advanced_param_ptr->_inv_obj_ptr != NULL && + !_advanced_param_ptr->_inv_obj_ptr->GetVlgConstraints().empty())) + invariantExists = true; + + if ((_vtg_config.ValidateSynthesizedInvariant == + RtlVerifyConfig::_validate_synthesized_inv::ALL || + _vtg_config.ValidateSynthesizedInvariant == + RtlVerifyConfig::_validate_synthesized_inv::CANDIDATE) && + (_advanced_param_ptr && + _advanced_param_ptr->_candidate_inv_ptr != NULL && + !_advanced_param_ptr->_candidate_inv_ptr->GetVlgConstraints().empty())) + invariantExists = true; + auto sub_output_path = os_portable_append_dir(_output_path, "invariants"); - if (_backend == backend_selector::COSA && invariantExists) { - auto target = VlgSglTgtGen_Cosa( + if (_backend == ModelCheckerSelection::PONO && invariantExists) { + auto target = VlgSglTgtGen_Pono( sub_output_path, NULL, // invariant - _ila_ptr, _cfg, rf_vmap, rf_cond, supplementary_info, vlg_info_ptr, - _vlg_mod_inst_name, _ila_mod_inst_name, "wrapper", _vlg_impl_srcs, + _ila_ptr, _refinement, vlg_info_ptr, "wrapper", _vlg_impl_srcs, _vlg_impl_include_path, _vtg_config, _backend, target_type_t::INVARIANTS, _advanced_param_ptr); target.ConstructWrapper(); - target.ExportAll("wrapper.v", "ila.v", "run.sh", "problem.txt", - "absmem.v"); - target.do_not_instantiate(); - } else if (_backend == backend_selector::JASPERGOLD && invariantExists) { + target.ExportAll("wrapper.v", "ila.v", "run.sh", "gen_btor.ys"); + target.do_not_instantiate(); // no use, just for coverage + } else if (_backend == ModelCheckerSelection::JASPERGOLD && invariantExists) { auto target = VlgSglTgtGen_Jasper( sub_output_path, NULL, // invariant - _ila_ptr, _cfg, rf_vmap, rf_cond, supplementary_info, vlg_info_ptr, - _vlg_mod_inst_name, _ila_mod_inst_name, "wrapper", _vlg_impl_srcs, + _ila_ptr, _refinement, vlg_info_ptr, "wrapper", _vlg_impl_srcs, _vlg_impl_include_path, _vtg_config, _backend, target_type_t::INVARIANTS, _advanced_param_ptr); target.ConstructWrapper(); - target.ExportAll("wrapper.v", "ila.v", "run.sh", "do.tcl", "absmem.v"); - target.do_not_instantiate(); - } else if (_backend == backend_selector::RELCHC && invariantExists) { + target.ExportAll("wrapper.v", "ila.v", "run.sh", "do.tcl"); + target.do_not_instantiate(); // no use, just for coverage + } +#if 0 + else if (_backend == ModelCheckerSelection::RELCHC && invariantExists) { // will actually fail : not supported for using relchc for invariant // targets auto target = VlgSglTgtGen_Relchc( sub_output_path, NULL, // invariant _ila_ptr, _cfg, rf_vmap, rf_cond, supplementary_info, vlg_info_ptr, - _vlg_mod_inst_name, _ila_mod_inst_name, "wrapper", _vlg_impl_srcs, + "wrapper", _vlg_impl_srcs, _vlg_impl_include_path, _vtg_config, _backend, target_type_t::INVARIANTS, _advanced_param_ptr); target.ConstructWrapper(); target.ExportAll("wrapper.v", "ila.v", "run.sh", "__design_smt.smt2", "absmem.v"); target.do_not_instantiate(); - } else if ((_backend & backend_selector::YOSYS) == - backend_selector::YOSYS && + } else if ((_backend & ModelCheckerSelection::YOSYS) == + ModelCheckerSelection::YOSYS && invariantExists) { auto target = VlgSglTgtGen_Yosys( sub_output_path, NULL, // instruction _ila_ptr, _cfg, rf_vmap, rf_cond, supplementary_info, vlg_info_ptr, - _vlg_mod_inst_name, _ila_mod_inst_name, "wrapper", _vlg_impl_srcs, + "wrapper", _vlg_impl_srcs, _vlg_impl_include_path, _vtg_config, _backend, target_type_t::INVARIANTS, _advanced_param_ptr, _chc_target_t::GENERAL_PROPERTY); target.ConstructWrapper(); std::string design_file; - if (_backend == backend_selector::ABCPDR) + if (_backend == ModelCheckerSelection::ABCPDR) design_file = "wrapper.aig"; - else if ((_backend & backend_selector::CHC) == backend_selector::CHC) + else if ((_backend & ModelCheckerSelection::CHC) == ModelCheckerSelection::CHC) design_file = "wrapper.smt2"; - else if (_backend == backend_selector::BTOR_GENERIC) + else if (_backend == ModelCheckerSelection::BTOR_GENERIC) design_file = "wrapper.btor2"; else design_file = "wrapper.unknfmt"; @@ -252,7 +165,7 @@ void VlgVerifTgtGen::GenerateTargets(void) { target.ExportAll("wrapper.v", "ila.v", "run.sh", design_file, "absmem.v"); target.do_not_instantiate(); } - +#endif if (invariantExists) runnable_script_name.push_back( os_portable_append_dir(sub_output_path, "run.sh")); @@ -261,91 +174,50 @@ void VlgVerifTgtGen::GenerateTargets(void) { // == INV) // now let's deal w. instructions in rf_cond - if (_vtg_config.target_select == vtg_config_t::BOTH || - _vtg_config.target_select == vtg_config_t::INST) { - auto& instrs = rf_cond["instructions"]; - for (auto&& instr : instrs) { - std::string iname = instr["instruction"].get(); + if (_vtg_config.target_select == RtlVerifyConfig::BOTH || + _vtg_config.target_select == RtlVerifyConfig::INST) { + bool generate_forall_inst = _refinement.global_inst_complete_set; + + for (auto&& instr : _refinement.inst_complete_cond) { + std::string iname = instr.first; + auto instr_ptr = _ila_ptr->instr(iname); + ILA_ERROR_IF(instr_ptr == nullptr) + << "ila:" << _ila_ptr->name().str() + << " has no instruction:" << iname; + } + for (unsigned inst_idx = 0; inst_idx < _ila_ptr->instr_num() ; ++ inst_idx) { + auto instr_ptr = _ila_ptr->instr(inst_idx); + std::string iname = instr_ptr->name().str(); if (_vtg_config.CheckThisInstructionOnly != "" && _vtg_config.CheckThisInstructionOnly != iname) continue; // skip, not checking this instruction - - auto instr_ptr = _ila_ptr->instr(iname); - if (instr_ptr == nullptr) { - ILA_ERROR << "ila:" << _ila_ptr->name().str() - << " has no instruction:" << iname; + if (!generate_forall_inst && + _refinement.inst_complete_cond.find(iname) == _refinement.inst_complete_cond.end()) continue; - } - + auto sub_output_path = os_portable_append_dir(_output_path, iname); - if (_backend == backend_selector::COSA) { - auto target = VlgSglTgtGen_Cosa( + if (_backend == ModelCheckerSelection::PONO) { + auto target = VlgSglTgtGen_Pono( sub_output_path, instr_ptr, // instruction - _ila_ptr, _cfg, rf_vmap, rf_cond, supplementary_info, vlg_info_ptr, - _vlg_mod_inst_name, _ila_mod_inst_name, "wrapper", _vlg_impl_srcs, + _ila_ptr, _refinement, vlg_info_ptr, "wrapper", _vlg_impl_srcs, _vlg_impl_include_path, _vtg_config, _backend, target_type_t::INSTRUCTIONS, _advanced_param_ptr); target.ConstructWrapper(); - target.ExportAll("wrapper.v", "ila.v", "run.sh", "problem.txt", - "absmem.v"); + target.ExportAll("wrapper.v", "ila.v", "run.sh", "gen_btor.ys"); target.do_not_instantiate(); - } else if (_backend == backend_selector::JASPERGOLD) { + } else if (_backend == ModelCheckerSelection::JASPERGOLD) { auto target = VlgSglTgtGen_Jasper( sub_output_path, instr_ptr, // instruction - _ila_ptr, _cfg, rf_vmap, rf_cond, supplementary_info, vlg_info_ptr, - _vlg_mod_inst_name, _ila_mod_inst_name, "wrapper", _vlg_impl_srcs, - _vlg_impl_include_path, _vtg_config, _backend, - target_type_t::INSTRUCTIONS, _advanced_param_ptr); - target.ConstructWrapper(); - target.ExportAll("wrapper.v", "ila.v", "run.sh", "do.tcl", "absmem.v"); - target.do_not_instantiate(); - } else if (_backend == backend_selector::RELCHC) { - // will actually fail : not supported for using relchc for invariant - // targets - auto target = VlgSglTgtGen_Relchc( - sub_output_path, - instr_ptr, // instruction - _ila_ptr, _cfg, rf_vmap, rf_cond, supplementary_info, vlg_info_ptr, - _vlg_mod_inst_name, _ila_mod_inst_name, "wrapper", _vlg_impl_srcs, + _ila_ptr, _refinement, vlg_info_ptr, "wrapper", _vlg_impl_srcs, _vlg_impl_include_path, _vtg_config, _backend, target_type_t::INSTRUCTIONS, _advanced_param_ptr); target.ConstructWrapper(); - target.ExportAll("wrapper.v", "ila.v", "run.sh", "__design_smt.smt2", - "absmem.v"); - target.do_not_instantiate(); - } else if ((_backend & backend_selector::YOSYS) == - backend_selector::YOSYS) { - // in this case we will have two targets to generate - // one is the target with only the design and - // and the second one should use the smt file it generates - // and create conversion (map) function - - auto target = VlgSglTgtGen_Yosys( - sub_output_path, - instr_ptr, // instruction - _ila_ptr, _cfg, rf_vmap, rf_cond, supplementary_info, vlg_info_ptr, - _vlg_mod_inst_name, _ila_mod_inst_name, "wrapper", _vlg_impl_srcs, - _vlg_impl_include_path, _vtg_config, _backend, - target_type_t::INSTRUCTIONS, _advanced_param_ptr, - _chc_target_t::GENERAL_PROPERTY); - target.ConstructWrapper(); - std::string design_file; - if (_backend == backend_selector::ABCPDR) - design_file = "wrapper.aig"; - else if ((_backend & backend_selector::CHC) == backend_selector::CHC) - design_file = "wrapper.smt2"; - else if (_backend == backend_selector::BTOR_GENERIC) - design_file = "wrapper.btor2"; - else - design_file = "wrapper.unknfmt"; - - target.ExportAll("wrapper.v", "ila.v", "run.sh", design_file, - "absmem.v"); + target.ExportAll("wrapper.v", "ila.v", "run.sh", "do.tcl"); target.do_not_instantiate(); - } // end case backend + } runnable_script_name.push_back( os_portable_append_dir(sub_output_path, "run.sh")); } // end for instrs @@ -357,108 +229,24 @@ void VlgVerifTgtGen::GenerateTargets(void) { } } // end of function GenerateTargets -void VlgVerifTgtGen::set_module_instantiation_name() { - if (bad_state_return()) - return; - // use the content in the refinement relations to determine the instance name - auto& model_specified = rf_vmap["models"]; - for (auto&& name_description_pair : model_specified.items()) { - if (name_description_pair.key() == "ILA") { - _ila_mod_inst_name = name_description_pair.value(); - } else if (name_description_pair.key() == "VERILOG") { - _vlg_mod_inst_name = name_description_pair.value(); - } else - ILA_ERROR << "Unknown model specification:" << name_description_pair.key() - << " expect VERILOG or ILA"; - } - // if unset - if (_vlg_mod_inst_name == "") { - ILA_WARN - << "Verilog top module instance name not set, assuming to be VERILOG"; - _vlg_mod_inst_name = "VERILOG"; - } - if (_ila_mod_inst_name == "") { - ILA_WARN << "ILA top module instance name not set, assuming to be ILA"; - _ila_mod_inst_name = "ILA"; - } -} // set_module_instantiation_name - bool VlgVerifTgtGen::bad_state_return(void) { ILA_ERROR_IF(_bad_state) << "VlgVerifTgtGen is in a bad state, cannot proceed."; return _bad_state; } // bad_state_return -// return npos if no comments in -static size_t find_comments(const std::string& line) { - enum state_t { PLAIN, STR, LEFT } state, next_state; - state = PLAIN; - size_t ret = 0; - for (const auto& c : line) { - if (state == PLAIN) { - if (c == '/') - next_state = LEFT; - else if (c == '"') - next_state = STR; - else - next_state = PLAIN; - } else if (state == STR) { - if (c == '"' || c == '\n') - next_state = PLAIN; - // the '\n' case is in case we encounter some issue to find - // the ending of a string - else - next_state = STR; - } else if (state == LEFT) { - if (c == '/') { - ILA_CHECK(ret > 0); - return ret - 1; - } else - next_state = PLAIN; - } - state = next_state; - ++ret; - } - return std::string::npos; -} - -void VlgVerifTgtGen::load_json(const std::string& fname, nlohmann::json& j) { - if (bad_state_return()) - return; - std::ifstream fin(fname); - - if (!fin.is_open()) { - ILA_ERROR << "Cannot read from file:" << fname; - _bad_state = true; - return; - } - - // remove the comments - std::string contents; - std::string line; - while (std::getline(fin, line)) { - auto comment_begin = find_comments(line); - if (comment_begin != std::string::npos) - contents += line.substr(0, comment_begin); - else - contents += line; - contents += "\n"; - } - j = nlohmann::json::parse(contents); -} // load_json - -#ifdef INVSYN_INTERFACE +#if 0 std::shared_ptr VlgVerifTgtGen::GenerateInvSynTargets(synthesis_backend_selector s_backend) { - ILA_CHECK(_backend == backend_selector::YOSYS) + ILA_CHECK(_backend == ModelCheckerSelection::YOSYS) << "All inv-syn relies on yosys!"; if (vlg_info_ptr) delete vlg_info_ptr; vlg_info_ptr = new VerilogInfo(_vlg_impl_include_path, _vlg_impl_srcs, - _vlg_mod_inst_name, _vlg_impl_top_name); + "RTL", _vlg_impl_top_name); if (vlg_info_ptr == NULL or vlg_info_ptr->in_bad_state()) { ILA_ERROR << "Unable to generate targets. Verilog parser failed."; return nullptr; // @@ -467,13 +255,13 @@ VlgVerifTgtGen::GenerateInvSynTargets(synthesis_backend_selector s_backend) { // parameter override auto tmp_vtg_config(_vtg_config); tmp_vtg_config.CosaDotReferenceNotify = - vtg_config_t::CosaDotReferenceNotify_t::NOTIFY_PANIC; + RtlVerifyConfig::CosaDotReferenceNotify_t::NOTIFY_PANIC; auto target = VlgSglTgtGen_Chc( os_portable_append_dir(_output_path, "inv-syn/"), NULL, // invariant _ila_ptr, _cfg, rf_vmap, rf_cond, supplementary_info, vlg_info_ptr, - _vlg_mod_inst_name, _ila_mod_inst_name, "wrapper", _vlg_impl_srcs, + "wrapper", _vlg_impl_srcs, _vlg_impl_include_path, tmp_vtg_config, _backend, s_backend, target_type_t::INV_SYN_DESIGN_ONLY, _advanced_param_ptr, true, _chc_target_t::CEX); @@ -490,14 +278,14 @@ VlgVerifTgtGen::GenerateInvSynTargets(synthesis_backend_selector s_backend) { std::shared_ptr VlgVerifTgtGen::GenerateInvSynEnhanceTargets(const InvariantInCnf& cnf) { - ILA_ERROR_IF(_backend != backend_selector::YOSYS) + ILA_ERROR_IF(_backend != ModelCheckerSelection::YOSYS) << "All inv-syn relies on yosys!"; if (vlg_info_ptr) delete vlg_info_ptr; vlg_info_ptr = new VerilogInfo(_vlg_impl_include_path, _vlg_impl_srcs, - _vlg_mod_inst_name, _vlg_impl_top_name); + "RTL", _vlg_impl_top_name); if (vlg_info_ptr == NULL or vlg_info_ptr->in_bad_state()) { ILA_ERROR << "Unable to generate targets. Verilog parser failed."; return nullptr; // @@ -508,20 +296,7 @@ VlgVerifTgtGen::GenerateInvSynEnhanceTargets(const InvariantInCnf& cnf) { tmp_vtg_config.InvariantSynthesisReachableCheckKeepOldInvariant = true; tmp_vtg_config.YosysSmtFlattenDatatype = true; tmp_vtg_config.CosaDotReferenceNotify = - vtg_config_t::CosaDotReferenceNotify_t::NOTIFY_PANIC; -#if 0 - // currently we do this on the outer level - // here we remove the last one, because it is the one we want to enhance - InvariantObject * inv_obj_backup = NULL; - if (_advanced_param_ptr->_inv_obj_ptr) { - InvariantObject * reduced_inv = new InvariantObject(*( _advanced_param_ptr->_inv_obj_ptr)); // make a copy - ILA_NOT_NULL(reduced_inv); - if (reduced_inv->NumInvariant() > 0) - reduced_inv->RemoveInvByIdx(reduced_inv->NumInvariant()-1); - inv_obj_backup = _advanced_param_ptr->_inv_obj_ptr; - _advanced_param_ptr->_inv_obj_ptr = reduced_inv; - } -#endif + RtlVerifyConfig::CosaDotReferenceNotify_t::NOTIFY_PANIC; // TODO: you may need to change a bit of _advanced_param_ptr's inv // and maybe the assume inv part @@ -529,7 +304,7 @@ VlgVerifTgtGen::GenerateInvSynEnhanceTargets(const InvariantInCnf& cnf) { os_portable_append_dir(_output_path, "inv-enhance/"), NULL, // invariant _ila_ptr, _cfg, rf_vmap, rf_cond, supplementary_info, vlg_info_ptr, - _vlg_mod_inst_name, _ila_mod_inst_name, "wrapper", _vlg_impl_srcs, + "wrapper", _vlg_impl_srcs, _vlg_impl_include_path, tmp_vtg_config, _backend, VlgVerifTgtGenBase::synthesis_backend_selector::GRAIN, target_type_t::INV_SYN_DESIGN_ONLY, _advanced_param_ptr, true, @@ -541,26 +316,21 @@ VlgVerifTgtGen::GenerateInvSynEnhanceTargets(const InvariantInCnf& cnf) { runnable_script_name.clear(); runnable_script_name.push_back(os_portable_append_dir( os_portable_append_dir(_output_path, "inv-enhance/"), "run.sh")); -#if 0 - if (inv_obj_backup) { // recover the invariant - delete (_advanced_param_ptr->_inv_obj_ptr); - _advanced_param_ptr->_inv_obj_ptr = inv_obj_backup; - } // recover the invariant -#endif + return target.GetDesignSmtInfo(); } // GenerateInvSynEnhanceTargets void VlgVerifTgtGen::GenerateInvSynTargetsAbc(bool useGla, bool useCorr, bool useAiger) { - ILA_ERROR_IF(_backend != backend_selector::YOSYS) + ILA_ERROR_IF(_backend != ModelCheckerSelection::YOSYS) << "All inv-syn relies on yosys!"; if (vlg_info_ptr) delete vlg_info_ptr; vlg_info_ptr = new VerilogInfo(_vlg_impl_include_path, _vlg_impl_srcs, - _vlg_mod_inst_name, _vlg_impl_top_name); + "RTL", _vlg_impl_top_name); if (vlg_info_ptr == NULL or vlg_info_ptr->in_bad_state()) { ILA_ERROR << "Unable to generate targets. Verilog parser failed."; return; // @@ -568,13 +338,13 @@ void VlgVerifTgtGen::GenerateInvSynTargetsAbc(bool useGla, bool useCorr, // parameter override auto tmp_vtg_config(_vtg_config); tmp_vtg_config.CosaDotReferenceNotify = - vtg_config_t::CosaDotReferenceNotify_t::NOTIFY_PANIC; + RtlVerifyConfig::CosaDotReferenceNotify_t::NOTIFY_PANIC; auto target = VlgSglTgtGen_Abc( os_portable_append_dir(_output_path, "inv-syn-abc/"), NULL, // invariant _ila_ptr, _cfg, rf_vmap, rf_cond, supplementary_info, vlg_info_ptr, - _vlg_mod_inst_name, _ila_mod_inst_name, "wrapper", _vlg_impl_srcs, + "wrapper", _vlg_impl_srcs, _vlg_impl_include_path, tmp_vtg_config, _backend, synthesis_backend_selector::ABC, target_type_t::INV_SYN_DESIGN_ONLY, _advanced_param_ptr, true, _chc_target_t::CEX, useGla, useCorr, useAiger); diff --git a/src/vtarget-out/vtarget_gen_jasper.cc b/src/vtarget-out/vtarget_gen_jasper.cc index 5d394c7c4..f6d1fc88a 100644 --- a/src/vtarget-out/vtarget_gen_jasper.cc +++ b/src/vtarget-out/vtarget_gen_jasper.cc @@ -19,51 +19,32 @@ VlgSglTgtGen_Jasper::VlgSglTgtGen_Jasper( output_path, // will be a sub directory of the output_path of its parent const InstrPtr& instr_ptr, // which could be an empty pointer, and it will // be used to verify invariants - const InstrLvlAbsPtr& ila_ptr, const VerilogGenerator::VlgGenConfig& config, - nlohmann::json& _rf_vmap, nlohmann::json& _rf_cond, - VlgTgtSupplementaryInfo& _supplementary_info, VerilogInfo* _vlg_info_ptr, - const std::string& vlg_mod_inst_name, const std::string& ila_mod_inst_name, + const InstrLvlAbsPtr& ila_ptr, + const rfmap::VerilogRefinementMap& refinement, VerilogInfo* _vlg_info_ptr, const std::string& wrapper_name, const std::vector& implementation_srcs, const std::vector& implementation_include_path, - const vtg_config_t& vtg_config, backend_selector backend, + const RtlVerifyConfig& vtg_config, ModelCheckerSelection backend, const target_type_t& target_tp, advanced_parameters_t* adv_ptr) - : VlgSglTgtGen(output_path, instr_ptr, ila_ptr, config, _rf_vmap, _rf_cond, - _supplementary_info, _vlg_info_ptr, vlg_mod_inst_name, - ila_mod_inst_name, wrapper_name, implementation_srcs, + : VlgSglTgtGen(output_path, instr_ptr, ila_ptr, refinement, _vlg_info_ptr, + wrapper_name, implementation_srcs, implementation_include_path, vtg_config, backend, target_tp, adv_ptr) {} -void VlgSglTgtGen_Jasper::add_wire_assign_assumption( - const std::string& varname, const std::string& expression, - const std::string& dspt) { - // a plain assign - vlg_wrapper.add_assign_stmt(varname, expression); +/// Add SMT-lib2 assumption +void VlgSglTgtGen_Jasper::add_a_direct_smt_assumption(const std::string& arg, + const std::string& ret, + const std::string& body, + const std::string& dspt) { + ILA_CHECK(false) << "SMT assumption should not be generated for JasperGold"; } -void VlgSglTgtGen_Jasper::add_reg_cassign_assumption( - const std::string& varname, const std::string& expression, int width, - const std::string& cond, const std::string& dspt) { - - std::string rand_in_name = "__" + varname + "_init__"; - vlg_wrapper.add_input(rand_in_name, width); - vlg_wrapper.add_wire(rand_in_name, width); - - vlg_wrapper.add_init_stmt(varname + " <= " + rand_in_name + ";"); - vlg_wrapper.add_always_stmt(varname + " <= " + varname + ";"); - add_an_assumption( - "(~(" + cond + ") || ((" + varname + ") == (" + expression + ")))", dspt); -} - -/// Add an assumption -void VlgSglTgtGen_Jasper::add_an_assumption(const std::string& aspt, - const std::string& dspt) { - assumptions.push_back(std::make_pair(aspt, dspt)); -} -/// Add an assertion -void VlgSglTgtGen_Jasper::add_an_assertion(const std::string& asst, - const std::string& dspt) { - assertions.push_back(std::make_pair(asst, dspt)); +/// Add SMT-lib2 assertion +void VlgSglTgtGen_Jasper::add_a_direct_smt_assertion(const std::string& arg, + const std::string& ret, + const std::string& body, + const std::string& dspt) { + ILA_CHECK(false) << "SMT assertions should not be generated for JasperGold"; } /// Add an assumption @@ -76,16 +57,12 @@ void VlgSglTgtGen_Jasper::add_a_direct_assertion(const std::string& asst, const std::string& dspt) { assertions.push_back(std::make_pair(asst, dspt)); } - -void VlgSglTgtGen_Jasper::add_addition_clock_info( - const std::string& clock_expr) { - additional_clock_expr.push_back(clock_expr); +/// Add an cover check +void VlgSglTgtGen_Jasper::add_a_direct_cover_check(const std::string& cvr, + const std::string& dspt) { + covers.push_back(std::make_pair(cvr, dspt)); } -void VlgSglTgtGen_Jasper::add_addition_reset_info( - const std::string& reset_expr) { - additional_reset_expr.push_back(reset_expr); -} /// export the script to run the verification void VlgSglTgtGen_Jasper::Export_script(const std::string& script_name) { @@ -120,22 +97,27 @@ void VlgSglTgtGen_Jasper::Export_problem(const std::string& extra_name) { if (top_file_name != "") fout << " \\\n " << top_file_name; - if (abs_mem_name != "") - fout << " \\\n " << abs_mem_name; - fout << "\n\n"; fout << "elaborate -top " << top_mod_name << std::endl; - if (additional_clock_expr.empty()) - fout << "clock clk" << std::endl; - else - ILA_ERROR << "Not supporting multiple clock. Future work!"; - if (additional_reset_expr.empty()) - fout << "reset rst" << std::endl; - else - fout << "reset -expression " << Join(additional_reset_expr, " ") - << std::endl; + // in fact clock configuration should not stay here + // because this controls the top-level reset/clock + // whereas we want internal reset/clock signals to be + // changed + ILA_CHECK( + refinement_map.clock_specification.custom_clock_factor.empty() && + refinement_map.clock_specification.custom_clock_sequence.empty() + ) << "TODO: custom clock sequence not implemented yet"; + + fout << "clock clk" << std::endl; + + ILA_CHECK( + refinement_map.reset_specification.custom_reset_sequence.empty() && + refinement_map.reset_specification.initial_state.empty() + ) << "TODO: custom reset sequence not implemented yet"; + + fout << "reset rst" << std::endl; unsigned No = 0; for (auto&& asmpt_dspt_pair : assumptions) @@ -147,22 +129,12 @@ void VlgSglTgtGen_Jasper::Export_problem(const std::string& extra_name) { fout << "assert -name " << asst_dspt_pair.second + std::to_string(No++) << " {" << asst_dspt_pair.first << "}" << std::endl; -} // -/// export the memory abstraction (implementation) -/// Yes, this is also implementation specific, (jasper may use a different one) -void VlgSglTgtGen_Jasper::Export_mem(const std::string& mem_name) { - // TODO; - if (!VlgAbsMem::hasAbsMem()) - return; - - abs_mem_name = mem_name; - - auto outfn = os_portable_append_dir(_output_path, mem_name); - std::ofstream fout(outfn); // will not append - - VlgAbsMem::OutputMemFile(fout, - _vtg_config.VerificationSettingAvoidIssueStage); + No = 0; + for (auto&& cover_dspt_pair : covers) + fout << "cover -name " << cover_dspt_pair.second + std::to_string(No++) + << " {" << cover_dspt_pair.first << "}" << std::endl; } + /// For jasper, this means do nothing, for yosys, you need to add (*keep*) void VlgSglTgtGen_Jasper::Export_modify_verilog() { // COPY Files? diff --git a/src/vtarget-out/vtarget_gen_pono.cc b/src/vtarget-out/vtarget_gen_pono.cc new file mode 100644 index 000000000..943cb3f85 --- /dev/null +++ b/src/vtarget-out/vtarget_gen_pono.cc @@ -0,0 +1,592 @@ +/// \file Source of generating Pono accepted problem, vlg, mem, script +// --- Hongce Zhang + +#include + +#include +#include +#include + +#include +#include +#include +#include + +namespace ilang { + +#define VLG_TRUE "`true" +#define VLG_FALSE "`false" + +// should not be used +static std::string yosysGenerateBtor = R"***( +hierarchy -check +proc +chformal -assume -early; +%propselect% +memory %-nomap%; +flatten +setundef -undriven -expose; +sim -clock clk -reset rst -rstlen %rstlen% -n %cycle% -w %module% +)***"; +// %propselect% is for + +static const std::string show_result_bash_script = R"***( +function show_result () { + RfError="" + SanityError="" + CoverError="" + + if test $RfResult = 0; then RfMsg=" (* buggy)"; + elif test $RfResult = 1; then RfMsg=" (passed)"; + elif test $RfResult = 2; then RfMsg=" (* checker error)"; + elif test $RfResult = 3; then RfMsg=" (skipped)"; + elif test $RfResult = 255; then RfMsg=" (unknown)"; + else echo "UNKNOWN PONO RESULT: " $RfResult; RfMsg=" (* terminated)"; RfResult=2 + fi + + if test $SanityResult = 0; then SanityMsg=" (* sanity violation)"; + elif test $SanityResult = 1; then SanityMsg=" (sanity is proved to hold)"; + elif test $SanityResult = 2; then SanityMsg=" (* checker error)"; + elif test $SanityResult = 3; then SanityMsg=" (skipped)"; + elif test $SanityResult = 255; then SanityMsg=" (no sanity violation within bound)"; + else echo "UNKNOWN PONO RESULT: " $SanityResult; SanityMsg=" (* terminated)"; SanityResult=2 + fi + + if test $CoverResult = 0; then CoverMsg=" (covered)"; + elif test $CoverResult = 1; then CoverMsg=" (* not reachable)"; + elif test $CoverResult = 2; then CoverMsg=" (* checker error)"; + elif test $CoverResult = 3; then CoverMsg=" (skipped)"; + elif test $CoverResult = 255; then CoverMsg=" (* not yet reachable)"; + else echo "UNKNOWN PONO RESULT: " $CoverResult; CoverMsg=" (* terminated)"; CoverResult=2; + fi + + echo '============ SUMMARY ============' + echo 'Refinement Check:' $RfResult $RfMsg + echo 'Santiy Check:' $SanityResult $SanityMsg + echo 'Cover Check:' $CoverResult $CoverMsg + echo '============ END OF SUMMARY ============' + echo "" + + if [ $RfResult = 2 ] || [ $SanityResult = 2 ] || [ $CoverResult = 2 ]; then + return 2 + fi + + if test $RfResult = 0; then return 0; + elif test $SanityResult = 0; then return 0; + elif test $CoverResult = 1; then return 0; + elif test $CoverResult = 255; then return 255; + else return $RfResult; + fi +} + +show_result +exit $? + +)***"; + +VlgSglTgtGen_Pono::VlgSglTgtGen_Pono( + const std::string& + output_path, // will be a sub directory of the output_path of its parent + const InstrPtr& instr_ptr, // which could be an empty pointer, and it will + // be used to verify invariants + const InstrLvlAbsPtr& ila_ptr, + const rfmap::VerilogRefinementMap& refinement, VerilogInfo* _vlg_info_ptr, + const std::string& wrapper_name, + const std::vector& implementation_srcs, + const std::vector& implementation_include_path, + const RtlVerifyConfig& vtg_config, ModelCheckerSelection vbackend, + const target_type_t& target_tp, advanced_parameters_t* adv_ptr) + : VlgSglTgtGen(output_path, instr_ptr, ila_ptr, refinement, _vlg_info_ptr, + wrapper_name, implementation_srcs, + implementation_include_path, vtg_config, vbackend, target_tp, + adv_ptr) {} + +/// Add an assumption +void VlgSglTgtGen_Pono::add_a_direct_assumption(const std::string& aspt, + const std::string& dspt) { + auto wire_name = dspt + new_property_id(); + vlg_wrapper.add_wire(wire_name, 1); + vlg_wrapper.add_output(wire_name, 1); + vlg_wrapper.add_assign_stmt(wire_name, aspt); + _problems.assumptions[dspt].exprs.push_back(wire_name); +} +/// Add an assertion +void VlgSglTgtGen_Pono::add_a_direct_assertion(const std::string& asst, + const std::string& dspt) { + auto wire_name = dspt + new_property_id(); + vlg_wrapper.add_wire(wire_name, 1); + vlg_wrapper.add_output(wire_name, 1); + vlg_wrapper.add_assign_stmt(wire_name, asst); + _problems.assertions[dspt].exprs.push_back(wire_name); +} + +/// Add an assertion +void VlgSglTgtGen_Pono::add_a_direct_sanity_assertion(const std::string& asst, + const std::string& dspt) { + auto wire_name = dspt + new_property_id(); + vlg_wrapper.add_wire(wire_name, 1); + vlg_wrapper.add_output(wire_name, 1); + vlg_wrapper.add_assign_stmt(wire_name, asst); + _problems.sanity_assertions[dspt].exprs.push_back(wire_name); +} + +/// Add a cover assertion +void VlgSglTgtGen_Pono::add_a_direct_cover_check(const std::string& asst, + const std::string& dspt) { + auto wire_name = dspt + new_property_id(); + vlg_wrapper.add_wire(wire_name, 1); + vlg_wrapper.add_output(wire_name, 1); + vlg_wrapper.add_assign_stmt(wire_name, asst); + _problems.cover_checks[dspt].exprs.push_back(wire_name); +} + +/// export the script to run the verification +void VlgSglTgtGen_Pono::Export_script(const std::string& script_name) { + + auto fname = os_portable_append_dir(_output_path, script_name); + std::ofstream fout(fname); + if (!fout.is_open()) { + ILA_ERROR << "Error writing to file:" << fname; + return; + } + fout << "#!/bin/bash" << std::endl; + fout << "echo \"* Remove prior results...\"" << std::endl; + fout << "rm -f *.btor2 *.vcd __yosys*.txt" << std::endl; + + fout << "echo \"* Parsing input...\"" << std::endl; + + std::string yosys = "yosys"; + + if (!_vtg_config.YosysPath.empty()) + yosys = os_portable_append_dir(_vtg_config.YosysPath, yosys); + + // execute it + fout << yosys << " -s " << ys_script_name << " > __yosys_exec_result.txt\n"; + + std::string pono = "pono"; + std::string options; + + if (!_vtg_config.PonoVcdOutputName.empty()) + options += " --vcd " + _vtg_config.PonoVcdOutputName; + if (!_vtg_config.PonoEngine.empty()) + options += " -e " + _vtg_config.PonoEngine; + options += " " + _vtg_config.PonoOtherOptions; + + // no need, copy is good enough + // if(vlg_include_files_path.size() != 0) + // options += " -I./"; + + if (!_vtg_config.PonoPath.empty()) { + pono = os_portable_append_dir(_vtg_config.PonoPath, pono); + } + + std::string extra_smt_properties; + if (!_problems.smt_assertions.empty() || !_problems.smt_assumptions.empty()) { + extra_smt_properties += " --property-file property.smt2 "; + } + + fout << "echo \"* Run Pono to check refinement...\"" << std::endl; + fout << pono << options << extra_smt_properties << " problem.btor2 " + << std::endl; + + fout << "RfResult=$?" << std::endl; + + if (!_problems.sanity_assertions.empty()) { + fout << "echo \"* Parsing sanity check input...\"" << std::endl; + fout << yosys + << " -s gen_sanity_prop.ys > __yosys_exec_result.sanity.txt\n"; + // here we intentionally leave out the property interface file. + + fout << "echo \"* Run Pono to check assumption sanity...\"" << std::endl; + fout << pono << options << extra_smt_properties << " sanity.btor2 " << std::endl; + fout << "SanityResult=$?" << std::endl; + } else { + fout << "SanityResult=3" << std::endl; + } + + if(all_cover_assert_property_names.empty()) { + fout << "CoverResult=3" << std::endl; + } else + fout << "CoverResult=0" << std::endl; + + for (unsigned idx = 0; idx < all_cover_assert_property_names.size(); ++idx) { + auto cover_fname = "cover" + std::to_string(idx)+".btor2"; + std::string cover_options = " -e bmc " + _vtg_config.PonoOtherOptions; + cover_options += extra_smt_properties; + + fout << "echo \"* Parsing cover check input #" < __yosys_exec_result.cover" << idx<<".txt\n"; + + fout << "echo \"Run Pono to check cover property (expecting sat)...\"" << std::endl; + fout << pono << cover_options << " " << cover_fname << std::endl; + fout << "if test $? != 0; then CoverResult=$?; fi" << std::endl; + } + + fout << show_result_bash_script << std::endl; + +} // Export_script + + +/// Add SMT-lib2 assumption +void VlgSglTgtGen_Pono::add_a_direct_smt_assumption(const std::string& arg, + const std::string& ret, + const std::string& body, + const std::string& dspt) { + size_t idx = _problems.smt_assumptions.size(); + _problems.smt_assumptions.push_back("(define-fun assumption." + + std::to_string(idx) + " " + arg + " " + + ret + " " + body + ")"); +} + +/// Add SMT-lib2 assertion +void VlgSglTgtGen_Pono::add_a_direct_smt_assertion(const std::string& arg, + const std::string& ret, + const std::string& body, + const std::string& dspt) { + size_t idx = _problems.smt_assertions.size(); + _problems.smt_assertions.push_back("(define-fun assertion." + + std::to_string(idx) + " " + arg + " " + + ret + " " + body + ")"); +} + + +void VlgSglTgtGen_Pono::GenYosysScript( + const std::string& ys_script_name_path, + const std::string& property_selection_cmd, + const std::string& generated_btor_name ) +{ + // export to ys_script_name + std::ofstream ys_script_fout(ys_script_name_path); + + std::string write_btor_options; + write_btor_options += _vtg_config.BtorAddCommentsInOutputs ? " -v" : ""; + write_btor_options += _vtg_config.BtorSingleProperty ? " -s" : ""; + + ys_script_fout << "read_verilog -sv " + << top_file_name // os_portable_append_dir(_output_path, top_file_name) + << std::endl; + ys_script_fout << "prep -top " << top_mod_name << std::endl; + + ILA_CHECK( + refinement_map.clock_specification.custom_clock_factor.empty() && + refinement_map.clock_specification.custom_clock_sequence.empty() + ) << "TODO: custom clock sequence not implemented yet"; + + ILA_CHECK( + refinement_map.reset_specification.custom_reset_sequence.empty() && + refinement_map.reset_specification.initial_state.empty() + ) << "TODO: custom reset sequence not implemented yet"; + + ys_script_fout << ReplaceAll( + ReplaceAll( + ReplaceAll( + ReplaceAll( + ReplaceAll(yosysGenerateBtor, "%rstlen%", + std::to_string( + refinement_map.reset_specification.reset_cycle)), + "%cycle%", + std::to_string(refinement_map.reset_specification.reset_cycle)), + "%module%", top_mod_name), + "%propselect%", property_selection_cmd), + "%-nomap%", _vtg_config.YosysSmtArrayForRegFile ? "-nomap" : "" ); + + // this is for pono, I don't know why it is unhappy, but we need fix this + // in the long run + if (_vtg_config.YosysSetUndrivenZero) + ys_script_fout << "setundef -undriven -zero\n"; + + ys_script_fout << "write_btor " << write_btor_options + << " " << generated_btor_name + << std::endl; +} // VlgSglTgtGen_Pono::GenYosysScript + +/// export the yosys script +void VlgSglTgtGen_Pono::Export_problem(const std::string& yosys_script_name) { + + if (_problems.assertions.empty() && _problems.smt_assertions.empty() && + _problems.sanity_assertions.empty() && _problems.cover_checks.empty() + ) { + ILA_ERROR << "Nothing to prove, no assertions inserted!"; + return; + } + + ys_script_name = yosys_script_name; + + { // export the main script + std::string ys_script_name_path = + os_portable_append_dir(_output_path, ys_script_name); + std::string property_selection_cmd; + if (!_problems.sanity_assertions.empty()) { + property_selection_cmd +="\n" + "select wrapper/sanitycheck\n" + "chformal -remove\n" + "select *\n"; + } + if (!_problems.cover_checks.empty()) { + ILA_CHECK(!all_cover_assert_property_names.empty()); + for(const auto & p : all_cover_assert_property_names) + property_selection_cmd +="\n" + "select wrapper/"+ p +(" \n" + "chformal -remove\n" + "select *\n"); + } + + GenYosysScript(ys_script_name_path, property_selection_cmd, "problem.btor2"); + } // finish writing + + auto smt_property_fname = + os_portable_append_dir(_output_path, "property.smt2"); + { + std::ofstream smt_fout(smt_property_fname); + for (const auto& prop : _problems.smt_assumptions) + smt_fout << prop << std::endl; + + for (const auto& prop : _problems.smt_assertions) + smt_fout << prop << std::endl; + } + + if (!_problems.sanity_assertions.empty()) { + std::string ys_script_name_path = + os_portable_append_dir(_output_path, "gen_sanity_prop.ys"); + std::string property_selection_cmd = "\n" + "select wrapper/normalassert\n" + "chformal -remove\n" + "select *\n"; + + if (!_problems.cover_checks.empty()) { + ILA_CHECK(!all_cover_assert_property_names.empty()); + for(const auto & p : all_cover_assert_property_names) + property_selection_cmd +="\n" + "select wrapper/"+ p +(" \n" + "chformal -remove\n" + "select *\n"); + } + + GenYosysScript(ys_script_name_path, property_selection_cmd, "sanity.btor2"); + } // finish writing sanity check Yosys script + + if (!_problems.cover_checks.empty()) { + ILA_CHECK(!all_cover_assert_property_names.empty()); + + std::string property_selection_cmd_tmpl = "\n" + "select wrapper/normalassert\n" + "chformal -remove\n" + "select *\n"; + + if(!_problems.sanity_assertions.empty()) { + property_selection_cmd_tmpl += "\n" + "select wrapper/sanitycheck\n" + "chformal -remove\n" + "select *\n"; + } + + for (unsigned idx = 0; idx < all_cover_assert_property_names.size() ; ++idx) { + std::string ys_script_name_path = + os_portable_append_dir(_output_path, "gen_cover_prop" + std::to_string(idx) + ".ys"); + + std::string property_selection_cmd = property_selection_cmd_tmpl; + for(unsigned jdx = 0; jdx < all_cover_assert_property_names.size(); ++jdx) { + if (jdx == idx) + continue; + // remove all other covers + property_selection_cmd += "\n" + "select wrapper/" + all_cover_assert_property_names.at(jdx) + "\n" + "chformal -remove\n" + "select *\n"; + } // end for each other cover property remove it + + GenYosysScript(ys_script_name_path, property_selection_cmd, "cover"+ std::to_string(idx) +".btor2"); + } // end for each cover property + } // finish writing cover check Yosys script + + + if(_vtg_config.PonoGenJgScript) { + auto jg_script_fname = os_portable_append_dir(_output_path, "jg.tcl"); + std::ofstream fout(jg_script_fname); + ILA_ERROR_IF(!fout.is_open()) << "Cannot write to " << jg_script_fname; + fout << "analyze -sva " << top_file_name << std::endl; + fout << "elaborate -top " << top_mod_name << std::endl; + fout << "clock clk" << std::endl; + fout << "reset rst" << std::endl; + // remove cover assert + for (const auto & pname : all_cover_assert_property_names) { + fout << "assert -disable " << pname << std::endl; + } + // re-insert as jg covers + unsigned cover_property_id = 0; + for (auto && pbname_prob_pair : _problems.cover_checks) { + // const auto& prbname = pbname_prob_pair.first; + const auto& prob = pbname_prob_pair.second; + + for (auto&& p : prob.exprs) { + // there should be only one expression (for cex target) + // ILA_CHECK(all_assert_wire_content.empty()); + fout << "cover -name " << "cover_"<<(cover_property_id++) << " {" + << p << "}"; + } // for expr + } // end for each cover + } // end for jg script + +} // end of Export_problem -- export Yosys script + +// PreExportProcess is about how to add assumption/assertions +void VlgSglTgtGen_Pono::PreExportProcess() { + + std::string all_assert_wire_content; + std::string all_sanity_assert_wire_content; + + std::string all_assume_wire_content; + + // you need to add assumptions as well + for (auto&& pbname_prob_pair : _problems.assumptions) { + const auto& prbname = pbname_prob_pair.first; + const auto& prob = pbname_prob_pair.second; + ILA_DLOG("VlgSglTgtGen_Pono.PreExportProcess") + << "Adding assumption:" << prbname; + + for (auto&& p : prob.exprs) { + if (all_assume_wire_content.empty()) + all_assume_wire_content = "(" + p + ")"; + else + all_assume_wire_content += "&& (" + p + ")"; + } // for prob.exprs + } // for _problems.assumption + + // this is to check given assertions + for (auto&& pbname_prob_pair : _problems.assertions) { + // const auto& prbname = pbname_prob_pair.first; + const auto& prob = pbname_prob_pair.second; + + // ILA_CHECK(prbname == "cex_nonreachable_assert") + // << "BUG: assertion can only be cex reachability queries."; + // sanity check, should only be invariant's related asserts + + for (auto&& p : prob.exprs) { + // there should be only one expression (for cex target) + // ILA_CHECK(all_assert_wire_content.empty()); + if (all_assert_wire_content.empty()) + all_assert_wire_content = "(" + p + ")"; + else + all_assert_wire_content += " && (" + p + ")"; + } // for expr + } // for problem + // add assert wire (though no use : make sure will not optimized away) + if (_problems.smt_assertions.empty()) + ILA_CHECK(!all_assert_wire_content.empty()) << "no property to check!"; + + if (all_assert_wire_content + .empty()) { // in case all_assert_wire_content is empty + all_assert_wire_content = "1'b1"; // (assert true) + } + + // this is to check given sanity assertions + for (auto&& pbname_prob_pair : _problems.sanity_assertions) { + // const auto& prbname = pbname_prob_pair.first; + const auto& prob = pbname_prob_pair.second; + + // ILA_CHECK(prbname == "cex_nonreachable_assert") + // << "BUG: assertion can only be cex reachability queries."; + // sanity check, should only be invariant's related asserts + + for (auto&& p : prob.exprs) { + // there should be only one expression (for cex target) + // ILA_CHECK(all_assert_wire_content.empty()); + if (all_sanity_assert_wire_content.empty()) + all_sanity_assert_wire_content = "(" + p + ")"; + else + all_sanity_assert_wire_content += " && (" + p + ")"; + } // for expr + } + + unsigned cover_property_id = 0; + for (auto && pbname_prob_pair : _problems.cover_checks) { + // const auto& prbname = pbname_prob_pair.first; + const auto& prob = pbname_prob_pair.second; + + for (auto&& p : prob.exprs) { + // there should be only one expression (for cex target) + // ILA_CHECK(all_assert_wire_content.empty()); + auto property_name = "negcoverassert" + std::to_string(cover_property_id ++); + vlg_wrapper.add_stmt(property_name + ": assert property (!" + + p +"); /*expecting: false*/"); + all_cover_assert_property_names.push_back(property_name); + } // for expr + } + + vlg_wrapper.add_wire("__all_assert_wire__", 1, true); + vlg_wrapper.add_output("__all_assert_wire__", 1); + vlg_wrapper.add_assign_stmt("__all_assert_wire__", all_assert_wire_content); + vlg_wrapper.add_stmt("normalassert: assert property ( __all_assert_wire__ ); " + "// the only assertion \n"); + + if (!all_assume_wire_content.empty()) { + vlg_wrapper.add_wire("__all_assume_wire__", 1, true); + vlg_wrapper.add_output("__all_assume_wire__", 1); + vlg_wrapper.add_assign_stmt("__all_assume_wire__", all_assume_wire_content); + + vlg_wrapper.add_stmt("all_assume: assume property ( __all_assume_wire__ ); " + "// the only sanity assertion \n"); + } + + if (!all_sanity_assert_wire_content.empty()) { + vlg_wrapper.add_wire("__sanitycheck_wire__", 1, true); + vlg_wrapper.add_output("__sanitycheck_wire__", 1); + vlg_wrapper.add_assign_stmt("__sanitycheck_wire__", + all_sanity_assert_wire_content); + + vlg_wrapper.add_stmt("sanitycheck: assert property ( __sanitycheck_wire__ " + "); // the only assumption \n"); + } +} // PreExportProcess + +/// For jasper, this means do nothing, for yosys, you need to add (*keep*) +void VlgSglTgtGen_Pono::Export_modify_verilog() { + // collect all locations: filename -> lineno + // open, read, count and write + // if it is a port name, we will ask user to specify its upper level + // signal name + VerilogModifier vlg_mod(vlg_info_ptr, + static_cast( + _vtg_config.PortDeclStyle), + _vtg_config.PonoAddKeep, + refinement_map.width_info, + refinement_map.range_info); + + for (auto&& wn_extraw : rtl_extra_wire) { + ILA_CHECK(StrStartsWith(wn_extraw.first, "RTL__DOT__")); + vlg_mod.RecordConnectSigName( + wn_extraw.second.wire_name, wn_extraw.second.hierarchy, + wn_extraw.second.internal_name, wn_extraw.second.width); + // will not record keep + } + vlg_mod.FinishRecording(); + + // auto tmp_fn = os_portable_append_dir(_output_path, tmp_design_file); + auto tmp_fn = os_portable_append_dir(_output_path, top_file_name); + // now let's do the job + for (auto&& fn : vlg_design_files) { + std::ifstream fin(fn); + std::ofstream fout(tmp_fn, std::ios_base::app); // append to a temp file + if (!fin.is_open()) { + ILA_ERROR << "Cannot read file:" << fn; + continue; + } + if (!fout.is_open()) { + ILA_ERROR << "Cannot open file for write:" << tmp_fn; + continue; + } + vlg_mod.ReadModifyWrite(fn, fin, fout); + } // for (auto && fn : vlg_design_files) + + // handles the includes + // .. (copy all the verilog file in the folder), this has to be os independent + if (vlg_include_files_path.size() != 0) { + // copy the files and specify the -I commandline to the run.sh + for (auto&& include_path : vlg_include_files_path) + os_portable_copy_dir(include_path, _output_path); + } + +} // Export_modify_verilog + +}; // namespace ilang diff --git a/src/vtarget-out/vtarget_gen_relchc.cc b/src/vtarget-out/vtarget_gen_relchc.cc deleted file mode 100644 index 1e41df9ca..000000000 --- a/src/vtarget-out/vtarget_gen_relchc.cc +++ /dev/null @@ -1,394 +0,0 @@ -/// \file Source of generating rel chc synthesis target -/// the inv-syn related horn clasue generation is located in inv-syn/rel_chc.cc -// --- Hongce Zhang - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -namespace ilang { - -#define VLG_TRUE "`true" -#define VLG_FALSE "`false" - -/// template for generating relchc script wo arrays -static std::string relchcGenerateSmtScript_wo_Array = R"***( -hierarchy -check -proc -opt -opt_expr -mux_undef -opt -opt -flatten \%dutmodulename% -%setundef -undriven -init -expose% -sim -clock clk -reset rst -rstlen %rstlen% -n %cycle% -w %module% -memory -nordff -proc -opt;; -)***"; -// you may want to flatten just -/// template for generating relchc script -static std::string relchcGenerateSmtScript_w_Array = R"***( -hierarchy -check -proc -opt -opt_expr -mux_undef -opt -opt -flatten \%dutmodulename% -%setundef -undriven -init -expose% -sim -clock clk -reset rst -rstlen %rstlen% -n %cycle% -w %module% -memory_dff -wr_only -memory_collect; -memory_unpack -splitnets -driver -opt;; -memory_collect; -pmuxtree -proc -opt;; -)***"; - - -VlgSglTgtGen_Relchc::VlgSglTgtGen_Relchc( - const std::string& - output_path, // will be a sub directory of the output_path of its parent - const InstrPtr& instr_ptr, // which could be an empty pointer, and it will - // be used to verify invariants - const InstrLvlAbsPtr& ila_ptr, const VerilogGenerator::VlgGenConfig& config, - nlohmann::json& _rf_vmap, nlohmann::json& _rf_cond, VlgTgtSupplementaryInfo & _sup_info, - VerilogInfo* _vlg_info_ptr, const std::string& vlg_mod_inst_name, - const std::string& ila_mod_inst_name, const std::string& wrapper_name, - const std::vector& implementation_srcs, - const std::vector& implementation_include_path, - const vtg_config_t& vtg_config, backend_selector backend, - const target_type_t& target_tp, - advanced_parameters_t* adv_ptr ) - : VlgSglTgtGen(output_path, instr_ptr, ila_ptr, config, _rf_vmap, _rf_cond, _sup_info, - _vlg_info_ptr, vlg_mod_inst_name, ila_mod_inst_name, - wrapper_name, implementation_srcs, - implementation_include_path, vtg_config, backend, - target_tp, adv_ptr) { - - ILA_ASSERT(! _vtg_config.YosysSmtArrayForRegFile) - << "Future work to support array in synthesis"; - - ILA_ASSERT( - target_tp == target_type_t::INSTRUCTIONS ) - << "Only support target type : INSTRUCTIONS, but get: " << target_tp; - - ILA_ASSERT(! vtg_config.YosysSmtFlattenHierarchy) - << "Monolithic synthesis requires not to flatten hierarchy"; - - ILA_ASSERT(! vtg_config.YosysSmtFlattenDatatype) - << "BUG: not implemented, future work."; - - } - - - -/// Add an assumption -void VlgSglTgtGen_Relchc::add_a_direct_assumption(const std::string& aspt, - const std::string& dspt) { - _problems.assumptions[dspt].exprs.push_back(aspt); -} -/// Add an assertion -void VlgSglTgtGen_Relchc::add_a_direct_assertion(const std::string& asst, - const std::string& dspt) { - _problems.assertions[dspt].exprs.push_back(asst); -} - -/// Pre export work : add assume and asssert to the top level -/// collect the type of assumptions and assertions -/// Assertions: variable_map_assert (no invariant_assert --- not for invariant target) -/// Assumptions: -/// 1. global: noreset, funcmap, absmem, additonal_mapping_control_assume -/// 2. only at starting state: -/// variable_map_assume, issue_decode, issue_valid, ... -/// Question: invariant assume? where to put it? Depends on ? - -void VlgSglTgtGen_Relchc::PreExportProcess() { -/* - std::string global_assume = "`true"; - std::string start_assume = "`true"; - - for(auto&& dspt_exprs_pair : _problems.assumptions) { - const auto & dspt = dspt_exprs_pair.first; - const auto & expr = dspt_exprs_pair.second; - for (auto&& p: expr.exprs) - vlg_wrapper.add_stmt( - "assume property ("+p+"); // " + dspt - ); - } - - //std::string assmpt = "(" + Join(_problems.assumptions, ") & (") + ")"; - std::string all_assert_wire_content = "`true"; -*/ - - if(target_type == target_type_t::INSTRUCTIONS) { - // this is to synthesize invariants - for (auto & pbname_prob_pair : _problems.assumptions) { - const auto& prbname = pbname_prob_pair.first; - auto& prob = pbname_prob_pair.second; // will be modified !!! - - if (prbname == "invariant_assume") { // add to submodule ? why? - for (auto & p : prob.exprs) { - // p does not contain "top." - - auto assumption_wire_name = - vlg_wrapper.sanitizeName(prbname) + "_sub_" + new_mapping_id(); - - vlg_mod_inv_vec.push_back( - "wire " + assumption_wire_name + - " = " + p +";"); - - p = assumption_wire_name; - } - } // dspt == invariant_assume - } // for assumptions - } -#if 0 // Target Type Invariant, we will not handle - else if(target_type == target_type_t::INVARIANTS) { - // this is to check given invariants - for (auto&& pbname_prob_pair : _problems.assertions) { - const auto& prbname = pbname_prob_pair.first; - const auto& prob = pbname_prob_pair.second; - - ILA_ASSERT(prbname == "invariant_assert"); - // sanity check, should only be invariant's related asserts - - for (auto&& p: prob.exprs) { - vlg_wrapper.add_stmt( - "assert property ("+p+"); //" + prbname + "\n" - ); - all_assert_wire_content += "&& ( " + p + " ) "; - } // for expr - } // for problem - } // target_type == target_type_t::INVARIANTS - - vlg_wrapper.add_wire("__all_assert_wire__", 1, true); - vlg_wrapper.add_output("__all_assert_wire__",1); - vlg_wrapper.add_assign_stmt("__all_assert_wire__", all_assert_wire_content); -#endif // Target Type Invariant, we will not handle - -} // PreExportProcess - -/// export the script to run the verification : -/// like "yosys gemsmt.ys" -void VlgSglTgtGen_Relchc::Export_script(const std::string& script_name) { - relchc_run_script_name = script_name; - - auto fname = os_portable_append_dir(_output_path, script_name); - std::ofstream fout(fname); - if (!fout.is_open()) { - ILA_ERROR << "Error writing to file:" << fname; - return; - } - fout << "#!/bin/bash" << std::endl; - //fout << "trap \"trap - SIGTERM && kill -- -$$\" SIGINT SIGTERM"< lineno - // open, read, count and write - // if it is a port name, we will ask user to specify its upper level - // signal name - VerilogModifier vlg_mod(vlg_info_ptr, - static_cast( - _vtg_config.PortDeclStyle), - _vtg_config.CosaAddKeep, - supplementary_info.width_info); - - // add mod stmt (wire something ... like that) - for (auto && stmt : vlg_mod_inv_vec) - vlg_mod.RecordAdditionalVlgModuleStmt(stmt, _vlg_mod_inst_name); - - for (auto&& refered_vlg_item : _all_referred_vlg_names) { - auto idx = refered_vlg_item.first.find("["); - auto removed_range_name = refered_vlg_item.first.substr(0, idx); - vlg_mod.RecordKeepSignalName(removed_range_name); - // auto sig = // no use, this is too late, vlg_wrapper already exported - vlg_mod.RecordConnectSigName(removed_range_name, - refered_vlg_item.second.range); - // vlg_wrapper.add_output(sig.first, sig.second); - } - vlg_mod.FinishRecording(); - - - //auto tmp_fn = os_portable_append_dir(_output_path, tmp_design_file); - auto tmp_fn = os_portable_append_dir(_output_path, top_file_name); - // now let's do the job - for (auto&& fn : vlg_design_files) { - std::ifstream fin(fn); - std::ofstream fout(tmp_fn, std::ios_base::app); // append to a temp file - if (!fin.is_open()) { - ILA_ERROR << "Cannot read file:" << fn; - continue; - } - if (!fout.is_open()) { - ILA_ERROR << "Cannot open file for write:" << tmp_fn; - continue; - } - vlg_mod.ReadModifyWrite(fn, fin, fout); - } // for (auto && fn : vlg_design_files) - - // handles the includes - // .. (copy all the verilog file in the folder), this has to be os independent - if (vlg_include_files_path.size() != 0) { - // copy the files and specify the -I commandline to the run.sh - for (auto&& include_path : vlg_include_files_path) - os_portable_copy_dir(include_path, _output_path); - } - -} // Export_modify_verilog - - -/// export the memory abstraction (implementation) -/// Yes, this is also implementation specific, (jasper may use a different one) -void VlgSglTgtGen_Relchc::Export_mem(const std::string& mem_name) { - // we will ignore the mem_name - - auto outfn = os_portable_append_dir(_output_path, top_file_name); - std::ofstream fout(outfn, std::ios_base::app); // append - - VlgAbsMem::OutputMemFile(fout, _vtg_config.VerificationSettingAvoidIssueStage); -} - - -// export the gensmt.ys -void VlgSglTgtGen_Relchc::Export_problem(const std::string& extra_name) { - // used by export script! - relchc_prob_fname = extra_name; - - ILA_CHECK(!_vtg_config.ForceInstCheckReset) << - "If start from init, please use Yosys target."; - // generate tpl - - // first generate a temporary smt - // and extract from it the necessary info - auto smt_info = dual_inv_gen_smt("__design_smt.smt2","__gen_smt_script.ys"); - auto final_smt_name = - os_portable_append_dir(_output_path, - os_portable_remove_file_name_extension(top_file_name) + ".smt2" ); - - dual_inv_tpl(final_smt_name, smt_info); - dual_inv_problem(extra_name); - -} // Export_problem - - -void VlgSglTgtGen_Relchc::ExportAll(const std::string& wrapper_name, - const std::string& ila_vlg_name, - const std::string& script_name, - const std::string& extra_name, - const std::string& mem_name) { - - PreExportProcess(); - if (os_portable_mkdir(_output_path) == false) - ILA_WARN << "Cannot create output directory:" << _output_path; - - // you don't need to worry about the path and names - Export_wrapper(wrapper_name); - if (target_type == target_type_t::INSTRUCTIONS) - Export_ila_vlg(ila_vlg_name); // this has to be after Export_wrapper - - // for Jasper, this will be put to multiple files - // for CoSA & Yosys, this will be put after the wrapper file (wrapper.v) - Export_modify_verilog(); // this must be after Export_wrapper - Export_mem(mem_name); - - // you need to create the map function -- - Export_problem(extra_name); // the gensmt.ys - - Export_script(script_name); -} - - -/// generate the wrapper's smt first -std::string VlgSglTgtGen_Relchc::dual_inv_gen_smt( - const std::string & smt_name, - const std::string & ys_script_name) { - - auto ys_full_name = - os_portable_append_dir(_output_path, ys_script_name); - { // export to ys_full_name - std::ofstream ys_script_fout( ys_full_name ); - - std::string write_smt2_options = " -mem -bv -stdt "; // future work : -stbv, or nothing - - ys_script_fout << "read_verilog -sv " - << os_portable_append_dir( _output_path , top_file_name ) << std::endl; - ys_script_fout << "prep -top " << top_mod_name << std::endl; - ys_script_fout << - ReplaceAll( - ReplaceAll( - ReplaceAll( - ReplaceAll( - ReplaceAll( - relchcGenerateSmtScript_wo_Array, - "%setundef -undriven -init -expose%", _vtg_config.YosysUndrivenNetAsInput ? "setundef -undriven -init -expose" : ""), - "%module%", top_mod_name), - "%rstlen%", "1" // this is because, the reset analysis is applied on the DUT not the wrapper - /*std::to_string( - supplementary_info.cosa_yosys_reset_config.reset_cycles)*/), - "%cycle%", "1" // this is because, the reset analysis is applied on the DUT not the wrapper - /*std::to_string( - supplementary_info.cosa_yosys_reset_config.reset_cycles) */), - "%dutmodulename%", vlg_info_ptr->get_top_module_name()) - ; - ys_script_fout << "write_smt2"< cmd; - cmd.push_back(yosys); cmd.push_back("-s"); cmd.push_back(ys_full_name); - - std::string logfilename = - os_portable_append_dir(_output_path, "yosys_output.log"); - - auto res = os_portable_execute_shell( cmd , logfilename); // this does not redirect - ILA_ERROR_IF( res.failure != res.NONE ) - << "Executing Yosys failed!"; - ILA_ERROR_IF( res.failure == res.NONE && res.ret != 0) - << "Yosys returns error code:" << res.ret; - - { // now read in the file - std::stringstream ibuf; - auto smt_in_fn = os_portable_append_dir(_output_path, smt_name); - std::ifstream smtfin( smt_in_fn ); - - if (! smtfin.is_open()) { - ILA_ERROR << "Cannot read from: " << smt_in_fn; - return ""; - } - ibuf << smtfin.rdbuf(); - return ibuf.str(); - } // finish file readin -} // dual_inv_gen_smt - - -}; // namespace ilang diff --git a/src/vtarget-out/vtarget_gen_yosys.cc b/src/vtarget-out/vtarget_gen_yosys.cc deleted file mode 100644 index 0426fce00..000000000 --- a/src/vtarget-out/vtarget_gen_yosys.cc +++ /dev/null @@ -1,1025 +0,0 @@ -/// \file Source of generating Yosys accepted problem, vlg, mem, script -/// the inv-syn related HC generation is located in inv_syn.cc -// --- Hongce Zhang - -#include - -#include -#include -#include - -#include -#include -#include -#include -#include - -namespace ilang { - -#define VLG_TRUE "`true" -#define VLG_FALSE "`false" - -// initialize templates -static std::string chcGenerateSmtScript_wo_Array = R"***( -hierarchy -check -proc -opt -opt_expr -mux_undef -opt -opt -%flatten% -%setundef -undriven -init -expose% -sim -clock clk -reset rst -rstlen %rstlen% -n %cycle% -w %module% -memory -nordff -proc -opt;; -)***"; - -// should not be used -static std::string chcGenerateSmtScript_w_Array = R"***( -hierarchy -check -proc -opt -opt_expr -mux_undef -opt -opt -%flatten% -%setundef -undriven -init -expose% -sim -clock clk -reset rst -rstlen %rstlen% -n %cycle% -w %module% -memory_dff -wr_only -memory_collect; -memory_unpack -splitnets -driver -opt;; -memory_collect; -pmuxtree -proc -opt;; -)***"; - -static std::string chc_tmpl_datatypes = R"***( -;---------------------------------------- -; Single Inductive Invariant Synthesis -; Generated from ILAng -;---------------------------------------- -%(set-option :fp.engine spacer)% - -%% - -(declare-rel INV (|%1%_s|)) -(declare-rel fail ()) - -(declare-var |__S__| |%1%_s|) -(declare-var |__S'__| |%1%_s|) - -; -------------------------------- -; note if you want it a bit faster -; if can try removing wrapper-u in rule 1 -; or remove the assume previous invariants -; -------------------------------- - -; init => inv -(rule (=> - (and - (|%1%_i| |__S__|) - (|%1%_u| |__S__|) - (|%1%_h| |__S__|) - ) - (INV |__S__|))) - -; inv /\ T => inv -(rule (=> (and - (INV |__S__|) - (|%1%_u| |__S__|) - (|%1%_u| |__S'__|) - (|%1%_h| |__S__|) - (|%1%_h| |__S'__|) - (|%1%_t| |__S__| |__S'__|)) - (INV |__S'__|))) - -; inv /\ ~p => \bot -(rule (=> (and - (INV |__S__|) - (|%1%_u| |__S__|) - (|%1%_h| |__S__|) - (not (|%1%_a| |__S__|))) - fail)) - -; (query fail :print-certificate true) - -)***"; - -static std::string chc_tmpl_wo_datatypes = R"***( -;---------------------------------------- -; Single Inductive Invariant Synthesis -; Generated from ILAng -;---------------------------------------- -%(set-option :fp.engine spacer)% - -%% - -(declare-rel INV %WrapperDataType%) -(declare-rel fail ()) - - -%State% -%StatePrime% -;(declare-var |__S__state| Type) -;(declare-var |__S'__state| Type) - -; same for flattened - -; init => inv -(rule (=> - (and - (|%WrapperName%_i| %Ss%) - (|%WrapperName%_u| %Ss%) - (|%WrapperName%_h| %Ss%) - ) - (INV %Ss%))) - -; inv /\ T => inv -(rule (=> (and - (INV %Ss%) - (|%WrapperName%_u| %Ss%) - (|%WrapperName%_u| %Sps%) - (|%WrapperName%_h| %Ss%) - (|%WrapperName%_h| %Sps%) - (|%WrapperName%_t| %Ss% %Sps%)) - (INV %Sps%))) - -; inv /\ ~p => \bot -(rule (=> (and - (INV %Ss%) - (|%WrapperName%_u| %Ss%) - (|%WrapperName%_h| %Ss%) - (not (|%WrapperName%_a| %Ss%))) - fail)) - -; (query fail :print-certificate true) - -)***"; - -// yosys template -static std::string abcGenerateAigerWInit_wo_Array = R"***( -read_verilog -formal %topfile% -prep -top %module% -sim -clock clk -reset rst -rstlen %rstlen% -n %cycle% -w %module% -miter -assert %module% -flatten -%setundef -undriven -init -expose% -memory -nordff -opt_clean -techmap -abc -fast -g AND -write_aiger -zinit -map %mapname% %aigname% -write_blif %blifname% -)***"; - -static std::string abcAigCmdNoGLA = R"***( - &read %aigname% - &put - fold - pdr {-v -d} - {inv_min} - {inv_print -v} -)***"; - -static std::string abcAigCmdGLA = R"***( - &read %aigname% - &gla -T %glatime% -F %glaframe% -v - &gla_derive - &put - dc2 -v - dc2 -v - dc2 -v - dc2 -v - dc2 -v - dc2 -v - dc2 -v - dc2 -v - {scorr} - dc2 -v - dc2 -v - dc2 -v - dc2 -v - {lcorr} - dc2 -v - dc2 -v - dc2 -v - dc2 -v - pdr {-v -d} - {inv_min} - {inv_print -v} -)***"; - -#define IMPLY(a, b) (!(a) || (b)) - -VlgSglTgtGen_Yosys::~VlgSglTgtGen_Yosys() {} - -VlgSglTgtGen_Yosys::VlgSglTgtGen_Yosys( - const std::string& - output_path, // will be a sub directory of the output_path of its parent - const InstrPtr& instr_ptr, // which could be an empty pointer, and it will - // be used to verify invariants - const InstrLvlAbsPtr& ila_ptr, const VerilogGenerator::VlgGenConfig& config, - nlohmann::json& _rf_vmap, nlohmann::json& _rf_cond, - VlgTgtSupplementaryInfo& _sup_info, VerilogInfo* _vlg_info_ptr, - const std::string& vlg_mod_inst_name, const std::string& ila_mod_inst_name, - const std::string& wrapper_name, - const std::vector& implementation_srcs, - const std::vector& implementation_include_path, - const vtg_config_t& vtg_config, backend_selector vbackend, - const target_type_t& target_tp, advanced_parameters_t* adv_ptr, - _chc_target_t _chc_target) - : VlgSglTgtGen(output_path, instr_ptr, ila_ptr, config, _rf_vmap, _rf_cond, - _sup_info, _vlg_info_ptr, vlg_mod_inst_name, - ila_mod_inst_name, wrapper_name, implementation_srcs, - implementation_include_path, vtg_config, vbackend, target_tp, - adv_ptr), - - s_backend(synthesis_backend_selector(vbackend ^ backend_selector::YOSYS)), - chc_target(_chc_target) { - - ILA_CHECK(chc_target == _chc_target_t::GENERAL_PROPERTY); - - ILA_CHECK(target_tp == target_type_t::INVARIANTS || - target_tp == target_type_t::INSTRUCTIONS) - << "Unknown target type: " << target_tp; - - ILA_CHECK((vbackend & backend_selector::YOSYS) == backend_selector::YOSYS) - << "Must use Yosys as vbackend"; - - ILA_CHECK(s_backend == synthesis_backend_selector::ABC || - s_backend == synthesis_backend_selector::Z3 || - s_backend == synthesis_backend_selector::GRAIN || - s_backend == synthesis_backend_selector::ELDERICA || - s_backend == synthesis_backend_selector::NOSYN); - - ILA_CHECK(IMPLY(s_backend == synthesis_backend_selector::GRAIN, - vtg_config.YosysSmtFlattenDatatype && - vtg_config.YosysSmtFlattenHierarchy)) - << "Grain requires not to flatten hierarchy/datatype"; - - ILA_CHECK(IMPLY(s_backend == synthesis_backend_selector::ABC, - _vtg_config.AbcUseAiger)) - << "Currently only support using AIGER"; - - ILA_CHECK(IMPLY(s_backend == synthesis_backend_selector::ABC, - vtg_config.YosysSmtFlattenHierarchy)) - << "ABC requires to flatten hierarchy"; - // This is hard-coded in the Yosys script - // if not flattened, abc will be unhappy - - ILA_CHECK(IMPLY(s_backend == synthesis_backend_selector::ABC, - vbackend == backend_selector::ABCPDR)); - - ILA_CHECK(IMPLY(s_backend == synthesis_backend_selector::GRAIN, - vbackend == backend_selector::GRAIN_SYGUS && - _vtg_config.YosysSmtStateSort == _vtg_config.Datatypes)); - - ILA_CHECK(IMPLY(s_backend == synthesis_backend_selector::Z3, - vbackend == backend_selector::Z3PDR)); - - ILA_CHECK(IMPLY(vbackend == backend_selector::BTOR_GENERIC, - s_backend == synthesis_backend_selector::NOSYN)); - - ILA_CHECK(s_backend != synthesis_backend_selector::ELDERICA) - << "Bug : not implemented yet!"; - - ILA_CHECK(!(_vtg_config.YosysSmtFlattenDatatype && - _vtg_config.YosysSmtStateSort != _vtg_config.Datatypes)) - << "Must use Datatypes to encode state in order to flatten"; -} // VlgSglTgtGen_Yosys - -/// Add an assumption -void VlgSglTgtGen_Yosys::add_a_direct_assumption(const std::string& aspt, - const std::string& dspt) { - _problems.assumptions[dspt].exprs.push_back(aspt); -} -/// Add an assertion -void VlgSglTgtGen_Yosys::add_a_direct_assertion(const std::string& asst, - const std::string& dspt) { - _problems.assertions[dspt].exprs.push_back(asst); -} - -// PreExportProcess is about how to add assumption/assertions -void VlgSglTgtGen_Yosys::PreExportProcess() { - - std::string all_assert_wire_content; - std::string all_assume_wire_content; - - // you need to add assumptions as well - for (auto&& pbname_prob_pair : _problems.assumptions) { - const auto& prbname = pbname_prob_pair.first; - const auto& prob = pbname_prob_pair.second; - ILA_DLOG("VlgSglTgtGen_Yosys.PreExportProcess") - << "Adding assumption:" << prbname; - - for (auto&& p : prob.exprs) { - if (all_assume_wire_content.empty()) - all_assume_wire_content = "(" + p + ")"; - else - all_assume_wire_content += "&& (" + p + ")"; - } // for prob.exprs - } // for _problems.assumption - - // this is to check given invariants - for (auto&& pbname_prob_pair : _problems.assertions) { - // const auto& prbname = pbname_prob_pair.first; - const auto& prob = pbname_prob_pair.second; - - // ILA_CHECK(prbname == "cex_nonreachable_assert") - // << "BUG: assertion can only be cex reachability queries."; - // sanity check, should only be invariant's related asserts - - for (auto&& p : prob.exprs) { - // there should be only one expression (for cex target) - // ILA_CHECK(all_assert_wire_content.empty()); - if (all_assert_wire_content.empty()) - all_assert_wire_content = p; - else - all_assert_wire_content += " && " + p; - } // for expr - } // for problem - // add assert wire (though no use : make sure will not optimized away) - ILA_CHECK(!all_assert_wire_content.empty()) << "no property to check!"; - - vlg_wrapper.add_wire("__all_assert_wire__", 1, true); - vlg_wrapper.add_output("__all_assert_wire__", 1); - vlg_wrapper.add_assign_stmt("__all_assert_wire__", all_assert_wire_content); - - if (!all_assume_wire_content.empty()) { - vlg_wrapper.add_wire("__all_assume_wire__", 1, true); - vlg_wrapper.add_output("__all_assume_wire__", 1); - vlg_wrapper.add_assign_stmt("__all_assume_wire__", all_assume_wire_content); - } - - if ((_backend & backend_selector::CHC) == backend_selector::CHC) { - vlg_wrapper.add_stmt( - "assert property ( __all_assert_wire__ ); // the only assertion \n"); - if (!all_assume_wire_content.empty()) - vlg_wrapper.add_stmt( - "assume property ( __all_assume_wire__ ); // the only assumption \n"); - } else if (_backend == backend_selector::ABCPDR) { - if (all_assume_wire_content.empty()) { - vlg_wrapper.add_stmt( - "assert property ( __all_assert_wire__ ); // the only assertion \n"); - } else { - std::string precond; - ILA_CHECK( - !(_vtg_config.AbcUseAiger == false && - _vtg_config.AbcAssumptionStyle == _vtg_config.AigMiterExtraOutput)) - << "If you don't use aiger, and has assumptions, there is no way to " - "pass the extra output."; - if (_vtg_config.AbcAssumptionStyle == _vtg_config.AigMiterExtraOutput) { - ILA_CHECK(_vtg_config.AbcUseGla == false) << "Cannot use it with GLA"; - vlg_wrapper.add_stmt("assume property (__all_assume_wire__);\n"); - } else { - vlg_wrapper.add_reg("__all_assumed_reg__", 1); - vlg_wrapper.add_stmt("always @(posedge clk) begin"); - vlg_wrapper.add_stmt("if (rst) __all_assumed_reg__ <= 0;"); - vlg_wrapper.add_stmt( - "else if (!__all_assume_wire__) __all_assumed_reg__ <= 1; end"); - precond = "!( __all_assume_wire__ && !__all_assumed_reg__) || "; - } - vlg_wrapper.add_stmt("assert property (" + precond + - " __all_assert_wire__ ); // the only assertion \n"); - } // all_assume_wire_content has sth. there - } // if (_backend == backend_selector::ABCPDR) - else { - // same as CHC - vlg_wrapper.add_stmt( - "assert property ( __all_assert_wire__ ); // the only assertion \n"); - if (!all_assume_wire_content.empty()) - vlg_wrapper.add_stmt( - "assume property ( __all_assume_wire__ ); // the only assumption \n"); - } -} // PreExportProcess - -/// For jasper, this means do nothing, for yosys, you need to add (*keep*) -void VlgSglTgtGen_Yosys::Export_modify_verilog() { - // collect all locations: filename -> lineno - // open, read, count and write - // if it is a port name, we will ask user to specify its upper level - // signal name - VerilogModifier vlg_mod(vlg_info_ptr, - static_cast( - _vtg_config.PortDeclStyle), - _vtg_config.CosaAddKeep, - supplementary_info.width_info); - - for (auto&& refered_vlg_item : _all_referred_vlg_names) { - auto idx = refered_vlg_item.first.find("["); - auto removed_range_name = refered_vlg_item.first.substr(0, idx); - vlg_mod.RecordKeepSignalName(removed_range_name); - // auto sig = // no use, this is too late, vlg_wrapper already exported - vlg_mod.RecordConnectSigName(removed_range_name, - refered_vlg_item.second.range); - // vlg_wrapper.add_output(sig.first, sig.second); - } - vlg_mod.FinishRecording(); - - // auto tmp_fn = os_portable_append_dir(_output_path, tmp_design_file); - auto tmp_fn = os_portable_append_dir(_output_path, top_file_name); - // now let's do the job - for (auto&& fn : vlg_design_files) { - std::ifstream fin(fn); - std::ofstream fout(tmp_fn, std::ios_base::app); // append to a temp file - if (!fin.is_open()) { - ILA_ERROR << "Cannot read file:" << fn; - continue; - } - if (!fout.is_open()) { - ILA_ERROR << "Cannot open file for write:" << tmp_fn; - continue; - } - vlg_mod.ReadModifyWrite(fn, fin, fout); - } // for (auto && fn : vlg_design_files) - - // handles the includes - // .. (copy all the verilog file in the folder), this has to be os independent - if (vlg_include_files_path.size() != 0) { - // copy the files and specify the -I commandline to the run.sh - for (auto&& include_path : vlg_include_files_path) - os_portable_copy_dir(include_path, _output_path); - } - -} // Export_modify_verilog - -/// export the memory abstraction (implementation) -/// Yes, this is also implementation specific, (jasper may use a different one) -void VlgSglTgtGen_Yosys::Export_mem(const std::string& mem_name) { - // we will ignore the mem_name - - auto outfn = os_portable_append_dir(_output_path, top_file_name); - std::ofstream fout(outfn, std::ios_base::app); // append - - VlgAbsMem::OutputMemFile(fout, - _vtg_config.VerificationSettingAvoidIssueStage); -} - -void VlgSglTgtGen_Yosys::ExportAll(const std::string& wrapper_name, // wrapper.v - const std::string& ila_vlg_name, // no use - const std::string& script_name, // the run.sh - const std::string& extra_name, // the chc - const std::string& mem_name) { // no use - - PreExportProcess(); - - if (os_portable_mkdir(_output_path) == false) - ILA_WARN << "Cannot create output directory:" << _output_path; - - // you don't need to worry about the path and names - Export_wrapper(wrapper_name); - // design only - if (target_type == target_type_t::INSTRUCTIONS) - Export_ila_vlg(ila_vlg_name); // this has to be after Export_wrapper - - // for Jasper, this will be put to multiple files - // for CoSA & Yosys, this will be put after the wrapper file (wrapper.v) - Export_modify_verilog(); // this must be after Export_wrapper - Export_mem(mem_name); - - // you need to create the map function -- - Export_problem(extra_name); // the gensmt.ys - - Export_script(script_name); -} - -// ------------------------------------------------------------------ -// The above is generic for all -// The followings are backend specific -// ------------------------------------------------------------------ - -void VlgSglTgtGen_Yosys::Export_script(const std::string& script_name) { - run_script_name = script_name; - - auto fname = os_portable_append_dir(_output_path, script_name); - std::ofstream fout(fname); - if (!fout.is_open()) { - ILA_ERROR << "Error writing to file:" << fname; - return; - } - fout << "#!/bin/bash" << std::endl; - - std::string runnable; - std::string options; - std::string redirect; - - if (s_backend == synthesis_backend_selector::Z3) { - runnable = "z3"; - if (!_vtg_config.Z3Path.empty()) - runnable = os_portable_append_dir(_vtg_config.Z3Path, runnable); - } else if (s_backend == synthesis_backend_selector::GRAIN) { - runnable = "bv"; - if (!_vtg_config.GrainPath.empty()) - runnable = os_portable_append_dir(_vtg_config.GrainPath, runnable); - for (auto&& op : _vtg_config.GrainOptions) - options += " " + op; - - if (_vtg_config.GrainHintsUseCnfStyle) { - ILA_ERROR_IF(!S_IN(" --cnf ", options) && !S_IN(" --grammar ", options)) - << "You must provide grammar in Grain options!"; - } else { - ILA_ERROR_IF(!S_IN(" --grammar-file=", options)) - << "You must provide grammar in Grain options!"; - options += " --chc-file=\"" + prob_fname + "\""; - } - redirect = " 2> ../grain.result"; - } else if (s_backend == synthesis_backend_selector::ABC) { - runnable = "abc"; - if (!_vtg_config.AbcPath.empty()) - runnable = os_portable_append_dir(_vtg_config.AbcPath, runnable); - std::string abc_cmd; - if (_vtg_config.AbcUseGla) - abc_cmd = abcAigCmdGLA; - else - abc_cmd = abcAigCmdNoGLA; - - abc_cmd = ReplaceAll(abc_cmd, "%glatime%", - std::to_string(_vtg_config.AbcGlaTimeLimit)); - abc_cmd = ReplaceAll(abc_cmd, "%glaframe%", - std::to_string(_vtg_config.AbcGlaFrameLimit)); - abc_cmd = ReplaceAll(abc_cmd, "{scorr}", - _vtg_config.AbcUseCorr ? "scorr -v -l -k -F 4" : ""); - abc_cmd = ReplaceAll(abc_cmd, "{lcorr}", - _vtg_config.AbcUseCorr ? "lcorr -v" : ""); - abc_cmd = ReplaceAll(abc_cmd, "{inv_min}", - _vtg_config.AbcMinimizeInv ? "inv_min -l" : ""); - abc_cmd = - ReplaceAll(abc_cmd, "{-v -d}", - _vtg_config.YosysPropertyCheckShowProof ? "-v -d" : ""); - abc_cmd = ReplaceAll( - abc_cmd, "{inv_print -v}", - _vtg_config.YosysPropertyCheckShowProof ? "inv_print -v" : ""); - - std::string abc_command_file_name = "abcCmd.txt"; - { // generate abc command - abc_cmd = ReplaceAll(abc_cmd, "%blifname%", "__aiger_prepare.blif"); - abc_cmd = ReplaceAll(abc_cmd, "%aigname%", prob_fname); - auto abc_cmd_fname = - os_portable_append_dir(_output_path, abc_command_file_name); - std::ofstream abc_cmd_fn(abc_cmd_fname); - if (!abc_cmd_fn.is_open()) { - ILA_ERROR << "Error writing to file:" << abc_cmd_fname; - return; - } - abc_cmd_fn << abc_cmd; - } // generate abc command - options = " -F " + abc_command_file_name; - - } else if (s_backend == synthesis_backend_selector::ELDERICA) { - ILA_CHECK(false) << "Not implemented."; - } else if (s_backend == synthesis_backend_selector::NOSYN) { - if (!_vtg_config.BtorGenericCmdline.empty()) { - runnable = - ReplaceAll(_vtg_config.BtorGenericCmdline, "%btorfile%", prob_fname); - options = ""; - } else { - runnable = "echo"; - options = " \"btor file is available as: " + prob_fname + "\""; - } - } - - if (prob_fname != "") { - if (s_backend == synthesis_backend_selector::Z3 || - (s_backend == synthesis_backend_selector::GRAIN && - _vtg_config.GrainHintsUseCnfStyle)) - fout << runnable << options << " " << prob_fname << redirect << std::endl; - else // ABC, GRAIN, None - fout << runnable << options << redirect << std::endl; - } else - fout << "echo 'Nothing to check!'" << std::endl; - -} // Export_script - -std::shared_ptr -VlgSglTgtGen_Yosys::GetDesignSmtInfo() const { - ILA_CHECK((_backend & backend_selector::CHC) == backend_selector::CHC && - _vtg_config.YosysSmtStateSort == _vtg_config.Datatypes) - << "Only CHC target with datatypes will generate suitable smt-lib2."; - ILA_CHECK(design_smt_info != nullptr); - return design_smt_info; -} - -// export the chc file -void VlgSglTgtGen_Yosys::Export_problem(const std::string& extra_name) { - // used by export script! - prob_fname = extra_name; - if (s_backend == synthesis_backend_selector::ABC) { - generate_aiger( - os_portable_append_dir(_output_path, "__aiger_prepare.blif"), - os_portable_append_dir(_output_path, extra_name), - os_portable_append_dir(_output_path, extra_name + ".map"), - os_portable_append_dir(_output_path, "__gen_blif_script.ys")); - } else if (s_backend == synthesis_backend_selector::GRAIN || - s_backend == synthesis_backend_selector::Z3) { - // first generate a temporary smt - // and extract from it the necessary info - // this is the CHC-style thing - design_only_gen_smt( - os_portable_append_dir(_output_path, "__design_smt.smt2"), - os_portable_append_dir(_output_path, "__gen_smt_script.ys")); - // if (_vtg_config.YosysSmtStateSort == _vtg_config.DataSort) - convert_smt_to_chc_datatype( - os_portable_append_dir(_output_path, "__design_smt.smt2"), - os_portable_append_dir(_output_path, - s_backend == synthesis_backend_selector::GRAIN - ? "grain_prep.txt" - : extra_name)); - // design_smt_info is assigned here in this function - - // for grain : convert wrapper# --> w wrapper_ --> w - if (s_backend == synthesis_backend_selector::GRAIN) { - std::ifstream fin(os_portable_append_dir(_output_path, "grain_prep.txt")); - std::ofstream fout(os_portable_append_dir(_output_path, extra_name)); - if (!fin.is_open()) { - ILA_ERROR << "Cannot read from : " - << os_portable_append_dir(_output_path, "grain_prep.txt"); - return; - } - if (!fout.is_open()) { - ILA_ERROR << "Cannot write to : " - << os_portable_append_dir(_output_path, extra_name); - return; - } - std::string line; - while (std::getline(fin, line)) { - fout << ReplaceAll(ReplaceAll(line, "wrapper#", "w"), "wrapper_", "w_") - << "\n"; - } - } - } else if (s_backend == synthesis_backend_selector::ELDERICA) - ILA_CHECK(false) << "Not implemented."; - else if (s_backend == synthesis_backend_selector::NOSYN) { - design_only_gen_btor( - os_portable_append_dir(_output_path, extra_name), - os_portable_append_dir(_output_path, "__gen_btor_script.ys")); - } - // else: None , Eldarica -} // Export_problem - -/// generate the wrapper's btor -void VlgSglTgtGen_Yosys::design_only_gen_btor( - const std::string& btor_name, const std::string& ys_script_name) { - - auto ys_output_full_name = - os_portable_append_dir(_output_path, "__yosys_exec_result.txt"); - { // export to ys_script_name - std::ofstream ys_script_fout(ys_script_name); - - std::string write_btor_options; - write_btor_options += _vtg_config.BtorAddCommentsInOutputs ? " -v" : ""; - write_btor_options += _vtg_config.BtorSingleProperty ? " -s" : ""; - - ys_script_fout << "read_verilog -sv " - << os_portable_append_dir(_output_path, top_file_name) - << std::endl; - ys_script_fout << "prep -top " << top_mod_name << std::endl; - - auto chcGenSmtTemplate = _vtg_config.ChcWordBlastArray - ? chcGenerateSmtScript_wo_Array - : chcGenerateSmtScript_w_Array; - - ys_script_fout << ReplaceAll( - ReplaceAll( - ReplaceAll( - ReplaceAll(ReplaceAll(chcGenSmtTemplate, "%flatten%", - _vtg_config.YosysSmtFlattenHierarchy - ? "flatten;" - : ""), - "%setundef -undriven -init -expose%", - _vtg_config.YosysUndrivenNetAsInput - ? "setundef -undriven -init -expose" - : ""), - "%rstlen%", - std::to_string( - supplementary_info.cosa_yosys_reset_config.reset_cycles)), - "%cycle%", - std::to_string( - supplementary_info.cosa_yosys_reset_config.reset_cycles)), - "%module%", top_mod_name); - - // this is for cosa2, I don't know why it is unhappy, but we need fix this - // in the long run - ys_script_fout << "setundef -undriven -zero\n"; - ys_script_fout << "write_btor " << write_btor_options << " " << btor_name; - } // finish writing - - std::string yosys = "yosys"; - - if (!_vtg_config.YosysPath.empty()) - yosys = os_portable_append_dir(_vtg_config.YosysPath, yosys); - - // execute it - std::vector cmd; - cmd.push_back(yosys); - cmd.push_back("-s"); - cmd.push_back(ys_script_name); - auto res = os_portable_execute_shell(cmd, ys_output_full_name); - ILA_ERROR_IF(res.failure != res.NONE) << "Executing Yosys failed!"; - ILA_ERROR_IF(res.failure == res.NONE && res.ret != 0) - << "Yosys returns error code:" << res.ret; -} // design_only_gen_smt - -/// generate the wrapper's smt first -void VlgSglTgtGen_Yosys::design_only_gen_smt( - const std::string& smt_name, const std::string& ys_script_name) { - - auto ys_output_full_name = - os_portable_append_dir(_output_path, "__yosys_exec_result.txt"); - { // export to ys_script_name - std::ofstream ys_script_fout(ys_script_name); - - std::string write_smt2_options = - " -mem -bv "; // future work : -stbv, or nothing - if (_vtg_config.YosysSmtStateSort == _vtg_config.Datatypes) - write_smt2_options += "-stdt "; - else if (_vtg_config.YosysSmtStateSort == _vtg_config.BitVec) - write_smt2_options += "-stbv "; - else - ILA_CHECK(false) << "Unsupported smt state sort encoding:" - << _vtg_config.YosysSmtStateSort; - - ys_script_fout << "read_verilog -sv " - << os_portable_append_dir(_output_path, top_file_name) - << std::endl; - ys_script_fout << "prep -top " << top_mod_name << std::endl; - - auto chcGenSmtTemplate = _vtg_config.ChcWordBlastArray - ? chcGenerateSmtScript_wo_Array - : chcGenerateSmtScript_w_Array; - - ys_script_fout << ReplaceAll( - ReplaceAll( - ReplaceAll( - ReplaceAll(ReplaceAll(chcGenSmtTemplate, "%flatten%", - _vtg_config.YosysSmtFlattenHierarchy - ? "flatten;" - : ""), - "%setundef -undriven -init -expose%", - _vtg_config.YosysUndrivenNetAsInput - ? "setundef -undriven -init -expose" - : ""), - "%rstlen%", - std::to_string( - supplementary_info.cosa_yosys_reset_config.reset_cycles)), - "%cycle%", - std::to_string( - supplementary_info.cosa_yosys_reset_config.reset_cycles)), - "%module%", top_mod_name); - - ys_script_fout << "write_smt2" << write_smt2_options << smt_name; - } // finish writing - - std::string yosys = "yosys"; - - if (!_vtg_config.YosysPath.empty()) - yosys = os_portable_append_dir(_vtg_config.YosysPath, yosys); - - // execute it - std::vector cmd; - cmd.push_back(yosys); - cmd.push_back("-s"); - cmd.push_back(ys_script_name); - auto res = os_portable_execute_shell(cmd, ys_output_full_name); - ILA_ERROR_IF(res.failure != res.NONE) << "Executing Yosys failed!"; - ILA_ERROR_IF(res.failure == res.NONE && res.ret != 0) - << "Yosys returns error code:" << res.ret; -} // design_only_gen_smt - -// %WrapperName% -// %WrapperDataType% -// %State% -// %StatePrime% -// %Ss% %Sps% -static std::string RewriteDatatypeChc(const std::string& tmpl, - const std::vector& dt, - const std::string& wrapper_mod_name) { - - std::string chc = tmpl; - - std::vector inv_tps; - smt::YosysSmtParser::convert_datatype_to_type_vec(dt, inv_tps); - auto WrapperDataType = smt::var_type::toString(inv_tps); - - // %BeforeInitVar% - // %InitVar% - // %State% - // %StatePrime% - // declare-var s ... - std::string State; - std::string StatePrime; - // %BIs% %Is% %Ss% %Sps% - std::string Ss; - std::string Sps; - bool first = true; - - std::set name_set; // avoid repetition - for (auto&& st : dt) { - auto st_name = st.verilog_name.back() == '.' || st.verilog_name.empty() - ? st.internal_name - : st.verilog_name; - st_name = ReplaceAll(st_name, "|", ""); // remove its || - // check no repetition is very important! - ILA_CHECK(!IN(st_name, name_set)) << "Bug: name repetition!"; - ILA_CHECK(!st._type.is_datatype()); - name_set.insert(st_name); - auto type_string = st._type.toString(); - State += "(declare-var |S_" + st_name + "| " + type_string + ")\n"; - StatePrime += "(declare-var |S'_" + st_name + "| " + type_string + ")\n"; - - if (!first) { - Ss += " "; - Sps += " "; - } - first = false; - Ss += "|S_" + st_name + "|"; - Sps += "|S'_" + st_name + "|"; - } - // Replacement - chc = ReplaceAll(chc, "%WrapperName%", wrapper_mod_name); - chc = ReplaceAll(chc, "%WrapperDataType%", WrapperDataType); - chc = ReplaceAll(chc, "%State%", State); - chc = ReplaceAll(chc, "%StatePrime%", StatePrime); - chc = ReplaceAll(chc, "%Ss%", Ss); - chc = ReplaceAll(chc, "%Sps%", Sps); - - return chc; -} // RewriteDatatypeChc - -void VlgSglTgtGen_Yosys::convert_smt_to_chc_datatype( - const std::string& smt_fname, const std::string& chc_fname) { - - std::stringstream ibuf; - { // read file - std::ifstream smt_fin(smt_fname); - if (!smt_fin.is_open()) { - ILA_ERROR << "Cannot read from " << smt_fname; - return; - } - ibuf << smt_fin.rdbuf(); - } // end read file - - std::string smt_converted; - if (_vtg_config.YosysSmtStateSort == _vtg_config.Datatypes) - design_smt_info = std::make_shared(ibuf.str()); - - if (_vtg_config.YosysSmtFlattenDatatype) { - ILA_NOT_NULL(design_smt_info); - design_smt_info->BreakDatatypes(); - // smt_rewriter.AddNoChangeStateUpdateFunction(); - smt_converted = design_smt_info->Export(); - } else { - smt_converted = ibuf.str(); - } - - std::string wrapper_mod_name = - design_smt_info ? design_smt_info->get_module_def_orders().back() - : "wrapper"; - // construct the template - - std::string chc; - if (_vtg_config.YosysSmtFlattenDatatype) { - ILA_NOT_NULL(design_smt_info); - const auto& datatype_top_mod = - design_smt_info->get_module_flatten_dt(wrapper_mod_name); - auto tmpl = - ReplaceAll(chc_tmpl_wo_datatypes, "%(set-option :fp.engine spacer)%", - s_backend == synthesis_backend_selector::GRAIN - ? "" - : "(set-option :fp.engine spacer)"); - tmpl = ReplaceAll( - tmpl, "(|%WrapperName%_u| %Ss%)", - _vtg_config.ChcAssumptionsReset ? "(|%WrapperName%_u| %Ss%)" : ""); - tmpl = ReplaceAll( - tmpl, "(|%WrapperName%_u| %Sps%)", - _vtg_config.ChcAssumptionNextState ? "(|%WrapperName%_u| %Sps%)" : ""); - tmpl = ReplaceAll(tmpl, "(|%WrapperName%_u| %Ss%)", - _vtg_config.ChcAssumptionEnd ? "(|%WrapperName%_u| %Ss%)" - : ""); - tmpl = ReplaceAll( - tmpl, "(|%WrapperName%_h| %Ss%)", - _vtg_config.YosysSmtFlattenHierarchy ? "" : "(|%WrapperName%_h| %Ss%)"); - tmpl = ReplaceAll(tmpl, "(|%WrapperName%_h| %Sps%)", - _vtg_config.YosysSmtFlattenHierarchy - ? "" - : "(|%WrapperName%_h| %Sps%)"); - tmpl = ReplaceAll(tmpl, "(and", - !_vtg_config.ChcAssumptionsReset && - _vtg_config.YosysSmtFlattenHierarchy - ? "" - : "(and"); - tmpl = ReplaceAll(tmpl, ")", - !_vtg_config.ChcAssumptionsReset && - _vtg_config.YosysSmtFlattenHierarchy - ? "" - : ")"); - chc = RewriteDatatypeChc(tmpl, datatype_top_mod, wrapper_mod_name); - chc = ReplaceAll(chc, "%%", smt_converted); - } else { - chc = ReplaceAll(chc_tmpl_datatypes, "%(set-option :fp.engine spacer)%", - "(set-option :fp.engine spacer)"); - - chc = - ReplaceAll(chc, "(|%1%_u| |__S__|)", - _vtg_config.ChcAssumptionsReset ? "(|%1%_u| |__S__|)" : ""); - chc = ReplaceAll(chc, "(|%1%_u| |__S'__|)", - _vtg_config.ChcAssumptionNextState ? "(|%1%_u| |__S'__|)" - : ""); - chc = ReplaceAll(chc, "(|%1%_u| |__S__|)", - _vtg_config.ChcAssumptionEnd ? "(|%1%_u| |__S__|)" : ""); - chc = ReplaceAll( - chc, "(|%1%_h| |__S__|)", - _vtg_config.YosysSmtFlattenHierarchy ? "" : "(|%1%_h| |__S__|)"); - chc = ReplaceAll( - chc, "(|%1%_h| |__S'__|)", - _vtg_config.YosysSmtFlattenHierarchy ? "" : "(|%1%_h| |__S'__|)"); - chc = ReplaceAll(chc, "(and", - !_vtg_config.ChcAssumptionsReset && - _vtg_config.YosysSmtFlattenHierarchy - ? "" - : "(and"); - chc = ReplaceAll(chc, ")", - !_vtg_config.ChcAssumptionsReset && - _vtg_config.YosysSmtFlattenHierarchy - ? "" - : ")"); - chc = ReplaceAll(chc, "%1%", wrapper_mod_name); - chc = ReplaceAll(chc, "%%", smt_converted); - } // end of ~_vtg_config.YosysSmtFlattenDatatype -- no convert - - { // (query fail :print-certificate true) - if (_vtg_config.YosysPropertyCheckShowProof) - chc += "\n(query fail :print-certificate true)\n"; - else - chc += "\n(query fail)\n"; - } - - { // write file - std::ofstream chc_fout(chc_fname); - if (!chc_fout.is_open()) { - ILA_ERROR << "Error writing to : " << chc_fname; - return; - } - chc_fout << chc; - } // end write file - -} // convert_smt_to_chc_datatype - -/// generate the wrapper's smt first -void VlgSglTgtGen_Yosys::generate_aiger(const std::string& blif_name, - const std::string& aiger_name, - const std::string& map_name, - const std::string& ys_script_name) { - - auto ys_output_full_name = - os_portable_append_dir(_output_path, "__yosys_exec_result.txt"); - { // export to ys_script_name - std::ofstream ys_script_fout(ys_script_name); - - ys_script_fout << ReplaceAll( - ReplaceAll( - ReplaceAll( - ReplaceAll( - ReplaceAll( - ReplaceAll( - ReplaceAll( - ReplaceAll(abcGenerateAigerWInit_wo_Array, - "%topfile%", - os_portable_append_dir( - _output_path, top_file_name)), - "%module%", top_mod_name), - "%blifname%", blif_name), - "%aigname%", aiger_name), - "%mapname%", map_name), - "%setundef -undriven -init -expose%", - _vtg_config.YosysUndrivenNetAsInput - ? "setundef -undriven -init -expose" - : ""), - "%rstlen%", - std::to_string( - supplementary_info.cosa_yosys_reset_config.reset_cycles)), - "%cycle%", - std::to_string( - supplementary_info.cosa_yosys_reset_config.reset_cycles)); - } // finish writing - - std::string yosys = "yosys"; - - if (!_vtg_config.YosysPath.empty()) - yosys = os_portable_append_dir(_vtg_config.YosysPath, yosys); - - // execute it - std::vector cmd; - cmd.push_back(yosys); - cmd.push_back("-s"); - cmd.push_back(ys_script_name); - auto res = os_portable_execute_shell(cmd, ys_output_full_name); - ILA_ERROR_IF(res.failure != res.NONE) << "Executing Yosys failed!"; - ILA_ERROR_IF(res.failure == res.NONE && res.ret != 0) - << "Yosys returns error code:" << res.ret; -} // generate_aiger - -}; // namespace ilang diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index b4cad2fff..5ff2ff882 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -76,6 +76,8 @@ package_add_test(${ILANG_TEST_MAIN} t_smt_shim.cc t_smt_switch_itf.cc t_smt_trans.cc + t_rfexpr_smt_out.cc + t_rfmap_proc.cc t_sort.cc t_symbol.cc t_unroll_seq.cc diff --git a/test/t_api.cc b/test/t_api.cc index e2da6facf..389bf4b26 100644 --- a/test/t_api.cc +++ b/test/t_api.cc @@ -599,4 +599,32 @@ TEST(TestApi, Portable) { DisableDebug("Portable"); } +TEST(TestApi, RtlVerify) { + // 1. build the ila + auto proc = Ila("proc"); + auto v = proc.NewBvState("v",1); + proc.SetValid(BoolConst(true)); + { // + auto inst = proc.NewInstr("inst"); + inst.SetDecode(BoolConst(true)); + inst.SetUpdate(v, BvConst(1,1)); + } + + // 2. verify + auto dirName = os_portable_join_dir( + {ILANG_TEST_SRC_ROOT, "unit-data", "vpipe", "reset"}); + auto vlg_name = os_portable_join_dir( + {dirName, "verilog", "resetter.v"}); + auto vmap_name = os_portable_join_dir( + {dirName, "rfmap", "vmap-e1.json"}); + auto cond_name = os_portable_join_dir( + {dirName, "rfmap", "cond.json"}); + auto out_name = os_portable_append_dir(dirName, "out3"); + + IlaVerilogRefinementChecker checker( + proc, {}, {vlg_name}, "resetter", vmap_name, cond_name, out_name, + ModelCheckerSelection::PONO); + +} + } // namespace ilang diff --git a/test/t_inv_extract.cc b/test/t_inv_extract.cc index eb59645f6..1c9c1c18f 100644 --- a/test/t_inv_extract.cc +++ b/test/t_inv_extract.cc @@ -6,7 +6,7 @@ #include #include #include -#include +// #include #include #include "unit-include/config.h" @@ -28,7 +28,7 @@ class TestInvExtract : public ::testing::Test { }; // class TestInvExtract -#ifdef ILANG_BUILD_INVSYN +#if 0 TEST_F(TestInvExtract, Abc) { diff --git a/test/t_inv_obj.cc b/test/t_inv_obj.cc index 7f8013205..ccff04f72 100644 --- a/test/t_inv_obj.cc +++ b/test/t_inv_obj.cc @@ -5,7 +5,7 @@ #include #include #include -#include +// #include #include #include "unit-include/config.h" diff --git a/test/t_inv_syn.cc b/test/t_inv_syn.cc index 628f2c9fa..c6e19cb2b 100644 --- a/test/t_inv_syn.cc +++ b/test/t_inv_syn.cc @@ -4,7 +4,7 @@ #include #include #include -#include +// #include #include #include "unit-include/config.h" @@ -14,7 +14,8 @@ namespace ilang { -#ifdef ILANG_BUILD_INVSYN +// #ifdef ILANG_BUILD_INVSYN +#if 0 #define DBG_TAG "VlgVerifInvSyn" @@ -49,9 +50,9 @@ class TestVlgVerifInvSyn : public ::testing::Test { TEST_F(TestVlgVerifInvSyn, SimpleCntCegar) { auto ila_model = CntTest::BuildModel(); - VerilogVerificationTargetGenerator::vtg_config_t cfg; + RtlVerifyConfig cfg; cfg.InvariantSynthesisReachableCheckKeepOldInvariant = false; - cfg.CosaAddKeep = false; + cfg.PonoAddKeep = false; cfg.VerificationSettingAvoidIssueStage = true; cfg.YosysSmtFlattenDatatype = false; // let's test flatten datatype also cfg.YosysSmtFlattenHierarchy = true; @@ -76,7 +77,7 @@ TEST_F(TestVlgVerifInvSyn, SimpleCntCegar) { P({"rfmap", "vmap.json"})), // variable mapping os_portable_append_dir(dirName, P({"rfmap", "cond-noinv.json"})), outDir, ila_model.get(), - VerilogVerificationTargetGenerator::backend_selector::COSA, + ModelCheckerSelection::COSA, VerilogVerificationTargetGenerator::synthesis_backend_selector::Z3, cfg); EXPECT_FALSE(vg.in_bad_state()); @@ -148,9 +149,9 @@ TEST_F(TestVlgVerifInvSyn, SimpleCntCegar) { TEST_F(TestVlgVerifInvSyn, SimpleCntCegarWithAssumptions) { auto ila_model = CntTest::BuildModel(); - VerilogVerificationTargetGenerator::vtg_config_t cfg; + RtlVerifyConfig cfg; cfg.InvariantSynthesisReachableCheckKeepOldInvariant = true; - cfg.CosaAddKeep = false; + cfg.PonoAddKeep = false; cfg.VerificationSettingAvoidIssueStage = true; cfg.YosysSmtFlattenDatatype = false; // let's test flatten datatype also cfg.YosysSmtFlattenHierarchy = true; @@ -175,7 +176,7 @@ TEST_F(TestVlgVerifInvSyn, SimpleCntCegarWithAssumptions) { P({"rfmap", "vmap.json"})), // variable mapping os_portable_append_dir(dirName, P({"rfmap", "cond-noinv.json"})), outDir, ila_model.get(), - VerilogVerificationTargetGenerator::backend_selector::COSA, + ModelCheckerSelection::COSA, VerilogVerificationTargetGenerator::synthesis_backend_selector::Z3, cfg); EXPECT_FALSE(vg.in_bad_state()); @@ -193,9 +194,9 @@ TEST_F(TestVlgVerifInvSyn, SimpleCntCegarWithAssumptions) { TEST_F(TestVlgVerifInvSyn, LoadInvFromBeginning) { auto ila_model = CntTest::BuildModel(); - VerilogVerificationTargetGenerator::vtg_config_t cfg; + RtlVerifyConfig cfg; cfg.InvariantSynthesisReachableCheckKeepOldInvariant = false; - cfg.CosaAddKeep = false; + cfg.PonoAddKeep = false; cfg.VerificationSettingAvoidIssueStage = true; cfg.YosysSmtFlattenDatatype = false; // let's test flatten datatype also cfg.YosysSmtFlattenHierarchy = true; @@ -222,7 +223,7 @@ TEST_F(TestVlgVerifInvSyn, LoadInvFromBeginning) { P({"rfmap", "vmap.json"})), // variable mapping os_portable_append_dir(dirName, P({"rfmap", "cond-noinv.json"})), outDir, ila_model.get(), - VerilogVerificationTargetGenerator::backend_selector::COSA, + ModelCheckerSelection::COSA, VerilogVerificationTargetGenerator::synthesis_backend_selector::Z3, cfg); @@ -243,7 +244,7 @@ TEST_F(TestVlgVerifInvSyn, LoadInvFromBeginning) { P({"rfmap", "vmap.json"})), // variable mapping os_portable_append_dir(dirName, P({"rfmap", "cond-noinv.json"})), outDir, ila_model.get(), - VerilogVerificationTargetGenerator::backend_selector::COSA, + ModelCheckerSelection::COSA, VerilogVerificationTargetGenerator::synthesis_backend_selector::Z3, cfg); @@ -264,7 +265,7 @@ TEST_F(TestVlgVerifInvSyn, LoadInvFromBeginning) { P({"rfmap", "vmap.json"})), // variable mapping os_portable_append_dir(dirName, P({"rfmap", "cond-noinv.json"})), outDir, ila_model.get(), - VerilogVerificationTargetGenerator::backend_selector::COSA, + ModelCheckerSelection::COSA, VerilogVerificationTargetGenerator::synthesis_backend_selector::Z3, cfg); @@ -293,7 +294,7 @@ TEST_F(TestVlgVerifInvSyn, LoadInvFromBeginning) { P({"rfmap", "vmap.json"})), // variable mapping os_portable_append_dir(dirName, P({"rfmap", "cond-noinv.json"})), outDir, ila_model.get(), - VerilogVerificationTargetGenerator::backend_selector::COSA, + ModelCheckerSelection::COSA, VerilogVerificationTargetGenerator::synthesis_backend_selector::Z3, cfg); @@ -317,9 +318,9 @@ TEST_F(TestVlgVerifInvSyn, LoadInvFromBeginning) { TEST_F(TestVlgVerifInvSyn, SimpleCntCegarPassed) { auto ila_model = CntTest::BuildModel(); - VerilogVerificationTargetGenerator::vtg_config_t cfg; + RtlVerifyConfig cfg; cfg.InvariantSynthesisReachableCheckKeepOldInvariant = false; - cfg.CosaAddKeep = false; + cfg.PonoAddKeep = false; cfg.VerificationSettingAvoidIssueStage = true; cfg.YosysSmtFlattenDatatype = false; // let's test flatten datatype also cfg.YosysSmtFlattenHierarchy = true; @@ -345,7 +346,7 @@ TEST_F(TestVlgVerifInvSyn, SimpleCntCegarPassed) { P({"rfmap", "vmap.json"})), // variable mapping os_portable_append_dir(dirName, P({"rfmap", "cond-noinv.json"})), outDir, ila_model.get(), - VerilogVerificationTargetGenerator::backend_selector::COSA, + ModelCheckerSelection::COSA, VerilogVerificationTargetGenerator::synthesis_backend_selector::Z3, cfg); EXPECT_FALSE(vg.in_bad_state()); @@ -359,9 +360,9 @@ TEST_F(TestVlgVerifInvSyn, SimpleCntCegarPassed) { TEST_F(TestVlgVerifInvSyn, CegarCntAbc) { auto ila_model = CntTest::BuildModel(); - VerilogVerificationTargetGenerator::vtg_config_t cfg; + RtlVerifyConfig cfg; cfg.InvariantSynthesisReachableCheckKeepOldInvariant = false; - cfg.CosaAddKeep = false; + cfg.PonoAddKeep = false; cfg.VerificationSettingAvoidIssueStage = true; cfg.YosysSmtFlattenDatatype = false; cfg.YosysSmtFlattenHierarchy = true; @@ -389,7 +390,7 @@ TEST_F(TestVlgVerifInvSyn, CegarCntAbc) { P({"rfmap", "vmap.json"})), // variable mapping os_portable_append_dir(dirName, P({"rfmap", "cond-noinv.json"})), outDir, ila_model.get(), - VerilogVerificationTargetGenerator::backend_selector::COSA, + ModelCheckerSelection::COSA, VerilogVerificationTargetGenerator::synthesis_backend_selector::ABC, cfg); EXPECT_FALSE(vg.in_bad_state()); @@ -411,9 +412,9 @@ TEST_F(TestVlgVerifInvSyn, CegarCntAbc) { TEST_F(TestVlgVerifInvSyn, CegarCntAbcBlif) { auto ila_model = CntTest::BuildModel(); - VerilogVerificationTargetGenerator::vtg_config_t cfg; + RtlVerifyConfig cfg; cfg.InvariantSynthesisReachableCheckKeepOldInvariant = false; - cfg.CosaAddKeep = false; + cfg.PonoAddKeep = false; cfg.VerificationSettingAvoidIssueStage = true; cfg.YosysSmtFlattenDatatype = false; cfg.YosysSmtFlattenHierarchy = true; @@ -443,7 +444,7 @@ TEST_F(TestVlgVerifInvSyn, CegarCntAbcBlif) { P({"rfmap", "vmap.json"})), // variable mapping os_portable_append_dir(dirName, P({"rfmap", "cond-noinv.json"})), outDir, ila_model.get(), - VerilogVerificationTargetGenerator::backend_selector::COSA, + ModelCheckerSelection::COSA, VerilogVerificationTargetGenerator::synthesis_backend_selector::ABC, cfg); EXPECT_FALSE(vg.in_bad_state()); @@ -464,9 +465,9 @@ TEST_F(TestVlgVerifInvSyn, CegarCntAbcBlif) { TEST_F(TestVlgVerifInvSyn, CegarCntAbcWithAssumption) { auto ila_model = CntTest::BuildModel(); - VerilogVerificationTargetGenerator::vtg_config_t cfg; + RtlVerifyConfig cfg; cfg.InvariantSynthesisReachableCheckKeepOldInvariant = true; - cfg.CosaAddKeep = false; + cfg.PonoAddKeep = false; cfg.VerificationSettingAvoidIssueStage = true; cfg.YosysSmtFlattenDatatype = false; cfg.YosysSmtFlattenHierarchy = true; @@ -494,7 +495,7 @@ TEST_F(TestVlgVerifInvSyn, CegarCntAbcWithAssumption) { P({"rfmap", "vmap.json"})), // variable mapping os_portable_append_dir(dirName, P({"rfmap", "cond-noinv.json"})), outDir, ila_model.get(), - VerilogVerificationTargetGenerator::backend_selector::COSA, + ModelCheckerSelection::COSA, VerilogVerificationTargetGenerator::synthesis_backend_selector::ABC, cfg); EXPECT_FALSE(vg.in_bad_state()); @@ -510,9 +511,9 @@ TEST_F(TestVlgVerifInvSyn, CegarCntAbcWithAssumption) { TEST_F(TestVlgVerifInvSyn, CegarCntAbcInvStart) { auto ila_model = CntTest::BuildModel(); - VerilogVerificationTargetGenerator::vtg_config_t cfg; + RtlVerifyConfig cfg; cfg.InvariantSynthesisReachableCheckKeepOldInvariant = false; - cfg.CosaAddKeep = false; + cfg.PonoAddKeep = false; cfg.VerificationSettingAvoidIssueStage = true; cfg.YosysSmtFlattenDatatype = false; cfg.YosysSmtFlattenHierarchy = true; @@ -544,7 +545,7 @@ TEST_F(TestVlgVerifInvSyn, CegarCntAbcInvStart) { P({"rfmap", "vmap.json"})), // variable mapping os_portable_append_dir(dirName, P({"rfmap", "cond-noinv.json"})), outDir, ila_model.get(), - VerilogVerificationTargetGenerator::backend_selector::COSA, + ModelCheckerSelection::COSA, VerilogVerificationTargetGenerator::synthesis_backend_selector::ABC, cfg); @@ -580,7 +581,7 @@ TEST_F(TestVlgVerifInvSyn, CegarCntAbcInvStart) { P({"rfmap", "vmap.json"})), // variable mapping os_portable_append_dir(dirName, P({"rfmap", "cond-noinv.json"})), outDir, ila_model.get(), - VerilogVerificationTargetGenerator::backend_selector::COSA, + ModelCheckerSelection::COSA, VerilogVerificationTargetGenerator::synthesis_backend_selector::ABC, cfg); @@ -605,9 +606,9 @@ TEST_F(TestVlgVerifInvSyn, CegarCntAbcInvStart) { TEST_F(TestVlgVerifInvSyn, CegarCntGrain) { auto ila_model = CntTest::BuildModel(); - VerilogVerificationTargetGenerator::vtg_config_t cfg; + RtlVerifyConfig cfg; cfg.InvariantSynthesisReachableCheckKeepOldInvariant = true; - cfg.CosaAddKeep = false; + cfg.PonoAddKeep = false; cfg.VerificationSettingAvoidIssueStage = true; cfg.YosysSmtFlattenDatatype = true; // let's test flatten datatype also cfg.YosysSmtFlattenHierarchy = true; @@ -653,7 +654,7 @@ TEST_F(TestVlgVerifInvSyn, CegarCntGrain) { P({"rfmap", "vmap.json"})), // variable mapping os_portable_append_dir(dirName, P({"rfmap", "cond-noinv.json"})), outDir, ila_model.get(), - VerilogVerificationTargetGenerator::backend_selector::COSA, + ModelCheckerSelection::COSA, VerilogVerificationTargetGenerator::synthesis_backend_selector::GRAIN, cfg); @@ -677,9 +678,9 @@ TEST_F(TestVlgVerifInvSyn, CegarCntGrain) { TEST_F(TestVlgVerifInvSyn, CegarCntGrainBackVars) { auto ila_model = CntTest::BuildModel(); - VerilogVerificationTargetGenerator::vtg_config_t cfg; + RtlVerifyConfig cfg; cfg.InvariantSynthesisReachableCheckKeepOldInvariant = true; - cfg.CosaAddKeep = false; + cfg.PonoAddKeep = false; cfg.VerificationSettingAvoidIssueStage = true; cfg.YosysSmtFlattenDatatype = true; // let's test flatten datatype also cfg.YosysSmtFlattenHierarchy = true; @@ -726,7 +727,7 @@ TEST_F(TestVlgVerifInvSyn, CegarCntGrainBackVars) { P({"rfmap", "vmap.json"})), // variable mapping os_portable_append_dir(dirName, P({"rfmap", "cond-noinv.json"})), outDir, ila_model.get(), - VerilogVerificationTargetGenerator::backend_selector::COSA, + ModelCheckerSelection::COSA, VerilogVerificationTargetGenerator::synthesis_backend_selector::GRAIN, cfg); @@ -752,9 +753,9 @@ TEST_F(TestVlgVerifInvSyn, CegarCntGrainBackVars) { TEST_F(TestVlgVerifInvSyn, CegarPipelineAbcAigEnhance) { auto ila_model = SimplePipe::BuildModel(); - VerilogVerificationTargetGenerator::vtg_config_t cfg; + RtlVerifyConfig cfg; // cfg.InvariantSynthesisReachableCheckKeepOldInvariant = false; - cfg.CosaAddKeep = false; + cfg.PonoAddKeep = false; cfg.VerificationSettingAvoidIssueStage = true; cfg.YosysSmtFlattenDatatype = true; // for freqhorn cfg.YosysSmtFlattenHierarchy = true; @@ -785,7 +786,7 @@ TEST_F(TestVlgVerifInvSyn, CegarPipelineAbcAigEnhance) { os_portable_join_dir({dirName, "rfmap", "vmap.json"}), // variable mapping os_portable_join_dir({dirName, "rfmap", "cond-noinv.json"}), outDir, ila_model.get(), - VerilogVerificationTargetGenerator::backend_selector::COSA, + ModelCheckerSelection::COSA, VerilogVerificationTargetGenerator::synthesis_backend_selector::ABC, cfg); EXPECT_FALSE(vg.in_bad_state()); @@ -835,8 +836,8 @@ TEST_F(TestVlgVerifInvSyn, CegarPipelineAbcAigEnhance) { TEST_F(TestVlgVerifInvSyn, SimpleCntRelChc) { auto ila_model = CntTest::BuildModel(); - VerilogVerificationTargetGenerator::vtg_config_t cfg; - cfg.CosaAddKeep = false; + RtlVerifyConfig cfg; + cfg.PonoAddKeep = false; cfg.YosysPath = "N/A"; cfg.YosysSmtFlattenHierarchy = false; @@ -847,7 +848,7 @@ TEST_F(TestVlgVerifInvSyn, SimpleCntRelChc) { "opposite", // top_module_name dirName + "rfmap/vmap.json", // variable mapping dirName + "rfmap/cond-relchc.json", dirName + "out/", ila_model.get(), - VerilogVerificationTargetGenerator::backend_selector::RELCHC, cfg); + ModelCheckerSelection::RELCHC, cfg); EXPECT_FALSE(vg.in_bad_state()); @@ -857,8 +858,8 @@ TEST_F(TestVlgVerifInvSyn, SimpleCntRelChc) { TEST_F(TestVlgVerifInvSyn, SimpleCntRelChcNoStart) { auto ila_model = CntTest::BuildModel(); - VerilogVerificationTargetGenerator::vtg_config_t cfg; - cfg.CosaAddKeep = false; + RtlVerifyConfig cfg; + cfg.PonoAddKeep = false; cfg.YosysPath = "N/A"; cfg.YosysSmtFlattenHierarchy = false; cfg.VerificationSettingAvoidIssueStage = true; @@ -871,7 +872,7 @@ TEST_F(TestVlgVerifInvSyn, SimpleCntRelChcNoStart) { dirName + "rfmap/vmap.json", // variable mapping dirName + "rfmap/cond-relchc.json", dirName + "out-no-start/", ila_model.get(), - VerilogVerificationTargetGenerator::backend_selector::RELCHC, cfg); + ModelCheckerSelection::RELCHC, cfg); EXPECT_FALSE(vg.in_bad_state()); diff --git a/test/t_rfexpr_smt_out.cc b/test/t_rfexpr_smt_out.cc new file mode 100644 index 000000000..94b56341c --- /dev/null +++ b/test/t_rfexpr_smt_out.cc @@ -0,0 +1,99 @@ +/// \file +/// Unit test for refinement expression to smt-lib2 + +#include + +#include "unit-include/config.h" +#include "unit-include/util.h" + +// use rfmap::VerilogRefinementMap::ParseRfExprFromString +// to parse a refinement expression +// and use rfmap::RfExpr2Smt::to_smt2 to translate to smt-lib2 +// but you need type annotation first +// this flow is used in array handling with pono + +namespace ilang { + +class TypeVars { +public: + static rfmap::RfExpr GiveVarTheirTypes(const rfmap::RfExpr & inout, rfmap::TypeAnalysisUtility::var_typecheck_t checker) { + rfmap::RfExprVarReplUtility repl; + + std::unordered_map vars; + rfmap::RfExprAstUtility::GetVars(inout, vars); + for(const auto & v : vars ) { + auto tp = checker(v.first); + auto newv = verilog_expr::VExprAst::MakeSpecialName(v.first); + auto newtp_ptr = std::make_shared(tp); + newv->set_annotation(newtp_ptr); + repl.RegisterInternalVariableWithMapping(v.first, rfmap::VarReplacement(v.second, newv)); + } + return repl.ReplacingRtlIlaVar(inout, {}); + } +}; + +#define PRINT_SMT(s, b, expand) do { \ + std::string rfstr = (s); \ + auto rfexpr = rfmap::VerilogRefinementMap::ParseRfExprFromString(rfstr); \ + if(expand) rfexpr = rfmap::RfExprAstUtility::FindExpandQuantifier(rfexpr); \ + rfexpr = TypeVars::GiveVarTheirTypes(rfexpr, check_var_type); \ + annotator.AnnotateType(rfexpr, {}); \ + ILA_DLOG("SMTOUT.TEST") << rfmap::RfExpr2Smt::to_smt2(rfexpr, \ + (b) ? rfmap::SmtType() : \ + rfmap::SmtType( (rfexpr->get_annotation())->type, false )) \ + << std::endl; \ +} while(0) + +// + +TEST(TestRfexpr, ToSmt) { + // 1. construct var to rf_var_type map + // and the function to map that + // 2. annotate the type + // 3. convert + std::map var_type = + { + {"a", rfmap::RfMapVarType(16) }, + {"b", rfmap::RfMapVarType(8) }, + {"c", rfmap::RfMapVarType(1) }, + {"array1", rfmap::RfMapVarType(16,8) }, + {"array2", rfmap::RfMapVarType(16,8) }, + {"array3", rfmap::RfMapVarType(8,16) } + }; + + auto check_var_type = + [&var_type](const std::string & n) -> rfmap::RfVarTypeOrig { + rfmap::RfVarTypeOrig ret; + auto pos = var_type.find(n); + if(pos != var_type.end()) + ret.type = pos->second; + return ret; + }; + + rfmap::TypeAnalysisUtility annotator; + bool expand = false; + { + PRINT_SMT("a[4] == b[4]" , true, expand); // should be (extract) + PRINT_SMT("a[5:4] + c[4:3] != array1[a][2:1]" , true, expand); // extract and select + PRINT_SMT(" c ? array1 : array2 " , false, expand); // should handle array well + PRINT_SMT(" c == 1'b1? array1 : array2 " , false, expand); // should be able to convert + PRINT_SMT(" array3[b+1] " , false, expand); // should set the right type of 1 + PRINT_SMT(" a+b == c " , true, expand); // should expand b, c + PRINT_SMT(" $forall(i:bv16 , array1[i+a] == array2[i]) " , true, expand); // should expand b, c + PRINT_SMT(" $exist(i:bv8 , array1[array3[i]] == array2[{8'd0, i}])" , true, expand); // should expand b, c + } + expand = true; + { + PRINT_SMT("a[4] == b[4]" , true, expand); // should be (extract) + PRINT_SMT("a[5:4] + c[4:3] != array1[a][2:1]" , true, expand); // extract and select + PRINT_SMT(" c ? array1 : array2 " , false, expand); // should handle array well + PRINT_SMT(" c == 1'b1? array1 : array2 " , false, expand); // should be able to convert + PRINT_SMT(" array3[b+1] " , false, expand); // should set the right type of 1 + PRINT_SMT(" a+b == c " , true, expand); // should expand b, c + PRINT_SMT(" $forall(i:bv2 , array1[{ 14'd0, i}+a] == array2[{ 14'd0, i}]) " , true, expand); // should expand b, c + PRINT_SMT(" $exist(i:bv3 , array1[array3[{5'd0,i}]] == array2[{13'd0, i}])" , true, expand); // should expand b, c + } +} // TEST(TestRfexpr, ToSmt) + +} // namespace ilang + diff --git a/test/t_rfmap_proc.cc b/test/t_rfmap_proc.cc new file mode 100644 index 000000000..bec180e58 --- /dev/null +++ b/test/t_rfmap_proc.cc @@ -0,0 +1,42 @@ +/// \file +/// Unit test for generating Verilog verification target + +#include +#include +#include +#include + +#include "unit-include/config.h" +#include "unit-include/memswap.h" +#include "unit-include/pipe_ila.h" +#include "unit-include/util.h" + +namespace ilang { + +typedef std::vector P; + +TEST(TestRfmapProcess, TypeResolve) { + auto ila_model = SimplePipe::BuildModel(); + + auto dirName = os_portable_append_dir(ILANG_TEST_DATA_DIR, "vpipe"); + auto rfDir = os_portable_append_dir(dirName, "rfmap_t"); + auto outDir = os_portable_append_dir(os_portable_append_dir(dirName, "rfmap_t_out"), "t1"); + auto vtg_config = RtlVerifyConfig(); + + VerilogVerificationTargetGenerator vg( + {}, // no include + {os_portable_append_dir(dirName, "simple_pipe.v")}, // vlog files + "pipeline_v", // top_module_name + os_portable_append_dir(rfDir, "vmap-1.json"), // variable mapping + os_portable_append_dir(rfDir, "cond-1.json"), // instruction-mapping + outDir, // verification dir + ila_model.get(), // ILA model + ModelCheckerSelection::PONO, // engine + vtg_config); + + EXPECT_FALSE(vg.in_bad_state()); + vg.GenerateTargets(); +} // TEST(TestRfmapProcess, TypeResolve) + + +}; // namespace ilang diff --git a/test/t_verilog_analysis.cc b/test/t_verilog_analysis.cc index 60ae60bfb..07535e605 100644 --- a/test/t_verilog_analysis.cc +++ b/test/t_verilog_analysis.cc @@ -81,9 +81,26 @@ TEST(TestVerilogAnalysis, Include) { << "End loc of m1:" << va.get_endmodule_loc("m1"); } +TEST(TestVerilogAnalysis, RangeAnalysisArray) { +#define IS_ARRAY_RANGE_SIZE(n, w) EXPECT_EQ(va.get_signal("m1." n).get_addr_range_size(), w) + { + VerilogInfo va( + VerilogInfo::path_vec_t( + {std::string(ILANG_TEST_SRC_ROOT) + "/unit-data/verilog_sample/"}), + VerilogInfo::path_vec_t({std::string(ILANG_TEST_SRC_ROOT) + + "/unit-data/verilog_sample/range-array.v"}), + "m1"); + IS_ARRAY_RANGE_SIZE("r12", 8-1); + IS_ARRAY_RANGE_SIZE("r22", 8-1); + IS_ARRAY_RANGE_SIZE("r14", 9-1); + IS_ARRAY_RANGE_SIZE("r24", 7-1); + } +} + TEST(TestVerilogAnalysis, RangeAnalysis) { #define IS_WIDTH(n, w) EXPECT_EQ(va.get_signal("m1." n).get_width(), w) +#define NOT_ARRAY(n) EXPECT_EQ(va.get_signal("m1." n).get_addr_range_size(), 0) { // test 1 VerilogInfo va( @@ -97,22 +114,39 @@ TEST(TestVerilogAnalysis, RangeAnalysis) { IS_WIDTH("r2", 8); IS_WIDTH("r3", 8); IS_WIDTH("r4", 8); + NOT_ARRAY("r1"); + NOT_ARRAY("r2"); + NOT_ARRAY("r3"); + NOT_ARRAY("r4"); IS_WIDTH("r12", 8); IS_WIDTH("r22", 8); IS_WIDTH("r32", 8); IS_WIDTH("r42", 8); + NOT_ARRAY("r12"); + NOT_ARRAY("r22"); + NOT_ARRAY("r32"); + NOT_ARRAY("r42"); IS_WIDTH("r14", 9); IS_WIDTH("r24", 7); IS_WIDTH("r34", 8); IS_WIDTH("r44", 8); + NOT_ARRAY("r14"); + NOT_ARRAY("r24"); + NOT_ARRAY("r34"); + NOT_ARRAY("r44"); IS_WIDTH("rm", 2); IS_WIDTH("a", 1); // F IS_WIDTH("b", 1); // F IS_WIDTH("c", 2); // F IS_WIDTH("d", 1); // F + NOT_ARRAY("rm"); + NOT_ARRAY("a"); // F + NOT_ARRAY("b"); // F + NOT_ARRAY("c"); // F + NOT_ARRAY("d"); // F } // end of test1 { // test 2 VerilogInfo va( @@ -187,7 +221,7 @@ TEST(TestVerilogAnalysis, RangeAnalysisOverwriteWidth) { EXPECT_EQ(va.get_signal("m1.i1.sig").get_width(), 2); std::map width_overwrite_map({{"m1.i1.sig", 5}}); - EXPECT_EQ(va.get_signal("m1.i1.sig", width_overwrite_map).get_width(), 5); + EXPECT_EQ(va.get_signal("m1.i1.sig", width_overwrite_map, {}).get_width(), 5); { // no overwrite case VerilogInfo::module_io_vec_t top_io = va.get_top_module_io(); @@ -222,7 +256,7 @@ TEST(TestVerilogAnalysis, RangeAnalysisOverwriteWidth) { EXPECT_EQ(va.get_signal("m1.in1").get_width(), 4); std::map width_overwrite_map({{"m1.in1", 5}}); - EXPECT_EQ(va.get_signal("m1.in1", width_overwrite_map).get_width(), 5); + EXPECT_EQ(va.get_signal("m1.in1", width_overwrite_map, {}).get_width(), 5); { // no overwrite case VerilogInfo::module_io_vec_t top_io = va.get_top_module_io(); @@ -245,7 +279,7 @@ TEST(TestVerilogAnalysis, RangeAnalysisOverwriteWidth) { std::map width_overwrite_map3({{"m1.in2", 128}}); - EXPECT_EQ(va.get_signal("m1.in2", width_overwrite_map3).get_width(), 128); + EXPECT_EQ(va.get_signal("m1.in2", width_overwrite_map3, {}).get_width(), 128); { // overwrite case diff --git a/test/t_verilog_mod.cc b/test/t_verilog_mod.cc index 633dd3731..1bb4bcdf8 100644 --- a/test/t_verilog_mod.cc +++ b/test/t_verilog_mod.cc @@ -37,14 +37,16 @@ TEST(TestVerilogMod, Modify) { VerilogInfo va(VerilogInfo::path_vec_t(), VerilogInfo::path_vec_t({fn}), "m1"); - VerilogModifier vm(&va, VerilogModifier::port_decl_style_t::AUTO, true, {}); + std::map empty_annotation; + VerilogModifier vm(&va, VerilogModifier::port_decl_style_t::AUTO, + true, empty_annotation, empty_annotation); vm.RecordKeepSignalName("m1.__COUNTER_start__n3"); vm.RecordKeepSignalName("m1.__ILA_proc_decode_of_Add__"); vm.RecordKeepSignalName("m1.subm4.a"); - vm.RecordConnectSigName("m1.subm4.b"); - vm.RecordConnectSigName("m1.n27"); - vm.RecordConnectSigName("m1.ir"); + vm.RecordConnectSigName("m1__DOTz__subm4__DOTz__b", "m1.subm4","b",1); + vm.RecordConnectSigName("m1__DOTz__n27z","m1","n27",1); + vm.RecordConnectSigName("m1__DOT__orz_ir_0_","m1","ir[0]", 8); vm.RecordAdditionalVlgModuleStmt("wire abcd; assign abcd = 1'b1;", "m1"); vm.FinishRecording(); @@ -57,7 +59,7 @@ TEST(TestVerilogMod, Modify) { } if (!fout.is_open()) { - ILA_ERROR << ofn << " is not readable"; + ILA_ERROR << ofn << " is not write-able"; return; } @@ -65,6 +67,7 @@ TEST(TestVerilogMod, Modify) { fin.close(); fout.close(); + os_portable_remove_file(ofn); } diff --git a/test/t_vtarget_gen.cc b/test/t_vtarget_gen.cc index a0ed39d58..c966558fa 100644 --- a/test/t_vtarget_gen.cc +++ b/test/t_vtarget_gen.cc @@ -20,8 +20,7 @@ TEST(TestVlgTargetGen, PipeExample) { auto dirName = os_portable_append_dir(ILANG_TEST_DATA_DIR, "vpipe"); auto rfDir = os_portable_append_dir(dirName, "rfmap"); - auto vtg_config = VerilogVerificationTargetGenerator::vtg_config_t(); - vtg_config.CosaGenJgTesterScript = true; + auto vtg_config = RtlVerifyConfig(); VerilogVerificationTargetGenerator vg( {}, // no include @@ -31,196 +30,164 @@ TEST(TestVlgTargetGen, PipeExample) { os_portable_append_dir(rfDir, "cond.json"), // instruction-mapping os_portable_append_dir(dirName, "verify"), // verification dir ila_model.get(), // ILA model - VerilogVerificationTargetGenerator::backend_selector::COSA, // engine + ModelCheckerSelection::PONO, // engine vtg_config); EXPECT_FALSE(vg.in_bad_state()); - vg.GenerateTargets(); } -TEST(TestVlgTargetGen, PipeExampleZ3) { - auto ila_model = SimplePipe::BuildModel(); - - auto dirName = os_portable_append_dir(ILANG_TEST_DATA_DIR, "vpipe"); - auto rfDir = os_portable_append_dir(dirName, "rfmap"); - auto vtg_config = VerilogVerificationTargetGenerator::vtg_config_t(); - vtg_config.YosysPath = "N/A"; - vtg_config.Z3Path = "N/A"; - VerilogVerificationTargetGenerator vg( - {}, // no include - {os_portable_append_dir(dirName, "simple_pipe.v")}, // vlog files - "pipeline_v", // top_module_name - os_portable_append_dir(rfDir, "vmap.json"), // variable mapping - os_portable_append_dir(rfDir, "cond.json"), // instruction-mapping - os_portable_append_dir(dirName, "verify-z3"), // verification dir - ila_model.get(), // ILA model - VerilogVerificationTargetGenerator::backend_selector::Z3PDR, // engine - vtg_config); - - EXPECT_FALSE(vg.in_bad_state()); - - vg.GenerateTargets(); -} - -TEST(TestVlgTargetGen, PipeExampleGrain) { +TEST(TestVlgTargetGen, PipeExampleRfmapPost) { auto ila_model = SimplePipe::BuildModel(); + RtlVerifyConfig cfg; + cfg.CheckInstrCommitSatisfiable = true; + cfg.PonoGenJgScript = true; + auto dirName = os_portable_append_dir(ILANG_TEST_DATA_DIR, "vpipe"); auto rfDir = os_portable_append_dir(dirName, "rfmap"); - auto vtg_config = VerilogVerificationTargetGenerator::vtg_config_t(); - vtg_config.YosysPath = "N/A"; - vtg_config.GrainPath = "N/A"; - vtg_config.YosysSmtFlattenDatatype = true; - vtg_config.GrainHintsUseCnfStyle = true; - vtg_config.GrainOptions = { - "--skip-cnf --skip-const-check --skip-stat-collect --ante-size 1 " - "--conseq-size 1 --cnf cnt-no-group.cnf --use-arith-bvnot " - "--no-const-enum-vars-on m1.v,m1.imp"}; VerilogVerificationTargetGenerator vg( {}, // no include {os_portable_append_dir(dirName, "simple_pipe.v")}, // vlog files "pipeline_v", // top_module_name - os_portable_append_dir(rfDir, "vmap.json"), // variable mapping - os_portable_append_dir(rfDir, "cond.json"), // instruction-mapping - os_portable_append_dir(dirName, "verify-grain"), // verification dir + os_portable_append_dir(rfDir, + "vmap-rfmap-pvholder.json"), // variable mapping + os_portable_append_dir(rfDir, + "cond-rfmap-pvholder.json"), // instruction-mapping + os_portable_append_dir(dirName, "verify_pvholder"), // verification dir ila_model.get(), // ILA model - VerilogVerificationTargetGenerator::backend_selector:: - GRAIN_SYGUS, // engine - vtg_config); + ModelCheckerSelection::PONO, // engine + cfg + ); EXPECT_FALSE(vg.in_bad_state()); vg.GenerateTargets(); } -TEST(TestVlgTargetGen, PipeExampleGrainDeath) { - auto ila_model = SimplePipe::BuildModel(); - - auto dirName = os_portable_append_dir(ILANG_TEST_DATA_DIR, "vpipe"); - auto rfDir = os_portable_append_dir(dirName, "rfmap"); - auto vtg_config = VerilogVerificationTargetGenerator::vtg_config_t(); - vtg_config.YosysSmtFlattenDatatype = false; - vtg_config.YosysPath = "N/A"; - vtg_config.GrainPath = "N/A"; - vtg_config.Z3Path = "N/A"; - - VerilogVerificationTargetGenerator vg( - {}, // no include - {os_portable_append_dir(dirName, "simple_pipe.v")}, // vlog files - "pipeline_v", // top_module_name - os_portable_append_dir(rfDir, "vmap.json"), // variable mapping - os_portable_append_dir(rfDir, "cond.json"), // instruction-mapping - os_portable_append_dir(dirName, "verify-grain"), // verification dir - ila_model.get(), // ILA model - VerilogVerificationTargetGenerator::backend_selector:: - GRAIN_SYGUS, // engine - vtg_config); - - EXPECT_FALSE(vg.in_bad_state()); - - EXPECT_DEATH(vg.GenerateTargets(), ".*"); -} -TEST(TestVlgTargetGen, PipeExampleEldaricaDeath) { +TEST(TestVlgTargetGen, PipeExampleRfmapPostResetStart) { auto ila_model = SimplePipe::BuildModel(); + RtlVerifyConfig cfg; + cfg.PonoGenJgScript = true; + cfg.ForceInstCheckReset = true; + cfg.CheckInstrCommitSatisfiable = true; + cfg.PonoOtherOptions = " -v 1 "; auto dirName = os_portable_append_dir(ILANG_TEST_DATA_DIR, "vpipe"); auto rfDir = os_portable_append_dir(dirName, "rfmap"); - auto vtg_config = VerilogVerificationTargetGenerator::vtg_config_t(); - vtg_config.YosysPath = "N/A"; - vtg_config.GrainPath = "N/A"; - vtg_config.Z3Path = "N/A"; VerilogVerificationTargetGenerator vg( {}, // no include {os_portable_append_dir(dirName, "simple_pipe.v")}, // vlog files "pipeline_v", // top_module_name - os_portable_append_dir(rfDir, "vmap.json"), // variable mapping - os_portable_append_dir(rfDir, "cond.json"), // instruction-mapping - os_portable_append_dir(dirName, "verify-grain"), // verification dir + os_portable_append_dir(rfDir, + "vmap-rfmap-pvholder-reset.json"), // variable mapping + os_portable_append_dir(rfDir, + "cond-rfmap-pvholder-reset.json"), // instruction-mapping + os_portable_append_dir(dirName, "verify_pvholder_reset"), // verification dir ila_model.get(), // ILA model - VerilogVerificationTargetGenerator::backend_selector::ELD_CEGAR, // engine - vtg_config); + ModelCheckerSelection::PONO, // engine + cfg + ); EXPECT_FALSE(vg.in_bad_state()); - EXPECT_DEATH(vg.GenerateTargets(), ".*"); + vg.GenerateTargets(); } -TEST(TestVlgTargetGen, PipeExampleBtor) { - auto ila_model = SimplePipe::BuildModel(); +TEST(TestVlgTargetGen, PipeStallRfmapShortNoValueHolder) { + RtlVerifyConfig cfg; + cfg.PonoEngine = "bmc"; + cfg.PonoOtherOptions = " -k 5 -v 1 "; + + auto ila_model = SimplePipe::BuildStallModel(); auto dirName = os_portable_append_dir(ILANG_TEST_DATA_DIR, "vpipe"); auto rfDir = os_portable_append_dir(dirName, "rfmap"); - auto vtg_config = VerilogVerificationTargetGenerator::vtg_config_t(); - vtg_config.YosysPath = "N/A"; - vtg_config.GrainPath = "N/A"; - vtg_config.Z3Path = "N/A"; VerilogVerificationTargetGenerator vg( - {}, // no include - {os_portable_append_dir(dirName, "simple_pipe.v")}, // vlog files - "pipeline_v", // top_module_name - os_portable_append_dir(rfDir, "vmap.json"), // variable mapping - os_portable_append_dir(rfDir, "cond.json"), // instruction-mapping - os_portable_append_dir(dirName, "verify-btor"), // verification dir - ila_model.get(), // ILA model - VerilogVerificationTargetGenerator::backend_selector:: - BTOR_GENERIC, // engine - vtg_config); + {}, // no include + {os_portable_append_dir(dirName, + "simple_pipe_stall_short.v")}, // vlog files + "pipeline_v", // top_module_name + os_portable_append_dir(rfDir, + "vmap-rfmap-stall-short.json"), // variable mapping + os_portable_append_dir( + rfDir, + "cond-rfmap-stall-short.json"), // instruction-mapping + os_portable_append_dir( + dirName, "verify_stall_short_nopvholder"), // verification dir + ila_model.get(), // ILA model + ModelCheckerSelection::PONO, // engine + cfg + ); EXPECT_FALSE(vg.in_bad_state()); vg.GenerateTargets(); } -TEST(TestVlgTargetGen, PipeExampleAbc) { - auto ila_model = SimplePipe::BuildModel(); +// stall short has no instruction buffer +// it is 1 stage shorter than stall +TEST(TestVlgTargetGen, PipeStallRfmapShort) { + RtlVerifyConfig cfg; + cfg.PonoEngine = "bmc"; + cfg.PonoOtherOptions = " -k 5 -v 1 "; + + auto ila_model = SimplePipe::BuildStallModel(); auto dirName = os_portable_append_dir(ILANG_TEST_DATA_DIR, "vpipe"); auto rfDir = os_portable_append_dir(dirName, "rfmap"); - auto vtg_config = VerilogVerificationTargetGenerator::vtg_config_t(); - vtg_config.YosysPath = "N/A"; - vtg_config.GrainPath = "N/A"; - vtg_config.Z3Path = "N/A"; - vtg_config.AbcPath = "N/A"; VerilogVerificationTargetGenerator vg( - {}, // no include - {os_portable_append_dir(dirName, "simple_pipe.v")}, // vlog files - "pipeline_v", // top_module_name - os_portable_append_dir(rfDir, "vmap.json"), // variable mapping - os_portable_append_dir(rfDir, "cond.json"), // instruction-mapping - os_portable_append_dir(dirName, "verify-abc"), // verification dir - ila_model.get(), // ILA model - VerilogVerificationTargetGenerator::backend_selector::ABCPDR, // engine - vtg_config); + {}, // no include + {os_portable_append_dir(dirName, + "simple_pipe_stall_short.v")}, // vlog files + "pipeline_v", // top_module_name + os_portable_append_dir( + rfDir, + "vmap-rfmap-pvholder-stall-short.json"), // variable mapping + os_portable_append_dir( + rfDir, + "cond-rfmap-pvholder-stall-short.json"), // instruction-mapping + os_portable_append_dir(dirName, "verify_stall_short"), // verification dir + ila_model.get(), // ILA model + ModelCheckerSelection::PONO, // engine + cfg + ); EXPECT_FALSE(vg.in_bad_state()); vg.GenerateTargets(); } -TEST(TestVlgTargetGen, PipeExampleRfmapPost) { - auto ila_model = SimplePipe::BuildModel(); +TEST(TestVlgTargetGen, PipeStallRfmap) { + RtlVerifyConfig cfg; + cfg.PonoEngine = "bmc"; + cfg.PonoOtherOptions = " -k 5 -v 1 "; + + auto ila_model = SimplePipe::BuildStallModel(); auto dirName = os_portable_append_dir(ILANG_TEST_DATA_DIR, "vpipe"); auto rfDir = os_portable_append_dir(dirName, "rfmap"); VerilogVerificationTargetGenerator vg( - {}, // no include - {os_portable_append_dir(dirName, "simple_pipe.v")}, // vlog files - "pipeline_v", // top_module_name - os_portable_append_dir(rfDir, - "vmap-rfmap-pvholder.json"), // variable mapping - os_portable_append_dir(rfDir, - "cond-rfmap-pvholder.json"), // instruction-mapping - os_portable_append_dir(dirName, "verify_pvholder"), // verification dir - ila_model.get(), // ILA model - VerilogVerificationTargetGenerator::backend_selector::COSA // engine + {}, // no include + {os_portable_append_dir(dirName, "simple_pipe_stall.v")}, // vlog files + "pipeline_v", // top_module_name + os_portable_append_dir( + rfDir, + "vmap-rfmap-pvholder-stall.json"), // variable mapping + os_portable_append_dir( + rfDir, + "cond-rfmap-pvholder-stall.json"), // instruction-mapping + os_portable_append_dir(dirName, "verify_stall"), // verification dir + ila_model.get(), // ILA model + ModelCheckerSelection::PONO, // engine + cfg ); EXPECT_FALSE(vg.in_bad_state()); @@ -244,7 +211,7 @@ TEST(TestVlgTargetGen, PipeExampleJasperGold) { P({"rfmap", "vmap.json"})), // variable mapping os_portable_append_dir(dirName, P({"rfmap", "cond.json"})), os_portable_append_dir(dirName, "verify_jg/"), ila_model.get(), - VerilogVerificationTargetGenerator::backend_selector::JASPERGOLD); + ModelCheckerSelection::JASPERGOLD); EXPECT_FALSE(vg.in_bad_state()); @@ -264,13 +231,40 @@ TEST(TestVlgTargetGen, PipeExampleNotEqu) { P({"rfmap", "vmap.json"})), // variable mapping os_portable_append_dir(dirName, P({"rfmap", "cond.json"})), os_portable_append_dir(dirName, "disprove/"), ila_model.get(), - VerilogVerificationTargetGenerator::backend_selector::COSA); + ModelCheckerSelection::PONO); + + EXPECT_FALSE(vg.in_bad_state()); + + vg.GenerateTargets(); +} + + +TEST(TestVlgTargetGen, PipeExampleNotEquFromReset) { + auto ila_model = SimplePipe::BuildModel(); + RtlVerifyConfig cfg; + cfg.ForceInstCheckReset = true; + cfg.PonoGenJgScript = true; + + auto dirName = + os_portable_join_dir({ILANG_TEST_SRC_ROOT, "unit-data", "vpipe"}); + VerilogVerificationTargetGenerator vg( + {}, // no include + {os_portable_append_dir(dirName, "simple_pipe_wrong.v")}, // + "pipeline_v", // top_module_name + os_portable_append_dir(dirName, + P({"rfmap", "vmap.json"})), // variable mapping + os_portable_append_dir(dirName, P({"rfmap", "cond.json"})), + os_portable_append_dir(dirName, "disprove-reset/"), ila_model.get(), + ModelCheckerSelection::PONO, + cfg); EXPECT_FALSE(vg.in_bad_state()); vg.GenerateTargets(); } +// #warning "Continue your test from here" + TEST(TestVlgTargetGen, Memory) { auto ila_model = MemorySwap::BuildModel(); @@ -284,7 +278,7 @@ TEST(TestVlgTargetGen, Memory) { os_portable_append_dir(dirName, P({"cond.json"})), dirName, // output path ila_model.get(), - VerilogVerificationTargetGenerator::backend_selector::COSA); + ModelCheckerSelection::PONO); EXPECT_FALSE(vg.in_bad_state()); @@ -295,8 +289,7 @@ TEST(TestVlgTargetGen, MemoryInternal) { // test the expansion of memory auto ila_model = MemorySwap::BuildSimpleSwapModel(); - VerilogVerificationTargetGenerator::vtg_config_t - vtg_cfg; // default configuration + RtlVerifyConfig vtg_cfg; // default configuration VerilogGeneratorBase::VlgGenConfig vlg_cfg; vlg_cfg.extMem = false; auto dirName = @@ -309,7 +302,7 @@ TEST(TestVlgTargetGen, MemoryInternal) { // test the expansion of memory os_portable_append_dir(dirName, "cond-expand.json"), dirName, // output path ila_model.get(), - VerilogVerificationTargetGenerator::backend_selector::COSA, vtg_cfg, + ModelCheckerSelection::PONO, vtg_cfg, vlg_cfg); EXPECT_FALSE(vg.in_bad_state()); @@ -331,7 +324,7 @@ TEST(TestVlgTargetGen, MemoryInternalExternal) { os_portable_append_dir(dirName, "cond-rfarray.json"), dirName, // output path ila_model.get(), - VerilogVerificationTargetGenerator::backend_selector::COSA); + ModelCheckerSelection::PONO); EXPECT_FALSE(vg.in_bad_state()); @@ -340,19 +333,28 @@ TEST(TestVlgTargetGen, MemoryInternalExternal) { TEST(TestVlgTargetGen, MemoryInternalExternalEntry6) { auto ila_model = MemorySwap::BuildRfAsMemModelRegEntry6(); - VlgVerifTgtGenBase::vtg_config_t vtg_cfg; - vtg_cfg.CosaAddKeep = false; + + // DebugLog::Enable("VTG.ReplWireEq"); + // DebugLog::Enable("VTG.ReplAssert"); + // DebugLog::Enable("VTG.ReplAssume"); + + // DebugLog::Enable("VTG.AddWireEq"); + // DebugLog::Enable("VTG.AddAssert"); + // DebugLog::Enable("VTG.AddAssume"); + + RtlVerifyConfig vtg_cfg; + vtg_cfg.PonoAddKeep = false; auto dirName = std::string(ILANG_TEST_SRC_ROOT) + "/unit-data/vpipe/vmem/"; VerilogVerificationTargetGenerator vg( - {}, // no include - {dirName + "rf_as_mem_6rf.v"}, // vlog files - "proc", // top_module_name - dirName + "vmap-rfarray.json", // variable mapping - dirName + "cond-rfarray.json", // cond path - dirName + "rfarray_rf6/", // output path + {}, // no include + {dirName + "rf_as_mem_6rf.v"}, // vlog files + "proc", // top_module_name + dirName + "vmap-rfarray6.json", // variable mapping + dirName + "cond-rfarray.json", // cond path + dirName + "rfarray_rf6/", // output path ila_model.get(), - VerilogVerificationTargetGenerator::backend_selector::COSA, vtg_cfg); + ModelCheckerSelection::PONO, vtg_cfg); EXPECT_FALSE(vg.in_bad_state()); @@ -371,76 +373,74 @@ TEST(TestVlgTargetGen, MemoryRead) { dirName + "cond-rd.json", // cond path dirName, // output path ila_model.get(), - VerilogVerificationTargetGenerator::backend_selector::COSA); + ModelCheckerSelection::PONO); EXPECT_FALSE(vg.in_bad_state()); vg.GenerateTargets(); } -TEST(TestVlgTargetGen, MemoryAbsRead) { - VerilogVerificationTargetGenerator::vtg_config_t vtg_cfg; - - vtg_cfg.MemAbsReadAbstraction = true; // enable read abstraction +TEST(TestVlgTargetGen, MemoryReadAbsReadJasperGold) { + RtlVerifyConfig vtg_cfg; - auto ila_model = MemorySwap::BuildModel(); + auto ila_model = MemorySwap::BuildRdModel(); auto dirName = std::string(ILANG_TEST_SRC_ROOT) + "/unit-data/vpipe/vmem/"; VerilogVerificationTargetGenerator vg( - {}, // no include - {dirName + "swap.v"}, // vlog files - "swap", // top_module_name - dirName + "vmap.json", // variable mapping - dirName + "cond.json", // cond path - dirName + "rdabs/", // output path + {}, // no include + {dirName + "read.v"}, // vlog files + "rdtop", // top_module_name + dirName + "vmap-rd.json", // variable mapping + dirName + "cond-rd.json", // cond path + dirName + "rdabs_jg/", // output path ila_model.get(), - VerilogVerificationTargetGenerator::backend_selector::COSA, vtg_cfg); + ModelCheckerSelection::JASPERGOLD, + vtg_cfg); EXPECT_FALSE(vg.in_bad_state()); vg.GenerateTargets(); } -TEST(TestVlgTargetGen, MemoryReadAbsRead) { - VerilogVerificationTargetGenerator::vtg_config_t vtg_cfg; - vtg_cfg.MemAbsReadAbstraction = true; // enable read abstraction +TEST(TestVlgTargetGen, MemoryForallEqualPono) { + RtlVerifyConfig vtg_cfg; - auto ila_model = MemorySwap::BuildRdModel(); + auto ila_model = MemorySwap::BuildSimpleLargeArray(); auto dirName = std::string(ILANG_TEST_SRC_ROOT) + "/unit-data/vpipe/vmem/"; VerilogVerificationTargetGenerator vg( {}, // no include - {dirName + "read.v"}, // vlog files - "rdtop", // top_module_name - dirName + "vmap-rd.json", // variable mapping - dirName + "cond-rd.json", // cond path - dirName + "rdabs/", // output path + {dirName + "smallarray.v"}, // vlog files + "top", // top_module_name + dirName + "vmap-forall.json", // variable mapping + dirName + "cond-forall.json", // cond path + dirName + "large_small_forall/", // output path ila_model.get(), - VerilogVerificationTargetGenerator::backend_selector::COSA, vtg_cfg); + ModelCheckerSelection::PONO, + vtg_cfg); EXPECT_FALSE(vg.in_bad_state()); vg.GenerateTargets(); } -TEST(TestVlgTargetGen, MemoryReadAbsReadJasperGold) { - VerilogVerificationTargetGenerator::vtg_config_t vtg_cfg; - vtg_cfg.MemAbsReadAbstraction = true; // enable read abstraction +TEST(TestVlgTargetGen, MemoryForallEqualJg) { + RtlVerifyConfig vtg_cfg; - auto ila_model = MemorySwap::BuildRdModel(); + auto ila_model = MemorySwap::BuildSimpleLargeArray(); auto dirName = std::string(ILANG_TEST_SRC_ROOT) + "/unit-data/vpipe/vmem/"; VerilogVerificationTargetGenerator vg( {}, // no include - {dirName + "read.v"}, // vlog files - "rdtop", // top_module_name - dirName + "vmap-rd.json", // variable mapping - dirName + "cond-rd.json", // cond path - dirName + "rdabs_jg/", // output path + {dirName + "smallarray.v"}, // vlog files + "top", // top_module_name + dirName + "vmap-forall.json", // variable mapping + dirName + "cond-forall.json", // cond path + dirName + "large_small_forall_jg/", // output path ila_model.get(), - VerilogVerificationTargetGenerator::backend_selector::JASPERGOLD, + ModelCheckerSelection::JASPERGOLD, vtg_cfg); EXPECT_FALSE(vg.in_bad_state()); @@ -448,6 +448,7 @@ TEST(TestVlgTargetGen, MemoryReadAbsReadJasperGold) { vg.GenerateTargets(); } + TEST(TestVlgTargetGen, UndetValue) { auto ila_model = UndetVal::BuildModel(); @@ -460,7 +461,7 @@ TEST(TestVlgTargetGen, UndetValue) { dirName + "cond-val.json", // cond path dirName, // output path ila_model.get(), - VerilogVerificationTargetGenerator::backend_selector::COSA); + ModelCheckerSelection::PONO); EXPECT_FALSE(vg.in_bad_state()); @@ -479,28 +480,7 @@ TEST(TestVlgTargetGen, UndetFunc) { dirName + "cond-func.json", // cond path dirName, // output path ila_model.get(), - VerilogVerificationTargetGenerator::backend_selector::COSA); - - EXPECT_FALSE(vg.in_bad_state()); - - vg.GenerateTargets(); -} - -TEST(TestVlgTargetGen, UndetFuncIteUnknown) { - auto ila_model = UndetFunc::BuildIteUknModel(); - auto vtg_cfg = VerilogVerificationTargetGenerator::vtg_config_t(); - vtg_cfg.IteUnknownAutoIgnore = true; - - auto dirName = std::string(ILANG_TEST_SRC_ROOT) + "/unit-data/vpipe/undetf2/"; - VerilogVerificationTargetGenerator vg( - {}, // no include - {dirName + "func.v"}, // vlog files - "undetfunc", // top_module_name - dirName + "vmap-func.json", // variable mapping - dirName + "cond-func.json", // cond path - dirName, // output path - ila_model.get(), - VerilogVerificationTargetGenerator::backend_selector::COSA, vtg_cfg); + ModelCheckerSelection::PONO); EXPECT_FALSE(vg.in_bad_state()); @@ -523,70 +503,7 @@ TEST(TestVlgTargetGen, ResetAnnotation) { os_portable_join_dir({dirName, "rfmap", "cond.json"}), // cond path os_portable_append_dir(dirName, "out"), // output path ila_model.get(), - VerilogVerificationTargetGenerator::backend_selector::COSA); - - EXPECT_FALSE(vg.in_bad_state()); - - vg.GenerateTargets(); - } - { - auto ila_model = MemorySwap::BuildResetterTest(); - auto dirName = os_portable_join_dir( - {ILANG_TEST_SRC_ROOT, "unit-data", "vpipe", "reset"}); - - VerilogVerificationTargetGenerator vg( - {}, // no include - {os_portable_join_dir( - {dirName, "verilog", "resetter.v"})}, // vlog files - "resetter", // top_module_name - os_portable_join_dir( - {dirName, "rfmap", "vmap-e2.json"}), // variable mapping - os_portable_join_dir({dirName, "rfmap", "cond.json"}), // cond path - os_portable_append_dir(dirName, "out"), // output path - ila_model.get(), - VerilogVerificationTargetGenerator::backend_selector::COSA); - - EXPECT_FALSE(vg.in_bad_state()); - - vg.GenerateTargets(); - } - { - auto ila_model = MemorySwap::BuildResetterTest(); - auto dirName = os_portable_join_dir( - {ILANG_TEST_SRC_ROOT, "unit-data", "vpipe", "reset"}); - - VerilogVerificationTargetGenerator vg( - {}, // no include - {os_portable_join_dir( - {dirName, "verilog", "resetter.v"})}, // vlog files - "resetter", // top_module_name - os_portable_join_dir( - {dirName, "rfmap", "vmap-e3.json"}), // variable mapping - os_portable_join_dir({dirName, "rfmap", "cond.json"}), // cond path - os_portable_append_dir(dirName, "out"), // output path - ila_model.get(), - VerilogVerificationTargetGenerator::backend_selector::COSA); - - EXPECT_FALSE(vg.in_bad_state()); - - vg.GenerateTargets(); - } - { - auto ila_model = MemorySwap::BuildResetterTest(); - auto dirName = os_portable_join_dir( - {ILANG_TEST_SRC_ROOT, "unit-data", "vpipe", "reset"}); - - VerilogVerificationTargetGenerator vg( - {}, // no include - {os_portable_join_dir( - {dirName, "verilog", "resetter.v"})}, // vlog files - "resetter", // top_module_name - os_portable_join_dir( - {dirName, "rfmap", "vmap-e4.json"}), // variable mapping - os_portable_join_dir({dirName, "rfmap", "cond.json"}), // cond path - os_portable_append_dir(dirName, "out"), // output path - ila_model.get(), - VerilogVerificationTargetGenerator::backend_selector::COSA); + ModelCheckerSelection::PONO); EXPECT_FALSE(vg.in_bad_state()); @@ -605,9 +522,9 @@ TEST(TestVlgTargetGen, ResetAnnotation) { os_portable_join_dir( {dirName, "rfmap", "vmap.json"}), // variable mapping os_portable_join_dir({dirName, "rfmap", "cond.json"}), // cond path - os_portable_append_dir(dirName, "out"), // output path + os_portable_append_dir(dirName, "out2"), // output path ila_model.get(), - VerilogVerificationTargetGenerator::backend_selector::COSA); + ModelCheckerSelection::PONO); EXPECT_FALSE(vg.in_bad_state()); @@ -615,58 +532,4 @@ TEST(TestVlgTargetGen, ResetAnnotation) { } } -TEST(TestVlgTargetGen, ResetAnnotationZ3) { - auto ila_model = MemorySwap::BuildResetterTest(); - auto dirName = os_portable_join_dir( - {ILANG_TEST_SRC_ROOT, "unit-data", "vpipe", "reset"}); - - auto vtg_config = VerilogVerificationTargetGenerator::vtg_config_t(); - vtg_config.YosysPath = "N/A"; - vtg_config.GrainPath = "N/A"; - vtg_config.Z3Path = "N/A"; - vtg_config.AbcPath = "N/A"; - - VerilogVerificationTargetGenerator vg( - {}, // no include - {os_portable_join_dir({dirName, "verilog", "resetter.v"})}, // vlog files - "resetter", // top_module_name - os_portable_join_dir({dirName, "rfmap", "vmap.json"}), // variable mapping - os_portable_join_dir({dirName, "rfmap", "cond.json"}), // cond path - os_portable_append_dir(dirName, "out-z3"), // output path - ila_model.get(), - VerilogVerificationTargetGenerator::backend_selector::Z3PDR, vtg_config); - - EXPECT_FALSE(vg.in_bad_state()); - - vg.GenerateTargets(); -} - -TEST(TestVlgTargetGen, ResetAnnotationABC) { - auto ila_model = MemorySwap::BuildResetterTest(); - auto dirName = os_portable_join_dir( - {ILANG_TEST_SRC_ROOT, "unit-data", "vpipe", "reset"}); - - auto vtg_config = VerilogVerificationTargetGenerator::vtg_config_t(); - vtg_config.YosysPath = "N/A"; - vtg_config.GrainPath = "N/A"; - vtg_config.Z3Path = "N/A"; - vtg_config.AbcPath = "N/A"; - - VerilogVerificationTargetGenerator vg( - {}, // no include - {os_portable_join_dir({dirName, "verilog", "resetter.v"})}, // vlog files - "resetter", // top_module_name - os_portable_join_dir({dirName, "rfmap", "vmap.json"}), // variable mapping - os_portable_join_dir({dirName, "rfmap", "cond.json"}), // cond path - os_portable_append_dir(dirName, "out-abc"), // output path - ila_model.get(), - VerilogVerificationTargetGenerator::backend_selector::ABCPDR, vtg_config); - - EXPECT_FALSE(vg.in_bad_state()); - - vg.GenerateTargets(); -} - -TEST(TestVlgTargetGen, AesExample) {} - }; // namespace ilang diff --git a/test/unit-data/verilog_sample/range-array.v b/test/unit-data/verilog_sample/range-array.v new file mode 100644 index 000000000..8416b8144 --- /dev/null +++ b/test/unit-data/verilog_sample/range-array.v @@ -0,0 +1,25 @@ + +module range( clk, rst, r1, r2); + +`include "rangeheader2.v" + +input clk; +input rst; +output [`R1:0] r1; +output [`R2-1:0] r2; + +wire [`R3:0] r3; +wire [`R4] r4; + +reg [`R12:0] r12 [`R12-1:0]; +reg [`R22-1:0] r22 [`R22-2:0]; +wire [`R32:0] r32; +wire [`R42] r42; + +reg [`R14:0] r14 [`R14-1:0]; +reg [`R24-1:0] r24 [`R24-2:0]; +wire [`R34:0] r34; +wire [`R44] r44; + + +endmodule diff --git a/test/unit-data/vpipe/.gitignore b/test/unit-data/vpipe/.gitignore index 6e701d8f2..94d1d5813 100644 --- a/test/unit-data/vpipe/.gitignore +++ b/test/unit-data/vpipe/.gitignore @@ -3,7 +3,9 @@ verify/* verify_jg/* verify_pvholder/* +verify_pvholder_reset/* disprove/* +disprove-reset/* vmem/invariants vmem/SWAP vmem/SWAPExpand diff --git a/test/unit-data/vpipe/autoRunAll.py b/test/unit-data/vpipe/autoRunAll.py new file mode 100755 index 000000000..71415a82d --- /dev/null +++ b/test/unit-data/vpipe/autoRunAll.py @@ -0,0 +1,83 @@ +#!/usr/bin/env python +import os + +rootDir = '.' +allTaskInfo = {} # 'path -> result' + +ignored_subdir = set() + +cmd = "bash run.sh" + + +# --------------------- HELPER --------------------- ## +def ExecOnPath(p): + if not os.path.exists(p): + print 'Path:',p,'does not exist' + return + if not os.path.exists(os.path.join(p,'run.sh')): + # ignored + ignored_subdir.add(p) + return + if not os.path.exists(os.path.join(p,'gen_btor.ys')): + # ignored + allTaskInfo[p] = "skip" + return + + curDir = os.getcwd() + os.chdir(p) + print 'cd',p + finalCmd = cmd + print 'exec:',finalCmd + + os.system("rm -f *.btor *.btor2") + ret = os.system(finalCmd) + if ret == 256: + ret = 1 + elif ret == 65280: + ret = 255 + elif ret == 512: + ret = 2 + + os.chdir(curDir) + allTaskInfo[p] = ret + +# --------------------- MAIN --------------------- ## + +for dirName, subdirList, fileList in os.walk(rootDir): + for subDirName in subdirList: + ExecOnPath(os.path.join(dirName, subDirName)) + +print +print '----------- PASSED ------------' +for t,r in allTaskInfo.items(): + if r == 1: + print t + +print +print '----------- UNKNOWN ------------' +for t,r in allTaskInfo.items(): + if r == 255: + print t + +print +print '----------- FAILED ------------' +for t,r in allTaskInfo.items(): + if r == 0: + print t + +print +print '----------- SKIPPED ------------' +for t,r in allTaskInfo.items(): + if r == "skip": + print t + +print +print '----------- No Valid run.sh ------------' +print ignored_subdir + +print +print '----------- STATUS-ERR ------------' +for t,r in allTaskInfo.items(): + if r not in [0,1,255,"skip"]: + print r,':',t + diff --git a/test/unit-data/vpipe/disprove-reset/.placeholder b/test/unit-data/vpipe/disprove-reset/.placeholder new file mode 100644 index 000000000..e69de29bb diff --git a/test/unit-data/vpipe/reset/out-z3/inst/__design_smt.smt2 b/test/unit-data/vpipe/reset/out-z3/inst/__design_smt.smt2 deleted file mode 100644 index 222f73170..000000000 --- a/test/unit-data/vpipe/reset/out-z3/inst/__design_smt.smt2 +++ /dev/null @@ -1,175 +0,0 @@ -; SMT-LIBv2 description generated by Yosys 0.8+598 (git sha1 becd98cc, gcc 7.4.0-1ubuntu1~18.04.1 -fPIC -Os) -; yosys-smt2-stdt -; yosys-smt2-module wrapper -(declare-datatype |wrapper_s| ((|wrapper_mk| - (|wrapper_is| Bool) - (|wrapper#0| (_ BitVec 1)) ; \__2ndENDED__ - (|wrapper#1| (_ BitVec 4)) ; \__CYCLE_CNT__ - (|wrapper#3| (_ BitVec 1)) ; \__STARTED__ - (|wrapper#5| (_ BitVec 1)) ; \__ENDED__ - (|wrapper#8| (_ BitVec 1)) ; \m0.v - (|wrapper#9| (_ BitVec 1)) ; \__START__ - (|wrapper#11| (_ BitVec 1)) ; \m1.v1 - (|wrapper#12| (_ BitVec 1)) ; \m1.v2 - (|wrapper#18| (_ BitVec 1)) ; \dummy_reset - (|wrapper#22| Bool) ; \clk - (|wrapper#23| Bool) ; \m0.v_randinit - (|wrapper#24| Bool) ; \rst -))) -; yosys-smt2-output __2ndENDED__ 1 -; yosys-smt2-register __2ndENDED__ 1 -(define-fun |wrapper_n __2ndENDED__| ((state |wrapper_s|)) Bool (= ((_ extract 0 0) (|wrapper#0| state)) #b1)) -; yosys-smt2-output __CYCLE_CNT__ 4 -; yosys-smt2-register __CYCLE_CNT__ 4 -(define-fun |wrapper_n __CYCLE_CNT__| ((state |wrapper_s|)) (_ BitVec 4) (|wrapper#1| state)) -; yosys-smt2-wire __EDCOND__ 1 -(define-fun |wrapper#2| ((state |wrapper_s|)) Bool (= (|wrapper#1| state) #b0001)) ; $eq$/home/hongce/ila/ila-stable/test/unit-data/vpipe/reset/out-z3/inst/wrapper.v:112$27_Y -(define-fun |wrapper#4| ((state |wrapper_s|)) Bool (and (or (|wrapper#2| state) false) (or (= ((_ extract 0 0) (|wrapper#3| state)) #b1) false))) ; \__EDCOND__ -(define-fun |wrapper_n __EDCOND__| ((state |wrapper_s|)) Bool (|wrapper#4| state)) -; yosys-smt2-output __ENDED__ 1 -; yosys-smt2-register __ENDED__ 1 -(define-fun |wrapper_n __ENDED__| ((state |wrapper_s|)) Bool (= ((_ extract 0 0) (|wrapper#5| state)) #b1)) -; yosys-smt2-wire __IEND__ 1 -(define-fun |wrapper#6| ((state |wrapper_s|)) (_ BitVec 1) (bvnot (|wrapper#5| state))) ; $not$/home/hongce/ila/ila-stable/test/unit-data/vpipe/reset/out-z3/inst/wrapper.v:113$34_Y -(define-fun |wrapper#7| ((state |wrapper_s|)) Bool (and (or (|wrapper#4| state) false) (or (= ((_ extract 0 0) (|wrapper#6| state)) #b1) false))) ; \__IEND__ -(define-fun |wrapper_n __IEND__| ((state |wrapper_s|)) Bool (|wrapper#7| state)) -; yosys-smt2-output __ILA_SO_v 1 -; yosys-smt2-wire __ILA_SO_v 1 -(define-fun |wrapper_n __ILA_SO_v| ((state |wrapper_s|)) Bool (= ((_ extract 0 0) (|wrapper#8| state)) #b1)) -; yosys-smt2-wire __ILA_proc_decode_of_inst__ 1 -(define-fun |wrapper_n __ILA_proc_decode_of_inst__| ((state |wrapper_s|)) Bool true) -; yosys-smt2-wire __ILA_proc_valid__ 1 -(define-fun |wrapper_n __ILA_proc_valid__| ((state |wrapper_s|)) Bool true) -; yosys-smt2-wire __ISSUE__ 1 -(define-fun |wrapper_n __ISSUE__| ((state |wrapper_s|)) Bool true) -; yosys-smt2-output __RESETED__ 1 -(define-fun |wrapper_n __RESETED__| ((state |wrapper_s|)) Bool true) -; yosys-smt2-output __STARTED__ 1 -; yosys-smt2-register __STARTED__ 1 -(define-fun |wrapper_n __STARTED__| ((state |wrapper_s|)) Bool (= ((_ extract 0 0) (|wrapper#3| state)) #b1)) -; yosys-smt2-output __START__ 1 -; yosys-smt2-register __START__ 1 -(define-fun |wrapper_n __START__| ((state |wrapper_s|)) Bool (= ((_ extract 0 0) (|wrapper#9| state)) #b1)) -; yosys-smt2-output __all_assert_wire__ 1 -; yosys-smt2-wire __all_assert_wire__ 1 -(define-fun |wrapper#10| ((state |wrapper_s|)) (_ BitVec 1) (bvnot (ite (|wrapper#7| state) #b1 #b0))) ; $not$/home/hongce/ila/ila-stable/test/unit-data/vpipe/reset/out-z3/inst/wrapper.v:110$23_Y -(define-fun |wrapper#13| ((state |wrapper_s|)) (_ BitVec 1) (bvxor (|wrapper#11| state) (|wrapper#12| state))) ; \m1__DOT__v -(define-fun |wrapper#14| ((state |wrapper_s|)) Bool (= (|wrapper#13| state) (|wrapper#8| state))) ; \__m3__ -(define-fun |wrapper#15| ((state |wrapper_s|)) Bool (or (= ((_ extract 0 0) (|wrapper#10| state)) #b1) false (|wrapper#14| state) false)) ; \__all_assert_wire__ -(define-fun |wrapper_n __all_assert_wire__| ((state |wrapper_s|)) Bool (|wrapper#15| state)) -; yosys-smt2-output __all_assume_wire__ 1 -; yosys-smt2-wire __all_assume_wire__ 1 -(define-fun |wrapper#16| ((state |wrapper_s|)) (_ BitVec 1) (bvnot (|wrapper#12| state))) ; $not$/home/hongce/ila/ila-stable/test/unit-data/vpipe/reset/out-z3/inst/wrapper.v:111$25_Y -(define-fun |wrapper#17| ((state |wrapper_s|)) Bool (= (|wrapper#11| state) (|wrapper#16| state))) ; \invariant_assume__m5__ -(define-fun |wrapper#19| ((state |wrapper_s|)) (_ BitVec 1) (bvnot (|wrapper#18| state))) ; \noreset__m0__ -(define-fun |wrapper#20| ((state |wrapper_s|)) Bool (and (or (|wrapper#17| state) false) (or (= ((_ extract 0 0) (|wrapper#19| state)) #b1) false))) ; $logic_and$/home/hongce/ila/ila-stable/test/unit-data/vpipe/reset/out-z3/inst/wrapper.v:136$42_Y -(define-fun |wrapper#21| ((state |wrapper_s|)) Bool (and (or (|wrapper#20| state) false) (or (|wrapper#14| state) false))) ; \__all_assume_wire__ -(define-fun |wrapper_n __all_assume_wire__| ((state |wrapper_s|)) Bool (|wrapper#21| state)) -; yosys-smt2-output __m1__ 1 -; yosys-smt2-wire __m1__ 1 -(define-fun |wrapper_n __m1__| ((state |wrapper_s|)) Bool (|wrapper#14| state)) -; yosys-smt2-output __m3__ 1 -; yosys-smt2-wire __m3__ 1 -(define-fun |wrapper_n __m3__| ((state |wrapper_s|)) Bool (|wrapper#14| state)) -; yosys-smt2-input clk 1 -; yosys-smt2-clock clk posedge -(define-fun |wrapper_n clk| ((state |wrapper_s|)) Bool (|wrapper#22| state)) -; yosys-smt2-input dummy_reset 1 -; yosys-smt2-wire dummy_reset 1 -(define-fun |wrapper_n dummy_reset| ((state |wrapper_s|)) Bool (= ((_ extract 0 0) (|wrapper#18| state)) #b1)) -; yosys-smt2-output invariant_assume__m5__ 1 -; yosys-smt2-wire invariant_assume__m5__ 1 -(define-fun |wrapper_n invariant_assume__m5__| ((state |wrapper_s|)) Bool (|wrapper#17| state)) -; yosys-smt2-output issue_decode__m6__ 1 -; yosys-smt2-wire issue_decode__m6__ 1 -(define-fun |wrapper_n issue_decode__m6__| ((state |wrapper_s|)) Bool true) -; yosys-smt2-output issue_valid__m7__ 1 -; yosys-smt2-wire issue_valid__m7__ 1 -(define-fun |wrapper_n issue_valid__m7__| ((state |wrapper_s|)) Bool true) -; yosys-smt2-register m0.v 1 -(define-fun |wrapper_n m0.v| ((state |wrapper_s|)) Bool (= ((_ extract 0 0) (|wrapper#8| state)) #b1)) -; yosys-smt2-input m0.v_randinit 1 -; yosys-smt2-wire m0.v_randinit 1 -(define-fun |wrapper_n m0.v_randinit| ((state |wrapper_s|)) Bool (|wrapper#23| state)) -; yosys-smt2-wire m1.v 1 -(define-fun |wrapper_n m1.v| ((state |wrapper_s|)) Bool (= ((_ extract 0 0) (|wrapper#13| state)) #b1)) -; yosys-smt2-register m1.v1 1 -; yosys-smt2-wire m1.v1 1 -(define-fun |wrapper_n m1.v1| ((state |wrapper_s|)) Bool (= ((_ extract 0 0) (|wrapper#11| state)) #b1)) -; yosys-smt2-register m1.v2 1 -; yosys-smt2-wire m1.v2 1 -(define-fun |wrapper_n m1.v2| ((state |wrapper_s|)) Bool (= ((_ extract 0 0) (|wrapper#12| state)) #b1)) -; yosys-smt2-output m1__DOT__v 1 -; yosys-smt2-wire m1__DOT__v 1 -(define-fun |wrapper_n m1__DOT__v| ((state |wrapper_s|)) Bool (= ((_ extract 0 0) (|wrapper#13| state)) #b1)) -; yosys-smt2-output m1__DOT__v1 1 -; yosys-smt2-wire m1__DOT__v1 1 -(define-fun |wrapper_n m1__DOT__v1| ((state |wrapper_s|)) Bool (= ((_ extract 0 0) (|wrapper#11| state)) #b1)) -; yosys-smt2-output m1__DOT__v2 1 -; yosys-smt2-wire m1__DOT__v2 1 -(define-fun |wrapper_n m1__DOT__v2| ((state |wrapper_s|)) Bool (= ((_ extract 0 0) (|wrapper#12| state)) #b1)) -; yosys-smt2-output noreset__m0__ 1 -; yosys-smt2-wire noreset__m0__ 1 -(define-fun |wrapper_n noreset__m0__| ((state |wrapper_s|)) Bool (= ((_ extract 0 0) (|wrapper#19| state)) #b1)) -; yosys-smt2-input rst 1 -(define-fun |wrapper_n rst| ((state |wrapper_s|)) Bool (|wrapper#24| state)) -; yosys-smt2-output v 1 -; yosys-smt2-wire v 1 -(define-fun |wrapper_n v| ((state |wrapper_s|)) Bool (= ((_ extract 0 0) (|wrapper#13| state)) #b1)) -; yosys-smt2-output variable_map_assert__p4__ 1 -; yosys-smt2-wire variable_map_assert__p4__ 1 -(define-fun |wrapper_n variable_map_assert__p4__| ((state |wrapper_s|)) Bool (|wrapper#15| state)) -; yosys-smt2-output variable_map_assume___m2__ 1 -; yosys-smt2-wire variable_map_assume___m2__ 1 -(define-fun |wrapper_n variable_map_assume___m2__| ((state |wrapper_s|)) Bool (|wrapper#14| state)) -; yosys-smt2-assert 0 /home/hongce/ila/ila-stable/test/unit-data/vpipe/reset/out-z3/inst/wrapper.v:137 -(define-fun |wrapper_a 0| ((state |wrapper_s|)) Bool (or (|wrapper#15| state) (not true))) ; $assert$/home/hongce/ila/ila-stable/test/unit-data/vpipe/reset/out-z3/inst/wrapper.v:137$44 -; yosys-smt2-assume 0 /home/hongce/ila/ila-stable/test/unit-data/vpipe/reset/out-z3/inst/wrapper.v:139 -(define-fun |wrapper_u 0| ((state |wrapper_s|)) Bool (or (|wrapper#21| state) (not true))) ; $assume$/home/hongce/ila/ila-stable/test/unit-data/vpipe/reset/out-z3/inst/wrapper.v:139$45 -(define-fun |wrapper#25| ((state |wrapper_s|)) Bool (not (or (= ((_ extract 0 0) (|wrapper#11| state)) #b1) false))) ; $techmap\m1.$logic_not$/home/hongce/ila/ila-stable/test/unit-data/vpipe/reset/out-z3/inst/wrapper.v:192$53_Y -(define-fun |wrapper#26| ((state |wrapper_s|)) (_ BitVec 1) (ite (= ((_ extract 0 0) (|wrapper#18| state)) #b1) (ite (|wrapper#25| state) #b1 #b0) (|wrapper#12| state))) ; $techmap\m1.$0\v1[0:0] -(define-fun |wrapper#27| ((state |wrapper_s|)) Bool (or (= ((_ extract 0 0) (|wrapper#9| state)) #b1) false (= ((_ extract 0 0) (|wrapper#3| state)) #b1) false)) ; $logic_or$/home/hongce/ila/ila-stable/test/unit-data/vpipe/reset/out-z3/inst/wrapper.v:85$5_Y -(define-fun |wrapper#28| ((state |wrapper_s|)) (_ BitVec 1) (ite (|wrapper#27| state) #b0 #b1)) ; $procmux$97_Y -(define-fun |wrapper#29| ((state |wrapper_s|)) (_ BitVec 1) (ite (|wrapper#24| state) #b0 (|wrapper#28| state))) ; $0\__START__[0:0] -(define-fun |wrapper#30| ((state |wrapper_s|)) (_ BitVec 1) (ite (= ((_ extract 0 0) (|wrapper#9| state)) #b1) #b1 (|wrapper#8| state))) ; $techmap\m0.$procmux$72_Y -(define-fun |wrapper#31| ((state |wrapper_s|)) (_ BitVec 1) (ite (|wrapper#24| state) (ite (|wrapper#23| state) #b1 #b0) (|wrapper#30| state))) ; $techmap\m0.$0\v[0:0] -(define-fun |wrapper#32| ((state |wrapper_s|)) (_ BitVec 1) (ite (|wrapper#7| state) #b1 (|wrapper#5| state))) ; $procmux$84_Y -(define-fun |wrapper#33| ((state |wrapper_s|)) (_ BitVec 1) (ite (|wrapper#24| state) #b0 (|wrapper#32| state))) ; $0\__ENDED__[0:0] -(define-fun |wrapper#34| ((state |wrapper_s|)) (_ BitVec 1) (ite (= ((_ extract 0 0) (|wrapper#9| state)) #b1) #b1 (|wrapper#3| state))) ; $procmux$89_Y -(define-fun |wrapper#35| ((state |wrapper_s|)) (_ BitVec 1) (ite (|wrapper#24| state) #b0 (|wrapper#34| state))) ; $0\__STARTED__[0:0] -(define-fun |wrapper#36| ((state |wrapper_s|)) (_ BitVec 4) (bvadd (|wrapper#1| state) #b0001)) ; $add$/home/hongce/ila/ila-stable/test/unit-data/vpipe/reset/out-z3/inst/wrapper.v:85$8_Y -(define-fun |wrapper#37| ((state |wrapper_s|)) Bool (bvult (|wrapper#1| state) #b0110)) ; $lt$/home/hongce/ila/ila-stable/test/unit-data/vpipe/reset/out-z3/inst/wrapper.v:85$6_Y -(define-fun |wrapper#38| ((state |wrapper_s|)) Bool (and (or (|wrapper#27| state) false) (or (|wrapper#37| state) false))) ; $logic_and$/home/hongce/ila/ila-stable/test/unit-data/vpipe/reset/out-z3/inst/wrapper.v:85$7_Y -(define-fun |wrapper#39| ((state |wrapper_s|)) (_ BitVec 4) (ite (|wrapper#38| state) (|wrapper#36| state) (|wrapper#1| state))) ; $procmux$102_Y -(define-fun |wrapper#40| ((state |wrapper_s|)) (_ BitVec 4) (ite (|wrapper#24| state) #b0000 (|wrapper#39| state))) ; $0\__CYCLE_CNT__[3:0] -(define-fun |wrapper#41| ((state |wrapper_s|)) Bool (and (or (= ((_ extract 0 0) (|wrapper#5| state)) #b1) false) (or (|wrapper#4| state) false))) ; $logic_and$/home/hongce/ila/ila-stable/test/unit-data/vpipe/reset/out-z3/inst/wrapper.v:102$14_Y -(define-fun |wrapper#42| ((state |wrapper_s|)) (_ BitVec 1) (bvnot (|wrapper#0| state))) ; $not$/home/hongce/ila/ila-stable/test/unit-data/vpipe/reset/out-z3/inst/wrapper.v:102$15_Y -(define-fun |wrapper#43| ((state |wrapper_s|)) Bool (and (or (|wrapper#41| state) false) (or (= ((_ extract 0 0) (|wrapper#42| state)) #b1) false))) ; $logic_and$/home/hongce/ila/ila-stable/test/unit-data/vpipe/reset/out-z3/inst/wrapper.v:102$16_Y -(define-fun |wrapper#44| ((state |wrapper_s|)) (_ BitVec 1) (ite (|wrapper#43| state) #b1 (|wrapper#0| state))) ; $procmux$79_Y -(define-fun |wrapper#45| ((state |wrapper_s|)) (_ BitVec 1) (ite (|wrapper#24| state) #b0 (|wrapper#44| state))) ; $0\__2ndENDED__[0:0] -(define-fun |wrapper_a| ((state |wrapper_s|)) Bool - (|wrapper_a 0| state) -) -(define-fun |wrapper_u| ((state |wrapper_s|)) Bool - (|wrapper_u 0| state) -) -(define-fun |wrapper_i| ((state |wrapper_s|)) Bool (and - (= (= ((_ extract 0 0) (|wrapper#0| state)) #b1) false) ; __2ndENDED__ - (= (|wrapper#1| state) #b0000) ; __CYCLE_CNT__ - (= (= ((_ extract 0 0) (|wrapper#5| state)) #b1) false) ; __ENDED__ - (= (= ((_ extract 0 0) (|wrapper#3| state)) #b1) false) ; __STARTED__ - (= (= ((_ extract 0 0) (|wrapper#9| state)) #b1) false) ; __START__ -)) -(define-fun |wrapper_h| ((state |wrapper_s|)) Bool true) -(define-fun |wrapper_t| ((state |wrapper_s|) (next_state |wrapper_s|)) Bool (and - (= (|wrapper#11| state) (|wrapper#12| next_state)) ; $techmap/m1.$procdff$108 \m1.v2 - (= (|wrapper#26| state) (|wrapper#11| next_state)) ; $techmap/m1.$procdff$107 \m1.v1 - (= (|wrapper#29| state) (|wrapper#9| next_state)) ; $procdff$115 \__START__ - (= (|wrapper#31| state) (|wrapper#8| next_state)) ; $techmap/m0.$procdff$109 \m0.v - (= (|wrapper#33| state) (|wrapper#5| next_state)) ; $procdff$113 \__ENDED__ - (= (|wrapper#35| state) (|wrapper#3| next_state)) ; $procdff$114 \__STARTED__ - (= (|wrapper#40| state) (|wrapper#1| next_state)) ; $procdff$116 \__CYCLE_CNT__ - (= (|wrapper#45| state) (|wrapper#0| next_state)) ; $procdff$112 \__2ndENDED__ -)) ; end of module wrapper -; yosys-smt2-topmod wrapper -; end of yosys output diff --git a/test/unit-data/vpipe/reset/out-z3/invariants/__design_smt.smt2 b/test/unit-data/vpipe/reset/out-z3/invariants/__design_smt.smt2 deleted file mode 100644 index af56047ee..000000000 --- a/test/unit-data/vpipe/reset/out-z3/invariants/__design_smt.smt2 +++ /dev/null @@ -1,68 +0,0 @@ -; SMT-LIBv2 description generated by Yosys 0.8+598 (git sha1 becd98cc, gcc 7.4.0-1ubuntu1~18.04.1 -fPIC -Os) -; yosys-smt2-stdt -; yosys-smt2-module wrapper -(declare-datatype |wrapper_s| ((|wrapper_mk| - (|wrapper_is| Bool) - (|wrapper#0| Bool) ; \__ILA_SO_v - (|wrapper#1| (_ BitVec 1)) ; \m1.v1 - (|wrapper#2| (_ BitVec 1)) ; \m1.v2 - (|wrapper#5| (_ BitVec 1)) ; \rst - (|wrapper#7| Bool) ; \clk -))) -; yosys-smt2-input __ILA_SO_v 1 -; yosys-smt2-output __ILA_SO_v 1 -; yosys-smt2-wire __ILA_SO_v 1 -(define-fun |wrapper_n __ILA_SO_v| ((state |wrapper_s|)) Bool (|wrapper#0| state)) -; yosys-smt2-output __all_assert_wire__ 1 -; yosys-smt2-wire __all_assert_wire__ 1 -(define-fun |wrapper#3| ((state |wrapper_s|)) (_ BitVec 1) (bvnot (|wrapper#2| state))) ; $not$/home/hongce/ila/ila-stable/test/unit-data/vpipe/reset/out-z3/invariants/wrapper.v:37$1_Y -(define-fun |wrapper#4| ((state |wrapper_s|)) Bool (= (|wrapper#1| state) (|wrapper#3| state))) ; \__all_assert_wire__ -(define-fun |wrapper_n __all_assert_wire__| ((state |wrapper_s|)) Bool (|wrapper#4| state)) -; yosys-smt2-output __all_assume_wire__ 1 -; yosys-smt2-wire __all_assume_wire__ 1 -(define-fun |wrapper#6| ((state |wrapper_s|)) (_ BitVec 1) (bvnot (|wrapper#5| state))) ; \__all_assume_wire__ -(define-fun |wrapper_n __all_assume_wire__| ((state |wrapper_s|)) Bool (= ((_ extract 0 0) (|wrapper#6| state)) #b1)) -; yosys-smt2-input clk 1 -; yosys-smt2-clock clk posedge -(define-fun |wrapper_n clk| ((state |wrapper_s|)) Bool (|wrapper#7| state)) -; yosys-smt2-output invariant_assert__p0__ 1 -; yosys-smt2-wire invariant_assert__p0__ 1 -(define-fun |wrapper_n invariant_assert__p0__| ((state |wrapper_s|)) Bool (|wrapper#4| state)) -; yosys-smt2-register m1.v1 1 -; yosys-smt2-wire m1.v1 1 -(define-fun |wrapper_n m1.v1| ((state |wrapper_s|)) Bool (= ((_ extract 0 0) (|wrapper#1| state)) #b1)) -; yosys-smt2-register m1.v2 1 -; yosys-smt2-wire m1.v2 1 -(define-fun |wrapper_n m1.v2| ((state |wrapper_s|)) Bool (= ((_ extract 0 0) (|wrapper#2| state)) #b1)) -; yosys-smt2-output m1__DOT__v1 1 -; yosys-smt2-wire m1__DOT__v1 1 -(define-fun |wrapper_n m1__DOT__v1| ((state |wrapper_s|)) Bool (= ((_ extract 0 0) (|wrapper#1| state)) #b1)) -; yosys-smt2-output m1__DOT__v2 1 -; yosys-smt2-wire m1__DOT__v2 1 -(define-fun |wrapper_n m1__DOT__v2| ((state |wrapper_s|)) Bool (= ((_ extract 0 0) (|wrapper#2| state)) #b1)) -; yosys-smt2-input rst 1 -(define-fun |wrapper_n rst| ((state |wrapper_s|)) Bool (= ((_ extract 0 0) (|wrapper#5| state)) #b1)) -; yosys-smt2-output v 1 -; yosys-smt2-wire v 1 -(define-fun |wrapper#8| ((state |wrapper_s|)) (_ BitVec 1) (bvxor (|wrapper#1| state) (|wrapper#2| state))) ; \m1.v -(define-fun |wrapper_n v| ((state |wrapper_s|)) Bool (= ((_ extract 0 0) (|wrapper#8| state)) #b1)) -; yosys-smt2-assert 0 /home/hongce/ila/ila-stable/test/unit-data/vpipe/reset/out-z3/invariants/wrapper.v:48 -(define-fun |wrapper_a 0| ((state |wrapper_s|)) Bool (or (|wrapper#4| state) (not true))) ; $assert$/home/hongce/ila/ila-stable/test/unit-data/vpipe/reset/out-z3/invariants/wrapper.v:48$4 -; yosys-smt2-assume 0 /home/hongce/ila/ila-stable/test/unit-data/vpipe/reset/out-z3/invariants/wrapper.v:50 -(define-fun |wrapper_u 0| ((state |wrapper_s|)) Bool (or (= ((_ extract 0 0) (|wrapper#6| state)) #b1) (not true))) ; $assume$/home/hongce/ila/ila-stable/test/unit-data/vpipe/reset/out-z3/invariants/wrapper.v:50$5 -(define-fun |wrapper#9| ((state |wrapper_s|)) Bool (not (or (= ((_ extract 0 0) (|wrapper#1| state)) #b1) false))) ; $techmap\m1.$logic_not$/home/hongce/ila/ila-stable/test/unit-data/vpipe/reset/out-z3/invariants/wrapper.v:61$7_Y -(define-fun |wrapper#10| ((state |wrapper_s|)) (_ BitVec 1) (ite (= ((_ extract 0 0) (|wrapper#5| state)) #b1) (ite (|wrapper#9| state) #b1 #b0) (|wrapper#2| state))) ; $techmap\m1.$0\v1[0:0] -(define-fun |wrapper_a| ((state |wrapper_s|)) Bool - (|wrapper_a 0| state) -) -(define-fun |wrapper_u| ((state |wrapper_s|)) Bool - (|wrapper_u 0| state) -) -(define-fun |wrapper_i| ((state |wrapper_s|)) Bool true) -(define-fun |wrapper_h| ((state |wrapper_s|)) Bool true) -(define-fun |wrapper_t| ((state |wrapper_s|) (next_state |wrapper_s|)) Bool (and - (= (|wrapper#1| state) (|wrapper#2| next_state)) ; $techmap/m1.$procdff$15 \m1.v2 - (= (|wrapper#10| state) (|wrapper#1| next_state)) ; $techmap/m1.$procdff$14 \m1.v1 -)) ; end of module wrapper -; yosys-smt2-topmod wrapper -; end of yosys output diff --git a/test/unit-data/vpipe/reset/out-abc/.gitignore b/test/unit-data/vpipe/reset/out2/.gitignore similarity index 100% rename from test/unit-data/vpipe/reset/out-abc/.gitignore rename to test/unit-data/vpipe/reset/out2/.gitignore diff --git a/test/unit-data/vpipe/reset/out-z3/.gitignore b/test/unit-data/vpipe/reset/out3/.gitignore similarity index 100% rename from test/unit-data/vpipe/reset/out-z3/.gitignore rename to test/unit-data/vpipe/reset/out3/.gitignore diff --git a/test/unit-data/vpipe/reset/rfmap/cond.json b/test/unit-data/vpipe/reset/rfmap/cond.json index 0c83f684e..ce6495528 100644 --- a/test/unit-data/vpipe/reset/rfmap/cond.json +++ b/test/unit-data/vpipe/reset/rfmap/cond.json @@ -1,5 +1,5 @@ { - "global invariants": ["m1.v1 == ~m1.v2"], + "global invariants": ["RTL.v1 == ~RTL.v2"], "instructions": [ { diff --git a/test/unit-data/vpipe/reset/rfmap/vmap-e1.json b/test/unit-data/vpipe/reset/rfmap/vmap-e1.json index 99ebcff9d..21818ff65 100644 --- a/test/unit-data/vpipe/reset/rfmap/vmap-e1.json +++ b/test/unit-data/vpipe/reset/rfmap/vmap-e1.json @@ -1,24 +1,15 @@ { - "models": { "ILA":"m0" , "VERILOG": "m1" }, "state mapping": { - "v":"v"}, + "v":"RTL.v"}, - "interface mapping": { - "rst":"**RESET**", - "clk":"**CLOCK**", - "v":"**SO**" + "RTL interface connection" : { + "CLOCK" : "clk", + "RESET" : "rst" }, // "mapping control" : ["__MEM_mema_0_ren == ((m1.state == 1)?1'b1:1'b0)", "__MEM_memb_0_ren == ((m1.state == 1)?1'b1:1'b0)"], - "annotation": { - "reset" : { - "cycle": 0, - "no-reset-after": true, - "reset-state":[], - "reset-sequence":[] - } - }, + "assumptions":["1==1"] } diff --git a/test/unit-data/vpipe/reset/rfmap/vmap-e2.json b/test/unit-data/vpipe/reset/rfmap/vmap-e2.json deleted file mode 100644 index 72ef32c1a..000000000 --- a/test/unit-data/vpipe/reset/rfmap/vmap-e2.json +++ /dev/null @@ -1,17 +0,0 @@ -{ - "models": { "ILA":"m0" , "VERILOG": "m1" }, - - "state mapping": { - "v":"v"}, - - "interface mapping": { - "rst":"**RESET**", - "clk":"**CLOCK**", - "v":"**SO**" - }, - - // "mapping control" : ["__MEM_mema_0_ren == ((m1.state == 1)?1'b1:1'b0)", "__MEM_memb_0_ren == ((m1.state == 1)?1'b1:1'b0)"], - - "annotation": "none", - "assumptions":["1==1"] -} diff --git a/test/unit-data/vpipe/reset/rfmap/vmap-e3.json b/test/unit-data/vpipe/reset/rfmap/vmap-e3.json deleted file mode 100644 index eeb62b144..000000000 --- a/test/unit-data/vpipe/reset/rfmap/vmap-e3.json +++ /dev/null @@ -1,22 +0,0 @@ -{ - "models": { "ILA":"m0" , "VERILOG": "m1" }, - - "state mapping": { - "v":"v"}, - - "interface mapping": { - "rst":"**RESET**", - "clk":"**CLOCK**", - "v":"**SO**" - }, - - // "mapping control" : ["__MEM_mema_0_ren == ((m1.state == 1)?1'b1:1'b0)", "__MEM_memb_0_ren == ((m1.state == 1)?1'b1:1'b0)"], - - "annotation": { - "width":{"m1.v":1}, - "memory":{"abc":"unknown"}, - "memory-ports":{"abc.r1":123,"bcd.r2":"abc"} - }, - - "assumptions":["1==1"] -} diff --git a/test/unit-data/vpipe/reset/rfmap/vmap-e4.json b/test/unit-data/vpipe/reset/rfmap/vmap-e4.json deleted file mode 100644 index a4dbd547f..000000000 --- a/test/unit-data/vpipe/reset/rfmap/vmap-e4.json +++ /dev/null @@ -1,16 +0,0 @@ -{ - "models": { "ILA":"m0" , "VERILOG": "m1" }, - - "state mapping": { - "v":"v"}, - - "interface mapping": { - "rst":"**RESET**", - "clk":"**CLOCK**", - "v":"" - }, - - // "mapping control" : ["__MEM_mema_0_ren == ((m1.state == 1)?1'b1:1'b0)", "__MEM_memb_0_ren == ((m1.state == 1)?1'b1:1'b0)"], - - "assumptions":["1==1"] -} diff --git a/test/unit-data/vpipe/reset/rfmap/vmap.json b/test/unit-data/vpipe/reset/rfmap/vmap.json index 73a81f4dc..c4f7a02e7 100644 --- a/test/unit-data/vpipe/reset/rfmap/vmap.json +++ b/test/unit-data/vpipe/reset/rfmap/vmap.json @@ -1,24 +1,16 @@ { - "models": { "ILA":"m0" , "VERILOG": "m1" }, - "state mapping": { - "v":"v"}, + "v":"RTL.v"}, - "interface mapping": { - "rst":"**RESET**", - "clk":"**CLOCK**", - "v":"**SO**" + "RTL interface connection" : { + "CLOCK" : "clk", + "RESET" : "rst" }, - // "mapping control" : ["__MEM_mema_0_ren == ((m1.state == 1)?1'b1:1'b0)", "__MEM_memb_0_ren == ((m1.state == 1)?1'b1:1'b0)"], - "annotation": { - "reset" : { - "cycle": 5, - "no-reset-after": true, - "reset-state":[], - "reset-sequence":[] - } + // "mapping control" : ["__MEM_mema_0_ren == ((m1.state == 1)?1'b1:1'b0)", "__MEM_memb_0_ren == ((m1.state == 1)?1'b1:1'b0)"], + "reset" : { + "cycles" : 5 }, "assumptions":["1==1"] } diff --git a/test/unit-data/vpipe/rfmap/cond-noinv.json b/test/unit-data/vpipe/rfmap/cond-noinv.json index b3f4464f9..ea6e9afea 100644 --- a/test/unit-data/vpipe/rfmap/cond-noinv.json +++ b/test/unit-data/vpipe/rfmap/cond-noinv.json @@ -1,28 +1,20 @@ { - "target ILA": "vlg-gen/pipe.v:simpePipe", - "target Verilog": "verilog/simple_pipe.v:pipeline_v", - - "global invariants": [], "instructions": [ { "instruction": "NOP", - "ready signal": [], "ready bound": 1 }, { "instruction": "ADD", - "ready signal": [], "ready bound": 1 }, { "instruction": "SUB", - "ready signal": [], "ready bound": 1 }, { "instruction": "AND", - "ready signal": [], "ready bound": 1 } ] diff --git a/test/unit-data/vpipe/rfmap/cond-rfmap-pvholder-reset.json b/test/unit-data/vpipe/rfmap/cond-rfmap-pvholder-reset.json new file mode 100644 index 000000000..067d2f47c --- /dev/null +++ b/test/unit-data/vpipe/rfmap/cond-rfmap-pvholder-reset.json @@ -0,0 +1,5 @@ +{ + // this is a comment + "ready signal": "#ppl_stage_wb# ## 1" +} + diff --git a/test/unit-data/vpipe/rfmap/cond-rfmap-pvholder-stall-short.json b/test/unit-data/vpipe/rfmap/cond-rfmap-pvholder-stall-short.json new file mode 100644 index 000000000..b5848f1a1 --- /dev/null +++ b/test/unit-data/vpipe/rfmap/cond-rfmap-pvholder-stall-short.json @@ -0,0 +1,33 @@ +{ + // this is a comment + "global invariants": [ + "RTL.scoreboard[0][1:1] == ( RTL.id_ex_valid && RTL.id_ex_reg_wen && RTL.id_ex_rd == 2'd0)", + "RTL.scoreboard[0][0:0] == ( RTL.ex_wb_valid && RTL.ex_wb_reg_wen && RTL.ex_wb_rd == 2'd0)", + "RTL.scoreboard[1][1:1] == ( RTL.id_ex_valid && RTL.id_ex_reg_wen && RTL.id_ex_rd == 2'd1)", + "RTL.scoreboard[1][0:0] == ( RTL.ex_wb_valid && RTL.ex_wb_reg_wen && RTL.ex_wb_rd == 2'd1)", + "RTL.scoreboard[2][1:1] == ( RTL.id_ex_valid && RTL.id_ex_reg_wen && RTL.id_ex_rd == 2'd2)", + "RTL.scoreboard[2][0:0] == ( RTL.ex_wb_valid && RTL.ex_wb_reg_wen && RTL.ex_wb_rd == 2'd2)", + "RTL.scoreboard[3][1:1] == ( RTL.id_ex_valid && RTL.id_ex_reg_wen && RTL.id_ex_rd == 2'd3)", + "RTL.scoreboard[3][0:0] == ( RTL.ex_wb_valid && RTL.ex_wb_reg_wen && RTL.ex_wb_rd == 2'd3)" + ], + + "instructions": [ + { + "instruction": "NOP", + "ready signal": "#ppl_stage_finish# == 1" + }, + { + "instruction": "ADD", + "ready signal": "#ppl_stage_finish# == 1" + }, + { + "instruction": "SET", + "ready signal": "#ppl_stage_finish# == 1" + }, + { + "instruction": "NAND", + "ready signal": "#ppl_stage_finish# == 1" + } + ] +} + diff --git a/test/unit-data/vpipe/rfmap/cond-rfmap-pvholder-stall.json b/test/unit-data/vpipe/rfmap/cond-rfmap-pvholder-stall.json new file mode 100644 index 000000000..9bc36068b --- /dev/null +++ b/test/unit-data/vpipe/rfmap/cond-rfmap-pvholder-stall.json @@ -0,0 +1,33 @@ +{ + // this is a comment + "global invariants": [ + "RTL.scoreboard[0][1:1] == ( RTL.id_ex_valid && RTL.id_ex_reg_wen && RTL.id_ex_rd == 2'd0)", + "RTL.scoreboard[0][0:0] == ( RTL.ex_wb_valid && RTL.ex_wb_reg_wen && RTL.ex_wb_rd == 2'd0)", + "RTL.scoreboard[1][1:1] == ( RTL.id_ex_valid && RTL.id_ex_reg_wen && RTL.id_ex_rd == 2'd1)", + "RTL.scoreboard[1][0:0] == ( RTL.ex_wb_valid && RTL.ex_wb_reg_wen && RTL.ex_wb_rd == 2'd1)", + "RTL.scoreboard[2][1:1] == ( RTL.id_ex_valid && RTL.id_ex_reg_wen && RTL.id_ex_rd == 2'd2)", + "RTL.scoreboard[2][0:0] == ( RTL.ex_wb_valid && RTL.ex_wb_reg_wen && RTL.ex_wb_rd == 2'd2)", + "RTL.scoreboard[3][1:1] == ( RTL.id_ex_valid && RTL.id_ex_reg_wen && RTL.id_ex_rd == 2'd3)", + "RTL.scoreboard[3][0:0] == ( RTL.ex_wb_valid && RTL.ex_wb_reg_wen && RTL.ex_wb_rd == 2'd3)" + ], + + "instructions": [ + { + "instruction": "NOP", + "ready signal": "#wb_iuv# == 1" + }, + { + "instruction": "ADD", + "ready signal": "#wb_iuv# == 1" + }, + { + "instruction": "SET", + "ready signal": "#wb_iuv# == 1" + }, + { + "instruction": "NAND", + "ready signal": "#wb_iuv# == 1" + } + ] +} + diff --git a/test/unit-data/vpipe/rfmap/cond-rfmap-pvholder.json b/test/unit-data/vpipe/rfmap/cond-rfmap-pvholder.json index a3c5b6353..8a2f1bcf6 100644 --- a/test/unit-data/vpipe/rfmap/cond-rfmap-pvholder.json +++ b/test/unit-data/vpipe/rfmap/cond-rfmap-pvholder.json @@ -1,42 +1,40 @@ { - "target ILA": "vlg-gen/pipe.v:simpePipe", - "target Verilog": "verilog/simple_pipe.v:pipeline_v", // this is a comment "global invariants": [ - "(! (m1.reg_0_w_stage == 2'b00 ) ) || ( ( (m1.id_ex_reg_wen == 0) || (m1.id_ex_rd != 2'd0) ) && ( (m1.ex_wb_reg_wen == 0) || (m1.ex_wb_rd != 2'd0) ) )", - "(! (m1.reg_1_w_stage == 2'b00 ) ) || ( ( (m1.id_ex_reg_wen == 0) || (m1.id_ex_rd != 2'd1) ) && ( (m1.ex_wb_reg_wen == 0) || (m1.ex_wb_rd != 2'd1) ) )", - "(! (m1.reg_2_w_stage == 2'b00 ) ) || ( ( (m1.id_ex_reg_wen == 0) || (m1.id_ex_rd != 2'd2) ) && ( (m1.ex_wb_reg_wen == 0) || (m1.ex_wb_rd != 2'd2) ) )", - "(! (m1.reg_3_w_stage == 2'b00 ) ) || ( ( (m1.id_ex_reg_wen == 0) || (m1.id_ex_rd != 2'd3) ) && ( (m1.ex_wb_reg_wen == 0) || (m1.ex_wb_rd != 2'd3) ) )", - "(! (m1.reg_0_w_stage == 2'b10 ) ) || ( ( (m1.id_ex_reg_wen == 1) && (m1.id_ex_rd == 2'd0) ) && ( (m1.ex_wb_reg_wen == 0) || (m1.ex_wb_rd != 2'd0) ) )", - "(! (m1.reg_1_w_stage == 2'b10 ) ) || ( ( (m1.id_ex_reg_wen == 1) && (m1.id_ex_rd == 2'd1) ) && ( (m1.ex_wb_reg_wen == 0) || (m1.ex_wb_rd != 2'd1) ) )", - "(! (m1.reg_2_w_stage == 2'b10 ) ) || ( ( (m1.id_ex_reg_wen == 1) && (m1.id_ex_rd == 2'd2) ) && ( (m1.ex_wb_reg_wen == 0) || (m1.ex_wb_rd != 2'd2) ) )", - "(! (m1.reg_3_w_stage == 2'b10 ) ) || ( ( (m1.id_ex_reg_wen == 1) && (m1.id_ex_rd == 2'd3) ) && ( (m1.ex_wb_reg_wen == 0) || (m1.ex_wb_rd != 2'd3) ) )", - "(! (m1.reg_0_w_stage == 2'b11 ) ) || ( ( (m1.id_ex_reg_wen == 1) && (m1.id_ex_rd == 2'd0) ) && ( (m1.ex_wb_reg_wen == 1) && (m1.ex_wb_rd == 2'd0) ) )", - "(! (m1.reg_1_w_stage == 2'b11 ) ) || ( ( (m1.id_ex_reg_wen == 1) && (m1.id_ex_rd == 2'd1) ) && ( (m1.ex_wb_reg_wen == 1) && (m1.ex_wb_rd == 2'd1) ) )", - "(! (m1.reg_2_w_stage == 2'b11 ) ) || ( ( (m1.id_ex_reg_wen == 1) && (m1.id_ex_rd == 2'd2) ) && ( (m1.ex_wb_reg_wen == 1) && (m1.ex_wb_rd == 2'd2) ) )", - "(! (m1.reg_3_w_stage == 2'b11 ) ) || ( ( (m1.id_ex_reg_wen == 1) && (m1.id_ex_rd == 2'd3) ) && ( (m1.ex_wb_reg_wen == 1) && (m1.ex_wb_rd == 2'd3) ) )", - "(! (m1.reg_0_w_stage == 2'b01 ) ) || ( ( (m1.id_ex_reg_wen == 0) || (m1.id_ex_rd != 2'd0) ) && ( (m1.ex_wb_reg_wen == 1) && (m1.ex_wb_rd == 2'd0) ) )", - "(! (m1.reg_1_w_stage == 2'b01 ) ) || ( ( (m1.id_ex_reg_wen == 0) || (m1.id_ex_rd != 2'd1) ) && ( (m1.ex_wb_reg_wen == 1) && (m1.ex_wb_rd == 2'd1) ) )", - "(! (m1.reg_2_w_stage == 2'b01 ) ) || ( ( (m1.id_ex_reg_wen == 0) || (m1.id_ex_rd != 2'd2) ) && ( (m1.ex_wb_reg_wen == 1) && (m1.ex_wb_rd == 2'd2) ) )", - "(! (m1.reg_3_w_stage == 2'b01 ) ) || ( ( (m1.id_ex_reg_wen == 0) || (m1.id_ex_rd != 2'd3) ) && ( (m1.ex_wb_reg_wen == 1) && (m1.ex_wb_rd == 2'd3) ) )" + " (RTL.reg_0_w_stage == 2'b00 ) |-> ( ( (RTL.id_ex_reg_wen == 0) || (RTL.id_ex_rd != 2'd0) ) && ( (RTL.ex_wb_reg_wen == 0) || (RTL.ex_wb_rd != 2'd0) ) )", + " (RTL.reg_1_w_stage == 2'b00 ) |-> ( ( (RTL.id_ex_reg_wen == 0) || (RTL.id_ex_rd != 2'd1) ) && ( (RTL.ex_wb_reg_wen == 0) || (RTL.ex_wb_rd != 2'd1) ) )", + " (RTL.reg_2_w_stage == 2'b00 ) |-> ( ( (RTL.id_ex_reg_wen == 0) || (RTL.id_ex_rd != 2'd2) ) && ( (RTL.ex_wb_reg_wen == 0) || (RTL.ex_wb_rd != 2'd2) ) )", + " (RTL.reg_3_w_stage == 2'b00 ) |-> ( ( (RTL.id_ex_reg_wen == 0) || (RTL.id_ex_rd != 2'd3) ) && ( (RTL.ex_wb_reg_wen == 0) || (RTL.ex_wb_rd != 2'd3) ) )", + " (RTL.reg_0_w_stage == 2'b10 ) |-> ( ( (RTL.id_ex_reg_wen == 1) && (RTL.id_ex_rd == 2'd0) ) && ( (RTL.ex_wb_reg_wen == 0) || (RTL.ex_wb_rd != 2'd0) ) )", + " (RTL.reg_1_w_stage == 2'b10 ) |-> ( ( (RTL.id_ex_reg_wen == 1) && (RTL.id_ex_rd == 2'd1) ) && ( (RTL.ex_wb_reg_wen == 0) || (RTL.ex_wb_rd != 2'd1) ) )", + " (RTL.reg_2_w_stage == 2'b10 ) |-> ( ( (RTL.id_ex_reg_wen == 1) && (RTL.id_ex_rd == 2'd2) ) && ( (RTL.ex_wb_reg_wen == 0) || (RTL.ex_wb_rd != 2'd2) ) )", + " (RTL.reg_3_w_stage == 2'b10 ) |-> ( ( (RTL.id_ex_reg_wen == 1) && (RTL.id_ex_rd == 2'd3) ) && ( (RTL.ex_wb_reg_wen == 0) || (RTL.ex_wb_rd != 2'd3) ) )", + " (RTL.reg_0_w_stage == 2'b11 ) |-> ( ( (RTL.id_ex_reg_wen == 1) && (RTL.id_ex_rd == 2'd0) ) && ( (RTL.ex_wb_reg_wen == 1) && (RTL.ex_wb_rd == 2'd0) ) )", + " (RTL.reg_1_w_stage == 2'b11 ) |-> ( ( (RTL.id_ex_reg_wen == 1) && (RTL.id_ex_rd == 2'd1) ) && ( (RTL.ex_wb_reg_wen == 1) && (RTL.ex_wb_rd == 2'd1) ) )", + " (RTL.reg_2_w_stage == 2'b11 ) |-> ( ( (RTL.id_ex_reg_wen == 1) && (RTL.id_ex_rd == 2'd2) ) && ( (RTL.ex_wb_reg_wen == 1) && (RTL.ex_wb_rd == 2'd2) ) )", + " (RTL.reg_3_w_stage == 2'b11 ) |-> ( ( (RTL.id_ex_reg_wen == 1) && (RTL.id_ex_rd == 2'd3) ) && ( (RTL.ex_wb_reg_wen == 1) && (RTL.ex_wb_rd == 2'd3) ) )", + " (RTL.reg_0_w_stage == 2'b01 ) |-> ( ( (RTL.id_ex_reg_wen == 0) || (RTL.id_ex_rd != 2'd0) ) && ( (RTL.ex_wb_reg_wen == 1) && (RTL.ex_wb_rd == 2'd0) ) )", + " (RTL.reg_1_w_stage == 2'b01 ) |-> ( ( (RTL.id_ex_reg_wen == 0) || (RTL.id_ex_rd != 2'd1) ) && ( (RTL.ex_wb_reg_wen == 1) && (RTL.ex_wb_rd == 2'd1) ) )", + " (RTL.reg_2_w_stage == 2'b01 ) |-> ( ( (RTL.id_ex_reg_wen == 0) || (RTL.id_ex_rd != 2'd2) ) && ( (RTL.ex_wb_reg_wen == 1) && (RTL.ex_wb_rd == 2'd2) ) )", + " (RTL.reg_3_w_stage == 2'b01 ) |-> ( ( (RTL.id_ex_reg_wen == 0) || (RTL.id_ex_rd != 2'd3) ) && ( (RTL.ex_wb_reg_wen == 1) && (RTL.ex_wb_rd == 2'd3) ) )" ], "instructions": [ { "instruction": "NOP", - "ready signal": ["#stage_tracker# == 2"] + "ready signal": "#stage_tracker# == 2" }, { "instruction": "ADD", - "ready signal": ["#stage_tracker# == 2"] + "ready signal": "#stage_tracker# == 2" }, { "instruction": "SUB", - "ready signal": ["#stage_tracker# == 2"] + "ready signal": "#stage_tracker# == 2" }, { "instruction": "AND", - "ready signal": ["#stage_tracker# == 2"] + "ready signal": "#ppl_stage_wb# ## 1" } ] } diff --git a/test/unit-data/vpipe/rfmap/cond-rfmap-stall-short.json b/test/unit-data/vpipe/rfmap/cond-rfmap-stall-short.json new file mode 100644 index 000000000..b5848f1a1 --- /dev/null +++ b/test/unit-data/vpipe/rfmap/cond-rfmap-stall-short.json @@ -0,0 +1,33 @@ +{ + // this is a comment + "global invariants": [ + "RTL.scoreboard[0][1:1] == ( RTL.id_ex_valid && RTL.id_ex_reg_wen && RTL.id_ex_rd == 2'd0)", + "RTL.scoreboard[0][0:0] == ( RTL.ex_wb_valid && RTL.ex_wb_reg_wen && RTL.ex_wb_rd == 2'd0)", + "RTL.scoreboard[1][1:1] == ( RTL.id_ex_valid && RTL.id_ex_reg_wen && RTL.id_ex_rd == 2'd1)", + "RTL.scoreboard[1][0:0] == ( RTL.ex_wb_valid && RTL.ex_wb_reg_wen && RTL.ex_wb_rd == 2'd1)", + "RTL.scoreboard[2][1:1] == ( RTL.id_ex_valid && RTL.id_ex_reg_wen && RTL.id_ex_rd == 2'd2)", + "RTL.scoreboard[2][0:0] == ( RTL.ex_wb_valid && RTL.ex_wb_reg_wen && RTL.ex_wb_rd == 2'd2)", + "RTL.scoreboard[3][1:1] == ( RTL.id_ex_valid && RTL.id_ex_reg_wen && RTL.id_ex_rd == 2'd3)", + "RTL.scoreboard[3][0:0] == ( RTL.ex_wb_valid && RTL.ex_wb_reg_wen && RTL.ex_wb_rd == 2'd3)" + ], + + "instructions": [ + { + "instruction": "NOP", + "ready signal": "#ppl_stage_finish# == 1" + }, + { + "instruction": "ADD", + "ready signal": "#ppl_stage_finish# == 1" + }, + { + "instruction": "SET", + "ready signal": "#ppl_stage_finish# == 1" + }, + { + "instruction": "NAND", + "ready signal": "#ppl_stage_finish# == 1" + } + ] +} + diff --git a/test/unit-data/vpipe/rfmap/cond.json b/test/unit-data/vpipe/rfmap/cond.json index 3b42d6ec7..9d5baf45e 100644 --- a/test/unit-data/vpipe/rfmap/cond.json +++ b/test/unit-data/vpipe/rfmap/cond.json @@ -1,45 +1,36 @@ { - "target ILA": "vlg-gen/pipe.v:simpePipe", - "target Verilog": "verilog/simple_pipe.v:pipeline_v", // this is a comment "global invariants": [ - "(! (m1.reg_0_w_stage == 2'b00 ) ) || ( ( (m1.id_ex_reg_wen == 0) || (m1.id_ex_rd != 2'd0) ) && ( (m1.ex_wb_reg_wen == 0) || (m1.ex_wb_rd != 2'd0) ) )", - "(! (m1.reg_1_w_stage == 2'b00 ) ) || ( ( (m1.id_ex_reg_wen == 0) || (m1.id_ex_rd != 2'd1) ) && ( (m1.ex_wb_reg_wen == 0) || (m1.ex_wb_rd != 2'd1) ) )", - "(! (m1.reg_2_w_stage == 2'b00 ) ) || ( ( (m1.id_ex_reg_wen == 0) || (m1.id_ex_rd != 2'd2) ) && ( (m1.ex_wb_reg_wen == 0) || (m1.ex_wb_rd != 2'd2) ) )", - "(! (m1.reg_3_w_stage == 2'b00 ) ) || ( ( (m1.id_ex_reg_wen == 0) || (m1.id_ex_rd != 2'd3) ) && ( (m1.ex_wb_reg_wen == 0) || (m1.ex_wb_rd != 2'd3) ) )", - "(! (m1.reg_0_w_stage == 2'b10 ) ) || ( ( (m1.id_ex_reg_wen == 1) && (m1.id_ex_rd == 2'd0) ) && ( (m1.ex_wb_reg_wen == 0) || (m1.ex_wb_rd != 2'd0) ) )", - "(! (m1.reg_1_w_stage == 2'b10 ) ) || ( ( (m1.id_ex_reg_wen == 1) && (m1.id_ex_rd == 2'd1) ) && ( (m1.ex_wb_reg_wen == 0) || (m1.ex_wb_rd != 2'd1) ) )", - "(! (m1.reg_2_w_stage == 2'b10 ) ) || ( ( (m1.id_ex_reg_wen == 1) && (m1.id_ex_rd == 2'd2) ) && ( (m1.ex_wb_reg_wen == 0) || (m1.ex_wb_rd != 2'd2) ) )", - "(! (m1.reg_3_w_stage == 2'b10 ) ) || ( ( (m1.id_ex_reg_wen == 1) && (m1.id_ex_rd == 2'd3) ) && ( (m1.ex_wb_reg_wen == 0) || (m1.ex_wb_rd != 2'd3) ) )", - "(! (m1.reg_0_w_stage == 2'b11 ) ) || ( ( (m1.id_ex_reg_wen == 1) && (m1.id_ex_rd == 2'd0) ) && ( (m1.ex_wb_reg_wen == 1) && (m1.ex_wb_rd == 2'd0) ) )", - "(! (m1.reg_1_w_stage == 2'b11 ) ) || ( ( (m1.id_ex_reg_wen == 1) && (m1.id_ex_rd == 2'd1) ) && ( (m1.ex_wb_reg_wen == 1) && (m1.ex_wb_rd == 2'd1) ) )", - "(! (m1.reg_2_w_stage == 2'b11 ) ) || ( ( (m1.id_ex_reg_wen == 1) && (m1.id_ex_rd == 2'd2) ) && ( (m1.ex_wb_reg_wen == 1) && (m1.ex_wb_rd == 2'd2) ) )", - "(! (m1.reg_3_w_stage == 2'b11 ) ) || ( ( (m1.id_ex_reg_wen == 1) && (m1.id_ex_rd == 2'd3) ) && ( (m1.ex_wb_reg_wen == 1) && (m1.ex_wb_rd == 2'd3) ) )", - "(! (m1.reg_0_w_stage == 2'b01 ) ) || ( ( (m1.id_ex_reg_wen == 0) || (m1.id_ex_rd != 2'd0) ) && ( (m1.ex_wb_reg_wen == 1) && (m1.ex_wb_rd == 2'd0) ) )", - "(! (m1.reg_1_w_stage == 2'b01 ) ) || ( ( (m1.id_ex_reg_wen == 0) || (m1.id_ex_rd != 2'd1) ) && ( (m1.ex_wb_reg_wen == 1) && (m1.ex_wb_rd == 2'd1) ) )", - "(! (m1.reg_2_w_stage == 2'b01 ) ) || ( ( (m1.id_ex_reg_wen == 0) || (m1.id_ex_rd != 2'd2) ) && ( (m1.ex_wb_reg_wen == 1) && (m1.ex_wb_rd == 2'd2) ) )", - "(! (m1.reg_3_w_stage == 2'b01 ) ) || ( ( (m1.id_ex_reg_wen == 0) || (m1.id_ex_rd != 2'd3) ) && ( (m1.ex_wb_reg_wen == 1) && (m1.ex_wb_rd == 2'd3) ) )" + " (RTL.reg_0_w_stage == 2'b00 ) |-> ( ( (RTL.id_ex_reg_wen == 0) || (RTL.id_ex_rd != 2'd0) ) && ( (RTL.ex_wb_reg_wen == 0) || (RTL.ex_wb_rd != 2'd0) ) )", + " (RTL.reg_1_w_stage == 2'b00 ) |-> ( ( (RTL.id_ex_reg_wen == 0) || (RTL.id_ex_rd != 2'd1) ) && ( (RTL.ex_wb_reg_wen == 0) || (RTL.ex_wb_rd != 2'd1) ) )", + " (RTL.reg_2_w_stage == 2'b00 ) |-> ( ( (RTL.id_ex_reg_wen == 0) || (RTL.id_ex_rd != 2'd2) ) && ( (RTL.ex_wb_reg_wen == 0) || (RTL.ex_wb_rd != 2'd2) ) )", + " (RTL.reg_3_w_stage == 2'b00 ) |-> ( ( (RTL.id_ex_reg_wen == 0) || (RTL.id_ex_rd != 2'd3) ) && ( (RTL.ex_wb_reg_wen == 0) || (RTL.ex_wb_rd != 2'd3) ) )", + " (RTL.reg_0_w_stage == 2'b10 ) |-> ( ( (RTL.id_ex_reg_wen == 1) && (RTL.id_ex_rd == 2'd0) ) && ( (RTL.ex_wb_reg_wen == 0) || (RTL.ex_wb_rd != 2'd0) ) )", + " (RTL.reg_1_w_stage == 2'b10 ) |-> ( ( (RTL.id_ex_reg_wen == 1) && (RTL.id_ex_rd == 2'd1) ) && ( (RTL.ex_wb_reg_wen == 0) || (RTL.ex_wb_rd != 2'd1) ) )", + " (RTL.reg_2_w_stage == 2'b10 ) |-> ( ( (RTL.id_ex_reg_wen == 1) && (RTL.id_ex_rd == 2'd2) ) && ( (RTL.ex_wb_reg_wen == 0) || (RTL.ex_wb_rd != 2'd2) ) )", + " (RTL.reg_3_w_stage == 2'b10 ) |-> ( ( (RTL.id_ex_reg_wen == 1) && (RTL.id_ex_rd == 2'd3) ) && ( (RTL.ex_wb_reg_wen == 0) || (RTL.ex_wb_rd != 2'd3) ) )", + " (RTL.reg_0_w_stage == 2'b11 ) |-> ( ( (RTL.id_ex_reg_wen == 1) && (RTL.id_ex_rd == 2'd0) ) && ( (RTL.ex_wb_reg_wen == 1) && (RTL.ex_wb_rd == 2'd0) ) )", + " (RTL.reg_1_w_stage == 2'b11 ) |-> ( ( (RTL.id_ex_reg_wen == 1) && (RTL.id_ex_rd == 2'd1) ) && ( (RTL.ex_wb_reg_wen == 1) && (RTL.ex_wb_rd == 2'd1) ) )", + " (RTL.reg_2_w_stage == 2'b11 ) |-> ( ( (RTL.id_ex_reg_wen == 1) && (RTL.id_ex_rd == 2'd2) ) && ( (RTL.ex_wb_reg_wen == 1) && (RTL.ex_wb_rd == 2'd2) ) )", + " (RTL.reg_3_w_stage == 2'b11 ) |-> ( ( (RTL.id_ex_reg_wen == 1) && (RTL.id_ex_rd == 2'd3) ) && ( (RTL.ex_wb_reg_wen == 1) && (RTL.ex_wb_rd == 2'd3) ) )", + " (RTL.reg_0_w_stage == 2'b01 ) |-> ( ( (RTL.id_ex_reg_wen == 0) || (RTL.id_ex_rd != 2'd0) ) && ( (RTL.ex_wb_reg_wen == 1) && (RTL.ex_wb_rd == 2'd0) ) )", + " (RTL.reg_1_w_stage == 2'b01 ) |-> ( ( (RTL.id_ex_reg_wen == 0) || (RTL.id_ex_rd != 2'd1) ) && ( (RTL.ex_wb_reg_wen == 1) && (RTL.ex_wb_rd == 2'd1) ) )", + " (RTL.reg_2_w_stage == 2'b01 ) |-> ( ( (RTL.id_ex_reg_wen == 0) || (RTL.id_ex_rd != 2'd2) ) && ( (RTL.ex_wb_reg_wen == 1) && (RTL.ex_wb_rd == 2'd2) ) )", + " (RTL.reg_3_w_stage == 2'b01 ) |-> ( ( (RTL.id_ex_reg_wen == 0) || (RTL.id_ex_rd != 2'd3) ) && ( (RTL.ex_wb_reg_wen == 1) && (RTL.ex_wb_rd == 2'd3) ) )" ], + "ready bound" : 1, // this is the default bound "instructions": [ - { - "instruction": "NOP", - "ready signal": [], - "ready bound": 1 - }, - { - "instruction": "ADD", - "ready signal": [], - "ready bound": 1 - }, + // { // no need + // "instruction": "ADD", + // "ready bound": 1 + // }, { "instruction": "SUB", - "ready signal": [], "ready bound": 1 }, { "instruction": "AND", - "ready signal": [], "ready bound": 1 } ] diff --git a/test/unit-data/vpipe/rfmap/cond.note b/test/unit-data/vpipe/rfmap/cond.note deleted file mode 100644 index 92ffbbc38..000000000 --- a/test/unit-data/vpipe/rfmap/cond.note +++ /dev/null @@ -1,2 +0,0 @@ - - "monitor" : "monitor1", diff --git a/test/unit-data/vpipe/rfmap/vmap-rfmap-pvholder-reset.json b/test/unit-data/vpipe/rfmap/vmap-rfmap-pvholder-reset.json new file mode 100644 index 000000000..34983898b --- /dev/null +++ b/test/unit-data/vpipe/rfmap/vmap-rfmap-pvholder-reset.json @@ -0,0 +1,38 @@ +{ + "state mapping": { + "r0":[ ["__START__", "RTL.registers[0] @ ppl_stage_wb"] , ["1'b1", "RTL.registers[0]"] ] , + "r1":[ ["__START__", "RTL.registers[1] @ ppl_stage_wb"] , ["1'b1", "RTL.registers[1]"] ] , + "r2":[ ["__START__", "RTL.registers[2] @ ppl_stage_wb"] , ["1'b1", "RTL.registers[2]"] ] , + "r3":[ ["__START__", "RTL.registers[3] @ ppl_stage_wb"] , ["1'b1", "RTL.registers[3]"] ] }, + + + "input mapping": { + "inst":"RTL.inst" + }, + + "rtl-interface-connection" : { + "CLOCK" : "clk", + "RESET" : "rst" + }, + + "monitor" :{ + // pipeline tracker + "ppl_stage" : { + "template" : "phase tracker", + "rules" : [ + { // + "name" : "ex", + "enter" : {"event" : "#decode#"}, + "exit" : {"event" : "1"} + }, + + { // + "name" : "wb", + "enter" : {"event" : "#ppl_stage_ex#"}, + "exit" : {"event" : "1"} + } + ] + + } + } +} diff --git a/test/unit-data/vpipe/rfmap/vmap-rfmap-pvholder-stall-short.json b/test/unit-data/vpipe/rfmap/vmap-rfmap-pvholder-stall-short.json new file mode 100644 index 000000000..c7b8e123a --- /dev/null +++ b/test/unit-data/vpipe/rfmap/vmap-rfmap-pvholder-stall-short.json @@ -0,0 +1,47 @@ +{ + "state mapping": { + "r0":[ ["__START__", "RTL.registers[0] @ (#ppl_stage_wb# && RTL.wb_go)"] , ["1'b1", "RTL.registers[0]"] ] , + "r1":[ ["__START__", "RTL.registers[1] @ (#ppl_stage_wb# && RTL.wb_go)"] , ["1'b1", "RTL.registers[1]"] ] , + "r2":[ ["__START__", "RTL.registers[2] @ (#ppl_stage_wb# && RTL.wb_go)"] , ["1'b1", "RTL.registers[2]"] ] , + "r3":[ ["__START__", "RTL.registers[3] @ (#ppl_stage_wb# && RTL.wb_go)"] , ["1'b1", "RTL.registers[3]"] ] }, + + "input mapping": { + "inst":"RTL.inst" + }, + + "rtl-interface-connection" : { + "CLOCK" : "clk", + "RESET" : "rst" + }, + + "monitor" : { + // pipeline tracker + "ppl_stage" : { + "template" : "phase tracker", + "rules" : [ + { // 1 + "name" : "ex", + "enter" : {"event" : "#decode#"}, + "exit" : {"event" : "RTL.ex_go"} + }, + + { // 2 + "name" : "wb", + "enter" : {"event" : "#ppl_stage_ex# && RTL.ex_go"}, + "exit" : {"event" : "RTL.wb_go"} + }, + + { // 3 + "name" : "finish", + "enter" : {"event" : "#ppl_stage_wb# && RTL.wb_go"}, + "exit" : {"event" : "1"} + } + ] + + } + }, // end of monitor + "additional mapping" : [ + "#decode# |-> ( RTL.inst_ready && RTL.inst_valid)", + "#decode# |-> ( RTL.inst == ILA.inst ) " // for the other time, there is no guarantee + ] +} diff --git a/test/unit-data/vpipe/rfmap/vmap-rfmap-pvholder-stall.json b/test/unit-data/vpipe/rfmap/vmap-rfmap-pvholder-stall.json new file mode 100644 index 000000000..adf2d5649 --- /dev/null +++ b/test/unit-data/vpipe/rfmap/vmap-rfmap-pvholder-stall.json @@ -0,0 +1,68 @@ +{ + "state mapping": { + "r0":[ ["__START__", "RTL.registers[0] @ (#ex_wb_iuv# && RTL.wb_go)"] , ["1'b1", "RTL.registers[0]"] ] , + "r1":[ ["__START__", "RTL.registers[1] @ (#ex_wb_iuv# && RTL.wb_go)"] , ["1'b1", "RTL.registers[1]"] ] , + "r2":[ ["__START__", "RTL.registers[2] @ (#ex_wb_iuv# && RTL.wb_go)"] , ["1'b1", "RTL.registers[2]"] ] , + "r3":[ ["__START__", "RTL.registers[3] @ (#ex_wb_iuv# && RTL.wb_go)"] , ["1'b1", "RTL.registers[3]"] ] }, + + "input mapping": { + "inst":"RTL.inst" + }, + + "rtl-interface-connection" : { + "CLOCK" : "clk", + "RESET" : "rst" + }, + + "monitor" : { + "stage_tracker" : { + "verilog": + [ "always @(posedge clk) begin", + " if(rst)", + " if_id_iuv <= 0;", + " else if(__START__)", + " if_id_iuv <= 1;", + " else if(if_id_iuv && RTL.id_go)", + " if_id_iuv <= 0;", + "end", + "", + "always @(posedge clk) begin", + " if(rst)", + " id_ex_iuv <= 0;", + " else if(if_id_iuv && RTL.id_go)", + " id_ex_iuv <= 1;", + " else if(id_ex_iuv && RTL.ex_go)", + " id_ex_iuv <= 0;", + "end", + "", + "always @(posedge clk) begin", + " if(rst)", + " ex_wb_iuv <= 0;", + " else if(id_ex_iuv && RTL.ex_go)", + " ex_wb_iuv <= 1;", + " else if(ex_wb_iuv && RTL.wb_go)", + " ex_wb_iuv <= 0;", + "end", + "", + "always @(posedge clk) begin", + " if(rst)", + " wb_iuv <= 0;", + " else if(ex_wb_iuv && RTL.wb_go)", + " wb_iuv <= 1;", + " else if(wb_iuv )", + " wb_iuv <= 0; // just last for one cycle", + "end"], + "defs" :[ + ["if_id_iuv", 1, "reg"], + ["id_ex_iuv", 1, "reg"], + ["ex_wb_iuv", 1, "reg"], + ["wb_iuv", 1, "reg"] + ], + "refs" :["RTL.if_go", "RTL.id_go", "RTL.ex_go", "RTL.wb_go"] + } + }, // end of monitor + "additional mapping" : [ + "#decode# |-> ( RTL.inst_ready && RTL.inst_valid)", + "#decode# |-> ( RTL.inst == ILA.inst ) " // for the other time, there is no guarantee + ] +} diff --git a/test/unit-data/vpipe/rfmap/vmap-rfmap-pvholder.json b/test/unit-data/vpipe/rfmap/vmap-rfmap-pvholder.json index 975c912d9..a0f700da3 100644 --- a/test/unit-data/vpipe/rfmap/vmap-rfmap-pvholder.json +++ b/test/unit-data/vpipe/rfmap/vmap-rfmap-pvholder.json @@ -1,79 +1,101 @@ { - "models": { "ILA":"m0" , "VERILOG": "m1" }, - "instruction mapping": [], "state mapping": { - "r0":[ ["__START__", "#r0_pvholder#"] , ["1'b1", "m1.registers[0]"] ] , - "r1":[ ["__START__", "#r1_pvholder#"] , ["1'b1", "m1.registers[1]"] ] , - "r2":[ ["__START__", "#r2_pvholder#"] , ["1'b1", "m1.registers[2]"] ] , - "r3":[ ["__START__", "#r3_pvholder#"] , ["1'b1", "m1.registers[3]"] ] }, + "r0":[ ["__START__", "#r0_pvholder#"] , ["1'b1", "RTL.registers[0]"] ] , + "r1":[ ["__START__", "RTL.registers[1] @ ppl_stage_wb"] , ["1'b1", "RTL.registers[1]"] ] , + "r2":[ ["__START__", "RTL.registers[2] @ ppl_stage_wb"] , ["1'b1", "RTL.registers[2]"] ] , + "r3":[ ["__START__", "RTL.registers[3] @ ppl_stage_wb"] , ["1'b1", "RTL.registers[3]"] ] }, - "interface mapping": { - "rst":"**RESET**", - "clk":"**CLOCK**", - "inst":"inst", - "dummy_read_rf":"**KEEP**", - "dummy_rf_data":"**KEEP**" + + "input mapping": { + "inst":"RTL.inst" }, - "value-holder": { - "r0_pvholder" : [ { - "cond": "#stage_tracker# == 1 && 1 == 0", - "val":"m1.registers[0]", - "width":"auto" - }, - { - "cond": "#stage_tracker# == 1 && 1 == 1", - "val":"m1.registers[0]" - } - ], - "r1_pvholder" : { - "cond": "#stage_tracker# == 1", - "val":"m1.registers[1]", - "width":8 - }, - "r2_pvholder" : { - "cond": "#stage_tracker# == 1", - "val":"m1.registers[2]", - "width":8 - }, - "r3_pvholder" : { - "cond": "#stage_tracker# == 1", - "val":"m1.registers[3]", - "width":8 + "rtl-interface-connection" : { + "CLOCK" : "clk", + "RESET" : "rst", + "INPUT" : { + "dummy_read_rf" : "#dummy_read_rf#" + // if you use it here, you must define it in a keep-for-invariants block !!! } }, - "verilog-inline-monitors" : { + + "monitor" :{ + // monitor 1 : value recorder + "r0_pvholder" : { // this is just a name + "template" : "value recorder", + "cond": "#stage_tracker# == 1", + "val":"RTL.registers[0]" + }, + + // monitor 2 : arb verilog - stage tracker and append verilog "stage_tracker" : { "verilog": ["always @(posedge clk) begin", - " if (__START__) stage_tracker <= 0;", + " if (rst ) stage_tracker <= 0;", + " else if ( __START__ ) stage_tracker <= 0;", " else if (__STARTED__ && !__ENDED__) stage_tracker <= stage_tracker + 1;", "end"], + "append-verilog" : "module nouse2(input wire a, output wire b); assign b=a; endmodule", "defs" :[ ["stage_tracker", 2, "reg"] ], "refs" :[] }, + // monitor 3 : ref/def test "ref_test" : { "verilog": ["always @(posedge clk) begin", " if (__START__) ref_test <= 0;", - " else if (__STARTED__ && !__ENDED__ && stage_tracker == 1) ref_test <= m1.registers[0] + 1;", + " else if (__STARTED__ && !__ENDED__ && stage_tracker == 1) ref_test <= RTL.registers[0] + 1;", "end"], "defs" :[ ["ref_test", 2, "reg"] ], - "refs" :[ "m1.registers[0]" ] + "refs" :[ "RTL.registers[0]" ] }, - + // a monitor that always exists "delay_wb_write" : { "verilog": [ "always @(posedge clk) begin", - " delay_wb_write <= m1.ex_wb_val;", - "end" + " delay_wb_write <= (#decode# & #afterdecode#) ? RTL.ex_wb_val : delay_wb_write;", + "end", + "assign usefl = RTL.registers[RTL.ex_wb_rd] ;" ], - "defs" :[ ["delay_wb_write", 8, "reg"] ], - "refs" :[ "m1.ex_wb_val" ], + "append-verilog" : [ + "module nouse(input wire aa, output wire bb);", + " /*keep-for-invariants*/ assign bb=aa;", + " endmodule"], + "defs" :[ ["delay_wb_write", 8, "reg"], ["usefl", 8, "wire"], ["dummy_read_rf", 2, "wire"] ], + "refs" :[ "RTL.ex_wb_val", "#decode#", "#afterdecode#","RTL.registers[RTL.ex_wb_rd]"], + // actually, you should not use #decode# or #afterdecode# here + // because they should not exist when verifying invariants "keep-for-invariants" : true - } + }, + + // pipeline tracker + "ppl_stage" : { + "template" : "phase tracker", + "event-alias" : { + "dsignal" : "ppl_stage_ex ## [1:$] ppl_stage_wb ##1 (1'b1)" + }, + "aux-var" : [["cnt", 2, "reg"]], + "rules" : [ + { // + "name" : "ex", + "enter" : {"event" : "#decode#"}, + "exit" : {"event" : "1", "action": " cnt <= RTL.reg_0_w_stage "} + }, + + { // + "name" : "wb", + "enter" : {"event" : "#ppl_stage_ex#"}, + "exit" : {"event" : "1"} + }, + + { + "name" : "teststage1", + "enter" : "#ppl_stage_ex#" + } + ] - }// end of monitor + } + } } diff --git a/test/unit-data/vpipe/rfmap/vmap-rfmap-stall-short.json b/test/unit-data/vpipe/rfmap/vmap-rfmap-stall-short.json new file mode 100644 index 000000000..208e96ebc --- /dev/null +++ b/test/unit-data/vpipe/rfmap/vmap-rfmap-stall-short.json @@ -0,0 +1,73 @@ +{ + "state mapping": { + + "r0": + [ ["#decode# && RTL.scoreboard[0] == 2'b10 ", " RTL.ex_alu_result == ILA.r0"], + ["#decode# && RTL.scoreboard[0] == 2'b11 ", " RTL.ex_alu_result == ILA.r0"], + ["#decode# && RTL.scoreboard[0] == 2'b01 ", " RTL.ex_wb_val == ILA.r0"], + ["#decode# && RTL.scoreboard[0] == 2'b00 ", " RTL.registers[0] == ILA.r0"], + ["1'b1", "RTL.registers[0]"]] , + + "r1": + [ ["#decode# && RTL.scoreboard[1] == 2'b10 ", "RTL.ex_alu_result == ILA.r1"], + ["#decode# && RTL.scoreboard[1] == 2'b11 ", "RTL.ex_alu_result == ILA.r1"], + ["#decode# && RTL.scoreboard[1] == 2'b01 ", "RTL.ex_wb_val == ILA.r1"], + ["#decode# && RTL.scoreboard[1] == 2'b00 ", "RTL.registers[1] == ILA.r1"], + ["1'b1", "RTL.registers[1]"]], + + "r2": + [ ["#decode# && RTL.scoreboard[2] == 2'b10 ", "RTL.ex_alu_result == ILA.r2"], + ["#decode# && RTL.scoreboard[2] == 2'b11 ", "RTL.ex_alu_result == ILA.r2"], + ["#decode# && RTL.scoreboard[2] == 2'b01 ", "RTL.ex_wb_val == ILA.r2"], + ["#decode# && RTL.scoreboard[2] == 2'b00 ", "RTL.registers[2] == ILA.r2"], + ["1'b1", "RTL.registers[2]"]], + + "r3": + + [ ["#decode# && RTL.scoreboard[3] == 2'b10 " , "RTL.ex_alu_result"], + ["#decode# && RTL.scoreboard[3] == 2'b11 " , "RTL.ex_alu_result"], + ["#decode# && RTL.scoreboard[3] == 2'b01 " , " RTL.ex_wb_val == ILA.r3"], + ["#decode# && RTL.scoreboard[3] == 2'b00 " , " RTL.registers[3] == ILA.r3"], + ["1'b1", "RTL.registers[3]"]] + }, + + "input mapping": { + "inst":"RTL.inst" + }, + + "rtl-interface-connection" : { + "CLOCK" : "clk", + "RESET" : "rst" + }, + + "monitor" : { + // pipeline tracker + "ppl_stage" : { + "template" : "phase tracker", + "rules" : [ + { // 1 + "name" : "ex", + "enter" : {"event" : "#decode#"}, + "exit" : {"event" : "RTL.ex_go"} + }, + + { // 2 + "name" : "wb", + "enter" : {"event" : "#ppl_stage_ex# && RTL.ex_go"}, + "exit" : {"event" : "RTL.wb_go"} + }, + + { // 3 + "name" : "finish", + "enter" : {"event" : "#ppl_stage_wb# && RTL.wb_go"}, + "exit" : {"event" : "1"} + } + ] + + } + }, // end of monitor + "additional mapping" : [ + "#decode# |-> ( RTL.inst_ready && RTL.inst_valid)", + "#decode# |-> ( RTL.inst == ILA.inst ) " // for the other time, there is no guarantee + ] +} diff --git a/test/unit-data/vpipe/rfmap/vmap.json b/test/unit-data/vpipe/rfmap/vmap.json index 52dbc555c..33a1a9849 100644 --- a/test/unit-data/vpipe/rfmap/vmap.json +++ b/test/unit-data/vpipe/rfmap/vmap.json @@ -1,36 +1,40 @@ { - "models": { "ILA":"m0" , "VERILOG": "m1" }, - "instruction mapping": [], "state mapping": { "r0": - [ "~( m1.reg_0_w_stage == 2'b10 ) || (m1.ex_alu_result == m0.r0)", - "~( m1.reg_0_w_stage == 2'b11 ) || (m1.ex_alu_result == m0.r0)", - "~( m1.reg_0_w_stage == 2'b01 ) || (m1.ex_wb_val == m0.r0)", - "~( m1.reg_0_w_stage == 2'b00 ) || (m1.registers[0] == m0.r0)"] , + [ [" RTL.reg_0_w_stage == 2'b10 ", " RTL.ex_alu_result == ILA.r0"], + [" RTL.reg_0_w_stage == 2'b11 ", " RTL.ex_alu_result == ILA.r0"], + [" RTL.reg_0_w_stage == 2'b01 ", " RTL.ex_wb_val == ILA.r0"], + [" RTL.reg_0_w_stage == 2'b00 ", " RTL.registers[0] == ILA.r0"]] , "r1": - [ "~( m1.reg_1_w_stage == 2'b10 ) || (m1.ex_alu_result == m0.r1)", - "~( m1.reg_1_w_stage == 2'b11 ) || (m1.ex_alu_result == m0.r1)", - "~( m1.reg_1_w_stage == 2'b01 ) || (m1.ex_wb_val == m0.r1)", - "~( m1.reg_1_w_stage == 2'b00 ) || (m1.registers[1] == m0.r1)"], + [ [" RTL.reg_1_w_stage == 2'b10 ", "RTL.ex_alu_result == ILA.r1"], + [" RTL.reg_1_w_stage == 2'b11 ", "RTL.ex_alu_result == ILA.r1"], + [" RTL.reg_1_w_stage == 2'b01 ", "RTL.ex_wb_val == ILA.r1"], + [" RTL.reg_1_w_stage == 2'b00 ", "RTL.registers[1] == ILA.r1"]], "r2": - [ "~( m1.reg_2_w_stage == 2'b10 ) || (m1.ex_alu_result == m0.r2)", - "~( m1.reg_2_w_stage == 2'b11 ) || (m1.ex_alu_result == m0.r2)", - "~( m1.reg_2_w_stage == 2'b01 ) || (m1.ex_wb_val == m0.r2)", - "~( m1.reg_2_w_stage == 2'b00 ) || (m1.registers[2] == m0.r2)"], + [ ["RTL.reg_2_w_stage == 2'b10 ", "RTL.ex_alu_result == ILA.r2"], + ["RTL.reg_2_w_stage == 2'b11 ", "RTL.ex_alu_result == ILA.r2"], + ["RTL.reg_2_w_stage == 2'b01 ", "RTL.ex_wb_val == ILA.r2"], + ["RTL.reg_2_w_stage == 2'b00 ", "RTL.registers[2] == ILA.r2"]], "r3": - [ {"cond":" m1.reg_3_w_stage == 2'b10 " , "map":"m1.ex_alu_result"}, - {"cond":" m1.reg_3_w_stage == 2'b11 " , "map":"ex_alu_result"}, - {"cond":" m1.reg_3_w_stage == 2'b01 " , "map":" m1.ex_wb_val == m0.r3"}, - {"cond":" m1.reg_3_w_stage == 2'b00 " , "map":" m1.registers[3] == m0.r3"}]}, + [ ["RTL.reg_3_w_stage == 2'b10 " , "RTL.ex_alu_result"], + ["RTL.reg_3_w_stage == 2'b11 " , "RTL.ex_alu_result"], + ["RTL.reg_3_w_stage == 2'b01 " , " RTL.ex_wb_val == ILA.r3"], + ["RTL.reg_3_w_stage == 2'b00 " , " RTL.registers[3] == ILA.r3"]] + }, - "interface mapping": { - "rst":"**RESET**", - "clk":"**CLOCK**", - "inst":"inst", - "dummy_read_rf":"**KEEP**", - "dummy_rf_data":"**SO**" + "input mapping": { + "inst":"RTL.inst" }, - // the following line has no use, it is just a case of finding wire - "mapping control" : ["m1.reg_0_w_stage_nxt != 2'b11"] + + "RTL interface connection" : { + "CLOCK" : "clk", + "RESET" : "rst" + }, + + "monitor" : { + // this will not use for invariant by default + // because "@1" means nothing without instructions + "test_aux_var" : "RTL.ex_wb_val@1 + 1" + } } diff --git a/test/unit-data/vpipe/rfmap/vmap.note b/test/unit-data/vpipe/rfmap/vmap.note deleted file mode 100644 index f430c23f9..000000000 --- a/test/unit-data/vpipe/rfmap/vmap.note +++ /dev/null @@ -1,24 +0,0 @@ - -// additional mapping -"wr" : "**KEEP**" // by default -"addr": "cmd_addr" -"data_in": "cmd_data" -"data_out": "**SO**" -"ack": "**KEEP**" -"stb": "**KEEP**" - -"xram_ack":"**KEEP**" -"xram_data_out":"**MEM**xram.wdata" -"xram_addr":"**MEM**xram.waddr" -"xram_wr":"**KEEP**" -"xram_stb":"**KEEP**" -// add invariant: (xram_wr&xram_stb) == xram.w_en -// you need to create memory -"xram_addr": "**MEM**xram.raddr.0" -"xram_data_in": "**MEM**xram.rdata.0" - - -"aes_state":"**SO**" -"aes_addr":"**SO**" - -"mapping control" :["(xram_wr&xram_stb) == MEM_xram.wen"] diff --git a/test/unit-data/vpipe/rfmap_t/cond-1.json b/test/unit-data/vpipe/rfmap_t/cond-1.json new file mode 100644 index 000000000..8a2f1bcf6 --- /dev/null +++ b/test/unit-data/vpipe/rfmap_t/cond-1.json @@ -0,0 +1,41 @@ +{ + // this is a comment + "global invariants": [ + " (RTL.reg_0_w_stage == 2'b00 ) |-> ( ( (RTL.id_ex_reg_wen == 0) || (RTL.id_ex_rd != 2'd0) ) && ( (RTL.ex_wb_reg_wen == 0) || (RTL.ex_wb_rd != 2'd0) ) )", + " (RTL.reg_1_w_stage == 2'b00 ) |-> ( ( (RTL.id_ex_reg_wen == 0) || (RTL.id_ex_rd != 2'd1) ) && ( (RTL.ex_wb_reg_wen == 0) || (RTL.ex_wb_rd != 2'd1) ) )", + " (RTL.reg_2_w_stage == 2'b00 ) |-> ( ( (RTL.id_ex_reg_wen == 0) || (RTL.id_ex_rd != 2'd2) ) && ( (RTL.ex_wb_reg_wen == 0) || (RTL.ex_wb_rd != 2'd2) ) )", + " (RTL.reg_3_w_stage == 2'b00 ) |-> ( ( (RTL.id_ex_reg_wen == 0) || (RTL.id_ex_rd != 2'd3) ) && ( (RTL.ex_wb_reg_wen == 0) || (RTL.ex_wb_rd != 2'd3) ) )", + " (RTL.reg_0_w_stage == 2'b10 ) |-> ( ( (RTL.id_ex_reg_wen == 1) && (RTL.id_ex_rd == 2'd0) ) && ( (RTL.ex_wb_reg_wen == 0) || (RTL.ex_wb_rd != 2'd0) ) )", + " (RTL.reg_1_w_stage == 2'b10 ) |-> ( ( (RTL.id_ex_reg_wen == 1) && (RTL.id_ex_rd == 2'd1) ) && ( (RTL.ex_wb_reg_wen == 0) || (RTL.ex_wb_rd != 2'd1) ) )", + " (RTL.reg_2_w_stage == 2'b10 ) |-> ( ( (RTL.id_ex_reg_wen == 1) && (RTL.id_ex_rd == 2'd2) ) && ( (RTL.ex_wb_reg_wen == 0) || (RTL.ex_wb_rd != 2'd2) ) )", + " (RTL.reg_3_w_stage == 2'b10 ) |-> ( ( (RTL.id_ex_reg_wen == 1) && (RTL.id_ex_rd == 2'd3) ) && ( (RTL.ex_wb_reg_wen == 0) || (RTL.ex_wb_rd != 2'd3) ) )", + " (RTL.reg_0_w_stage == 2'b11 ) |-> ( ( (RTL.id_ex_reg_wen == 1) && (RTL.id_ex_rd == 2'd0) ) && ( (RTL.ex_wb_reg_wen == 1) && (RTL.ex_wb_rd == 2'd0) ) )", + " (RTL.reg_1_w_stage == 2'b11 ) |-> ( ( (RTL.id_ex_reg_wen == 1) && (RTL.id_ex_rd == 2'd1) ) && ( (RTL.ex_wb_reg_wen == 1) && (RTL.ex_wb_rd == 2'd1) ) )", + " (RTL.reg_2_w_stage == 2'b11 ) |-> ( ( (RTL.id_ex_reg_wen == 1) && (RTL.id_ex_rd == 2'd2) ) && ( (RTL.ex_wb_reg_wen == 1) && (RTL.ex_wb_rd == 2'd2) ) )", + " (RTL.reg_3_w_stage == 2'b11 ) |-> ( ( (RTL.id_ex_reg_wen == 1) && (RTL.id_ex_rd == 2'd3) ) && ( (RTL.ex_wb_reg_wen == 1) && (RTL.ex_wb_rd == 2'd3) ) )", + " (RTL.reg_0_w_stage == 2'b01 ) |-> ( ( (RTL.id_ex_reg_wen == 0) || (RTL.id_ex_rd != 2'd0) ) && ( (RTL.ex_wb_reg_wen == 1) && (RTL.ex_wb_rd == 2'd0) ) )", + " (RTL.reg_1_w_stage == 2'b01 ) |-> ( ( (RTL.id_ex_reg_wen == 0) || (RTL.id_ex_rd != 2'd1) ) && ( (RTL.ex_wb_reg_wen == 1) && (RTL.ex_wb_rd == 2'd1) ) )", + " (RTL.reg_2_w_stage == 2'b01 ) |-> ( ( (RTL.id_ex_reg_wen == 0) || (RTL.id_ex_rd != 2'd2) ) && ( (RTL.ex_wb_reg_wen == 1) && (RTL.ex_wb_rd == 2'd2) ) )", + " (RTL.reg_3_w_stage == 2'b01 ) |-> ( ( (RTL.id_ex_reg_wen == 0) || (RTL.id_ex_rd != 2'd3) ) && ( (RTL.ex_wb_reg_wen == 1) && (RTL.ex_wb_rd == 2'd3) ) )" + ], + + "instructions": [ + { + "instruction": "NOP", + "ready signal": "#stage_tracker# == 2" + }, + { + "instruction": "ADD", + "ready signal": "#stage_tracker# == 2" + }, + { + "instruction": "SUB", + "ready signal": "#stage_tracker# == 2" + }, + { + "instruction": "AND", + "ready signal": "#ppl_stage_wb# ## 1" + } + ] +} + diff --git a/test/unit-data/vpipe/rfmap_t/vmap-1.json b/test/unit-data/vpipe/rfmap_t/vmap-1.json new file mode 100644 index 000000000..1c39e5dd1 --- /dev/null +++ b/test/unit-data/vpipe/rfmap_t/vmap-1.json @@ -0,0 +1,108 @@ +{ + "state mapping": { + "r0":[ ["__START__", "#r0_pvholder#"] , ["1'b1", "RTL.registers[0]"] ] , + "r1":[ ["__START__", "RTL.registers[1] @ ppl_stage_wb"] , ["1'b1", "RTL.registers[1]"] ] , + "r2":[ ["__START__", "RTL.registers[2] @ ppl_stage_wb"] , ["1'b1", "RTL.registers[2]"] ] , + "r3":[ ["__START__", "RTL.registers[3] @ ppl_stage_wb"] , ["1'b1", "RTL.registers[3]"] ] }, + + + "input mapping": { + "inst":"RTL.inst" + }, + + "rtl-interface-connection" : { + "CLOCK" : "clk", + "RESET" : "rst", + "INPUT" : { + "dummy_read_rf" : "#dummy_read_rf#" + // if you use it here, you must define it in a keep-for-invariants block !!! + } + }, + + "monitor" :{ + // monitor 1 : value recorder + "r0_pvholder" : { // this is just a name + "template" : "value recorder", + "cond": "#stage_tracker# == 1", + "val":"RTL.registers[0]" + }, + + // monitor 2 : arb verilog - stage tracker and append verilog + "stage_tracker" : { + "verilog": + ["always @(posedge clk) begin", + " if (rst ) stage_tracker <= 0;", + " else if ( __START__ ) stage_tracker <= 0;", + " else if (__STARTED__ && !__ENDED__) stage_tracker <= stage_tracker + 1;", + "end"], + "append-verilog" : "module nouse2(input wire a, output wire b); assign b=a; endmodule", + "defs" :[ ["stage_tracker", 2, "reg"] ], + "refs" :[] + }, + + // monitor 3 : ref/def test + "ref_test" : { + "verilog": + ["always @(posedge clk) begin", + " if (__START__) ref_test <= 0;", + " else if (__STARTED__ && !__ENDED__ && stage_tracker == 1) ref_test <= RTL.registers[0] + 1;", + "end"], + "defs" :[ ["ref_test", 2, "reg"] ], + "refs" :[ "RTL.registers[0]" ] + }, + + // a monitor that always exists + "delay_wb_write" : { + "verilog": + [ "always @(posedge clk) begin", + " delay_wb_write <= (#decode# & #afterdecode#) ? RTL.ex_wb_val : delay_wb_write;", + "end", + "assign usefl = RTL.registers[RTL.ex_wb_rd] ;" + ], + "append-verilog" : [ + "module nouse(input wire aa, output wire bb);", + " /*keep-for-invariants*/ assign bb=aa;", + " endmodule"], + "defs" :[ ["delay_wb_write", 8, "reg"], ["usefl", 8, "wire"], ["dummy_read_rf", 2, "wire"] ], + "refs" :[ "RTL.ex_wb_val", "#decode#", "#afterdecode#","RTL.registers[RTL.ex_wb_rd]"], + // actually, you should not use #decode# or #afterdecode# here + // because they should not exist when verifying invariants + "keep-for-invariants" : true + }, + + "rt7" : "RTL.inst[0]@0", + "rt2" : "RTL.inst @ 1", + "rt22" : " RTL.inst @ 2", + "rt0" : "rt7 ? rt2 : rt22", + "rt1" : "rt7 ? rt2 : rt0", + + + // pipeline tracker + "ppl_stage" : { + "template" : "phase tracker", + "event-alias" : { + "dsignal" : "ppl_stage_ex ## [1:$] ppl_stage_wb ##1 (1'b1)" + }, + "aux-var" : [["cnt", 2, "reg"]], + "rules" : [ + { // + "name" : "ex", + "enter" : {"event" : "#decode#"}, + "exit" : {"event" : "1", "action": " cnt <= RTL.reg_0_w_stage "} + }, + + { // + "name" : "wb", + "enter" : {"event" : "#ppl_stage_ex#"}, + "exit" : {"event" : "1"} + }, + + { + "name" : "teststage1", + "enter" : "#ppl_stage_ex#" + } + ] + + } + } +} diff --git a/test/unit-data/vpipe/rfmap_t_out/.placeholder b/test/unit-data/vpipe/rfmap_t_out/.placeholder new file mode 100644 index 000000000..e69de29bb diff --git a/test/unit-data/vpipe/rfmap_t_out/t1/.gitignore b/test/unit-data/vpipe/rfmap_t_out/t1/.gitignore new file mode 100644 index 000000000..72e8ffc0d --- /dev/null +++ b/test/unit-data/vpipe/rfmap_t_out/t1/.gitignore @@ -0,0 +1 @@ +* diff --git a/test/unit-data/vpipe/simple_pipe.v b/test/unit-data/vpipe/simple_pipe.v index 82c47d975..fb37ce94d 100644 --- a/test/unit-data/vpipe/simple_pipe.v +++ b/test/unit-data/vpipe/simple_pipe.v @@ -18,7 +18,7 @@ `define OP_SUB 2'b10 `define OP_AND 2'b11 -module pipeline_v(input clk, input rst, input [7:0] inst, input [1:0] dummy_read_rf, output [7:0] dummy_rf_data +module pipeline_v(input wire clk, input wire rst, input wire [7:0] inst, input wire [1:0] dummy_read_rf, output wire [7:0] dummy_rf_data ); wire [1:0] op; @@ -76,10 +76,7 @@ assign rs2= inst[3:2]; assign rd = inst[1:0]; assign id_wen = op == `OP_ADD || op == `OP_SUB || op == `OP_AND; -assign dummy_rf_data = dummy_read_rf == 0 ? registers[0] : - dummy_read_rf == 1 ? registers[1] : - dummy_read_rf == 2 ? registers[2] : - registers[3]; +assign dummy_rf_data = registers[dummy_read_rf]; @@ -198,21 +195,8 @@ end // WB always @(posedge clk ) begin - if (rst) begin - // reset - registers[0] <= 8'd0; - registers[1] <= 8'd0; - registers[2] <= 8'd0; - registers[3] <= 8'd0; - end - else if (ex_wb_reg_wen) begin - case (ex_wb_rd) - 2'd0: registers[0] <= ex_wb_val; - 2'd1: registers[1] <= ex_wb_val; - 2'd2: registers[2] <= ex_wb_val; - 2'd3: registers[3] <= ex_wb_val; - default: registers[0] <= ex_wb_val; // nouse - endcase + if (ex_wb_reg_wen) begin + registers[ex_wb_rd] <= ex_wb_val; end end diff --git a/test/unit-data/vpipe/simple_pipe_stall.v b/test/unit-data/vpipe/simple_pipe_stall.v new file mode 100644 index 000000000..8bc9c1605 --- /dev/null +++ b/test/unit-data/vpipe/simple_pipe_stall.v @@ -0,0 +1,304 @@ +`default_nettype none + +// Hongce Zhang @ Princeton +// A simple pipelined processor +// that can only do add/sub/nop/and +// with only 4 registers +// for simplicity, we even make the instruction part +// as input +// ADD/SUB/AND 2-bit op, 2-bit rs1, 2-bit rs2, 2-bit rd +// SET 2-bit op, 4bit imm 2-bit rd + +// -- ID --|-- EX --|-- WB +// ^ | | +// | | | +// ------------------- +// forwarding + +`define OP_NOP 2'b00 +`define OP_ADD 2'b01 +`define OP_SET 2'b10 +`define OP_NAND 2'b11 + +module pipeline_v( + input wire clk, input wire rst, + input wire [7:0] inst, input wire inst_valid, output wire inst_ready, + input wire stallex, input wire stallwb, + input wire [1:0] dummy_read_rf, output wire [7:0] dummy_rf_data +); + +// TODO: finish this +// check invariant +// run inst sim + + +// main pipeline +reg [7:0] if_id_inst; +// can be removed +reg [7:0] id_ex_inst; +reg [7:0] ex_wb_inst; + +reg [7:0] id_ex_operand1; +reg [7:0] id_ex_operand2; +reg [1:0] id_ex_op; +reg [1:0] id_ex_rd; +reg id_ex_reg_wen; + +reg [7:0] ex_wb_val; +reg [1:0] ex_wb_rd; +reg ex_wb_reg_wen; + +reg [7:0] registers[3:0]; + + +// interlocking +// using ready valid signal + +wire stallif = 0; +wire if_go; + +reg if_id_valid; +wire id_if_ready; +wire id_go; +wire stallid = 0; + +reg id_ex_valid; +wire ex_id_ready; +wire ex_go; + +reg ex_wb_valid; +wire wb_ex_ready; +wire wb_go; + + +// +// IF --|-- ID --|-- EX --|-- WB +// ^ | | +// | | | +// ------------------- +// forwarding logic + +wire [1:0] forwarding_id_wdst; +wire forwarding_id_wen; +wire [1:0] forwarding_ex_wdst; +wire forwarding_ex_wen; + + +// plus ex_go +wire [7:0] ex_forwarding_val; + +// plus wb_go +wire [7:0] wb_forwarding_val; + +reg [1:0] scoreboard[0:3]; // for reg 0-3 + +// -------------------------------------- +// scoreboard +wire [1:0] scoreboard_nxt[0:3]; + +assign scoreboard_nxt[0][1] = + id_go ? forwarding_id_wen && forwarding_id_wdst == 2'd0 : + ex_go ? 1'b0 : scoreboard[0][1]; + +assign scoreboard_nxt[0][0] = + ex_go ? forwarding_ex_wen && forwarding_ex_wdst == 2'd0 : + wb_go ? 1'b0 : scoreboard[0][0]; + +assign scoreboard_nxt[1][1] = + id_go ? forwarding_id_wen && forwarding_id_wdst == 2'd1 : + ex_go ? 1'b0 : scoreboard[1][1]; + +assign scoreboard_nxt[1][0] = + ex_go ? forwarding_ex_wen && forwarding_ex_wdst == 2'd1 : + wb_go ? 1'b0 : scoreboard[1][0]; + +assign scoreboard_nxt[2][1] = + id_go ? forwarding_id_wen && forwarding_id_wdst == 2'd2 : + ex_go ? 1'b0 : scoreboard[2][1]; + +assign scoreboard_nxt[2][0] = + ex_go ? forwarding_ex_wen && forwarding_ex_wdst == 2'd2 : + wb_go ? 1'b0 : scoreboard[2][0]; + +assign scoreboard_nxt[3][1] = + id_go ? forwarding_id_wen && forwarding_id_wdst == 2'd3 : + ex_go ? 1'b0 : scoreboard[3][1]; + +assign scoreboard_nxt[3][0] = + ex_go ? forwarding_ex_wen && forwarding_ex_wdst == 2'd3 : + wb_go ? 1'b0 : scoreboard[3][0]; + +// in reality, this will be generate +always @(posedge clk) begin + if (rst) begin + scoreboard[0] <= 0; + scoreboard[1] <= 0; + scoreboard[2] <= 0; + scoreboard[3] <= 0; + end else begin + scoreboard[0] <= scoreboard_nxt[0]; + scoreboard[1] <= scoreboard_nxt[1]; + scoreboard[2] <= scoreboard_nxt[2]; + scoreboard[3] <= scoreboard_nxt[3]; + end +end + +// -------------------------------------- +// IF + +assign inst_ready = ~stallif && (id_if_ready || ~if_id_valid); +assign if_go = inst_valid && inst_ready; + +always @(posedge clk) begin + if(rst) begin + if_id_valid <= 0; + end + if(if_go) begin + if_id_valid <= inst_valid && ~stallif; + if_id_inst <= inst; + end else begin + if(id_go) + if_id_valid <= 1'b0; + end +end + +// -------------------------------------- +// ID + +// datapath +wire [1:0] op = if_id_inst[7:6]; +wire [1:0] rs1= if_id_inst[5:4]; +wire [1:0] rs2= if_id_inst[3:2]; +wire [1:0] rd = if_id_inst[1:0]; +wire [7:0] immd = {4'd0, if_id_inst[5:2]}; +wire id_wen = op == `OP_ADD || op == `OP_SET || op == `OP_NAND; + +wire [1:0] rs1_write_loc = scoreboard[rs1]; +wire [1:0] rs2_write_loc = scoreboard[rs2]; +wire [7:0] rs1_val = registers[rs1]; +wire [7:0] rs2_val = registers[rs2]; + +wire [7:0] id_rs1_val = rs1_write_loc == 2'b00 ? rs1_val : + rs1_write_loc == 2'b01 ? wb_forwarding_val : + ex_forwarding_val ; // 10/11 + +wire [7:0] id_rs2_val = rs2_write_loc == 2'b00 ? rs2_val : + rs2_write_loc == 2'b01 ? wb_forwarding_val : + ex_forwarding_val ; // 10/11 + +wire [7:0] id_operand1 = op == `OP_SET ? immd : id_rs1_val; +wire [7:0] id_operand2 = id_rs2_val; + +// forwarding output +assign forwarding_id_wdst = rd; +assign forwarding_id_wen = if_id_valid && id_wen; + +// control +assign id_if_ready = !stallid && + ( ex_id_ready || ( !id_ex_valid ) ); +assign id_go = if_id_valid & id_if_ready; + + +always @(posedge clk) begin + if(rst) begin + id_ex_reg_wen <= 1'b0; + id_ex_valid <= 1'b0; + end + else begin + if(id_go) begin + id_ex_inst <= if_id_inst; + + id_ex_valid <= if_id_valid & ~stallid; + id_ex_op <= op; + id_ex_reg_wen <= id_wen; + id_ex_rd <= rd; + id_ex_operand1 <= id_operand1; + id_ex_operand2 <= id_operand2; + end else begin + if(ex_go) + id_ex_valid <= 1'b0; + end + end +end + +// -------------------------------------- +// EX + +// datapath +wire[7:0] ex_alu_result = id_ex_op == `OP_ADD ? id_ex_operand1 + id_ex_operand2 : + id_ex_op == `OP_SET ? id_ex_operand1 : + id_ex_op == `OP_NAND ? ~(id_ex_operand1 & id_ex_operand2) : + 8'bxxxxxxxx; // `OP_NOP +assign ex_forwarding_val = ex_alu_result; + +assign forwarding_ex_wdst = id_ex_rd; +assign forwarding_ex_wen = id_ex_valid && id_ex_reg_wen; + +// control +assign ex_id_ready = !stallex && + ( wb_ex_ready || ( !ex_wb_valid ) ); +// stallex wb_ex_ready ex_wb_valid ex_id_ready +// 1 x x 0 +// 0 1 x 1 +// 0 0 0 1 +// 0 0 1 0 + +assign ex_go = id_ex_valid && ex_id_ready; + + +always @(posedge clk) begin + if (rst) begin + // reset + ex_wb_reg_wen <= 1'b0; + ex_wb_valid <= 1'b0; + end + else begin + if (ex_go) begin + ex_wb_inst <= id_ex_inst; + + ex_wb_valid <= id_ex_valid && !stallex; + ex_wb_reg_wen <= id_ex_reg_wen; + ex_wb_val <= ex_alu_result; + ex_wb_rd <= id_ex_rd; + end else begin + if(wb_go) + ex_wb_valid <= 1'b0; + end + end +end + + +// -------------------------------------- + + +// WB +assign wb_ex_ready = !stallwb; +assign wb_go = ex_wb_valid && wb_ex_ready; + +assign wb_forwarding_val = ex_wb_val; + +always @(posedge clk ) begin + if (wb_go && ex_wb_reg_wen) begin + registers[ex_wb_rd] <= ex_wb_val; + end +end + +// dummy read +assign dummy_rf_data = registers[dummy_read_rf]; + + +// formal properties +/* +assert property (scoreboard[0][1] == ( id_ex_valid && id_ex_reg_wen && id_ex_rd == 2'd0)); +assert property (scoreboard[0][0] == ( ex_wb_valid && ex_wb_reg_wen && ex_wb_rd == 2'd0)); + +assert property (scoreboard[1][1] == ( id_ex_valid && id_ex_reg_wen && id_ex_rd == 2'd1)); +assert property (scoreboard[1][0] == ( ex_wb_valid && ex_wb_reg_wen && ex_wb_rd == 2'd1)); + +assert property (scoreboard[2][1] == ( id_ex_valid && id_ex_reg_wen && id_ex_rd == 2'd2)); +assert property (scoreboard[2][0] == ( ex_wb_valid && ex_wb_reg_wen && ex_wb_rd == 2'd2)); + +assert property (scoreboard[3][1] == ( id_ex_valid && id_ex_reg_wen && id_ex_rd == 2'd3)); +assert property (scoreboard[3][0] == ( ex_wb_valid && ex_wb_reg_wen && ex_wb_rd == 2'd3)); +*/ +endmodule diff --git a/test/unit-data/vpipe/simple_pipe_stall_short.v b/test/unit-data/vpipe/simple_pipe_stall_short.v new file mode 100644 index 000000000..e225515f8 --- /dev/null +++ b/test/unit-data/vpipe/simple_pipe_stall_short.v @@ -0,0 +1,290 @@ +`default_nettype none + +// Hongce Zhang @ Princeton +// A simple pipelined processor +// that can only do add/sub/nop/and +// with only 4 registers +// for simplicity, we even make the instruction part +// as input +// ADD/SUB/AND 2-bit op, 2-bit rs1, 2-bit rs2, 2-bit rd +// SET 2-bit op, 4bit imm 2-bit rd + +// -- ID --|-- EX --|-- WB +// ^ | | +// | | | +// ------------------- +// forwarding + +`define OP_NOP 2'b00 +`define OP_ADD 2'b01 +`define OP_SET 2'b10 +`define OP_NAND 2'b11 + +module pipeline_v( + input wire clk, input wire rst, + input wire [7:0] inst, input wire inst_valid, output wire inst_ready, + input wire stallex, input wire stallwb, + input wire [1:0] dummy_read_rf, output wire [7:0] dummy_rf_data +); + +// TODO: finish this +// check invariant +// run inst sim + + +// main pipeline +wire [7:0] if_id_inst; +// can be removed +reg [7:0] id_ex_inst; +reg [7:0] ex_wb_inst; + +reg [7:0] id_ex_operand1; +reg [7:0] id_ex_operand2; +reg [1:0] id_ex_op; +reg [1:0] id_ex_rd; +reg id_ex_reg_wen; + +reg [7:0] ex_wb_val; +reg [1:0] ex_wb_rd; +reg ex_wb_reg_wen; + +reg [7:0] registers[3:0]; + + +// interlocking +// using ready valid signal + + +wire if_id_valid; +wire id_if_ready; +wire id_go; +wire stallid = 0; + +reg id_ex_valid; +wire ex_id_ready; +wire ex_go; + +reg ex_wb_valid; +wire wb_ex_ready; +wire wb_go; + + +// +// IF --|-- ID --|-- EX --|-- WB +// ^ | | +// | | | +// ------------------- +// forwarding logic + +wire [1:0] forwarding_id_wdst; +wire forwarding_id_wen; +wire [1:0] forwarding_ex_wdst; +wire forwarding_ex_wen; + + +// plus ex_go +wire [7:0] ex_forwarding_val; + +// plus wb_go +wire [7:0] wb_forwarding_val; + +reg [1:0] scoreboard[0:3]; // for reg 0-3 + +// -------------------------------------- +// scoreboard +wire [1:0] scoreboard_nxt[0:3]; + +assign scoreboard_nxt[0][1] = + id_go ? forwarding_id_wen && forwarding_id_wdst == 2'd0 : + ex_go ? 1'b0 : scoreboard[0][1]; + +assign scoreboard_nxt[0][0] = + ex_go ? forwarding_ex_wen && forwarding_ex_wdst == 2'd0 : + wb_go ? 1'b0 : scoreboard[0][0]; + +assign scoreboard_nxt[1][1] = + id_go ? forwarding_id_wen && forwarding_id_wdst == 2'd1 : + ex_go ? 1'b0 : scoreboard[1][1]; + +assign scoreboard_nxt[1][0] = + ex_go ? forwarding_ex_wen && forwarding_ex_wdst == 2'd1 : + wb_go ? 1'b0 : scoreboard[1][0]; + +assign scoreboard_nxt[2][1] = + id_go ? forwarding_id_wen && forwarding_id_wdst == 2'd2 : + ex_go ? 1'b0 : scoreboard[2][1]; + +assign scoreboard_nxt[2][0] = + ex_go ? forwarding_ex_wen && forwarding_ex_wdst == 2'd2 : + wb_go ? 1'b0 : scoreboard[2][0]; + +assign scoreboard_nxt[3][1] = + id_go ? forwarding_id_wen && forwarding_id_wdst == 2'd3 : + ex_go ? 1'b0 : scoreboard[3][1]; + +assign scoreboard_nxt[3][0] = + ex_go ? forwarding_ex_wen && forwarding_ex_wdst == 2'd3 : + wb_go ? 1'b0 : scoreboard[3][0]; + +// in reality, this will be generate +always @(posedge clk) begin + if (rst) begin + scoreboard[0] <= 0; + scoreboard[1] <= 0; + scoreboard[2] <= 0; + scoreboard[3] <= 0; + end else begin + scoreboard[0] <= scoreboard_nxt[0]; + scoreboard[1] <= scoreboard_nxt[1]; + scoreboard[2] <= scoreboard_nxt[2]; + scoreboard[3] <= scoreboard_nxt[3]; + end +end + +// -------------------------------------- +// IF + +assign inst_ready = id_if_ready; +assign if_id_inst = inst; +assign if_id_valid = inst_valid; + +// -------------------------------------- +// ID + +// datapath +wire [1:0] op = if_id_inst[7:6]; +wire [1:0] rs1= if_id_inst[5:4]; +wire [1:0] rs2= if_id_inst[3:2]; +wire [1:0] rd = if_id_inst[1:0]; +wire [7:0] immd = {4'd0, if_id_inst[5:2]}; +wire id_wen = op == `OP_ADD || op == `OP_SET || op == `OP_NAND; + +wire [1:0] rs1_write_loc = scoreboard[rs1]; +wire [1:0] rs2_write_loc = scoreboard[rs2]; +wire [7:0] rs1_val = registers[rs1]; +wire [7:0] rs2_val = registers[rs2]; + +wire [7:0] id_rs1_val = rs1_write_loc == 2'b00 ? rs1_val : + rs1_write_loc == 2'b01 ? wb_forwarding_val : + ex_forwarding_val ; // 10/11 + +wire [7:0] id_rs2_val = rs2_write_loc == 2'b00 ? rs2_val : + rs2_write_loc == 2'b01 ? wb_forwarding_val : + ex_forwarding_val ; // 10/11 + +wire [7:0] id_operand1 = op == `OP_SET ? immd : id_rs1_val; +wire [7:0] id_operand2 = id_rs2_val; + +// forwarding output +assign forwarding_id_wdst = rd; +assign forwarding_id_wen = if_id_valid && id_wen; + +// control +assign id_if_ready = !stallid && + ( ex_id_ready || ( !id_ex_valid ) ); +assign id_go = if_id_valid & id_if_ready; + + +always @(posedge clk) begin + if(rst) begin + id_ex_reg_wen <= 1'b0; + id_ex_valid <= 1'b0; + end + else begin + if(id_go) begin + id_ex_inst <= if_id_inst; + + id_ex_valid <= if_id_valid & ~stallid; + id_ex_op <= op; + id_ex_reg_wen <= id_wen; + id_ex_rd <= rd; + id_ex_operand1 <= id_operand1; + id_ex_operand2 <= id_operand2; + end else begin + if(ex_go) + id_ex_valid <= 1'b0; + end + end +end + +// -------------------------------------- +// EX + +// datapath +wire[7:0] ex_alu_result = id_ex_op == `OP_ADD ? id_ex_operand1 + id_ex_operand2 : + id_ex_op == `OP_SET ? id_ex_operand1 : + id_ex_op == `OP_NAND ? ~(id_ex_operand1 & id_ex_operand2) : + 8'bxxxxxxxx; // `OP_NOP +assign ex_forwarding_val = ex_alu_result; + +assign forwarding_ex_wdst = id_ex_rd; +assign forwarding_ex_wen = id_ex_valid && id_ex_reg_wen; + +// control +assign ex_id_ready = !stallex && + ( wb_ex_ready || ( !ex_wb_valid ) ); +// stallex wb_ex_ready ex_wb_valid ex_id_ready +// 1 x x 0 +// 0 1 x 1 +// 0 0 0 1 +// 0 0 1 0 + +assign ex_go = id_ex_valid && ex_id_ready; + + +always @(posedge clk) begin + if (rst) begin + // reset + ex_wb_reg_wen <= 1'b0; + ex_wb_valid <= 1'b0; + end + else begin + if (ex_go) begin + ex_wb_inst <= id_ex_inst; + + ex_wb_valid <= id_ex_valid && !stallex; + ex_wb_reg_wen <= id_ex_reg_wen; + ex_wb_val <= ex_alu_result; + ex_wb_rd <= id_ex_rd; + end else begin + if(wb_go) + ex_wb_valid <= 1'b0; + end + end +end + + +// -------------------------------------- + + +// WB +assign wb_ex_ready = !stallwb; +assign wb_go = ex_wb_valid && wb_ex_ready; + +assign wb_forwarding_val = ex_wb_val; + +always @(posedge clk ) begin + if (wb_go && ex_wb_reg_wen) begin + registers[ex_wb_rd] <= ex_wb_val; + end +end + +// dummy read +assign dummy_rf_data = registers[dummy_read_rf]; + + +// formal properties +/* +assert property (scoreboard[0][1] == ( id_ex_valid && id_ex_reg_wen && id_ex_rd == 2'd0)); +assert property (scoreboard[0][0] == ( ex_wb_valid && ex_wb_reg_wen && ex_wb_rd == 2'd0)); + +assert property (scoreboard[1][1] == ( id_ex_valid && id_ex_reg_wen && id_ex_rd == 2'd1)); +assert property (scoreboard[1][0] == ( ex_wb_valid && ex_wb_reg_wen && ex_wb_rd == 2'd1)); + +assert property (scoreboard[2][1] == ( id_ex_valid && id_ex_reg_wen && id_ex_rd == 2'd2)); +assert property (scoreboard[2][0] == ( ex_wb_valid && ex_wb_reg_wen && ex_wb_rd == 2'd2)); + +assert property (scoreboard[3][1] == ( id_ex_valid && id_ex_reg_wen && id_ex_rd == 2'd3)); +assert property (scoreboard[3][0] == ( ex_wb_valid && ex_wb_reg_wen && ex_wb_rd == 2'd3)); +*/ +endmodule diff --git a/test/unit-data/vpipe/simple_pipe_wrong.v b/test/unit-data/vpipe/simple_pipe_wrong.v index 3c4e58986..77b888324 100644 --- a/test/unit-data/vpipe/simple_pipe_wrong.v +++ b/test/unit-data/vpipe/simple_pipe_wrong.v @@ -17,7 +17,7 @@ `define OP_SUB 2'b10 `define OP_AND 2'b11 -module pipeline_v(input clk, input rst, input [7:0] inst, input [1:0] dummy_read_rf, output [7:0] dummy_rf_data ); +module pipeline_v(input wire clk, input wire rst, input wire [7:0] inst, input wire [1:0] dummy_read_rf, output wire [7:0] dummy_rf_data ); wire [1:0] op; wire [1:0] rs1; @@ -194,26 +194,15 @@ always @(posedge clk) begin end end + // WB always @(posedge clk ) begin - if (rst) begin - // reset - registers[0] <= 8'd0; - registers[1] <= 8'd0; - registers[2] <= 8'd0; - registers[3] <= 8'd0; - end - else if (ex_wb_reg_wen) begin - case (ex_wb_rd) - 2'd0: registers[0] <= ex_wb_val; - 2'd1: registers[1] <= ex_wb_val; - 2'd2: registers[2] <= ex_wb_val; - 2'd3: registers[3] <= ex_wb_val; - default: registers[0] <= ex_wb_val; // nouse - endcase + if (ex_wb_reg_wen) begin + registers[ex_wb_rd] <= ex_wb_val; end end + /*inner_assign_list*/ endmodule diff --git a/test/unit-data/vpipe/undetf/vmap-func.json b/test/unit-data/vpipe/undetf/vmap-func.json index 25bcf3ee8..9141bdcfc 100644 --- a/test/unit-data/vpipe/undetf/vmap-func.json +++ b/test/unit-data/vpipe/undetf/vmap-func.json @@ -1,25 +1,23 @@ { - "models": { "ILA":"m0" , "VERILOG": "m1" }, - "instruction mapping": [], "state mapping": { - "r0":"r0", - "r1":"r1", - "r2":"r2", - "r3":"r3", - "r4":"r4"}, + "r0":"RTL.r0", + "r1":"RTL.r1", + "r2":"RTL.r2", + "r3":"RTL.r3", + "r4":"RTL.r4"}, - "interface mapping": { - "rst":"**RESET**", - "clk":"**CLOCK**", - "d":"**KEEP**" - }, + "RTL interface connection" : { + "CLOCK" : "clk", + "RESET" : "rst" + }, // d keep - "mapping control" : [], "functions":{ "nondet8_1":[ - ["__START__","res1","__START__","r0"], - ["__START__","res3","__START__","r0"]], + {"result": "RTL.res1@0", "arg":["RTL.r0@0"]}, + {"result": "RTL.res3@0", "arg":["RTL.r0@0"]} + ], "nondet8_2":[ - ["__START__","res4","__START__","r1","__START__","r2"], - ["__START__","res5","__START__","r3","__START__","r4"] - ] } + {"result": "RTL.res4@0", "arg":["RTL.r1@0", "RTL.r2@0"]}, + {"result": "RTL.res5@0", "arg":["RTL.r3@0", "RTL.r4@0"]} + ] + } } diff --git a/test/unit-data/vpipe/undetf/vmap-val.json b/test/unit-data/vpipe/undetf/vmap-val.json index 32e490d57..eaa574db3 100644 --- a/test/unit-data/vpipe/undetf/vmap-val.json +++ b/test/unit-data/vpipe/undetf/vmap-val.json @@ -1,20 +1,18 @@ { - "models": { "ILA":"m0" , "VERILOG": "m1" }, - "instruction mapping": [], "state mapping": { - "r0":"r0", - "r1":"r1", - "r2":"r2", - "r3":"r3", - "r4":"r4"}, + "r0":"RTL.r0", + "r1":"RTL.r1", + "r2":"RTL.r2", + "r3":"RTL.r3", + "r4":"RTL.r4"}, - "interface mapping": { - "rst":"**RESET**", - "clk":"**CLOCK**", - "d":"**KEEP**" - }, + "RTL interface connection" : { + "CLOCK" : "clk", + "RESET" : "rst" + }, // d keep - "mapping control" : [], - "functions":{ "nondet8_1":[["__START__","res1"],["__START__","res3"]], - "nondet8_2":[["__START__","res4"],["__START__","res5"]] } + "functions":{ "nondet8_1": [{"result" : "RTL.res1@0", "arg" : []}, + {"result" : "RTL.res3@0", "arg" : []}], + "nondet8_2": [{"result" : "RTL.res4@0", "arg" : []}, + {"result" : "RTL.res5@0", "arg" : []}] } } diff --git a/test/unit-data/vpipe/verify_pvholder_reset/.placeholder b/test/unit-data/vpipe/verify_pvholder_reset/.placeholder new file mode 100644 index 000000000..e69de29bb diff --git a/test/unit-data/vpipe/verify_stall/.gitignore b/test/unit-data/vpipe/verify_stall/.gitignore new file mode 100644 index 000000000..1bb4ab336 --- /dev/null +++ b/test/unit-data/vpipe/verify_stall/.gitignore @@ -0,0 +1,5 @@ +invariants/* +ADD/* +NOP/* +SET/* +NAND/* diff --git a/test/unit-data/vpipe/verify_stall_short/.gitignore b/test/unit-data/vpipe/verify_stall_short/.gitignore new file mode 100644 index 000000000..1bb4ab336 --- /dev/null +++ b/test/unit-data/vpipe/verify_stall_short/.gitignore @@ -0,0 +1,5 @@ +invariants/* +ADD/* +NOP/* +SET/* +NAND/* diff --git a/test/unit-data/vpipe/verify_stall_short_nopvholder/.gitignore b/test/unit-data/vpipe/verify_stall_short_nopvholder/.gitignore new file mode 100644 index 000000000..1bb4ab336 --- /dev/null +++ b/test/unit-data/vpipe/verify_stall_short_nopvholder/.gitignore @@ -0,0 +1,5 @@ +invariants/* +ADD/* +NOP/* +SET/* +NAND/* diff --git a/test/unit-data/vpipe/vmem/cond-forall.json b/test/unit-data/vpipe/vmem/cond-forall.json new file mode 100644 index 000000000..78295a070 --- /dev/null +++ b/test/unit-data/vpipe/vmem/cond-forall.json @@ -0,0 +1,15 @@ +{ + "global invariants": [], + + "instructions": [ + { + "instruction": "WRITE", + "ready bound": 1 + }, + { + "instruction": "READ", + "ready bound": 1 + } + ] +} + diff --git a/test/unit-data/vpipe/vmem/cond-rd.json b/test/unit-data/vpipe/vmem/cond-rd.json index aa5491a8c..f79e88fcb 100644 --- a/test/unit-data/vpipe/vmem/cond-rd.json +++ b/test/unit-data/vpipe/vmem/cond-rd.json @@ -4,7 +4,7 @@ "instructions": [ { "instruction": "Rd", - "start condition":["m1.state == 0" , "$valid$", "$decode$" ], + "start condition":["RTL.state == 0" , "$valid", "$decode" ], "ready bound": 2 } ] diff --git a/test/unit-data/vpipe/vmem/cond.json b/test/unit-data/vpipe/vmem/cond.json index 7bc670bb3..950e5019e 100644 --- a/test/unit-data/vpipe/vmem/cond.json +++ b/test/unit-data/vpipe/vmem/cond.json @@ -4,7 +4,7 @@ "instructions": [ { "instruction": "SWAP", - "start condition":["m1.state == 0" , "$valid$", "$decode$" ], + "start condition":["RTL.state == 0" , "$valid", "$decode" ], "ready bound": 3 } ] diff --git a/test/unit-data/vpipe/vmem/large_small_forall/.gitignore b/test/unit-data/vpipe/vmem/large_small_forall/.gitignore new file mode 100644 index 000000000..15bb95a3d --- /dev/null +++ b/test/unit-data/vpipe/vmem/large_small_forall/.gitignore @@ -0,0 +1,3 @@ +READ/* +WRITE/* + diff --git a/test/unit-data/vpipe/vmem/large_small_forall_jg/.gitignore b/test/unit-data/vpipe/vmem/large_small_forall_jg/.gitignore new file mode 100644 index 000000000..15bb95a3d --- /dev/null +++ b/test/unit-data/vpipe/vmem/large_small_forall_jg/.gitignore @@ -0,0 +1,3 @@ +READ/* +WRITE/* + diff --git a/test/unit-data/vpipe/vmem/smallarray.v b/test/unit-data/vpipe/vmem/smallarray.v new file mode 100644 index 000000000..714dd99bc --- /dev/null +++ b/test/unit-data/vpipe/vmem/smallarray.v @@ -0,0 +1,36 @@ +module top(input clk, input rst, input [3:0] addr, input[7:0] data, + input wen, input ren, output [7:0] odata); + +wire array1_sel = addr[3] == 1'b0; +wire array2_sel = addr[3] == 1'b1; +wire [2:0] subaddr = addr[2:0]; +wire[7:0] odata1,odata2; + +reg array1_sel_d1; +always @(posedge clk) begin + array1_sel_d1 <= array1_sel; +end + +subarray a1(.clk(clk), .rst(rst), .addr(subaddr), .data(data), .wen(wen&array1_sel), .ren(ren&array1_sel), .odata(odata1)); +subarray a2(.clk(clk), .rst(rst), .addr(subaddr), .data(data), .wen(wen&array2_sel), .ren(ren&array2_sel), .odata(odata2)); + +assign odata = array1_sel_d1 ? odata1 : odata2; + +endmodule + +module subarray(input clk, input rst, input [2:0] addr, input[7:0] data, + input wen, input ren, output reg [7:0] odata); + + reg [7:0] array[0:7]; + + always @(posedge clk) begin + if(wen) + array[addr] <= data; + end + + always @(posedge clk) begin + if(ren) + odata <= array[addr]; + end + +endmodule diff --git a/test/unit-data/vpipe/vmem/swap_im.v b/test/unit-data/vpipe/vmem/swap_im.v index 9703d12ac..8e1adde76 100644 --- a/test/unit-data/vpipe/vmem/swap_im.v +++ b/test/unit-data/vpipe/vmem/swap_im.v @@ -5,10 +5,12 @@ module swap ( input rst, // Synchronous reset active high input [3:0] addra, input [3:0] addrb, - input start); + input start, + output [3:0] dummyrd, + output reg [7:0] dummyv); -reg [7:0] mema[0:15]; -reg [7:0] memb[0:15]; +(* keep *) reg [7:0] mema[0:15]; +(* keep *) reg [7:0] memb[0:15]; always @(posedge clk) begin @@ -18,4 +20,8 @@ always @(posedge clk) begin end end +always @(posedge clk) begin + dummyv <= (^dummyrd) ? mema[dummyrd] : memb[dummyrd]; +end + endmodule \ No newline at end of file diff --git a/test/unit-data/vpipe/vmem/vmap-expand.json b/test/unit-data/vpipe/vmem/vmap-expand.json index d11d0a6a0..d72edea22 100644 --- a/test/unit-data/vpipe/vmem/vmap-expand.json +++ b/test/unit-data/vpipe/vmem/vmap-expand.json @@ -1,17 +1,16 @@ { - "models": { "ILA":"m0" , "VERILOG": "m1" }, - "instruction mapping": [], "state mapping": { - "mema":"mema", - "memb":"memb"}, + "mema":"RTL.mema", + "memb":"RTL.memb"}, - "interface mapping": { - "rst":"**RESET**", - "clk":"**CLOCK**", - "addra":"addra", - "addrb":"addrb", - "start":"start" + "RTL interface connection" : { + "CLOCK" : "clk", + "RESET" : "rst" }, - "mapping control" : [] + "input mapping": { + "addra":"RTL.addra", + "addrb":"RTL.addrb", + "start":"RTL.start" + } } diff --git a/test/unit-data/vpipe/vmem/vmap-forall.json b/test/unit-data/vpipe/vmem/vmap-forall.json new file mode 100644 index 000000000..dbe3e7320 --- /dev/null +++ b/test/unit-data/vpipe/vmem/vmap-forall.json @@ -0,0 +1,18 @@ +{ + "state mapping": { + "array":"$forall(i:bv4, ILA.array[i] == ( i < 8 ? RTL.a1.array[i[2:0]] : RTL.a2.array[i[2:0]]) )", + "odata":"RTL.odata"}, + + "RTL interface connection" : { + "CLOCK" : "clk", + "RESET" : "rst" + }, + + "input mapping" : { + "addr" : "RTL.addr", + "data" : "RTL.data", + "ren" : "RTL.ren", + "wen" : "RTL.wen" + } + +} diff --git a/test/unit-data/vpipe/vmem/vmap-rd.json b/test/unit-data/vpipe/vmem/vmap-rd.json index b819b6a48..7b30ab740 100644 --- a/test/unit-data/vpipe/vmem/vmap-rd.json +++ b/test/unit-data/vpipe/vmem/vmap-rd.json @@ -1,25 +1,20 @@ { - "models": { "ILA":"m0" , "VERILOG": "m1" }, - "instruction mapping": [], "state mapping": { - "mema":"**MEM**mema", - "membuf":"rdataa_buf"}, + "mema":{ + "ren" : "1'b1", // will always read + "raddr" : "RTL.mem_a_raddr@1", + "rdata" : "RTL.mem_a_rdata@1" + }, + "membuf":"RTL.rdataa_buf"}, - "interface mapping": { - "rst":"**RESET**", - "clk":"**CLOCK**", - "addra":"addra", - "start":"start", - "mem_a_raddr":"**MEM**mema.raddr", - "mem_a_rdata":"**MEM**mema.rdata" + "RTL interface connection" : { + "CLOCK" : "clk", + "RESET" : "rst" }, - // "mapping control" : ["__MEM_mema_0_ren == ((m1.state == 1)?1'b1:1'b0)"], - - - "annotation": { - "memory-ports" : { - "mema.ren":"m1.state == 1" - } + "input mapping" : { + "addra" : "RTL.addra", + "start" : "RTL.start" } + } diff --git a/test/unit-data/vpipe/vmem/vmap-rfarray.json b/test/unit-data/vpipe/vmem/vmap-rfarray.json index d0cd1752f..205c72591 100644 --- a/test/unit-data/vpipe/vmem/vmap-rfarray.json +++ b/test/unit-data/vpipe/vmem/vmap-rfarray.json @@ -1,32 +1,23 @@ { - "models": { "ILA":"m0" , "VERILOG": "m1" }, - "instruction mapping": [], "state mapping": { - "rf":"rf", - "mem":"**MEM**mem"}, + "rf":"RTL.rf", + "mem":{ + "wen" :"RTL.mem_w_en@0", + "waddr" :"RTL.mem_w_addr@0", + "wdata" :"RTL.mem_w_data@0", + "ren" :"RTL.mem_r_en@0", + "raddr" :"RTL.mem_r_addr@0", + "rdata" :"RTL.mem_r_data@0" + }}, - "interface mapping": { - "rst":"**RESET**", - "clk":"**CLOCK**", - "op":"op", - "operand1":"operand1", - "operand2":"operand2", - - "mem_w_en" :"**MEM**mem.wen", - "mem_w_addr":"**MEM**mem.waddr", - "mem_w_data":"**MEM**mem.wdata", - "mem_r_en" :"**MEM**mem.ren", - "mem_r_addr":"**MEM**mem.raddr", - "mem_r_data":"**MEM**mem.rdata" + "RTL interface connection" : { + "CLOCK" : "clk", + "RESET" : "rst" }, - "mapping control" : [ - "m1.operand1 <= 5 && m1.operand2 <= 5" - ], - "annotation" : { - "memory" : { - "rf":"internal", - "mem":"external" - } + "input mapping": { + "op":"RTL.op", + "operand1":"RTL.operand1", + "operand2":"RTL.operand2" } } diff --git a/test/unit-data/vpipe/vmem/vmap-rfarray6.json b/test/unit-data/vpipe/vmem/vmap-rfarray6.json new file mode 100644 index 000000000..1a7f1a285 --- /dev/null +++ b/test/unit-data/vpipe/vmem/vmap-rfarray6.json @@ -0,0 +1,27 @@ +{ + "state mapping": { + "rf":"RTL.rf", + "mem":{ + "wen" :"RTL.mem_w_en@0", + "waddr" :"RTL.mem_w_addr@0", + "wdata" :"RTL.mem_w_data@0", + "ren" :"RTL.mem_r_en@0", + "raddr" :"RTL.mem_r_addr@0", + "rdata" :"RTL.mem_r_data@0" + }}, + + "RTL interface connection" : { + "CLOCK" : "clk", + "RESET" : "rst" + }, + + "input mapping": { + "op":"RTL.op", + "operand1":"RTL.operand1", + "operand2":"RTL.operand2" + }, + + "additional mapping" : [ + "ILA.operand1 <= 5 && ILA.operand2 <= 5" + ] +} diff --git a/test/unit-data/vpipe/vmem/vmap.json b/test/unit-data/vpipe/vmem/vmap.json index c07bfddee..8b6c64225 100644 --- a/test/unit-data/vpipe/vmem/vmap.json +++ b/test/unit-data/vpipe/vmem/vmap.json @@ -1,34 +1,31 @@ { - "models": { "ILA":"m0" , "VERILOG": "m1" }, - "instruction mapping": [], "state mapping": { - "mema":"**MEM**mema", - "memb":"**MEM**memb"}, - - "interface mapping": { - "rst":"**RESET**", - "clk":"**CLOCK**", - "addra":"addra", - "addrb":"addrb", - "start":"start", - "mem_a_raddr":"**MEM**mema.raddr", - "mem_a_rdata":"**MEM**mema.rdata", - "mem_a_waddr":"**MEM**mema.waddr", - "mem_a_wdata":"**MEM**mema.wdata", - "mem_a_wen":"**MEM**mema.wen", - "mem_b_raddr":"**MEM**memb.raddr", - "mem_b_rdata":"**MEM**memb.rdata", - "mem_b_waddr":"**MEM**memb.waddr", - "mem_b_wdata":"**MEM**memb.wdata", - "mem_b_wen":"**MEM**memb.wen" + "mema": { + "ren" : "1'b1" , + "raddr" : "RTL.mem_a_raddr @ (RTL.state == 1)", + "rdata" : "RTL.mem_a_rdata @ (RTL.state == 1)", + "wen" : "1'b1 " , + "waddr" : "RTL.mem_a_waddr @ (RTL.state == 2)", + "wdata" : "RTL.mem_a_wdata @ (RTL.state == 2)" + }, + "memb": { + "ren" : "1'b1" , + "raddr" : "RTL.mem_b_raddr @ (RTL.state == 1)", + "rdata" : "RTL.mem_b_rdata @ (RTL.state == 1)", + "wen" : "1'b1 " , + "waddr" : "RTL.mem_b_waddr @ (RTL.state == 2)", + "wdata" : "RTL.mem_b_wdata @ (RTL.state == 2)" + } }, - // "mapping control" : ["__MEM_mema_0_ren == ((m1.state == 1)?1'b1:1'b0)", "__MEM_memb_0_ren == ((m1.state == 1)?1'b1:1'b0)"], + "input mapping": { + "addra":"RTL.addra", + "addrb":"RTL.addrb", + "start":"RTL.start" + }, - "annotation": { - "memory-ports" : { - "mema.ren":"((m1.state == 1)?1'b1:1'b0)", // you can use arbitrary verilog expression here - "memb.ren":"m1.state == 1" - } - } + "RTL interface connection" : { + "CLOCK" : "clk", + "RESET" : "rst" + } } diff --git a/test/unit-include/memswap.h b/test/unit-include/memswap.h index 190ec2c3c..102af43cb 100644 --- a/test/unit-include/memswap.h +++ b/test/unit-include/memswap.h @@ -18,6 +18,7 @@ class MemorySwap { static Ila BuildRfAsMemModelRegEntry6(); static Ila BuildRdModel(); static Ila BuildResetterTest(); + static Ila BuildSimpleLargeArray(); }; // class MemorySwap diff --git a/test/unit-include/pipe_ila.h b/test/unit-include/pipe_ila.h index 786825598..ab18f8bd3 100644 --- a/test/unit-include/pipe_ila.h +++ b/test/unit-include/pipe_ila.h @@ -14,6 +14,7 @@ class SimplePipe { public: static Ila BuildModel(); + static Ila BuildStallModel(); }; // class SimplePipe diff --git a/test/unit-src/memswap.cc b/test/unit-src/memswap.cc index 2c5e15a71..6bddb0c97 100644 --- a/test/unit-src/memswap.cc +++ b/test/unit-src/memswap.cc @@ -31,6 +31,31 @@ Ila MemorySwap::BuildModel() { } +Ila MemorySwap::BuildSimpleLargeArray() { + auto ila = Ila("LargeArray"); + ila.SetValid(BoolConst(true)); + auto wen = ila.NewBvInput("wen", 1); + auto ren = ila.NewBvInput("ren", 1); + auto addr = ila.NewBvInput("addr", 4); + auto data = ila.NewBvInput("data", 8); + auto odata = ila.NewBvState("odata", 8); + + auto array = ila.NewMemState("array", 4, 8); + + { + auto WRITE = ila.NewInstr("WRITE"); + WRITE.SetDecode(wen == 1); + WRITE.SetUpdate(array,Store(array, addr,data)); + } + + { + auto READ = ila.NewInstr("READ"); + READ.SetDecode(ren == 1); + READ.SetUpdate(odata, Load(array, addr)); + } + return ila; +} + Ila MemorySwap::BuildSimpleSwapModel() { // build the ila auto memswap = Ila("MemorySwap"); diff --git a/test/unit-src/pipe_ila.cc b/test/unit-src/pipe_ila.cc index eb5e8e671..f53315de6 100644 --- a/test/unit-src/pipe_ila.cc +++ b/test/unit-src/pipe_ila.cc @@ -66,6 +66,60 @@ Ila SimplePipe::BuildModel() { return pipe_ila; } + +Ila SimplePipe::BuildStallModel() { + // build the ila + auto pipe_ila = Ila("simplePipe"); + pipe_ila.SetValid(BoolConst(true)); + + auto inst = pipe_ila.NewBvInput("inst", 8); + auto r0 = pipe_ila.NewBvState("r0", 8); + auto r1 = pipe_ila.NewBvState("r1", 8); + auto r2 = pipe_ila.NewBvState("r2", 8); + auto r3 = pipe_ila.NewBvState("r3", 8); + + auto op = inst(7, 6); + auto rs1 = inst(5, 4); + auto rs2 = inst(3, 2); + auto rd = inst(1, 0); + auto immd = ZExt( inst(5,2), 8); + + auto rs1_val = Ite(rs1 == 0, r0, Ite(rs1 == 1, r1, Ite(rs1 == 2, r2, r3))); + + auto rs2_val = Ite(rs2 == 0, r0, Ite(rs2 == 1, r1, Ite(rs2 == 2, r2, r3))); + + auto NOP = pipe_ila.NewInstr("NOP"); + { + NOP.SetDecode(op == BvConst(0, 2)); + NOP.SetUpdate(r0, r0); + NOP.SetUpdate(r1, r1); + NOP.SetUpdate(r2, r2); + NOP.SetUpdate(r3, r3); + } + + auto ADD = pipe_ila.NewInstr("ADD"); + { + ADD.SetDecode(op == BvConst(1, 2)); + auto res = rs1_val + rs2_val; + SET_UPDATE(ADD, rd, res); + } + + auto SET = pipe_ila.NewInstr("SET"); + { + SET.SetDecode(op == BvConst(2, 2)); + SET_UPDATE(SET, rd, immd); + } + + auto NAND = pipe_ila.NewInstr("NAND"); + { + NAND.SetDecode(op == BvConst(3, 2)); + auto res = ~( rs1_val & rs2_val ); + SET_UPDATE(NAND, rd, res); + } + + return pipe_ila; +} + Ila UndetVal::BuildModel() { auto m = Ila("undetval"); auto r0 = m.NewBvState("r0", 8);