diff --git a/src/gate/CMakeLists.txt b/src/gate/CMakeLists.txt index 7e466eda..122f290b 100644 --- a/src/gate/CMakeLists.txt +++ b/src/gate/CMakeLists.txt @@ -5,10 +5,10 @@ add_library(Gate OBJECT model/gate.cpp model/gnet.cpp model/gsymbol.cpp - model/hMetis_formatter.cpp premapper/aigmapper.cpp premapper/premapper.cpp simulator/simulator.cpp + transformer/hmetis.cpp ) add_library(Utopia::Gate ALIAS Gate) diff --git a/src/gate/debugger/checker.h b/src/gate/debugger/checker.h index 97c75278..e598818e 100644 --- a/src/gate/debugger/checker.h +++ b/src/gate/debugger/checker.h @@ -15,8 +15,6 @@ #include #include -using namespace eda::gate::model; - namespace eda::gate::debugger { /** @@ -24,6 +22,9 @@ namespace eda::gate::debugger { * \author Alexander Kamkin */ class Checker final { + using Gate = eda::gate::model::Gate; + using GNet = eda::gate::model::GNet; + public: using GateBinding = std::unordered_map; using SubnetBinding = std::unordered_map; diff --git a/src/gate/debugger/context.h b/src/gate/debugger/context.h index 9537a1a7..bc88b431 100644 --- a/src/gate/debugger/context.h +++ b/src/gate/debugger/context.h @@ -15,8 +15,6 @@ #include #include -using namespace eda::gate::model; - namespace eda::gate::debugger { /** @@ -24,6 +22,8 @@ namespace eda::gate::debugger { * \author Alexander Kamkin */ class Context final { + using Gate = eda::gate::model::Gate; + public: // MiniSAT-related types. using Var = Minisat::Var; diff --git a/src/gate/debugger/encoder.cpp b/src/gate/debugger/encoder.cpp index 4e6d96ed..b4b33efa 100644 --- a/src/gate/debugger/encoder.cpp +++ b/src/gate/debugger/encoder.cpp @@ -19,6 +19,8 @@ void Encoder::encode(const GNet &net, uint16_t version) { } void Encoder::encode(const Gate &gate, uint16_t version) { + using GateSymbol = eda::gate::model::GateSymbol; + switch (gate.func()) { case GateSymbol::IN: case GateSymbol::OUT: diff --git a/src/gate/debugger/encoder.h b/src/gate/debugger/encoder.h index 082bcd4d..99d1c281 100644 --- a/src/gate/debugger/encoder.h +++ b/src/gate/debugger/encoder.h @@ -16,8 +16,6 @@ #include #include -using namespace eda::gate::model; - namespace eda::gate::debugger { /** @@ -25,6 +23,9 @@ namespace eda::gate::debugger { * \author Alexander Kamkin */ class Encoder final { + using Gate = eda::gate::model::Gate; + using GNet = eda::gate::model::GNet; + public: void encode(const GNet &net, uint16_t version); void encode(const Gate &gate, uint16_t version); diff --git a/src/gate/debugger/symexec.h b/src/gate/debugger/symexec.h index 367bd571..ff673bb4 100644 --- a/src/gate/debugger/symexec.h +++ b/src/gate/debugger/symexec.h @@ -11,8 +11,6 @@ #include "gate/debugger/context.h" #include "gate/model/gnet.h" -using namespace eda::gate::model; - namespace eda::gate::debugger { /** @@ -20,6 +18,8 @@ namespace eda::gate::debugger { * \author Alexander Kamkin */ class SymbolicExecutor final { + using GNet = eda::gate::model::GNet; + public: SymbolicExecutor(): _cycle(1 /* should be positive */) {} diff --git a/src/gate/model/gate.h b/src/gate/model/gate.h index d15f284e..7a675b94 100644 --- a/src/gate/model/gate.h +++ b/src/gate/model/gate.h @@ -84,6 +84,14 @@ class Gate final : public GateBase { /// Creates a source gate. Gate(): Gate(GateSymbol::IN, {}) {} + + /// Invariant. + bool invariant() const { + return // Source <=> no inputs. + (isSource() == (arity() == 0)) + // Target ==> no outputs. + && (!isTarget() || (fanout() == 0)); + } }; //===----------------------------------------------------------------------===// diff --git a/src/gate/model/gnet.cpp b/src/gate/model/gnet.cpp index 3822f5f2..d3c89620 100644 --- a/src/gate/model/gnet.cpp +++ b/src/gate/model/gnet.cpp @@ -147,7 +147,7 @@ GNet::GateId GNet::addGate(Gate *gate, SubnetId sid) { } void GNet::setGate(GateId gid, GateSymbol func, const SignalList &inputs) { - // ASSERT: Inputs belong to the net (no need to modify the upper nets). + // ASSERT: All inputs belong to the net (no need to modify the upper nets). // ASSERT: Adding the given inputs does not lead to combinational cycles. auto *gate = Gate::get(gid); @@ -165,6 +165,7 @@ void GNet::setGate(GateId gid, GateSymbol func, const SignalList &inputs) { gate->setFunc(func); gate->setInputs(inputs); + assert(gate->invariant()); std::for_each(subnets.rbegin(), subnets.rend(), [gate](GNet *subnet) { subnet->onAddGate(gate, true); @@ -648,52 +649,6 @@ void GNet::sortTopologically() { } } -//===--------------------------------------------------------------------===// -// Cloning -//===--------------------------------------------------------------------===// - -/// Clones the net -GNet *GNet::clone() { - if (_gates.empty()) { - return new GNet(_level); - } - std::unordered_map oldToNewId = {}; - return clone(oldToNewId); -} - -GNet *GNet::clone(std::unordered_map &oldToNewId) { - GNet *resultNet = new GNet(_level); - if (oldToNewId.empty()) { - for (Gate *gate : _gates) { - SignalList newSignals; - Gate *newGate = new Gate(gate->func(), newSignals); - oldToNewId[gate->id()] = newGate->id(); - } - - for (Gate *gate : _gates) { - SignalList newSignals; - newSignals.reserve(gate->_inputs.capacity()); - for (Signal signal : gate->inputs()) { - newSignals.push_back(Signal(signal.event(), oldToNewId[signal.node()])); - } - Gate::Id newGateId = oldToNewId[gate->id()]; - Gate::get(newGateId)->setInputs(newSignals); - resultNet->addGate(Gate::get(newGateId)); - } - } else { - for (Gate *gate : _gates) { - resultNet->addGate(Gate::get(oldToNewId[gate->id()])); - } - } - if (!_subnets.empty()) { - for (GNet *subnet : _subnets) { - resultNet->addSubnet(subnet->clone(oldToNewId)); - } - } - - return resultNet; -} - //===----------------------------------------------------------------------===// // Output //===----------------------------------------------------------------------===// diff --git a/src/gate/model/gnet.h b/src/gate/model/gnet.h index 4e1e1ffe..fbb1798b 100644 --- a/src/gate/model/gnet.h +++ b/src/gate/model/gnet.h @@ -17,6 +17,43 @@ #include #include +/// Defines the add/set methods for a gate. +#define DEFINE_GATE_METHODS(gateSymbol, addMethod, setMethod)\ + GateId addMethod(const SignalList &args) {\ + return addGate(gateSymbol, args);\ + }\ + void setMethod(GateId gid, const SignalList &args) {\ + setGate(gid, gateSymbol, args);\ + } + +/// Defines the add/set methods for a nullary gate. +#define DEFINE_GATE0_METHODS(gateSymbol, addMethod, setMethod)\ + GateId addMethod() {\ + return addGate(gateSymbol);\ + }\ + void setMethod(GateId gid) {\ + setGate(gid, gateSymbol);\ + } + +/// Defines the add/set methods for a unary gate. +#define DEFINE_GATE1_METHODS(gateSymbol, addMethod, setMethod)\ + template GateId addMethod(const T &arg) {\ + return addGate(gateSymbol, arg);\ + }\ + template void setMethod(GateId gid, const T &arg) {\ + setGate(gid, gateSymbol, arg);\ + } + +/// Defines the add/set methods for a binary gate. +#define DEFINE_GATE2_METHODS(gateSymbol, addMethod, setMethod)\ + DEFINE_GATE_METHODS(gateSymbol, addMethod, setMethod)\ + template GateId addMethod(const T &lhs, const T &rhs) {\ + return addGate(gateSymbol, lhs, rhs);\ + }\ + template void setMethod(GateId gid, const T &lhs, const T &rhs) {\ + setGate(gid, gateSymbol, lhs, rhs);\ + } + namespace eda::gate::premapper { class PreMapper; } // namespace eda::gate::premapper @@ -252,6 +289,113 @@ class GNet final { /// Removes the gate from the net. void removeGate(GateId gid); + //===--------------------------------------------------------------------===// + // Convenience Methods + //===--------------------------------------------------------------------===// + + /// Adds a gate w/o inputs. + GateId addGate(GateSymbol func) { + return addGate(func, SignalList{}); + } + + /// Changes the given gate to the gate w/o inputs. + void setGate(GateId gid, GateSymbol func) { + setGate(gid, func, SignalList{}); + } + + /// Adds a single-input gate. + GateId addGate(GateSymbol func, const Signal &arg) { + return addGate(func, SignalList{arg}); + } + + /// Adds a single-input gate. + GateId addGate(GateSymbol func, GateId arg) { + return addGate(func, Signal::always(arg)); + } + + /// Changes the given gate to the single-input gate. + void setGate(GateId gid, GateSymbol func, const Signal &arg) { + setGate(gid, func, SignalList{arg}); + } + + /// Changes the given gate to the single-input gate. + void setGate(GateId gid, GateSymbol func, GateId arg) { + setGate(gid, func, Signal::always(arg)); + } + + /// Adds a two-inputs gate. + GateId addGate(GateSymbol func, const Signal &lhs, const Signal &rhs) { + return addGate(func, SignalList{lhs, rhs}); + } + + /// Adds a two-inputs gate. + GateId addGate(GateSymbol func, GateId lhs, GateId rhs) { + return addGate(func, Signal::always(lhs), Signal::always(rhs)); + } + + /// Changes the given gate to the two-inputs gate. + void setGate(GateId gid, GateSymbol func, const Signal &lhs, const Signal &rhs) { + setGate(gid, func, SignalList{lhs, rhs}); + } + + /// Changes the given gate to the two-inputs gate. + void setGate(GateId gid, GateSymbol func, GateId lhs, GateId rhs) { + setGate(gid, func, Signal::always(lhs), Signal::always(rhs)); + } + + DEFINE_GATE0_METHODS(GateSymbol::IN, addIn, setIn) + DEFINE_GATE1_METHODS(GateSymbol::OUT, addOut, setOut) + DEFINE_GATE0_METHODS(GateSymbol::ZERO, addZero, setZero) + DEFINE_GATE0_METHODS(GateSymbol::ONE, addOne, setOne) + DEFINE_GATE1_METHODS(GateSymbol::NOP, addNop, setNop) + DEFINE_GATE1_METHODS(GateSymbol::NOT, addNot, setNot) + DEFINE_GATE2_METHODS(GateSymbol::AND, addAnd, setAnd) + DEFINE_GATE2_METHODS(GateSymbol::OR, addOr, setOr) + DEFINE_GATE2_METHODS(GateSymbol::XOR, addXor, setXor) + DEFINE_GATE2_METHODS(GateSymbol::NAND, addNand, setNand) + DEFINE_GATE2_METHODS(GateSymbol::NOR, addNor, setNor) + DEFINE_GATE2_METHODS(GateSymbol::XNOR, addXnor, setXnor) + + /// Adds a LATCH gate. + GateId addLatch(GateId d, GateId ena) { + return addGate(GateSymbol::LATCH, {Signal::always(d), Signal::level1(ena)}); + } + + /// Changes the given gate to LATCH. + void setLatch(GateId gid, GateId d, GateId ena) { + setGate(gid, GateSymbol::LATCH, {Signal::always(d), Signal::level1(ena)}); + } + + /// Adds a DFF gate. + GateId addDff(GateId d, GateId clk) { + return addGate(GateSymbol::DFF, {Signal::always(d), Signal::posedge(clk)}); + } + + /// Changes the given gate to DFF. + void setDff(GateId gid, GateId d, GateId clk) { + setGate(gid, GateSymbol::DFF, {Signal::always(d), Signal::posedge(clk)}); + } + + /// Adds a DFFrs gate. + GateId addDffrs(GateId d, GateId clk, GateId rst, GateId set) { + return addGate(GateSymbol::DFFrs, { + Signal::always(d), + Signal::posedge(clk), + Signal::level1(rst), + Signal::level1(set) + }); + } + + /// Changes the given gate to DFFrs. + void setDffrs(GateId gid, GateId d, GateId clk, GateId rst, GateId set) { + setGate(gid, GateSymbol::DFFrs, { + Signal::always(d), + Signal::posedge(clk), + Signal::level1(rst), + Signal::level1(set) + }); + } + //===--------------------------------------------------------------------===// // Subnets //===--------------------------------------------------------------------===// @@ -362,14 +506,6 @@ class GNet final { /// Sorts the gates in topological order. void sortTopologically(); - //===--------------------------------------------------------------------===// - // Cloning - //===--------------------------------------------------------------------===// - - /// Clones the net - GNet* clone(); - GNet* clone(std::unordered_map &oldToNewId); - private: //===--------------------------------------------------------------------===// // Internal Methods diff --git a/src/gate/model/hMetis_formatter.h b/src/gate/model/hMetis_formatter.h deleted file mode 100644 index fde0b8ef..00000000 --- a/src/gate/model/hMetis_formatter.h +++ /dev/null @@ -1,28 +0,0 @@ -//===----------------------------------------------------------------------===// -// -// Part of the Utopia EDA Project, under the Apache License v2.0 -// SPDX-License-Identifier: Apache-2.0 -// Copyright 2022 ISP RAS (http://www.ispras.ru) -// -//===----------------------------------------------------------------------===// - -#pragma once - -#include - -#include "gnet.h" - -class FormatterHMetis { - std::vector weights; - std::vector eptr; - std::vector eind; - -public: - explicit FormatterHMetis(const eda::gate::model::GNet &net); - - inline std::vector *getWeights() { return &weights; } - - inline std::vector *getEptr() { return &eptr; } - - inline std::vector *getEind() { return &eind; } -}; diff --git a/src/gate/parser/reader_gate.h b/src/gate/parser/reader_gate.h new file mode 100644 index 00000000..84e7a5b0 --- /dev/null +++ b/src/gate/parser/reader_gate.h @@ -0,0 +1,219 @@ +//===----------------------------------------------------------------------===// +// +// Part of the Utopia EDA Project, under the Apache License v2.0 +// SPDX-License-Identifier: Apache-2.0 +// Copyright 2022 ISP RAS (http://www.ispras.ru) +// +//===----------------------------------------------------------------------===// + +#pragma once + +#include +#include + +#include + +#include "gate/model/gnet.h" + +class ReaderGate : public lorina::verilog_reader { +private: + struct ParserData { + struct GateData { + std::vector inputs; + eda::gate::model::GNet::GateId id = 0; + eda::gate::model::GateSymbol kind = eda::gate::model::GateSymbol::ZERO; + }; + + std::unordered_map gates; + std::unordered_map gIds; + // Wire name / + std::unordered_map> links; + + std::string netName; + bool startParse = false; + eda::gate::model::GNet gnet; + }; + + ParserData *data = new ParserData(); + +public: + explicit ReaderGate(std::string name) { + data->netName = std::move(name); + } + + ~ReaderGate() { + delete data; + } + + eda::gate::model::GNet *getGnet() { return &data->gnet; } + + /*! \brief Callback method for parsed module. + * + * \param moduleName Name of the module + * \param inouts Container for input and output names + */ + void on_module_header(const std::string &moduleName, + const std::vector &inputs) const override { + data->startParse = moduleName == data->netName; + } + + /*! \brief Callback method for parsed inputs. + * + * \param inputs Input names + * \param size Size modifier + */ + void on_inputs(const std::vector &inputs, + std::string const &size) const override { + if (data->startParse) { + for (const std::string &input: inputs) { + std::string in = "#" + input; + auto &gate = data->gates[in]; + gate.id = data->gnet.newGate(); + data->gIds.emplace(gate.id, data->gates.size() - 1); + gate.kind = eda::gate::model::GateSymbol::IN; + data->links[input] = {in, ""}; + } + } + } + + /*! \brief Callback method for parsed wires. + * + * \param wires Wire names + * \param size Size modifier + */ + void on_wires(const std::vector &wires, + std::string const &size) const override { + if (data->startParse) { + for (auto &name: wires) { + auto &gates = data->links[name]; + gates.reserve(3); + gates.resize(1); + } + } + } + + /*! \brief Callback method for parsed module instantiation of form `NAME + * #(P1,P2) NAME(.SIGNAL(SIGANL), ..., .SIGNAL(SIGNAL));` + * + * \param moduleName Name of the module + * \param params List of parameters + * \param instName Name of the instantiation + * \param args List (a_1,b_1), ..., (a_n,b_n) of name pairs, where + * a_i is a name of a signals in moduleName and b_i is a name of + * a signal in instName. + */ + void on_module_instantiation( + std::string const &moduleName, std::vector const ¶ms, + std::string const &instName, + std::vector> const &args) const override { + if (data->startParse) { + auto &gateData = data->gates[instName]; + gateData.id = data->gnet.newGate(); + data->gIds.emplace(gateData.id, data->gates.size() - 1); + gateData.kind = symbol(moduleName); + + insertLink(args[0].second, instName, false); + for (size_t i = 1; i < args.size(); ++i) { + insertLink(args[i].second, instName, true); + } + } + } + + /*! \brief Callback method for parsed endmodule. + * + */ + void on_endmodule() const override { + if (data->startParse) { + // Collect links to make inputs arrays. + for (auto &[name, links]: data->links) { + auto source = data->gates.find(links[0]); + + for (size_t i = 1; i < links.size(); ++i) { + auto target = data->gates.find(links[i]); + if (source != data->gates.end() && target != data->gates.end()) { + target->second.inputs.push_back(source->second.id); + } + } + + } + // All gates are created - modifying them. + for (const auto &[name, gateData]: data->gates) { + std::vector> + signals; + signals.reserve(gateData.inputs.size()); + + for (auto input: gateData.inputs) { + signals.emplace_back(eda::base::model::Event::ALWAYS, input); + } + + data->gnet.setGate(gateData.id, gateData.kind, signals); + } + } + } + + void print() const { + for (auto &gate: data->gnet.gates()) { + std::cout << gate->id() << " :\n"; // << " " << gate->kind() + for (auto &link: gate->links()) { + std::cout << "\t( " << link.source << " ) " << link.target << "\n"; + } + } + } + + void static print(std::ofstream &stream, const eda::gate::model::Gate *gate) { + stream << gate->id(); // << " " << gate->kind() + } + + void dotPrint(const std::string &filename) const { + std::ofstream out(filename); + dot(out); + out.close(); + } + + void dot(std::ofstream &stream) const { + stream << "digraph gnet {\n"; + for (const auto &gate: data->gnet.gates()) { + for (auto &links: gate->links()) { + stream << "\t"; + print(stream, gate); + stream << " -> "; + print(stream, data->gnet.gate(data->gIds.at(links.target))); + stream << ";\n"; + } + } + stream << "}" << std::endl; + } + +private: + void insertLink(const std::string &name, const std::string &instName, + bool out) const { + auto &link = data->links[name]; + if (out) { + link.emplace_back(instName); + } else { + assert(link[0].empty()); + link[0] = instName; + } + } + + static eda::gate::model::GateSymbol symbol(const std::string &s) { + if (s == "not") { + return eda::gate::model::GateSymbol::NOT; + } else if (s == "or") { + return eda::gate::model::GateSymbol::OR; + } else if (s == "xor") { + return eda::gate::model::GateSymbol::XOR; + } else if (s == "nand") { + return eda::gate::model::GateSymbol::NAND; + } else if (s == "nor") { + return eda::gate::model::GateSymbol::NOR; + } else if (s == "xnor") { + return eda::gate::model::GateSymbol::XNOR; + } else if (s == "and") { + return eda::gate::model::GateSymbol::AND; + } + return eda::gate::model::GateSymbol::ZERO; + } +}; + diff --git a/src/gate/premapper/aigmapper.cpp b/src/gate/premapper/aigmapper.cpp index edbf8162..023b7c6d 100644 --- a/src/gate/premapper/aigmapper.cpp +++ b/src/gate/premapper/aigmapper.cpp @@ -13,6 +13,9 @@ namespace eda::gate::premapper { +using Gate = eda::gate::model::Gate; +using GNet = eda::gate::model::GNet; + Gate::SignalList getNewInputs(const Gate &oldGate, const AigMapper::GateIdMap &oldToNewGates, size_t &n0, size_t &n1) { @@ -42,6 +45,8 @@ Gate::SignalList getNewInputs(const Gate &oldGate, Gate::Id AigMapper::mapGate(const Gate &oldGate, const GateIdMap &oldToNewGates, GNet &newNet) const { + using GateSymbol = eda::gate::model::GateSymbol; + if (oldGate.isSource() || oldGate.isTrigger()) { // Clone sources and triggers gates w/o changes. return PreMapper::mapGate(oldGate, oldToNewGates, newNet); @@ -74,7 +79,7 @@ Gate::Id AigMapper::mapGate(const Gate &oldGate, //===----------------------------------------------------------------------===// Gate::Id AigMapper::mapIn(GNet &newNet) const { - return newNet.addGate(GateSymbol::IN, {}); + return newNet.addIn(); } Gate::Id AigMapper::mapOut(const Gate::SignalList &newInputs, @@ -84,10 +89,10 @@ Gate::Id AigMapper::mapOut(const Gate::SignalList &newInputs, // Constant output. if (n0 > 0 || n1 > 0) { auto valId = mapVal(n1 > 0, newNet); - return newNet.addGate(GateSymbol::OUT, {Gate::Signal::always(valId)}); + return newNet.addOut(valId); } - return newNet.addGate(GateSymbol::OUT, newInputs); + return newNet.addOut(newInputs); } //===----------------------------------------------------------------------===// @@ -95,7 +100,7 @@ Gate::Id AigMapper::mapOut(const Gate::SignalList &newInputs, //===----------------------------------------------------------------------===// Gate::Id AigMapper::mapVal(bool value, GNet &newNet) const { - return newNet.addGate(value ? GateSymbol::ONE : GateSymbol::ZERO, {}); + return value ? newNet.addOne() : newNet.addZero(); } //===----------------------------------------------------------------------===// @@ -112,12 +117,12 @@ Gate::Id AigMapper::mapNop(const Gate::SignalList &newInputs, // NOT(NOT(x)) = x. const auto *inputGate = Gate::get(inputId); - if (inputGate->func() == GateSymbol::NOT) { + if (inputGate->func() == eda::gate::model::GateSymbol::NOT) { return inputGate->input(0).node(); } // NOT(x). - return newNet.addGate(GateSymbol::NOT, newInputs); + return newNet.addNot(newInputs); } Gate::Id AigMapper::mapNop(const Gate::SignalList &newInputs, @@ -155,7 +160,7 @@ Gate::Id AigMapper::mapAnd(const Gate::SignalList &newInputs, gateId = mapVal(!sign, newNet); } else { // AND(x,y). - gateId = newNet.addGate(GateSymbol::AND, {x, y}); + gateId = newNet.addAnd(x, y); } inputs.push_back(Gate::Signal::always(gateId)); diff --git a/src/gate/premapper/premapper.cpp b/src/gate/premapper/premapper.cpp index 65980503..8b8e30b6 100644 --- a/src/gate/premapper/premapper.cpp +++ b/src/gate/premapper/premapper.cpp @@ -13,11 +13,15 @@ namespace eda::gate::premapper { -Gate::SignalList getNewInputs(const Gate::SignalList &oldInputs, - const PreMapper::GateIdMap &oldToNewGates) { +using Gate = eda::gate::model::Gate; +using GNet = eda::gate::model::GNet; + +Gate::SignalList getNewInputs( + const Gate::SignalList &oldInputs, + const PreMapper::GateIdMap &oldToNewGates) { Gate::SignalList newInputs(oldInputs.size()); - for (size_t i = 0; i< oldInputs.size(); i++) { + for (size_t i = 0; i < oldInputs.size(); i++) { auto oldInput = oldInputs[i]; auto newInput = oldToNewGates.find(oldInput.node()); assert(newInput != oldToNewGates.end()); @@ -59,7 +63,7 @@ GNet *PreMapper::mapGates(const GNet &net, GateIdMap &oldToNewGates) const { const auto newGateId = mapGate(*oldGate, oldToNewGates, *newNet); assert(newGateId != Gate::INVALID); - oldToNewGates.insert({oldGateId, newGateId}); + oldToNewGates.emplace(oldGateId, newGateId); } return newNet; diff --git a/src/gate/premapper/premapper.h b/src/gate/premapper/premapper.h index e00190fa..f8003ef9 100644 --- a/src/gate/premapper/premapper.h +++ b/src/gate/premapper/premapper.h @@ -13,8 +13,6 @@ #include #include -using namespace eda::gate::model; - namespace eda::gate::premapper { /** @@ -22,6 +20,10 @@ namespace eda::gate::premapper { * \author Alexander Kamkin */ class PreMapper { +protected: + using Gate = eda::gate::model::Gate; + using GNet = eda::gate::model::GNet; + public: using GateIdMap = std::unordered_map; diff --git a/src/gate/simulator/simulator.cpp b/src/gate/simulator/simulator.cpp index 59c47800..5ce327de 100644 --- a/src/gate/simulator/simulator.cpp +++ b/src/gate/simulator/simulator.cpp @@ -13,9 +13,12 @@ namespace eda::gate::simulator { using Compiled = Simulator::Compiled; Compiled::OP Compiled::getOp(const Gate &gate) const { + using GateSymbol = eda::gate::model::GateSymbol; + const auto n = gate.arity(); switch (gate.func()) { + case GateSymbol::OUT : return getNop(n); case GateSymbol::ZERO : return getZero(n); case GateSymbol::ONE : return getOne(n); case GateSymbol::NOP : return getNop(n); diff --git a/src/gate/simulator/simulator.h b/src/gate/simulator/simulator.h index 29b8aacb..b8e159d6 100644 --- a/src/gate/simulator/simulator.h +++ b/src/gate/simulator/simulator.h @@ -14,8 +14,6 @@ #include #include -using namespace eda::gate::model; - namespace eda::gate::simulator { /** @@ -23,6 +21,9 @@ namespace eda::gate::simulator { * \author Alexander Kamkin */ class Simulator final { + using Gate = eda::gate::model::Gate; + using GNet = eda::gate::model::GNet; + public: /// Representation of a gate-level net optimized for simulation. class Compiled final { diff --git a/src/gate/model/hMetis_formatter.cpp b/src/gate/transformer/hmetis.cpp similarity index 80% rename from src/gate/model/hMetis_formatter.cpp rename to src/gate/transformer/hmetis.cpp index b016d01b..cdbec120 100644 --- a/src/gate/model/hMetis_formatter.cpp +++ b/src/gate/transformer/hmetis.cpp @@ -6,9 +6,9 @@ // //===----------------------------------------------------------------------===// -#include "hMetis_formatter.h" +#include "hmetis.h" -FormatterHMetis::FormatterHMetis(const eda::gate::model::GNet &net) { +HMetisPrinter::HMetisPrinter(const eda::gate::model::GNet &net) { weights = std::vector(net.nGates(), 1); std::vector involved; @@ -34,9 +34,9 @@ FormatterHMetis::FormatterHMetis(const eda::gate::model::GNet &net) { eptr.push_back(0); for (eda::gate::model::Gate* gate : net.gates()) { for (const eda::gate::model::Gate::Link& link : gate->links()) { - eind.push_back(map[link.source]); - eind.push_back(map[link.target]); - eptr.push_back(eind.size()); - } + eind.push_back(map[link.source]); + eind.push_back(map[link.target]); + eptr.push_back(eind.size()); + } } } diff --git a/src/gate/transformer/hmetis.h b/src/gate/transformer/hmetis.h new file mode 100644 index 00000000..7bb98865 --- /dev/null +++ b/src/gate/transformer/hmetis.h @@ -0,0 +1,34 @@ +//===----------------------------------------------------------------------===// +// +// Part of the Utopia EDA Project, under the Apache License v2.0 +// SPDX-License-Identifier: Apache-2.0 +// Copyright 2022 ISP RAS (http://www.ispras.ru) +// +//===----------------------------------------------------------------------===// + +#pragma once + +#include + +#include "gate/model/gnet.h" + +/** + * \brief Converts GNet scheme representation to hMetis representation + * \(see "hMETIS A Hypergraph Partitioning Package Version 1.5.3" + * \ by George Karypis and Vipin Kumar). + * \author Liza Shcherbakova + */ +class HMetisPrinter { + std::vector weights; + std::vector eptr; + std::vector eind; + +public: + explicit HMetisPrinter(const eda::gate::model::GNet &net); + + std::vector *getWeights() { return &weights; } + + std::vector *getEptr() { return &eptr; } + + std::vector *getEind() { return &eind; } +}; diff --git a/test/gate/model/gnet_test.cpp b/test/gate/model/gnet_test.cpp index a14372c1..130309a0 100644 --- a/test/gate/model/gnet_test.cpp +++ b/test/gate/model/gnet_test.cpp @@ -12,7 +12,6 @@ #include #include -#include #include using namespace eda::gate::model; @@ -25,14 +24,14 @@ static std::unique_ptr makeNet(GateSymbol gate, auto net = std::make_unique(); for (unsigned i = 0; i < N; i++) { - const Gate::Id inputId = net->newGate(); - const Gate::Signal input = Gate::Signal::always(inputId); - inputs.push_back(input); + const Gate::Id inputId = net->addIn(); + inputs.push_back(Gate::Signal::always(inputId)); } - outputId = net->addGate(gate, inputs); - net->sortTopologically(); + auto gateId = net->addGate(gate, inputs); + outputId = net->addOut(gateId); + net->sortTopologically(); return net; } @@ -45,18 +44,17 @@ static std::unique_ptr makeNetn(GateSymbol gate, Gate::SignalList andInputs; for (unsigned i = 0; i < N; i++) { - const Gate::Id inputId = net->newGate(); - const Gate::Signal input = Gate::Signal::always(inputId); - inputs.push_back(input); + const Gate::Id inputId = net->addIn(); + inputs.push_back(Gate::Signal::always(inputId)); - const Gate::Id notGateId = net->addGate(GateSymbol::NOT, { input }); - const Gate::Signal andInput = Gate::Signal::always(notGateId); - andInputs.push_back(andInput); + const Gate::Id notGateId = net->addNot(inputId); + andInputs.push_back(Gate::Signal::always(notGateId)); } - outputId = net->addGate(gate, andInputs); - net->sortTopologically(); + auto gateId = net->addGate(gate, inputs); + outputId = net->addOut(gateId); + net->sortTopologically(); return net; } @@ -122,7 +120,6 @@ std::unique_ptr makeRand(std::size_t nGates, } const auto maxGateId = net->newGate(); - std::mt19937 gen(0); std::uniform_int_distribution snetDist(0, nSubnets - 1); std::uniform_int_distribution gateDist(minGateId, maxGateId); @@ -135,7 +132,7 @@ std::unique_ptr makeRand(std::size_t nGates, // Create subnets. for (std::size_t i = 0; i < nSubnets; i++) { net->newSubnet(); - } + } // for: create subnets. // Randomly distributes the gates among the subnets. for (std::size_t i = 0; i < nGates; i++) { @@ -145,37 +142,67 @@ std::unique_ptr makeRand(std::size_t nGates, if (net->contains(gid)) { net->moveGate(gid, dst); } - } // for: moveGate. + } // for: move gates. // Randomly modify/connect the gates. for (std::size_t i = 0; i < nGates; i++) { const auto gid = gateDist(gen); + if (!net->contains(gid)) { + continue; + } - if (net->contains(gid)) { - Gate::SignalList inputs; + Gate::SignalList inputs; + + const std::size_t arity = arityDist(gen); + for (std::size_t j = 0; j < arity; j++) { + const auto inputId = gateDist(gen); - const std::size_t arity = arityDist(gen); - for (std::size_t j = 0; j < arity; j++) { - const auto inputId = gateDist(gen); + if (net->contains(inputId)) { const auto input = Gate::Signal::always(inputId); inputs.push_back(input); } + } // for: arity - // Beware of combinational cycles. - if (!net->hasCombFlow(gid, inputs)) { - net->setGate(gid, GateSymbol::AND, inputs); - } + // Beware of combinational cycles. + if (!net->hasCombFlow(gid, inputs)) { + const auto func = (inputs.empty() ? GateSymbol::IN : GateSymbol::AND); + net->setGate(gid, func, inputs); } - } // for: setGate. + } // for: set gates. // Randomly remove some gates. for (std::size_t i = 0; i < nGates / 16; i++) { const auto gid = gateDist(gen); - - if (net->contains(gid)) { - net->removeGate(gid); + if (!net->contains(gid)) { + continue; } - } // for: removeGate. + + auto *source = Gate::get(gid); + + // Check the dependent gates. + for (const auto link : source->links()) { + auto *target = Gate::get(link.target); + if (!net->contains(target->id())) { + continue; + } + + bool allFromSource = true; + for (const auto input : target->inputs()) { + if (input.node() != source->id()) { + allFromSource = false; + break; + } + } + + // If a gate depends solely on the gate being removed, + // it will have no inputs (became an input). + if (allFromSource) { + net->setIn(target->id()); + } + } // for: source links. + + net->removeGate(gid); + } // for: remove gate. net->groupOrphans(); net->removeEmptySubnets(); @@ -183,7 +210,7 @@ std::unique_ptr makeRand(std::size_t nGates, net->sortTopologically(); net->flatten(); - } // top-level for. + } // for: top-level. return net; } @@ -239,3 +266,4 @@ TEST(GNetTest, GNetRandTestIssue11877) { auto net = makeRand(7, 5); EXPECT_TRUE(net != nullptr); } + diff --git a/test/gate/parser/parser_test.cpp b/test/gate/parser/parser_test.cpp new file mode 100644 index 00000000..e74cdf26 --- /dev/null +++ b/test/gate/parser/parser_test.cpp @@ -0,0 +1,60 @@ +//===----------------------------------------------------------------------===// +// +// Part of the Utopia EDA Project, under the Apache License v2.0 +// SPDX-License-Identifier: Apache-2.0 +// Copyright 2022 ISP RAS (http://www.ispras.ru) +// +//===----------------------------------------------------------------------===// + +#include +#include +#include + +#include +#include + +#include "gate/parser/reader_gate.h" +#include "gate/transformer/hmetis.h" +#include "gtest/gtest.h" +#include "util/partition_hgraph.h" + +using namespace lorina; + +TEST(ParserVTest, all) { + /* + if (!getenv("UTOPIA_HOME")) { + FAIL() << "UTOPIA_HOME is not set."; + }*/ + + const std::filesystem::path subCatalog = "test/data/gate/parser"; + const std::filesystem::path homePath = std::string(getenv("UTOPIA_HOME")); + const std::filesystem::path prefixPath = homePath / subCatalog; + const std::filesystem::path prefixPathIn = prefixPath / "input"; + const std::filesystem::path prefixPathOut = prefixPath / "output"; + const std::string filenames = prefixPath / "verilog_filenames.txt"; + + std::ifstream in(filenames); + std::string infile; + + while (std::getline(in, infile)) { + std::string filename = prefixPathIn / (infile + ".v"); + std::string outFilename = prefixPathOut / (infile + ".dot"); + std::string outBaseFilename = prefixPathOut / ("base" + infile + ".dot"); + + text_diagnostics consumer; + diagnostic_engine diag(&consumer); + + ReaderGate reader(infile); + + return_code result = read_verilog(filename, reader, &diag); + EXPECT_EQ(result, return_code::success); + reader.dotPrint(outFilename); + //reader.print(); + + HMetisPrinter metis(*reader.getGnet()); + HyperGraph graph(metis.getWeights(), metis.getEptr(), + metis.getEind()); + graph.graphOutput(outBaseFilename); + } + in.close(); +} diff --git a/test/util/fm_test.cpp b/test/util/fm_test.cpp index 372cbe2b..95f08814 100644 --- a/test/util/fm_test.cpp +++ b/test/util/fm_test.cpp @@ -7,7 +7,7 @@ //===----------------------------------------------------------------------===// #include "gate/model/gnet_test.h" -#include "gate/model/hMetis_formatter.h" +#include "gate/transformer/hmetis.h" #include "util/fm.h" #include "util/partition_hgraph.h" @@ -122,7 +122,7 @@ void testGate(const eda::gate::model::GNet &net, int passes, double r, std::ofstream fout(outPath); fout.close(); - FormatterHMetis formatter(net); + HMetisPrinter formatter(net); HyperGraph hgraph(formatter.getWeights(), formatter.getEptr(), formatter.getEind());