From c89027ca5d5e6cd7a31cdb647edf724abf53507f Mon Sep 17 00:00:00 2001 From: Pepijn de Vos Date: Wed, 2 Dec 2020 16:37:18 +0100 Subject: [PATCH] broken packing stuff --- gowin/arch.cc | 12 ++-- gowin/cells.cc | 134 ++++++++++++++++++++++----------------------- gowin/cells.h | 48 ++++++++++++++-- gowin/constids.inc | 54 +++++++++++++++++- gowin/pack.cc | 95 +++++++++++++++++--------------- 5 files changed, 219 insertions(+), 124 deletions(-) diff --git a/gowin/arch.cc b/gowin/arch.cc index be326069..b1ee2690 100644 --- a/gowin/arch.cc +++ b/gowin/arch.cc @@ -332,8 +332,8 @@ const GlobalAliasPOD* aliasLookup(const GlobalAliasPOD *first, int len, const Gl Arch::Arch(ArchArgs args) : args(args) { - family = "GW1N-1"; - device = "GW1N-1"; + family = "GW1N-9"; + device = "GW1N-9"; speed = "C6/E5"; // or whatever package = "QFN48"; // or something @@ -469,7 +469,7 @@ Arch::Arch(ArchArgs args) : args(args) portname = pairLookup(bel->ports.get(), bel->num_ports, -1, ID_OE)->src_id; snprintf(buf, 32, "R%dC%d_%s", row + 1, col + 1, portname.c_str(this)); wirename = id(buf); - addBelInput(belname, id_OE, wirename); + addBelInput(belname, id_OEN, wirename); break; default: @@ -503,7 +503,7 @@ Arch::Arch(ArchArgs args) : args(args) delay.delay = 0.1; // TODO // local alias auto local_alias = pairLookup(tile->aliases.get(), tile->num_aliases, -1, srcid.index); - std::cout << "srcid " << srcid.str(this) << std::endl; + // std::cout << "srcid " << srcid.str(this) << std::endl; if(local_alias!=nullptr) { srcid = local_alias->src_id; gsrcname = wireToGlobal(srcrow, srccol, db, srcid); @@ -689,8 +689,8 @@ const std::map &Arch::getPipAttrs(PipId pip) const { retu uint32_t Arch::getPipChecksum(PipId wire) const { - // FIXME - return 0; + // FIXEDME? + return wire.index; } void Arch::bindPip(PipId pip, NetInfo *net, PlaceStrength strength) diff --git a/gowin/cells.cc b/gowin/cells.cc index c4421f90..fb049d4c 100644 --- a/gowin/cells.cc +++ b/gowin/cells.cc @@ -21,12 +21,12 @@ #include "design_utils.h" #include "log.h" #include "util.h" +#include NEXTPNR_NAMESPACE_BEGIN -void add_port(const Context *ctx, CellInfo *cell, std::string name, PortType dir) +void add_port(const Context *ctx, CellInfo *cell, IdString id, PortType dir) { - IdString id = ctx->id(name); NPNR_ASSERT(cell->ports.count(id) == 0); cell->ports[id] = PortInfo{id, nullptr, dir}; } @@ -41,27 +41,31 @@ std::unique_ptr create_generic_cell(Context *ctx, IdString type, std:: new_cell->name = ctx->id(name); } new_cell->type = type; - if (type == ctx->id("GENERIC_SLICE")) { - new_cell->params[ctx->id("K")] = ctx->args.K; - new_cell->params[ctx->id("INIT")] = 0; - new_cell->params[ctx->id("FF_USED")] = 0; + if (type == id_SLICE) { + new_cell->params[id_INIT] = 0; + new_cell->params[id_FF_USED] = 0; + new_cell->params[id_FF_TYPE] = id_DFF.str(ctx); - for (int i = 0; i < ctx->args.K; i++) - add_port(ctx, new_cell.get(), "I[" + std::to_string(i) + "]", PORT_IN); + IdString names[4] = {id_A, id_B, id_C, id_D}; + for (int i = 0; i < 4; i++) { + add_port(ctx, new_cell.get(), names[i], PORT_IN); + } - add_port(ctx, new_cell.get(), "CLK", PORT_IN); + add_port(ctx, new_cell.get(), id_CLK, PORT_IN); - add_port(ctx, new_cell.get(), "F", PORT_OUT); - add_port(ctx, new_cell.get(), "Q", PORT_OUT); - } else if (type == ctx->id("GENERIC_IOB")) { - new_cell->params[ctx->id("INPUT_USED")] = 0; - new_cell->params[ctx->id("OUTPUT_USED")] = 0; - new_cell->params[ctx->id("ENABLE_USED")] = 0; + add_port(ctx, new_cell.get(), id_F, PORT_OUT); + add_port(ctx, new_cell.get(), id_Q, PORT_OUT); + add_port(ctx, new_cell.get(), id_CE, PORT_IN); + add_port(ctx, new_cell.get(), id_LSR, PORT_IN); + } else if (type == id_IOB) { + 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(), "PAD", PORT_INOUT); - add_port(ctx, new_cell.get(), "I", PORT_IN); - add_port(ctx, new_cell.get(), "EN", PORT_IN); - add_port(ctx, new_cell.get(), "O", PORT_OUT); + 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_O, PORT_OUT); } else { log_error("unable to create generic cell of type %s", type.c_str(ctx)); } @@ -70,78 +74,74 @@ std::unique_ptr create_generic_cell(Context *ctx, IdString type, std:: void lut_to_lc(const Context *ctx, CellInfo *lut, CellInfo *lc, bool no_dff) { - lc->params[ctx->id("INIT")] = lut->params[ctx->id("INIT")]; + for(auto f : lut->ports) { + std::cout << f.first.str(ctx) << std::endl; + } + lc->params[id_INIT] = lut->params[id_INIT]; - int lut_k = int_or_default(lut->params, ctx->id("K"), 4); - NPNR_ASSERT(lut_k <= ctx->args.K); - - for (int i = 0; i < lut_k; i++) { - IdString port = ctx->id("I[" + std::to_string(i) + "]"); - replace_port(lut, port, lc, port); + IdString sim_names[4] = {id_I0, id_I1, id_I2, id_I3}; + IdString wire_names[4] = {id_A, id_B, id_C, id_D}; + for (int i = 0; i < 4; i++) { + replace_port(lut, sim_names[i], lc, wire_names[i]); } if (no_dff) { - lc->params[ctx->id("FF_USED")] = 0; - replace_port(lut, ctx->id("Q"), lc, ctx->id("F")); + lc->params[id_FF_USED] = 0; + replace_port(lut, id_F, lc, id_F); } } void dff_to_lc(const Context *ctx, CellInfo *dff, CellInfo *lc, bool pass_thru_lut) { - lc->params[ctx->id("FF_USED")] = 1; - replace_port(dff, ctx->id("CLK"), lc, ctx->id("CLK")); - + lc->params[id_FF_USED] = 1; + lc->params[id_FF_TYPE] = dff->type.str(ctx); + replace_port(dff, id_CLK, lc, id_CLK); + replace_port(dff, id_CE, lc, id_CE); + replace_port(dff, id_SET, lc, id_LSR); + replace_port(dff, id_RESET, lc, id_LSR); + replace_port(dff, id_CLEAR, lc, id_LSR); + replace_port(dff, id_PRESET, lc, id_LSR); + for(auto f : dff->ports) { + std::cout << f.first.str(ctx) << std::endl; + } if (pass_thru_lut) { // Fill LUT with alternating 10 - const int init_size = 1 << lc->params[ctx->id("K")].as_int64(); + const int init_size = 1 << 4; std::string init; init.reserve(init_size); for (int i = 0; i < init_size; i += 2) init.append("10"); - lc->params[ctx->id("INIT")] = Property::from_string(init); + lc->params[id_INIT] = Property::from_string(init); - replace_port(dff, ctx->id("D"), lc, ctx->id("I[0]")); + replace_port(dff, id_D, lc, id_A); } - replace_port(dff, ctx->id("Q"), lc, ctx->id("Q")); + replace_port(dff, id_Q, lc, id_Q); } -void nxio_to_iob(Context *ctx, CellInfo *nxio, CellInfo *iob, std::unordered_set &todelete_cells) +void gwio_to_iob(Context *ctx, CellInfo *nxio, CellInfo *iob, std::unordered_set &todelete_cells) { - if (nxio->type == ctx->id("$nextpnr_ibuf")) { - iob->params[ctx->id("INPUT_USED")] = 1; - replace_port(nxio, ctx->id("O"), iob, ctx->id("O")); - } else if (nxio->type == ctx->id("$nextpnr_obuf")) { - iob->params[ctx->id("OUTPUT_USED")] = 1; - replace_port(nxio, ctx->id("I"), iob, ctx->id("I")); - } else if (nxio->type == ctx->id("$nextpnr_iobuf")) { - // N.B. tristate will be dealt with below - iob->params[ctx->id("INPUT_USED")] = 1; - iob->params[ctx->id("OUTPUT_USED")] = 1; - replace_port(nxio, ctx->id("I"), iob, ctx->id("I")); - replace_port(nxio, ctx->id("O"), iob, ctx->id("O")); + if (nxio->type == id_IBUF) { + iob->params[id_INPUT_USED] = 1; + replace_port(nxio, id_O, iob, id_O); + } else if (nxio->type == id_OBUF) { + iob->params[id_OUTPUT_USED] = 1; + replace_port(nxio, id_I, iob, id_I); + } else if (nxio->type == id_TBUF) { + iob->params[id_ENABLE_USED] = 1; + iob->params[id_OUTPUT_USED] = 1; + replace_port(nxio, id_I, iob, id_I); + replace_port(nxio, id_OEN, iob, id_OEN); + } else if (nxio->type == id_IOBUF) { + iob->params[id_ENABLE_USED] = 1; + iob->params[id_INPUT_USED] = 1; + iob->params[id_OUTPUT_USED] = 1; + replace_port(nxio, id_I, iob, id_I); + replace_port(nxio, id_O, iob, id_O); + replace_port(nxio, id_OEN, iob, id_OEN); } else { NPNR_ASSERT(false); } - NetInfo *donet = iob->ports.at(ctx->id("I")).net; - CellInfo *tbuf = net_driven_by( - ctx, donet, [](const Context *ctx, const CellInfo *cell) { return cell->type == ctx->id("$_TBUF_"); }, - ctx->id("Y")); - if (tbuf) { - iob->params[ctx->id("ENABLE_USED")] = 1; - replace_port(tbuf, ctx->id("A"), iob, ctx->id("I")); - replace_port(tbuf, ctx->id("E"), iob, ctx->id("EN")); - - if (donet->users.size() > 1) { - for (auto user : donet->users) - log_info(" remaining tristate user: %s.%s\n", user.cell->name.c_str(ctx), user.port.c_str(ctx)); - log_error("unsupported tristate IO pattern for IO buffer '%s', " - "instantiate GENERIC_IOB manually to ensure correct behaviour\n", - nxio->name.c_str(ctx)); - } - ctx->nets.erase(donet->name); - todelete_cells.insert(tbuf->name); - } } NEXTPNR_NAMESPACE_END diff --git a/gowin/cells.h b/gowin/cells.h index 646d738d..536f2139 100644 --- a/gowin/cells.h +++ b/gowin/cells.h @@ -29,12 +29,50 @@ NEXTPNR_NAMESPACE_BEGIN std::unique_ptr create_generic_cell(Context *ctx, IdString type, std::string name = ""); // Return true if a cell is a LUT -inline bool is_lut(const BaseCtx *ctx, const CellInfo *cell) { return cell->type == ctx->id("LUT"); } +inline bool is_lut(const BaseCtx *ctx, const CellInfo *cell) +{ + switch (cell->type.index) { + case ID_LUT1: + case ID_LUT2: + case ID_LUT3: + case ID_LUT4: + return true; + default: + return false; + } +} // Return true if a cell is a flipflop -inline bool is_ff(const BaseCtx *ctx, const CellInfo *cell) { return cell->type == ctx->id("DFF"); } +inline bool is_ff(const BaseCtx *ctx, const CellInfo *cell) +{ + switch (cell->type.index) { + case ID_DFF: + case ID_DFFE: + case ID_DFFS: + case ID_DFFSE: + case ID_DFFR: + case ID_DFFRE: + case ID_DFFP: + case ID_DFFPE: + case ID_DFFC: + case ID_DFFCE: + case ID_DFFN: + case ID_DFFNE: + case ID_DFFNS: + case ID_DFFNSE: + case ID_DFFNR: + case ID_DFFNRE: + case ID_DFFNP: + case ID_DFFNPE: + case ID_DFFNC: + case ID_DFFNCE: + return true; + default: + return false; + } +} -inline bool is_lc(const BaseCtx *ctx, const CellInfo *cell) { return cell->type == ctx->id("GENERIC_SLICE"); } +inline bool is_lc(const BaseCtx *ctx, const CellInfo *cell) { return cell->type == id_SLICE; } // Convert a LUT primitive to (part of) an GENERIC_SLICE, swapping ports // as needed. Set no_dff if a DFF is not being used, so that the output @@ -47,8 +85,8 @@ void lut_to_lc(const Context *ctx, CellInfo *lut, CellInfo *lc, bool no_dff = tr // ignored void dff_to_lc(const Context *ctx, CellInfo *dff, CellInfo *lc, bool pass_thru_lut = false); -// Convert a nextpnr IO buffer to a GENERIC_IOB -void nxio_to_iob(Context *ctx, CellInfo *nxio, CellInfo *sbio, std::unordered_set &todelete_cells); +// Convert a Gowin IO buffer to a IOB bel +void gwio_to_iob(Context *ctx, CellInfo *nxio, CellInfo *sbio, std::unordered_set &todelete_cells); NEXTPNR_NAMESPACE_END diff --git a/gowin/constids.inc b/gowin/constids.inc index adf52ead..c24559a0 100644 --- a/gowin/constids.inc +++ b/gowin/constids.inc @@ -328,6 +328,7 @@ X(D) X(IOB) X(I) X(O) +X(IO) X(OE) // bels X(DFF0) @@ -355,4 +356,55 @@ X(IOBF) X(IOBG) X(IOBH) X(IOBI) -X(IOBJ) \ No newline at end of file +X(IOBJ) + +// DFF types +X(DFF) +X(DFFE) +X(DFFS) +X(DFFSE) +X(DFFR) +X(DFFRE) +X(DFFP) +X(DFFPE) +X(DFFC) +X(DFFCE) +X(DFFN) +X(DFFNE) +X(DFFNS) +X(DFFNSE) +X(DFFNR) +X(DFFNRE) +X(DFFNP) +X(DFFNPE) +X(DFFNC) +X(DFFNCE) + +// IOB types +X(IBUF) +X(OBUF) +X(IOBUF) +X(TBUF) + +// primitive attributes +X(INIT) +X(FF_USED) +X(FF_TYPE) +X(INPUT_USED) +X(OUTPUT_USED) +X(ENABLE_USED) + +// ports +X(EN) +X(E) +X(Y) +X(PAD) +X(RESET) +X(SET) +X(PRESET) +X(CLEAR) +X(I0) +X(I1) +X(I2) +X(I3) +X(OEN) \ No newline at end of file diff --git a/gowin/pack.cc b/gowin/pack.cc index 43157b6c..c2d927b4 100644 --- a/gowin/pack.cc +++ b/gowin/pack.cc @@ -24,6 +24,7 @@ #include "design_utils.h" #include "log.h" #include "util.h" +#include NEXTPNR_NAMESPACE_BEGIN @@ -40,14 +41,14 @@ static void pack_lut_lutffs(Context *ctx) log_info("cell '%s' is of type '%s'\n", ci->name.c_str(ctx), ci->type.c_str(ctx)); if (is_lut(ctx, ci)) { std::unique_ptr packed = - create_generic_cell(ctx, ctx->id("GENERIC_SLICE"), ci->name.str(ctx) + "_LC"); + create_generic_cell(ctx, ctx->id("SLICE"), ci->name.str(ctx) + "_LC"); std::copy(ci->attrs.begin(), ci->attrs.end(), std::inserter(packed->attrs, packed->attrs.begin())); packed_cells.insert(ci->name); if (ctx->verbose) log_info("packed cell %s into %s\n", ci->name.c_str(ctx), packed->name.c_str(ctx)); // See if we can pack into a DFF // TODO: LUT cascade - NetInfo *o = ci->ports.at(ctx->id("Q")).net; + NetInfo *o = ci->ports.at(ctx->id("F")).net; CellInfo *dff = net_only_drives(ctx, o, is_ff, ctx->id("D"), true); auto lut_bel = ci->attrs.find(ctx->id("BEL")); bool packed_dff = false; @@ -95,7 +96,7 @@ static void pack_nonlut_ffs(Context *ctx) CellInfo *ci = cell.second; if (is_ff(ctx, ci)) { std::unique_ptr packed = - create_generic_cell(ctx, ctx->id("GENERIC_SLICE"), ci->name.str(ctx) + "_DFFLC"); + create_generic_cell(ctx, ctx->id("SLICE"), ci->name.str(ctx) + "_DFFLC"); std::copy(ci->attrs.begin(), ci->attrs.end(), std::inserter(packed->attrs, packed->attrs.begin())); if (ctx->verbose) log_info("packed cell %s into %s\n", ci->name.c_str(ctx), packed->name.c_str(ctx)); @@ -137,7 +138,7 @@ static void pack_constants(Context *ctx) { log_info("Packing constants..\n"); - std::unique_ptr gnd_cell = create_generic_cell(ctx, ctx->id("GENERIC_SLICE"), "$PACKER_GND"); + std::unique_ptr gnd_cell = create_generic_cell(ctx, ctx->id("SLICE"), "$PACKER_GND"); gnd_cell->params[ctx->id("INIT")] = Property(0, 1 << ctx->args.K); std::unique_ptr gnd_net = std::unique_ptr(new NetInfo); gnd_net->name = ctx->id("$PACKER_GND_NET"); @@ -145,7 +146,7 @@ static void pack_constants(Context *ctx) gnd_net->driver.port = ctx->id("F"); gnd_cell->ports.at(ctx->id("F")).net = gnd_net.get(); - std::unique_ptr vcc_cell = create_generic_cell(ctx, ctx->id("GENERIC_SLICE"), "$PACKER_VCC"); + std::unique_ptr vcc_cell = create_generic_cell(ctx, ctx->id("SLICE"), "$PACKER_VCC"); // Fill with 1s vcc_cell->params[ctx->id("INIT")] = Property(Property::S1).extract(0, (1 << ctx->args.K), Property::S1); std::unique_ptr vcc_net = std::unique_ptr(new NetInfo); @@ -188,13 +189,24 @@ static void pack_constants(Context *ctx) } } -static bool is_nextpnr_iob(Context *ctx, CellInfo *cell) +static bool is_nextpnr_iob(const Context *ctx, CellInfo *cell) { return cell->type == ctx->id("$nextpnr_ibuf") || cell->type == ctx->id("$nextpnr_obuf") || cell->type == ctx->id("$nextpnr_iobuf"); } -static bool is_generic_iob(const Context *ctx, const CellInfo *cell) { return cell->type == ctx->id("GENERIC_IOB"); } +static bool is_gowin_iob(const Context *ctx, const CellInfo *cell) { + switch (cell->type.index) + { + case ID_IBUF: + case ID_OBUF: + case ID_IOBUF: + case ID_TBUF: + return true; + default: + return false; + } + } // Pack IO buffers static void pack_io(Context *ctx) @@ -207,49 +219,42 @@ static void pack_io(Context *ctx) for (auto cell : sorted(ctx->cells)) { CellInfo *ci = cell.second; - if (is_nextpnr_iob(ctx, ci)) { + if (is_gowin_iob(ctx, ci)) { + std::cout << ci->type.str(ctx) << std::endl; + for(auto p : ci->ports) { + std::cout << p.first.str(ctx) << std::endl; + } CellInfo *iob = nullptr; - if (ci->type == ctx->id("$nextpnr_ibuf") || ci->type == ctx->id("$nextpnr_iobuf")) { - iob = net_only_drives(ctx, ci->ports.at(ctx->id("O")).net, is_generic_iob, ctx->id("PAD"), true, ci); - - } else if (ci->type == ctx->id("$nextpnr_obuf")) { - NetInfo *net = ci->ports.at(ctx->id("I")).net; - iob = net_only_drives(ctx, net, is_generic_iob, ctx->id("PAD"), true, ci); + switch (ci->type.index) + { + case ID_IBUF: + iob = net_driven_by(ctx, ci->ports.at(id_I).net, is_nextpnr_iob, id_O); + break; + case ID_OBUF: + iob = net_only_drives(ctx, ci->ports.at(id_O).net, is_nextpnr_iob, id_I); + break; + case ID_IOBUF: + case ID_TBUF: + log_error("untested tristate stuff"); + break; + default: + break; } if (iob != nullptr) { - // Trivial case, GENERIC_IOB used. Just destroy the net and the - // iobuf - log_info("%s feeds GENERIC_IOB %s, removing %s %s.\n", ci->name.c_str(ctx), iob->name.c_str(ctx), - ci->type.c_str(ctx), ci->name.c_str(ctx)); - NetInfo *net = iob->ports.at(ctx->id("PAD")).net; - if (((ci->type == ctx->id("$nextpnr_ibuf") || ci->type == ctx->id("$nextpnr_iobuf")) && - net->users.size() > 1) || - (ci->type == ctx->id("$nextpnr_obuf") && (net->users.size() > 2 || net->driver.cell != nullptr))) - log_error("PAD of %s '%s' connected to more than a single top level IO.\n", iob->type.c_str(ctx), - iob->name.c_str(ctx)); - - if (net != nullptr) { - delete_nets.insert(net->name); - iob->ports.at(ctx->id("PAD")).net = nullptr; + // delete the $nexpnr_[io]buf + for (auto &p : iob->ports) { + disconnect_port(ctx, iob, p.first); + delete_nets.insert(p.second.net->name); } - if (ci->type == ctx->id("$nextpnr_iobuf")) { - NetInfo *net2 = ci->ports.at(ctx->id("I")).net; - if (net2 != nullptr) { - delete_nets.insert(net2->name); - } - } - } else if (bool_or_default(ctx->settings, ctx->id("disable_iobs"))) { - // No IO buffer insertion; just remove nextpnr_[io]buf - for (auto &p : ci->ports) - disconnect_port(ctx, ci, p.first); - } else { - // Create a GENERIC_IOB buffer - std::unique_ptr ice_cell = - create_generic_cell(ctx, ctx->id("GENERIC_IOB"), ci->name.str(ctx) + "$iob"); - nxio_to_iob(ctx, ci, ice_cell.get(), packed_cells); - new_cells.push_back(std::move(ice_cell)); - iob = new_cells.back().get(); + packed_cells.insert(iob->name); } + // Create a IOB buffer + std::unique_ptr ice_cell = + create_generic_cell(ctx, id_IOB, ci->name.str(ctx) + "$iob"); + gwio_to_iob(ctx, ci, ice_cell.get(), packed_cells); + new_cells.push_back(std::move(ice_cell)); + iob = new_cells.back().get(); + packed_cells.insert(ci->name); if (iob != nullptr) std::copy(ci->attrs.begin(), ci->attrs.end(), std::inserter(iob->attrs, iob->attrs.begin()));