aboutsummaryrefslogtreecommitdiffstats
path: root/machxo2
diff options
context:
space:
mode:
Diffstat (limited to 'machxo2')
-rw-r--r--machxo2/cells.cc13
-rw-r--r--machxo2/cells.h2
-rw-r--r--machxo2/pack.cc29
3 files changed, 39 insertions, 5 deletions
diff --git a/machxo2/cells.cc b/machxo2/cells.cc
index 20e68ab5..7d15b1af 100644
--- a/machxo2/cells.cc
+++ b/machxo2/cells.cc
@@ -154,15 +154,24 @@ void lut_to_lc(const Context *ctx, CellInfo *lut, CellInfo *lc, bool no_dff)
replace_port(lut, ctx->id("Z"), lc, ctx->id("F0"));
}
-void dff_to_lc(const Context *ctx, CellInfo *dff, CellInfo *lc, bool pass_thru_lut)
+void dff_to_lc(Context *ctx, CellInfo *dff, CellInfo *lc, bool pass_thru_lut)
{
// FIXME: This will have to change once we support FFs with reset value of 1.
lc->params[ctx->id("REG0_REGSET")] = std::string("RESET");
replace_port(dff, ctx->id("CLK"), lc, ctx->id("CLK"));
- replace_port(dff, ctx->id("DI"), lc, ctx->id("DI0"));
replace_port(dff, ctx->id("LSR"), lc, ctx->id("LSR"));
replace_port(dff, ctx->id("Q"), lc, ctx->id("Q0"));
+
+ // If a register's DI port is fed by a constant, options for placing are
+ // limited. Use the LUT to get around this.
+ if(pass_thru_lut) {
+ lc->params[ctx->id("LUT0_INITVAL")] = 0xAAAA;
+ replace_port(dff, ctx->id("DI"), lc, ctx->id("A0"));
+ connect_ports(ctx, lc, ctx->id("F0"), lc, ctx->id("DI0"));
+ } else {
+ replace_port(dff, ctx->id("DI"), lc, ctx->id("DI0"));
+ }
}
void nxio_to_iob(Context *ctx, CellInfo *nxio, CellInfo *iob, std::unordered_set<IdString> &todelete_cells) {}
diff --git a/machxo2/cells.h b/machxo2/cells.h
index 351780ec..a6de219e 100644
--- a/machxo2/cells.h
+++ b/machxo2/cells.h
@@ -46,7 +46,7 @@ void lut_to_lc(const Context *ctx, CellInfo *lut, CellInfo *lc, bool no_dff = tr
// and reconnecting signals as necessary. If pass_thru_lut is True, the LUT will
// be configured as pass through and D connected to I0, otherwise D will be
// ignored
-void dff_to_lc(const Context *ctx, CellInfo *dff, CellInfo *lc, bool pass_thru_lut = false);
+void dff_to_lc(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<IdString> &todelete_cells);
diff --git a/machxo2/pack.cc b/machxo2/pack.cc
index 47f8c907..786a84d6 100644
--- a/machxo2/pack.cc
+++ b/machxo2/pack.cc
@@ -124,10 +124,13 @@ static void pack_remaining_ffs(Context *ctx)
}
// Merge a net into a constant net
-static void set_net_constant(const Context *ctx, NetInfo *orig, NetInfo *constnet, bool constval)
+static void set_net_constant(Context *ctx, NetInfo *orig, NetInfo *constnet, bool constval)
{
(void)constval;
+ std::unordered_set<IdString> packed_cells;
+ std::vector<std::unique_ptr<CellInfo>> new_cells;
+
orig->driver.cell = nullptr;
for (auto user : orig->users) {
if (user.cell != nullptr) {
@@ -135,11 +138,33 @@ static void set_net_constant(const Context *ctx, NetInfo *orig, NetInfo *constne
if (ctx->verbose)
log_info("%s user %s\n", orig->name.c_str(ctx), uc->name.c_str(ctx));
- uc->ports[user.port].net = constnet;
+ if(uc->type == id_FACADE_FF && user.port == id_DI) {
+ log_info("FACADE_FF %s is driven by a constant\n", uc->name.c_str(ctx));
+
+ std::unique_ptr<CellInfo> lc = create_machxo2_cell(ctx, id_FACADE_SLICE, uc->name.str(ctx) + "_CONST");
+ dff_to_lc(ctx, uc, lc.get(), true);
+ packed_cells.insert(uc->name);
+
+ lc->ports[id_A0].net = constnet;
+ user.cell = lc.get();
+ user.port = id_A0;
+
+ new_cells.push_back(std::move(lc));
+ } else {
+ uc->ports[user.port].net = constnet;
+ }
+
constnet->users.push_back(user);
}
}
orig->users.clear();
+
+ for (auto pcell : packed_cells) {
+ ctx->cells.erase(pcell);
+ }
+ for (auto &ncell : new_cells) {
+ ctx->cells[ncell->name] = std::move(ncell);
+ }
}
// Pack constants (based on simple implementation in generic).