mirror of https://github.com/openXC7/prjxray.git
Merge pull request #821 from litghost/timing_model_objects
Add objects and docstrings for timing model.
This commit is contained in:
commit
02026c2d8b
|
|
@ -0,0 +1,65 @@
|
|||
""" Math models are used to represent abstract operations for the timing models.
|
||||
This is useful for creating excel workbooks that can update dynamically, or
|
||||
generating a model with symbolic constants to be backsolved.
|
||||
"""
|
||||
|
||||
|
||||
class ExcelMathModel(object):
|
||||
""" Math model used for outputting to an dyanmic Excel sheet. """
|
||||
|
||||
def __init__(self):
|
||||
pass
|
||||
|
||||
def sum(self, elems):
|
||||
sum_val = '(' + ' + '.join(elems) + ')'
|
||||
if sum_val == '()':
|
||||
return '0'
|
||||
else:
|
||||
return sum_val
|
||||
|
||||
def product(self, elems):
|
||||
sum_val = '(' + ' * '.join(elems) + ')'
|
||||
if sum_val == '()':
|
||||
return '1'
|
||||
else:
|
||||
return sum_val
|
||||
|
||||
def plus(self, a, b):
|
||||
return self.sum((a, b))
|
||||
|
||||
def divide(self, a, b):
|
||||
return '({}/{})'.format(a, b)
|
||||
|
||||
def multiply(self, a, b):
|
||||
return '({}*{})'.format(a, b)
|
||||
|
||||
def eval(self, elem):
|
||||
return '=' + elem
|
||||
|
||||
|
||||
def PythonMathModel(object):
|
||||
""" Math model used for outputting values equalated immediately. """
|
||||
|
||||
def __init__(self):
|
||||
pass
|
||||
|
||||
def sum(self, elems):
|
||||
return sum(elems)
|
||||
|
||||
def product(self, elems):
|
||||
v = 1.0
|
||||
for elem in elems:
|
||||
v *= elem
|
||||
return v
|
||||
|
||||
def divide(self, a, b):
|
||||
return a / b
|
||||
|
||||
def plus(self, a, b):
|
||||
return a + b
|
||||
|
||||
def multiply(self, a, b):
|
||||
return a * b
|
||||
|
||||
def eval(self, elem):
|
||||
return elem
|
||||
285
prjxray/tile.py
285
prjxray/tile.py
|
|
@ -1,38 +1,251 @@
|
|||
""" Database files available for a tile type. """
|
||||
from collections import namedtuple
|
||||
import json
|
||||
from prjxray import lib
|
||||
""" Database files available for a tile """
|
||||
from prjxray.timing import fast_slow_tuple_to_corners, RcElement
|
||||
|
||||
TileDbs = namedtuple(
|
||||
'TileDbs', 'segbits block_ram_segbits ppips mask tile_type')
|
||||
|
||||
Pip = namedtuple(
|
||||
'Pip', 'name net_to net_from can_invert is_directional is_pseudo')
|
||||
""" Site - Represents an instance of a site within a tile.
|
||||
|
||||
name - Name of site within tile, instance specific.
|
||||
prefix - Prefix of site naming in Xilinx parlance.
|
||||
type - What type of slice this instance presents.
|
||||
pins - Instaces of site pins within this site and tile. This is an tuple of
|
||||
SitePin tuples, and is specific to this instance of the site within
|
||||
the tile.
|
||||
class OutPinTiming(namedtuple('OutPinTiming', 'delays drive_resistance')):
|
||||
""" Timing for site output pins.
|
||||
|
||||
"""
|
||||
Site = namedtuple('Site', 'name prefix x y type site_pins')
|
||||
""" SitePin - Tuple representing a site pin within a tile.
|
||||
Attributes
|
||||
----------
|
||||
delays : dicts of PvtCorner to IntristicDelay
|
||||
Intristic delay of output pin.
|
||||
drive_resistance : float
|
||||
Resistance of drive output pin (milliOhms).
|
||||
|
||||
Sites are generic based on type, however sites are instanced
|
||||
within a tile 1 or more times. The SitePin contains both site type generic
|
||||
information and tile type specific information.
|
||||
"""
|
||||
pass
|
||||
|
||||
name - Site type specific name. This name is expected to be the same for all
|
||||
sites of the same type.
|
||||
wire - Wire name within the tile. This name is site instance specific.
|
||||
|
||||
"""
|
||||
SitePin = namedtuple('SitePin', 'name wire')
|
||||
class InPinTiming(namedtuple('InPinTiming', 'delays capacitance')):
|
||||
""" Timing for site input pins.
|
||||
|
||||
Attributes
|
||||
----------
|
||||
delays : dicts of PvtCorner to IntristicDelay
|
||||
Intristic delay of input pin.
|
||||
capacitance : float
|
||||
Capacitance of input pints (microFarads).
|
||||
|
||||
"""
|
||||
pass
|
||||
|
||||
|
||||
class PipTiming(namedtuple('PipTiming',
|
||||
'delays drive_resistance internal_capacitance')):
|
||||
""" Timing for pips.
|
||||
|
||||
Attributes
|
||||
----------
|
||||
delays : dicts of PvtCorner to IntristicDelay
|
||||
Intristic delay of pip.
|
||||
internal_capacitance : float
|
||||
Capacitance (microFarads) of pip (which is only seen if pip is used).
|
||||
drive_resistance : float
|
||||
Resistance of drive output pin (milliOhms).
|
||||
|
||||
"""
|
||||
pass
|
||||
|
||||
|
||||
class Pip(namedtuple(
|
||||
'Pip',
|
||||
('name', 'net_to', 'net_from', 'can_invert', 'is_directional', 'is_pseudo',
|
||||
'is_pass_transistor', 'timing', 'backward_timing'))):
|
||||
""" Pip information.
|
||||
|
||||
Attributes
|
||||
----------
|
||||
|
||||
name : str
|
||||
Name of pip
|
||||
net_to : str
|
||||
Name of output tile wire when pip is unidirectional.
|
||||
net_from: str
|
||||
Name of input tile wire when pip is unidirectional.
|
||||
can_invert : bool
|
||||
Can this pip invert the signal.
|
||||
is_directional : bool
|
||||
True if this pip is unidirectional, False if this pip is
|
||||
unidirectional.
|
||||
is_pseudo : bool
|
||||
True if this pip is mark as a pseudo-pip.
|
||||
is_pass_transistor : bool
|
||||
True if this pip is non-isolating.
|
||||
timing : PipTiming
|
||||
Timing used when connecting net_from to net_to. This is the only
|
||||
timing used when a pip is unidirectional.
|
||||
|
||||
May be None if timing information is not present in the database.
|
||||
backward_timing : PipTiming
|
||||
Timing used when connecting net_to to net_from. This is only used
|
||||
if the pip is bidirectional.
|
||||
|
||||
May be None if timing information is not present in the database.
|
||||
|
||||
"""
|
||||
pass
|
||||
|
||||
|
||||
class Site(namedtuple('Site', 'name prefix x y type site_pins')):
|
||||
""" Represents an instance of a site within a tile.
|
||||
|
||||
Attributes
|
||||
----------
|
||||
name : str
|
||||
Name of site within tile, instance specific.
|
||||
prefix : str
|
||||
Prefix of site naming in Xilinx parlance.
|
||||
type : str
|
||||
What type of slice this instance presents.
|
||||
site_pins : list of SitePin
|
||||
Instaces of site pins within this site and tile. This is an tuple of
|
||||
SitePin tuples, and is specific to this instance of the site within
|
||||
the tile.
|
||||
|
||||
"""
|
||||
|
||||
|
||||
class SitePin(namedtuple('SitePin', 'name wire timing')):
|
||||
""" Tuple representing a site pin within a tile.
|
||||
|
||||
Sites are generic based on type, however sites are instanced
|
||||
within a tile 1 or more times. The SitePin contains both site type generic
|
||||
information and tile type specific information.
|
||||
|
||||
Attributes
|
||||
----------
|
||||
name : str
|
||||
Site type specific name. This name is expected to be the same for
|
||||
all sites of the same type.
|
||||
wire : str
|
||||
Wire name within the tile. This name is site instance specific.
|
||||
timing : Either InPinTiming or OutPinTiming
|
||||
Timing of site pin. May be None if database lacks timing information.
|
||||
|
||||
"""
|
||||
|
||||
|
||||
WireInfo = namedtuple('WireInfo', 'pips sites')
|
||||
|
||||
# Conversion factor from database to internal units.
|
||||
RESISTANCE_FACTOR = 1
|
||||
CAPACITANCE_FACTOR = 1e3
|
||||
|
||||
|
||||
def get_pip_timing(pip_timing_json):
|
||||
""" Convert pip_timing_json JSON into PipTiming object.
|
||||
|
||||
Returns
|
||||
-------
|
||||
If timing information is not present for this pip, returns None.
|
||||
If timing information is present, returns PipTiming. Some fields may be
|
||||
None if the pip type lacks that field.
|
||||
|
||||
"""
|
||||
|
||||
if pip_timing_json is None:
|
||||
return None
|
||||
|
||||
delays = None
|
||||
|
||||
if pip_timing_json.get('delay') is not None:
|
||||
delays = fast_slow_tuple_to_corners(pip_timing_json.get('delay'))
|
||||
|
||||
in_cap = pip_timing_json.get('in_cap')
|
||||
if in_cap is not None:
|
||||
in_cap = float(in_cap) / CAPACITANCE_FACTOR
|
||||
else:
|
||||
in_cap = 0
|
||||
|
||||
res = pip_timing_json.get('res')
|
||||
if res is not None:
|
||||
res = float(res) / RESISTANCE_FACTOR
|
||||
else:
|
||||
res = 0
|
||||
|
||||
return PipTiming(
|
||||
delays=delays,
|
||||
drive_resistance=res,
|
||||
internal_capacitance=in_cap,
|
||||
)
|
||||
|
||||
|
||||
def get_site_pin_timing(site_pin_info):
|
||||
""" Convert site_pin_info JSON into InPinTiming or OutPinTiming object.
|
||||
|
||||
Returns
|
||||
-------
|
||||
If timing information is not present for this site pin, returns None.
|
||||
If this is an output pin, returns OutPinTiming.
|
||||
If this is an input pin, returns InPinTiming.
|
||||
|
||||
"""
|
||||
if isinstance(site_pin_info, str):
|
||||
return site_pin_info, None
|
||||
|
||||
wire = site_pin_info['wire']
|
||||
|
||||
if 'delay' not in site_pin_info:
|
||||
return None
|
||||
|
||||
delays = fast_slow_tuple_to_corners(site_pin_info['delay'])
|
||||
|
||||
if 'cap' in site_pin_info:
|
||||
assert 'res' not in site_pin_info
|
||||
return wire, InPinTiming(
|
||||
delays=delays,
|
||||
capacitance=float(site_pin_info['cap']) / CAPACITANCE_FACTOR,
|
||||
)
|
||||
else:
|
||||
assert 'res' in site_pin_info
|
||||
return wire, OutPinTiming(
|
||||
delays=delays,
|
||||
drive_resistance=float(site_pin_info['res']) / RESISTANCE_FACTOR,
|
||||
)
|
||||
|
||||
|
||||
def get_wires(wires):
|
||||
""" Converts database input to dictionary of tile wires to wire timing.
|
||||
|
||||
Returns dictionary of tile wire name to RcElement or None. """
|
||||
|
||||
if isinstance(wires, list):
|
||||
# Handle old database gracefully.
|
||||
return {wire: None for wire in wires}
|
||||
|
||||
output = {}
|
||||
|
||||
for wire, rc_json in wires.items():
|
||||
if rc_json is None:
|
||||
output[wire] = RcElement(
|
||||
resistance=0,
|
||||
capacitance=0,
|
||||
)
|
||||
else:
|
||||
output[wire] = RcElement(
|
||||
resistance=float(rc_json['res']) / RESISTANCE_FACTOR,
|
||||
capacitance=float(rc_json['cap']) / CAPACITANCE_FACTOR,
|
||||
)
|
||||
|
||||
return output
|
||||
|
||||
|
||||
def is_pass_transistor(pip_json):
|
||||
""" Returns boolean if pip JSON indicates pip is a pass transistor.
|
||||
|
||||
Always returns False if database lacks this information.
|
||||
"""
|
||||
if 'is_pass_transistor' in pip_json:
|
||||
return bool(int(pip_json['is_pass_transistor']))
|
||||
else:
|
||||
return False
|
||||
|
||||
|
||||
class Tile(object):
|
||||
""" Provides abstration of a tile in the database. """
|
||||
|
|
@ -49,17 +262,32 @@ class Tile(object):
|
|||
|
||||
def yield_sites(sites):
|
||||
for site in sites:
|
||||
site_pins = []
|
||||
for name, site_pin_info in site['site_pins'].items():
|
||||
if site_pin_info is not None:
|
||||
wire, timing = get_site_pin_timing(site_pin_info)
|
||||
site_pins.append(
|
||||
SitePin(
|
||||
name=name,
|
||||
wire=wire,
|
||||
timing=timing,
|
||||
))
|
||||
else:
|
||||
site_pins.append(
|
||||
SitePin(
|
||||
name=name,
|
||||
wire=None,
|
||||
timing=None,
|
||||
))
|
||||
|
||||
yield Site(
|
||||
name=site['name'],
|
||||
prefix=site['prefix'],
|
||||
type=site['type'],
|
||||
x=site['x_coord'],
|
||||
y=site['y_coord'],
|
||||
site_pins=tuple(
|
||||
SitePin(
|
||||
name=name,
|
||||
wire=wire,
|
||||
) for name, wire in site['site_pins'].items()))
|
||||
site_pins=site_pins,
|
||||
)
|
||||
|
||||
def yield_pips(pips):
|
||||
for name, pip in pips.items():
|
||||
|
|
@ -70,12 +298,15 @@ class Tile(object):
|
|||
can_invert=bool(int(pip['can_invert'])),
|
||||
is_directional=bool(int(pip['is_directional'])),
|
||||
is_pseudo=bool(int(pip['is_pseudo'])),
|
||||
is_pass_transistor=is_pass_transistor(pip),
|
||||
timing=get_pip_timing(pip.get('src_to_dst')),
|
||||
backward_timing=get_pip_timing(pip.get('dst_to_src')),
|
||||
)
|
||||
|
||||
with open(self.tile_dbs.tile_type) as f:
|
||||
tile_type = json.load(f)
|
||||
assert self.tilename_upper == tile_type['tile_type']
|
||||
self.wires = tile_type['wires']
|
||||
self.wires = get_wires(tile_type['wires'])
|
||||
self.sites = tuple(yield_sites(tile_type['sites']))
|
||||
self.pips = tuple(yield_pips(tile_type['pips']))
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,550 @@
|
|||
""" Route timing delay definitions.
|
||||
|
||||
Routing delay is formed from two parts in this model:
|
||||
|
||||
- Intristic delay of the element
|
||||
- Capactive loading delay of the net
|
||||
|
||||
Intristic delay is a time value (e.g. nanoseconds), does not vary based on
|
||||
routing fanout. It does vary based on the PVT (process, voltage, temperature)
|
||||
corner. PvtCorner and IntristicDelay objects are used to model intristic
|
||||
delay of elements.
|
||||
|
||||
Capactive loading is the elmore delay from the RC tree formed by interconnect.
|
||||
The RC tree is made up of 5 types of RC nodes:
|
||||
|
||||
|
||||
|Element type |Object |Intrinsic delays?|Output resistance?|Capacitance type |
|
||||
|----------------------|--------------|-----------------|------------------|--------------------|
|
||||
|Site output pin |Outpin |Yes |Yes |N/A |
|
||||
|Buffered switch |Buffer |Yes |Yes |Internal capacitance|
|
||||
|Pass-transistor switch|PassTransistor|Yes |Yes |N/A |
|
||||
|Wire |Wire |No |Yes |Pi model |
|
||||
|Site input pin |Inpin |Yes |No |Input capacitance |
|
||||
|
||||
The elmore delay is the RC tree formed by these 5 components. Out pins and
|
||||
buffer switches are the roots of the elmore tree. Buffer switches
|
||||
and inpins are leafs of the elmore tree. Wires and pass-transistor switches are
|
||||
nodes in the tree. Wires share their capacitance upstream and downstream using
|
||||
a pi-model.
|
||||
|
||||
Example timing tree:
|
||||
|
||||
+------+
|
||||
|Outpin|
|
||||
+--+---+
|
||||
|
|
||||
|
|
||||
v
|
||||
+--+--+
|
||||
|Wire |
|
||||
+--+--+
|
||||
|
|
||||
+-----------------+
|
||||
| |
|
||||
+--+---+ +-------+------+
|
||||
|Buffer| |PassTransistor|
|
||||
+--+---+ +------+-------+
|
||||
| |
|
||||
v v
|
||||
+--+-+ +--+-+
|
||||
|Wire| |Wire|
|
||||
+--+-+ +--+-+
|
||||
| |
|
||||
v v
|
||||
+--+--+ +--+--+
|
||||
|Inpin| |Inpin|
|
||||
+-----+ +-----+
|
||||
|
||||
Note on units:
|
||||
|
||||
The timing model operates on the following types of units:
|
||||
- Time
|
||||
- Resistance
|
||||
- Capacitance
|
||||
|
||||
For a consistent unit set, the following equation must be satisfied:
|
||||
|
||||
1 Resistance unit * 1 Capacitance unit = 1 Time unit
|
||||
|
||||
The SI unit set would be:
|
||||
- Time = seconds
|
||||
- Resistance = Ohms
|
||||
- Capacitance = Farads
|
||||
|
||||
However as long as the scale factors are consistent, the model will work
|
||||
with other unit combinations. For example:
|
||||
- Time = nanoseconds (1e-9 seconds)
|
||||
- Resistance = milliOhms (1e-3 Ohms)
|
||||
- Capacitance = microFarads (1e-6 Farads)
|
||||
|
||||
(1e-3 * 1e-6) (Ohms * Farads) does equal (1e-9) seconds.
|
||||
|
||||
"""
|
||||
import enum
|
||||
from collections import namedtuple
|
||||
|
||||
|
||||
class PvtCorner(enum.Enum):
|
||||
""" Process/voltage/temperature corner definitions. """
|
||||
|
||||
# Corner where device operates with fastest intristic delays.
|
||||
FAST = "FAST"
|
||||
|
||||
# Corner where device operates with slowest intristic delays.
|
||||
SLOW = "SLOW"
|
||||
|
||||
|
||||
class IntristicDelay(namedtuple('IntristicDelay', 'min max')):
|
||||
""" An intristic delay instance.
|
||||
|
||||
Represents is the intristic delay through an element (e.g. a site pin or
|
||||
interconnect pip).
|
||||
|
||||
The intristic delay of an element is generally modelled at a particular
|
||||
"corner" of a design. The "corner" generally speaking is modelled over
|
||||
process, voltage and temperature PVT. The IntristicDelay object
|
||||
reperesents the minimum or maximum delay through all instances of the
|
||||
element at 1 corner.
|
||||
|
||||
Attributes
|
||||
----------
|
||||
|
||||
min : float
|
||||
Minimum instrinsic delay (nsec)
|
||||
|
||||
max : float
|
||||
Maximum instrinsic delay (nsec)
|
||||
"""
|
||||
|
||||
|
||||
class RcElement(namedtuple('RcElement', 'resistance capacitance')):
|
||||
""" One part of an RcNode, embedded within an RcTree.
|
||||
|
||||
Attributes
|
||||
----------
|
||||
|
||||
resistance : float
|
||||
Resistance of element
|
||||
|
||||
capacitance : float
|
||||
Capacitance of element
|
||||
|
||||
"""
|
||||
pass
|
||||
|
||||
|
||||
def fast_slow_tuple_to_corners(arr):
|
||||
""" Convert delay 4-tuple into two IntristicDelay objects.
|
||||
|
||||
Returns
|
||||
-------
|
||||
|
||||
corners : dict of PvtCorner to IntristicDelay
|
||||
Dictionary keys of FAST and SLOW, mapping to the instrinsic delay
|
||||
for each corner.
|
||||
|
||||
"""
|
||||
|
||||
fast_min, fast_max, slow_min, slow_max = map(float, arr)
|
||||
|
||||
return {
|
||||
PvtCorner.FAST: IntristicDelay(
|
||||
min=fast_min,
|
||||
max=fast_max,
|
||||
),
|
||||
PvtCorner.SLOW: IntristicDelay(
|
||||
min=slow_min,
|
||||
max=slow_max,
|
||||
),
|
||||
}
|
||||
|
||||
|
||||
class TimingNode(object):
|
||||
""" Base class for timing node models.
|
||||
"""
|
||||
|
||||
def get_intrinsic_delays(self):
|
||||
""" Returns Intristic delays (if any) timing node.
|
||||
|
||||
Returns
|
||||
-------
|
||||
|
||||
Dictionary of PvtCorner to Intristic. Is None if node has no intristic
|
||||
delay.
|
||||
"""
|
||||
|
||||
pass
|
||||
|
||||
def get_rc_delay(self):
|
||||
""" Return portion of net delay due to elmore (RC) delay at this node.
|
||||
|
||||
Must be called after propigate_delays has been called on the Outpin
|
||||
object of this tree.
|
||||
|
||||
"""
|
||||
pass
|
||||
|
||||
def get_downstream_cap(self):
|
||||
""" Returns downstream capacitance at this node.
|
||||
|
||||
Must be called after propigate_delays has been called on the Outpin
|
||||
object of this tree.
|
||||
|
||||
"""
|
||||
pass
|
||||
|
||||
def propigate_downstream_capacitance(self, math):
|
||||
""" Returns capacitance visible to parent of this node.
|
||||
|
||||
Must call propigate_downstream_capacitance on all children of this node.
|
||||
Should save downstream capacitance visible to this node's output
|
||||
(if any) to be returned in the get_downstream_cap method.
|
||||
"""
|
||||
pass
|
||||
|
||||
|
||||
class DownstreamNode(TimingNode):
|
||||
""" All non-root TimingNode's are DownstreamNode's.
|
||||
|
||||
"""
|
||||
|
||||
def propigate_delays(self, elements, math):
|
||||
""" Propigates upstream delay elements to children of the tree.
|
||||
|
||||
Must call propigated_delays on all children of this node, and add this
|
||||
node to elements.
|
||||
|
||||
Arguments
|
||||
---------
|
||||
elements : list of TimingNode's
|
||||
List of delay nodes between root of this tree and this node.
|
||||
math : MathModel
|
||||
Math model to use to compute delays
|
||||
"""
|
||||
pass
|
||||
|
||||
|
||||
class Outpin(TimingNode):
|
||||
""" Represents a site output pin.
|
||||
|
||||
Outpin object is the root of the timing tree. Once tree is built with
|
||||
set_sink_wire and Wire.add_child methods, propigate_delays should be
|
||||
invoked to estabilish model.
|
||||
|
||||
Arguments
|
||||
---------
|
||||
|
||||
resistance
|
||||
Drive resistance in elmore delay model
|
||||
delays
|
||||
Intristic delays on output pin.
|
||||
|
||||
"""
|
||||
|
||||
def __init__(self, resistance, delays):
|
||||
self.resistance = resistance
|
||||
self.delays = delays
|
||||
self.sink_wire = None
|
||||
|
||||
self.downstream_cap = None
|
||||
self.rc_delay = None
|
||||
|
||||
def set_sink_wire(self, wire):
|
||||
""" Sets sink wire for this output pin.
|
||||
|
||||
An output pin always sinks to exactly 1 wire.
|
||||
|
||||
This method must be called prior to calling propigate_delays method
|
||||
on this object.
|
||||
|
||||
Arguments
|
||||
---------
|
||||
wire : Wire object
|
||||
Sink wire for this output pin.
|
||||
|
||||
"""
|
||||
self.sink_wire = wire
|
||||
|
||||
def propigate_downstream_capacitance(self, math):
|
||||
assert self.sink_wire is not None
|
||||
self.downstream_cap = self.sink_wire.propigate_downstream_capacitance(
|
||||
math)
|
||||
self.rc_delay = math.multiply(self.downstream_cap, self.resistance)
|
||||
|
||||
def propigate_delays(self, math):
|
||||
""" Propigate delays throughout tree using specified math model.
|
||||
|
||||
Must be called after elmore tree is estabilished.
|
||||
|
||||
Arguments
|
||||
---------
|
||||
math : MathModel object
|
||||
Math model used when doing timing computations.
|
||||
|
||||
"""
|
||||
self.propigate_downstream_capacitance(math)
|
||||
self.sink_wire.propigate_delays([self], math)
|
||||
self.rc_delay = math.multiply(self.resistance, self.downstream_cap)
|
||||
|
||||
def get_intrinsic_delays(self):
|
||||
return self.delays
|
||||
|
||||
def get_rc_delay(self):
|
||||
assert self.rc_delay is not None
|
||||
return self.rc_delay
|
||||
|
||||
def get_downstream_cap(self):
|
||||
assert self.downstream_cap is not None
|
||||
return self.downstream_cap
|
||||
|
||||
|
||||
class Inpin(DownstreamNode):
|
||||
""" Represents a site input pin.
|
||||
|
||||
Represents leaf of timing model. Once model is connected and delays
|
||||
are propigate (by calling Outpin,propigated_delays), get_delays will
|
||||
correctly return the list of delay elements from the root to this leaf.
|
||||
|
||||
Arguments
|
||||
---------
|
||||
|
||||
capacitance
|
||||
Pin capacitance for input pin.
|
||||
delays
|
||||
Intristic delays on input pin.
|
||||
|
||||
"""
|
||||
|
||||
def __init__(self, capacitance, delays, name=None):
|
||||
self.capacitance = capacitance
|
||||
self.delays = delays
|
||||
self.propigated_delays = None
|
||||
self.name = name
|
||||
|
||||
def get_intrinsic_delays(self):
|
||||
return self.delays
|
||||
|
||||
def get_rc_delay(self):
|
||||
return None
|
||||
|
||||
def get_downstream_cap(self):
|
||||
return None
|
||||
|
||||
def propigate_downstream_capacitance(self, math):
|
||||
return self.capacitance
|
||||
|
||||
def propigate_delays(self, elements, math):
|
||||
self.propigated_delays = list(elements)
|
||||
|
||||
def get_delays(self):
|
||||
""" Return list of delay models that make up the delay for this pin.
|
||||
|
||||
The sum of all delay elements (both intristic and RC) is the net
|
||||
delay from the output pin to this input pin.
|
||||
|
||||
"""
|
||||
return self.propigated_delays + [self]
|
||||
|
||||
|
||||
class Wire(DownstreamNode):
|
||||
""" Represents a wire in the timing model.
|
||||
|
||||
Wires must be connected to an upstream driver model (Outpin, Buffer,
|
||||
PassTransistor objects) with set_sink_wire, and add_child must be called
|
||||
attaching output nodes (Buffer, PassTransistor, Inpin objects).
|
||||
|
||||
Arguments
|
||||
---------
|
||||
rc_elements : List of RcElement
|
||||
Resistance and capacitance of this wire.
|
||||
math : MathModel
|
||||
Math model used to compute lumped resistance and capacitance.
|
||||
|
||||
"""
|
||||
|
||||
def __init__(self, rc_elements, math):
|
||||
self.resistance = math.sum(elem.resistance for elem in rc_elements)
|
||||
self.capacitance = math.sum(elem.capacitance for elem in rc_elements)
|
||||
self.children = []
|
||||
|
||||
self.downstream_cap = None
|
||||
self.propigated_delays = None
|
||||
self.rc_delay = None
|
||||
|
||||
def add_child(self, child):
|
||||
""" Add a child node to this wire.
|
||||
|
||||
Call this method as needed prior to calling propigate_delays on the
|
||||
root Outpin object.
|
||||
|
||||
Arguments
|
||||
---------
|
||||
child : Buffer or PassTransistor or Inpin
|
||||
Adds child load to this wire.
|
||||
|
||||
"""
|
||||
self.children.append(child)
|
||||
|
||||
def propigate_downstream_capacitance(self, math):
|
||||
downstream_cap = math.sum(
|
||||
child.propigate_downstream_capacitance(math)
|
||||
for child in self.children)
|
||||
|
||||
# Pi-model is definied such that wire resistance only sees half of the
|
||||
# wire capacitance.
|
||||
self.downstream_cap = math.plus(
|
||||
math.divide(self.capacitance, 2), downstream_cap)
|
||||
|
||||
# Upstream seems all of the wires capacitance
|
||||
return math.plus(downstream_cap, self.capacitance)
|
||||
|
||||
def propigate_delays(self, elements, math):
|
||||
self.propigated_delays = list(elements)
|
||||
|
||||
for child in self.children:
|
||||
child.propigate_delays(self.propigated_delays + [self], math)
|
||||
|
||||
self.rc_delay = math.multiply(self.resistance, self.downstream_cap)
|
||||
|
||||
def get_intrinsic_delays(self):
|
||||
return None
|
||||
|
||||
def get_rc_delay(self):
|
||||
assert self.rc_delay is not None
|
||||
return self.rc_delay
|
||||
|
||||
def get_downstream_cap(self):
|
||||
assert self.downstream_cap is not None
|
||||
return self.downstream_cap
|
||||
|
||||
|
||||
class Buffer(DownstreamNode):
|
||||
""" Represents an isolating switch.
|
||||
|
||||
The internal_capacitance model is such that the upstream node only sees
|
||||
the capacitance of this node when the switch is enabled. Therefore, only
|
||||
active buffers should be included in the model.
|
||||
|
||||
Arguments
|
||||
---------
|
||||
internal_capacitance
|
||||
Capacitance seen by upstream node when this buffer is enabled.
|
||||
drive_resistance
|
||||
Driver resistance used for computing elmore delay.
|
||||
delays : Dictionary of PvtCorner to IntristicDelay
|
||||
Delay through switch
|
||||
|
||||
"""
|
||||
|
||||
def __init__(self, internal_capacitance, drive_resistance, delays):
|
||||
self.internal_capacitance = internal_capacitance
|
||||
self.drive_resistance = drive_resistance
|
||||
self.delays = delays
|
||||
|
||||
self.downstream_cap = None
|
||||
self.rc_delay = None
|
||||
|
||||
def set_sink_wire(self, wire):
|
||||
""" Sets sink wire for this output pin.
|
||||
|
||||
An output pin always sinks to exactly 1 wire.
|
||||
|
||||
This method must be called prior to calling propigate_delays method
|
||||
on the root Outpin object of this tree.
|
||||
|
||||
Arguments
|
||||
---------
|
||||
wire : Wire object
|
||||
Sink wire for this output pin.
|
||||
|
||||
"""
|
||||
self.sink_wire = wire
|
||||
|
||||
def propigate_downstream_capacitance(self, math):
|
||||
assert self.sink_wire is not None
|
||||
self.downstream_cap = self.sink_wire.propigate_downstream_capacitance(
|
||||
math)
|
||||
return self.internal_capacitance
|
||||
|
||||
def propigate_delays(self, elements, math):
|
||||
self.propigated_delays = list(elements)
|
||||
|
||||
assert self.sink_wire is not None
|
||||
self.sink_wire.propigate_delays(self.propigated_delays + [self], math)
|
||||
self.rc_delay = math.multiply(
|
||||
self.downstream_cap, self.drive_resistance)
|
||||
|
||||
def get_intrinsic_delays(self):
|
||||
return self.delays
|
||||
|
||||
def get_rc_delay(self):
|
||||
assert self.rc_delay is not None
|
||||
return self.rc_delay
|
||||
|
||||
def get_downstream_cap(self):
|
||||
assert self.downstream_cap is not None
|
||||
return self.downstream_cap
|
||||
|
||||
|
||||
class PassTransistor(DownstreamNode):
|
||||
""" Represents a non-isolating switch.
|
||||
|
||||
Arguments
|
||||
---------
|
||||
drive_resistance
|
||||
Driver resistance used for computing elmore delay.
|
||||
delays : Dictionary of PvtCorner to IntristicDelay
|
||||
Delay through switch.
|
||||
|
||||
"""
|
||||
|
||||
def __init__(self, drive_resistance, delays):
|
||||
self.drive_resistance = drive_resistance
|
||||
self.delays = delays
|
||||
self.sink_wire = None
|
||||
|
||||
self.downstream_cap = None
|
||||
self.rc_delay = None
|
||||
|
||||
def set_sink_wire(self, wire):
|
||||
""" Sets sink wire for this output pin.
|
||||
|
||||
An output pin always sinks to exactly 1 wire.
|
||||
|
||||
This method must be called prior to calling propigate_delays method
|
||||
on the root Outpin object of this tree.
|
||||
|
||||
Arguments
|
||||
---------
|
||||
wire : Wire object
|
||||
Sink wire for this output pin.
|
||||
|
||||
"""
|
||||
self.sink_wire = wire
|
||||
|
||||
def propigate_downstream_capacitance(self, math):
|
||||
assert self.sink_wire is not None
|
||||
self.downstream_cap = self.sink_wire.propigate_downstream_capacitance(
|
||||
math)
|
||||
|
||||
return self.downstream_cap
|
||||
|
||||
def propigate_delays(self, elements, math):
|
||||
self.propigated_delays = list(elements)
|
||||
|
||||
assert self.sink_wire is not None
|
||||
self.sink_wire.propigate_delays(self.propigated_delays + [self], math)
|
||||
self.rc_delay = math.multiply(
|
||||
self.downstream_cap, self.drive_resistance)
|
||||
|
||||
def get_intrinsic_delays(self):
|
||||
return self.delays
|
||||
|
||||
def get_rc_delay(self):
|
||||
assert self.rc_delay is not None
|
||||
return self.rc_delay
|
||||
|
||||
def get_downstream_cap(self):
|
||||
assert self.downstream_cap is not None
|
||||
return self.downstream_cap
|
||||
Loading…
Reference in New Issue