Add support for cell arrays
authorClifford Wolf <clifford@clifford.at>
Sat, 7 Jun 2014 09:48:50 +0000 (11:48 +0200)
committerClifford Wolf <clifford@clifford.at>
Sat, 7 Jun 2014 09:48:50 +0000 (11:48 +0200)
frontends/ast/ast.cc
frontends/ast/ast.h
frontends/ast/simplify.cc
frontends/verilog/parser.y
kernel/rtlil.cc
passes/hierarchy/hierarchy.cc

index 105645f950eda5e84a0f48979f50e60bb85e70a6..0780f7b59fd19dfb0e875975995d664d0ee67d3b 100644 (file)
@@ -127,6 +127,7 @@ std::string AST::type2str(AstNodeType type)
        X(AST_ASSIGN)
        X(AST_CELL)
        X(AST_PRIMITIVE)
+       X(AST_CELLARRAY)
        X(AST_ALWAYS)
        X(AST_INITIAL)
        X(AST_BLOCK)
index 3e69e3bc06401826fa83a6ecd4ea0b0d430b6cc5..802bf98ffe720bace810af11effbdfdbc62d6ad8 100644 (file)
@@ -107,6 +107,7 @@ namespace AST
                AST_ASSIGN,
                AST_CELL,
                AST_PRIMITIVE,
+               AST_CELLARRAY,
                AST_ALWAYS,
                AST_INITIAL,
                AST_BLOCK,
index e5e8980a2da4111b2c53959fae79369352f65183..fc040baac0bf4682c0f8a09055e370460ac01c99 100644 (file)
@@ -878,6 +878,31 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage,
                did_something = true;
        }
 
+       // unroll cell arrays
+       if (type == AST_CELLARRAY)
+       {
+               if (!children.at(0)->range_valid)
+                       log_error("Non-constant array range on cell array at %s:%d.\n", filename.c_str(), linenum);
+
+               newNode = new AstNode(AST_GENBLOCK);
+               int num = std::max(children.at(0)->range_left, children.at(0)->range_right) - std::min(children.at(0)->range_left, children.at(0)->range_right) + 1;
+
+               for (int i = 0; i < num; i++) {
+                       int idx = children.at(0)->range_left > children.at(0)->range_right ? children.at(0)->range_right + i : children.at(0)->range_right - i;
+                       AstNode *new_cell = children.at(1)->clone();
+                       newNode->children.push_back(new_cell);
+                       new_cell->str += stringf("[%d]", idx);
+                       if (new_cell->type == AST_PRIMITIVE) {
+                               log_error("Cell arrays of primitives are currently not supported at %s:%d.\n", filename.c_str(), linenum);
+                       } else {
+                               log_assert(new_cell->children.at(0)->type == AST_CELLTYPE);
+                               new_cell->children.at(0)->str = stringf("$array:%d:%d:%s", i, num, new_cell->children.at(0)->str.c_str());
+                       }
+               }
+
+               goto apply_newNode;
+       }
+
        // replace primitives with assignmens
        if (type == AST_PRIMITIVE)
        {
index 42a8f91c58cd9fb3ae9dabdee7243f6e16499017..f422258c7712dd6a3e6f62feb745ae350ce7e4a5 100644 (file)
@@ -634,6 +634,13 @@ single_cell:
                        astbuf2->str = *$1;
                delete $1;
                ast_stack.back()->children.push_back(astbuf2);
+       } '(' cell_port_list ')' |
+       TOK_ID non_opt_range {
+               astbuf2 = astbuf1->clone();
+               if (astbuf2->type != AST_PRIMITIVE)
+                       astbuf2->str = *$1;
+               delete $1;
+               ast_stack.back()->children.push_back(new AstNode(AST_CELLARRAY, $2, astbuf2));
        } '(' cell_port_list ')';
 
 prim_list:
index 1168102a3d88f91aebb1054b0bba682238bdf23a..028cd6d8126f55b8a6b0ba87b3bcf0aed9f70b2a 100644 (file)
@@ -740,7 +740,8 @@ void RTLIL::Module::check()
                for (auto &it2 : it.second->parameters) {
                        assert(it2.first.size() > 0 && (it2.first[0] == '\\' || it2.first[0] == '$'));
                }
-               if (it.second->type[0] == '$' && it.second->type.substr(0, 3) != "$__" && it.second->type.substr(0, 8) != "$paramod" && it.second->type.substr(0, 9) != "$verific$") {
+               if (it.second->type[0] == '$' && it.second->type.substr(0, 3) != "$__" && it.second->type.substr(0, 8) != "$paramod" &&
+                               it.second->type.substr(0, 9) != "$verific$" && it.second->type.substr(0, 7) != "$array:") {
                        InternalCellChecker checker(this, it.second);
                        checker.check();
                }
index 526d17294c9e6685d678c7d2f7087e2a9dfeddcf..6890cb9eae5c058526d5afeb0a3d2d7e1e6bfe32 100644 (file)
@@ -137,12 +137,23 @@ static void generate(RTLIL::Design *design, const std::vector<std::string> &cell
 static bool expand_module(RTLIL::Design *design, RTLIL::Module *module, bool flag_check, std::vector<std::string> &libdirs)
 {
        bool did_something = false;
+       std::map<RTLIL::Cell*, std::pair<int, int>> array_cells;
        std::string filename;
 
        for (auto &cell_it : module->cells)
        {
                RTLIL::Cell *cell = cell_it.second;
 
+               if (cell->type.substr(0, 7) == "$array:") {
+                       int pos_idx = cell->type.find_first_of(':');
+                       int pos_num = cell->type.find_first_of(':', pos_idx + 1);
+                       int pos_type = cell->type.find_first_of(':', pos_num + 1);
+                       int idx = atoi(cell->type.substr(pos_idx + 1, pos_num).c_str());
+                       int num = atoi(cell->type.substr(pos_num + 1, pos_type).c_str());
+                       array_cells[cell] = std::pair<int, int>(idx, num);
+                       cell->type = cell->type.substr(pos_type + 1);
+               }
+
                if (design->modules.count(cell->type) == 0)
                {
                        if (design->modules.count("$abstract" + cell->type))
@@ -198,6 +209,29 @@ static bool expand_module(RTLIL::Design *design, RTLIL::Module *module, bool fla
                did_something = true;
        }
 
+       for (auto &it : array_cells)
+       {
+               RTLIL::Cell *cell = it.first;
+               int idx = it.second.first, num = it.second.second;
+
+               if (design->modules.count(cell->type) == 0)
+                       log_error("Array cell `%s.%s' of unkown type `%s'.\n", RTLIL::id2cstr(module->name), RTLIL::id2cstr(cell->name), RTLIL::id2cstr(cell->type));
+
+               RTLIL::Module *mod = design->modules[cell->type];
+
+               for (auto &conn : cell->connections) {
+                       int conn_size = conn.second.width;
+                       if (mod->wires.count(conn.first) == 0)
+                               log_error("Array cell `%s.%s' connects to unkown port `%s'.\n", RTLIL::id2cstr(module->name), RTLIL::id2cstr(cell->name), RTLIL::id2cstr(conn.first));
+                       int port_size = mod->wires.at(conn.first)->width;
+                       if (conn_size == port_size)
+                               continue;
+                       if (conn_size != port_size*num)
+                               log_error("Array cell `%s.%s' has invalid port vs. signal size for port `%s'.\n", RTLIL::id2cstr(module->name), RTLIL::id2cstr(cell->name), RTLIL::id2cstr(conn.first));
+                       conn.second = conn.second.extract(port_size*idx, port_size);
+               }
+       }
+
        return did_something;
 }