From 4e8436a1fc6904b3d66dafaa20e15082470fc41c Mon Sep 17 00:00:00 2001 From: YRabbit Date: Fri, 9 Feb 2024 17:44:57 +1000 Subject: [PATCH] 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 --- himbaechel/uarch/gowin/constids.inc | 3 +- himbaechel/uarch/gowin/gowin.cc | 17 +++++--- himbaechel/uarch/gowin/gowin.h | 21 ++++++---- himbaechel/uarch/gowin/gowin_arch_gen.py | 31 +++++++------- himbaechel/uarch/gowin/gowin_utils.cc | 5 ++- himbaechel/uarch/gowin/pack.cc | 51 ++++++++++++++++++++---- 6 files changed, 91 insertions(+), 37 deletions(-) diff --git a/himbaechel/uarch/gowin/constids.inc b/himbaechel/uarch/gowin/constids.inc index f357783c..7b888ee8 100644 --- a/himbaechel/uarch/gowin/constids.inc +++ b/himbaechel/uarch/gowin/constids.inc @@ -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) diff --git a/himbaechel/uarch/gowin/gowin.cc b/himbaechel/uarch/gowin/gowin.cc index cae8f1ab..0b80fd50 100644 --- a/himbaechel/uarch/gowin/gowin.cc +++ b/himbaechel/uarch/gowin/gowin.cc @@ -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); diff --git a/himbaechel/uarch/gowin/gowin.h b/himbaechel/uarch/gowin/gowin.h index 79fc4ea7..715f54e6 100644 --- a/himbaechel/uarch/gowin/gowin.h +++ b/himbaechel/uarch/gowin/gowin.h @@ -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, diff --git a/himbaechel/uarch/gowin/gowin_arch_gen.py b/himbaechel/uarch/gowin/gowin_arch_gen.py index 413801f4..2f96ee55 100644 --- a/himbaechel/uarch/gowin/gowin_arch_gen.py +++ b/himbaechel/uarch/gowin/gowin_arch_gen.py @@ -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 diff --git a/himbaechel/uarch/gowin/gowin_utils.cc b/himbaechel/uarch/gowin/gowin_utils.cc index e19c64c8..4aec5e50 100644 --- a/himbaechel/uarch/gowin/gowin_utils.cc +++ b/himbaechel/uarch/gowin/gowin_utils.cc @@ -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); } diff --git a/himbaechel/uarch/gowin/pack.cc b/himbaechel/uarch/gowin/pack.cc index 1045c76c..8133e46a 100644 --- a/himbaechel/uarch/gowin/pack.cc +++ b/himbaechel/uarch/gowin/pack.cc @@ -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 &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)));