clangformat

This commit is contained in:
Miodrag Milanovic 2024-11-29 09:45:16 +01:00
parent 858ff546d8
commit 96b073c001
11 changed files with 1812 additions and 1550 deletions

View File

@ -61,8 +61,7 @@ struct BitstreamJsonBackend
{ {
if (boost::starts_with(tile, "FENCE[")) { if (boost::starts_with(tile, "FENCE[")) {
char last = tile[tile.size() - 2]; char last = tile[tile.size() - 2];
switch(last) switch (last) {
{
case 'T': case 'T':
case 'B': case 'B':
case 'U': case 'U':
@ -101,10 +100,13 @@ struct BitstreamJsonBackend
return name; return name;
} }
void add_net(std::set<std::string> &nets, std::string src_tile, std::string src_name, std::string dst_tile, std::string dst_name, IdString src_type, IdString dst_type) void add_net(std::set<std::string> &nets, std::string src_tile, std::string src_name, std::string dst_tile,
std::string dst_name, IdString src_type, IdString dst_type)
{ {
if (src_type.in(ctx->id("LUT_PERMUTATION_WIRE"), ctx->id("MUX_WIRE"), ctx->id("INTERCONNECT_INPUT"))) return; if (src_type.in(ctx->id("LUT_PERMUTATION_WIRE"), ctx->id("MUX_WIRE"), ctx->id("INTERCONNECT_INPUT")))
if (boost::starts_with(src_type.c_str(ctx),"CROSSBAR_") && boost::ends_with(src_type.c_str(ctx),"INPUT_WIRE")) return; return;
if (boost::starts_with(src_type.c_str(ctx), "CROSSBAR_") && boost::ends_with(src_type.c_str(ctx), "INPUT_WIRE"))
return;
if (dst_type == ctx->id("MUX_WIRE")) if (dst_type == ctx->id("MUX_WIRE"))
dst_name = dst_name.substr(0, dst_name.rfind('.')); dst_name = dst_name.substr(0, dst_name.rfind('.'));
src_name = update_name(src_tile, src_name); src_name = update_name(src_tile, src_name);
@ -125,8 +127,10 @@ struct BitstreamJsonBackend
bool first_net = true; bool first_net = true;
for (auto &net : ctx->nets) { for (auto &net : ctx->nets) {
NetInfo *ni = net.second.get(); NetInfo *ni = net.second.get();
if (ni->wires.empty()) continue; if (ni->wires.empty())
out << (first_net ? "" : ",\n"); first_net = false; continue;
out << (first_net ? "" : ",\n");
first_net = false;
out << stringf("\t\t%s: [\n", get_string(cleanup_name(ni->name.c_str(ctx))).c_str()); out << stringf("\t\t%s: [\n", get_string(cleanup_name(ni->name.c_str(ctx))).c_str());
std::set<std::string> nets; std::set<std::string> nets;
for (auto &w : ni->wires) { for (auto &w : ni->wires) {
@ -139,7 +143,8 @@ struct BitstreamJsonBackend
IdString src_type = ctx->getWireType(swire); IdString src_type = ctx->getWireType(swire);
IdString src_orig = IdString(chip_tile_info(ctx->chip_info, pip.tile).wires[pd.src_wire].name); IdString src_orig = IdString(chip_tile_info(ctx->chip_info, pip.tile).wires[pd.src_wire].name);
IdString src_orig_type = IdString(chip_tile_info(ctx->chip_info, pip.tile).wires[pd.src_wire].wire_type); IdString src_orig_type =
IdString(chip_tile_info(ctx->chip_info, pip.tile).wires[pd.src_wire].wire_type);
WireId dwire = ctx->getPipDstWire(pip); WireId dwire = ctx->getPipDstWire(pip);
IdString dst = ctx->getWireName(dwire)[1]; IdString dst = ctx->getWireName(dwire)[1];
@ -149,9 +154,13 @@ struct BitstreamJsonBackend
std::string tile_name = uarch->tile_name(pip.tile); std::string tile_name = uarch->tile_name(pip.tile);
if (src_orig != src) if (src_orig != src)
add_net(nets, s_tile_name, src.c_str(ctx), tile_name, src_orig.c_str(ctx), src_type, src_orig_type); add_net(nets, s_tile_name, src.c_str(ctx), tile_name, src_orig.c_str(ctx), src_type,
if (!extra_data.name || (extra_data.type != PipExtra::PIP_EXTRA_BYPASS && extra_data.type != PipExtra::PIP_EXTRA_VIRTUAL && extra_data.type != PipExtra::PIP_EXTRA_MUX)) src_orig_type);
add_net(nets, tile_name, src_orig.c_str(ctx), tile_name, dst.c_str(ctx), src_orig_type, dst_type); if (!extra_data.name ||
(extra_data.type != PipExtra::PIP_EXTRA_BYPASS &&
extra_data.type != PipExtra::PIP_EXTRA_VIRTUAL && extra_data.type != PipExtra::PIP_EXTRA_MUX))
add_net(nets, tile_name, src_orig.c_str(ctx), tile_name, dst.c_str(ctx), src_orig_type,
dst_type);
} else if (ni->wires.size() == 1) { } else if (ni->wires.size() == 1) {
IdString src = ctx->getWireName(w.first)[1]; IdString src = ctx->getWireName(w.first)[1];
IdString src_type = ctx->getWireType(w.first); IdString src_type = ctx->getWireType(w.first);
@ -159,7 +168,8 @@ struct BitstreamJsonBackend
for (auto &u : ni->users) { for (auto &u : ni->users) {
std::string tile_name = uarch->tile_name(u.cell->bel.tile); std::string tile_name = uarch->tile_name(u.cell->bel.tile);
IdString bel_name = ctx->getBelName(u.cell->bel)[1]; IdString bel_name = ctx->getBelName(u.cell->bel)[1];
add_net(nets, s_tile_name, src.c_str(ctx), tile_name, stringf("%s.%s", bel_name.c_str(ctx), u.port.c_str(ctx)), src_type, src_type); add_net(nets, s_tile_name, src.c_str(ctx), tile_name,
stringf("%s.%s", bel_name.c_str(ctx), u.port.c_str(ctx)), src_type, src_type);
} }
} }
} }
@ -206,7 +216,8 @@ struct BitstreamJsonBackend
} }
}; };
template <typename KeyType> std::string extract_bits_or_default(const dict<KeyType, Property> &ct, const KeyType &key, int bits, int def = 0) template <typename KeyType>
std::string extract_bits_or_default(const dict<KeyType, Property> &ct, const KeyType &key, int bits, int def = 0)
{ {
Property extr = get_or_default(ct, key, Property()).extract(0, bits); Property extr = get_or_default(ct, key, Property()).extract(0, bits);
std::string str = extr.str; std::string str = extr.str;
@ -218,8 +229,10 @@ struct BitstreamJsonBackend
void open_instance(CellInfo *cell, std::string rename = "") void open_instance(CellInfo *cell, std::string rename = "")
{ {
out << stringf("%s", first_instance ? "" : ",\n"); first_instance = false; out << stringf("%s", first_instance ? "" : ",\n");
out << stringf("\t\t%s: {\n", get_string(cleanup_name(rename.empty() ? cell->name.c_str(ctx) : rename.c_str())).c_str()); first_instance = false;
out << stringf("\t\t%s: {\n",
get_string(cleanup_name(rename.empty() ? cell->name.c_str(ctx) : rename.c_str())).c_str());
std::string tile_name = uarch->tile_name(cell->bel.tile); std::string tile_name = uarch->tile_name(cell->bel.tile);
IdString idx = ctx->getBelName(cell->bel)[1]; IdString idx = ctx->getBelName(cell->bel)[1];
std::string belname = idx.c_str(ctx); std::string belname = idx.c_str(ctx);
@ -230,7 +243,8 @@ struct BitstreamJsonBackend
void open_instance_fe(CellInfo *cell, std::string type, std::string replace, std::string postfix = "") void open_instance_fe(CellInfo *cell, std::string type, std::string replace, std::string postfix = "")
{ {
out << stringf("%s", first_instance ? "" : ",\n"); first_instance = false; out << stringf("%s", first_instance ? "" : ",\n");
first_instance = false;
out << stringf("\t\t%s: {\n", get_string(cleanup_name(cell->name.c_str(ctx)) + postfix).c_str()); out << stringf("\t\t%s: {\n", get_string(cleanup_name(cell->name.c_str(ctx)) + postfix).c_str());
std::string tile_name = uarch->tile_name(cell->bel.tile); std::string tile_name = uarch->tile_name(cell->bel.tile);
IdString idx = ctx->getBelName(cell->bel)[1]; IdString idx = ctx->getBelName(cell->bel)[1];
@ -256,20 +270,24 @@ struct BitstreamJsonBackend
config.push_back(stringf("\t\t\t\t%s:%s", get_string(name).c_str(), get_string(val).c_str())); config.push_back(stringf("\t\t\t\t%s:%s", get_string(name).c_str(), get_string(val).c_str()));
} }
void close_instance() { void close_instance()
{
bool first = true; bool first = true;
if (!config.empty()) out << ",\n\t\t\t\"config\": {\n"; if (!config.empty())
out << ",\n\t\t\t\"config\": {\n";
for (auto &str : config) { for (auto &str : config) {
out << (first ? "" : ",\n"); out << (first ? "" : ",\n");
out << str.c_str(); out << str.c_str();
first = false; first = false;
} }
if (!config.empty()) out << "\n\t\t\t}"; if (!config.empty())
out << "\n\t\t\t}";
out << "\n\t\t}"; out << "\n\t\t}";
config.clear(); config.clear();
} }
void write_iop(CellInfo *cell) { void write_iop(CellInfo *cell)
{
open_instance(cell, str_or_default(cell->params, id_iobname, "")); open_instance(cell, str_or_default(cell->params, id_iobname, ""));
add_config("location", str_or_default(cell->params, id_location, "")); add_config("location", str_or_default(cell->params, id_location, ""));
add_config("differential", str_or_n_value_lower(cell->params, id_differential, "false")); add_config("differential", str_or_n_value_lower(cell->params, id_differential, "false"));
@ -302,7 +320,8 @@ struct BitstreamJsonBackend
} }
} }
void write_ddfr(CellInfo *cell) { void write_ddfr(CellInfo *cell)
{
open_instance(cell); open_instance(cell);
add_config("dff_load", bool_or_default(cell->params, id_dff_load, false)); add_config("dff_load", bool_or_default(cell->params, id_dff_load, false));
add_config("dff_sync", bool_or_default(cell->params, id_dff_sync, false)); add_config("dff_sync", bool_or_default(cell->params, id_dff_sync, false));
@ -312,7 +331,8 @@ struct BitstreamJsonBackend
close_instance(); close_instance();
} }
void write_dfr(CellInfo *cell) { void write_dfr(CellInfo *cell)
{
open_instance(cell); open_instance(cell);
add_config("data_inv", bool_or_default(cell->params, id_data_inv, false)); add_config("data_inv", bool_or_default(cell->params, id_data_inv, false));
add_config("dff_edge", bool_or_default(cell->params, id_dff_edge, false)); add_config("dff_edge", bool_or_default(cell->params, id_dff_edge, false));
@ -325,7 +345,8 @@ struct BitstreamJsonBackend
close_instance(); close_instance();
} }
void write_bfr(CellInfo *cell) { void write_bfr(CellInfo *cell)
{
open_instance(cell); open_instance(cell);
add_config("mode", int_or_default(cell->params, id_mode, 2)); add_config("mode", int_or_default(cell->params, id_mode, 2));
add_config("iobname", str_or_default(cell->params, id_iobname, "")); add_config("iobname", str_or_default(cell->params, id_iobname, ""));
@ -335,14 +356,16 @@ struct BitstreamJsonBackend
close_instance(); close_instance();
} }
void write_cy(CellInfo *cell) { void write_cy(CellInfo *cell)
{
open_instance(cell); open_instance(cell);
add_config("add_carry", int_or_default(cell->params, id_add_carry, 0)); add_config("add_carry", int_or_default(cell->params, id_add_carry, 0));
add_config("shifter", bool_or_default(cell->params, id_shifter, false)); add_config("shifter", bool_or_default(cell->params, id_shifter, false));
close_instance(); close_instance();
} }
void write_fe(CellInfo *cell) { void write_fe(CellInfo *cell)
{
if (bool_or_default(cell->params, id_lut_used)) { if (bool_or_default(cell->params, id_lut_used)) {
open_instance_fe(cell, "LUT", ".LUT"); open_instance_fe(cell, "LUT", ".LUT");
add_config("lut_table", extract_bits_or_default(cell->params, id_lut_table, 16)); add_config("lut_table", extract_bits_or_default(cell->params, id_lut_table, 16));
@ -363,19 +386,22 @@ struct BitstreamJsonBackend
} }
} }
void write_xlut(CellInfo *cell) { void write_xlut(CellInfo *cell)
{
open_instance(cell); open_instance(cell);
add_config("lut_table", extract_bits_or_default(cell->params, id_lut_table, 16)); add_config("lut_table", extract_bits_or_default(cell->params, id_lut_table, 16));
close_instance(); close_instance();
} }
void write_iom(CellInfo *cell) { void write_iom(CellInfo *cell)
{
open_instance(cell); open_instance(cell);
add_config("pads_path", str_or_default(cell->params, id_pads_path, ";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;")); add_config("pads_path", str_or_default(cell->params, id_pads_path, ";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;"));
close_instance(); close_instance();
} }
void write_gck(CellInfo *cell) { void write_gck(CellInfo *cell)
{
open_instance(cell); open_instance(cell);
add_config("inv_in", bool_or_default(cell->params, id_inv_in, false)); add_config("inv_in", bool_or_default(cell->params, id_inv_in, false));
add_config("inv_out", bool_or_default(cell->params, id_inv_out, false)); add_config("inv_out", bool_or_default(cell->params, id_inv_out, false));
@ -383,7 +409,8 @@ struct BitstreamJsonBackend
close_instance(); close_instance();
} }
void write_wfb(CellInfo *cell) { void write_wfb(CellInfo *cell)
{
open_instance(cell); open_instance(cell);
add_config("delay_on", bool_or_default(cell->params, id_delay_on, false)); add_config("delay_on", bool_or_default(cell->params, id_delay_on, false));
add_config("delay", int_or_default(cell->params, id_delay, 0)); add_config("delay", int_or_default(cell->params, id_delay, 0));
@ -391,7 +418,8 @@ struct BitstreamJsonBackend
close_instance(); close_instance();
} }
void write_wfg(CellInfo *cell) { void write_wfg(CellInfo *cell)
{
open_instance(cell); open_instance(cell);
add_config("mode", int_or_default(cell->params, id_mode, 0)); add_config("mode", int_or_default(cell->params, id_mode, 0));
add_config("delay_on", bool_or_default(cell->params, id_delay_on, false)); add_config("delay_on", bool_or_default(cell->params, id_delay_on, false));
@ -407,7 +435,8 @@ struct BitstreamJsonBackend
close_instance(); close_instance();
} }
void write_pll(CellInfo *cell) { void write_pll(CellInfo *cell)
{
open_instance(cell); open_instance(cell);
add_config("clk_outdiv1", extract_bits_or_default(cell->params, id_clk_outdiv1, 3)); add_config("clk_outdiv1", extract_bits_or_default(cell->params, id_clk_outdiv1, 3));
add_config("clk_outdiv2", extract_bits_or_default(cell->params, id_clk_outdiv2, 3)); add_config("clk_outdiv2", extract_bits_or_default(cell->params, id_clk_outdiv2, 3));
@ -437,15 +466,18 @@ struct BitstreamJsonBackend
close_instance(); close_instance();
} }
void write_rfb(CellInfo *cell) { void write_rfb(CellInfo *cell)
{
open_instance(cell); open_instance(cell);
std::string context = str_or_default(cell->params, id_mem_ctxt, ""); std::string context = str_or_default(cell->params, id_mem_ctxt, "");
if (!context.empty()) add_config("mem_ctxt", context); if (!context.empty())
add_config("mem_ctxt", context);
add_config("wck_edge", bool_or_default(cell->params, id_wck_edge, false)); add_config("wck_edge", bool_or_default(cell->params, id_wck_edge, false));
close_instance(); close_instance();
} }
void write_ram(CellInfo *cell) { void write_ram(CellInfo *cell)
{
open_instance(cell); open_instance(cell);
add_config("mcka_edge", bool_or_default(cell->params, id_mcka_edge, false)); add_config("mcka_edge", bool_or_default(cell->params, id_mcka_edge, false));
add_config("mckb_edge", bool_or_default(cell->params, id_mckb_edge, false)); add_config("mckb_edge", bool_or_default(cell->params, id_mckb_edge, false));
@ -454,11 +486,13 @@ struct BitstreamJsonBackend
add_config("raw_config0", extract_bits_or_default(cell->params, id_raw_config0, 4)); add_config("raw_config0", extract_bits_or_default(cell->params, id_raw_config0, 4));
add_config("raw_config1", extract_bits_or_default(cell->params, id_raw_config1, 16)); add_config("raw_config1", extract_bits_or_default(cell->params, id_raw_config1, 16));
std::string context = str_or_default(cell->params, id_mem_ctxt, ""); std::string context = str_or_default(cell->params, id_mem_ctxt, "");
if (!context.empty()) add_config("mem_ctxt", context); if (!context.empty())
add_config("mem_ctxt", context);
close_instance(); close_instance();
} }
void write_dsp(CellInfo *cell) { void write_dsp(CellInfo *cell)
{
open_instance(cell); open_instance(cell);
add_config("raw_config0", extract_bits_or_default(cell->params, id_raw_config0, 27)); add_config("raw_config0", extract_bits_or_default(cell->params, id_raw_config0, 27));
add_config("raw_config1", extract_bits_or_default(cell->params, id_raw_config1, 24)); add_config("raw_config1", extract_bits_or_default(cell->params, id_raw_config1, 24));
@ -467,7 +501,8 @@ struct BitstreamJsonBackend
close_instance(); close_instance();
} }
void write_cdc(CellInfo *cell) { void write_cdc(CellInfo *cell)
{
open_instance(cell); open_instance(cell);
if (cell->type.in(id_DDE, id_TDE, id_CDC, id_XCDC)) { if (cell->type.in(id_DDE, id_TDE, id_CDC, id_XCDC)) {
add_config("ck0_edge", bool_or_default(cell->params, id_ck0_edge, false)); add_config("ck0_edge", bool_or_default(cell->params, id_ck0_edge, false));
@ -495,7 +530,8 @@ struct BitstreamJsonBackend
close_instance(); close_instance();
} }
void write_fifo(CellInfo *cell) { void write_fifo(CellInfo *cell)
{
open_instance(cell); open_instance(cell);
add_config("rck_edge", bool_or_default(cell->params, id_rck_edge, false)); add_config("rck_edge", bool_or_default(cell->params, id_rck_edge, false));
add_config("wck_edge", bool_or_default(cell->params, id_wck_edge, false)); add_config("wck_edge", bool_or_default(cell->params, id_wck_edge, false));
@ -511,13 +547,15 @@ struct BitstreamJsonBackend
{ {
for (auto &net : ctx->nets) { for (auto &net : ctx->nets) {
NetInfo *ni = net.second.get(); NetInfo *ni = net.second.get();
if (ni->wires.size()==0) continue; if (ni->wires.size() == 0)
continue;
std::vector<std::string> nets; std::vector<std::string> nets;
for (auto &w : ni->wires) { for (auto &w : ni->wires) {
if (w.second.pip != PipId()) { if (w.second.pip != PipId()) {
PipId pip = w.second.pip; PipId pip = w.second.pip;
const auto &extra_data = *uarch->pip_extra_data(w.second.pip); const auto &extra_data = *uarch->pip_extra_data(w.second.pip);
if (!extra_data.name || extra_data.type != PipExtra::PIP_EXTRA_INTERCONNECT) continue; if (!extra_data.name || extra_data.type != PipExtra::PIP_EXTRA_INTERCONNECT)
continue;
auto &pd = chip_pip_info(ctx->chip_info, pip); auto &pd = chip_pip_info(ctx->chip_info, pip);
IdString src = IdString(chip_tile_info(ctx->chip_info, pip.tile).wires[pd.src_wire].name); IdString src = IdString(chip_tile_info(ctx->chip_info, pip.tile).wires[pd.src_wire].name);
std::string tile_name = uarch->tile_name(pip.tile); std::string tile_name = uarch->tile_name(pip.tile);
@ -525,8 +563,10 @@ struct BitstreamJsonBackend
std::string type = "OTC"; std::string type = "OTC";
if (src_name.find("UI1x") != std::string::npos) if (src_name.find("UI1x") != std::string::npos)
type = "ITC"; type = "ITC";
if (boost::starts_with(src_name,"SO1.")) type = "OTS"; if (boost::starts_with(src_name, "SO1."))
if (boost::starts_with(src_name,"SI1.")) type = "ITS"; type = "OTS";
if (boost::starts_with(src_name, "SI1."))
type = "ITS";
src_name = update_name(tile_name, src_name); src_name = update_name(tile_name, src_name);
src_name = src_name.substr(0, src_name.size() - 2); src_name = src_name.substr(0, src_name.size() - 2);
@ -545,46 +585,81 @@ struct BitstreamJsonBackend
first_instance = true; first_instance = true;
for (auto &cell : ctx->cells) { for (auto &cell : ctx->cells) {
switch (cell.second->type.index) { switch (cell.second->type.index) {
case id_BEYOND_FE.index: write_fe(cell.second.get()); break; case id_BEYOND_FE.index:
write_fe(cell.second.get());
break;
case id_IOP.index: case id_IOP.index:
case id_IP.index: case id_IP.index:
case id_OP.index: case id_OP.index:
case id_IOTP.index: case id_IOTP.index:
case id_ITP.index: case id_ITP.index:
case id_OTP.index: write_iop(cell.second.get()); break; case id_OTP.index:
case id_CY.index: write_cy(cell.second.get()); break; write_iop(cell.second.get());
case id_WFB.index: write_wfb(cell.second.get()); break; break;
case id_WFG.index: write_wfg(cell.second.get()); break; case id_CY.index:
case id_GCK.index: write_gck(cell.second.get()); break; write_cy(cell.second.get());
case id_IOM.index: write_iom(cell.second.get()); break; break;
case id_BFR.index: write_bfr(cell.second.get()); break; case id_WFB.index:
case id_DDFR.index: write_ddfr(cell.second.get()); break; write_wfb(cell.second.get());
case id_DFR.index: write_dfr(cell.second.get()); break; break;
case id_RAM.index: write_ram(cell.second.get()); break; case id_WFG.index:
write_wfg(cell.second.get());
break;
case id_GCK.index:
write_gck(cell.second.get());
break;
case id_IOM.index:
write_iom(cell.second.get());
break;
case id_BFR.index:
write_bfr(cell.second.get());
break;
case id_DDFR.index:
write_ddfr(cell.second.get());
break;
case id_DFR.index:
write_dfr(cell.second.get());
break;
case id_RAM.index:
write_ram(cell.second.get());
break;
case id_RF.index: case id_RF.index:
case id_RFSP.index: case id_RFSP.index:
case id_XHRF.index: case id_XHRF.index:
case id_XWRF.index: case id_XWRF.index:
case id_XPRF.index: write_rfb(cell.second.get()); break; case id_XPRF.index:
case id_XLUT.index: write_xlut(cell.second.get()); break; write_rfb(cell.second.get());
break;
case id_XLUT.index:
write_xlut(cell.second.get());
break;
case id_FIFO.index: // mode 0 case id_FIFO.index: // mode 0
case id_XHFIFO.index: // mode 1 case id_XHFIFO.index: // mode 1
case id_XWFIFO.index: write_fifo(cell.second.get()); break; // mode 2 case id_XWFIFO.index:
write_fifo(cell.second.get());
break; // mode 2
case id_DDE.index: // mode 0 case id_DDE.index: // mode 0
case id_TDE.index: // mode 1 case id_TDE.index: // mode 1
case id_CDC.index: // mode 2 case id_CDC.index: // mode 2
case id_BGC.index: // mode 3 case id_BGC.index: // mode 3
case id_GBC.index: // mode 4 case id_GBC.index: // mode 4
case id_XCDC.index: write_cdc(cell.second.get()); break; // mode 5 case id_XCDC.index:
case id_DSP.index: write_dsp(cell.second.get()); break; write_cdc(cell.second.get());
case id_PLL.index: write_pll(cell.second.get()); break; break; // mode 5
case id_DSP.index:
write_dsp(cell.second.get());
break;
case id_PLL.index:
write_pll(cell.second.get());
break;
// case id_CRX.index: // case id_CRX.index:
// case id_CTX.index: // case id_CTX.index:
// case id_PMA.index: // case id_PMA.index:
// case id_Service.index: // case id_Service.index:
// case id_SOCIF.index: // case id_SOCIF.index:
default: default:
log_error("Unhandled cell %s of type %s\n", cell.second.get()->name.c_str(ctx), cell.second->type.c_str(ctx)); log_error("Unhandled cell %s of type %s\n", cell.second.get()->name.c_str(ctx),
cell.second->type.c_str(ctx));
} }
} }
write_interconnections(); write_interconnections();

View File

@ -83,8 +83,7 @@ void NgUltraImpl::parse_csv(const std::string &filename)
if (arguments.empty()) if (arguments.empty())
continue; continue;
switch (line_type) { switch (line_type) {
case IO_PADS: case IO_PADS: {
{
if (arguments.size() == 1 && arguments[0][0] == '!') { if (arguments.size() == 1 && arguments[0][0] == '!') {
line_type = IO_BANKS; line_type = IO_BANKS;
continue; continue;
@ -126,14 +125,16 @@ void NgUltraImpl::parse_csv(const std::string &filename)
// End of block // End of block
if (!(boost::starts_with(arg_location, "IOB") && boost::contains(arg_location, "_D"))) if (!(boost::starts_with(arg_location, "IOB") && boost::contains(arg_location, "_D")))
log_error("invalid location name '%s' must start with 'IOB' in line %d\n", arg_location.c_str(), lineno); log_error("invalid location name '%s' must start with 'IOB' in line %d\n", arg_location.c_str(),
lineno);
const std::vector<std::string> standard_values = {"LVDS", "LVCMOS", "SSTL", "HSTL"}; // , "POD" const std::vector<std::string> standard_values = {"LVDS", "LVCMOS", "SSTL", "HSTL"}; // , "POD"
auto it = std::find(std::begin(standard_values), std::end(standard_values), arg_standard); auto it = std::find(std::begin(standard_values), std::end(standard_values), arg_standard);
if (it == std::end(standard_values)) if (it == std::end(standard_values))
log_error("unknown standard value '%s' in line %d\n", arg_standard.c_str(), lineno); log_error("unknown standard value '%s' in line %d\n", arg_standard.c_str(), lineno);
const std::vector<std::string> drive_values = { "2mA", "4mA", "8mA", "16mA", "CatI", "CatII", "Undefined" }; // "6mA", "12mA", const std::vector<std::string> drive_values = {"2mA", "4mA", "8mA", "16mA",
"CatI", "CatII", "Undefined"}; // "6mA", "12mA",
it = std::find(std::begin(drive_values), std::end(drive_values), arg_drive); it = std::find(std::begin(drive_values), std::end(drive_values), arg_drive);
if (it == std::end(drive_values)) if (it == std::end(drive_values))
log_error("unknown drive value '%s' in line %d\n", arg_drive.c_str(), lineno); log_error("unknown drive value '%s' in line %d\n", arg_drive.c_str(), lineno);
@ -168,7 +169,8 @@ void NgUltraImpl::parse_csv(const std::string &filename)
if (!arg_termination.empty()) { if (!arg_termination.empty()) {
if (!is_number(arg_termination)) { if (!is_number(arg_termination)) {
log_error("termination must be string containing int, value '%s' in line %d\n", arg_termination.c_str(), lineno); log_error("termination must be string containing int, value '%s' in line %d\n",
arg_termination.c_str(), lineno);
} else { } else {
int termination = std::stoi(arg_termination); int termination = std::stoi(arg_termination);
if (termination < 30 || termination > 80) if (termination < 30 || termination > 80)
@ -179,7 +181,8 @@ void NgUltraImpl::parse_csv(const std::string &filename)
const std::vector<std::string> termref_values = {"Floating", "VT"}; const std::vector<std::string> termref_values = {"Floating", "VT"};
it = std::find(std::begin(termref_values), std::end(termref_values), arg_terminationReference); it = std::find(std::begin(termref_values), std::end(termref_values), arg_terminationReference);
if (it == std::end(termref_values)) if (it == std::end(termref_values))
log_error("unknown termination reference value '%s' in line %d\n", arg_terminationReference.c_str(), lineno); log_error("unknown termination reference value '%s' in line %d\n", arg_terminationReference.c_str(),
lineno);
if (!arg_turbo.empty() && arg_turbo != "True" && arg_turbo != "False") if (!arg_turbo.empty() && arg_turbo != "True" && arg_turbo != "False")
log_error("turbo must be boolean, value '%s' in line %d\n", arg_turbo.c_str(), lineno); log_error("turbo must be boolean, value '%s' in line %d\n", arg_turbo.c_str(), lineno);
@ -187,7 +190,8 @@ void NgUltraImpl::parse_csv(const std::string &filename)
if (!arg_inputSignalSlope.empty() && !is_number(arg_inputSignalSlope)) if (!arg_inputSignalSlope.empty() && !is_number(arg_inputSignalSlope))
log_error("signal slope must be number, value '%s' in line %d\n", arg_inputSignalSlope.c_str(), lineno); log_error("signal slope must be number, value '%s' in line %d\n", arg_inputSignalSlope.c_str(), lineno);
if (!arg_outputCapacity.empty() && !is_number(arg_outputCapacity)) if (!arg_outputCapacity.empty() && !is_number(arg_outputCapacity))
log_error("output capacity must be number, value '%s' in line %d\n", arg_outputCapacity.c_str(), lineno); log_error("output capacity must be number, value '%s' in line %d\n", arg_outputCapacity.c_str(),
lineno);
const std::vector<std::string> registered_values = {"Auto", "I", "IC", "O", "OC", "IO", "IOC"}; const std::vector<std::string> registered_values = {"Auto", "I", "IC", "O", "OC", "IO", "IOC"};
it = std::find(std::begin(registered_values), std::end(registered_values), arg_registered); it = std::find(std::begin(registered_values), std::end(registered_values), arg_registered);
@ -199,12 +203,15 @@ void NgUltraImpl::parse_csv(const std::string &filename)
if (arg_standard == "LVCMOS" && !boost::ends_with(arg_drive, "mA")) if (arg_standard == "LVCMOS" && !boost::ends_with(arg_drive, "mA"))
log_error("for port in line %d when standard is 'LVCMOS' drive current must be in mA\n", lineno); log_error("for port in line %d when standard is 'LVCMOS' drive current must be in mA\n", lineno);
if ((arg_standard == "SSTL" || arg_standard == "HSTL") && !boost::starts_with(arg_drive, "Cat")) if ((arg_standard == "SSTL" || arg_standard == "HSTL") && !boost::starts_with(arg_drive, "Cat"))
log_error("for port in line %d when standard is 'SSTL' or 'HSTL' drive current must be in 'CatI' or 'CatII'\n", lineno); log_error("for port in line %d when standard is 'SSTL' or 'HSTL' drive current must be in 'CatI' or "
"'CatII'\n",
lineno);
if (arg_terminationReference == "Floating") { if (arg_terminationReference == "Floating") {
if (!(arg_differential == "True" && arg_weakTermination == "None")) { if (!(arg_differential == "True" && arg_weakTermination == "None")) {
log_error("for floating termination, differential myst be 'True' and weakTermination must be 'None' in line %d\n", lineno); log_error("for floating termination, differential myst be 'True' and weakTermination must be "
"'None' in line %d\n",
lineno);
} }
} }
std::vector<CellInfo *> dest = get_cells(arg_iobname); std::vector<CellInfo *> dest = get_cells(arg_iobname);
@ -234,10 +241,8 @@ void NgUltraImpl::parse_csv(const std::string &filename)
std::string bank_name = arg_location.substr(0, arg_location.find_first_of('_')); std::string bank_name = arg_location.substr(0, arg_location.find_first_of('_'));
banks_used.emplace(bank_name); banks_used.emplace(bank_name);
} } break;
break; case IO_BANKS: {
case IO_BANKS:
{
if (arguments.size() == 1 && arguments[0][0] == '!') { if (arguments.size() == 1 && arguments[0][0] == '!') {
line_type = IO_GCKS; line_type = IO_GCKS;
continue; continue;
@ -262,32 +267,29 @@ void NgUltraImpl::parse_csv(const std::string &filename)
case 0: case 0:
case 1: case 1:
case 6: case 6:
case 7: case 7: {
{
auto it = std::find(std::begin(direct_io_voltages), std::end(direct_io_voltages), arguments.at(1)); auto it = std::find(std::begin(direct_io_voltages), std::end(direct_io_voltages), arguments.at(1));
if (it == std::end(direct_io_voltages)) if (it == std::end(direct_io_voltages))
log_error("unsupported voltage level '%s' for bank '%s'\n", arguments.at(1).c_str(), arguments.at(0).c_str()); log_error("unsupported voltage level '%s' for bank '%s'\n", arguments.at(1).c_str(),
} arguments.at(0).c_str());
break; } break;
// complex // complex
default: default:
auto it = std::find(std::begin(complex_io_voltages), std::end(complex_io_voltages), arguments.at(1)); auto it = std::find(std::begin(complex_io_voltages), std::end(complex_io_voltages), arguments.at(1));
if (it == std::end(complex_io_voltages)) if (it == std::end(complex_io_voltages))
log_error("unsupported voltage level '%s' for bank '%s'\n", arguments.at(1).c_str(), arguments.at(0).c_str()); log_error("unsupported voltage level '%s' for bank '%s'\n", arguments.at(1).c_str(),
arguments.at(0).c_str());
} }
bank_voltage[arguments.at(0)] = arguments.at(1); bank_voltage[arguments.at(0)] = arguments.at(1);
} } break;
break; case IO_GCKS: {
case IO_GCKS:
{
if (arguments.size() == 1 && arguments[0][0] == '!') { if (arguments.size() == 1 && arguments[0][0] == '!') {
line_type = IO_ERROR; line_type = IO_ERROR;
continue; continue;
} }
if (arguments.size() != 2) if (arguments.size() != 2)
log_error("number of parameters in line %d must be 2\n", lineno); log_error("number of parameters in line %d must be 2\n", lineno);
} } break;
break;
default: default:
log_error("switching to unknown block of data in line %d\n", lineno); log_error("switching to unknown block of data in line %d\n", lineno);
} }

View File

@ -40,8 +40,15 @@ NPNR_PACKED_STRUCT(struct NGUltraPipExtraDataPOD {
NPNR_PACKED_STRUCT(struct NGUltraBelExtraDataPOD { int32_t flags; }); NPNR_PACKED_STRUCT(struct NGUltraBelExtraDataPOD { int32_t flags; });
struct GckConfig { struct GckConfig
explicit GckConfig(BelId belid) { bel = belid; si1 = IdString(); si2 = IdString(); used = false; } {
explicit GckConfig(BelId belid)
{
bel = belid;
si1 = IdString();
si2 = IdString();
used = false;
}
BelId bel; BelId bel;
IdString si1; IdString si1;
IdString si2; IdString si2;

View File

@ -55,8 +55,7 @@ const Loc ng_ultra_place_cy_map[24] = {
{0, -1, 0}, // S10 3 -> S9 3 CY12->CY13 {0, -1, 0}, // S10 3 -> S9 3 CY12->CY13
}; };
const Loc ng_ultra_place_xrf[] = const Loc ng_ultra_place_xrf[] = {
{
{-1, 0, 1}, // I/O1 {-1, 0, 1}, // I/O1
{-1, 0, 2}, // I/O2 {-1, 0, 2}, // I/O2
{-1, 0, 5}, // I/O3 {-1, 0, 5}, // I/O3
@ -120,8 +119,7 @@ const Loc ng_ultra_place_xrf[] =
}; };
const Loc ng_ultra_place_cdc1[] = const Loc ng_ultra_place_cdc1[] = {
{
{+1, 0, 1}, // AI1 {+1, 0, 1}, // AI1
{+1, 0, 2}, // AI2 {+1, 0, 2}, // AI2
{+1, 0, 9}, // AI3 {+1, 0, 9}, // AI3
@ -142,8 +140,7 @@ const Loc ng_ultra_place_cdc1[] =
{+1, 0, 8}, // BDRSTI {+1, 0, 8}, // BDRSTI
}; };
const Loc ng_ultra_place_cdc2[] = const Loc ng_ultra_place_cdc2[] = {
{
{-1, 0, 4}, // AI1 {-1, 0, 4}, // AI1
{-1, 0, 5}, // AI2 {-1, 0, 5}, // AI2
{-1, 0, 12}, // AI3 {-1, 0, 12}, // AI3
@ -164,8 +161,7 @@ const Loc ng_ultra_place_cdc2[] =
{-1, 0, 7}, // BDRSTI {-1, 0, 7}, // BDRSTI
}; };
const Loc ng_ultra_place_xcdc[] = const Loc ng_ultra_place_xcdc[] = {
{
{0, 0, 1}, // AI1 {0, 0, 1}, // AI1
{0, 0, 2}, // AI2 {0, 0, 2}, // AI2
{0, 0, 9}, // AI3 {0, 0, 9}, // AI3
@ -205,8 +201,7 @@ const Loc ng_ultra_place_xcdc[] =
{0, 0, 7}, // DDRSTI {0, 0, 7}, // DDRSTI
}; };
const Loc ng_ultra_place_fifo1[] = const Loc ng_ultra_place_fifo1[] = {
{
{-1, 0, 1}, // I/O1 {-1, 0, 1}, // I/O1
{-1, 0, 2}, // I/O2 {-1, 0, 2}, // I/O2
{-1, 0, 5}, // I/O3 {-1, 0, 5}, // I/O3
@ -285,8 +280,7 @@ const Loc ng_ultra_place_fifo1[] =
{0, 0, 0}, // REQ2 {0, 0, 0}, // REQ2
}; };
const Loc ng_ultra_place_fifo2[] = const Loc ng_ultra_place_fifo2[] = {
{
{+1, 0, 1}, // I/O1 {+1, 0, 1}, // I/O1
{+1, 0, 2}, // I/O2 {+1, 0, 2}, // I/O2
{+1, 0, 5}, // I/O3 {+1, 0, 5}, // I/O3
@ -365,8 +359,7 @@ const Loc ng_ultra_place_fifo2[] =
{0, 0, 0}, // REQ2 {0, 0, 0}, // REQ2
}; };
const Loc ng_ultra_place_xfifo[] = const Loc ng_ultra_place_xfifo[] = {
{
{-1, 0, 1}, // I/O1 {-1, 0, 1}, // I/O1
{-1, 0, 2}, // I/O2 {-1, 0, 2}, // I/O2
{-1, 0, 5}, // I/O3 {-1, 0, 5}, // I/O3
@ -450,7 +443,7 @@ const Loc ng_ultra_place_xfifo[] =
// {+1, 0, 28}, REQ2 // {+1, 0, 28}, REQ2
}; };
}; }; // namespace
namespace ng_ultra { namespace ng_ultra {
@ -497,7 +490,8 @@ Loc getNextLocInDFFChain(Loc loc)
return result; return result;
} }
int z = loc.z + 8; int z = loc.z + 8;
if (z>31) z++; if (z > 31)
z++;
result.z = z % 32; // BEL_LUT_Z is 0 result.z = z % 32; // BEL_LUT_Z is 0
return result; return result;
} }
@ -570,5 +564,5 @@ Loc getFIFOFE(Loc root, int pos)
return result; return result;
} }
}; }; // namespace ng_ultra
NEXTPNR_NAMESPACE_END NEXTPNR_NAMESPACE_END

View File

@ -37,7 +37,7 @@ Loc getXRFFE(Loc root, int pos);
Loc getCDCFE(Loc root, int pos); Loc getCDCFE(Loc root, int pos);
Loc getFIFOFE(Loc root, int pos); Loc getFIFOFE(Loc root, int pos);
}; }; // namespace ng_ultra
NEXTPNR_NAMESPACE_END NEXTPNR_NAMESPACE_END
#endif #endif

View File

@ -21,18 +21,18 @@
#include <fstream> #include <fstream>
#include <queue> #include <queue>
#include "himbaechel_api.h"
#include "design_utils.h" #include "design_utils.h"
#include "extra_data.h"
#include "himbaechel_api.h"
#include "log.h" #include "log.h"
#include "nextpnr.h" #include "nextpnr.h"
#include "util.h"
#include "extra_data.h"
#include "placer_heap.h" #include "placer_heap.h"
#include "util.h"
#include "himbaechel_helpers.h" #include "himbaechel_helpers.h"
#include "ng_ultra.h"
#include "location_map.h" #include "location_map.h"
#include "ng_ultra.h"
#define GEN_INIT_CONSTIDS #define GEN_INIT_CONSTIDS
#define HIMBAECHEL_CONSTIDS "uarch/ng-ultra/constids.inc" #define HIMBAECHEL_CONSTIDS "uarch/ng-ultra/constids.inc"
@ -68,8 +68,7 @@ void NgUltraImpl::init(Context *ctx)
for (const auto &item : ctx->getWireBelPins(pip_dst)) { for (const auto &item : ctx->getWireBelPins(pip_dst)) {
if (boost::contains(ctx->nameOfBel(item.bel), "WFG_C")) { if (boost::contains(ctx->nameOfBel(item.bel), "WFG_C")) {
unused_wfg[item.bel] = tile_name_id(item.bel.tile); unused_wfg[item.bel] = tile_name_id(item.bel.tile);
} } else if (boost::contains(ctx->nameOfBel(item.bel), "PLL")) {
else if (boost::contains(ctx->nameOfBel(item.bel),"PLL")) {
ckg.emplace(tile_name_id(item.bel.tile)); ckg.emplace(tile_name_id(item.bel.tile));
unused_pll[item.bel] = tile_name_id(item.bel.tile); unused_pll[item.bel] = tile_name_id(item.bel.tile);
} }
@ -77,7 +76,8 @@ void NgUltraImpl::init(Context *ctx)
} }
std::pair<IdString, IdString> p; std::pair<IdString, IdString> p;
p.first = *ckg.begin(); p.first = *ckg.begin();
if (ckg.size()==2) p.second = *(ckg.begin()++); if (ckg.size() == 2)
p.second = *(ckg.begin()++);
bank_to_ckg[bank] = p; bank_to_ckg[bank] = p;
} else if (ctx->getBelType(bel) == id_IOTP) { } else if (ctx->getBelType(bel) == id_IOTP) {
if (ctx->getBelName(bel)[1] == ctx->id("D08P_CLK.IOTP")) { if (ctx->getBelName(bel)[1] == ctx->id("D08P_CLK.IOTP")) {
@ -144,8 +144,7 @@ const dict<IdString,pool<IdString>> ring_clock_sinks = {
// CKG // CKG
{id_PLL, {id_CLK_CAL, id_FBK, id_REF}}, {id_PLL, {id_CLK_CAL, id_FBK, id_REF}},
{id_WFB, {id_ZI}}, {id_WFB, {id_ZI}},
{ id_WFG, { id_ZI }} {id_WFG, {id_ZI}}};
};
const dict<IdString, pool<IdString>> ring_over_tile_clock_sinks = { const dict<IdString, pool<IdString>> ring_over_tile_clock_sinks = {
// IOB // IOB
@ -171,17 +170,15 @@ const dict<IdString,pool<IdString>> ring_clock_source = {
{id_IOM, {id_CKO1, id_CKO2}}, {id_IOM, {id_CKO1, id_CKO2}},
{id_WFB, {id_ZO}}, {id_WFB, {id_ZO}},
{id_WFG, {id_ZO}}, {id_WFG, {id_ZO}},
{ id_PLL, { id_OSC, id_VCO, id_REFO, id_LDFO, {id_PLL,
id_CLK_DIV1, id_CLK_DIV2, id_CLK_DIV3, id_CLK_DIV4, {id_OSC, id_VCO, id_REFO, id_LDFO, id_CLK_DIV1, id_CLK_DIV2, id_CLK_DIV3, id_CLK_DIV4, id_CLK_DIVD1,
id_CLK_DIVD1, id_CLK_DIVD2, id_CLK_DIVD3, id_CLK_DIVD4, id_CLK_DIVD5, id_CLK_DIVD2, id_CLK_DIVD3, id_CLK_DIVD4, id_CLK_DIVD5, id_CLK_CAL_DIV}}};
id_CLK_CAL_DIV }}
};
// TUBE // TUBE
const dict<IdString, pool<IdString>> tube_clock_source = { const dict<IdString, pool<IdString>> tube_clock_source = {
{id_GCK, {id_SO}}, {id_GCK, {id_SO}},
}; };
}; }; // namespace
const dict<IdString, pool<IdString>> &NgUltraImpl::get_fabric_lowskew_sinks() { return fabric_lowskew_sinks; } const dict<IdString, pool<IdString>> &NgUltraImpl::get_fabric_lowskew_sinks() { return fabric_lowskew_sinks; }
@ -197,7 +194,8 @@ bool NgUltraImpl::is_ring_clock_sink(const PortRef &ref)
bool NgUltraImpl::is_ring_over_tile_clock_sink(const PortRef &ref) bool NgUltraImpl::is_ring_over_tile_clock_sink(const PortRef &ref)
{ {
return ring_over_tile_clock_sinks.count(ref.cell->type) && ring_over_tile_clock_sinks.at(ref.cell->type).count(ref.port); return ring_over_tile_clock_sinks.count(ref.cell->type) &&
ring_over_tile_clock_sinks.at(ref.cell->type).count(ref.port);
} }
bool NgUltraImpl::is_tube_clock_sink(const PortRef &ref) bool NgUltraImpl::is_tube_clock_sink(const PortRef &ref)
@ -236,10 +234,7 @@ IdString NgUltraImpl::tile_name_id(int tile) const
return IdString(data.name); return IdString(data.name);
} }
std::string NgUltraImpl::tile_name(int tile) const std::string NgUltraImpl::tile_name(int tile) const { return stringf("%s", tile_name_id(tile).c_str(ctx)); }
{
return stringf("%s", tile_name_id(tile).c_str(ctx));
}
int NgUltraImpl::tile_lobe(int tile) const int NgUltraImpl::tile_lobe(int tile) const
{ {
@ -264,7 +259,8 @@ bool NgUltraImpl::get_mux_data(WireId wire, uint8_t *value)
if (!ctx->getBoundPipNet(pip)) if (!ctx->getBoundPipNet(pip))
continue; continue;
const auto &extra_data = *pip_extra_data(pip); const auto &extra_data = *pip_extra_data(pip);
if (!extra_data.name) continue; if (!extra_data.name)
continue;
if (extra_data.type == PipExtra::PIP_EXTRA_MUX) { if (extra_data.type == PipExtra::PIP_EXTRA_MUX) {
*value = extra_data.input; *value = extra_data.input;
return true; return true;
@ -330,7 +326,8 @@ void NgUltraImpl::postRoute()
for (auto &w : ni->wires) { for (auto &w : ni->wires) {
if (w.second.pip != PipId()) { if (w.second.pip != PipId()) {
const auto &extra_data = *pip_extra_data(w.second.pip); const auto &extra_data = *pip_extra_data(w.second.pip);
if (!extra_data.name) continue; if (!extra_data.name)
continue;
if (extra_data.type == PipExtra::PIP_EXTRA_BYPASS) { if (extra_data.type == PipExtra::PIP_EXTRA_BYPASS) {
IdStringList id = ctx->getPipName(w.second.pip); IdStringList id = ctx->getPipName(w.second.pip);
BelId bel = ctx->getBelByName(IdStringList::concat(id[0], IdString(extra_data.name))); BelId bel = ctx->getBelByName(IdStringList::concat(id[0], IdString(extra_data.name)));
@ -338,7 +335,8 @@ void NgUltraImpl::postRoute()
if (!ctx->getBoundBelCell(bel)) { if (!ctx->getBoundBelCell(bel)) {
CellInfo *cell = ctx->createCell(ctx->id(ctx->nameOfBel(bel)), type); CellInfo *cell = ctx->createCell(ctx->id(ctx->nameOfBel(bel)), type);
ctx->bindBel(bel, cell, PlaceStrength::STRENGTH_FIXED); ctx->bindBel(bel, cell, PlaceStrength::STRENGTH_FIXED);
if (type==id_BEYOND_FE) fe_new++; if (type == id_BEYOND_FE)
fe_new++;
} }
CellInfo *cell = ctx->getBoundBelCell(bel); CellInfo *cell = ctx->getBoundBelCell(bel);
switch (type.index) { switch (type.index) {
@ -360,10 +358,12 @@ void NgUltraImpl::postRoute()
cell->params[id_lut_table] = Property(0xaaaa, 16); cell->params[id_lut_table] = Property(0xaaaa, 16);
} }
break; break;
case id_WFG.index : wfg_bypass++; case id_WFG.index:
wfg_bypass++;
cell->type = id_WFB; cell->type = id_WFB;
break; break;
case id_GCK.index : gck_bypass++; case id_GCK.index:
gck_bypass++;
cell->setParam(id_std_mode, extra_data.input == 0 ? Property("BYPASS") : Property("CSC")); cell->setParam(id_std_mode, extra_data.input == 0 ? Property("BYPASS") : Property("CSC"));
break; break;
default: default:
@ -402,7 +402,8 @@ void NgUltraImpl::postRoute()
if (!ctx->getBoundPipNet(pip)) if (!ctx->getBoundPipNet(pip))
continue; continue;
const auto &extra_data = *pip_extra_data(pip); const auto &extra_data = *pip_extra_data(pip);
if (!extra_data.name) continue; if (!extra_data.name)
continue;
if (extra_data.type == PipExtra::PIP_EXTRA_LUT_PERMUTATION) { if (extra_data.type == PipExtra::PIP_EXTRA_LUT_PERMUTATION) {
NPNR_ASSERT(extra_data.output == i); NPNR_ASSERT(extra_data.output == i);
phys_to_log[extra_data.input].push_back(i); phys_to_log[extra_data.input].push_back(i);
@ -485,8 +486,10 @@ struct SectionFEWorker
const auto &extra_data = *impl->bel_extra_data(bel); const auto &extra_data = *impl->bel_extra_data(bel);
if (cell->params.count(id_type)) { if (cell->params.count(id_type)) {
const std::string &type = cell->params[id_type].as_string(); const std::string &type = cell->params[id_type].as_string();
if (type=="CSC" && (extra_data.flags & BEL_EXTRA_FE_CSC) == 0) return false; // No CSC capability on FE if (type == "CSC" && (extra_data.flags & BEL_EXTRA_FE_CSC) == 0)
if (type=="SCC" && (extra_data.flags & BEL_EXTRA_FE_SCC) == 0) return false; // No SCC capability on FE return false; // No CSC capability on FE
if (type == "SCC" && (extra_data.flags & BEL_EXTRA_FE_SCC) == 0)
return false; // No SCC capability on FE
} }
if (extra_data.flags & BEL_EXTRA_FE_CSC) if (extra_data.flags & BEL_EXTRA_FE_CSC)
return false; return false;
@ -505,83 +508,109 @@ bool NgUltraImpl::isBelLocationValid(BelId bel, bool explain_invalid) const
if (ctx->getBelType(bel) == id_BEYOND_FE) { if (ctx->getBelType(bel) == id_BEYOND_FE) {
SectionFEWorker worker; SectionFEWorker worker;
return worker.run(this, ctx, bel, cell); return worker.run(this, ctx, bel, cell);
} } else if (ctx->getBelType(bel).in(id_RF, id_XRF)) {
else if (ctx->getBelType(bel).in(id_RF, id_XRF)) {
Loc loc = ctx->getBelLocation(bel); Loc loc = ctx->getBelLocation(bel);
if (loc.z == BEL_XRF_Z) { if (loc.z == BEL_XRF_Z) {
// If we used any of RFs we can not used XRF // If we used any of RFs we can not used XRF
if (ctx->getBoundBelCell(ctx->getBelByLocation(Loc(loc.x,loc.y,BEL_RF_Z)))) return false; if (ctx->getBoundBelCell(ctx->getBelByLocation(Loc(loc.x, loc.y, BEL_RF_Z))))
if (ctx->getBoundBelCell(ctx->getBelByLocation(Loc(loc.x,loc.y,BEL_RF_Z+1)))) return false; return false;
if (ctx->getBoundBelCell(ctx->getBelByLocation(Loc(loc.x, loc.y, BEL_RF_Z + 1))))
return false;
// If we used any FIFO we can not use XRF // If we used any FIFO we can not use XRF
if (ctx->getBoundBelCell(ctx->getBelByLocation(Loc(loc.x,loc.y,BEL_FIFO_Z)))) return false; if (ctx->getBoundBelCell(ctx->getBelByLocation(Loc(loc.x, loc.y, BEL_FIFO_Z))))
if (ctx->getBoundBelCell(ctx->getBelByLocation(Loc(loc.x,loc.y,BEL_FIFO_Z+1)))) return false; return false;
if (ctx->getBoundBelCell(ctx->getBelByLocation(Loc(loc.x, loc.y, BEL_FIFO_Z + 1))))
return false;
// If we used XFIFO we can not use XRF // If we used XFIFO we can not use XRF
if (ctx->getBoundBelCell(ctx->getBelByLocation(Loc(loc.x,loc.y,BEL_XFIFO_Z)))) return false; if (ctx->getBoundBelCell(ctx->getBelByLocation(Loc(loc.x, loc.y, BEL_XFIFO_Z))))
return false;
} else { } else {
// If we used XRF we can not use individual RF // If we used XRF we can not use individual RF
if (ctx->getBoundBelCell(ctx->getBelByLocation(Loc(loc.x,loc.y,BEL_XRF_Z)))) return false; if (ctx->getBoundBelCell(ctx->getBelByLocation(Loc(loc.x, loc.y, BEL_XRF_Z))))
return false;
// If we used XFIFO we can not use RF // If we used XFIFO we can not use RF
if (ctx->getBoundBelCell(ctx->getBelByLocation(Loc(loc.x,loc.y,BEL_XFIFO_Z)))) return false; if (ctx->getBoundBelCell(ctx->getBelByLocation(Loc(loc.x, loc.y, BEL_XFIFO_Z))))
return false;
int index = loc.z - BEL_RF_Z; int index = loc.z - BEL_RF_Z;
// If we used coresponding FIFO we can not use RF // If we used coresponding FIFO we can not use RF
if (ctx->getBoundBelCell(ctx->getBelByLocation(Loc(loc.x,loc.y,BEL_FIFO_Z + index)))) return false; if (ctx->getBoundBelCell(ctx->getBelByLocation(Loc(loc.x, loc.y, BEL_FIFO_Z + index))))
return false;
} }
} } else if (ctx->getBelType(bel).in(id_FIFO, id_XFIFO)) {
else if (ctx->getBelType(bel).in(id_FIFO, id_XFIFO)) {
Loc loc = ctx->getBelLocation(bel); Loc loc = ctx->getBelLocation(bel);
if (loc.z == BEL_XFIFO_Z) { if (loc.z == BEL_XFIFO_Z) {
// If we used any of RFs we can not used XFIFO // If we used any of RFs we can not used XFIFO
if (ctx->getBoundBelCell(ctx->getBelByLocation(Loc(loc.x,loc.y,BEL_RF_Z)))) return false; if (ctx->getBoundBelCell(ctx->getBelByLocation(Loc(loc.x, loc.y, BEL_RF_Z))))
if (ctx->getBoundBelCell(ctx->getBelByLocation(Loc(loc.x,loc.y,BEL_RF_Z+1)))) return false; return false;
if (ctx->getBoundBelCell(ctx->getBelByLocation(Loc(loc.x, loc.y, BEL_RF_Z + 1))))
return false;
// If we used any FIFO we can not use XFIFO // If we used any FIFO we can not use XFIFO
if (ctx->getBoundBelCell(ctx->getBelByLocation(Loc(loc.x,loc.y,BEL_FIFO_Z)))) return false; if (ctx->getBoundBelCell(ctx->getBelByLocation(Loc(loc.x, loc.y, BEL_FIFO_Z))))
if (ctx->getBoundBelCell(ctx->getBelByLocation(Loc(loc.x,loc.y,BEL_FIFO_Z+1)))) return false; return false;
if (ctx->getBoundBelCell(ctx->getBelByLocation(Loc(loc.x, loc.y, BEL_FIFO_Z + 1))))
return false;
// If we used XFIFO we can not use XFIFO // If we used XFIFO we can not use XFIFO
if (ctx->getBoundBelCell(ctx->getBelByLocation(Loc(loc.x,loc.y,BEL_XFIFO_Z)))) return false; if (ctx->getBoundBelCell(ctx->getBelByLocation(Loc(loc.x, loc.y, BEL_XFIFO_Z))))
return false;
// If we used any CDC we can not use XFIFO // If we used any CDC we can not use XFIFO
// NOTE: CDC1 is in S4 and CDC2 is S12 // NOTE: CDC1 is in S4 and CDC2 is S12
if (ctx->getBoundBelCell(ctx->getBelByLocation(Loc(loc.x-1,loc.y,BEL_CDC_Z)))) return false; if (ctx->getBoundBelCell(ctx->getBelByLocation(Loc(loc.x - 1, loc.y, BEL_CDC_Z))))
if (ctx->getBoundBelCell(ctx->getBelByLocation(Loc(loc.x+1,loc.y,BEL_CDC_Z+1)))) return false; return false;
if (ctx->getBoundBelCell(ctx->getBelByLocation(Loc(loc.x + 1, loc.y, BEL_CDC_Z + 1))))
return false;
// If we used XCDC we can not use XFIFO // If we used XCDC we can not use XFIFO
if (ctx->getBoundBelCell(ctx->getBelByLocation(Loc(loc.x,loc.y,BEL_XCDC_Z)))) return false; if (ctx->getBoundBelCell(ctx->getBelByLocation(Loc(loc.x, loc.y, BEL_XCDC_Z))))
return false;
} else { } else {
// If we used XFIFO we can not use individual FIFO // If we used XFIFO we can not use individual FIFO
if (ctx->getBoundBelCell(ctx->getBelByLocation(Loc(loc.x,loc.y,BEL_XFIFO_Z)))) return false; if (ctx->getBoundBelCell(ctx->getBelByLocation(Loc(loc.x, loc.y, BEL_XFIFO_Z))))
return false;
// If we used XRF we can not use FIFO // If we used XRF we can not use FIFO
if (ctx->getBoundBelCell(ctx->getBelByLocation(Loc(loc.x,loc.y,BEL_XRF_Z)))) return false; if (ctx->getBoundBelCell(ctx->getBelByLocation(Loc(loc.x, loc.y, BEL_XRF_Z))))
return false;
// If we used XCDC we can not use FIFO // If we used XCDC we can not use FIFO
if (ctx->getBoundBelCell(ctx->getBelByLocation(Loc(loc.x,loc.y,BEL_XCDC_Z)))) return false; if (ctx->getBoundBelCell(ctx->getBelByLocation(Loc(loc.x, loc.y, BEL_XCDC_Z))))
return false;
int index = loc.z - BEL_FIFO_Z; int index = loc.z - BEL_FIFO_Z;
// If we used coresponding RF we can not use FIFO // If we used coresponding RF we can not use FIFO
if (ctx->getBoundBelCell(ctx->getBelByLocation(Loc(loc.x,loc.y,BEL_RF_Z + index)))) return false; if (ctx->getBoundBelCell(ctx->getBelByLocation(Loc(loc.x, loc.y, BEL_RF_Z + index))))
return false;
// If we used coresponding CDC we can not use FIFO // If we used coresponding CDC we can not use FIFO
// NOTE: CDC1 is in S4 and CDC2 is S12 // NOTE: CDC1 is in S4 and CDC2 is S12
int rel = (index == 0) ? -1 : +1; int rel = (index == 0) ? -1 : +1;
if (ctx->getBoundBelCell(ctx->getBelByLocation(Loc(loc.x + rel,loc.y,BEL_CDC_Z + index)))) return false; if (ctx->getBoundBelCell(ctx->getBelByLocation(Loc(loc.x + rel, loc.y, BEL_CDC_Z + index))))
return false;
} }
} } else if (ctx->getBelType(bel).in(id_CDC, id_XCDC)) {
else if (ctx->getBelType(bel).in(id_CDC, id_XCDC)) {
Loc loc = ctx->getBelLocation(bel); Loc loc = ctx->getBelLocation(bel);
if (loc.z == BEL_XCDC_Z) { if (loc.z == BEL_XCDC_Z) {
// If we used any of CDCs we can not used XCDC // If we used any of CDCs we can not used XCDC
// NOTE: CDC1 is in S4 and CDC2 is S12 // NOTE: CDC1 is in S4 and CDC2 is S12
if (ctx->getBoundBelCell(ctx->getBelByLocation(Loc(loc.x-1,loc.y,BEL_CDC_Z)))) return false; if (ctx->getBoundBelCell(ctx->getBelByLocation(Loc(loc.x - 1, loc.y, BEL_CDC_Z))))
if (ctx->getBoundBelCell(ctx->getBelByLocation(Loc(loc.x+1,loc.y,BEL_CDC_Z+1)))) return false; return false;
if (ctx->getBoundBelCell(ctx->getBelByLocation(Loc(loc.x + 1, loc.y, BEL_CDC_Z + 1))))
return false;
// If we used any FIFO we can not use XCDC // If we used any FIFO we can not use XCDC
if (ctx->getBoundBelCell(ctx->getBelByLocation(Loc(loc.x,loc.y,BEL_FIFO_Z)))) return false; if (ctx->getBoundBelCell(ctx->getBelByLocation(Loc(loc.x, loc.y, BEL_FIFO_Z))))
if (ctx->getBoundBelCell(ctx->getBelByLocation(Loc(loc.x,loc.y,BEL_FIFO_Z+1)))) return false; return false;
if (ctx->getBoundBelCell(ctx->getBelByLocation(Loc(loc.x, loc.y, BEL_FIFO_Z + 1))))
return false;
// If we used XFIFO we can not use XCDC // If we used XFIFO we can not use XCDC
if (ctx->getBoundBelCell(ctx->getBelByLocation(Loc(loc.x,loc.y,BEL_XFIFO_Z)))) return false; if (ctx->getBoundBelCell(ctx->getBelByLocation(Loc(loc.x, loc.y, BEL_XFIFO_Z))))
return false;
} else { } else {
// NOTE: CDC1 is in S4 and CDC2 is S12 so we move calculation relative to S8 // NOTE: CDC1 is in S4 and CDC2 is S12 so we move calculation relative to S8
int index = loc.z - BEL_CDC_Z; int index = loc.z - BEL_CDC_Z;
int fix = (index == 0) ? +1 : -1; int fix = (index == 0) ? +1 : -1;
// If we used XCDC we can not use individual CDC // If we used XCDC we can not use individual CDC
if (ctx->getBoundBelCell(ctx->getBelByLocation(Loc(loc.x+fix,loc.y,BEL_XCDC_Z)))) return false; if (ctx->getBoundBelCell(ctx->getBelByLocation(Loc(loc.x + fix, loc.y, BEL_XCDC_Z))))
return false;
// If we used XFIFO we can not use CDC // If we used XFIFO we can not use CDC
if (ctx->getBoundBelCell(ctx->getBelByLocation(Loc(loc.x+fix,loc.y,BEL_XFIFO_Z)))) return false; if (ctx->getBoundBelCell(ctx->getBelByLocation(Loc(loc.x + fix, loc.y, BEL_XFIFO_Z))))
return false;
// If we used coresponding FIFO we can not use CDC // If we used coresponding FIFO we can not use CDC
if (ctx->getBoundBelCell(ctx->getBelByLocation(Loc(loc.x+fix,loc.y,BEL_FIFO_Z + index)))) return false; if (ctx->getBoundBelCell(ctx->getBelByLocation(Loc(loc.x + fix, loc.y, BEL_FIFO_Z + index))))
return false;
} }
} }
return true; return true;
@ -658,18 +687,37 @@ bool NgUltraImpl::getChildPlacement(const BaseClusterInfo *cluster, Loc root_loc
for (auto child : cluster->constr_children) { for (auto child : cluster->constr_children) {
Loc child_loc; Loc child_loc;
switch (child->constr_z) { switch (child->constr_z) {
case PLACE_CY_CHAIN :child_loc = getNextLocInCYChain(prev); prev = child_loc; break; case PLACE_CY_CHAIN:
case PLACE_LUT_CHAIN : child_loc = getNextLocInLUTChain(prev); prev = child_loc; break; child_loc = getNextLocInCYChain(prev);
case PLACE_DFF_CHAIN : child_loc = getNextLocInDFFChain(prev); prev = child_loc; break; prev = child_loc;
case PLACE_CY_FE1 ... PLACE_CY_FE4: child_loc = getCYFE(root_loc, child->constr_z - PLACE_CY_FE1 ); break; break;
case PLACE_XLUT_FE1 ... PLACE_XLUT_FE4: child_loc = getXLUTFE(root_loc, child->constr_z - PLACE_XLUT_FE1 );break; case PLACE_LUT_CHAIN:
child_loc = getNextLocInLUTChain(prev);
prev = child_loc;
break;
case PLACE_DFF_CHAIN:
child_loc = getNextLocInDFFChain(prev);
prev = child_loc;
break;
case PLACE_CY_FE1 ... PLACE_CY_FE4:
child_loc = getCYFE(root_loc, child->constr_z - PLACE_CY_FE1);
break;
case PLACE_XLUT_FE1 ... PLACE_XLUT_FE4:
child_loc = getXLUTFE(root_loc, child->constr_z - PLACE_XLUT_FE1);
break;
case PLACE_XRF_I1 ... PLACE_XRF_WEA: case PLACE_XRF_I1 ... PLACE_XRF_WEA:
child_loc = getXRFFE(root_loc, child->constr_z - PLACE_XRF_I1 ); break; child_loc = getXRFFE(root_loc, child->constr_z - PLACE_XRF_I1);
break;
case PLACE_CDC_AI1 ... PLACE_CDC_DDRSTI: case PLACE_CDC_AI1 ... PLACE_CDC_DDRSTI:
child_loc = getCDCFE(root_loc, child->constr_z - PLACE_CDC_AI1 ); break; child_loc = getCDCFE(root_loc, child->constr_z - PLACE_CDC_AI1);
break;
case PLACE_FIFO_I1 ... PLACE_FIFO_REQ2: case PLACE_FIFO_I1 ... PLACE_FIFO_REQ2:
child_loc = getFIFOFE(root_loc, child->constr_z - PLACE_FIFO_I1 ); break; child_loc = getFIFOFE(root_loc, child->constr_z - PLACE_FIFO_I1);
case PLACE_DSP_CHAIN : child_loc = getNextLocInDSPChain(this, prev); prev = child_loc; break; break;
case PLACE_DSP_CHAIN:
child_loc = getNextLocInDSPChain(this, prev);
prev = child_loc;
break;
default: default:
child_loc.x = root_loc.x + child->constr_x; child_loc.x = root_loc.x + child->constr_x;
child_loc.y = root_loc.y + child->constr_y; child_loc.y = root_loc.y + child->constr_y;
@ -679,7 +727,8 @@ bool NgUltraImpl::getChildPlacement(const BaseClusterInfo *cluster, Loc root_loc
if (child_bel == BelId() || !this->isValidBelForCellType(child->type, child_bel)) if (child_bel == BelId() || !this->isValidBelForCellType(child->type, child_bel))
return false; return false;
placement.emplace_back(child, child_bel); placement.emplace_back(child, child_bel);
if (!getChildPlacement(child, child_loc, placement)) return false; if (!getChildPlacement(child, child_loc, placement))
return false;
} }
return true; return true;
} }
@ -753,7 +802,6 @@ delay_t NgUltraImpl::estimateDelay(WireId src, WireId dst) const
return 500 + 100 * (std::abs(dy - sy) / 4 + std::abs(dx - sx) / 4); return 500 + 100 * (std::abs(dy - sy) / 4 + std::abs(dx - sx) / 4);
} }
delay_t NgUltraImpl::predictDelay(BelId src_bel, IdString src_pin, BelId dst_bel, IdString dst_pin) const delay_t NgUltraImpl::predictDelay(BelId src_bel, IdString src_pin, BelId dst_bel, IdString dst_pin) const
{ {
Loc src_loc = ctx->getBelLocation(src_bel), dst_loc = ctx->getBelLocation(dst_bel); Loc src_loc = ctx->getBelLocation(src_bel), dst_loc = ctx->getBelLocation(dst_bel);
@ -823,7 +871,8 @@ void NgUltraImpl::fixup_crossbars()
} }
NPNR_ASSERT(found_pip != PipId()); NPNR_ASSERT(found_pip != PipId());
// rebind // rebind
//log_info(" replacing crossbar pip %s with %s on %s\n", ctx->nameOfPip(pip), ctx->nameOfPip(found_pip), ctx->nameOf(ni)); // log_info(" replacing crossbar pip %s with %s on %s\n", ctx->nameOfPip(pip),
// ctx->nameOfPip(found_pip), ctx->nameOf(ni));
ctx->bindPip(found_pip, ni, STRENGTH_STRONG); ctx->bindPip(found_pip, ni, STRENGTH_STRONG);
} }
} }
@ -842,8 +891,7 @@ void NgUltraImpl::drawBel(std::vector<GraphicElement> &g, GraphicElement::style_
GraphicElement el; GraphicElement el;
el.type = GraphicElement::TYPE_BOX; el.type = GraphicElement::TYPE_BOX;
el.style = style; el.style = style;
switch (bel_type.index) switch (bel_type.index) {
{
case id_BEYOND_FE.index: case id_BEYOND_FE.index:
el.x1 = loc.x + 0.15 + (loc.z % 8) * 0.1; el.x1 = loc.x + 0.15 + (loc.z % 8) * 0.1;
el.x2 = el.x1 + 0.05; el.x2 = el.x1 + 0.05;
@ -995,16 +1043,14 @@ void NgUltraImpl::drawBel(std::vector<GraphicElement> &g, GraphicElement::style_
el.y2 = el.y1 - 1.6; el.y2 = el.y1 - 1.6;
g.push_back(el); g.push_back(el);
break; break;
case id_GCK.index: case id_GCK.index: {
{
int lobe = loc.z / 20; int lobe = loc.z / 20;
el.x1 = (47 + (lobe % 2) * 3) * 4 + 0.1; el.x1 = (47 + (lobe % 2) * 3) * 4 + 0.1;
el.x2 = el.x1 + 0.8; el.x2 = el.x1 + 0.8;
el.y1 = (ctx->getGridDimY() - 1 - (7 * 4 + 12 * 4 * (lobe >> 1))) + 0.95 - (loc.z % 20) * 0.25; el.y1 = (ctx->getGridDimY() - 1 - (7 * 4 + 12 * 4 * (lobe >> 1))) + 0.95 - (loc.z % 20) * 0.25;
el.y2 = el.y1 - 0.2; el.y2 = el.y1 - 0.2;
g.push_back(el); g.push_back(el);
} } break;
break;
default: default:
break; break;
} }

View File

@ -71,6 +71,7 @@ struct NgUltraImpl : HimbaechelAPI
void expandBoundingBox(BoundingBox &bb) const override; void expandBoundingBox(BoundingBox &bb) const override;
void drawBel(std::vector<GraphicElement> &g, GraphicElement::style_t style, IdString bel_type, Loc loc) override; void drawBel(std::vector<GraphicElement> &g, GraphicElement::style_t style, IdString bel_type, Loc loc) override;
public: public:
int tile_lobe(int tile) const; int tile_lobe(int tile) const;
TileTypeExtra tile_type(int tile) const; TileTypeExtra tile_type(int tile) const;

View File

@ -72,8 +72,10 @@ void NgUltraPacker::pack_constants(void)
{ {
log_info("Packing constants..\n"); log_info("Packing constants..\n");
// Replace constants with LUTs // Replace constants with LUTs
const dict<IdString, Property> vcc_params = {{id_lut_table, Property(0xFFFF, 16)}, {id_lut_used, Property(1,1)}, {id_dff_used, Property(1,1)}}; const dict<IdString, Property> vcc_params = {
const dict<IdString, Property> gnd_params = {{id_lut_table, Property(0x0000, 16)}, {id_lut_used, Property(1,1)}, {id_dff_used, Property(1,1)}}; {id_lut_table, Property(0xFFFF, 16)}, {id_lut_used, Property(1, 1)}, {id_dff_used, Property(1, 1)}};
const dict<IdString, Property> gnd_params = {
{id_lut_table, Property(0x0000, 16)}, {id_lut_used, Property(1, 1)}, {id_dff_used, Property(1, 1)}};
h.replace_constants(CellTypePort(id_BEYOND_FE, id_LO), CellTypePort(id_BEYOND_FE, id_LO), vcc_params, gnd_params); h.replace_constants(CellTypePort(id_BEYOND_FE, id_LO), CellTypePort(id_BEYOND_FE, id_LO), vcc_params, gnd_params);
} }
@ -253,7 +255,8 @@ void NgUltraPacker::connect_gnd_if_unconnected(CellInfo *cell, IdString input, b
if (fnd_net != ctx->nets.end()) { if (fnd_net != ctx->nets.end()) {
cell->connectPort(input, fnd_net->second.get()); cell->connectPort(input, fnd_net->second.get());
if (warn) if (warn)
log_warning("Connected GND to mandatory port '%s' of cell '%s'(%s).\n", input.c_str(ctx), cell->name.c_str(ctx), cell->type.c_str(ctx)); log_warning("Connected GND to mandatory port '%s' of cell '%s'(%s).\n", input.c_str(ctx),
cell->name.c_str(ctx), cell->type.c_str(ctx));
} }
} }
@ -285,8 +288,7 @@ void NgUltraPacker::dff_to_fe(CellInfo *dff, CellInfo *fe, bool pass_thru_lut)
dff->movePortTo(id_I, fe, id_I1); dff->movePortTo(id_I, fe, id_I1);
} }
fe->params[id_lut_used] = Property(1, 1); fe->params[id_lut_used] = Property(1, 1);
} } else
else
dff->movePortTo(id_I, fe, id_DI); dff->movePortTo(id_I, fe, id_DI);
fe->params[id_dff_used] = Property(1, 1); fe->params[id_dff_used] = Property(1, 1);
dff->movePortTo(id_O, fe, id_DO); dff->movePortTo(id_O, fe, id_DO);
@ -299,12 +301,18 @@ void NgUltraPacker::dff_to_fe(CellInfo *dff, CellInfo *fe, bool pass_thru_lut)
dff->movePortTo(id_CK, fe, id_CK); dff->movePortTo(id_CK, fe, id_CK);
dff->movePortTo(id_L, fe, id_L); dff->movePortTo(id_L, fe, id_L);
if (dff->params.count(id_dff_ctxt)) fe->setParam(id_dff_ctxt,dff->params[id_dff_ctxt]); if (dff->params.count(id_dff_ctxt))
if (dff->params.count(id_dff_edge)) fe->setParam(id_dff_edge,dff->params[id_dff_edge]); fe->setParam(id_dff_ctxt, dff->params[id_dff_ctxt]);
if (dff->params.count(id_dff_init)) fe->setParam(id_dff_init,dff->params[id_dff_init]); if (dff->params.count(id_dff_edge))
if (dff->params.count(id_dff_load)) fe->setParam(id_dff_load,dff->params[id_dff_load]); fe->setParam(id_dff_edge, dff->params[id_dff_edge]);
if (dff->params.count(id_dff_sync)) fe->setParam(id_dff_sync,dff->params[id_dff_sync]); if (dff->params.count(id_dff_init))
if (dff->params.count(id_dff_type)) fe->setParam(id_dff_type,dff->params[id_dff_type]); fe->setParam(id_dff_init, dff->params[id_dff_init]);
if (dff->params.count(id_dff_load))
fe->setParam(id_dff_load, dff->params[id_dff_load]);
if (dff->params.count(id_dff_sync))
fe->setParam(id_dff_sync, dff->params[id_dff_sync]);
if (dff->params.count(id_dff_type))
fe->setParam(id_dff_type, dff->params[id_dff_type]);
} }
if (pass_thru_lut) { if (pass_thru_lut) {
NetInfo *new_out = ctx->createNet(ctx->idf("%s$LO", dff->name.c_str(ctx))); NetInfo *new_out = ctx->createNet(ctx->idf("%s$LO", dff->name.c_str(ctx)));
@ -353,7 +361,8 @@ void NgUltraPacker::pack_xluts(void)
if (lut[i] == cell.second.get()) if (lut[i] == cell.second.get())
continue; continue;
if (lut[i]) { if (lut[i]) {
if (net->users.entries()>1) dff_parts_used++; if (net->users.entries() > 1)
dff_parts_used++;
inputs_used++; inputs_used++;
} }
} }
@ -422,15 +431,18 @@ void NgUltraPacker::pack_dff_chains(void)
if (!ci.type.in(id_NX_DFF)) if (!ci.type.in(id_NX_DFF))
continue; continue;
NetInfo *inp = ci.getPort(id_I); NetInfo *inp = ci.getPort(id_I);
if (!inp || (inp->driver.cell && inp->driver.cell->type.in(id_NX_DFF))) continue; if (!inp || (inp->driver.cell && inp->driver.cell->type.in(id_NX_DFF)))
continue;
int cnt = 0; int cnt = 0;
CellInfo *dff = &ci; CellInfo *dff = &ci;
std::vector<CellInfo *> chain; std::vector<CellInfo *> chain;
CellInfo *start_dff = &ci; CellInfo *start_dff = &ci;
while (1) { while (1) {
NetInfo *o = dff->getPort(id_O); NetInfo *o = dff->getPort(id_O);
if (!o) break; if (!o)
if (o->users.entries() != 1) break; break;
if (o->users.entries() != 1)
break;
dff = (*o->users.begin()).cell; dff = (*o->users.begin()).cell;
if (dff->type == id_NX_DFF && (*o->users.begin()).port == id_I) { if (dff->type == id_NX_DFF && (*o->users.begin()).port == id_I) {
if (cnt == 95) { // note that start_dff is also part of chain if (cnt == 95) { // note that start_dff is also part of chain
@ -442,7 +454,8 @@ void NgUltraPacker::pack_dff_chains(void)
chain.push_back(dff); chain.push_back(dff);
cnt++; cnt++;
} }
} else break; } else
break;
} }
if (cnt) if (cnt)
dff_chain_start.push_back(make_pair(start_dff, chain)); dff_chain_start.push_back(make_pair(start_dff, chain));
@ -489,7 +502,8 @@ void NgUltraPacker::pack_lut_multi_dffs(void)
{ {
log_info("Pack LUT-multi DFFs...\n"); log_info("Pack LUT-multi DFFs...\n");
int dff_only = 0, lut_and_ff = 0, bff_only = 0;; int dff_only = 0, lut_and_ff = 0, bff_only = 0;
;
for (auto &cell : ctx->cells) { for (auto &cell : ctx->cells) {
CellInfo &ci = *cell.second; CellInfo &ci = *cell.second;
if (!ci.type.in(id_NX_LUT)) if (!ci.type.in(id_NX_LUT))
@ -499,15 +513,16 @@ void NgUltraPacker::pack_lut_multi_dffs(void)
NetInfo *o = ci.getPort(id_O); NetInfo *o = ci.getPort(id_O);
if (o) { if (o) {
if (o->users.entries()<2) continue; if (o->users.entries() < 2)
continue;
int cnt = 0; int cnt = 0;
for (auto u : o->users) for (auto u : o->users) {
{
if (u.cell->type == id_NX_DFF && u.cell->getPort(id_I) == o) if (u.cell->type == id_NX_DFF && u.cell->getPort(id_I) == o)
cnt++; cnt++;
} }
if (cnt<2) continue; if (cnt < 2)
continue;
CellInfo *root = create_cell_ptr(id_BEYOND_FE, ctx->idf("%s$fe", ci.name.c_str(ctx))); CellInfo *root = create_cell_ptr(id_BEYOND_FE, ctx->idf("%s$fe", ci.name.c_str(ctx)));
packed_cells.insert(ci.name); packed_cells.insert(ci.name);
@ -519,8 +534,7 @@ void NgUltraPacker::pack_lut_multi_dffs(void)
bool use_bff = max_use != 4 && cnt >= 4; bool use_bff = max_use != 4 && cnt >= 4;
int i = 0; int i = 0;
std::vector<PortRef> users; std::vector<PortRef> users;
for (auto u : o->users) for (auto u : o->users) {
{
if (u.cell->type == id_NX_DFF && u.cell->getPort(id_I) == o) { if (u.cell->type == id_NX_DFF && u.cell->getPort(id_I) == o) {
if (i == 0) { if (i == 0) {
packed_cells.insert(u.cell->name); packed_cells.insert(u.cell->name);
@ -733,16 +747,21 @@ void NgUltraPacker::pack_iobs(void)
if (ci.getPort(id_T)) { if (ci.getPort(id_T)) {
// In case T input is used must use different types // In case T input is used must use different types
new_type = id_IOTP; new_type = id_IOTP;
if (ci.type==id_NX_IOB_O) new_type = id_OTP; if (ci.type == id_NX_IOB_O)
if (ci.type==id_NX_IOB_I) new_type = id_ITP; new_type = id_OTP;
if (ci.type == id_NX_IOB_I)
new_type = id_ITP;
} else { } else {
if (ci.type==id_NX_IOB_O) new_type = id_OP; if (ci.type == id_NX_IOB_O)
if (ci.type==id_NX_IOB_I) new_type = id_IP; new_type = id_OP;
if (ci.type == id_NX_IOB_I)
new_type = id_IP;
} }
ci.type = new_type; ci.type = new_type;
ctx->bindBel(bel, &ci, PlaceStrength::STRENGTH_LOCKED); ctx->bindBel(bel, &ci, PlaceStrength::STRENGTH_LOCKED);
if (!ctx->isValidBelForCellType(new_type, bel)) if (!ctx->isValidBelForCellType(new_type, bel))
log_error("Invalid type of IO for specified location %s %s.\n", new_type.c_str(ctx), ctx->getBelType(bel).c_str(ctx)); log_error("Invalid type of IO for specified location %s %s.\n", new_type.c_str(ctx),
ctx->getBelType(bel).c_str(ctx));
to_update.push_back(&ci); to_update.push_back(&ci);
} }
int bfr_added = 0; int bfr_added = 0;
@ -909,8 +928,10 @@ void NgUltraPacker::pack_iobs(void)
WireId dwire = ctx->getBelPinWire(bel, id_O); WireId dwire = ctx->getBelPinWire(bel, id_O);
for (PipId pip : ctx->getPipsDownhill(dwire)) { for (PipId pip : ctx->getPipsDownhill(dwire)) {
const auto &extra_data = *uarch->pip_extra_data(pip); const auto &extra_data = *uarch->pip_extra_data(pip);
if (!extra_data.name) continue; if (!extra_data.name)
if (extra_data.type != PipExtra::PIP_EXTRA_MUX) continue; continue;
if (extra_data.type != PipExtra::PIP_EXTRA_MUX)
continue;
if (bfr_mode && extra_data.input == 2) { if (bfr_mode && extra_data.input == 2) {
uarch->blocked_pips.emplace(pip); uarch->blocked_pips.emplace(pip);
} else if (!bfr_mode && extra_data.input == 1) { } else if (!bfr_mode && extra_data.input == 1) {
@ -966,7 +987,8 @@ void NgUltraPacker::pack_ioms(void)
} }
} }
void NgUltraPacker::pack_cy_input_and_output(CellInfo *cy, IdString cluster, IdString in_port, IdString out_port, int placer, int &lut_only, int &lut_and_ff, int &dff_only) void NgUltraPacker::pack_cy_input_and_output(CellInfo *cy, IdString cluster, IdString in_port, IdString out_port,
int placer, int &lut_only, int &lut_and_ff, int &dff_only)
{ {
CellInfo *fe = create_cell_ptr(id_BEYOND_FE, ctx->idf("%s$%s", cy->name.c_str(ctx), in_port.c_str(ctx))); CellInfo *fe = create_cell_ptr(id_BEYOND_FE, ctx->idf("%s$%s", cy->name.c_str(ctx), in_port.c_str(ctx)));
NetInfo *net = cy->getPort(in_port); NetInfo *net = cy->getPort(in_port);
@ -1087,7 +1109,8 @@ void NgUltraPacker::pack_cys(void)
log_error("NX_CY can only be chained with one other NX_CY cell\n"); log_error("NX_CY can only be chained with one other NX_CY cell\n");
} }
group.push_back(cy); group.push_back(cy);
} else break; } else
break;
} }
groups.push_back(group); groups.push_back(group);
} }
@ -1136,8 +1159,8 @@ void NgUltraPacker::pack_cys(void)
flush_cells(); flush_cells();
} }
void NgUltraPacker::pack_xrf_input_and_output(CellInfo *xrf, IdString cluster, IdString in_port, IdString out_port,
void NgUltraPacker::pack_xrf_input_and_output(CellInfo *xrf, IdString cluster, IdString in_port, IdString out_port, ClusterPlacement placement, int &lut_only, int &lut_and_ff, int &dff_only) ClusterPlacement placement, int &lut_only, int &lut_and_ff, int &dff_only)
{ {
NetInfo *net = xrf->getPort(in_port); NetInfo *net = xrf->getPort(in_port);
NetInfo *net_out = nullptr; NetInfo *net_out = nullptr;
@ -1148,9 +1171,11 @@ void NgUltraPacker::pack_xrf_input_and_output(CellInfo *xrf, IdString cluster, I
net_out = nullptr; net_out = nullptr;
} }
} }
if (!net && !net_out) return; if (!net && !net_out)
return;
IdString name = in_port; IdString name = in_port;
if (name == IdString()) name = out_port; if (name == IdString())
name = out_port;
CellInfo *fe = create_cell_ptr(id_BEYOND_FE, ctx->idf("%s$%s", xrf->name.c_str(ctx), name.c_str(ctx))); CellInfo *fe = create_cell_ptr(id_BEYOND_FE, ctx->idf("%s$%s", xrf->name.c_str(ctx), name.c_str(ctx)));
if (net) { if (net) {
@ -1221,11 +1246,21 @@ void NgUltraPacker::pack_rfs(void)
continue; continue;
int mode = int_or_default(ci.params, id_mode, 0); int mode = int_or_default(ci.params, id_mode, 0);
switch (mode) { switch (mode) {
case 0 : ci.type = id_RF; break; case 0:
case 1 : ci.type = id_RFSP; break; ci.type = id_RF;
case 2 : ci.type = id_XHRF; break; break;
case 3 : ci.type = id_XWRF; break; case 1:
case 4 : ci.type = id_XPRF; break; ci.type = id_RFSP;
break;
case 2:
ci.type = id_XHRF;
break;
case 3:
ci.type = id_XWRF;
break;
case 4:
ci.type = id_XPRF;
break;
default: default:
log_error("Unknown mode %d for cell '%s'.\n", mode, ci.name.c_str(ctx)); log_error("Unknown mode %d for cell '%s'.\n", mode, ci.name.c_str(ctx));
} }
@ -1234,12 +1269,14 @@ void NgUltraPacker::pack_rfs(void)
for (int i = 1; i <= 18; i++) { for (int i = 1; i <= 18; i++) {
connect_gnd_if_unconnected(&ci, ctx->idf("I%d", i)); connect_gnd_if_unconnected(&ci, ctx->idf("I%d", i));
pack_xrf_input_and_output(&ci, ci.name, ctx->idf("I%d",i), ctx->idf("O%d",i), ClusterPlacement(PLACE_XRF_I1 + i-1), lut_only, lut_and_ff, dff_only); pack_xrf_input_and_output(&ci, ci.name, ctx->idf("I%d", i), ctx->idf("O%d", i),
ClusterPlacement(PLACE_XRF_I1 + i - 1), lut_only, lut_and_ff, dff_only);
} }
if (mode != 1) { if (mode != 1) {
for (int i = 1; i <= 5; i++) { for (int i = 1; i <= 5; i++) {
connect_gnd_if_unconnected(&ci, ctx->idf("RA%d", i)); connect_gnd_if_unconnected(&ci, ctx->idf("RA%d", i));
pack_xrf_input_and_output(&ci, ci.name, ctx->idf("RA%d",i), IdString(), ClusterPlacement(PLACE_XRF_RA1 + i-1), lut_only, lut_and_ff, dff_only); pack_xrf_input_and_output(&ci, ci.name, ctx->idf("RA%d", i), IdString(),
ClusterPlacement(PLACE_XRF_RA1 + i - 1), lut_only, lut_and_ff, dff_only);
} }
} else { } else {
// SPREG mode does not use RA inputs // SPREG mode does not use RA inputs
@ -1257,17 +1294,18 @@ void NgUltraPacker::pack_rfs(void)
if (mode == 4) { if (mode == 4) {
for (int i = 7; i <= 10; i++) { for (int i = 7; i <= 10; i++) {
connect_gnd_if_unconnected(&ci, ctx->idf("RA%d", i)); connect_gnd_if_unconnected(&ci, ctx->idf("RA%d", i));
pack_xrf_input_and_output(&ci, ci.name, ctx->idf("RA%d",i), IdString(), ClusterPlacement(PLACE_XRF_RA1 + i-1), lut_only, lut_and_ff, dff_only); pack_xrf_input_and_output(&ci, ci.name, ctx->idf("RA%d", i), IdString(),
ClusterPlacement(PLACE_XRF_RA1 + i - 1), lut_only, lut_and_ff, dff_only);
} }
} else { } else {
for (int i = 7; i <= 10; i++) for (int i = 7; i <= 10; i++)
disconnect_unused(&ci, ctx->idf("RA%d", i)); disconnect_unused(&ci, ctx->idf("RA%d", i));
} }
for (int i = 1; i <= 5; i++) { for (int i = 1; i <= 5; i++) {
connect_gnd_if_unconnected(&ci, ctx->idf("WA%d", i)); connect_gnd_if_unconnected(&ci, ctx->idf("WA%d", i));
pack_xrf_input_and_output(&ci, ci.name, ctx->idf("WA%d",i), IdString(), ClusterPlacement(PLACE_XRF_WA1 + i-1), lut_only, lut_and_ff, dff_only); pack_xrf_input_and_output(&ci, ci.name, ctx->idf("WA%d", i), IdString(),
ClusterPlacement(PLACE_XRF_WA1 + i - 1), lut_only, lut_and_ff, dff_only);
} }
if (mode == 2) { if (mode == 2) {
@ -1286,12 +1324,14 @@ void NgUltraPacker::pack_rfs(void)
if (mode == 3) { if (mode == 3) {
for (int i = 19; i <= 36; i++) { for (int i = 19; i <= 36; i++) {
connect_gnd_if_unconnected(&ci, ctx->idf("I%d", i)); connect_gnd_if_unconnected(&ci, ctx->idf("I%d", i));
pack_xrf_input_and_output(&ci, ci.name, ctx->idf("I%d",i), ctx->idf("O%d",i), ClusterPlacement(PLACE_XRF_I1 + i-1), lut_only, lut_and_ff, dff_only); pack_xrf_input_and_output(&ci, ci.name, ctx->idf("I%d", i), ctx->idf("O%d", i),
ClusterPlacement(PLACE_XRF_I1 + i - 1), lut_only, lut_and_ff, dff_only);
} }
} else if (mode == 4) { } else if (mode == 4) {
for (int i = 19; i <= 36; i++) { for (int i = 19; i <= 36; i++) {
disconnect_unused(&ci, ctx->idf("I%d", i)); disconnect_unused(&ci, ctx->idf("I%d", i));
pack_xrf_input_and_output(&ci, ci.name, IdString(), ctx->idf("O%d",i), ClusterPlacement(PLACE_XRF_I1 + i-1), lut_only, lut_and_ff, dff_only); pack_xrf_input_and_output(&ci, ci.name, IdString(), ctx->idf("O%d", i),
ClusterPlacement(PLACE_XRF_I1 + i - 1), lut_only, lut_and_ff, dff_only);
} }
} else { } else {
for (int i = 19; i <= 36; i++) { for (int i = 19; i <= 36; i++) {
@ -1334,12 +1374,24 @@ void NgUltraPacker::pack_cdcs(void)
continue; continue;
int mode = int_or_default(ci.params, id_mode, 0); int mode = int_or_default(ci.params, id_mode, 0);
switch (mode) { switch (mode) {
case 0 : ci.type = id_DDE; break; case 0:
case 1 : ci.type = id_TDE; break; ci.type = id_DDE;
case 2 : ci.type = id_CDC; break; break;
case 3 : ci.type = id_BGC; break; case 1:
case 4 : ci.type = id_GBC; break; ci.type = id_TDE;
case 5 : ci.type = id_XCDC; break; break;
case 2:
ci.type = id_CDC;
break;
case 3:
ci.type = id_BGC;
break;
case 4:
ci.type = id_GBC;
break;
case 5:
ci.type = id_XCDC;
break;
default: default:
log_error("Unknown mode %d for cell '%s'.\n", mode, ci.name.c_str(ctx)); log_error("Unknown mode %d for cell '%s'.\n", mode, ci.name.c_str(ctx));
} }
@ -1349,23 +1401,27 @@ void NgUltraPacker::pack_cdcs(void)
for (int i = 1; i <= 6; i++) { for (int i = 1; i <= 6; i++) {
if (ci.getPort(ctx->idf("AO%d", i))) { if (ci.getPort(ctx->idf("AO%d", i))) {
connect_gnd_if_unconnected(&ci, ctx->idf("AI%d", i)); connect_gnd_if_unconnected(&ci, ctx->idf("AI%d", i));
pack_xrf_input_and_output(&ci, ci.name, ctx->idf("AI%d",i), ctx->idf("AO%d",i), ClusterPlacement(PLACE_CDC_AI1 + i-1), lut_only, lut_and_ff, dff_only); pack_xrf_input_and_output(&ci, ci.name, ctx->idf("AI%d", i), ctx->idf("AO%d", i),
ClusterPlacement(PLACE_CDC_AI1 + i - 1), lut_only, lut_and_ff, dff_only);
} else } else
disconnect_unused(&ci, ctx->idf("AI%d", i)); disconnect_unused(&ci, ctx->idf("AI%d", i));
if (ci.getPort(ctx->idf("BO%d", i))) { if (ci.getPort(ctx->idf("BO%d", i))) {
connect_gnd_if_unconnected(&ci, ctx->idf("BI%d", i)); connect_gnd_if_unconnected(&ci, ctx->idf("BI%d", i));
pack_xrf_input_and_output(&ci, ci.name, ctx->idf("BI%d",i), ctx->idf("BO%d",i), ClusterPlacement(PLACE_CDC_BI1 + i-1), lut_only, lut_and_ff, dff_only); pack_xrf_input_and_output(&ci, ci.name, ctx->idf("BI%d", i), ctx->idf("BO%d", i),
ClusterPlacement(PLACE_CDC_BI1 + i - 1), lut_only, lut_and_ff, dff_only);
} else } else
disconnect_unused(&ci, ctx->idf("BI%d", i)); disconnect_unused(&ci, ctx->idf("BI%d", i));
if (ci.type.in(id_XCDC)) { if (ci.type.in(id_XCDC)) {
if (ci.getPort(ctx->idf("CO%d", i))) { if (ci.getPort(ctx->idf("CO%d", i))) {
connect_gnd_if_unconnected(&ci, ctx->idf("CI%d", i)); connect_gnd_if_unconnected(&ci, ctx->idf("CI%d", i));
pack_xrf_input_and_output(&ci, ci.name, ctx->idf("CI%d",i), ctx->idf("CO%d",i), ClusterPlacement(PLACE_CDC_CI1 + i-1), lut_only, lut_and_ff, dff_only); pack_xrf_input_and_output(&ci, ci.name, ctx->idf("CI%d", i), ctx->idf("CO%d", i),
ClusterPlacement(PLACE_CDC_CI1 + i - 1), lut_only, lut_and_ff, dff_only);
} else } else
disconnect_unused(&ci, ctx->idf("CI%d", i)); disconnect_unused(&ci, ctx->idf("CI%d", i));
if (ci.getPort(ctx->idf("DO%d", i))) { if (ci.getPort(ctx->idf("DO%d", i))) {
connect_gnd_if_unconnected(&ci, ctx->idf("DI%d", i)); connect_gnd_if_unconnected(&ci, ctx->idf("DI%d", i));
pack_xrf_input_and_output(&ci, ci.name, ctx->idf("DI%d",i), ctx->idf("DO%d",i), ClusterPlacement(PLACE_CDC_DI1 + i-1), lut_only, lut_and_ff, dff_only); pack_xrf_input_and_output(&ci, ci.name, ctx->idf("DI%d", i), ctx->idf("DO%d", i),
ClusterPlacement(PLACE_CDC_DI1 + i - 1), lut_only, lut_and_ff, dff_only);
} else } else
disconnect_unused(&ci, ctx->idf("DI%d", i)); disconnect_unused(&ci, ctx->idf("DI%d", i));
} }
@ -1381,9 +1437,11 @@ void NgUltraPacker::pack_cdcs(void)
disconnect_unused(&ci, id_BDRSTO); disconnect_unused(&ci, id_BDRSTO);
} else { } else {
connect_gnd_if_unconnected(&ci, id_ADRSTI); connect_gnd_if_unconnected(&ci, id_ADRSTI);
pack_xrf_input_and_output(&ci, ci.name, id_ADRSTI, id_ADRSTO, PLACE_CDC_ADRSTI, lut_only, lut_and_ff, dff_only); pack_xrf_input_and_output(&ci, ci.name, id_ADRSTI, id_ADRSTO, PLACE_CDC_ADRSTI, lut_only, lut_and_ff,
dff_only);
connect_gnd_if_unconnected(&ci, id_BDRSTI); connect_gnd_if_unconnected(&ci, id_BDRSTI);
pack_xrf_input_and_output(&ci, ci.name, id_BDRSTI, id_BDRSTO, PLACE_CDC_BDRSTI, lut_only, lut_and_ff, dff_only); pack_xrf_input_and_output(&ci, ci.name, id_BDRSTI, id_BDRSTO, PLACE_CDC_BDRSTI, lut_only, lut_and_ff,
dff_only);
} }
if (ci.type.in(id_BGC, id_GBC, id_DDE)) { if (ci.type.in(id_BGC, id_GBC, id_DDE)) {
disconnect_unused(&ci, id_ASRSTI); disconnect_unused(&ci, id_ASRSTI);
@ -1392,9 +1450,11 @@ void NgUltraPacker::pack_cdcs(void)
disconnect_unused(&ci, id_BSRSTO); disconnect_unused(&ci, id_BSRSTO);
} else { } else {
connect_gnd_if_unconnected(&ci, id_ASRSTI); connect_gnd_if_unconnected(&ci, id_ASRSTI);
pack_xrf_input_and_output(&ci, ci.name, id_ASRSTI, id_ASRSTO, PLACE_CDC_ASRSTI, lut_only, lut_and_ff, dff_only); pack_xrf_input_and_output(&ci, ci.name, id_ASRSTI, id_ASRSTO, PLACE_CDC_ASRSTI, lut_only, lut_and_ff,
dff_only);
connect_gnd_if_unconnected(&ci, id_BSRSTI); connect_gnd_if_unconnected(&ci, id_BSRSTI);
pack_xrf_input_and_output(&ci, ci.name, id_BSRSTI, id_BSRSTO, PLACE_CDC_BSRSTI, lut_only, lut_and_ff, dff_only); pack_xrf_input_and_output(&ci, ci.name, id_BSRSTI, id_BSRSTO, PLACE_CDC_BSRSTI, lut_only, lut_and_ff,
dff_only);
} }
// Only XCDC is using these ports, remove from others if used // Only XCDC is using these ports, remove from others if used
@ -1418,13 +1478,17 @@ void NgUltraPacker::pack_cdcs(void)
disconnect_unused(&ci, id_DSRSTO); disconnect_unused(&ci, id_DSRSTO);
} else { } else {
connect_gnd_if_unconnected(&ci, id_CDRSTI); connect_gnd_if_unconnected(&ci, id_CDRSTI);
pack_xrf_input_and_output(&ci, ci.name, id_CDRSTI, id_CDRSTO, PLACE_CDC_CDRSTI, lut_only, lut_and_ff, dff_only); pack_xrf_input_and_output(&ci, ci.name, id_CDRSTI, id_CDRSTO, PLACE_CDC_CDRSTI, lut_only, lut_and_ff,
dff_only);
connect_gnd_if_unconnected(&ci, id_DDRSTI); connect_gnd_if_unconnected(&ci, id_DDRSTI);
pack_xrf_input_and_output(&ci, ci.name, id_DDRSTI, id_DDRSTO, PLACE_CDC_DDRSTI, lut_only, lut_and_ff, dff_only); pack_xrf_input_and_output(&ci, ci.name, id_DDRSTI, id_DDRSTO, PLACE_CDC_DDRSTI, lut_only, lut_and_ff,
dff_only);
connect_gnd_if_unconnected(&ci, id_CSRSTI); connect_gnd_if_unconnected(&ci, id_CSRSTI);
pack_xrf_input_and_output(&ci, ci.name, id_CSRSTI, id_CSRSTO, PLACE_CDC_CSRSTI, lut_only, lut_and_ff, dff_only); pack_xrf_input_and_output(&ci, ci.name, id_CSRSTI, id_CSRSTO, PLACE_CDC_CSRSTI, lut_only, lut_and_ff,
dff_only);
connect_gnd_if_unconnected(&ci, id_DSRSTI); connect_gnd_if_unconnected(&ci, id_DSRSTI);
pack_xrf_input_and_output(&ci, ci.name, id_DSRSTI, id_DSRSTO, PLACE_CDC_DSRSTI, lut_only, lut_and_ff, dff_only); pack_xrf_input_and_output(&ci, ci.name, id_DSRSTI, id_DSRSTO, PLACE_CDC_DSRSTI, lut_only, lut_and_ff,
dff_only);
} }
} }
if (lut_only) if (lut_only)
@ -1446,9 +1510,15 @@ void NgUltraPacker::pack_fifos(void)
continue; continue;
int mode = int_or_default(ci.params, id_mode, 0); int mode = int_or_default(ci.params, id_mode, 0);
switch (mode) { switch (mode) {
case 0 : ci.type = id_FIFO; break; case 0:
case 1 : ci.type = id_XHFIFO; break; ci.type = id_FIFO;
case 2 : ci.type = id_XWFIFO; break; break;
case 1:
ci.type = id_XHFIFO;
break;
case 2:
ci.type = id_XWFIFO;
break;
default: default:
log_error("Unknown mode %d for cell '%s'.\n", mode, ci.name.c_str(ctx)); log_error("Unknown mode %d for cell '%s'.\n", mode, ci.name.c_str(ctx));
} }
@ -1473,12 +1543,17 @@ void NgUltraPacker::pack_fifos(void)
ci.disconnectPort(port); ci.disconnectPort(port);
for (int i = 1; i <= rsti; i++) for (int i = 1; i <= rsti; i++)
ci.connectPort(ctx->idf("WRSTI%d", i), wrsti_net); ci.connectPort(ctx->idf("WRSTI%d", i), wrsti_net);
if (mode!=0) disconnect_unused(&ci, id_WRSTO); if (mode != 0)
pack_xrf_input_and_output(&ci, ci.name, id_WRSTI1, id_WRSTO, PLACE_FIFO_WRSTI1, lut_only, lut_and_ff, dff_only); disconnect_unused(&ci, id_WRSTO);
pack_xrf_input_and_output(&ci, ci.name, id_WRSTI2, IdString(), PLACE_FIFO_WRSTI2, lut_only, lut_and_ff, dff_only); pack_xrf_input_and_output(&ci, ci.name, id_WRSTI1, id_WRSTO, PLACE_FIFO_WRSTI1, lut_only, lut_and_ff,
dff_only);
pack_xrf_input_and_output(&ci, ci.name, id_WRSTI2, IdString(), PLACE_FIFO_WRSTI2, lut_only, lut_and_ff,
dff_only);
if (mode != 0) { if (mode != 0) {
pack_xrf_input_and_output(&ci, ci.name, id_WRSTI3, IdString(), PLACE_FIFO_WRSTI3, lut_only, lut_and_ff, dff_only); pack_xrf_input_and_output(&ci, ci.name, id_WRSTI3, IdString(), PLACE_FIFO_WRSTI3, lut_only, lut_and_ff,
pack_xrf_input_and_output(&ci, ci.name, id_WRSTI4, IdString(), PLACE_FIFO_WRSTI4, lut_only, lut_and_ff, dff_only); dff_only);
pack_xrf_input_and_output(&ci, ci.name, id_WRSTI4, IdString(), PLACE_FIFO_WRSTI4, lut_only, lut_and_ff,
dff_only);
} }
} else { } else {
disconnect_unused(&ci, id_WRSTI); disconnect_unused(&ci, id_WRSTI);
@ -1490,12 +1565,17 @@ void NgUltraPacker::pack_fifos(void)
ci.disconnectPort(port); ci.disconnectPort(port);
for (int i = 1; i <= rsti; i++) for (int i = 1; i <= rsti; i++)
ci.connectPort(ctx->idf("RRSTI%d", i), rrsti_net); ci.connectPort(ctx->idf("RRSTI%d", i), rrsti_net);
if (mode!=0) disconnect_unused(&ci, id_RRSTO); if (mode != 0)
pack_xrf_input_and_output(&ci, ci.name, id_RRSTI1, id_RRSTO, PLACE_FIFO_RRSTI1, lut_only, lut_and_ff, dff_only); disconnect_unused(&ci, id_RRSTO);
pack_xrf_input_and_output(&ci, ci.name, id_RRSTI2, IdString(), PLACE_FIFO_RRSTI2, lut_only, lut_and_ff, dff_only); pack_xrf_input_and_output(&ci, ci.name, id_RRSTI1, id_RRSTO, PLACE_FIFO_RRSTI1, lut_only, lut_and_ff,
dff_only);
pack_xrf_input_and_output(&ci, ci.name, id_RRSTI2, IdString(), PLACE_FIFO_RRSTI2, lut_only, lut_and_ff,
dff_only);
if (mode != 0) { if (mode != 0) {
pack_xrf_input_and_output(&ci, ci.name, id_RRSTI3, IdString(), PLACE_FIFO_RRSTI3, lut_only, lut_and_ff, dff_only); pack_xrf_input_and_output(&ci, ci.name, id_RRSTI3, IdString(), PLACE_FIFO_RRSTI3, lut_only, lut_and_ff,
pack_xrf_input_and_output(&ci, ci.name, id_RRSTI4, IdString(), PLACE_FIFO_RRSTI4, lut_only, lut_and_ff, dff_only); dff_only);
pack_xrf_input_and_output(&ci, ci.name, id_RRSTI4, IdString(), PLACE_FIFO_RRSTI4, lut_only, lut_and_ff,
dff_only);
} }
} else { } else {
disconnect_unused(&ci, id_RRSTI); disconnect_unused(&ci, id_RRSTI);
@ -1503,7 +1583,8 @@ void NgUltraPacker::pack_fifos(void)
for (int i = 1; i <= 18; i++) { for (int i = 1; i <= 18; i++) {
connect_gnd_if_unconnected(&ci, ctx->idf("I%d", i)); connect_gnd_if_unconnected(&ci, ctx->idf("I%d", i));
pack_xrf_input_and_output(&ci, ci.name, ctx->idf("I%d",i), ctx->idf("O%d",i), ClusterPlacement(PLACE_FIFO_I1 + i-1), lut_only, lut_and_ff, dff_only); pack_xrf_input_and_output(&ci, ci.name, ctx->idf("I%d", i), ctx->idf("O%d", i),
ClusterPlacement(PLACE_FIFO_I1 + i - 1), lut_only, lut_and_ff, dff_only);
} }
if (mode == 0) { if (mode == 0) {
@ -1514,15 +1595,18 @@ void NgUltraPacker::pack_fifos(void)
} else { } else {
for (int i = 19; i <= 36; i++) { for (int i = 19; i <= 36; i++) {
connect_gnd_if_unconnected(&ci, ctx->idf("I%d", i)); connect_gnd_if_unconnected(&ci, ctx->idf("I%d", i));
pack_xrf_input_and_output(&ci, ci.name, ctx->idf("I%d",i), ctx->idf("O%d",i), ClusterPlacement(PLACE_FIFO_I1 + i-1), lut_only, lut_and_ff, dff_only); pack_xrf_input_and_output(&ci, ci.name, ctx->idf("I%d", i), ctx->idf("O%d", i),
ClusterPlacement(PLACE_FIFO_I1 + i - 1), lut_only, lut_and_ff, dff_only);
} }
} }
for (int i = 1; i <= 6; i++) { for (int i = 1; i <= 6; i++) {
connect_gnd_if_unconnected(&ci, ctx->idf("RAI%d", i)); connect_gnd_if_unconnected(&ci, ctx->idf("RAI%d", i));
pack_xrf_input_and_output(&ci, ci.name, ctx->idf("RAI%d",i), ctx->idf("RAO%d",i), ClusterPlacement(PLACE_FIFO_RAI1 + i-1), lut_only, lut_and_ff, dff_only); pack_xrf_input_and_output(&ci, ci.name, ctx->idf("RAI%d", i), ctx->idf("RAO%d", i),
ClusterPlacement(PLACE_FIFO_RAI1 + i - 1), lut_only, lut_and_ff, dff_only);
connect_gnd_if_unconnected(&ci, ctx->idf("WAI%d", i)); connect_gnd_if_unconnected(&ci, ctx->idf("WAI%d", i));
pack_xrf_input_and_output(&ci, ci.name, ctx->idf("WAI%d",i), ctx->idf("WAO%d",i), ClusterPlacement(PLACE_FIFO_WAI1 + i-1), lut_only, lut_and_ff, dff_only); pack_xrf_input_and_output(&ci, ci.name, ctx->idf("WAI%d", i), ctx->idf("WAO%d", i),
ClusterPlacement(PLACE_FIFO_WAI1 + i - 1), lut_only, lut_and_ff, dff_only);
} }
if (mode == 0) { if (mode == 0) {
@ -1545,17 +1629,23 @@ void NgUltraPacker::pack_fifos(void)
if (mode == 0) { if (mode == 0) {
// FIFO // FIFO
ci.renamePort(id_WEQ1, id_WEQ); ci.renamePort(id_WEQ1, id_WEQ);
pack_xrf_input_and_output(&ci, ci.name, IdString(), id_WEQ, PLACE_FIFO_WEQ1, lut_only, lut_and_ff, dff_only); pack_xrf_input_and_output(&ci, ci.name, IdString(), id_WEQ, PLACE_FIFO_WEQ1, lut_only, lut_and_ff,
dff_only);
disconnect_unused(&ci, id_WEQ2); disconnect_unused(&ci, id_WEQ2);
ci.renamePort(id_REQ1, id_REQ); ci.renamePort(id_REQ1, id_REQ);
pack_xrf_input_and_output(&ci, ci.name, IdString(), id_REQ, PLACE_FIFO_REQ1, lut_only, lut_and_ff, dff_only); pack_xrf_input_and_output(&ci, ci.name, IdString(), id_REQ, PLACE_FIFO_REQ1, lut_only, lut_and_ff,
dff_only);
disconnect_unused(&ci, id_REQ2); disconnect_unused(&ci, id_REQ2);
} else { } else {
pack_xrf_input_and_output(&ci, ci.name, IdString(), id_WEQ1, PLACE_FIFO_WEQ1, lut_only, lut_and_ff, dff_only); pack_xrf_input_and_output(&ci, ci.name, IdString(), id_WEQ1, PLACE_FIFO_WEQ1, lut_only, lut_and_ff,
pack_xrf_input_and_output(&ci, ci.name, IdString(), id_WEQ2, PLACE_FIFO_WEQ2, lut_only, lut_and_ff, dff_only); dff_only);
pack_xrf_input_and_output(&ci, ci.name, IdString(), id_WEQ1, PLACE_FIFO_REQ1, lut_only, lut_and_ff, dff_only); pack_xrf_input_and_output(&ci, ci.name, IdString(), id_WEQ2, PLACE_FIFO_WEQ2, lut_only, lut_and_ff,
pack_xrf_input_and_output(&ci, ci.name, IdString(), id_WEQ2, PLACE_FIFO_REQ2, lut_only, lut_and_ff, dff_only); dff_only);
pack_xrf_input_and_output(&ci, ci.name, IdString(), id_WEQ1, PLACE_FIFO_REQ1, lut_only, lut_and_ff,
dff_only);
pack_xrf_input_and_output(&ci, ci.name, IdString(), id_WEQ2, PLACE_FIFO_REQ2, lut_only, lut_and_ff,
dff_only);
// XFIFO // XFIFO
ci.ports[id_WCK1].name = id_WCK1; ci.ports[id_WCK1].name = id_WCK1;
@ -1581,7 +1671,6 @@ void NgUltraPacker::pack_fifos(void)
ci.connectPort(id_RCK2, net); ci.connectPort(id_RCK2, net);
} }
} }
} }
if (lut_only) if (lut_only)
log_info(" %6d FEs used as LUT only\n", lut_only); log_info(" %6d FEs used as LUT only\n", lut_only);
@ -1609,7 +1698,8 @@ void NgUltraPacker::insert_ioms()
if (uarch->global_capable_bels.count(bel) == 0) if (uarch->global_capable_bels.count(bel) == 0)
continue; continue;
for (const auto &usr : ni->users) { for (const auto &usr : ni->users) {
if (uarch->is_fabric_lowskew_sink(usr) || uarch->is_ring_clock_sink(usr) || uarch->is_tube_clock_sink(usr) || uarch->is_ring_over_tile_clock_sink(usr)) { if (uarch->is_fabric_lowskew_sink(usr) || uarch->is_ring_clock_sink(usr) ||
uarch->is_tube_clock_sink(usr) || uarch->is_ring_over_tile_clock_sink(usr)) {
pins_needing_iom.emplace_back(ni->name); pins_needing_iom.emplace_back(ni->name);
break; break;
} }
@ -1693,7 +1783,8 @@ void NgUltraPacker::insert_wfbs()
void NgUltraPacker::mandatory_param(CellInfo *cell, IdString param) void NgUltraPacker::mandatory_param(CellInfo *cell, IdString param)
{ {
if (!cell->params.count(param)) if (!cell->params.count(param))
log_error("Mandatory parameter '%s' of cell '%s'(%s) is missing.\n", param.c_str(ctx), cell->name.c_str(ctx), cell->type.c_str(ctx)); log_error("Mandatory parameter '%s' of cell '%s'(%s) is missing.\n", param.c_str(ctx), cell->name.c_str(ctx),
cell->type.c_str(ctx));
} }
int NgUltraPacker::memory_width(int config, bool ecc) int NgUltraPacker::memory_width(int config, bool ecc)
@ -1704,16 +1795,23 @@ int NgUltraPacker::memory_width(int config, bool ecc)
else else
log_error("ECC mode only support width of 18.\n"); log_error("ECC mode only support width of 18.\n");
} else { } else {
switch(config) switch (config) {
{ case 0:
case 0: return 1; // NOECC_48kx1 return 1; // NOECC_48kx1
case 1: return 2; // NOECC_24kx2 case 1:
case 2: return 4; // NOECC_12kx4 return 2; // NOECC_24kx2
case 3: return 8; // NOECC_6kx8 case 2:
case 4: return 12; // NOECC_4kx12 return 4; // NOECC_12kx4
case 5: return 24; // NOECC_2kx24 case 3:
case 6: return 3; // NOECC_16kx3 return 8; // NOECC_6kx8
case 7: return 6; // NOECC_8kx6 case 4:
return 12; // NOECC_4kx12
case 5:
return 24; // NOECC_2kx24
case 6:
return 3; // NOECC_16kx3
case 7:
return 6; // NOECC_8kx6
} }
log_error("Unknown memory configuration width config '%d'.\n", config); log_error("Unknown memory configuration width config '%d'.\n", config);
} }
@ -1727,16 +1825,23 @@ int NgUltraPacker::memory_addr_bits(int config,bool ecc)
else else
log_error("ECC mode only support width of 18.\n"); log_error("ECC mode only support width of 18.\n");
} else { } else {
switch(config) switch (config) {
{ case 0:
case 0: return 16; // NOECC_48kx1 return 16; // NOECC_48kx1
case 1: return 15; // NOECC_24kx2 case 1:
case 2: return 14; // NOECC_12kx4 return 15; // NOECC_24kx2
case 3: return 13; // NOECC_6kx8 case 2:
case 4: return 12; // NOECC_4kx12 return 14; // NOECC_12kx4
case 5: return 11; // NOECC_2kx24 case 3:
case 6: return 14; // NOECC_16kx3 return 13; // NOECC_6kx8
case 7: return 13; // NOECC_8kx6 case 4:
return 12; // NOECC_4kx12
case 5:
return 11; // NOECC_2kx24
case 6:
return 14; // NOECC_16kx3
case 7:
return 13; // NOECC_8kx6
} }
log_error("Unknown memory configuration width config '%d'.\n", config); log_error("Unknown memory configuration width config '%d'.\n", config);
} }
@ -1745,20 +1850,24 @@ int NgUltraPacker::memory_addr_bits(int config,bool ecc)
void NgUltraPacker::insert_wfb(CellInfo *cell, IdString port) void NgUltraPacker::insert_wfb(CellInfo *cell, IdString port)
{ {
NetInfo *net = cell->getPort(port); NetInfo *net = cell->getPort(port);
if (!net) return; if (!net)
return;
CellInfo *wfg = net_only_drives(ctx, net, is_wfg, id_ZI, true); CellInfo *wfg = net_only_drives(ctx, net, is_wfg, id_ZI, true);
if (wfg) return; if (wfg)
return;
bool in_fabric = false; bool in_fabric = false;
bool in_ring = false; bool in_ring = false;
for (const auto &usr : net->users) { for (const auto &usr : net->users) {
if (uarch->is_fabric_lowskew_sink(usr) || uarch->is_tube_clock_sink(usr) || uarch->is_ring_over_tile_clock_sink(usr)) if (uarch->is_fabric_lowskew_sink(usr) || uarch->is_tube_clock_sink(usr) ||
uarch->is_ring_over_tile_clock_sink(usr))
in_fabric = true; in_fabric = true;
else else
in_ring = true; in_ring = true;
} }
// If all in ring and none in fabric no need for WFB // If all in ring and none in fabric no need for WFB
if (in_ring && !in_fabric) return; if (in_ring && !in_fabric)
return;
log_info(" Inserting WFB for cell '%s' port '%s'\n", cell->name.c_str(ctx), port.c_str(ctx)); log_info(" Inserting WFB for cell '%s' port '%s'\n", cell->name.c_str(ctx), port.c_str(ctx));
CellInfo *wfb = create_cell_ptr(id_WFB, ctx->idf("%s$%s", cell->name.c_str(ctx), port.c_str(ctx))); CellInfo *wfb = create_cell_ptr(id_WFB, ctx->idf("%s$%s", cell->name.c_str(ctx), port.c_str(ctx)));
if (in_ring && in_fabric) { if (in_ring && in_fabric) {
@ -1792,7 +1901,8 @@ void NgUltraPacker::constrain_location(CellInfo *cell)
log_error("Location '%s' is wrong for bel type '%s'.\n", location.c_str(), cell->type.c_str(ctx)); log_error("Location '%s' is wrong for bel type '%s'.\n", location.c_str(), cell->type.c_str(ctx));
} }
if (ctx->checkBelAvail(bel)) { if (ctx->checkBelAvail(bel)) {
log_info(" Constraining %s '%s' to '%s'\n", cell->type.c_str(ctx), cell->name.c_str(ctx), location.c_str()); log_info(" Constraining %s '%s' to '%s'\n", cell->type.c_str(ctx), cell->name.c_str(ctx),
location.c_str());
ctx->bindBel(bel, cell, PlaceStrength::STRENGTH_LOCKED); ctx->bindBel(bel, cell, PlaceStrength::STRENGTH_LOCKED);
} else { } else {
log_error("Bel at location '%s' is already used by other cell.\n", location.c_str()); log_error("Bel at location '%s' is already used by other cell.\n", location.c_str());
@ -1858,7 +1968,6 @@ void NgUltraPacker::pack_wfgs(void)
NetInfo *zo = ci.getPort(id_ZO); NetInfo *zo = ci.getPort(id_ZO);
if (!zo || zo->users.entries() == 0) if (!zo || zo->users.entries() == 0)
log_error("WFG port ZO of '%s' must be connected.\n", ci.name.c_str(ctx)); log_error("WFG port ZO of '%s' must be connected.\n", ci.name.c_str(ctx));
} }
} }
@ -1881,7 +1990,8 @@ void NgUltraPacker::pack_gcks(void)
disconnect_unused(&ci, id_SI2); disconnect_unused(&ci, id_SI2);
} else if (mode == "MUX") { } else if (mode == "MUX") {
// all used // all used
} else log_error("Unknown mode '%s' for cell '%s'.\n", mode.c_str(), ci.name.c_str(ctx)); } else
log_error("Unknown mode '%s' for cell '%s'.\n", mode.c_str(), ci.name.c_str(ctx));
if (net_driven_by(ctx, ci.getPort(id_SI1), is_gck, id_SO) || if (net_driven_by(ctx, ci.getPort(id_SI1), is_gck, id_SO) ||
net_driven_by(ctx, ci.getPort(id_SI2), is_gck, id_SO) || net_driven_by(ctx, ci.getPort(id_SI2), is_gck, id_SO) ||
@ -1923,7 +2033,6 @@ void NgUltraPacker::pack_rams(void)
int b_addr = std::max(memory_addr_bits((bits[3] ? 1 : 0) | (bits[4] ? 2 : 0) | (bits[5] ? 4 : 0), ecc), int b_addr = std::max(memory_addr_bits((bits[3] ? 1 : 0) | (bits[4] ? 2 : 0) | (bits[5] ? 4 : 0), ecc),
memory_addr_bits((bits[9] ? 1 : 0) | (bits[10] ? 2 : 0) | (bits[11] ? 4 : 0), ecc)); memory_addr_bits((bits[9] ? 1 : 0) | (bits[10] ? 2 : 0) | (bits[11] ? 4 : 0), ecc));
NetInfo *a_cs = ci.getPort(id_ACS); NetInfo *a_cs = ci.getPort(id_ACS);
if (!a_cs || a_cs->name.in(ctx->id("$PACKER_GND"))) { if (!a_cs || a_cs->name.in(ctx->id("$PACKER_GND"))) {
// If there is no chip-select disconnect all // If there is no chip-select disconnect all
@ -2038,10 +2147,12 @@ void NgUltraPacker::pack_dsps(void)
} }
for (auto root : root_dsps) { for (auto root : root_dsps) {
CellInfo *dsp = root; CellInfo *dsp = root;
if (dsp_output.count(dsp->name)==0) continue; if (dsp_output.count(dsp->name) == 0)
continue;
root->cluster = root->name; root->cluster = root->name;
while (true) { while (true) {
if (dsp_output.count(dsp->name)==0) break; if (dsp_output.count(dsp->name) == 0)
break;
dsp = dsp_output[dsp->name]; dsp = dsp_output[dsp->name];
dsp->cluster = root->name; dsp->cluster = root->name;
root->constr_children.push_back(dsp); root->constr_children.push_back(dsp);
@ -2065,7 +2176,6 @@ void NgUltraPacker::remove_not_used()
} }
} }
void NgUltraImpl::pack() void NgUltraImpl::pack()
{ {
const ArchArgs &args = ctx->args; const ArchArgs &args = ctx->args;
@ -2119,7 +2229,8 @@ IdString NgUltraPacker::assign_wfg(IdString ckg, IdString ckg2, CellInfo *cell)
if (item.second == ckg || item.second == ckg2) { if (item.second == ckg || item.second == ckg2) {
IdString ckg = item.second; IdString ckg = item.second;
uarch->unused_wfg.erase(bel); uarch->unused_wfg.erase(bel);
log_info(" Using '%s:%s' for cell '%s'.\n", uarch->tile_name(bel.tile).c_str(), ctx->getBelName(bel)[1].c_str(ctx), cell->name.c_str(ctx)); log_info(" Using '%s:%s' for cell '%s'.\n", uarch->tile_name(bel.tile).c_str(),
ctx->getBelName(bel)[1].c_str(ctx), cell->name.c_str(ctx));
ctx->bindBel(bel, cell, PlaceStrength::STRENGTH_LOCKED); ctx->bindBel(bel, cell, PlaceStrength::STRENGTH_LOCKED);
return ckg; return ckg;
} }
@ -2127,7 +2238,8 @@ IdString NgUltraPacker::assign_wfg(IdString ckg, IdString ckg2, CellInfo *cell)
log_error(" No more available WFGs for cell '%s'.\n", cell->name.c_str(ctx)); log_error(" No more available WFGs for cell '%s'.\n", cell->name.c_str(ctx));
} }
void NgUltraPacker::extract_lowskew_signals(CellInfo *cell, dict<IdString,dict<IdString,std::vector<PortRef>>> &lowskew_signals) void NgUltraPacker::extract_lowskew_signals(CellInfo *cell,
dict<IdString, dict<IdString, std::vector<PortRef>>> &lowskew_signals)
{ {
IdString loc; IdString loc;
if (cell->bel != BelId()) if (cell->bel != BelId())
@ -2175,7 +2287,8 @@ void NgUltraPacker::pre_place(void)
std::pair<IdString, IdString> &ckgs = uarch->bank_to_ckg[bank]; std::pair<IdString, IdString> &ckgs = uarch->bank_to_ckg[bank];
if (item.second == ckgs.first || item.second == ckgs.second) { if (item.second == ckgs.first || item.second == ckgs.second) {
uarch->unused_pll.erase(bel); uarch->unused_pll.erase(bel);
log_info(" Using PLL in '%s' for cell '%s'.\n", uarch->tile_name(bel.tile).c_str(), ci.name.c_str(ctx)); log_info(" Using PLL in '%s' for cell '%s'.\n", uarch->tile_name(bel.tile).c_str(),
ci.name.c_str(ctx));
ctx->bindBel(bel, &ci, PlaceStrength::STRENGTH_LOCKED); ctx->bindBel(bel, &ci, PlaceStrength::STRENGTH_LOCKED);
// found = true; // found = true;
break; break;
@ -2221,8 +2334,10 @@ void NgUltraPacker::pre_place(void)
if (zo_net->users.entries() != 1) if (zo_net->users.entries() != 1)
log_error("WFG can only be chained with one other WFG cell\n"); log_error("WFG can only be chained with one other WFG cell\n");
group.push_back(wfg); group.push_back(wfg);
} else break; } else
} else break; break;
} else
break;
} }
groups.push_back(group); groups.push_back(group);
} }
@ -2286,10 +2401,14 @@ void NgUltraPacker::pre_place(void)
} }
if (net->driver.cell->type.in(id_BEYOND_FE)) { if (net->driver.cell->type.in(id_BEYOND_FE)) {
CellInfo *fe = net->driver.cell; CellInfo *fe = net->driver.cell;
if (!fe->params.count(id_lut_table)) continue; if (!fe->params.count(id_lut_table))
if (fe->params.count(id_dff_used)) continue; continue;
if (fe->params[id_lut_table] != Property(0x5555, 16)) continue; if (fe->params.count(id_dff_used))
if (!fe->getPort(id_I1)) continue; continue;
if (fe->params[id_lut_table] != Property(0x5555, 16))
continue;
if (!fe->getPort(id_I1))
continue;
CellInfo *bfr = fe->getPort(id_I1)->driver.cell; CellInfo *bfr = fe->getPort(id_I1)->driver.cell;
if (bfr->type.in(id_BFR, id_DFR, id_DDFR)) { if (bfr->type.in(id_BFR, id_DFR, id_DDFR)) {
CellInfo *gck_cell = create_cell_ptr(id_GCK, ctx->idf("%s$csc", bfr->name.c_str(ctx))); CellInfo *gck_cell = create_cell_ptr(id_GCK, ctx->idf("%s$csc", bfr->name.c_str(ctx)));
@ -2333,7 +2452,8 @@ void NgUltraImpl::postPlace()
const auto &extra_data = *bel_extra_data(ci.bel); const auto &extra_data = *bel_extra_data(ci.bel);
// Check if CSC mode only if FE is capable // Check if CSC mode only if FE is capable
if ((extra_data.flags & BEL_EXTRA_FE_CSC)) { if ((extra_data.flags & BEL_EXTRA_FE_CSC)) {
if (str_or_default(ci.params, id_type, "")=="CSC") continue; if (str_or_default(ci.params, id_type, "") == "CSC")
continue;
// Disable routing to S output if CSC is not used // Disable routing to S output if CSC is not used
disable_beyond_fe_s_output(ci.bel); disable_beyond_fe_s_output(ci.bel);
} }
@ -2383,7 +2503,8 @@ BelId NgUltraPacker::getCSC(Loc l, int row)
for (int j = 0; j < 3; j++) { for (int j = 0; j < 3; j++) {
for (int i = 0; i < 4; i++) { for (int i = 0; i < 4; i++) {
BelId bel = ctx->getBelByLocation(Loc(l.x + j + 1, l.y + j % 2 + 2, z_loc[i])); BelId bel = ctx->getBelByLocation(Loc(l.x + j + 1, l.y + j % 2 + 2, z_loc[i]));
if (!ctx->getBoundBelCell(bel) && (row==0 || row==(i+1))) return bel; if (!ctx->getBoundBelCell(bel) && (row == 0 || row == (i + 1)))
return bel;
} }
} }
return BelId(); return BelId();
@ -2416,9 +2537,11 @@ void NgUltraPacker::insert_csc()
NetInfo *net = ctx->nets.at(n.second).get(); NetInfo *net = ctx->nets.at(n.second).get();
CellInfo *cell = net->driver.cell; CellInfo *cell = net->driver.cell;
if (uarch->tile_name(cell->bel.tile) == lsm.first.c_str(ctx) && !cell->params.count(id_dff_used) && cell->cluster == ClusterId()) { if (uarch->tile_name(cell->bel.tile) == lsm.first.c_str(ctx) && !cell->params.count(id_dff_used) &&
cell->cluster == ClusterId()) {
BelId newbel = getCSC(loc, 0); BelId newbel = getCSC(loc, 0);
if (newbel==BelId()) break; if (newbel == BelId())
break;
ctx->unbindBel(cell->bel); ctx->unbindBel(cell->bel);
cell->disconnectPort(id_LO); cell->disconnectPort(id_LO);
@ -2436,11 +2559,15 @@ void NgUltraPacker::insert_csc()
} }
Loc cell_loc = ctx->getBelLocation(cell->bel); Loc cell_loc = ctx->getBelLocation(cell->bel);
BelId newbel = getCSC(loc, (cell_loc.y & 3) + 1); // Take CSC from pefered row BelId newbel = getCSC(loc, (cell_loc.y & 3) + 1); // Take CSC from pefered row
if (newbel==BelId()) newbel = getCSC(loc,0); // Try getting any other CSC if (newbel == BelId())
if (newbel==BelId()) break; newbel = getCSC(loc, 0); // Try getting any other CSC
if (lsm.second[n.second].size() < 4) break; if (newbel == BelId())
break;
if (lsm.second[n.second].size() < 4)
break;
CellInfo *fe = create_cell_ptr(id_BEYOND_FE, ctx->idf("%s$%s$csc", net->name.c_str(ctx), lsm.first.c_str(ctx))); CellInfo *fe =
create_cell_ptr(id_BEYOND_FE, ctx->idf("%s$%s$csc", net->name.c_str(ctx), lsm.first.c_str(ctx)));
NetInfo *new_out = ctx->createNet(ctx->idf("%s$o", fe->name.c_str(ctx))); NetInfo *new_out = ctx->createNet(ctx->idf("%s$o", fe->name.c_str(ctx)));
fe->params[id_lut_table] = Property(0xaaaa, 16); fe->params[id_lut_table] = Property(0xaaaa, 16);
fe->params[id_lut_used] = Property(1, 1); fe->params[id_lut_used] = Property(1, 1);
@ -2463,23 +2590,29 @@ void NgUltraPacker::insert_csc()
log_info(" %6d FEs inserted as CSC\n", insert_new_csc); log_info(" %6d FEs inserted as CSC\n", insert_new_csc);
if (change_to_csc) if (change_to_csc)
log_info(" %6d FEs converted to CSC\n", change_to_csc); log_info(" %6d FEs converted to CSC\n", change_to_csc);
} }
BelId NgUltraPacker::get_available_gck(int lobe, NetInfo *si1, NetInfo *si2) BelId NgUltraPacker::get_available_gck(int lobe, NetInfo *si1, NetInfo *si2)
{ {
auto &gcks = uarch->gck_per_lobe[lobe]; auto &gcks = uarch->gck_per_lobe[lobe];
for (int i = 0; i < 20; i++) { for (int i = 0; i < 20; i++) {
auto &g = gcks.at(i); auto &g = gcks.at(i);
if (g.used) continue; if (g.used)
if (si1 && g.si1!=IdString() && g.si1!=si1->name) continue; continue;
if (si2 && g.si2!=IdString() && g.si2!=si2->name) continue; if (si1 && g.si1 != IdString() && g.si1 != si1->name)
if (si1) g.si1 = si1->name; continue;
if (si2) g.si2 = si2->name; if (si2 && g.si2 != IdString() && g.si2 != si2->name)
continue;
if (si1)
g.si1 = si1->name;
if (si2)
g.si2 = si2->name;
g.used = true; g.used = true;
if (i % 2 == 0) { if (i % 2 == 0) {
// next GCK share inputs in reverse order // next GCK share inputs in reverse order
if (si2) gcks.at(i+1).si1 = si2->name; if (si2)
if (si1) gcks.at(i+1).si2 = si1->name; gcks.at(i + 1).si1 = si2->name;
if (si1)
gcks.at(i + 1).si2 = si1->name;
} }
return g.bel; return g.bel;
} }
@ -2536,9 +2669,12 @@ void NgUltraPacker::duplicate_gck()
log_info(" Create GCK '%s' for lobe %d\n", gck_cell->name.c_str(ctx), conn.first); log_info(" Create GCK '%s' for lobe %d\n", gck_cell->name.c_str(ctx), conn.first);
for (auto &params : driver->params) for (auto &params : driver->params)
gck_cell->params[params.first] = params.second; gck_cell->params[params.first] = params.second;
if (si1) gck_cell->connectPort(id_SI1, si1); if (si1)
if (si2) gck_cell->connectPort(id_SI2, si2); gck_cell->connectPort(id_SI1, si1);
if (cmd) gck_cell->connectPort(id_CMD, cmd); if (si2)
gck_cell->connectPort(id_SI2, si2);
if (cmd)
gck_cell->connectPort(id_CMD, cmd);
} }
gck_cell->disconnectPort(id_SO); gck_cell->disconnectPort(id_SO);
NetInfo *new_clk = ctx->createNet(ctx->id(gck_cell->name.str(ctx))); NetInfo *new_clk = ctx->createNet(ctx->id(gck_cell->name.str(ctx)));
@ -2553,7 +2689,6 @@ void NgUltraPacker::duplicate_gck()
cnt++; cnt++;
} }
} }
} }
void NgUltraPacker::insert_bypass_gck() void NgUltraPacker::insert_bypass_gck()

View File

@ -83,9 +83,11 @@ TESTABLE_PRIVATE:
void ddfr_rewrite(CellInfo *cell); void ddfr_rewrite(CellInfo *cell);
void exchange_if_constant(CellInfo *cell, IdString input1, IdString input2); void exchange_if_constant(CellInfo *cell, IdString input1, IdString input2);
void pack_cy_input_and_output(CellInfo *cy, IdString cluster, IdString in_port, IdString out_port, int placer, int &lut_only, int &lut_and_ff, int &dff_only); void pack_cy_input_and_output(CellInfo *cy, IdString cluster, IdString in_port, IdString out_port, int placer,
int &lut_only, int &lut_and_ff, int &dff_only);
void pack_xrf_input_and_output(CellInfo *cy, IdString cluster, IdString in_port, IdString out_port, ClusterPlacement placement, int &lut_only, int &lut_and_ff, int &dff_only); void pack_xrf_input_and_output(CellInfo *cy, IdString cluster, IdString in_port, IdString out_port,
ClusterPlacement placement, int &lut_only, int &lut_and_ff, int &dff_only);
void connect_gnd_if_unconnected(CellInfo *cell, IdString input, bool warn); void connect_gnd_if_unconnected(CellInfo *cell, IdString input, bool warn);
void disconnect_if_gnd(CellInfo *cell, IdString input); void disconnect_if_gnd(CellInfo *cell, IdString input);

View File

@ -18,9 +18,9 @@
*/ */
#include <vector> #include <vector>
#include "command.h"
#include "gtest/gtest.h" #include "gtest/gtest.h"
#include "nextpnr.h" #include "nextpnr.h"
#include "command.h"
#include "uarch/ng-ultra/ng_ultra.h" #include "uarch/ng-ultra/ng_ultra.h"
#include "uarch/ng-ultra/pack.h" #include "uarch/ng-ultra/pack.h"
#define HIMBAECHEL_CONSTIDS "uarch/ng-ultra/constids.inc" #define HIMBAECHEL_CONSTIDS "uarch/ng-ultra/constids.inc"

View File

@ -18,8 +18,8 @@
*/ */
#include <vector> #include <vector>
#include "log.h"
#include "gtest/gtest.h" #include "gtest/gtest.h"
#include "log.h"
USING_NEXTPNR_NAMESPACE USING_NEXTPNR_NAMESPACE