Clean up. Split class into own file.

This commit is contained in:
Matt Guthaus 2019-07-24 08:15:10 -07:00
parent 07401fc6ea
commit 3df8abd38c
7 changed files with 163 additions and 131 deletions

View File

@ -28,6 +28,7 @@ class spice():
def __init__(self, name): def __init__(self, name):
self.name = name self.name = name
self.valid_signal_types = ["INOUT", "INPUT", "OUTPUT", "POWER", "GROUND"]
# Holds subckts/mods for this module # Holds subckts/mods for this module
self.mods = [] self.mods = []
# Holds the pins for this module # Holds the pins for this module
@ -64,16 +65,20 @@ class spice():
""" Adds a pin to the pins list. Default type is INOUT signal. """ """ Adds a pin to the pins list. Default type is INOUT signal. """
self.pins.append(name) self.pins.append(name)
self.pin_type[name]=pin_type self.pin_type[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_list="INOUT"): def add_pin_list(self, pin_list, pin_type="INOUT"):
""" Adds a pin_list to the pins list """ """ Adds a pin_list to the pins list """
# The type list can be a single type for all pins # The type list can be a single type for all pins
# or a list that is the same length as the pin list. # or a list that is the same length as the pin list.
if type(pin_type_list)==str: if type(pin_type)==str:
for pin in pin_list: for pin in pin_list:
self.add_pin(pin,pin_type_list) debug.check(pin_type in self.valid_signal_types, "Invalid signaltype for {0}: {1}".format(pin,pin_type))
elif len(pin_type_list)==len(pin_list): self.add_pin(pin,pin_type)
for (pin,ptype) in zip(pin_list, pin_type_list):
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) self.add_pin(pin,ptype)
else: else:
debug.error("Mismatch in type and pin list lengths.", -1) debug.error("Mismatch in type and pin list lengths.", -1)
@ -91,7 +96,9 @@ class spice():
def get_pin_type(self, name): def get_pin_type(self, name):
""" Returns the type of the signal pin. """ """ Returns the type of the signal pin. """
return self.pin_type[name] pin_type = self.pin_type[name]
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): def get_pin_dir(self, name):
""" Returns the direction of the pin. (Supply/ground are INOUT). """ """ Returns the direction of the pin. (Supply/ground are INOUT). """

View File

@ -0,0 +1,14 @@
# See LICENSE for licensing information.
#
# Copyright (c) 2016-2019 Regents of the University of California and The Board
# of Regents for the Oklahoma Agricultural and Mechanical College
# (acting for and on behalf of Oklahoma State University)
# All rights reserved.
#
from enum import Enum
class bit_polarity(Enum):
NONINVERTING = 0
INVERTING = 1

View File

@ -8,17 +8,7 @@
import re import re
import debug import debug
from globals import OPTS from globals import OPTS
from enum import Enum
class sram_op(Enum):
READ_ZERO = 0
READ_ONE = 1
WRITE_ZERO = 2
WRITE_ONE = 3
class bit_polarity(Enum):
NONINVERTING = 0
INVERTING = 1
def relative_compare(value1,value2,error_tolerance=0.001): def relative_compare(value1,value2,error_tolerance=0.001):
""" This is used to compare relative values for convergence. """ """ This is used to compare relative values for convergence. """

View File

