blob: ec32aa9a361a8b315f3a4994082334ecf95d6d39 [file] [log] [blame]
#include <cmath>
#include "atom_delay_calc.h"
/*
* AtomDelayCalc
*/
inline AtomDelayCalc::AtomDelayCalc(const AtomNetlist& netlist, const AtomLookup& netlist_lookup)
: netlist_(netlist)
, netlist_lookup_(netlist_lookup) {}
inline float AtomDelayCalc::atom_combinational_delay(const AtomPinId src_pin, const AtomPinId sink_pin, const DelayType delay_type) const {
VTR_ASSERT_MSG(netlist_.pin_block(src_pin) == netlist_.pin_block(sink_pin), "Combinational primitive delay must be between pins on the same block");
auto src_pin_type = netlist_.port_type(netlist_.pin_port(src_pin));
auto sink_pin_type = netlist_.port_type(netlist_.pin_port(sink_pin));
VTR_ASSERT_MSG((src_pin_type == PortType::INPUT && sink_pin_type == PortType::OUTPUT)
|| (src_pin_type == PortType::CLOCK && sink_pin_type == PortType::OUTPUT),
"Combinational connections must go from primitive input to output");
//Determine the combinational delay from the pb_graph_pin.
// By convention the delay is annotated on the corresponding input pg_graph_pin
const t_pb_graph_pin* src_gpin = find_pb_graph_pin(src_pin);
const t_pb_graph_pin* sink_gpin = find_pb_graph_pin(sink_pin);
VTR_ASSERT(src_gpin->num_pin_timing > 0);
//Find the annotation on the source that matches the sink
float delay = NAN;
for(int i = 0; i < src_gpin->num_pin_timing; ++i) {
const t_pb_graph_pin* timing_sink_gpin = src_gpin->pin_timing[i];
if(timing_sink_gpin == sink_gpin) {
if (delay_type == DelayType::MAX) {
delay = src_gpin->pin_timing_del_max[i];
} else {
VTR_ASSERT(delay_type == DelayType::MIN);
delay = src_gpin->pin_timing_del_min[i];
}
break;
}
}
VTR_ASSERT_MSG(!std::isnan(delay), "Must have a valid delay");
return delay;
}
inline float AtomDelayCalc::atom_setup_time(const AtomPinId /*clock_pin*/, const AtomPinId pin) const {
auto port_type = netlist_.port_type(netlist_.pin_port(pin));
VTR_ASSERT(port_type == PortType::OUTPUT || port_type == PortType::INPUT);
const t_pb_graph_pin* gpin = find_pb_graph_pin(pin);
VTR_ASSERT(gpin->type == PB_PIN_SEQUENTIAL);
return gpin->tsu;
}
inline float AtomDelayCalc::atom_hold_time(const AtomPinId /*clock_pin*/, const AtomPinId pin) const {
auto port_type = netlist_.port_type(netlist_.pin_port(pin));
VTR_ASSERT(port_type == PortType::OUTPUT || port_type == PortType::INPUT);
const t_pb_graph_pin* gpin = find_pb_graph_pin(pin);
VTR_ASSERT(gpin->type == PB_PIN_SEQUENTIAL);
return gpin->thld;
}
inline float AtomDelayCalc::atom_clock_to_q_delay(const AtomPinId /*clock_pin*/, const AtomPinId pin, const DelayType delay_type) const {
auto port_type = netlist_.port_type(netlist_.pin_port(pin));
VTR_ASSERT(port_type == PortType::OUTPUT || port_type == PortType::INPUT);
const t_pb_graph_pin* gpin = find_pb_graph_pin(pin);
VTR_ASSERT(gpin->type == PB_PIN_SEQUENTIAL);
if (delay_type == DelayType::MAX) {
return gpin->tco_max;
} else {
VTR_ASSERT(delay_type == DelayType::MIN);
return gpin->tco_min;
}
}
inline const t_pb_graph_pin* AtomDelayCalc::find_pb_graph_pin(const AtomPinId atom_pin) const {
//Note that the netlist lookup already considers any pin rotations applied during clustering,
//which were considered when the look-up was created (i.e. in read_netlist).
//
//Therefore, despite the fact that we look-up the delays on the atom netlist (which does not
//reflect the current pin rotation state), we do get actual post-rotation physical pin here.
//
//This means we will get the 'correct' delay (considering any applied rotations).
const t_pb_graph_pin* gpin = netlist_lookup_.atom_pin_pb_graph_pin(atom_pin);
VTR_ASSERT(gpin != nullptr);
return gpin;
}