mirror of https://github.com/YosysHQ/yosys.git
parent
82f5829aba
commit
13b901bf1c
|
@ -155,7 +155,7 @@ struct MemoryMapWorker
|
||||||
if (!port.clk_enable) {
|
if (!port.clk_enable) {
|
||||||
if (port.addr.is_fully_const() && port.en.is_fully_ones()) {
|
if (port.addr.is_fully_const() && port.en.is_fully_ones()) {
|
||||||
for (int sub = 0; sub < (1 << port.wide_log2); sub++)
|
for (int sub = 0; sub < (1 << port.wide_log2); sub++)
|
||||||
static_cells_map[port.addr.as_int() - mem.start_offset + sub] = port.data.extract(sub * mem.width, mem.width);
|
static_cells_map[port.addr.as_int() + sub] = port.data.extract(sub * mem.width, mem.width);
|
||||||
static_ports.insert(i);
|
static_ports.insert(i);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
@ -176,22 +176,24 @@ struct MemoryMapWorker
|
||||||
|
|
||||||
log("Mapping memory %s in module %s:\n", mem.memid.c_str(), module->name.c_str());
|
log("Mapping memory %s in module %s:\n", mem.memid.c_str(), module->name.c_str());
|
||||||
|
|
||||||
std::vector<RTLIL::SigSpec> data_reg_in;
|
int abits = ceil_log2(mem.size);
|
||||||
std::vector<RTLIL::SigSpec> data_reg_out;
|
std::vector<RTLIL::SigSpec> data_reg_in(1 << abits);
|
||||||
|
std::vector<RTLIL::SigSpec> data_reg_out(1 << abits);
|
||||||
|
|
||||||
int count_static = 0;
|
int count_static = 0;
|
||||||
|
|
||||||
for (int i = 0; i < mem.size; i++)
|
for (int i = 0; i < mem.size; i++)
|
||||||
{
|
{
|
||||||
if (static_cells_map.count(i) > 0)
|
int addr = i + mem.start_offset;
|
||||||
|
int idx = addr & ((1 << abits) - 1);
|
||||||
|
if (static_cells_map.count(addr) > 0)
|
||||||
{
|
{
|
||||||
data_reg_in.push_back(RTLIL::SigSpec(RTLIL::State::Sz, mem.width));
|
data_reg_out[idx] = static_cells_map[addr];
|
||||||
data_reg_out.push_back(static_cells_map[i]);
|
|
||||||
count_static++;
|
count_static++;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
RTLIL::Cell *c = module->addCell(genid(mem.memid, "", i), ID($dff));
|
RTLIL::Cell *c = module->addCell(genid(mem.memid, "", addr), ID($dff));
|
||||||
c->parameters[ID::WIDTH] = mem.width;
|
c->parameters[ID::WIDTH] = mem.width;
|
||||||
if (GetSize(refclock) != 0) {
|
if (GetSize(refclock) != 0) {
|
||||||
c->parameters[ID::CLK_POLARITY] = RTLIL::Const(refclock_pol);
|
c->parameters[ID::CLK_POLARITY] = RTLIL::Const(refclock_pol);
|
||||||
|
@ -201,13 +203,13 @@ struct MemoryMapWorker
|
||||||
c->setPort(ID::CLK, RTLIL::SigSpec(RTLIL::State::S0));
|
c->setPort(ID::CLK, RTLIL::SigSpec(RTLIL::State::S0));
|
||||||
}
|
}
|
||||||
|
|
||||||
RTLIL::Wire *w_in = module->addWire(genid(mem.memid, "", i, "$d"), mem.width);
|
RTLIL::Wire *w_in = module->addWire(genid(mem.memid, "", addr, "$d"), mem.width);
|
||||||
data_reg_in.push_back(RTLIL::SigSpec(w_in));
|
data_reg_in[idx] = w_in;
|
||||||
c->setPort(ID::D, data_reg_in.back());
|
c->setPort(ID::D, w_in);
|
||||||
|
|
||||||
std::string w_out_name = stringf("%s[%d]", mem.memid.c_str(), i);
|
std::string w_out_name = stringf("%s[%d]", mem.memid.c_str(), addr);
|
||||||
if (module->wires_.count(w_out_name) > 0)
|
if (module->wires_.count(w_out_name) > 0)
|
||||||
w_out_name = genid(mem.memid, "", i, "$q");
|
w_out_name = genid(mem.memid, "", addr, "$q");
|
||||||
|
|
||||||
RTLIL::Wire *w_out = module->addWire(w_out_name, mem.width);
|
RTLIL::Wire *w_out = module->addWire(w_out_name, mem.width);
|
||||||
SigSpec w_init = init_data.extract(i*mem.width, mem.width);
|
SigSpec w_init = init_data.extract(i*mem.width, mem.width);
|
||||||
|
@ -215,8 +217,8 @@ struct MemoryMapWorker
|
||||||
if (!w_init.is_fully_undef())
|
if (!w_init.is_fully_undef())
|
||||||
w_out->attributes[ID::init] = w_init.as_const();
|
w_out->attributes[ID::init] = w_init.as_const();
|
||||||
|
|
||||||
data_reg_out.push_back(RTLIL::SigSpec(w_out));
|
data_reg_out[idx] = w_out;
|
||||||
c->setPort(ID::Q, data_reg_out.back());
|
c->setPort(ID::Q, w_out);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -224,7 +226,6 @@ struct MemoryMapWorker
|
||||||
|
|
||||||
int count_dff = 0, count_mux = 0, count_wrmux = 0;
|
int count_dff = 0, count_mux = 0, count_wrmux = 0;
|
||||||
|
|
||||||
int abits = ceil_log2(mem.size);
|
|
||||||
for (int i = 0; i < GetSize(mem.rd_ports); i++)
|
for (int i = 0; i < GetSize(mem.rd_ports); i++)
|
||||||
{
|
{
|
||||||
auto &port = mem.rd_ports[i];
|
auto &port = mem.rd_ports[i];
|
||||||
|
@ -233,9 +234,6 @@ struct MemoryMapWorker
|
||||||
RTLIL::SigSpec rd_addr = port.addr;
|
RTLIL::SigSpec rd_addr = port.addr;
|
||||||
rd_addr.extend_u0(abits, false);
|
rd_addr.extend_u0(abits, false);
|
||||||
|
|
||||||
if (mem.start_offset)
|
|
||||||
rd_addr = module->Sub(NEW_ID, rd_addr, SigSpec(mem.start_offset, abits));
|
|
||||||
|
|
||||||
std::vector<RTLIL::SigSpec> rd_signals;
|
std::vector<RTLIL::SigSpec> rd_signals;
|
||||||
rd_signals.push_back(port.data);
|
rd_signals.push_back(port.data);
|
||||||
|
|
||||||
|
@ -261,31 +259,29 @@ struct MemoryMapWorker
|
||||||
next_rd_signals.swap(rd_signals);
|
next_rd_signals.swap(rd_signals);
|
||||||
}
|
}
|
||||||
|
|
||||||
for (int j = 0; j < mem.size; j++)
|
for (int j = 0; j < (1 << abits); j++)
|
||||||
module->connect(RTLIL::SigSig(rd_signals[j >> port.wide_log2].extract((j & ((1 << port.wide_log2) - 1)) * mem.width, mem.width), data_reg_out[j]));
|
if (data_reg_out[j] != SigSpec())
|
||||||
|
module->connect(RTLIL::SigSig(rd_signals[j >> port.wide_log2].extract((j & ((1 << port.wide_log2) - 1)) * mem.width, mem.width), data_reg_out[j]));
|
||||||
}
|
}
|
||||||
|
|
||||||
log(" read interface: %d $dff and %d $mux cells.\n", count_dff, count_mux);
|
log(" read interface: %d $dff and %d $mux cells.\n", count_dff, count_mux);
|
||||||
|
|
||||||
for (int i = 0; i < mem.size; i++)
|
for (int i = 0; i < mem.size; i++)
|
||||||
{
|
{
|
||||||
if (static_cells_map.count(i) > 0)
|
int addr = i + mem.start_offset;
|
||||||
|
int idx = addr & ((1 << abits) - 1);
|
||||||
|
if (static_cells_map.count(addr) > 0)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
RTLIL::SigSpec sig = data_reg_out[i];
|
RTLIL::SigSpec sig = data_reg_out[idx];
|
||||||
|
|
||||||
for (int j = 0; j < GetSize(mem.wr_ports); j++)
|
for (int j = 0; j < GetSize(mem.wr_ports); j++)
|
||||||
{
|
{
|
||||||
auto &port = mem.wr_ports[j];
|
auto &port = mem.wr_ports[j];
|
||||||
RTLIL::SigSpec wr_addr = port.addr;
|
RTLIL::SigSpec wr_addr = port.addr.extract_end(port.wide_log2);
|
||||||
|
RTLIL::Wire *w_seladdr = addr_decode(wr_addr, RTLIL::SigSpec(addr >> port.wide_log2, GetSize(wr_addr)));
|
||||||
|
|
||||||
if (mem.start_offset)
|
int sub = addr & ((1 << port.wide_log2) - 1);
|
||||||
wr_addr = module->Sub(NEW_ID, wr_addr, SigSpec(mem.start_offset, GetSize(wr_addr)));
|
|
||||||
|
|
||||||
wr_addr = wr_addr.extract_end(port.wide_log2);
|
|
||||||
RTLIL::Wire *w_seladdr = addr_decode(wr_addr, RTLIL::SigSpec(i >> port.wide_log2, GetSize(wr_addr)));
|
|
||||||
|
|
||||||
int sub = i & ((1 << port.wide_log2) - 1);
|
|
||||||
|
|
||||||
int wr_offset = 0;
|
int wr_offset = 0;
|
||||||
while (wr_offset < mem.width)
|
while (wr_offset < mem.width)
|
||||||
|
@ -304,7 +300,7 @@ struct MemoryMapWorker
|
||||||
|
|
||||||
if (wr_bit != State::S1)
|
if (wr_bit != State::S1)
|
||||||
{
|
{
|
||||||
RTLIL::Cell *c = module->addCell(genid(mem.memid, "$wren", i, "", j, "", wr_offset), ID($and));
|
RTLIL::Cell *c = module->addCell(genid(mem.memid, "$wren", addr, "", j, "", wr_offset), ID($and));
|
||||||
c->parameters[ID::A_SIGNED] = RTLIL::Const(0);
|
c->parameters[ID::A_SIGNED] = RTLIL::Const(0);
|
||||||
c->parameters[ID::B_SIGNED] = RTLIL::Const(0);
|
c->parameters[ID::B_SIGNED] = RTLIL::Const(0);
|
||||||
c->parameters[ID::A_WIDTH] = RTLIL::Const(1);
|
c->parameters[ID::A_WIDTH] = RTLIL::Const(1);
|
||||||
|
@ -313,17 +309,17 @@ struct MemoryMapWorker
|
||||||
c->setPort(ID::A, w);
|
c->setPort(ID::A, w);
|
||||||
c->setPort(ID::B, wr_bit);
|
c->setPort(ID::B, wr_bit);
|
||||||
|
|
||||||
w = module->addWire(genid(mem.memid, "$wren", i, "", j, "", wr_offset, "$y"));
|
w = module->addWire(genid(mem.memid, "$wren", addr, "", j, "", wr_offset, "$y"));
|
||||||
c->setPort(ID::Y, RTLIL::SigSpec(w));
|
c->setPort(ID::Y, RTLIL::SigSpec(w));
|
||||||
}
|
}
|
||||||
|
|
||||||
RTLIL::Cell *c = module->addCell(genid(mem.memid, "$wrmux", i, "", j, "", wr_offset), ID($mux));
|
RTLIL::Cell *c = module->addCell(genid(mem.memid, "$wrmux", addr, "", j, "", wr_offset), ID($mux));
|
||||||
c->parameters[ID::WIDTH] = wr_width;
|
c->parameters[ID::WIDTH] = wr_width;
|
||||||
c->setPort(ID::A, sig.extract(wr_offset, wr_width));
|
c->setPort(ID::A, sig.extract(wr_offset, wr_width));
|
||||||
c->setPort(ID::B, port.data.extract(wr_offset + sub * mem.width, wr_width));
|
c->setPort(ID::B, port.data.extract(wr_offset + sub * mem.width, wr_width));
|
||||||
c->setPort(ID::S, RTLIL::SigSpec(w));
|
c->setPort(ID::S, RTLIL::SigSpec(w));
|
||||||
|
|
||||||
w = module->addWire(genid(mem.memid, "$wrmux", i, "", j, "", wr_offset, "$y"), wr_width);
|
w = module->addWire(genid(mem.memid, "$wrmux", addr, "", j, "", wr_offset, "$y"), wr_width);
|
||||||
c->setPort(ID::Y, w);
|
c->setPort(ID::Y, w);
|
||||||
|
|
||||||
sig.replace(wr_offset, w);
|
sig.replace(wr_offset, w);
|
||||||
|
@ -332,7 +328,7 @@ struct MemoryMapWorker
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
module->connect(RTLIL::SigSig(data_reg_in[i], sig));
|
module->connect(RTLIL::SigSig(data_reg_in[idx], sig));
|
||||||
}
|
}
|
||||||
|
|
||||||
log(" write interface: %d write mux blocks.\n", count_wrmux);
|
log(" write interface: %d write mux blocks.\n", count_wrmux);
|
||||||
|
|
|
@ -0,0 +1,100 @@
|
||||||
|
read_verilog << EOT
|
||||||
|
|
||||||
|
module top(...);
|
||||||
|
|
||||||
|
input [3:0] ra;
|
||||||
|
input [3:0] wa;
|
||||||
|
|
||||||
|
input [15:0] wd;
|
||||||
|
output [15:0] rd;
|
||||||
|
input en, clk;
|
||||||
|
|
||||||
|
reg [15:0] mem[3:9];
|
||||||
|
|
||||||
|
always @(posedge clk)
|
||||||
|
if (en)
|
||||||
|
mem[wa] <= wd;
|
||||||
|
|
||||||
|
assign rd = mem[ra];
|
||||||
|
|
||||||
|
endmodule
|
||||||
|
|
||||||
|
EOT
|
||||||
|
|
||||||
|
hierarchy -auto-top
|
||||||
|
proc
|
||||||
|
opt_clean
|
||||||
|
memory_map
|
||||||
|
|
||||||
|
design -stash gate
|
||||||
|
|
||||||
|
read_verilog << EOT
|
||||||
|
|
||||||
|
module top(...);
|
||||||
|
|
||||||
|
input [3:0] ra;
|
||||||
|
input [3:0] wa;
|
||||||
|
|
||||||
|
input [15:0] wd;
|
||||||
|
output reg [15:0] rd;
|
||||||
|
input en, clk;
|
||||||
|
|
||||||
|
reg [15:0] \mem[3] ;
|
||||||
|
reg [15:0] \mem[4] ;
|
||||||
|
reg [15:0] \mem[5] ;
|
||||||
|
reg [15:0] \mem[6] ;
|
||||||
|
reg [15:0] \mem[7] ;
|
||||||
|
reg [15:0] \mem[8] ;
|
||||||
|
reg [15:0] \mem[9] ;
|
||||||
|
|
||||||
|
always @(posedge clk) begin
|
||||||
|
if (en && wa == 3)
|
||||||
|
\mem[3] <= wd;
|
||||||
|
if (en && wa == 4)
|
||||||
|
\mem[4] <= wd;
|
||||||
|
if (en && wa == 5)
|
||||||
|
\mem[5] <= wd;
|
||||||
|
if (en && wa == 6)
|
||||||
|
\mem[6] <= wd;
|
||||||
|
if (en && wa == 7)
|
||||||
|
\mem[7] <= wd;
|
||||||
|
if (en && wa == 8)
|
||||||
|
\mem[8] <= wd;
|
||||||
|
if (en && wa == 9)
|
||||||
|
\mem[9] <= wd;
|
||||||
|
end
|
||||||
|
|
||||||
|
always @* begin
|
||||||
|
rd = 16'bx;
|
||||||
|
if (ra == 3)
|
||||||
|
rd = \mem[3] ;
|
||||||
|
if (ra == 4)
|
||||||
|
rd = \mem[4] ;
|
||||||
|
if (ra == 5)
|
||||||
|
rd = \mem[5] ;
|
||||||
|
if (ra == 6)
|
||||||
|
rd = \mem[6] ;
|
||||||
|
if (ra == 7)
|
||||||
|
rd = \mem[7] ;
|
||||||
|
if (ra == 8)
|
||||||
|
rd = \mem[8] ;
|
||||||
|
if (ra == 9)
|
||||||
|
rd = \mem[9] ;
|
||||||
|
end
|
||||||
|
|
||||||
|
endmodule
|
||||||
|
|
||||||
|
EOT
|
||||||
|
|
||||||
|
hierarchy -auto-top
|
||||||
|
proc
|
||||||
|
opt_clean
|
||||||
|
|
||||||
|
design -stash gold
|
||||||
|
|
||||||
|
design -copy-from gold -as gold A:top
|
||||||
|
design -copy-from gate -as gate A:top
|
||||||
|
|
||||||
|
equiv_make gold gate equiv
|
||||||
|
equiv_induct -undef equiv
|
||||||
|
equiv_status -assert equiv
|
Loading…
Reference in New Issue