From 720d7e8335a7c3ba2f175ba31e101ccd9e4c561c Mon Sep 17 00:00:00 2001 From: Sergey Dolgov Date: Wed, 30 Oct 2024 23:09:55 -0700 Subject: [PATCH] checker: better diagnostics for clock-data EDA-3235 --- planning/src/RS/rsCheck.cpp | 5 +- planning/src/file_io/pln_blif_file.cpp | 114 ++++++++++++++++++++----- planning/src/file_io/pln_blif_file.h | 12 ++- planning/src/main.cpp | 2 +- planning/src/util/nw/Nw.cpp | 4 +- planning/src/util/nw/Nw.h | 15 +--- planning/src/util/nw/Nw_io.cpp | 21 +++-- planning/src/util/nw/Nw_node.cpp | 22 +++++ 8 files changed, 148 insertions(+), 47 deletions(-) diff --git a/planning/src/RS/rsCheck.cpp b/planning/src/RS/rsCheck.cpp index 571b5430..2f37be45 100644 --- a/planning/src/RS/rsCheck.cpp +++ b/planning/src/RS/rsCheck.cpp @@ -59,7 +59,7 @@ bool do_check_blif(CStr cfn, uint numInp = bfile.numInputs(); uint numOut = bfile.numOutputs(); - lprintf(" (blif_file) #inputs= %u #outputs= %u topModel= %s\n", + lprintf(" (blif_file) #inputs= %u #outputs= %u topModel= %s\n", numInp, numOut, bfile.topModel_.c_str()); if (tr >= 4) { @@ -115,6 +115,7 @@ bool do_check_blif(CStr cfn, ls << "----- #TDP_RAM36K= " << nTDP_RAM36K << endl; ls << "----- #TDP_RAM18KX2= " << nTDP_RAM18K << endl; ls << "----- #CARRY= " << nCARRY << endl; + ls << "----- #WIREs= " << bfile.countWires() << endl; } ls << "-----\n"; ls << "----- PinGraph: " << bfile.pinGraphFile_ << endl; @@ -173,6 +174,8 @@ bool do_check_blif(CStr cfn, ls << "[Error] ERROR BLIF is not OK ERROR" << endl; ls << "[Error] ERROR " << bfile.err_msg_ << endl; + if (not bfile.err_info2_.empty()) + ls << "[Error] ERROR " << bfile.err_info2_ << endl; flush_out(true); uint errLnum = std::max(bfile.err_lnum_, bfile.err_lnum2_); diff --git a/planning/src/file_io/pln_blif_file.cpp b/planning/src/file_io/pln_blif_file.cpp index 7a01c4fd..51976959 100644 --- a/planning/src/file_io/pln_blif_file.cpp +++ b/planning/src/file_io/pln_blif_file.cpp @@ -25,6 +25,7 @@ void BLIF_file::reset(CStr nm, uint16_t tr) noexcept { inputs_lnum_ = outputs_lnum_ = 0; err_lnum_ = err_lnum2_ = 0; err_msg_.clear(); + err_info2_.clear(); pg_.clear(); pg2blif_.clear(); @@ -253,6 +254,7 @@ bool BLIF_file::readBlif() noexcept { rd_ok_ = chk_ok_ = false; err_msg_.clear(); + err_info2_.clear(); trace_ = 0; { @@ -779,6 +781,17 @@ uint BLIF_file::countFFs() const noexcept { return cnt; } +uint BLIF_file::countWires() const noexcept { + if (numNodes() == 0 or fabricRealNodes_.empty()) + return 0; + uint cnt = 0; + for (const BNode* x : fabricRealNodes_) { + if (x->is_WIRE()) + cnt++; + } + return cnt; +} + uint BLIF_file::countCBUFs() const noexcept { uint nn = numNodes(); if (nn == 0) @@ -1628,24 +1641,24 @@ void BLIF_file::BNode::allInputPins(vector& V) const noexcept { return; } -BLIF_file::BNode* BLIF_file::findOutputPort(const string& contact) noexcept { - assert(not contact.empty()); +BLIF_file::BNode* BLIF_file::findOutputPort(const string& sig) noexcept { + assert(not sig.empty()); if (topOutputs_.empty()) return nullptr; // TMP linear for (BNode* x : topOutputs_) { - if (x->out_ == contact) return x; + if (x->out_ == sig) return x; } return nullptr; } -BLIF_file::BNode* BLIF_file::findInputPort(const string& contact) noexcept { - assert(not contact.empty()); +BLIF_file::BNode* BLIF_file::findInputPort(const string& sig) noexcept { + assert(not sig.empty()); if (topInputs_.empty()) return nullptr; // TMP linear for (BNode* x : topInputs_) { - if (x->out_ == contact) return x; + if (x->out_ == sig) return x; } return nullptr; } @@ -2010,7 +2023,7 @@ bool BLIF_file::checkClockSepar(vector& clocked) noexcept { } bool color_ok = true; - CStr viol_prefix = " ===!!! clock-data separation error"; + CStr viol_prefix = " [Error] clock-data separation ERROR"; // -- check that end-points of red edges are red for (NW::cEI E(pg_); E.valid(); ++E) { @@ -2039,11 +2052,18 @@ bool BLIF_file::checkClockSepar(vector& clocked) noexcept { lprintf("%s: blif lines: %u - %u\n", viol_prefix, err_lnum_, err_lnum2_); char B[512] = {}; - ::sprintf(B, " line %u : %s ", err_lnum_, bnode1.kw_.c_str()); + ::sprintf(B, " ERROR line %u : %s ", err_lnum_, bnode1.kw_.c_str()); logVec(bnode1.data_, B); - ::sprintf(B, " line %u : %s ", err_lnum2_, bnode2.kw_.c_str()); + ::sprintf(B, " ERROR line %u : %s ", err_lnum2_, bnode2.kw_.c_str()); logVec(bnode2.data_, B); flush_out(true); + if (bnode1.isTopInput() and bnode2.is_WIRE()) { + err_info2_ = str::concat( "clock input port ", bnode1.out_, + " drives feedthrough wire at line ", + std::to_string(err_lnum2_) ); + lprintf("error-info: %s\n", err_info2_.c_str()); + flush_out(true); + } } break; } @@ -2060,7 +2080,8 @@ bool BLIF_file::checkClockSepar(vector& clocked) noexcept { if (!color_ok) { flush_out(true); err_puts(); - lprintf2("[Error] clock-data separation error\n"); + lprintf2("[Error] clock-data separation error: lines %u - %u\n", + err_lnum_, err_lnum2_); err_puts(); flush_out(true); return false; } @@ -2097,6 +2118,7 @@ bool BLIF_file::createPinGraph() noexcept { if (fabricNodes_.empty()) return false; err_msg_.clear(); + err_info2_.clear(); uint64_t key = 0; uint nid = 0, kid = 0, eid = 0; vector INP; @@ -2146,6 +2168,54 @@ bool BLIF_file::createPinGraph() noexcept { vector Q; Q.reserve(topInputs_.size()); + // -- link in-ports to out-ports via feedthrough wires + for (BNode* x : fabricRealNodes_) { + if (x->is_WIRE()) { + BNode& w = *x; + assert(w.data_.size() == 2); + const string& w_inp = w.data_.front(); + const string& w_out = w.data_.back(); + BNode* iport = findInputPort(w_inp); + if (!iport) + continue; + BNode* oport = findOutputPort(w_out); + if (!oport) + continue; + assert(iport->isTopInput()); + assert(oport->isTopOutput()); + // NW-nodes for i/o ports should exist already + assert(iport->nw_id_); + assert(oport->nw_id_); + assert(pg_.hasNode(iport->nw_id_)); + assert(pg_.hasNode(oport->nw_id_)); + assert(map_pg2blif(iport->nw_id_) == iport->id_); + assert(map_pg2blif(oport->nw_id_) == oport->id_); + + // NW keys and nodes for wire pseudo-cell: + uint64_t w_k1 = hashCantor(w.id_, 1) + max_key1; + uint64_t w_k2 = hashCantor(w.id_, 2) + max_key1; + assert(w_k1); + assert(w_k2); + assert(w_k1 != w_k2); + uint w_n1 = pg_.insK(w_k1); + assert(w_n1); + uint w_n2 = pg_.insK(w_k2); + assert(w_n2); + pg2blif_.emplace(w_n1, w.id_); + pg2blif_.emplace(w_n2, w.id_); + pg_.setNodeName4(w_n1, w.id_, w.lnum_, 1, "FTwireI"); + pg_.setNodeName4(w_n2, w.id_, w.lnum_, 2, "FTwireO"); + + // link feedthrough: + uint ee; + ee = pg_.linkNodes(iport->nw_id_, w_n1, false); + ee = pg_.linkNodes(w_n1, w_n2, true); + ee = pg_.linkNodes(w_n2, oport->nw_id_, false); + if (trace_ >= 11) + lprintf("\t\t ee = %u\n", ee); + } + } + // -- link from input ports to fabric for (BNode* p : topInputs_) { INP.clear(); @@ -2163,9 +2233,6 @@ bool BLIF_file::createPinGraph() noexcept { lprintf(" %s\n", port.cPortName()); } - // if (port.id_ == 24) - // lputs1(); - for (const upair& pa : PAR) { if (pa.first == port.id_) continue; @@ -2295,12 +2362,12 @@ bool BLIF_file::createPinGraph() noexcept { uint cn_realId = cn.realId(*this); key = hashCantor(cn_realId, i + 1) + max_key1; assert(key); - // if (key == 110) - // lputs3(); kid = pg_.findNode(key); if (kid) { - lprintf("\t\t ___ found nid %u '%s' for key %zu", - kid, pg_.cnodeName(kid), key); + if (trace_ >= 8) { + lprintf("\t\t ___ found nid %u '%s' for key %zu", + kid, pg_.cnodeName(kid), key); + } } else { kid = pg_.insK(key); @@ -2529,7 +2596,8 @@ bool BLIF_file::createPinGraph() noexcept { pg_.setNwName("pin_graph"); - // writePinGraph("pin_graph_1.dot"); + if (trace_ >= 8) + writePinGraph("Dpin_graph_1.dot", true, false); #ifndef NDEBUG // -- verify that all NW IDs are mapped to BNodes: @@ -2577,11 +2645,13 @@ string BLIF_file::writePinGraph(CStr fn0, bool nodeTable, bool noDeg0) const noe err_puts(); flush_out(true); } - lprintf("(writePinGraph) status:%s file: %s\n", - wrDot_ok ? "OK" : "FAIL", - fn.c_str()); + if (not wrDot_ok or trace_ >= 4) { + lprintf("(writePinGraph) status:%s file: %s\n\n", + wrDot_ok ? "OK" : "FAIL", + fn.c_str()); + } - flush_out(true); + flush_out(false); if (wrDot_ok) return fn; return {}; diff --git a/planning/src/file_io/pln_blif_file.h b/planning/src/file_io/pln_blif_file.h index 29926aa0..fb97a837 100644 --- a/planning/src/file_io/pln_blif_file.h +++ b/planning/src/file_io/pln_blif_file.h @@ -204,6 +204,11 @@ struct BLIF_file : public fio::MMapReader bool is_CARRY() const noexcept { return ptype_ == prim::CARRY; } + bool is_WIRE() const noexcept { + if (ptype_ != prim::A_ZERO or kw_ != ".names") + return false; + return data_.size() == 2; + } bool canDriveClockNode() const noexcept { return isTopInput() or is_CLK_BUF() or ptype_ == prim::I_SERDES; @@ -291,7 +296,7 @@ struct BLIF_file : public fio::MMapReader size_t inputs_lnum_ = 0, outputs_lnum_ = 0; mutable uint err_lnum_ = 0, err_lnum2_ = 0; - string err_msg_; + string err_msg_, err_info2_; uint16_t trace_ = 0; bool rd_ok_ = false; @@ -321,6 +326,7 @@ struct BLIF_file : public fio::MMapReader uint numNodes() const noexcept { return nodePool_.empty() ? 0 : nodePool_.size() - 1; } uint countLUTs() const noexcept; uint countFFs() const noexcept; + uint countWires() const noexcept; uint countCBUFs() const noexcept; void countBUFs(uint& nIBUF, uint& nOBUF, uint& nCBUF) const noexcept; @@ -358,8 +364,8 @@ struct BLIF_file : public fio::MMapReader bool checkClockSepar(vector& clocked) noexcept; - BNode* findOutputPort(const string& contact) noexcept; - BNode* findInputPort(const string& contact) noexcept; + BNode* findOutputPort(const string& sig) noexcept; + BNode* findInputPort(const string& sig) noexcept; BNode* findFabricParent(uint of, const string& contact, int& pinIndex) noexcept; // searches inputs BNode* findFabricDriver(uint of, const string& contact) noexcept; // matches out_ diff --git a/planning/src/main.cpp b/planning/src/main.cpp index 853db45b..b8b8bb7e 100644 --- a/planning/src/main.cpp +++ b/planning/src/main.cpp @@ -1,4 +1,4 @@ -static const char* _pln_VERSION_STR = "pln0362"; +static const char* _pln_VERSION_STR = "pln0363"; #include "RS/rsEnv.h" #include "util/pln_log.h" diff --git a/planning/src/util/nw/Nw.cpp b/planning/src/util/nw/Nw.cpp index 9f69bd25..44c8549f 100644 --- a/planning/src/util/nw/Nw.cpp +++ b/planning/src/util/nw/Nw.cpp @@ -51,7 +51,7 @@ uint NW::insK(uint64_t k) noexcept { newNid = nid_at(I - nids_.begin()); ndStor_.pop_back(); nids_.pop_back(); - // if (newNid == 36) + // if (newNid == 16) // lputs4(); } else { newNid = p->id_; @@ -62,7 +62,7 @@ uint NW::insK(uint64_t k) noexcept { } assert(nodeRef(newNid).key_ == k); - //if (newNid == 36) + // if (newNid == 16) // lputs4(); return newNid; } diff --git a/planning/src/util/nw/Nw.h b/planning/src/util/nw/Nw.h index e6fec488..d98ea570 100644 --- a/planning/src/util/nw/Nw.h +++ b/planning/src/util/nw/Nw.h @@ -274,7 +274,9 @@ struct NW { inline uint numE() const noexcept; uint countRedEdges() const noexcept; - inline upair countRoots() const noexcept; + upair countRoots() const noexcept; + upair countPorts() const noexcept; + bool hasClockNodes() const noexcept; uint countClockNodes() const noexcept; uint countRedNodes() const noexcept; @@ -795,17 +797,6 @@ inline uint NW::linK(uint64_t k1, uint64_t k2) noexcept { return linkNodes(n1, n2); } -inline upair NW::countRoots() const noexcept { - uint cnt = 0, mark_cnt = 0; - if (empty()) return {cnt, mark_cnt}; - for (cNI I(*this); I.valid(); ++I) { - const Node& nd = *I; - if (nd.isTreeRoot()) cnt++; - if (nd.isFlagRoot()) mark_cnt++; - } - return {cnt, mark_cnt}; -} - inline uint NW::getMaxLabel() const noexcept { if (empty()) return 0; uint maxLabel = 0; diff --git a/planning/src/util/nw/Nw_io.cpp b/planning/src/util/nw/Nw_io.cpp index 5a1a9877..43427a0f 100644 --- a/planning/src/util/nw/Nw_io.cpp +++ b/planning/src/util/nw/Nw_io.cpp @@ -372,13 +372,19 @@ void NW::Node::nprint_dot(ostream& os) const noexcept { } else { - if (isRed()) { - ::strcpy(attrib, "[ shape=octagon, color=purple, fillcolor=pink, style=filled ];"); + if (out_flag_) { + CStr cs = isRed() ? "red" : "brown"; + ::sprintf(attrib, "[ shape=box, color=%s, style=filled ];", cs); } else { - ::strcpy(attrib, "[ shape=record, style=rounded ];"); - if (viol_flag_) { - ::strcpy(attrib, "[ shape=doubleoctagon, color=blueviolet, fillcolor=violet, style=filled ];"); + if (isRed()) { + ::strcpy(attrib, "[ shape=octagon, color=purple, fillcolor=pink, style=filled ];"); + } + else { + ::strcpy(attrib, "[ shape=record, style=rounded ];"); + if (viol_flag_) { + ::strcpy(attrib, "[ shape=doubleoctagon, color=blueviolet, fillcolor=violet, style=filled ];"); + } } } @@ -504,6 +510,7 @@ uint NW::printSum(ostream& os, uint16_t forDot) const noexcept { upair mmD = getMinMaxDeg(); upair mmL = getMinMaxLbl(); upair rcnt = countRoots(); + upair pcnt = countPorts(); uint numClkNodes = countClockNodes(); dot_comment(os, forDot); @@ -522,7 +529,9 @@ uint NW::printSum(ostream& os, uint16_t forDot) const noexcept { numNamedNodes, numRedNodes, numRedEdges); dot_comment(os, forDot); - os_printf(os, "nr=(%u,%u)\n", rcnt.first, rcnt.second); + os_printf(os, "nr=(%u,%u) #Inp=%u #Out=%u\n", + rcnt.first, rcnt.second, + pcnt.first, pcnt.second); return size(); } diff --git a/planning/src/util/nw/Nw_node.cpp b/planning/src/util/nw/Nw_node.cpp index 9e2bc603..49878110 100644 --- a/planning/src/util/nw/Nw_node.cpp +++ b/planning/src/util/nw/Nw_node.cpp @@ -158,6 +158,28 @@ uint NW::countRedEdges() const noexcept { return cnt; } +upair NW::countRoots() const noexcept { + uint cnt = 0, mark_cnt = 0; + if (empty()) return {cnt, mark_cnt}; + for (cNI I(*this); I.valid(); ++I) { + const Node& nd = *I; + if (nd.isTreeRoot()) cnt++; + if (nd.isFlagRoot()) mark_cnt++; + } + return {cnt, mark_cnt}; +} + +upair NW::countPorts() const noexcept { + uint inp_cnt = 0, out_cnt = 0; + if (empty()) return {inp_cnt, out_cnt}; + for (cNI I(*this); I.valid(); ++I) { + const Node& nd = *I; + inp_cnt += uint(nd.inp_flag_); + out_cnt += uint(nd.out_flag_); + } + return {inp_cnt, out_cnt}; +} + void NW::clearEdges() noexcept { edStor_.clear(); edStor_.emplace_back();