aboutsummaryrefslogtreecommitdiffstats
path: root/gowin
diff options
context:
space:
mode:
Diffstat (limited to 'gowin')
-rw-r--r--gowin/arch.cc33
-rw-r--r--gowin/cells.cc12
-rw-r--r--gowin/constids.inc13
-rw-r--r--gowin/pack.cc23
4 files changed, 77 insertions, 4 deletions
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<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) {
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<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();