mirror of https://github.com/YosysHQ/yosys.git
kernel/mem: Add read-first semantic emulation code.
This commit is contained in:
parent
9a2294f285
commit
bac750fb99
104
kernel/mem.cc
104
kernel/mem.cc
|
@ -1560,3 +1560,107 @@ void Mem::emulate_rd_srst_over_ce(int idx) {
|
|||
port.ce_over_srst = true;
|
||||
port.en = module->Or(NEW_ID, port.en, port.srst);
|
||||
}
|
||||
|
||||
bool Mem::emulate_read_first_ok() {
|
||||
if (wr_ports.empty())
|
||||
return false;
|
||||
SigSpec clk = wr_ports[0].clk;
|
||||
bool clk_polarity = wr_ports[0].clk_polarity;
|
||||
for (auto &port: wr_ports) {
|
||||
if (!port.clk_enable)
|
||||
return false;
|
||||
if (port.clk != clk)
|
||||
return false;
|
||||
if (port.clk_polarity != clk_polarity)
|
||||
return false;
|
||||
}
|
||||
bool found_read_first = false;
|
||||
for (auto &port: rd_ports) {
|
||||
if (!port.clk_enable)
|
||||
return false;
|
||||
if (port.clk != clk)
|
||||
return false;
|
||||
if (port.clk_polarity != clk_polarity)
|
||||
return false;
|
||||
// No point doing this operation if there is no read-first relationship
|
||||
// in the first place.
|
||||
for (int j = 0; j < GetSize(wr_ports); j++)
|
||||
if (!port.transparency_mask[j] && !port.collision_x_mask[j])
|
||||
found_read_first = true;
|
||||
}
|
||||
return found_read_first;
|
||||
}
|
||||
|
||||
void Mem::emulate_read_first(FfInitVals *initvals) {
|
||||
log_assert(emulate_read_first_ok());
|
||||
for (int i = 0; i < GetSize(rd_ports); i++)
|
||||
for (int j = 0; j < GetSize(wr_ports); j++)
|
||||
if (rd_ports[i].transparency_mask[j])
|
||||
emulate_transparency(j, i, initvals);
|
||||
for (int i = 0; i < GetSize(rd_ports); i++)
|
||||
for (int j = 0; j < GetSize(wr_ports); j++) {
|
||||
log_assert(!rd_ports[i].transparency_mask[j]);
|
||||
rd_ports[i].collision_x_mask[j] = false;
|
||||
rd_ports[i].transparency_mask[j] = true;
|
||||
}
|
||||
for (auto &port: wr_ports) {
|
||||
Wire *new_data = module->addWire(NEW_ID, GetSize(port.data));
|
||||
Wire *new_addr = module->addWire(NEW_ID, GetSize(port.addr));
|
||||
auto compressed = port.compress_en();
|
||||
Wire *new_en = module->addWire(NEW_ID, GetSize(compressed.first));
|
||||
FfData ff_data(module, initvals, NEW_ID);
|
||||
FfData ff_addr(module, initvals, NEW_ID);
|
||||
FfData ff_en(module, initvals, NEW_ID);
|
||||
ff_data.width = GetSize(port.data);
|
||||
ff_data.has_clk = true;
|
||||
ff_data.sig_clk = port.clk;
|
||||
ff_data.pol_clk = port.clk_polarity;
|
||||
ff_data.sig_d = port.data;
|
||||
ff_data.sig_q = new_data;;
|
||||
ff_data.val_init = Const(State::Sx, ff_data.width);
|
||||
ff_data.emit();
|
||||
ff_addr.width = GetSize(port.addr);
|
||||
ff_addr.has_clk = true;
|
||||
ff_addr.sig_clk = port.clk;
|
||||
ff_addr.pol_clk = port.clk_polarity;
|
||||
ff_addr.sig_d = port.addr;
|
||||
ff_addr.sig_q = new_addr;;
|
||||
ff_addr.val_init = Const(State::Sx, ff_addr.width);
|
||||
ff_addr.emit();
|
||||
ff_en.width = GetSize(compressed.first);
|
||||
ff_en.has_clk = true;
|
||||
ff_en.sig_clk = port.clk;
|
||||
ff_en.pol_clk = port.clk_polarity;
|
||||
ff_en.sig_d = compressed.first;
|
||||
ff_en.sig_q = new_en;;
|
||||
ff_en.val_init = Const(State::S0, ff_en.width);
|
||||
ff_en.emit();
|
||||
port.data = new_data;
|
||||
port.addr = new_addr;
|
||||
port.en = port.decompress_en(compressed.second, new_en);
|
||||
}
|
||||
}
|
||||
|
||||
std::pair<SigSpec, std::vector<int>> MemWr::compress_en() {
|
||||
SigSpec sig = en[0];
|
||||
std::vector<int> swizzle;
|
||||
SigBit prev_bit = en[0];
|
||||
int idx = 0;
|
||||
for (auto &bit: en) {
|
||||
if (bit != prev_bit) {
|
||||
sig.append(bit);
|
||||
prev_bit = bit;
|
||||
idx++;
|
||||
}
|
||||
swizzle.push_back(idx);
|
||||
}
|
||||
log_assert(idx + 1 == GetSize(sig));
|
||||
return {sig, swizzle};
|
||||
}
|
||||
|
||||
SigSpec MemWr::decompress_en(const std::vector<int> &swizzle, SigSpec sig) {
|
||||
SigSpec res;
|
||||
for (int i: swizzle)
|
||||
res.append(sig[i]);
|
||||
return res;
|
||||
}
|
||||
|
|
12
kernel/mem.h
12
kernel/mem.h
|
@ -74,6 +74,9 @@ struct MemWr : RTLIL::AttrObject {
|
|||
res[i] = State(sub >> i & 1);
|
||||
return res;
|
||||
}
|
||||
|
||||
std::pair<SigSpec, std::vector<int>> compress_en();
|
||||
SigSpec decompress_en(const std::vector<int> &swizzle, SigSpec sig);
|
||||
};
|
||||
|
||||
struct MemInit : RTLIL::AttrObject {
|
||||
|
@ -209,6 +212,15 @@ struct Mem : RTLIL::AttrObject {
|
|||
// emulation logic.
|
||||
void emulate_rd_srst_over_ce(int idx);
|
||||
|
||||
// Returns true iff emulate_read_first makes sense to call.
|
||||
bool emulate_read_first_ok();
|
||||
|
||||
// Emulates all read-first read-write port relationships in terms of
|
||||
// all-transparent ports, by delaying all write ports by one cycle.
|
||||
// This can only be used when all read ports and all write ports are
|
||||
// in the same clock domain.
|
||||
void emulate_read_first(FfInitVals *initvals);
|
||||
|
||||
Mem(Module *module, IdString memid, int width, int start_offset, int size) : module(module), memid(memid), packed(false), mem(nullptr), cell(nullptr), width(width), start_offset(start_offset), size(size) {}
|
||||
};
|
||||
|
||||
|
|
Loading…
Reference in New Issue