aboutsummaryrefslogtreecommitdiffstats
path: root/ecp5/pack.cc
diff options
context:
space:
mode:
Diffstat (limited to 'ecp5/pack.cc')
-rw-r--r--ecp5/pack.cc84
1 files changed, 84 insertions, 0 deletions
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();