// -*- mode: C++; c-file-style: "cc-mode" -*- //************************************************************************* // DESCRIPTION: Verilator: Graph tests // // Code available from: http://www.veripool.org/verilator // //************************************************************************* // // Copyright 2003-2018 by Wilson Snyder. This program is free software; you can // redistribute it and/or modify it under the terms of either the GNU // Lesser General Public License Version 3 or the Perl Artistic License // Version 2.0. // // Verilator is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // //************************************************************************* #include "config_build.h" #include "verilatedos.h" #include #include #include #include "V3Global.h" #include "V3Graph.h" #include "V3GraphDfa.h" //###################################################################### //###################################################################### // Test class class V3GraphTest { public: // ***These tests only run with DEBUG ON*** static int debug() { static int level = -1; // Note setting just --debug will not enable this, as we exit when we run the test if (VL_UNLIKELY(level < 0)) level = v3Global.opt.debugSrcLevel(__FILE__, 0); return level; } protected: // MEMBERS DfaGraph m_graph; // METHODS - for children virtual void runTest() = 0; // Run the test virtual string name() = 0; // Name of the test // Utilities void dump() { if (debug()>=9) { m_graph.dumpDotFilePrefixed("v3graphtest_"+name()); } } public: V3GraphTest() {} virtual ~V3GraphTest() {} void run() { if (debug()) runTest(); } }; //###################################################################### //###################################################################### // Vertices and nodes class V3GraphTestVertex : public V3GraphVertex { string m_name; public: V3GraphTestVertex(V3Graph* graphp, const string& name) : V3GraphVertex(graphp), m_name(name) {} virtual ~V3GraphTestVertex() {} // ACCESSORS virtual string name() const { return m_name; } }; class V3GraphTestVarVertex : public V3GraphTestVertex { public: V3GraphTestVarVertex(V3Graph* graphp, const string& name) : V3GraphTestVertex(graphp, name) {} virtual ~V3GraphTestVarVertex() {} // ACCESSORS virtual string dotColor() const { return "blue"; } }; //###################################################################### //###################################################################### // Test vertices and nodes class V3GraphTestStrong : public V3GraphTest { public: virtual string name() { return "strong"; } virtual void runTest() { V3Graph* gp = &m_graph; // Verify we break edges at a good point // A simple alg would make 3 breaks, below only requires b->i to break V3GraphTestVertex* i = new V3GraphTestVarVertex(gp,"*INPUTS*"); V3GraphTestVertex* a = new V3GraphTestVarVertex(gp,"a"); V3GraphTestVertex* b = new V3GraphTestVarVertex(gp,"b"); V3GraphTestVertex* g1 = new V3GraphTestVarVertex(gp,"g1"); V3GraphTestVertex* g2 = new V3GraphTestVarVertex(gp,"g2"); V3GraphTestVertex* g3 = new V3GraphTestVarVertex(gp,"g3"); V3GraphTestVertex* q = new V3GraphTestVarVertex(gp,"q"); new V3GraphEdge(gp, i, a, 2, true); new V3GraphEdge(gp, a, b, 2, true); new V3GraphEdge(gp, b, g1, 2, true); new V3GraphEdge(gp, b, g2, 2, true); new V3GraphEdge(gp, b, g3, 2, true); new V3GraphEdge(gp, g1, a, 2, true); new V3GraphEdge(gp, g3, g2, 2, true); new V3GraphEdge(gp, g2, g3, 2, true); new V3GraphEdge(gp, g1, q, 2, true); new V3GraphEdge(gp, g2, q, 2, true); new V3GraphEdge(gp, g3, q, 2, true); gp->stronglyConnected(&V3GraphEdge::followAlwaysTrue); dump(); UASSERT(i->color()!=a->color() && a->color() != g2->color() && g2->color() != q->color(), "Separate colors not assigned"); UASSERT(a->color()==b->color() && a->color()==g1->color(), "Strongly connected nodes not colored together"); UASSERT(g2->color()==g3->color(), "Strongly connected nodes not colored together"); } }; class V3GraphTestAcyc : public V3GraphTest { public: virtual string name() { return "acyc"; } virtual void runTest() { V3Graph* gp = &m_graph; // Verify we break edges at a good point // A simple alg would make 3 breaks, below only requires b->i to break V3GraphTestVertex* i = new V3GraphTestVarVertex(gp,"*INPUTS*"); V3GraphTestVertex* a = new V3GraphTestVarVertex(gp,"a"); V3GraphTestVertex* b = new V3GraphTestVarVertex(gp,"b"); V3GraphTestVertex* g1 = new V3GraphTestVarVertex(gp,"g1"); V3GraphTestVertex* g2 = new V3GraphTestVarVertex(gp,"g2"); V3GraphTestVertex* g3 = new V3GraphTestVarVertex(gp,"g3"); new V3GraphEdge(gp, i, a, 2, true); new V3GraphEdge(gp, a, b, 2, true); new V3GraphEdge(gp, b, g1, 2, true); new V3GraphEdge(gp, b, g2, 2, true); new V3GraphEdge(gp, b, g3, 2, true); new V3GraphEdge(gp, g1, a, 2, true); new V3GraphEdge(gp, g2, a, 2, true); new V3GraphEdge(gp, g3, a, 2, true); gp->acyclic(&V3GraphEdge::followAlwaysTrue); gp->order(); dump(); } }; class V3GraphTestVars : public V3GraphTest { public: virtual string name() { return "vars"; } virtual void runTest() { V3Graph* gp = &m_graph; V3GraphTestVertex* clk = new V3GraphTestVarVertex(gp,"$clk"); V3GraphTestVertex* a = new V3GraphTestVarVertex(gp,"$a"); V3GraphTestVertex* a_dly = new V3GraphTestVarVertex(gp,"$a_dly"); V3GraphTestVertex* a_dlyblk= new V3GraphTestVarVertex(gp,"$a_dlyblk"); V3GraphTestVertex* b = new V3GraphTestVarVertex(gp,"$b"); V3GraphTestVertex* b_dly = new V3GraphTestVarVertex(gp,"$b_dly"); V3GraphTestVertex* b_dlyblk= new V3GraphTestVarVertex(gp,"$b_dlyblk"); V3GraphTestVertex* c = new V3GraphTestVarVertex(gp,"$c"); V3GraphTestVertex* i = new V3GraphTestVarVertex(gp,"$i"); V3GraphTestVertex* ap = new V3GraphTestVarVertex(gp,"$a_pre"); V3GraphTestVertex* bp = new V3GraphTestVarVertex(gp,"$b_pre"); V3GraphTestVertex* cp = new V3GraphTestVarVertex(gp,"$c_pre"); V3GraphTestVertex* n; // Logical order between clk, and posedge blocks // implemented by special CLK prod/cons? // Required order between first x_DLY<=x_pre and final x<=x_DLY // implemented by producer/consumer on a_dly signals // Required order between first x_DLY<=x_pre and x_DLY<=setters // implemented by fake dependency on _dlyblk // Required order between x_DLY<=setters and final x<=x_DLY // implemented by producer/consumer on a_dly signals // Desired order between different _DLY blocks so we can elim temporaries // implemented by cutable "pre" signal dependencies n = new V3GraphTestVertex(gp,"*INPUTS*"); { new V3GraphEdge(gp, n, clk, 2); new V3GraphEdge(gp, n, i, 2); } V3GraphTestVertex* posedge = n = new V3GraphTestVertex(gp,"*posedge clk*"); { new V3GraphEdge(gp, clk, n, 2); } // AssignPre's VarRefs on LHS: generate special BLK // normal: VarRefs on LHS: generate normal // underSBlock: VarRefs on RHS: consume 'pre' (required to save cutable tests) n = new V3GraphTestVertex(gp,"a_dlyacyclic(&V3GraphEdge::followAlwaysTrue); gp->order(); dump(); } }; //====================================================================== class DfaTestVertex : public DfaVertex { string m_name; public: DfaTestVertex(DfaGraph* graphp, const string& name) : DfaVertex(graphp), m_name(name) {} virtual ~DfaTestVertex() {} // ACCESSORS virtual string name() const { return m_name; } }; class V3GraphTestDfa : public V3GraphTest { public: virtual string name() { return "dfa"; } virtual void runTest() { DfaGraph* gp = &m_graph; // NFA Pattern for ( (LR) | (L*R)) Z DfaTestVertex* st = new DfaTestVertex(gp,"*START*"); st->start(true); DfaTestVertex* sl = new DfaTestVertex(gp,"sL"); DfaTestVertex* srs = new DfaTestVertex(gp,"sR*"); DfaTestVertex* sls = new DfaTestVertex(gp,"sL*"); DfaTestVertex* sr = new DfaTestVertex(gp,"sR"); DfaTestVertex* sz = new DfaTestVertex(gp,"sZ"); DfaTestVertex* sac = new DfaTestVertex(gp,"*ACCEPT*"); sac->accepting(true); VNUser L = VNUser::fromInt(0xaa); VNUser R = VNUser::fromInt(0xbb); VNUser Z = VNUser::fromInt(0xcc); new DfaEdge(gp, st, sl, DfaEdge::EPSILON()); new DfaEdge(gp, sl, srs, L); new DfaEdge(gp, srs, srs, R); new DfaEdge(gp, srs, sz, Z); new DfaEdge(gp, sz, sac, DfaEdge::EPSILON()); new DfaEdge(gp, st, sls, DfaEdge::EPSILON()); new DfaEdge(gp, sls, sls, L); new DfaEdge(gp, sls, sr, R); new DfaEdge(gp, sr, sz, Z); new DfaEdge(gp, sz, sac, DfaEdge::EPSILON()); dump(); gp->nfaToDfa(); dump(); gp->dfaReduce(); dump(); gp->dfaComplement(); dump(); gp->dfaReduce(); dump(); } }; //====================================================================== class V3GraphTestImport : public V3GraphTest { // cppcheck-suppress functionConst void dotImport(); public: virtual string name() { return "import"; } virtual void runTest() { DfaGraph* gp = &m_graph; if (V3GraphTest::debug()) gp->debug(9); dotImport(); dump(); gp->acyclic(&V3GraphEdge::followAlwaysTrue); dump(); gp->rank(&V3GraphEdge::followAlwaysTrue); dump(); } }; #if 0 # include "graph_export.cpp" #else void V3GraphTestImport::dotImport() { } #endif //====================================================================== void V3Graph::selfTest() { // Execute all of the tests UINFO(2,__FUNCTION__<<": "<