aboutsummaryrefslogtreecommitdiff
path: root/src/parser/parse_tree.h
diff options
context:
space:
mode:
Diffstat (limited to 'src/parser/parse_tree.h')
-rw-r--r--src/parser/parse_tree.h890
1 files changed, 890 insertions, 0 deletions
diff --git a/src/parser/parse_tree.h b/src/parser/parse_tree.h
new file mode 100644
index 0000000..fbcefbc
--- /dev/null
+++ b/src/parser/parse_tree.h
@@ -0,0 +1,890 @@
+#pragma once
+
+#include "specs.h"
+#include "strutils.h"
+
+#include <initializer_list>
+#include <utility>
+#include <memory>
+#include <string>
+#include <vector>
+#include <map>
+#include <iostream>
+
+using std::pair;
+using std::make_pair;
+using std::string;
+using std::vector;
+using std::map;
+using std::cout;
+using std::cerr;
+using std::endl;
+using std::pair;
+using std::unique_ptr;
+
+struct ParseTree;
+struct SUBCKTDirective;
+
+/* Struct to hold a typed variable */
+struct Variable {
+ enum Type {
+ TYPE_MIN = -1,
+ DOUBLE = 0,
+ COMPLEX_DOUBLE,
+ INTEGER,
+ BOOLEAN,
+ STRING,
+ LIST,
+ NONE,
+ TYPE_MAX,
+ };
+ Type type;
+ double num;
+ complex<double> cnum;
+ int inum;
+ bool bnum;
+ string str;
+ vector<Variable> vec;
+
+ Variable(const Variable &v) { *this = v; }
+ Variable(Type type): type(type) {}
+ Variable(double num = 0): type(DOUBLE), num(num) {}
+ explicit Variable(const complex<double> &cnum): type(COMPLEX_DOUBLE), cnum(cnum) {}
+ explicit Variable(int inum): type(INTEGER), inum(inum) {}
+ explicit Variable(bool bnum): type(BOOLEAN), bnum(bnum) {}
+ explicit Variable(const string &str): type(STRING), str(str) {}
+ explicit Variable(const vector<Variable> &vec): type(LIST), vec(vec) {}
+ explicit Variable(const vector<double> &dvec): type(LIST)
+ {
+ vec.resize(dvec.size());
+ for (size_t i = 0; i < dvec.size(); ++i)
+ {
+ vec[i] = Variable(dvec[i]);
+ }
+ }
+
+ bool type_is_valid() const {
+ return TYPE_MIN < type && type < TYPE_MAX;
+ }
+
+ bool is_none() const {
+ return type == NONE;
+ }
+
+ bool is_list() const {
+ return type == LIST;
+ }
+
+ bool is_number() const {
+ return type == DOUBLE || type == INTEGER || type == BOOLEAN;
+ }
+
+ string get_str() const
+ {
+ stringstream ss;
+ switch (type)
+ {
+ case STRING:
+ return str;
+ case DOUBLE:
+ ss << num;
+ return ss.str();
+ case COMPLEX_DOUBLE:
+ ss << cnum.real() << " + " << cnum.imag() << "i";
+ return ss.str();
+ case INTEGER:
+ ss << inum;
+ return ss.str();
+ case BOOLEAN:
+ ss << bnum;
+ return ss.str();
+ case LIST:
+ ss << "[";
+ for (size_t i = 0; i < vec.size(); ++i)
+ {
+ ss << vec[i].to_json();
+ if (i != vec.size() - 1)
+ ss << ", ";
+ }
+ ss << "]";
+ return ss.str();
+ case NONE:
+ return "None";
+ default:
+ cerr << "error: cannot convert variable to string" << endl;
+ exit(1);
+ }
+ }
+
+ string to_json() const
+ {
+ stringstream ss;
+ ss << '{';
+ ss << "\"type\":" << '"' << kind() << '"' << ',';
+ ss << "\"value\":";
+ {
+ stringstream tss;
+ switch (type) {
+ case STRING:
+ tss << '"' << str << '"';
+ break;
+ case DOUBLE:
+ tss << scientific << num;
+ break;
+ case COMPLEX_DOUBLE:
+ tss << "{\"real\":";
+ tss << scientific << cnum.real();
+ tss << ",\"imag\":" << cnum.imag();
+ tss << '}';
+ break;
+ case INTEGER:
+ tss << inum;
+ break;
+ case BOOLEAN:
+ tss << (bnum ? "true" : "false");
+ break;
+ case LIST:
+ tss << "[";
+ for (size_t i = 0; i < vec.size(); ++i) {
+ tss << vec[i].to_json();
+ if (i != vec.size() - 1)
+ tss << ", ";
+ }
+ tss << "]";
+ break;
+ case NONE:
+ tss << "null";
+ break;
+ default:
+ cerr << "error: cannot convert variable to json representation" << endl;
+ exit(1);
+ }
+ ss << tss.str();
+ }
+ ss << '}';
+ return ss.str();
+ }
+
+ double as_double() const
+ {
+ if (type == DOUBLE)
+ return num;
+ if (type == INTEGER)
+ return inum;
+ if (type == BOOLEAN)
+ return bnum;
+ cerr << "Variable cannot be converted to a double value: " << get_str() << endl;
+ exit(1);
+ }
+
+ int as_integer() const
+ {
+ if (type == DOUBLE)
+ return num;
+ if (type == INTEGER)
+ return inum;
+ if (type == BOOLEAN)
+ return bnum;
+ cerr << "Variable cannot be converted to an integer value: " << get_str() << endl;
+ exit(1);
+ }
+
+ bool as_boolean() const
+ {
+ if (type == DOUBLE)
+ return num;
+ if (type == INTEGER)
+ return inum;
+ if (type == BOOLEAN)
+ return bnum;
+ cerr << "Variable cannot be converted to a boolean value: " << get_str() << endl;
+ exit(1);
+ }
+
+ complex<double> as_complex() const
+ {
+ if (type == DOUBLE)
+ return num;
+ if (type == COMPLEX_DOUBLE)
+ return cnum;
+ if (type == INTEGER)
+ return inum;
+ if (type == BOOLEAN)
+ return bnum;
+ cerr << "Variable cannot be converted to a complex value: " << get_str() << endl;
+ exit(1);
+ }
+
+ string as_string() const
+ {
+ if (type == STRING)
+ return str;
+ cerr << "Variable is not a string: " << get_str() << endl;
+ exit(1);
+ return 0;
+ }
+
+ string kind() const
+ {
+ if (type == DOUBLE)
+ return "DOUBLE";
+ if (type == COMPLEX_DOUBLE)
+ return "COMPLEX_DOUBLE";
+ if (type == INTEGER)
+ return "INTEGER";
+ if (type == BOOLEAN)
+ return "BOOLEAN";
+ if (type == STRING)
+ return "STRING";
+ if (type == LIST)
+ return "LIST";
+ if (type == NONE)
+ return "NONE";
+
+ return "UNDEFINED";
+ }
+
+ Variable &operator+=(const Variable &rhs)
+ {
+ num = as_double() + rhs.as_double();
+ type = DOUBLE;
+ return *this;
+ }
+ Variable &operator-=(const Variable &rhs)
+ {
+ num = as_double() - rhs.as_double();
+ type = DOUBLE;
+ return *this;
+ }
+ Variable &operator*=(const Variable &rhs)
+ {
+ num = as_double() * rhs.as_double();
+ type = DOUBLE;
+ return *this;
+ }
+ Variable &operator/=(const Variable &rhs)
+ {
+ num = as_double() / rhs.as_double();
+ type = DOUBLE;
+ return *this;
+ }
+ Variable &operator^=(const Variable &rhs)
+ {
+ num = pow(as_double(), rhs.as_double());
+ type = DOUBLE;
+ return *this;
+ }
+ Variable &operator=(const Variable &rhs) = default;
+ operator string() const { return get_str(); }
+};
+
+/* Dummy circuit directive struct */
+struct ParseDirective {
+ ParseTree *parent;
+ vector<Variable> args; // list of non-keyword arguments found on netlist
+ map<string, Variable> kwargs; // list of kw arguments found on netlist
+
+ ParseDirective()
+ {}
+
+ ParseDirective(const ParseDirective& other) = default;
+
+ virtual void print() const
+ {
+ cout << "DIRECTIVE[" << kind() << "] ";
+ cout << "{";
+ for (const auto &x : args)
+ cout << x.get_str() << " (" << x.kind() << "), ";
+ if ( !args.empty() )
+ cout << "\b\b";
+ cout << "} ";
+ cout << "{";
+ for (const auto &x : kwargs)
+ cout << x.first << " (" << x.second.kind() << ") = " << x.second.get_str() << ", ";
+ if ( !kwargs.empty() )
+ cout << "\b\b";
+ cout << "}" << endl;
+ }
+ virtual string to_json() const;
+
+ virtual ParseDirective *clone() const = 0;
+ virtual void create() const = 0;
+ virtual string kind() const { return "UNDEFINED"; }
+ virtual ~ParseDirective() {}
+};
+
+/* Dummy circuit analysis struct */
+struct ParseAnalysis {
+ const ParseTree *parent;
+ vector<Variable> args; // list of non-keyword arguments found on netlist
+ map<string, Variable> kwargs; // list of kw arguments found on netlist
+
+ ParseAnalysis()
+ {}
+
+ ParseAnalysis(const ParseAnalysis& other) = default;
+
+ void print() const
+ {
+ cout << "ANALYSIS[" << kind() << "] ";
+ cout << "{";
+ for (const auto &x : args)
+ cout << x.get_str() << " (" << x.kind() << "), ";
+ if ( !args.empty() )
+ cout << "\b\b";
+ cout << "} ";
+ cout << "{";
+ for (const auto &x : kwargs)
+ cout << x.first << " (" << x.second.kind() << ") = " << x.second.get_str() << ", ";
+ if ( !kwargs.empty() )
+ cout << "\b\b";
+ cout << "}" << endl;
+ }
+ virtual string to_json() const;
+
+ virtual ParseAnalysis *clone() const = 0;
+ virtual void create() const = 0;
+ virtual string kind() const { return "UNDEFINED"; }
+ virtual ~ParseAnalysis() {}
+};
+
+/* SUBCKT: subcircuit definition */
+struct ParseSubcircuit {
+ string name; // name of the subcircuit
+ string netlist; // subcircuit netlist (extracted from parent netlist)
+ vector<string> ports; // name of ports
+ map<string, Variable> kwargs; // list of kw arguments found on netlist
+ const ParseTree *parent;
+
+ ParseSubcircuit(const string &name, ParseTree *parent = nullptr)
+ : name(name)
+ , parent(parent)
+ {}
+
+ ParseSubcircuit(const ParseSubcircuit& other) = default;
+
+ void register_port(const string &port_name)
+ {
+ auto it = find(ports.cbegin(), ports.cend(), port_name);
+ if (it == ports.cend())
+ {
+ ports.push_back(port_name);
+ }
+ else
+ {
+ cerr << "Subcircuit cannot have duplicate port names";
+ cerr << "(" << port_name << " was already defined)" << endl;
+ exit(1);
+ }
+ }
+ //ParseTree *instantiate(const string &instance_name, const map<string,Variable> &kwargs) const;
+ void print() const
+ {
+ cout << name << " (" << kind() << ") ";
+ for (const auto &x : ports)
+ cout << x << " ";
+ cout << "{";
+ for (const auto &x : kwargs)
+ cout << x.first << " (" << x.second.kind() << ") = " << x.second.get_str() << ", ";
+ if ( !kwargs.empty() )
+ cout << "\b\b";
+ cout << "}" << endl;
+ if (false)
+ {
+ cout << "###########################" << endl;
+ cout << "## Start netlist of " << name << endl;
+ cout << "###########################" << endl;
+ cout << netlist;
+ cout << "###########################" << endl;
+ cout << "## End netlist of " << name << endl;
+ cout << "###########################" << endl;
+ }
+ }
+ string to_json() const;
+ string kind() const
+ { return "SUBCIRCUIT DEFINITION"; }
+ ParseSubcircuit *clone() const
+ { return new ParseSubcircuit(*this); }
+};
+
+/* Dummy circuit net struct (although close to what it should look like) */
+struct ParseNet {
+ /* Possible net types */
+ enum Type {
+ NONE,
+ OANALOG,
+ EANALOG,
+ EDIGITAL,
+ };
+
+ /* Member variables */
+ Type m_type;
+ unsigned int m_size; // number of "wires (more than 1 for buses)
+ bool m_bidirectional = false; // whether the signal should be bidirectional (for oanalog and eanalog representing forward/backward waves)
+ unsigned int m_writers_count = 0; // number of writers
+ unsigned int m_readers_count = 0; // number of readers
+ unsigned int m_ports_count = 0; // number of individual ports connected (in total)
+ unsigned int m_connect_count = 0; // number of ports actually connected (updated during creation phase only)
+ unsigned int m_connect_writer_count = 0; // number of writer ports actually connected (updated during creation phase only)
+ unsigned int m_connect_reader_count = 0; // number of reader ports actually connected (updated during creation phase only)
+
+ /* Constructor */
+ ParseNet(Type type = NONE, unsigned int size = 1): m_type(type), m_size(size) {}
+ ParseNet(const ParseNet &n) = default;
+ inline ParseNet& operator=(const ParseNet &n) = default;
+ bool combine_with(const ParseNet &n)
+ {
+ if (m_type != n.m_type)
+ return false;
+ if (m_size != n.m_size)
+ return false;
+ if (m_connect_count || n.m_connect_count)
+ return false;
+
+ m_bidirectional |= n.m_bidirectional;
+ m_writers_count += n.m_writers_count;
+ m_readers_count += n.m_readers_count;
+ m_ports_count += n.m_ports_count;
+
+ return true;
+ }
+
+ /* const Getters */
+ unsigned int size() const { return m_size; }
+ Type type() const { return m_type; }
+ bool bidirectional() const
+ {
+ return m_bidirectional || (m_writers_count == 2);
+ //return m_bidirectional || (m_writers_count == 2) || (m_readers_count == 2);
+ }
+ bool validate() const
+ {
+ return m_writers_count <= 2 && m_ports_count <= 2;
+ }
+
+ /* setters */
+ inline bool setType(Type type, bool force = false) {
+ //cout << type_str() << " - " << ParseNet(type).type_str() << endl;
+ if (m_type == type)
+ // no need to do anything
+ return true;
+ if (m_type == NONE || force)
+ {
+ m_type = type;
+ return true;
+ }
+ // cerr << "Incompatible net type assignment" << endl;
+ return false;
+ }
+
+ string type_str() const
+ {
+ switch (m_type) {
+ case Type::NONE:
+ return "NONE";
+ case Type::OANALOG:
+ return "OANALOG";
+ case Type::EANALOG:
+ return "EANALOG";
+ case Type::EDIGITAL:
+ return "EDIGITAL";
+ default:
+ cerr << "Unexpected type" << endl;
+ exit(1);
+ }
+ }
+
+ string to_json() const;
+
+ // create the net
+ vector<shared_ptr<sc_object>> create(const string &name, bool force_bidir = false) const;
+ shared_ptr<sc_object> create_uni(const string &name) const;
+
+ /* Get a generic net name from net number (different from id) */
+ static string name_from_id(int net_number);
+};
+
+struct ParseTreeCreationHelper;
+
+/* Dummy circuit element struct (although close to )*/
+struct ParseElement {
+ typedef sc_module element_type_base;
+
+ string name;
+ const ParseTree *parent;
+ vector<string> nets; // name of parent nets connected to element
+ vector<Variable> args; // list of non-keyword arguments found on netlist
+ map<string, Variable> kwargs; // list of kw arguments found on netlist
+
+ const int n_nets = 0;
+ const bool bidirectionalable = false;
+
+ ParseElement(const string &name)
+ : name(name)
+ {}
+
+ ParseElement(const string &name, const vector<string> &nets)
+ : name(name)
+ , nets(nets)
+ {}
+
+ ParseElement(const ParseElement& other) = default;
+
+ void print() const
+ {
+ cout << name << " (" << kind() << ") ";
+ for (const auto &x : nets)
+ cout << x << " ";
+ cout << "{";
+ for (const auto &x : args)
+ cout << x.get_str() << " (" << x.kind() << "), ";
+ if ( !args.empty() )
+ cout << "\b\b";
+ cout << "} ";
+ cout << "{";
+ for (const auto &x : kwargs)
+ cout << x.first << " (" << x.second.kind() << ") = " << x.second.get_str() << ", ";
+ if ( !kwargs.empty() )
+ cout << "\b\b";
+ cout << "}" << endl;
+ }
+
+ virtual ParseElement *clone() const = 0;
+ virtual sc_module *create(ParseTreeCreationHelper &pt_helper) const = 0;
+ virtual element_type_base *instantiate_and_connect_uni(ParseTreeCreationHelper &pt_helper) const = 0;
+ virtual element_type_base *instantiate_and_connect_bi(ParseTreeCreationHelper &pt_helper) const
+ {
+ (void) pt_helper;
+ cerr << "Elements of type " << kind() << " cannot be bidirectional" << endl;
+ exit(1);
+ }
+
+ virtual string kind() const { return "UNDEFINED"; }
+ virtual ~ParseElement() {}
+
+ virtual string to_json() const;
+};
+
+struct ParseTree {
+ string name;
+ const ParseTree *parent = nullptr;
+ bool is_subcircuit = false;
+ size_t unnamed_net_count = 0;
+
+ map<string, ParseNet> nets;
+ vector<string> ports; // only for subcircuits
+ vector<ParseElement *> elements;
+ vector<ParseAnalysis *> analyses;
+ vector<ParseDirective *> directives;
+ vector<ParseSubcircuit *> subcircuits;
+ map<string, Variable> local_assignments;
+ static map<string, Variable> global_assignments;
+
+ ParseTree(const string &name = "ROOT")
+ : name(name)
+ {}
+
+ ParseTree(const string &name, const ParseSubcircuit &subcircuit, const map<string, Variable> &kwargs);
+
+ int register_directive(ParseDirective *directive);
+ int register_element(ParseElement *element);
+ int register_analysis(ParseAnalysis *analysis);
+ int register_subcircuit(string name);
+ const ParseSubcircuit *find_subcircuit(const string &name) const;
+
+ string get_or_create_net(string net_name, unsigned int size = 1,
+ ParseNet::Type type = ParseNet::NONE)
+ {
+ if (net_name == "_")
+ {
+ net_name = "_" + to_string(unnamed_net_count++);
+ }
+
+ string full_net_name = name_prefix() + net_name;
+ if (nets.count(full_net_name) == 0)
+ {
+ nets.emplace(full_net_name, ParseNet(type, size));
+ return full_net_name;
+ }
+ if (nets[full_net_name].size() != size)
+ {
+ cerr << "Incompatible size: " << net_name << "<" << size << ">"
+ << " (previously declared size was: " << nets[full_net_name].size()
+ << ")" << endl;
+ exit(1);
+ }
+ if (nets[full_net_name].type() == ParseNet::NONE && type != ParseNet::NONE)
+ nets[full_net_name].m_type = type;
+ if (type == ParseNet::NONE && nets[full_net_name].type() != ParseNet::NONE)
+ type = nets[full_net_name].m_type;
+ if (nets[full_net_name].type() != type)
+ {
+ cerr << "Incompatible type: " << net_name << "[" << ParseNet(type).type_str() << "]"
+ << " (previously declared type was: " << nets[full_net_name].type_str()
+ << ")" << endl;
+ exit(1);
+ }
+ return full_net_name;
+ }
+
+ string get_or_create_net(int i, unsigned int size = 1,
+ ParseNet::Type type = ParseNet::NONE)
+ {
+ return get_or_create_net(ParseNet::name_from_id(i), size, type);
+ }
+ string get_or_create_net(Variable v, unsigned int size = 1,
+ ParseNet::Type type = ParseNet::NONE)
+ {
+ if (v.type == Variable::STRING)
+ return get_or_create_net(v.as_string(), size, type);
+ else if (v.type == Variable::INTEGER)
+ return get_or_create_net(v.as_integer(), size, type);
+ else
+ {
+ cerr << "Incompatible variable type for creating a net" << endl;
+ exit(1);
+ }
+ }
+
+ string name_prefix() const
+ {
+ string ret = "";
+ if ( !is_subcircuit && parent )
+ {
+ ret = parent->name_prefix();
+ if ( name.empty() )
+ {
+ cerr << "Name of child parse tree should not be empty" << endl;
+ exit(1);
+ }
+ }
+ ret += name + "/";
+ strutils::toupper(ret);
+ return ret;
+ }
+
+ template <typename T>
+ void set_local_variable(string &name, T val)
+ {
+ // will throw a compile error if type T is not supported by Variable
+ local_assignments[name] = val;
+ }
+
+ template <typename T>
+ void set_global_variable(string &name, T val)
+ {
+ // will throw a compile error if type T is not supported by Variable
+ global_assignments[name] = val;
+ }
+
+ Variable get_variable(string &name)
+ {
+ // try to find variable in locals table first
+ auto it = local_assignments.find(name);
+ if (it != local_assignments.end())
+ return it->second;
+
+ // try to find variable in globals table
+ it = global_assignments.find(name);
+ if (it != global_assignments.end())
+ return it->second;
+
+ // error
+ cerr << "Variable not found: " << name << endl;
+ exit(1);
+ }
+
+ void print() const;
+ string to_json() const;
+
+ ParseTree *clone() const
+ {
+ ParseTree *clone = new ParseTree(name);
+
+ clone->parent = nullptr;
+ clone->ports = ports;
+ clone->nets = nets;
+ clone->local_assignments = local_assignments;
+ clone->unnamed_net_count = unnamed_net_count;
+
+ for (const auto &x : elements)
+ clone->elements.push_back(x->clone());
+ for (const auto &x : analyses)
+ clone->analyses.push_back(x->clone());
+ for (const auto &x : directives)
+ clone->directives.push_back(x->clone());
+ for (const auto &x : subcircuits)
+ clone->subcircuits.push_back(x->clone());
+
+ return clone;
+ }
+ void build_circuit();
+ void flatten();
+
+ ~ParseTree()
+ {
+ if (!parent)
+ {
+ for (const auto &x : elements)
+ if(x) delete x;
+ for (const auto &x : analyses)
+ if(x) delete x;
+ for (const auto &x : directives)
+ if(x) delete x;
+ for (const auto &x : subcircuits)
+ if(x) delete x;
+ }
+ }
+};
+
+struct ParseTreeCreationHelper {
+ ParseTree *pt;
+
+ // backlog: elements to be created in priority
+ map<string, ParseNet> *nets;
+
+ // backlog: elements to be created in priority
+ set<const ParseElement *> elements_backlog;
+
+ // Circuit elements generated by build
+ map<string, vector<shared_ptr<sc_object>>> circuit_signals;
+ map<string, shared_ptr<sc_module>> circuit_modules;
+
+ ParseTreeCreationHelper()
+ : pt(nullptr)
+ {}
+
+ ParseTreeCreationHelper(ParseTree *parse_tree)
+ {
+ resetParseTree(parse_tree);
+ }
+
+ void resetParseTree(ParseTree *parse_tree)
+ {
+ pt = parse_tree;
+ nets = &parse_tree->nets;
+ elements_backlog.clear();
+ circuit_signals.clear();
+ circuit_modules.clear();
+ }
+
+ // return next bidir net which doesn't have a corresponding signal in circuit_signals
+ map<string, ParseNet>::iterator next_fresh_bidir_net();
+
+ // return next net which doesn't have a corresponding signal in circuit_signals
+ map<string, ParseNet>::iterator next_fresh_net();
+
+ // return next element which is connected to "net_name" and doesnt have a corresponding module in circuit_modules
+ vector<ParseElement *>::iterator next_fresh_element_bound_to(const string &net_name, const set<const ParseElement *> &excludes = {});
+
+ // upgrade a signal to bidirectional
+ void upgrade_signal(const string &name);
+
+ // Create signals connected to a given element
+ void create_signals(const ParseElement *elem);
+
+ // Connect a port to a signal using the net name
+ template <typename signal_type, typename port_type>
+ void connect_uni(port_type &port, const string& net_name, bool as_writer);
+
+ // Connect a bidirectional port to a signal pair using the net name
+ template <typename signal_type, typename port_in_type, typename port_out_type>
+ void connect_bi(port_in_type &p_in, port_out_type &p_out, const string& net_name);
+
+ ~ParseTreeCreationHelper()
+ {}
+};
+
+/** ******************************************* **/
+/** Non-specialized template implementations **/
+/** ******************************************* **/
+
+template <typename signal_type, typename port_type>
+void ParseTreeCreationHelper::connect_uni(port_type &port, const string& net_name, bool as_writer)
+{
+ assert(pt->nets.find(net_name) != pt->nets.end());
+ const auto &net = pt->nets.at(net_name);
+
+ // Get the signal to be written or read
+ signal_type *sig = nullptr;
+ if ( !net.bidirectional())
+ {
+ auto sig_raw = circuit_signals.at(net_name)[0].get();
+ sig = dynamic_cast<signal_type *>(sig_raw);
+ }
+ else
+ {
+ int i_write = pt->nets.at(net_name).m_connect_count;
+ int i_read = (i_write + 1) % 2;
+ int i = as_writer ? i_write : i_read;
+
+ auto sig_raw = circuit_signals.at(net_name)[i].get();
+ sig = dynamic_cast<signal_type *>(sig_raw);
+ }
+
+ // Check it could correctly be cast to requested type
+ if (!sig)
+ {
+ cerr << "Wrong signal type for " << sig << " connected to "
+ << net_name << endl;
+ exit(1);
+ }
+
+ // Connect the port to the signal
+ port.bind(*sig);
+
+ // Update connection count of the net
+ pt->nets[net_name].m_connect_count++;
+ if (as_writer)
+ pt->nets[net_name].m_connect_writer_count++;
+ else
+ pt->nets[net_name].m_connect_reader_count++;
+}
+
+template <typename signal_type, typename port_in_type, typename port_out_type>
+void ParseTreeCreationHelper::connect_bi(port_in_type &p_in, port_out_type &p_out, const string& net_name)
+{
+ assert(pt->nets.find(net_name) != pt->nets.end());
+ const auto &net = pt->nets.at(net_name);
+
+ if (net.bidirectional())
+ {
+
+ // First get the signal to be written or read (in the right order)
+ int i_write = pt->nets.at(net_name).m_connect_count;
+ int i_read = (i_write + 1) % 2;
+
+ auto sig_writeable_raw = circuit_signals.at(net_name)[i_write].get();
+ auto sig_readable_raw = circuit_signals.at(net_name)[i_read].get();
+ auto sig_writeable = dynamic_cast<signal_type *>(sig_writeable_raw);
+ auto sig_readable = dynamic_cast<signal_type *>(sig_readable_raw);
+
+ // Check they could correctly be cast to requested type
+ if (!sig_writeable)
+ {
+ cerr << "Wrong signal type for " << sig_writeable << " connected to "
+ << net_name << endl;
+ exit(1);
+ }
+ if (!sig_readable)
+ {
+ cerr << "Wrong signal type for " << sig_readable << " connected to "
+ << net_name << endl;
+ exit(1);
+ }
+
+ // Connect ports to both signals
+ p_out.bind(*sig_writeable);
+ p_in.bind(*sig_readable);
+
+ // Update connection count of the net
+ pt->nets[net_name].m_connect_count++;
+ pt->nets[net_name].m_connect_writer_count++;
+ pt->nets[net_name].m_connect_reader_count++;
+ }
+ else
+ {
+ cerr << "Expected a bidirectional net for " << net_name << endl;
+ exit(1);
+ }
+} \ No newline at end of file