gowin: Himbaechel. Deal with SP BSRAM ports.
The OCE signal in the SP(X)9B primitive is intended to control the built-in output register. The documentation states that this port is invalid when READ_MODE=0 is used. However, it has been experimentally established that you cannot simply apply VCC or GND to it and forget it - the discrepancy between the signal on this port and the signal on the CE port leads to both skipping data reading and unnecessary reading after CE has switched to 0. Here we force these ports to be connected to the network, except in the case where the user controls the OCE signal using non-constant signals. Also: * All PIPs for clock spines are made inaccessible to the common router - in general, using these routes for signals that have not been processed by a special globals router is fraught with effects that are difficult to detect. * The INV primitive has been added purely to speed up development - this primitive is not generated by Yosys, but is almost always present in vendor output files. Signed-off-by: YRabbit <rabbit@yrabbit.cyou>
This commit is contained in:
parent
97f5c3ca2c
commit
91b0c4f90a
@ -934,6 +934,9 @@ X(GSR)
|
||||
X(GSR0)
|
||||
X(GSRI)
|
||||
|
||||
// inverter
|
||||
X(INV)
|
||||
|
||||
// Oscillators
|
||||
X(OSC)
|
||||
X(OSCZ)
|
||||
|
@ -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);
|
||||
|
@ -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"))) {
|
||||
|
@ -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);
|
||||
|
@ -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();
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user