Ophidian
 All Classes Namespaces Functions
generic_sta.h
1 /*
2  * Copyright 2016 Ophidian
3 Licensed to the Apache Software Foundation (ASF) under one
4 or more contributor license agreements. See the NOTICE file
5 distributed with this work for additional information
6 regarding copyright ownership. The ASF licenses this file
7 to you under the Apache License, Version 2.0 (the
8 "License"); you may not use this file except in compliance
9 with the License. You may obtain a copy of the License at
10 
11  http://www.apache.org/licenses/LICENSE-2.0
12 
13 Unless required by applicable law or agreed to in writing,
14 software distributed under the License is distributed on an
15 "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16 KIND, either express or implied. See the License for the
17 specific language governing permissions and limitations
18 under the License.
19  */
20 
21 #include "../timing/library.h"
22 #include "../timing/graph.h"
23 #include "../netlist/netlist.h"
24 #include "../interconnection/rc_tree.h"
25 
26 #include <lemon/connectivity.h>
27 
28 #include <boost/units/limits.hpp>
29 #include <boost/units/cmath.hpp>
30 #include <functional>
31 
32 #include "ceff.h"
33 #include "design_constraints.h"
34 
35 #include "graph_nodes_timing.h"
36 #include "graph_arcs_timing.h"
37 
38 #include <omp.h>
39 #include <lemon/path.h>
40 
41 #ifndef OPHIDIAN_TIMING_GENERIC_STA_H
42 #define OPHIDIAN_TIMING_GENERIC_STA_H
43 
44 namespace ophidian {
45 namespace timing {
46 
47 struct optimistic {
48  using TimingType = boost::units::quantity< boost::units::si::time >;
49 
50  TimingType operator()(const TimingType &a, const TimingType &b) const {
51  return std::min(a, b);
52  }
53  TimingType inverted(const TimingType &a, const TimingType &b) const {
54  return std::max(a, b);
55  }
56  static double slack_signal() {
57  return -1.0;
58  }
59  static TimingType best() {
60  return std::numeric_limits<TimingType >::infinity();
61  }
62  static TimingType worst() {
63  return -std::numeric_limits<TimingType >::infinity();
64  }
65 };
66 
67 
68 struct pessimistic {
69  using TimingType = boost::units::quantity< boost::units::si::time >;
70 
71  TimingType operator()(const TimingType &a, const TimingType &b) const {
72  return std::max(a, b);
73  }
74  TimingType inverted(const TimingType &a, const TimingType &b) const {
75  return std::min(a, b);
76  }
77  static double slack_signal() {
78  return 1.0;
79  }
80  static TimingType best() {
81  return -std::numeric_limits<TimingType >::infinity();
82  }
83  static TimingType worst() {
84  return std::numeric_limits<TimingType >::infinity();
85  }
86 };
87 
88 
89 struct timing_data {
90  const library & lib;
91  graph_nodes_timing nodes;
92  graph_arcs_timing arcs;
93 
94 
95  timing_data(const library & lib, const graph& g):
96  lib(lib),
97  nodes(g.G()),
98  arcs(g.G())
99  {
100 
101  }
102 
103 };
104 
105 
107  const graph & g;
108  const netlist::netlist & netlist;
109  std::vector<lemon::ListDigraph::Node> sorted;
110  std::vector< std::vector<lemon::ListDigraph::Node> > levels;
111  std::vector<lemon::ListDigraph::Node> sorted_drivers;
112  graph_and_topology(const graph & G, const netlist::netlist & netlist, const library & lib);
113 
114 };
115 
116 
118 
119  const graph_and_topology & topology;
120  timing_data & early;
121  timing_data & late;
122  boost::units::quantity< boost::units::si::time > clock_period;
123 
124  void compute_tests();
125 
126 
127 };
128 
129 template <class WireDelayModel, class MergeStrategy>
131 {
132  using SlewType = boost::units::quantity< boost::units::si::time >;
133  using CapacitanceType = boost::units::quantity< boost::units::si::capacitance >;
134 
135 
136 
137  timing_data & m_timing;
138  graph_and_topology * m_topology;
140  MergeStrategy m_merge;
141 
142  SlewType compute_slew(lemon::ListDigraph::Node node, CapacitanceType load) const {
143  SlewType worst_slew = MergeStrategy::best();
144  if(lemon::countInArcs(m_topology->g.G(), node) == 0) // PI without driver
145  return m_timing.nodes.slew(node);
146  switch(m_topology->g.node_edge(node))
147  {
148  case edges::RISE:
149  for(lemon::ListDigraph::InArcIt it(m_topology->g.G(), node); it != lemon::INVALID; ++it)
150  {
151  auto tarc = m_topology->g.edge_entity(it) ;
152  worst_slew = m_merge(worst_slew, m_timing.lib.timing_arc_rise_slew(tarc).compute(load, m_timing.nodes.slew(m_topology->g.edge_source(it))));
153  }
154  break;
155  case edges::FALL:
156  for(lemon::ListDigraph::InArcIt it(m_topology->g.G(), node); it != lemon::INVALID; ++it)
157  {
158  auto tarc = m_topology->g.edge_entity(it) ;
159  worst_slew = m_merge(worst_slew, m_timing.lib.timing_arc_fall_slew(tarc).compute(load, m_timing.nodes.slew(m_topology->g.edge_source(it))));
160  }
161  break;
162  }
163  return worst_slew;
164  }
165 
166 public:
168  m_timing(timing),
169  m_topology(&topology),
170  m_rc_trees(rc_trees)
171  {
172 
173 
174 
175 
176  }
177 
178 
179  void topology(graph_and_topology & topology)
180  {
181  m_topology = &topology;
182  }
183 
184 
185 
186  void set_constraints(const design_constraints & dc)
187  {
188 
189  using namespace boost::units;
190  using namespace boost::units::si;
191 
192  m_timing.nodes.arrival( m_topology->g.rise_node(m_topology->netlist.pin_by_name(dc.clock.port_name)), 0.0*seconds );
193  m_timing.nodes.arrival( m_topology->g.fall_node(m_topology->netlist.pin_by_name(dc.clock.port_name)), 0.0*seconds );
194 
195  for(auto & i : dc.input_delays)
196  {
197  auto pin = m_topology->netlist.pin_by_name(i.port_name);
198  m_timing.nodes.arrival( m_topology->g.rise_node(pin), quantity<si::time>(i.delay*pico*seconds) );
199  m_timing.nodes.arrival( m_topology->g.fall_node(pin), quantity<si::time>(i.delay*pico*seconds) );
200  }
201 
202  for(auto & i : dc.input_drivers)
203  {
204  auto pin = m_topology->netlist.pin_by_name(i.port_name);
205  m_timing.nodes.slew( m_topology->g.rise_node(pin), quantity<si::time>(i.slew_rise*pico*seconds) );
206  m_timing.nodes.slew( m_topology->g.fall_node(pin), quantity<si::time>(i.slew_fall*pico*seconds) );
207  }
208 
209 
210  for(lemon::ListDigraph::NodeIt node(m_topology->g.G()); node != lemon::INVALID; ++node)
211  {
212  if(m_timing.lib.pin_clock_input(m_topology->netlist.pin_std_cell(m_topology->g.pin(node))))
213  m_timing.nodes.required( node, MergeStrategy::worst() );
214  else if(lemon::countOutArcs(m_topology->g.G(), node) == 0 )
215  m_timing.nodes.required( node, m_merge(quantity<si::time>(0.0*seconds), quantity<si::time>(dc.clock.period * pico* seconds)) );
216  }
217 
218  }
219 
220 
221  SlewType rise_arrival(const entity_system::entity pin) const
222  {
223  return m_timing.nodes.arrival(m_topology->g.rise_node(pin));
224  }
225  SlewType fall_arrival(const entity_system::entity pin) const
226  {
227  return m_timing.nodes.arrival(m_topology->g.fall_node(pin));
228  }
229 
230  SlewType rise_slew(const entity_system::entity pin) const
231  {
232  return m_timing.nodes.slew(m_topology->g.rise_node(pin));
233  }
234  SlewType fall_slew(const entity_system::entity pin) const
235  {
236  return m_timing.nodes.slew(m_topology->g.fall_node(pin));
237  }
238 
239  SlewType rise_slack(const entity_system::entity pin) const
240  {
241  auto node = m_topology->g.rise_node(pin);
242  return MergeStrategy::slack_signal()*(m_timing.nodes.required(node)-m_timing.nodes.arrival(node));
243  }
244  SlewType fall_slack(const entity_system::entity pin) const
245  {
246  auto node = m_topology->g.fall_node(pin);
247  return MergeStrategy::slack_signal()*(m_timing.nodes.required(node)-m_timing.nodes.arrival(node));
248  }
249 
250  void update_ats() {
251  {
252  for(auto & level : m_topology->levels)
253  {
254  std::size_t i;
255  for(i = 0; i < level.size(); ++i) // paralell
256  {
257  auto node = level[i];
258  if(lemon::countInArcs(m_topology->g.G(), node) != 0)
259  {
260  auto pin = m_topology->g.pin(node);
261  auto net = m_topology->netlist.pin_net(pin);
262  auto & tree = m_rc_trees[m_topology->netlist.net_system().lookup(net)];
263 
264  std::vector< SlewType > slews(tree.node_count());
265  std::vector< SlewType > delays(tree.node_count());
266  std::vector< CapacitanceType > ceffs(tree.node_count());
267  WireDelayModel calculator;
268  calculator.delay_map(delays);
269  calculator.slew_map(slews);
270  calculator.ceff_map(ceffs);
271  std::function<SlewType(CapacitanceType)> s_calculator = std::bind(&generic_sta::compute_slew, this, node, std::placeholders::_1);
272 
273  CapacitanceType load = calculator.simulate(s_calculator, tree);
274 
275  m_timing.nodes.load(node, load);
276  m_timing.nodes.slew(node, slews[0]);
277 
278  SlewType worst_arrival = MergeStrategy::best();
279  switch(m_topology->g.node_edge(node))
280  {
281  case edges::RISE:
282  for(lemon::ListDigraph::InArcIt it(m_topology->g.G(), node); it != lemon::INVALID; ++it)
283  {
284  auto tarc = m_topology->g.edge_entity(it) ;
285  auto edge_source = m_topology->g.edge_source(it);
286  auto arc_delay = m_timing.lib.timing_arc_rise_delay(tarc).compute(load, m_timing.nodes.slew(edge_source));
287  auto arc_slew = m_timing.lib.timing_arc_rise_slew(tarc).compute(load, m_timing.nodes.slew(edge_source));
288  m_timing.arcs.delay(it, arc_delay);
289  m_timing.arcs.slew(it, arc_slew);
290  worst_arrival = m_merge(worst_arrival, m_timing.nodes.arrival(edge_source) + arc_delay);
291  }
292  break;
293  case edges::FALL:
294  for(lemon::ListDigraph::InArcIt it(m_topology->g.G(), node); it != lemon::INVALID; ++it)
295  {
296  auto tarc = m_topology->g.edge_entity(it) ;
297  auto edge_source = m_topology->g.edge_source(it);
298  auto arc_delay = m_timing.lib.timing_arc_fall_delay(tarc).compute(load, m_timing.nodes.slew(edge_source));
299  auto arc_slew = m_timing.lib.timing_arc_fall_slew(tarc).compute(load, m_timing.nodes.slew(edge_source));
300  m_timing.arcs.delay(it, arc_delay);
301  m_timing.arcs.slew(it, arc_slew);
302  worst_arrival = m_merge(worst_arrival, m_timing.nodes.arrival(edge_source) + arc_delay);
303  }
304  break;
305  }
306  m_timing.nodes.arrival(node, worst_arrival);
307  for(lemon::ListDigraph::OutArcIt arc(m_topology->g.G(), node); arc != lemon::INVALID; ++arc)
308  {
309  auto arc_target = m_topology->g.edge_target(arc);
310  auto target_pin = m_topology->g.pin(arc_target);
311  auto target_capacitor = tree.tap(m_topology->netlist.pin_name(target_pin));
312  m_timing.arcs.slew(arc, slews[target_capacitor]);
313  m_timing.arcs.delay(arc, delays[target_capacitor]);
314  m_timing.nodes.slew(arc_target, m_timing.arcs.slew(arc));
315  m_timing.nodes.arrival(arc_target, m_timing.nodes.arrival(node) + m_timing.arcs.delay(arc));
316  }
317  }
318  }
319  }
320 
321  }
322  }
323 
324  void update_rts() {
325  for(auto node_it = m_topology->sorted.rbegin(); node_it != m_topology->sorted.rend(); ++node_it)
326  {
327  auto node = *node_it;
328  if(lemon::countOutArcs(m_topology->g.G(), node) > 0)
329  {
330  SlewType required = MergeStrategy::worst();
331  for(lemon::ListDigraph::OutArcIt arc(m_topology->g.G(), node); arc != lemon::INVALID; ++arc)
332  required = m_merge.inverted(required, m_timing.nodes.required(m_topology->g.edge_target(arc))-m_timing.arcs.delay(arc));
333  m_timing.nodes.required(node, required);
334  }
335  }
336  }
337 
338 
339  lemon::Path<lemon::ListDigraph> critical_path() const {
340  lemon::Path<lemon::ListDigraph> cp;
341  SlewType worst_slack = std::numeric_limits<SlewType>::infinity();
342  lemon::ListDigraph::Node worst_PO;
343  for(auto node_it = m_topology->sorted.rbegin(); node_it != m_topology->sorted.rend(); ++node_it)
344  {
345  auto node = *node_it;
346  if(lemon::countOutArcs(m_topology->g.G(), node) == 0)
347  {
348  SlewType current_PO_slack = MergeStrategy::slack_signal()*(m_timing.nodes.required(node)-m_timing.nodes.arrival(node));
349  if(current_PO_slack < worst_slack)
350  {
351  worst_slack = current_PO_slack;
352  worst_PO = node;
353  }
354  }
355  }
356  lemon::ListDigraph::Node current_node = worst_PO;
357  lemon::ListDigraph::Node next_node = current_node;
358  while(next_node != lemon::INVALID)
359  {
360  current_node = next_node;
361  next_node = lemon::INVALID;
362  lemon::ListDigraph::Arc worst_arc = lemon::INVALID;
363  SlewType worst_slack_input = std::numeric_limits<SlewType>::infinity();
364  for(lemon::ListDigraph::InArcIt in(m_topology->g.G(), current_node); in != lemon::INVALID; ++in)
365  {
366  auto source = m_topology->g.G().source(in);
367  SlewType slack = MergeStrategy::slack_signal()*(m_timing.nodes.required(source)-m_timing.nodes.arrival(source));
368  if(slack < worst_slack_input)
369  {
370  worst_slack_input = slack;
371  worst_arc = in;
372  next_node = source;
373  }
374  }
375  if(worst_arc != lemon::INVALID)
376  cp.addFront(worst_arc);
377  }
378  return cp;
379  }
380 
381 
382 };
383 
384 }
385 }
386 
387 
388 #endif // OPHIDIAN_TIMING_GENERIC_STA_H
389 
Definition: generic_sta.h:68
Definition: generic_sta.h:47
Definition: generic_sta.h:117
Definition: design_constraints.h:63
Definition: graph.h:44
Definition: graph_nodes_timing.h:31
Definition: generic_sta.h:89
Netlist class.
Definition: netlist.h:41
Definition: generic_sta.h:106
Definition: graph_arcs_timing.h:30
Definition: library.h:44
Definition: generic_sta.h:130
entity_system::entity pin_by_name(std::string name) const
Finds pin.
Definition: netlist.h:276