Merge branch 'master' into 'master'
Master See merge request eddiehung/nextpnr!3
This commit is contained in:
commit
7e6332735d
@ -200,7 +200,7 @@ struct PipMap
|
|||||||
PlaceStrength strength = STRENGTH_NONE;
|
PlaceStrength strength = STRENGTH_NONE;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct NetInfo
|
struct NetInfo : ArchNetInfo
|
||||||
{
|
{
|
||||||
IdString name;
|
IdString name;
|
||||||
PortRef driver;
|
PortRef driver;
|
||||||
@ -225,7 +225,7 @@ struct PortInfo
|
|||||||
PortType type;
|
PortType type;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct CellInfo
|
struct CellInfo : ArchCellInfo
|
||||||
{
|
{
|
||||||
IdString name, type;
|
IdString name, type;
|
||||||
std::unordered_map<IdString, PortInfo> ports;
|
std::unordered_map<IdString, PortInfo> ports;
|
||||||
|
@ -129,6 +129,9 @@ struct DecalId
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct ArchNetInfo { };
|
||||||
|
struct ArchCellInfo { };
|
||||||
|
|
||||||
NEXTPNR_NAMESPACE_END
|
NEXTPNR_NAMESPACE_END
|
||||||
|
|
||||||
namespace std {
|
namespace std {
|
||||||
|
@ -214,6 +214,18 @@ void write_bitstream(Context *ctx, std::string base_config_file, std::string tex
|
|||||||
cc.tiles[tname].add_enum(slice + ".REG1.REGSET",
|
cc.tiles[tname].add_enum(slice + ".REG1.REGSET",
|
||||||
str_or_default(ci->params, ctx->id("REG1_REGSET"), "RESET"));
|
str_or_default(ci->params, ctx->id("REG1_REGSET"), "RESET"));
|
||||||
cc.tiles[tname].add_enum(slice + ".CEMUX", str_or_default(ci->params, ctx->id("CEMUX"), "1"));
|
cc.tiles[tname].add_enum(slice + ".CEMUX", str_or_default(ci->params, ctx->id("CEMUX"), "1"));
|
||||||
|
IdString lsrnet;
|
||||||
|
if (ci->ports.find(ctx->id("LSR")) != ci->ports.end() && ci->ports.at(ctx->id("LSR")).net != nullptr)
|
||||||
|
lsrnet = ci->ports.at(ctx->id("LSR")).net->name;
|
||||||
|
if (ctx->getBoundWireNet(ctx->getWireByName(
|
||||||
|
ctx->id(fmt_str("X" << bel.location.x << "/Y" << bel.location.y << "/LSR0")))) == lsrnet) {
|
||||||
|
cc.tiles[tname].add_enum("LSR0.SRMODE", str_or_default(ci->params, ctx->id("SRMODE"), "LSR_OVER_CE"));
|
||||||
|
cc.tiles[tname].add_enum("LSR0.LSRMUX", str_or_default(ci->params, ctx->id("LSRMUX"), "LSR"));
|
||||||
|
} else if (ctx->getBoundWireNet(ctx->getWireByName(ctx->id(
|
||||||
|
fmt_str("X" << bel.location.x << "/Y" << bel.location.y << "/LSR1")))) == lsrnet) {
|
||||||
|
cc.tiles[tname].add_enum("LSR1.SRMODE", str_or_default(ci->params, ctx->id("SRMODE"), "LSR_OVER_CE"));
|
||||||
|
cc.tiles[tname].add_enum("LSR1.LSRMUX", str_or_default(ci->params, ctx->id("LSRMUX"), "LSR"));
|
||||||
|
}
|
||||||
// TODO: CLKMUX, CEMUX, carry
|
// TODO: CLKMUX, CEMUX, carry
|
||||||
} else if (ci->type == ctx->id("TRELLIS_IO")) {
|
} else if (ci->type == ctx->id("TRELLIS_IO")) {
|
||||||
std::string pio = ctx->locInfo(bel)->bel_data[bel.index].name.get();
|
std::string pio = ctx->locInfo(bel)->bel_data[bel.index].name.get();
|
||||||
|
@ -41,7 +41,7 @@ std::unique_ptr<CellInfo> create_ecp5_cell(Context *ctx, IdString type, std::str
|
|||||||
new_cell->name = ctx->id(name);
|
new_cell->name = ctx->id(name);
|
||||||
}
|
}
|
||||||
new_cell->type = type;
|
new_cell->type = type;
|
||||||
if (type == ctx->id("TRELLIS_LC")) {
|
if (type == ctx->id("TRELLIS_SLICE")) {
|
||||||
new_cell->params[ctx->id("MODE")] = "LOGIC";
|
new_cell->params[ctx->id("MODE")] = "LOGIC";
|
||||||
new_cell->params[ctx->id("GSR")] = "DISABLED";
|
new_cell->params[ctx->id("GSR")] = "DISABLED";
|
||||||
new_cell->params[ctx->id("SRMODE")] = "LSR_OVER_CE";
|
new_cell->params[ctx->id("SRMODE")] = "LSR_OVER_CE";
|
||||||
@ -131,7 +131,7 @@ static void set_param_safe(bool has_ff, CellInfo *lc, IdString name, const std::
|
|||||||
static void replace_port_safe(bool has_ff, CellInfo *ff, IdString ff_port, CellInfo *lc, IdString lc_port)
|
static void replace_port_safe(bool has_ff, CellInfo *ff, IdString ff_port, CellInfo *lc, IdString lc_port)
|
||||||
{
|
{
|
||||||
if (has_ff) {
|
if (has_ff) {
|
||||||
assert(lc->ports.at(lc_port).net == ff->ports.at(ff_port).net);
|
NPNR_ASSERT(lc->ports.at(lc_port).net == ff->ports.at(ff_port).net);
|
||||||
NetInfo *ffnet = ff->ports.at(ff_port).net;
|
NetInfo *ffnet = ff->ports.at(ff_port).net;
|
||||||
if (ffnet != nullptr)
|
if (ffnet != nullptr)
|
||||||
ffnet->users.erase(
|
ffnet->users.erase(
|
||||||
@ -154,8 +154,10 @@ void ff_to_slice(Context *ctx, CellInfo *ff, CellInfo *lc, int index, bool drive
|
|||||||
lc->params[ctx->id(reg + "_SD")] = driven_by_lut ? "1" : "0";
|
lc->params[ctx->id(reg + "_SD")] = driven_by_lut ? "1" : "0";
|
||||||
lc->params[ctx->id(reg + "_REGSET")] = str_or_default(ff->params, ctx->id("REGSET"), "RESET");
|
lc->params[ctx->id(reg + "_REGSET")] = str_or_default(ff->params, ctx->id("REGSET"), "RESET");
|
||||||
replace_port_safe(has_ff, ff, ctx->id("CLK"), lc, ctx->id("CLK"));
|
replace_port_safe(has_ff, ff, ctx->id("CLK"), lc, ctx->id("CLK"));
|
||||||
replace_port_safe(has_ff, ff, ctx->id("LSR"), lc, ctx->id("LSR"));
|
if (ff->ports.find(ctx->id("LSR")) != ff->ports.end())
|
||||||
replace_port_safe(has_ff, ff, ctx->id("CE"), lc, ctx->id("CE"));
|
replace_port_safe(has_ff, ff, ctx->id("LSR"), lc, ctx->id("LSR"));
|
||||||
|
if (ff->ports.find(ctx->id("CE")) != ff->ports.end())
|
||||||
|
replace_port_safe(has_ff, ff, ctx->id("CE"), lc, ctx->id("CE"));
|
||||||
|
|
||||||
replace_port(ff, ctx->id("Q"), lc, ctx->id("Q" + std::to_string(index)));
|
replace_port(ff, ctx->id("Q"), lc, ctx->id("Q" + std::to_string(index)));
|
||||||
if (driven_by_lut) {
|
if (driven_by_lut) {
|
||||||
|
41
ecp5/pack.cc
41
ecp5/pack.cc
@ -119,7 +119,8 @@ class Ecp5Packer
|
|||||||
NetInfo *znet = ci->ports.at(ctx->id("Z")).net;
|
NetInfo *znet = ci->ports.at(ctx->id("Z")).net;
|
||||||
if (znet != nullptr) {
|
if (znet != nullptr) {
|
||||||
for (auto user : znet->users) {
|
for (auto user : znet->users) {
|
||||||
if (is_lut(ctx, user.cell) && procdLuts.find(user.cell->name) == procdLuts.end()) {
|
if (is_lut(ctx, user.cell) && user.cell != ci &&
|
||||||
|
procdLuts.find(user.cell->name) == procdLuts.end()) {
|
||||||
if (can_pack_lutff(ci->name, user.cell->name)) {
|
if (can_pack_lutff(ci->name, user.cell->name)) {
|
||||||
procdLuts.insert(ci->name);
|
procdLuts.insert(ci->name);
|
||||||
procdLuts.insert(user.cell->name);
|
procdLuts.insert(user.cell->name);
|
||||||
@ -137,7 +138,8 @@ class Ecp5Packer
|
|||||||
NetInfo *qnet = ctx->cells.at(lutffPairs[ci->name])->ports.at(ctx->id("Q")).net;
|
NetInfo *qnet = ctx->cells.at(lutffPairs[ci->name])->ports.at(ctx->id("Q")).net;
|
||||||
if (qnet != nullptr) {
|
if (qnet != nullptr) {
|
||||||
for (auto user : qnet->users) {
|
for (auto user : qnet->users) {
|
||||||
if (is_lut(ctx, user.cell) && procdLuts.find(user.cell->name) == procdLuts.end()) {
|
if (is_lut(ctx, user.cell) && user.cell != ci &&
|
||||||
|
procdLuts.find(user.cell->name) == procdLuts.end()) {
|
||||||
if (can_pack_lutff(ci->name, user.cell->name)) {
|
if (can_pack_lutff(ci->name, user.cell->name)) {
|
||||||
procdLuts.insert(ci->name);
|
procdLuts.insert(ci->name);
|
||||||
procdLuts.insert(user.cell->name);
|
procdLuts.insert(user.cell->name);
|
||||||
@ -152,11 +154,11 @@ class Ecp5Packer
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for (char inp : "ABCD") {
|
for (const char *inp : {"A", "B", "C", "D"}) {
|
||||||
NetInfo *innet = ci->ports.at(ctx->id(std::string("") + inp)).net;
|
NetInfo *innet = ci->ports.at(ctx->id(inp)).net;
|
||||||
if (innet != nullptr && innet->driver.cell != nullptr) {
|
if (innet != nullptr && innet->driver.cell != nullptr) {
|
||||||
CellInfo *drv = innet->driver.cell;
|
CellInfo *drv = innet->driver.cell;
|
||||||
if (is_lut(ctx, drv) && innet->driver.port == ctx->id("Z")) {
|
if (is_lut(ctx, drv) && drv != ci && innet->driver.port == ctx->id("Z")) {
|
||||||
if (procdLuts.find(drv->name) == procdLuts.end()) {
|
if (procdLuts.find(drv->name) == procdLuts.end()) {
|
||||||
if (can_pack_lutff(ci->name, drv->name)) {
|
if (can_pack_lutff(ci->name, drv->name)) {
|
||||||
procdLuts.insert(ci->name);
|
procdLuts.insert(ci->name);
|
||||||
@ -167,7 +169,8 @@ class Ecp5Packer
|
|||||||
}
|
}
|
||||||
} else if (is_ff(ctx, drv) && innet->driver.port == ctx->id("Q")) {
|
} else if (is_ff(ctx, drv) && innet->driver.port == ctx->id("Q")) {
|
||||||
auto fflut = fflutPairs.find(drv->name);
|
auto fflut = fflutPairs.find(drv->name);
|
||||||
if (fflut != fflutPairs.end() && procdLuts.find(fflut->second) == procdLuts.end()) {
|
if (fflut != fflutPairs.end() && fflut->second != ci->name &&
|
||||||
|
procdLuts.find(fflut->second) == procdLuts.end()) {
|
||||||
if (can_pack_lutff(ci->name, fflut->second)) {
|
if (can_pack_lutff(ci->name, fflut->second)) {
|
||||||
procdLuts.insert(ci->name);
|
procdLuts.insert(ci->name);
|
||||||
procdLuts.insert(fflut->second);
|
procdLuts.insert(fflut->second);
|
||||||
@ -356,6 +359,32 @@ class Ecp5Packer
|
|||||||
flush_cells();
|
flush_cells();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void set_lut_input_constant(CellInfo *cell, IdString input, bool value)
|
||||||
|
{
|
||||||
|
int index = std::string("ABCD").find(input.str(ctx));
|
||||||
|
int init = int_or_default(cell->params, ctx->id("INIT"));
|
||||||
|
int new_init = 0;
|
||||||
|
for (int i = 0; i < 16; i++) {
|
||||||
|
if (((i >> index) & 0x1) != value) {
|
||||||
|
int other_i = (i & (~(1 << index))) | (value << index);
|
||||||
|
if ((init >> other_i) & 0x1)
|
||||||
|
new_init |= (1 << i);
|
||||||
|
} else {
|
||||||
|
if ((init >> i) & 0x1)
|
||||||
|
new_init |= (1 << i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
cell->params[ctx->id("INIT")] = std::to_string(init);
|
||||||
|
NetInfo *innet = cell->ports.at(input).net;
|
||||||
|
if (innet != nullptr) {
|
||||||
|
innet->users.erase(
|
||||||
|
std::remove_if(innet->users.begin(), innet->users.end(),
|
||||||
|
[cell, input](PortRef port) { return port.cell == cell && port.port == input; }),
|
||||||
|
innet->users.end());
|
||||||
|
}
|
||||||
|
cell->ports.at(input).net = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
public:
|
public:
|
||||||
void pack()
|
void pack()
|
||||||
{
|
{
|
||||||
|
2
ecp5/synth/blinky_nopack.ys
Normal file
2
ecp5/synth/blinky_nopack.ys
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
read_verilog blinky.v
|
||||||
|
synth_ecp5 -noccu2 -nomux -nodram -json blinky.json
|
@ -52,4 +52,7 @@ typedef IdString PipId;
|
|||||||
typedef IdString GroupId;
|
typedef IdString GroupId;
|
||||||
typedef IdString DecalId;
|
typedef IdString DecalId;
|
||||||
|
|
||||||
|
struct ArchNetInfo { };
|
||||||
|
struct ArchCellInfo { };
|
||||||
|
|
||||||
NEXTPNR_NAMESPACE_END
|
NEXTPNR_NAMESPACE_END
|
||||||
|
@ -61,9 +61,9 @@ YosysTab::YosysTab(QString folder, QWidget *parent) : QWidget(parent)
|
|||||||
connect(process, SIGNAL(readyReadStandardError()), this, SLOT(onReadyReadStandardError()));
|
connect(process, SIGNAL(readyReadStandardError()), this, SLOT(onReadyReadStandardError()));
|
||||||
connect(process, SIGNAL(readyReadStandardOutput()), this, SLOT(onReadyReadStandardOutput()));
|
connect(process, SIGNAL(readyReadStandardOutput()), this, SLOT(onReadyReadStandardOutput()));
|
||||||
connect(process, &QProcess::started, this, [this] { lineEdit->setEnabled(true); });
|
connect(process, &QProcess::started, this, [this] { lineEdit->setEnabled(true); });
|
||||||
/*
|
|
||||||
#if QT_VERSION < QT_VERSION_CHECK(5, 6, 0)
|
#if QT_VERSION < QT_VERSION_CHECK(5, 6, 0)
|
||||||
connect(process, &QProcess::error, this, [this](QProcess::ProcessError error) {
|
connect(process, static_cast<void (QProcess::*)(QProcess::ProcessError)>(&QProcess::error), this, [this](QProcess::ProcessError error) {
|
||||||
#else
|
#else
|
||||||
connect(process, &QProcess::errorOccurred, this, [this](QProcess::ProcessError error) {
|
connect(process, &QProcess::errorOccurred, this, [this](QProcess::ProcessError error) {
|
||||||
#endif
|
#endif
|
||||||
@ -74,7 +74,6 @@ YosysTab::YosysTab(QString folder, QWidget *parent) : QWidget(parent)
|
|||||||
Q_EMIT deleteLater();
|
Q_EMIT deleteLater();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
*/
|
|
||||||
process->setWorkingDirectory(folder);
|
process->setWorkingDirectory(folder);
|
||||||
process->start("yosys");
|
process->start("yosys");
|
||||||
}
|
}
|
||||||
|
@ -150,6 +150,9 @@ struct DecalId
|
|||||||
bool operator!=(const DecalId &other) const { return (type != other.type) || (index != other.index); }
|
bool operator!=(const DecalId &other) const { return (type != other.type) || (index != other.index); }
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct ArchNetInfo { };
|
||||||
|
struct ArchCellInfo { };
|
||||||
|
|
||||||
NEXTPNR_NAMESPACE_END
|
NEXTPNR_NAMESPACE_END
|
||||||
|
|
||||||
namespace std {
|
namespace std {
|
||||||
@ -201,5 +204,4 @@ template <> struct hash<NEXTPNR_NAMESPACE_PREFIX DecalId>
|
|||||||
return seed;
|
return seed;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace std
|
} // namespace std
|
||||||
|
Loading…
Reference in New Issue
Block a user