From 8d6d5c30d9f39ce5b15d1bd3f3a528b38f2f9f9c Mon Sep 17 00:00:00 2001 From: Clifford Wolf Date: Fri, 31 Jul 2015 10:40:09 +0200 Subject: [PATCH] Added WORDS parameter to $meminit --- frontends/ast/ast.h | 2 +- frontends/ast/genrtlil.cc | 10 +++++- frontends/ast/simplify.cc | 62 +++++++++++++++++++++++++++++++--- kernel/rtlil.cc | 2 +- passes/memory/memory_unpack.cc | 32 ++++++++++++++---- techlibs/common/simlib.v | 3 +- 6 files changed, 95 insertions(+), 16 deletions(-) diff --git a/frontends/ast/ast.h b/frontends/ast/ast.h index 28959d5d9..44315d493 100644 --- a/frontends/ast/ast.h +++ b/frontends/ast/ast.h @@ -210,7 +210,7 @@ namespace AST // simplify() creates a simpler AST by unrolling for-loops, expanding generate blocks, etc. // it also sets the id2ast pointers so that identifier lookups are fast in genRTLIL() bool simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage, int width_hint, bool sign_hint, bool in_param); - AstNode *readmem(bool is_readmemh, std::string mem_filename, AstNode *memory, int start_addr, int finish_addr); + AstNode *readmem(bool is_readmemh, std::string mem_filename, AstNode *memory, int start_addr, int finish_addr, bool unconditional_init); void expand_genblock(std::string index_var, std::string prefix, std::map &name_map); void replace_ids(const std::string &prefix, const std::map &rules); void mem2reg_as_needed_pass1(dict> &mem2reg_places, diff --git a/frontends/ast/genrtlil.cc b/frontends/ast/genrtlil.cc index ae538c541..4ed0e2bae 100644 --- a/frontends/ast/genrtlil.cc +++ b/frontends/ast/genrtlil.cc @@ -1247,8 +1247,16 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint) int mem_width, mem_size, addr_bits; id2ast->meminfo(mem_width, mem_size, addr_bits); + int num_words = 1; + if (type == AST_MEMINIT) { + if (children[2]->type != AST_CONSTANT) + log_error("Memory init with non-constant word count at %s:%d!\n", filename.c_str(), linenum); + num_words = children[2]->asInt(false); + cell->parameters["\\WORDS"] = RTLIL::Const(num_words); + } + cell->setPort("\\ADDR", children[0]->genWidthRTLIL(addr_bits)); - cell->setPort("\\DATA", children[1]->genWidthRTLIL(current_module->memories[str]->width)); + cell->setPort("\\DATA", children[1]->genWidthRTLIL(current_module->memories[str]->width * num_words)); cell->parameters["\\MEMID"] = RTLIL::Const(str); cell->parameters["\\ABITS"] = RTLIL::Const(addr_bits); diff --git a/frontends/ast/simplify.cc b/frontends/ast/simplify.cc index efa65f30f..299356528 100644 --- a/frontends/ast/simplify.cc +++ b/frontends/ast/simplify.cc @@ -1425,6 +1425,8 @@ skip_dynamic_range_lvalue_expansion:; wrnode->children.push_back(new AstNode(AST_IDENTIFIER)); if (current_always->type != AST_INITIAL) wrnode->children.push_back(new AstNode(AST_IDENTIFIER)); + else + wrnode->children.push_back(AstNode::mkconst_int(1, false)); wrnode->str = children[0]->str; wrnode->id2ast = children[0]->id2ast; wrnode->children[0]->str = id_addr; @@ -1602,7 +1604,17 @@ skip_dynamic_range_lvalue_expansion:; finish_addr = node_addr->asInt(false); } - newNode = readmem(str == "\\$readmemh", node_filename->bitsAsConst().decode_string(), node_memory->id2ast, start_addr, finish_addr); + bool unconditional_init = false; + if (current_always->type == AST_INITIAL) { + log_assert(current_always->children[0]->type == AST_BLOCK); + for (auto n : current_always->children[0]->children) + if (n == this) { + unconditional_init = true; + break; + } + } + + newNode = readmem(str == "\\$readmemh", node_filename->bitsAsConst().decode_string(), node_memory->id2ast, start_addr, finish_addr, unconditional_init); goto apply_newNode; } @@ -2085,10 +2097,15 @@ static void replace_result_wire_name_in_function(AstNode *node, std::string &fro } // replace a readmem[bh] TCALL ast node with a block of memory assignments -AstNode *AstNode::readmem(bool is_readmemh, std::string mem_filename, AstNode *memory, int start_addr, int finish_addr) +AstNode *AstNode::readmem(bool is_readmemh, std::string mem_filename, AstNode *memory, int start_addr, int finish_addr, bool unconditional_init) { AstNode *block = new AstNode(AST_BLOCK); + AstNode *meminit = nullptr; + int next_meminit_cursor; + vector meminit_bits; + int meminit_size; + std::ifstream f; f.open(mem_filename.c_str()); @@ -2145,9 +2162,39 @@ AstNode *AstNode::readmem(bool is_readmemh, std::string mem_filename, AstNode *m AstNode *value = VERILOG_FRONTEND::const2ast((is_readmemh ? "'h" : "'b") + token); - block->children.push_back(new AstNode(AST_ASSIGN_EQ, new AstNode(AST_IDENTIFIER, new AstNode(AST_RANGE, AstNode::mkconst_int(cursor, false))), value)); - block->children.back()->children[0]->str = memory->str; - block->children.back()->children[0]->id2ast = memory; + if (unconditional_init) + { + if (meminit == nullptr || cursor != next_meminit_cursor) + { + if (meminit != nullptr) { + meminit->children[1] = AstNode::mkconst_bits(meminit_bits, false); + meminit->children[2] = AstNode::mkconst_int(meminit_size, false); + } + + meminit = new AstNode(AST_MEMINIT); + meminit->children.push_back(AstNode::mkconst_int(cursor, false)); + meminit->children.push_back(nullptr); + meminit->children.push_back(nullptr); + meminit->str = memory->str; + meminit->id2ast = memory; + meminit_bits.clear(); + meminit_size = 0; + + current_ast_mod->children.push_back(meminit); + next_meminit_cursor = cursor; + } + + meminit_size++; + next_meminit_cursor++; + meminit_bits.insert(meminit_bits.end(), value->bits.begin(), value->bits.end()); + delete value; + } + else + { + block->children.push_back(new AstNode(AST_ASSIGN_EQ, new AstNode(AST_IDENTIFIER, new AstNode(AST_RANGE, AstNode::mkconst_int(cursor, false))), value)); + block->children.back()->children[0]->str = memory->str; + block->children.back()->children[0]->id2ast = memory; + } if ((cursor == finish_addr) || (increment > 0 && cursor >= range_max) || (increment < 0 && cursor <= range_min)) break; @@ -2158,6 +2205,11 @@ AstNode *AstNode::readmem(bool is_readmemh, std::string mem_filename, AstNode *m break; } + if (meminit != nullptr) { + meminit->children[1] = AstNode::mkconst_bits(meminit_bits, false); + meminit->children[2] = AstNode::mkconst_int(meminit_size, false); + } + return block; } diff --git a/kernel/rtlil.cc b/kernel/rtlil.cc index c497ee102..abdd1ff8a 100644 --- a/kernel/rtlil.cc +++ b/kernel/rtlil.cc @@ -970,7 +970,7 @@ namespace { param("\\MEMID"); param("\\PRIORITY"); port("\\ADDR", param("\\ABITS")); - port("\\DATA", param("\\WIDTH")); + port("\\DATA", param("\\WIDTH") * param("\\WORDS")); check_expected(); return; } diff --git a/passes/memory/memory_unpack.cc b/passes/memory/memory_unpack.cc index c07c4b60c..07ec4564c 100644 --- a/passes/memory/memory_unpack.cc +++ b/passes/memory/memory_unpack.cc @@ -77,6 +77,10 @@ void handle_memory(RTLIL::Module *module, RTLIL::Cell *memory) } Const initval = memory->parameters.at("\\INIT"); + RTLIL::Cell *last_init_cell = nullptr; + SigSpec last_init_data; + int last_init_addr; + for (int i = 0; i < GetSize(initval) && i/mem->width < (1 << abits); i += mem->width) { Const val = initval.extract(i, mem->width, State::Sx); for (auto bit : val.bits) @@ -84,15 +88,29 @@ void handle_memory(RTLIL::Module *module, RTLIL::Cell *memory) goto found_non_undef_initval; continue; found_non_undef_initval: - RTLIL::Cell *cell = module->addCell(NEW_ID, "$meminit"); - cell->parameters["\\MEMID"] = mem_name.str(); - cell->parameters["\\ABITS"] = memory->parameters.at("\\ABITS"); - cell->parameters["\\WIDTH"] = memory->parameters.at("\\WIDTH"); - cell->parameters["\\PRIORITY"] = i/mem->width; - cell->setPort("\\ADDR", SigSpec(i/mem->width, abits)); - cell->setPort("\\DATA", val); + if (last_init_cell && last_init_addr+1 == i/mem->width) { + last_init_cell->parameters["\\WORDS"] = last_init_cell->parameters["\\WORDS"].as_int() + 1; + last_init_data.append(val); + last_init_addr++; + } else { + if (last_init_cell) + last_init_cell->setPort("\\DATA", last_init_data); + RTLIL::Cell *cell = module->addCell(NEW_ID, "$meminit"); + cell->parameters["\\MEMID"] = mem_name.str(); + cell->parameters["\\ABITS"] = memory->parameters.at("\\ABITS"); + cell->parameters["\\WIDTH"] = memory->parameters.at("\\WIDTH"); + cell->parameters["\\WORDS"] = 1; + cell->parameters["\\PRIORITY"] = i/mem->width; + cell->setPort("\\ADDR", SigSpec(i/mem->width, abits)); + last_init_cell = cell; + last_init_addr = i/mem->width; + last_init_data = val; + } } + if (last_init_cell) + last_init_cell->setPort("\\DATA", last_init_data); + module->remove(memory); } diff --git a/techlibs/common/simlib.v b/techlibs/common/simlib.v index ddc7fe3be..9de71e6f9 100644 --- a/techlibs/common/simlib.v +++ b/techlibs/common/simlib.v @@ -1536,11 +1536,12 @@ module \$meminit (ADDR, DATA); parameter MEMID = ""; parameter ABITS = 8; parameter WIDTH = 8; +parameter WORDS = 1; parameter PRIORITY = 0; input [ABITS-1:0] ADDR; -input [WIDTH-1:0] DATA; +input [WORDS*WIDTH-1:0] DATA; initial begin if (MEMID != "") begin -- 2.30.2