kernel/mem: Add model for wide ports.
authorMarcelina Kościelnicka <mwk@0x04.net>
Sat, 22 May 2021 14:48:46 +0000 (16:48 +0200)
committerMarcelina Kościelnicka <mwk@0x04.net>
Tue, 25 May 2021 00:07:25 +0000 (02:07 +0200)
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.

kernel/mem.cc
kernel/mem.h

index 2a51ec5d9bab7ebc9e8c797b416a1bf84ee18c29..2285cf74d676fa5eaa88c3124cce214745a7a63b 100644 (file)
@@ -121,6 +121,8 @@ void Mem::emit() {
                        abits = std::max(abits, GetSize(port.addr));
                cell->parameters[ID::ABITS] = Const(abits);
                for (auto &port : rd_ports) {
+                       // TODO: remove
+                       log_assert(port.wide_log2 == 0);
                        if (port.cell) {
                                module->remove(port.cell);
                                port.cell = nullptr;
@@ -152,6 +154,8 @@ void Mem::emit() {
                cell->setPort(ID::RD_ADDR, rd_addr);
                cell->setPort(ID::RD_DATA, rd_data);
                for (auto &port : wr_ports) {
+                       // TODO: remove
+                       log_assert(port.wide_log2 == 0);
                        if (port.cell) {
                                module->remove(port.cell);
                                port.cell = nullptr;
@@ -206,7 +210,7 @@ void Mem::emit() {
                                port.cell = module->addCell(NEW_ID, ID($memrd));
                        port.cell->parameters[ID::MEMID] = memid.str();
                        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_POLARITY] = port.clk_polarity;
                        port.cell->parameters[ID::TRANSPARENT] = port.transparent;
@@ -221,7 +225,7 @@ void Mem::emit() {
                                port.cell = module->addCell(NEW_ID, ID($memwr));
                        port.cell->parameters[ID::MEMID] = memid.str();
                        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_POLARITY] = port.clk_polarity;
                        port.cell->parameters[ID::PRIORITY] = idx++;
@@ -264,23 +268,32 @@ Const Mem::get_init_data() const {
 }
 
 void Mem::check() {
+       int max_wide_log2 = 0;
        for (auto &port : rd_ports) {
                if (port.removed)
                        continue;
                log_assert(GetSize(port.clk) == 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) {
                        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++) {
                auto &port = wr_ports[i];
                if (port.removed)
                        continue;
                log_assert(GetSize(port.clk) == 1);
-               log_assert(GetSize(port.en) == width);
-               log_assert(GetSize(port.data) == width);
+               log_assert(GetSize(port.en) == (width << port.wide_log2));
+               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));
                for (int j = 0; j < GetSize(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 {
@@ -331,6 +347,7 @@ namespace {
                                mrd.en = cell->getPort(ID::EN);
                                mrd.addr = cell->getPort(ID::ADDR);
                                mrd.data = cell->getPort(ID::DATA);
+                               mrd.wide_log2 = ceil_log2(GetSize(mrd.data) / mem->width);
                                res.rd_ports.push_back(mrd);
                        }
                }
@@ -346,6 +363,7 @@ namespace {
                                mwr.en = cell->getPort(ID::EN);
                                mwr.addr = cell->getPort(ID::ADDR);
                                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));
                        }
                        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++) {
                        MemRd mrd;
+                       mrd.wide_log2 = 0;
                        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.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++) {
                        MemWr mwr;
+                       mwr.wide_log2 = 0;
                        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 = cell->getPort(ID::WR_CLK).extract(i, 1);
@@ -507,7 +527,7 @@ Cell *Mem::extract_rdff(int idx, FfInitVals *initvals) {
        }
        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;
                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);
index af06e970af84bc899ad6c442f885a54f2fc8f412..e0d8c277f49fe84b646eb1af4d2fbb1d169027ef 100644 (file)
@@ -29,6 +29,7 @@ struct MemRd {
        bool removed;
        dict<IdString, Const> attributes;
        Cell *cell;
+       int wide_log2;
        bool clk_enable, clk_polarity;
        bool transparent;
        SigSpec clk, en, addr, data;
@@ -39,6 +40,7 @@ struct MemWr {
        bool removed;
        dict<IdString, Const> attributes;
        Cell *cell;
+       int wide_log2;
        bool clk_enable, clk_polarity;
        std::vector<bool> priority_mask;
        SigSpec clk, en, addr, data;