Change characterizer to be one data structure. Add approximate diff for lib file.

This commit is contained in:
Matt Guthaus 2016-11-23 17:18:48 -08:00
parent 233acc3fcc
commit 841532a52f
5 changed files with 102 additions and 27 deletions

View File

@ -386,15 +386,15 @@ class delay():
debug.info(1, "Min Period for high_to_low transistion: {0}n with a delay of {1}".format(min_period0, delay0)) debug.info(1, "Min Period for high_to_low transistion: {0}n with a delay of {1}".format(min_period0, delay0))
read_power=ch.convert_to_float(ch.parse_output("timing", "power_read")) read_power=ch.convert_to_float(ch.parse_output("timing", "power_read"))
write_power=ch.convert_to_float(ch.parse_output("timing", "power_write")) write_power=ch.convert_to_float(ch.parse_output("timing", "power_write"))
data = {"min_period1": min_period1, # period in ns data = {"min_period1": min_period1, # period in ns
"delay1": delay1, # delay in s "delay1": delay1, # delay in s
"min_period0": min_period0, "min_period0": min_period0,
"delay0": delay0 "delay0": delay0,
"read_power": read_power,
"write_power": write_power
} }
power = {"Read_Power": read_power, return data
"Write_Power": write_power
}
return data, power
def obtain_cycle_times(self, slow_period, fast_period): def obtain_cycle_times(self, slow_period, fast_period):

View File

@ -61,12 +61,14 @@ class lib:
probe_address = "1" * self.addr_size probe_address = "1" * self.addr_size
probe_data = self.word_size - 1 probe_data = self.word_size - 1
data , power = self.d.analyze(probe_address, probe_data) data = self.d.analyze(probe_address, probe_data)
for i in data.keys(): for i in data.keys():
if i == "read_power" or i == "write_power":
continue
data[i] = ch.round_time(data[i]) data[i] = ch.round_time(data[i])
self.write_data_bus(data, power, times) self.write_data_bus(data, times)
self.write_addr_bus(times) self.write_addr_bus(times)
self.write_control_pins(times) self.write_control_pins(times)
self.write_clk(data) self.write_clk(data)
@ -199,7 +201,7 @@ class lib:
def write_data_bus(self, data, power, times): def write_data_bus(self, data, times):
""" Adds data bus timing results.""" """ Adds data bus timing results."""
self.lib.write(" bus(DATA){\n") self.lib.write(" bus(DATA){\n")
self.lib.write(" bus_type : DATA; \n") self.lib.write(" bus_type : DATA; \n")
@ -217,10 +219,10 @@ class lib:
self.lib.write(" internal_power(){\n") self.lib.write(" internal_power(){\n")
self.lib.write(" when : \"OEb & !clk\"; \n") self.lib.write(" when : \"OEb & !clk\"; \n")
self.lib.write(" rise_power(INPUT_BY_TRANS_FOR_SIGNAL){\n") self.lib.write(" rise_power(INPUT_BY_TRANS_FOR_SIGNAL){\n")
self.lib.write(" values(\"{0}\");\n".format(power["Write_Power"]* 1e3)) self.lib.write(" values(\"{0}\");\n".format(data["write_power"]* 1e3))
self.lib.write(" }\n") self.lib.write(" }\n")
self.lib.write(" fall_power(INPUT_BY_TRANS_FOR_SIGNAL){\n") self.lib.write(" fall_power(INPUT_BY_TRANS_FOR_SIGNAL){\n")
self.lib.write(" values(\"{0}\");\n".format(power["Write_Power"]* 1e3)) self.lib.write(" values(\"{0}\");\n".format(data["write_power"]* 1e3))
self.lib.write(" }\n") self.lib.write(" }\n")
self.lib.write(" }\n") self.lib.write(" }\n")
self.write_timing(times) self.write_timing(times)
@ -231,10 +233,10 @@ class lib:
self.lib.write(" internal_power(){\n") self.lib.write(" internal_power(){\n")
self.lib.write(" when : \"!OEb & !clk\"; \n") self.lib.write(" when : \"!OEb & !clk\"; \n")
self.lib.write(" rise_power(INPUT_BY_TRANS_FOR_SIGNAL){\n") self.lib.write(" rise_power(INPUT_BY_TRANS_FOR_SIGNAL){\n")
self.lib.write(" values(\"{0}\");\n".format(power["Read_Power"]* 1e3)) self.lib.write(" values(\"{0}\");\n".format(data["read_power"]* 1e3))
self.lib.write(" }\n") self.lib.write(" }\n")
self.lib.write(" fall_power(INPUT_BY_TRANS_FOR_SIGNAL){\n") self.lib.write(" fall_power(INPUT_BY_TRANS_FOR_SIGNAL){\n")
self.lib.write(" values(\"{0}\");\n".format(power["Read_Power"]* 1e3)) self.lib.write(" values(\"{0}\");\n".format(data["read_power"]* 1e3))
self.lib.write(" }\n") self.lib.write(" }\n")
self.lib.write(" }\n") self.lib.write(" }\n")
self.lib.write(" timing(){ \n") self.lib.write(" timing(){ \n")

