Gowin: Remove nextpnr-gowin

Boards with Gowin chips are supported in the Himbaechel architecture
with much greater correctness and a wider range of primitives.

In fact, at the moment the advice “use himbaechel-gowin” immediately
solves a
significant part of the issues opened by users.

Of course, you need to wait for amendments to oss-cad-suite, at least
https://github.com/YosysHQ/oss-cad-suite-build/pull/109

Signed-off-by: YRabbit <rabbit@yrabbit.cyou>
This commit is contained in:
YRabbit 2024-05-01 09:44:22 +10:00
parent f085950383
commit b84d07eddd
27 changed files with 3 additions and 13675 deletions

View File

@ -1,23 +0,0 @@
#!/bin/bash
function get_dependencies {
pip3 install apycula==${APYCULA_REVISION}
}
function build_nextpnr {
mkdir build
pushd build
cmake .. -DARCH=gowin -DWERROR=on -DBUILD_GUI=on -DUSE_IPO=off
make nextpnr-gowin -j`nproc`
popd
}
function run_tests {
:
}
function run_archcheck {
pushd build
./nextpnr-gowin --device GW1N-UV4LQ144C6/I5 --test
popd
}

View File

@ -9,7 +9,7 @@ jobs:
strategy:
fail-fast: false
matrix:
arch: [mistral, ice40, ecp5, generic, nexus, machxo2, gowin, himbaechel]
arch: [mistral, ice40, ecp5, generic, nexus, machxo2, himbaechel]
runs-on: ubuntu-latest
env:
DEPS_PATH: ${{ github.workspace }}/deps

1
.gitignore vendored
View File

@ -5,7 +5,6 @@
/nextpnr-ecp5*
/nextpnr-nexus*
/nextpnr-fpga_interchange*
/nextpnr-gowin*
/nextpnr-machxo2*
/nextpnr-himbaechel*
.cache

View File

@ -108,9 +108,9 @@ endif()
set(PROGRAM_PREFIX "" CACHE STRING "Name prefix for executables")
# List of families to build
set(FAMILIES generic ice40 ecp5 nexus gowin fpga_interchange machxo2 mistral himbaechel)
set(FAMILIES generic ice40 ecp5 nexus fpga_interchange machxo2 mistral himbaechel)
set(STABLE_FAMILIES generic ice40 ecp5)
set(EXPERIMENTAL_FAMILIES nexus gowin fpga_interchange machxo2 mistral himbaechel)
set(EXPERIMENTAL_FAMILIES nexus fpga_interchange machxo2 mistral himbaechel)
set(ARCH "" CACHE STRING "Architecture family for nextpnr build")
set_property(CACHE ARCH PROPERTY STRINGS ${FAMILIES})

View File

@ -1,53 +0,0 @@
cmake_minimum_required(VERSION 3.5)
project(chipdb-gowin NONE)
set(ALL_GOWIN_DEVICES GW1N-1 GW1NZ-1 GW1N-4 GW1N-9 GW1N-9C GW1NS-2 GW1NS-4 GW2A-18)
set(GOWIN_DEVICES ${ALL_GOWIN_DEVICES} CACHE STRING
"Include support for these Gowin devices (available: ${ALL_GOWIN_DEVICES})")
message(STATUS "Enabled Gowin devices: ${GOWIN_DEVICES}")
find_program (GOWIN_BBA_EXECUTABLE gowin_bba)
message(STATUS "gowin_bba executable: ${GOWIN_BBA_EXECUTABLE}")
if(DEFINED GOWIN_CHIPDB)
add_custom_target(chipdb-gowin-bbas ALL)
else()
# shared among all families
set(SERIALIZE_CHIPDBS TRUE CACHE BOOL
"Serialize device data preprocessing to minimize memory use")
set(all_device_bbas)
file(MAKE_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/chipdb)
foreach(device ${GOWIN_DEVICES})
if(NOT device IN_LIST ALL_GOWIN_DEVICES)
message(FATAL_ERROR "Device ${device} is not a supported Gowin device")
endif()
set(device_bba chipdb/chipdb-${device}.bba)
add_custom_command(
OUTPUT ${device_bba}
COMMAND ${GOWIN_BBA_EXECUTABLE} -d ${device} -i ${CMAKE_CURRENT_SOURCE_DIR}/constids.inc -o ${device_bba}.new
# atomically update
COMMAND ${CMAKE_COMMAND} -E rename ${device_bba}.new ${device_bba}
DEPENDS
${GOWIN_BBA_EXECUTABLE}
${PREVIOUS_CHIPDB_TARGET}
${CMAKE_CURRENT_SOURCE_DIR}/constids.inc
VERBATIM)
list(APPEND all_device_bbas ${device_bba})
if(SERIALIZE_CHIPDBS)
set(PREVIOUS_CHIPDB_TARGET ${CMAKE_CURRENT_BINARY_DIR}/${device_bba})
endif()
endforeach()
add_custom_target(chipdb-gowin-bbas ALL DEPENDS ${all_device_bbas})
get_directory_property(has_parent PARENT_DIRECTORY)
if(has_parent)
set(GOWIN_CHIPDB ${CMAKE_CURRENT_BINARY_DIR}/chipdb PARENT_SCOPE)
# serialize chipdb build across multiple architectures
set(PREVIOUS_CHIPDB_TARGET chipdb-gowin-bbas PARENT_SCOPE)
else()
message(STATUS "Build nextpnr with -DGOWIN_CHIPDB=${CMAKE_CURRENT_BINARY_DIR}/chipdb")
endif()
endif()

File diff suppressed because it is too large Load Diff

View File

