Gowin. Implement GW5A HCLK and CLKDIV2. (#1687)

* Gowin. Implement GW5A HCLK and CLKDIV2.

HCLK pins have been added for the GW5A series, and the placement of
CLKDIV2 primitives has been updated to account for the specific
characteristics of this chip series.

Signed-off-by: YRabbit <rabbit@yrabbit.cyou>

* Gowin. Fix style.

* Gowin. Fix style.

---------

Signed-off-by: YRabbit <rabbit@yrabbit.cyou>
This commit is contained in:
YRabbit 2026-04-03 07:40:45 +00:00 committed by GitHub
parent d6b4d3ed3d
commit c7da64d8c8
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
7 changed files with 347 additions and 26 deletions

View File

@ -1345,6 +1345,22 @@ X(HCLK_OUT0)
X(HCLK_OUT1)
X(HCLK_OUT2)
X(HCLK_OUT3)
X(HCLK00)
X(HCLK01)
X(HCLK02)
X(HCLK03)
X(HCLK10)
X(HCLK11)
X(HCLK12)
X(HCLK13)
X(HCLK20)
X(HCLK21)
X(HCLK22)
X(HCLK23)
X(HCLK30)
X(HCLK31)
X(HCLK32)
X(HCLK33)
// BUFG, clock buffers stuff
X(CLKSEL)

View File

@ -110,6 +110,7 @@ struct GowinImpl : HimbaechelAPI
// Place explicityl constrained or implicitly constrained (by IOLOGIC) CLKDIV and CLKDIV2 cells
// to avoid routing conflicts and maximize utilization
void place_constrained_hclk_cells();
void place_5a_hclks(void);
// bel placement validation
bool slice_valid(int x, int y, int z) const;
@ -333,6 +334,179 @@ void GowinImpl::adjust_dsp_pin_mapping(void)
}
}
// GW5A HCLK
// Each serializer/deserializer can use one of several HCLK wire from a block
// (hclk_idx), but only from the specific block assigned to that
// serializer/deserializer.
// Each HCLK line can be routed through a CLKDIV2 primitive, which halves the signal frequency.
//
// Thus, if the SERDES uses CLKDIV2, the latter must be placed in the specific
// HCLK block corresponding to the SERDES (since the SERDES is part of the I/O,
// and we do not allow unconstrained I/O, the placement of the SERDES is always
// known).
//
// Since users typically do not track which pins belong to which HCLK block,
// situations may arise where a single CLKDIV2 divider in the design serves as
// the signal source for SERDES located in different HCLK blocks, making it
// impossible to connect them. Alternatively, some SERDES in one block may
// receive the signal directly, while others receive it from the CLKDIV2.
//
// Here, we solve this by duplicating the CLKDIV2 cells and placing them
// exactly where they serve specific HCLK blocks.
//
// Information regarding which IO corresponds to a specific HCLK, as well as
// the placement of CLKDIV2 for that specific HCLK, is retrieved from the
// chip's database.
//
void GowinImpl::place_5a_hclks(void)
{
std::vector<std::unique_ptr<CellInfo>> new_cells;
// Cloned CLKDIV2 cells
dict<int, CellInfo *> clkdiv2_clones;
// Which users need to be reconnected, and to where.
std::vector<std::pair<PortRef, CellInfo *>> users_to_reconect;
// CLKDIV2 allocator
dict<int, std::vector<Loc>> free_clkdiv2;
// SERDES can use any wire from the HCLK block; here, we select a wire from
// the unused ones and return the CLKDIV2 location that serves that wire.
auto alloc_clkdiv2 = [&](int hclk_idx, CellInfo *ci) -> Loc {
// first allocation for hclk_idx
if (!free_clkdiv2.count(hclk_idx)) {
std::vector<Loc> locs;
gwu.get_clkdiv2_locs(hclk_idx, locs);
free_clkdiv2[hclk_idx] = locs;
}
if (!free_clkdiv2.at(hclk_idx).size()) {
log_error("Can't place %s CLKDIV2.\n", ctx->nameOf(ci));
}
Loc loc = free_clkdiv2.at(hclk_idx).back();
free_clkdiv2.at(hclk_idx).pop_back();
return loc;
};
for (auto &cell : ctx->cells) {
auto ci = cell.second.get();
// The CLKDIV2s described in the design
if (is_clkdiv2(ci)) {
NetInfo *hclk_net = ci->getPort(id_CLKOUT);
if (!hclk_net || !ci->getPort(id_HCLKIN)) {
continue;
}
if (ctx->debug) {
log_info(" CLKDIV2 cell:%s, HCLKIN:%s, CLKOUT:%s\n", ctx->nameOf(ci),
ctx->nameOf(ci->getPort(id_HCLKIN)), ctx->nameOf(hclk_net));
}
clkdiv2_clones.clear();
users_to_reconect.clear();
int cur_clkdiv2_hclk_idx = -1;
// SERDES only
for (auto user : hclk_net->users) {
if (!is_iologico(user.cell) && !is_iologici(user.cell)) {
continue;
}
// checking users' hclk index
NPNR_ASSERT(user.cell->bel != BelId());
Loc user_loc = ctx->getBelLocation(user.cell->bel);
int hclk_idx = gwu.get_hclk_for_io(user_loc);
if (hclk_idx == -1) {
log_error("%s can't use HCLK with %s.\n", ctx->nameOf(user.cell), ctx->nameOf(ci));
}
if (cur_clkdiv2_hclk_idx == -1) {
// Place CLKDIV2
cur_clkdiv2_hclk_idx = hclk_idx;
BelId bel = ctx->getBelByLocation(alloc_clkdiv2(hclk_idx, ci));
ctx->bindBel(bel, ci, PlaceStrength::STRENGTH_LOCKED);
if (ctx->debug) {
log_info(" @%s\n", ctx->nameOfBel(bel));
}
if (ctx->debug) {
log_info(" hclk:%d - %s %s\n", hclk_idx, ctx->nameOfBel(user.cell->bel),
ctx->nameOf(user.cell));
}
continue;
}
// If the SERDES is in the current HCLK block, it remains there
if (cur_clkdiv2_hclk_idx == hclk_idx) {
if (ctx->debug) {
log_info(" hclk:%d - %s %s\n", hclk_idx, ctx->nameOfBel(user.cell->bel),
ctx->nameOf(user.cell));
}
continue;
}
// Since the SERDES is located in a different HCLK block, we
// need to create a copy of CLKDIV2 and save the SERDES
// for later connection to the copy.
CellInfo *new_clkdiv2;
if (clkdiv2_clones.count(hclk_idx)) {
// already have clone
new_clkdiv2 = clkdiv2_clones.at(hclk_idx);
} else {
// create clone
new_cells.push_back(gwu.create_cell(gwu.create_aux_name(ci->name, hclk_idx), id_CLKDIV2));
new_clkdiv2 = new_cells.back().get();
new_clkdiv2->addInput(id_HCLKIN);
new_clkdiv2->addOutput(id_CLKOUT);
clkdiv2_clones[hclk_idx] = new_clkdiv2;
if (ctx->debug) {
log_info(" create clone for hclk:%d - %s\n", hclk_idx, ctx->nameOf(new_clkdiv2));
}
}
users_to_reconect.push_back(std::make_pair(user, new_clkdiv2));
}
// move the SERDES by connecting it to a copy of CLKDIV2
for (auto us_ci : users_to_reconect) {
PortRef user = us_ci.first;
CellInfo *new_clkdiv2 = us_ci.second;
if (ctx->debug) {
log_info(" reconnect %s.%s to %s\n", ctx->nameOf(user.cell), user.port.c_str(ctx),
ctx->nameOf(new_clkdiv2));
}
// input is same
if (!new_clkdiv2->getPort(id_HCLKIN)) {
ci->copyPortTo(id_HCLKIN, new_clkdiv2, id_HCLKIN);
}
// move user
user.cell->disconnectPort(user.port);
new_clkdiv2->connectPorts(id_CLKOUT, user.cell, user.port);
}
}
}
// Place new CLKDIV2
for (auto &ncell : new_cells) {
CellInfo *ci = ncell.get();
NetInfo *hclk_net = ci->getPort(id_CLKOUT);
if (ctx->debug) {
log_info(" CLKDIV2 cell:%s, HCLKIN:%s, CLKOUT:%s\n", ctx->nameOf(ci), ctx->nameOf(ci->getPort(id_HCLKIN)),
ctx->nameOf(hclk_net));
}
// Any user can be used to determine hclk_idx because we connected them
// to copies of CLKDIV2 based precisely on the fact that hclk_idx is
// the same
PortRef &user = *hclk_net->users.begin();
Loc user_loc = ctx->getBelLocation(user.cell->bel);
int hclk_idx = gwu.get_hclk_for_io(user_loc);
BelId bel = ctx->getBelByLocation(alloc_clkdiv2(hclk_idx, ci));
ctx->bindBel(bel, ci, PlaceStrength::STRENGTH_LOCKED);
if (ctx->debug) {
log_info(" @%s\n", ctx->nameOfBel(bel));
log_info(" hclk:%d - %s %s\n", hclk_idx, ctx->nameOfBel(user.cell->bel), ctx->nameOf(user.cell));
}
ctx->cells[ncell->name] = std::move(ncell);
}
}
/*
Each HCLK section can serve one of three purposes:
1. A simple routing path to IOLOGIC FCLK or PLL inputs
@ -348,6 +522,11 @@ void GowinImpl::adjust_dsp_pin_mapping(void)
void GowinImpl::place_constrained_hclk_cells()
{
log_info("Running custom HCLK placer...\n");
if (gwu.has_5A_HCLK()) {
place_5a_hclks();
return;
}
std::map<IdStringList, IdString> constrained_clkdivs;
std::map<BelId, std::set<std::pair<IdString, int>>> bel_cell_map;
std::vector<std::pair<IdString, int>> alias_cells;
@ -620,6 +799,7 @@ void GowinImpl::place_constrained_hclk_cells()
void GowinImpl::prePlace()
{
place_constrained_hclk_cells();
ctx->assignArchInfo();
assign_cell_info();
fast_logic_cell.reset(ctx->getGridDimX(), ctx->getGridDimY());
for (auto bel : ctx->getBels()) {
@ -632,7 +812,6 @@ void GowinImpl::prePlace()
void GowinImpl::postPlace()
{
gwu.has_SP32();
if (ctx->debug) {
log_info("================== Final Placement ===================\n");
for (auto &cell : ctx->cells) {
@ -673,11 +852,21 @@ void GowinImpl::postRoute()
visited_hclk_users.insert(user.cell->name);
PipId up_pip = h_net->wires.at(ctx->getNetinfoSinkWire(h_net, user, 0)).pip;
IdString up_wire_name = ctx->getWireName(ctx->getPipSrcWire(up_pip))[1];
if (up_wire_name.in(id_HCLK_OUT0, id_HCLK_OUT1, id_HCLK_OUT2, id_HCLK_OUT3)) {
user.cell->setAttr(id_IOLOGIC_FCLK, Property(up_wire_name.str(ctx)));
if (ctx->debug) {
log_info("set IOLOGIC_FCLK to %s\n", up_wire_name.c_str(ctx));
if (!gwu.has_5A_HCLK()) {
if (up_wire_name.in(id_HCLK_OUT0, id_HCLK_OUT1, id_HCLK_OUT2, id_HCLK_OUT3)) {
user.cell->setAttr(id_IOLOGIC_FCLK, Property(up_wire_name.str(ctx)));
if (ctx->debug) {
log_info("set IOLOGIC_FCLK to %s\n", up_wire_name.c_str(ctx));
}
}
} else if (up_wire_name.in(id_HCLK00, id_HCLK10, id_HCLK20, id_HCLK30)) {
user.cell->setAttr(id_IOLOGIC_FCLK, Property("HCLK_OUT0"));
} else if (up_wire_name.in(id_HCLK01, id_HCLK11, id_HCLK21, id_HCLK31)) {
user.cell->setAttr(id_IOLOGIC_FCLK, Property("HCLK_OUT1"));
} else if (up_wire_name.in(id_HCLK02, id_HCLK12, id_HCLK22, id_HCLK32)) {
user.cell->setAttr(id_IOLOGIC_FCLK, Property("HCLK_OUT2"));
} else if (up_wire_name.in(id_HCLK03, id_HCLK13, id_HCLK23, id_HCLK33)) {
user.cell->setAttr(id_IOLOGIC_FCLK, Property("HCLK_OUT3"));
}
if (ctx->debug) {
log_info("HCLK user cell:%s, port:%s, wire:%s, pip:%s, up wire:%s\n",

View File

@ -199,6 +199,19 @@ NPNR_PACKED_STRUCT(struct Constraint_POD {
int32_t iostd;
});
NPNR_PACKED_STRUCT(struct Io2Hclk_POD {
int16_t x;
int16_t y;
int32_t hclk_idx;
});
NPNR_PACKED_STRUCT(struct HclkDiv2_POD {
int16_t hclk_idx;
int16_t x;
int16_t y;
int16_t z;
});
NPNR_PACKED_STRUCT(struct Extra_package_data_POD { RelSlice<Constraint_POD> cst; });
NPNR_PACKED_STRUCT(struct Extra_chip_data_POD {
@ -215,6 +228,8 @@ NPNR_PACKED_STRUCT(struct Extra_chip_data_POD {
RelSlice<Segment_POD> segments;
RelSlice<SpineSelectWire_POD> spine_select_wires_top;
RelSlice<SpineSelectWire_POD> spine_select_wires_bottom;
RelSlice<Io2Hclk_POD> io_to_hclk;
RelSlice<HclkDiv2_POD> hclk_div2;
// chip flags
static constexpr int32_t HAS_SP32 = 1;
@ -233,6 +248,7 @@ NPNR_PACKED_STRUCT(struct Extra_chip_data_POD {
static constexpr int32_t HAS_I2CCFG = 8192;
static constexpr int32_t HAS_5A_DSP = 16384;
static constexpr int32_t NEED_BSRAM_DP_CE_FIX = 32768;
static constexpr int32_t HAS_5A_HCLK = 65536;
});
} // namespace

View File

@ -35,6 +35,7 @@ CHIP_NEED_CFGPINS_INVERSION = 0x1000
CHIP_HAS_I2CCFG = 0x2000
CHIP_HAS_5A_DSP = 0x4000
CHIP_NEED_BSRAM_DP_CE_FIX = 0x8000
CHIP_HAS_5A_HCLK = 0x10000
# Tile flags
TILE_I3C_CAPABLE_IO = 0x1
@ -292,6 +293,35 @@ class SpineSelectWire(BBAStruct):
bba.u32(self.wire.index)
bba.u32(self.vcc_gnd)
@dataclass
class Io2Hclk(BBAStruct):
x: int
y: int
hclk_idx: int
def serialise_lists(self, context: str, bba: BBAWriter):
pass
def serialise(self, context: str, bba: BBAWriter):
bba.u16(self.x)
bba.u16(self.y)
bba.u32(self.hclk_idx)
@dataclass
class HclkDiv2(BBAStruct):
hclk_idx: int
# CLKDIV2 location
x: int
y: int
z: int
def serialise_lists(self, context: str, bba: BBAWriter):
pass
def serialise(self, context: str, bba: BBAWriter):
bba.u16(self.hclk_idx)
bba.u16(self.x)
bba.u16(self.y)
bba.u16(self.z)
@dataclass
class ChipExtraData(BBAStruct):
strs: StringPool
@ -308,6 +338,8 @@ class ChipExtraData(BBAStruct):
segments: list[Segment] = field(default_factory = list)
spine_select_wires_top: list[SpineSelectWire] = field(default_factory = list)
spine_select_wires_bottom: list[SpineSelectWire] = field(default_factory = list)
io_to_hclk: list[Io2Hclk] = field(default_factory = list)
hclk_div2: list[HclkDiv2] = field(default_factory = list)
def set_dcs_prefix(self, prefix: str):
self.dcs_prefix = self.strs.id(prefix)
@ -354,6 +386,12 @@ class ChipExtraData(BBAStruct):
def add_spine_select_wire_bottom(self, spine: str, x: int, y: int, wire: str, vcc_gnd: int):
self.spine_select_wires_bottom.append(SpineSelectWire(self.strs.id(spine), x, y, self.strs.id(wire), vcc_gnd))
def add_io2hclk(self, hclk_idx: int, x: int, y: int):
self.io_to_hclk.append(Io2Hclk(x, y, hclk_idx))
def add_hclkdiv2(self, hclk_idx: int, x: int, y: int, z: int):
self.hclk_div2.append(HclkDiv2(hclk_idx, x, y, z))
def serialise_lists(self, context: str, bba: BBAWriter):
self.bottom_io.serialise_lists(f"{context}_bottom_io", bba)
for i, t in enumerate(self.segments):
@ -382,6 +420,12 @@ class ChipExtraData(BBAStruct):
bba.label(f"{context}_spine_select_wires_bottom")
for i, t in enumerate(self.spine_select_wires_bottom):
t.serialise(f"{context}_spine_select_wire_bottom{i}", bba)
bba.label(f"{context}_io_to_hclk")
for i, t in enumerate(self.io_to_hclk):
t.serialise(f"{context}_io_to_hclk{i}", bba)
bba.label(f"{context}_hclk_div2")
for i, t in enumerate(self.hclk_div2):
t.serialise(f"{context}_hclk_div2{i}", bba)
def serialise(self, context: str, bba: BBAWriter):
bba.u32(self.flags)
@ -397,6 +441,8 @@ class ChipExtraData(BBAStruct):
bba.slice(f"{context}_segments", len(self.segments))
bba.slice(f"{context}_spine_select_wires_top", len(self.spine_select_wires_top))
bba.slice(f"{context}_spine_select_wires_bottom", len(self.spine_select_wires_bottom))
bba.slice(f"{context}_io_to_hclk", len(self.io_to_hclk))
bba.slice(f"{context}_hclk_div2", len(self.hclk_div2))
@dataclass
class PackageExtraData(BBAStruct):
@ -859,6 +905,18 @@ def create_extra_funcs(tt: TileType, db: chipdb, x: int, y: int):
tt.create_wire('VCC', 'VCC', const_value = 'VCC')
gnd = tt.create_bel('VCC', 'VCC', z = VCC_Z)
tt.add_bel_pin(gnd, "V", "VCC", PinType.OUTPUT)
elif func == 'clkdiv2':
for i, pins in desc['bels'].items():
clkdiv2 = tt.create_bel(f"CLKDIV2_{i}", "CLKDIV2", z = CLKDIV2_0_Z + i)
for pin, wire in pins['outputs'].items():
tt.create_wire(wire, "HCLK")
tt.add_bel_pin(clkdiv2, pin, wire, PinType.OUTPUT)
for pin, wire in pins['inputs'].items():
if pin == 'RESETN':
tt.create_wire(wire, "")
else:
tt.create_wire(wire, "HCLK")
tt.add_bel_pin(clkdiv2, pin, wire, PinType.INPUT)
def set_wire_flags(tt: TileType, tdesc: TypeDesc):
@ -1617,6 +1675,14 @@ def create_extra_data(chip: Chip, db: chipdb, chip_flags: int):
for spine, wire_desc in db.spine_select_wires['bottom'].items():
for y, x, wire, vcc_gnd in wire_desc:
chip.extra_data.add_spine_select_wire_bottom(spine, x, y, wire, vcc_gnd)
# create HCLK<->IO and HCLK<->CLKDIV2
if hasattr(db, "io2hclk"):
for hclk_idx, ios in db.io2hclk.items():
for row_col in ios:
chip.extra_data.add_io2hclk(hclk_idx, row_col[1], row_col[0])
for hclk_idx, div2 in db.hclk_div2.items():
for row_col_idx in div2:
chip.extra_data.add_hclkdiv2(hclk_idx, row_col_idx[1], row_col_idx[0], row_col_idx[2] + CLKDIV2_0_Z)
def create_timing_info(chip: Chip, db: chipdb.Device):
def group_to_timingvalue(group):
@ -1847,6 +1913,8 @@ def main():
chip_flags |= CHIP_HAS_I2CCFG;
if "HAS_5A_DSP" in db.chip_flags:
chip_flags |= CHIP_HAS_5A_DSP;
if "HAS_5A_HCLK" in db.chip_flags:
chip_flags |= CHIP_HAS_5A_HCLK;
X = db.cols;
Y = db.rows;

View File

@ -368,7 +368,7 @@ IdString GowinUtils::get_bottom_io_wire_b_net(int8_t condition)
return IdString(extra->bottom_io.conditions[condition].wire_b_net);
}
bool GowinUtils::has_BANDGAP(void)
bool GowinUtils::has_BANDGAP(void) const
{
const Extra_chip_data_POD *extra = reinterpret_cast<const Extra_chip_data_POD *>(ctx->chip_info->extra_data.get());
return extra->chip_flags & Extra_chip_data_POD::HAS_BANDGAP;
@ -425,60 +425,66 @@ bool GowinUtils::has_CIN_MUX(void) const
return extra->chip_flags & Extra_chip_data_POD::HAS_CIN_MUX;
}
bool GowinUtils::has_SP32(void)
bool GowinUtils::has_SP32(void) const
{
const Extra_chip_data_POD *extra = reinterpret_cast<const Extra_chip_data_POD *>(ctx->chip_info->extra_data.get());
return extra->chip_flags & Extra_chip_data_POD::HAS_SP32;
}
bool GowinUtils::need_SP_fix(void)
bool GowinUtils::need_SP_fix(void) const
{
const Extra_chip_data_POD *extra = reinterpret_cast<const Extra_chip_data_POD *>(ctx->chip_info->extra_data.get());
return extra->chip_flags & Extra_chip_data_POD::NEED_SP_FIX;
}
bool GowinUtils::need_SDP_fix(void)
bool GowinUtils::need_SDP_fix(void) const
{
const Extra_chip_data_POD *extra = reinterpret_cast<const Extra_chip_data_POD *>(ctx->chip_info->extra_data.get());
return extra->chip_flags & Extra_chip_data_POD::NEED_SDP_FIX;
}
bool GowinUtils::need_BSRAM_OUTREG_fix(void)
bool GowinUtils::need_BSRAM_OUTREG_fix(void) const
{
const Extra_chip_data_POD *extra = reinterpret_cast<const Extra_chip_data_POD *>(ctx->chip_info->extra_data.get());
return extra->chip_flags & Extra_chip_data_POD::NEED_BSRAM_OUTREG_FIX;
}
bool GowinUtils::need_BSRAM_DP_CE_fix(void)
bool GowinUtils::need_BSRAM_DP_CE_fix(void) const
{
const Extra_chip_data_POD *extra = reinterpret_cast<const Extra_chip_data_POD *>(ctx->chip_info->extra_data.get());
return extra->chip_flags & Extra_chip_data_POD::NEED_BSRAM_DP_CE_FIX;
}
bool GowinUtils::need_BSRAM_RESET_fix(void)
bool GowinUtils::need_BSRAM_RESET_fix(void) const
{
const Extra_chip_data_POD *extra = reinterpret_cast<const Extra_chip_data_POD *>(ctx->chip_info->extra_data.get());
return extra->chip_flags & Extra_chip_data_POD::NEED_BSRAM_RESET_FIX;
}
bool GowinUtils::need_BLKSEL_fix(void)
bool GowinUtils::need_BLKSEL_fix(void) const
{
const Extra_chip_data_POD *extra = reinterpret_cast<const Extra_chip_data_POD *>(ctx->chip_info->extra_data.get());
return extra->chip_flags & Extra_chip_data_POD::NEED_BLKSEL_FIX;
}
bool GowinUtils::has_PLL_HCLK(void)
bool GowinUtils::has_PLL_HCLK(void) const
{
const Extra_chip_data_POD *extra = reinterpret_cast<const Extra_chip_data_POD *>(ctx->chip_info->extra_data.get());
return extra->chip_flags & Extra_chip_data_POD::HAS_PLL_HCLK;
}
bool GowinUtils::has_CLKDIV_HCLK(void)
bool GowinUtils::has_CLKDIV_HCLK(void) const
{
const Extra_chip_data_POD *extra = reinterpret_cast<const Extra_chip_data_POD *>(ctx->chip_info->extra_data.get());
return extra->chip_flags & Extra_chip_data_POD::HAS_CLKDIV_HCLK;
}
bool GowinUtils::has_5A_HCLK(void) const
{
const Extra_chip_data_POD *extra = reinterpret_cast<const Extra_chip_data_POD *>(ctx->chip_info->extra_data.get());
return extra->chip_flags & Extra_chip_data_POD::HAS_5A_HCLK;
}
IdString GowinUtils::create_aux_name(IdString main_name, int idx, const char *str_suffix)
{
return idx ? ctx->idf("%s%s%d", main_name.c_str(ctx), str_suffix, idx)
@ -634,6 +640,29 @@ CellInfo *GowinUtils::dsp_bus_dst(const CellInfo *ci, const char *bus_prefix, in
return connected_to_cell;
}
int GowinUtils::get_hclk_for_io(Loc io_loc) const
{
const Extra_chip_data_POD *extra = reinterpret_cast<const Extra_chip_data_POD *>(ctx->chip_info->extra_data.get());
for (auto &io_hclk : extra->io_to_hclk) {
if (io_hclk.x == io_loc.x && io_hclk.y == io_loc.y) {
return io_hclk.hclk_idx;
}
}
return -1;
}
// Location of clkdiv2 for HCLK
void GowinUtils::get_clkdiv2_locs(int hclk_idx, std::vector<Loc> &locs)
{
const Extra_chip_data_POD *extra = reinterpret_cast<const Extra_chip_data_POD *>(ctx->chip_info->extra_data.get());
locs.clear();
for (auto &hclk_div2 : extra->hclk_div2) {
if (hclk_div2.hclk_idx == hclk_idx) {
locs.push_back(Loc(hclk_div2.x, hclk_div2.y, hclk_div2.z));
}
}
}
// Use the upper CLKDIV as the id for a hclk section
IdStringList GowinUtils::get_hclk_id(BelId hclk_bel) const
{

View File

@ -106,18 +106,19 @@ struct GowinUtils
bool get_spine_select_wire(WireId spine, std::vector<std::pair<WireId, int>> &);
// BSRAM
bool has_SP32(void);
bool need_SP_fix(void);
bool need_SDP_fix(void);
bool need_BSRAM_OUTREG_fix(void);
bool need_BSRAM_DP_CE_fix(void);
bool need_BSRAM_RESET_fix(void);
bool need_BLKSEL_fix(void);
bool has_PLL_HCLK(void);
bool has_CLKDIV_HCLK(void);
bool has_SP32(void) const;
bool need_SP_fix(void) const;
bool need_SDP_fix(void) const;
bool need_BSRAM_OUTREG_fix(void) const;
bool need_BSRAM_DP_CE_fix(void) const;
bool need_BSRAM_RESET_fix(void) const;
bool need_BLKSEL_fix(void) const;
bool has_PLL_HCLK(void) const;
bool has_CLKDIV_HCLK(void) const;
bool has_5A_HCLK(void) const;
// Power saving
bool has_BANDGAP(void);
bool has_BANDGAP(void) const;
// Pin function configuration via wires
bool has_PINCFG(void) const;
@ -192,6 +193,8 @@ struct GowinUtils
std::unique_ptr<CellInfo> create_cell(IdString name, IdString type);
// HCLK
void get_clkdiv2_locs(int hclk_idx, std::vector<Loc> &locs);
int get_hclk_for_io(Loc io_loc) const;
BelId get_clkdiv_for_clkdiv2(BelId clkdiv2_bel) const;
BelId get_other_hclk_clkdiv2(BelId clkdiv2_bel) const;
BelId get_other_hclk_clkdiv(BelId clkdiv_bel) const;

View File

@ -203,7 +203,7 @@ void GowinPacker::pack_single_output_iol(CellInfo &ci, std::vector<IdString> &ne
out_mode = "EMPTY";
break;
case ID_OVIDEO:
out_mode = "VIDEORX";
out_mode = "VIDEOTX";
break;
case ID_OSER10:
out_mode = "ODDRX5";