gowin: Himbaechel. Allow to combine IOLOGIC.

Corrects the situation when it is impossible to use IOBUF with two
IOLOGIC elements at the same time - input and output.

Addresses https://github.com/YosysHQ/nextpnr/issues/1275

This is done by dividing one IOLOGIC Bel into two - input IOLOGIC and
output IOLOGIC plus checking for compatibility of the cells located
there.

At the moment, this check is simple and allows only the combination of
DDR and DDRC primitives.

Signed-off-by: YRabbit <rabbit@yrabbit.cyou>
This commit is contained in:
YRabbit 2024-02-09 17:44:57 +10:00 committed by myrtle
parent 4981ebb698
commit 4e8436a1fc
6 changed files with 91 additions and 37 deletions

View File

@ -797,7 +797,8 @@ X(IDES8)
X(IDES10)
X(IVIDEO)
X(IDES16)
X(IOLOGIC)
X(IOLOGICI)
X(IOLOGICO)
X(IOLOGICA)
X(IOLOGICB)
X(IOLOGIC_TYPE)

View File

@ -200,7 +200,8 @@ void GowinImpl::postRoute()
for (auto &cell : ctx->cells) {
auto ci = cell.second.get();
if (ci->type == id_IOLOGIC || (is_iologic(ci) && !ci->type.in(id_ODDR, id_ODDRC, id_IDDR, id_IDDRC))) {
if (ci->type.in(id_IOLOGICI, id_IOLOGICO) ||
((is_iologici(ci) || is_iologico(ci)) && !ci->type.in(id_ODDR, id_ODDRC, id_IDDR, id_IDDRC))) {
if (visited_hclk_users.find(ci->name) == visited_hclk_users.end()) {
// mark FCLK<-HCLK connections
const NetInfo *h_net = ci->getPort(id_FCLK);
@ -269,8 +270,11 @@ IdString GowinImpl::getBelBucketForCellType(IdString cell_type) const
if (type_is_ssram(cell_type)) {
return id_RAM16SDP4;
}
if (type_is_iologic(cell_type)) {
return id_IOLOGIC;
if (type_is_iologici(cell_type)) {
return id_IOLOGICI;
}
if (type_is_iologico(cell_type)) {
return id_IOLOGICO;
}
if (type_is_bsram(cell_type)) {
return id_BSRAM;
@ -299,8 +303,11 @@ bool GowinImpl::isValidBelForCellType(IdString cell_type, BelId bel) const
if (bel_type == id_RAM16SDP4) {
return type_is_ssram(cell_type);
}
if (bel_type == id_IOLOGIC) {
return type_is_iologic(cell_type);
if (bel_type == id_IOLOGICI) {
return type_is_iologici(cell_type);
}
if (bel_type == id_IOLOGICO) {
return type_is_iologico(cell_type);
}
if (bel_type == id_BSRAM) {
return type_is_bsram(cell_type);

View File

@ -28,12 +28,19 @@ inline bool type_is_diffio(IdString cell_type)
}
inline bool is_diffio(const CellInfo *cell) { return type_is_diffio(cell->type); }
inline bool type_is_iologic(IdString cell_type)
// IOLOGIC input and output separately
inline bool type_is_iologico(IdString cell_type)
{
return cell_type.in(id_ODDR, id_ODDRC, id_OSER4, id_OSER8, id_OSER10, id_OVIDEO, id_IDDR, id_IDDRC, id_IDES4,
id_IDES8, id_IDES10, id_IVIDEO);
return cell_type.in(id_ODDR, id_ODDRC, id_OSER4, id_OSER8, id_OSER10, id_OVIDEO);
}
inline bool is_iologic(const CellInfo *cell) { return type_is_iologic(cell->type); }
inline bool is_iologico(const CellInfo *cell) { return type_is_iologico(cell->type); }
inline bool type_is_iologici(IdString cell_type)
{
return cell_type.in(id_IDDR, id_IDDRC, id_IDES4, id_IDES8, id_IDES10, id_IVIDEO);
}
inline bool is_iologici(const CellInfo *cell) { return type_is_iologici(cell->type); }
// Return true if a cell is a SSRAM
inline bool type_is_ssram(IdString cell_type) { return cell_type.in(id_RAM16SDP1, id_RAM16SDP2, id_RAM16SDP4); }
@ -96,10 +103,10 @@ enum
IOBB_Z = 51, // +IOBC...IOBL
IOLOGICA_Z = 70,
IDES16_Z = 72,
OSER16_Z = 73,
IDES16_Z = 74,
OSER16_Z = 75,
BUFG_Z = 74, // : 81 reserve just in case
BUFG_Z = 76, // : 81 reserve just in case
BSRAM_Z = 100,
OSC_Z = 274,

View File

@ -32,10 +32,10 @@ IOBA_Z = 50
IOBB_Z = 51
IOLOGICA_Z = 70
IDES16_Z = 72
OSER16_Z = 73
IDES16_Z = 74
OSER16_Z = 75
BUFG_Z = 74 # : 81 reserve just in case
BUFG_Z = 76 # : 81 reserve just in case
BSRAM_Z = 100
OSC_Z = 274
@ -438,19 +438,20 @@ def create_io_tiletype(chip: Chip, db: chipdb, x: int, y: int, ttyp: int, tdesc:
for idx, name in {(IOLOGICA_Z, 'IOLOGICA'), (IOLOGICA_Z + 1, 'IOLOGICB')}:
if name not in db.grid[y][x].bels:
continue
iol = tt.create_bel(name, "IOLOGIC", z = idx)
for port, wire in db.grid[y][x].bels[name].portmap.items():
if port == 'FCLK': # XXX compatibility
wire = f'FCLK{name[-1]}'
if not tt.has_wire(wire):
if port in {'CLK', 'PCLK'}:
tt.create_wire(wire, "TILE_CLK")
for off, io_type in {(0, 'O'), (2, 'I')}:
iol = tt.create_bel(f"{name}{io_type}", f"IOLOGIC{io_type}", z = idx + off)
for port, wire in db.grid[y][x].bels[name].portmap.items():
if port == 'FCLK': # XXX compatibility
wire = f'FCLK{name[-1]}'
if not tt.has_wire(wire):
if port in {'CLK', 'PCLK'}:
tt.create_wire(wire, "TILE_CLK")
else:
tt.create_wire(wire, "IOL_PORT")
if port in {'Q', 'Q0', 'Q1', 'Q2', 'Q3', 'Q4', 'Q5', 'Q6', 'Q7', 'Q8', 'Q9', 'DF', 'LAG', 'LEAD'}:
tt.add_bel_pin(iol, port, wire, PinType.OUTPUT)
else:
tt.create_wire(wire, "IOL_PORT")
if port in {'Q', 'Q0', 'Q1', 'Q2', 'Q3', 'Q4', 'Q5', 'Q6', 'Q7', 'Q8', 'Q9', 'DF', 'LAG', 'LEAD'}:
tt.add_bel_pin(iol, port, wire, PinType.OUTPUT)
else:
tt.add_bel_pin(iol, port, wire, PinType.INPUT)
tt.add_bel_pin(iol, port, wire, PinType.INPUT)
tdesc.tiletype = tiletype
return tt

View File

@ -52,14 +52,15 @@ bool GowinUtils::is_simple_io_bel(BelId bel)
Loc GowinUtils::get_pair_iologic_bel(Loc loc)
{
loc.z = BelZ::IOLOGICA_Z + (1 - (loc.z - BelZ::IOLOGICA_Z));
int const z[] = {1, 0, 3, 2};
loc.z = BelZ::IOLOGICA_Z + z[(loc.z - BelZ::IOLOGICA_Z)];
return loc;
}
BelId GowinUtils::get_io_bel_from_iologic(BelId bel)
{
Loc loc = ctx->getBelLocation(bel);
loc.z = BelZ::IOBA_Z + loc.z - BelZ::IOLOGICA_Z;
loc.z = BelZ::IOBA_Z + ((loc.z - BelZ::IOLOGICA_Z) & 1);
return ctx->getBelByLocation(loc);
}

View File

@ -347,7 +347,7 @@ struct GowinPacker
}
}
BelId get_iologic_bel(CellInfo *iob)
BelId get_iologico_bel(CellInfo *iob)
{
NPNR_ASSERT(iob->bel != BelId());
Loc loc = ctx->getBelLocation(iob->bel);
@ -355,6 +355,14 @@ struct GowinPacker
return ctx->getBelByLocation(loc);
}
BelId get_iologici_bel(CellInfo *iob)
{
NPNR_ASSERT(iob->bel != BelId());
Loc loc = ctx->getBelLocation(iob->bel);
loc.z = loc.z - BelZ::IOBA_Z + BelZ::IOLOGICA_Z + 2;
return ctx->getBelByLocation(loc);
}
void check_iologic_placement(CellInfo &ci, Loc iob_loc, int diff /* 1 - diff */)
{
if (ci.type.in(id_ODDR, id_ODDRC, id_IDDR, id_IDDRC, id_OSER4) || diff) {
@ -367,6 +375,26 @@ struct GowinPacker
}
}
// While we require an exact match of the type, in the future the criteria
// may be relaxed and there will be a comparison of the control networks
// used.
bool are_iologic_compatible(CellInfo *ci_0, CellInfo *ci_1)
{
switch (ci_0->type.hash()) {
case ID_ODDR:
return ci_1->type == id_IDDR;
case ID_ODDRC:
return ci_1->type == id_IDDRC;
case ID_IDDR:
return ci_1->type == id_ODDR;
case ID_IDDRC:
return ci_1->type == id_ODDRC;
default:
return false;
}
return false;
}
void pack_bi_output_iol(CellInfo &ci, std::vector<IdString> &nets_to_remove)
{
// These primitives have an additional pin to control the tri-state iob - Q1.
@ -377,7 +405,16 @@ struct GowinPacker
NPNR_ASSERT(out_iob != nullptr && out_iob->bel != BelId());
BelId iob_bel = out_iob->bel;
BelId l_bel = get_iologic_bel(out_iob);
BelId l_bel = get_iologico_bel(out_iob);
// check compatible Input and Output iologic if any
BelId in_l_bel = get_iologici_bel(out_iob);
if (in_l_bel != BelId() && !ctx->checkBelAvail(in_l_bel)) {
CellInfo *in_iologic_ci = ctx->getBoundBelCell(in_l_bel);
if (!are_iologic_compatible(&ci, in_iologic_ci)) {
log_error("IOLOGIC %s at %s cannot coexist with %s\n", ctx->nameOf(&ci), ctx->nameOfBel(iob_bel),
ctx->nameOf(in_iologic_ci));
}
}
if (l_bel == BelId()) {
log_error("Can't place IOLOGIC %s at %s\n", ctx->nameOf(&ci), ctx->nameOfBel(iob_bel));
}
@ -434,7 +471,7 @@ struct GowinPacker
NPNR_ASSERT(out_iob != nullptr && out_iob->bel != BelId());
BelId iob_bel = out_iob->bel;
BelId l_bel = get_iologic_bel(out_iob);
BelId l_bel = get_iologico_bel(out_iob);
if (l_bel == BelId()) {
log_error("Can't place IOLOGIC %s at %s\n", ctx->nameOf(&ci), ctx->nameOfBel(iob_bel));
}
@ -554,7 +591,7 @@ struct GowinPacker
NPNR_ASSERT(in_iob != nullptr && in_iob->bel != BelId());
BelId iob_bel = in_iob->bel;
BelId l_bel = get_iologic_bel(in_iob);
BelId l_bel = get_iologici_bel(in_iob);
if (l_bel == BelId()) {
log_error("Can't place IOLOGIC %s at %s\n", ctx->nameOf(&ci), ctx->nameOfBel(iob_bel));
}
@ -605,7 +642,7 @@ struct GowinPacker
for (auto &cell : ctx->cells) {
CellInfo &ci = *cell.second;
if (!is_iologic(&ci)) {
if (!(is_iologici(&ci) || is_iologico(&ci))) {
continue;
}
if (ctx->debug) {
@ -704,7 +741,7 @@ struct GowinPacker
aux->setParam(ctx->id("UPDATE"), Property("SAME"));
// make cell in the next location
ctx->createCell(main_name, id_IOLOGIC);
ctx->createCell(main_name, id_IOLOGICO);
aux = ctx->cells.at(main_name).get();
aux->setAttr(ctx->id("MAIN_CELL"), Property(main_name.str(ctx)));
@ -777,7 +814,7 @@ struct GowinPacker
ci.copyPortTo(id_CALIB, aux, id_CALIB);
// make cell in the next location
ctx->createCell(main_name, id_IOLOGIC);
ctx->createCell(main_name, id_IOLOGICI);
aux = ctx->cells.at(main_name).get();
aux->setAttr(ctx->id("MAIN_CELL"), Property(main_name.str(ctx)));