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)) ||
|
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,
|
src_name.in(id_SPINE6, id_SPINE7, id_SPINE14, id_SPINE15, id_SPINE22, id_SPINE23, id_SPINE30,
|
||||||
id_SPINE31);
|
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);
|
bool res = (src_valid && dst_valid) || (src_valid && is_local(dst_type)) || (is_local(src_type) && dst_valid);
|
||||||
if (ctx->debug && false /*&& res*/) {
|
if (ctx->debug && false /*&& res*/) {
|
||||||
@ -207,6 +207,7 @@ struct GowinGlobalRouter
|
|||||||
if (!pip_filter(pip, src)) {
|
if (!pip_filter(pip, src)) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Add to the queue
|
// Add to the queue
|
||||||
visit.push(prev);
|
visit.push(prev);
|
||||||
backtrace[prev] = pip;
|
backtrace[prev] = pip;
|
||||||
@ -399,6 +400,8 @@ struct GowinGlobalRouter
|
|||||||
|
|
||||||
void route_dcs_net(NetInfo *net)
|
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
|
// Since CLKOUT is responsible for only one quadrant, we will do
|
||||||
// routing not from it, but from any CLK0-3 input actually connected to
|
// routing not from it, but from any CLK0-3 input actually connected to
|
||||||
// the clock source.
|
// the clock source.
|
||||||
@ -406,7 +409,7 @@ struct GowinGlobalRouter
|
|||||||
NetInfo *net_before_dcs;
|
NetInfo *net_before_dcs;
|
||||||
PortRef driver;
|
PortRef driver;
|
||||||
for (int i = 0; i < 4; ++i) {
|
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) {
|
if (net_before_dcs == nullptr) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
@ -449,7 +452,8 @@ struct GowinGlobalRouter
|
|||||||
}
|
}
|
||||||
WireId dst = ctx->getPipDstWire(pip);
|
WireId dst = ctx->getPipDstWire(pip);
|
||||||
IdString dst_name = ctx->getWireName(dst)[1];
|
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
|
// step over dummy pip
|
||||||
for (PipId next_pip : ctx->getPipsDownhill(dst)) {
|
for (PipId next_pip : ctx->getPipsDownhill(dst)) {
|
||||||
if (ctx->getBoundPipNet(next_pip) != nullptr) {
|
if (ctx->getBoundPipNet(next_pip) != nullptr) {
|
||||||
@ -498,7 +502,7 @@ struct GowinGlobalRouter
|
|||||||
|
|
||||||
// The input networks must bs same for all hardware dcs.
|
// The input networks must bs same for all hardware dcs.
|
||||||
dcs_ci->copyPortTo(id_SELFORCE, hw_dcs, id_SELFORCE);
|
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);
|
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);
|
dcs_ci->disconnectPort(id_CLKOUT);
|
||||||
for (int i = 0; i < 4; ++i) {
|
for (int i = 0; i < 4; ++i) {
|
||||||
dcs_ci->disconnectPort(ctx->idf("CLKSEL[%d]", 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));
|
log_info(" '%s' net was routed.\n", ctx->nameOf(net));
|
||||||
ctx->cells.erase(dcs_ci->name);
|
ctx->cells.erase(dcs_ci->name);
|
||||||
@ -1281,7 +1285,7 @@ struct GowinGlobalRouter
|
|||||||
}
|
}
|
||||||
if (route_clk_net(ni) == NOT_ROUTED) {
|
if (route_clk_net(ni) == NOT_ROUTED) {
|
||||||
if (ctx->verbose) {
|
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);
|
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 {
|
NPNR_PACKED_STRUCT(struct Extra_chip_data_POD {
|
||||||
int32_t chip_flags;
|
int32_t chip_flags;
|
||||||
|
IdString dcs_prefix;
|
||||||
Bottom_io_POD bottom_io;
|
Bottom_io_POD bottom_io;
|
||||||
RelSlice<IdString> diff_io_types;
|
RelSlice<IdString> diff_io_types;
|
||||||
RelSlice<Spine_bel_POD> dqce_bels;
|
RelSlice<Spine_bel_POD> dqce_bels;
|
||||||
|
|||||||
@ -266,7 +266,8 @@ class Segment(BBAStruct):
|
|||||||
class ChipExtraData(BBAStruct):
|
class ChipExtraData(BBAStruct):
|
||||||
strs: StringPool
|
strs: StringPool
|
||||||
flags: int
|
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)
|
diff_io_types: list[IdString] = field(default_factory = list)
|
||||||
dqce_bels: list[SpineBel] = field(default_factory = list)
|
dqce_bels: list[SpineBel] = field(default_factory = list)
|
||||||
dcs_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)
|
io_dlldly_bels: list[IoBel] = field(default_factory = list)
|
||||||
segments: list[Segment] = 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):
|
def create_bottom_io(self):
|
||||||
self.bottom_io = BottomIO()
|
self.bottom_io = BottomIO()
|
||||||
|
|
||||||
@ -334,6 +338,7 @@ class ChipExtraData(BBAStruct):
|
|||||||
|
|
||||||
def serialise(self, context: str, bba: BBAWriter):
|
def serialise(self, context: str, bba: BBAWriter):
|
||||||
bba.u32(self.flags)
|
bba.u32(self.flags)
|
||||||
|
bba.u32(self.dcs_prefix.index)
|
||||||
self.bottom_io.serialise(f"{context}_bottom_io", bba)
|
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}_diff_io_types", len(self.diff_io_types))
|
||||||
bba.slice(f"{context}_dqce_bels", len(self.dqce_bels))
|
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):
|
for idx in range(2):
|
||||||
if idx not in desc:
|
if idx not in desc:
|
||||||
continue
|
continue
|
||||||
|
dcs_prefix = 'CLK'
|
||||||
|
if hasattr(db, "dcs_prefix"):
|
||||||
|
dcs_prefix = db.dcs_prefix
|
||||||
bel_z = DCS_Z + idx
|
bel_z = DCS_Z + idx
|
||||||
bel = tt.create_bel(f"DCS{idx}", "DCS", bel_z)
|
bel = tt.create_bel(f"DCS{idx}", "DCS", bel_z)
|
||||||
wire = desc[idx]['clkout']
|
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']):
|
for clk_idx, wire in enumerate(desc[idx]['clk']):
|
||||||
if not tt.has_wire(wire):
|
if not tt.has_wire(wire):
|
||||||
tt.create_wire(wire, "GLOBAL_CLK")
|
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
|
# This is a fake PIP that allows routing “through” this
|
||||||
# primitive from the CLK input to the CLKOUT output.
|
# primitive from the CLK input to the CLKOUT output.
|
||||||
tt.create_pip(wire, clkout_wire)
|
tt.create_pip(wire, clkout_wire)
|
||||||
@ -1413,7 +1421,11 @@ def create_packages(chip: Chip, db: chipdb):
|
|||||||
|
|
||||||
# Extra chip data
|
# Extra chip data
|
||||||
def create_extra_data(chip: Chip, db: chipdb, chip_flags: int):
|
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()
|
chip.extra_data.create_bottom_io()
|
||||||
for net_a, net_b in db.bottom_io[2]:
|
for net_a, net_b in db.bottom_io[2]:
|
||||||
chip.extra_data.add_bottom_io_cnd(net_a, net_b)
|
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();
|
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)
|
bool GowinUtils::is_simple_io_bel(BelId bel)
|
||||||
{
|
{
|
||||||
return chip_bel_info(ctx->chip_info, bel).flags & BelFlags::FLAG_SIMPLE_IO;
|
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_dcs_bel(IdString spine_name);
|
||||||
BelId get_dhcen_bel(WireId hclkin_wire, IdString &side);
|
BelId get_dhcen_bel(WireId hclkin_wire, IdString &side);
|
||||||
BelId get_dlldly_bel(BelId io_bel);
|
BelId get_dlldly_bel(BelId io_bel);
|
||||||
|
IdString get_dcs_prefix(void);
|
||||||
|
|
||||||
// Segments
|
// Segments
|
||||||
int get_segments_count(void) const;
|
int get_segments_count(void) const;
|
||||||
|
|||||||
@ -4141,12 +4141,7 @@ struct GowinPacker
|
|||||||
if (dcs_bel != BelId()) {
|
if (dcs_bel != BelId()) {
|
||||||
IdString dcs_name = ctx->idf("$PACKER_DCS_SPINE%d", 8 * (i % 4) + 6 + (i >> 2));
|
IdString dcs_name = ctx->idf("$PACKER_DCS_SPINE%d", 8 * (i % 4) + 6 + (i >> 2));
|
||||||
CellInfo *dcs = ctx->createCell(dcs_name, id_DCS);
|
CellInfo *dcs = ctx->createCell(dcs_name, id_DCS);
|
||||||
dcs->addInput(id_SELFORCE);
|
ctx->copyBelPorts(dcs_name, dcs_bel);
|
||||||
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->bindBel(dcs_bel, dcs, STRENGTH_LOCKED);
|
ctx->bindBel(dcs_bel, dcs, STRENGTH_LOCKED);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user