diff --git a/common/kernel/command.cc b/common/kernel/command.cc index 68066af6cf..95204751a5 100644 --- a/common/kernel/command.cc +++ b/common/kernel/command.cc @@ -97,7 +97,6 @@ bool CommandHandler::executeBeforeContext() << " -- Next Generation Place and Route (Version " GIT_DESCRIBE_STR ")\n"; return true; } - validate(); if (vm.count("quiet")) { log_streams.push_back(std::make_pair(&std::cerr, LogLevel::WARNING_MSG)); @@ -105,6 +104,8 @@ bool CommandHandler::executeBeforeContext() log_streams.push_back(std::make_pair(&std::cerr, LogLevel::LOG_MSG)); } + validate(); + if (vm.count("Werror")) { log_warn_as_error = true; } diff --git a/ecp5/arch.cc b/ecp5/arch.cc index 11429eb46e..3111f3a84d 100644 --- a/ecp5/arch.cc +++ b/ecp5/arch.cc @@ -34,6 +34,7 @@ #include "router2.h" #include "timing.h" #include "util.h" +#include "ecp5_available.h" NEXTPNR_NAMESPACE_BEGIN @@ -48,68 +49,103 @@ void IdString::initialize_arch(const BaseCtx *ctx) #undef X } -// ----------------------------------------------------------------------- +// --------------------------------------------------------------- -static const ChipInfoPOD *get_chip_info(ArchArgs::ArchArgsTypes chip) +bool is_equal(const std::string& a, const std::string& b) { - std::string chipdb; - if (chip == ArchArgs::LFE5U_12F || chip == ArchArgs::LFE5U_25F || chip == ArchArgs::LFE5UM_25F || - chip == ArchArgs::LFE5UM5G_25F) { - chipdb = "ecp5/chipdb-25k.bin"; - } else if (chip == ArchArgs::LFE5U_45F || chip == ArchArgs::LFE5UM_45F || chip == ArchArgs::LFE5UM5G_45F) { - chipdb = "ecp5/chipdb-45k.bin"; - } else if (chip == ArchArgs::LFE5U_85F || chip == ArchArgs::LFE5UM_85F || chip == ArchArgs::LFE5UM5G_85F) { - chipdb = "ecp5/chipdb-85k.bin"; - } else { - log_error("Unknown chip\n"); - } - - auto ptr = reinterpret_cast *>(get_chipdb(chipdb)); - if (ptr == nullptr) - return nullptr; - return ptr->get(); + return std::equal(a.begin(), a.end(), b.begin(), b.end(), + [](char a, char b) { return tolower(a) == tolower(b); }); } -bool Arch::is_available(ArchArgs::ArchArgsTypes chip) { return get_chip_info(chip) != nullptr; } - -std::vector Arch::get_supported_packages(ArchArgs::ArchArgsTypes chip) +static void get_chip_info(std::string device, ArchDevice *selected_device) { - const ChipInfoPOD *chip_info = get_chip_info(chip); - std::vector packages; - for (auto &pkg : chip_info->package_info) - packages.push_back(pkg.name.get()); - return packages; + std::stringstream ss(available_devices); + std::string name; + while (getline(ss, name, ';')) { + std::string chipdb = stringf("ecp5/chipdb-%s.bin", name.c_str()); + auto db_ptr = reinterpret_cast *>(get_chipdb(chipdb)); + if (!db_ptr) + continue; // chipdb not available + for (auto &dev : db_ptr->get()->devices) { + for (auto &chip : dev.variants) { + for (auto &pkg : chip.packages) { + for (auto &speedgrade : chip.speed_grades) { + for (auto &rating : chip.suffixes) { + std::string devname = stringf("%s-%d%s%s", chip.name.get(), speedgrade.speed, + pkg.short_name.get(), rating.suffix.get()); + if (device == devname) { + selected_device->device_info = &dev; + selected_device->chip_info = db_ptr->get(); + selected_device->package_info = nullptr; + selected_device->package_name = pkg.name.get(); + selected_device->device_name = chip.name.get(); + selected_device->type = ArchDevice::NONE; + std::string device_name = chip.name.get(); + if ((device_name == "LFE5U-12F")|| (device_name == "LAE5U-12F")) + selected_device->type = ArchDevice::LFE5U_12F; + else if (device_name == "LFE5U-25F") + selected_device->type = ArchDevice::LFE5U_25F; + else if (device_name == "LFE5U-45F") + selected_device->type = ArchDevice::LFE5U_45F; + else if (device_name == "LFE5U-85F") + selected_device->type = ArchDevice::LFE5U_85F; + else if ((device_name == "LFE5UM-25F") || (device_name == "LAE5UM-25F")) + selected_device->type = ArchDevice::LFE5UM_25F; + else if ((device_name == "LFE5UM-45F") || (device_name == "LAE5UM-45F")) + selected_device->type = ArchDevice::LFE5UM_45F; + else if ((device_name == "LFE5UM-85F") || (device_name == "LAE5UM-85F")) + selected_device->type = ArchDevice::LFE5UM_85F; + else if (device_name == "LFE5UM5G-25F") + selected_device->type = ArchDevice::LFE5UM5G_25F; + else if (device_name == "LFE5UM5G-45F") + selected_device->type = ArchDevice::LFE5UM5G_45F; + else if (device_name == "LFE5UM5G-85F") + selected_device->type = ArchDevice::LFE5UM5G_85F; + else + log_error("Unsupported device '%s'.\n", device_name.c_str()); + + selected_device->speed = ArchDevice::SpeedGrade(speedgrade.speed - 6); + if (device_name.rfind("LFE5UM5G")==0) { + selected_device->speed = ArchDevice::SPEED_8_5G; + } + selected_device->speed_grade = &(selected_device->chip_info->speed_grades[selected_device->speed]); + for (auto &pi : db_ptr->get()->package_info) { + if (is_equal(pkg.name.get(),pi.name.get())) { + selected_device->package_info = π + break; + } + } + return; + } + } + } + } + } + } + } } -// ----------------------------------------------------------------------- +// --------------------------------------------------------------- Arch::Arch(ArchArgs args) : args(args) { - chip_info = get_chip_info(args.type); - if (chip_info == nullptr) - log_error("Unsupported ECP5 chip type.\n"); - if (chip_info->const_id_count != DB_CONST_ID_COUNT) + get_chip_info(args.device, &device); + if (device.chip_info == nullptr) + log_error("Unsupported device '%s'.\n", args.device.c_str()); + if (device.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 (auto &pkg : chip_info->package_info) { - if (args.package == pkg.name.get()) { - package_info = &pkg; - break; - } - } - speed_grade = &(chip_info->speed_grades[args.speed]); - if (!package_info) - log_error("Unsupported package '%s' for '%s'.\n", args.package.c_str(), getChipName().c_str()); + if (!device.package_info) + log_error("Unsupported package '%s' for '%s'.\n", device.package_name, getChipName().c_str()); - tile_status.resize(chip_info->num_tiles); - for (int i = 0; i < chip_info->num_tiles; i++) { + tile_status.resize(device.chip_info->num_tiles); + for (int i = 0; i < device.chip_info->num_tiles; i++) { auto &ts = tile_status.at(i); - auto &tile_data = chip_info->tile_info[i]; - ts.boundcells.resize(chip_info->locations[chip_info->location_type[i]].bel_data.size(), nullptr); + auto &tile_data = device.chip_info->tile_info[i]; + ts.boundcells.resize(device.chip_info->locations[device.chip_info->location_type[i]].bel_data.size(), nullptr); for (auto &name : tile_data.tile_names) { - if (strcmp(chip_info->tiletype_names[name.type_idx].get(), "PLC2") == 0) { + if (strcmp(device.chip_info->tiletype_names[name.type_idx].get(), "PLC2") == 0) { // Is a logic tile ts.lts = new LogicTileStatus(); break; @@ -120,121 +156,75 @@ Arch::Arch(ArchArgs args) : args(args) BaseArch::init_cell_types(); BaseArch::init_bel_buckets(); - for (int i = 0; i < chip_info->width; i++) + for (int i = 0; i < device.chip_info->width; i++) x_ids.push_back(idf("X%d", i)); - for (int i = 0; i < chip_info->height; i++) + for (int i = 0; i < device.chip_info->height; i++) y_ids.push_back(idf("Y%d", i)); - for (int i = 0; i < chip_info->width; i++) { + for (int i = 0; i < device.chip_info->width; i++) { IdString x_id = idf("X%d", i); x_ids.push_back(x_id); id_to_x[x_id] = i; } - for (int i = 0; i < chip_info->height; i++) { + for (int i = 0; i < device.chip_info->height; i++) { IdString y_id = idf("Y%d", i); y_ids.push_back(y_id); id_to_y[y_id] = i; } - wire_tile_vecidx.resize(chip_info->num_tiles, -1); + wire_tile_vecidx.resize(device.chip_info->num_tiles, -1); int n_wires = 0; for (auto e : getWires()) { if (e.index == 0) { - wire_tile_vecidx.at(e.location.y * chip_info->width + e.location.x) = n_wires; + wire_tile_vecidx.at(e.location.y * device.chip_info->width + e.location.x) = n_wires; } n_wires++; } wire2net.resize(n_wires, nullptr); wire_fanout.resize(n_wires, 0); - pip_tile_vecidx.resize(chip_info->num_tiles, -1); + pip_tile_vecidx.resize(device.chip_info->num_tiles, -1); int n_pips = 0; for (auto e : getPips()) { if (e.index == 0) { - pip_tile_vecidx.at(e.location.y * chip_info->width + e.location.x) = n_pips; + pip_tile_vecidx.at(e.location.y * device.chip_info->width + e.location.x) = n_pips; } n_pips++; } pip2net.resize(n_pips, nullptr); - lutperm_allowed.resize(chip_info->width * chip_info->height * 4); -} - -// ----------------------------------------------------------------------- - -std::string Arch::getChipName() const -{ - if (args.type == ArchArgs::LFE5U_12F) { - return "LFE5U-12F"; - } else if (args.type == ArchArgs::LFE5U_25F) { - return "LFE5U-25F"; - } else if (args.type == ArchArgs::LFE5U_45F) { - return "LFE5U-45F"; - } else if (args.type == ArchArgs::LFE5U_85F) { - return "LFE5U-85F"; - } else if (args.type == ArchArgs::LFE5UM_25F) { - return "LFE5UM-25F"; - } else if (args.type == ArchArgs::LFE5UM_45F) { - return "LFE5UM-45F"; - } else if (args.type == ArchArgs::LFE5UM_85F) { - return "LFE5UM-85F"; - } else if (args.type == ArchArgs::LFE5UM5G_25F) { - return "LFE5UM5G-25F"; - } else if (args.type == ArchArgs::LFE5UM5G_45F) { - return "LFE5UM5G-45F"; - } else if (args.type == ArchArgs::LFE5UM5G_85F) { - return "LFE5UM5G-85F"; - } else { - log_error("Unknown chip\n"); - } + lutperm_allowed.resize(device.chip_info->width * device.chip_info->height * 4); } -std::string Arch::get_full_chip_name() const +void Arch::list_devices() { - std::string name = getChipName(); - name += "-"; - switch (args.speed) { - case ArchArgs::SPEED_6: - name += "6"; - break; - case ArchArgs::SPEED_7: - name += "7"; - break; - case ArchArgs::SPEED_8: - case ArchArgs::SPEED_8_5G: - name += "8"; - break; + log("Supported devices: \n"); + std::stringstream ss(available_devices); + std::string name; + while (getline(ss, name, ';')) { + std::string chipdb = stringf("ecp5/chipdb-%s.bin", name.c_str()); + auto db_ptr = reinterpret_cast *>(get_chipdb(chipdb)); + if (!db_ptr) + continue; // chipdb not available + for (auto &dev : db_ptr->get()->devices) { + for (auto &chip : dev.variants) { + for (auto &pkg : chip.packages) { + for (auto &speedgrade : chip.speed_grades) { + for (auto &rating : chip.suffixes) { + log(" %s-%d%s%s\n", chip.name.get(), speedgrade.speed, pkg.short_name.get(), + rating.suffix.get()); + } + } + } + } + } } - name += args.package; - return name; } // ----------------------------------------------------------------------- -IdString Arch::archArgsToId(ArchArgs args) const -{ - if (args.type == ArchArgs::LFE5U_12F) - return id_lfe5u_12f; - if (args.type == ArchArgs::LFE5U_25F) - return id_lfe5u_25f; - if (args.type == ArchArgs::LFE5U_45F) - return id_lfe5u_45f; - if (args.type == ArchArgs::LFE5U_85F) - return id_lfe5u_85f; - if (args.type == ArchArgs::LFE5UM_25F) - return id_lfe5um_25f; - if (args.type == ArchArgs::LFE5UM_45F) - return id_lfe5um_45f; - if (args.type == ArchArgs::LFE5UM_85F) - return id_lfe5um_85f; - if (args.type == ArchArgs::LFE5UM5G_25F) - return id_lfe5um5g_25f; - if (args.type == ArchArgs::LFE5UM5G_45F) - return id_lfe5um5g_45f; - if (args.type == ArchArgs::LFE5UM5G_85F) - return id_lfe5um5g_85f; - return IdString(); -} +std::string Arch::getChipName() const { return args.device; } +IdString Arch::archArgsToId(ArchArgs args) const { return id(args.device); } // ----------------------------------------------------------------------- @@ -261,12 +251,12 @@ BelRange Arch::getBelsByTile(int x, int y) const { BelRange br; - br.b.cursor_tile = y * chip_info->width + x; - br.e.cursor_tile = y * chip_info->width + x; + br.b.cursor_tile = y * device.chip_info->width + x; + br.e.cursor_tile = y * device.chip_info->width + x; br.b.cursor_index = 0; - br.e.cursor_index = chip_info->locations[chip_info->location_type[br.b.cursor_tile]].bel_data.ssize() - 1; - br.b.chip = chip_info; - br.e.chip = chip_info; + br.e.cursor_index = device.chip_info->locations[device.chip_info->location_type[br.b.cursor_tile]].bel_data.ssize() - 1; + br.b.chip = device.chip_info; + br.e.chip = device.chip_info; if (br.e.cursor_index == -1) ++br.e.cursor_index; else @@ -369,7 +359,7 @@ IdStringList Arch::getPipName(PipId pip) const BelId Arch::get_package_pin_bel(const std::string &pin) const { - for (auto &ppin : package_info->pin_data) { + for (auto &ppin : device.package_info->pin_data) { if (ppin.name.get() == pin) { BelId bel; bel.location = ppin.abs_loc; @@ -382,7 +372,7 @@ BelId Arch::get_package_pin_bel(const std::string &pin) const std::string Arch::get_bel_package_pin(BelId bel) const { - for (auto &ppin : package_info->pin_data) { + for (auto &ppin : device.package_info->pin_data) { if (Location(ppin.abs_loc) == bel.location && ppin.bel_index == bel.index) { return ppin.name.get(); } @@ -392,7 +382,7 @@ std::string Arch::get_bel_package_pin(BelId bel) const int Arch::get_pio_bel_bank(BelId bel) const { - for (auto &pio : chip_info->pio_info) { + for (auto &pio : device.chip_info->pio_info) { if (Location(pio.abs_loc) == bel.location && pio.bel_index == bel.index) { return pio.bank; } @@ -402,7 +392,7 @@ int Arch::get_pio_bel_bank(BelId bel) const std::string Arch::get_pio_function_name(BelId bel) const { - for (auto &pio : chip_info->pio_info) { + for (auto &pio : device.chip_info->pio_info) { if (Location(pio.abs_loc) == bel.location && pio.bel_index == bel.index) { const char *func = pio.function_name.get(); if (func == nullptr) @@ -416,7 +406,7 @@ std::string Arch::get_pio_function_name(BelId bel) const BelId Arch::get_pio_by_function_name(const std::string &name) const { - for (auto &pio : chip_info->pio_info) { + for (auto &pio : device.chip_info->pio_info) { const char *func = pio.function_name.get(); if (func != nullptr && func == name) { BelId bel; @@ -444,9 +434,9 @@ std::vector Arch::getBelPins(BelId bel) const BelId Arch::getBelByLocation(Loc loc) const { - if (loc.x >= chip_info->width || loc.y >= chip_info->height) + if (loc.x >= device.chip_info->width || loc.y >= device.chip_info->height) return BelId(); - const LocationTypePOD &locI = chip_info->locations[chip_info->location_type[loc.y * chip_info->width + loc.x]]; + const LocationTypePOD &locI = device.chip_info->locations[device.chip_info->location_type[loc.y * device.chip_info->width + loc.x]]; for (int i = 0; i < locI.bel_data.ssize(); i++) { if (locI.bel_data[i].z == loc.z) { BelId bi; @@ -500,7 +490,7 @@ delay_t Arch::estimateDelay(WireId src, WireId dst) const int dx = abs(src_loc.first - dst_loc.first), dy = abs(src_loc.second - dst_loc.second); - return (120 - 22 * args.speed) * + return (120 - 22 * device.speed) * (6 + std::max(dx - 5, 0) + std::max(dy - 5, 0) + 2 * (std::min(dx, 5) + std::min(dy, 5))); } @@ -578,7 +568,7 @@ delay_t Arch::predictDelay(BelId src_bel, IdString src_pin, BelId dst_bel, IdStr int dx = abs(driver_loc.x - sink_loc.x), dy = abs(driver_loc.y - sink_loc.y); - return (120 - 22 * args.speed) * + return (120 - 22 * device.speed) * (3 + std::max(dx - 5, 0) + std::max(dy - 5, 0) + 2 * (std::min(dx, 5) + std::min(dy, 5))); } @@ -701,7 +691,7 @@ std::vector Arch::getDecalGraphics(DecalId decal) const int y = decal.location.y; GraphicElement::style_t style = decal.active ? GraphicElement::STYLE_ACTIVE : GraphicElement::STYLE_INACTIVE; GfxTileWireId tilewire = GfxTileWireId(loc_info(wire)->wire_data[wire.index].tile_wire); - gfxTileWire(ret, x, y, chip_info->width, chip_info->height, wire_type, tilewire, style); + gfxTileWire(ret, x, y, device.chip_info->width, device.chip_info->height, wire_type, tilewire, style); } else if (decal.type == DecalId::TYPE_PIP) { PipId pip; pip.index = decal.z; @@ -713,7 +703,7 @@ std::vector Arch::getDecalGraphics(DecalId decal) const GfxTileWireId src_id = GfxTileWireId(loc_info(src_wire)->wire_data[src_wire.index].tile_wire); GfxTileWireId dst_id = GfxTileWireId(loc_info(dst_wire)->wire_data[dst_wire.index].tile_wire); GraphicElement::style_t style = decal.active ? GraphicElement::STYLE_ACTIVE : GraphicElement::STYLE_HIDDEN; - gfxTilePip(ret, x, y, chip_info->width, chip_info->height, src_wire, getWireType(src_wire), src_id, dst_wire, + gfxTilePip(ret, x, y, device.chip_info->width, device.chip_info->height, src_wire, getWireType(src_wire), src_id, dst_wire, getWireType(dst_wire), dst_id, style); } else if (decal.type == DecalId::TYPE_BEL) { BelId bel; @@ -724,7 +714,7 @@ std::vector Arch::getDecalGraphics(DecalId decal) const int y = decal.location.y; int z = loc_info(bel)->bel_data[bel.index].z; GraphicElement::style_t style = decal.active ? GraphicElement::STYLE_ACTIVE : GraphicElement::STYLE_INACTIVE; - gfxTileBel(ret, x, y, z, chip_info->width, chip_info->height, bel_type, style); + gfxTileBel(ret, x, y, z, device.chip_info->width, device.chip_info->height, bel_type, style); } return ret; @@ -779,7 +769,7 @@ bool Arch::get_delay_from_tmg_db(IdString tctype, IdString from, IdString to, De delay = fnd_dk->second.second; return fnd_dk->second.first; } - for (auto &tc : speed_grade->cell_timings) { + for (auto &tc : device.speed_grade->cell_timings) { if (tc.cell_type == tctype.index) { for (auto &dly : tc.prop_delays) { if (dly.from_port == from.index && dly.to_port == to.index) { @@ -798,7 +788,7 @@ bool Arch::get_delay_from_tmg_db(IdString tctype, IdString from, IdString to, De void Arch::get_setuphold_from_tmg_db(IdString tctype, IdString clock, IdString port, DelayPair &setup, DelayPair &hold) const { - for (auto &tc : speed_grade->cell_timings) { + for (auto &tc : device.speed_grade->cell_timings) { if (tc.cell_type == tctype.index) { for (auto &sh : tc.setup_holds) { if (sh.clock_port == clock.index && sh.sig_port == port.index) { @@ -1188,22 +1178,22 @@ TimingClockingInfo Arch::getPortClockingInfo(const CellInfo *cell, IdString port std::vector> Arch::get_tiles_at_loc(int row, int col) { std::vector> ret; - auto &tileloc = chip_info->tile_info[row * chip_info->width + col]; + auto &tileloc = device.chip_info->tile_info[row * device.chip_info->width + col]; for (auto &tn : tileloc.tile_names) { - ret.push_back(std::make_pair(tn.name.get(), chip_info->tiletype_names[tn.type_idx].get())); + ret.push_back(std::make_pair(tn.name.get(), device.chip_info->tiletype_names[tn.type_idx].get())); } return ret; } GlobalInfoPOD Arch::global_info_at_loc(Location loc) { - int locidx = loc.y * chip_info->width + loc.x; - return chip_info->location_glbinfo[locidx]; + int locidx = loc.y * device.chip_info->width + loc.x; + return device.chip_info->location_glbinfo[locidx]; } bool Arch::get_pio_dqs_group(BelId pio, bool &dqsright, int &dqsrow) { - for (auto &ppio : chip_info->pio_info) { + for (auto &ppio : device.chip_info->pio_info) { if (Location(ppio.abs_loc) == pio.location && ppio.bel_index == pio.index) { int dqs = ppio.dqsgroup; if (dqs == -1) @@ -1222,7 +1212,7 @@ BelId Arch::get_dqsbuf(bool dqsright, int dqsrow) { BelId bel; bel.location.y = dqsrow; - bel.location.x = (dqsright ? (chip_info->width - 1) : 0); + bel.location.x = (dqsright ? (device.chip_info->width - 1) : 0); for (int i = 0; i < loc_info(bel)->bel_data.ssize(); i++) { auto &bd = loc_info(bel)->bel_data[i]; if (bd.type == id_DQSBUFM.index) { @@ -1275,8 +1265,8 @@ std::vector Arch::getGroups() const { std::vector ret; - for (int y = 1; y < chip_info->height - 1; y++) { - for (int x = 1; x < chip_info->width - 1; x++) { + for (int y = 1; y < device.chip_info->height - 1; y++) { + for (int x = 1; x < device.chip_info->width - 1; x++) { GroupId group; group.type = GroupId::TYPE_SWITCHBOX; group.location.x = x; diff --git a/ecp5/arch.h b/ecp5/arch.h index 56ba3e7b51..aeed0360be 100644 --- a/ecp5/arch.h +++ b/ecp5/arch.h @@ -169,6 +169,28 @@ NPNR_PACKED_STRUCT(struct SpeedGradePOD { RelSlice pip_classes; }); +NPNR_PACKED_STRUCT(struct PackageSupportedPOD { + RelPtr name; + RelPtr short_name; +}); + +NPNR_PACKED_STRUCT(struct SuffixeSupportedPOD { RelPtr suffix; }); + +NPNR_PACKED_STRUCT(struct SpeedSupportedPOD { int32_t speed; }); + +NPNR_PACKED_STRUCT(struct VariantInfoPOD { + RelPtr name; + RelSlice packages; + RelSlice speed_grades; + RelSlice suffixes; +}); + +NPNR_PACKED_STRUCT(struct DeviceInfoPOD { + RelPtr family; + RelPtr name; + RelSlice variants; +}); + NPNR_PACKED_STRUCT(struct ChipInfoPOD { int32_t width, height; int32_t num_tiles; @@ -181,6 +203,7 @@ NPNR_PACKED_STRUCT(struct ChipInfoPOD { RelSlice pio_info; RelSlice tile_info; RelSlice speed_grades; + RelSlice devices; }); /************************ End of chipdb section. ************************/ @@ -394,28 +417,7 @@ struct PipRange struct ArchArgs { - enum ArchArgsTypes - { - NONE, - LFE5U_12F, - LFE5U_25F, - LFE5U_45F, - LFE5U_85F, - LFE5UM_25F, - LFE5UM_45F, - LFE5UM_85F, - LFE5UM5G_25F, - LFE5UM5G_45F, - LFE5UM5G_85F, - } type = NONE; - std::string package; - enum SpeedGrade - { - SPEED_6 = 0, - SPEED_7, - SPEED_8, - SPEED_8_5G, - } speed = SPEED_6; + std::string device; }; struct DelayKey @@ -444,11 +446,40 @@ struct ArchRanges : BaseArchRanges using AllPipsRangeT = AllPipRange; }; -struct Arch : BaseArch -{ +struct ArchDevice { + const DeviceInfoPOD *device_info; const ChipInfoPOD *chip_info; const PackageInfoPOD *package_info; const SpeedGradePOD *speed_grade; + const char *package_name; + const char *device_name; + enum ArchTypes + { + NONE, + LFE5U_12F, + LFE5U_25F, + LFE5U_45F, + LFE5U_85F, + LFE5UM_25F, + LFE5UM_45F, + LFE5UM_85F, + LFE5UM5G_25F, + LFE5UM5G_45F, + LFE5UM5G_85F, + } type = NONE; + + enum SpeedGrade + { + SPEED_6 = 0, + SPEED_7, + SPEED_8, + SPEED_8_5G, + } speed = SPEED_6; +}; + +struct Arch : BaseArch +{ + ArchDevice device; mutable dict pip_by_name; @@ -513,11 +544,9 @@ struct Arch : BaseArch ArchArgs args; Arch(ArchArgs args); - static bool is_available(ArchArgs::ArchArgsTypes chip); - static std::vector get_supported_packages(ArchArgs::ArchArgsTypes chip); + static void list_devices(); std::string getChipName() const override; - std::string get_full_chip_name() const; ArchArgs archArgs() const override { return args; } IdString archArgsToId(ArchArgs args) const override; @@ -526,8 +555,8 @@ struct Arch : BaseArch static const int max_loc_bels = 32; - int getGridDimX() const override { return chip_info->width; }; - int getGridDimY() const override { return chip_info->height; }; + int getGridDimX() const override { return device.chip_info->width; }; + int getGridDimY() const override { return device.chip_info->height; }; int getTileBelDimZ(int, int) const override { return max_loc_bels; }; int getTilePipDimZ(int, int) const override { return 1; }; char getNameDelimiter() const override { return '/'; } @@ -538,12 +567,12 @@ struct Arch : BaseArch template const LocationTypePOD *loc_info(Id &id) const { - return &(chip_info->locations[chip_info->location_type[id.location.y * chip_info->width + id.location.x]]); + return &(device.chip_info->locations[device.chip_info->location_type[id.location.y * device.chip_info->width + id.location.x]]); } template inline int tile_index(Id id) const { - return id.location.y * chip_info->width + id.location.x; + return id.location.y * device.chip_info->width + id.location.x; } IdStringList getBelName(BelId bel) const override @@ -559,7 +588,7 @@ struct Arch : BaseArch int get_slice_index(int x, int y, int slice) const { NPNR_ASSERT(slice >= 0 && slice < 4); - return (y * chip_info->width + x) * 4 + slice; + return (y * device.chip_info->width + x) * 4 + slice; } void update_bel(BelId bel, CellInfo *old_cell, CellInfo *new_cell) @@ -650,11 +679,11 @@ struct Arch : BaseArch BelRange range; range.b.cursor_tile = 0; range.b.cursor_index = -1; - range.b.chip = chip_info; + range.b.chip = device.chip_info; ++range.b; //-1 and then ++ deals with the case of no Bels in the first tile - range.e.cursor_tile = chip_info->width * chip_info->height; + range.e.cursor_tile = device.chip_info->width * device.chip_info->height; range.e.cursor_index = 0; - range.e.chip = chip_info; + range.e.chip = device.chip_info; return range; } @@ -707,7 +736,7 @@ struct Arch : BaseArch uint32_t get_wire_vecidx(const WireId &e) const { - uint32_t tile = e.location.y * chip_info->width + e.location.x; + uint32_t tile = e.location.y * device.chip_info->width + e.location.x; int32_t base = wire_tile_vecidx.at(tile); NPNR_ASSERT(base != -1); int32_t i = base + e.index; @@ -754,11 +783,11 @@ struct Arch : BaseArch WireRange range; range.b.cursor_tile = 0; range.b.cursor_index = -1; - range.b.chip = chip_info; + range.b.chip = device.chip_info; ++range.b; //-1 and then ++ deals with the case of no wries in the first tile - range.e.cursor_tile = chip_info->width * chip_info->height; + range.e.cursor_tile = device.chip_info->width * device.chip_info->height; range.e.cursor_index = 0; - range.e.chip = chip_info; + range.e.chip = device.chip_info; return range; } @@ -786,7 +815,7 @@ struct Arch : BaseArch uint32_t get_pip_vecidx(const PipId &e) const { - uint32_t tile = e.location.y * chip_info->width + e.location.x; + uint32_t tile = e.location.y * device.chip_info->width + e.location.x; int32_t base = pip_tile_vecidx.at(tile); NPNR_ASSERT(base != -1); int32_t i = base + e.index; @@ -859,11 +888,11 @@ struct Arch : BaseArch AllPipRange range; range.b.cursor_tile = 0; range.b.cursor_index = -1; - range.b.chip = chip_info; + range.b.chip = device.chip_info; ++range.b; //-1 and then ++ deals with the case of no wries in the first tile - range.e.cursor_tile = chip_info->width * chip_info->height; + range.e.cursor_tile = device.chip_info->width * device.chip_info->height; range.e.cursor_index = 0; - range.e.chip = chip_info; + range.e.chip = device.chip_info; return range; } @@ -890,11 +919,11 @@ struct Arch : BaseArch NPNR_ASSERT(pip != PipId()); int fanout = wire_fanout[get_wire_vecidx(getPipSrcWire(pip))]; delay_t min_dly = - speed_grade->pip_classes[loc_info(pip)->pip_data[pip.index].timing_class].min_base_delay + - fanout * speed_grade->pip_classes[loc_info(pip)->pip_data[pip.index].timing_class].min_fanout_adder; + device.speed_grade->pip_classes[loc_info(pip)->pip_data[pip.index].timing_class].min_base_delay + + fanout * device.speed_grade->pip_classes[loc_info(pip)->pip_data[pip.index].timing_class].min_fanout_adder; delay_t max_dly = - speed_grade->pip_classes[loc_info(pip)->pip_data[pip.index].timing_class].max_base_delay + - fanout * speed_grade->pip_classes[loc_info(pip)->pip_data[pip.index].timing_class].max_fanout_adder; + device.speed_grade->pip_classes[loc_info(pip)->pip_data[pip.index].timing_class].max_base_delay + + fanout * device.speed_grade->pip_classes[loc_info(pip)->pip_data[pip.index].timing_class].max_fanout_adder; return DelayQuad(min_dly, max_dly); } @@ -922,7 +951,7 @@ struct Arch : BaseArch std::string get_pip_tilename(PipId pip) const { - auto &tileloc = chip_info->tile_info[pip.location.y * chip_info->width + pip.location.x]; + auto &tileloc = device.chip_info->tile_info[pip.location.y * device.chip_info->width + pip.location.x]; for (auto &tn : tileloc.tile_names) { if (tn.type_idx == loc_info(pip)->pip_data[pip.index].tile_type) return tn.name.get(); @@ -932,7 +961,7 @@ struct Arch : BaseArch std::string get_pip_tiletype(PipId pip) const { - return chip_info->tiletype_names[loc_info(pip)->pip_data[pip.index].tile_type].get(); + return device.chip_info->tiletype_names[loc_info(pip)->pip_data[pip.index].tile_type].get(); } Loc getPipLocation(PipId pip) const override @@ -1021,9 +1050,9 @@ struct Arch : BaseArch std::vector> get_tiles_at_loc(int row, int col); std::string get_tile_by_type_loc(int row, int col, std::string type) const { - auto &tileloc = chip_info->tile_info[row * chip_info->width + col]; + auto &tileloc = device.chip_info->tile_info[row * device.chip_info->width + col]; for (auto &tn : tileloc.tile_names) { - if (chip_info->tiletype_names[tn.type_idx].get() == type) + if (device.chip_info->tiletype_names[tn.type_idx].get() == type) return tn.name.get(); } NPNR_ASSERT_FALSE_STR("no tile at (" + std::to_string(col) + ", " + std::to_string(row) + ") with type " + @@ -1032,9 +1061,9 @@ struct Arch : BaseArch std::string get_tile_by_type_loc(int row, int col, const std::set &type) const { - auto &tileloc = chip_info->tile_info[row * chip_info->width + col]; + auto &tileloc = device.chip_info->tile_info[row * device.chip_info->width + col]; for (auto &tn : tileloc.tile_names) { - if (type.count(chip_info->tiletype_names[tn.type_idx].get())) + if (type.count(device.chip_info->tiletype_names[tn.type_idx].get())) return tn.name.get(); } NPNR_ASSERT_FALSE_STR("no tile at (" + std::to_string(col) + ", " + std::to_string(row) + ") with type in set"); @@ -1042,10 +1071,10 @@ struct Arch : BaseArch std::string get_tile_by_type(std::string type) const { - for (int i = 0; i < chip_info->height * chip_info->width; i++) { - auto &tileloc = chip_info->tile_info[i]; + for (int i = 0; i < device.chip_info->height * device.chip_info->width; i++) { + auto &tileloc = device.chip_info->tile_info[i]; for (auto &tn : tileloc.tile_names) - if (chip_info->tiletype_names[tn.type_idx].get() == type) + if (device.chip_info->tiletype_names[tn.type_idx].get() == type) return tn.name.get(); } NPNR_ASSERT_FALSE_STR("no tile with type " + type); diff --git a/ecp5/arch_place.cc b/ecp5/arch_place.cc index e89e8fb4cc..4df27facb2 100644 --- a/ecp5/arch_place.cc +++ b/ecp5/arch_place.cc @@ -188,8 +188,8 @@ bool Arch::isBelLocationValid(BelId bel, bool explain_invalid) const if (cell == nullptr) { return true; } else if (cell->type.in(id_DCUA, id_EXTREFB, id_PCSCLKDIV)) { - return args.type != ArchArgs::LFE5U_25F && args.type != ArchArgs::LFE5U_45F && - args.type != ArchArgs::LFE5U_85F; + return device.type != ArchDevice::LFE5U_25F && device.type != ArchDevice::LFE5U_45F && + device.type != ArchDevice::LFE5U_85F; } else if (cell->type.in(id_MULT18X18D, id_ALU54B)) { return is_dsp_location_valid(cell); } else { diff --git a/ecp5/arch_pybindings.cc b/ecp5/arch_pybindings.cc index a4a58d4c48..a834c52226 100644 --- a/ecp5/arch_pybindings.cc +++ b/ecp5/arch_pybindings.cc @@ -30,7 +30,7 @@ NEXTPNR_NAMESPACE_BEGIN void arch_wrap_python(py::module &m) { using namespace PythonConversion; - py::class_(m, "ArchArgs").def_readwrite("type", &ArchArgs::type); + py::class_(m, "ArchArgs").def_readwrite("device", &ArchArgs::device); py::class_(m, "BelId").def_readwrite("index", &BelId::index); diff --git a/ecp5/baseconfigs.cc b/ecp5/baseconfigs.cc index f76e6c9386..f26d1acff9 100644 --- a/ecp5/baseconfigs.cc +++ b/ecp5/baseconfigs.cc @@ -5,7 +5,6 @@ NEXTPNR_NAMESPACE_BEGIN namespace BaseConfigs { void config_empty_lfe5u_25f(ChipConfig &cc) { - cc.chip_name = "LFE5U-25F"; cc.tiles["CIB_R49C3:CIB_PLL3"].add_enum("CIB.JA3MUX", "0"); cc.tiles["CIB_R49C3:CIB_PLL3"].add_enum("CIB.JB3MUX", "0"); cc.tiles["CIB_R49C42:VCIB_DCU0"].add_enum("CIB.JA1MUX", "0"); @@ -189,7 +188,6 @@ void config_empty_lfe5u_25f(ChipConfig &cc) void config_empty_lfe5u_45f(ChipConfig &cc) { - cc.chip_name = "LFE5U-45F"; cc.tiles["CIB_R10C3:PVT_COUNT2"].add_unknown(2, 0); cc.tiles["CIB_R10C3:PVT_COUNT2"].add_unknown(3, 0); cc.tiles["CIB_R10C3:PVT_COUNT2"].add_unknown(5, 0); @@ -522,7 +520,6 @@ void config_empty_lfe5u_45f(ChipConfig &cc) void config_empty_lfe5u_85f(ChipConfig &cc) { - cc.chip_name = "LFE5U-85F"; cc.tiles["CIB_R10C3:PVT_COUNT2"].add_unknown(2, 0); cc.tiles["CIB_R10C3:PVT_COUNT2"].add_unknown(3, 0); cc.tiles["CIB_R10C3:PVT_COUNT2"].add_unknown(5, 0); @@ -879,7 +876,6 @@ void config_empty_lfe5u_85f(ChipConfig &cc) void config_empty_lfe5um_25f(ChipConfig &cc) { - cc.chip_name = "LFE5UM-25F"; cc.tiles["CIB_R49C3:CIB_PLL3"].add_enum("CIB.JA3MUX", "0"); cc.tiles["CIB_R49C3:CIB_PLL3"].add_enum("CIB.JB3MUX", "0"); cc.tiles["CIB_R49C42:CIB_DCU0"].add_unknown(20, 10); @@ -1063,7 +1059,6 @@ void config_empty_lfe5um_25f(ChipConfig &cc) void config_empty_lfe5um_45f(ChipConfig &cc) { - cc.chip_name = "LFE5UM-45F"; cc.tiles["CIB_R10C3:PVT_COUNT2"].add_unknown(2, 0); cc.tiles["CIB_R10C3:PVT_COUNT2"].add_unknown(3, 0); cc.tiles["CIB_R10C3:PVT_COUNT2"].add_unknown(5, 0); @@ -1396,7 +1391,6 @@ void config_empty_lfe5um_45f(ChipConfig &cc) void config_empty_lfe5um5g_25f(ChipConfig &cc) { - cc.chip_name = "LFE5UM5G-25F"; cc.tiles["CIB_R49C3:CIB_PLL3"].add_enum("CIB.JA3MUX", "0"); cc.tiles["CIB_R49C3:CIB_PLL3"].add_enum("CIB.JB3MUX", "0"); cc.tiles["CIB_R49C42:CIB_DCU0"].add_unknown(20, 10); @@ -1580,7 +1574,6 @@ void config_empty_lfe5um5g_25f(ChipConfig &cc) void config_empty_lfe5um5g_45f(ChipConfig &cc) { - cc.chip_name = "LFE5UM5G-45F"; cc.tiles["CIB_R10C3:PVT_COUNT2"].add_unknown(2, 0); cc.tiles["CIB_R10C3:PVT_COUNT2"].add_unknown(3, 0); cc.tiles["CIB_R10C3:PVT_COUNT2"].add_unknown(5, 0); @@ -1913,7 +1906,6 @@ void config_empty_lfe5um5g_45f(ChipConfig &cc) void config_empty_lfe5um5g_85f(ChipConfig &cc) { - cc.chip_name = "LFE5UM5G-85F"; cc.tiles["CIB_R10C3:PVT_COUNT2"].add_unknown(2, 0); cc.tiles["CIB_R10C3:PVT_COUNT2"].add_unknown(3, 0); cc.tiles["CIB_R10C3:PVT_COUNT2"].add_unknown(5, 0); @@ -2270,7 +2262,6 @@ void config_empty_lfe5um5g_85f(ChipConfig &cc) void config_empty_lfe5um_85f(ChipConfig &cc) { - cc.chip_name = "LFE5UM-85F"; cc.tiles["CIB_R10C3:PVT_COUNT2"].add_unknown(2, 0); cc.tiles["CIB_R10C3:PVT_COUNT2"].add_unknown(3, 0); cc.tiles["CIB_R10C3:PVT_COUNT2"].add_unknown(5, 0); diff --git a/ecp5/bitstream.cc b/ecp5/bitstream.cc index 8987fefb70..aaad927278 100644 --- a/ecp5/bitstream.cc +++ b/ecp5/bitstream.cc @@ -195,7 +195,7 @@ struct ECP5Bitgen } else { NPNR_ASSERT_FALSE("bad PIO location"); } - } else if (bel.location.y == ctx->chip_info->height - 1) { + } else if (bel.location.y == ctx->device.chip_info->height - 1) { if (pio_name == "PIOA") { return ctx->get_tile_by_type_loc(bel.location.y, bel.location.x, pioa_b); } else if (pio_name == "PIOB") { @@ -205,7 +205,7 @@ struct ECP5Bitgen } } else if (bel.location.x == 0) { return ctx->get_tile_by_type_loc(bel.location.y + 1, bel.location.x, pioabcd_l); - } else if (bel.location.x == ctx->chip_info->width - 1) { + } else if (bel.location.x == ctx->device.chip_info->width - 1) { return ctx->get_tile_by_type_loc(bel.location.y + 1, bel.location.x, pioabcd_r); } else { NPNR_ASSERT_FALSE("bad PIO location"); @@ -232,7 +232,7 @@ struct ECP5Bitgen } else { NPNR_ASSERT_FALSE("bad PIO location"); } - } else if (bel.location.y == ctx->chip_info->height - 1) { + } else if (bel.location.y == ctx->device.chip_info->height - 1) { if (pio_name == "PIOA") { return ctx->get_tile_by_type_loc(bel.location.y, bel.location.x, pica_b); } else if (pio_name == "PIOB") { @@ -248,7 +248,7 @@ struct ECP5Bitgen } else { NPNR_ASSERT_FALSE("bad PIO location"); } - } else if (bel.location.x == ctx->chip_info->width - 1) { + } else if (bel.location.x == ctx->device.chip_info->width - 1) { if (pio_name == "PIOA" || pio_name == "PIOB") { return ctx->get_tile_by_type_loc(bel.location.y, bel.location.x, picab_r); } else if (pio_name == "PIOC" || pio_name == "PIOD") { @@ -443,8 +443,8 @@ struct ECP5Bitgen void fix_tile_names() { // Remove the V prefix/suffix on certain tiles if device is a SERDES variant - if (ctx->args.type == ArchArgs::LFE5U_12F || ctx->args.type == ArchArgs::LFE5U_25F || - ctx->args.type == ArchArgs::LFE5U_45F || ctx->args.type == ArchArgs::LFE5U_85F) { + if (ctx->device.type == ArchDevice::LFE5U_12F || ctx->device.type == ArchDevice::LFE5U_25F || + ctx->device.type == ArchDevice::LFE5U_45F || ctx->device.type == ArchDevice::LFE5U_85F) { std::map tiletype_xform; for (const auto &tile : cc.tiles) { std::string newname = tile.first; @@ -1370,36 +1370,35 @@ struct ECP5Bitgen } config_file >> cc; } else { - switch (ctx->args.type) { - case ArchArgs::LFE5U_12F: + switch (ctx->device.type) { + case ArchDevice::LFE5U_12F: BaseConfigs::config_empty_lfe5u_25f(cc); - cc.chip_name = "LFE5U-12F"; break; - case ArchArgs::LFE5U_25F: + case ArchDevice::LFE5U_25F: BaseConfigs::config_empty_lfe5u_25f(cc); break; - case ArchArgs::LFE5U_45F: + case ArchDevice::LFE5U_45F: BaseConfigs::config_empty_lfe5u_45f(cc); break; - case ArchArgs::LFE5U_85F: + case ArchDevice::LFE5U_85F: BaseConfigs::config_empty_lfe5u_85f(cc); break; - case ArchArgs::LFE5UM_25F: + case ArchDevice::LFE5UM_25F: BaseConfigs::config_empty_lfe5um_25f(cc); break; - case ArchArgs::LFE5UM_45F: + case ArchDevice::LFE5UM_45F: BaseConfigs::config_empty_lfe5um_45f(cc); break; - case ArchArgs::LFE5UM_85F: + case ArchDevice::LFE5UM_85F: BaseConfigs::config_empty_lfe5um_85f(cc); break; - case ArchArgs::LFE5UM5G_25F: + case ArchDevice::LFE5UM5G_25F: BaseConfigs::config_empty_lfe5um5g_25f(cc); break; - case ArchArgs::LFE5UM5G_45F: + case ArchDevice::LFE5UM5G_45F: BaseConfigs::config_empty_lfe5um5g_45f(cc); break; - case ArchArgs::LFE5UM5G_85F: + case ArchDevice::LFE5UM5G_85F: BaseConfigs::config_empty_lfe5um5g_85f(cc); break; default: @@ -1407,7 +1406,9 @@ struct ECP5Bitgen } } - cc.metadata.push_back("Part: " + ctx->get_full_chip_name()); + cc.chip_name = ctx->device.device_info->name.get(); + cc.chip_variant = ctx->device.device_name; + cc.metadata.push_back("Part: " + ctx->getChipName()); // Clear out DCU tieoffs in base config if DCU used for (auto &cell : ctx->cells) { @@ -1550,8 +1551,8 @@ struct ECP5Bitgen Loc loc = ctx->getBelLocation(ci->bel); bool u = loc.y<15, r = loc.x> 15; std::string tiletype = fmt_str("DDRDLL_" << (u ? 'U' : 'L') << (r ? 'R' : 'L')); - if ((ctx->args.type == ArchArgs::LFE5U_12F || ctx->args.type == ArchArgs::LFE5U_25F || - ctx->args.type == ArchArgs::LFE5UM_25F || ctx->args.type == ArchArgs::LFE5UM5G_25F) && + if ((ctx->device.type == ArchDevice::LFE5U_12F || ctx->device.type == ArchDevice::LFE5U_25F || + ctx->device.type == ArchDevice::LFE5UM_25F || ctx->device.type == ArchDevice::LFE5UM5G_25F) && u) tiletype += "A"; std::string tile = ctx->get_tile_by_type(tiletype); diff --git a/ecp5/config.cc b/ecp5/config.cc index ea9ece0dc3..9d8941cbc9 100644 --- a/ecp5/config.cc +++ b/ecp5/config.cc @@ -267,6 +267,7 @@ bool TileConfig::empty() const { return carcs.empty() && cwords.empty() && cenum std::ostream &operator<<(std::ostream &out, const ChipConfig &cc) { out << ".device " << cc.chip_name << std::endl << std::endl; + out << ".variant " << cc.chip_variant << std::endl << std::endl; for (const auto &meta : cc.metadata) out << ".comment " << meta << std::endl; for (const auto &sc : cc.sysconfig) @@ -311,6 +312,8 @@ std::istream &operator>>(std::istream &in, ChipConfig &cc) in >> verb; if (verb == ".device") { in >> cc.chip_name; + } else if (verb == ".variant") { + in >> cc.chip_variant; } else if (verb == ".comment") { std::string line; getline(in, line); diff --git a/ecp5/config.h b/ecp5/config.h index c51902fa19..8dc456a5ad 100644 --- a/ecp5/config.h +++ b/ecp5/config.h @@ -111,6 +111,7 @@ class ChipConfig { public: std::string chip_name; + std::string chip_variant; std::vector metadata; std::map tiles; std::vector tilegroups; diff --git a/ecp5/ecp5_available.h.in b/ecp5/ecp5_available.h.in new file mode 100644 index 0000000000..d51afc7a26 --- /dev/null +++ b/ecp5/ecp5_available.h.in @@ -0,0 +1 @@ +static const char *available_devices = "@ECP5_DEVICES@"; \ No newline at end of file diff --git a/ecp5/family.cmake b/ecp5/family.cmake index 0c4fa69562..5ecdadaf74 100644 --- a/ecp5/family.cmake +++ b/ecp5/family.cmake @@ -48,6 +48,9 @@ target_compile_options(chipdb-${family} PRIVATE -g0 -O0 -w) target_compile_definitions(chipdb-${family} PRIVATE NEXTPNR_NAMESPACE=nextpnr_${family}) target_include_directories(chipdb-${family} PRIVATE ${family}) +configure_file(${family}/ecp5_available.h.in ${CMAKE_CURRENT_BINARY_DIR}/generated/ecp5_available.h) + foreach(family_target ${family_targets}) target_sources(${family_target} PRIVATE $) + target_sources(${family_target} PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/generated/ecp5_available.h) endforeach() diff --git a/ecp5/main.cc b/ecp5/main.cc index 6abea4a9f7..5dabcf6add 100644 --- a/ecp5/main.cc +++ b/ecp5/main.cc @@ -49,29 +49,21 @@ ECP5CommandHandler::ECP5CommandHandler(int argc, char **argv) : CommandHandler(a po::options_description ECP5CommandHandler::getArchOptions() { po::options_description specific("Architecture specific options"); - if (Arch::is_available(ArchArgs::LFE5U_12F)) - specific.add_options()("12k", "set device type to LFE5U-12F"); - if (Arch::is_available(ArchArgs::LFE5U_25F)) - specific.add_options()("25k", "set device type to LFE5U-25F"); - if (Arch::is_available(ArchArgs::LFE5U_45F)) - specific.add_options()("45k", "set device type to LFE5U-45F"); - if (Arch::is_available(ArchArgs::LFE5U_85F)) - specific.add_options()("85k", "set device type to LFE5U-85F"); - if (Arch::is_available(ArchArgs::LFE5UM_25F)) - specific.add_options()("um-25k", "set device type to LFE5UM-25F"); - if (Arch::is_available(ArchArgs::LFE5UM_45F)) - specific.add_options()("um-45k", "set device type to LFE5UM-45F"); - if (Arch::is_available(ArchArgs::LFE5UM_85F)) - specific.add_options()("um-85k", "set device type to LFE5UM-85F"); - if (Arch::is_available(ArchArgs::LFE5UM5G_25F)) - specific.add_options()("um5g-25k", "set device type to LFE5UM5G-25F"); - if (Arch::is_available(ArchArgs::LFE5UM5G_45F)) - specific.add_options()("um5g-45k", "set device type to LFE5UM5G-45F"); - if (Arch::is_available(ArchArgs::LFE5UM5G_85F)) - specific.add_options()("um5g-85k", "set device type to LFE5UM5G-85F"); - - specific.add_options()("package", po::value(), "select device package (defaults to CABGA381)"); - specific.add_options()("speed", po::value(), "select device speedgrade (6, 7 or 8)"); + specific.add_options()("device", po::value(), "device name"); + specific.add_options()("list-devices", "list all supported device names"); + specific.add_options()("12k", "set device type to LFE5U-12F (deprecated)"); + specific.add_options()("25k", "set device type to LFE5U-25F (deprecated)"); + specific.add_options()("45k", "set device type to LFE5U-45F (deprecated)"); + specific.add_options()("85k", "set device type to LFE5U-85F (deprecated)"); + specific.add_options()("um-25k", "set device type to LFE5UM-25F (deprecated)"); + specific.add_options()("um-45k", "set device type to LFE5UM-45F (deprecated)"); + specific.add_options()("um-85k", "set device type to LFE5UM-85F (deprecated)"); + specific.add_options()("um5g-25k", "set device type to LFE5UM5G-25F (deprecated)"); + specific.add_options()("um5g-45k", "set device type to LFE5UM5G-45F (deprecated)"); + specific.add_options()("um5g-85k", "set device type to LFE5UM5G-85F (deprecated)"); + + specific.add_options()("package", po::value(), "select device package (defaults to CABGA381) (deprecated)"); + specific.add_options()("speed", po::value(), "select device speedgrade (6, 7 or 8) (deprecated)"); specific.add_options()("basecfg", po::value(), "base chip configuration in Trellis text format (deprecated)"); @@ -91,7 +83,10 @@ po::options_description ECP5CommandHandler::getArchOptions() } void ECP5CommandHandler::validate() { - if ((vm.count("25k") + vm.count("45k") + vm.count("85k")) > 1) + if ((vm.count("12k") + vm.count("25k") + vm.count("45k") + vm.count("85k") + + vm.count("um-25k") + vm.count("um-45k") + vm.count("um-85k") + + vm.count("um5g-25k") + vm.count("um5g-45k") + vm.count("um5g-85k") + + vm.count("device")) > 1) log_error("Only one device type can be set\n"); } @@ -117,70 +112,37 @@ void ECP5CommandHandler::customBitstream(Context *ctx) } } -static std::string speedString(ArchArgs::SpeedGrade speed) -{ - switch (speed) { - case ArchArgs::SPEED_6: - return "6"; - case ArchArgs::SPEED_7: - return "7"; - case ArchArgs::SPEED_8: - return "8"; - case ArchArgs::SPEED_8_5G: - return "8"; - } - return ""; -} std::unique_ptr ECP5CommandHandler::createContext(dict &values) { ArchArgs chipArgs; - chipArgs.type = ArchArgs::NONE; - if (vm.count("12k")) - chipArgs.type = ArchArgs::LFE5U_12F; - if (vm.count("25k")) - chipArgs.type = ArchArgs::LFE5U_25F; - if (vm.count("45k")) - chipArgs.type = ArchArgs::LFE5U_45F; - if (vm.count("85k")) - chipArgs.type = ArchArgs::LFE5U_85F; - if (vm.count("um-25k")) - chipArgs.type = ArchArgs::LFE5UM_25F; - if (vm.count("um-45k")) - chipArgs.type = ArchArgs::LFE5UM_45F; - if (vm.count("um-85k")) - chipArgs.type = ArchArgs::LFE5UM_85F; - if (vm.count("um5g-25k")) - chipArgs.type = ArchArgs::LFE5UM5G_25F; - if (vm.count("um5g-45k")) - chipArgs.type = ArchArgs::LFE5UM5G_45F; - if (vm.count("um5g-85k")) - chipArgs.type = ArchArgs::LFE5UM5G_85F; - if (vm.count("package")) - chipArgs.package = vm["package"].as(); - - if (vm.count("speed")) { - int speed = vm["speed"].as(); - switch (speed) { - case 6: - chipArgs.speed = ArchArgs::SPEED_6; - break; - case 7: - chipArgs.speed = ArchArgs::SPEED_7; - break; - case 8: - chipArgs.speed = ArchArgs::SPEED_8; - break; - default: - log_error("Unsupported speed grade '%d'\n", speed); - } - } else { - if (chipArgs.type == ArchArgs::LFE5UM5G_25F || chipArgs.type == ArchArgs::LFE5UM5G_45F || - chipArgs.type == ArchArgs::LFE5UM5G_85F) { - chipArgs.speed = ArchArgs::SPEED_8; - } else - chipArgs.speed = ArchArgs::SPEED_6; + if (vm.count("list-devices")) { + Arch::list_devices(); + exit(0); } + if (vm.count("device")) + chipArgs.device = vm["device"].as(); + else if (vm.count("12k")) + chipArgs.device = "LFE5U-12F"; + else if (vm.count("25k")) + chipArgs.device = "LFE5U-25F"; + else if (vm.count("45k")) + chipArgs.device = "LFE5U-45F"; + else if (vm.count("85k")) + chipArgs.device = "LFE5U-85F"; + else if (vm.count("um-25k")) + chipArgs.device = "LFE5UM-25F"; + else if (vm.count("um-45k")) + chipArgs.device = "LFE5UM-45F"; + else if (vm.count("um-85k")) + chipArgs.device = "LFE5UM-85F"; + else if (vm.count("um5g-25k")) + chipArgs.device = "LFE5UM5G-25F"; + else if (vm.count("um5g-45k")) + chipArgs.device = "LFE5UM5G-45F"; + else if (vm.count("um5g-85k")) + chipArgs.device = "LFE5UM5G-85F"; + if (values.find("arch.name") != values.end()) { std::string arch_name = values["arch.name"].as_string(); if (arch_name != "ecp5") @@ -188,71 +150,61 @@ std::unique_ptr ECP5CommandHandler::createContext(dict(); + switch (speed) { + case 6: + chipArgs.device += "-6"; + break; + case 7: + chipArgs.device += "-7"; + break; + case 8: + chipArgs.device += "-8"; + break; + default: + log_error("Unsupported speed grade '%d'\n", speed); + } + } else { + if (strstr(chipArgs.device.c_str(),"LFE5UM5G")) { + chipArgs.device += "-8"; + } else + chipArgs.device += "-6"; + } + if (vm.count("package")) { + std::string package = vm["package"].as(); + if (strcasecmp(package.c_str(), "csfBGA285")==0) { + chipArgs.device += "MG285C"; + } else if (strcasecmp(package.c_str(), "caBGA256")==0) { + chipArgs.device += "BG256C"; + } else if (strcasecmp(package.c_str(), "caBGA381")==0) { + chipArgs.device += "BG381C"; + } else if (strcasecmp(package.c_str(), "caBGA554")==0) { + chipArgs.device += "BG554C"; + } else if (strcasecmp(package.c_str(), "caBGA756")==0) { + chipArgs.device += "BG756C"; + } else { + log_error("Unsupported package '%s'\n", package.c_str()); + } + } + else { + chipArgs.device += "BG381C"; + log_warning("Use of default value for --package is deprecated. Please add '--package caBGA381' to arguments.\n"); + } } auto ctx = std::unique_ptr(new Context(chipArgs)); for (auto &val : values) ctx->settings[ctx->id(val.first)] = val.second; - ctx->settings[ctx->id("arch.package")] = ctx->archArgs().package; - ctx->settings[ctx->id("arch.speed")] = speedString(ctx->archArgs().speed); if (vm.count("out-of-context")) ctx->settings[ctx->id("arch.ooc")] = 1; if (vm.count("disable-router-lutperm")) diff --git a/ecp5/pack.cc b/ecp5/pack.cc index 3b56daa92f..386ad97f72 100644 --- a/ecp5/pack.cc +++ b/ecp5/pack.cc @@ -582,7 +582,7 @@ class Ecp5Packer BelId pinBel = ctx->get_package_pin_bel(pin); if (pinBel == BelId()) { log_error("IO pin '%s' constrained to pin '%s', which does not exist for package '%s'.\n", - trio->name.c_str(ctx), pin.c_str(), ctx->args.package.c_str()); + trio->name.c_str(ctx), pin.c_str(), ctx->device.package_name); } else { log_info("pin '%s' constrained to Bel '%s'.\n", trio->name.c_str(ctx), ctx->nameOfBel(pinBel)); @@ -665,7 +665,7 @@ class Ecp5Packer { bool start_of_chain = true; std::vector chains; - const int max_length = (ctx->chip_info->width - 4) * 4 - 2; + const int max_length = (ctx->device.chip_info->width - 4) * 4 - 2; auto curr_cell = carryc.cells.begin(); while (curr_cell != carryc.cells.end()) { CellInfo *cell = *curr_cell; @@ -1323,19 +1323,19 @@ class Ecp5Packer if (ci->attrs.count(id_LOC)) { std::string loc = ci->attrs.at(id_LOC).as_string(); if (loc == "DCU0" && - (ctx->args.type == ArchArgs::LFE5UM_25F || ctx->args.type == ArchArgs::LFE5UM5G_25F)) + (ctx->device.type == ArchDevice::LFE5UM_25F || ctx->device.type == ArchDevice::LFE5UM5G_25F)) ci->attrs[id_BEL] = std::string("X42/Y50/DCU"); else if (loc == "DCU0" && - (ctx->args.type == ArchArgs::LFE5UM_45F || ctx->args.type == ArchArgs::LFE5UM5G_45F)) + (ctx->device.type == ArchDevice::LFE5UM_45F || ctx->device.type == ArchDevice::LFE5UM5G_45F)) ci->attrs[id_BEL] = std::string("X42/Y71/DCU"); else if (loc == "DCU1" && - (ctx->args.type == ArchArgs::LFE5UM_45F || ctx->args.type == ArchArgs::LFE5UM5G_45F)) + (ctx->device.type == ArchDevice::LFE5UM_45F || ctx->device.type == ArchDevice::LFE5UM5G_45F)) ci->attrs[id_BEL] = std::string("X69/Y71/DCU"); else if (loc == "DCU0" && - (ctx->args.type == ArchArgs::LFE5UM_85F || ctx->args.type == ArchArgs::LFE5UM5G_85F)) + (ctx->device.type == ArchDevice::LFE5UM_85F || ctx->device.type == ArchDevice::LFE5UM5G_85F)) ci->attrs[id_BEL] = std::string("X46/Y95/DCU"); else if (loc == "DCU1" && - (ctx->args.type == ArchArgs::LFE5UM_85F || ctx->args.type == ArchArgs::LFE5UM5G_85F)) + (ctx->device.type == ArchDevice::LFE5UM_85F || ctx->device.type == ArchDevice::LFE5UM5G_85F)) ci->attrs[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()); @@ -1378,19 +1378,19 @@ class Ecp5Packer if (ci->attrs.count(id_LOC)) { std::string loc = ci->attrs.at(id_LOC).as_string(); if (loc == "EXTREF0" && - (ctx->args.type == ArchArgs::LFE5UM_25F || ctx->args.type == ArchArgs::LFE5UM5G_25F)) + (ctx->device.type == ArchDevice::LFE5UM_25F || ctx->device.type == ArchDevice::LFE5UM5G_25F)) loc_bel = std::string("X42/Y50/EXTREF"); else if (loc == "EXTREF0" && - (ctx->args.type == ArchArgs::LFE5UM_45F || ctx->args.type == ArchArgs::LFE5UM5G_45F)) + (ctx->device.type == ArchDevice::LFE5UM_45F || ctx->device.type == ArchDevice::LFE5UM5G_45F)) loc_bel = std::string("X42/Y71/EXTREF"); else if (loc == "EXTREF1" && - (ctx->args.type == ArchArgs::LFE5UM_45F || ctx->args.type == ArchArgs::LFE5UM5G_45F)) + (ctx->device.type == ArchDevice::LFE5UM_45F || ctx->device.type == ArchDevice::LFE5UM5G_45F)) loc_bel = std::string("X69/Y71/EXTREF"); else if (loc == "EXTREF0" && - (ctx->args.type == ArchArgs::LFE5UM_85F || ctx->args.type == ArchArgs::LFE5UM5G_85F)) + (ctx->device.type == ArchDevice::LFE5UM_85F || ctx->device.type == ArchDevice::LFE5UM5G_85F)) loc_bel = std::string("X46/Y95/EXTREF"); else if (loc == "EXTREF1" && - (ctx->args.type == ArchArgs::LFE5UM_85F || ctx->args.type == ArchArgs::LFE5UM5G_85F)) + (ctx->device.type == ArchDevice::LFE5UM_85F || ctx->device.type == ArchDevice::LFE5UM5G_85F)) loc_bel = std::string("X71/Y95/EXTREF"); } if (refo == nullptr) @@ -1859,7 +1859,7 @@ class Ecp5Packer log_info("IOLOGIC component %s connected to PIO Bel %s\n", curr->name.c_str(ctx), ctx->nameOfBel(bel)); Loc loc = ctx->getBelLocation(bel); bool s = false; - if (loc.y == 0 || loc.y == (ctx->chip_info->height - 1)) + if (loc.y == 0 || loc.y == (ctx->device.chip_info->height - 1)) s = true; std::unique_ptr iol = create_ecp5_cell(ctx, s ? id_SIOLOGIC : id_IOLOGIC, pio->name.str(ctx) + "$IOL"); diff --git a/ecp5/trellis_import.py b/ecp5/trellis_import.py index 1554ea1a0c..c097d636fa 100755 --- a/ecp5/trellis_import.py +++ b/ecp5/trellis_import.py @@ -167,6 +167,14 @@ def get_tiletype_index(name): tiletype_names[name] = idx return idx +def package_shortname(long_name): + if long_name.startswith("caBGA"): + return "BG" + long_name[5:] + elif long_name.startswith("csfBGA"): + return "MG" + long_name[6:] + else: + print("unknown package name " + long_name) + sys.exit(-1) constids = dict() @@ -241,6 +249,17 @@ def get_bel_index(ddrg, loc, name): packages = {} pindata = [] +devices = {} + +def process_devices_db(family, device): + devicefile = path.join(database.get_db_root(), "devices.json") + with open(devicefile, 'r') as f: + devicedb = json.load(f) + for dev in device: + variants = {} + for varname, vardata in sorted(devicedb["families"][family]["devices"][dev]["variants"].items()): + variants[varname] = vardata + devices[dev] = variants def process_pio_db(ddrg, device): piofile = path.join(database.get_db_root(), "ECP5", dev_names[device], "iodb.json") @@ -640,6 +659,33 @@ def get_wire_name(arc_loctype, rel, idx): bba.r_slice("cell_timing_data_%s" % grade, len(speed_grade_cells[grade]), "cell_timings") bba.r_slice("pip_timing_data_%s" % grade, len(speed_grade_pips[grade]), "pip_classes") + for _, dev_data in sorted(devices.items()): + for name, var_data in sorted(dev_data.items()): + bba.l("supported_packages_%s" % name, "PackageSupportedPOD") + for package in var_data["packages"]: + bba.s(package, "name") + bba.s(package_shortname(package), "short_name") + bba.l("supported_speed_grades_%s" % name, "SpeedSupportedPOD") + for speed in var_data["speeds"]: + bba.u32(speed, "speed") + bba.l("supported_suffixes_%s" % name, "SuffixeSupportedPOD") + for suffix in var_data["suffixes"]: + bba.s(suffix, "suffix") + + for name, dev_data in sorted(devices.items()): + bba.l("variant_data_%s" % name, "VariantInfoPOD") + for name, var_data in sorted(dev_data.items()): + bba.s(name, "variant_name") + bba.r_slice("supported_packages_%s" % name, len(var_data["packages"]), "supported_packages") + bba.r_slice("supported_speed_grades_%s" % name, len(var_data["speeds"]), "supported_speed_grades") + bba.r_slice("supported_suffixes_%s" % name, len(var_data["suffixes"]), "supported_suffixes") + + bba.l("devices_data", "DeviceInfoPOD") + for name, dev_data in sorted(devices.items()): + bba.s(chip.info.family, "family") + bba.s(name, "device_name") + bba.r_slice("variant_data_%s" % name, len(dev_data), "variant_info") + bba.l("chip_info") bba.u32(max_col + 1, "width") bba.u32(max_row + 1, "height") @@ -654,11 +700,12 @@ def get_wire_name(arc_loctype, rel, idx): bba.r_slice("pio_info", len(pindata), "pio_info") bba.r_slice("tiles_info", (max_col + 1) * (max_row + 1), "tile_info") bba.r_slice("speed_grade_data", len(speed_grade_names), "speed_grades") + bba.r_slice("devices_data", len(devices), "device_info") bba.pop() return bba -dev_names = {"25k": "LFE5UM5G-25F", "45k": "LFE5UM5G-45F", "85k": "LFE5UM5G-85F"} +dev_names = {"25k": "LFE5UM-25F", "45k": "LFE5UM-45F", "85k": "LFE5UM-85F"} def main(): global max_row, max_col, const_id_count @@ -692,6 +739,7 @@ def main(): process_timing_data() process_pio_db(ddrg, args.device) process_loc_globals(chip) + process_devices_db(chip.info.family, [ chip.info.name, chip.info.name.replace("LFE5UM","LFE5U") ]) # print("{} unique location types".format(len(ddrg.locationTypes))) bba = write_database(args.device, chip, ddrg, "le") diff --git a/gui/ecp5/mainwindow.cc b/gui/ecp5/mainwindow.cc index 73d4a9891b..306f362832 100644 --- a/gui/ecp5/mainwindow.cc +++ b/gui/ecp5/mainwindow.cc @@ -20,7 +20,9 @@ #include "mainwindow.h" #include #include "bitstream.h" +#include "embed.h" #include "log.h" +#include "ecp5_available.h" #include #include @@ -47,7 +49,8 @@ MainWindow::~MainWindow() {} void MainWindow::newContext(Context *ctx) { - std::string title = "nextpnr-ecp5 - " + ctx->getChipName() + " ( " + ctx->archArgs().package + " )"; + std::string title = "nextpnr-ecp5 - " + std::string(ctx->device.device_name) + " (" + std::string(ctx->device.package_name) + + ") - Part : " + ctx->getChipName(); setWindowTitle(title.c_str()); } @@ -78,50 +81,46 @@ void MainWindow::createMenu() void MainWindow::new_proj() { - QMap arch; - if (Arch::is_available(ArchArgs::LFE5U_25F)) - arch.insert("Lattice ECP5 LFE5U-25F", ArchArgs::LFE5U_25F); - if (Arch::is_available(ArchArgs::LFE5U_45F)) - arch.insert("Lattice ECP5 LFE5U-45F", ArchArgs::LFE5U_45F); - if (Arch::is_available(ArchArgs::LFE5U_85F)) - arch.insert("Lattice ECP5 LFE5U-85F", ArchArgs::LFE5U_85F); - if (Arch::is_available(ArchArgs::LFE5UM_25F)) - arch.insert("Lattice ECP5 LFE5UM-25F", ArchArgs::LFE5UM_25F); - if (Arch::is_available(ArchArgs::LFE5UM_45F)) - arch.insert("Lattice ECP5 LFE5UM-45F", ArchArgs::LFE5UM_45F); - if (Arch::is_available(ArchArgs::LFE5UM_85F)) - arch.insert("Lattice ECP5 LFE5UM-85F", ArchArgs::LFE5UM_85F); - if (Arch::is_available(ArchArgs::LFE5UM5G_25F)) - arch.insert("Lattice ECP5 LFE5UM5G-25F", ArchArgs::LFE5UM5G_25F); - if (Arch::is_available(ArchArgs::LFE5UM5G_45F)) - arch.insert("Lattice ECP5 LFE5UM5G-45F", ArchArgs::LFE5UM5G_45F); - if (Arch::is_available(ArchArgs::LFE5UM5G_85F)) - arch.insert("Lattice ECP5 LFE5UM5G-85F", ArchArgs::LFE5UM5G_85F); + QList arch; + + std::stringstream ss(available_devices); + std::string name; + while (getline(ss, name, ';')) { + std::string chipdb = stringf("ecp5/chipdb-%s.bin", name.c_str()); + auto db_ptr = reinterpret_cast *>(get_chipdb(chipdb)); + if (!db_ptr) + continue; // chipdb not available + for (auto &dev : db_ptr->get()->devices) { + for (auto &chip : dev.variants) { + for (auto &pkg : chip.packages) { + for (auto &speedgrade : chip.speed_grades) { + for (auto &rating : chip.suffixes) { + std::string devname = stringf("%s-%d%s%s", chip.name.get(), speedgrade.speed, + pkg.short_name.get(), rating.suffix.get()); + arch.append(QString::fromLocal8Bit(devname.c_str())); + } + } + } + } + } + } bool ok; - QString item = QInputDialog::getItem(this, "Select new context", "Chip:", arch.keys(), 0, false, &ok); + QString item = QInputDialog::getItem(this, "Select new context", "Part:", arch, 0, false, &ok); if (ok && !item.isEmpty()) { ArchArgs chipArgs; - chipArgs.type = (ArchArgs::ArchArgsTypes)arch.value(item); - - QStringList packages; - for (auto package : Arch::get_supported_packages(chipArgs.type)) - packages.append(QLatin1String(package.data(), package.size())); - QString package = QInputDialog::getItem(this, "Select package", "Package:", packages, 0, false, &ok); - - if (ok && !item.isEmpty()) { - handler->clear(); - currentProj = ""; - disableActions(); - chipArgs.package = package.toStdString().c_str(); - ctx = std::unique_ptr(new Context(chipArgs)); - actionLoadJSON->setEnabled(true); - - Q_EMIT contextChanged(ctx.get()); - } + chipArgs.device = item.toUtf8().constData(); + ; + + handler->clear(); + currentProj = ""; + disableActions(); + ctx = std::unique_ptr(new Context(chipArgs)); + actionLoadJSON->setEnabled(true); + + Q_EMIT contextChanged(ctx.get()); } } - void MainWindow::open_lpf() { QString fileName = QFileDialog::getOpenFileName(this, QString("Open LPF"), QString(), QString("*.lpf"));