diff options
Diffstat (limited to 'ecp5')
-rw-r--r-- | ecp5/arch.cc | 12 | ||||
-rw-r--r-- | ecp5/arch.h | 6 | ||||
-rw-r--r-- | ecp5/arch_place.cc | 24 | ||||
-rw-r--r-- | ecp5/archdefs.h | 2 | ||||
-rw-r--r-- | ecp5/bitstream.cc | 10 | ||||
-rw-r--r-- | ecp5/constids.inc | 8 | ||||
-rw-r--r-- | ecp5/family.cmake | 4 | ||||
-rw-r--r-- | ecp5/pack.cc | 57 | ||||
-rwxr-xr-x | ecp5/trellis_import.py | 8 |
9 files changed, 114 insertions, 17 deletions
diff --git a/ecp5/arch.cc b/ecp5/arch.cc index 8ce0653c..d931c5b2 100644 --- a/ecp5/arch.cc +++ b/ecp5/arch.cc @@ -117,6 +117,9 @@ Arch::Arch(ArchArgs args) : args(args) log_error("Unsupported ECP5 chip type.\n"); } #endif + if (chip_info->const_id_count != DB_CONST_ID_COUNT) + log_error("Chip database 'bba' and nextpnr code are out of sync; please rebuild (or contact distribution " + "maintainer)!\n"); package_info = nullptr; for (int i = 0; i < chip_info->num_packages; i++) { if (args.package == chip_info->package_info[i].name.get()) { @@ -477,7 +480,13 @@ delay_t Arch::estimateDelay(WireId src, WireId dst) const } }; - auto src_loc = est_location(src), dst_loc = est_location(dst); + auto src_loc = est_location(src); + std::pair<int, int> dst_loc; + if (wire_loc_overrides.count(dst)) { + dst_loc = wire_loc_overrides.at(dst); + } else { + dst_loc = est_location(dst); + } int dx = abs(src_loc.first - dst_loc.first), dy = abs(src_loc.second - dst_loc.second); @@ -562,6 +571,7 @@ bool Arch::place() bool Arch::route() { + setupWireLocations(); route_ecp5_globals(getCtx()); assignArchInfo(); assign_budget(getCtx(), true); diff --git a/ecp5/arch.h b/ecp5/arch.h index a479abb6..3df2d84f 100644 --- a/ecp5/arch.h +++ b/ecp5/arch.h @@ -194,6 +194,7 @@ NPNR_PACKED_STRUCT(struct ChipInfoPOD { int32_t num_tiles; int32_t num_location_types; int32_t num_packages, num_pios; + int32_t const_id_count; RelPtr<LocationTypePOD> locations; RelPtr<int32_t> location_type; RelPtr<GlobalInfoPOD> location_glbinfo; @@ -1048,6 +1049,11 @@ struct Arch : BaseCtx // Special case for delay estimates due to its physical location // being far from the logical location of its primitive WireId gsrclk_wire; + // Improves directivity of routing to DSP inputs, avoids issues + // with different routes to the same physical reset wire causing + // conflicts and slow routing + std::unordered_map<WireId, std::pair<int, int>> wire_loc_overrides; + void setupWireLocations(); mutable std::unordered_map<DelayKey, std::pair<bool, DelayInfo>> celldelay_cache; diff --git a/ecp5/arch_place.cc b/ecp5/arch_place.cc index d5c345af..6057605b 100644 --- a/ecp5/arch_place.cc +++ b/ecp5/arch_place.cc @@ -196,4 +196,28 @@ void Arch::permute_luts() } } +void Arch::setupWireLocations() +{ + wire_loc_overrides.clear(); + for (auto cell : sorted(cells)) { + CellInfo *ci = cell.second; + if (ci->bel == BelId()) + continue; + if (ci->type == id_MULT18X18D || ci->type == id_DCUA) { + for (auto &port : ci->ports) { + if (port.second.type != PORT_IN || port.second.net == nullptr) + continue; + WireId pw = getBelPinWire(ci->bel, port.first); + if (pw == WireId()) + continue; + for (auto uh : getPipsUphill(pw)) { + WireId pip_src = getPipSrcWire(uh); + wire_loc_overrides[pw] = std::make_pair(pip_src.location.x, pip_src.location.y); + break; + } + } + } + } +} + NEXTPNR_NAMESPACE_END diff --git a/ecp5/archdefs.h b/ecp5/archdefs.h index da12eeaa..3cd92119 100644 --- a/ecp5/archdefs.h +++ b/ecp5/archdefs.h @@ -58,6 +58,8 @@ enum ConstIds #define X(t) , ID_##t #include "constids.inc" #undef X + , + DB_CONST_ID_COUNT }; #define X(t) static constexpr auto id_##t = IdString(ID_##t); diff --git a/ecp5/bitstream.cc b/ecp5/bitstream.cc index acab95dd..9732cd52 100644 --- a/ecp5/bitstream.cc +++ b/ecp5/bitstream.cc @@ -865,6 +865,16 @@ void write_bitstream(Context *ctx, std::string base_config_file, std::string tex if (ci->attrs.count(ctx->id("DIFFRESISTOR"))) cc.tiles[pio_tile].add_enum(pio + ".DIFFRESISTOR", str_or_default(ci->attrs, ctx->id("DIFFRESISTOR"), "OFF")); + if (ci->attrs.count(ctx->id("DRIVE"))) { + static bool drive_3v3_warning_done = false; + if (iotype == "LVCMOS33") { + cc.tiles[pio_tile].add_enum(pio + ".DRIVE", str_or_default(ci->attrs, ctx->id("DRIVE"), "8")); + } else { + if (!drive_3v3_warning_done) + log_warning("Trellis limitation: DRIVE can only be set on 3V3 IO pins.\n"); + drive_3v3_warning_done = true; + } + } if (ci->attrs.count(ctx->id("TERMINATION"))) { auto vccio = get_vccio(ioType_from_str(iotype)); switch (vccio) { diff --git a/ecp5/constids.inc b/ecp5/constids.inc index 5e8fc7da..4b5e3a3a 100644 --- a/ecp5/constids.inc +++ b/ecp5/constids.inc @@ -1294,3 +1294,11 @@ X(P) X(ECLKBRIDGECS) X(SEL) X(ECSOUT) + +X(IOLOGIC_MODE_IDDRX1F) +X(IOLOGIC_MODE_IDDRX2F) +X(IOLOGIC_MODE_IREG) +X(IOLOGIC_MODE_ODDRX1F) +X(IOLOGIC_MODE_ODDRX2F) +X(IOLOGIC_MODE_OREG) +X(IOLOGIC_MODE_TSREG) diff --git a/ecp5/family.cmake b/ecp5/family.cmake index 5512e7dd..2d8dcfcc 100644 --- a/ecp5/family.cmake +++ b/ecp5/family.cmake @@ -48,7 +48,7 @@ if (NOT EXTERNAL_CHIPDB) else() add_custom_command(OUTPUT ${DEV_CC_BBA_DB} COMMAND ${ENV_CMD} ${PYTHON_EXECUTABLE} ${DB_PY} -p ${DEV_CONSTIDS_INC} ${dev} > ${DEV_CC_BBA_DB} - DEPENDS ${DB_PY} ${PREV_DEV_CC_BBA_DB} + DEPENDS ${DB_PY} ${DEV_CONSTIDS_INC} ${PREV_DEV_CC_BBA_DB} ) add_custom_command(OUTPUT ${DEV_CC_DB} COMMAND bbasm ${BBASM_ENDIAN_FLAG} ${DEV_CC_BBA_DB} ${DEV_CC_DB} @@ -80,7 +80,7 @@ if (NOT EXTERNAL_CHIPDB) add_custom_command(OUTPUT ${DEV_CC_BBA_DB} COMMAND ${ENV_CMD} ${PYTHON_EXECUTABLE} ${DB_PY} -p ${DEV_CONSTIDS_INC} ${dev} > ${DEV_CC_BBA_DB}.new COMMAND mv ${DEV_CC_BBA_DB}.new ${DEV_CC_BBA_DB} - DEPENDS ${DB_PY} ${PREV_DEV_CC_BBA_DB} + DEPENDS ${DB_PY} ${DEV_CONSTIDS_INC} ${PREV_DEV_CC_BBA_DB} ) add_custom_command(OUTPUT ${DEV_CC_DB} COMMAND bbasm --c ${BBASM_ENDIAN_FLAG} ${DEV_CC_BBA_DB} ${DEV_CC_DB}.new diff --git a/ecp5/pack.cc b/ecp5/pack.cc index 00ed891a..c498d20a 100644 --- a/ecp5/pack.cc +++ b/ecp5/pack.cc @@ -2345,6 +2345,7 @@ class Ecp5Packer for (auto cell : sorted(ctx->cells)) { CellInfo *ci = cell.second; if (ci->type == id_ECLKBRIDGECS) { + Loc loc; NetInfo *i0 = get_net_or_empty(ci, id_CLK0), *i1 = get_net_or_empty(ci, id_CLK1), *o = get_net_or_empty(ci, id_ECSOUT); for (NetInfo *input : {i0, i1}) { @@ -2358,24 +2359,53 @@ class Ecp5Packer for (auto bel : ctx->getBels()) { if (ctx->getBelType(bel) != id_ECLKBRIDGECS) continue; - Loc loc = ctx->getBelLocation(bel); + loc = ctx->getBelLocation(bel); if (loc.x == user_loc.x) { ci->attrs[ctx->id("BEL")] = ctx->getBelName(bel).str(ctx); - if (o != nullptr) - for (auto user2 : o->users) { - // Set side hint to ensure edge clock choice is routeable - if (user2.cell->type == id_ECLKSYNCB && user2.port == id_ECLKI) { - NetInfo *synco = get_net_or_empty(user2.cell, id_ECLKO); - if (synco != nullptr) - bridge_side_hint[synco] = (loc.x > 1) ? 0 : 1; - } - } goto eclkbridge_done; } } } + if (input->driver.cell != nullptr) { + CellInfo *drv = input->driver.cell; + if (!drv->attrs.count(ctx->id("BEL"))) + continue; + Loc drv_loc = ctx->getBelLocation( + ctx->getBelByName(ctx->id(drv->attrs.at(ctx->id("BEL")).as_string()))); + BelId closest; + int closest_x = -1; // aim for same side of chip + for (auto bel : ctx->getBels()) { + if (ctx->getBelType(bel) != id_ECLKBRIDGECS) + continue; + loc = ctx->getBelLocation(bel); + if (closest_x == -1 || std::abs(loc.x - drv_loc.x) < std::abs(closest_x - drv_loc.x)) { + closest_x = loc.x; + closest = bel; + } + } + NPNR_ASSERT(closest != BelId()); + loc = ctx->getBelLocation(closest); + ci->attrs[ctx->id("BEL")] = ctx->getBelName(closest).str(ctx); + goto eclkbridge_done; + } + } + // If all else fails, place randomly + for (auto bel : ctx->getBels()) { + if (ctx->getBelType(bel) != id_ECLKBRIDGECS) + continue; + loc = ctx->getBelLocation(bel); + ci->attrs[ctx->id("BEL")] = ctx->getBelName(bel).str(ctx); } eclkbridge_done: + if (o != nullptr) + for (auto user2 : o->users) { + // Set side hint to ensure edge clock choice is routeable + if (user2.cell->type == id_ECLKSYNCB && user2.port == id_ECLKI) { + NetInfo *synco = get_net_or_empty(user2.cell, id_ECLKO); + if (synco != nullptr) + bridge_side_hint[synco] = (loc.x > 1) ? 0 : 1; + } + } continue; } } @@ -2575,7 +2605,7 @@ class Ecp5Packer std::unordered_set<IdString> changed_cells; for (auto net : changed_nets) for (auto &user : ctx->nets.at(net)->users) - if (user.port == id_CLKI || user.port == id_ECLKI) + if (user.port == id_CLKI || user.port == id_ECLKI || user.port == id_CLK0 || user.port == id_CLK1) changed_cells.insert(user.cell->name); changed_nets.clear(); for (auto cell : sorted(changed_cells)) { @@ -2592,6 +2622,9 @@ class Ecp5Packer copy_constraint(ci, id_CLKI, id_CDIVX, ratio); } else if (ci->type == id_ECLKSYNCB || ci->type == id_TRELLIS_ECLKBUF) { copy_constraint(ci, id_ECLKI, id_ECLKO, 1); + } else if (ci->type == id_ECLKBRIDGECS) { + copy_constraint(ci, id_CLK0, id_ECSOUT, 1); + copy_constraint(ci, id_CLK1, id_ECSOUT, 1); } else if (ci->type == id_DCCA) { copy_constraint(ci, id_CLKI, id_CLKO, 1); } else if (ci->type == id_EHXPLLL) { @@ -2651,12 +2684,12 @@ class Ecp5Packer prepack_checks(); pack_io(); pack_dqsbuf(); + preplace_plls(); pack_iologic(); pack_ebr(); pack_dsps(); pack_dcus(); pack_misc(); - preplace_plls(); pack_constants(); pack_dram(); pack_carries(); diff --git a/ecp5/trellis_import.py b/ecp5/trellis_import.py index 610bd331..ee960fd3 100755 --- a/ecp5/trellis_import.py +++ b/ecp5/trellis_import.py @@ -186,6 +186,8 @@ def process_timing_data(): max_delay = min(entry["rising"][2], entry["falling"][2]) delays.append((constids[from_pin], constids[to_pin], min_delay, max_delay)) elif entry["type"] == "SetupHold": + if type(entry["pin"]) is list: + continue pin = constids[entry["pin"]] clock = constids[entry["clock"][1]] min_setup = entry["setup"][0] @@ -441,6 +443,7 @@ def write_database(dev_name, chip, ddrg, endianness): bba.u32(len(location_types), "num_location_types") bba.u32(len(packages), "num_packages") bba.u32(len(pindata), "num_pios") + bba.u32(const_id_count, "const_id_count") bba.r("locations", "locations") bba.r("location_types", "location_type") @@ -457,11 +460,12 @@ def write_database(dev_name, chip, ddrg, endianness): dev_names = {"25k": "LFE5UM5G-25F", "45k": "LFE5UM5G-45F", "85k": "LFE5UM5G-85F"} def main(): - global max_row, max_col + global max_row, max_col, const_id_count pytrellis.load_database(database.get_db_root()) args = parser.parse_args() # Read port pin file + const_id_count = 1 # count ID_NONE with open(args.constids) as f: for line in f: line = line.replace("(", " ") @@ -473,7 +477,7 @@ def main(): assert line[0] == "X" idx = len(constids) + 1 constids[line[1]] = idx - + const_id_count += 1 constids["SLICE"] = constids["TRELLIS_SLICE"] constids["PIO"] = constids["TRELLIS_IO"] |