diff --git a/himbaechel/uarch/gowin/constids.inc b/himbaechel/uarch/gowin/constids.inc index 70f0d989..f357783c 100644 --- a/himbaechel/uarch/gowin/constids.inc +++ b/himbaechel/uarch/gowin/constids.inc @@ -934,6 +934,9 @@ X(GSR) X(GSR0) X(GSRI) +// inverter +X(INV) + // Oscillators X(OSC) X(OSCZ) diff --git a/himbaechel/uarch/gowin/globals.cc b/himbaechel/uarch/gowin/globals.cc index c818f762..0489a9e0 100644 --- a/himbaechel/uarch/gowin/globals.cc +++ b/himbaechel/uarch/gowin/globals.cc @@ -40,6 +40,8 @@ struct GowinGlobalRouter GowinGlobalRouter(Context *ctx) : ctx(ctx) { gwu.init(ctx); }; + bool checkPipAvail(PipId pip) const { return gwu.is_global_pip(pip) || ctx->checkPipAvail(pip); }; + // allow io->global, global->global and global->tile clock bool global_pip_filter(PipId pip) const { @@ -91,7 +93,7 @@ struct GowinGlobalRouter // Search uphill pips for (PipId pip : ctx->getPipsUphill(cursor)) { // Skip pip if unavailable, and not because it's already used for this net - if (!ctx->checkPipAvail(pip) && ctx->getBoundPipNet(pip) != net) { + if (!checkPipAvail(pip) && ctx->getBoundPipNet(pip) != net) { continue; } WireId prev = ctx->getPipSrcWire(pip); diff --git a/himbaechel/uarch/gowin/gowin.cc b/himbaechel/uarch/gowin/gowin.cc index 920d86fa..cae8f1ab 100644 --- a/himbaechel/uarch/gowin/gowin.cc +++ b/himbaechel/uarch/gowin/gowin.cc @@ -38,6 +38,9 @@ struct GowinImpl : HimbaechelAPI bool isValidBelForCellType(IdString cell_type, BelId bel) const override; + // wires + bool checkPipAvail(PipId pip) const override; + private: HimbaechelHelpers h; GowinUtils gwu; @@ -154,6 +157,9 @@ void GowinImpl::init(Context *ctx) } } +// We do not allow the use of global wires that bypass a special router. +bool GowinImpl::checkPipAvail(PipId pip) const { return !gwu.is_global_pip(pip); } + void GowinImpl::pack() { if (ctx->settings.count(ctx->id("cst.filename"))) { diff --git a/himbaechel/uarch/gowin/gowin_utils.h b/himbaechel/uarch/gowin/gowin_utils.h index 5d2c6571..d93c6029 100644 --- a/himbaechel/uarch/gowin/gowin_utils.h +++ b/himbaechel/uarch/gowin/gowin_utils.h @@ -38,6 +38,21 @@ struct GowinUtils // wires inline bool is_wire_type_default(IdString wire_type) { return wire_type == IdString(); } + // If wire is an important part of the global network (like SPINExx) + inline bool is_global_wire(WireId wire) const + { + return ctx->getWireName(wire)[1].in( + id_SPINE0, id_SPINE1, id_SPINE2, id_SPINE3, id_SPINE4, id_SPINE5, id_SPINE6, id_SPINE7, id_SPINE8, + id_SPINE9, id_SPINE10, id_SPINE11, id_SPINE12, id_SPINE13, id_SPINE14, id_SPINE15, id_SPINE16, + id_SPINE17, id_SPINE18, id_SPINE19, id_SPINE20, id_SPINE21, id_SPINE22, id_SPINE23, id_SPINE24, + id_SPINE25, id_SPINE26, id_SPINE27, id_SPINE28, id_SPINE29, id_SPINE30, id_SPINE31); + } + + // pips + inline bool is_global_pip(PipId pip) const + { + return is_global_wire(ctx->getPipSrcWire(pip)) || is_global_wire(ctx->getPipDstWire(pip)); + } // chip dependent bool have_SP32(void); diff --git a/himbaechel/uarch/gowin/pack.cc b/himbaechel/uarch/gowin/pack.cc index 5b0cc183..5a2867de 100644 --- a/himbaechel/uarch/gowin/pack.cc +++ b/himbaechel/uarch/gowin/pack.cc @@ -1294,6 +1294,24 @@ struct GowinPacker } } + // If the memory is controlled by the CE, then it is logical for the OCE to + // also respond to this signal, unless the OCE is controlled separately. + void bsram_handle_sp_oce(CellInfo *ci, IdString ce_pin, IdString oce_pin) + { + const NetInfo *net = ci->getPort(oce_pin); + NPNR_ASSERT(ci->getPort(ce_pin) != nullptr); + if (net == nullptr || net->name == ctx->id("$PACKER_VCC") || net->name == ctx->id("$PACKER_GND")) { + if (net != nullptr) { + ci->disconnectPort(oce_pin); + } + ci->copyPortTo(ce_pin, ci, oce_pin); + } + if (ctx->verbose) { + log_info("%s: %s = %s = %s\n", ctx->nameOf(ci), ce_pin.c_str(ctx), oce_pin.c_str(ctx), + ctx->nameOf(ci->getPort(oce_pin))); + } + } + void pack_ROM(CellInfo *ci) { int default_bw = 32; @@ -1512,6 +1530,8 @@ struct GowinPacker } int bit_width = ci->params.at(id_BIT_WIDTH).as_int64(); + bsram_handle_sp_oce(ci, id_CE, id_OCE); + // XXX UG285-1.3.6_E Gowin BSRAM & SSRAM User Guide: // For GW1N-9/GW1NR-9/GW1NS-4 series, 32/36-bit SP/SPX9 is divided into two // SP/SPX9s, which occupy two BSRAMs. @@ -1623,6 +1643,25 @@ struct GowinPacker } } + // =================================== + // Replace INV with LUT + // =================================== + void pack_inv(void) + { + log_info("Pack INV..\n"); + + for (auto &cell : ctx->cells) { + auto &ci = *cell.second; + + if (ci.type == id_INV) { + ci.type = id_LUT4; + ci.renamePort(id_O, id_F); + ci.renamePort(id_I, id_I3); // use D - it's simple for INIT + ci.params[id_INIT] = Property(0x00ff); + } + } + } + // =================================== // PLL // =================================== @@ -1700,6 +1739,9 @@ struct GowinPacker pack_gsr(); ctx->check(); + pack_inv(); + ctx->check(); + pack_wideluts(); ctx->check();