aboutsummaryrefslogtreecommitdiffstats
path: root/gowin/arch.cc
diff options
context:
space:
mode:
Diffstat (limited to 'gowin/arch.cc')
-rw-r--r--gowin/arch.cc108
1 files changed, 100 insertions, 8 deletions
diff --git a/gowin/arch.cc b/gowin/arch.cc
index 022c93c3..2d637695 100644
--- a/gowin/arch.cc
+++ b/gowin/arch.cc
@@ -583,6 +583,87 @@ void Arch::read_cst(std::istream &in)
}
}
+// Add all MUXes for the cell
+void Arch::addMuxBels(const DatabasePOD *db, int row, int col)
+{
+ IdString belname, bel_id;
+ char buf[40];
+ int z;
+ // XXX do real delay
+ DelayQuad delay = DelayQuad(0);
+ // make all wide luts with these parameters
+ struct
+ {
+ char type; // MUX type 5,6,7,8
+ char bel_idx; // just bel name suffix
+ char in_prefix[2]; // input from F or OF
+ char in_idx[2]; // input from bel with idx
+ } const mux_names[] = {{'5', '0', "", {'0', '1'}}, {'6', '0', "O", {'2', '0'}}, {'5', '1', "", {'2', '3'}},
+ {'7', '0', "O", {'5', '1'}}, {'5', '2', "", {'4', '5'}}, {'6', '1', "O", {'6', '4'}},
+ {'5', '3', "", {'6', '7'}}, {'8', '0', "O", {'3', '3'}}};
+
+ // 4 MUX2_LUT5, 2 MUX2_LUT6, 1 MUX2_LUT7, 1 MUX2_LUT8
+ for (int j = 0; j < 8; ++j) {
+ z = j + mux_0_z;
+
+ int grow = row + 1;
+ int gcol = col + 1;
+
+ // no MUX2_LUT8 in the last column
+ if (j == 7 && col == getGridDimX() - 1) {
+ continue;
+ }
+
+ // bel
+ snprintf(buf, 40, "R%dC%d_MUX2_LUT%c%c", grow, gcol, mux_names[j].type, mux_names[j].bel_idx);
+ belname = id(buf);
+ snprintf(buf, 40, "GW_MUX2_LUT%c", mux_names[j].type);
+ bel_id = id(buf);
+ addBel(belname, bel_id, Loc(col, row, z), false);
+
+ // dummy wires
+ snprintf(buf, 40, "I0MUX%d", j);
+ IdString id_wire_i0 = id(buf);
+ IdString wire_i0_name = wireToGlobal(row, col, db, id_wire_i0);
+ addWire(wire_i0_name, id_wire_i0, col, row);
+
+ snprintf(buf, 40, "I1MUX%d", j);
+ IdString id_wire_i1 = id(buf);
+ IdString wire_i1_name = wireToGlobal(row, col, db, id_wire_i1);
+ addWire(wire_i1_name, id_wire_i1, col, row);
+
+ // dummy left pip
+ snprintf(buf, 40, "%sF%c", mux_names[j].in_prefix, mux_names[j].in_idx[0]);
+ IdString id_src_F = id(buf);
+ // LUT8's I0 is wired to the right cell
+ IdString src_F;
+ int src_col = col;
+ if (j == 7) {
+ ++src_col;
+ }
+ src_F = wireToGlobal(row, src_col, db, id_src_F);
+ snprintf(buf, 40, "R%dC%d_%s__%s", grow, gcol, id_src_F.c_str(this), id_wire_i0.c_str(this));
+ addPip(id(buf), id_wire_i0, src_F, wire_i0_name, delay, Loc(col, row, 0));
+
+ // dummy right pip
+ snprintf(buf, 40, "%sF%c", mux_names[j].in_prefix, mux_names[j].in_idx[1]);
+ id_src_F = id(buf);
+ src_F = wireToGlobal(row, col, db, id_src_F);
+ snprintf(buf, 40, "R%dC%d_%s__%s", grow, gcol, id_src_F.c_str(this), id_wire_i1.c_str(this));
+ addPip(id(buf), id_wire_i1, src_F, wire_i1_name, delay, Loc(col, row, 0));
+
+ // the MUX ports
+ snprintf(buf, 40, "R%dC%d_OF%d", grow, gcol, j);
+ addBelOutput(belname, id_OF, id(buf));
+ snprintf(buf, 40, "R%dC%d_SEL%d", grow, gcol, j);
+ addBelInput(belname, id_SEL, id(buf));
+ snprintf(buf, 40, "R%dC%d_I0MUX%d", grow, gcol, j);
+ addBelInput(belname, id_I0, id(buf));
+ snprintf(buf, 40, "R%dC%d_I1MUX%d", grow, gcol, j);
+ addBelInput(belname, id_I1, id(buf));
+ }
+}
+
Arch::Arch(ArchArgs args) : args(args)
{
family = args.family;
@@ -645,7 +726,9 @@ Arch::Arch(ArchArgs args) : args(args)
}
// setup db
char buf[32];
- for (int i = 0; i < db->rows * db->cols; i++) {
+ // 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) {
int row = i / db->cols;
int col = i % db->cols;
const TilePOD *tile = db->grid[i].get();
@@ -718,6 +801,9 @@ Arch::Arch(ArchArgs args) : args(args)
snprintf(buf, 32, "R%dC%d_Q%d", row + 1, col + 1, z);
addBelOutput(belname, id_Q, id(buf));
}
+ if (z == 0) {
+ addMuxBels(db, row, col);
+ }
break;
case ID_IOBJ:
z++; /* fall-through*/
@@ -1094,6 +1180,7 @@ ArcBounds Arch::getRouteBoundingBox(WireId src, WireId dst) const
bool Arch::place()
{
std::string placer = str_or_default(settings, id("placer"), defaultPlacer);
+ bool retVal;
if (placer == "heap") {
bool have_iobuf_or_constr = false;
for (auto &cell : cells) {
@@ -1103,7 +1190,6 @@ bool Arch::place()
break;
}
}
- bool retVal;
if (!have_iobuf_or_constr) {
log_warning("Unable to use HeAP due to a lack of IO buffers or constrained cells as anchors; reverting to "
"SA.\n");
@@ -1116,15 +1202,21 @@ bool Arch::place()
}
getCtx()->settings[getCtx()->id("place")] = 1;
archInfoToAttributes();
- return retVal;
} else if (placer == "sa") {
- bool retVal = placer1(getCtx(), Placer1Cfg(getCtx()));
+ retVal = placer1(getCtx(), Placer1Cfg(getCtx()));
getCtx()->settings[getCtx()->id("place")] = 1;
archInfoToAttributes();
return retVal;
} else {
log_error("Gowin architecture does not support placer '%s'\n", placer.c_str());
}
+ // debug placement
+ if (getCtx()->debug) {
+ for (auto &cell : getCtx()->cells) {
+ log_info("Placed: %s -> %s\n", cell.first.c_str(getCtx()), getCtx()->nameOfBel(cell.second->bel));
+ }
+ }
+ return retVal;
}
bool Arch::route()
@@ -1183,13 +1275,15 @@ TimingClockingInfo Arch::getPortClockingInfo(const CellInfo *cell, IdString port
bool Arch::isBelLocationValid(BelId bel) const
{
- std::vector<const CellInfo *> cells;
Loc loc = getBelLocation(bel);
+
+ std::vector<const CellInfo *> cells;
for (auto tbel : getBelsByTile(loc.x, loc.y)) {
CellInfo *bound = getBoundBelCell(tbel);
if (bound != nullptr)
cells.push_back(bound);
}
+
return cellsCompatible(cells.data(), int(cells.size()));
}
@@ -1213,6 +1307,7 @@ void Arch::assignArchInfo()
for (auto &cell : getCtx()->cells) {
IdString cname = cell.first;
CellInfo *ci = cell.second.get();
+ ci->is_slice = false;
if (ci->type == id("SLICE")) {
ci->is_slice = true;
ci->ff_used = ci->params.at(id_FF_USED).as_bool();
@@ -1238,9 +1333,6 @@ void Arch::assignArchInfo()
DelayQuad delay = delayLookup(speed->lut.timings.get(), speed->lut.num_timings, port_delay[i]);
addCellTimingDelay(cname, ports[i], id_F, delay);
}
-
- } else {
- ci->is_slice = false;
}
}
}