diff --git a/himbaechel/family.cmake b/himbaechel/family.cmake index 88a52b33..1c11c24b 100644 --- a/himbaechel/family.cmake +++ b/himbaechel/family.cmake @@ -1,4 +1,4 @@ -set(HIMBAECHEL_UARCHES "example;gowin;xilinx") +set(HIMBAECHEL_UARCHES "example;gowin;xilinx;ng-ultra") foreach(uarch ${HIMBAECHEL_UARCHES}) add_subdirectory(${family}/uarch/${uarch}) aux_source_directory(${family}/uarch/${uarch} HM_UARCH_FILES) diff --git a/himbaechel/uarch/ng-ultra/CMakeLists.txt b/himbaechel/uarch/ng-ultra/CMakeLists.txt new file mode 100644 index 00000000..e7437bde --- /dev/null +++ b/himbaechel/uarch/ng-ultra/CMakeLists.txt @@ -0,0 +1,2 @@ +message(STATUS "Configuring Himbaechel-NG-ULTRA uarch") + diff --git a/himbaechel/uarch/ng-ultra/constids.inc b/himbaechel/uarch/ng-ultra/constids.inc new file mode 100644 index 00000000..b40d5be8 --- /dev/null +++ b/himbaechel/uarch/ng-ultra/constids.inc @@ -0,0 +1,14 @@ +X(LUT4) +X(DFF) +X(CLK) +X(D) +X(F) +X(Q) +X(INBUF) +X(OUTBUF) +X(I) +X(EN) +X(O) +X(IOB) +X(PAD) +X(INIT) diff --git a/himbaechel/uarch/ng-ultra/ng_ultra.cc b/himbaechel/uarch/ng-ultra/ng_ultra.cc new file mode 100644 index 00000000..7e103e94 --- /dev/null +++ b/himbaechel/uarch/ng-ultra/ng_ultra.cc @@ -0,0 +1,151 @@ +/* + * nextpnr -- Next Generation Place and Route + * + * Copyright (C) 2023 Lofty + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + */ + +#include "himbaechel_api.h" +#include "log.h" +#include "nextpnr.h" +#include "util.h" + +#include "himbaechel_helpers.h" + +#define GEN_INIT_CONSTIDS +#define HIMBAECHEL_CONSTIDS "uarch/ng-ultra/constids.inc" +#include "himbaechel_constids.h" + +NEXTPNR_NAMESPACE_BEGIN + +namespace { +struct NgUltraImpl : HimbaechelAPI +{ + + static constexpr int K = 4; + + ~NgUltraImpl(){}; + void init_database(Arch *arch) override + { + init_uarch_constids(arch); + arch->load_chipdb("ng-ultra/ng-ultra.bin"); + arch->set_speed_grade("DEFAULT"); + } + + void init(Context *ctx) override + { + h.init(ctx); + HimbaechelAPI::init(ctx); + } + + void prePlace() override { assign_cell_info(); } + + void pack() override + { + // Trim nextpnr IOBs - assume IO buffer insertion has been done in synthesis + const pool top_ports{ + CellTypePort(id_INBUF, id_PAD), + CellTypePort(id_OUTBUF, id_PAD), + }; + h.remove_nextpnr_iobs(top_ports); + // Replace constants with LUTs + const dict vcc_params = {{id_INIT, Property(0xFFFF, 16)}}; + const dict gnd_params = {{id_INIT, Property(0x0000, 16)}}; + h.replace_constants(CellTypePort(id_LUT4, id_F), CellTypePort(id_LUT4, id_F), vcc_params, gnd_params); + // Constrain directly connected LUTs and FFs together to use dedicated resources + int lutffs = h.constrain_cell_pairs(pool{{id_LUT4, id_F}}, pool{{id_DFF, id_D}}, 1); + log_info("Constrained %d LUTFF pairs.\n", lutffs); + } + + bool isBelLocationValid(BelId bel, bool explain_invalid) const override + { + Loc l = ctx->getBelLocation(bel); + if (ctx->getBelType(bel).in(id_LUT4, id_DFF)) { + return slice_valid(l.x, l.y, l.z / 2); + } else { + return true; + } + } + + // Bel bucket functions + IdString getBelBucketForCellType(IdString cell_type) const override + { + if (cell_type.in(id_INBUF, id_OUTBUF)) + return id_IOB; + return cell_type; + } + bool isValidBelForCellType(IdString cell_type, BelId bel) const override + { + IdString bel_type = ctx->getBelType(bel); + if (bel_type == id_IOB) + return cell_type.in(id_INBUF, id_OUTBUF); + else + return (bel_type == cell_type); + } + + private: + HimbaechelHelpers h; + + // Validity checking + struct NgUltraCellInfo + { + const NetInfo *lut_f = nullptr, *ff_d = nullptr; + bool lut_i3_used = false; + }; + std::vector fast_cell_info; + void assign_cell_info() + { + fast_cell_info.resize(ctx->cells.size()); + for (auto &cell : ctx->cells) { + CellInfo *ci = cell.second.get(); + auto &fc = fast_cell_info.at(ci->flat_index); + if (ci->type == id_LUT4) { + fc.lut_f = ci->getPort(id_F); + fc.lut_i3_used = (ci->getPort(ctx->idf("I[%d]", K - 1)) != nullptr); + } else if (ci->type == id_DFF) { + fc.ff_d = ci->getPort(id_D); + } + } + } + bool slice_valid(int x, int y, int z) const + { + const CellInfo *lut = ctx->getBoundBelCell(ctx->getBelByLocation(Loc(x, y, z * 2))); + const CellInfo *ff = ctx->getBoundBelCell(ctx->getBelByLocation(Loc(x, y, z * 2 + 1))); + if (!lut || !ff) + return true; // always valid if only LUT or FF used + const auto &lut_data = fast_cell_info.at(lut->flat_index); + const auto &ff_data = fast_cell_info.at(ff->flat_index); + // In our example arch; the FF D can either be driven from LUT F or LUT I3 + // so either; FF D must equal LUT F or LUT I3 must be unused + if (ff_data.ff_d == lut_data.lut_f) + return true; + if (lut_data.lut_i3_used) + return false; + return true; + } +}; + +struct NgUltraArch : HimbaechelArch +{ + NgUltraArch() : HimbaechelArch("ng-ultra"){}; + bool match_device(const std::string &device) override { return device == "NG-ULTRA"; } + std::unique_ptr create(const std::string &device, const dict &args) + { + return std::make_unique(); + } +} ngUltraArch; +} // namespace + +NEXTPNR_NAMESPACE_END diff --git a/himbaechel/uarch/ng-ultra/ng_ultra_arch_gen.py b/himbaechel/uarch/ng-ultra/ng_ultra_arch_gen.py new file mode 100644 index 00000000..8141d7c2 --- /dev/null +++ b/himbaechel/uarch/ng-ultra/ng_ultra_arch_gen.py @@ -0,0 +1,33 @@ +import json +from os import path +import sys +sys.path.append(path.join(path.dirname(__file__), "../..")) +from himbaechel_dbgen.chip import * + +def create_tile(ch: Chip): + tt = ch.create_tile_type("TILE") + +def create_mesh(ch: Chip): + tt = ch.create_tile_type("MESH") + +def create_cgb(ch: Chip): + tt = ch.create_tile_type("CGB") + +def main(): + ch = Chip("ng-ultra", "NG-ULTRA", 93, 50) + ch.strs.read_constids(path.join(path.dirname(__file__), "constids.inc")) + pkg = ch.create_package("FF-1760") + + create_tile(ch) + create_mesh(ch) + create_cgb(ch) + + with open("/home/lofty/prjbeyond/database/NG-ULTRA/tilegrid.json") as f: + tilegrid = json.load(f) + for name, data in tilegrid.items(): + ch.set_tile_type(data["x"], data["y"], data["type"]) + + ch.write_bba(sys.argv[1]) + +if __name__ == '__main__': + main()