Skip to content

Commit 91b0c4f

Browse files
yrabbitgatecat
authored andcommitted
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 <[email protected]>
1 parent 97f5c3c commit 91b0c4f

File tree

5 files changed

+69
-1
lines changed

5 files changed

+69
-1
lines changed

himbaechel/uarch/gowin/constids.inc

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -934,6 +934,9 @@ X(GSR)
934934
X(GSR0)
935935
X(GSRI)
936936

937+
// inverter
938+
X(INV)
939+
937940
// Oscillators
938941
X(OSC)
939942
X(OSCZ)

himbaechel/uarch/gowin/globals.cc

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,8 @@ struct GowinGlobalRouter
4040

4141
GowinGlobalRouter(Context *ctx) : ctx(ctx) { gwu.init(ctx); };
4242

43+
bool checkPipAvail(PipId pip) const { return gwu.is_global_pip(pip) || ctx->checkPipAvail(pip); };
44+
4345
// allow io->global, global->global and global->tile clock
4446
bool global_pip_filter(PipId pip) const
4547
{
@@ -91,7 +93,7 @@ struct GowinGlobalRouter
9193
// Search uphill pips
9294
for (PipId pip : ctx->getPipsUphill(cursor)) {
9395
// Skip pip if unavailable, and not because it's already used for this net
94-
if (!ctx->checkPipAvail(pip) && ctx->getBoundPipNet(pip) != net) {
96+
if (!checkPipAvail(pip) && ctx->getBoundPipNet(pip) != net) {
9597
continue;
9698
}
9799
WireId prev = ctx->getPipSrcWire(pip);

himbaechel/uarch/gowin/gowin.cc

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,9 @@ struct GowinImpl : HimbaechelAPI
3838

3939
bool isValidBelForCellType(IdString cell_type, BelId bel) const override;
4040

41+
// wires
42+
bool checkPipAvail(PipId pip) const override;
43+
4144
private:
4245
HimbaechelHelpers h;
4346
GowinUtils gwu;
@@ -154,6 +157,9 @@ void GowinImpl::init(Context *ctx)
154157
}
155158
}
156159

160+
// We do not allow the use of global wires that bypass a special router.
161+
bool GowinImpl::checkPipAvail(PipId pip) const { return !gwu.is_global_pip(pip); }
162+
157163
void GowinImpl::pack()
158164
{
159165
if (ctx->settings.count(ctx->id("cst.filename"))) {

himbaechel/uarch/gowin/gowin_utils.h

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,21 @@ struct GowinUtils
3838

3939
// wires
4040
inline bool is_wire_type_default(IdString wire_type) { return wire_type == IdString(); }
41+
// If wire is an important part of the global network (like SPINExx)
42+
inline bool is_global_wire(WireId wire) const
43+
{
44+
return ctx->getWireName(wire)[1].in(
45+
id_SPINE0, id_SPINE1, id_SPINE2, id_SPINE3, id_SPINE4, id_SPINE5, id_SPINE6, id_SPINE7, id_SPINE8,
46+
id_SPINE9, id_SPINE10, id_SPINE11, id_SPINE12, id_SPINE13, id_SPINE14, id_SPINE15, id_SPINE16,
47+
id_SPINE17, id_SPINE18, id_SPINE19, id_SPINE20, id_SPINE21, id_SPINE22, id_SPINE23, id_SPINE24,
48+
id_SPINE25, id_SPINE26, id_SPINE27, id_SPINE28, id_SPINE29, id_SPINE30, id_SPINE31);
49+
}
50+
51+
// pips
52+
inline bool is_global_pip(PipId pip) const
53+
{
54+
return is_global_wire(ctx->getPipSrcWire(pip)) || is_global_wire(ctx->getPipDstWire(pip));
55+
}
4156

4257
// chip dependent
4358
bool have_SP32(void);

himbaechel/uarch/gowin/pack.cc

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1294,6 +1294,24 @@ struct GowinPacker
12941294
}
12951295
}
12961296

1297+
// If the memory is controlled by the CE, then it is logical for the OCE to
1298+
// also respond to this signal, unless the OCE is controlled separately.
1299+
void bsram_handle_sp_oce(CellInfo *ci, IdString ce_pin, IdString oce_pin)
1300+
{
1301+
const NetInfo *net = ci->getPort(oce_pin);
1302+
NPNR_ASSERT(ci->getPort(ce_pin) != nullptr);
1303+
if (net == nullptr || net->name == ctx->id("$PACKER_VCC") || net->name == ctx->id("$PACKER_GND")) {
1304+
if (net != nullptr) {
1305+
ci->disconnectPort(oce_pin);
1306+
}
1307+
ci->copyPortTo(ce_pin, ci, oce_pin);
1308+
}
1309+
if (ctx->verbose) {
1310+
log_info("%s: %s = %s = %s\n", ctx->nameOf(ci), ce_pin.c_str(ctx), oce_pin.c_str(ctx),
1311+
ctx->nameOf(ci->getPort(oce_pin)));
1312+
}
1313+
}
1314+
12971315
void pack_ROM(CellInfo *ci)
12981316
{
12991317
int default_bw = 32;
@@ -1512,6 +1530,8 @@ struct GowinPacker
15121530
}
15131531

15141532
int bit_width = ci->params.at(id_BIT_WIDTH).as_int64();
1533+
bsram_handle_sp_oce(ci, id_CE, id_OCE);
1534+
15151535
// XXX UG285-1.3.6_E Gowin BSRAM & SSRAM User Guide:
15161536
// For GW1N-9/GW1NR-9/GW1NS-4 series, 32/36-bit SP/SPX9 is divided into two
15171537
// SP/SPX9s, which occupy two BSRAMs.
@@ -1623,6 +1643,25 @@ struct GowinPacker
16231643
}
16241644
}
16251645

1646+
// ===================================
1647+
// Replace INV with LUT
1648+
// ===================================
1649+
void pack_inv(void)
1650+
{
1651+
log_info("Pack INV..\n");
1652+
1653+
for (auto &cell : ctx->cells) {
1654+
auto &ci = *cell.second;
1655+
1656+
if (ci.type == id_INV) {
1657+
ci.type = id_LUT4;
1658+
ci.renamePort(id_O, id_F);
1659+
ci.renamePort(id_I, id_I3); // use D - it's simple for INIT
1660+
ci.params[id_INIT] = Property(0x00ff);
1661+
}
1662+
}
1663+
}
1664+
16261665
// ===================================
16271666
// PLL
16281667
// ===================================
@@ -1700,6 +1739,9 @@ struct GowinPacker
17001739
pack_gsr();
17011740
ctx->check();
17021741

1742+
pack_inv();
1743+
ctx->check();
1744+
17031745
pack_wideluts();
17041746
ctx->check();
17051747

0 commit comments

Comments
 (0)