aboutsummaryrefslogtreecommitdiffstats
path: root/frontends/ast/genrtlil.cc
diff options
context:
space:
mode:
authorRupert Swarbrick <rswarbrick@gmail.com>2020-04-20 16:06:53 +0100
committerZachary Snow <zachary.j.snow@gmail.com>2021-08-13 17:11:35 -0600
commitee2b5b7ed186414897a8a570a9e503c438803ad8 (patch)
tree649b8773ac8f332439b1071086e55512bf356697 /frontends/ast/genrtlil.cc
parentf7913285067ed30bf5087f265db7e0bd523af2b6 (diff)
downloadyosys-ee2b5b7ed186414897a8a570a9e503c438803ad8.tar.gz
yosys-ee2b5b7ed186414897a8a570a9e503c438803ad8.tar.bz2
yosys-ee2b5b7ed186414897a8a570a9e503c438803ad8.zip
Generate an RTLIL representation of bind constructs
This code now takes the AST nodes of type AST_BIND and generates a representation in the RTLIL for them. This is a little tricky, because a binding of the form: bind baz foo_t foo_i (.arg (1 + bar)); means "make an instance of foo_t called foo_i, instantiate it inside baz and connect the port arg to the result of the expression 1+bar". Of course, 1+bar needs a cell for the addition. Where should that cell live? With this patch, the Binding structure that represents the construct is itself an AST::AstModule module. This lets us put the adder cell inside it. We'll pull the contents out and plonk them into 'baz' when we actually do the binding operation as part of the hierarchy pass. Of course, we don't want RTLIL::Binding to contain an AST::AstModule (since kernel code shouldn't depend on a frontend), so we define RTLIL::Binding as an abstract base class and put the AST-specific code into an AST::Binding subclass. This is analogous to the AST::AstModule class.
Diffstat (limited to 'frontends/ast/genrtlil.cc')
-rw-r--r--frontends/ast/genrtlil.cc79
1 files changed, 77 insertions, 2 deletions
diff --git a/frontends/ast/genrtlil.cc b/frontends/ast/genrtlil.cc
index 45aab9d8e..c82664b98 100644
--- a/frontends/ast/genrtlil.cc
+++ b/frontends/ast/genrtlil.cc
@@ -28,8 +28,10 @@
#include "kernel/log.h"
#include "kernel/utils.h"
+#include "kernel/binding.h"
#include "libs/sha1/sha1.h"
#include "ast.h"
+#include "ast_binding.h"
#include <sstream>
#include <stdarg.h>
@@ -733,6 +735,69 @@ struct AST_INTERNAL::ProcessGenerator
}
};
+// Generate RTLIL for a bind construct
+//
+// The AST node will have one or more AST_IDENTIFIER children, which were added
+// by bind_target_instance in the parser. After these, it will have one or more
+// cells, as parsed by single_cell. These have type AST_CELL.
+//
+// If there is more than one AST_IDENTIFIER, the first one should be considered
+// a module identifier. If there is only one AST_IDENTIFIER, we can't tell at
+// this point whether it's a module/interface name or the name of an instance
+// because the correct interpretation depends on what's visible at elaboration
+// time. For now, we just treat it as a target instance with unknown type, and
+// we'll deal with the corner case in the hierarchy pass.
+//
+// To simplify downstream code, RTLIL::Binding only has a single target and
+// single bound instance. If we see the syntax that allows more than one of
+// either, we split it into multiple Binding objects.
+std::vector<RTLIL::Binding *> AstNode::genBindings() const
+{
+ // Partition children into identifiers and cells
+ int num_ids = 0;
+ for (int i = 0; i < GetSize(children); ++i) {
+ if (children[i]->type != AST_IDENTIFIER) {
+ log_assert(i > 0);
+ num_ids = i;
+ break;
+ }
+ }
+
+ // We should have found at least one child that's not an identifier
+ log_assert(num_ids > 0);
+
+ // Make sense of the identifiers, extracting a possible type name and a
+ // list of hierarchical IDs. We represent an unknown type with an empty
+ // string.
+ RTLIL::IdString tgt_type;
+ int first_tgt_inst = 0;
+ if (num_ids > 1) {
+ tgt_type = children[0]->str;
+ first_tgt_inst = 1;
+ }
+
+ std::vector<RTLIL::Binding *> ret;
+
+ // At this point, we know that children with index >= first_tgt_inst and
+ // index < num_ids are (hierarchical?) names of target instances. Make a
+ // binding object for each of them, and fill in the generated instance
+ // cells each time.
+ for (int i = first_tgt_inst; i < num_ids; ++i) {
+ const AstNode &tgt_child = *children[i];
+
+ for (int j = num_ids; j < GetSize(children); ++j) {
+ const AstNode &cell_child = *children[j];
+
+ log_assert(cell_child.type == AST_CELL);
+
+ ret.push_back(new AST::Binding(tgt_type, tgt_child.str,
+ cell_child));
+ }
+ }
+
+ return ret;
+}
+
// detect sign and width of an expression
void AstNode::detectSignWidthWorker(int &width_hint, bool &sign_hint, bool *found_real)
{
@@ -1311,7 +1376,15 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint)
RTLIL::Wire *wire = current_module->addWire(str);
set_src_attr(wire, this);
wire->name = str;
- if (flag_autowire)
+
+ // If we are currently processing a bind directive which wires up
+ // signals or parameters explicitly, rather than with .*, then
+ // current_module will start out empty and we don't want to warn the
+ // user about it: we'll spot broken wiring later, when we run the
+ // hierarchy pass.
+ if (dynamic_cast<RTLIL::Binding*>(current_module)) {
+ /* nothing to do here */
+ } else if (flag_autowire)
log_file_warning(filename, location.first_line, "Identifier `%s' is implicitly declared.\n", str.c_str());
else
log_file_error(filename, location.first_line, "Identifier `%s' is implicitly declared and `default_nettype is set to none.\n", str.c_str());
@@ -1975,7 +2048,9 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint)
} break;
case AST_BIND: {
- // The bind construct. Currently unimplemented: just ignore it.
+ // Read a bind construct. This should have one or more cells as children.
+ for (RTLIL::Binding *binding : genBindings())
+ current_module->add(binding);
break;
}