Added WORDS parameter to $meminit
authorClifford Wolf <clifford@clifford.at>
Fri, 31 Jul 2015 08:40:09 +0000 (10:40 +0200)
committerClifford Wolf <clifford@clifford.at>
Fri, 31 Jul 2015 08:40:09 +0000 (10:40 +0200)
frontends/ast/ast.h
frontends/ast/genrtlil.cc
frontends/ast/simplify.cc
kernel/rtlil.cc
passes/memory/memory_unpack.cc
techlibs/common/simlib.v

index 28959d5d9ba57a41346b110a179e85fd15578ed7..44315d493b67e8e77a0c3b468fe736659f8f1df0 100644 (file)
@@ -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<std::string, std::string> &name_map);
                void replace_ids(const std::string &prefix, const std::map<std::string, std::string> &rules);
                void mem2reg_as_needed_pass1(dict<AstNode*, pool<std::string>> &mem2reg_places,
index ae538c54165fe63767729707dd129c44b2b6255d..4ed0e2bae9c43dc87cc1baad866e25b333475fe5 100644 (file)
@@ -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);
index efa65f30fc4d8ec1f746ad1b70793d7da238fe1e..29935652880f1474f6c893c633ab8708005fe81a 100644 (file)
@@ -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<State> 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;
 }
 
index c497ee102fa526ea1ad575ad21bb94bea26f201a..abdd1ff8a046a2d6350633affb37e136b8ca8309 100644 (file)
@@ -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;
                        }
index c07c4b60c011b42bc81e2522924a5be5165af95e..07ec4564c590ee18d44d28517a224f496aa2ddb8 100644 (file)
@@ -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);
 }
 
index ddc7fe3be5f8d3ed5d1a11390a9c9dc821131c23..9de71e6f9f527e32306affaba145d69d7152d255 100644 (file)
@@ -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