Merge pull request #613 from YosysHQ/gatecat/nexus-dphy

Add basic support for Nexus DPHY hard IP
This commit is contained in:
gatecat 2021-03-08 21:11:13 +00:00 committed by GitHub
commit 0f17e80eef
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 121 additions and 2 deletions

View File

@ -800,6 +800,7 @@ enum CellPinStyle
PINSTYLE_DEDI = 0x0000, // dedicated signals, leave alone
PINSTYLE_PU = 0x4022, // signals that float high and default high
PINSTYLE_PU_NONCIB = 0x0022, // signals that float high and default high
PINSTYLE_PD_NONCIB = 0x0012, // signals that float high and default low
PINSTYLE_T = 0x4027, // PIO 'T' signal
PINSTYLE_ADLSB = 0x4017, // special case of the EBR address MSBs

View File

@ -480,3 +480,26 @@ X(CEB2B3)
X(RSTB0B1)
X(RSTB2B3)
X(M9ADDSUB)
X(DPHY)
X(DPHY_CORE)
X(CKN)
X(CKP)
X(DN0)
X(DN1)
X(DN2)
X(DN3)
X(DP0)
X(DP1)
X(DP2)
X(DP3)
X(DP4)
X(SCCLKIN)
X(SCRSTNIN)
X(CLKREF)
X(U2TDE4CK)
X(U1ENTHEN)
X(U2END2)
X(U3END3)
X(UED0THEN)
X(URXCKINE)

View File

@ -569,6 +569,15 @@ struct NexusFasmWriter
{"SSC_STEP_IN", 7}, {"SSC_TBASE", 12},
{"V2I_PP_ICTRL", 5},
};
// Which MIPI params are 'word' values
const std::unordered_map<std::string, int> dphy_word_params = {
{"CM", 8}, {"CN", 5}, {"CO", 3}, {"RSEL", 2}, {"RXCDRP", 2},
{"RXDATAWIDTHHS", 2}, {"RXLPRP", 3}, {"TEST_ENBL", 6},
{"TEST_PATTERN", 32}, {"TST", 4}, {"TXDATAWIDTHHS", 2},
{"UC_PRG_RXHS_SETTLE", 6}, {"U_PRG_HS_PREPARE", 2},
{"U_PRG_HS_TRAIL", 6}, {"U_PRG_HS_ZERO", 6}, {"U_PRG_RXHS_SETTLE", 6}
};
/* clang-format on */
// Write out config for some kind of PLL cell
@ -596,6 +605,27 @@ struct NexusFasmWriter
}
pop();
}
// Write out config for a DPHY_CORE cell
// TODO: duplication with PLL and other hard IP...
void write_dphy(const CellInfo *cell)
{
BelId bel = cell->bel;
push(stringf("IP_%s", ctx->nameOf(IdString(ctx->bel_data(bel).name))));
for (auto param : sorted_cref(cell->params)) {
const std::string &name = param.first.str(ctx);
if (is_mux_param(name) || name == "GSR")
continue;
auto fnd_word = dphy_word_params.find(name);
if (fnd_word != dphy_word_params.end()) {
write_int_vector(stringf("%s[%d:0]", name.c_str(), fnd_word->second - 1),
ctx->parse_lattice_param(cell, param.first, fnd_word->second, 0).as_int64(),
fnd_word->second);
} else {
write_bit(stringf("%s.%s", name.c_str(), param.second.as_string().c_str()));
}
}
pop();
}
// Write out config for an LRAM_CORE cell
void write_lram(const CellInfo *cell)
{
@ -750,6 +780,8 @@ struct NexusFasmWriter
write_pll(ci);
else if (ci->type == id_LRAM_CORE)
write_lram(ci);
else if (ci->type == id_DPHY_CORE)
write_dphy(ci);
blank();
}
// Write config for unused bels

View File

