ice40: Promote one clock to a global buffer
Signed-off-by: David Shah <davey1576@gmail.com>
This commit is contained in:
parent
d80e60cce2
commit
14b5e46b5d
@ -79,7 +79,9 @@ CellInfo *create_ice_cell(Design *design, IdString type, IdString name)
|
|||||||
|
|
||||||
add_port(new_cell, "D_IN_0", PORT_OUT);
|
add_port(new_cell, "D_IN_0", PORT_OUT);
|
||||||
add_port(new_cell, "D_IN_1", PORT_OUT);
|
add_port(new_cell, "D_IN_1", PORT_OUT);
|
||||||
|
} else if (type == "SB_GB") {
|
||||||
|
add_port(new_cell, "USER_SIGNAL_TO_GLOBAL_BUFFER", PORT_IN);
|
||||||
|
add_port(new_cell, "GLOBAL_BUFFER_OUTPUT", PORT_OUT);
|
||||||
} else {
|
} else {
|
||||||
log_error("unable to create iCE40 cell of type %s", type.c_str());
|
log_error("unable to create iCE40 cell of type %s", type.c_str());
|
||||||
}
|
}
|
||||||
@ -164,4 +166,8 @@ void nxio_to_sb(CellInfo *nxio, CellInfo *sbio)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool is_global_net(NetInfo *net) {
|
||||||
|
return bool(net_driven_by(net, is_gbuf, "GLOBAL_BUFFER_OUTPUT"));
|
||||||
|
}
|
||||||
|
|
||||||
NEXTPNR_NAMESPACE_END
|
NEXTPNR_NAMESPACE_END
|
||||||
|
@ -50,6 +50,9 @@ inline bool is_ff(const CellInfo *cell)
|
|||||||
// Return true if a cell is a SB_IO
|
// Return true if a cell is a SB_IO
|
||||||
inline bool is_sb_io(const CellInfo *cell) { return cell->type == "SB_IO"; }
|
inline bool is_sb_io(const CellInfo *cell) { return cell->type == "SB_IO"; }
|
||||||
|
|
||||||
|
// Return true if a cell is a global buffer
|
||||||
|
inline bool is_gbuf(const CellInfo *cell) {return cell->type == "SB_GB"; }
|
||||||
|
|
||||||
// Convert a SB_LUT primitive to (part of) an ICESTORM_LC, swapping ports
|
// Convert a SB_LUT primitive to (part of) an ICESTORM_LC, swapping ports
|
||||||
// as needed. Set no_dff if a DFF is not being used, so that the output
|
// as needed. Set no_dff if a DFF is not being used, so that the output
|
||||||
// can be reconnected
|
// can be reconnected
|
||||||
@ -64,6 +67,9 @@ void dff_to_lc(CellInfo *dff, CellInfo *lc, bool pass_thru_lut = false);
|
|||||||
// Convert a nextpnr IO buffer to a SB_IO
|
// Convert a nextpnr IO buffer to a SB_IO
|
||||||
void nxio_to_sb(CellInfo *nxio, CellInfo *sbio);
|
void nxio_to_sb(CellInfo *nxio, CellInfo *sbio);
|
||||||
|
|
||||||
|
// Return true if a net is a global net
|
||||||
|
bool is_global_net(NetInfo *net);
|
||||||
|
|
||||||
NEXTPNR_NAMESPACE_END
|
NEXTPNR_NAMESPACE_END
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -222,10 +222,58 @@ static void pack_io(Design *design)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Simple global promoter (clock only)
|
||||||
|
static void promote_globals(Design *design)
|
||||||
|
{
|
||||||
|
std::unordered_map<IdString, int> clock_count;
|
||||||
|
for (auto net : design->nets) {
|
||||||
|
NetInfo *ni = net.second;
|
||||||
|
if (ni->driver.cell != nullptr && !is_global_net(ni)) {
|
||||||
|
clock_count[net.first] = 0;
|
||||||
|
for (auto user : ni->users) {
|
||||||
|
if (user.cell != nullptr && is_ff(user.cell) && user.port == "C")
|
||||||
|
clock_count[net.first]++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
auto global_clock = std::max_element(clock_count.begin(), clock_count.end(), [](
|
||||||
|
const std::pair<IdString, int> &a, const std::pair<IdString, int> &b) {
|
||||||
|
return a.second < b.second;
|
||||||
|
});
|
||||||
|
if (global_clock->second > 0) {
|
||||||
|
NetInfo *clknet = design->nets[global_clock->first];
|
||||||
|
CellInfo *gb = create_ice_cell(design, "SB_GB");
|
||||||
|
gb->ports["USER_SIGNAL_TO_GLOBAL_BUFFER"].net = clknet;
|
||||||
|
PortRef pr;
|
||||||
|
pr.cell = gb;
|
||||||
|
pr.port = "USER_SIGNAL_TO_GLOBAL_BUFFER";
|
||||||
|
clknet->users.push_back(pr);
|
||||||
|
|
||||||
|
pr.cell = gb;
|
||||||
|
pr.port = "GLOBAL_BUFFER_OUTPUT";
|
||||||
|
NetInfo *glbnet = new NetInfo();
|
||||||
|
glbnet->name = clknet->name.str() + "_glb";
|
||||||
|
glbnet->driver = pr;
|
||||||
|
design->nets[glbnet->name] = glbnet;
|
||||||
|
std::vector<PortRef> keep_users;
|
||||||
|
for (auto user : clknet->users) {
|
||||||
|
if (user.cell != nullptr && is_ff(user.cell) && user.port == "C") {
|
||||||
|
user.cell->ports[user.port].net = glbnet;
|
||||||
|
glbnet->users.push_back(user);
|
||||||
|
} else {
|
||||||
|
keep_users.push_back(user);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
clknet->users = keep_users;
|
||||||
|
design->cells[gb->name] = gb;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Main pack function
|
// Main pack function
|
||||||
void pack_design(Design *design)
|
void pack_design(Design *design)
|
||||||
{
|
{
|
||||||
pack_constants(design);
|
pack_constants(design);
|
||||||
|
promote_globals(design);
|
||||||
pack_io(design);
|
pack_io(design);
|
||||||
pack_lut_lutffs(design);
|
pack_lut_lutffs(design);
|
||||||
pack_nonlut_ffs(design);
|
pack_nonlut_ffs(design);
|
||||||
|
Loading…
Reference in New Issue
Block a user