From 22041ed5df511fd1cd056976f9f3a08c5a0f3660 Mon Sep 17 00:00:00 2001 From: YRabbit Date: Tue, 23 Sep 2025 20:42:33 +1000 Subject: [PATCH] Gowin. GW5A chips. Implement the DCS primitive. (#1558) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 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 --- himbaechel/uarch/gowin/globals.cc | 16 ++++++++++------ himbaechel/uarch/gowin/gowin.h | 1 + himbaechel/uarch/gowin/gowin_arch_gen.py | 18 +++++++++++++++--- himbaechel/uarch/gowin/gowin_utils.cc | 6 ++++++ himbaechel/uarch/gowin/gowin_utils.h | 1 + himbaechel/uarch/gowin/pack.cc | 7 +------ 6 files changed, 34 insertions(+), 15 deletions(-) diff --git a/himbaechel/uarch/gowin/globals.cc b/himbaechel/uarch/gowin/globals.cc index fa7bb2aa..ee90b5d9 100644 --- a/himbaechel/uarch/gowin/globals.cc +++ b/himbaechel/uarch/gowin/globals.cc @@ -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); } diff --git a/himbaechel/uarch/gowin/gowin.h b/himbaechel/uarch/gowin/gowin.h index 1a79243c..0300bbc7 100644 --- a/himbaechel/uarch/gowin/gowin.h +++ b/himbaechel/uarch/gowin/gowin.h @@ -184,6 +184,7 @@ NPNR_PACKED_STRUCT(struct Extra_package_data_POD { RelSlice cst; NPNR_PACKED_STRUCT(struct Extra_chip_data_POD { int32_t chip_flags; + IdString dcs_prefix; Bottom_io_POD bottom_io; RelSlice diff_io_types; RelSlice dqce_bels; diff --git a/himbaechel/uarch/gowin/gowin_arch_gen.py b/himbaechel/uarch/gowin/gowin_arch_gen.py index c4fb0651..93ac46c1 100644 --- a/himbaechel/uarch/gowin/gowin_arch_gen.py +++ b/himbaechel/uarch/gowin/gowin_arch_gen.py @@ -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) diff --git a/himbaechel/uarch/gowin/gowin_utils.cc b/himbaechel/uarch/gowin/gowin_utils.cc index b2b41569..475b9902 100644 --- a/himbaechel/uarch/gowin/gowin_utils.cc +++ b/himbaechel/uarch/gowin/gowin_utils.cc @@ -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(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; diff --git a/himbaechel/uarch/gowin/gowin_utils.h b/himbaechel/uarch/gowin/gowin_utils.h index c3a598ea..425162d4 100644 --- a/himbaechel/uarch/gowin/gowin_utils.h +++ b/himbaechel/uarch/gowin/gowin_utils.h @@ -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; diff --git a/himbaechel/uarch/gowin/pack.cc b/himbaechel/uarch/gowin/pack.cc index 0a8d7155..6530615d 100644 --- a/himbaechel/uarch/gowin/pack.cc +++ b/himbaechel/uarch/gowin/pack.cc @@ -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); } }