From c12dd987dcd8dbfbb4894ec4fc7ac5fd64e703ad Mon Sep 17 00:00:00 2001 From: Hunter Nichols Date: Tue, 30 Jul 2019 00:49:43 -0700 Subject: [PATCH 1/3] Fixed pbitcell graph edge formation. --- compiler/bitcells/pbitcell.py | 7 ++++++- compiler/characterizer/delay.py | 11 +++-------- compiler/characterizer/functional.py | 14 +++++--------- 3 files changed, 14 insertions(+), 18 deletions(-) diff --git a/compiler/bitcells/pbitcell.py b/compiler/bitcells/pbitcell.py index 6d95a15f..3c59a9e3 100644 --- a/compiler/bitcells/pbitcell.py +++ b/compiler/bitcells/pbitcell.py @@ -962,11 +962,16 @@ class pbitcell(design.design): def build_graph(self, graph, inst_name, port_nets): """Adds edges to graph for pbitcell. Only readwrite and read ports.""" + + if self.dummy_bitcell: + return + pin_dict = {pin:port for pin,port in zip(self.pins, port_nets)} # Edges added wl->bl, wl->br for every port except write ports rw_pin_names = zip(self.r_wl_names, self.r_bl_names, self.r_br_names) r_pin_names = zip(self.rw_wl_names, self.rw_bl_names, self.rw_br_names) - for pin_zip in zip(rw_pin_names, r_pin_names): + + for pin_zip in [rw_pin_names, r_pin_names]: for wl,bl,br in pin_zip: graph.add_edge(pin_dict[wl],pin_dict[bl]) graph.add_edge(pin_dict[wl],pin_dict[br]) diff --git a/compiler/characterizer/delay.py b/compiler/characterizer/delay.py index 09bf4571..854739cb 100644 --- a/compiler/characterizer/delay.py +++ b/compiler/characterizer/delay.py @@ -261,7 +261,7 @@ class delay(simulation): port = 0 self.graph.get_all_paths('{}{}'.format(tech.spice["clk"], port), '{}{}_{}'.format(self.dout_name, port, self.probe_data)) - + self.sen_name = self.get_sen_name(self.graph.all_paths) debug.info(2,"s_en name = {}".format(self.sen_name)) @@ -285,12 +285,7 @@ class delay(simulation): def get_bl_name(self, paths): """Gets the signal name associated with the bitlines in the bank.""" - cell_mods = factory.get_mods(OPTS.bitcell) - if len(cell_mods)>=1: - cell_mod = self.get_primary_cell_mod(cell_mods) - elif len(cell_mods)==0: - debug.error("No bitcells found. Cannot determine bitline names.", 1) - + cell_mod = factory.create(module_type=OPTS.bitcell) cell_bl = cell_mod.get_bl_name() cell_br = cell_mod.get_br_name() @@ -301,7 +296,7 @@ class delay(simulation): for int_net in [cell_bl, cell_br]: bl_names.append(self.get_alias_in_path(paths, int_net, cell_mod, exclude_set)) - return bl_names[0], bl_names[1] + return bl_names[0], bl_names[1] def get_bl_name_search_exclusions(self): diff --git a/compiler/characterizer/functional.py b/compiler/characterizer/functional.py index 0b3e7b4b..dc4fe48a 100644 --- a/compiler/characterizer/functional.py +++ b/compiler/characterizer/functional.py @@ -413,7 +413,7 @@ class functional(simulation): port = 0 self.graph.get_all_paths('{}{}'.format(tech.spice["clk"], port), - '{}{}_{}'.format(self.dout_name, port, 0)) + '{}{}_{}'.format(self.dout_name, port, 0).lower()) self.sen_name = self.get_sen_name(self.graph.all_paths) debug.info(2,"s_en name = {}".format(self.sen_name)) @@ -422,7 +422,7 @@ class functional(simulation): debug.info(2,"bl name={}, br name={}".format(self.bl_name,self.br_name)) self.q_name,self.qbar_name = self.get_bit_name() - debug.info(2,"q name={}\nqbar name={}".format(self.bl_name,self.br_name)) + debug.info(2,"q name={}\nqbar name={}".format(self.q_name,self.qbar_name)) def get_bit_name(self): """ Get a bit cell name """ @@ -454,12 +454,7 @@ class functional(simulation): def get_bl_name(self, paths): """Gets the signal name associated with the bitlines in the bank.""" - cell_mods = factory.get_mods(OPTS.bitcell) - if len(cell_mods)>=1: - cell_mod = self.get_primary_cell_mod(cell_mods) - elif len(cell_mods)==0: - debug.error("No bitcells found. Cannot determine bitline names.", 1) - + cell_mod = factory.create(module_type=OPTS.bitcell) cell_bl = cell_mod.get_bl_name() cell_br = cell_mod.get_br_name() @@ -494,8 +489,9 @@ class functional(simulation): has_cell = has_cell or replica_cell.contains(bitcell, replica_cell.mods) if not has_cell: non_rbc_mods.append(bitcell) + if len(non_rbc_mods) != 1: - debug.error('Multiple bitcell mods found. Cannot distinguish for characterization',1) + debug.error('{} possible bitcell mods found. Cannot distinguish for characterization'.format(len(non_rbc_mods)),1) return non_rbc_mods[0] def are_mod_pins_equal(self, mods): From 24b1fa38a0466606771f876b5acb70562486b5ac Mon Sep 17 00:00:00 2001 From: Hunter Nichols Date: Tue, 30 Jul 2019 20:31:32 -0700 Subject: [PATCH 2/3] Added graph fixes to handmade multiport cells. --- compiler/bitcells/bitcell_1w_1r.py | 4 +-- compiler/bitcells/dummy_bitcell_1rw_1r.py | 12 ++----- compiler/bitcells/dummy_bitcell_1w_1r.py | 10 ++---- compiler/bitcells/replica_bitcell_1w_1r.py | 11 +++--- compiler/characterizer/delay.py | 10 +++--- compiler/characterizer/functional.py | 42 ++++------------------ compiler/modules/replica_bitcell_array.py | 7 ++-- compiler/modules/replica_column.py | 11 +++--- 8 files changed, 32 insertions(+), 75 deletions(-) diff --git a/compiler/bitcells/bitcell_1w_1r.py b/compiler/bitcells/bitcell_1w_1r.py index b36c38bf..6063cf86 100644 --- a/compiler/bitcells/bitcell_1w_1r.py +++ b/compiler/bitcells/bitcell_1w_1r.py @@ -139,6 +139,6 @@ class bitcell_1w_1r(design.design): pin_dict = {pin:port for pin,port in zip(self.pins, port_nets)} #Edges hardcoded here. Essentially wl->bl/br for both ports. # Port 0 edges - graph.add_edge(pin_dict["wl0"], pin_dict["bl0"]) - graph.add_edge(pin_dict["wl0"], pin_dict["br0"]) + graph.add_edge(pin_dict["wl1"], pin_dict["bl1"]) + graph.add_edge(pin_dict["wl1"], pin_dict["br1"]) # Port 1 is a write port, so its timing is not considered here. diff --git a/compiler/bitcells/dummy_bitcell_1rw_1r.py b/compiler/bitcells/dummy_bitcell_1rw_1r.py index 189c4894..f8986f2d 100644 --- a/compiler/bitcells/dummy_bitcell_1rw_1r.py +++ b/compiler/bitcells/dummy_bitcell_1rw_1r.py @@ -41,13 +41,5 @@ class dummy_bitcell_1rw_1r(design.design): return 2*access_tx_cin def build_graph(self, graph, inst_name, port_nets): - """Adds edges to graph. Multiport bitcell timing graph is too complex - to use the add_graph_edges function.""" - pin_dict = {pin:port for pin,port in zip(self.pins, port_nets)} - #Edges hardcoded here. Essentially wl->bl/br for both ports. - # Port 0 edges - graph.add_edge(pin_dict["wl0"], pin_dict["bl0"]) - graph.add_edge(pin_dict["wl0"], pin_dict["br0"]) - # Port 1 edges - graph.add_edge(pin_dict["wl1"], pin_dict["bl1"]) - graph.add_edge(pin_dict["wl1"], pin_dict["br1"]) + """Dummy bitcells are cannot form a path and be part of the timing graph""" + return diff --git a/compiler/bitcells/dummy_bitcell_1w_1r.py b/compiler/bitcells/dummy_bitcell_1w_1r.py index 95d514f8..ef451b8c 100644 --- a/compiler/bitcells/dummy_bitcell_1w_1r.py +++ b/compiler/bitcells/dummy_bitcell_1w_1r.py @@ -41,11 +41,5 @@ class dummy_bitcell_1w_1r(design.design): return 2*access_tx_cin def build_graph(self, graph, inst_name, port_nets): - """Adds edges to graph. Multiport bitcell timing graph is too complex - to use the add_graph_edges function.""" - pin_dict = {pin:port for pin,port in zip(self.pins, port_nets)} - #Edges hardcoded here. Essentially wl->bl/br for both ports. - # Port 0 edges - graph.add_edge(pin_dict["wl0"], pin_dict["bl0"]) - graph.add_edge(pin_dict["wl0"], pin_dict["br0"]) - # Port 1 is a write port, so its timing is not considered here. + """Dummy bitcells are cannot form a path and be part of the timing graph""" + return diff --git a/compiler/bitcells/replica_bitcell_1w_1r.py b/compiler/bitcells/replica_bitcell_1w_1r.py index c0d31a69..79171bf5 100644 --- a/compiler/bitcells/replica_bitcell_1w_1r.py +++ b/compiler/bitcells/replica_bitcell_1w_1r.py @@ -43,9 +43,10 @@ class replica_bitcell_1w_1r(design.design): def build_graph(self, graph, inst_name, port_nets): """Adds edges to graph. Multiport bitcell timing graph is too complex to use the add_graph_edges function.""" + debug.info(1,'Adding edges for {}'.format(inst_name)) pin_dict = {pin:port for pin,port in zip(self.pins, port_nets)} - #Edges hardcoded here. Essentially wl->bl/br for both ports. - # Port 0 edges - graph.add_edge(pin_dict["wl0"], pin_dict["bl0"]) - graph.add_edge(pin_dict["wl0"], pin_dict["br0"]) - # Port 1 is a write port, so its timing is not considered here. \ No newline at end of file + #Edges hardcoded here. Essentially wl->bl/br for the read port. + # Port 1 edges + graph.add_edge(pin_dict["wl1"], pin_dict["bl1"]) + graph.add_edge(pin_dict["wl1"], pin_dict["br1"]) + # Port 0 is a write port, so its timing is not considered here. \ No newline at end of file diff --git a/compiler/characterizer/delay.py b/compiler/characterizer/delay.py index 854739cb..37c38353 100644 --- a/compiler/characterizer/delay.py +++ b/compiler/characterizer/delay.py @@ -258,14 +258,14 @@ class delay(simulation): def set_internal_spice_names(self): """Sets important names for characterization such as Sense amp enable and internal bit nets.""" - port = 0 + port = self.read_ports[0] self.graph.get_all_paths('{}{}'.format(tech.spice["clk"], port), '{}{}_{}'.format(self.dout_name, port, self.probe_data)) self.sen_name = self.get_sen_name(self.graph.all_paths) debug.info(2,"s_en name = {}".format(self.sen_name)) - self.bl_name,self.br_name = self.get_bl_name(self.graph.all_paths) + self.bl_name,self.br_name = self.get_bl_name(self.graph.all_paths, port) debug.info(2,"bl name={}, br name={}".format(self.bl_name,self.br_name)) def get_sen_name(self, paths): @@ -282,12 +282,12 @@ class delay(simulation): sen_name = self.get_alias_in_path(paths, enable_name, sa_mods[0]) return sen_name - def get_bl_name(self, paths): + def get_bl_name(self, paths, port): """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() - cell_br = cell_mod.get_br_name() + cell_bl = cell_mod.get_bl_name(port) + cell_br = cell_mod.get_br_name(port) bl_found = False # Only a single path should contain a single s_en name. Anything else is an error. diff --git a/compiler/characterizer/functional.py b/compiler/characterizer/functional.py index dc4fe48a..9f8e3d43 100644 --- a/compiler/characterizer/functional.py +++ b/compiler/characterizer/functional.py @@ -411,14 +411,15 @@ class functional(simulation): def set_internal_spice_names(self): """Sets important names for characterization such as Sense amp enable and internal bit nets.""" - port = 0 + # For now, only testing these using first read port. + port = self.read_ports[0] self.graph.get_all_paths('{}{}'.format(tech.spice["clk"], port), '{}{}_{}'.format(self.dout_name, port, 0).lower()) self.sen_name = self.get_sen_name(self.graph.all_paths) debug.info(2,"s_en name = {}".format(self.sen_name)) - self.bl_name,self.br_name = self.get_bl_name(self.graph.all_paths) + self.bl_name,self.br_name = self.get_bl_name(self.graph.all_paths, port) debug.info(2,"bl name={}, br name={}".format(self.bl_name,self.br_name)) self.q_name,self.qbar_name = self.get_bit_name() @@ -451,12 +452,12 @@ class functional(simulation): return sen_name # FIXME: refactor to share with delay.py - def get_bl_name(self, paths): + def get_bl_name(self, paths, port): """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() - cell_br = cell_mod.get_br_name() + cell_bl = cell_mod.get_bl_name(port) + cell_br = cell_mod.get_br_name(port) bl_found = False # Only a single path should contain a single s_en name. Anything else is an error. @@ -473,37 +474,6 @@ class functional(simulation): # Exclude the RBL as it contains bitcells which are not in the main bitcell array # so it makes the search awkward return set(factory.get_mods(OPTS.replica_bitline)) - - def get_primary_cell_mod(self, cell_mods): - """ - Distinguish bitcell array mod from replica bitline array. - Assume there are no replica bitcells in the primary array. - """ - if len(cell_mods) == 1: - return cell_mods[0] - rbc_mods = factory.get_mods(OPTS.replica_bitcell) - non_rbc_mods = [] - for bitcell in cell_mods: - has_cell = False - for replica_cell in rbc_mods: - has_cell = has_cell or replica_cell.contains(bitcell, replica_cell.mods) - if not has_cell: - non_rbc_mods.append(bitcell) - - if len(non_rbc_mods) != 1: - debug.error('{} possible bitcell mods found. Cannot distinguish for characterization'.format(len(non_rbc_mods)),1) - return non_rbc_mods[0] - - def are_mod_pins_equal(self, mods): - """Determines if there are pins differences in the input mods""" - - if len(mods) == 0: - return True - pins = mods[0].pins - for mod in mods[1:]: - if pins != mod.pins: - return False - return True def get_alias_in_path(self, paths, int_net, mod, exclusion_set=None): """ diff --git a/compiler/modules/replica_bitcell_array.py b/compiler/modules/replica_bitcell_array.py index c748e83d..6f4e96c5 100644 --- a/compiler/modules/replica_bitcell_array.py +++ b/compiler/modules/replica_bitcell_array.py @@ -138,8 +138,6 @@ class replica_bitcell_array(design.design): # Create the full WL names include dummy, replica, and regular bit cells self.replica_col_wl_names = [] self.replica_col_wl_names.extend(["{0}_bot".format(x) for x in self.dummy_cell_wl_names]) - #Save where the RBL wordlines start for graph purposes. Even positions are changed then graph will break - self.rbl_row_pos = len(self.replica_col_wl_names) # Left port WLs (one dummy for each port when we allow >1 port) for port in range(self.left_rbl): # Make names for all RBLs @@ -445,9 +443,10 @@ class replica_bitcell_array(design.design): self.bitcell_array.graph_exclude_bits(targ_row, targ_col) def graph_exclude_replica_col_bits(self): + """Exclude all replica/dummy cells in the replica columns except the replica bit.""" + for port in range(self.left_rbl+self.right_rbl): - #While the rbl_wl bits may be on a few rows. Only keep one for simplicity. - self.replica_columns[port].exclude_bits_except_one(self.rbl_row_pos) + self.replica_columns[port].exclude_all_but_replica() def get_cell_name(self, inst_name, row, col): """Gets the spice name of the target bitcell.""" diff --git a/compiler/modules/replica_column.py b/compiler/modules/replica_column.py index b18c49fe..fb11a8f5 100644 --- a/compiler/modules/replica_column.py +++ b/compiler/modules/replica_column.py @@ -29,7 +29,7 @@ class replica_column(design.design): self.replica_bit = replica_bit # left, right, regular rows plus top/bottom dummy cells self.total_size = self.left_rbl+rows+self.right_rbl+2 - + debug.check(replica_bit!=0 and replica_bit!=rows,"Replica bit cannot be the dummy row.") debug.check(replica_bit<=left_rbl or replica_bit>=self.total_size-right_rbl-1, "Replica bit cannot be in the regular array.") @@ -152,8 +152,9 @@ class replica_column(design.design): return bitcell_pins - def exclude_bits_except_one(self, selected_row): + def exclude_all_but_replica(self): + """Excludes all bits except the replica cell (self.replica_bit).""" + for row, cell in self.cell_inst.items(): - if row == selected_row: - continue - self.graph_inst_exclude.add(cell) + if row != self.replica_bit: + self.graph_inst_exclude.add(cell) From b4ef0ec36dc099a455e40f142f6547c9d53e0bb2 Mon Sep 17 00:00:00 2001 From: Hunter Nichols Date: Tue, 30 Jul 2019 20:33:17 -0700 Subject: [PATCH 3/3] Removed unused characterization module. --- compiler/characterizer/__init__.py | 1 - compiler/characterizer/worst_case.py | 84 ---------------------------- 2 files changed, 85 deletions(-) delete mode 100644 compiler/characterizer/worst_case.py diff --git a/compiler/characterizer/__init__.py b/compiler/characterizer/__init__.py index 8153251b..93dd5bcb 100644 --- a/compiler/characterizer/__init__.py +++ b/compiler/characterizer/__init__.py @@ -13,7 +13,6 @@ from .lib import * from .delay import * from .setup_hold import * from .functional import * -from .worst_case import * from .simulation import * from .measurements import * from .model_check import * diff --git a/compiler/characterizer/worst_case.py b/compiler/characterizer/worst_case.py deleted file mode 100644 index 1d4c095e..00000000 --- a/compiler/characterizer/worst_case.py +++ /dev/null @@ -1,84 +0,0 @@ -# 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 sys,re,shutil -import debug -import tech -import math -from .stimuli import * -from .trim_spice import * -from .charutils import * -import utils -from globals import OPTS -from .delay import delay - -class worst_case(delay): - """Functions to test for the worst case delay in a target SRAM - - The current worst case determines a feasible period for the SRAM then tests - several bits and record the delay and differences between the bits. - - """ - - def __init__(self, sram, spfile, corner): - delay.__init__(self,sram,spfile,corner) - - - def analyze(self,probe_address, probe_data, slews, loads): - """ - Main function to test the delays of different bits. - """ - debug.check(OPTS.num_rw_ports < 2 and OPTS.num_w_ports < 1 and OPTS.num_r_ports < 1 , - "Bit testing does not currently support multiport.") - #Dict to hold all characterization values - char_sram_data = {} - - self.set_probe(probe_address, probe_data) - #self.prepare_netlist() - - self.load=max(loads) - self.slew=max(slews) - - # 1) Find a feasible period and it's corresponding delays using the trimmed array. - feasible_delays = self.find_feasible_period() - - # 2) Find the delays of several bits - test_bits = self.get_test_bits() - bit_delays = self.simulate_for_bit_delays(test_bits) - - for i in range(len(test_bits)): - debug.info(1, "Bit tested: addr {0[0]} data_pos {0[1]}\n Values {1}".format(test_bits[i], bit_delays[i])) - - def simulate_for_bit_delays(self, test_bits): - """Simulates the delay of the sram of over several bits.""" - bit_delays = [{} for i in range(len(test_bits))] - - #Assumes a bitcell with only 1 rw port. (6t, port 0) - port = 0 - self.targ_read_ports = [self.read_ports[port]] - self.targ_write_ports = [self.write_ports[port]] - - for i in range(len(test_bits)): - (bit_addr, bit_data) = test_bits[i] - self.set_probe(bit_addr, bit_data) - debug.info(1,"Delay bit test: period {}, addr {}, data_pos {}".format(self.period, bit_addr, bit_data)) - (success, results)=self.run_delay_simulation() - debug.check(success, "Bit Test Failed: period {}, addr {}, data_pos {}".format(self.period, bit_addr, bit_data)) - bit_delays[i] = results[port] - - return bit_delays - - - def get_test_bits(self): - """Statically determines address and bit values to test""" - #First and last address, first middle, and last bit. Last bit is repeated twice with different data position. - bit_addrs = ["0"*self.addr_size, "0"+"1"*(self.addr_size-1), "1"*self.addr_size, "1"*self.addr_size] - data_positions = [0, (self.word_size-1)//2, 0, self.word_size-1] - #Return them in a tuple form - return [(bit_addrs[i], data_positions[i]) for i in range(len(bit_addrs))] - -