From 7862d1b84b9f770a97f1650cf4a1eb2e02b6389f Mon Sep 17 00:00:00 2001 From: David Shah Date: Fri, 6 Jul 2018 12:15:07 +0200 Subject: ecp5: Implementing core arch.h functions Signed-off-by: David Shah --- ecp5/arch.cc | 386 ++++++++++++++++++++++++++++++++++++++++++++++++ ecp5/arch.h | 199 +++++++++++++++---------- ecp5/arch_pybindings.cc | 32 ++++ ecp5/arch_pybindings.h | 31 ++++ ecp5/archdefs.h | 46 +++++- ecp5/main.cc | 139 +++++++++++++++++ 6 files changed, 746 insertions(+), 87 deletions(-) create mode 100644 ecp5/arch.cc create mode 100644 ecp5/arch_pybindings.cc create mode 100644 ecp5/arch_pybindings.h create mode 100644 ecp5/main.cc diff --git a/ecp5/arch.cc b/ecp5/arch.cc new file mode 100644 index 00000000..41c73cf8 --- /dev/null +++ b/ecp5/arch.cc @@ -0,0 +1,386 @@ +/* + * nextpnr -- Next Generation Place and Route + * + * Copyright (C) 2018 Clifford Wolf + * + * 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 +#include +#include "log.h" +#include "nextpnr.h" +#include "util.h" +NEXTPNR_NAMESPACE_BEGIN + +// ----------------------------------------------------------------------- + +IdString Arch::belTypeToId(BelType type) const +{ + if (type == TYPE_ICESTORM_LC) + return id("ICESTORM_LC"); + if (type == TYPE_ICESTORM_RAM) + return id("ICESTORM_RAM"); + if (type == TYPE_SB_IO) + return id("SB_IO"); + if (type == TYPE_SB_GB) + return id("SB_GB"); + if (type == TYPE_ICESTORM_PLL) + return id("ICESTORM_PLL"); + if (type == TYPE_SB_WARMBOOT) + return id("SB_WARMBOOT"); + if (type == TYPE_SB_MAC16) + return id("SB_MAC16"); + if (type == TYPE_ICESTORM_HFOSC) + return id("ICESTORM_HFOSC"); + if (type == TYPE_ICESTORM_LFOSC) + return id("ICESTORM_LFOSC"); + if (type == TYPE_SB_I2C) + return id("SB_I2C"); + if (type == TYPE_SB_SPI) + return id("SB_SPI"); + if (type == TYPE_IO_I3C) + return id("IO_I3C"); + if (type == TYPE_SB_LEDDA_IP) + return id("SB_LEDDA_IP"); + if (type == TYPE_SB_RGBA_DRV) + return id("SB_RGBA_DRV"); + if (type == TYPE_ICESTORM_SPRAM) + return id("ICESTORM_SPRAM"); + return IdString(); +} + +BelType Arch::belTypeFromId(IdString type) const +{ + if (type == id("ICESTORM_LC")) + return TYPE_ICESTORM_LC; + if (type == id("ICESTORM_RAM")) + return TYPE_ICESTORM_RAM; + if (type == id("SB_IO")) + return TYPE_SB_IO; + if (type == id("SB_GB")) + return TYPE_SB_GB; + if (type == id("ICESTORM_PLL")) + return TYPE_ICESTORM_PLL; + if (type == id("SB_WARMBOOT")) + return TYPE_SB_WARMBOOT; + if (type == id("SB_MAC16")) + return TYPE_SB_MAC16; + if (type == id("ICESTORM_HFOSC")) + return TYPE_ICESTORM_HFOSC; + if (type == id("ICESTORM_LFOSC")) + return TYPE_ICESTORM_LFOSC; + if (type == id("SB_I2C")) + return TYPE_SB_I2C; + if (type == id("SB_SPI")) + return TYPE_SB_SPI; + if (type == id("IO_I3C")) + return TYPE_IO_I3C; + if (type == id("SB_LEDDA_IP")) + return TYPE_SB_LEDDA_IP; + if (type == id("SB_RGBA_DRV")) + return TYPE_SB_RGBA_DRV; + if (type == id("ICESTORM_SPRAM")) + return TYPE_ICESTORM_SPRAM; + return TYPE_NONE; +} + +// ----------------------------------------------------------------------- + +void IdString::initialize_arch(const BaseCtx *ctx) +{ +#define X(t) initialize_add(ctx, #t, PIN_##t); +#include "portpins.inc" +#undef X +} + +IdString Arch::portPinToId(PortPin type) const +{ + IdString ret; + if (type > 0 && type < PIN_MAXIDX) + ret.index = type; + return ret; +} + +PortPin Arch::portPinFromId(IdString type) const +{ + if (type.index > 0 && type.index < PIN_MAXIDX) + return PortPin(type.index); + return PIN_NONE; +} + +// ----------------------------------------------------------------------- + +static const ChipInfoPOD *get_chip_info(const RelPtr *ptr) { return ptr->get(); } + +#if defined(_MSC_VER) +void load_chipdb(); +#endif + +Arch::Arch(ArchArgs args) : args(args) +{ +#if defined(_MSC_VER) + load_chipdb(); +#endif + +#ifdef ICE40_HX1K_ONLY + if (args.type == ArchArgs::HX1K) { + chip_info = get_chip_info(reinterpret_cast *>(chipdb_blob_1k)); + } else { + log_error("Unsupported iCE40 chip type.\n"); + } +#else + if (args.type == ArchArgs::LP384) { + chip_info = get_chip_info(reinterpret_cast *>(chipdb_blob_384)); + } else if (args.type == ArchArgs::LP1K || args.type == ArchArgs::HX1K) { + chip_info = get_chip_info(reinterpret_cast *>(chipdb_blob_1k)); + } else if (args.type == ArchArgs::UP5K) { + chip_info = get_chip_info(reinterpret_cast *>(chipdb_blob_5k)); + } else if (args.type == ArchArgs::LP8K || args.type == ArchArgs::HX8K) { + chip_info = get_chip_info(reinterpret_cast *>(chipdb_blob_8k)); + } else { + log_error("Unsupported iCE40 chip type.\n"); + } +#endif + + package_info = nullptr; + for (int i = 0; i < chip_info->num_packages; i++) { + if (chip_info->packages_data[i].name.get() == args.package) { + package_info = &(chip_info->packages_data[i]); + break; + } + } + if (package_info == nullptr) + log_error("Unsupported package '%s'.\n", args.package.c_str()); + + bel_to_cell.resize(chip_info->num_bels); + wire_to_net.resize(chip_info->num_wires); + pip_to_net.resize(chip_info->num_pips); + switches_locked.resize(chip_info->num_switches); + + // Initialise regularly used IDStrings for performance + id_glb_buf_out = id("GLOBAL_BUFFER_OUTPUT"); + id_icestorm_lc = id("ICESTORM_LC"); + id_sb_io = id("SB_IO"); + id_sb_gb = id("SB_GB"); + id_cen = id("CEN"); + id_clk = id("CLK"); + id_sr = id("SR"); + id_i0 = id("I0"); + id_i1 = id("I1"); + id_i2 = id("I2"); + id_i3 = id("I3"); + id_dff_en = id("DFF_ENABLE"); + id_neg_clk = id("NEG_CLK"); +} + +// ----------------------------------------------------------------------- + +std::string Arch::getChipName() +{ +#ifdef ICE40_HX1K_ONLY + if (args.type == ArchArgs::HX1K) { + return "Lattice LP1K"; + } else { + log_error("Unsupported iCE40 chip type.\n"); + } +#else + if (args.type == ArchArgs::LP384) { + return "Lattice LP384"; + } else if (args.type == ArchArgs::LP1K) { + return "Lattice LP1K"; + } else if (args.type == ArchArgs::HX1K) { + return "Lattice HX1K"; + } else if (args.type == ArchArgs::UP5K) { + return "Lattice UP5K"; + } else if (args.type == ArchArgs::LP8K) { + return "Lattice LP8K"; + } else if (args.type == ArchArgs::HX8K) { + return "Lattice HX8K"; + } else { + log_error("Unknown chip\n"); + } +#endif +} + +// ----------------------------------------------------------------------- + +IdString Arch::archArgsToId(ArchArgs args) const +{ + if (args.type == ArchArgs::LP384) + return id("lp384"); + if (args.type == ArchArgs::LP1K) + return id("lp1k"); + if (args.type == ArchArgs::HX1K) + return id("hx1k"); + if (args.type == ArchArgs::UP5K) + return id("up5k"); + if (args.type == ArchArgs::LP8K) + return id("lp8k"); + if (args.type == ArchArgs::HX8K) + return id("hx8k"); + return IdString(); +} + +// ----------------------------------------------------------------------- + +BelId Arch::getBelByName(IdString name) const +{ + BelId ret; + + if (bel_by_name.empty()) { + for (int i = 0; i < chip_info->num_bels; i++) + bel_by_name[id(chip_info->bel_data[i].name.get())] = i; + } + + auto it = bel_by_name.find(name); + if (it != bel_by_name.end()) + ret.index = it->second; + + return ret; +} + +BelRange Arch::getBelsAtSameTile(BelId bel) const +{ + BelRange br; + NPNR_ASSERT(bel != BelId()); + // This requires Bels at the same tile are consecutive + int x = chip_info->bel_data[bel.index].x; + int y = chip_info->bel_data[bel.index].y; + int start = bel.index, end = bel.index; + while (start >= 0 && chip_info->bel_data[start].x == x && chip_info->bel_data[start].y == y) + start--; + start++; + br.b.cursor = start; + while (end < chip_info->num_bels && chip_info->bel_data[end].x == x && chip_info->bel_data[end].y == y) + end++; + br.e.cursor = end; + return br; +} + +WireId Arch::getWireBelPin(BelId bel, PortPin pin) const +{ + WireId ret; + + NPNR_ASSERT(bel != BelId()); + + int num_bel_wires = chip_info->bel_data[bel.index].num_bel_wires; + const BelWirePOD *bel_wires = chip_info->bel_data[bel.index].bel_wires.get(); + + for (int i = 0; i < num_bel_wires; i++) + if (bel_wires[i].port == pin) { + ret.index = bel_wires[i].wire_index; + break; + } + + return ret; +} + +// ----------------------------------------------------------------------- + +WireId Arch::getWireByName(IdString name) const +{ + WireId ret; + + if (wire_by_name.empty()) { + for (int i = 0; i < chip_info->num_wires; i++) + wire_by_name[id(chip_info->wire_data[i].name.get())] = i; + } + + auto it = wire_by_name.find(name); + if (it != wire_by_name.end()) + ret.index = it->second; + + return ret; +} + +// ----------------------------------------------------------------------- + +PipId Arch::getPipByName(IdString name) const +{ + PipId ret; + + if (pip_by_name.empty()) { + for (int i = 0; i < chip_info->num_pips; i++) { + PipId pip; + pip.index = i; + pip_by_name[getPipName(pip)] = i; + } + } + + auto it = pip_by_name.find(name); + if (it != pip_by_name.end()) + ret.index = it->second; + + return ret; +} + +IdString Arch::getPipName(PipId pip) const +{ + NPNR_ASSERT(pip != PipId()); + + int x = chip_info->pip_data[pip.index].x; + int y = chip_info->pip_data[pip.index].y; + + std::string src_name = chip_info->wire_data[chip_info->pip_data[pip.index].src].name.get(); + std::replace(src_name.begin(), src_name.end(), '/', '.'); + + std::string dst_name = chip_info->wire_data[chip_info->pip_data[pip.index].dst].name.get(); + std::replace(dst_name.begin(), dst_name.end(), '/', '.'); + + return id("X" + std::to_string(x) + "/Y" + std::to_string(y) + "/" + src_name + ".->." + dst_name); +} + +// ----------------------------------------------------------------------- + +BelId Arch::getPackagePinBel(const std::string &pin) const { return BelId(); } + +std::string Arch::getBelPackagePin(BelId bel) const { return ""; } +// ----------------------------------------------------------------------- + +void Arch::estimatePosition(BelId bel, int &x, int &y, bool &gb) const {} + +delay_t Arch::estimateDelay(WireId src, WireId dst) const { return 1; } + +// ----------------------------------------------------------------------- + +std::vector Arch::getFrameGraphics() const +{ + std::vector ret; + + return ret; +} + +std::vector Arch::getBelGraphics(BelId bel) const +{ + std::vector ret; + + return ret; +} + +std::vector Arch::getWireGraphics(WireId wire) const +{ + std::vector ret; + // FIXME + return ret; +} + +std::vector Arch::getPipGraphics(PipId pip) const +{ + std::vector ret; + // FIXME + return ret; +}; + +NEXTPNR_NAMESPACE_END diff --git a/ecp5/arch.h b/ecp5/arch.h index 98c4cd76..85a3e44c 100644 --- a/ecp5/arch.h +++ b/ecp5/arch.h @@ -44,7 +44,7 @@ template struct RelPtr }; NPNR_PACKED_STRUCT(struct BelWirePOD { - Location rel_wire_loc; + LocationPOD rel_wire_loc; int32_t wire_index; PortPin port; }); @@ -59,23 +59,23 @@ NPNR_PACKED_STRUCT(struct BelInfoPOD { }); NPNR_PACKED_STRUCT(struct BelPortPOD { - Location rel_bel_loc; + LocationPOD rel_bel_loc; int32_t bel_index; PortPin port; }); NPNR_PACKED_STRUCT(struct PipInfoPOD { - Location rel_src_loc, rel_dst_loc; + LocationPOD rel_src_loc, rel_dst_loc; int32_t src_idx, dst_idx; int32_t delay; - Location rel_tile_loc; + LocationPOD rel_tile_loc; int16_t tile_type; int8_t pip_type; int8_t padding_0; }); NPNR_PACKED_STRUCT(struct PipLocatorPOD { - Location rel_loc; + LocationPOD rel_loc; int32_t index; }); @@ -98,21 +98,20 @@ NPNR_PACKED_STRUCT(struct LocationTypePOD { NPNR_PACKED_STRUCT(struct ChipInfoPOD { int32_t width, height; + int32_t num_tiles; int32_t num_location_types; RelPtr locations; RelPtr location_type; }); #if defined(_MSC_VER) -extern const char *chipdb_blob_384; -extern const char *chipdb_blob_1k; -extern const char *chipdb_blob_5k; -extern const char *chipdb_blob_8k; +extern const char *chipdb_blob_25k; +extern const char *chipdb_blob_45k; +extern const char *chipdb_blob_85k; #else -extern const char chipdb_blob_384[]; -extern const char chipdb_blob_1k[]; -extern const char chipdb_blob_5k[]; -extern const char chipdb_blob_8k[]; +extern const char chipdb_blob_25k[]; +extern const char chipdb_blob_45k[]; +extern const char chipdb_blob_85k[]; #endif /************************ End of chipdb section. ************************/ @@ -126,7 +125,8 @@ struct BelIterator BelIterator operator++() { cursor_index++; - while (cursor_index >= ci->locations[ci->location_type[cursor_tile]]->num_bels) { + while (cursor_tile < chip->num_tiles && + cursor_index >= chip->locations[chip->location_type[cursor_tile]].num_bels) { cursor_index = 0; cursor_tile++; } @@ -135,7 +135,7 @@ struct BelIterator BelIterator operator++(int) { BelIterator prior(*this); - cursor++; + ++(*this); return prior; } @@ -171,7 +171,7 @@ struct BelRange struct BelPinIterator { const BelPortPOD *ptr = nullptr; - const Location wire_loc; + Location wire_loc; void operator++() { ptr++; } bool operator!=(const BelPinIterator &other) const { return ptr != other.ptr; } @@ -203,7 +203,8 @@ struct WireIterator WireIterator operator++() { cursor_index++; - while (cursor_index >= ci->locations[ci->location_type[cursor_tile]]->num_wires) { + while (cursor_tile < chip->num_tiles && + cursor_index >= chip->locations[chip->location_type[cursor_tile]].num_wires) { cursor_index = 0; cursor_tile++; } @@ -212,7 +213,7 @@ struct WireIterator WireIterator operator++(int) { WireIterator prior(*this); - cursor++; + ++(*this); return prior; } @@ -254,7 +255,8 @@ struct AllPipIterator AllPipIterator operator++() { cursor_index++; - while (cursor_index >= ci->locations[ci->location_type[cursor_tile]]->num_pips) { + while (cursor_tile < chip->num_tiles && + cursor_index >= chip->locations[chip->location_type[cursor_tile]].num_pips) { cursor_index = 0; cursor_tile++; } @@ -262,8 +264,8 @@ struct AllPipIterator } AllPipIterator operator++(int) { - WireIterator prior(*this); - cursor++; + AllPipIterator prior(*this); + ++(*this); return prior; } @@ -309,7 +311,7 @@ struct PipIterator { PipId ret; ret.index = cursor->index; - ret.location = wire_loc + cursor->location; + ret.location = wire_loc + cursor->rel_loc; return ret; } }; @@ -337,7 +339,6 @@ struct ArchArgs struct Arch : BaseCtx { const ChipInfoPOD *chip_info; - const PackageInfoPOD *package_info; mutable std::unordered_map bel_by_name; mutable std::unordered_map wire_by_name; @@ -366,10 +367,15 @@ struct Arch : BaseCtx BelId getBelByName(IdString name) const; + template const LocationTypePOD *locInfo(Id &id) const + { + return &(chip_info->locations[chip_info->location_type[id.location.y * chip_info->width + id.location.x]]); + } + IdString getBelName(BelId bel) const { NPNR_ASSERT(bel != BelId()); - return id(chip_info->bel_data[bel.index].name.get()); + return id(locInfo(bel)->bel_data[bel.index].name.get()); } uint32_t getBelChecksum(BelId bel) const { return bel.index; } @@ -386,35 +392,46 @@ struct Arch : BaseCtx void unbindBel(BelId bel) { NPNR_ASSERT(bel != BelId()); - NPNR_ASSERT(bel_to_cell[bel.index] != IdString()); - cells[bel_to_cell[bel.index]]->bel = BelId(); - cells[bel_to_cell[bel.index]]->belStrength = STRENGTH_NONE; - bel_to_cell[bel.index] = IdString(); + NPNR_ASSERT(bel_to_cell[bel] != IdString()); + cells[bel_to_cell[bel]]->bel = BelId(); + cells[bel_to_cell[bel]]->belStrength = STRENGTH_NONE; + bel_to_cell[bel] = IdString(); } bool checkBelAvail(BelId bel) const { NPNR_ASSERT(bel != BelId()); - return bel_to_cell[bel.index] == IdString(); + return bel_to_cell.find(bel) == bel_to_cell.end() || bel_to_cell.at(bel) == IdString(); } IdString getBoundBelCell(BelId bel) const { NPNR_ASSERT(bel != BelId()); - return bel_to_cell.at(bel); + if (bel_to_cell.find(bel) == bel_to_cell.end()) + return IdString(); + else + return bel_to_cell.at(bel); } IdString getConflictingBelCell(BelId bel) const { NPNR_ASSERT(bel != BelId()); - return bel_to_cell.at(bel); + if (bel_to_cell.find(bel) == bel_to_cell.end()) + return IdString(); + else + return bel_to_cell.at(bel); } BelRange getBels() const { BelRange range; - range.b.cursor = 0; - range.e.cursor = chip_info->num_bels; + range.b.cursor_tile = 0; + range.b.cursor_index = -1; + range.b.chip = 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_index = 0; + range.e.chip = chip_info; return range; } @@ -437,7 +454,7 @@ struct Arch : BaseCtx BelType getBelType(BelId bel) const { NPNR_ASSERT(bel != BelId()); - return chip_info->bel_data[bel.index].type; + return locInfo(bel)->bel_data[bel.index].type; } WireId getWireBelPin(BelId bel, PortPin pin) const; @@ -447,9 +464,10 @@ struct Arch : BaseCtx BelPin ret; NPNR_ASSERT(wire != WireId()); - if (chip_info->wire_data[wire.index].bel_uphill.bel_index >= 0) { - ret.bel.index = chip_info->wire_data[wire.index].bel_uphill.bel_index; - ret.pin = chip_info->wire_data[wire.index].bel_uphill.port; + if (locInfo(wire)->wire_data[wire.index].bel_uphill.bel_index >= 0) { + ret.bel.index = locInfo(wire)->wire_data[wire.index].bel_uphill.bel_index; + ret.bel.location = wire.location + locInfo(wire)->wire_data[wire.index].bel_uphill.rel_bel_loc; + ret.pin = locInfo(wire)->wire_data[wire.index].bel_uphill.port; } return ret; @@ -459,8 +477,10 @@ struct Arch : BaseCtx { BelPinRange range; NPNR_ASSERT(wire != WireId()); - range.b.ptr = chip_info->wire_data[wire.index].bels_downhill.get(); - range.e.ptr = range.b.ptr + chip_info->wire_data[wire.index].num_bels_downhill; + range.b.ptr = locInfo(wire)->wire_data[wire.index].bels_downhill.get(); + range.b.wire_loc = wire.location; + range.e.ptr = range.b.ptr + locInfo(wire)->wire_data[wire.index].num_bels_downhill; + range.e.wire_loc = wire.location; return range; } @@ -471,7 +491,7 @@ struct Arch : BaseCtx IdString getWireName(WireId wire) const { NPNR_ASSERT(wire != WireId()); - return id(chip_info->wire_data[wire.index].name.get()); + return id(locInfo(wire)->wire_data[wire.index].name.get()); } uint32_t getWireChecksum(WireId wire) const { return wire.index; } @@ -479,8 +499,8 @@ struct Arch : BaseCtx void bindWire(WireId wire, IdString net, PlaceStrength strength) { NPNR_ASSERT(wire != WireId()); - NPNR_ASSERT(wire_to_net[wire.index] == IdString()); - wire_to_net[wire.index] = net; + NPNR_ASSERT(wire_to_net[wire] == IdString()); + wire_to_net[wire] = net; nets[net]->wires[wire].pip = PipId(); nets[net]->wires[wire].strength = strength; } @@ -488,45 +508,55 @@ struct Arch : BaseCtx void unbindWire(WireId wire) { NPNR_ASSERT(wire != WireId()); - NPNR_ASSERT(wire_to_net[wire.index] != IdString()); + NPNR_ASSERT(wire_to_net[wire] != IdString()); - auto &net_wires = nets[wire_to_net[wire.index]]->wires; + auto &net_wires = nets[wire_to_net[wire]]->wires; auto it = net_wires.find(wire); NPNR_ASSERT(it != net_wires.end()); auto pip = it->second.pip; if (pip != PipId()) { - pip_to_net[pip.index] = IdString(); - switches_locked[chip_info->pip_data[pip.index].switch_index] = IdString(); + pip_to_net[pip] = IdString(); } net_wires.erase(it); - wire_to_net[wire.index] = IdString(); + wire_to_net[wire] = IdString(); } bool checkWireAvail(WireId wire) const { NPNR_ASSERT(wire != WireId()); - return wire_to_net[wire.index] == IdString(); + return wire_to_net.find(wire) == wire_to_net.end() || wire_to_net.at(wire) == IdString(); } IdString getBoundWireNet(WireId wire) const { NPNR_ASSERT(wire != WireId()); - return wire_to_net[wire.index]; + if (wire_to_net.find(wire) == wire_to_net.end()) + return IdString(); + else + return wire_to_net.at(wire); } IdString getConflictingWireNet(WireId wire) const { NPNR_ASSERT(wire != WireId()); - return wire_to_net[wire.index]; + if (wire_to_net.find(wire) == wire_to_net.end()) + return IdString(); + else + return wire_to_net.at(wire); } WireRange getWires() const { WireRange range; - range.b.cursor = 0; - range.e.cursor = chip_info->num_wires; + range.b.cursor_tile = 0; + range.b.cursor_index = -1; + range.b.chip = 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_index = 0; + range.e.chip = chip_info; return range; } @@ -540,16 +570,15 @@ struct Arch : BaseCtx void bindPip(PipId pip, IdString net, PlaceStrength strength) { NPNR_ASSERT(pip != PipId()); - NPNR_ASSERT(pip_to_net[pip.index] == IdString()); - NPNR_ASSERT(switches_locked[chip_info->pip_data[pip.index].switch_index] == IdString()); + NPNR_ASSERT(pip_to_net[pip] == IdString()); - pip_to_net[pip.index] = net; - switches_locked[chip_info->pip_data[pip.index].switch_index] = net; + pip_to_net[pip] = net; WireId dst; - dst.index = chip_info->pip_data[pip.index].dst; - NPNR_ASSERT(wire_to_net[dst.index] == IdString()); - wire_to_net[dst.index] = net; + dst.index = locInfo(pip)->pip_data[pip.index].dst_idx; + dst.location = pip.location + locInfo(pip)->pip_data[pip.index].rel_dst_loc; + NPNR_ASSERT(wire_to_net[dst] == IdString()); + wire_to_net[dst] = net; nets[net]->wires[dst].pip = pip; nets[net]->wires[dst].strength = strength; } @@ -557,42 +586,52 @@ struct Arch : BaseCtx void unbindPip(PipId pip) { NPNR_ASSERT(pip != PipId()); - NPNR_ASSERT(pip_to_net[pip.index] != IdString()); - NPNR_ASSERT(switches_locked[chip_info->pip_data[pip.index].switch_index] != IdString()); + NPNR_ASSERT(pip_to_net[pip] != IdString()); WireId dst; - dst.index = chip_info->pip_data[pip.index].dst; - NPNR_ASSERT(wire_to_net[dst.index] != IdString()); - wire_to_net[dst.index] = IdString(); - nets[pip_to_net[pip.index]]->wires.erase(dst); + dst.index = locInfo(pip)->pip_data[pip.index].dst_idx; + dst.location = pip.location + locInfo(pip)->pip_data[pip.index].rel_dst_loc; + NPNR_ASSERT(wire_to_net[dst] != IdString()); + wire_to_net[dst] = IdString(); + nets[pip_to_net[pip]]->wires.erase(dst); - pip_to_net[pip.index] = IdString(); - switches_locked[chip_info->pip_data[pip.index].switch_index] = IdString(); + pip_to_net[pip] = IdString(); } bool checkPipAvail(PipId pip) const { NPNR_ASSERT(pip != PipId()); - return switches_locked[chip_info->pip_data[pip.index].switch_index] == IdString(); + return pip_to_net.find(pip) == pip_to_net.end() || pip_to_net.at(pip) == IdString(); } IdString getBoundPipNet(PipId pip) const { NPNR_ASSERT(pip != PipId()); - return pip_to_net[pip.index]; + if (pip_to_net.find(pip) == pip_to_net.end()) + return IdString(); + else + return pip_to_net.at(pip); } IdString getConflictingPipNet(PipId pip) const { NPNR_ASSERT(pip != PipId()); - return switches_locked[chip_info->pip_data[pip.index].switch_index]; + if (pip_to_net.find(pip) == pip_to_net.end()) + return IdString(); + else + return pip_to_net.at(pip); } AllPipRange getPips() const { AllPipRange range; - range.b.cursor = 0; - range.e.cursor = chip_info->num_pips; + range.b.cursor_tile = 0; + range.b.cursor_index = -1; + range.b.chip = 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_index = 0; + range.e.chip = chip_info; return range; } @@ -600,7 +639,8 @@ struct Arch : BaseCtx { WireId wire; NPNR_ASSERT(pip != PipId()); - wire.index = chip_info->pip_data[pip.index].src; + wire.index = locInfo(pip)->pip_data[pip.index].src_idx; + wire.location = pip.location + locInfo(pip)->pip_data[pip.index].rel_src_loc; return wire; } @@ -608,7 +648,8 @@ struct Arch : BaseCtx { WireId wire; NPNR_ASSERT(pip != PipId()); - wire.index = chip_info->pip_data[pip.index].dst; + wire.index = locInfo(pip)->pip_data[pip.index].dst_idx; + wire.location = pip.location + locInfo(pip)->pip_data[pip.index].rel_dst_loc; return wire; } @@ -616,7 +657,7 @@ struct Arch : BaseCtx { DelayInfo delay; NPNR_ASSERT(pip != PipId()); - delay.delay = chip_info->pip_data[pip.index].delay; + delay.delay = locInfo(pip)->pip_data[pip.index].delay; return delay; } @@ -624,8 +665,8 @@ struct Arch : BaseCtx { PipRange range; NPNR_ASSERT(wire != WireId()); - range.b.cursor = chip_info->wire_data[wire.index].pips_downhill.get(); - range.e.cursor = range.b.cursor + chip_info->wire_data[wire.index].num_downhill; + range.b.cursor = locInfo(wire)->wire_data[wire.index].pips_downhill.get(); + range.e.cursor = range.b.cursor + locInfo(wire)->wire_data[wire.index].num_downhill; return range; } @@ -633,8 +674,8 @@ struct Arch : BaseCtx { PipRange range; NPNR_ASSERT(wire != WireId()); - range.b.cursor = chip_info->wire_data[wire.index].pips_uphill.get(); - range.e.cursor = range.b.cursor + chip_info->wire_data[wire.index].num_uphill; + range.b.cursor = locInfo(wire)->wire_data[wire.index].pips_uphill.get(); + range.e.cursor = range.b.cursor + locInfo(wire)->wire_data[wire.index].num_uphill; return range; } diff --git a/ecp5/arch_pybindings.cc b/ecp5/arch_pybindings.cc new file mode 100644 index 00000000..8310c3a1 --- /dev/null +++ b/ecp5/arch_pybindings.cc @@ -0,0 +1,32 @@ +/* + * nextpnr -- Next Generation Place and Route + * + * Copyright (C) 2018 Clifford Wolf + * Copyright (C) 2018 David Shah + * + * 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. + * + */ + +#ifndef NO_PYTHON + +#include "nextpnr.h" +#include "pybindings.h" + +NEXTPNR_NAMESPACE_BEGIN + +void arch_wrap_python() {} + +NEXTPNR_NAMESPACE_END + +#endif diff --git a/ecp5/arch_pybindings.h b/ecp5/arch_pybindings.h new file mode 100644 index 00000000..f7f07529 --- /dev/null +++ b/ecp5/arch_pybindings.h @@ -0,0 +1,31 @@ +/* + * nextpnr -- Next Generation Place and Route + * + * Copyright (C) 2018 Clifford Wolf + * Copyright (C) 2018 David Shah + * + * 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. + * + */ +#ifndef ARCH_PYBINDINGS_H +#define ARCH_PYBINDINGS_H +#ifndef NO_PYTHON + +#include "nextpnr.h" +#include "pybindings.h" + +NEXTPNR_NAMESPACE_BEGIN + +NEXTPNR_NAMESPACE_END +#endif +#endif diff --git a/ecp5/archdefs.h b/ecp5/archdefs.h index 0af48753..f913e445 100644 --- a/ecp5/archdefs.h +++ b/ecp5/archdefs.h @@ -60,13 +60,21 @@ enum PortPin : int32_t PIN_MAXIDX }; -NPNR_PACKED_STRUCT(struct Location { +NPNR_PACKED_STRUCT(struct LocationPOD { int16_t x, y; }); + +struct Location +{ int16_t x = -1, y = -1; + Location() : x(-1), y(-1){}; + Location(int16_t x, int16_t y) : x(x), y(y){}; + Location(const LocationPOD &pod) : x(pod.x), y(pod.y){}; + Location(const Location &loc) : x(loc.x), y(loc.y){}; + bool operator==(const Location &other) const { return x == other.x && y == other.y; } bool operator!=(const Location &other) const { return x != other.x || y == other.y; } -}); +}; -Location operator+(const Location &a, const Location &b) { return Location{a.x + b.x, a.y + b.y};} +Location operator+(const Location &a, const Location &b) { return Location(a.x + b.x, a.y + b.y); } struct BelId { @@ -91,29 +99,51 @@ struct PipId Location location; int32_t index = -1; - bool operator==(const WireId &other) const { return index == other.index && location == other.location; } - bool operator!=(const WireId &other) const { return index != other.index || location != other.location; } + bool operator==(const PipId &other) const { return index == other.index && location == other.location; } + bool operator!=(const PipId &other) const { return index != other.index || location != other.location; } }; NEXTPNR_NAMESPACE_END namespace std { +template <> struct hash +{ + std::size_t operator()(const NEXTPNR_NAMESPACE_PREFIX Location &loc) const noexcept + { + std::size_t seed = std::hash()(loc.x); + seed ^= std::hash()(loc.y) + 0x9e3779b9 + (seed << 6) + (seed >> 2); + return seed; + } +}; + template <> struct hash { - std::size_t operator()(const NEXTPNR_NAMESPACE_PREFIX BelId &bel) const noexcept { return hash()(bel.index); } + std::size_t operator()(const NEXTPNR_NAMESPACE_PREFIX BelId &bel) const noexcept + { + std::size_t seed = std::hash()(bel.location); + seed ^= std::hash()(bel.index) + 0x9e3779b9 + (seed << 6) + (seed >> 2); + return seed; + } }; template <> struct hash { std::size_t operator()(const NEXTPNR_NAMESPACE_PREFIX WireId &wire) const noexcept { - return hash()(wire.index); + std::size_t seed = std::hash()(wire.location); + seed ^= std::hash()(wire.index) + 0x9e3779b9 + (seed << 6) + (seed >> 2); + return seed; } }; template <> struct hash { - std::size_t operator()(const NEXTPNR_NAMESPACE_PREFIX PipId &pip) const noexcept { return hash()(pip.index); } + std::size_t operator()(const NEXTPNR_NAMESPACE_PREFIX PipId &pip) const noexcept + { + std::size_t seed = std::hash()(pip.location); + seed ^= std::hash()(pip.index) + 0x9e3779b9 + (seed << 6) + (seed >> 2); + return seed; + } }; template <> struct hash : hash diff --git a/ecp5/main.cc b/ecp5/main.cc new file mode 100644 index 00000000..d025d8d4 --- /dev/null +++ b/ecp5/main.cc @@ -0,0 +1,139 @@ +/* + * nextpnr -- Next Generation Place and Route + * + * Copyright (C) 2018 Clifford Wolf + * + * 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. + * + */ + +#ifdef MAIN_EXECUTABLE + +#ifndef NO_GUI +#include +#include "application.h" +#include "mainwindow.h" +#endif +#ifndef NO_PYTHON +#include "pybindings.h" +#endif +#include +#include +#include +#include "log.h" +#include "nextpnr.h" +#include "version.h" + +USING_NEXTPNR_NAMESPACE + +int main(int argc, char *argv[]) +{ + try { + + namespace po = boost::program_options; + int rc = 0; + + log_files.push_back(stdout); + + po::options_description options("Allowed options"); + options.add_options()("help,h", "show help"); + options.add_options()("verbose,v", "verbose output"); + options.add_options()("force,f", "keep running after errors"); +#ifndef NO_GUI + options.add_options()("gui", "start gui"); +#endif + + po::positional_options_description pos; +#ifndef NO_PYTHON + options.add_options()("run", po::value>(), "python file to execute"); + pos.add("run", -1); +#endif + options.add_options()("version,V", "show version"); + + po::variables_map vm; + try { + po::parsed_options parsed = po::command_line_parser(argc, argv).options(options).positional(pos).run(); + + po::store(parsed, vm); + + po::notify(vm); + } + + catch (std::exception &e) { + std::cout << e.what() << "\n"; + return 1; + } + + if (vm.count("help") || argc == 1) { + std::cout << boost::filesystem::basename(argv[0]) + << " -- Next Generation Place and Route (git " + "sha1 " GIT_COMMIT_HASH_STR ")\n"; + std::cout << "\n"; + std::cout << options << "\n"; + return argc != 1; + } + + if (vm.count("version")) { + std::cout << boost::filesystem::basename(argv[0]) + << " -- Next Generation Place and Route (git " + "sha1 " GIT_COMMIT_HASH_STR ")\n"; + return 1; + } + + Context ctx(ArchArgs{}); + + if (vm.count("verbose")) { + ctx.verbose = true; + } + + if (vm.count("force")) { + ctx.force = true; + } + + if (vm.count("seed")) { + ctx.rngseed(vm["seed"].as()); + } + +#ifndef NO_PYTHON + if (vm.count("run")) { + init_python(argv[0], true); + python_export_global("ctx", ctx); + + std::vector files = vm["run"].as>(); + for (auto filename : files) + execute_python_file(filename.c_str()); + + deinit_python(); + } +#endif + +#ifndef NO_GUI + if (vm.count("gui")) { + Application a(argc, argv); + MainWindow w; + w.show(); + + rc = a.exec(); + } +#endif + return rc; + } catch (log_execution_error_exception) { +#if defined(_MSC_VER) + _exit(EXIT_FAILURE); +#else + _Exit(EXIT_FAILURE); +#endif + } +} + +#endif -- cgit v1.2.3