mirror of https://github.com/VLSIDA/OpenRAM.git
PEP8 cleanup
This commit is contained in:
parent
2850b9efb5
commit
8603d3edd6
|
|
@ -15,6 +15,7 @@ from wire_spice_model import *
|
|||
from power_data import *
|
||||
import logical_effort
|
||||
|
||||
|
||||
class spice():
|
||||
"""
|
||||
This provides a set of useful generic types for hierarchy
|
||||
|
|
@ -30,19 +31,19 @@ class spice():
|
|||
|
||||
self.valid_signal_types = ["INOUT", "INPUT", "OUTPUT", "POWER", "GROUND"]
|
||||
# Holds subckts/mods for this module
|
||||
self.mods = []
|
||||
self.mods = []
|
||||
# Holds the pins for this module
|
||||
self.pins = []
|
||||
# The type map of each pin: INPUT, OUTPUT, INOUT, POWER, GROUND
|
||||
# for each instance, this is the set of nets/nodes that map to the pins for this instance
|
||||
self.pin_type = {}
|
||||
self.pin_type = {}
|
||||
# THE CONNECTIONS MUST MATCH THE ORDER OF THE PINS (restriction imposed by the
|
||||
# Spice format)
|
||||
self.conns = []
|
||||
# Keep track of any comments to add the the spice
|
||||
try:
|
||||
self.commments
|
||||
except:
|
||||
except NameError:
|
||||
self.comments = []
|
||||
|
||||
self.sp_read()
|
||||
|
|
@ -56,7 +57,7 @@ class spice():
|
|||
|
||||
try:
|
||||
self.commments
|
||||
except:
|
||||
except NameError:
|
||||
self.comments = []
|
||||
|
||||
self.comments.append(comment)
|
||||
|
|
@ -65,7 +66,9 @@ class spice():
|
|||
""" Adds a pin to the pins list. Default type is INOUT signal. """
|
||||
self.pins.append(name)
|
||||
self.pin_type[name]=pin_type
|
||||
debug.check(pin_type in self.valid_signal_types, "Invalid signaltype for {0}: {1}".format(name,pin_type))
|
||||
debug.check(pin_type in self.valid_signal_types,
|
||||
"Invalid signaltype for {0}: {1}".format(name,
|
||||
pin_type))
|
||||
|
||||
def add_pin_list(self, pin_list, pin_type="INOUT"):
|
||||
""" Adds a pin_list to the pins list """
|
||||
|
|
@ -73,36 +76,43 @@ class spice():
|
|||
# or a list that is the same length as the pin list.
|
||||
if type(pin_type)==str:
|
||||
for pin in pin_list:
|
||||
debug.check(pin_type in self.valid_signal_types, "Invalid signaltype for {0}: {1}".format(pin,pin_type))
|
||||
self.add_pin(pin,pin_type)
|
||||
debug.check(pin_type in self.valid_signal_types,
|
||||
"Invalid signaltype for {0}: {1}".format(pin,
|
||||
pin_type))
|
||||
self.add_pin(pin, pin_type)
|
||||
|
||||
elif len(pin_type)==len(pin_list):
|
||||
for (pin,ptype) in zip(pin_list, pin_type):
|
||||
debug.check(ptype in self.valid_signal_types, "Invalid signaltype for {0}: {1}".format(pin,ptype))
|
||||
self.add_pin(pin,ptype)
|
||||
for (pin, ptype) in zip(pin_list, pin_type):
|
||||
debug.check(ptype in self.valid_signal_types,
|
||||
"Invalid signaltype for {0}: {1}".format(pin,
|
||||
ptype))
|
||||
self.add_pin(pin, ptype)
|
||||
else:
|
||||
debug.error("Mismatch in type and pin list lengths.", -1)
|
||||
|
||||
def add_pin_types(self, type_list):
|
||||
"""Add pin types for all the cell's pins.
|
||||
Typically, should only be used for handmade cells."""
|
||||
#This only works if self.pins == bitcell.pin_names
|
||||
"""
|
||||
Add pin types for all the cell's pins.
|
||||
Typically, should only be used for handmade cells.
|
||||
"""
|
||||
# This only works if self.pins == bitcell.pin_names
|
||||
if self.pin_names != self.pins:
|
||||
debug.error("{} spice subcircuit port names do not match pin_names\
|
||||
\n SPICE names={}\
|
||||
\n Module names={}\
|
||||
".format(self.name, self.pin_names, self.pins),1)
|
||||
self.pin_type = {pin:type for pin,type in zip(self.pin_names, type_list)}
|
||||
".format(self.name, self.pin_names, self.pins), 1)
|
||||
self.pin_type = {pin: type for pin, type in zip(self.pin_names, type_list)}
|
||||
|
||||
def get_pin_type(self, name):
|
||||
""" Returns the type of the signal pin. """
|
||||
pin_type = self.pin_type[name]
|
||||
debug.check(pin_type in self.valid_signal_types, "Invalid signaltype for {0}: {1}".format(name,pin_type))
|
||||
debug.check(pin_type in self.valid_signal_types,
|
||||
"Invalid signaltype for {0}: {1}".format(name, pin_type))
|
||||
return pin_type
|
||||
|
||||
def get_pin_dir(self, name):
|
||||
""" Returns the direction of the pin. (Supply/ground are INOUT). """
|
||||
if self.pin_type[name] in ["POWER","GROUND"]:
|
||||
if self.pin_type[name] in ["POWER", "GROUND"]:
|
||||
return "INOUT"
|
||||
else:
|
||||
return self.pin_type[name]
|
||||
|
|
@ -125,11 +135,10 @@ class spice():
|
|||
output_list.append(pin)
|
||||
return output_list
|
||||
|
||||
|
||||
def copy_pins(self, other_module, suffix=""):
|
||||
""" This will copy all of the pins from the other module and add an optional suffix."""
|
||||
for pin in other_module.pins:
|
||||
self.add_pin(pin+suffix, other_module.get_pin_type(pin))
|
||||
self.add_pin(pin + suffix, other_module.get_pin_type(pin))
|
||||
|
||||
def get_inouts(self):
|
||||
""" These use pin types to determine pin lists. These
|
||||
|
|
@ -144,7 +153,6 @@ class spice():
|
|||
"""Adds a subckt/submodule to the subckt hierarchy"""
|
||||
self.mods.append(mod)
|
||||
|
||||
|
||||
def connect_inst(self, args, check=True):
|
||||
"""Connects the pins of the last instance added
|
||||
It is preferred to use the function with the check to find if
|
||||
|
|
@ -169,21 +177,23 @@ class spice():
|
|||
debug.error("{0} : Not all instance pins ({1}) are connected ({2}).".format(self.name,
|
||||
len(self.insts),
|
||||
len(self.conns)))
|
||||
debug.error("Instances: \n"+str(insts_string))
|
||||
debug.error("Instances: \n" + str(insts_string))
|
||||
debug.error("-----")
|
||||
debug.error("Connections: \n"+str(conns_string),1)
|
||||
debug.error("Connections: \n" + str(conns_string), 1)
|
||||
|
||||
def get_conns(self, inst):
|
||||
"""Returns the connections of a given instance."""
|
||||
for i in range(len(self.insts)):
|
||||
if inst is self.insts[i]:
|
||||
return self.conns[i]
|
||||
#If not found, returns None
|
||||
# If not found, returns None
|
||||
return None
|
||||
|
||||
def sp_read(self):
|
||||
"""Reads the sp file (and parse the pins) from the library
|
||||
Otherwise, initialize it to null for dynamic generation"""
|
||||
"""
|
||||
Reads the sp file (and parse the pins) from the library
|
||||
Otherwise, initialize it to null for dynamic generation
|
||||
"""
|
||||
if self.sp_file and os.path.isfile(self.sp_file):
|
||||
debug.info(3, "opening {0}".format(self.sp_file))
|
||||
f = open(self.sp_file)
|
||||
|
|
@ -202,13 +212,14 @@ class spice():
|
|||
|
||||
def check_net_in_spice(self, net_name):
|
||||
"""Checks if a net name exists in the current. Intended to be check nets in hand-made cells."""
|
||||
#Remove spaces and lower case then add spaces. Nets are separated by spaces.
|
||||
net_formatted = ' '+net_name.lstrip().rstrip().lower()+' '
|
||||
# Remove spaces and lower case then add spaces.
|
||||
# Nets are separated by spaces.
|
||||
net_formatted = ' ' + net_name.lstrip().rstrip().lower() + ' '
|
||||
for line in self.spice:
|
||||
#Lowercase the line and remove any part of the line that is a comment.
|
||||
# Lowercase the line and remove any part of the line that is a comment.
|
||||
line = line.lower().split('*')[0]
|
||||
|
||||
#Skip .subckt or .ENDS lines
|
||||
# Skip .subckt or .ENDS lines
|
||||
if line.find('.') == 0:
|
||||
continue
|
||||
if net_formatted in line:
|
||||
|
|
@ -220,7 +231,7 @@ class spice():
|
|||
nets_match = True
|
||||
for net in nets:
|
||||
nets_match = nets_match and self.check_net_in_spice(net)
|
||||
return nets_match
|
||||
return nets_match
|
||||
|
||||
def contains(self, mod, modlist):
|
||||
for x in modlist:
|
||||
|
|
@ -244,34 +255,31 @@ class spice():
|
|||
if self.pins == []:
|
||||
return
|
||||
|
||||
|
||||
# write out the first spice line (the subcircuit)
|
||||
sp.write("\n.SUBCKT {0} {1}\n".format(self.name,
|
||||
" ".join(self.pins)))
|
||||
|
||||
for pin in self.pins:
|
||||
sp.write("* {1:6}: {0} \n".format(pin,self.pin_type[pin]))
|
||||
sp.write("* {1:6}: {0} \n".format(pin, self.pin_type[pin]))
|
||||
|
||||
for line in self.comments:
|
||||
sp.write("* {}\n".format(line))
|
||||
|
||||
# every instance must have a set of connections, even if it is empty.
|
||||
if len(self.insts)!=len(self.conns):
|
||||
if len(self.insts) != len(self.conns):
|
||||
debug.error("{0} : Not all instance pins ({1}) are connected ({2}).".format(self.name,
|
||||
len(self.insts),
|
||||
len(self.conns)))
|
||||
debug.error("Instances: \n"+str(self.insts))
|
||||
debug.error("Instances: \n" + str(self.insts))
|
||||
debug.error("-----")
|
||||
debug.error("Connections: \n"+str(self.conns),1)
|
||||
|
||||
|
||||
debug.error("Connections: \n" + str(self.conns), 1)
|
||||
|
||||
for i in range(len(self.insts)):
|
||||
# we don't need to output connections of empty instances.
|
||||
# these are wires and paths
|
||||
if self.conns[i] == []:
|
||||
continue
|
||||
if hasattr(self.insts[i].mod,"spice_device"):
|
||||
if hasattr(self.insts[i].mod, "spice_device"):
|
||||
sp.write(self.insts[i].mod.spice_device.format(self.insts[i].name,
|
||||
" ".join(self.conns[i])))
|
||||
sp.write("\n")
|
||||
|
|
@ -286,7 +294,7 @@ class spice():
|
|||
else:
|
||||
# write the subcircuit itself
|
||||
# Including the file path makes the unit test fail for other users.
|
||||
#if os.path.isfile(self.sp_file):
|
||||
# if os.path.isfile(self.sp_file):
|
||||
# sp.write("\n* {0}\n".format(self.sp_file))
|
||||
sp.write("\n".join(self.spice))
|
||||
|
||||
|
|
@ -305,7 +313,8 @@ class spice():
|
|||
def analytical_delay(self, corner, slew, load=0.0):
|
||||
"""Inform users undefined delay module while building new modules"""
|
||||
|
||||
# FIXME: Slew is not used in the model right now. Can be added heuristically as linear factor
|
||||
# FIXME: Slew is not used in the model right now.
|
||||
# Can be added heuristically as linear factor
|
||||
relative_cap = logical_effort.convert_farad_to_relative_c(load)
|
||||
stage_effort = self.get_stage_effort(relative_cap)
|
||||
|
||||
|
|
@ -316,7 +325,7 @@ class spice():
|
|||
abs_delay = stage_effort.get_absolute_delay()
|
||||
corner_delay = self.apply_corners_analytically(abs_delay, corner)
|
||||
SLEW_APPROXIMATION = 0.1
|
||||
corner_slew = SLEW_APPROXIMATION*corner_delay
|
||||
corner_slew = SLEW_APPROXIMATION * corner_delay
|
||||
return delay_data(corner_delay, corner_slew)
|
||||
|
||||
def get_stage_effort(self, cout, inp_is_rise=True):
|
||||
|
|
@ -326,7 +335,7 @@ class spice():
|
|||
debug.warning("Class {0} name {1}"
|
||||
.format(self.__class__.__name__,
|
||||
self.name))
|
||||
return None
|
||||
return None
|
||||
|
||||
def get_cin(self):
|
||||
"""Returns input load in Femto-Farads. All values generated using
|
||||
|
|
@ -342,35 +351,35 @@ class spice():
|
|||
debug.warning("Design Class {0} input capacitance function needs to be defined"
|
||||
.format(self.__class__.__name__))
|
||||
debug.warning("Class {0} name {1}"
|
||||
.format(self.__class__.__name__,
|
||||
self.name))
|
||||
return 0
|
||||
.format(self.__class__.__name__,
|
||||
self.name))
|
||||
return 0
|
||||
|
||||
def cal_delay_with_rc(self, corner, r, c ,slew, swing = 0.5):
|
||||
"""
|
||||
Calculate the delay of a mosfet by
|
||||
def cal_delay_with_rc(self, corner, r, c, slew, swing=0.5):
|
||||
"""
|
||||
Calculate the delay of a mosfet by
|
||||
modeling it as a resistance driving a capacitance
|
||||
"""
|
||||
swing_factor = abs(math.log(1-swing)) # time constant based on swing
|
||||
delay = swing_factor * r * c #c is in ff and delay is in fs
|
||||
swing_factor = abs(math.log(1 - swing)) # time constant based on swing
|
||||
delay = swing_factor * r * c # c is in ff and delay is in fs
|
||||
delay = self.apply_corners_analytically(delay, corner)
|
||||
delay = delay * 0.001 #make the unit to ps
|
||||
delay = delay * 0.001 # make the unit to ps
|
||||
|
||||
# Output slew should be linear to input slew which is described
|
||||
# Output slew should be linear to input slew which is described
|
||||
# as 0.005* slew.
|
||||
|
||||
# The slew will be also influenced by the delay.
|
||||
# If no input slew(or too small to make impact)
|
||||
# The mimum slew should be the time to charge RC.
|
||||
# If no input slew(or too small to make impact)
|
||||
# The mimum slew should be the time to charge RC.
|
||||
# Delay * 2 is from 0 to 100% swing. 0.6*2*delay is from 20%-80%.
|
||||
slew = delay * 0.6 * 2 + 0.005 * slew
|
||||
return delay_data(delay = delay, slew = slew)
|
||||
return delay_data(delay=delay, slew=slew)
|
||||
|
||||
def apply_corners_analytically(self, delay, corner):
|
||||
"""Multiply delay by corner factors"""
|
||||
proc,vdd,temp = corner
|
||||
#FIXME: type of delay is needed to know which process to use.
|
||||
proc_mult = max(self.get_process_delay_factor(proc))
|
||||
proc, vdd, temp = corner
|
||||
# FIXME: type of delay is needed to know which process to use.
|
||||
proc_mult = max(self.get_process_delay_factor(proc))
|
||||
volt_mult = self.get_voltage_delay_factor(vdd)
|
||||
temp_mult = self.get_temp_delay_factor(temp)
|
||||
return delay * proc_mult * volt_mult * temp_mult
|
||||
|
|
@ -385,48 +394,51 @@ class spice():
|
|||
elif mos_proc == 'F':
|
||||
proc_factors.append(0.9)
|
||||
elif mos_proc == 'S':
|
||||
proc_factors.append(1.1)
|
||||
proc_factors.append(1.1)
|
||||
return proc_factors
|
||||
|
||||
def get_voltage_delay_factor(self, voltage):
|
||||
"""Returns delay increase due to voltage.
|
||||
Implemented as linear factor based off nominal voltage.
|
||||
"""
|
||||
return tech.spice["nom_supply_voltage"]/voltage
|
||||
return tech.spice["nom_supply_voltage"] / voltage
|
||||
|
||||
def get_temp_delay_factor(self, temp):
|
||||
"""Returns delay increase due to temperature (in C).
|
||||
Determines effect on threshold voltage and then linear factor is estimated.
|
||||
"""
|
||||
#Some portions of equation condensed (phi_t = k*T/q for T in Kelvin) in mV
|
||||
#(k/q)/100 = .008625, The division 100 simplifies the conversion from C to K and mV to V
|
||||
thermal_voltage_nom = 0.008625*tech.spice["nom_temperature"]
|
||||
thermal_voltage = 0.008625*temp
|
||||
vthresh = (tech.spice["nom_threshold"]+2*(thermal_voltage-thermal_voltage_nom))
|
||||
#Calculate effect on Vdd-Vth. The current vdd is not used here. A separate vdd factor is calculated.
|
||||
return (tech.spice["nom_supply_voltage"] - tech.spice["nom_threshold"])/(tech.spice["nom_supply_voltage"]-vthresh)
|
||||
# Some portions of equation condensed (phi_t = k*T/q for T in Kelvin) in mV
|
||||
# (k/q)/100 = .008625, The division 100 simplifies the conversion from C to K and mV to V
|
||||
thermal_voltage_nom = 0.008625 * tech.spice["nom_temperature"]
|
||||
thermal_voltage = 0.008625 * temp
|
||||
vthresh = (tech.spice["nom_threshold"] + 2 * (thermal_voltage - thermal_voltage_nom))
|
||||
# Calculate effect on Vdd-Vth.
|
||||
# The current vdd is not used here.
|
||||
# A separate vdd factor is calculated.
|
||||
return (tech.spice["nom_supply_voltage"] - tech.spice["nom_threshold"]) / (tech.spice["nom_supply_voltage"] - vthresh)
|
||||
|
||||
def return_delay(self, delay, slew):
|
||||
return delay_data(delay, slew)
|
||||
|
||||
def generate_rc_net(self,lump_num, wire_length, wire_width):
|
||||
def generate_rc_net(self, lump_num, wire_length, wire_width):
|
||||
return wire_spice_model(lump_num, wire_length, wire_width)
|
||||
|
||||
def calc_dynamic_power(self, corner, c, freq, swing=1.0):
|
||||
"""
|
||||
"""
|
||||
Calculate dynamic power using effective capacitance, frequency, and corner (PVT)
|
||||
"""
|
||||
proc,vdd,temp = corner
|
||||
net_vswing = vdd*swing
|
||||
power_dyn = c*vdd*net_vswing*freq
|
||||
proc, vdd, temp = corner
|
||||
net_vswing = vdd * swing
|
||||
power_dyn = c * vdd * net_vswing * freq
|
||||
|
||||
#Apply process and temperature factors. Roughly, process and Vdd affect the delay which affects the power.
|
||||
#No other estimations are currently used. Increased delay->slower freq.->less power
|
||||
proc_div = max(self.get_process_delay_factor(proc))
|
||||
# A pply process and temperature factors.
|
||||
# Roughly, process and Vdd affect the delay which affects the power.
|
||||
# No other estimations are currently used. Increased delay->slower freq.->less power
|
||||
proc_div = max(self.get_process_delay_factor(proc))
|
||||
temp_div = self.get_temp_delay_factor(temp)
|
||||
power_dyn = power_dyn/(proc_div*temp_div)
|
||||
power_dyn = power_dyn / (proc_div * temp_div)
|
||||
|
||||
return power_dyn
|
||||
return power_dyn
|
||||
|
||||
def return_power(self, dynamic=0.0, leakage=0.0):
|
||||
return power_data(dynamic, leakage)
|
||||
|
|
|
|||
Loading…
Reference in New Issue