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)));