@ -1,555 +0,0 @@
/*
* nextpnr -- Next Generation Place and Route
*
* Copyright (C) 2018 Claire Xenia Wolf <claire@yosyshq.com>
* Copyright (C) 2020 Pepijn de Vos <pepijn@symbioticeda.com>
*
* 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 GOWIN_ARCH_H
#define GOWIN_ARCH_H
#include <cstdint>
#include <map>
#include <string>
#include <vector>
#include "base_arch.h"
#include "idstring.h"
#include "nextpnr_namespaces.h"
#include "nextpnr_types.h"
#include "globals.h"
NEXTPNR_NAMESPACE_BEGIN
template <typename T> struct RelPtr
{
int32_t offset;
// void set(const T *ptr) {
// offset = reinterpret_cast<const char*>(ptr) -
// reinterpret_cast<const char*>(this);
// }
const T *get() const { return reinterpret_cast<const T *>(reinterpret_cast<const char *>(this) + offset); }
T *get_mut() const
{
return const_cast<T *>(reinterpret_cast<const T *>(reinterpret_cast<const char *>(this) + offset));
}
const T &operator[](std::size_t index) const { return get()[index]; }
const T &operator*() const { return *(get()); }
const T *operator->() const { return get(); }
RelPtr(const RelPtr &) = delete;
RelPtr &operator=(const RelPtr &) = delete;
};
NPNR_PACKED_STRUCT(struct PairPOD {
uint16_t dest_id;
uint16_t src_id;
});
NPNR_PACKED_STRUCT(struct BelsPOD {
uint16_t type_id;
uint16_t num_ports;
RelPtr<PairPOD> ports;
});
NPNR_PACKED_STRUCT(struct TilePOD /*TidePOD*/ {
uint32_t num_bels;
RelPtr<BelsPOD> bels;
uint32_t num_pips;
RelPtr<PairPOD> pips;
uint32_t num_clock_pips;
RelPtr<PairPOD> clock_pips;
uint32_t num_aliases;
RelPtr<PairPOD> aliases;
});
NPNR_PACKED_STRUCT(struct GlobalAliasPOD {
uint16_t dest_row;
uint16_t dest_col;
uint16_t dest_id;
uint16_t src_row;
uint16_t src_col;
uint16_t src_id;
});
NPNR_PACKED_STRUCT(struct TimingPOD {
uint32_t name_id;
// input, output
uint32_t ff;
uint32_t fr;
uint32_t rf;
uint32_t rr;
});
NPNR_PACKED_STRUCT(struct TimingGroupPOD {
uint32_t name_id;
uint32_t num_timings;
RelPtr<TimingPOD> timings;
});
NPNR_PACKED_STRUCT(struct TimingGroupsPOD {
TimingGroupPOD lut;
TimingGroupPOD alu;
TimingGroupPOD sram;
TimingGroupPOD dff;
// TimingGroupPOD dl;
// TimingGroupPOD iddroddr;
// TimingGroupPOD pll;
// TimingGroupPOD dll;
TimingGroupPOD bram;
// TimingGroupPOD dsp;
TimingGroupPOD fanout;
TimingGroupPOD glbsrc;
TimingGroupPOD hclk;
TimingGroupPOD iodelay;
// TimingGroupPOD io;
// TimingGroupPOD iregoreg;
TimingGroupPOD wire;
});
NPNR_PACKED_STRUCT(struct TimingClassPOD {
uint32_t name_id;
uint32_t num_groups;
RelPtr<TimingGroupsPOD> groups;
});
NPNR_PACKED_STRUCT(struct PartnumberPOD {
uint32_t name_id;
uint32_t package_id;
uint32_t device_id;
uint32_t speed_id;
});
NPNR_PACKED_STRUCT(struct PinPOD {
uint16_t index_id;
uint16_t loc_id;
uint32_t num_cfgs;
RelPtr<uint32_t> cfgs;
});
NPNR_PACKED_STRUCT(struct PackagePOD {
uint32_t name_id;
uint32_t num_pins;
RelPtr<PinPOD> pins;
});
NPNR_PACKED_STRUCT(struct VariantPOD {
uint32_t name_id;
uint32_t num_packages;
RelPtr<PackagePOD> packages;
});
NPNR_PACKED_STRUCT(struct DatabasePOD {
RelPtr<char> family;
uint32_t version;
uint16_t rows;
uint16_t cols;
RelPtr<RelPtr<TilePOD>> grid;
uint32_t num_aliases;
RelPtr<GlobalAliasPOD> aliases;
uint32_t num_speeds;
RelPtr<TimingClassPOD> speeds;
uint32_t num_partnumbers;
RelPtr<PartnumberPOD> partnumber_packages;
uint32_t num_variants;
RelPtr<VariantPOD> variants;
uint16_t num_constids;
uint16_t num_ids;
RelPtr<RelPtr<char>> id_strs;
});
struct ArchArgs
{
std::string family;
std::string partnumber;
// y = mx + c relationship between distance and delay for interconnect
// delay estimates
double delayScale = 0.4, delayOffset = 0.4;
bool gui;
};
struct WireInfo;
struct PipInfo
{
IdString name, type;
std::map<IdString, std::string> attrs;
NetInfo *bound_net;
WireId srcWire, dstWire;
DelayQuad delay;
DecalXY decalxy_active, decalxy_inactive;
Loc loc;
};
struct WireInfo
{
IdString name, type;
std::map<IdString, std::string> attrs;
NetInfo *bound_net;
std::vector<PipId> downhill, uphill;
BelPin uphill_bel_pin;
std::vector<BelPin> downhill_bel_pins;
std::vector<BelPin> bel_pins;
DecalXY decalxy_active, decalxy_inactive;
int x, y;
};
struct PinInfo
{
IdString name;
WireId wire;
PortType type;
};
struct BelInfo
{
IdString name, type;
std::map<IdString, std::string> attrs;
CellInfo *bound_cell;
dict<IdString, PinInfo> pins;
std::vector<IdString> pin_cfgs;
DecalXY decalxy_active, decalxy_inactive;
int x, y, z;
bool gb;
};
struct GroupInfo
{
IdString name;
std::vector<BelId> bels;
std::vector<WireId> wires;
std::vector<PipId> pips;
std::vector<GroupId> groups;
DecalXY decalxy;
};
struct CellDelayKey
{
IdString from, to;
inline bool operator==(const CellDelayKey &other) const { return from == other.from && to == other.to; }
unsigned int hash() const { return mkhash(from.hash(), to.hash()); }
};
struct CellTiming
{
dict<IdString, TimingPortClass> portClasses;
dict<CellDelayKey, DelayQuad> combDelays;
dict<IdString, std::vector<TimingClockingInfo>> clockingInfo;
};
struct ArchRanges : BaseArchRanges
{
using ArchArgsT = ArchArgs;
// Bels
using AllBelsRangeT = const std::vector<BelId> &;
using TileBelsRangeT = const std::vector<BelId> &;
using BelAttrsRangeT = const std::map<IdString, std::string> &;
using BelPinsRangeT = std::vector<IdString>;
using CellBelPinRangeT = std::array<IdString, 1>;
// Wires
using AllWiresRangeT = const std::vector<WireId> &;
using DownhillPipRangeT = const std::vector<PipId> &;
using UphillPipRangeT = const std::vector<PipId> &;
using WireBelPinRangeT = const std::vector<BelPin> &;
using WireAttrsRangeT = const std::map<IdString, std::string> &;
// Pips
using AllPipsRangeT = const std::vector<PipId> &;
using PipAttrsRangeT = const std::map<IdString, std::string> &;
// Groups
using AllGroupsRangeT = std::vector<GroupId>;
using GroupBelsRangeT = const std::vector<BelId> &;
using GroupWiresRangeT = const std::vector<WireId> &;
using GroupPipsRangeT = const std::vector<PipId> &;
using GroupGroupsRangeT = const std::vector<GroupId> &;
};
enum class PLL // fixed PLL locations
{
left,
right
};
struct Arch : BaseArch<ArchRanges>
{
std::string family;
std::string device;
const PackagePOD *package;
const TimingGroupsPOD *speed;
dict<IdString, WireInfo> wires;
dict<IdString, PipInfo> pips;
dict<IdString, BelInfo> bels;
dict<GroupId, GroupInfo> groups;
// These functions include useful errors if not found
WireInfo &wire_info(IdString wire);
PipInfo &pip_info(IdString pip);
BelInfo &bel_info(IdString bel);
NetInfo &net_info(IdString net);
std::vector<IdString> bel_ids, wire_ids, pip_ids;
dict<Loc, BelId> bel_by_loc;
std::vector<std::vector<std::vector<BelId>>> bels_by_tile;
dict<DecalId, std::vector<GraphicElement>> decal_graphics;
int gridDimX = 0, gridDimY = 0;
std::vector<std::vector<int>> tileBelDimZ;
std::vector<std::vector<int>> tilePipDimZ;
dict<IdString, CellTiming> cellTiming;
void addWire(IdString name, IdString type, int x, int y);
void addPip(IdString name, IdString type, IdString srcWire, IdString dstWire, DelayQuad delay, Loc loc);
void addBel(IdString name, IdString type, Loc loc, bool gb);
void addBelInput(IdString bel, IdString name, IdString wire);
void addBelOutput(IdString bel, IdString name, IdString wire);
void addBelInout(IdString bel, IdString name, IdString wire);
void addGroup(IdString name);
void addGroupBel(IdString group, IdString bel);
void addGroupWire(IdString group, IdString wire);
void addGroupPip(IdString group, IdString pip);
void addGroupGroup(IdString group, IdString grp);
void addDecalGraphic(DecalId decal, const GraphicElement &graphic);
void setWireDecal(WireId wire, DecalXY active, DecalXY inactive);
void setPipDecal(PipId pip, DecalXY active, DecalXY inactive);
void setBelDecal(BelId bel, DecalXY active, DecalXY inactive);
void setDefaultDecals(void);
void setGroupDecal(GroupId group, DecalXY decalxy);
std::vector<GraphicElement> getDecalGraphics(DecalId decal) const override;
DecalXY getBelDecal(BelId bel) const override;
DecalXY getGroupDecal(GroupId grp) const override;
DecalXY getPipDecal(PipId pip) const override;
DecalXY getWireDecal(WireId pip) const override;
void setWireAttr(IdString wire, IdString key, const std::string &value);
void setPipAttr(IdString pip, IdString key, const std::string &value);
void setBelAttr(IdString bel, IdString key, const std::string &value);
void setDelayScaling(double scale, double offset);
void addCellTimingClock(IdString cell, IdString port);
void addCellTimingClass(IdString cell, IdString port, TimingPortClass cls);
void addCellTimingDelay(IdString cell, IdString fromPort, IdString toPort, DelayQuad delay);
void addCellTimingSetupHold(IdString cell, IdString port, IdString clock, DelayPair setup, DelayPair hold);
void addCellTimingClockToOut(IdString cell, IdString port, IdString clock, DelayQuad clktoq);
IdString wireToGlobal(int &row, int &col, const DatabasePOD *db, IdString &wire);
DelayQuad getWireTypeDelay(IdString wire);
void read_cst(std::istream &in);
void addMuxBels(const DatabasePOD *db, int row, int col);
// ---------------------------------------------------------------
// Common Arch API. Every arch must provide the following methods.
ArchArgs args;
Arch(ArchArgs args);
std::string getChipName() const override { return device; }
ArchArgs archArgs() const override { return args; }
IdString archArgsToId(ArchArgs args) const override { return id_none; }
int getGridDimX() const override { return gridDimX; }
int getGridDimY() const override { return gridDimY; }
int getTileBelDimZ(int x, int y) const override { return tileBelDimZ[x][y]; }
int getTilePipDimZ(int x, int y) const override { return tilePipDimZ[x][y]; }
char getNameDelimiter() const override
{
return ' '; /* use a non-existent delimiter as we aren't using IdStringLists yet */
}
BelId getBelByName(IdStringList name) const override;
IdStringList getBelName(BelId bel) const override;
Loc getBelLocation(BelId bel) const override;
BelId getBelByLocation(Loc loc) const override;
const std::vector<BelId> &getBelsByTile(int x, int y) const override;
bool getBelGlobalBuf(BelId bel) const override;
void bindBel(BelId bel, CellInfo *cell, PlaceStrength strength) override;
void unbindBel(BelId bel) override;
bool checkBelAvail(BelId bel) const override;
CellInfo *getBoundBelCell(BelId bel) const override;
CellInfo *getConflictingBelCell(BelId bel) const override;
const std::vector<BelId> &getBels() const override;
IdString getBelType(BelId bel) const override;
const std::map<IdString, std::string> &getBelAttrs(BelId bel) const override;
WireId getBelPinWire(BelId bel, IdString pin) const override;
PortType getBelPinType(BelId bel, IdString pin) const override;
std::vector<IdString> getBelPins(BelId bel) const override;
std::array<IdString, 1> getBelPinsForCellPin(const CellInfo *cell_info, IdString pin) const override;
// Placement validity checks
virtual bool isValidBelForCellType(IdString cell_type, BelId bel) const override
{
return cell_type == id_DUMMY_CELL || cell_type == this->getBelType(bel);
}
WireId getWireByName(IdStringList name) const override;
IdStringList getWireName(WireId wire) const override;
IdString getWireType(WireId wire) const override;
const std::map<IdString, std::string> &getWireAttrs(WireId wire) const override;
void bindWire(WireId wire, NetInfo *net, PlaceStrength strength) override;
void unbindWire(WireId wire) override;
bool checkWireAvail(WireId wire) const override;
NetInfo *getBoundWireNet(WireId wire) const override;
WireId getConflictingWireWire(WireId wire) const override { return wire; }
NetInfo *getConflictingWireNet(WireId wire) const override;
DelayQuad getWireDelay(WireId wire) const override { return DelayQuad(0); }
const std::vector<WireId> &getWires() const override;
const std::vector<BelPin> &getWireBelPins(WireId wire) const override;
PipId getPipByName(IdStringList name) const override;
IdStringList getPipName(PipId pip) const override;
IdString getPipType(PipId pip) const override;
const std::map<IdString, std::string> &getPipAttrs(PipId pip) const override;
void bindPip(PipId pip, NetInfo *net, PlaceStrength strength) override;
void unbindPip(PipId pip) override;
bool checkPipAvail(PipId pip) const override;
NetInfo *getBoundPipNet(PipId pip) const override;
WireId getConflictingPipWire(PipId pip) const override;
NetInfo *getConflictingPipNet(PipId pip) const override;
const std::vector<PipId> &getPips() const override;
Loc getPipLocation(PipId pip) const override;
WireId getPipSrcWire(PipId pip) const override;
WireId getPipDstWire(PipId pip) const override;
DelayQuad getPipDelay(PipId pip) const override;
const std::vector<PipId> &getPipsDownhill(WireId wire) const override;
const std::vector<PipId> &getPipsUphill(WireId wire) const override;
GroupId getGroupByName(IdStringList name) const override;
IdStringList getGroupName(GroupId group) const override;
std::vector<GroupId> getGroups() const override;
const std::vector<BelId> &getGroupBels(GroupId group) const override;
const std::vector<WireId> &getGroupWires(GroupId group) const override;
const std::vector<PipId> &getGroupPips(GroupId group) const override;
const std::vector<GroupId> &getGroupGroups(GroupId group) const override;
delay_t estimateDelay(WireId src, WireId dst) const override;
delay_t predictDelay(BelId src_bel, IdString src_pin, BelId dst_bel, IdString dst_pin) const override;
delay_t getDelayEpsilon() const override { return 0.01; }
delay_t getRipupDelayPenalty() const override { return 0.4; }
float getDelayNS(delay_t v) const override { return v; }
delay_t getDelayFromNS(float ns) const override { return ns; }
uint32_t getDelayChecksum(delay_t v) const override { return 0; }
BoundingBox getRouteBoundingBox(WireId src, WireId dst) const override;
bool pack() override;
bool place() override;
bool route() override;
bool getCellDelay(const CellInfo *cell, IdString fromPort, IdString toPort, DelayQuad &delay) const override;
// 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 override;
// Get the TimingClockingInfo of a port
TimingClockingInfo getPortClockingInfo(const CellInfo *cell, IdString port, int index) const override;
bool isBelLocationValid(BelId bel, bool explain_invalid = false) const override;
static const std::string defaultPlacer;
static const std::vector<std::string> availablePlacers;
static const std::string defaultRouter;
static const std::vector<std::string> availableRouters;
// ---------------------------------------------------------------
// Internal usage
void assignArchInfo() override;
bool cellsCompatible(const CellInfo **cells, int count) const;
bool haveBelType(int x, int y, IdString bel_type);
bool allocate_longwire(NetInfo *ni, int lw_idx = -1);
void fix_longwire_bels();
void pre_pack(Context *ctx);
void post_pack(Context *ctx);
void pre_route(Context *ctx);
void post_route(Context *ctx);
void auto_longwires();
void add_pllvr_ports(DatabasePOD const *db, BelsPOD const *bel, IdString belname, int row, int col);
void add_rpll_ports(DatabasePOD const *db, BelsPOD const *bel, IdString belname, int row, int col);
void fix_pll_nets(Context *ctx);
bool is_GCLKT_iob(const CellInfo *cell);
void bind_pll_to_bel(CellInfo *ci, PLL loc);
void mark_used_hclk(Context *ctx);
IdString apply_local_aliases(int row, int col, const DatabasePOD *db, IdString &wire);
WireId get_make_port_wire(const DatabasePOD *db, const BelsPOD *bel, int row, int col, IdString port);
GowinGlobalRouter globals_router;
void mark_gowin_globals(Context *ctx);
void route_gowin_globals(Context *ctx);
// chip db version
unsigned int const chipdb_version = 2;
std::vector<IdString> cell_types;
// clock spines cache
// spine_id : [wire_id, wire_id, ...]
dict<IdString, std::vector<IdString>> clockSpinesCache;
void updateClockSpinesCache(IdString spine_id, IdString wire_id);
void fixClockSpineDecals(void);
// XXX GW1N-9C DDR quirk
bool ddr_has_extra_inputs = false;
// XXX GW1NR-9 iobuf quirk
bool gw1n9_quirk = false;
// 8 Long wires
uint8_t avail_longwires = 0xff;
// Permissible combinations of modes in a single slice
std::map<const IdString, IdString> dff_comp_mode;
// max global clock wires
int max_clock;
};
// Bels Z range
namespace BelZ {
enum
{
ioba_z = 0, // IOBA
iobb_z = 1, // IOBB
mux_0_z = 10, // start Z for the MUX2LUT5 bels
lutram_0_z = 30, // start Z for the LUTRAM bels
vcc_0_z = 277, // virtual VCC bel Z
gnd_0_z = 278, // virtual VSS bel Z
osc_z = 280, // Z for the oscillator bels
bufs_0_z = 281, // Z for long wire buffer bel
pll_z = 289, // PLL
pllvr_z = 290, // PLLVR
iologic_z = 291, // IOLOGIC
oser16_z = 293, // OSER16
ides16_z = 294, // IDES16
free_z = 295 // Must be the last, one can use z starting from this value, adjust accordingly.
};
}
NEXTPNR_NAMESPACE_END
#endif /* GOWIN_ARCH_H */

