diff options
Diffstat (limited to 'kernel')
-rw-r--r-- | kernel/celltypes.h | 1 | ||||
-rw-r--r-- | kernel/mem.cc | 41 | ||||
-rw-r--r-- | kernel/mem.h | 4 | ||||
-rw-r--r-- | kernel/rtlil.cc | 12 |
4 files changed, 52 insertions, 6 deletions
diff --git a/kernel/celltypes.h b/kernel/celltypes.h index 2918b9039..2ce7978a4 100644 --- a/kernel/celltypes.h +++ b/kernel/celltypes.h @@ -157,6 +157,7 @@ struct CellTypes setup_type(ID($memrd), {ID::CLK, ID::EN, ID::ADDR}, {ID::DATA}); setup_type(ID($memwr), {ID::CLK, ID::EN, ID::ADDR, ID::DATA}, pool<RTLIL::IdString>()); setup_type(ID($meminit), {ID::ADDR, ID::DATA}, pool<RTLIL::IdString>()); + setup_type(ID($meminit_v2), {ID::ADDR, ID::DATA, ID::EN}, pool<RTLIL::IdString>()); setup_type(ID($mem), {ID::RD_CLK, ID::RD_EN, ID::RD_ADDR, ID::WR_CLK, ID::WR_EN, ID::WR_ADDR, ID::WR_DATA}, {ID::RD_DATA}); setup_type(ID($fsm), {ID::CLK, ID::ARST, ID::CTRL_IN}, {ID::CTRL_OUT}); diff --git a/kernel/mem.cc b/kernel/mem.cc index e95118d4c..a3b244eab 100644 --- a/kernel/mem.cc +++ b/kernel/mem.cc @@ -263,8 +263,11 @@ void Mem::emit() { } idx = 0; for (auto &init : inits) { + bool v2 = !init.en.is_fully_ones(); if (!init.cell) - init.cell = module->addCell(NEW_ID, ID($meminit)); + init.cell = module->addCell(NEW_ID, v2 ? ID($meminit_v2) : ID($meminit)); + else + init.cell->type = v2 ? ID($meminit_v2) : ID($meminit); init.cell->attributes = init.attributes; init.cell->parameters[ID::MEMID] = memid.str(); init.cell->parameters[ID::ABITS] = GetSize(init.addr); @@ -273,6 +276,10 @@ void Mem::emit() { init.cell->parameters[ID::PRIORITY] = idx++; init.cell->setPort(ID::ADDR, init.addr); init.cell->setPort(ID::DATA, init.data); + if (v2) + init.cell->setPort(ID::EN, init.en); + else + init.cell->unsetPort(ID::EN); } } } @@ -289,6 +296,14 @@ void Mem::coalesce_inits() { for (auto &init : inits) { if (init.removed) continue; + bool valid = false; + for (auto bit : init.en) + if (bit == State::S1) + valid = true; + if (!valid) { + init.removed = true; + continue; + } int addr = init.addr.as_int(); int addr_e = addr + GetSize(init.data) / width; auto it_e = chunks.upper_bound(addr_e); @@ -335,6 +350,13 @@ void Mem::coalesce_inits() { int caddr_e = chunks[caddr]; auto &chunk_inits = it.second; if (GetSize(chunk_inits) == 1) { + auto &init = inits[chunk_inits[0]]; + if (!init.en.is_fully_ones()) { + for (int i = 0; i < GetSize(init.data); i++) + if (init.en[i % width] != State::S1) + init.data[i] = State::Sx; + init.en = Const(State::S1, width); + } continue; } Const cdata(State::Sx, (caddr_e - caddr) * width); @@ -344,12 +366,14 @@ void Mem::coalesce_inits() { log_assert(offset >= 0); log_assert(offset + GetSize(init.data) <= GetSize(cdata)); for (int i = 0; i < GetSize(init.data); i++) - cdata.bits[i+offset] = init.data.bits[i]; + if (init.en[i % width] == State::S1) + cdata.bits[i+offset] = init.data.bits[i]; init.removed = true; } MemInit new_init; new_init.addr = caddr; new_init.data = cdata; + new_init.en = Const(State::S1, width); inits.push_back(new_init); } } @@ -361,7 +385,7 @@ Const Mem::get_init_data() const { continue; int offset = (init.addr.as_int() - start_offset) * width; for (int i = 0; i < GetSize(init.data); i++) - if (0 <= i+offset && i+offset < GetSize(init_data)) + if (0 <= i+offset && i+offset < GetSize(init_data) && init.en[i % width] == State::S1) init_data.bits[i+offset] = init.data.bits[i]; } return init_data; @@ -432,7 +456,7 @@ namespace { wr_ports[cell->parameters.at(ID::MEMID).decode_string()].insert(cell); else if (cell->type == ID($memrd)) rd_ports[cell->parameters.at(ID::MEMID).decode_string()].insert(cell); - else if (cell->type == ID($meminit)) + else if (cell->type.in(ID($meminit), ID($meminit_v2))) inits[cell->parameters.at(ID::MEMID).decode_string()].insert(cell); } } @@ -507,6 +531,14 @@ namespace { log_error("Non-constant data %s in memory initialization %s.\n", log_signal(data), log_id(cell)); init.addr = addr.as_const(); init.data = data.as_const(); + if (cell->type == ID($meminit_v2)) { + auto en = cell->getPort(ID::EN); + if (!en.is_fully_const()) + log_error("Non-constant enable %s in memory initialization %s.\n", log_signal(en), log_id(cell)); + init.en = en.as_const(); + } else { + init.en = RTLIL::Const(State::S1, mem->width); + } inits.push_back(std::make_pair(cell->parameters.at(ID::PRIORITY).as_int(), init)); } std::sort(inits.begin(), inits.end(), [](const std::pair<int, MemInit> &a, const std::pair<int, MemInit> &b) { return a.first < b.first; }); @@ -558,6 +590,7 @@ namespace { MemInit minit; minit.addr = res.start_offset + pos; minit.data = init.extract(pos * res.width, (epos - pos) * res.width, State::Sx); + minit.en = RTLIL::Const(State::S1, res.width); res.inits.push_back(minit); pos = epos; } diff --git a/kernel/mem.h b/kernel/mem.h index 62403e00c..24c2d64c8 100644 --- a/kernel/mem.h +++ b/kernel/mem.h @@ -69,6 +69,7 @@ struct MemInit : RTLIL::AttrObject { Cell *cell; Const addr; Const data; + Const en; MemInit() : removed(false), cell(nullptr) {} }; @@ -101,7 +102,8 @@ struct Mem : RTLIL::AttrObject { // address ranges, they are combined into one, with the higher-priority // one's data overwriting the other. Running this results in // an inits list equivalent to the original, in which all entries - // cover disjoint (and non-touching) address ranges. + // cover disjoint (and non-touching) address ranges, and all enable + // masks are all-1. void coalesce_inits(); // Checks consistency of this memory and all its ports/inits, using diff --git a/kernel/rtlil.cc b/kernel/rtlil.cc index 21ee15ac5..bd6b3ad05 100644 --- a/kernel/rtlil.cc +++ b/kernel/rtlil.cc @@ -1414,6 +1414,16 @@ namespace { return; } + if (cell->type == ID($meminit_v2)) { + param(ID::MEMID); + param(ID::PRIORITY); + port(ID::ADDR, param(ID::ABITS)); + port(ID::DATA, param(ID::WIDTH) * param(ID::WORDS)); + port(ID::EN, param(ID::WIDTH)); + check_expected(); + return; + } + if (cell->type == ID($mem)) { param(ID::MEMID); param(ID::SIZE); @@ -3177,7 +3187,7 @@ void RTLIL::Cell::fixup_parameters(bool set_a_signed, bool set_b_signed) bool RTLIL::Cell::has_memid() const { - return type.in(ID($memwr), ID($memrd), ID($meminit)); + return type.in(ID($memwr), ID($memrd), ID($meminit), ID($meminit_v2)); } bool RTLIL::Cell::is_mem_cell() const |