Added WORDS parameter to $meminit

This commit is contained in:
Clifford Wolf 2015-07-31 10:40:09 +02:00
parent 3860c9a9f2
commit 8d6d5c30d9
6 changed files with 95 additions and 16 deletions

View File

@ -210,7 +210,7 @@ namespace AST
// simplify() creates a simpler AST by unrolling for-loops, expanding generate blocks, etc. // 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() // 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); 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 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 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, void mem2reg_as_needed_pass1(dict<AstNode*, pool<std::string>> &mem2reg_places,

View File

@ -1247,8 +1247,16 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint)
int mem_width, mem_size, addr_bits; int mem_width, mem_size, addr_bits;
id2ast->meminfo(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("\\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["\\MEMID"] = RTLIL::Const(str);
cell->parameters["\\ABITS"] = RTLIL::Const(addr_bits); cell->parameters["\\ABITS"] = RTLIL::Const(addr_bits);

View File

@ -1425,6 +1425,8 @@ skip_dynamic_range_lvalue_expansion:;
wrnode->children.push_back(new AstNode(AST_IDENTIFIER)); wrnode->children.push_back(new AstNode(AST_IDENTIFIER));
if (current_always->type != AST_INITIAL) if (current_always->type != AST_INITIAL)
wrnode->children.push_back(new AstNode(AST_IDENTIFIER)); wrnode->children.push_back(new AstNode(AST_IDENTIFIER));
else
wrnode->children.push_back(AstNode::mkconst_int(1, false));
wrnode->str = children[0]->str; wrnode->str = children[0]->str;
wrnode->id2ast = children[0]->id2ast; wrnode->id2ast = children[0]->id2ast;
wrnode->children[0]->str = id_addr; wrnode->children[0]->str = id_addr;
@ -1602,7 +1604,17 @@ skip_dynamic_range_lvalue_expansion:;
finish_addr = node_addr->asInt(false); 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; 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 // 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 *block = new AstNode(AST_BLOCK);
AstNode *meminit = nullptr;
int next_meminit_cursor;
vector<State> meminit_bits;
int meminit_size;
std::ifstream f; std::ifstream f;
f.open(mem_filename.c_str()); 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); 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)); if (unconditional_init)
block->children.back()->children[0]->str = memory->str; {
block->children.back()->children[0]->id2ast = memory; 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)) if ((cursor == finish_addr) || (increment > 0 && cursor >= range_max) || (increment < 0 && cursor <= range_min))
break; break;
@ -2158,6 +2205,11 @@ AstNode *AstNode::readmem(bool is_readmemh, std::string mem_filename, AstNode *m
break; break;
} }
if (meminit != nullptr) {
meminit->children[1] = AstNode::mkconst_bits(meminit_bits, false);
meminit->children[2] = AstNode::mkconst_int(meminit_size, false);
}
return block; return block;
} }

View File

@ -970,7 +970,7 @@ namespace {
param("\\MEMID"); param("\\MEMID");
param("\\PRIORITY"); param("\\PRIORITY");
port("\\ADDR", param("\\ABITS")); port("\\ADDR", param("\\ABITS"));
port("\\DATA", param("\\WIDTH")); port("\\DATA", param("\\WIDTH") * param("\\WORDS"));
check_expected(); check_expected();
return; return;
} }

View File

@ -77,6 +77,10 @@ void handle_memory(RTLIL::Module *module, RTLIL::Cell *memory)
} }
Const initval = memory->parameters.at("\\INIT"); 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) { for (int i = 0; i < GetSize(initval) && i/mem->width < (1 << abits); i += mem->width) {
Const val = initval.extract(i, mem->width, State::Sx); Const val = initval.extract(i, mem->width, State::Sx);
for (auto bit : val.bits) for (auto bit : val.bits)
@ -84,15 +88,29 @@ void handle_memory(RTLIL::Module *module, RTLIL::Cell *memory)
goto found_non_undef_initval; goto found_non_undef_initval;
continue; continue;
found_non_undef_initval: found_non_undef_initval:
RTLIL::Cell *cell = module->addCell(NEW_ID, "$meminit"); if (last_init_cell && last_init_addr+1 == i/mem->width) {
cell->parameters["\\MEMID"] = mem_name.str(); last_init_cell->parameters["\\WORDS"] = last_init_cell->parameters["\\WORDS"].as_int() + 1;
cell->parameters["\\ABITS"] = memory->parameters.at("\\ABITS"); last_init_data.append(val);
cell->parameters["\\WIDTH"] = memory->parameters.at("\\WIDTH"); last_init_addr++;
cell->parameters["\\PRIORITY"] = i/mem->width; } else {
cell->setPort("\\ADDR", SigSpec(i/mem->width, abits)); if (last_init_cell)
cell->setPort("\\DATA", val); 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); module->remove(memory);
} }

View File

@ -1536,11 +1536,12 @@ module \$meminit (ADDR, DATA);
parameter MEMID = ""; parameter MEMID = "";
parameter ABITS = 8; parameter ABITS = 8;
parameter WIDTH = 8; parameter WIDTH = 8;
parameter WORDS = 1;
parameter PRIORITY = 0; parameter PRIORITY = 0;
input [ABITS-1:0] ADDR; input [ABITS-1:0] ADDR;
input [WIDTH-1:0] DATA; input [WORDS*WIDTH-1:0] DATA;
initial begin initial begin
if (MEMID != "") begin if (MEMID != "") begin