From 83d6e01e3c0c57097b130cdeef7f0f5f0882cf79 Mon Sep 17 00:00:00 2001 From: panhongyang Date: Thu, 30 Mar 2023 15:14:19 +0800 Subject: [PATCH] simulator --- src/commands/abc/cec.hpp | 84 +++++++++ src/commands/abc/comb.hpp | 72 ++++++++ src/commands/simulator.hpp | 68 +++++++ src/core/simulator/circuit_graph.cpp | 210 ++++++++++++++++++++++ src/core/simulator/circuit_graph.hpp | 136 ++++++++++++++ src/core/simulator/lut_parser.cpp | 189 +++++++++++++++++++ src/core/simulator/lut_parser.hpp | 20 +++ src/core/simulator/myfunction.hpp | 40 +++++ src/core/simulator/simulator.cpp | 180 +++++++++++++++++++ src/core/simulator/simulator.hpp | 48 +++++ src/core/simulator/stp_vector.hpp | 260 +++++++++++++++++++++++++++ src/phyLS.cpp | 3 + src/store.hpp | 10 ++ 13 files changed, 1320 insertions(+) create mode 100644 src/commands/abc/cec.hpp create mode 100644 src/commands/abc/comb.hpp create mode 100644 src/commands/simulator.hpp create mode 100644 src/core/simulator/circuit_graph.cpp create mode 100644 src/core/simulator/circuit_graph.hpp create mode 100644 src/core/simulator/lut_parser.cpp create mode 100644 src/core/simulator/lut_parser.hpp create mode 100644 src/core/simulator/myfunction.hpp create mode 100644 src/core/simulator/simulator.cpp create mode 100644 src/core/simulator/simulator.hpp create mode 100644 src/core/simulator/stp_vector.hpp diff --git a/src/commands/abc/cec.hpp b/src/commands/abc/cec.hpp new file mode 100644 index 0000000..fd9cd9b --- /dev/null +++ b/src/commands/abc/cec.hpp @@ -0,0 +1,84 @@ +/* phyLS: powerful heightened yielded Logic Synthesis + * Copyright (C) 2022 */ + +/** + * @file cec.hpp + * + * @brief performs combinational equivalence checking + * + * @author Homyoung + * @since 2022/12/14 + */ + +#ifndef CEC2_HPP +#define CEC2_HPP + +#include + +#include "base/abc/abc.h" +#include "base/abci/abcVerify.c" + +using namespace std; +using namespace mockturtle; + +namespace alice { + +class acec_command : public command { + public: + explicit acec_command(const environment::ptr &env) + : command(env, "performs combinational equivalence checking") { + add_option("file1, -f", filename_1, "the input file name"); + add_option("file2, -b", filename_2, "the input file name"); + add_flag("--verbose, -v", "print the information"); + } + + protected: + void execute() { + clock_t begin, end; + double totalTime; + + begin = clock(); + + pabc::Abc_Ntk_t *pNtk; + int fDelete1 = 0, fDelete2 = 0; + int nArgcNew = 0; + char **pArgvNew; + int fCheck = 1, fBarBufs = 0; + + pabc::Abc_Ntk_t *pNtk1 = pabc::Io_Read( + (char *)(filename_1.c_str()), + pabc::Io_ReadFileType((char *)(filename_1.c_str())), fCheck, fBarBufs); + end = clock(); + pabc::Abc_Ntk_t *pNtk2 = pabc::Io_Read( + (char *)(filename_2.c_str()), + pabc::Io_ReadFileType((char *)(filename_2.c_str())), fCheck, fBarBufs); + + // set defaults + int fSat = 0; + int fVerbose = 0; + int nSeconds = 20; + int nPartSize = 0; + int nConfLimit = 10000; + int nInsLimit = 0; + int fPartition = 0; + int fIgnoreNames = 0; + + pabc::Abc_NtkCecFraig(pNtk1, pNtk2, nSeconds, fVerbose); + + end = clock(); + totalTime = (double)(end - begin) / CLOCKS_PER_SEC; + + cout.setf(ios::fixed); + cout << "[CPU time] " << setprecision(2) << totalTime << " s" << endl; + } + + private: + string filename_1; + string filename_2; +}; + +ALICE_ADD_COMMAND(acec, "Verification") + +} // namespace alice + +#endif \ No newline at end of file diff --git a/src/commands/abc/comb.hpp b/src/commands/abc/comb.hpp new file mode 100644 index 0000000..6b6460f --- /dev/null +++ b/src/commands/abc/comb.hpp @@ -0,0 +1,72 @@ +/* phyLS: powerful heightened yielded Logic Synthesis + * Copyright (C) 2023 */ + +/** + * @file comb.hpp + * + * @brief converts comb network into seq, and vice versa + * + * @author Homyoung + * @since 2023/03/21 + */ + +#ifndef COMB_HPP +#define COMB_HPP + +#include "base/abc/abc.h" + +using namespace std; +using namespace mockturtle; + +namespace alice { + +class comb_command : public command { + public: + explicit comb_command(const environment::ptr &env) + : command(env, "converts comb network into seq, and vice versa") { + add_flag( + "--convert, -c", + "converting latches to PIs/POs or removing them [default = convert]"); + add_flag("--verbose, -v", "print the information"); + } + + protected: + void execute() { + clock_t begin, end; + double totalTime; + + begin = clock(); + + if (store().size() == 0u) + std::cerr << "Error: Empty ABC AIG network.\n"; + else { + pabc::Abc_Ntk_t *pNtk, *pNtkRes; + pNtk = store().current(); + if (pabc::Abc_NtkIsComb(pNtk)) + std::cerr << "The network is already combinational.\n"; + + int fRemoveLatches = 0; + if (is_set("convert")) fRemoveLatches ^= 1; + + pNtkRes = pabc::Abc_NtkDup(pNtk); + pabc::Abc_NtkMakeComb(pNtkRes, fRemoveLatches); + + store().extend(); + store().current() = pNtkRes; + } + + end = clock(); + totalTime = (double)(end - begin) / CLOCKS_PER_SEC; + + cout.setf(ios::fixed); + cout << "[CPU time] " << setprecision(2) << totalTime << " s" << endl; + } + + private: +}; + +ALICE_ADD_COMMAND(comb, "ABC") + +} // namespace alice + +#endif \ No newline at end of file diff --git a/src/commands/simulator.hpp b/src/commands/simulator.hpp new file mode 100644 index 0000000..53d5328 --- /dev/null +++ b/src/commands/simulator.hpp @@ -0,0 +1,68 @@ +/* phyLS: powerful heightened yielded Logic Synthesis + * Copyright (C) 2022 */ + +/** + * @file simulator.hpp + * + * @brief Semi-tensor product based logic network simulation + * + * @author Homyoung + * @since 2023/03/21 + */ + +#ifndef SIMULATOR_HPP +#define SIMULATOR_HPP + +#include + +#include + +#include "../core/simulator/lut_parser.hpp" +#include "../core/simulator/simulator.hpp" + +namespace alice { + +class simulator_command : public command { + public: + explicit simulator_command(const environment::ptr &env) + : command(env, "STP-based logic network simulation") { + add_option("filename,-f", filename, "name of input file"); + add_flag("--verbose, -v", "verbose output"); + } + + protected: + void execute() { + std::ifstream ifs(filename); + if (!ifs.good()) std::cerr << "Can't open file " << filename << std::endl; + + phyLS::CircuitGraph graph; + phyLS::LutParser parser; + + if (!parser.parse(ifs, graph)) + std::cerr << "Can't parse file " << filename << std::endl; + + clock_t begin, end; + double totalTime = 0.0; + + begin = clock(); + + phyLS::simulator sim(graph); + sim.simulate(); + if (is_set("verbose")) sim.print_simulation_result(); + + end = clock(); + totalTime = (double)(end - begin) / CLOCKS_PER_SEC; + + std::cout.setf(ios::fixed); + std::cout << "[CPU time] " << setprecision(2) << totalTime << " s" + << std::endl; + } + + private: + std::string filename; +}; + +ALICE_ADD_COMMAND(simulator, "Verification") +} // namespace alice + +#endif diff --git a/src/core/simulator/circuit_graph.cpp b/src/core/simulator/circuit_graph.cpp new file mode 100644 index 0000000..6f9ea6e --- /dev/null +++ b/src/core/simulator/circuit_graph.cpp @@ -0,0 +1,210 @@ +#include "circuit_graph.hpp" + +#include +#include +#include +#include + +namespace phyLS { +Gate::Gate(Type type, line_idx output, std::vector&& inputs) + : m_type(type), m_inputs(inputs), m_output(output) {} + +int Gate::make_gate_name(Type type) { + int lut = 0; + for (int i = 1; i < type.cols(); i++) { + lut = (lut << 1) + 1 - type(i); + } + return lut; +} + +// 图的构造函数,预留一块空间 +CircuitGraph::CircuitGraph() { + m_gates.reserve(5000u); + m_lines.reserve(5000u); +} + +line_idx CircuitGraph::add_input(const std::string& name) { + line_idx p_line = ensure_line(name); + if (!m_lines[p_line].is_input) { + m_lines[p_line].is_input = true; + m_inputs.push_back(p_line); + } + return p_line; +} + +line_idx CircuitGraph::add_output(const std::string& name) { + line_idx p_line = ensure_line(name); + if (!m_lines[p_line].is_output) { + m_lines[p_line].is_output = true; + m_outputs.push_back(p_line); + } + return p_line; +} + +gate_idx CircuitGraph::add_gate(Type type, + const std::vector& input_names, + const std::string& output_name) { + std::vector inputs; + // for (size_t i = 0; i < input_names.size(); ++i) + for (int i = input_names.size() - 1; i >= 0; i--) { + line_idx p_input = ensure_line(input_names[i]); + inputs.push_back(p_input); + } + + line_idx p_output = ensure_line(output_name); + + m_gates.emplace_back(type, p_output, std::move(inputs)); + gate_idx gate = m_gates.size() - 1; + m_lines[p_output].source = gate; + m_gates.back().id() = gate; + + for (size_t i = 0; i < m_gates[gate].get_inputs().size(); ++i) { + m_lines[m_gates[gate].get_inputs().at(i)].connect_as_input(gate); + } + return gate; +} + +line_idx CircuitGraph::line(const std::string& name) { + auto it = m_name_to_line_idx.find(name); + + if (it != m_name_to_line_idx.end()) { + return it->second; + } + + return NULL_INDEX; +} + +const line_idx CircuitGraph::get_line(const std::string& name) const { + auto it = m_name_to_line_idx.find(name); + + if (it != m_name_to_line_idx.end()) { + return it->second; + } + return NULL_INDEX; +} + +const std::vector& CircuitGraph::get_inputs() const { + return m_inputs; +} + +const std::vector& CircuitGraph::get_outputs() const { + return m_outputs; +} + +const std::vector& CircuitGraph::get_gates() const { return m_gates; } + +std::vector& CircuitGraph::get_gates() { return m_gates; } + +const std::vector& CircuitGraph::get_lines() const { return m_lines; } + +line_idx CircuitGraph::ensure_line(const std::string& name) { + auto it = m_name_to_line_idx.find(name); + + if (it != m_name_to_line_idx.end()) { + return it->second; + } + + m_lines.emplace_back(); + Line& line = m_lines.back(); + + line.name = name; + line.id_line = m_lines.size() - 1; + + m_name_to_line_idx[name] = m_lines.size() - 1; + + return line.id_line; +} + +void CircuitGraph::match_logic_depth() { + for (int i = 0, num = m_outputs.size(); i < num; i++) { + int level = compute_node_depth(m_lines[m_outputs[i]].source); + if (level > max_logic_depth) max_logic_depth = level; + } + m_node_level.resize(max_logic_depth + 1); + for (int i = 0; i < m_gates.size(); i++) { + m_node_level[m_gates[i].get_level()].push_back(i); + } +} + +// 计算该节点的depth = max children's depth +int CircuitGraph::compute_node_depth(const gate_idx g_id) { + Gate& gate = m_gates[g_id]; + // 如果已经被计算过 直接返回 + if (gate.get_level() != NO_LEVEL) return gate.get_level(); + // 访问所有子节点计算 + int max_depth = NO_LEVEL; + int level = -1; + for (const auto& child : gate.get_inputs()) { + if (m_lines[child].is_input) continue; + level = compute_node_depth(m_lines[child].source); + if (level > max_depth) { + max_depth = level; + } + } + if (max_depth == + NO_LEVEL) // 走出for循环max_depth没有改变,说明该节点所有的输入线都是input + max_depth = -1; + m_gates[g_id].level() = max_depth + 1; + return m_gates[g_id].level(); +} + +void CircuitGraph::print_graph() { + // 打印INPUT + for (unsigned i = 0, length = m_inputs.size(); i < length; i++) { + std::cout << "INPUT(" << m_lines[m_inputs[i]].name << ")" << std::endl; + } + // 打印OUTPUT + for (unsigned i = 0, length = m_outputs.size(); i < length; i++) { + std::cout << "OUTPUT(" << m_lines[m_outputs[i]].name << ")" << std::endl; + } + // 打印gate + for (unsigned i = 0, length = m_gates.size(); i < length; i++) { + auto& gate = m_gates[i]; + std::cout << m_lines[gate.get_output()].name << " = LUT 0x" << std::hex + << int(gate.make_gate_name(gate.get_type())) << "("; + std::vector inputs_name; + // for(const auto& input : gate.get_inputs()) + for (int i = gate.get_inputs().size() - 1; i > -1;) { + inputs_name.push_back(m_lines[gate.get_inputs()[i]].name); + inputs_name.push_back(", "); + } + inputs_name.pop_back(); + for (const auto& temp : inputs_name) std::cout << temp; + std::cout << ")" << std::endl; + } + + // //打印逻辑深度的信息 + // int level = -1; + // std::cout << "*************************************" << std::endl; + // for(const auto& t1 : m_node_level) + // { + // level++; + // std::cout << "lev = " << level << " : "; + // for(const auto& t2 : t1) + // { + // std::cout << t2 << " "; + // } + // std::cout << std::endl; + // } + + // //遍历所有的线 打印线的前后节点信息 + // for(const auto& line : m_lines) + // { + // std::cout << "*************************************" << std::endl; + // std::cout << "name: " << line.name << " "; + // if(line.is_input) + // std::cout << "input" << " /"; + // if(line.is_output) + // std::cout << "output" << " /"; + // if(!line.is_input) + // std::cout << "source: " << line.source << std::endl; + // if(!line.is_output) + // { + // std::cout << "destination_gates: "; + // for(const auto& gate : line.destination_gates) + // std::cout << gate << " "; + // std::cout << std::endl; + // } + // } +} +} // namespace phyLS diff --git a/src/core/simulator/circuit_graph.hpp b/src/core/simulator/circuit_graph.hpp new file mode 100644 index 0000000..eac2c84 --- /dev/null +++ b/src/core/simulator/circuit_graph.hpp @@ -0,0 +1,136 @@ +#ifndef CIRCUIT_GRAPH_H +#define CIRCUIT_GRAPH_H + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "stp_vector.hpp" + +#define NULL_INDEX -1 +#define NO_LEVEL -10000 + +namespace phyLS { + +using gate_idx = int; +using line_idx = int; +using node_level = int; + +using Type = stp_vec; +class Gate; +class CircuitGraph; + +struct Line { + void connect_as_input(gate_idx gate) { destination_gates.insert(gate); } + + gate_idx source = NULL_INDEX; // nullptr means input port + std::set destination_gates; + bool is_input = false; + bool is_output = false; + int id_line = NULL_INDEX; + std::string name; +}; + +class Gate { + public: + Gate(Type type, line_idx output, + std::vector &&inputs); // 构造一般gate + + Type get_type() const { return m_type; } + Type &type() { return m_type; } + + const std::vector &get_inputs() const { return m_inputs; } + std::vector &inputs() { return m_inputs; } + + const line_idx &get_output() const { return m_output; } + line_idx &output() { return m_output; } + + const int &get_id() const { return m_id; } + int &id() { return m_id; } + + const int &get_level() const { return m_level; } + int &level() { return m_level; } + + bool is_input() const { return m_type.cols() == 0; } + + int make_gate_name(Type type); + + private: + Type m_type; + int m_id = NULL_INDEX; + node_level m_level = NO_LEVEL; + std::vector m_inputs; + line_idx m_output = NULL_INDEX; +}; + +class CircuitGraph { + public: + CircuitGraph(); + + line_idx add_input(const std::string &name); + line_idx add_output(const std::string &name); + gate_idx add_gate(Type type, const std::vector &input_names, + const std::string &output_name); + + const line_idx get_line(const std::string &name) const; + line_idx line(const std::string &name); + + const Gate &get_gate(const gate_idx &idx) const { return m_gates[idx]; } + Gate &gate(const gate_idx &idx) { return m_gates[idx]; } + + const Line &get_line(const line_idx &idx) const { return m_lines[idx]; } + Line &line(const line_idx &idx) { return m_lines[idx]; } + + const std::vector &get_inputs() const; + std::vector &inputs() { return m_inputs; } + + const std::vector &get_outputs() const; + std::vector &outputs() { return m_outputs; } + + const std::vector &get_gates() const; + std::vector &get_gates(); + + const std::vector &get_lines() const; + std::vector &lines() { return m_lines; } + + const std::vector> &get_m_node_level() const { + return m_node_level; + } + std::vector> &get_m_node_level() { + return m_node_level; + } + + const int &get_mld() const { return max_logic_depth; } + + void match_logic_depth(); + void print_graph(); + + private: + line_idx ensure_line(const std::string &name); + int compute_node_depth(const gate_idx g_id); + + private: + std::vector m_lines; + std::vector m_gates; + + std::vector m_inputs; + std::vector m_outputs; + + std::vector> m_node_level; + int max_logic_depth = -1; + + public: + std::unordered_map m_name_to_line_idx; +}; +} // namespace phyLS + +#endif \ No newline at end of file diff --git a/src/core/simulator/lut_parser.cpp b/src/core/simulator/lut_parser.cpp new file mode 100644 index 0000000..c1651a6 --- /dev/null +++ b/src/core/simulator/lut_parser.cpp @@ -0,0 +1,189 @@ +#include "lut_parser.hpp" + +#include +#include + +namespace phyLS { +bool LutParser::parse(std::istream& is, CircuitGraph& graph) { + const std::string flag_input = "INPUT"; + const std::string flag_output = "OUTPUT"; + const std::string flag_lut = "LUT"; + const std::string flag_gnd = "gnd"; + for (std::string line; std::getline(is, line, '\n');) { + if (line.empty()) continue; + if (line.find(flag_input) != std::string::npos) { + match_input(graph, line); + continue; + } + if (line.find(flag_output) != std::string::npos) { + match_output(graph, line); + continue; + } + if (line.find(flag_lut) != std::string::npos) { + match_gate(graph, line); + continue; + } + } + return true; +} + +bool LutParser::match_input(CircuitGraph& graph, const std::string& line) { + std::string input_name = m_split(line, "( )")[1]; + graph.add_input(input_name); + return true; +} + +bool LutParser::match_output(CircuitGraph& graph, const std::string& line) { + std::string output_name = m_split(line, "( )")[1]; + graph.add_output(output_name); + return true; +} + +bool LutParser::match_gate(CircuitGraph& graph, const std::string& line) { + std::vector gate = m_split(line, ",=( )"); + std::string output = gate[0]; + std::string tt = gate[2]; + gate.erase(gate.begin(), gate.begin() + 3); + std::vector inputs(gate); + tt.erase(0, 2); // 删除0x + Type type = get_stp_vec(tt, inputs.size()); + graph.add_gate(type, inputs, output); + return true; +} + +stp_vec LutParser::get_stp_vec(const std::string& tt, const int& inputs_num) { + // 只有一个输入的节点(buff 或 not) + if (inputs_num == 1 && tt.size() == 1) { + stp_vec type(3); + type(0) = 2; + switch (tt[0]) { + case '0': + type(1) = 1; + type(2) = 1; + break; + case '1': + type(1) = 1; + type(2) = 0; + break; + case '2': + type(1) = 0; + type(2) = 1; + break; + case '3': + type(1) = 0; + type(2) = 0; + break; + default: + break; + } + return type; + } + stp_vec type((1 << inputs_num) + 1); + type(0) = 2; + int type_idx; + for (int i = 0, len = tt.size(); i < len; i++) { + type_idx = 4 * i + 1; + switch (tt[i]) { + case '0': // 0000 - > 1111 + type(type_idx) = 1; + type(type_idx + 1) = 1; + type(type_idx + 2) = 1; + type(type_idx + 3) = 1; + break; + case '1': // 0001 - > 1110 + type(type_idx) = 1; + type(type_idx + 1) = 1; + type(type_idx + 2) = 1; + type(type_idx + 3) = 0; + break; + case '2': // 0010 - > 1101 + type(type_idx) = 1; + type(type_idx + 1) = 1; + type(type_idx + 2) = 0; + type(type_idx + 3) = 1; + break; + case '3': // 0011 - > 1100 + type(type_idx) = 1; + type(type_idx + 1) = 1; + type(type_idx + 2) = 0; + type(type_idx + 3) = 0; + break; + case '4': // 0100 - > 1011 + type(type_idx) = 1; + type(type_idx + 1) = 0; + type(type_idx + 2) = 1; + type(type_idx + 3) = 1; + break; + case '5': // 0101 - > 1010 + type(type_idx) = 1; + type(type_idx + 1) = 0; + type(type_idx + 2) = 1; + type(type_idx + 3) = 0; + break; + case '6': // 0110 - > 1001 + type(type_idx) = 1; + type(type_idx + 1) = 0; + type(type_idx + 2) = 0; + type(type_idx + 3) = 1; + break; + case '7': // 0111 - > 1000 + type(type_idx) = 1; + type(type_idx + 1) = 0; + type(type_idx + 2) = 0; + type(type_idx + 3) = 0; + break; + case '8': // 1000 - > 0111 + type(type_idx) = 0; + type(type_idx + 1) = 1; + type(type_idx + 2) = 1; + type(type_idx + 3) = 1; + break; + case '9': // 1001 - > 0110 + type(type_idx) = 0; + type(type_idx + 1) = 1; + type(type_idx + 2) = 1; + type(type_idx + 3) = 0; + break; + case 'a': // 1010 - > 0101 + type(type_idx) = 0; + type(type_idx + 1) = 1; + type(type_idx + 2) = 0; + type(type_idx + 3) = 1; + break; + case 'b': // 1011 - > 0100 + type(type_idx) = 0; + type(type_idx + 1) = 1; + type(type_idx + 2) = 0; + type(type_idx + 3) = 0; + break; + case 'c': // 1100 - > 0011 + type(type_idx) = 0; + type(type_idx + 1) = 0; + type(type_idx + 2) = 1; + type(type_idx + 3) = 1; + break; + case 'd': // 1101 - > 0010 + type(type_idx) = 0; + type(type_idx + 1) = 0; + type(type_idx + 2) = 1; + type(type_idx + 3) = 0; + break; + case 'e': // 1110 - > 0001 + type(type_idx) = 0; + type(type_idx + 1) = 0; + type(type_idx + 2) = 0; + type(type_idx + 3) = 1; + break; + case 'f': // 1111 - > 0000 + type(type_idx) = 0; + type(type_idx + 1) = 0; + type(type_idx + 2) = 0; + type(type_idx + 3) = 0; + break; + default: + break; + } + } + return type; +} +} // namespace phyLS \ No newline at end of file diff --git a/src/core/simulator/lut_parser.hpp b/src/core/simulator/lut_parser.hpp new file mode 100644 index 0000000..fbfcdd0 --- /dev/null +++ b/src/core/simulator/lut_parser.hpp @@ -0,0 +1,20 @@ +#ifndef LUT_PARSER_HPP +#define LUT_PARSER_HPP + +#include "circuit_graph.hpp" +#include "myfunction.hpp" + +namespace phyLS { +class LutParser { + public: + bool parse(std::istream& is, CircuitGraph& graph); + + private: + bool match_input(CircuitGraph& graph, const std::string& line); + bool match_output(CircuitGraph& graph, const std::string& line); + bool match_gate(CircuitGraph& graph, const std::string& line); + Type get_stp_vec(const std::string& tt, const int& inputs_num); +}; +} // namespace phyLS + +#endif diff --git a/src/core/simulator/myfunction.hpp b/src/core/simulator/myfunction.hpp new file mode 100644 index 0000000..0dd4c75 --- /dev/null +++ b/src/core/simulator/myfunction.hpp @@ -0,0 +1,40 @@ +#ifndef MYFUNCTION_HPP +#define MYFUNCTION_HPP + +#include +#include +#include + +namespace phyLS { +static std::vector m_split(const std::string& input, + const std::string& pred) { + std::vector result; + std::string temp = ""; + unsigned count1 = input.size(); + unsigned count2 = pred.size(); + unsigned j; + for (size_t i = 0; i < count1; i++) { + for (j = 0; j < count2; j++) { + if (input[i] == pred[j]) { + break; + } + } + // if input[i] != pred中的任何一个 该字符加到temp上 + if (j == count2) + temp += input[i]; + else { + if (!temp.empty()) { + result.push_back(temp); + temp.clear(); + } + } + } + return result; +} + +static void seg_fault(const std::string& name, int size, int idx) { + std::cout << name << " " << size << " : " << idx << std::endl; +} +} // namespace phyLS + +#endif \ No newline at end of file diff --git a/src/core/simulator/simulator.cpp b/src/core/simulator/simulator.cpp new file mode 100644 index 0000000..836aa35 --- /dev/null +++ b/src/core/simulator/simulator.cpp @@ -0,0 +1,180 @@ +#include "simulator.hpp" + +namespace phyLS { +simulator::simulator(CircuitGraph& graph) : graph(graph) { + pattern_num = 20; // 随机产生10000个仿真向量 + // max_branch = int( log2(pattern_num) ); //做cut的界 + max_branch = 8; + sim_info.resize(graph.get_lines().size()); // 按照lines的id记录仿真向量的信息 + lines_flag.resize(graph.get_lines().size(), false); // 按照线的id给线做标记 + for (const line_idx& line_id : graph.get_inputs()) { + sim_info[line_id].resize(pattern_num); + lines_flag[line_id] = true; + for (int i = 0; i < pattern_num; i++) { + sim_info[line_id][i] = rand() % 2; + } + } +} + +bool simulator::simulate() { + // 1: 给电路划分层级 + graph.match_logic_depth(); + // 2: 确定电路中需要仿真的nodes + need_sim_nodes nodes = get_need_nodes(); + // 3: 仿真 + for (const auto& node : nodes) { + single_node_sim(node); + } + // 4: 打印结果 + // print_simulation_result(); + return true; +} + +need_sim_nodes simulator::get_need_nodes() { + need_sim_nodes nodes; + for (const auto& nodes_id : graph.get_m_node_level()) { + for (const auto& node_id : nodes_id) { + const auto& node = graph.get_gates()[node_id]; + const auto& output = graph.get_lines()[node.get_output()]; + // 如果是output节点或多扇出节点,则需要仿真 + if (output.is_output || output.destination_gates.size() > fanout_limit) { + nodes.clear(); + lines_flag[node.get_output()] = true; // 给需要仿真的节点打标记 + nodes.push_back(node_id); + cut_tree(nodes); + } + nodes.push_back(node_id); + } + } + nodes.clear(); + for (unsigned level = 0; level <= graph.get_mld(); level++) { + for (const auto& node_id : graph.get_m_node_level()[level]) { + line_idx output = graph.get_gates()[node_id].get_output(); + lines_flag[output] == true; + if (lines_flag[output] == true) { + nodes.push_back(node_id); + } + } + } + return nodes; +} + +// 广度优先遍历 cut tree +void simulator::cut_tree(need_sim_nodes& nodes) { + need_sim_nodes temp_nodes; + const auto& graph_lines = graph.get_lines(); + const auto& graph_gates = graph.get_gates(); + while (!nodes.empty()) { + temp_nodes.clear(); + temp_nodes.push_back(nodes.front()); + nodes.pop_front(); + int count = 0; + while (1) { + for (const auto& input : graph_gates[temp_nodes.front()].get_inputs()) { + count++; + if (lines_flag[input] == false) { + temp_nodes.push_back(graph_lines[input].source); + } + } + temp_nodes.pop_front(); + count--; + // 对应该两种情况 (确实是棵大树,将其化为小树 || 本就是一颗小树) + if (count > max_branch || temp_nodes.empty()) { + break; + } + } + for (const auto& node_id : temp_nodes) { + lines_flag[graph_gates[node_id].get_output()] = true; + nodes.push_back(node_id); + } + } +} + +void simulator::single_node_sim(const gate_idx node_id) { + const auto& node = graph.get_gates()[node_id]; + const gate_idx& output = node.get_output(); + // 1:生成矩阵链 + std::map map; + m_chain matrix_chain; + get_node_matrix(node_id, matrix_chain, map); + // 2:分析矩阵链,减少变量个数 + stp_logic_manage stp; + stp_vec root_stp_vec = stp.normalize_matrix(matrix_chain); + // 3:仿真 + std::vector variable(map.size()); + int inputs_number = variable.size(); + for (const auto& temp : map) variable[temp.second - 1] = temp.first; + sim_info[output].resize(pattern_num); + int idx; + int bits = 1 << inputs_number; + for (int i = 0; i < pattern_num; i++) { + idx = 0; + for (int j = 0; j < inputs_number; j++) { + idx = (idx << 1) + sim_info[variable[j]][i]; + } + idx = bits - idx; + sim_info[output][i] = 1 - root_stp_vec(idx); + } + lines_flag[output] = true; +} + +// 对于某个cut 生成matrix chain +void simulator::get_node_matrix(const gate_idx node_id, m_chain& mc, + std::map& map) { + const auto& node = graph.get_gates()[node_id]; + mc.push_back(node.get_type()); + int temp; + for (const auto& line_id : node.get_inputs()) { + if (lines_flag[line_id]) // 存变量 + { + if (map.find(line_id) == map.end()) { + temp = map.size() + 1; + map.emplace(line_id, map.size() + 1); + } else + temp = map.at(line_id); + mc.emplace_back(1, temp); + } else // 存lut (PIs)的lines_flag必为true 所以这种情况不可能出现source为空 + { + get_node_matrix(graph.get_lines()[line_id].source, mc, map); + } + } +} + +void simulator::print_simulation_result() { + for (const auto& input_id : graph.get_inputs()) { + std::cout << graph.get_lines()[input_id].name << " "; + } + std::cout << ": "; + for (const auto& output_id : graph.get_outputs()) { + std::cout << graph.get_lines()[output_id].name << " "; + } + std::cout << std::endl; + for (int i = 0; i < pattern_num; i++) { + for (const auto& input_id : graph.get_inputs()) { + std::cout << sim_info[input_id][i] << " "; + } + std::cout << ": "; + for (const auto& output_id : graph.get_outputs()) { + std::cout << sim_info[output_id][i] << " "; + } + std::cout << std::endl; + } +} + +bool simulator::check_sim_info() { + for (int i = 0; i < sim_info.size(); i++) { + if (sim_info[i].size() != pattern_num) { + std::cout << "!" << std::endl; + return false; + } + for (int j = 0; j < sim_info[i].size(); j++) { + if (sim_info[i][j] != 0 && sim_info[i][j] != 1) { + std::cout << "!" << std::endl; + return false; + } + } + } + std::cout << "^ ^" << std::endl; + return true; +} +} // namespace phyLS diff --git a/src/core/simulator/simulator.hpp b/src/core/simulator/simulator.hpp new file mode 100644 index 0000000..f675e51 --- /dev/null +++ b/src/core/simulator/simulator.hpp @@ -0,0 +1,48 @@ +#ifndef C_SIMLUATOR_HPP +#define C_SIMLUATOR_HPP + +#include +#include +#include +#include +#include +#include + +#include "circuit_graph.hpp" +#include "myfunction.hpp" + +namespace phyLS { + +using need_sim_nodes = std::deque; +using line_sim_info = std::vector; + +class simulator { + public: + simulator(CircuitGraph& graph); + bool simulate(); // simulate + void print_simulation_result(); + + private: + bool is_simulated(const line_idx id) { + return sim_info[id].size() == pattern_num; + } + + need_sim_nodes get_need_nodes(); + void single_node_sim(const gate_idx node); + void get_node_matrix(const gate_idx node, m_chain& mc, + std::map& map); + void cut_tree(need_sim_nodes& nodes); + bool check_sim_info(); + + private: + std::vector sim_info; + std::vector time_interval; + std::vector lines_flag; + CircuitGraph& graph; + int pattern_num; + int max_branch; + int fanout_limit = 1; +}; +} // namespace phyLS + +#endif \ No newline at end of file diff --git a/src/core/simulator/stp_vector.hpp b/src/core/simulator/stp_vector.hpp new file mode 100644 index 0000000..be17899 --- /dev/null +++ b/src/core/simulator/stp_vector.hpp @@ -0,0 +1,260 @@ +#ifndef STP_VECTOR_HPP +#define STP_VECTOR_HPP + +#include +#include +#include + +#include "myfunction.hpp" + +namespace phyLS { +class stp_vec; +using word = unsigned; +using m_chain = std::vector; + +class stp_vec { + // 重载打印操作符 + friend std::ostream &operator<<(std::ostream &os, const stp_vec &v) { + const unsigned length = v.cols(); + for (unsigned i = 0; i < length; ++i) os << v.vec[i] << " "; + os << std::endl; + return os; + } + + // 重载初始化操作符 + friend std::istream &operator>>(std::istream &is, stp_vec &v) { + const unsigned length = v.cols(); + for (unsigned i = 0; i < length; ++i) is >> v.vec[i]; + return is; + } + + public: + // 各种初始化操作 + stp_vec() { this->vec.clear(); } + stp_vec(unsigned cols, unsigned value = 0) { this->vec.resize(cols, value); } + stp_vec(const stp_vec &v) { this->vec = v.vec; } + stp_vec &operator=(const stp_vec &v) { + this->vec = v.vec; + return *this; + } + + // 重载== + bool operator==(const stp_vec &v) { + unsigned m_length = this->cols(); + unsigned length = v.cols(); + if (m_length != length) return false; + for (unsigned i = 0; i < length; ++i) { + if (this->vec[i] != v.vec[i]) { + return false; + } + } + return true; + } + // 重载() + word &operator()(unsigned idx) { return vec[idx]; } + + const word &operator()(unsigned idx) const { return vec[idx]; } + + // 获取矩阵的列数 + const unsigned cols() const { return this->vec.size(); } + + // 判断是不是一个变量 + bool is_variable() { return this->cols() == 1; } + + // 块赋值 + bool block(const stp_vec &v, int m_begin, int begin, int num) { + if (this->cols() < num || v.cols() < num) { + std::cout << "block abnormal" << std::endl; + return false; + } + for (unsigned i = 0; i < num; ++i) { + this->vec[m_begin + i] = v.vec[begin + i]; + } + return true; + } + + private: + private: + std::vector vec; // 可以对比一下vector 与 deque +}; + +class stp_logic_manage { + public: + // 生成一个交换矩阵 + stp_vec logic_swap_matrix(int m, int n) { + stp_vec result(m * n + 1); + int p, q; + result(0) = m * n; + for (int i = 0; i < m * n; i++) { + p = i / m; + q = i % m; + int j = q * n + p; + result(j + 1) = i; + } + return result; + } + + // 克罗内克积 + stp_vec logic_kron_product(const stp_vec &v_f, const stp_vec &v_b) { + int m = v_f(0); + int n = v_f.cols() - 1; + int p = v_b(0); + int q = v_b.cols() - 1; + stp_vec result(n * q + 1); + result(0) = m * p; + for (int i = 0; i < n; i++) { + int temp = v_f(i + 1) * p; + int idx = i * q + 1; + for (int j = 0; j < q; j++) { + result(idx + j) = temp + v_b(j + 1); + } + } + return result; + } + + // 两矩阵乘法 + stp_vec logic_stpm_product(const stp_vec &v_f, const stp_vec &v_b) { + int mf_row = v_f(0); // m + int mf_col = v_f.cols() - 1; // n + int mb_row = v_b(0); // p + int mb_col = v_b.cols() - 1; // q + int row, col; + stp_vec result; + if (mf_col % mb_row == 0) { + int times = mf_col / mb_row; + row = mf_row; + col = times * mb_col; + stp_vec result_matrix(col + 1); + result_matrix(0) = row; + for (int i = 1; i <= mb_col; ++i) { + result_matrix.block(v_f, 1 + times * (i - 1), times * v_b(i) + 1, + times); + } + return result_matrix; + } else if (mb_row % mf_col == 0) { + int times = mb_row / mf_col; + stp_vec i_times(times + 1); + i_times(0) = times; + // 单位矩阵的编码向量 + for (int i = 1; i <= times; i++) { + i_times(i) = i - 1; + } + return logic_stpm_product(logic_kron_product(v_f, i_times), v_b); + } else { + std::cout << v_f << v_b << std::endl; + std::cout << "matrix type error!" << std::endl; + } + return result; + } + + // 矩阵链乘法 + stp_vec matrix_chain_mul(const m_chain &matrix_chain) { + if (matrix_chain.size() == 1) return matrix_chain[0]; + stp_vec result; + result = logic_stpm_product(matrix_chain[0], matrix_chain[1]); + for (int i = 2; i < matrix_chain.size(); i++) { + result = logic_stpm_product(result, matrix_chain[i]); + } + return result; + } + + // 化为规范型 提前给出变量的信息 + stp_vec normalize_matrix(m_chain &vec_chain) { + stp_vec Mr(3); + Mr(0) = 4; + Mr(1) = 0; + Mr(2) = 3; // Reduced power matrix + stp_vec I2(3); + I2(0) = 2; + I2(1) = 0; + I2(2) = 1; + stp_vec normal_matrix; + int p_variable; + int p; + int max = 0; + for (int i = 0; i < vec_chain.size(); + i++) // the max is the number of variable + { + if (vec_chain[i].is_variable() && vec_chain[i](0) > max) { + max = vec_chain[i](0); + } + } + // 处理直接就是规范型的矩阵链 + if (vec_chain.size() == max + 1) return vec_chain[0]; + // 常规处理 + std::vector idx(max + 1); // id0 is the max of idx + p_variable = vec_chain.size() - 1; + int flag; + while (p_variable >= 0) { + int flag = 0; + if (vec_chain[p_variable].is_variable()) // 1:find a variable + { + if (idx[vec_chain[p_variable](0)] == 0) { + idx[vec_chain[p_variable](0)] = idx[0] + 1; + idx[0]++; + if (p_variable == vec_chain.size() - 1) //! + { + vec_chain.pop_back(); + p_variable--; + continue; + } + } else { + if (idx[vec_chain[p_variable](0)] == idx[0]) { + flag = 1; + if (p_variable == vec_chain.size() - 1) { + vec_chain.pop_back(); + vec_chain.push_back(Mr); + continue; + } + } else { + flag = 1; + vec_chain.push_back(logic_swap_matrix( + 2, 1 << (idx[0] - idx[vec_chain[p_variable](0)]))); + for (int i = 1; i <= max; i++) { + if (idx[i] != 0 && idx[i] > idx[vec_chain[p_variable](0)]) + idx[i]--; + } + idx[vec_chain[p_variable](0)] = idx[0]; + } + } + m_chain matrix_chain1; //? + matrix_chain1.clear(); + for (p = p_variable + 1; p < vec_chain.size(); p++) { + matrix_chain1.push_back(vec_chain[p]); // have no matrix + } + while (p > p_variable + 1) { + vec_chain.pop_back(); + p--; + } + if (matrix_chain1.size() > 0) { + vec_chain.push_back(matrix_chain_mul(matrix_chain1)); + } + if (p_variable != vec_chain.size() - 1) { + vec_chain[p_variable] = + logic_kron_product(I2, vec_chain[p_variable + 1]); + vec_chain.pop_back(); + } + if (flag) vec_chain.push_back(Mr); + continue; + } else { + p_variable--; + } + } + // 后续矩阵链中已经没有变量 + for (int i = max; i > 0; i--) //! + { + vec_chain.push_back(logic_swap_matrix(2, 1 << (idx[0] - idx[i]))); + for (int j = 1; j <= max; j++) { + if (idx[j] != 0 && idx[j] > idx[i]) idx[j]--; + } + idx[i] = max; + } + normal_matrix = matrix_chain_mul(vec_chain); + return normal_matrix; + } + + private: +}; +} // namespace phyLS + +#endif \ No newline at end of file diff --git a/src/phyLS.cpp b/src/phyLS.cpp index 0b38ae2..6736630 100644 --- a/src/phyLS.cpp +++ b/src/phyLS.cpp @@ -47,5 +47,8 @@ #include "commands/abc/fraig.hpp" #include "commands/abc/&get.hpp" #include "commands/abc/&fraig.hpp" +#include "commands/abc/comb.hpp" +#include "commands/simulator.hpp" +#include "commands/abc/cec.hpp" ALICE_MAIN(phyLS) \ No newline at end of file diff --git a/src/store.hpp b/src/store.hpp index 8fc0b08..246da2f 100644 --- a/src/store.hpp +++ b/src/store.hpp @@ -231,6 +231,16 @@ ALICE_PRINT_STORE_STATISTICS(aig_network, os, aig) { ALICE_ADD_FILE_TYPE(verilog, "Verilog"); +ALICE_READ_FILE(aig_network, verilog, filename, cmd) { + aig_network aig; + + if (lorina::read_verilog(filename, mockturtle::verilog_reader(aig)) != + lorina::return_code::success) { + std::cout << "[w] parse error\n"; + } + return aig; +} + ALICE_READ_FILE(xmg_network, verilog, filename, cmd) { xmg_network xmg;