@ -136,10 +136,19 @@ struct NexusGlobalRouter
}
}
bool is_relaxed_sink(const PortRef &sink) const
{
// This DPHY clock port can't be routed without going through some general routing
if (sink.cell->type == id_DPHY_CORE && sink.port == id_URXCKINE)
return true;
return false;
}
void route_clk_net(NetInfo *net)
{
for (size_t i = 0; i < net->users.size(); i++)
backwards_bfs_route(net, i, 1000000, true, [&](PipId pip) { return global_pip_filter(pip); });
backwards_bfs_route(net, i, 1000000, true,
[&](PipId pip) { return is_relaxed_sink(net->users.at(i)) || global_pip_filter(pip); });
log_info(" routed net '%s' using global resources\n", ctx->nameOf(net));
}

View File

@ -1027,7 +1027,7 @@ struct NexusPacker
{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},
{id_PLL, id_PLL_CORE}, {id_DPHY, id_DPHY_CORE},
};
for (auto cell : sorted(ctx->cells)) {
@ -1959,6 +1959,33 @@ struct NexusPacker
}
}
// Map LOC attribute on DPHY_CORE to a bel
// TDPHY_CORE2 is Radiant 2.0 style, DPHY0 is Radiant 2.2
// TODO: LIFCL-17 (perhaps remove the hardcoded map)
const std::unordered_map<std::string, std::string> dphy_loc_map = {
{"TDPHY_CORE2", "X4/Y0/TDPHY_CORE2"},
{"DPHY0", "X4/Y0/TDPHY_CORE2"},
{"TDPHY_CORE26", "X28/Y0/TDPHY_CORE26"},
{"DPHY1", "X28/Y0/TDPHY_CORE26"},
};
void pack_ip()
{
for (auto cell : sorted(ctx->cells)) {
CellInfo *ci = cell.second;
if (ci->type == id_DPHY_CORE) {
auto loc_attr = ci->attrs.find(id_LOC);
if (loc_attr == ci->attrs.end())
log_error("LOC attribute is required for DPHY_CORE '%s'\n", ctx->nameOf(ci));
const std::string &loc = loc_attr->second.as_string();
auto dphy_bel = dphy_loc_map.find(loc);
if (dphy_bel == dphy_loc_map.end())
log_error("Invalid location '%s' for DPHY_CORE '%s'\n", loc.c_str(), ctx->nameOf(ci));
ci->attrs[id_BEL] = dphy_bel->second;
}
}
}
explicit NexusPacker(Context *ctx) : ctx(ctx) {}
void operator()()
@ -1975,6 +2002,7 @@ struct NexusPacker
pack_plls();
pack_constants();
pack_luts();
pack_ip();
promote_globals();
place_globals();
generate_constraints();

View File

@ -189,6 +189,32 @@ static const std::unordered_map<IdString, Arch::CellPinsData> base_cell_pin_data
{id_SCANRST, PINSTYLE_DEDI},
{id_OPCGLDCK, PINSTYLE_DEDI},
{{}, PINSTYLE_CIB},
}},
{id_DPHY_CORE,
{
{id_CKN, PINSTYLE_DEDI},
{id_CKP, PINSTYLE_DEDI},
{id_DN0, PINSTYLE_DEDI},
{id_DN1, PINSTYLE_DEDI},
{id_DN2, PINSTYLE_DEDI},
{id_DN3, PINSTYLE_DEDI},
{id_DP0, PINSTYLE_DEDI},
{id_DP1, PINSTYLE_DEDI},
{id_DP2, PINSTYLE_DEDI},
{id_DP3, PINSTYLE_DEDI},
{id_SCCLKIN, PINSTYLE_DEDI},
{id_SCRSTNIN, PINSTYLE_DEDI},
{id_SCANCLK, PINSTYLE_DEDI},
{id_SCANRST, PINSTYLE_DEDI},
{id_LMMIRESETN, PINSTYLE_DEDI},
{id_CLKREF, PINSTYLE_DEDI},
{id_U2TDE4CK, PINSTYLE_DEDI},
{id_OPCGLDCK, PINSTYLE_DEDI},
{id_U1ENTHEN, PINSTYLE_PD_NONCIB},
{id_U2END2, PINSTYLE_PD_NONCIB},
{id_U3END3, PINSTYLE_PD_NONCIB},
{id_UED0THEN, PINSTYLE_PD_NONCIB},
{{}, PINSTYLE_CIB},
}}};
} // namespace