aboutsummaryrefslogtreecommitdiffstats
path: root/nexus
diff options
context:
space:
mode:
authorDavid Shah <dave@ds0.me>2020-12-02 17:07:34 +0000
committerDavid Shah <dave@ds0.me>2020-12-02 17:07:34 +0000
commit270efdca8571a58c6ec40dbe27247f6a30fb62fb (patch)
treee452061dc9cf7f682ce7d16e0e69fb54a94ecf91 /nexus
parent86e6a2225c57cf26961efa92ba82b4e59ad53fda (diff)
downloadnextpnr-270efdca8571a58c6ec40dbe27247f6a30fb62fb.tar.gz
nextpnr-270efdca8571a58c6ec40dbe27247f6a30fb62fb.tar.bz2
nextpnr-270efdca8571a58c6ec40dbe27247f6a30fb62fb.zip
nexus: Add basic LRAM support (no init)
Signed-off-by: David Shah <dave@ds0.me>
Diffstat (limited to 'nexus')
-rw-r--r--nexus/arch.cc11
-rw-r--r--nexus/arch.h2
-rw-r--r--nexus/constids.inc21
-rw-r--r--nexus/fasm.cc18
-rw-r--r--nexus/pack.cc57
-rw-r--r--nexus/pins.cc11
6 files changed, 116 insertions, 4 deletions
diff --git a/nexus/arch.cc b/nexus/arch.cc
index f222a5ad..dbc12c13 100644
--- a/nexus/arch.cc
+++ b/nexus/arch.cc
@@ -619,6 +619,10 @@ ArcBounds Arch::getRouteBoundingBox(WireId src, WireId dst) const
bb.x0 = std::max<int>(0, bb.x0 - 6);
bb.x1 = std::min<int>(chip_info->width, bb.x1 + 6);
}
+ if (lram_wires.count(src) || lram_wires.count(dst)) {
+ bb.y0 = std::max<int>(0, bb.y0 - 7);
+ bb.y1 = std::min<int>(chip_info->width, bb.y1 + 7);
+ }
return bb;
}
@@ -669,6 +673,13 @@ void Arch::pre_routing()
dsp_wires.insert(wire);
}
}
+ if (ci->type == id_LRAM_CORE) {
+ for (auto port : sorted_ref(ci->ports)) {
+ WireId wire = getBelPinWire(ci->bel, port.first);
+ if (wire != WireId())
+ lram_wires.insert(wire);
+ }
+ }
}
}
diff --git a/nexus/arch.h b/nexus/arch.h
index d4d4799e..c1a5fcde 100644
--- a/nexus/arch.h
+++ b/nexus/arch.h
@@ -1363,7 +1363,7 @@ struct Arch : BaseCtx
// for better DSP bounding boxes
void pre_routing();
- std::unordered_set<WireId> dsp_wires;
+ std::unordered_set<WireId> dsp_wires, lram_wires;
// -------------------------------------------------
diff --git a/nexus/constids.inc b/nexus/constids.inc
index f8939263..e4901692 100644
--- a/nexus/constids.inc
+++ b/nexus/constids.inc
@@ -443,3 +443,24 @@ X(DIVF)
X(REF_MMD_DIG)
X(FBK_MMD_DIG)
X(CLKMUX_FB)
+
+X(LRAM_CORE)
+
+X(EBR_SP_EN)
+X(ECC_BYTE_SEL)
+X(CS)
+X(CSA)
+X(CSB)
+X(CSR)
+X(CSW)
+X(OCEA)
+X(OCEB)
+X(RSTR)
+X(DPS)
+X(IGN)
+X(INITN)
+X(STDBYN)
+X(TBISTN)
+X(WE)
+X(CEOUTA)
+X(CEOUTB)
diff --git a/nexus/fasm.cc b/nexus/fasm.cc
index fcbe0b8c..0c53e836 100644
--- a/nexus/fasm.cc
+++ b/nexus/fasm.cc
@@ -596,6 +596,22 @@ struct NexusFasmWriter
}
pop();
}
+ // Write out config for an LRAM_CORE cell
+ void write_lram(const CellInfo *cell)
+ {
+ BelId bel = cell->bel;
+ push_bel(bel);
+ write_enum(cell, "ASYNC_RST_RELEASE", "SYNC");
+ write_enum(cell, "EBR_SP_EN", "DISABLE");
+ write_enum(cell, "ECC_BYTE_SEL", "ECC_EN");
+ write_enum(cell, "GSR", "DISABLED");
+ write_enum(cell, "OUT_REGMODE_A", "NO_REG");
+ write_enum(cell, "OUT_REGMODE_B", "NO_REG");
+ write_enum(cell, "RESETMODE", "SYNC");
+ write_enum(cell, "UNALIGNED_READ", "DISABLE");
+ write_cell_muxes(cell);
+ pop();
+ }
// Write out FASM for unused bels where needed
void write_unused()
{
@@ -710,6 +726,8 @@ struct NexusFasmWriter
write_dsp(ci);
else if (ci->type == id_PLL_CORE)
write_pll(ci);
+ else if (ci->type == id_LRAM_CORE)
+ write_lram(ci);
blank();
}
// Write config for unused bels
diff --git a/nexus/pack.cc b/nexus/pack.cc
index eb1ac560..b1642153 100644
--- a/nexus/pack.cc
+++ b/nexus/pack.cc
@@ -1024,8 +1024,9 @@ struct NexusPacker
{
// Convert primitives from their non-CORE variant to their CORE variant
static const std::unordered_map<IdString, IdString> prim_map = {
- {id_OSCA, id_OSC_CORE}, {id_DP16K, id_DP16K_MODE}, {id_PDP16K, id_PDP16K_MODE},
- {id_PDPSC16K, id_PDPSC16K_MODE}, {id_SP16K, id_SP16K_MODE}, {id_FIFO16K, id_FIFO16K_MODE},
+ {id_OSCA, id_OSC_CORE}, {id_DP16K, id_DP16K_MODE}, {id_PDP16K, id_PDP16K_MODE},
+ {id_PDPSC16K, id_PDPSC16K_MODE}, {id_SP16K, id_SP16K_MODE}, {id_FIFO16K, id_FIFO16K_MODE},
+ {id_SP512K, id_SP512K_MODE}, {id_DPSC512K, id_DPSC512K_MODE}, {id_PDPSC512K, id_PDPSC512K_MODE},
{id_PLL, id_PLL_CORE},
};
@@ -1092,6 +1093,57 @@ struct NexusPacker
}
}
+ void pack_lram()
+ {
+ std::unordered_map<IdString, XFormRule> lram_rules;
+ lram_rules[id_SP512K_MODE].new_type = id_LRAM_CORE;
+ lram_rules[id_SP512K_MODE].set_params.emplace_back(id_EBR_SP_EN, std::string("ENABLE"));
+ lram_rules[id_SP512K_MODE].port_xform[id_CE] = id_CEA;
+ lram_rules[id_SP512K_MODE].port_xform[id_CS] = id_CSA;
+ lram_rules[id_SP512K_MODE].port_xform[id_WE] = id_WEA;
+ lram_rules[id_SP512K_MODE].port_xform[id_RSTOUT] = id_RSTA;
+ lram_rules[id_SP512K_MODE].port_xform[id_CEOUT] = id_OCEA;
+ add_bus_xform(lram_rules[id_SP512K_MODE], "DI", "DIA", 32);
+ add_bus_xform(lram_rules[id_SP512K_MODE], "DO", "DOA", 32);
+ add_bus_xform(lram_rules[id_SP512K_MODE], "AD", "ADA", 14);
+ add_bus_xform(lram_rules[id_SP512K_MODE], "BYTEEN_N", "BENA_N", 4);
+
+ lram_rules[id_PDPSC512K_MODE].new_type = id_LRAM_CORE;
+ lram_rules[id_PDPSC512K_MODE].port_xform[id_CEW] = id_CEA;
+ lram_rules[id_PDPSC512K_MODE].port_xform[id_CSW] = id_CSA;
+ lram_rules[id_PDPSC512K_MODE].port_xform[id_CER] = id_CEB;
+ lram_rules[id_PDPSC512K_MODE].port_xform[id_CSR] = id_CSB;
+ lram_rules[id_PDPSC512K_MODE].port_xform[id_WE] = id_WEA;
+ lram_rules[id_PDPSC512K_MODE].port_xform[id_RSTR] = id_RSTB;
+ add_bus_xform(lram_rules[id_PDPSC512K_MODE], "DI", "DIA", 32);
+ add_bus_xform(lram_rules[id_PDPSC512K_MODE], "DO", "DOB", 32);
+ add_bus_xform(lram_rules[id_PDPSC512K_MODE], "ADW", "ADA", 14);
+ add_bus_xform(lram_rules[id_PDPSC512K_MODE], "ADR", "ADB", 14);
+ add_bus_xform(lram_rules[id_PDPSC512K_MODE], "BYTEEN_N", "BENA_N", 4);
+
+ lram_rules[id_DPSC512K_MODE].new_type = id_LRAM_CORE;
+ lram_rules[id_DPSC512K_MODE].port_xform[id_CEOUTA] = id_OCEA;
+ lram_rules[id_DPSC512K_MODE].port_xform[id_CEOUTB] = id_OCEB;
+
+ log_info("Packing LRAM...\n");
+ generic_xform(lram_rules, true);
+
+ for (auto cell : sorted(ctx->cells)) {
+ CellInfo *ci = cell.second;
+ if (ci->type != id_LRAM_CORE)
+ continue;
+ for (int i = 0; i < 0x80; i++) {
+ // FIXME: support on the prjoxide side
+ std::string name = stringf("INITVAL_%02X", i);
+ if (!ci->params.count(ctx->id(name)))
+ continue;
+ if (ci->params.at(ctx->id(name)).str.find_last_not_of("0x") == std::string::npos)
+ continue;
+ log_error("LRAM initialisation is currently unsupported (prjoxide limitation).\n");
+ }
+ }
+ }
+
void pack_widefn()
{
std::vector<CellInfo *> widefns;
@@ -1883,6 +1935,7 @@ struct NexusPacker
pack_dsps();
convert_prims();
pack_bram();
+ pack_lram();
pack_lutram();
pack_carries();
pack_widefn();
diff --git a/nexus/pins.cc b/nexus/pins.cc
index 05bffb1e..5586aeea 100644
--- a/nexus/pins.cc
+++ b/nexus/pins.cc
@@ -168,7 +168,16 @@ static const std::unordered_map<IdString, Arch::CellPinsData> base_cell_pin_data
{id_ENEXT, PINSTYLE_DEDI},
{{}, PINSTYLE_CIB},
}},
-};
+ {id_LRAM_CORE,
+ {
+ {id_CLK, PINSTYLE_CLK}, {id_CEA, PINSTYLE_CE}, {id_CEB, PINSTYLE_CE},
+ {id_OCEA, PINSTYLE_PU}, {id_OCEB, PINSTYLE_PU}, {id_CSA, PINSTYLE_CE},
+ {id_CSB, PINSTYLE_CE}, {id_RSTA, PINSTYLE_LSR}, {id_RSTB, PINSTYLE_LSR},
+ {id_WEA, PINSTYLE_LSR}, {id_WEB, PINSTYLE_LSR}, {id_IGN, PINSTYLE_PU},
+ {id_INITN, PINSTYLE_PU}, {id_STDBYN, PINSTYLE_PU}, {id_TBISTN, PINSTYLE_PU},
+ {id_SCANCLK, PINSTYLE_DEDI}, {id_SCANRST, PINSTYLE_DEDI}, {id_OPCGLDCK, PINSTYLE_DEDI},
+ {{}, PINSTYLE_CIB},
+ }}};
} // namespace
void Arch::init_cell_pin_data() { cell_pins_db = base_cell_pin_data; }