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 <rabbit@yrabbit.cyou>
This commit is contained in:
YRabbit 2021-12-20 15:48:38 +10:00
parent 62a3e09385
commit 5a76b3cb4d
4 changed files with 77 additions and 4 deletions

View File

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

View File

@ -64,14 +64,14 @@ std::unique_ptr<CellInfo> 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<IdString> &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) {

View File

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

View File

@ -629,7 +629,7 @@ static void pack_constants(Context *ctx)
std::vector<IdString> 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<CellInfo> ice_cell = create_generic_cell(ctx, id_IOB, ci->name.str(ctx) + "$iob");
std::unique_ptr<CellInfo> 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();