aboutsummaryrefslogtreecommitdiffstats
path: root/gowin/arch.cc
diff options
context:
space:
mode:
Diffstat (limited to 'gowin/arch.cc')
-rw-r--r--gowin/arch.cc232
1 files changed, 223 insertions, 9 deletions
diff --git a/gowin/arch.cc b/gowin/arch.cc
index 8c654b2e..c55d4a71 100644
--- a/gowin/arch.cc
+++ b/gowin/arch.cc
@@ -23,6 +23,7 @@
#include <math.h>
#include <regex>
#include "embed.h"
+#include "gfx.h"
#include "nextpnr.h"
#include "placer1.h"
#include "placer_heap.h"
@@ -32,6 +33,148 @@
NEXTPNR_NAMESPACE_BEGIN
+// GUI
+void Arch::fixClockSpineDecals(void)
+{
+ for (auto sp : clockSpinesCache) {
+ // row: (#of spine cells, wire_id)
+ dict<int, std::pair<int, IdString>> rows;
+ IdString min_x, max_x;
+ min_x = max_x = *sp.second.begin();
+ for (auto wire : sp.second) {
+ WireInfo &wi = wire_info(wire);
+ std::pair<int, IdString> &row = rows[wi.y];
+ ++row.first;
+ row.second = wire;
+ if (wi.x < wire_info(min_x).x) {
+ min_x = wire;
+ } else {
+ if (wi.x > wire_info(max_x).x) {
+ max_x = wire;
+ }
+ }
+ }
+ // central mux row owns the global decal
+ int mux_row = -1;
+ for (auto row : rows) {
+ if (row.second.first == 1) {
+ mux_row = row.first;
+ break;
+ }
+ }
+ // if there is no separate central mux than all decals are the same
+ if (mux_row == -1) {
+ mux_row = rows.begin()->first;
+ WireInfo &wi = wire_info(rows.at(mux_row).second);
+ GraphicElement &el_active = decal_graphics.at(wi.decalxy_active.decal).at(0);
+ GraphicElement &el_inactive = decal_graphics.at(wi.decalxy_inactive.decal).at(0);
+ el_active.y1 -= wi.y;
+ el_active.y2 -= wi.y;
+ el_inactive.y1 -= wi.y;
+ el_inactive.y2 -= wi.y;
+ el_active.x1 += wire_info(min_x).x;
+ el_active.x2 += wire_info(max_x).x;
+ el_inactive.x1 += wire_info(min_x).x;
+ el_inactive.x2 += wire_info(max_x).x;
+ } else {
+ // change the global decal
+ WireInfo &wi = wire_info(rows.at(mux_row).second);
+ // clear spine decals
+ float y = 0.;
+ for (auto wire : sp.second) {
+ if (wire == wi.name) {
+ continue;
+ }
+ wire_info(wire).decalxy_active = DecalXY();
+ wire_info(wire).decalxy_inactive = DecalXY();
+ y = wire_info(wire).y;
+ }
+ GraphicElement &el_active = decal_graphics.at(wi.decalxy_active.decal).at(0);
+ GraphicElement &el_inactive = decal_graphics.at(wi.decalxy_inactive.decal).at(0);
+ el_active.y1 -= y;
+ el_active.y2 -= y;
+ el_inactive.y1 -= y;
+ el_inactive.y2 -= y;
+ el_active.x1 += wire_info(min_x).x;
+ el_active.x2 += wire_info(max_x).x;
+ el_inactive.x1 += wire_info(min_x).x;
+ el_inactive.x2 += wire_info(max_x).x;
+ }
+ refreshUi();
+ }
+}
+
+void Arch::updateClockSpinesCache(IdString spine_id, IdString wire_id)
+{
+ std::vector<IdString> &sp = clockSpinesCache[spine_id];
+ if (std::find(sp.begin(), sp.end(), wire_id) == sp.end()) {
+ sp.push_back(wire_id);
+ }
+}
+
+DecalXY Arch::getBelDecal(BelId bel) const
+{
+ CellInfo *ci = getBoundBelCell(bel);
+ if (ci == nullptr) {
+ return bels.at(bel).decalxy_inactive;
+ } else {
+ // LUT + used/unused DFF
+ if (bels.at(bel).type == id_SLICE) {
+ DecalXY decalxy = bels.at(bel).decalxy_active;
+ if (!ci->params.at(id_FF_USED).as_bool()) {
+ decalxy.decal = id_DECAL_LUT_UNUSED_DFF_ACTIVE;
+ if (ci->params.count(id_ALU_MODE) != 0) {
+ decalxy.decal = id_DECAL_ALU_ACTIVE;
+ }
+ }
+ return decalxy;
+ }
+ }
+ return bels.at(bel).decalxy_active;
+}
+
+DecalXY Arch::getGroupDecal(GroupId grp) const { return groups.at(grp).decalxy; }
+
+DecalXY Arch::getPipDecal(PipId pip) const
+{
+ if (getBoundPipNet(pip) == nullptr) {
+ return pips.at(pip).decalxy_inactive;
+ }
+ return pips.at(pip).decalxy_active;
+}
+
+DecalXY Arch::getWireDecal(WireId wire) const
+{
+ static std::vector<IdString> clk_wires = {id_GB00, id_GB10, id_GB20, id_GB30, id_GB40, id_GB50, id_GB60, id_GB70};
+ static std::vector<IdString> pip_dst = {id_CLK0, id_CLK1, id_CLK2, id_EW10, id_EW20, id_SN10, id_SN20};
+ if (getBoundWireNet(wire) == nullptr) {
+ if (std::find(clk_wires.begin(), clk_wires.end(), wires.at(wire).type) != clk_wires.end()) {
+ for (auto dst : pip_dst) {
+ // check if pip is used
+ char pip_name[20];
+ snprintf(pip_name, sizeof(pip_name), "%s_%s", wire.c_str(this), dst.c_str(this));
+ if (pips.count(id(pip_name)) != 0) {
+ if (getBoundPipNet(id(pip_name)) != nullptr) {
+ return wires.at(wire).decalxy_active;
+ }
+ }
+ }
+ } else {
+ // spines
+ if (clockSpinesCache.count(wires.at(wire).type) != 0) {
+ std::vector<IdString> const &sp = clockSpinesCache.at(wires.at(wire).type);
+ for (auto w : sp) {
+ if (getBoundWireNet(w) != nullptr) {
+ return wires.at(wire).decalxy_active;
+ }
+ }
+ }
+ }
+ return wires.at(wire).decalxy_inactive;
+ }
+ return wires.at(wire).decalxy_active;
+}
+
WireInfo &Arch::wire_info(IdString wire)
{
auto w = wires.find(wire);
@@ -58,7 +201,6 @@ BelInfo &Arch::bel_info(IdString bel)
void Arch::addWire(IdString name, IdString type, int x, int y)
{
- // std::cout << name.str(this) << std::endl;
NPNR_ASSERT(wires.count(name) == 0);
WireInfo &wi = wires[name];
wi.name = name;
@@ -105,6 +247,13 @@ void Arch::addPip(IdString name, IdString type, IdString srcWire, IdString dstWi
tilePipDimZ[loc.x][loc.y] = std::max(tilePipDimZ[loc.x][loc.y], loc.z + 1);
}
+void Arch::addGroup(IdString name)
+{
+ NPNR_ASSERT(groups.count(name) == 0);
+ GroupInfo &gi = groups[name];
+ gi.name = name;
+}
+
void Arch::addBel(IdString name, IdString type, Loc loc, bool gb)
{
NPNR_ASSERT(bels.count(name) == 0);
@@ -189,24 +338,41 @@ void Arch::addDecalGraphic(DecalId decal, const GraphicElement &graphic)
refreshUi();
}
-void Arch::setWireDecal(WireId wire, DecalXY decalxy)
+void Arch::setWireDecal(WireId wire, DecalXY active, DecalXY inactive)
{
- wire_info(wire).decalxy = decalxy;
+ wire_info(wire).decalxy_active = active;
+ wire_info(wire).decalxy_inactive = inactive;
refreshUiWire(wire);
}
-void Arch::setPipDecal(PipId pip, DecalXY decalxy)
+void Arch::setPipDecal(PipId pip, DecalXY active, DecalXY inactive)
{
- pip_info(pip).decalxy = decalxy;
+ pip_info(pip).decalxy_active = active;
+ pip_info(pip).decalxy_inactive = inactive;
refreshUiPip(pip);
}
-void Arch::setBelDecal(BelId bel, DecalXY decalxy)
+void Arch::setBelDecal(BelId bel, DecalXY active, DecalXY inactive)
{
- bel_info(bel).decalxy = decalxy;
+ bel_info(bel).decalxy_active = active;
+ bel_info(bel).decalxy_inactive = inactive;
refreshUiBel(bel);
}
+void Arch::setDefaultDecals(void)
+{
+ for (BelId bel : getBels()) {
+ gfxSetBelDefaultDecal(this, bel_info(bel));
+ }
+ for (PipId pip : getPips()) {
+ gfxSetPipDefaultDecal(this, pip_info(pip));
+ }
+ for (WireId wire : getWires()) {
+ gfxSetWireDefaultDecal(this, wire_info(wire));
+ }
+ fixClockSpineDecals();
+}
+
void Arch::setGroupDecal(GroupId group, DecalXY decalxy)
{
groups[group].decalxy = decalxy;
@@ -519,6 +685,7 @@ void Arch::read_cst(std::istream &in)
insloc
} cst_type;
+ settings.erase(id("cst"));
while (!in.eof()) {
std::getline(in, line);
cst_type = ioloc;
@@ -584,6 +751,7 @@ void Arch::read_cst(std::istream &in)
}
}
}
+ settings[id("cst")] = 1;
}
// Add all MUXes for the cell
@@ -689,6 +857,14 @@ Arch::Arch(ArchArgs args) : args(args)
IdString::initialize_add(this, db->id_strs[i].get(), uint32_t(i) + db->num_constids);
}
+ // Empty decal
+ addDecalGraphic(IdString(), GraphicElement());
+
+ if (args.gui) {
+ // decals
+ gfxCreateBelDecals(this);
+ }
+
// setup package
IdString package_name;
IdString device_id;
@@ -762,9 +938,17 @@ Arch::Arch(ArchArgs args) : args(args)
// The reverse order of the enumeration simplifies the creation
// of MUX2_LUT8s: they need the existence of the wire on the right.
for (int i = db->rows * db->cols - 1; i >= 0; --i) {
+ IdString grpname;
int row = i / db->cols;
int col = i % db->cols;
const TilePOD *tile = db->grid[i].get();
+ if (args.gui) {
+ // CRU decal
+ snprintf(buf, 32, "R%dC%d_CRU", row + 1, col + 1);
+ grpname = id(buf);
+ addGroup(grpname);
+ setGroupDecal(grpname, gfxGetCruGroupDecalXY(col, row));
+ }
// setup wires
const PairPOD *pips[2] = {tile->pips.get(), tile->clock_pips.get()};
unsigned int num_pips[2] = {tile->num_pips, tile->num_clock_pips};
@@ -837,6 +1021,14 @@ Arch::Arch(ArchArgs args) : args(args)
if (z == 0) {
addMuxBels(db, row, col);
}
+ if (z % 2 == 0) {
+ snprintf(buf, 32, "R%dC%d_LUT_GRP%d", row + 1, col + 1, z);
+ grpname = id(buf);
+ if (args.gui) {
+ addGroup(grpname);
+ setGroupDecal(grpname, gfxGetLutGroupDecalXY(col, row, z >> 1));
+ }
+ }
break;
case ID_IOBJ:
z++; /* fall-through*/
@@ -933,7 +1125,6 @@ Arch::Arch(ArchArgs args) : args(args)
DelayQuad delay = getWireTypeDelay(destid);
// local alias
auto local_alias = pairLookup(tile->aliases.get(), tile->num_aliases, srcid.index);
- // std::cout << "srcid " << srcid.str(this) << std::endl;
if (local_alias != nullptr) {
srcid = IdString(local_alias->src_id);
gsrcname = wireToGlobal(srcrow, srccol, db, srcid);
@@ -950,12 +1141,14 @@ Arch::Arch(ArchArgs args) : args(args)
srcrow = alias_src->src_row;
srcid = IdString(alias_src->src_id);
gsrcname = wireToGlobal(srcrow, srccol, db, srcid);
- // std::cout << buf << std::endl;
}
addPip(pipname, destid, gsrcname, gdestname, delay, Loc(col, row, j));
}
}
}
+ if (args.gui) {
+ setDefaultDecals();
+ }
// Permissible combinations of modes in a single slice
dff_comp_mode[id_DFF] = id_DFF;
@@ -1015,6 +1208,17 @@ BelId Arch::getBelByLocation(Loc loc) const
const std::vector<BelId> &Arch::getBelsByTile(int x, int y) const { return bels_by_tile.at(x).at(y); }
+bool Arch::haveBelType(int x, int y, IdString bel_type)
+{
+ for (auto bel : getBelsByTile(x, y)) {
+ BelInfo bi = bel_info(bel);
+ if (bi.type == bel_type) {
+ return true;
+ }
+ }
+ return false;
+}
+
bool Arch::getBelGlobalBuf(BelId bel) const { return bels.at(bel).gb; }
void Arch::bindBel(BelId bel, CellInfo *cell, PlaceStrength strength)
@@ -1304,6 +1508,16 @@ bool Arch::route()
}
// ---------------------------------------------------------------
+std::vector<GraphicElement> Arch::getDecalGraphics(DecalId decal) const
+{
+ if (!decal_graphics.count(decal)) {
+ // XXX
+ return std::vector<GraphicElement>();
+ }
+ return decal_graphics.at(decal);
+}
+
+// ---------------------------------------------------------------
bool Arch::getCellDelay(const CellInfo *cell, IdString fromPort, IdString toPort, DelayQuad &delay) const
{