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:
parent
1742d09edb
commit
22041ed5df
@ -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);
|
||||
}
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -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)
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user