From e275e8eef9ae47670075bd73a671f3acd3c0ca52 Mon Sep 17 00:00:00 2001 From: Clifford Wolf Date: Sat, 7 Jun 2014 11:48:50 +0200 Subject: [PATCH] Add support for cell arrays --- frontends/ast/ast.cc | 1 + frontends/ast/ast.h | 1 + frontends/ast/simplify.cc | 25 +++++++++++++++++++++++++ frontends/verilog/parser.y | 7 +++++++ kernel/rtlil.cc | 3 ++- passes/hierarchy/hierarchy.cc | 34 ++++++++++++++++++++++++++++++++++ 6 files changed, 70 insertions(+), 1 deletion(-) diff --git a/frontends/ast/ast.cc b/frontends/ast/ast.cc index 105645f95..0780f7b59 100644 --- a/frontends/ast/ast.cc +++ b/frontends/ast/ast.cc @@ -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) diff --git a/frontends/ast/ast.h b/frontends/ast/ast.h index 3e69e3bc0..802bf98ff 100644 --- a/frontends/ast/ast.h +++ b/frontends/ast/ast.h @@ -107,6 +107,7 @@ namespace AST AST_ASSIGN, AST_CELL, AST_PRIMITIVE, + AST_CELLARRAY, AST_ALWAYS, AST_INITIAL, AST_BLOCK, diff --git a/frontends/ast/simplify.cc b/frontends/ast/simplify.cc index e5e8980a2..fc040baac 100644 --- a/frontends/ast/simplify.cc +++ b/frontends/ast/simplify.cc @@ -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) { diff --git a/frontends/verilog/parser.y b/frontends/verilog/parser.y index 42a8f91c5..f422258c7 100644 --- a/frontends/verilog/parser.y +++ b/frontends/verilog/parser.y @@ -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: diff --git a/kernel/rtlil.cc b/kernel/rtlil.cc index 1168102a3..028cd6d81 100644 --- a/kernel/rtlil.cc +++ b/kernel/rtlil.cc @@ -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(); } diff --git a/passes/hierarchy/hierarchy.cc b/passes/hierarchy/hierarchy.cc index 526d17294..6890cb9ea 100644 --- a/passes/hierarchy/hierarchy.cc +++ b/passes/hierarchy/hierarchy.cc @@ -137,12 +137,23 @@ static void generate(RTLIL::Design *design, const std::vector &cell static bool expand_module(RTLIL::Design *design, RTLIL::Module *module, bool flag_check, std::vector &libdirs) { bool did_something = false; + std::map> 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(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; } -- 2.30.2