View File

@ -4,7 +4,7 @@ Check the .lib file for an SRAM
""" """
import unittest import unittest
from testutils import header,isdiff from testutils import header,isapproxdiff
import sys,os import sys,os
sys.path.append(os.path.join(sys.path[0],"..")) sys.path.append(os.path.join(sys.path[0],".."))
import globals import globals
@ -40,7 +40,8 @@ class lib_test(unittest.TestCase):
# let's diff the result with a golden model # let's diff the result with a golden model
golden = "{0}/golden/{1}".format(os.path.dirname(os.path.realpath(__file__)),filename) golden = "{0}/golden/{1}".format(os.path.dirname(os.path.realpath(__file__)),filename)
self.assertEqual(isdiff(libname,golden),True) # Randomly decided 10% difference between spice simulators is ok.
self.assertEqual(isapproxdiff(libname,golden,0.10),True)
os.system("rm {0}".format(libname)) os.system("rm {0}".format(libname))

View File

@ -124,10 +124,10 @@ cell (sram_2_16_1_freepdk45){
internal_power(){ internal_power(){
when : "OEb & !clk"; when : "OEb & !clk";
rise_power(INPUT_BY_TRANS_FOR_SIGNAL){ rise_power(INPUT_BY_TRANS_FOR_SIGNAL){
values("0.6942568"); values("0.66109");
} }
fall_power(INPUT_BY_TRANS_FOR_SIGNAL){ fall_power(INPUT_BY_TRANS_FOR_SIGNAL){
values("0.6942568"); values("0.66109");
} }
} }
timing(){ timing(){
@ -156,10 +156,10 @@ cell (sram_2_16_1_freepdk45){
internal_power(){ internal_power(){
when : "!OEb & !clk"; when : "!OEb & !clk";
rise_power(INPUT_BY_TRANS_FOR_SIGNAL){ rise_power(INPUT_BY_TRANS_FOR_SIGNAL){
values("0.0290396"); values("0.027754");
} }
fall_power(INPUT_BY_TRANS_FOR_SIGNAL){ fall_power(INPUT_BY_TRANS_FOR_SIGNAL){
values("0.0290396"); values("0.027754");
} }
} }
timing(){ timing(){
@ -167,16 +167,16 @@ cell (sram_2_16_1_freepdk45){
related_pin : "clk"; related_pin : "clk";
timing_type : rising_edge; timing_type : rising_edge;
cell_rise(CELL_UP_FOR_CLOCK) { cell_rise(CELL_UP_FOR_CLOCK) {
values("0.061"); values("0.042");
} }
cell_fall(CELL_DN_FOR_CLOCK) { cell_fall(CELL_DN_FOR_CLOCK) {
values("0.24"); values("0.241");
} }
rise_transition(TRAN) { rise_transition(TRAN) {
values("0.061"); values("0.042");
} }
fall_transition(TRAN) { fall_transition(TRAN) {
values("0.24"); values("0.241");
} }
} }
} }
@ -294,20 +294,20 @@ cell (sram_2_16_1_freepdk45){
timing_type :"min_pulse_width"; timing_type :"min_pulse_width";
related_pin : clk; related_pin : clk;
rise_constraint(CLK_TRAN) { rise_constraint(CLK_TRAN) {
values("0.1745"); values("0.174");
} }
fall_constraint(CLK_TRAN) { fall_constraint(CLK_TRAN) {
values("0.1745"); values("0.174");
} }
} }
timing(){ timing(){
timing_type :"minimum_period"; timing_type :"minimum_period";
related_pin : clk; related_pin : clk;
rise_constraint(CLK_TRAN) { rise_constraint(CLK_TRAN) {
values("0.349"); values("0.348");
} }
fall_constraint(CLK_TRAN) { fall_constraint(CLK_TRAN) {
values("0.349"); values("0.348");
} }
} }
} }

