timing: iCE40 Arch API changes for clocking info
Signed-off-by: David Shah <dave@ds0.me>
This commit is contained in:
parent
3ca02cc55c
commit
122771cac3
@ -455,11 +455,17 @@ Cell Delay Methods
|
|||||||
Returns the delay for the specified path through a cell in the `&delay` argument. The method returns
|
Returns the delay for the specified path through a cell in the `&delay` argument. The method returns
|
||||||
false if there is no timing relationship from `fromPort` to `toPort`.
|
false if there is no timing relationship from `fromPort` to `toPort`.
|
||||||
|
|
||||||
### TimingPortClass getPortTimingClass(const CellInfo *cell, IdString port, IdString &clockPort) const
|
### TimingPortClass getPortTimingClass(const CellInfo *cell, IdString port, int &clockInfoCount) const
|
||||||
|
|
||||||
Return the _timing port class_ of a port. This can be a register or combinational input or output; clock input or
|
Return the _timing port class_ of a port. This can be a register or combinational input or output; clock input or
|
||||||
output; general startpoint or endpoint; or a port ignored for timing purposes. For register ports, clockPort is set
|
output; general startpoint or endpoint; or a port ignored for timing purposes. For register ports, clockInfoCount is set
|
||||||
to the associated clock port.
|
to the number of associated _clock edges_ that can be queried by getPortClockingInfo.
|
||||||
|
|
||||||
|
### TimingClockingInfo getPortClockingInfo(const CellInfo *cell, IdString port, int index) const
|
||||||
|
|
||||||
|
Return the _clocking info_ (including port name of clock, clock polarity and setup/hold/clock-to-out times) of a
|
||||||
|
port. Where ports have more than one clock edge associated with them (such as DDR outputs), `index` can be used to obtain
|
||||||
|
information for all edges. `index` must be in [0, clockInfoCount), behaviour is undefined otherwise.
|
||||||
|
|
||||||
Placer Methods
|
Placer Methods
|
||||||
--------------
|
--------------
|
||||||
|
@ -856,8 +856,9 @@ bool Arch::getCellDelay(const CellInfo *cell, IdString fromPort, IdString toPort
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Get the port class, also setting clockPort to associated clock if applicable
|
// Get the port class, also setting clockPort to associated clock if applicable
|
||||||
TimingPortClass Arch::getPortTimingClass(const CellInfo *cell, IdString port, IdString &clockPort) const
|
TimingPortClass Arch::getPortTimingClass(const CellInfo *cell, IdString port, int &clockInfoCount) const
|
||||||
{
|
{
|
||||||
|
clockInfoCount = 0;
|
||||||
if (cell->type == id_ICESTORM_LC) {
|
if (cell->type == id_ICESTORM_LC) {
|
||||||
if (port == id_CLK)
|
if (port == id_CLK)
|
||||||
return TMG_CLOCK_INPUT;
|
return TMG_CLOCK_INPUT;
|
||||||
@ -870,18 +871,15 @@ TimingPortClass Arch::getPortTimingClass(const CellInfo *cell, IdString port, Id
|
|||||||
if (cell->lcInfo.inputCount == 0)
|
if (cell->lcInfo.inputCount == 0)
|
||||||
return TMG_IGNORE;
|
return TMG_IGNORE;
|
||||||
if (cell->lcInfo.dffEnable) {
|
if (cell->lcInfo.dffEnable) {
|
||||||
clockPort = id_CLK;
|
clockInfoCount = 1;
|
||||||
return TMG_REGISTER_OUTPUT;
|
return TMG_REGISTER_OUTPUT;
|
||||||
}
|
} else
|
||||||
else
|
|
||||||
return TMG_COMB_OUTPUT;
|
return TMG_COMB_OUTPUT;
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
if (cell->lcInfo.dffEnable) {
|
if (cell->lcInfo.dffEnable) {
|
||||||
clockPort = id_CLK;
|
clockInfoCount = 1;
|
||||||
return TMG_REGISTER_INPUT;
|
return TMG_REGISTER_INPUT;
|
||||||
}
|
} else
|
||||||
else
|
|
||||||
return TMG_COMB_INPUT;
|
return TMG_COMB_INPUT;
|
||||||
}
|
}
|
||||||
} else if (cell->type == id_ICESTORM_RAM) {
|
} else if (cell->type == id_ICESTORM_RAM) {
|
||||||
@ -889,23 +887,22 @@ TimingPortClass Arch::getPortTimingClass(const CellInfo *cell, IdString port, Id
|
|||||||
if (port == id_RCLK || port == id_WCLK)
|
if (port == id_RCLK || port == id_WCLK)
|
||||||
return TMG_CLOCK_INPUT;
|
return TMG_CLOCK_INPUT;
|
||||||
|
|
||||||
if (port.str(this)[0] == 'R')
|
clockInfoCount = 1;
|
||||||
clockPort = id_RCLK;
|
|
||||||
else
|
|
||||||
clockPort = id_WCLK;
|
|
||||||
|
|
||||||
if (cell->ports.at(port).type == PORT_OUT)
|
if (cell->ports.at(port).type == PORT_OUT)
|
||||||
return TMG_REGISTER_OUTPUT;
|
return TMG_REGISTER_OUTPUT;
|
||||||
else
|
else
|
||||||
return TMG_REGISTER_INPUT;
|
return TMG_REGISTER_INPUT;
|
||||||
} else if (cell->type == id_ICESTORM_DSP || cell->type == id_ICESTORM_SPRAM) {
|
} else if (cell->type == id_ICESTORM_DSP || cell->type == id_ICESTORM_SPRAM) {
|
||||||
clockPort = id_CLK;
|
|
||||||
if (port == id_CLK)
|
if (port == id_CLK)
|
||||||
return TMG_CLOCK_INPUT;
|
return TMG_CLOCK_INPUT;
|
||||||
else if (cell->ports.at(port).type == PORT_OUT)
|
else {
|
||||||
|
clockInfoCount = 1;
|
||||||
|
if (cell->ports.at(port).type == PORT_OUT)
|
||||||
return TMG_REGISTER_OUTPUT;
|
return TMG_REGISTER_OUTPUT;
|
||||||
else
|
else
|
||||||
return TMG_REGISTER_INPUT;
|
return TMG_REGISTER_INPUT;
|
||||||
|
}
|
||||||
} else if (cell->type == id_SB_IO) {
|
} else if (cell->type == id_SB_IO) {
|
||||||
if (port == id_D_IN_0 || port == id_D_IN_1)
|
if (port == id_D_IN_0 || port == id_D_IN_1)
|
||||||
return TMG_STARTPOINT;
|
return TMG_STARTPOINT;
|
||||||
@ -934,6 +931,53 @@ TimingPortClass Arch::getPortTimingClass(const CellInfo *cell, IdString port, Id
|
|||||||
log_error("no timing info for port '%s' of cell type '%s'\n", port.c_str(this), cell->type.c_str(this));
|
log_error("no timing info for port '%s' of cell type '%s'\n", port.c_str(this), cell->type.c_str(this));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TimingClockingInfo Arch::getPortClockingInfo(const CellInfo *cell, IdString port, int index) const
|
||||||
|
{
|
||||||
|
TimingClockingInfo info;
|
||||||
|
if (cell->type == id_ICESTORM_LC) {
|
||||||
|
info.clock_port = id_CLK;
|
||||||
|
info.edge = cell->lcInfo.negClk ? TimingClockingInfo::FALLING : TimingClockingInfo::RISING;
|
||||||
|
if (port == id_O) {
|
||||||
|
bool has_clktoq = getCellDelay(cell, id_CLK, id_O, info.clockToQ);
|
||||||
|
NPNR_ASSERT(has_clktoq);
|
||||||
|
} else {
|
||||||
|
info.setup.delay = 100;
|
||||||
|
info.hold.delay = 0;
|
||||||
|
}
|
||||||
|
} else if (cell->type == id_ICESTORM_RAM) {
|
||||||
|
if (port.str(this)[0] == 'R') {
|
||||||
|
info.clock_port = id_RCLK;
|
||||||
|
info.edge = bool_or_default(cell->params, id("NEG_CLK_R")) ? TimingClockingInfo::FALLING
|
||||||
|
: TimingClockingInfo::RISING;
|
||||||
|
} else {
|
||||||
|
info.clock_port = id_WCLK;
|
||||||
|
info.edge = bool_or_default(cell->params, id("NEG_CLK_W")) ? TimingClockingInfo::FALLING
|
||||||
|
: TimingClockingInfo::RISING;
|
||||||
|
}
|
||||||
|
if (cell->ports.at(port).type == PORT_OUT) {
|
||||||
|
bool has_clktoq = getCellDelay(cell, info.clock_port, port, info.clockToQ);
|
||||||
|
NPNR_ASSERT(has_clktoq);
|
||||||
|
} else {
|
||||||
|
info.setup.delay = 100;
|
||||||
|
info.hold.delay = 0;
|
||||||
|
}
|
||||||
|
} else if (cell->type == id_ICESTORM_DSP || cell->type == id_ICESTORM_SPRAM) {
|
||||||
|
info.clock_port = id_CLK;
|
||||||
|
info.edge = TimingClockingInfo::RISING;
|
||||||
|
if (cell->ports.at(port).type == PORT_OUT) {
|
||||||
|
bool has_clktoq = getCellDelay(cell, info.clock_port, port, info.clockToQ);
|
||||||
|
if (!has_clktoq)
|
||||||
|
info.clockToQ.delay = 100;
|
||||||
|
} else {
|
||||||
|
info.setup.delay = 100;
|
||||||
|
info.hold.delay = 0;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
NPNR_ASSERT_FALSE("unhandled cell type in getPortClockingInfo");
|
||||||
|
}
|
||||||
|
return info;
|
||||||
|
}
|
||||||
|
|
||||||
bool Arch::isGlobalNet(const NetInfo *net) const
|
bool Arch::isGlobalNet(const NetInfo *net) const
|
||||||
{
|
{
|
||||||
if (net == nullptr)
|
if (net == nullptr)
|
||||||
|
@ -798,8 +798,10 @@ struct Arch : BaseCtx
|
|||||||
// Get the delay through a cell from one port to another, returning false
|
// Get the delay through a cell from one port to another, returning false
|
||||||
// if no path exists
|
// if no path exists
|
||||||
bool getCellDelay(const CellInfo *cell, IdString fromPort, IdString toPort, DelayInfo &delay) const;
|
bool getCellDelay(const CellInfo *cell, IdString fromPort, IdString toPort, DelayInfo &delay) const;
|
||||||
// Get the port class, also setting clockDomain if applicable
|
// Get the port class, also setting clockInfoCount to the number of TimingClockingInfos associated with a port
|
||||||
TimingPortClass getPortTimingClass(const CellInfo *cell, IdString port, IdString &clockDomain) const;
|
TimingPortClass getPortTimingClass(const CellInfo *cell, IdString port, int &clockInfoCount) const;
|
||||||
|
// Get the TimingClockingInfo of a port
|
||||||
|
TimingClockingInfo getPortClockingInfo(const CellInfo *cell, IdString port, int index) const;
|
||||||
// Return true if a port is a net
|
// Return true if a port is a net
|
||||||
bool isGlobalNet(const NetInfo *net) const;
|
bool isGlobalNet(const NetInfo *net) const;
|
||||||
|
|
||||||
|
@ -462,7 +462,8 @@ static bool is_logic_port(BaseCtx *ctx, const PortRef &port)
|
|||||||
|
|
||||||
static void insert_global(Context *ctx, NetInfo *net, bool is_reset, bool is_cen, bool is_logic)
|
static void insert_global(Context *ctx, NetInfo *net, bool is_reset, bool is_cen, bool is_logic)
|
||||||
{
|
{
|
||||||
log_info("promoting %s%s%s%s\n", net->name.c_str(ctx), is_reset ? " [reset]" : "", is_cen ? " [cen]" : "", is_logic ? " [logic]" : "");
|
log_info("promoting %s%s%s%s\n", net->name.c_str(ctx), is_reset ? " [reset]" : "", is_cen ? " [cen]" : "",
|
||||||
|
is_logic ? " [logic]" : "");
|
||||||
|
|
||||||
std::string glb_name = net->name.str(ctx) + std::string("_$glb_") + (is_reset ? "sr" : (is_cen ? "ce" : "clk"));
|
std::string glb_name = net->name.str(ctx) + std::string("_$glb_") + (is_reset ? "sr" : (is_cen ? "ce" : "clk"));
|
||||||
std::unique_ptr<CellInfo> gb = create_ice_cell(ctx, ctx->id("SB_GB"), "$gbuf_" + glb_name);
|
std::unique_ptr<CellInfo> gb = create_ice_cell(ctx, ctx->id("SB_GB"), "$gbuf_" + glb_name);
|
||||||
|
Loading…
Reference in New Issue
Block a user