diff --git a/ecp5/arch.cc b/ecp5/arch.cc index 11429eb4..01f01f10 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,60 +49,89 @@ void IdString::initialize_arch(const BaseCtx *ctx) #undef X } -// ----------------------------------------------------------------------- +// --------------------------------------------------------------- -static const ChipInfoPOD *get_chip_info(ArchArgs::ArchArgsTypes chip) +static void get_chip_info(std::string device, const DeviceInfoPOD **device_info, const ChipInfoPOD **chip_info, const PackageInfoPOD **package_info, + const char **device_name, const char **package_name, Arch::ArchTypes *type, Arch::SpeedGrade *speed) { - 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"); + 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) { + *device_info = &dev; + *chip_info = db_ptr->get(); + *package_info = nullptr; + *package_name = pkg.name.get(); + *device_name = chip.name.get(); + *type = Arch::ArchTypes::NONE; + if (strcmp(*device_name,"LFE5U-12F")==0 || strcmp(*device_name,"LAE5U-12F")==0) + *type = Arch::ArchTypes::LFE5U_12F; + else if (strcmp(*device_name,"LFE5U-25F")==0) + *type = Arch::ArchTypes::LFE5U_25F; + else if (strcmp(*device_name,"LFE5U-45F")==0) + *type = Arch::ArchTypes::LFE5U_45F; + else if (strcmp(*device_name,"LFE5U-85F")==0) + *type = Arch::ArchTypes::LFE5U_85F; + else if (strcmp(*device_name,"LFE5UM-25F")==0 || strcmp(*device_name,"LAE5UM-25F")==0) + *type = Arch::ArchTypes::LFE5UM_25F; + else if (strcmp(*device_name,"LFE5UM-45F")==0 || strcmp(*device_name,"LAE5UM-45F")==0) + *type = Arch::ArchTypes::LFE5UM_45F; + else if (strcmp(*device_name,"LFE5UM-85F")==0 || strcmp(*device_name,"LAE5UM-85F")==0) + *type = Arch::ArchTypes::LFE5UM_85F; + else if (strcmp(*device_name,"LFE5UM5G-25F")==0) + *type = Arch::ArchTypes::LFE5UM5G_25F; + else if (strcmp(*device_name,"LFE5UM5G-45F")==0) + *type = Arch::ArchTypes::LFE5UM5G_45F; + else if (strcmp(*device_name,"LFE5UM5G-85F")==0) + *type = Arch::ArchTypes::LFE5UM5G_85F; + else + log_error("Unsupported device '%s'.\n", *device_name); + + *speed = Arch::SpeedGrade(speedgrade.speed - 6); + if (strstr(*device_name,"LFE5UM5G")) { + *speed = Arch::SPEED_8_5G; + } + for (auto &pi : db_ptr->get()->package_info) { + if (strcasecmp(pkg.name.get(),pi.name.get())==0) { + *package_info = π + break; + } + } + return; + } + } + } + } + } + } } - - auto ptr = reinterpret_cast *>(get_chipdb(chipdb)); - if (ptr == nullptr) - return nullptr; - return ptr->get(); } -bool Arch::is_available(ArchArgs::ArchArgsTypes chip) { return get_chip_info(chip) != nullptr; } - -std::vector Arch::get_supported_packages(ArchArgs::ArchArgsTypes chip) -{ - 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; -} - -// ----------------------------------------------------------------------- +// --------------------------------------------------------------- Arch::Arch(ArchArgs args) : args(args) { - chip_info = get_chip_info(args.type); + get_chip_info(args.device, &device_info, &chip_info, &package_info, &device_name, &package_name, &type, &speed); if (chip_info == nullptr) - log_error("Unsupported ECP5 chip type.\n"); + log_error("Unsupported device '%s'.\n", args.device.c_str()); 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 (auto &pkg : chip_info->package_info) { - if (args.package == pkg.name.get()) { - package_info = &pkg; - break; - } - } - speed_grade = &(chip_info->speed_grades[args.speed]); + speed_grade = &(chip_info->speed_grades[speed]); if (!package_info) - log_error("Unsupported package '%s' for '%s'.\n", args.package.c_str(), getChipName().c_str()); + log_error("Unsupported package '%s' for '%s'.\n", package_name, getChipName().c_str()); tile_status.resize(chip_info->num_tiles); for (int i = 0; i < chip_info->num_tiles; i++) { @@ -160,81 +190,35 @@ Arch::Arch(ArchArgs args) : args(args) lutperm_allowed.resize(chip_info->width * chip_info->height * 4); } -// ----------------------------------------------------------------------- - -std::string Arch::getChipName() const +void Arch::list_devices() { - 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"); + 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()); + } + } + } + } + } } } -std::string Arch::get_full_chip_name() const -{ - 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; - } - 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); } // ----------------------------------------------------------------------- @@ -500,7 +484,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 * speed) * (6 + std::max(dx - 5, 0) + std::max(dy - 5, 0) + 2 * (std::min(dx, 5) + std::min(dy, 5))); } @@ -578,7 +562,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 * speed) * (3 + std::max(dx - 5, 0) + std::max(dy - 5, 0) + 2 * (std::min(dx, 5) + std::min(dy, 5))); } diff --git a/ecp5/arch.h b/ecp5/arch.h index 56ba3e7b..58a0b86b 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 @@ -446,9 +448,34 @@ struct ArchRanges : BaseArchRanges struct Arch : BaseArch { + 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; mutable dict pip_by_name; @@ -513,11 +540,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; diff --git a/ecp5/arch_place.cc b/ecp5/arch_place.cc index e89e8fb4..8009054d 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 type != Arch::ArchTypes::LFE5U_25F && type != Arch::ArchTypes::LFE5U_45F && + type != Arch::ArchTypes::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 a4a58d4c..a834c522 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 f76e6c93..f26d1acf 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 8987fefb..d2630be9 100644 --- a/ecp5/bitstream.cc +++ b/ecp5/bitstream.cc @@ -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->type == Arch::ArchTypes::LFE5U_12F || ctx->type == Arch::ArchTypes::LFE5U_25F || + ctx->type == Arch::ArchTypes::LFE5U_45F || ctx->type == Arch::ArchTypes::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: - BaseConfigs::config_empty_lfe5u_25f(cc); - cc.chip_name = "LFE5U-12F"; - break; - case ArchArgs::LFE5U_25F: + switch (ctx->type) { + case Arch::ArchTypes::LFE5U_12F: BaseConfigs::config_empty_lfe5u_25f(cc); break; - case ArchArgs::LFE5U_45F: + case Arch::ArchTypes::LFE5U_25F: + BaseConfigs::config_empty_lfe5u_25f(cc); + break; + case Arch::ArchTypes::LFE5U_45F: BaseConfigs::config_empty_lfe5u_45f(cc); break; - case ArchArgs::LFE5U_85F: + case Arch::ArchTypes::LFE5U_85F: BaseConfigs::config_empty_lfe5u_85f(cc); break; - case ArchArgs::LFE5UM_25F: + case Arch::ArchTypes::LFE5UM_25F: BaseConfigs::config_empty_lfe5um_25f(cc); break; - case ArchArgs::LFE5UM_45F: + case Arch::ArchTypes::LFE5UM_45F: BaseConfigs::config_empty_lfe5um_45f(cc); break; - case ArchArgs::LFE5UM_85F: + case Arch::ArchTypes::LFE5UM_85F: BaseConfigs::config_empty_lfe5um_85f(cc); break; - case ArchArgs::LFE5UM5G_25F: + case Arch::ArchTypes::LFE5UM5G_25F: BaseConfigs::config_empty_lfe5um5g_25f(cc); break; - case ArchArgs::LFE5UM5G_45F: + case Arch::ArchTypes::LFE5UM5G_45F: BaseConfigs::config_empty_lfe5um5g_45f(cc); break; - case ArchArgs::LFE5UM5G_85F: + case Arch::ArchTypes::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_info->name.get(); + cc.chip_variant = ctx->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->type == Arch::ArchTypes::LFE5U_12F || ctx->type == Arch::ArchTypes::LFE5U_25F || + ctx->type == Arch::ArchTypes::LFE5UM_25F || ctx->type == Arch::ArchTypes::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 ea9ece0d..9d8941cb 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 c51902fa..8dc456a5 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 00000000..d51afc7a --- /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 0c4fa695..5ecdadaf 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 6abea4a9..5dabcf6a 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()("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)"); - specific.add_options()("speed", po::value(), "select device speedgrade (6, 7 or 8)"); + 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 3b56daa9..089ec643 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->package_name); } else { log_info("pin '%s' constrained to Bel '%s'.\n", trio->name.c_str(ctx), ctx->nameOfBel(pinBel)); @@ -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->type == Arch::ArchTypes::LFE5UM_25F || ctx->type == Arch::ArchTypes::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->type == Arch::ArchTypes::LFE5UM_45F || ctx->type == Arch::ArchTypes::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->type == Arch::ArchTypes::LFE5UM_45F || ctx->type == Arch::ArchTypes::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->type == Arch::ArchTypes::LFE5UM_85F || ctx->type == Arch::ArchTypes::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->type == Arch::ArchTypes::LFE5UM_85F || ctx->type == Arch::ArchTypes::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->type == Arch::ArchTypes::LFE5UM_25F || ctx->type == Arch::ArchTypes::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->type == Arch::ArchTypes::LFE5UM_45F || ctx->type == Arch::ArchTypes::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->type == Arch::ArchTypes::LFE5UM_45F || ctx->type == Arch::ArchTypes::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->type == Arch::ArchTypes::LFE5UM_85F || ctx->type == Arch::ArchTypes::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->type == Arch::ArchTypes::LFE5UM_85F || ctx->type == Arch::ArchTypes::LFE5UM5G_85F)) loc_bel = std::string("X71/Y95/EXTREF"); } if (refo == nullptr) diff --git a/ecp5/trellis_import.py b/ecp5/trellis_import.py index 1554ea1a..c097d636 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 write_database(dev_name, chip, ddrg, endianness): 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 write_database(dev_name, chip, ddrg, endianness): 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 73d4a989..fb728d09 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_name) + " (" + std::string(ctx->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; - bool ok; - QString item = QInputDialog::getItem(this, "Select new context", "Chip:", arch.keys(), 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()); + 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", "Part:", arch, 0, false, &ok); + if (ok && !item.isEmpty()) { + ArchArgs chipArgs; + 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"));