aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMarcelina Kościelnicka <mwk@0x04.net>2021-05-22 17:18:59 +0200
committerMarcelina Kościelnicka <mwk@0x04.net>2021-05-25 20:06:00 +0200
commit24b880b2de1676b420f5a0bbdf3805dab38b8f00 (patch)
tree5d71ef2f4389ca661861b223bcde08227d6e057f
parent097de6c5f8c5170cc275b7250bf3780ae6ab3a00 (diff)
downloadyosys-24b880b2de1676b420f5a0bbdf3805dab38b8f00.tar.gz
yosys-24b880b2de1676b420f5a0bbdf3805dab38b8f00.tar.bz2
yosys-24b880b2de1676b420f5a0bbdf3805dab38b8f00.zip
kernel/mem: Add model support for read port init value and resets.
Like wide port support, this is still completely unusable, and support in various passes will be gradually added later. It also has no support at all in the cell library, so attempting to create a read port with a reset or initial value will cause an assert failure for now.
-rw-r--r--kernel/mem.cc72
-rw-r--r--kernel/mem.h5
2 files changed, 73 insertions, 4 deletions
diff --git a/kernel/mem.cc b/kernel/mem.cc
index f1fedf3c2..6d6778b57 100644
--- a/kernel/mem.cc
+++ b/kernel/mem.cc
@@ -18,6 +18,7 @@
*/
#include "kernel/mem.h"
+#include "kernel/ff.h"
USING_YOSYS_NAMESPACE
@@ -119,6 +120,10 @@ 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.arst == State::S0);
+ log_assert(port.srst == State::S0);
+ log_assert(port.init_value == Const(State::Sx, width << port.wide_log2));
if (port.cell) {
module->remove(port.cell);
port.cell = nullptr;
@@ -210,6 +215,10 @@ void Mem::emit() {
mem->start_offset = start_offset;
mem->size = size;
for (auto &port : rd_ports) {
+ // TODO: remove
+ log_assert(port.arst == State::S0);
+ log_assert(port.srst == State::S0);
+ log_assert(port.init_value == Const(State::Sx, width << port.wide_log2));
if (!port.cell)
port.cell = module->addCell(NEW_ID, ID($memrd));
port.cell->parameters[ID::MEMID] = memid.str();
@@ -278,9 +287,16 @@ void Mem::check() {
continue;
log_assert(GetSize(port.clk) == 1);
log_assert(GetSize(port.en) == 1);
+ log_assert(GetSize(port.arst) == 1);
+ log_assert(GetSize(port.srst) == 1);
log_assert(GetSize(port.data) == (width << port.wide_log2));
+ log_assert(GetSize(port.init_value) == (width << port.wide_log2));
+ log_assert(GetSize(port.arst_value) == (width << port.wide_log2));
+ log_assert(GetSize(port.srst_value) == (width << port.wide_log2));
if (!port.clk_enable) {
log_assert(!port.transparent);
+ log_assert(port.arst == State::S0);
+ log_assert(port.srst == State::S0);
}
for (int j = 0; j < port.wide_log2; j++) {
log_assert(port.addr[j] == State::S0);
@@ -352,6 +368,12 @@ namespace {
mrd.addr = cell->getPort(ID::ADDR);
mrd.data = cell->getPort(ID::DATA);
mrd.wide_log2 = ceil_log2(GetSize(mrd.data) / mem->width);
+ mrd.ce_over_srst = false;
+ mrd.arst_value = Const(State::Sx, mem->width << mrd.wide_log2);
+ mrd.srst_value = Const(State::Sx, mem->width << mrd.wide_log2);
+ mrd.init_value = Const(State::Sx, mem->width << mrd.wide_log2);
+ mrd.srst = State::S0;
+ mrd.arst = State::S0;
res.rd_ports.push_back(mrd);
}
}
@@ -454,6 +476,12 @@ namespace {
mrd.en = cell->getPort(ID::RD_EN).extract(i, 1);
mrd.addr = cell->getPort(ID::RD_ADDR).extract(i * abits, abits);
mrd.data = cell->getPort(ID::RD_DATA).extract(i * res.width, res.width);
+ mrd.ce_over_srst = false;
+ mrd.arst_value = Const(State::Sx, res.width << mrd.wide_log2);
+ mrd.srst_value = Const(State::Sx, res.width << mrd.wide_log2);
+ mrd.init_value = Const(State::Sx, res.width << mrd.wide_log2);
+ mrd.srst = State::S0;
+ mrd.arst = State::S0;
res.rd_ports.push_back(mrd);
}
for (int i = 0; i < cell->parameters.at(ID::WR_PORTS).as_int(); i++) {
@@ -525,6 +553,9 @@ Cell *Mem::extract_rdff(int idx, FfInitVals *initvals) {
if (port.transparent)
{
log_assert(port.en == State::S1);
+ log_assert(port.srst == State::S0);
+ log_assert(port.arst == State::S0);
+ log_assert(port.init_value.is_fully_undef());
// Do not put a register in front of constant address bits — this is both
// unnecessary and will break wide ports.
@@ -547,10 +578,38 @@ Cell *Mem::extract_rdff(int idx, FfInitVals *initvals) {
}
else
{
+ log_assert(port.arst == State::S0 || port.srst == State::S0);
+
SigSpec sig_d = module->addWire(stringf("$%s$rdreg[%d]$d", memid.c_str(), idx), GetSize(port.data));
- SigSpec sig_q = port.data;
+ IdString name = stringf("$%s$rdreg[%d]", memid.c_str(), idx);
+ FfData ff(initvals);
+ ff.width = GetSize(port.data);
+ ff.has_clk = true;
+ ff.sig_clk = port.clk;
+ ff.pol_clk = port.clk_polarity;
+ if (port.en != State::S1) {
+ ff.has_en = true;
+ ff.pol_en = true;
+ ff.sig_en = port.en;
+ }
+ if (port.arst != State::S0) {
+ ff.has_arst = true;
+ ff.pol_arst = true;
+ ff.sig_arst = port.arst;
+ ff.val_arst = port.arst_value;
+ }
+ if (port.srst != State::S0) {
+ ff.has_srst = true;
+ ff.pol_srst = true;
+ ff.sig_srst = port.srst;
+ ff.val_srst = port.srst_value;
+ ff.ce_over_srst = ff.has_en && port.ce_over_srst;
+ }
+ ff.sig_d = sig_d;
+ ff.sig_q = port.data;
+ ff.val_init = port.init_value;
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 = ff.emit(module, name);
}
log("Extracted %s FF from read port %d of %s.%s: %s\n", port.transparent ? "addr" : "data",
@@ -558,9 +617,15 @@ Cell *Mem::extract_rdff(int idx, FfInitVals *initvals) {
port.en = State::S1;
port.clk = State::S0;
+ port.arst = State::S0;
+ port.srst = State::S0;
port.clk_enable = false;
port.clk_polarity = true;
port.transparent = false;
+ port.ce_over_srst = false;
+ port.arst_value = Const(State::Sx, GetSize(port.data));
+ port.srst_value = Const(State::Sx, GetSize(port.data));
+ port.init_value = Const(State::Sx, GetSize(port.data));
return c;
}
@@ -589,6 +654,9 @@ void Mem::narrow() {
port.cell = nullptr;
if (port.wide_log2) {
port.data = port.data.extract(it.second * width, width);
+ port.init_value = port.init_value.extract(it.second * width, width);
+ port.arst_value = port.arst_value.extract(it.second * width, width);
+ port.srst_value = port.srst_value.extract(it.second * width, width);
for (int i = 0; i < port.wide_log2; i++)
port.addr[i] = State(it.second >> i & 1);
port.wide_log2 = 0;
diff --git a/kernel/mem.h b/kernel/mem.h
index 08befebdb..49b72bc35 100644
--- a/kernel/mem.h
+++ b/kernel/mem.h
@@ -30,9 +30,10 @@ struct MemRd {
dict<IdString, Const> attributes;
Cell *cell;
int wide_log2;
- bool clk_enable, clk_polarity;
+ bool clk_enable, clk_polarity, ce_over_srst;
+ Const arst_value, srst_value, init_value;
bool transparent;
- SigSpec clk, en, addr, data;
+ SigSpec clk, en, arst, srst, addr, data;
MemRd() : removed(false), cell(nullptr) {}
};