aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDavid Shah <davey1576@gmail.com>2018-07-18 09:35:40 +0200
committerDavid Shah <davey1576@gmail.com>2018-07-18 09:35:40 +0200
commitf138368e343d0d69b6e1f74d44e13d7097999de6 (patch)
tree4029320dd0b01010d72740b137b3ebc5bf398f7b
parentedf7bd09cf2a27fa1ada1a1e34cbe47c4bf0d48a (diff)
downloadnextpnr-f138368e343d0d69b6e1f74d44e13d7097999de6.tar.gz
nextpnr-f138368e343d0d69b6e1f74d44e13d7097999de6.tar.bz2
nextpnr-f138368e343d0d69b6e1f74d44e13d7097999de6.zip
ecp5: Add simple constant packer
Signed-off-by: David Shah <davey1576@gmail.com>
-rw-r--r--ecp5/archdefs.h8
-rw-r--r--ecp5/cells.cc8
-rw-r--r--ecp5/pack.cc84
3 files changed, 98 insertions, 2 deletions
diff --git a/ecp5/archdefs.h b/ecp5/archdefs.h
index df1add44..941607ba 100644
--- a/ecp5/archdefs.h
+++ b/ecp5/archdefs.h
@@ -129,8 +129,12 @@ struct DecalId
}
};
-struct ArchNetInfo { };
-struct ArchCellInfo { };
+struct ArchNetInfo
+{
+};
+struct ArchCellInfo
+{
+};
NEXTPNR_NAMESPACE_END
diff --git a/ecp5/cells.cc b/ecp5/cells.cc
index 59504735..22e6a8dc 100644
--- a/ecp5/cells.cc
+++ b/ecp5/cells.cc
@@ -116,6 +116,14 @@ std::unique_ptr<CellInfo> create_ecp5_cell(Context *ctx, IdString type, std::str
add_port(ctx, new_cell.get(), "I", PORT_IN);
add_port(ctx, new_cell.get(), "T", PORT_IN);
add_port(ctx, new_cell.get(), "O", PORT_OUT);
+ } else if (type == ctx->id("LUT4")) {
+ new_cell->params[ctx->id("INIT")] = "0";
+
+ add_port(ctx, new_cell.get(), "A", PORT_IN);
+ add_port(ctx, new_cell.get(), "B", PORT_IN);
+ add_port(ctx, new_cell.get(), "C", PORT_IN);
+ add_port(ctx, new_cell.get(), "D", PORT_IN);
+ add_port(ctx, new_cell.get(), "Z", PORT_OUT);
} else {
log_error("unable to create ECP5 cell of type %s", type.c_str(ctx));
}
diff --git a/ecp5/pack.cc b/ecp5/pack.cc
index c0427d46..47f22e55 100644
--- a/ecp5/pack.cc
+++ b/ecp5/pack.cc
@@ -385,10 +385,94 @@ class Ecp5Packer
cell->ports.at(input).net = nullptr;
}
+ // Merge a net into a constant net
+ void set_net_constant(const Context *ctx, NetInfo *orig, NetInfo *constnet, bool constval)
+ {
+ orig->driver.cell = nullptr;
+ for (auto user : orig->users) {
+ if (user.cell != nullptr) {
+ CellInfo *uc = user.cell;
+ if (ctx->verbose)
+ log_info("%s user %s\n", orig->name.c_str(ctx), uc->name.c_str(ctx));
+ if (is_lut(ctx, uc)) {
+ set_lut_input_constant(uc, user.port, constval);
+ } else if (is_ff(ctx, uc) && user.port == ctx->id("CE")) {
+ uc->params[ctx->id("CEMUX")] = constval ? "1" : "0";
+ uc->ports[user.port].net = nullptr;
+ } else if (is_ff(ctx, uc) && user.port == ctx->id("LSR") &&
+ ((!constval && str_or_default(uc->params, ctx->id("LSRMUX"), "LSR") == "LSR") ||
+ (constval && str_or_default(uc->params, ctx->id("LSRMUX"), "LSR") == "INV"))) {
+ uc->ports[user.port].net = nullptr;
+ } else {
+ uc->ports[user.port].net = constnet;
+ constnet->users.push_back(user);
+ }
+ }
+ }
+ orig->users.clear();
+ }
+
+ // Pack constants (simple implementation)
+ void pack_constants()
+ {
+ log_info("Packing constants..\n");
+
+ std::unique_ptr<CellInfo> gnd_cell = create_ecp5_cell(ctx, ctx->id("LUT4"), "$PACKER_GND");
+ gnd_cell->params[ctx->id("LUT_INIT")] = "0";
+ std::unique_ptr<NetInfo> gnd_net = std::unique_ptr<NetInfo>(new NetInfo);
+ gnd_net->name = ctx->id("$PACKER_GND_NET");
+ gnd_net->driver.cell = gnd_cell.get();
+ gnd_net->driver.port = ctx->id("Z");
+ gnd_cell->ports.at(ctx->id("Z")).net = gnd_net.get();
+
+ std::unique_ptr<CellInfo> vcc_cell = create_ecp5_cell(ctx, ctx->id("LUT4"), "$PACKER_VCC");
+ vcc_cell->params[ctx->id("LUT_INIT")] = "65535";
+ std::unique_ptr<NetInfo> vcc_net = std::unique_ptr<NetInfo>(new NetInfo);
+ vcc_net->name = ctx->id("$PACKER_VCC_NET");
+ vcc_net->driver.cell = vcc_cell.get();
+ vcc_net->driver.port = ctx->id("Z");
+ vcc_cell->ports.at(ctx->id("Z")).net = vcc_net.get();
+
+ std::vector<IdString> dead_nets;
+
+ bool gnd_used = false, vcc_used = false;
+
+ for (auto net : sorted(ctx->nets)) {
+ NetInfo *ni = net.second;
+ if (ni->driver.cell != nullptr && ni->driver.cell->type == ctx->id("GND")) {
+ IdString drv_cell = ni->driver.cell->name;
+ set_net_constant(ctx, ni, gnd_net.get(), false);
+ gnd_used = true;
+ dead_nets.push_back(net.first);
+ ctx->cells.erase(drv_cell);
+ } else if (ni->driver.cell != nullptr && ni->driver.cell->type == ctx->id("VCC")) {
+ IdString drv_cell = ni->driver.cell->name;
+ set_net_constant(ctx, ni, vcc_net.get(), true);
+ vcc_used = true;
+ dead_nets.push_back(net.first);
+ ctx->cells.erase(drv_cell);
+ }
+ }
+
+ if (gnd_used) {
+ ctx->cells[gnd_cell->name] = std::move(gnd_cell);
+ ctx->nets[gnd_net->name] = std::move(gnd_net);
+ }
+ if (vcc_used) {
+ ctx->cells[vcc_cell->name] = std::move(vcc_cell);
+ ctx->nets[vcc_net->name] = std::move(vcc_net);
+ }
+
+ for (auto dn : dead_nets) {
+ ctx->nets.erase(dn);
+ }
+ }
+
public:
void pack()
{
pack_io();
+ pack_constants();
find_lutff_pairs();
pack_lut5s();
pair_luts();