@ -12,6 +12,8 @@ import math
from .stimuli import * from .stimuli import *
from .trim_spice import * from .trim_spice import *
from .charutils import * from .charutils import *
from .sram_op import *
from .bit_polarity import *
import utils import utils
from globals import OPTS from globals import OPTS
from .simulation import simulation from .simulation import simulation
@ -21,7 +23,8 @@ import graph_util
from sram_factory import factory from sram_factory import factory
class delay(simulation): class delay(simulation):
"""Functions to measure the delay and power of an SRAM at a given address and """
Functions to measure the delay and power of an SRAM at a given address and
data bit. data bit.
In general, this will perform the following actions: In general, this will perform the following actions:
@ -40,7 +43,6 @@ class delay(simulation):
def __init__(self, sram, spfile, corner): def __init__(self, sram, spfile, corner):
simulation.__init__(self, sram, spfile, corner) simulation.__init__(self, sram, spfile, corner)
# These are the member variables for a simulation
self.targ_read_ports = [] self.targ_read_ports = []
self.targ_write_ports = [] self.targ_write_ports = []
self.period = 0 self.period = 0
@ -51,11 +53,11 @@ class delay(simulation):
def create_measurement_names(self): def create_measurement_names(self):
"""Create measurement names. The names themselves currently define the type of measurement""" """Create measurement names. The names themselves currently define the type of measurement"""
#Altering the names will crash the characterizer. TODO: object orientated approach to the measurements.
self.delay_meas_names = ["delay_lh", "delay_hl", "slew_lh", "slew_hl"] self.delay_meas_names = ["delay_lh", "delay_hl", "slew_lh", "slew_hl"]
self.power_meas_names = ["read0_power", "read1_power", "write0_power", "write1_power"] self.power_meas_names = ["read0_power", "read1_power", "write0_power", "write1_power"]
#self.voltage_when_names = ["volt_bl", "volt_br"] # self.voltage_when_names = ["volt_bl", "volt_br"]
#self.bitline_delay_names = ["delay_bl", "delay_br"] # self.bitline_delay_names = ["delay_bl", "delay_br"]
def create_measurement_objects(self): def create_measurement_objects(self):
"""Create the measurements used for read and write ports""" """Create the measurements used for read and write ports"""
@ -78,11 +80,11 @@ class delay(simulation):
"""Create the measurements used for read ports: delays, slews, powers""" """Create the measurements used for read ports: delays, slews, powers"""
self.read_lib_meas = [] self.read_lib_meas = []
self.clk_frmt = "clk{0}" #Unformatted clock name self.clk_frmt = "clk{0}" # Unformatted clock name
targ_name = "{0}{1}_{2}".format(self.dout_name,"{}",self.probe_data) #Empty values are the port and probe data bit targ_name = "{0}{1}_{2}".format(self.dout_name,"{}",self.probe_data) # Empty values are the port and probe data bit
self.delay_meas = [] self.delay_meas = []
self.delay_meas.append(delay_measure("delay_lh", self.clk_frmt, targ_name, "RISE", "RISE", measure_scale=1e9)) self.delay_meas.append(delay_measure("delay_lh", self.clk_frmt, targ_name, "RISE", "RISE", measure_scale=1e9))
self.delay_meas[-1].meta_str = sram_op.READ_ONE #Used to index time delay values when measurements written to spice file. self.delay_meas[-1].meta_str = sram_op.READ_ONE # Used to index time delay values when measurements written to spice file.
self.delay_meas.append(delay_measure("delay_hl", self.clk_frmt, targ_name, "FALL", "FALL", measure_scale=1e9)) self.delay_meas.append(delay_measure("delay_hl", self.clk_frmt, targ_name, "FALL", "FALL", measure_scale=1e9))
self.delay_meas[-1].meta_str = sram_op.READ_ZERO self.delay_meas[-1].meta_str = sram_op.READ_ZERO
self.read_lib_meas+=self.delay_meas self.read_lib_meas+=self.delay_meas
@ -99,14 +101,14 @@ class delay(simulation):
self.read_lib_meas.append(power_measure("read0_power", "FALL", measure_scale=1e3)) self.read_lib_meas.append(power_measure("read0_power", "FALL", measure_scale=1e3))
self.read_lib_meas[-1].meta_str = sram_op.READ_ZERO self.read_lib_meas[-1].meta_str = sram_op.READ_ZERO
#This will later add a half-period to the spice time delay. Only for reading 0. # This will later add a half-period to the spice time delay. Only for reading 0.
for obj in self.read_lib_meas: for obj in self.read_lib_meas:
if obj.meta_str is sram_op.READ_ZERO: if obj.meta_str is sram_op.READ_ZERO:
obj.meta_add_delay = True obj.meta_add_delay = True
read_measures = [] read_measures = []
read_measures.append(self.read_lib_meas) read_measures.append(self.read_lib_meas)
#Other measurements associated with the read port not included in the liberty file # Other measurements associated with the read port not included in the liberty file
read_measures.append(self.create_bitline_measurement_objects()) read_measures.append(self.create_bitline_measurement_objects())
read_measures.append(self.create_debug_measurement_objects()) read_measures.append(self.create_debug_measurement_objects())
read_measures.append(self.create_read_bit_measures()) read_measures.append(self.create_read_bit_measures())
@ -114,11 +116,13 @@ class delay(simulation):
return read_measures return read_measures
def create_bitline_measurement_objects(self): def create_bitline_measurement_objects(self):
"""Create the measurements used for bitline delay values. Due to unique error checking, these are separated from other measurements. """
These measurements are only associated with read values Create the measurements used for bitline delay values. Due to
unique error checking, these are separated from other measurements.
These measurements are only associated with read values.
""" """
self.bitline_volt_meas = [] self.bitline_volt_meas = []
#Bitline voltage measures
self.bitline_volt_meas.append(voltage_at_measure("v_bl_READ_ZERO", self.bitline_volt_meas.append(voltage_at_measure("v_bl_READ_ZERO",
self.bl_name)) self.bl_name))
self.bitline_volt_meas[-1].meta_str = sram_op.READ_ZERO self.bitline_volt_meas[-1].meta_str = sram_op.READ_ZERO
@ -151,7 +155,7 @@ class delay(simulation):
"""Create debug measurement to help identify failures.""" """Create debug measurement to help identify failures."""
self.debug_volt_meas = [] self.debug_volt_meas = []
for meas in self.delay_meas: for meas in self.delay_meas:
#Output voltage measures # Output voltage measures
self.debug_volt_meas.append(voltage_at_measure("v_{}".format(meas.name), self.debug_volt_meas.append(voltage_at_measure("v_{}".format(meas.name),
meas.targ_name_no_port)) meas.targ_name_no_port))
self.debug_volt_meas[-1].meta_str = meas.meta_str self.debug_volt_meas[-1].meta_str = meas.meta_str
@ -172,7 +176,7 @@ class delay(simulation):
for polarity,meas in single_bit_meas.items(): for polarity,meas in single_bit_meas.items():
meas.meta_str = cycle meas.meta_str = cycle
self.bit_meas[polarity].append(meas) self.bit_meas[polarity].append(meas)
#Dictionary values are lists, reduce to a single list of measurements # Dictionary values are lists, reduce to a single list of measurements
return [meas for meas_list in self.bit_meas.values() for meas in meas_list] return [meas for meas_list in self.bit_meas.values() for meas in meas_list]
def get_bit_measures(self, meas_tag, probe_address, probe_data): def get_bit_measures(self, meas_tag, probe_address, probe_data):
@ -186,7 +190,7 @@ class delay(simulation):
"supported for characterization. Storage nets={}").format(storage_names)) "supported for characterization. Storage nets={}").format(storage_names))
q_name = cell_name+'.'+str(storage_names[0]) q_name = cell_name+'.'+str(storage_names[0])
qbar_name = cell_name+'.'+str(storage_names[1]) qbar_name = cell_name+'.'+str(storage_names[1])
#Bit measures, measurements times to be defined later. The measurement names must be unique # Bit measures, measurements times to be defined later. The measurement names must be unique
# but they is enforced externally # but they is enforced externally
q_meas = voltage_at_measure("v_q_{}".format(meas_tag), q_name, has_port=False) q_meas = voltage_at_measure("v_q_{}".format(meas_tag), q_name, has_port=False)
qbar_meas = voltage_at_measure("v_qbar_{}".format(meas_tag), qbar_name, has_port=False) qbar_meas = voltage_at_measure("v_qbar_{}".format(meas_tag), qbar_name, has_port=False)
@ -200,8 +204,8 @@ class delay(simulation):
def add_graph_exclusions(self): def add_graph_exclusions(self):
"""Exclude portions of SRAM from timing graph which are not relevant""" """Exclude portions of SRAM from timing graph which are not relevant"""
#other initializations can only be done during analysis when a bit has been selected # other initializations can only be done during analysis when a bit has been selected
#for testing. # for testing.
self.sram.bank.graph_exclude_precharge() self.sram.bank.graph_exclude_precharge()
self.sram.graph_exclude_addr_dff() self.sram.graph_exclude_addr_dff()
self.sram.graph_exclude_data_dff() self.sram.graph_exclude_data_dff()
@ -210,10 +214,10 @@ class delay(simulation):
def create_graph(self): def create_graph(self):
"""Creates timing graph to generate the timing paths for the SRAM output.""" """Creates timing graph to generate the timing paths for the SRAM output."""
self.sram.bank.bitcell_array.init_graph_params() #Removes previous bit exclusions self.sram.bank.bitcell_array.init_graph_params() # Removes previous bit exclusions
self.sram.bank.bitcell_array.graph_exclude_bits(self.wordline_row, self.bitline_column) self.sram.bank.bitcell_array.graph_exclude_bits(self.wordline_row, self.bitline_column)
#Generate new graph every analysis as edges might change depending on test bit # Generate new graph every analysis as edges might change depending on test bit
self.graph = graph_util.timing_graph() self.graph = graph_util.timing_graph()
self.sram_spc_name = "X{}".format(self.sram.name) self.sram_spc_name = "X{}".format(self.sram.name)
self.sram.build_graph(self.graph,self.sram_spc_name,self.pins) self.sram.build_graph(self.graph,self.sram_spc_name,self.pins)
@ -234,8 +238,8 @@ class delay(simulation):
"""Gets the signal name associated with the sense amp enable from input paths. """Gets the signal name associated with the sense amp enable from input paths.
Only expects a single path to contain the sen signal name.""" Only expects a single path to contain the sen signal name."""
sa_mods = factory.get_mods(OPTS.sense_amp) sa_mods = factory.get_mods(OPTS.sense_amp)
#Any sense amp instantiated should be identical, any change to that # Any sense amp instantiated should be identical, any change to that
#will require some identification to determine the mod desired. # will require some identification to determine the mod desired.
debug.check(len(sa_mods) == 1, "Only expected one type of Sense Amp. Cannot perform s_en checks.") debug.check(len(sa_mods) == 1, "Only expected one type of Sense Amp. Cannot perform s_en checks.")
enable_name = sa_mods[0].get_enable_name() enable_name = sa_mods[0].get_enable_name()
sen_name = self.get_alias_in_path(paths, enable_name, sa_mods[0]) sen_name = self.get_alias_in_path(paths, enable_name, sa_mods[0])
@ -253,7 +257,7 @@ class delay(simulation):
cell_br = cell_mod.get_br_name() cell_br = cell_mod.get_br_name()
bl_found = False bl_found = False
#Only a single path should contain a single s_en name. Anything else is an error. # Only a single path should contain a single s_en name. Anything else is an error.
bl_names = [] bl_names = []
exclude_set = self.get_bl_name_search_exclusions() exclude_set = self.get_bl_name_search_exclusions()
for int_net in [cell_bl, cell_br]: for int_net in [cell_bl, cell_br]:
@ -263,8 +267,8 @@ class delay(simulation):
def get_bl_name_search_exclusions(self): def get_bl_name_search_exclusions(self):
"""Gets the mods as a set which should be excluded while searching for name.""" """Gets the mods as a set which should be excluded while searching for name."""
#Exclude the RBL as it contains bitcells which are not in the main bitcell array # Exclude the RBL as it contains bitcells which are not in the main bitcell array
#so it makes the search awkward # so it makes the search awkward
return set(factory.get_mods(OPTS.replica_bitline)) return set(factory.get_mods(OPTS.replica_bitline))
def get_primary_cell_mod(self, cell_mods): def get_primary_cell_mod(self, cell_mods):
@ -325,7 +329,7 @@ class delay(simulation):
if not isinstance(self.probe_data, int) or self.probe_data>self.word_size or self.probe_data<0: if not isinstance(self.probe_data, int) or self.probe_data>self.word_size or self.probe_data<0:
debug.error("Given probe_data is not an integer to specify a data bit",1) debug.error("Given probe_data is not an integer to specify a data bit",1)
#Adding port options here which the characterizer cannot handle. Some may be added later like ROM # Adding port options here which the characterizer cannot handle. Some may be added later like ROM
if len(self.read_ports) == 0: if len(self.read_ports) == 0:
debug.error("Characterizer does not currently support SRAMs without read ports.",1) debug.error("Characterizer does not currently support SRAMs without read ports.",1)
if len(self.write_ports) == 0: if len(self.write_ports) == 0:
@ -460,26 +464,26 @@ class delay(simulation):
variant_tuple = self.get_volt_at_measure_variants(port, measure_obj) variant_tuple = self.get_volt_at_measure_variants(port, measure_obj)
else: else:
debug.error("Input function not defined for measurement type={}".format(meas_type)) debug.error("Input function not defined for measurement type={}".format(meas_type))
#Removes port input from any object which does not use it. This shorthand only works if # Removes port input from any object which does not use it. This shorthand only works if
#the measurement has port as the last input. Could be implemented by measurement type or # the measurement has port as the last input. Could be implemented by measurement type or
#remove entirely from measurement classes. # remove entirely from measurement classes.
if not measure_obj.has_port: if not measure_obj.has_port:
variant_tuple = variant_tuple[:-1] variant_tuple = variant_tuple[:-1]
return variant_tuple return variant_tuple
def get_delay_measure_variants(self, port, delay_obj): def get_delay_measure_variants(self, port, delay_obj):
"""Get the measurement values that can either vary from simulation to simulation (vdd, address) or port to port (time delays)""" """Get the measurement values that can either vary from simulation to simulation (vdd, address) or port to port (time delays)"""
#Return value is intended to match the delay measure format: trig_td, targ_td, vdd, port # Return value is intended to match the delay measure format: trig_td, targ_td, vdd, port
#vdd is arguably constant as that is true for a single lib file. # vdd is arguably constant as that is true for a single lib file.
if delay_obj.meta_str == sram_op.READ_ZERO: if delay_obj.meta_str == sram_op.READ_ZERO:
#Falling delay are measured starting from neg. clk edge. Delay adjusted to that. # Falling delay are measured starting from neg. clk edge. Delay adjusted to that.
meas_cycle_delay = self.cycle_times[self.measure_cycles[port][delay_obj.meta_str]] meas_cycle_delay = self.cycle_times[self.measure_cycles[port][delay_obj.meta_str]]
elif delay_obj.meta_str == sram_op.READ_ONE: elif delay_obj.meta_str == sram_op.READ_ONE:
meas_cycle_delay = self.cycle_times[self.measure_cycles[port][delay_obj.meta_str]] meas_cycle_delay = self.cycle_times[self.measure_cycles[port][delay_obj.meta_str]]
else: else:
debug.error("Unrecognised delay Index={}".format(delay_obj.meta_str),1) debug.error("Unrecognised delay Index={}".format(delay_obj.meta_str),1)
#These measurements have there time further delayed to the neg. edge of the clock. # These measurements have there time further delayed to the neg. edge of the clock.
if delay_obj.meta_add_delay: if delay_obj.meta_add_delay:
meas_cycle_delay += self.period/2 meas_cycle_delay += self.period/2
@ -487,7 +491,7 @@ class delay(simulation):
def get_power_measure_variants(self, port, power_obj, operation): def get_power_measure_variants(self, port, power_obj, operation):
"""Get the measurement values that can either vary port to port (time delays)""" """Get the measurement values that can either vary port to port (time delays)"""
#Return value is intended to match the power measure format: t_initial, t_final, port # Return value is intended to match the power measure format: t_initial, t_final, port
t_initial = self.cycle_times[self.measure_cycles[port][power_obj.meta_str]] t_initial = self.cycle_times[self.measure_cycles[port][power_obj.meta_str]]
t_final = self.cycle_times[self.measure_cycles[port][power_obj.meta_str]+1] t_final = self.cycle_times[self.measure_cycles[port][power_obj.meta_str]+1]
@ -495,21 +499,21 @@ class delay(simulation):
def get_volt_at_measure_variants(self, port, volt_meas): def get_volt_at_measure_variants(self, port, volt_meas):
"""Get the measurement values that can either vary port to port (time delays)""" """Get the measurement values that can either vary port to port (time delays)"""
#Only checking 0 value reads for now. # Only checking 0 value reads for now.
if volt_meas.meta_str == sram_op.READ_ZERO: if volt_meas.meta_str == sram_op.READ_ZERO:
#Falling delay are measured starting from neg. clk edge. Delay adjusted to that. # Falling delay are measured starting from neg. clk edge. Delay adjusted to that.
meas_cycle = self.cycle_times[self.measure_cycles[port][volt_meas.meta_str]] meas_cycle = self.cycle_times[self.measure_cycles[port][volt_meas.meta_str]]
elif volt_meas.meta_str == sram_op.READ_ONE: elif volt_meas.meta_str == sram_op.READ_ONE:
meas_cycle = self.cycle_times[self.measure_cycles[port][volt_meas.meta_str]] meas_cycle = self.cycle_times[self.measure_cycles[port][volt_meas.meta_str]]
else: else:
debug.error("Unrecognised delay Index={}".format(volt_meas.meta_str),1) debug.error("Unrecognised delay Index={}".format(volt_meas.meta_str),1)
#Measurement occurs at the end of the period -> current period start + period # Measurement occurs at the end of the period -> current period start + period
at_time = meas_cycle+self.period at_time = meas_cycle+self.period
return (at_time, port) return (at_time, port)
def get_volt_when_measure_variants(self, port, volt_meas): def get_volt_when_measure_variants(self, port, volt_meas):
"""Get the measurement values that can either vary port to port (time delays)""" """Get the measurement values that can either vary port to port (time delays)"""
#Only checking 0 value reads for now. # Only checking 0 value reads for now.
t_trig = meas_cycle_delay = self.cycle_times[self.measure_cycles[port][sram_op.READ_ZERO]] t_trig = meas_cycle_delay = self.cycle_times[self.measure_cycles[port][sram_op.READ_ZERO]]
return (t_trig, self.vdd_voltage, port) return (t_trig, self.vdd_voltage, port)
@ -590,7 +594,7 @@ class delay(simulation):
if (time_out <= 0): if (time_out <= 0):
debug.error("Timed out, could not find a feasible period.",2) debug.error("Timed out, could not find a feasible period.",2)
#Clear any write target ports and set read port # Clear any write target ports and set read port
self.targ_write_ports = [] self.targ_write_ports = []
self.targ_read_ports = [port] self.targ_read_ports = [port]
success = False success = False
@ -598,14 +602,14 @@ class delay(simulation):
debug.info(1, "Trying feasible period: {0}ns on Port {1}".format(feasible_period, port)) debug.info(1, "Trying feasible period: {0}ns on Port {1}".format(feasible_period, port))
self.period = feasible_period self.period = feasible_period
(success, results)=self.run_delay_simulation() (success, results)=self.run_delay_simulation()
#Clear these target ports after simulation # Clear these target ports after simulation
self.targ_read_ports = [] self.targ_read_ports = []
if not success: if not success:
feasible_period = 2 * feasible_period feasible_period = 2 * feasible_period
continue continue
#Positions of measurements currently hardcoded. First 2 are delays, next 2 are slews # Positions of measurements currently hardcoded. First 2 are delays, next 2 are slews
feasible_delays = [results[port][mname] for mname in self.delay_meas_names if "delay" in mname] feasible_delays = [results[port][mname] for mname in self.delay_meas_names if "delay" in mname]
feasible_slews = [results[port][mname] for mname in self.delay_meas_names if "slew" in mname] feasible_slews = [results[port][mname] for mname in self.delay_meas_names if "slew" in mname]
delay_str = "feasible_delay {0:.4f}ns/{1:.4f}ns".format(*feasible_delays) delay_str = "feasible_delay {0:.4f}ns/{1:.4f}ns".format(*feasible_delays)
@ -618,7 +622,7 @@ class delay(simulation):
if success: if success:
debug.info(2, "Found feasible_period for port {0}: {1}ns".format(port, feasible_period)) debug.info(2, "Found feasible_period for port {0}: {1}ns".format(port, feasible_period))
self.period = feasible_period self.period = feasible_period
#Only return results related to input port. # Only return results related to input port.
return results[port] return results[port]
def find_feasible_period(self): def find_feasible_period(self):
@ -628,19 +632,19 @@ class delay(simulation):
""" """
feasible_delays = [{} for i in self.all_ports] feasible_delays = [{} for i in self.all_ports]
#Get initial feasible delays from first port # Get initial feasible delays from first port
feasible_delays[self.read_ports[0]] = self.find_feasible_period_one_port(self.read_ports[0]) feasible_delays[self.read_ports[0]] = self.find_feasible_period_one_port(self.read_ports[0])
previous_period = self.period previous_period = self.period
#Loops through all the ports checks if the feasible period works. Everything restarts it if does not. # Loops through all the ports checks if the feasible period works. Everything restarts it if does not.
#Write ports do not produce delays which is why they are not included here. # Write ports do not produce delays which is why they are not included here.
i = 1 i = 1
while i < len(self.read_ports): while i < len(self.read_ports):
port = self.read_ports[i] port = self.read_ports[i]
#Only extract port values from the specified port, not the entire results. # Only extract port values from the specified port, not the entire results.
feasible_delays[port].update(self.find_feasible_period_one_port(port)) feasible_delays[port].update(self.find_feasible_period_one_port(port))
#Function sets the period. Restart the entire process if period changes to collect accurate delays # Function sets the period. Restart the entire process if period changes to collect accurate delays
if self.period > previous_period: if self.period > previous_period:
i = 0 i = 0
else: else:
@ -656,7 +660,7 @@ class delay(simulation):
works on the trimmed netlist by default, so powers do not works on the trimmed netlist by default, so powers do not
include leakage of all cells. include leakage of all cells.
""" """
#Sanity Check # Sanity Check
debug.check(self.period > 0, "Target simulation period non-positive") debug.check(self.period > 0, "Target simulation period non-positive")
sim_passed = True sim_passed = True
@ -666,25 +670,25 @@ class delay(simulation):
self.stim.run_sim() self.stim.run_sim()
#Loop through all targeted ports and collect delays and powers. # Loop through all targeted ports and collect delays and powers.
#Too much duplicate code here. Try reducing # Too much duplicate code here. Try reducing
for port in self.targ_read_ports: for port in self.targ_read_ports:
debug.info(2, "Checking delay values for port {}".format(port)) debug.info(2, "Checking delay values for port {}".format(port))
read_port_dict = {} read_port_dict = {}
#Get measurements from output file # Get measurements from output file
for measure in self.read_lib_meas: for measure in self.read_lib_meas:
read_port_dict[measure.name] = measure.retrieve_measure(port=port) read_port_dict[measure.name] = measure.retrieve_measure(port=port)
#Check sen timing, then bitlines, then general measurements. # Check sen timing, then bitlines, then general measurements.
if not self.check_sen_measure(port): if not self.check_sen_measure(port):
return (False,{}) return (False,{})
success = self.check_debug_measures(port) success = self.check_debug_measures(port)
success = success and self.check_bit_measures() success = success and self.check_bit_measures()
#Check timing for read ports. Power is only checked if it was read correctly # Check timing for read ports. Power is only checked if it was read correctly
if not self.check_valid_delays(read_port_dict) or not success: if not self.check_valid_delays(read_port_dict) or not success:
return (False,{}) return (False,{})
if not check_dict_values_is_float(read_port_dict): if not check_dict_values_is_float(read_port_dict):
debug.error("Failed to Measure Read Port Values:\n\t\t{0}".format(read_port_dict),1) #Printing the entire dict looks bad. debug.error("Failed to Measure Read Port Values:\n\t\t{0}".format(read_port_dict),1) # Printing the entire dict looks bad.
result[port].update(read_port_dict) result[port].update(read_port_dict)
@ -694,7 +698,7 @@ class delay(simulation):
write_port_dict[measure.name] = measure.retrieve_measure(port=port) write_port_dict[measure.name] = measure.retrieve_measure(port=port)
if not check_dict_values_is_float(write_port_dict): if not check_dict_values_is_float(write_port_dict):
debug.error("Failed to Measure Write Port Values:\n\t\t{0}".format(write_port_dict),1) #Printing the entire dict looks bad. debug.error("Failed to Measure Write Port Values:\n\t\t{0}".format(write_port_dict),1) # Printing the entire dict looks bad.
result[port].update(write_port_dict) result[port].update(write_port_dict)
# The delay is from the negative edge for our SRAM # The delay is from the negative edge for our SRAM
@ -712,10 +716,10 @@ class delay(simulation):
def check_debug_measures(self, port): def check_debug_measures(self, port):
"""Debug measures that indicate special conditions.""" """Debug measures that indicate special conditions."""
#Currently, only check if the opposite than intended value was read during # Currently, only check if the opposite than intended value was read during
# the read cycles i.e. neither of these measurements should pass. # the read cycles i.e. neither of these measurements should pass.
success = True success = True
#FIXME: these checks need to be re-done to be more robust against possible errors # FIXME: these checks need to be re-done to be more robust against possible errors
bl_vals = {} bl_vals = {}
br_vals = {} br_vals = {}
for meas in self.bitline_volt_meas: for meas in self.bitline_volt_meas:
@ -734,17 +738,17 @@ class delay(simulation):
if type(val) != float: if type(val) != float:
continue continue
if meas.meta_str == sram_op.READ_ONE and val < self.vdd_voltage*.1: if meas.meta_str == sram_op.READ_ONE and val < self.vdd_voltage*0.1:
success = False success = False
debug.info(1, "Debug measurement failed. Value {}v was read on read 1 cycle.".format(val)) debug.info(1, "Debug measurement failed. Value {}V was read on read 1 cycle.".format(val))
bl_check = self.check_bitline_meas(bl_vals[sram_op.READ_ONE], br_vals[sram_op.READ_ONE]) bl_check = self.check_bitline_meas(bl_vals[sram_op.READ_ONE], br_vals[sram_op.READ_ONE])
elif meas.meta_str == sram_op.READ_ZERO and val > self.vdd_voltage*.9: elif meas.meta_str == sram_op.READ_ZERO and val > self.vdd_voltage*0.9:
success = False success = False
debug.info(1, "Debug measurement failed. Value {}v was read on read 0 cycle.".format(val)) debug.info(1, "Debug measurement failed. Value {}V was read on read 0 cycle.".format(val))
bl_check = self.check_bitline_meas(br_vals[sram_op.READ_ONE], bl_vals[sram_op.READ_ONE]) bl_check = self.check_bitline_meas(br_vals[sram_op.READ_ONE], bl_vals[sram_op.READ_ONE])
#If the bitlines have a correct value while the output does not then that is a # If the bitlines have a correct value while the output does not then that is a
#sen error. FIXME: there are other checks that can be done to solidfy this conclusion. # sen error. FIXME: there are other checks that can be done to solidfy this conclusion.
if bl_check: if bl_check:
debug.error("Sense amp enable timing error. Increase the delay chain through the configuration file.",1) debug.error("Sense amp enable timing error. Increase the delay chain through the configuration file.",1)
@ -762,7 +766,7 @@ class delay(simulation):
if type(val) != float: if type(val) != float:
continue continue
meas_cycle = meas.meta_str meas_cycle = meas.meta_str
#Loose error conditions. Assume it's not metastable but account for noise during reads. # Loose error conditions. Assume it's not metastable but account for noise during reads.
if (meas_cycle == sram_op.READ_ZERO and polarity == bit_polarity.NONINVERTING) or\ if (meas_cycle == sram_op.READ_ZERO and polarity == bit_polarity.NONINVERTING) or\
(meas_cycle == sram_op.READ_ONE and polarity == bit_polarity.INVERTING): (meas_cycle == sram_op.READ_ONE and polarity == bit_polarity.INVERTING):
success = val < self.vdd_voltage/2 success = val < self.vdd_voltage/2
@ -778,9 +782,9 @@ class delay(simulation):
def check_bitline_meas(self, v_discharged_bl, v_charged_bl): def check_bitline_meas(self, v_discharged_bl, v_charged_bl):
"""Checks the value of the discharging bitline. Confirms s_en timing errors. """Checks the value of the discharging bitline. Confirms s_en timing errors.
Returns true if the bitlines are at there expected value.""" Returns true if the bitlines are at there expected value."""
#The inputs looks at discharge/charged bitline rather than left or right (bl/br) # The inputs looks at discharge/charged bitline rather than left or right (bl/br)
#Performs two checks, discharging bitline is at least 10% away from vdd and there is a # Performs two checks, discharging bitline is at least 10% away from vdd and there is a
#10% vdd difference between the bitlines. Both need to fail to be considered a s_en error. # 10% vdd difference between the bitlines. Both need to fail to be considered a s_en error.
min_dicharge = v_discharged_bl < self.vdd_voltage*0.9 min_dicharge = v_discharged_bl < self.vdd_voltage*0.9
min_diff = (v_charged_bl - v_discharged_bl) > self.vdd_voltage*0.1 min_diff = (v_charged_bl - v_discharged_bl) > self.vdd_voltage*0.1
@ -798,8 +802,8 @@ class delay(simulation):
leakage_power=parse_spice_list("timing", "leakage_power") leakage_power=parse_spice_list("timing", "leakage_power")
debug.check(leakage_power!="Failed","Could not measure leakage power.") debug.check(leakage_power!="Failed","Could not measure leakage power.")
debug.info(1, "Leakage power of full array is {0} mW".format(leakage_power*1e3)) debug.info(1, "Leakage power of full array is {0} mW".format(leakage_power*1e3))
#debug # debug
#sys.exit(1) # sys.exit(1)
self.write_power_stimulus(trim=True) self.write_power_stimulus(trim=True)
self.stim.run_sim() self.stim.run_sim()
@ -808,12 +812,12 @@ class delay(simulation):
debug.info(1, "Leakage power of trimmed array is {0} mW".format(trim_leakage_power*1e3)) debug.info(1, "Leakage power of trimmed array is {0} mW".format(trim_leakage_power*1e3))
# For debug, you sometimes want to inspect each simulation. # For debug, you sometimes want to inspect each simulation.
#key=raw_input("press return to continue") # key=raw_input("press return to continue")
return (leakage_power*1e3, trim_leakage_power*1e3) return (leakage_power*1e3, trim_leakage_power*1e3)
def check_valid_delays(self, result_dict): def check_valid_delays(self, result_dict):
""" Check if the measurements are defined and if they are valid. """ """ Check if the measurements are defined and if they are valid. """
#Hard coded names currently # Hard coded names currently
delay_hl = result_dict["delay_hl"] delay_hl = result_dict["delay_hl"]
delay_lh = result_dict["delay_lh"] delay_lh = result_dict["delay_lh"]
slew_hl = result_dict["slew_hl"] slew_hl = result_dict["slew_hl"]
@ -831,7 +835,7 @@ class delay(simulation):
delays_str = "delay_hl={0} delay_lh={1}".format(delay_hl, delay_lh) delays_str = "delay_hl={0} delay_lh={1}".format(delay_hl, delay_lh)
slews_str = "slew_hl={0} slew_lh={1}".format(slew_hl,slew_lh) slews_str = "slew_hl={0} slew_lh={1}".format(slew_hl,slew_lh)
half_period = self.period/2 #high-to-low delays start at neg. clk edge, so they need to be less than half_period half_period = self.period/2 # high-to-low delays start at neg. clk edge, so they need to be less than half_period
if abs(delay_hl)>half_period or abs(delay_lh)>self.period or abs(slew_hl)>half_period or abs(slew_lh)>self.period \ if abs(delay_hl)>half_period or abs(delay_lh)>self.period or abs(slew_hl)>half_period or abs(slew_lh)>self.period \
or delay_hl<0 or delay_lh<0 or slew_hl<0 or slew_lh<0: or delay_hl<0 or delay_lh<0 or slew_hl<0 or slew_lh<0:
debug.info(2,"UNsuccessful simulation (in ns):\n\t\t{0}\n\t\t{1}\n\t\t{2}".format(period_load_slew_str, debug.info(2,"UNsuccessful simulation (in ns):\n\t\t{0}\n\t\t{1}\n\t\t{2}".format(period_load_slew_str,
@ -854,15 +858,15 @@ class delay(simulation):
lb_period = 0.0 lb_period = 0.0
target_period = 0.5 * (ub_period + lb_period) target_period = 0.5 * (ub_period + lb_period)
#Find the minimum period for all ports. Start at one port and perform binary search then use that delay as a starting position. # Find the minimum period for all ports. Start at one port and perform binary search then use that delay as a starting position.
#For testing purposes, only checks read ports. # For testing purposes, only checks read ports.
for port in self.read_ports: for port in self.read_ports:
target_period = self.find_min_period_one_port(feasible_delays, port, lb_period, ub_period, target_period) target_period = self.find_min_period_one_port(feasible_delays, port, lb_period, ub_period, target_period)
#The min period of one port becomes the new lower bound. Reset the upper_bound. # The min period of one port becomes the new lower bound. Reset the upper_bound.
lb_period = target_period lb_period = target_period
ub_period = feasible_period ub_period = feasible_period
#Clear the target ports before leaving # Clear the target ports before leaving
self.targ_read_ports = [] self.targ_read_ports = []
self.targ_write_ports = [] self.targ_write_ports = []
return target_period return target_period
@ -873,10 +877,10 @@ class delay(simulation):
long period. For the current logic to characterize multiport, bounds are required as an input. long period. For the current logic to characterize multiport, bounds are required as an input.
""" """
#previous_period = ub_period = self.period # previous_period = ub_period = self.period
#ub_period = self.period # ub_period = self.period
#lb_period = 0.0 # lb_period = 0.0
#target_period = 0.5 * (ub_period + lb_period) # target_period = 0.5 * (ub_period + lb_period)
# Binary search algorithm to find the min period (max frequency) of input port # Binary search algorithm to find the min period (max frequency) of input port
time_out = 25 time_out = 25
@ -901,9 +905,9 @@ class delay(simulation):
# ub_period is always feasible. # ub_period is always feasible.
return ub_period return ub_period
#Update target # Update target
target_period = 0.5 * (ub_period + lb_period) target_period = 0.5 * (ub_period + lb_period)
#key=input("press return to continue") # key=input("press return to continue")
def try_period(self, feasible_delays): def try_period(self, feasible_delays):
@ -916,13 +920,13 @@ class delay(simulation):
if not success: if not success:
return False return False
#Check the values of target readwrite and read ports. Write ports do not produce delays in this current version # Check the values of target readwrite and read ports. Write ports do not produce delays in this current version
for port in self.targ_read_ports: for port in self.targ_read_ports:
for dname in self.delay_meas_names: #check that the delays and slews do not degrade with tested period. for dname in self.delay_meas_names: # check that the delays and slews do not degrade with tested period.
#FIXME: This is a hack solution to fix the min period search. The slew will always be based on the period when there # FIXME: This is a hack solution to fix the min period search. The slew will always be based on the period when there
#is a column mux. Therefore, the checks are skipped for this condition. This is hard to solve without changing the netlist. # is a column mux. Therefore, the checks are skipped for this condition. This is hard to solve without changing the netlist.
#Delays/slews based on the period will cause the min_period search to come to the wrong period. # Delays/slews based on the period will cause the min_period search to come to the wrong period.
if self.sram.col_addr_size>0 and "slew" in dname: if self.sram.col_addr_size>0 and "slew" in dname:
continue continue
@ -930,9 +934,9 @@ class delay(simulation):
debug.info(2,"Delay too big {0} vs {1}".format(results[port][dname],feasible_delays[port][dname])) debug.info(2,"Delay too big {0} vs {1}".format(results[port][dname],feasible_delays[port][dname]))
return False return False
#key=raw_input("press return to continue") # key=raw_input("press return to continue")
#Dynamic way to build string. A bit messy though. # Dynamic way to build string. A bit messy though.
delay_str = ', '.join("{0}={1}ns".format(mname, results[port][mname]) for mname in self.delay_meas_names) delay_str = ', '.join("{0}={1}ns".format(mname, results[port][mname]) for mname in self.delay_meas_names)
debug.info(2,"Successful period {0}, Port {2}, {1}".format(self.period, debug.info(2,"Successful period {0}, Port {2}, {1}".format(self.period,
delay_str, delay_str,
@ -994,7 +998,7 @@ class delay(simulation):
""" """
Main function to characterize an SRAM for a table. Computes both delay and power characterization. Main function to characterize an SRAM for a table. Computes both delay and power characterization.
""" """
#Dict to hold all characterization values # Dict to hold all characterization values
char_sram_data = {} char_sram_data = {}
self.analysis_init(probe_address, probe_data) self.analysis_init(probe_address, probe_data)
@ -1019,14 +1023,14 @@ class delay(simulation):
self.period = min_period self.period = min_period
char_port_data = self.simulate_loads_and_slews(slews, loads, leakage_offset) char_port_data = self.simulate_loads_and_slews(slews, loads, leakage_offset)
#FIXME: low-to-high delays are altered to be independent of the period. This makes the lib results less accurate. # FIXME: low-to-high delays are altered to be independent of the period. This makes the lib results less accurate.
self.alter_lh_char_data(char_port_data) self.alter_lh_char_data(char_port_data)
return (char_sram_data, char_port_data) return (char_sram_data, char_port_data)
def alter_lh_char_data(self, char_port_data): def alter_lh_char_data(self, char_port_data):
"""Copies high-to-low data to low-to-high data to make them consistent on the same clock edge.""" """Copies high-to-low data to low-to-high data to make them consistent on the same clock edge."""
#This is basically a hack solution which should be removed/fixed later. # This is basically a hack solution which should be removed/fixed later.
for port in self.all_ports: for port in self.all_ports:
char_port_data[port]['delay_lh'] = char_port_data[port]['delay_hl'] char_port_data[port]['delay_lh'] = char_port_data[port]['delay_hl']
char_port_data[port]['slew_lh'] = char_port_data[port]['slew_hl'] char_port_data[port]['slew_lh'] = char_port_data[port]['slew_hl']
@ -1034,7 +1038,7 @@ class delay(simulation):
def simulate_loads_and_slews(self, slews, loads, leakage_offset): def simulate_loads_and_slews(self, slews, loads, leakage_offset):
"""Simulate all specified output loads and input slews pairs of all ports""" """Simulate all specified output loads and input slews pairs of all ports"""
measure_data = self.get_empty_measure_data_dict() measure_data = self.get_empty_measure_data_dict()
#Set the target simulation ports to all available ports. This make sims slower but failed sims exit anyways. # Set the target simulation ports to all available ports. This make sims slower but failed sims exit anyways.
self.targ_read_ports = self.read_ports self.targ_read_ports = self.read_ports
self.targ_write_ports = self.write_ports self.targ_write_ports = self.write_ports
for slew in slews: for slew in slews:
@ -1044,7 +1048,7 @@ class delay(simulation):
(success, delay_results) = self.run_delay_simulation() (success, delay_results) = self.run_delay_simulation()
debug.check(success,"Couldn't run a simulation. slew={0} load={1}\n".format(self.slew,self.load)) debug.check(success,"Couldn't run a simulation. slew={0} load={1}\n".format(self.slew,self.load))
debug.info(1, "Simulation Passed: Port {0} slew={1} load={2}".format("All", self.slew,self.load)) debug.info(1, "Simulation Passed: Port {0} slew={1} load={2}".format("All", self.slew,self.load))
#The results has a dict for every port but dicts can be empty (e.g. ports were not targeted). # The results has a dict for every port but dicts can be empty (e.g. ports were not targeted).
for port in self.all_ports: for port in self.all_ports:
for mname,value in delay_results[port].items(): for mname,value in delay_results[port].items():
if "power" in mname: if "power" in mname:
@ -1056,11 +1060,11 @@ class delay(simulation):
def calculate_inverse_address(self): def calculate_inverse_address(self):
"""Determine dummy test address based on probe address and column mux size.""" """Determine dummy test address based on probe address and column mux size."""
#The inverse address needs to share the same bitlines as the probe address as the trimming will remove all other bitlines # The inverse address needs to share the same bitlines as the probe address as the trimming will remove all other bitlines
#This is only an issue when there is a column mux and the address maps to different bitlines. # This is only an issue when there is a column mux and the address maps to different bitlines.
column_addr = self.probe_address[:self.sram.col_addr_size] #do not invert this part column_addr = self.probe_address[:self.sram.col_addr_size] # do not invert this part
inverse_address = "" inverse_address = ""
for c in self.probe_address[self.sram.col_addr_size:]: #invert everything else for c in self.probe_address[self.sram.col_addr_size:]: # invert everything else
if c=="0": if c=="0":
inverse_address += "1" inverse_address += "1"
elif c=="1": elif c=="1":
@ -1133,29 +1137,31 @@ class delay(simulation):
self.measure_cycles = [{} for port in self.all_ports] self.measure_cycles = [{} for port in self.all_ports]
def create_test_cycles(self): def create_test_cycles(self):
"""Returns a list of key time-points [ns] of the waveform (each rising edge) """
Returns a list of key time-points [ns] of the waveform (each rising edge)
of the cycles to do a timing evaluation. The last time is the end of the simulation of the cycles to do a timing evaluation. The last time is the end of the simulation
and does not need a rising edge.""" and does not need a rising edge.
#Using this requires setting at least one port to target for simulation. """
# Using this requires setting at least one port to target for simulation.
if len(self.targ_write_ports) == 0 and len(self.targ_read_ports) == 0: if len(self.targ_write_ports) == 0 and len(self.targ_read_ports) == 0:
debug.error("No port selected for characterization.",1) debug.error("No port selected for characterization.",1)
self.set_stimulus_variables() self.set_stimulus_variables()
#Get any available read/write port in case only a single write or read ports is being characterized. # Get any available read/write port in case only a single write or read ports is being characterized.
cur_read_port = self.get_available_port(get_read_port=True) cur_read_port = self.get_available_port(get_read_port=True)
cur_write_port = self.get_available_port(get_read_port=False) cur_write_port = self.get_available_port(get_read_port=False)
debug.check(cur_read_port != None, "Characterizer requires at least 1 read port") debug.check(cur_read_port != None, "Characterizer requires at least 1 read port")
debug.check(cur_write_port != None, "Characterizer requires at least 1 write port") debug.check(cur_write_port != None, "Characterizer requires at least 1 write port")
#Create test cycles for specified target ports. # Create test cycles for specified target ports.
write_pos = 0 write_pos = 0
read_pos = 0 read_pos = 0
while True: while True:
#Exit when all ports have been characterized # Exit when all ports have been characterized
if write_pos >= len(self.targ_write_ports) and read_pos >= len(self.targ_read_ports): if write_pos >= len(self.targ_write_ports) and read_pos >= len(self.targ_read_ports):
break break
#Select new write and/or read ports for the next cycle. Use previous port if none remaining. # Select new write and/or read ports for the next cycle. Use previous port if none remaining.
if write_pos < len(self.targ_write_ports): if write_pos < len(self.targ_write_ports):
cur_write_port = self.targ_write_ports[write_pos] cur_write_port = self.targ_write_ports[write_pos]
write_pos+=1 write_pos+=1
@ -1163,7 +1169,7 @@ class delay(simulation):
cur_read_port = self.targ_read_ports[read_pos] cur_read_port = self.targ_read_ports[read_pos]
read_pos+=1 read_pos+=1
#Add test cycle of read/write port pair. One port could have been used already, but the other has not. # Add test cycle of read/write port pair. One port could have been used already, but the other has not.
self.gen_test_cycles_one_port(cur_read_port, cur_write_port) self.gen_test_cycles_one_port(cur_read_port, cur_write_port)
def analytical_delay(self, slews, loads): def analytical_delay(self, slews, loads):
@ -1200,10 +1206,10 @@ class delay(simulation):
def analytical_power(self, slews, loads): def analytical_power(self, slews, loads):
"""Get the dynamic and leakage power from the SRAM""" """Get the dynamic and leakage power from the SRAM"""
#slews unused, only last load is used # slews unused, only last load is used
load = loads[-1] load = loads[-1]
power = self.sram.analytical_power(self.corner, load) power = self.sram.analytical_power(self.corner, load)
#convert from nW to mW # convert from nW to mW
power.dynamic /= 1e6 power.dynamic /= 1e6
power.leakage /= 1e6 power.leakage /= 1e6
debug.info(1,"Dynamic Power: {0} mW".format(power.dynamic)) debug.info(1,"Dynamic Power: {0} mW".format(power.dynamic))
@ -1238,6 +1244,6 @@ class delay(simulation):
def get_empty_measure_data_dict(self): def get_empty_measure_data_dict(self):
"""Make a dict of lists for each type of delay and power measurement to append results to""" """Make a dict of lists for each type of delay and power measurement to append results to"""
measure_names = self.delay_meas_names + self.power_meas_names measure_names = self.delay_meas_names + self.power_meas_names
#Create list of dicts. List lengths is # of ports. Each dict maps the measurement names to lists. # Create list of dicts. List lengths is # of ports. Each dict maps the measurement names to lists.
measure_data = [{mname:[] for mname in measure_names} for i in self.all_ports] measure_data = [{mname:[] for mname in measure_names} for i in self.all_ports]
return measure_data return measure_data

View File

@ -0,0 +1,15 @@
# See LICENSE for licensing information.
#
# Copyright (c) 2016-2019 Regents of the University of California and The Board
# of Regents for the Oklahoma Agricultural and Mechanical College
# (acting for and on behalf of Oklahoma State University)
# All rights reserved.
#
from enum import Enum
class sram_op(Enum):
READ_ZERO = 0
READ_ONE = 1
WRITE_ZERO = 2
WRITE_ONE = 3

View File

@ -77,14 +77,14 @@ class bank(design.design):
""" Adding pins for Bank module""" """ Adding pins for Bank module"""
for port in self.read_ports: for port in self.read_ports:
for bit in range(self.word_size): for bit in range(self.word_size):
self.add_pin("dout{0}_{1}".format(port,bit),"OUT") self.add_pin("dout{0}_{1}".format(port,bit),"OUTPUT")
for port in self.read_ports: for port in self.read_ports:
self.add_pin(self.bitcell_array.get_rbl_bl_name(self.port_rbl_map[port]),"OUT") self.add_pin(self.bitcell_array.get_rbl_bl_name(self.port_rbl_map[port]),"OUTPUT")
for port in self.read_ports: for port in self.read_ports:
self.add_pin(self.bitcell_array.get_rbl_wl_name(self.port_rbl_map[port]),"IN") self.add_pin(self.bitcell_array.get_rbl_wl_name(self.port_rbl_map[port]),"INPUT")
for port in self.write_ports: for port in self.write_ports:
for bit in range(self.word_size): for bit in range(self.word_size):
self.add_pin("din{0}_{1}".format(port,bit),"IN") self.add_pin("din{0}_{1}".format(port,bit),"INPUT")
# if (self.word_size != self.write_size): # if (self.word_size != self.write_size):
# for bit in range(self.word_size): # for bit in range(self.word_size):
# self.add_pin() # self.add_pin()

View File

@ -84,7 +84,7 @@ class options(optparse.Values):
# This determines whether LVS and DRC is checked for every submodule. # This determines whether LVS and DRC is checked for every submodule.
inline_lvsdrc = False inline_lvsdrc = False
# Remove noncritical memory cells for characterization speed-up # Remove noncritical memory cells for characterization speed-up
trim_netlist = True trim_netlist = False
# Run with extracted parasitics # Run with extracted parasitics
use_pex = False use_pex = False