View File

@ -1,160 +0,0 @@
/*
* nextpnr -- Next Generation Place and Route
*
* Copyright (C) 2018 Claire Xenia Wolf <claire@yosyshq.com>
* Copyright (C) 2018 gatecat <gatecat@ds0.me>
*
* 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 "arch_pybindings.h"
#include "nextpnr.h"
#include "pybindings.h"
#include "pywrappers.h"
using namespace pybind11::literals;
NEXTPNR_NAMESPACE_BEGIN
namespace PythonConversion {
template <> struct string_converter<const IdString &>
{
const IdString &from_str(Context *ctx, std::string name) { NPNR_ASSERT_FALSE("unsupported"); }
std::string to_str(Context *ctx, const IdString &id) { return id.str(ctx); }
};
} // namespace PythonConversion
void arch_wrap_python(py::module &m)
{
using namespace PythonConversion;
auto arch_cls = py::class_<Arch, BaseCtx>(m, "Arch").def(py::init<ArchArgs>());
auto dxy_cls = py::class_<ContextualWrapper<DecalXY>>(m, "DecalXY_");
readwrite_wrapper<DecalXY, decltype(&DecalXY::decal), &DecalXY::decal, conv_to_str<DecalId>,
conv_from_str<DecalId>>::def_wrap(dxy_cls, "decal");
readwrite_wrapper<DecalXY, decltype(&DecalXY::x), &DecalXY::x, pass_through<float>, pass_through<float>>::def_wrap(
dxy_cls, "x");
readwrite_wrapper<DecalXY, decltype(&DecalXY::y), &DecalXY::y, pass_through<float>, pass_through<float>>::def_wrap(
dxy_cls, "y");
auto ctx_cls = py::class_<Context, Arch>(m, "Context")
.def("checksum", &Context::checksum)
.def("pack", &Context::pack)
.def("place", &Context::place)
.def("route", &Context::route);
py::class_<BelPin>(m, "BelPin").def_readwrite("bel", &BelPin::bel).def_readwrite("pin", &BelPin::pin);
fn_wrapper_1a<Context, decltype(&Context::getBelType), &Context::getBelType, conv_to_str<IdString>,
conv_from_str<BelId>>::def_wrap(ctx_cls, "getBelType");
fn_wrapper_1a<Context, decltype(&Context::checkBelAvail), &Context::checkBelAvail, pass_through<bool>,
conv_from_str<BelId>>::def_wrap(ctx_cls, "checkBelAvail");
fn_wrapper_1a<Context, decltype(&Context::getBelChecksum), &Context::getBelChecksum, pass_through<uint32_t>,
conv_from_str<BelId>>::def_wrap(ctx_cls, "getBelChecksum");
fn_wrapper_3a_v<Context, decltype(&Context::bindBel), &Context::bindBel, conv_from_str<BelId>,
addr_and_unwrap<CellInfo>, pass_through<PlaceStrength>>::def_wrap(ctx_cls, "bindBel");
fn_wrapper_1a_v<Context, decltype(&Context::unbindBel), &Context::unbindBel, conv_from_str<BelId>>::def_wrap(
ctx_cls, "unbindBel");
fn_wrapper_1a<Context, decltype(&Context::getBoundBelCell), &Context::getBoundBelCell, deref_and_wrap<CellInfo>,
conv_from_str<BelId>>::def_wrap(ctx_cls, "getBoundBelCell");
fn_wrapper_1a<Context, decltype(&Context::getConflictingBelCell), &Context::getConflictingBelCell,
deref_and_wrap<CellInfo>, conv_from_str<BelId>>::def_wrap(ctx_cls, "getConflictingBelCell");
fn_wrapper_0a<Context, decltype(&Context::getBels), &Context::getBels,
wrap_context<const std::vector<BelId> &>>::def_wrap(ctx_cls, "getBels");
fn_wrapper_2a<Context, decltype(&Context::getBelPinWire), &Context::getBelPinWire, conv_to_str<WireId>,
conv_from_str<BelId>, conv_from_str<IdString>>::def_wrap(ctx_cls, "getBelPinWire");
fn_wrapper_1a<Context, decltype(&Context::getWireBelPins), &Context::getWireBelPins,
wrap_context<const std::vector<BelPin> &>, conv_from_str<WireId>>::def_wrap(ctx_cls,
"getWireBelPins");
fn_wrapper_1a<Context, decltype(&Context::getWireChecksum), &Context::getWireChecksum, pass_through<uint32_t>,
conv_from_str<WireId>>::def_wrap(ctx_cls, "getWireChecksum");
fn_wrapper_3a_v<Context, decltype(&Context::bindWire), &Context::bindWire, conv_from_str<WireId>,
addr_and_unwrap<NetInfo>, pass_through<PlaceStrength>>::def_wrap(ctx_cls, "bindWire");
fn_wrapper_1a_v<Context, decltype(&Context::unbindWire), &Context::unbindWire, conv_from_str<WireId>>::def_wrap(
ctx_cls, "unbindWire");
fn_wrapper_1a<Context, decltype(&Context::checkWireAvail), &Context::checkWireAvail, pass_through<bool>,
conv_from_str<WireId>>::def_wrap(ctx_cls, "checkWireAvail");
fn_wrapper_1a<Context, decltype(&Context::getBoundWireNet), &Context::getBoundWireNet, deref_and_wrap<NetInfo>,
conv_from_str<WireId>>::def_wrap(ctx_cls, "getBoundWireNet");
fn_wrapper_1a<Context, decltype(&Context::getConflictingWireNet), &Context::getConflictingWireNet,
deref_and_wrap<NetInfo>, conv_from_str<WireId>>::def_wrap(ctx_cls, "getConflictingWireNet");
fn_wrapper_0a<Context, decltype(&Context::getWires), &Context::getWires,
wrap_context<const std::vector<WireId> &>>::def_wrap(ctx_cls, "getWires");
fn_wrapper_0a<Context, decltype(&Context::getPips), &Context::getPips,
wrap_context<const std::vector<PipId> &>>::def_wrap(ctx_cls, "getPips");
fn_wrapper_1a<Context, decltype(&Context::getPipChecksum), &Context::getPipChecksum, pass_through<uint32_t>,
conv_from_str<PipId>>::def_wrap(ctx_cls, "getPipChecksum");
fn_wrapper_3a_v<Context, decltype(&Context::bindPip), &Context::bindPip, conv_from_str<PipId>,
addr_and_unwrap<NetInfo>, pass_through<PlaceStrength>>::def_wrap(ctx_cls, "bindPip");
fn_wrapper_1a_v<Context, decltype(&Context::unbindPip), &Context::unbindPip, conv_from_str<PipId>>::def_wrap(
ctx_cls, "unbindPip");
fn_wrapper_1a<Context, decltype(&Context::checkPipAvail), &Context::checkPipAvail, pass_through<bool>,
conv_from_str<PipId>>::def_wrap(ctx_cls, "checkPipAvail");
fn_wrapper_1a<Context, decltype(&Context::getBoundPipNet), &Context::getBoundPipNet, deref_and_wrap<NetInfo>,
conv_from_str<PipId>>::def_wrap(ctx_cls, "getBoundPipNet");
fn_wrapper_1a<Context, decltype(&Context::getConflictingPipNet), &Context::getConflictingPipNet,
deref_and_wrap<NetInfo>, conv_from_str<PipId>>::def_wrap(ctx_cls, "getConflictingPipNet");
fn_wrapper_1a<Context, decltype(&Context::getPipsDownhill), &Context::getPipsDownhill,
wrap_context<const std::vector<PipId> &>, conv_from_str<WireId>>::def_wrap(ctx_cls,
"getPipsDownhill");
fn_wrapper_1a<Context, decltype(&Context::getPipsUphill), &Context::getPipsUphill,
wrap_context<const std::vector<PipId> &>, conv_from_str<WireId>>::def_wrap(ctx_cls, "getPipsUphill");
fn_wrapper_1a<Context, decltype(&Context::getPipSrcWire), &Context::getPipSrcWire, conv_to_str<WireId>,
conv_from_str<PipId>>::def_wrap(ctx_cls, "getPipSrcWire");
fn_wrapper_1a<Context, decltype(&Context::getPipDstWire), &Context::getPipDstWire, conv_to_str<WireId>,
conv_from_str<PipId>>::def_wrap(ctx_cls, "getPipDstWire");
fn_wrapper_1a<Context, decltype(&Context::getPipDelay), &Context::getPipDelay, pass_through<DelayQuad>,
conv_from_str<PipId>>::def_wrap(ctx_cls, "getPipDelay");
fn_wrapper_1a<Context, decltype(&Context::getDelayFromNS), &Context::getDelayFromNS, pass_through<delay_t>,
pass_through<double>>::def_wrap(ctx_cls, "getDelayFromNS");
fn_wrapper_0a<Context, decltype(&Context::getChipName), &Context::getChipName, pass_through<std::string>>::def_wrap(
ctx_cls, "getChipName");
fn_wrapper_0a<Context, decltype(&Context::archId), &Context::archId, conv_to_str<IdString>>::def_wrap(ctx_cls,
"archId");
fn_wrapper_3a<Context, decltype(&Context::constructDecalXY), &Context::constructDecalXY, wrap_context<DecalXY>,
conv_from_str<DecalId>, pass_through<float>, pass_through<float>>::def_wrap(ctx_cls, "DecalXY");
typedef dict<IdString, std::unique_ptr<CellInfo>> CellMap;
typedef dict<IdString, std::unique_ptr<NetInfo>> NetMap;
typedef dict<IdString, HierarchicalCell> HierarchyMap;
readonly_wrapper<Context, decltype(&Context::cells), &Context::cells, wrap_context<CellMap &>>::def_wrap(ctx_cls,
"cells");
readonly_wrapper<Context, decltype(&Context::nets), &Context::nets, wrap_context<NetMap &>>::def_wrap(ctx_cls,
"nets");
fn_wrapper_2a_v<Context, decltype(&Context::addClock), &Context::addClock, conv_from_str<IdString>,
pass_through<float>>::def_wrap(ctx_cls, "addClock");
WRAP_MAP_UPTR(m, CellMap, "IdCellMap");
WRAP_MAP_UPTR(m, NetMap, "IdNetMap");
WRAP_MAP(m, HierarchyMap, wrap_context<HierarchicalCell &>, "HierarchyMap");
WRAP_VECTOR(m, const std::vector<IdString>, conv_to_str<IdString>);
}
NEXTPNR_NAMESPACE_END
#endif

View File

@ -1,31 +0,0 @@
/*
* nextpnr -- Next Generation Place and Route
*
* Copyright (C) 2018 Claire Xenia Wolf <claire@yosyshq.com>
* Copyright (C) 2018 gatecat <gatecat@ds0.me>
*
* 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

View File

@ -1,77 +0,0 @@
/*
* nextpnr -- Next Generation Place and Route
*
* Copyright (C) 2018 Claire Xenia Wolf <claire@yosyshq.com>
* Copyright (C) 2020 Pepijn de Vos <pepijn@symbioticeda.com>
*
* 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 GOWIN_ARCHDEFS_H
#define GOWIN_ARCHDEFS_H
#include "base_clusterinfo.h"
#include "idstring.h"
#include "nextpnr_namespaces.h"
NEXTPNR_NAMESPACE_BEGIN
typedef float delay_t;
#ifndef Q_MOC_RUN
enum ConstIds
{
ID_NONE
#define X(t) , ID_##t
#include "constids.inc"
#undef X
};
#define X(t) static constexpr auto id_##t = IdString(ID_##t);
#include "constids.inc"
#undef X
#endif
typedef IdString BelId;
typedef IdString WireId;
typedef IdString PipId;
typedef IdString GroupId;
typedef IdString DecalId;
typedef IdString BelBucketId;
typedef IdString ClusterId;
struct ArchNetInfo
{
};
struct NetInfo;
struct ArchCellInfo : BaseClusterInfo
{
// Is the flip-flop of this slice used
bool ff_used;
// The type of this flip-flop
IdString ff_type;
// Is a slice type primitive
bool is_slice;
// Only packing rule for slice type primitives is a single clock per tile
const NetInfo *slice_clk;
const NetInfo *slice_ce;
const NetInfo *slice_lsr;
};
NEXTPNR_NAMESPACE_END
#endif /* GOWIN_ARCHDEFS_H */

