From 6ffbb9ed87ae11ccf3a1f1053162f668bda8e135 Mon Sep 17 00:00:00 2001 From: Dan Ravensloft Date: Fri, 12 Jun 2020 22:09:46 +0100 Subject: cyclonev: basic platform --- CMakeLists.txt | 2 +- cyclonev/arch.cc | 18 +++ cyclonev/arch.h | 373 ++++++++++++++++++++++++++++++++++++++++++++++++++ cyclonev/archdefs.h | 187 +++++++++++++++++++++++++ cyclonev/family.cmake | 0 5 files changed, 579 insertions(+), 1 deletion(-) create mode 100644 cyclonev/arch.cc create mode 100644 cyclonev/arch.h create mode 100644 cyclonev/archdefs.h create mode 100644 cyclonev/family.cmake diff --git a/CMakeLists.txt b/CMakeLists.txt index 8291a21f..cc3e100f 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -97,7 +97,7 @@ set(PROGRAM_PREFIX "" CACHE STRING "Name prefix for executables") # List of families to build set(FAMILIES generic ice40 ecp5 nexus gowin fpga_interchange machxo2) set(STABLE_FAMILIES generic ice40 ecp5) -set(EXPERIMENTAL_FAMILIES nexus gowin fpga_interchange machxo2) +set(EXPERIMENTAL_FAMILIES nexus gowin fpga_interchange machxo2 cyclonev) set(ARCH "" CACHE STRING "Architecture family for nextpnr build") set_property(CACHE ARCH PROPERTY STRINGS ${FAMILIES}) diff --git a/cyclonev/arch.cc b/cyclonev/arch.cc new file mode 100644 index 00000000..e0721791 --- /dev/null +++ b/cyclonev/arch.cc @@ -0,0 +1,18 @@ +/* + * nextpnr -- Next Generation Place and Route + * + * Copyright (C) 2020 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. + * + */ + +#ifndef NEXTPNR_H +#error Include "arch.h" via "nextpnr.h" only. +#endif + +NEXTPNR_NAMESPACE_BEGIN + +struct BelIterator +{ + int cursor; + + BelIterator operator++() + { + cursor++; + return *this; + } + BelIterator operator++(int) + { + BelIterator prior(*this); + cursor++; + return prior; + } + + bool operator!=(const BelIterator &other) const { return cursor != other.cursor; } + + bool operator==(const BelIterator &other) const { return cursor == other.cursor; } + + BelId operator*() const + { + BelId ret; + ret.index = cursor; + return ret; + } +}; + +struct BelRange +{ + BelIterator b, e; + BelIterator begin() const { return b; } + BelIterator end() const { return e; } +}; + +// ----------------------------------------------------------------------- + +struct BelPinIterator +{ + const /* something */ int *ptr = nullptr; + + void operator++() { ptr++; } + bool operator!=(const BelPinIterator &other) const { return ptr != other.ptr; } + + BelPin operator*() const + { + BelPin ret; + return ret; + } +}; + +struct BelPinRange +{ + BelPinIterator b, e; + BelPinIterator begin() const { return b; } + BelPinIterator end() const { return e; } +}; + +// ----------------------------------------------------------------------- + +struct WireIterator +{ + int cursor = -1; + + void operator++() { cursor++; } + bool operator!=(const WireIterator &other) const { return cursor != other.cursor; } + + WireId operator*() const + { + WireId ret; + ret.index = cursor; + return ret; + } +}; + +struct WireRange +{ + WireIterator b, e; + WireIterator begin() const { return b; } + WireIterator end() const { return e; } +}; + +// ----------------------------------------------------------------------- + +struct AllPipIterator +{ + int cursor = -1; + + void operator++() { cursor++; } + bool operator!=(const AllPipIterator &other) const { return cursor != other.cursor; } + + PipId operator*() const + { + PipId ret; + ret.index = cursor; + return ret; + } +}; + +struct AllPipRange +{ + AllPipIterator b, e; + AllPipIterator begin() const { return b; } + AllPipIterator end() const { return e; } +}; + +// ----------------------------------------------------------------------- + +struct PipIterator +{ + const int *cursor = nullptr; + + void operator++() { cursor++; } + bool operator!=(const PipIterator &other) const { return cursor != other.cursor; } + + PipId operator*() const + { + PipId ret; + ret.index = *cursor; + return ret; + } +}; + +struct PipRange +{ + PipIterator b, e; + PipIterator begin() const { return b; } + PipIterator end() const { return e; } +}; + +struct ArchArgs +{ +}; + +struct Arch : BaseCtx +{ + ArchArgs args; + Arch(ArchArgs args); + + std::string getChipName() const; + + IdString archId() const { return id("cyclonev"); } + ArchArgs archArgs() const; + IdString archArgsToId(ArchArgs args) const; + + // ------------------------------------------------- + + int getGridDimX() const; + int getGridDimY() const; + int getTileBelDimZ(int, int) const; + int getTilePipDimZ(int, int) const; + + // ------------------------------------------------- + + BelId getBelByName(IdString name) const; + + IdString getBelName(BelId bel) const; + + uint32_t getBelChecksum(BelId bel) const; + + void bindBel(BelId bel, CellInfo *cell, PlaceStrength strength); + + void unbindBel(BelId bel); + + bool checkBelAvail(BelId bel) const; + + CellInfo *getBoundBelCell(BelId bel) const; + + CellInfo *getConflictingBelCell(BelId bel) const; + + BelRange getBels() const; + + Loc getBelLocation(BelId bel) const; + + BelId getBelByLocation(Loc loc) const; + BelRange getBelsByTile(int x, int y) const; + + bool getBelGlobalBuf(BelId bel) const; + + IdString getBelType(BelId bel) const; + + std::vector> getBelAttrs(BelId bel) const; + + WireId getBelPinWire(BelId bel, IdString pin) const; + PortType getBelPinType(BelId bel, IdString pin) const; + std::vector getBelPins(BelId bel) const; + + bool isBelLocked(BelId bel) const; + + // ------------------------------------------------- + + WireId getWireByName(IdString name) const; + + IdString getWireName(WireId wire) const; + + IdString getWireType(WireId wire) const; + std::vector> getWireAttrs(WireId wire) const; + + uint32_t getWireChecksum(WireId wire) const; + + void bindWire(WireId wire, NetInfo *net, PlaceStrength strength); + + void unbindWire(WireId wire); + + bool checkWireAvail(WireId wire) const; + + NetInfo *getBoundWireNet(WireId wire) const; + + WireId getConflictingWireWire(WireId wire) const; + + NetInfo *getConflictingWireNet(WireId wire) const; + + DelayInfo getWireDelay(WireId wire) const; + + BelPinRange getWireBelPins(WireId wire) const; + + WireRange getWires() const; + + // ------------------------------------------------- + + PipId getPipByName(IdString name) const; + + void bindPip(PipId pip, NetInfo *net, PlaceStrength strength); + + void unbindPip(PipId pip); + + bool checkPipAvail(PipId pip) const; + + NetInfo *getBoundPipNet(PipId pip) const; + + WireId getConflictingPipWire(PipId pip) const; + + NetInfo *getConflictingPipNet(PipId pip) const; + + AllPipRange getPips() const; + + Loc getPipLocation(PipId pip) const; + + IdString getPipName(PipId pip) const; + + IdString getPipType(PipId pip) const; + std::vector> getPipAttrs(PipId pip) const; + + uint32_t getPipChecksum(PipId pip) const; + + WireId getPipSrcWire(PipId pip) const; + + WireId getPipDstWire(PipId pip) const; + + DelayInfo getPipDelay(PipId pip) const; + + PipRange getPipsDownhill(WireId wire) const; + + PipRange getPipsUphill(WireId wire) const; + + PipRange getWireAliases(WireId wire) const; + + BelId getPackagePinBel(const std::string &pin) const; + std::string getBelPackagePin(BelId bel) const; + + // ------------------------------------------------- + + GroupId getGroupByName(IdString name) const; + IdString getGroupName(GroupId group) const; + std::vector getGroups() const; + std::vector getGroupBels(GroupId group) const; + std::vector getGroupWires(GroupId group) const; + std::vector getGroupPips(GroupId group) const; + std::vector getGroupGroups(GroupId group) const; + + // ------------------------------------------------- + + delay_t estimateDelay(WireId src, WireId dst) const; + delay_t predictDelay(const NetInfo *net_info, const PortRef &sink) const; + delay_t getDelayEpsilon() const; + delay_t getRipupDelayPenalty() const; + float getDelayNS(delay_t v) const; + DelayInfo getDelayFromNS(float ns) const; + uint32_t getDelayChecksum(delay_t v) const; + bool getBudgetOverride(const NetInfo *net_info, const PortRef &sink, delay_t &budget) const; + + ArcBounds getRouteBoundingBox(WireId src, WireId dst) const; + + // ------------------------------------------------- + + bool pack(); + bool place(); + bool route(); + + // ------------------------------------------------- + + std::vector getDecalGraphics(DecalId decal) const; + + DecalXY getBelDecal(BelId bel) const; + DecalXY getWireDecal(WireId wire) const; + DecalXY getPipDecal(PipId pip) const; + DecalXY getGroupDecal(GroupId group) const; + + // ------------------------------------------------- + + // Get the delay through a cell from one port to another, returning false + // if no path exists. This only considers combinational delays, as required by the Arch API + bool getCellDelay(const CellInfo *cell, IdString fromPort, IdString toPort, DelayInfo &delay) const; + // getCellDelayInternal is similar to the above, but without false path checks and including clock to out delays + // for internal arch use only + bool getCellDelayInternal(const CellInfo *cell, IdString fromPort, IdString toPort, DelayInfo &delay) const; + // Get the port class, also setting clockInfoCount to the number of TimingClockingInfos associated with a port + TimingPortClass getPortTimingClass(const CellInfo *cell, IdString port, int &clockInfoCount) const; + // Get the TimingClockingInfo of a port + TimingClockingInfo getPortClockingInfo(const CellInfo *cell, IdString port, int index) const; + // Return true if a port is a net + bool isGlobalNet(const NetInfo *net) const; + + // ------------------------------------------------- + + // Perform placement validity checks, returning false on failure (all + // implemented in arch_place.cc) + + // Whether or not a given cell can be placed at a given Bel + // This is not intended for Bel type checks, but finer-grained constraints + // such as conflicting set/reset signals, etc + bool isValidBelForCell(CellInfo *cell, BelId bel) const; + + // Return true whether all Bels at a given location are valid + bool isBelLocationValid(BelId bel) const; + + // Helper function for above + bool logicCellsCompatible(const CellInfo **it, const size_t size) const; + + // ------------------------------------------------- + // Assign architecure-specific arguments to nets and cells, which must be + // called between packing or further + // netlist modifications, and validity checks + void assignArchInfo(); + void assignCellInfo(CellInfo *cell); + + // ------------------------------------------------- + BelPin getIOBSharingPLLPin(BelId pll, IdString pll_pin) const; + + int getDrivenGlobalNetwork(BelId bel) const; + + static const std::string defaultPlacer; + static const std::vector availablePlacers; + static const std::string defaultRouter; + static const std::vector availableRouters; +}; + +NEXTPNR_NAMESPACE_END diff --git a/cyclonev/archdefs.h b/cyclonev/archdefs.h new file mode 100644 index 00000000..9b72d268 --- /dev/null +++ b/cyclonev/archdefs.h @@ -0,0 +1,187 @@ +/* + * nextpnr -- Next Generation Place and Route + * + * Copyright (C) 2020 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. + * + */ + +#ifndef NEXTPNR_H +#error Include "archdefs.h" via "nextpnr.h" only. +#endif + +NEXTPNR_NAMESPACE_BEGIN + +typedef int delay_t; + +struct DelayInfo +{ + delay_t delay = 0; + + delay_t minRaiseDelay() const { return delay; } + delay_t maxRaiseDelay() const { return delay; } + + delay_t minFallDelay() const { return delay; } + delay_t maxFallDelay() const { return delay; } + + delay_t minDelay() const { return delay; } + delay_t maxDelay() const { return delay; } + + DelayInfo operator+(const DelayInfo &other) const + { + DelayInfo ret; + ret.delay = this->delay + other.delay; + return ret; + } +}; + +struct BelId +{ + int32_t index = -1; + + bool operator==(const BelId &other) const { return index == other.index; } + bool operator!=(const BelId &other) const { return index != other.index; } + bool operator<(const BelId &other) const { return index < other.index; } +}; + +struct WireId +{ + int32_t index = -1; + + bool operator==(const WireId &other) const { return index == other.index; } + bool operator!=(const WireId &other) const { return index != other.index; } + bool operator<(const WireId &other) const { return index < other.index; } +}; + +struct PipId +{ + int32_t index = -1; + + bool operator==(const PipId &other) const { return index == other.index; } + bool operator!=(const PipId &other) const { return index != other.index; } + bool operator<(const PipId &other) const { return index < other.index; } +}; + +struct GroupId +{ + enum : int8_t + { + TYPE_NONE + } type = TYPE_NONE; + int8_t x = 0, y = 0; + + bool operator==(const GroupId &other) const { return (type == other.type) && (x == other.x) && (y == other.y); } + bool operator!=(const GroupId &other) const { return (type != other.type) || (x != other.x) || (y == other.y); } +}; + +struct DecalId +{ + enum : int8_t + { + TYPE_NONE, + TYPE_BEL, + TYPE_WIRE, + TYPE_PIP, + TYPE_GROUP + } type = TYPE_NONE; + int32_t index = -1; + bool active = false; + + bool operator==(const DecalId &other) const { return (type == other.type) && (index == other.index); } + bool operator!=(const DecalId &other) const { return (type != other.type) || (index != other.index); } +}; + +struct ArchNetInfo +{ + bool is_global = false; + bool is_reset = false, is_enable = false; +}; + +struct NetInfo; + +struct ArchCellInfo +{ + union + { + struct + { + bool dffEnable; + bool carryEnable; + bool negClk; + int inputCount; + const NetInfo *clk, *cen, *sr; + } lcInfo; + struct + { + bool lvds; + bool global; + bool negtrig; + int pintype; + // TODO: clk packing checks... + } ioInfo; + struct + { + bool forPadIn; + } gbInfo; + struct + { + bool ledCurConnected; + } ledInfo; + }; +}; + +NEXTPNR_NAMESPACE_END + +namespace std { +template <> struct hash +{ + std::size_t operator()(const NEXTPNR_NAMESPACE_PREFIX BelId &bel) const noexcept { return hash()(bel.index); } +}; + +template <> struct hash +{ + std::size_t operator()(const NEXTPNR_NAMESPACE_PREFIX WireId &wire) const noexcept + { + return hash()(wire.index); + } +}; + +template <> struct hash +{ + std::size_t operator()(const NEXTPNR_NAMESPACE_PREFIX PipId &pip) const noexcept { return hash()(pip.index); } +}; + +template <> struct hash +{ + std::size_t operator()(const NEXTPNR_NAMESPACE_PREFIX GroupId &group) const noexcept + { + std::size_t seed = 0; + boost::hash_combine(seed, hash()(group.type)); + boost::hash_combine(seed, hash()(group.x)); + boost::hash_combine(seed, hash()(group.y)); + return seed; + } +}; + +template <> struct hash +{ + std::size_t operator()(const NEXTPNR_NAMESPACE_PREFIX DecalId &decal) const noexcept + { + std::size_t seed = 0; + boost::hash_combine(seed, hash()(decal.type)); + boost::hash_combine(seed, hash()(decal.index)); + return seed; + } +}; +} // namespace std diff --git a/cyclonev/family.cmake b/cyclonev/family.cmake new file mode 100644 index 00000000..e69de29b -- cgit v1.2.3