ice40: Merge driving LUT<=2s into carry-only LCs
Signed-off-by: gatecat <gatecat@ds0.me>
This commit is contained in:
parent
3ed53153ca
commit
5a9ddc0675
@ -29,7 +29,7 @@ RUN set -e -x ;\
|
|||||||
cd /usr/local/src ;\
|
cd /usr/local/src ;\
|
||||||
git clone --recursive https://github.com/YosysHQ/icestorm.git ;\
|
git clone --recursive https://github.com/YosysHQ/icestorm.git ;\
|
||||||
cd icestorm ;\
|
cd icestorm ;\
|
||||||
git reset --hard 4bc68c9620e6be20f8fe10d20f84681d80beac23 ;\
|
git reset --hard 9f66f9ce16941c6417813cb87653c735a78b53ae ;\
|
||||||
make -j $(nproc) ;\
|
make -j $(nproc) ;\
|
||||||
make install
|
make install
|
||||||
|
|
||||||
|
@ -923,9 +923,20 @@ std::vector<GraphicElement> Arch::getDecalGraphics(DecalId decal) const
|
|||||||
|
|
||||||
bool Arch::getCellDelay(const CellInfo *cell, IdString fromPort, IdString toPort, DelayQuad &delay) const
|
bool Arch::getCellDelay(const CellInfo *cell, IdString fromPort, IdString toPort, DelayQuad &delay) const
|
||||||
{
|
{
|
||||||
if (cell->type == id_ICESTORM_LC && cell->lcInfo.dffEnable) {
|
if (cell->type == id_ICESTORM_LC) {
|
||||||
if (toPort == id_O)
|
if (toPort == id_O) {
|
||||||
return false;
|
if (cell->lcInfo.dffEnable)
|
||||||
|
return false;
|
||||||
|
// "false paths"
|
||||||
|
if (fromPort == id_I0 && ((cell->lcInfo.lutInputMask & 0x1U) == 0))
|
||||||
|
return false;
|
||||||
|
if (fromPort == id_I1 && ((cell->lcInfo.lutInputMask & 0x2U) == 0))
|
||||||
|
return false;
|
||||||
|
if (fromPort == id_I2 && ((cell->lcInfo.lutInputMask & 0x4U) == 0))
|
||||||
|
return false;
|
||||||
|
if (fromPort == id_I3 && ((cell->lcInfo.lutInputMask & 0x8U) == 0))
|
||||||
|
return false;
|
||||||
|
}
|
||||||
} else if (cell->type == id_ICESTORM_RAM || cell->type == id_ICESTORM_SPRAM) {
|
} else if (cell->type == id_ICESTORM_RAM || cell->type == id_ICESTORM_SPRAM) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@ -1231,6 +1242,18 @@ void Arch::assignCellInfo(CellInfo *cell)
|
|||||||
cell->lcInfo.inputCount++;
|
cell->lcInfo.inputCount++;
|
||||||
if (cell->getPort(id_I3))
|
if (cell->getPort(id_I3))
|
||||||
cell->lcInfo.inputCount++;
|
cell->lcInfo.inputCount++;
|
||||||
|
// Find don't care LUT inputs to mask for timing analysis
|
||||||
|
cell->lcInfo.lutInputMask = 0x0;
|
||||||
|
unsigned init = int_or_default(cell->params, id_LUT_INIT);
|
||||||
|
for (unsigned k = 0; k < 4; k++) {
|
||||||
|
for (unsigned i = 0; i < 16; i++) {
|
||||||
|
// If toggling the LUT input makes a difference it's not a don't care
|
||||||
|
if (((init >> i) & 0x1U) != ((init >> (i ^ (1U << k))) & 0x1U)) {
|
||||||
|
cell->lcInfo.lutInputMask |= (1U << k);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
} else if (cell->type == id_SB_IO) {
|
} else if (cell->type == id_SB_IO) {
|
||||||
cell->ioInfo.lvds = str_or_default(cell->params, id_IO_STANDARD, "SB_LVCMOS") == "SB_LVDS_INPUT";
|
cell->ioInfo.lvds = str_or_default(cell->params, id_IO_STANDARD, "SB_LVCMOS") == "SB_LVDS_INPUT";
|
||||||
cell->ioInfo.global = bool_or_default(cell->attrs, id_GLOBAL);
|
cell->ioInfo.global = bool_or_default(cell->attrs, id_GLOBAL);
|
||||||
|
@ -137,6 +137,7 @@ struct ArchCellInfo : BaseClusterInfo
|
|||||||
bool carryEnable;
|
bool carryEnable;
|
||||||
bool negClk;
|
bool negClk;
|
||||||
int inputCount;
|
int inputCount;
|
||||||
|
unsigned lutInputMask;
|
||||||
const NetInfo *clk, *cen, *sr;
|
const NetInfo *clk, *cen, *sr;
|
||||||
} lcInfo;
|
} lcInfo;
|
||||||
struct
|
struct
|
||||||
|
@ -266,6 +266,68 @@ static void pack_carries(Context *ctx)
|
|||||||
log_info(" %4d LCs used as CARRY only\n", carry_only);
|
log_info(" %4d LCs used as CARRY only\n", carry_only);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void merge_carry_luts(Context *ctx)
|
||||||
|
{
|
||||||
|
// Find carrys
|
||||||
|
log_info("Packing indirect carry+LUT pairs...\n");
|
||||||
|
// Find cases where a less-than-LUT2 is driving a carry and pack them together
|
||||||
|
// +----+ +-----+ |
|
||||||
|
// A--|LUT2|----|CARRY| |
|
||||||
|
// B--| | C-| |-+
|
||||||
|
// +----+ +-| |
|
||||||
|
// | +-----+
|
||||||
|
// |
|
||||||
|
pool<IdString> packed_cells;
|
||||||
|
auto rewrite_init = [](unsigned lut_init) {
|
||||||
|
// I0 -> LUT I2
|
||||||
|
// I1, I2 -> carry; don't care
|
||||||
|
// I3 -> LUT I3
|
||||||
|
unsigned result = 0;
|
||||||
|
for (unsigned i = 0; i < 16; i++) {
|
||||||
|
unsigned j = 0;
|
||||||
|
if ((i & 1))
|
||||||
|
j |= 4;
|
||||||
|
if ((i & 8))
|
||||||
|
j |= 8;
|
||||||
|
if (lut_init & (1 << j))
|
||||||
|
result |= (1 << i);
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
};
|
||||||
|
for (auto &cell : ctx->cells) {
|
||||||
|
CellInfo *ci = cell.second.get();
|
||||||
|
if (ci->type != id_ICESTORM_LC || !bool_or_default(ci->params, id_CARRY_ENABLE))
|
||||||
|
continue; // not a carry LC
|
||||||
|
if (ci->getPort(id_O))
|
||||||
|
continue; // LUT output is already used
|
||||||
|
for (auto port : {id_I1, id_I2}) { // check carry inputs
|
||||||
|
NetInfo *i = ci->getPort(port);
|
||||||
|
if (!i)
|
||||||
|
continue;
|
||||||
|
CellInfo *drv = i->driver.cell;
|
||||||
|
if (i->driver.port != id_O)
|
||||||
|
continue;
|
||||||
|
if (!drv || drv->type != id_ICESTORM_LC || packed_cells.count(drv->name) ||
|
||||||
|
bool_or_default(drv->params, id_CARRY_ENABLE) || bool_or_default(drv->params, id_DFF_ENABLE))
|
||||||
|
continue; // not driven by a LUT, or driver already swallowed
|
||||||
|
// Check cardinality - must be LUT2 or less, noting top inputs used first
|
||||||
|
if (drv->getPort(id_I0) || drv->getPort(id_I1))
|
||||||
|
continue;
|
||||||
|
// Pack into carry
|
||||||
|
drv->movePortTo(id_I2, ci, id_I0);
|
||||||
|
drv->movePortTo(id_I3, ci, id_I3);
|
||||||
|
drv->movePortTo(id_O, ci, id_O);
|
||||||
|
ci->params[id_LUT_INIT] = Property(rewrite_init(int_or_default(drv->params, id_LUT_INIT)), 16);
|
||||||
|
packed_cells.insert(drv->name);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for (auto pcell : packed_cells) {
|
||||||
|
ctx->cells.erase(pcell);
|
||||||
|
}
|
||||||
|
log_info(" %4d LUTs merged into carry LCs\n", int(packed_cells.size()));
|
||||||
|
}
|
||||||
|
|
||||||
// "Pack" RAMs
|
// "Pack" RAMs
|
||||||
static void pack_ram(Context *ctx)
|
static void pack_ram(Context *ctx)
|
||||||
{
|
{
|
||||||
@ -1642,6 +1704,7 @@ bool Arch::pack()
|
|||||||
pack_lut_lutffs(ctx);
|
pack_lut_lutffs(ctx);
|
||||||
pack_nonlut_ffs(ctx);
|
pack_nonlut_ffs(ctx);
|
||||||
pack_carries(ctx);
|
pack_carries(ctx);
|
||||||
|
merge_carry_luts(ctx);
|
||||||
pack_ram(ctx);
|
pack_ram(ctx);
|
||||||
place_plls(ctx);
|
place_plls(ctx);
|
||||||
pack_special(ctx);
|
pack_special(ctx);
|
||||||
|
Loading…
Reference in New Issue
Block a user