kernel/mem: Add model for wide ports.

Such ports cannot actually be created or used yet, this just adds the
necessary plumbing in the helper.  Subsequent commits will gradually
add wide port support to various yosys passes.
This commit is contained in:
Marcelina Kościelnicka 2021-05-22 16:48:46 +02:00
parent 95a39d3425
commit ff9713dd86
2 changed files with 28 additions and 6 deletions

View File

@ -121,6 +121,8 @@ void Mem::emit() {
abits = std::max(abits, GetSize(port.addr)); abits = std::max(abits, GetSize(port.addr));
cell->parameters[ID::ABITS] = Const(abits); cell->parameters[ID::ABITS] = Const(abits);
for (auto &port : rd_ports) { for (auto &port : rd_ports) {
// TODO: remove
log_assert(port.wide_log2 == 0);
if (port.cell) { if (port.cell) {
module->remove(port.cell); module->remove(port.cell);
port.cell = nullptr; port.cell = nullptr;
@ -152,6 +154,8 @@ void Mem::emit() {
cell->setPort(ID::RD_ADDR, rd_addr); cell->setPort(ID::RD_ADDR, rd_addr);
cell->setPort(ID::RD_DATA, rd_data); cell->setPort(ID::RD_DATA, rd_data);
for (auto &port : wr_ports) { for (auto &port : wr_ports) {
// TODO: remove
log_assert(port.wide_log2 == 0);
if (port.cell) { if (port.cell) {
module->remove(port.cell); module->remove(port.cell);
port.cell = nullptr; port.cell = nullptr;
@ -206,7 +210,7 @@ void Mem::emit() {
port.cell = module->addCell(NEW_ID, ID($memrd)); port.cell = module->addCell(NEW_ID, ID($memrd));
port.cell->parameters[ID::MEMID] = memid.str(); port.cell->parameters[ID::MEMID] = memid.str();
port.cell->parameters[ID::ABITS] = GetSize(port.addr); port.cell->parameters[ID::ABITS] = GetSize(port.addr);
port.cell->parameters[ID::WIDTH] = width; port.cell->parameters[ID::WIDTH] = width << port.wide_log2;
port.cell->parameters[ID::CLK_ENABLE] = port.clk_enable; port.cell->parameters[ID::CLK_ENABLE] = port.clk_enable;
port.cell->parameters[ID::CLK_POLARITY] = port.clk_polarity; port.cell->parameters[ID::CLK_POLARITY] = port.clk_polarity;
port.cell->parameters[ID::TRANSPARENT] = port.transparent; port.cell->parameters[ID::TRANSPARENT] = port.transparent;
@ -221,7 +225,7 @@ void Mem::emit() {
port.cell = module->addCell(NEW_ID, ID($memwr)); port.cell = module->addCell(NEW_ID, ID($memwr));
port.cell->parameters[ID::MEMID] = memid.str(); port.cell->parameters[ID::MEMID] = memid.str();
port.cell->parameters[ID::ABITS] = GetSize(port.addr); port.cell->parameters[ID::ABITS] = GetSize(port.addr);
port.cell->parameters[ID::WIDTH] = width; port.cell->parameters[ID::WIDTH] = width << port.wide_log2;
port.cell->parameters[ID::CLK_ENABLE] = port.clk_enable; port.cell->parameters[ID::CLK_ENABLE] = port.clk_enable;
port.cell->parameters[ID::CLK_POLARITY] = port.clk_polarity; port.cell->parameters[ID::CLK_POLARITY] = port.clk_polarity;
port.cell->parameters[ID::PRIORITY] = idx++; port.cell->parameters[ID::PRIORITY] = idx++;
@ -264,23 +268,32 @@ Const Mem::get_init_data() const {
} }
void Mem::check() { void Mem::check() {
int max_wide_log2 = 0;
for (auto &port : rd_ports) { for (auto &port : rd_ports) {
if (port.removed) if (port.removed)
continue; continue;
log_assert(GetSize(port.clk) == 1); log_assert(GetSize(port.clk) == 1);
log_assert(GetSize(port.en) == 1); log_assert(GetSize(port.en) == 1);
log_assert(GetSize(port.data) == width); log_assert(GetSize(port.data) == (width << port.wide_log2));
if (!port.clk_enable) { if (!port.clk_enable) {
log_assert(!port.transparent); log_assert(!port.transparent);
} }
for (int j = 0; j < port.wide_log2; j++) {
log_assert(port.addr[j] == State::S0);
}
max_wide_log2 = std::max(max_wide_log2, port.wide_log2);
} }
for (int i = 0; i < GetSize(wr_ports); i++) { for (int i = 0; i < GetSize(wr_ports); i++) {
auto &port = wr_ports[i]; auto &port = wr_ports[i];
if (port.removed) if (port.removed)
continue; continue;
log_assert(GetSize(port.clk) == 1); log_assert(GetSize(port.clk) == 1);
log_assert(GetSize(port.en) == width); log_assert(GetSize(port.en) == (width << port.wide_log2));
log_assert(GetSize(port.data) == width); log_assert(GetSize(port.data) == (width << port.wide_log2));
for (int j = 0; j < port.wide_log2; j++) {
log_assert(port.addr[j] == State::S0);
}
max_wide_log2 = std::max(max_wide_log2, port.wide_log2);
log_assert(GetSize(port.priority_mask) == GetSize(wr_ports)); log_assert(GetSize(port.priority_mask) == GetSize(wr_ports));
for (int j = 0; j < GetSize(wr_ports); j++) { for (int j = 0; j < GetSize(wr_ports); j++) {
auto &wport = wr_ports[j]; auto &wport = wr_ports[j];
@ -294,6 +307,9 @@ void Mem::check() {
} }
} }
} }
int mask = (1 << max_wide_log2) - 1;
log_assert(!(start_offset & mask));
log_assert(!(size & mask));
} }
namespace { namespace {
@ -331,6 +347,7 @@ namespace {
mrd.en = cell->getPort(ID::EN); mrd.en = cell->getPort(ID::EN);
mrd.addr = cell->getPort(ID::ADDR); mrd.addr = cell->getPort(ID::ADDR);
mrd.data = cell->getPort(ID::DATA); mrd.data = cell->getPort(ID::DATA);
mrd.wide_log2 = ceil_log2(GetSize(mrd.data) / mem->width);
res.rd_ports.push_back(mrd); res.rd_ports.push_back(mrd);
} }
} }
@ -346,6 +363,7 @@ namespace {
mwr.en = cell->getPort(ID::EN); mwr.en = cell->getPort(ID::EN);
mwr.addr = cell->getPort(ID::ADDR); mwr.addr = cell->getPort(ID::ADDR);
mwr.data = cell->getPort(ID::DATA); mwr.data = cell->getPort(ID::DATA);
mwr.wide_log2 = ceil_log2(GetSize(mwr.data) / mem->width);
ports.push_back(std::make_pair(cell->parameters.at(ID::PRIORITY).as_int(), mwr)); ports.push_back(std::make_pair(cell->parameters.at(ID::PRIORITY).as_int(), mwr));
} }
std::sort(ports.begin(), ports.end(), [](const std::pair<int, MemWr> &a, const std::pair<int, MemWr> &b) { return a.first < b.first; }); std::sort(ports.begin(), ports.end(), [](const std::pair<int, MemWr> &a, const std::pair<int, MemWr> &b) { return a.first < b.first; });
@ -424,6 +442,7 @@ namespace {
} }
for (int i = 0; i < cell->parameters.at(ID::RD_PORTS).as_int(); i++) { for (int i = 0; i < cell->parameters.at(ID::RD_PORTS).as_int(); i++) {
MemRd mrd; MemRd mrd;
mrd.wide_log2 = 0;
mrd.clk_enable = cell->parameters.at(ID::RD_CLK_ENABLE).extract(i, 1).as_bool(); mrd.clk_enable = cell->parameters.at(ID::RD_CLK_ENABLE).extract(i, 1).as_bool();
mrd.clk_polarity = cell->parameters.at(ID::RD_CLK_POLARITY).extract(i, 1).as_bool(); mrd.clk_polarity = cell->parameters.at(ID::RD_CLK_POLARITY).extract(i, 1).as_bool();
mrd.transparent = cell->parameters.at(ID::RD_TRANSPARENT).extract(i, 1).as_bool(); mrd.transparent = cell->parameters.at(ID::RD_TRANSPARENT).extract(i, 1).as_bool();
@ -435,6 +454,7 @@ namespace {
} }
for (int i = 0; i < cell->parameters.at(ID::WR_PORTS).as_int(); i++) { for (int i = 0; i < cell->parameters.at(ID::WR_PORTS).as_int(); i++) {
MemWr mwr; MemWr mwr;
mwr.wide_log2 = 0;
mwr.clk_enable = cell->parameters.at(ID::WR_CLK_ENABLE).extract(i, 1).as_bool(); mwr.clk_enable = cell->parameters.at(ID::WR_CLK_ENABLE).extract(i, 1).as_bool();
mwr.clk_polarity = cell->parameters.at(ID::WR_CLK_POLARITY).extract(i, 1).as_bool(); mwr.clk_polarity = cell->parameters.at(ID::WR_CLK_POLARITY).extract(i, 1).as_bool();
mwr.clk = cell->getPort(ID::WR_CLK).extract(i, 1); mwr.clk = cell->getPort(ID::WR_CLK).extract(i, 1);
@ -507,7 +527,7 @@ Cell *Mem::extract_rdff(int idx, FfInitVals *initvals) {
} }
else else
{ {
SigSpec sig_d = module->addWire(stringf("%s$rdreg[%d]$d", memid.c_str(), idx), width); SigSpec sig_d = module->addWire(stringf("%s$rdreg[%d]$d", memid.c_str(), idx), GetSize(port.data));
SigSpec sig_q = port.data; SigSpec sig_q = port.data;
port.data = sig_d; port.data = sig_d;
c = module->addDffe(stringf("%s$rdreg[%d]", memid.c_str(), idx), port.clk, port.en, sig_d, sig_q, port.clk_polarity, true); c = module->addDffe(stringf("%s$rdreg[%d]", memid.c_str(), idx), port.clk, port.en, sig_d, sig_q, port.clk_polarity, true);

View File

@ -29,6 +29,7 @@ struct MemRd {
bool removed; bool removed;
dict<IdString, Const> attributes; dict<IdString, Const> attributes;
Cell *cell; Cell *cell;
int wide_log2;
bool clk_enable, clk_polarity; bool clk_enable, clk_polarity;
bool transparent; bool transparent;
SigSpec clk, en, addr, data; SigSpec clk, en, addr, data;
@ -39,6 +40,7 @@ struct MemWr {
bool removed; bool removed;
dict<IdString, Const> attributes; dict<IdString, Const> attributes;
Cell *cell; Cell *cell;
int wide_log2;
bool clk_enable, clk_polarity; bool clk_enable, clk_polarity;
std::vector<bool> priority_mask; std::vector<bool> priority_mask;
SigSpec clk, en, addr, data; SigSpec clk, en, addr, data;