1
0
mirror of https://github.com/YosysHQ/nextpnr.git synced 2026-01-11 23:53:21 +00:00

Gowin. GW5A chips. Implement the DCS primitive. (#1558)

The GW5A series is interesting—in this particular primitive, the inputs
have been renamed from CLKx to CLKINx. Everything else remains the same,
including functionality.

As an output, we will store in the chip database which prefix the DCS
inputs have.

Signed-off-by: YRabbit <rabbit@yrabbit.cyou>
This commit is contained in:
YRabbit 2025-09-23 20:42:33 +10:00 committed by GitHub
parent 1742d09edb
commit 22041ed5df
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
6 changed files with 34 additions and 15 deletions

View File

@ -150,7 +150,7 @@ struct GowinGlobalRouter
bool src_valid = ((!src_is_spine) && src_type.in(id_GLOBAL_CLK, id_IO_O, id_PLL_O, id_HCLK)) ||
src_name.in(id_SPINE6, id_SPINE7, id_SPINE14, id_SPINE15, id_SPINE22, id_SPINE23, id_SPINE30,
id_SPINE31);
bool dst_valid = dst_type.in(id_GLOBAL_CLK, id_TILE_CLK, id_PLL_I, id_IO_I, id_HCLK);
bool dst_valid = dst_type.in(id_GLOBAL_CLK, id_TILE_CLK, id_PLL_I, id_PLL_O, id_IO_I, id_HCLK);
bool res = (src_valid && dst_valid) || (src_valid && is_local(dst_type)) || (is_local(src_type) && dst_valid);
if (ctx->debug && false /*&& res*/) {
@ -207,6 +207,7 @@ struct GowinGlobalRouter
if (!pip_filter(pip, src)) {
continue;
}
// Add to the queue
visit.push(prev);
backtrace[prev] = pip;
@ -399,6 +400,8 @@ struct GowinGlobalRouter
void route_dcs_net(NetInfo *net)
{
IdString dcs_clock_input_prefix = gwu.get_dcs_prefix();
const char *dcs_clock_input_prefix_str = dcs_clock_input_prefix.c_str(ctx);
// Since CLKOUT is responsible for only one quadrant, we will do
// routing not from it, but from any CLK0-3 input actually connected to
// the clock source.
@ -406,7 +409,7 @@ struct GowinGlobalRouter
NetInfo *net_before_dcs;
PortRef driver;
for (int i = 0; i < 4; ++i) {
net_before_dcs = dcs_ci->getPort(ctx->idf("CLK%d", i));
net_before_dcs = dcs_ci->getPort(ctx->idf("%s%d", dcs_clock_input_prefix_str, i));
if (net_before_dcs == nullptr) {
continue;
}
@ -449,7 +452,8 @@ struct GowinGlobalRouter
}
WireId dst = ctx->getPipDstWire(pip);
IdString dst_name = ctx->getWireName(dst)[1];
if (dst_name.str(ctx).rfind("PCLK", 0) == 0 || dst_name.str(ctx).rfind("LWSPINE", 0) == 0) {
if (dst_name.str(ctx).rfind("PCLK", 0) == 0 || dst_name.str(ctx).rfind("LWSPINE", 0) == 0 ||
dst_name.str(ctx).rfind("PLL") == 0) {
// step over dummy pip
for (PipId next_pip : ctx->getPipsDownhill(dst)) {
if (ctx->getBoundPipNet(next_pip) != nullptr) {
@ -498,7 +502,7 @@ struct GowinGlobalRouter
// The input networks must bs same for all hardware dcs.
dcs_ci->copyPortTo(id_SELFORCE, hw_dcs, id_SELFORCE);
dcs_ci->copyPortBusTo(id_CLK, 0, false, hw_dcs, id_CLK, 0, false, 4);
dcs_ci->copyPortBusTo(dcs_clock_input_prefix, 0, false, hw_dcs, dcs_clock_input_prefix, 0, false, 4);
dcs_ci->copyPortBusTo(id_CLKSEL, 0, true, hw_dcs, id_CLKSEL, 0, false, 4);
}
@ -507,7 +511,7 @@ struct GowinGlobalRouter
dcs_ci->disconnectPort(id_CLKOUT);
for (int i = 0; i < 4; ++i) {
dcs_ci->disconnectPort(ctx->idf("CLKSEL[%d]", i));
dcs_ci->disconnectPort(ctx->idf("CLK%d", i));
dcs_ci->disconnectPort(ctx->idf("%s%d", dcs_clock_input_prefix_str, i));
}
log_info(" '%s' net was routed.\n", ctx->nameOf(net));
ctx->cells.erase(dcs_ci->name);
@ -1281,7 +1285,7 @@ struct GowinGlobalRouter
}
if (route_clk_net(ni) == NOT_ROUTED) {
if (ctx->verbose) {
log_info(" try to route as a segmented network.\n");
log_info(" will try to route it as a segmented network.\n");
}
seg_nets.push_back(net_name);
}

View File

@ -184,6 +184,7 @@ NPNR_PACKED_STRUCT(struct Extra_package_data_POD { RelSlice<Constraint_POD> cst;
NPNR_PACKED_STRUCT(struct Extra_chip_data_POD {
int32_t chip_flags;
IdString dcs_prefix;
Bottom_io_POD bottom_io;
RelSlice<IdString> diff_io_types;
RelSlice<Spine_bel_POD> dqce_bels;

View File

@ -266,7 +266,8 @@ class Segment(BBAStruct):
class ChipExtraData(BBAStruct):
strs: StringPool
flags: int
bottom_io: BottomIO
dcs_prefix: IdString = field(default = None)
bottom_io: BottomIO = field(default = None)
diff_io_types: list[IdString] = field(default_factory = list)
dqce_bels: list[SpineBel] = field(default_factory = list)
dcs_bels: list[SpineBel] = field(default_factory = list)
@ -274,6 +275,9 @@ class ChipExtraData(BBAStruct):
io_dlldly_bels: list[IoBel] = field(default_factory = list)
segments: list[Segment] = field(default_factory = list)
def set_dcs_prefix(self, prefix: str):
self.dcs_prefix = self.strs.id(prefix)
def create_bottom_io(self):
self.bottom_io = BottomIO()
@ -334,6 +338,7 @@ class ChipExtraData(BBAStruct):
def serialise(self, context: str, bba: BBAWriter):
bba.u32(self.flags)
bba.u32(self.dcs_prefix.index)
self.bottom_io.serialise(f"{context}_bottom_io", bba)
bba.slice(f"{context}_diff_io_types", len(self.diff_io_types))
bba.slice(f"{context}_dqce_bels", len(self.dqce_bels))
@ -662,6 +667,9 @@ def create_extra_funcs(tt: TileType, db: chipdb, x: int, y: int):
for idx in range(2):
if idx not in desc:
continue
dcs_prefix = 'CLK'
if hasattr(db, "dcs_prefix"):
dcs_prefix = db.dcs_prefix
bel_z = DCS_Z + idx
bel = tt.create_bel(f"DCS{idx}", "DCS", bel_z)
wire = desc[idx]['clkout']
@ -672,7 +680,7 @@ def create_extra_funcs(tt: TileType, db: chipdb, x: int, y: int):
for clk_idx, wire in enumerate(desc[idx]['clk']):
if not tt.has_wire(wire):
tt.create_wire(wire, "GLOBAL_CLK")
tt.add_bel_pin(bel, f"CLK{clk_idx}", wire, PinType.INPUT)
tt.add_bel_pin(bel, f"{dcs_prefix}{clk_idx}", wire, PinType.INPUT)
# This is a fake PIP that allows routing “through” this
# primitive from the CLK input to the CLKOUT output.
tt.create_pip(wire, clkout_wire)
@ -1413,7 +1421,11 @@ def create_packages(chip: Chip, db: chipdb):
# Extra chip data
def create_extra_data(chip: Chip, db: chipdb, chip_flags: int):
chip.extra_data = ChipExtraData(chip.strs, chip_flags, None)
chip.extra_data = ChipExtraData(chip.strs, chip_flags)
if hasattr(db, "dcs_prefix"):
chip.extra_data.set_dcs_prefix(db.dcs_prefix)
else:
chip.extra_data.set_dcs_prefix("CLK")
chip.extra_data.create_bottom_io()
for net_a, net_b in db.bottom_io[2]:
chip.extra_data.add_bottom_io_cnd(net_a, net_b)

View File

@ -290,6 +290,12 @@ BelId GowinUtils::get_dhcen_bel(WireId hclkin_wire, IdString &side)
return BelId();
}
IdString GowinUtils::get_dcs_prefix(void)
{
const Extra_chip_data_POD *extra = reinterpret_cast<const Extra_chip_data_POD *>(ctx->chip_info->extra_data.get());
return extra->dcs_prefix;
}
bool GowinUtils::is_simple_io_bel(BelId bel)
{
return chip_bel_info(ctx->chip_info, bel).flags & BelFlags::FLAG_SIMPLE_IO;

View File

@ -49,6 +49,7 @@ struct GowinUtils
BelId get_dcs_bel(IdString spine_name);
BelId get_dhcen_bel(WireId hclkin_wire, IdString &side);
BelId get_dlldly_bel(BelId io_bel);
IdString get_dcs_prefix(void);
// Segments
int get_segments_count(void) const;

View File

@ -4141,12 +4141,7 @@ struct GowinPacker
if (dcs_bel != BelId()) {
IdString dcs_name = ctx->idf("$PACKER_DCS_SPINE%d", 8 * (i % 4) + 6 + (i >> 2));
CellInfo *dcs = ctx->createCell(dcs_name, id_DCS);
dcs->addInput(id_SELFORCE);
for (int j = 0; j < 4; ++j) {
dcs->addInput(ctx->idf("CLK%d", j));
dcs->addInput(ctx->idf("CLKSEL%d", j));
}
dcs->addOutput(id_CLKOUT);
ctx->copyBelPorts(dcs_name, dcs_bel);
ctx->bindBel(dcs_bel, dcs, STRENGTH_LOCKED);
}
}