From 5a76b3cb4d506c4920fc3d6b9aff935cbaa2987e Mon Sep 17 00:00:00 2001 From: YRabbit Date: Mon, 20 Dec 2021 15:48:38 +1000 Subject: gowin: Add simplified IO cells processing Some models have I/O cells that are IOBUFs, and other types (IBUFs and OBUFs) are obtained by feeding 1 or 0 to the OEN input. This is done with general-purpose routing so it's best to do it here to avoid conflicts. For this purpose, in the new bases, these special cells are of type IOBS (IOB Simplified). The proposed changes are compatible with bases of previous versions of Apycula and do not require changing .CST constraint files. Signed-off-by: YRabbit --- gowin/arch.cc | 33 +++++++++++++++++++++++++++++++++ gowin/cells.cc | 12 ++++++++++-- gowin/constids.inc | 13 +++++++++++++ gowin/pack.cc | 23 +++++++++++++++++++++-- 4 files changed, 77 insertions(+), 4 deletions(-) (limited to 'gowin') diff --git a/gowin/arch.cc b/gowin/arch.cc index 801540cc..2f61685a 100644 --- a/gowin/arch.cc +++ b/gowin/arch.cc @@ -870,6 +870,39 @@ Arch::Arch(ArchArgs args) : args(args) snprintf(buf, 32, "R%dC%d_%s", row + 1, col + 1, portname.c_str(this)); addBelInput(belname, id_OEN, id(buf)); break; + // Simplified IO + case ID_IOBJS: + z++; /* fall-through*/ + case ID_IOBIS: + z++; /* fall-through*/ + case ID_IOBHS: + z++; /* fall-through*/ + case ID_IOBGS: + z++; /* fall-through*/ + case ID_IOBFS: + z++; /* fall-through*/ + case ID_IOBES: + z++; /* fall-through*/ + case ID_IOBDS: + z++; /* fall-through*/ + case ID_IOBCS: + z++; /* fall-through*/ + case ID_IOBBS: + z++; /* fall-through*/ + case ID_IOBAS: + snprintf(buf, 32, "R%dC%d_IOB%c", row + 1, col + 1, 'A' + z); + belname = id(buf); + addBel(belname, id_IOBS, Loc(col, row, z), false); + portname = IdString(pairLookup(bel->ports.get(), bel->num_ports, ID_O)->src_id); + snprintf(buf, 32, "R%dC%d_%s", row + 1, col + 1, portname.c_str(this)); + addBelOutput(belname, id_O, id(buf)); + portname = IdString(pairLookup(bel->ports.get(), bel->num_ports, ID_I)->src_id); + snprintf(buf, 32, "R%dC%d_%s", row + 1, col + 1, portname.c_str(this)); + addBelInput(belname, id_I, id(buf)); + portname = IdString(pairLookup(bel->ports.get(), bel->num_ports, ID_OE)->src_id); + snprintf(buf, 32, "R%dC%d_%s", row + 1, col + 1, portname.c_str(this)); + addBelInput(belname, id_OEN, id(buf)); + break; default: break; diff --git a/gowin/cells.cc b/gowin/cells.cc index 57f3ab9c..dce3f456 100644 --- a/gowin/cells.cc +++ b/gowin/cells.cc @@ -64,14 +64,14 @@ std::unique_ptr create_generic_cell(Context *ctx, IdString type, std:: add_port(ctx, new_cell.get(), id_I1, PORT_IN); add_port(ctx, new_cell.get(), id_SEL, PORT_IN); add_port(ctx, new_cell.get(), id_OF, PORT_OUT); - } else if (type == id_IOB) { + } else if (type == id_IOB || type == id_IOBS) { new_cell->params[id_INPUT_USED] = 0; new_cell->params[id_OUTPUT_USED] = 0; new_cell->params[id_ENABLE_USED] = 0; add_port(ctx, new_cell.get(), id_PAD, PORT_INOUT); add_port(ctx, new_cell.get(), id_I, PORT_IN); - add_port(ctx, new_cell.get(), id_EN, PORT_IN); + add_port(ctx, new_cell.get(), id_OEN, PORT_IN); add_port(ctx, new_cell.get(), id_O, PORT_OUT); } else { log_error("unable to create generic cell of type %s\n", type.c_str(ctx)); @@ -140,9 +140,17 @@ void dff_to_lc(const Context *ctx, CellInfo *dff, CellInfo *lc, bool pass_thru_l void gwio_to_iob(Context *ctx, CellInfo *nxio, CellInfo *iob, pool &todelete_cells) { if (nxio->type == id_IBUF) { + if (iob->type == id_IOBS) { + // VCC -> OEN + connect_port(ctx, ctx->nets[ctx->id("$PACKER_VCC_NET")].get(), iob, id_OEN); + } iob->params[id_INPUT_USED] = 1; replace_port(nxio, id_O, iob, id_O); } else if (nxio->type == id_OBUF) { + if (iob->type == id_IOBS) { + // VSS -> OEN + connect_port(ctx, ctx->nets[ctx->id("$PACKER_GND_NET")].get(), iob, id_OEN); + } iob->params[id_OUTPUT_USED] = 1; replace_port(nxio, id_I, iob, id_I); } else if (nxio->type == id_TBUF) { diff --git a/gowin/constids.inc b/gowin/constids.inc index 7de754fc..6a730d5d 100644 --- a/gowin/constids.inc +++ b/gowin/constids.inc @@ -358,6 +358,19 @@ X(IOBH) X(IOBI) X(IOBJ) +// simplified iobs +X(IOBS) +X(IOBAS) +X(IOBBS) +X(IOBCS) +X(IOBDS) +X(IOBES) +X(IOBFS) +X(IOBGS) +X(IOBHS) +X(IOBIS) +X(IOBJS) + // Wide LUTs X(MUX2_LUT5) X(MUX2_LUT6) diff --git a/gowin/pack.cc b/gowin/pack.cc index cb63f1c9..553eeb4e 100644 --- a/gowin/pack.cc +++ b/gowin/pack.cc @@ -629,7 +629,7 @@ static void pack_constants(Context *ctx) std::vector dead_nets; - bool gnd_used = false; + bool gnd_used = true; // XXX May be needed for simplified IO for (auto &net : ctx->nets) { NetInfo *ni = net.second.get(); @@ -718,8 +718,27 @@ static void pack_io(Context *ctx) } packed_cells.insert(iob->name); } + // what type to create + IdString new_cell_type = id_IOB; + std::string constr_bel_name = std::string(""); + // check whether the given IO is limited to simplified IO cells + auto constr_bel = ci->attrs.find(id_BEL); + if (constr_bel != ci->attrs.end()) { + constr_bel_name = constr_bel->second.as_string(); + } + constr_bel = iob->attrs.find(id_BEL); + if (constr_bel != iob->attrs.end()) { + constr_bel_name = constr_bel->second.as_string(); + } + if (!constr_bel_name.empty()) { + BelId constr_bel = ctx->getBelByNameStr(constr_bel_name); + if (constr_bel != BelId()) { + new_cell_type = ctx->bels[constr_bel].type; + } + } + // Create a IOB buffer - std::unique_ptr ice_cell = create_generic_cell(ctx, id_IOB, ci->name.str(ctx) + "$iob"); + std::unique_ptr ice_cell = create_generic_cell(ctx, new_cell_type, ci->name.str(ctx) + "$iob"); gwio_to_iob(ctx, ci, ice_cell.get(), packed_cells); new_cells.push_back(std::move(ice_cell)); auto gwiob = new_cells.back().get(); -- cgit v1.2.3