From b32c123dab8e3928801bed6f6f59473b7b6a86f1 Mon Sep 17 00:00:00 2001 From: mrg Date: Thu, 1 Oct 2020 11:10:18 -0700 Subject: [PATCH] PEP8 cleanup. Un-hard-code bitcell layers. Remove dead variable. --- compiler/characterizer/simulation.py | 35 ++- compiler/sram/sram.py | 4 +- compiler/sram/sram_base.py | 70 +++-- compiler/tests/26_hspice_pex_pinv_test.py | 78 ++--- compiler/tests/26_ngspice_pex_pinv_test.py | 69 +++-- compiler/tests/26_pex_test.py | 319 --------------------- compiler/verify/magic.py | 66 ++--- 7 files changed, 168 insertions(+), 473 deletions(-) delete mode 100755 compiler/tests/26_pex_test.py diff --git a/compiler/characterizer/simulation.py b/compiler/characterizer/simulation.py index 4f045c82..ecb9adb8 100644 --- a/compiler/characterizer/simulation.py +++ b/compiler/characterizer/simulation.py @@ -51,23 +51,21 @@ class simulation(): self.load = tech.spice["dff_in_cap"] * 4 self.v_high = self.vdd_voltage - tech.spice["nom_threshold"] - self.v_low = tech.spice["nom_threshold"] + self.v_low = tech.spice["nom_threshold"] self.gnd_voltage = 0 def create_signal_names(self): self.addr_name = "a" self.din_name = "din" self.dout_name = "dout" - self.pins = self.gen_pin_names(port_signal_names=(self.addr_name,self.din_name,self.dout_name), - port_info=(len(self.all_ports),self.write_ports,self.read_ports), + self.pins = self.gen_pin_names(port_signal_names=(self.addr_name, self.din_name, self.dout_name), + port_info=(len(self.all_ports), self.write_ports, self.read_ports), abits=self.addr_size, dbits=self.word_size + self.num_spare_cols) debug.check(len(self.sram.pins) == len(self.pins), "Number of pins generated for characterization \ do not match pins of SRAM\nsram.pins = {0}\npin_names = {1}".format(self.sram.pins, - self.pins)) - #This is TODO once multiport control has been finalized. - #self.control_name = "CSB" + self.pins)) def set_stimulus_variables(self): # Clock signals @@ -96,7 +94,7 @@ class simulation(): def add_control_one_port(self, port, op): """Appends control signals for operation to a given port""" - #Determine values to write to port + # Determine values to write to port web_val = 1 csb_val = 1 if op == "read": @@ -406,7 +404,9 @@ class simulation(): return pin_names 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 # for testing. @@ -417,7 +417,9 @@ class simulation(): self.sram.bank.bitcell_array.graph_exclude_replica_col_bits() def set_internal_spice_names(self): - """Sets important names for characterization such as Sense amp enable and internal bit nets.""" + """ + Sets important names for characterization such as Sense amp enable and internal bit nets. + """ port = self.read_ports[0] if not OPTS.use_pex: @@ -458,11 +460,10 @@ class simulation(): self.sen_name = self.get_sen_name(self.graph.all_paths) debug.info(2, "s_en name = {}".format(self.sen_name)) - self.bl_name = "bl{0}_{1}".format(port, OPTS.word_size - 1) self.br_name = "br{0}_{1}".format(port, OPTS.word_size - 1) - debug.info(2, "bl name={}, br name={}".format(self.bl_name, self.br_name)) + debug.info(2, "bl name={}, br name={}".format(self.bl_name, self.br_name)) def get_sen_name(self, paths, assumed_port=None): """ @@ -481,7 +482,9 @@ class simulation(): return sen_name 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.clear_exclude_bits() # Removes previous bit exclusions self.sram.graph_exclude_bits(self.wordline_row, self.bitline_column) @@ -492,7 +495,9 @@ class simulation(): self.sram.build_graph(self.graph, self.sram_instance_name, self.pins) 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 # so it makes the search awkward @@ -519,7 +524,9 @@ class simulation(): return path_net_name def get_bl_name(self, paths, port): - """Gets the signal name associated with the bitlines in the bank.""" + """ + Gets the signal name associated with the bitlines in the bank. + """ cell_mod = factory.create(module_type=OPTS.bitcell) cell_bl = cell_mod.get_bl_name(port) diff --git a/compiler/sram/sram.py b/compiler/sram/sram.py index 6b5d117d..992919f0 100644 --- a/compiler/sram/sram.py +++ b/compiler/sram/sram.py @@ -67,7 +67,7 @@ class sram(): """Dump config file with all options. Include defaults and anything changed by input config.""" f = open(name, "w") - var_dict = dict((name, getattr(OPTS, name)) for name in dir(OPTS) if not name.startswith('__') and not callable(getattr(OPTS, name))) + var_dict = dict((name, getattr(OPTS, name)) for name in dir(OPTS) if not name.startswith('__') and not callable(getattr(OPTS, name))) for var_name, var_value in var_dict.items(): if isinstance(var_value, str): f.write(str(var_name) + " = " + "\"" + str(var_value) + "\"\n") @@ -156,4 +156,4 @@ class sram(): oname = OPTS.output_path + OPTS.output_name + "_extended.py" debug.print_raw("Extended Config: Writing to {0}".format(oname)) self.extended_config_write(oname) - print_time("Extended Config", datetime.datetime.now(), start_time) \ No newline at end of file + print_time("Extended Config", datetime.datetime.now(), start_time) diff --git a/compiler/sram/sram_base.py b/compiler/sram/sram_base.py index d18e1366..5f02ce56 100644 --- a/compiler/sram/sram_base.py +++ b/compiler/sram/sram_base.py @@ -15,9 +15,6 @@ from design import design from verilog import verilog from lef import lef from sram_factory import factory -from tech import drc -import numpy as np -import logical_effort class sram_base(design, verilog, lef): @@ -43,9 +40,6 @@ class sram_base(design, verilog, lef): if not self.num_spare_cols: self.num_spare_cols = 0 - # For logical effort delay calculations. - self.all_mods_except_control_done = False - def add_pins(self): """ Add pins for entire SRAM. """ @@ -87,14 +81,16 @@ class sram_base(design, verilog, lef): for bit in range(self.word_size + self.num_spare_cols): self.add_pin("dout{0}[{1}]".format(port, bit), "OUTPUT") - self.add_pin("vdd","POWER") - self.add_pin("gnd","GROUND") + self.add_pin("vdd", "POWER") + self.add_pin("gnd", "GROUND") def add_global_pex_labels(self): """ Add pex labels at the sram level for spice analysis """ + + # add pex labels for bitcells for bank_num in range(len(self.bank_insts)): bank = self.bank_insts[bank_num] @@ -111,47 +107,62 @@ class sram_base(design, verilog, lef): bl = [] br = [] - storage_layer_name = "m1" - bitline_layer_name = "m2" + storage_layer_name = self.bitcell.get_pin("Q").layer + bitline_layer_name = self.bitcell.get_pin("bl").layer for cell in range(len(bank_offset)): - Q = [bank_offset[cell][0] + Q_offset[cell][0], bank_offset[cell][1] + Q_offset[cell][1]] - Q_bar = [bank_offset[cell][0] + Q_bar_offset[cell][0], bank_offset[cell][1] + Q_bar_offset[cell][1]] + Q = [bank_offset[cell][0] + Q_offset[cell][0], + bank_offset[cell][1] + Q_offset[cell][1]] + Q_bar = [bank_offset[cell][0] + Q_bar_offset[cell][0], + bank_offset[cell][1] + Q_bar_offset[cell][1]] OPTS.words_per_row = self.words_per_row - self.add_layout_pin_rect_center("bitcell_Q_b{}_r{}_c{}".format(bank_num, int(cell % (OPTS.num_words / self.words_per_row)), int(cell / (OPTS.num_words))) , storage_layer_name, Q) - self.add_layout_pin_rect_center("bitcell_Q_bar_b{}_r{}_c{}".format(bank_num, int(cell % (OPTS.num_words / self.words_per_row)), int(cell / (OPTS.num_words))), storage_layer_name, Q_bar) + row = int(cell % (OPTS.num_words / self.words_per_row)) + col = int(cell / (OPTS.num_words)) + self.add_layout_pin_rect_center("bitcell_Q_b{}_r{}_c{}".format(bank_num, + row, + col), + storage_layer_name, + Q) + self.add_layout_pin_rect_center("bitcell_Q_bar_b{}_r{}_c{}".format(bank_num, + row, + col), + storage_layer_name, + Q_bar) for cell in range(len(bl_offsets)): col = bl_meta[cell][0][2] for bitline in range(len(bl_offsets[cell])): - bitline_location = [float(bank_offset[cell][0]) + bl_offsets[cell][bitline][0], float(bank_offset[cell][1]) + bl_offsets[cell][bitline][1]] + bitline_location = [float(bank_offset[cell][0]) + bl_offsets[cell][bitline][0], + float(bank_offset[cell][1]) + bl_offsets[cell][bitline][1]] bl.append([bitline_location, bl_meta[cell][bitline][3], col]) for cell in range(len(br_offsets)): col = br_meta[cell][0][2] for bitline in range(len(br_offsets[cell])): - bitline_location = [float(bank_offset[cell][0]) + br_offsets[cell][bitline][0], float(bank_offset[cell][1]) + br_offsets[cell][bitline][1]] - br.append([bitline_location, br_meta[cell][bitline][3], col]) + bitline_location = [float(bank_offset[cell][0]) + br_offsets[cell][bitline][0], + float(bank_offset[cell][1]) + br_offsets[cell][bitline][1]] + br.append([bitline_location, br_meta[cell][bitline][3], col]) for i in range(len(bl)): - self.add_layout_pin_rect_center("bl{0}_{1}".format(bl[i][1], bl[i][2]), bitline_layer_name, bl[i][0]) + self.add_layout_pin_rect_center("bl{0}_{1}".format(bl[i][1], bl[i][2]), + bitline_layer_name, bl[i][0]) for i in range(len(br)): - self.add_layout_pin_rect_center("br{0}_{1}".format(br[i][1], br[i][2]), bitline_layer_name, br[i][0]) + self.add_layout_pin_rect_center("br{0}_{1}".format(br[i][1], br[i][2]), + bitline_layer_name, br[i][0]) # add pex labels for control logic - for i in range (len(self.control_logic_insts)): + for i in range(len(self.control_logic_insts)): instance = self.control_logic_insts[i] control_logic_offset = instance.offset for output in instance.mod.output_list: pin = instance.mod.get_pin(output) - pin.transform([0,0], instance.mirror, instance.rotate) - offset = [control_logic_offset[0] + pin.center()[0], control_logic_offset[1] + pin.center()[1]] - self.add_layout_pin_rect_center("{0}{1}".format(pin.name,i), storage_layer_name, offset) - - - - + pin.transform([0, 0], instance.mirror, instance.rotate) + offset = [control_logic_offset[0] + pin.center()[0], + control_logic_offset[1] + pin.center()[1]] + self.add_layout_pin_rect_center("{0}{1}".format(pin.name, i), + storage_layer_name, + offset) def create_netlist(self): """ Netlist creation """ @@ -370,10 +381,6 @@ class sram_base(design, verilog, lef): self.bank_count = 0 - # The control logic can resize itself based on the other modules. - # Requires all other modules added before control logic. - self.all_mods_except_control_done = True - c = reload(__import__(OPTS.control_logic)) self.mod_control_logic = getattr(c, OPTS.control_logic) @@ -619,6 +626,7 @@ class sram_base(design, verilog, lef): sp.write("* Column mux: {}:1\n".format(self.words_per_row)) sp.write("**************************************************\n") # This causes unit test mismatch + # sp.write("* Created: {0}\n".format(datetime.datetime.now())) # sp.write("* User: {0}\n".format(getpass.getuser())) # sp.write(".global {0} {1}\n".format(spice["vdd_name"], diff --git a/compiler/tests/26_hspice_pex_pinv_test.py b/compiler/tests/26_hspice_pex_pinv_test.py index b4b55cdb..96b2d108 100755 --- a/compiler/tests/26_hspice_pex_pinv_test.py +++ b/compiler/tests/26_hspice_pex_pinv_test.py @@ -9,8 +9,8 @@ Run regression tests/pex test on an extracted pinv to ensure pex functionality with HSPICE. """ import unittest -from testutils import header,openram_test -import sys,os +from testutils import header, openram_test +import sys, os sys.path.append(os.path.join(sys.path[0],"..")) import globals from globals import OPTS @@ -35,43 +35,43 @@ class hspice_pex_pinv_test(openram_test): # generate the pinv prev_purge_value = OPTS.purge_temp - OPTS.purge_temp = False # force set purge to false to save the sp file + # force set purge to false to save the sp file + OPTS.purge_temp = False debug.info(2, "Checking 1x size inverter") tx = pinv.pinv(name="pinv", size=1) - tempgds = "{0}{1}.gds".format(OPTS.openram_temp,tx.name) + tempgds = "{0}{1}.gds".format(OPTS.openram_temp, tx.name) tx.gds_write(tempgds) - tempsp = "{0}{1}.sp".format(OPTS.openram_temp,tx.name) + tempsp = "{0}{1}.sp".format(OPTS.openram_temp, tx.name) tx.sp_write(tempsp) - # make sure that the library simulation is successful\ - sp_delay = self.simulate_delay(test_module = tempsp, - top_level_name = tx.name) - if sp_delay is "Failed": + # make sure that the library simulation is successful + sp_delay = self.simulate_delay(test_module=tempsp, + top_level_name=tx.name) + if sp_delay == "Failed": self.fail('Library Spice module did not behave as expected') # now generate its pex file pex_file = self.run_pex(tx) - OPTS.purge_temp = prev_purge_value # restore the old purge value + OPTS.purge_temp = prev_purge_value # restore the old purge value # generate simulation for pex, make sure the simulation is successful - pex_delay = self.simulate_delay(test_module = pex_file, - top_level_name = tx.name) + pex_delay = self.simulate_delay(test_module=pex_file, + top_level_name=tx.name) # make sure the extracted spice simulated - if pex_delay is "Failed": + if pex_delay == "Failed": self.fail('Pex file did not behave as expected') # if pex data is bigger than original spice file then result is ok # However this may not always be true depending on the netlist provided # comment out for now - #debug.info(2,"pex_delay: {0}".format(pex_delay)) - #debug.info(2,"sp_delay: {0}".format(sp_delay)) + # debug.info(2,"pex_delay: {0}".format(pex_delay)) + # debug.info(2,"sp_delay: {0}".format(sp_delay)) - #assert pex_delay > sp_delay, "pex delay {0} is smaller than sp_delay {1}"\ - #.format(pex_delay,sp_delay) + # assert pex_delay > sp_delay, "pex delay {0} is smaller than sp_delay {1}"\ + # .format(pex_delay,sp_delay) globals.end_openram() def simulate_delay(self, test_module, top_level_name): - from characterizer import charutils from charutils import parse_spice_list # setup simulation sim_file = OPTS.openram_temp + "stim.sp" @@ -87,43 +87,43 @@ class hspice_pex_pinv_test(openram_test): from characterizer import measurements, stimuli corner = (OPTS.process_corners[0], OPTS.supply_voltages[0], OPTS.temperatures[0]) sim_file = open(sim_file, "w") - simulation = stimuli(sim_file,corner) + simulation = stimuli(sim_file, corner) # library files simulation.write_include(cir_file) # supply voltages - simulation.gen_constant(sig_name ="vdd", - v_val = tech.spice["nom_supply_voltage"]) - simulation.gen_constant(sig_name = "gnd", - v_val = "0v") + simulation.gen_constant(sig_name="vdd", + v_val=tech.spice["nom_supply_voltage"]) + simulation.gen_constant(sig_name="gnd", + v_val="0v") run_time = tech.spice["feasible_period"] * 4 # input voltage clk_period = tech.spice["feasible_period"] - simulation.gen_pwl(sig_name ="input", - clk_times = [clk_period,clk_period], - data_values = [1,0], - period = clk_period, - slew = 0.001*tech.spice["feasible_period"], - setup = 0) + simulation.gen_pwl(sig_name="input", + clk_times=[clk_period, clk_period], + data_values=[1, 0], + period=clk_period, + slew=0.001 * tech.spice["feasible_period"], + setup=0) # instantiation of simulated pinv - simulation.inst_model(pins = ["input", "output", "vdd", "gnd"], - model_name = top_module_name) + simulation.inst_model(pins=["input", "output", "vdd", "gnd"], + model_name=top_module_name) # delay measurement - delay_measure = measurements.delay_measure(measure_name = "pinv_delay", - trig_name = "input", - targ_name = "output", - trig_dir_str = "FALL", - targ_dir_str = "RISE", - has_port = False) + delay_measure = measurements.delay_measure(measure_name="pinv_delay", + trig_name="input", + targ_name="output", + trig_dir_str="FALL", + targ_dir_str="RISE", + has_port=False) trig_td = trag_td = 0.01 * run_time - rest_info = trig_td,trag_td,tech.spice["nom_supply_voltage"] + rest_info = trig_td, trag_td, tech.spice["nom_supply_voltage"] delay_measure.write_measure(simulation, rest_info) - simulation.write_control(end_time = run_time) + simulation.write_control(end_time=run_time) sim_file.close() return simulation diff --git a/compiler/tests/26_ngspice_pex_pinv_test.py b/compiler/tests/26_ngspice_pex_pinv_test.py index e6e0cfb2..e5dbe5db 100755 --- a/compiler/tests/26_ngspice_pex_pinv_test.py +++ b/compiler/tests/26_ngspice_pex_pinv_test.py @@ -34,43 +34,43 @@ class ngspice_pex_pinv_test(openram_test): # generate the pinv module prev_purge_value = OPTS.purge_temp - OPTS.purge_temp = False # force set purge to false to save the sp file + OPTS.purge_temp = False # force set purge to false to save the sp file debug.info(2, "Checking 1x size inverter") tx = pinv.pinv(name="pinv", size=1) - tempgds = "{0}{1}.gds".format(OPTS.openram_temp,tx.name) + tempgds = "{0}{1}.gds".format(OPTS.openram_temp, tx.name) tx.gds_write(tempgds) - tempsp = "{0}{1}.sp".format(OPTS.openram_temp,tx.name) + tempsp = "{0}{1}.sp".format(OPTS.openram_temp, tx.name) tx.sp_write(tempsp) # make sure that the library simulation is successful - sp_delay = self.simulate_delay(test_module = tempsp, - top_level_name = tx.name) - if sp_delay is "Failed": + sp_delay = self.simulate_delay(test_module=tempsp, + top_level_name=tx.name) + if sp_delay == "Failed": self.fail('Library Spice module did not behave as expected') # now generate its pex file pex_file = self.run_pex(tx) - OPTS.purge_temp = prev_purge_value # restore the old purge value + # restore the old purge value + OPTS.purge_temp = prev_purge_value # generate simulation for pex, make sure the simulation is successful - pex_delay = self.simulate_delay(test_module = pex_file, - top_level_name = tx.name) + pex_delay = self.simulate_delay(test_module=pex_file, + top_level_name=tx.name) # make sure the extracted spice simulated - if pex_delay is "Failed": + if pex_delay == "Failed": self.fail('Pex file did not behave as expected') # if pex data is bigger than original spice file then result is ok # However this may not always be true depending on the netlist provided # comment out for now - #debug.info(2,"pex_delay: {0}".format(pex_delay)) - #debug.info(2,"sp_delay: {0}".format(sp_delay)) + # debug.info(2,"pex_delay: {0}".format(pex_delay)) + # debug.info(2,"sp_delay: {0}".format(sp_delay)) - #assert pex_delay > sp_delay, "pex delay {0} is smaller than sp_delay {1}"\ - #.format(pex_delay,sp_delay) + # assert pex_delay > sp_delay, "pex delay {0} is smaller than sp_delay {1}"\ + # .format(pex_delay,sp_delay) globals.end_openram() def simulate_delay(self, test_module, top_level_name): - from characterizer import charutils from charutils import parse_spice_list # setup simulation sim_file = OPTS.openram_temp + "stim.sp" @@ -86,47 +86,46 @@ class ngspice_pex_pinv_test(openram_test): from characterizer import measurements, stimuli corner = (OPTS.process_corners[0], OPTS.supply_voltages[0], OPTS.temperatures[0]) sim_file = open(sim_file, "w") - simulation = stimuli(sim_file,corner) + simulation = stimuli(sim_file, corner) # library files simulation.write_include(cir_file) # supply voltages - simulation.gen_constant(sig_name ="vdd", - v_val = tech.spice["nom_supply_voltage"]) + simulation.gen_constant(sig_name="vdd", + v_val=tech.spice["nom_supply_voltage"]) # The scn4m_subm and ngspice combination will have a gnd source error: # "Fatal error: instance vgnd is a shorted VSRC" # However, remove gnd power for all techa pass for this test # simulation.gen_constant(sig_name = "gnd", # v_val = "0v") - run_time = tech.spice["feasible_period"] * 4 # input voltage clk_period = tech.spice["feasible_period"] - simulation.gen_pwl(sig_name ="input", - clk_times = [clk_period,clk_period], - data_values = [1,0], - period = clk_period, - slew = 0.001*tech.spice["feasible_period"], - setup = 0) + simulation.gen_pwl(sig_name="input", + clk_times=[clk_period, clk_period], + data_values=[1, 0], + period=clk_period, + slew=0.001 * tech.spice["feasible_period"], + setup=0) # instantiation of simulated pinv - simulation.inst_model(pins = ["input", "output", "vdd", "gnd"], - model_name = top_module_name) + simulation.inst_model(pins=["input", "output", "vdd", "gnd"], + model_name=top_module_name) # delay measurement - delay_measure = measurements.delay_measure(measure_name = "pinv_delay", - trig_name = "input", - targ_name = "output", - trig_dir_str = "FALL", - targ_dir_str = "RISE", - has_port = False) + delay_measure = measurements.delay_measure(measure_name="pinv_delay", + trig_name="input", + targ_name="output", + trig_dir_str="FALL", + targ_dir_str="RISE", + has_port=False) trig_td = trag_td = 0.01 * run_time - rest_info = trig_td,trag_td,tech.spice["nom_supply_voltage"] + rest_info = trig_td, trag_td, tech.spice["nom_supply_voltage"] delay_measure.write_measure(simulation, rest_info) - simulation.write_control(end_time = run_time) + simulation.write_control(end_time=run_time) sim_file.close() return simulation diff --git a/compiler/tests/26_pex_test.py b/compiler/tests/26_pex_test.py deleted file mode 100755 index 4eff7db5..00000000 --- a/compiler/tests/26_pex_test.py +++ /dev/null @@ -1,319 +0,0 @@ -#!/usr/bin/env python3 -# 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. -# -import unittest -from testutils import * -import sys,os -sys.path.append(os.getenv("OPENRAM_HOME")) -import globals -from globals import OPTS -from sram_factory import factory -import debug - -@unittest.skip("SKIPPING 26_pex_test") -class sram_func_test(openram_test): - - def runTest(self): - config_file = "{}/tests/configs/config".format(os.getenv("OPENRAM_HOME")) - globals.init_openram(config_file) - - OPTS.use_pex = True - - # This is a hack to reload the characterizer __init__ with the spice version - from importlib import reload - import characterizer - reload(characterizer) - from characterizer import setup_hold - if not OPTS.spice_exe: - debug.error("Could not find {} simulator.".format(OPTS.spice_name),-1) - - self.func_test(bank_num=1) - self.func_test(bank_num=2) - self.func_test(bank_num=4) - - globals.end_openram() - - def func_test(self, bank_num): - - import sram - import tech - - debug.info(1, "Testing timing for sample 1bit, 16words SRAM with 1 bank") - s = sram.sram(word_size=OPTS.word_size, - num_words=OPTS.num_words, - num_banks=OPTS.num_banks, - name="test_sram1") - - tempspice = OPTS.openram_temp + "temp.sp" - tempgds = OPTS.openram_temp + "temp.gds" - - s.sp_write(tempspice) - s.gds_write(tempgds) - - self.assertFalse(verify.run_drc(s.name, tempgds)) - self.assertFalse(verify.run_lvs(s.name, tempgds, tempspice)) - self.assertFalse(verify.run_pex(s.name, tempgds, - tempspice, output=OPTS.openram_temp + "temp_pex.sp")) - - import sp_file - stimulus_file = OPTS.openram_temp + "stimulus.sp" - a_stimulus = sp_file.sp_file(stimulus_file) - self.write_stimulus(a_stimulus) - - simulator_file = OPTS.openram_temp + "simulator.sp" - a_simulator = sp_file.sp_file(simulator_file) - self.write_simulator(a_simulator) - - result_file = OPTS.openram_temp + "result" - - import os - - if OPTS.spice_name == "hspice": - cmd = "hspice -mt 2 -i {0} > {1} ".format( - simulator_file, result_file) - else: - cmd = "ngspice -b -i {0} > {1} ".format( - simulator_file, result_file) - os.system(cmd) - - import re - sp_result = open(result_file, "r") - contents = sp_result.read() - key = "vr1" - val = re.search( - r"{0}(\s*)=(\s*)(\d*(.).*)(\s*)(from)".format(key), contents) - val = val.group(3) - value1 = float(self.convert_voltage_unit(val)) - - key = "vr2" - val = re.search( - r"{0}(\s*)=(\s*)(\d*(.).*)(\s*)(from)".format(key), contents) - val = val.group(3) - value2 = float(self.convert_voltage_unit(val)) - - self.assertTrue(round(value1) > 0.5 * tech.spice["supply_voltage"]) - self.assertTrue(round(value2) < 0.5 * tech.spice["supply_voltage"]) - - - - def convert_voltage_unit(self, string): - newstring = "" - for letter in string: - if letter == "m": - letter = "10e-3" - elif letter == "u": - letter = "10e-6" - else: - letter = letter - newstring = str(newstring) + str(letter) - return newstring - - def convert_time_unit(self, string): - newstring = "" - for letter in string: - if letter == "f": - letter = "10e-15" - elif letter == "p": - letter = "10e-12" - elif letter == "n": - letter = "10e-9" - elif letter == "u": - letter = "10e-6" - elif letter == "m": - letter = "10e-3" - else: - letter = letter - newstring = str(newstring) + str(letter) - return newstring - - def write_simulator(self, sim_file): - sim_file.write("\n") - import tech - time_step = tech.spice["clock_period"] - for model in tech.spice["fet_models"]: - sim_file.write(".inc " + str(model) + "\n") - sim_file.write(".inc stimulus.sp\n") - sim_file.write(".inc temp_pex.sp\n") - sim_file.write(".options post runlvl=6\n") - sim_file.write("\n") - - sim_file.write( - "Xsource DATA[0] ADDR[0] ADDR[1] ADDR[2] ADDR[3] CSb WEb WEb_inv OEb clk vdd vss source\n") - sim_file.write( - "Xsram DATA[0] ADDR[0] ADDR[1] ADDR[2] ADDR[3] CSb WEb OEb clk vdd vss test_sram1\n") - sim_file.write("\n") - - sim_file.write(".MEASURE TRAN vr1 AVG V(DATA[0]) FROM ={0}ns TO ={1}ns\n".format( - 4.5 * tech.spice["clock_period"], 5 * tech.spice["clock_period"])) - sim_file.write(".MEASURE TRAN vr2 AVG V(DATA[0]) FROM ={0}ns TO ={1}ns\n".format( - 9.5 * tech.spice["clock_period"], 10 * tech.spice["clock_period"])) - sim_file.write("\n") - - if OPTS.spice_name in ["hspice","xa"]: - sim_file.write(".probe v(x*.*)\n") - sim_file.write(".tran 0.1ns {0}ns\n".format( - 10 * tech.spice["clock_period"])) - sim_file.write(".end\n") - else: - sim_file.write( - ".meas tran DELAY1.0 TRIG v(clk) VAL=0.5 RISE=6 TARG v(DATA[0]) VAL=0.5 TD=0.5n RISE=1\n") - sim_file.write(".tran 0.1ns {0}ns\n".format( - 10 * tech.spice["clock_period"])) - sim_file.write(".control\n") - sim_file.write("run\n") - #sim_file.write("plot CSb WEb OEb \n") - #sim_file.write("plot clk DATA0 \n") - sim_file.write("quit\n") - sim_file.write(".endc\n") - sim_file.write(".end\n") - sim_file.file.close() - - def write_stimulus(self, sti_file): - import tech - import sp_file - sti_file.write( - ".subckt source DATA[0] ADDR[0] ADDR[1] ADDR[2] ADDR[3] CSb WEb WEb_inv OEb clk vdd vss\n") - - time_step = tech.spice["clock_period"] - - clk = sp_file.PWL(name="clk", port=["clk", "0"]) - for i in range(0, 11): - clk.write_pulse(i * time_step, time_step, "UP") - clk.write_to_sp(sti_file) - - WEB_inv = sp_file.PWL(name="WEb_inv", port=["WEb_inv", "0"]) - WEB = sp_file.PWL(name="WEB", port=["WEb", "0"]) - OEb = sp_file.PWL(name="OEb", port=["OEb", "0"]) - CSb = sp_file.PWL(name="CSb", port=["CSb", "0"]) - - # write - CSb.write_pulse(0.75 * time_step, time_step, "DN") - WEB.write_pulse(0.75 * time_step, time_step, "DN") - WEB_inv.write_pulse(0.75 * time_step, time_step, "UP") - CSb.write_pulse(1.75 * time_step, time_step, "DN") - WEB.write_pulse(1.75 * time_step, time_step, "DN") - WEB_inv.write_pulse(1.75 * time_step, time_step, "UP") - - # read - OEb.write_pulse(3.75 * time_step, time_step, "DN") - CSb.write_pulse(3.75 * time_step, time_step, "DN") - - # write - CSb.write_pulse(5.75 * time_step, time_step, "DN") - WEB.write_pulse(5.75 * time_step, time_step, "DN") - WEB_inv.write_pulse(5.75 * time_step, time_step, "UP") - CSb.write_pulse(6.75 * time_step, time_step, "DN") - WEB.write_pulse(6.75 * time_step, time_step, "DN") - WEB_inv.write_pulse(6.75 * time_step, time_step, "UP") - - # read - OEb.write_pulse(8.75 * time_step, time_step, "DN") - CSb.write_pulse(8.75 * time_step, time_step, "DN") - - CSb.write_to_sp(sti_file) - WEB.write_to_sp(sti_file) - WEB_inv.write_to_sp(sti_file) - OEb.write_to_sp(sti_file) - - sti_file.write("VA[0] A[0] 0 PWL(0n {0} {1}n {0} {2}n 0 {3}n 0 {4}n {0})\n".format(tech.spice["supply_voltage"], 8.875 * tech.spice[ - "clock_period"], 13.875 * tech.spice["clock_period"], 14.5 * tech.spice["clock_period"], 14.501 * tech.spice["clock_period"])) - sti_file.write("VA[1] A[1] 0 PWL(0n {0} {1}n {0} {2}n 0 {3}n 0 {4}n {0})\n".format(tech.spice["supply_voltage"], 8.875 * tech.spice[ - "clock_period"], 13.875 * tech.spice["clock_period"], 14.5 * tech.spice["clock_period"], 14.501 * tech.spice["clock_period"])) - sti_file.write("VA[2] A[2] 0 PWL(0n {0} {1}n {0} {2}n 0 {3}n 0 {4}n {0})\n".format(tech.spice["supply_voltage"], 8.875 * tech.spice[ - "clock_period"], 13.875 * tech.spice["clock_period"], 14.5 * tech.spice["clock_period"], 14.501 * tech.spice["clock_period"])) - sti_file.write("VA[3] A[3] 0 PWL(0n {0} {1}n {0} {2}n 0 {3}n 0 {4}n {0})\n".format(tech.spice["supply_voltage"], 8.875 * tech.spice[ - "clock_period"], 13.875 * tech.spice["clock_period"], 14.5 * tech.spice["clock_period"], 14.501 * tech.spice["clock_period"])) - - sti_file.write( - "xA[0]_buff A[0] ADDR[0]_inv ADDR[0] vdd vss test_buf\n") - sti_file.write( - "xA[1]_buff A[1] ADDR[1]_inv ADDR[1] vdd vss test_buf\n") - sti_file.write( - "xA[2]_buff A[2] ADDR[2]_inv ADDR[2] vdd vss test_buf\n") - sti_file.write( - "xA[3]_buff A[3] ADDR[3]_inv ADDR[3] vdd vss test_buf\n") - - VD_0 = sp_file.PWL(name="VD[0]", port=["D[0]", "0"]) - VD_0.write_pulse(0, 5 * time_step, "S1") - VD_0.write_pulse(5 * time_step, 5 * time_step, "S0") - VD_0.write_to_sp(sti_file) - - sti_file.write( - "xD[0]_buff D[0] DATA[0]_inv DATA[0]s vdd vss test_buf\n") - sti_file.write( - "xD[0]_gate DATA[0]s WEb WEb_inv DATA[0] vdd vss tran_gate\n") - sti_file.write("mp[0]_gate_vdd vdd write_v DATA[0] vdd " + str(tech.spice["pmos"]) + - " w=" + str(2 * tech.parameter["min_tx_size"]) + "u" + - " l=" + str(tech.drc["minlength_channel"]) + "u" + - "\n") - sti_file.write("mn[0]_gate_vss vss write_g DATA[0] vss " + str(tech.spice["nmos"]) + - " w=" + str(tech.parameter["min_tx_size"]) + "u" + - " l=" + str(tech.drc["minlength_channel"]) + "u" + - "\n") - - Vwrite_v = sp_file.PWL(name="write_v", port=["write_vs", "0"]) - Vwrite_v.write_pulse(0, 0.5 * time_step, "S1") - Vwrite_v.write_pulse(7.5 * time_step, time_step, "DN") - Vwrite_v.write_to_sp(sti_file) - sti_file.write( - "xwrite_v write_vs write_v_inv write_v vdd vss test_buf\n") - - Vwrite_g = sp_file.PWL(name="write_g", port=["write_gs", "0"]) - Vwrite_g.write_pulse(0, 0.5 * time_step, "S0") - Vwrite_g.write_pulse(3 * time_step, time_step, "UP") - Vwrite_g.write_to_sp(sti_file) - sti_file.write( - "xwrite_g write_gs write_g_inv write_g vdd vss test_buf\n") - - sti_file.write("Vdd vdd 0 DC " + - str(tech.spice["supply_voltage"]) + "\n") - sti_file.write("Vvss vss 0 DC 0\n") - sti_file.write(".ENDS source\n") - sti_file.write("\n") - - sti_file.write(".SUBCKT tran_gate in gate gate_inv out vdd vss\n") - sti_file.write("mp0 in gate out vdd " + str(tech.spice["pmos"]) + - " w=" + str(2 * tech.parameter["min_tx_size"]) + "u" + - " l=" + str(tech.drc["minlength_channel"]) + "u" + - "\n") - sti_file.write("mn0 in gate_inv out vss " + str(tech.spice["nmos"]) + - " w=" + str(tech.parameter["min_tx_size"]) + "u" + - " l=" + str(tech.drc["minlength_channel"]) + "u" + - "\n") - sti_file.write(".ENDS tran_gate\n") - sti_file.write("\n") - - sti_file.write(".SUBCKT test_buf in out_inv out_buf vdd vss\n") - sti_file.write("mpinv1 out_inv in vdd vdd " + str(tech.spice["pmos"]) + - " w=" + str(2 * tech.parameter["min_tx_size"]) + "u" + - " l=" + str(tech.drc["minlength_channel"]) + "u" + - "\n") - sti_file.write("mninv1 out_inv in vss vss " + str(tech.spice["nmos"]) + - " w=" + str(tech.parameter["min_tx_size"]) + "u" + - " l=" + str(tech.drc["minlength_channel"]) + "u" + - "\n") - sti_file.write("mpinv2 out_buf out_inv vdd vdd " + str(tech.spice["pmos"]) + - " w=" + str(2 * tech.parameter["min_tx_size"]) + "u" + - " l=" + str(tech.drc["minlength_channel"]) + "u" + - "\n") - sti_file.write("mninv2 out_buf out_inv vss vss " + str(tech.spice["nmos"]) + - " w=" + str(tech.parameter["min_tx_size"]) + "u" + - " l=" + str(tech.drc["minlength_channel"]) + "u" + - "\n") - sti_file.write(".ENDS test_buf\n") - sti_file.write("\n") - - sti_file.file.close() - - -# run the test from the command line -if __name__ == "__main__": - (OPTS, args) = globals.parse_args() - del sys.argv[1:] - header(__file__, OPTS.tech_name) - unittest.main(testRunner=debugTestRunner()) diff --git a/compiler/verify/magic.py b/compiler/verify/magic.py index 2343da26..1401d834 100644 --- a/compiler/verify/magic.py +++ b/compiler/verify/magic.py @@ -295,11 +295,8 @@ def run_pex(name, gds_name, sp_name, output=None, final_verification=False): global num_pex_runs num_pex_runs += 1 - #debug.warning("PEX using magic not implemented.") - #return 1 os.chdir(OPTS.openram_temp) - from tech import drc if output == None: output = name + ".pex.netlist" @@ -312,17 +309,11 @@ def run_pex(name, gds_name, sp_name, output=None, final_verification=False): # pex_fix did run the pex using a script while dev orignial method # use batch mode. # the dev old code using batch mode does not run and is split into functions - #pex_runset = write_batch_pex_rule(gds_name,name,sp_name,output) - pex_runset = write_script_pex_rule(gds_name,name,output) + pex_runset = write_script_pex_rule(gds_name, name, output) errfile = "{0}{1}.pex.err".format(OPTS.openram_temp, name) outfile = "{0}{1}.pex.out".format(OPTS.openram_temp, name) - # bash mode command from dev branch - #batch_cmd = "{0} -gui -pex {1}pex_runset -batch 2> {2} 1> {3}".format(OPTS.pex_exe, - # OPTS.openram_temp, - # errfile, - # outfile) script_cmd = "{0} 2> {1} 1> {2}".format(pex_runset, errfile, outfile) @@ -334,8 +325,8 @@ def run_pex(name, gds_name, sp_name, output=None, final_verification=False): pex_nelist = open(output, 'r') s = pex_nelist.read() pex_nelist.close() - s = s.replace('pfet','p') - s = s.replace('nfet','n') + s = s.replace('pfet', 'p') + s = s.replace('nfet', 'n') f = open(output, 'w') f.write(s) f.close() @@ -345,12 +336,13 @@ def run_pex(name, gds_name, sp_name, output=None, final_verification=False): results = f.readlines() f.close() out_errors = find_error(results) - debug.check(os.path.isfile(output),"Couldn't find PEX extracted output.") + debug.check(os.path.isfile(output), "Couldn't find PEX extracted output.") - correct_port(name,output,sp_name) + correct_port(name, output, sp_name) return out_errors -def write_batch_pex_rule(gds_name,name,sp_name,output): + +def write_batch_pex_rule(gds_name, name, sp_name, output): """ The dev branch old batch mode runset 2. magic can perform extraction with the following: @@ -394,7 +386,8 @@ def write_batch_pex_rule(gds_name,name,sp_name,output): f.close() return file -def write_script_pex_rule(gds_name,cell_name,output): + +def write_script_pex_rule(gds_name, cell_name, output): global OPTS run_file = OPTS.openram_temp + "run_pex.sh" f = open(run_file, "w") @@ -412,23 +405,24 @@ def write_script_pex_rule(gds_name,cell_name,output): pre = "#" else: pre = "" - f.write(pre+"extract\n".format(cell_name)) - f.write(pre+"ext2spice hierarchy off\n") - f.write(pre+"ext2spice format ngspice\n") - f.write(pre+"ext2spice renumber off\n") - f.write(pre+"ext2spice scale off\n") - f.write(pre+"ext2spice blackbox on\n") - f.write(pre+"ext2spice subcircuit top on\n") - f.write(pre+"ext2spice global off\n") - f.write(pre+"ext2spice {}\n".format(cell_name)) + f.write(pre + "extract\n") + f.write(pre + "ext2spice hierarchy off\n") + f.write(pre + "ext2spice format ngspice\n") + f.write(pre + "ext2spice renumber off\n") + f.write(pre + "ext2spice scale off\n") + f.write(pre + "ext2spice blackbox on\n") + f.write(pre + "ext2spice subcircuit top on\n") + f.write(pre + "ext2spice global off\n") + f.write(pre + "ext2spice {}\n".format(cell_name)) f.write("quit -noprompt\n") f.write("eof\n") - f.write("mv {0}.spice {1}\n".format(cell_name,output)) + f.write("mv {0}.spice {1}\n".format(cell_name, output)) f.close() os.system("chmod u+x {}".format(run_file)) return run_file + def find_error(results): # Errors begin with "ERROR:" test = re.compile("ERROR:") @@ -438,6 +432,7 @@ def find_error(results): out_errors = len(stdouterrors) return out_errors + def correct_port(name, output_file_name, ref_file_name): pex_file = open(output_file_name, "r") contents = pex_file.read() @@ -456,9 +451,9 @@ def correct_port(name, output_file_name, ref_file_name): for bank in range(OPTS.num_banks): for bank in range(OPTS.num_banks): row = int(OPTS.num_words / OPTS.words_per_row) - 1 - col = int(OPTS.word_size * OPTS.words_per_row) - 1 - bitcell_list += "bitcell_Q_b{0}_r{1}_c{2} ".format(bank,row,col) - bitcell_list += "bitcell_Q_bar_b{0}_r{1}_c{2} ".format(bank,row,col) + col = int(OPTS.word_size * OPTS.words_per_row) - 1 + bitcell_list += "bitcell_Q_b{0}_r{1}_c{2} ".format(bank, row, col) + bitcell_list += "bitcell_Q_bar_b{0}_r{1}_c{2} ".format(bank, row, col) for col in range(OPTS.word_size * OPTS.words_per_row): for port in range(OPTS.num_r_ports + OPTS.num_w_ports + OPTS.num_rw_ports): bitcell_list += "bl{0}_{1} ".format(bank, col) @@ -484,13 +479,18 @@ def correct_port(name, output_file_name, ref_file_name): # write the new pex file with info in the memory output_file = open(output_file_name, "w") output_file.write(part1) - output_file.write(circuit_title+'\n') + output_file.write(circuit_title + '\n') output_file.write(part2) output_file.close() + def print_drc_stats(): - debug.info(1,"DRC runs: {0}".format(num_drc_runs)) + debug.info(1, "DRC runs: {0}".format(num_drc_runs)) + + def print_lvs_stats(): - debug.info(1,"LVS runs: {0}".format(num_lvs_runs)) + debug.info(1, "LVS runs: {0}".format(num_lvs_runs)) + + def print_pex_stats(): - debug.info(1,"PEX runs: {0}".format(num_pex_runs)) + debug.info(1, "PEX runs: {0}".format(num_pex_runs))