diff options
Diffstat (limited to 'ecp5/pack.cc')
-rw-r--r-- | ecp5/pack.cc | 152 |
1 files changed, 89 insertions, 63 deletions
diff --git a/ecp5/pack.cc b/ecp5/pack.cc index 9e2bc326..7cf9df78 100644 --- a/ecp5/pack.cc +++ b/ecp5/pack.cc @@ -204,6 +204,8 @@ class Ecp5Packer } } for (const char *inp : {"A", "B", "C", "D"}) { + if (!ci->ports.count(ctx->id(inp))) + continue; NetInfo *innet = ci->ports.at(ctx->id(inp)).net; if (innet != nullptr && innet->driver.cell != nullptr) { CellInfo *drv = innet->driver.cell; @@ -258,6 +260,8 @@ class Ecp5Packer // Pack LUTs sharing an input with a simple fanout-based heuristic for (const char *inp : {"A", "B", "C", "D"}) { + if (!ci->ports.count(ctx->id(inp))) + continue; NetInfo *innet = ci->ports.at(ctx->id(inp)).net; if (innet != nullptr && innet->users.size() < 5 && innet->users.size() > 1) inpnets.push_back(innet); @@ -352,7 +356,12 @@ class Ecp5Packer ionet = ci->ports.at(ctx->id("I")).net; trio = net_only_drives(ctx, ci->ports.at(ctx->id("I")).net, is_trellis_io, ctx->id("B"), true, ci); } - if (trio != nullptr) { + if (bool_or_default(ctx->settings, ctx->id("arch.ooc"))) { + // No IO buffer insertion in out-of-context mode, just remove the nextpnr buffer + // and leave the top level port + for (auto &port : ci->ports) + disconnect_port(ctx, ci, port.first); + } else if (trio != nullptr) { // Trivial case, TRELLIS_IO used. Just destroy the net and the // iobuf log_info("%s feeds TRELLIS_IO %s, removing %s %s.\n", ci->name.c_str(ctx), trio->name.c_str(ctx), @@ -406,7 +415,7 @@ class Ecp5Packer auto loc_attr = trio->attrs.find(ctx->id("LOC")); if (loc_attr != trio->attrs.end()) { - std::string pin = loc_attr->second; + std::string pin = loc_attr->second.as_string(); BelId pinBel = ctx->getPackagePinBel(pin); if (pinBel == BelId()) { log_error("IO pin '%s' constrained to pin '%s', which does not exist for package '%s'.\n", @@ -456,8 +465,10 @@ class Ecp5Packer replace_port(lut1, ctx->id("D"), packed.get(), ctx->id("D1")); replace_port(ci, ctx->id("C0"), packed.get(), ctx->id("M0")); replace_port(ci, ctx->id("Z"), packed.get(), ctx->id("OFX0")); - packed->params[ctx->id("LUT0_INITVAL")] = str_or_default(lut0->params, ctx->id("INIT"), "0"); - packed->params[ctx->id("LUT1_INITVAL")] = str_or_default(lut1->params, ctx->id("INIT"), "0"); + packed->params[ctx->id("LUT0_INITVAL")] = + get_or_default(lut0->params, ctx->id("INIT"), Property(0, 16)); + packed->params[ctx->id("LUT1_INITVAL")] = + get_or_default(lut1->params, ctx->id("INIT"), Property(0, 16)); ctx->nets.erase(f0->name); ctx->nets.erase(f1->name); @@ -637,10 +648,10 @@ class Ecp5Packer { std::unique_ptr<CellInfo> feedin = create_ecp5_cell(ctx, ctx->id("CCU2C")); - feedin->params[ctx->id("INIT0")] = "10"; // LUT4 = 0; LUT2 = A - feedin->params[ctx->id("INIT1")] = "65535"; - feedin->params[ctx->id("INJECT1_0")] = "NO"; - feedin->params[ctx->id("INJECT1_1")] = "YES"; + feedin->params[ctx->id("INIT0")] = Property(10, 16); // LUT4 = 0; LUT2 = A + feedin->params[ctx->id("INIT1")] = Property(65535, 16); + feedin->params[ctx->id("INJECT1_0")] = std::string("NO"); + feedin->params[ctx->id("INJECT1_1")] = std::string("YES"); carry->users.erase(std::remove_if(carry->users.begin(), carry->users.end(), [chain_in](const PortRef &user) { @@ -667,10 +678,11 @@ class Ecp5Packer CellInfo *make_carry_feed_out(NetInfo *carry, boost::optional<PortRef> chain_next = boost::optional<PortRef>()) { std::unique_ptr<CellInfo> feedout = create_ecp5_cell(ctx, ctx->id("CCU2C")); - feedout->params[ctx->id("INIT0")] = "0"; - feedout->params[ctx->id("INIT1")] = "10"; // LUT4 = 0; LUT2 = A - feedout->params[ctx->id("INJECT1_0")] = "NO"; - feedout->params[ctx->id("INJECT1_1")] = "NO"; + + feedout->params[ctx->id("INIT0")] = Property(0, 16); + feedout->params[ctx->id("INIT1")] = Property(10, 16); // LUT4 = 0; LUT2 = A + feedout->params[ctx->id("INJECT1_0")] = std::string("NO"); + feedout->params[ctx->id("INJECT1_1")] = std::string("NO"); PortRef carry_drv = carry->driver; carry->driver.cell = nullptr; @@ -1052,7 +1064,7 @@ class Ecp5Packer int index = std::string("ABCD").find(input.str(ctx)); int init = int_or_default(cell->params, ctx->id("INIT")); int new_init = make_init_with_const_input(init, index, value); - cell->params[ctx->id("INIT")] = std::to_string(new_init); + cell->params[ctx->id("INIT")] = Property(new_init, 16); cell->ports.at(input).net = nullptr; } @@ -1063,7 +1075,7 @@ class Ecp5Packer int index = std::string("ABCD").find(input_str[0]); int init = int_or_default(cell->params, ctx->id("INIT" + std::to_string(lut))); int new_init = make_init_with_const_input(init, index, value); - cell->params[ctx->id("INIT" + std::to_string(lut))] = std::to_string(new_init); + cell->params[ctx->id("INIT" + std::to_string(lut))] = Property(new_init, 16); cell->ports.at(input).net = nullptr; } @@ -1091,7 +1103,7 @@ class Ecp5Packer if (is_lut(ctx, uc)) { set_lut_input_constant(uc, user.port, constval); } else if (is_ff(ctx, uc) && user.port == ctx->id("CE")) { - uc->params[ctx->id("CEMUX")] = constval ? "1" : "0"; + uc->params[ctx->id("CEMUX")] = std::string(constval ? "1" : "0"); uc->ports[user.port].net = nullptr; } else if (is_carry(ctx, uc)) { if (constval && @@ -1137,7 +1149,7 @@ class Ecp5Packer uc->params[ctx->id(user.port.str(ctx) + "MUX")] = constval ? user.port.str(ctx) : "INV"; } else { // Connected to CIB ABCD. Default state is bitstream configurable - uc->params[ctx->id(user.port.str(ctx) + "MUX")] = constval ? "1" : "0"; + uc->params[ctx->id(user.port.str(ctx) + "MUX")] = std::string(constval ? "1" : "0"); } uc->ports[user.port].net = nullptr; } else if (uc->type == id_ALU54B || uc->type == id_MULT18X18D) { @@ -1152,7 +1164,7 @@ class Ecp5Packer constnet->users.push_back(user); } else { // Connected to CIB ABCD. Default state is bitstream configurable - uc->params[ctx->id(user.port.str(ctx) + "MUX")] = constval ? "1" : "0"; + uc->params[ctx->id(user.port.str(ctx) + "MUX")] = std::string(constval ? "1" : "0"); uc->ports[user.port].net = nullptr; } } else { @@ -1170,7 +1182,7 @@ class Ecp5Packer log_info("Packing constants..\n"); std::unique_ptr<CellInfo> gnd_cell = create_ecp5_cell(ctx, ctx->id("LUT4"), "$PACKER_GND"); - gnd_cell->params[ctx->id("INIT")] = "0"; + gnd_cell->params[ctx->id("INIT")] = Property(0, 16); std::unique_ptr<NetInfo> gnd_net = std::unique_ptr<NetInfo>(new NetInfo); gnd_net->name = ctx->id("$PACKER_GND_NET"); gnd_net->driver.cell = gnd_cell.get(); @@ -1178,7 +1190,7 @@ class Ecp5Packer gnd_cell->ports.at(ctx->id("Z")).net = gnd_net.get(); std::unique_ptr<CellInfo> vcc_cell = create_ecp5_cell(ctx, ctx->id("LUT4"), "$PACKER_VCC"); - vcc_cell->params[ctx->id("INIT")] = "65535"; + vcc_cell->params[ctx->id("INIT")] = Property(65535, 16); std::unique_ptr<NetInfo> vcc_net = std::unique_ptr<NetInfo>(new NetInfo); vcc_net->name = ctx->id("$PACKER_VCC_NET"); vcc_net->driver.cell = vcc_cell.get(); @@ -1267,7 +1279,7 @@ class Ecp5Packer autocreate_empty_port(ci, id_WEB); autocreate_empty_port(ci, id_RSTB); - ci->attrs[ctx->id("WID")] = std::to_string(wid++); + ci->attrs[ctx->id("WID")] = wid++; } } } @@ -1317,22 +1329,22 @@ class Ecp5Packer CellInfo *ci = cell.second; if (ci->type == id_DCUA) { if (ci->attrs.count(ctx->id("LOC"))) { - std::string loc = ci->attrs.at(ctx->id("LOC")); + std::string loc = ci->attrs.at(ctx->id("LOC")).as_string(); if (loc == "DCU0" && (ctx->args.type == ArchArgs::LFE5UM_25F || ctx->args.type == ArchArgs::LFE5UM5G_25F)) - ci->attrs[ctx->id("BEL")] = "X42/Y50/DCU"; + ci->attrs[ctx->id("BEL")] = std::string("X42/Y50/DCU"); else if (loc == "DCU0" && (ctx->args.type == ArchArgs::LFE5UM_45F || ctx->args.type == ArchArgs::LFE5UM5G_45F)) - ci->attrs[ctx->id("BEL")] = "X42/Y71/DCU"; + ci->attrs[ctx->id("BEL")] = std::string("X42/Y71/DCU"); else if (loc == "DCU1" && (ctx->args.type == ArchArgs::LFE5UM_45F || ctx->args.type == ArchArgs::LFE5UM5G_45F)) - ci->attrs[ctx->id("BEL")] = "X69/Y71/DCU"; + ci->attrs[ctx->id("BEL")] = std::string("X69/Y71/DCU"); else if (loc == "DCU0" && (ctx->args.type == ArchArgs::LFE5UM_85F || ctx->args.type == ArchArgs::LFE5UM5G_85F)) - ci->attrs[ctx->id("BEL")] = "X46/Y95/DCU"; + ci->attrs[ctx->id("BEL")] = std::string("X46/Y95/DCU"); else if (loc == "DCU1" && (ctx->args.type == ArchArgs::LFE5UM_85F || ctx->args.type == ArchArgs::LFE5UM5G_85F)) - ci->attrs[ctx->id("BEL")] = "X71/Y95/DCU"; + ci->attrs[ctx->id("BEL")] = std::string("X71/Y95/DCU"); else log_error("no DCU location '%s' in device '%s'\n", loc.c_str(), ctx->getChipName().c_str()); } @@ -1368,7 +1380,7 @@ class Ecp5Packer } if (!dcu->attrs.count(ctx->id("BEL"))) log_error("DCU must be constrained to a Bel!\n"); - std::string bel = dcu->attrs.at(ctx->id("BEL")); + std::string bel = dcu->attrs.at(ctx->id("BEL")).as_string(); NPNR_ASSERT(bel.substr(bel.length() - 3) == "DCU"); bel.replace(bel.length() - 3, 3, "EXTREF"); ci->attrs[ctx->id("BEL")] = bel; @@ -1378,7 +1390,7 @@ class Ecp5Packer CellInfo *dcu = clki->driver.cell; if (!dcu->attrs.count(ctx->id("BEL"))) log_error("DCU must be constrained to a Bel!\n"); - BelId bel = ctx->getBelByName(ctx->id(dcu->attrs.at(ctx->id("BEL")))); + BelId bel = ctx->getBelByName(ctx->id(dcu->attrs.at(ctx->id("BEL")).as_string())); if (bel == BelId()) log_error("Invalid DCU bel '%s'\n", dcu->attrs.at(ctx->id("BEL")).c_str()); Loc loc = ctx->getBelLocation(bel); @@ -1414,7 +1426,7 @@ class Ecp5Packer for (auto cell : sorted(ctx->cells)) { CellInfo *ci = cell.second; if (ci->type == id_EHXPLLL && ci->attrs.count(ctx->id("BEL"))) - available_plls.erase(ctx->getBelByName(ctx->id(ci->attrs.at(ctx->id("BEL"))))); + available_plls.erase(ctx->getBelByName(ctx->id(ci->attrs.at(ctx->id("BEL")).as_string()))); } // Place PLL connected to fixed drivers such as IO close to their source for (auto cell : sorted(ctx->cells)) { @@ -1426,7 +1438,7 @@ class Ecp5Packer const CellInfo *drivercell = drivernet->driver.cell; if (!drivercell->attrs.count(ctx->id("BEL"))) continue; - BelId drvbel = ctx->getBelByName(ctx->id(drivercell->attrs.at(ctx->id("BEL")))); + BelId drvbel = ctx->getBelByName(ctx->id(drivercell->attrs.at(ctx->id("BEL")).as_string())); Loc drvloc = ctx->getBelLocation(drvbel); BelId closest_pll; int closest_distance = std::numeric_limits<int>::max(); @@ -1508,8 +1520,7 @@ class Ecp5Packer std::unique_ptr<NetInfo> promoted_ecknet(new NetInfo); promoted_ecknet->name = eckname; - promoted_ecknet->attrs[ctx->id("ECP5_IS_GLOBAL")] = - "1"; // Prevents router etc touching this special net + promoted_ecknet->attrs[ctx->id("ECP5_IS_GLOBAL")] = 1; // Prevents router etc touching this special net eclk.buf = promoted_ecknet.get(); NPNR_ASSERT(!ctx->nets.count(eckname)); ctx->nets[eckname] = std::move(promoted_ecknet); @@ -1621,7 +1632,7 @@ class Ecp5Packer log_error("DQSBUFM can only be used with a pin-constrained PIO connected to its DQSI input" "(while processing '%s').\n", ci->name.c_str(ctx)); - BelId pio_bel = ctx->getBelByName(ctx->id(pio->attrs.at(ctx->id("BEL")))); + BelId pio_bel = ctx->getBelByName(ctx->id(pio->attrs.at(ctx->id("BEL")).as_string())); NPNR_ASSERT(pio_bel != BelId()); Loc pio_loc = ctx->getBelLocation(pio_bel); if (pio_loc.z != 0) @@ -1655,7 +1666,7 @@ class Ecp5Packer port.c_str(ctx), ci->name.c_str(ctx), usr.port.c_str(ctx), usr.cell->name.c_str(ctx)); } - pn->attrs[ctx->id("ECP5_IS_GLOBAL")] = "1"; + pn->attrs[ctx->id("ECP5_IS_GLOBAL")] = 1; } for (auto zport : @@ -1705,9 +1716,9 @@ class Ecp5Packer if (prim->ports.count(port)) sclk = prim->ports[port].net; if (sclk == nullptr) { - iol->params[input ? ctx->id("CLKIMUX") : ctx->id("CLKOMUX")] = "0"; + iol->params[input ? ctx->id("CLKIMUX") : ctx->id("CLKOMUX")] = std::string("0"); } else { - iol->params[input ? ctx->id("CLKIMUX") : ctx->id("CLKOMUX")] = "CLK"; + iol->params[input ? ctx->id("CLKIMUX") : ctx->id("CLKOMUX")] = std::string("CLK"); if (iol->ports[id_CLK].net != nullptr) { if (iol->ports[id_CLK].net != sclk && !equal_constant(iol->ports[id_CLK].net, sclk)) log_error("IOLOGIC '%s' has conflicting clocks '%s' and '%s'\n", iol->name.c_str(ctx), @@ -1743,9 +1754,9 @@ class Ecp5Packer if (prim->ports.count(port)) lsr = prim->ports[port].net; if (lsr == nullptr) { - iol->params[input ? ctx->id("LSRIMUX") : ctx->id("LSROMUX")] = "0"; + iol->params[input ? ctx->id("LSRIMUX") : ctx->id("LSROMUX")] = std::string("0"); } else { - iol->params[input ? ctx->id("LSRIMUX") : ctx->id("LSROMUX")] = "LSRMUX"; + iol->params[input ? ctx->id("LSRIMUX") : ctx->id("LSROMUX")] = std::string("LSRMUX"); if (iol->ports[id_LSR].net != nullptr && !equal_constant(iol->ports[id_LSR].net, lsr)) { if (iol->ports[id_LSR].net != lsr) log_error("IOLOGIC '%s' has conflicting LSR signals '%s' and '%s'\n", iol->name.c_str(ctx), @@ -1759,7 +1770,7 @@ class Ecp5Packer }; auto set_iologic_mode = [&](CellInfo *iol, std::string mode) { - auto &curr_mode = iol->params[ctx->id("MODE")]; + auto &curr_mode = iol->params[ctx->id("MODE")].str; if (curr_mode != "NONE" && curr_mode != "IREG_OREG" && curr_mode != mode) log_error("IOLOGIC '%s' has conflicting modes '%s' and '%s'\n", iol->name.c_str(ctx), curr_mode.c_str(), mode.c_str()); @@ -1774,7 +1785,7 @@ class Ecp5Packer log_error("IOLOGIC functionality (DDR, DELAY, DQS, etc) can only be used with pin-constrained PIO " "(while processing '%s').\n", curr->name.c_str(ctx)); - BelId bel = ctx->getBelByName(ctx->id(pio->attrs.at(ctx->id("BEL")))); + BelId bel = ctx->getBelByName(ctx->id(pio->attrs.at(ctx->id("BEL")).as_string())); NPNR_ASSERT(bel != BelId()); return bel; }; @@ -1865,7 +1876,7 @@ class Ecp5Packer packed_cells.insert(cell.first); } else if (o_pio != nullptr) { iol = create_pio_iologic(o_pio, ci); - iol->params[ctx->id("DELAY.OUTDEL")] = "ENABLED"; + iol->params[ctx->id("DELAY.OUTDEL")] = std::string("ENABLED"); bool driven_by_iol = false; NetInfo *input_net = ci->ports.at(ctx->id("A")).net, *dly_net = ci->ports.at(ctx->id("Z")).net; if (input_net->driver.cell != nullptr && is_iologic_output_cell(ctx, input_net->driver.cell) && @@ -1895,9 +1906,9 @@ class Ecp5Packer ci->name.c_str(ctx)); } iol->params[ctx->id("DELAY.DEL_VALUE")] = - std::to_string(lookup_delay(str_or_default(ci->params, ctx->id("DEL_MODE"), "USER_DEFINED"))); + lookup_delay(str_or_default(ci->params, ctx->id("DEL_MODE"), "USER_DEFINED")); if (ci->params.count(ctx->id("DEL_VALUE")) && - std::string(ci->params.at(ctx->id("DEL_VALUE"))).substr(0, 5) != "DELAY") + std::string(ci->params.at(ctx->id("DEL_VALUE")).as_string()).substr(0, 5) != "DELAY") iol->params[ctx->id("DELAY.DEL_VALUE")] = ci->params.at(ctx->id("DEL_VALUE")); if (ci->ports.count(id_LOADN)) replace_port(ci, id_LOADN, iol, id_LOADN); @@ -1953,7 +1964,7 @@ class Ecp5Packer pio->ports[id_IOLDO].type = PORT_IN; } replace_port(pio, id_I, pio, id_IOLDO); - pio->params[ctx->id("DATAMUX_ODDR")] = "IOLDO"; + pio->params[ctx->id("DATAMUX_ODDR")] = std::string("IOLDO"); set_iologic_sclk(iol, ci, ctx->id("SCLK"), false); set_iologic_lsr(iol, ci, ctx->id("RST"), false); replace_port(ci, ctx->id("D0"), iol, id_TXDATA0); @@ -1987,8 +1998,8 @@ class Ecp5Packer replace_port(ci, ctx->id("D2"), iol, id_TXDATA2); replace_port(ci, ctx->id("D3"), iol, id_TXDATA3); iol->params[ctx->id("GSR")] = str_or_default(ci->params, ctx->id("GSR"), "DISABLED"); - iol->params[ctx->id("ODDRXN.MODE")] = "ODDRX2"; - pio->params[ctx->id("DATAMUX_ODDR")] = "IOLDO"; + iol->params[ctx->id("ODDRXN.MODE")] = std::string("ODDRX2"); + pio->params[ctx->id("DATAMUX_ODDR")] = std::string("IOLDO"); packed_cells.insert(cell.first); } else if (ci->type == ctx->id("IDDRX2F")) { CellInfo *pio = net_driven_by(ctx, ci->ports.at(ctx->id("D")).net, is_trellis_io, id_O); @@ -2010,7 +2021,7 @@ class Ecp5Packer replace_port(ci, ctx->id("Q2"), iol, id_RXDATA2); replace_port(ci, ctx->id("Q3"), iol, id_RXDATA3); iol->params[ctx->id("GSR")] = str_or_default(ci->params, ctx->id("GSR"), "DISABLED"); - iol->params[ctx->id("IDDRXN.MODE")] = "IDDRX2"; + iol->params[ctx->id("IDDRXN.MODE")] = std::string("IDDRX2"); packed_cells.insert(cell.first); } else if (ci->type == ctx->id("OSHX2A")) { CellInfo *pio = net_only_drives(ctx, ci->ports.at(ctx->id("Q")).net, is_trellis_io, id_I, true); @@ -2036,8 +2047,8 @@ class Ecp5Packer replace_port(ci, ctx->id("D0"), iol, id_TXDATA0); replace_port(ci, ctx->id("D1"), iol, id_TXDATA2); iol->params[ctx->id("GSR")] = str_or_default(ci->params, ctx->id("GSR"), "DISABLED"); - iol->params[ctx->id("MODDRX.MODE")] = "MOSHX2"; - pio->params[ctx->id("DATAMUX_MDDR")] = "IOLDO"; + iol->params[ctx->id("MODDRX.MODE")] = std::string("MOSHX2"); + pio->params[ctx->id("DATAMUX_MDDR")] = std::string("IOLDO"); packed_cells.insert(cell.first); } else if (ci->type == ctx->id("ODDRX2DQA") || ci->type == ctx->id("ODDRX2DQSB")) { CellInfo *pio = net_only_drives(ctx, ci->ports.at(ctx->id("Q")).net, is_trellis_io, id_I, true); @@ -2065,10 +2076,11 @@ class Ecp5Packer replace_port(ci, ctx->id("D2"), iol, id_TXDATA2); replace_port(ci, ctx->id("D3"), iol, id_TXDATA3); iol->params[ctx->id("GSR")] = str_or_default(ci->params, ctx->id("GSR"), "DISABLED"); - iol->params[ctx->id("MODDRX.MODE")] = "MODDRX2"; - iol->params[ctx->id("MIDDRX_MODDRX.WRCLKMUX")] = ci->type == ctx->id("ODDRX2DQSB") ? "DQSW" : "DQSW270"; + iol->params[ctx->id("MODDRX.MODE")] = std::string("MODDRX2"); + iol->params[ctx->id("MIDDRX_MODDRX.WRCLKMUX")] = + std::string(ci->type == ctx->id("ODDRX2DQSB") ? "DQSW" : "DQSW270"); process_dqs_port(ci, pio, iol, ci->type == ctx->id("ODDRX2DQSB") ? id_DQSW : id_DQSW270); - pio->params[ctx->id("DATAMUX_MDDR")] = "IOLDO"; + pio->params[ctx->id("DATAMUX_MDDR")] = std::string("IOLDO"); packed_cells.insert(cell.first); } else if (ci->type == ctx->id("IDDRX2DQA")) { CellInfo *pio = net_driven_by(ctx, ci->ports.at(ctx->id("D")).net, is_trellis_io, id_O); @@ -2091,7 +2103,7 @@ class Ecp5Packer replace_port(ci, ctx->id("Q3"), iol, id_RXDATA3); replace_port(ci, ctx->id("QWL"), iol, id_INFF); iol->params[ctx->id("GSR")] = str_or_default(ci->params, ctx->id("GSR"), "DISABLED"); - iol->params[ctx->id("MIDDRX.MODE")] = "MIDDRX2"; + iol->params[ctx->id("MIDDRX.MODE")] = std::string("MIDDRX2"); process_dqs_port(ci, pio, iol, id_DQSR90); process_dqs_port(ci, pio, iol, id_RDPNTR2); process_dqs_port(ci, pio, iol, id_RDPNTR1); @@ -2124,11 +2136,13 @@ class Ecp5Packer replace_port(ci, ctx->id("T1"), iol, id_TSDATA1); process_dqs_port(ci, pio, iol, ci->type == ctx->id("TSHX2DQSA") ? id_DQSW : id_DQSW270); iol->params[ctx->id("GSR")] = str_or_default(ci->params, ctx->id("GSR"), "DISABLED"); - iol->params[ctx->id("MTDDRX.MODE")] = "MTSHX2"; - iol->params[ctx->id("MTDDRX.REGSET")] = "SET"; - iol->params[ctx->id("MTDDRX.DQSW_INVERT")] = ci->type == ctx->id("TSHX2DQSA") ? "ENABLED" : "DISABLED"; - iol->params[ctx->id("MIDDRX_MODDRX.WRCLKMUX")] = ci->type == ctx->id("TSHX2DQSA") ? "DQSW" : "DQSW270"; - iol->params[ctx->id("IOLTOMUX")] = "TDDR"; + iol->params[ctx->id("MTDDRX.MODE")] = std::string("MTSHX2"); + iol->params[ctx->id("MTDDRX.REGSET")] = std::string("SET"); + iol->params[ctx->id("MTDDRX.DQSW_INVERT")] = + std::string(ci->type == ctx->id("TSHX2DQSA") ? "ENABLED" : "DISABLED"); + iol->params[ctx->id("MIDDRX_MODDRX.WRCLKMUX")] = + std::string(ci->type == ctx->id("TSHX2DQSA") ? "DQSW" : "DQSW270"); + iol->params[ctx->id("IOLTOMUX")] = std::string("TDDR"); packed_cells.insert(cell.first); } } @@ -2184,8 +2198,8 @@ class Ecp5Packer log_error("ECLKSYNCB '%s' has disconnected port ECLKO\n", ci->name.c_str(ctx)); for (auto user : eclko->users) { if (user.cell->type == id_TRELLIS_ECLKBUF) { - Loc eckbuf_loc = - ctx->getBelLocation(ctx->getBelByName(ctx->id(user.cell->attrs.at(ctx->id("BEL"))))); + Loc eckbuf_loc = ctx->getBelLocation( + ctx->getBelByName(ctx->id(user.cell->attrs.at(ctx->id("BEL")).as_string()))); for (auto bel : ctx->getBels()) { if (ctx->getBelType(bel) != id_ECLKSYNCB) continue; @@ -2376,9 +2390,21 @@ class Ecp5Packer } } + void prepack_checks() + { + // Check for legacy-style JSON (use CEMUX as a clue) and error out, avoiding a confusing assertion failure + // later + for (auto cell : sorted(ctx->cells)) { + if (is_ff(ctx, cell.second) && cell.second->params.count(ctx->id("CEMUX")) && + !cell.second->params[ctx->id("CEMUX")].is_string) + log_error("Found netlist using legacy-style JSON parameter values, please update your Yosys.\n"); + } + } + public: void pack() { + prepack_checks(); pack_io(); pack_dqsbuf(); pack_iologic(); @@ -2429,7 +2455,7 @@ bool Arch::pack() Ecp5Packer(ctx).pack(); log_info("Checksum: 0x%08x\n", ctx->checksum()); assignArchInfo(); - ctx->settings[ctx->id("pack")] = "1"; + ctx->settings[ctx->id("pack")] = 1; archInfoToAttributes(); return true; } catch (log_execution_error_exception) { @@ -2464,8 +2490,8 @@ void Arch::assignArchInfo() ci->sliceInfo.lsrmux = id(str_or_default(ci->params, id_LSRMUX, "LSR")); ci->sliceInfo.srmode = id(str_or_default(ci->params, id_SRMODE, "LSR_OVER_CE")); ci->sliceInfo.is_carry = str_or_default(ci->params, id("MODE"), "LOGIC") == "CCU2"; - ci->sliceInfo.sd0 = int_or_default(ci->params, id("REG0_SD"), 0); - ci->sliceInfo.sd1 = int_or_default(ci->params, id("REG1_SD"), 0); + ci->sliceInfo.sd0 = std::stoi(str_or_default(ci->params, id("REG0_SD"), "0")); + ci->sliceInfo.sd1 = std::stoi(str_or_default(ci->params, id("REG1_SD"), "0")); ci->sliceInfo.has_l6mux = false; if (ci->ports.count(id_FXA) && ci->ports[id_FXA].net != nullptr && ci->ports[id_FXA].net->driver.port == id_OFX0) |