View File

@ -1,5 +1,4 @@
def isclose(value1,value2,error_tolerance=1e-2): def isclose(value1,value2,error_tolerance=1e-2):
""" This is used to compare relative values. """ """ This is used to compare relative values. """
import debug import debug
@ -11,6 +10,79 @@ def isclose(value1,value2,error_tolerance=1e-2):
debug.info(2,"CLOSE {0} {1} relative diff={2}".format(value1,value2,relative_diff)) debug.info(2,"CLOSE {0} {1} relative diff={2}".format(value1,value2,relative_diff))
return (check) return (check)
def relative_compare(value1,value2,error_tolerance):
""" This is used to compare relative values. """
if (value1==value2): # if we don't need a relative comparison!
return True
return (abs(value1 - value2) / max(value1,value2) <= error_tolerance)
def isapproxdiff(f1, f2, error_tolerance=0.001):
"""Compare two files.
Arguments:
f1 -- First file name
f2 -- Second file name
Return value:
True if the files are the same, False otherwise.
"""
import re
import debug
with open(f1, 'rb') as fp1, open(f2, 'rb') as fp2:
while True:
b1 = fp1.readline()
b2 = fp2.readline()
#print "b1:",b1,
#print "b2:",b2,
# 1. Find all of the floats using a regex
numeric_const_pattern = r"""
[-+]? # optional sign
(?:
(?: \d* \. \d+ ) # .1 .12 .123 etc 9.1 etc 98.1 etc
|
(?: \d+ \.? ) # 1. 12. 123. etc 1 12 123 etc
)
# followed by optional exponent part if desired
(?: [Ee] [+-]? \d+ ) ?
"""
rx = re.compile(numeric_const_pattern, re.VERBOSE)
b1_floats=rx.findall(b1)
b2_floats=rx.findall(b2)
debug.info(3,"b1_floats: "+str(b1_floats))
debug.info(3,"b2_floats: "+str(b2_floats))
# 2. Remove the floats from the string
for f in b1_floats:
b1=b1.replace(str(f),"")
for f in b2_floats:
b2=b2.replace(str(f),"")
#print "b1:",b1,
#print "b2:",b2,
# 3. Check if remaining string matches
if b1 != b2:
debug.info(2,"Line: {0}\n!=\nLine: {1}".format(b1,b2))
return False
# 4. Now compare that the floats match
if len(b1_floats)!=len(b2_floats):
debug.info(2,"Len {0} != {1}".format(len(b1_floats),len(b2_floats)))
return False
for (f1,f2) in zip(b1_floats,b2_floats):
if not relative_compare(float(f1),float(f2),error_tolerance):
debug.info(2, "Float {0} != {1}".format(f1,f2))
return False
if not b1:
return True
def isdiff(file1,file2): def isdiff(file1,file2):
""" This is used to compare two files and display the diff if they are different.. """ """ This is used to compare two files and display the diff if they are different.. """
import debug import debug