From 841532a52fcc328d9559f281b70b6d8792c188df Mon Sep 17 00:00:00 2001 From: Matt Guthaus Date: Wed, 23 Nov 2016 17:18:48 -0800 Subject: [PATCH] Change characterizer to be one data structure. Add approximate diff for lib file. --- compiler/characterizer/delay.py | 10 +-- compiler/characterizer/lib.py | 16 ++-- compiler/tests/23_lib_sram_test.py | 5 +- .../tests/golden/sram_2_16_1_freepdk45.lib | 24 +++--- compiler/tests/testutils.py | 74 ++++++++++++++++++- 5 files changed, 102 insertions(+), 27 deletions(-) diff --git a/compiler/characterizer/delay.py b/compiler/characterizer/delay.py index 690c9645..dbebb860 100644 --- a/compiler/characterizer/delay.py +++ b/compiler/characterizer/delay.py @@ -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)) read_power=ch.convert_to_float(ch.parse_output("timing", "power_read")) write_power=ch.convert_to_float(ch.parse_output("timing", "power_write")) + data = {"min_period1": min_period1, # period in ns "delay1": delay1, # delay in s "min_period0": min_period0, - "delay0": delay0 + "delay0": delay0, + "read_power": read_power, + "write_power": write_power } - power = {"Read_Power": read_power, - "Write_Power": write_power - } - return data, power + return data def obtain_cycle_times(self, slow_period, fast_period): diff --git a/compiler/characterizer/lib.py b/compiler/characterizer/lib.py index ec7ebc3e..bb7310ce 100644 --- a/compiler/characterizer/lib.py +++ b/compiler/characterizer/lib.py @@ -61,12 +61,14 @@ class lib: probe_address = "1" * self.addr_size 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(): + if i == "read_power" or i == "write_power": + continue 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_control_pins(times) 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.""" self.lib.write(" bus(DATA){\n") self.lib.write(" bus_type : DATA; \n") @@ -217,10 +219,10 @@ class lib: self.lib.write(" internal_power(){\n") self.lib.write(" when : \"OEb & !clk\"; \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(" 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.write_timing(times) @@ -231,10 +233,10 @@ class lib: self.lib.write(" internal_power(){\n") self.lib.write(" when : \"!OEb & !clk\"; \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(" 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(" timing(){ \n") diff --git a/compiler/tests/23_lib_sram_test.py b/compiler/tests/23_lib_sram_test.py index 6ad3041a..d132f906 100644 --- a/compiler/tests/23_lib_sram_test.py +++ b/compiler/tests/23_lib_sram_test.py @@ -4,7 +4,7 @@ Check the .lib file for an SRAM """ import unittest -from testutils import header,isdiff +from testutils import header,isapproxdiff import sys,os sys.path.append(os.path.join(sys.path[0],"..")) import globals @@ -40,7 +40,8 @@ class lib_test(unittest.TestCase): # let's diff the result with a golden model 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)) diff --git a/compiler/tests/golden/sram_2_16_1_freepdk45.lib b/compiler/tests/golden/sram_2_16_1_freepdk45.lib index 35a4f2d7..3a82b4eb 100644 --- a/compiler/tests/golden/sram_2_16_1_freepdk45.lib +++ b/compiler/tests/golden/sram_2_16_1_freepdk45.lib @@ -124,10 +124,10 @@ cell (sram_2_16_1_freepdk45){ internal_power(){ when : "OEb & !clk"; rise_power(INPUT_BY_TRANS_FOR_SIGNAL){ - values("0.6942568"); + values("0.66109"); } fall_power(INPUT_BY_TRANS_FOR_SIGNAL){ - values("0.6942568"); + values("0.66109"); } } timing(){ @@ -156,10 +156,10 @@ cell (sram_2_16_1_freepdk45){ internal_power(){ when : "!OEb & !clk"; rise_power(INPUT_BY_TRANS_FOR_SIGNAL){ - values("0.0290396"); + values("0.027754"); } fall_power(INPUT_BY_TRANS_FOR_SIGNAL){ - values("0.0290396"); + values("0.027754"); } } timing(){ @@ -167,16 +167,16 @@ cell (sram_2_16_1_freepdk45){ related_pin : "clk"; timing_type : rising_edge; cell_rise(CELL_UP_FOR_CLOCK) { - values("0.061"); + values("0.042"); } cell_fall(CELL_DN_FOR_CLOCK) { - values("0.24"); + values("0.241"); } rise_transition(TRAN) { - values("0.061"); + values("0.042"); } fall_transition(TRAN) { - values("0.24"); + values("0.241"); } } } @@ -294,20 +294,20 @@ cell (sram_2_16_1_freepdk45){ timing_type :"min_pulse_width"; related_pin : clk; rise_constraint(CLK_TRAN) { - values("0.1745"); + values("0.174"); } fall_constraint(CLK_TRAN) { - values("0.1745"); + values("0.174"); } } timing(){ timing_type :"minimum_period"; related_pin : clk; rise_constraint(CLK_TRAN) { - values("0.349"); + values("0.348"); } fall_constraint(CLK_TRAN) { - values("0.349"); + values("0.348"); } } } diff --git a/compiler/tests/testutils.py b/compiler/tests/testutils.py index 7b8e2cc6..c4e47c9e 100644 --- a/compiler/tests/testutils.py +++ b/compiler/tests/testutils.py @@ -1,5 +1,4 @@ - def isclose(value1,value2,error_tolerance=1e-2): """ This is used to compare relative values. """ 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)) 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): """ This is used to compare two files and display the diff if they are different.. """ import debug