ecp5: BRAM improvements with constant/inverted inputs
Signed-off-by: David Shah <dave@ds0.me>
This commit is contained in:
parent
cd688a2784
commit
d716292e3d
@ -92,9 +92,19 @@ static void tie_cib_signal(Context *ctx, ChipConfig &cc, WireId wire, bool value
|
|||||||
++iter;
|
++iter;
|
||||||
NPNR_ASSERT(!(iter != uphill.end())); // Exactly one uphill pip
|
NPNR_ASSERT(!(iter != uphill.end())); // Exactly one uphill pip
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool out_value = value;
|
||||||
|
if (basename.substr(0, 3) == "JCE")
|
||||||
|
NPNR_ASSERT(value);
|
||||||
|
if (basename.substr(0, 4) == "JCLK" || basename.substr(0, 4) == "JLSR") {
|
||||||
|
NPNR_ASSERT(value);
|
||||||
|
out_value = 0;
|
||||||
|
}
|
||||||
|
|
||||||
for (const auto &tile : ctx->getTilesAtLocation(cibsig.location.y, cibsig.location.x)) {
|
for (const auto &tile : ctx->getTilesAtLocation(cibsig.location.y, cibsig.location.x)) {
|
||||||
if (tile.second.substr(0, 3) == "CIB" || tile.second.substr(0, 4) == "VCIB") {
|
if (tile.second.substr(0, 3) == "CIB" || tile.second.substr(0, 4) == "VCIB") {
|
||||||
cc.tiles[tile.first].add_enum("CIB." + basename + "MUX", value ? "1" : "0");
|
|
||||||
|
cc.tiles[tile.first].add_enum("CIB." + basename + "MUX", out_value ? "1" : "0");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -367,11 +377,8 @@ void write_bitstream(Context *ctx, std::string base_config_file, std::string tex
|
|||||||
if (str_or_default(ci->params, ctx->id("MODE"), "LOGIC") == "DPRAM" && slice == "SLICEA") {
|
if (str_or_default(ci->params, ctx->id("MODE"), "LOGIC") == "DPRAM" && slice == "SLICEA") {
|
||||||
cc.tiles[tname].add_enum(slice + ".WREMUX", str_or_default(ci->params, ctx->id("WREMUX"), "WRE"));
|
cc.tiles[tname].add_enum(slice + ".WREMUX", str_or_default(ci->params, ctx->id("WREMUX"), "WRE"));
|
||||||
|
|
||||||
NetInfo *wcknet = nullptr;
|
|
||||||
std::string wckmux = str_or_default(ci->params, ctx->id("WCKMUX"), "WCK");
|
std::string wckmux = str_or_default(ci->params, ctx->id("WCKMUX"), "WCK");
|
||||||
wckmux = (wckmux == "WCK") ? "CLK" : wckmux;
|
wckmux = (wckmux == "WCK") ? "CLK" : wckmux;
|
||||||
if (ci->ports.find(ctx->id("WCK")) != ci->ports.end() && ci->ports.at(ctx->id("WCK")).net != nullptr)
|
|
||||||
wcknet = ci->ports.at(ctx->id("WCK")).net;
|
|
||||||
cc.tiles[tname].add_enum("CLK1.CLKMUX", wckmux);
|
cc.tiles[tname].add_enum("CLK1.CLKMUX", wckmux);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -430,10 +437,8 @@ void write_bitstream(Context *ctx, std::string base_config_file, std::string tex
|
|||||||
|
|
||||||
tg.config.add_enum(ebr + ".MODE", "DP16KD");
|
tg.config.add_enum(ebr + ".MODE", "DP16KD");
|
||||||
|
|
||||||
tg.config.add_word(ebr + ".CSDECODE_A",
|
auto csd_a = str_to_bitvector(str_or_default(ci->params, ctx->id("CSDECODE_A"), "0b000"), 3),
|
||||||
str_to_bitvector(str_or_default(ci->params, ctx->id("CSDECODE_A"), "0b000"), 3));
|
csd_b = str_to_bitvector(str_or_default(ci->params, ctx->id("CSDECODE_B"), "0b000"), 3);
|
||||||
tg.config.add_word(ebr + ".CSDECODE_B",
|
|
||||||
str_to_bitvector(str_or_default(ci->params, ctx->id("CSDECODE_B"), "0b000"), 3));
|
|
||||||
|
|
||||||
tg.config.add_enum(ebr + ".DP16KD.DATA_WIDTH_A", str_or_default(ci->params, ctx->id("DATA_WIDTH_A"), "18"));
|
tg.config.add_enum(ebr + ".DP16KD.DATA_WIDTH_A", str_or_default(ci->params, ctx->id("DATA_WIDTH_A"), "18"));
|
||||||
tg.config.add_enum(ebr + ".DP16KD.DATA_WIDTH_B", str_or_default(ci->params, ctx->id("DATA_WIDTH_B"), "18"));
|
tg.config.add_enum(ebr + ".DP16KD.DATA_WIDTH_B", str_or_default(ci->params, ctx->id("DATA_WIDTH_B"), "18"));
|
||||||
@ -457,15 +462,59 @@ void write_bitstream(Context *ctx, std::string base_config_file, std::string tex
|
|||||||
for (auto port : ci->ports) {
|
for (auto port : ci->ports) {
|
||||||
if (port.second.net == nullptr && port.second.type == PORT_IN) {
|
if (port.second.net == nullptr && port.second.type == PORT_IN) {
|
||||||
if (port.first == id_CLKA || port.first == id_CLKB || port.first == id_WEA ||
|
if (port.first == id_CLKA || port.first == id_CLKB || port.first == id_WEA ||
|
||||||
port.first == id_WEB || port.first == id_CEA || port.first == id_CEB || port.first == id_OCEA ||
|
port.first == id_WEB || port.first == id_RSTA || port.first == id_RSTB) {
|
||||||
port.first == id_OCEB || port.first == id_RSTA || port.first == id_RSTB)
|
// CIB clock or LSR. Tie to "1" (also 0 in prjtrellis db?) in CIB
|
||||||
continue; // these don't seem to have CIB ties
|
// If MUX doesn't exist, set to INV to emulate default 0
|
||||||
|
tie_cib_signal(ctx, cc, ctx->getBelPinWire(ci->bel, port.first), true);
|
||||||
|
if (!ci->params.count(ctx->id(port.first.str(ctx) + "MUX")))
|
||||||
|
ci->params[ctx->id(port.first.str(ctx) + "MUX")] = "INV";
|
||||||
|
} else if (port.first == id_CEA || port.first == id_CEB || port.first == id_OCEA ||
|
||||||
|
port.first == id_OCEB) {
|
||||||
|
// CIB CE. Tie to "1" in CIB
|
||||||
|
// If MUX doesn't exist, set to passthru to emulate default 1
|
||||||
|
tie_cib_signal(ctx, cc, ctx->getBelPinWire(ci->bel, port.first), true);
|
||||||
|
if (!ci->params.count(ctx->id(port.first.str(ctx) + "MUX")))
|
||||||
|
ci->params[ctx->id(port.first.str(ctx) + "MUX")] = port.first.str(ctx);
|
||||||
|
} else if (port.first == id_CSA0 || port.first == id_CSA1 || port.first == id_CSA2 ||
|
||||||
|
port.first == id_CSB0 || port.first == id_CSB1 || port.first == id_CSB2) {
|
||||||
|
// CIB CE. Tie to "1" in CIB.
|
||||||
|
// If MUX doesn't exist, set to INV to emulate default 0
|
||||||
|
tie_cib_signal(ctx, cc, ctx->getBelPinWire(ci->bel, port.first), true);
|
||||||
|
if (!ci->params.count(ctx->id(port.first.str(ctx) + "MUX")))
|
||||||
|
ci->params[ctx->id(port.first.str(ctx) + "MUX")] = "INV";
|
||||||
|
} else {
|
||||||
|
// CIB ABCD signal
|
||||||
// Tie signals low unless explicit MUX param specified
|
// Tie signals low unless explicit MUX param specified
|
||||||
bool value = bool_or_default(ci->params, ctx->id(port.first.str(ctx) + "MUX"), false);
|
bool value = bool_or_default(ci->params, ctx->id(port.first.str(ctx) + "MUX"), false);
|
||||||
tie_cib_signal(ctx, cc, ctx->getBelPinWire(ci->bel, port.first), value);
|
tie_cib_signal(ctx, cc, ctx->getBelPinWire(ci->bel, port.first), value);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Invert CSDECODE bits to emulate inversion muxes on CSA/CSB signals
|
||||||
|
for (auto port : {std::make_pair("CSA", std::ref(csd_a)), std::make_pair("CSB", std::ref(csd_b))}) {
|
||||||
|
for (int bit = 0; bit < 3; bit++) {
|
||||||
|
std::string sig = port.first + std::to_string(bit);
|
||||||
|
if (str_or_default(ci->params, ctx->id(sig + "MUX"), sig) == "INV")
|
||||||
|
port.second.at(bit) = !port.second.at(bit);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
tg.config.add_enum(ebr + ".CLKAMUX", str_or_default(ci->params, ctx->id("CLKAMUX"), "CLKA"));
|
||||||
|
tg.config.add_enum(ebr + ".CLKBMUX", str_or_default(ci->params, ctx->id("CLKBMUX"), "CLKB"));
|
||||||
|
|
||||||
|
tg.config.add_enum(ebr + ".RSTAMUX", str_or_default(ci->params, ctx->id("RSTAMUX"), "RSTA"));
|
||||||
|
tg.config.add_enum(ebr + ".RSTBMUX", str_or_default(ci->params, ctx->id("RSTBMUX"), "RSTB"));
|
||||||
|
tg.config.add_enum(ebr + ".WEAMUX", str_or_default(ci->params, ctx->id("WEAMUX"), "WEA"));
|
||||||
|
tg.config.add_enum(ebr + ".WEBMUX", str_or_default(ci->params, ctx->id("WEBMUX"), "WEB"));
|
||||||
|
|
||||||
|
tg.config.add_enum(ebr + ".CEAMUX", str_or_default(ci->params, ctx->id("CEAMUX"), "CEA"));
|
||||||
|
tg.config.add_enum(ebr + ".CEBMUX", str_or_default(ci->params, ctx->id("CEBMUX"), "CEB"));
|
||||||
|
tg.config.add_enum(ebr + ".OCEAMUX", str_or_default(ci->params, ctx->id("OCEAMUX"), "OCEA"));
|
||||||
|
tg.config.add_enum(ebr + ".OCEBMUX", str_or_default(ci->params, ctx->id("OCEBMUX"), "OCEB"));
|
||||||
|
|
||||||
|
tg.config.add_word(ebr + ".CSDECODE_A", csd_a);
|
||||||
|
tg.config.add_word(ebr + ".CSDECODE_B", csd_b);
|
||||||
|
|
||||||
cc.tilegroups.push_back(tg);
|
cc.tilegroups.push_back(tg);
|
||||||
} else {
|
} else {
|
||||||
|
17
ecp5/pack.cc
17
ecp5/pack.cc
@ -844,6 +844,19 @@ class Ecp5Packer
|
|||||||
((!constval && str_or_default(uc->params, ctx->id("LSRMUX"), "LSR") == "LSR") ||
|
((!constval && str_or_default(uc->params, ctx->id("LSRMUX"), "LSR") == "LSR") ||
|
||||||
(constval && str_or_default(uc->params, ctx->id("LSRMUX"), "LSR") == "INV"))) {
|
(constval && str_or_default(uc->params, ctx->id("LSRMUX"), "LSR") == "INV"))) {
|
||||||
uc->ports[user.port].net = nullptr;
|
uc->ports[user.port].net = nullptr;
|
||||||
|
} else if (uc->type == id_DP16KD) {
|
||||||
|
if (user.port == id_CLKA || user.port == id_CLKB || user.port == id_RSTA || user.port == id_RSTB ||
|
||||||
|
user.port == id_WEA || user.port == id_WEB || user.port == id_CEA || user.port == id_CEB ||
|
||||||
|
user.port == id_OCEA || user.port == id_OCEB || user.port == id_CSA0 || user.port == id_CSA1 ||
|
||||||
|
user.port == id_CSA2 || user.port == id_CSB0 || user.port == id_CSB1 || user.port == id_CSB2) {
|
||||||
|
// Connect to CIB CLK, LSR or CE. Default state is 1
|
||||||
|
uc->params[ctx->id(user.port.str(ctx) + "MUX")] = constval ? user.port.str(ctx) : "INV";
|
||||||
|
} else {
|
||||||
|
// Connected to CIB ABCD. Default state is bitstream configurable
|
||||||
|
uc->params[ctx->id(user.port.str(ctx) + "MUX")] = constval ? "1" : "0";
|
||||||
|
}
|
||||||
|
uc->ports[user.port].net = nullptr;
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
uc->ports[user.port].net = constnet;
|
uc->ports[user.port].net = constnet;
|
||||||
constnet->users.push_back(user);
|
constnet->users.push_back(user);
|
||||||
@ -921,6 +934,8 @@ class Ecp5Packer
|
|||||||
// Pack EBR
|
// Pack EBR
|
||||||
void pack_ebr()
|
void pack_ebr()
|
||||||
{
|
{
|
||||||
|
// Autoincrement WID (starting from 3 seems to match vendor behaviour?)
|
||||||
|
int wid = 3;
|
||||||
for (auto cell : sorted(ctx->cells)) {
|
for (auto cell : sorted(ctx->cells)) {
|
||||||
CellInfo *ci = cell.second;
|
CellInfo *ci = cell.second;
|
||||||
if (ci->type == id_DP16KD) {
|
if (ci->type == id_DP16KD) {
|
||||||
@ -953,6 +968,8 @@ class Ecp5Packer
|
|||||||
autocreate_empty_port(ci, id_OCEB);
|
autocreate_empty_port(ci, id_OCEB);
|
||||||
autocreate_empty_port(ci, id_WEB);
|
autocreate_empty_port(ci, id_WEB);
|
||||||
autocreate_empty_port(ci, id_RSTB);
|
autocreate_empty_port(ci, id_RSTB);
|
||||||
|
|
||||||
|
ci->attrs[ctx->id("WID")] = std::to_string(wid++);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user