diff --git a/himbaechel/uarch/gowin/gowin.cc b/himbaechel/uarch/gowin/gowin.cc index 2ff3555f..2ce0550f 100644 --- a/himbaechel/uarch/gowin/gowin.cc +++ b/himbaechel/uarch/gowin/gowin.cc @@ -175,7 +175,7 @@ void GowinImpl::postRoute() for (auto &cell : ctx->cells) { auto ci = cell.second.get(); - if (is_iologic(ci) && !ci->type.in(id_ODDR, id_ODDRC, id_IDDR, id_IDDRC)) { + if (ci->type == id_IOLOGIC || (is_iologic(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); @@ -192,6 +192,9 @@ void GowinImpl::postRoute() 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 (ctx->debug) { log_info("HCLK user cell:%s, port:%s, wire:%s, pip:%s, up wire:%s\n", diff --git a/himbaechel/uarch/gowin/gowin.h b/himbaechel/uarch/gowin/gowin.h index 239157ea..7086bfde 100644 --- a/himbaechel/uarch/gowin/gowin.h +++ b/himbaechel/uarch/gowin/gowin.h @@ -39,7 +39,15 @@ inline bool is_iologic(const CellInfo *cell) { return type_is_iologic(cell->type inline bool type_is_ssram(IdString cell_type) { return cell_type.in(id_RAM16SDP1, id_RAM16SDP2, id_RAM16SDP4); } inline bool is_ssram(const CellInfo *cell) { return type_is_ssram(cell->type); } +// ========================================== // extra data in the chip db +// ========================================== +NPNR_PACKED_STRUCT(struct Tile_extra_data_POD { + int32_t class_id; + int16_t io16_x_off; + int16_t io16_y_off; +}); + NPNR_PACKED_STRUCT(struct Bottom_io_cnd_POD { int32_t wire_a_net; int32_t wire_b_net; @@ -77,6 +85,8 @@ enum IOBB_Z = 51, // +IOBC...IOBL IOLOGICA_Z = 70, + IDES16_Z = 72, + OSER16_Z = 73, OSC_Z = 274, PLL_Z = 275, diff --git a/himbaechel/uarch/gowin/gowin_arch_gen.py b/himbaechel/uarch/gowin/gowin_arch_gen.py index 805f99b7..93dcc494 100644 --- a/himbaechel/uarch/gowin/gowin_arch_gen.py +++ b/himbaechel/uarch/gowin/gowin_arch_gen.py @@ -29,6 +29,8 @@ IOBA_Z = 50 IOBB_Z = 51 IOLOGICA_Z = 70 +IDES16_Z = 72 +OSER16_Z = 73 OSC_Z = 274 PLL_Z = 275 @@ -45,10 +47,15 @@ class TileExtraData(BBAStruct): # let's say the behavior of LUT+DFF in the tiles are completely identical, # but one of them also contains clock-wire switches, # then we assign them to the same LOGIC class. + io16_x_off: int = 0 # OSER16/IDES16 offsets to the aux cell + io16_y_off: int = 0 + def serialise_lists(self, context: str, bba: BBAWriter): pass def serialise(self, context: str, bba: BBAWriter): bba.u32(self.tile_class.index) + bba.u16(self.io16_x_off) + bba.u16(self.io16_y_off) @dataclass class BottomIOCnd(BBAStruct): @@ -262,6 +269,28 @@ def create_extra_funcs(tt: TileType, db: chipdb, x: int, y: int): tt.create_wire(wire, "GSRI") bel = tt.create_bel("GSR", "GSR", z = GSR_Z) tt.add_bel_pin(bel, "GSRI", wire, PinType.INPUT) + if func == 'io16': + role = desc['role'] + if role == 'MAIN': + y_off, x_off = desc['pair'] + tt.extra_data.io16_x_off = x_off + tt.extra_data.io16_y_off = y_off + + for io_type, z in {('IDES16', IDES16_Z), ('OSER16', OSER16_Z)}: + bel = tt.create_bel(io_type, io_type, z = z) + portmap = db.grid[y][x].bels[io_type].portmap + for port, wire in portmap.items(): + if port == 'FCLK': # XXX compatibility + wire = 'FCLKA' + 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 'OUT' in port: + tt.add_bel_pin(bel, port, wire, PinType.OUTPUT) + else: + tt.add_bel_pin(bel, port, wire, PinType.INPUT) def create_tiletype(create_func, chip: Chip, db: chipdb, x: int, y: int, ttyp: int): has_extra_func = (y, x) in db.extra_func diff --git a/himbaechel/uarch/gowin/gowin_utils.cc b/himbaechel/uarch/gowin/gowin_utils.cc index 3c23be50..16b39d47 100644 --- a/himbaechel/uarch/gowin/gowin_utils.cc +++ b/himbaechel/uarch/gowin/gowin_utils.cc @@ -11,6 +11,24 @@ NEXTPNR_NAMESPACE_BEGIN +// tile extra data +IdString GowinUtils::get_tile_class(int x, int y) +{ + int tile = tile_by_xy(ctx->chip_info, x, y); + const Tile_extra_data_POD *extra = + reinterpret_cast(chip_tile_info(ctx->chip_info, tile).extra_data.get()); + return IdString(extra->class_id); +} + +// oser16/ides16 aux cell offsets +Loc GowinUtils::get_tile_io16_offs(int x, int y) +{ + int tile = tile_by_xy(ctx->chip_info, x, y); + const Tile_extra_data_POD *extra = + reinterpret_cast(chip_tile_info(ctx->chip_info, tile).extra_data.get()); + return Loc(extra->io16_x_off, extra->io16_y_off, 0); +} + // pin functions: GCLKT_4, SSPI_CS, READY etc IdStringList GowinUtils::get_pin_funcs(BelId bel) { diff --git a/himbaechel/uarch/gowin/gowin_utils.h b/himbaechel/uarch/gowin/gowin_utils.h index 5d544a74..b88e9b7a 100644 --- a/himbaechel/uarch/gowin/gowin_utils.h +++ b/himbaechel/uarch/gowin/gowin_utils.h @@ -19,6 +19,10 @@ struct GowinUtils void init(Context *ctx) { this->ctx = ctx; } + // tile + IdString get_tile_class(int x, int y); + Loc get_tile_io16_offs(int x, int y); + // pin functions: GCLKT_4, SSPI_CS, READY etc IdStringList get_pin_funcs(BelId bel); diff --git a/himbaechel/uarch/gowin/pack.cc b/himbaechel/uarch/gowin/pack.cc index 79070040..1b6aa4c1 100644 --- a/himbaechel/uarch/gowin/pack.cc +++ b/himbaechel/uarch/gowin/pack.cc @@ -332,7 +332,19 @@ struct GowinPacker return ctx->getBelByLocation(loc); } - void pack_bi_output_iol(CellInfo &ci, std::vector &cells_to_remove, std::vector &nets_to_remove) + 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) || diff) { + return; + } + BelId l_bel = ctx->getBelByLocation(Loc(iob_loc.x, iob_loc.y, BelZ::IOBA_Z + 1 - (iob_loc.z - BelZ::IOBA_Z))); + if (!ctx->checkBelAvail(l_bel)) { + log_error("Can't place %s at %s because it's already taken by %s\n", ctx->nameOf(&ci), + ctx->nameOfBel(l_bel), ctx->nameOf(ctx->getBoundBelCell(l_bel))); + } + } + + 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. IdString out_port = id_Q0; @@ -346,6 +358,9 @@ struct GowinPacker if (l_bel == BelId()) { log_error("Can't place IOLOGIC %s at %s\n", ctx->nameOf(&ci), ctx->nameOfBel(iob_bel)); } + // mark IOB as used by IOLOGIC + out_iob->setParam(id_IOLOGIC_IOB, 1); + check_iologic_placement(ci, ctx->getBelLocation(iob_bel), out_iob->attrs.count(id_DIFF_TYPE)); if (!ctx->checkBelAvail(l_bel)) { log_error("Can't place %s at %s because it's already taken by %s\n", ctx->nameOf(&ci), @@ -367,8 +382,6 @@ struct GowinPacker } ci.setParam(ctx->id("OUTMODE"), out_mode); - // mark IOB as used by IOLOGIC - out_iob->setParam(id_IOLOGIC_IOB, 1); // disconnect Q output: it is wired internally nets_to_remove.push_back(ci.getPort(out_port)->name); out_iob->disconnectPort(id_I); @@ -390,8 +403,7 @@ struct GowinPacker make_iob_nets(*out_iob); } - void pack_single_output_iol(CellInfo &ci, std::vector &cells_to_remove, - std::vector &nets_to_remove) + void pack_single_output_iol(CellInfo &ci, std::vector &nets_to_remove) { IdString out_port = id_Q; @@ -403,6 +415,9 @@ struct GowinPacker if (l_bel == BelId()) { log_error("Can't place IOLOGIC %s at %s\n", ctx->nameOf(&ci), ctx->nameOfBel(iob_bel)); } + // mark IOB as used by IOLOGIC + out_iob->setParam(id_IOLOGIC_IOB, 1); + check_iologic_placement(ci, ctx->getBelLocation(iob_bel), out_iob->attrs.count(id_DIFF_TYPE)); if (!ctx->checkBelAvail(l_bel)) { log_error("Can't place %s at %s because it's already taken by %s\n", ctx->nameOf(&ci), @@ -420,8 +435,6 @@ struct GowinPacker } ci.setParam(ctx->id("OUTMODE"), out_mode); - // mark IOB as used by IOLOGIC - out_iob->setParam(id_IOLOGIC_IOB, 1); // disconnect Q output: it is wired internally nets_to_remove.push_back(ci.getPort(out_port)->name); out_iob->disconnectPort(id_I); @@ -451,12 +464,12 @@ struct GowinPacker bool is_diff_io(BelId bel) { return ctx->getBoundBelCell(bel)->attrs.count(id_DIFF_TYPE) != 0; } - void create_aux_iologic_cells(CellInfo &ci, IdString mode) + CellInfo *create_aux_iologic_cell(CellInfo &ci, IdString mode, bool io16 = false, int idx = 0) { if (ci.type.in(id_ODDR, id_ODDRC, id_OSER4, id_IDDR, id_IDDRC, id_IDES4)) { - return; + return nullptr; } - IdString aux_name = create_aux_iologic_name(ci.name); + IdString aux_name = create_aux_iologic_name(ci.name, idx); BelId bel = get_aux_iologic_bel(ci); BelId io_bel = gwu.get_io_bel_from_iologic(bel); if (!ctx->checkBelAvail(io_bel)) { @@ -467,15 +480,18 @@ struct GowinPacker } ctx->createCell(aux_name, id_IOLOGIC_DUMMY); - CellInfo *aux = ctx->cells[aux_name].get(); - aux->addInput(id_PCLK); - ci.copyPortTo(id_PCLK, ctx->cells.at(aux_name).get(), id_PCLK); - aux->addInput(id_RESET); - ci.copyPortTo(id_RESET, ctx->cells.at(aux_name).get(), id_RESET); - ctx->cells.at(aux_name)->setParam(mode, Property("DDRENABLE")); - ctx->cells.at(aux_name)->setAttr(ctx->id("IOLOGIC_TYPE"), Property("DUMMY")); - ctx->cells.at(aux_name)->setAttr(ctx->id("MAIN_CELL"), Property(ci.name.str(ctx))); + CellInfo *aux = ctx->cells.at(aux_name).get(); + ci.copyPortTo(id_PCLK, aux, id_PCLK); + ci.copyPortTo(id_RESET, aux, id_RESET); + if (io16) { + aux->setParam(mode, Property("DDRENABLE16")); + } else { + aux->setParam(mode, Property("DDRENABLE")); + } + aux->setAttr(ctx->id("IOLOGIC_TYPE"), Property("DUMMY")); + aux->setAttr(ctx->id("MAIN_CELL"), Property(ci.name.str(ctx))); ctx->bindBel(bel, aux, PlaceStrength::STRENGTH_LOCKED); + return aux; } void reconnect_ides_outs(CellInfo *ci) @@ -516,7 +532,7 @@ struct GowinPacker } } - void pack_ides_iol(CellInfo &ci, std::vector &cells_to_remove, std::vector &nets_to_remove) + void pack_ides_iol(CellInfo &ci, std::vector &nets_to_remove) { IdString in_port = id_D; @@ -528,6 +544,9 @@ struct GowinPacker if (l_bel == BelId()) { log_error("Can't place IOLOGIC %s at %s\n", ctx->nameOf(&ci), ctx->nameOfBel(iob_bel)); } + // mark IOB as used by IOLOGIC + in_iob->setParam(id_IOLOGIC_IOB, 1); + check_iologic_placement(ci, ctx->getBelLocation(iob_bel), in_iob->attrs.count(id_DIFF_TYPE)); if (!ctx->checkBelAvail(l_bel)) { log_error("Can't place %s at %s because it's already taken by %s\n", ctx->nameOf(&ci), @@ -555,9 +574,7 @@ struct GowinPacker } ci.setParam(ctx->id("INMODE"), in_mode); - // mark IOB as used by IOLOGIC - in_iob->setParam(id_IOLOGIC_IOB, 1); - // disconnect Q output: it is wired internally + // disconnect D input: it is wired internally nets_to_remove.push_back(ci.getPort(in_port)->name); in_iob->disconnectPort(id_O); ci.disconnectPort(in_port); @@ -570,7 +587,7 @@ struct GowinPacker void pack_iologic() { log_info("Pack IO logic...\n"); - std::vector cells_to_remove, nets_to_remove; + std::vector nets_to_remove; for (auto &cell : ctx->cells) { CellInfo &ci = *cell.second; @@ -581,29 +598,213 @@ struct GowinPacker log_info("pack %s of type %s.\n", ctx->nameOf(&ci), ci.type.c_str(ctx)); } if (ci.type.in(id_ODDR, id_ODDRC, id_OSER4, id_OSER8)) { - pack_bi_output_iol(ci, cells_to_remove, nets_to_remove); - create_aux_iologic_cells(ci, ctx->id("OUTMODE")); + pack_bi_output_iol(ci, nets_to_remove); + create_aux_iologic_cell(ci, ctx->id("OUTMODE")); continue; } if (ci.type.in(id_OVIDEO, id_OSER10)) { - pack_single_output_iol(ci, cells_to_remove, nets_to_remove); - create_aux_iologic_cells(ci, ctx->id("OUTMODE")); + pack_single_output_iol(ci, nets_to_remove); + create_aux_iologic_cell(ci, ctx->id("OUTMODE")); continue; } if (ci.type.in(id_IDDR, id_IDDRC, id_IDES4, id_IDES8, id_IDES10, id_IVIDEO)) { - pack_ides_iol(ci, cells_to_remove, nets_to_remove); - create_aux_iologic_cells(ci, ctx->id("INMODE")); + pack_ides_iol(ci, nets_to_remove); + create_aux_iologic_cell(ci, ctx->id("INMODE")); continue; } } - for (auto cell : cells_to_remove) { - ctx->cells.erase(cell); + for (auto net : nets_to_remove) { + ctx->nets.erase(net); + } + } + + // =================================== + // IDES16 / OSER16 + // =================================== + void check_io16_placement(CellInfo &ci, Loc main_loc, Loc aux_off, int diff /* 1 - diff */) + { + int mod[][3] = {{0, 0, 1}, {1, 1, 0}, {1, 1, 1}}; + for (int i = diff; i < 3; ++i) { + Loc aux_loc(main_loc.x + mod[i][0] * aux_off.x, main_loc.y + mod[i][1] * aux_off.y, main_loc.z + mod[i][2]); + BelId l_bel = ctx->getBelByLocation(aux_loc); + if (!ctx->checkBelAvail(l_bel)) { + log_error("Can't place %s at %s because it's already taken by %s\n", ctx->nameOf(&ci), + ctx->nameOfBel(l_bel), ctx->nameOf(ctx->getBoundBelCell(l_bel))); + } + } + } + + void pack_oser16(CellInfo &ci, std::vector &nets_to_remove) + { + IdString out_port = id_Q; + + CellInfo *out_iob = net_only_drives(ctx, ci.ports.at(out_port).net, is_iob, id_I, true); + NPNR_ASSERT(out_iob != nullptr && out_iob->bel != BelId()); + // mark IOB as used by IOLOGIC + out_iob->setParam(id_IOLOGIC_IOB, 1); + + BelId iob_bel = out_iob->bel; + + Loc iob_loc = ctx->getBelLocation(iob_bel); + Loc aux_offset = gwu.get_tile_io16_offs(iob_loc.x, iob_loc.y); + + if (aux_offset.x == 0 && aux_offset.y == 0) { + log_error("OSER16 %s can not be placed here\n", ctx->nameOf(&ci)); + } + check_io16_placement(ci, iob_loc, aux_offset, out_iob->attrs.count(id_DIFF_TYPE)); + + BelId main_bel = ctx->getBelByLocation(Loc(iob_loc.x, iob_loc.y, BelZ::OSER16_Z)); + ctx->bindBel(main_bel, &ci, PlaceStrength::STRENGTH_LOCKED); + + // disconnect Q output: it is wired internally + nets_to_remove.push_back(ci.getPort(out_port)->name); + out_iob->disconnectPort(id_I); + ci.disconnectPort(out_port); + + // to simplify packaging, the parts of the OSER16 are presented as IOLOGIC cells + // and one of these aux cells is declared as main + IdString main_name = create_aux_iologic_name(ci.name); + + IdString aux_name = create_aux_iologic_name(ci.name, 1); + ctx->createCell(aux_name, id_IOLOGIC_DUMMY); + CellInfo *aux = ctx->cells.at(aux_name).get(); + + aux->setAttr(ctx->id("MAIN_CELL"), Property(main_name.str(ctx))); + aux->setParam(ctx->id("OUTMODE"), Property("ODDRX8")); + aux->setParam(ctx->id("UPDATE"), Property("SAME")); + aux->setAttr(ctx->id("IOLOGIC_TYPE"), Property("DUMMY")); + ci.copyPortTo(id_PCLK, aux, id_PCLK); + ci.copyPortTo(id_RESET, aux, id_RESET); + ctx->bindBel(ctx->getBelByLocation(Loc(iob_loc.x, iob_loc.y, BelZ::IOLOGICA_Z)), aux, + PlaceStrength::STRENGTH_LOCKED); + + // make aux cell in the first cell + aux = create_aux_iologic_cell(*aux, ctx->id("OUTMODE"), true, 2); + aux->setAttr(ctx->id("MAIN_CELL"), Property(main_name.str(ctx))); + aux->setParam(ctx->id("UPDATE"), Property("SAME")); + + // make cell in the next location + ctx->createCell(main_name, id_IOLOGIC); + aux = ctx->cells.at(main_name).get(); + + aux->setAttr(ctx->id("MAIN_CELL"), Property(main_name.str(ctx))); + aux->setParam(ctx->id("OUTMODE"), Property("DDRENABLE16")); + aux->setParam(ctx->id("UPDATE"), Property("SAME")); + aux->setAttr(ctx->id("IOLOGIC_TYPE"), Property("DUMMY")); + ci.copyPortTo(id_PCLK, aux, id_PCLK); + ci.copyPortTo(id_RESET, aux, id_RESET); + ci.movePortTo(id_FCLK, aux, id_FCLK); + ci.movePortTo(id_D12, aux, id_D0); + ci.movePortTo(id_D13, aux, id_D1); + ci.movePortTo(id_D14, aux, id_D2); + ci.movePortTo(id_D15, aux, id_D3); + Loc next_io16(iob_loc.x + aux_offset.x, iob_loc.y + aux_offset.y, BelZ::IOLOGICA_Z); + ctx->bindBel(ctx->getBelByLocation(next_io16), aux, PlaceStrength::STRENGTH_LOCKED); + + Loc io_loc = ctx->getBelLocation(iob_bel); + if (io_loc.y == ctx->getGridDimY() - 1) { + config_bottom_row(*out_iob, io_loc, Bottom_io_POD::DDR); + } + make_iob_nets(*out_iob); + } + + void pack_ides16(CellInfo &ci, std::vector &nets_to_remove) + { + IdString in_port = id_D; + + CellInfo *in_iob = net_driven_by(ctx, ci.ports.at(in_port).net, is_iob, id_O); + NPNR_ASSERT(in_iob != nullptr && in_iob->bel != BelId()); + // mark IOB as used by IOLOGIC + in_iob->setParam(id_IOLOGIC_IOB, 1); + + BelId iob_bel = in_iob->bel; + + Loc iob_loc = ctx->getBelLocation(iob_bel); + Loc aux_offset = gwu.get_tile_io16_offs(iob_loc.x, iob_loc.y); + + if (aux_offset.x == 0 && aux_offset.y == 0) { + log_error("IDES16 %s can not be placed here\n", ctx->nameOf(&ci)); + } + check_io16_placement(ci, iob_loc, aux_offset, in_iob->attrs.count(id_DIFF_TYPE)); + + BelId main_bel = ctx->getBelByLocation(Loc(iob_loc.x, iob_loc.y, BelZ::IDES16_Z)); + ctx->bindBel(main_bel, &ci, PlaceStrength::STRENGTH_LOCKED); + + // disconnect Q output: it is wired internally + nets_to_remove.push_back(ci.getPort(in_port)->name); + in_iob->disconnectPort(id_O); + ci.disconnectPort(in_port); + + // to simplify packaging, the parts of the IDES16 are presented as IOLOGIC cells + // and one of these aux cells is declared as main + IdString main_name = create_aux_iologic_name(ci.name); + + IdString aux_name = create_aux_iologic_name(ci.name, 1); + ctx->createCell(aux_name, id_IOLOGIC_DUMMY); + CellInfo *aux = ctx->cells.at(aux_name).get(); + + aux->setAttr(ctx->id("MAIN_CELL"), Property(main_name.str(ctx))); + aux->setParam(ctx->id("INMODE"), Property("IDDRX8")); + aux->setAttr(ctx->id("IOLOGIC_TYPE"), Property("DUMMY")); + ci.copyPortTo(id_PCLK, aux, id_PCLK); + ci.copyPortTo(id_RESET, aux, id_RESET); + ctx->bindBel(ctx->getBelByLocation(Loc(iob_loc.x, iob_loc.y, BelZ::IOLOGICA_Z)), aux, + PlaceStrength::STRENGTH_LOCKED); + + // make aux cell in the first cell + aux = create_aux_iologic_cell(*aux, ctx->id("INMODE"), true, 2); + aux->setAttr(ctx->id("MAIN_CELL"), Property(main_name.str(ctx))); + ci.copyPortTo(id_CALIB, aux, id_CALIB); + + // make cell in the next location + ctx->createCell(main_name, id_IOLOGIC); + aux = ctx->cells.at(main_name).get(); + + aux->setAttr(ctx->id("MAIN_CELL"), Property(main_name.str(ctx))); + aux->setParam(ctx->id("INMODE"), Property("DDRENABLE16")); + aux->setAttr(ctx->id("IOLOGIC_TYPE"), Property("DUMMY")); + ci.copyPortTo(id_PCLK, aux, id_PCLK); + ci.copyPortTo(id_RESET, aux, id_RESET); + ci.copyPortTo(id_CALIB, aux, id_CALIB); + ci.movePortTo(id_FCLK, aux, id_FCLK); + ci.movePortTo(id_Q0, aux, id_Q6); + ci.movePortTo(id_Q1, aux, id_Q7); + ci.movePortTo(id_Q2, aux, id_Q8); + ci.movePortTo(id_Q3, aux, id_Q9); + Loc next_io16(iob_loc.x + aux_offset.x, iob_loc.y + aux_offset.y, BelZ::IOLOGICA_Z); + ctx->bindBel(ctx->getBelByLocation(next_io16), aux, PlaceStrength::STRENGTH_LOCKED); + + make_iob_nets(*in_iob); + } + + void pack_io16(void) + { + std::vector nets_to_remove; + log_info("Pack DESER16 logic...\n"); + + for (auto &cell : ctx->cells) { + CellInfo &ci = *cell.second; + if (ci.type == id_OSER16) { + if (ctx->debug) { + log_info("pack %s of type %s.\n", ctx->nameOf(&ci), ci.type.c_str(ctx)); + } + pack_oser16(ci, nets_to_remove); + continue; + } + if (ci.type == id_IDES16) { + if (ctx->debug) { + log_info("pack %s of type %s.\n", ctx->nameOf(&ci), ci.type.c_str(ctx)); + } + pack_ides16(ci, nets_to_remove); + continue; + } } for (auto net : nets_to_remove) { ctx->nets.erase(net); } } + // =================================== // Constant nets // =================================== @@ -1123,6 +1324,9 @@ struct GowinPacker pack_iologic(); ctx->check(); + pack_io16(); + ctx->check(); + pack_gsr(); ctx->check();