View File

@ -1,290 +0,0 @@
/*
* nextpnr -- Next Generation Place and Route
*
* Copyright (C) 2019 gatecat <gatecat@ds0.me>
* Copyright (C) 2020 Pepijn de Vos <pepijn@symbioticeda.com>
*
* 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 "cells.h"
#include <iostream>
#include "design_utils.h"
#include "log.h"
#include "util.h"
NEXTPNR_NAMESPACE_BEGIN
std::unique_ptr<CellInfo> create_generic_cell(Context *ctx, IdString type, std::string name)
{
static int auto_idx = 0;
IdString name_id =
name.empty() ? ctx->id("$nextpnr_" + type.str(ctx) + "_" + std::to_string(auto_idx++)) : ctx->id(name);
auto new_cell = std::make_unique<CellInfo>(ctx, name_id, type);
if (type == id_SLICE) {
new_cell->params[id_INIT] = 0;
new_cell->params[id_FF_USED] = 0;
new_cell->params[id_FF_TYPE] = id_DFF.str(ctx);
IdString names[4] = {id_A, id_B, id_C, id_D};
for (int i = 0; i < 4; i++) {
new_cell->addInput(names[i]);
}
new_cell->addInput(id_CLK);
new_cell->addOutput(id_F);
new_cell->addOutput(id_Q);
new_cell->addInput(id_CE);
new_cell->addInput(id_LSR);
} else if (type == id_RAMW) {
IdString names[8] = {id_A4, id_B4, id_C4, id_D4, id_A5, id_B5, id_C5, id_D5};
for (int i = 0; i < 8; i++) {
new_cell->addInput(names[i]);
}
new_cell->addInput(id_CLK);
new_cell->addInput(id_CE);
new_cell->addInput(id_LSR);
} else if (type.in(id_MUX2_LUT5, id_MUX2_LUT6, id_MUX2_LUT7, id_MUX2_LUT7, id_MUX2_LUT8)) {
new_cell->addInput(id_I0);
new_cell->addInput(id_I1);
new_cell->addInput(id_SEL);
new_cell->addOutput(id_OF);
} else if (type.in(id_IOB, id_IOBS)) {
new_cell->params[id_INPUT_USED] = 0;
new_cell->params[id_OUTPUT_USED] = 0;
new_cell->params[id_ENABLE_USED] = 0;
new_cell->addInout(id_PAD);
new_cell->addInput(id_I);
new_cell->addInput(id_OEN);
new_cell->addOutput(id_O);
} else if (type == id_GSR) {
new_cell->addInput(id_GSRI);
} else if (type == id_GND) {
new_cell->addOutput(id_G);
} else if (type == id_VCC) {
new_cell->addOutput(id_V);
} else if (type == id_BUFS) {
new_cell->addInput(id_I);
new_cell->addOutput(id_O);
} else if (type == id_rPLL) {
for (IdString iid :
{id_CLKIN, id_CLKFB, id_FBDSEL0, id_FBDSEL1, id_FBDSEL2, id_FBDSEL3, id_FBDSEL4, id_FBDSEL5, id_IDSEL0,
id_IDSEL1, id_IDSEL2, id_IDSEL3, id_IDSEL4, id_IDSEL5, id_ODSEL0, id_ODSEL1, id_ODSEL2, id_ODSEL3,
id_ODSEL4, id_ODSEL5, id_PSDA0, id_PSDA1, id_PSDA2, id_PSDA3, id_DUTYDA0, id_DUTYDA1, id_DUTYDA2,
id_DUTYDA3, id_FDLY0, id_FDLY1, id_FDLY2, id_FDLY3, id_RESET, id_RESET_P}) {
new_cell->addInput(iid);
}
new_cell->addOutput(id_CLKOUT);
new_cell->addOutput(id_CLKOUTP);
new_cell->addOutput(id_CLKOUTD);
new_cell->addOutput(id_CLKOUTD3);
new_cell->addOutput(id_LOCK);
} else if (type == id_PLLVR) {
for (IdString iid :
{id_CLKIN, id_CLKFB, id_FBDSEL0, id_FBDSEL1, id_FBDSEL2, id_FBDSEL3, id_FBDSEL4, id_FBDSEL5, id_IDSEL0,
id_IDSEL1, id_IDSEL2, id_IDSEL3, id_IDSEL4, id_IDSEL5, id_ODSEL0, id_ODSEL1, id_ODSEL2, id_ODSEL3,
id_ODSEL4, id_ODSEL5, id_PSDA0, id_PSDA1, id_PSDA2, id_PSDA3, id_DUTYDA0, id_DUTYDA1, id_DUTYDA2,
id_DUTYDA3, id_FDLY0, id_FDLY1, id_FDLY2, id_FDLY3, id_RESET, id_RESET_P, id_VREN}) {
new_cell->addInput(iid);
}
new_cell->addOutput(id_CLKOUT);
new_cell->addOutput(id_CLKOUTP);
new_cell->addOutput(id_CLKOUTD);
new_cell->addOutput(id_CLKOUTD3);
new_cell->addOutput(id_LOCK);
} else if (type == id_IOLOGIC) {
new_cell->addInput(id_FCLK);
new_cell->addInput(id_PCLK);
new_cell->addInput(id_RESET);
} else if (type == id_DUMMY_CELL) {
} else {
log_error("unable to create generic cell of type %s\n", type.c_str(ctx));
}
return new_cell;
}
void lut_to_lc(const Context *ctx, CellInfo *lut, CellInfo *lc, bool no_dff)
{
lc->params[id_INIT] = lut->params[id_INIT];
lc->cluster = lut->cluster;
lc->constr_x = lut->constr_x;
lc->constr_y = lut->constr_y;
lc->constr_z = lut->constr_z;
// add itself to the cluster root children list
if (lc->cluster != ClusterId()) {
CellInfo *cluster_root = ctx->cells.at(lc->cluster).get();
lc->constr_x += cluster_root->constr_x;
lc->constr_y += cluster_root->constr_y;
lc->constr_z += cluster_root->constr_z;
if (cluster_root->cluster != cluster_root->name) {
lc->cluster = cluster_root->cluster;
cluster_root = ctx->cells.at(cluster_root->cluster).get();
}
cluster_root->constr_children.push_back(lc);
}
IdString sim_names[4] = {id_I0, id_I1, id_I2, id_I3};
IdString wire_names[4] = {id_A, id_B, id_C, id_D};
for (int i = 0; i < 4; i++) {
lut->movePortTo(sim_names[i], lc, wire_names[i]);
}
if (no_dff) {
lc->params[id_FF_USED] = 0;
lut->movePortTo(id_F, lc, id_F);
}
}
void dff_to_lc(const Context *ctx, CellInfo *dff, CellInfo *lc, bool pass_thru_lut)
{
lc->params[id_FF_USED] = 1;
lc->params[id_FF_TYPE] = dff->type.str(ctx);
dff->movePortTo(id_CLK, lc, id_CLK);
dff->movePortTo(id_CE, lc, id_CE);
dff->movePortTo(id_SET, lc, id_LSR);
dff->movePortTo(id_RESET, lc, id_LSR);
dff->movePortTo(id_CLEAR, lc, id_LSR);
dff->movePortTo(id_PRESET, lc, id_LSR);
if (pass_thru_lut) {
// Fill LUT with alternating 10
const int init_size = 1 << 4;
std::string init;
init.reserve(init_size);
for (int i = 0; i < init_size; i += 2)
init.append("10");
lc->params[id_INIT] = Property::from_string(init);
dff->movePortTo(id_D, lc, id_A);
}
dff->movePortTo(id_Q, lc, id_Q);
}
void gwio_to_iob(Context *ctx, CellInfo *nxio, CellInfo *iob, pool<IdString> &todelete_cells)
{
if (nxio->type == id_IBUF) {
if (iob->type == id_IOBS) {
// VCC -> OEN
iob->connectPort(id_OEN, ctx->nets[ctx->id("$PACKER_VCC_NET")].get());
}
iob->params[id_INPUT_USED] = 1;
nxio->movePortTo(id_O, iob, id_O);
} else if (nxio->type == id_OBUF) {
if (iob->type == id_IOBS) {
// VSS -> OEN
iob->connectPort(id_OEN, ctx->nets[ctx->id("$PACKER_GND_NET")].get());
}
iob->params[id_OUTPUT_USED] = 1;
nxio->movePortTo(id_I, iob, id_I);
} else if (nxio->type == id_TBUF) {
iob->params[id_ENABLE_USED] = 1;
iob->params[id_OUTPUT_USED] = 1;
nxio->movePortTo(id_I, iob, id_I);
nxio->movePortTo(id_OEN, iob, id_OEN);
} else if (nxio->type == id_IOBUF) {
iob->params[id_ENABLE_USED] = 1;
iob->params[id_INPUT_USED] = 1;
iob->params[id_OUTPUT_USED] = 1;
nxio->movePortTo(id_I, iob, id_I);
nxio->movePortTo(id_O, iob, id_O);
nxio->movePortTo(id_OEN, iob, id_OEN);
} else {
NPNR_ASSERT(false);
}
}
void reconnect_pllvr(Context *ctx, CellInfo *pll, CellInfo *new_pll)
{
pll->movePortTo(id_CLKIN, new_pll, id_CLKIN);
pll->movePortTo(id_VREN, new_pll, id_VREN);
pll->movePortTo(id_CLKFB, new_pll, id_CLKFB);
pll->movePortTo(id_RESET, new_pll, id_RESET);
pll->movePortTo(id_RESET_P, new_pll, id_RESET_P);
for (int i = 0; i < 6; ++i) {
pll->movePortTo(ctx->idf("FBDSEL[%d]", i), new_pll, ctx->idf("FBDSEL%d", i));
pll->movePortTo(ctx->idf("IDSEL[%d]", i), new_pll, ctx->idf("IDSEL%d", i));
pll->movePortTo(ctx->idf("ODSEL[%d]", i), new_pll, ctx->idf("ODSEL%d", i));
if (i < 4) {
pll->movePortTo(ctx->idf("PSDA[%d]", i), new_pll, ctx->idf("PSDA%d", i));
pll->movePortTo(ctx->idf("DUTYDA[%d]", i), new_pll, ctx->idf("DUTYDA%d", i));
pll->movePortTo(ctx->idf("FDLY[%d]", i), new_pll, ctx->idf("FDLY%d", i));
}
}
pll->movePortTo(id_CLKOUT, new_pll, id_CLKOUT);
pll->movePortTo(id_CLKOUTP, new_pll, id_CLKOUTP);
pll->movePortTo(id_CLKOUTD, new_pll, id_CLKOUTD);
pll->movePortTo(id_CLKOUTD3, new_pll, id_CLKOUTD3);
pll->movePortTo(id_LOCK, new_pll, id_LOCK);
}
void reconnect_rpll(Context *ctx, CellInfo *pll, CellInfo *new_pll)
{
pll->movePortTo(id_CLKIN, new_pll, id_CLKIN);
pll->movePortTo(id_CLKFB, new_pll, id_CLKFB);
pll->movePortTo(id_RESET, new_pll, id_RESET);
pll->movePortTo(id_RESET_P, new_pll, id_RESET_P);
for (int i = 0; i < 6; ++i) {
pll->movePortTo(ctx->idf("FBDSEL[%d]", i), new_pll, ctx->idf("FBDSEL%d", i));
pll->movePortTo(ctx->idf("IDSEL[%d]", i), new_pll, ctx->idf("IDSEL%d", i));
pll->movePortTo(ctx->idf("ODSEL[%d]", i), new_pll, ctx->idf("ODSEL%d", i));
if (i < 4) {
pll->movePortTo(ctx->idf("PSDA[%d]", i), new_pll, ctx->idf("PSDA%d", i));
pll->movePortTo(ctx->idf("DUTYDA[%d]", i), new_pll, ctx->idf("DUTYDA%d", i));
pll->movePortTo(ctx->idf("FDLY[%d]", i), new_pll, ctx->idf("FDLY%d", i));
}
}
pll->movePortTo(id_CLKOUT, new_pll, id_CLKOUT);
pll->movePortTo(id_CLKOUTP, new_pll, id_CLKOUTP);
pll->movePortTo(id_CLKOUTD, new_pll, id_CLKOUTD);
pll->movePortTo(id_CLKOUTD3, new_pll, id_CLKOUTD3);
pll->movePortTo(id_LOCK, new_pll, id_LOCK);
}
void sram_to_ramw_split(Context *ctx, CellInfo *ram, CellInfo *ramw)
{
if (ramw->hierpath == IdString())
ramw->hierpath = ramw->hierpath;
ram->movePortTo(ctx->id("WAD[0]"), ramw, id_A4);
ram->movePortTo(ctx->id("WAD[1]"), ramw, id_B4);
ram->movePortTo(ctx->id("WAD[2]"), ramw, id_C4);
ram->movePortTo(ctx->id("WAD[3]"), ramw, id_D4);
ram->movePortTo(ctx->id("DI[0]"), ramw, id_A5);
ram->movePortTo(ctx->id("DI[1]"), ramw, id_B5);
ram->movePortTo(ctx->id("DI[2]"), ramw, id_C5);
ram->movePortTo(ctx->id("DI[3]"), ramw, id_D5);
ram->movePortTo(ctx->id("CLK"), ramw, id_CLK);
ram->movePortTo(ctx->id("WRE"), ramw, id_LSR);
}
void sram_to_slice(Context *ctx, CellInfo *ram, CellInfo *slice, int index)
{
if (slice->hierpath == IdString())
slice->hierpath = slice->hierpath;
slice->params[id_INIT] = ram->params[ctx->idf("INIT_%d", index)];
ram->movePortTo(ctx->idf("DO[%d]", index), slice, id_F);
ram->copyPortTo(ctx->id("RAD[0]"), slice, id_A);
ram->copyPortTo(ctx->id("RAD[1]"), slice, id_B);
ram->copyPortTo(ctx->id("RAD[2]"), slice, id_C);
ram->copyPortTo(ctx->id("RAD[3]"), slice, id_D);
}
NEXTPNR_NAMESPACE_END

View File

@ -1,136 +0,0 @@
/*
* nextpnr -- Next Generation Place and Route
*
* Copyright (C) 2019 gatecat <gatecat@ds0.me>
* Copyright (C) 2020 Pepijn de Vos <pepijn@symbioticeda.com>
*
* 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 "nextpnr.h"
#ifndef GENERIC_CELLS_H
#define GENERIC_CELLS_H
NEXTPNR_NAMESPACE_BEGIN
// Create a generic arch cell and return it
// Name will be automatically assigned if not specified
std::unique_ptr<CellInfo> create_generic_cell(Context *ctx, IdString type, std::string name = "");
// Return true if a cell is a LUT
inline bool is_lut(const BaseCtx *ctx, const CellInfo *cell)
{
switch (cell->type.index) {
case ID_LUT1:
case ID_LUT2:
case ID_LUT3:
case ID_LUT4:
return true;
default:
return false;
}
}
// Return true if a cell is a wide LUT mux
inline bool is_widelut(const BaseCtx *ctx, const CellInfo *cell)
{
switch (cell->type.index) {
case ID_MUX2_LUT5:
case ID_MUX2_LUT6:
case ID_MUX2_LUT7:
case ID_MUX2_LUT8:
return true;
default:
return false;
}
}
inline bool is_alu(const BaseCtx *ctx, const CellInfo *cell) { return (cell->type.index == ID_ALU); }
// is MUX2_LUT5
inline bool is_mux2_lut5(const BaseCtx *ctx, const CellInfo *cell) { return (cell->type.index == ID_MUX2_LUT5); }
// is MUX2_LUT6
inline bool is_mux2_lut6(const BaseCtx *ctx, const CellInfo *cell) { return (cell->type.index == ID_MUX2_LUT6); }
// is MUX2_LUT7
inline bool is_mux2_lut7(const BaseCtx *ctx, const CellInfo *cell) { return (cell->type.index == ID_MUX2_LUT7); }
// is MUX2_LUT8
inline bool is_mux2_lut8(const BaseCtx *ctx, const CellInfo *cell) { return (cell->type.index == ID_MUX2_LUT8); }
// Return true if a cell is a flipflop
inline bool is_ff(const BaseCtx *ctx, const CellInfo *cell)
{
switch (cell->type.index) {
case ID_DFF:
case ID_DFFE:
case ID_DFFS:
case ID_DFFSE:
case ID_DFFR:
case ID_DFFRE:
case ID_DFFP:
case ID_DFFPE:
case ID_DFFC:
case ID_DFFCE:
case ID_DFFN:
case ID_DFFNE:
case ID_DFFNS:
case ID_DFFNSE:
case ID_DFFNR:
case ID_DFFNRE:
case ID_DFFNP:
case ID_DFFNPE:
case ID_DFFNC:
case ID_DFFNCE:
return true;
default:
return false;
}
}
inline bool is_lc(const BaseCtx *ctx, const CellInfo *cell) { return cell->type == id_SLICE; }
inline bool is_sram(const BaseCtx *ctx, const CellInfo *cell) { return cell->type == id_RAM16SDP4; }
inline bool is_iob(const Context *ctx, const CellInfo *cell) { return (cell->type == id_IOB || cell->type == id_IOBS); }
// Convert a LUT primitive to (part of) an GENERIC_SLICE, swapping ports
// as needed. Set no_dff if a DFF is not being used, so that the output
// can be reconnected
void lut_to_lc(const Context *ctx, CellInfo *lut, CellInfo *lc, bool no_dff = true);
// Convert a DFF primitive to (part of) an GENERIC_SLICE, setting parameters
// and reconnecting signals as necessary. If pass_thru_lut is True, the LUT will
// be configured as pass through and D connected to I0, otherwise D will be
// ignored
void dff_to_lc(const Context *ctx, CellInfo *dff, CellInfo *lc, bool pass_thru_lut = false);
// Convert a Gowin IO buffer to a IOB bel
void gwio_to_iob(Context *ctx, CellInfo *nxio, CellInfo *sbio, pool<IdString> &todelete_cells);
// Reconnect PLL signals (B)
void reconnect_pllvr(Context *ctx, CellInfo *pll, CellInfo *new_pll);
void reconnect_rpll(Context *ctx, CellInfo *pll, CellInfo *new_pll);
// Convert RAM16 to write port
void sram_to_ramw_split(Context *ctx, CellInfo *ram, CellInfo *ramw);
// Convert RAM16 to slice
void sram_to_slice(Context *ctx, CellInfo *ram, CellInfo *slice, int index);
NEXTPNR_NAMESPACE_END
#endif

File diff suppressed because it is too large Load Diff

View File

@ -1,40 +0,0 @@
/*
* nextpnr -- Next Generation Place and Route
*
* Copyright (C) 2018 Claire Xenia Wolf <claire@yosyshq.com>
* Copyright (C) 2018 gatecat <gatecat@ds0.me>
*
* 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 "cst.h"
#include <regex>
#include <sstream>
#include "arch.h"
#include "log.h"
#include "util.h"
NEXTPNR_NAMESPACE_BEGIN
bool read_cst(Context *ctx, std::istream &in)
{
try {
ctx->read_cst(in);
return true;
} catch (log_execution_error_exception) {
return false;
}
}
NEXTPNR_NAMESPACE_END

View File

@ -1,34 +0,0 @@
/*
* nextpnr -- Next Generation Place and Route
*
* Copyright (C) 2018 Claire Xenia Wolf <claire@yosyshq.com>
* Copyright (C) 2018 gatecat <gatecat@ds0.me>
*
* 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 CST_H
#define CST_H
#include <iostream>
#include "nextpnr.h"
NEXTPNR_NAMESPACE_BEGIN
// Read the constraints file
bool read_cst(Context *ctx, std::istream &in);
NEXTPNR_NAMESPACE_END
#endif

View File

@ -1,53 +0,0 @@
add_subdirectory(${family})
message(STATUS "Using Gowin chipdb: ${GOWIN_CHIPDB}")
set(chipdb_sources)
set(chipdb_binaries)
file(MAKE_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/${family}/chipdb)
foreach(device ${GOWIN_DEVICES})
set(chipdb_bba ${GOWIN_CHIPDB}/chipdb-${device}.bba)
set(chipdb_bin ${family}/chipdb/chipdb-${device}.bin)
set(chipdb_cc ${family}/chipdb/chipdb-${device}.cc)
if(BBASM_MODE STREQUAL "binary")
add_custom_command(
OUTPUT ${chipdb_bin}
COMMAND bbasm ${BBASM_ENDIAN_FLAG} ${chipdb_bba} ${chipdb_bin}
DEPENDS bbasm chipdb-${family}-bbas ${chipdb_bba})
list(APPEND chipdb_binaries ${chipdb_bin})
elseif(BBASM_MODE STREQUAL "embed")
add_custom_command(
OUTPUT ${chipdb_cc} ${chipdb_bin}
COMMAND bbasm ${BBASM_ENDIAN_FLAG} --e ${chipdb_bba} ${chipdb_cc} ${chipdb_bin}
DEPENDS bbasm chipdb-${family}-bbas ${chipdb_bba})
list(APPEND chipdb_sources ${chipdb_cc})
list(APPEND chipdb_binaries ${chipdb_bin})
elseif(BBASM_MODE STREQUAL "string")
add_custom_command(
OUTPUT ${chipdb_cc}
COMMAND bbasm ${BBASM_ENDIAN_FLAG} --c ${chipdb_bba} ${chipdb_cc}
DEPENDS bbasm chipdb-${family}-bbas ${chipdb_bba})
list(APPEND chipdb_sources ${chipdb_cc})
endif()
endforeach()
if(WIN32)
set(chipdb_rc ${CMAKE_CURRENT_BINARY_DIR}/${family}/resource/chipdb.rc)
list(APPEND chipdb_sources ${chipdb_rc})
file(WRITE ${chipdb_rc})
foreach(device ${GOWIN_DEVICES})
file(APPEND ${chipdb_rc}
"${family}/chipdb-${device}.bin RCDATA \"${CMAKE_CURRENT_BINARY_DIR}/${family}/chipdb/chipdb-${device}.bin\"")
endforeach()
endif()
add_custom_target(chipdb-${family}-bins DEPENDS ${chipdb_sources} ${chipdb_binaries})
add_library(chipdb-${family} OBJECT ${GOWIN_CHIPDB} ${chipdb_sources})
add_dependencies(chipdb-${family} chipdb-${family}-bins)
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})
foreach(family_target ${family_targets})
target_sources(${family_target} PRIVATE $<TARGET_OBJECTS:chipdb-${family}>)
endforeach()

File diff suppressed because it is too large Load Diff

View File

@ -1,40 +0,0 @@
/*
* nextpnr -- Next Generation Place and Route
*
* Copyright (C) 2018 Claire Xenia Wolf <claire@yosyshq.com>
*
* 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 GFX_H
#define GFX_H
#include "nextpnr.h"
NEXTPNR_NAMESPACE_BEGIN
#ifndef NO_GUI
void gfxCreateBelDecals(Arch *arch);
void gfxSetBelDefaultDecal(Arch *arch, BelInfo &bel);
void gfxSetIOBWireDecals(Arch *arch, BelInfo &bel);
void gfxSetIOBSWireDecals(Arch *arch, BelInfo &bel);
void gfxSetPipDefaultDecal(Arch *arch, PipInfo &pip);
void gfxSetWireDefaultDecal(Arch *arch, WireInfo &wire);
DecalXY gfxGetLutGroupDecalXY(int x, int y, int z);
DecalXY gfxGetCruGroupDecalXY(int x, int y);
#endif
NEXTPNR_NAMESPACE_END
#endif // GFX_H

View File

@ -1,332 +0,0 @@
/*
* nextpnr -- Next Generation Place and Route
*
* Copyright (C) 2018 gatecat <gatecat@ds0.me>
* Copyright (C) 2022 YRabbit <rabbit@yrabbit.cyou>
*
* 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 <algorithm>
#include <iomanip>
#include <iostream>
#include <queue>
#include "cells.h"
#include "log.h"
#include "nextpnr.h"
#include "place_common.h"
#include "util.h"
NEXTPNR_NAMESPACE_BEGIN
bool GowinGlobalRouter::is_clock_port(PortRef const &user)
{
if ((user.cell->type.in(id_SLICE, id_ODDR, id_ODDRC)) && user.port == id_CLK) {
return true;
}
return false;
}
std::pair<WireId, BelId> GowinGlobalRouter::clock_src(Context *ctx, PortRef const &driver)
{
if (driver.cell == nullptr) {
return std::make_pair(WireId(), BelId());
}
BelInfo &bel = ctx->bel_info(driver.cell->bel);
WireId wire;
if (driver.cell->type == id_IOB) {
if (ctx->is_GCLKT_iob(driver.cell)) {
wire = bel.pins[id_O].wire;
return std::make_pair(wire, bel.name);
}
return std::make_pair(WireId(), BelId());
}
if (driver.cell->type == id_rPLL || driver.cell->type == id_PLLVR) {
if (driver.port == id_CLKOUT || driver.port == id_CLKOUTP || driver.port == id_CLKOUTD ||
driver.port == id_CLKOUTD3) {
wire = bel.pins[driver.port].wire;
return std::make_pair(wire, bel.name);
}
return std::make_pair(WireId(), BelId());
}
return std::make_pair(WireId(), BelId());
}
// gather the clock nets
void GowinGlobalRouter::gather_clock_nets(Context *ctx, std::vector<globalnet_t> &clock_nets)
{
for (auto const &net : ctx->nets) {
NetInfo const *ni = net.second.get();
auto new_clock = clock_nets.end();
auto clock_wire_bel = clock_src(ctx, ni->driver);
if (clock_wire_bel.first != WireId()) {
clock_nets.emplace_back(net.first);
new_clock = --clock_nets.end();
new_clock->clock_wire = clock_wire_bel.first;
new_clock->clock_bel = clock_wire_bel.second;
}
for (auto const &user : ni->users) {
if (is_clock_port(user)) {
if (new_clock == clock_nets.end()) {
clock_nets.emplace_back(net.first);
new_clock = --clock_nets.end();
}
++(new_clock->clock_ports);
}
}
}
// need to prioritize the nets
std::sort(clock_nets.begin(), clock_nets.end());
if (ctx->verbose) {
for (auto const &net : clock_nets) {
log_info(" Net:%s, ports:%d, clock source:%s\n", net.name.c_str(ctx), net.clock_ports,
net.clock_wire == WireId() ? "No" : net.clock_wire.c_str(ctx));
}
}
}
// non clock port
// returns GB pip
IdString GowinGlobalRouter::route_to_non_clock_port(Context *ctx, WireId const dstWire, int clock,
pool<IdString> &used_pips, pool<IdString> &undo_wires)
{
static std::vector<IdString> one_hop_0 = {id_W111, id_W121, id_E111, id_E121};
static std::vector<IdString> one_hop_4 = {id_S111, id_S121, id_N111, id_N121};
// uphill pips
for (auto const uphill : ctx->getPipsUphill(dstWire)) {
WireId srcWire = ctx->getPipSrcWire(uphill);
bool found;
if (clock < 4) {
found = find(one_hop_0.begin(), one_hop_0.end(), ctx->wire_info(ctx->getPipSrcWire(uphill)).type) !=
one_hop_0.end();
} else {
found = find(one_hop_4.begin(), one_hop_4.end(), ctx->wire_info(ctx->getPipSrcWire(uphill)).type) !=
one_hop_4.end();
}
if (found) {
// found one hop pip
if (used_wires.count(srcWire)) {
if (used_wires[srcWire] != clock) {
continue;
}
}
WireInfo wi = ctx->wire_info(srcWire);
std::string wire_alias = srcWire.str(ctx).substr(srcWire.str(ctx).rfind("_") + 1);
IdString gb = ctx->idf("R%dC%d_GB%d0_%s", wi.y + 1, wi.x + 1, clock, wire_alias.c_str());
if (ctx->verbose) {
log_info(" 1-hop gb:%s\n", gb.c_str(ctx));
}
// sanity
NPNR_ASSERT(find(ctx->getPipsUphill(srcWire).begin(), ctx->getPipsUphill(srcWire).end(), gb) !=
ctx->getPipsUphill(srcWire).end());
auto up_pips = ctx->getPipsUphill(srcWire);
if (find(up_pips.begin(), up_pips.end(), gb) != up_pips.end()) {
if (!used_wires.count(srcWire)) {
used_wires.insert(std::make_pair(srcWire, clock));
undo_wires.insert(srcWire);
}
used_pips.insert(uphill);
if (ctx->verbose) {
log_info(" 1-hop Pip:%s\n", uphill.c_str(ctx));
}
return gb;
}
}
}
return IdString();
}
// route one net
void GowinGlobalRouter::route_net(Context *ctx, globalnet_t const &net)
{
// For failed routing undo
pool<IdString> used_pips;
pool<IdString> undo_wires;
log_info(" Route net %s, use clock #%d.\n", net.name.c_str(ctx), net.clock);
for (auto const &user : ctx->net_info(net.name).users) {
// >>> port <- GB<clock>0
WireId dstWire = ctx->getNetinfoSinkWire(&ctx->net_info(net.name), user, 0);
if (ctx->verbose) {
log_info(" Cell:%s, port:%s, wire:%s\n", user.cell->name.c_str(ctx), user.port.c_str(ctx),
dstWire.c_str(ctx));
}
char buf[30];
PipId gb_pip_id;
if (user.port == id_CLK || user.port == id_CLKIN) {
WireInfo const wi = ctx->wire_info(dstWire);
gb_pip_id =
ctx->idf("R%dC%d_GB%d0_%s", wi.y + 1, wi.x + 1, net.clock, ctx->wire_info(dstWire).type.c_str(ctx));
// sanity
NPNR_ASSERT(find(ctx->getPipsUphill(dstWire).begin(), ctx->getPipsUphill(dstWire).end(), gb_pip_id) !=
ctx->getPipsUphill(dstWire).end());
} else {
// Non clock port
gb_pip_id = route_to_non_clock_port(ctx, dstWire, net.clock, used_pips, undo_wires);
if (gb_pip_id == IdString()) {
if (ctx->verbose) {
log_info(" Can't find route to %s, net %s will be routed in a standard way.\n", dstWire.c_str(ctx),
net.name.c_str(ctx));
}
for (IdString const undo : undo_wires) {
used_wires.erase(undo);
}
return;
}
}
if (ctx->verbose) {
log_info(" GB Pip:%s\n", gb_pip_id.c_str(ctx));
}
if (used_pips.count(gb_pip_id)) {
if (ctx->verbose) {
log_info(" ^routed already^\n");
}
continue;
}
used_pips.insert(gb_pip_id);
// >>> GBOx <- GTx0
dstWire = ctx->getPipSrcWire(gb_pip_id);
WireInfo dstWireInfo = ctx->wire_info(dstWire);
int branch_tap_idx = net.clock > 3 ? 1 : 0;
PipId gt_pip_id =
ctx->idf("R%dC%d_GT%d0_GBO%d", dstWireInfo.y + 1, dstWireInfo.x + 1, branch_tap_idx, branch_tap_idx);
if (ctx->verbose) {
log_info(" GT Pip:%s\n", gt_pip_id.c_str(ctx));
}
// sanity
NPNR_ASSERT(find(ctx->getPipsUphill(dstWire).begin(), ctx->getPipsUphill(dstWire).end(), gt_pip_id) !=
ctx->getPipsUphill(dstWire).end());
// if already routed
if (used_pips.count(gt_pip_id)) {
if (ctx->verbose) {
log_info(" ^routed already^\n");
}
continue;
}
used_pips.insert(gt_pip_id);
// >>> GTx0 <- SPINExx
// XXX no optimization here, we need to store
// the SPINE <-> clock# correspondence in the database. In the
// meantime, we define in run-time in a completely suboptimal way.
std::vector<std::string> clock_spine;
dstWire = ctx->getPipSrcWire(gt_pip_id);
for (auto const uphill_pip : ctx->getPipsUphill(dstWire)) {
std::string name = ctx->wire_info(ctx->getPipSrcWire(uphill_pip)).type.str(ctx);
if (name.rfind("SPINE", 0) == 0) {
clock_spine.push_back(name);
}
}
sort(clock_spine.begin(), clock_spine.end(), [](const std::string &a, const std::string &b) -> bool {
return (a.size() < b.size()) || (a.size() == b.size() && a < b);
});
dstWireInfo = ctx->wire_info(dstWire);
snprintf(buf, sizeof(buf), "R%dC%d_%s_GT%d0", dstWireInfo.y + 1, dstWireInfo.x + 1,
clock_spine[net.clock - branch_tap_idx * 4].c_str(), branch_tap_idx);
PipId spine_pip_id = ctx->id(buf);
if (ctx->verbose) {
log_info(" Spine Pip:%s\n", buf);
}
// sanity
NPNR_ASSERT(find(ctx->getPipsUphill(dstWire).begin(), ctx->getPipsUphill(dstWire).end(), spine_pip_id) !=
ctx->getPipsUphill(dstWire).end());
// if already routed
if (used_pips.count(spine_pip_id)) {
if (ctx->verbose) {
log_info(" ^routed already^\n");
}
continue;
}
used_pips.insert(spine_pip_id);
// >>> SPINExx <- Src
dstWire = ctx->getPipSrcWire(spine_pip_id);
dstWireInfo = ctx->wire_info(dstWire);
PipId src_pip_id = PipId();
for (auto const uphill_pip : ctx->getPipsUphill(dstWire)) {
if (ctx->getPipSrcWire(uphill_pip) == net.clock_wire) {
src_pip_id = uphill_pip;
break;
}
}
if (ctx->verbose) {
log_info(" Src Pip:%s\n", src_pip_id.c_str(ctx));
}
NPNR_ASSERT(src_pip_id != PipId());
// if already routed
if (used_pips.count(src_pip_id)) {
if (ctx->verbose) {
log_info(" ^routed already^\n");
}
continue;
}
used_pips.insert(src_pip_id);
}
log_info(" Net %s is routed.\n", net.name.c_str(ctx));
if (!ctx->net_info(net.name).users.empty()) {
for (auto const pip : used_pips) {
ctx->bindPip(pip, &ctx->net_info(net.name), STRENGTH_LOCKED);
}
ctx->bindWire(net.clock_wire, &ctx->net_info(net.name), STRENGTH_LOCKED);
}
}
void GowinGlobalRouter::route_globals(Context *ctx)
{
log_info("Routing globals...\n");
for (auto const &net : nets) {
route_net(ctx, net);
}
}
// Allocate networks that will be routed through the global system.
// Mark their driver cells as global buffers to exclude them from the analysis.
void GowinGlobalRouter::mark_globals(Context *ctx)
{
log_info("Find global nets...\n");
std::vector<globalnet_t> clock_nets;
gather_clock_nets(ctx, clock_nets);
// XXX we need to use the list of indexes of clocks from the database
// use 6 clocks (XXX 3 for GW1NZ-1)
int max_clock = ctx->max_clock, cur_clock = -1;
for (auto &net : clock_nets) {
// XXX only IO clock for now
if (net.clock_wire == WireId()) {
log_info(" Non clock source, skip %s.\n", net.name.c_str(ctx));
continue;
}
if (++cur_clock >= max_clock) {
log_info(" No more clock wires left, skip the remaining nets.\n");
break;
}
if (ctx->net_info(net.name).users.empty()) {
--cur_clock;
net.clock = -1;
} else {
net.clock = cur_clock;
}
BelInfo &bi = ctx->bel_info(net.clock_bel);
bi.gb = true;
nets.emplace_back(net);
}
}
NEXTPNR_NAMESPACE_END

View File

@ -1,91 +0,0 @@
/*
* nextpnr -- Next Generation Place and Route
*
* Copyright (C) 2018 gatecat <gatecat@ds0.me>
* Copyright (C) 2022 YRabbit <rabbit@yrabbit.cyou>
*
* 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 GOWIN_GLOBALS_H
#define GOWIN_GLOBALS_H
#include "nextpnr.h"
NEXTPNR_NAMESPACE_BEGIN
class GowinGlobalRouter
{
public:
GowinGlobalRouter() {}
private:
// wire -> clock#
dict<WireId, int> used_wires;
// ordered nets
struct globalnet_t
{
IdString name;
int clock_ports;
BelId clock_bel;
WireId clock_wire; // clock wire if there is one
int clock; // clock #
globalnet_t()
{
name = IdString();
clock_ports = 0;
clock_bel = BelId();
clock_wire = WireId();
clock = -1;
}
globalnet_t(IdString _name)
{
name = _name;
clock_ports = 0;
clock_bel = BelId();
clock_wire = WireId();
clock = -1;
}
// sort
bool operator<(const globalnet_t &other) const
{
if ((clock_wire != WireId()) ^ (other.clock_wire != WireId())) {
return !(clock_wire != WireId());
}
return clock_ports < other.clock_ports;
}
// search
bool operator==(const globalnet_t &other) const { return name == other.name; }
};
// discovered nets
std::vector<globalnet_t> nets;
bool is_clock_port(PortRef const &user);
std::pair<WireId, BelId> clock_src(Context *ctx, PortRef const &driver);
void gather_clock_nets(Context *ctx, std::vector<globalnet_t> &clock_nets);
IdString route_to_non_clock_port(Context *ctx, WireId const dstWire, int clock, pool<IdString> &used_pips,
pool<IdString> &undo_wires);
void route_net(Context *ctx, globalnet_t const &net);
public:
void mark_globals(Context *ctx);
void route_globals(Context *ctx);
};
NEXTPNR_NAMESPACE_END
#endif // GOWIN_GLOBALS_H

View File

@ -1,129 +0,0 @@
/*
* nextpnr -- Next Generation Place and Route
*
* Copyright (C) 2018 Claire Xenia Wolf <claire@yosyshq.com>
* Copyright (C) 2020 Pepijn de Vos <pepijn@symbioticeda.com>
*
* 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
#include <fstream>
#include <locale>
#include <regex>
#include "command.h"
#include "design_utils.h"
#include "log.h"
#include "timing.h"
USING_NEXTPNR_NAMESPACE
class GowinCommandHandler : public CommandHandler
{
public:
GowinCommandHandler(int argc, char **argv);
virtual ~GowinCommandHandler(){};
std::unique_ptr<Context> createContext(dict<std::string, Property> &values) override;
void setupArchContext(Context *ctx) override{};
void customAfterLoad(Context *ctx) override;
protected:
po::options_description getArchOptions() override;
};
GowinCommandHandler::GowinCommandHandler(int argc, char **argv) : CommandHandler(argc, argv) {}
po::options_description GowinCommandHandler::getArchOptions()
{
po::options_description specific("Architecture specific options");
specific.add_options()("device", po::value<std::string>(), "device name");
specific.add_options()("family", po::value<std::string>(), "family name");
specific.add_options()("cst", po::value<std::string>(), "physical constraints file");
specific.add_options()("enable-globals", "enable separate routing of the clocks");
specific.add_options()("disable-globals", "disable separate routing of the clocks");
specific.add_options()("enable-auto-longwires", "automatic detection and routing of long wires");
return specific;
}
std::unique_ptr<Context> GowinCommandHandler::createContext(dict<std::string, Property> &values)
{
if (!vm.count("device")) {
log_error("The device must be specified\n");
}
std::regex devicere = std::regex("GW1N([SZ]?)[A-Z]*-(LV|UV|UX)([0-9])(C?).*");
std::smatch match;
std::string device = vm["device"].as<std::string>();
bool GW2 = device == "GW2A-LV18PG256C8/I7";
if (!GW2 && !std::regex_match(device, match, devicere)) {
log_error("Invalid device %s\n", device.c_str());
}
ArchArgs chipArgs;
chipArgs.gui = vm.count("gui") != 0;
if (vm.count("family")) {
chipArgs.family = vm["family"].as<std::string>();
} else {
if (!GW2) {
char buf[36];
// GW1N and GW1NR variants share the same database.
// Most Gowin devices are a System in Package with some SDRAM wirebonded to a GPIO bank.
// However, it appears that the S series with embedded ARM core are unique silicon.
snprintf(buf, 36, "GW1N%s-%s", match[1].str().c_str(), match[3].str().c_str());
chipArgs.family = buf;
} else {
chipArgs.family = "GW2A-18";
}
}
if (!GW2) {
chipArgs.partnumber = match[0];
} else {
chipArgs.partnumber = device;
}
auto ctx = std::unique_ptr<Context>(new Context(chipArgs));
// routing options
ctx->settings[ctx->id("arch.enable-globals")] = 1;
ctx->settings[ctx->id("arch.enable-auto-longwires")] = 0;
if (vm.count("disable-globals")) {
ctx->settings[ctx->id("arch.enable-globals")] = 0;
}
if (vm.count("enable-auto-longwires")) {
ctx->settings[ctx->id("arch.enable-auto-longwires")] = 1;
}
// XXX disable clock lines for now
if (GW2) {
ctx->settings[ctx->id("arch.enable-globals")] = 0;
}
return ctx;
}
void GowinCommandHandler::customAfterLoad(Context *ctx)
{
if (vm.count("cst")) {
std::string filename = vm["cst"].as<std::string>();
std::ifstream in(filename);
if (!in)
log_error("Failed to open input CST file %s.\n", filename.c_str());
ctx->read_cst(in);
}
}
int main(int argc, char *argv[])
{
GowinCommandHandler handler(argc, argv);
return handler.exec();
}
#endif

File diff suppressed because it is too large Load Diff

View File

View File

@ -1,103 +0,0 @@
/*
* nextpnr -- Next Generation Place and Route
*
* Copyright (C) 2018 Miodrag Milanovic <micko@yosyshq.com>
*
* 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 "mainwindow.h"
#include <QFileDialog>
#include <QMessageBox>
#include <cstdlib>
#include "cst.h"
static void initMainResource() { Q_INIT_RESOURCE(nextpnr); }
NEXTPNR_NAMESPACE_BEGIN
MainWindow::MainWindow(std::unique_ptr<Context> context, CommandHandler *handler, QWidget *parent)
: BaseMainWindow(std::move(context), handler, parent)
{
initMainResource();
std::string title = "nextpnr-gowin - [EMPTY]";
setWindowTitle(title.c_str());
connect(this, &BaseMainWindow::contextChanged, this, &MainWindow::newContext);
createMenu();
}
MainWindow::~MainWindow() {}
void MainWindow::newContext(Context *ctx)
{
std::string title = "nextpnr-gowin - " + ctx->getChipName();
setWindowTitle(title.c_str());
}
void MainWindow::load_cst(std::string filename)
{
disableActions();
std::ifstream f(filename);
if (read_cst(ctx.get(), f)) {
log("Loading CST successful.\n");
actionPack->setEnabled(true);
} else {
actionLoadCST->setEnabled(true);
log("Loading CST failed.\n");
}
}
void MainWindow::createMenu()
{
actionLoadCST = new QAction("Open CST", this);
actionLoadCST->setIcon(QIcon(":/icons/resources/open_cst.png"));
actionLoadCST->setStatusTip("Open CST file");
actionLoadCST->setEnabled(false);
connect(actionLoadCST, &QAction::triggered, this, &MainWindow::open_cst);
// Add actions in menus
mainActionBar->addSeparator();
mainActionBar->addAction(actionLoadCST);
menuDesign->addSeparator();
menuDesign->addAction(actionLoadCST);
}
void MainWindow::new_proj() {}
void MainWindow::open_cst()
{
QString fileName = QFileDialog::getOpenFileName(this, QString("Open CST"), QString(), QString("*.cst"));
if (!fileName.isEmpty()) {
load_cst(fileName.toStdString());
}
}
void MainWindow::onDisableActions() { actionLoadCST->setEnabled(false); }
void MainWindow::onUpdateActions()
{
if (ctx->settings.find(ctx->id("synth")) != ctx->settings.end()) {
actionLoadCST->setEnabled(true);
}
if (ctx->settings.find(ctx->id("cst")) != ctx->settings.end()) {
actionLoadCST->setEnabled(false);
}
if (ctx->settings.find(ctx->id("pack")) != ctx->settings.end()) {
actionLoadCST->setEnabled(false);
}
}
NEXTPNR_NAMESPACE_END

View File

@ -1,57 +0,0 @@
/*
* nextpnr -- Next Generation Place and Route
*
* Copyright (C) 2018 Miodrag Milanovic <micko@yosyshq.com>
*
* 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 MAINWINDOW_H
#define MAINWINDOW_H
#include "../basewindow.h"
NEXTPNR_NAMESPACE_BEGIN
class MainWindow : public BaseMainWindow
{
Q_OBJECT
public:
explicit MainWindow(std::unique_ptr<Context> context, CommandHandler *handler, QWidget *parent = 0);
virtual ~MainWindow();
public:
void createMenu();
protected:
void onDisableActions() override;
void onUpdateActions() override;
void load_cst(std::string filename);
protected Q_SLOTS:
void new_proj() override;
void open_cst();
void newContext(Context *ctx);
private:
QAction *actionLoadCST;
};
NEXTPNR_NAMESPACE_END
#endif // MAINWINDOW_H

View File

@ -1,5 +0,0 @@
<RCC>
<qresource prefix="/icons">
<file>resources/open_cst.png</file>
</qresource>
</RCC>

Binary file not shown.

Before

Width:  |  Height:  |  Size: 9.2 KiB