Replaced delay measure statement with object implementation.

This commit is contained in:
Hunter Nichols 2018-12-19 18:33:06 -08:00
parent 8eb4812e16
commit b10ef3fb7e
3 changed files with 121 additions and 3 deletions

View File

@ -9,6 +9,7 @@ from .functional import *
from .worst_case import *
from .simulation import *
from .bitline_delay import *
from .measurements import *
debug.info(1,"Initializing characterizer...")
OPTS.spice_exe = ""

View File

@ -8,6 +8,7 @@ from .charutils import *
import utils
from globals import OPTS
from .simulation import simulation
from .measurements import *
class delay(simulation):
"""Functions to measure the delay and power of an SRAM at a given address and
@ -45,6 +46,16 @@ class delay(simulation):
#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.power_meas_names = ["read0_power", "read1_power", "write0_power", "write1_power"]
def create_measurement_objects(self):
self.meas_objs = []
trig_delay_name = "clk{0}"
targ_name = "{0}{1}_{2}".format(self.dout_name,"{}",self.probe_data) #Empty values are the port and probe data bit
self.meas_objs.append(delay_measure("delay_lh{}", trig_delay_name, targ_name, "RISE", "RISE"))
self.meas_objs.append(delay_measure("delay_hl{}", trig_delay_name, targ_name, "FALL", "FALL"))
self.meas_objs.append(slew_measure("slew_lh{}", targ_name, "RISE"))
self.meas_objs.append(slew_measure("slew_hl{}", targ_name, "FALL"))
def create_signal_names(self):
self.addr_name = "A"
@ -235,15 +246,28 @@ class delay(simulation):
else:
debug.error(1, "Measure command {0} not recognized".format(delay_name))
return (meas_name,trig_name,targ_name,trig_val,targ_val,trig_dir,targ_dir,trig_td,targ_td)
def get_measure_variants(self, port, measure_obj):
"""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
#vdd is arguably constant as that is true for a single lib file.
if measure_obj.targ_dir_str == "FALL":
meas_cycle_delay = self.cycle_times[self.measure_cycles[port]["read0"]]
elif measure_obj.targ_dir_str == "RISE":
meas_cycle_delay = self.cycle_times[self.measure_cycles[port]["read1"]]
else:
debug.error("Unrecognised measurement direction={}".format(measure_obj.targ_dir_str),1)
return (meas_cycle_delay, meas_cycle_delay, self.vdd_voltage, port)
def write_delay_measures_read_port(self, port):
"""
Write the measure statements to quantify the delay and power results for a read port.
"""
# add measure statements for delays/slews
for dname in self.delay_meas_names:
meas_values = self.get_delay_meas_values(dname, port)
self.stim.gen_meas_delay(*meas_values)
for measure in self.meas_objs:
measure_variant_tuple = self.get_measure_variants(port, measure)
measure.write_measure(self.stim, measure_variant_tuple)
# add measure statements for power
for pname in self.power_meas_names:
@ -645,6 +669,7 @@ class delay(simulation):
char_sram_data = {}
self.set_probe(probe_address, probe_data)
self.create_measurement_objects()
self.load=max(loads)
self.slew=max(slews)

View File

@ -0,0 +1,92 @@
import debug
from tech import drc, parameter, spice
from abc import ABC, abstractmethod
from .stimuli import *
class spice_measurement(ABC):
"""Base class for spice stimulus measurements."""
def __init__(self, measure_name):
#Names must be unique for correct spice simulation, but not enforced here.
self.name = measure_name
@abstractmethod
def get_measure_function(self):
return None
@abstractmethod
def get_measure_values(self):
return None
def write_measure(self, stim_obj, input_tuple):
measure_func = self.get_measure_function()
if measure_func == None:
debug.error("Did not set measure function",1)
measure_vals = self.get_measure_values(*input_tuple)
measure_func(stim_obj, *measure_vals)
class delay_measure(spice_measurement):
"""Generates a spice measurement for the delay of 50%-to-50% points of two signals."""
def __init__(self, measure_name, trig_name, targ_name, trig_dir_str, targ_dir_str):
spice_measurement.__init__(self, measure_name)
self.set_meas_constants(trig_name, targ_name, trig_dir_str, targ_dir_str)
def get_measure_function(self):
return stimuli.gen_meas_delay
def set_meas_constants(self, trig_name, targ_name, trig_dir_str, targ_dir_str):
"""Set the values needed to generate a Spice measurement statement based on the name of the measurement."""
self.trig_dir_str = trig_dir_str
self.targ_dir_str = targ_dir_str
self.trig_val_of_vdd = 0.5
self.targ_val_of_vdd = 0.5
self.trig_name_no_port = trig_name
self.targ_name_no_port = targ_name
#Time delays and ports are variant and needed as inputs when writing the measurement
def get_measure_values(self, trig_td, targ_td, vdd_voltage, port=None):
"""Constructs inputs to stimulus measurement function. Variant values are inputs here."""
trig_val = self.trig_val_of_vdd * vdd_voltage
targ_val = self.targ_val_of_vdd * vdd_voltage
if port != None:
meas_name = self.name.format(port)
trig_name = self.trig_name_no_port.format(port)
targ_name = self.targ_name_no_port.format(port)
else:
meas_name = self.name
trig_name = self.trig_name_no_port
targ_name = self.targ_name_no_port
return (meas_name,trig_name,targ_name,trig_val,targ_val,self.trig_dir_str,self.targ_dir_str,trig_td,targ_td)
class slew_measure(delay_measure):
def __init__(self, measure_name, signal_name, slew_dir_str):
spice_measurement.__init__(self, measure_name)
self.set_meas_constants(signal_name, slew_dir_str)
def set_meas_constants(self, signal_name, slew_dir_str):
"""Set the values needed to generate a Spice measurement statement based on the name of the measurement."""
self.trig_dir_str = slew_dir_str
self.targ_dir_str = slew_dir_str
if slew_dir_str == "RISE":
self.trig_val_of_vdd = 0.1
self.targ_val_of_vdd = 0.9
elif slew_dir_str == "FALL":
self.trig_val_of_vdd = 0.9
self.targ_val_of_vdd = 0.1
else:
debug.error("Unrecognised slew measurement direction={}".format(slew_dir_str),1)
self.trig_name_no_port = signal_name
self.targ_name_no_port = signal_name
#Time delays and ports are variant and needed as inputs when writing the measurement