From 5778901cfe84219f722879ae09aa79f6476b1024 Mon Sep 17 00:00:00 2001 From: Jesse Cirimelli-Low Date: Mon, 20 Jan 2020 12:16:30 +0000 Subject: [PATCH] pull bitline labels to top level spice --- compiler/base/geometry.py | 122 ++++++++++++++++-------------- compiler/bitcells/bitcell_base.py | 15 ++++ compiler/sram/sram_base.py | 27 +++++-- 3 files changed, 101 insertions(+), 63 deletions(-) diff --git a/compiler/base/geometry.py b/compiler/base/geometry.py index 885b139a..0fef7b72 100644 --- a/compiler/base/geometry.py +++ b/compiler/base/geometry.py @@ -255,13 +255,64 @@ class instance(geometry): p.transform(self.offset,self.mirror,self.rotate) new_pins.append(p) return new_pins + + def calculate_transform(self, node): + #set up the rotation matrix + angle = math.radians(float(node.rotate)) + mRotate = np.array([[math.cos(angle),-math.sin(angle),0.0], + [math.sin(angle),math.cos(angle),0.0], + [0.0,0.0,1.0]]) - def reverse_transformation(self, cell_name): + #set up translation matrix + translateX = float(node.offset[0]) + translateY = float(node.offset[1]) + mTranslate = np.array([[1.0,0.0,translateX], + [0.0,1.0,translateY], + [0.0,0.0,1.0]]) + + #set up the scale matrix (handles mirror X) + scaleX = 1.0 + if(node.mirror == 'MX'): + scaleY = -1.0 + else: + scaleY = 1.0 + mScale = np.array([[scaleX,0.0,0.0], + [0.0,scaleY,0.0], + [0.0,0.0,1.0]]) + + return (mRotate, mScale, mTranslate) + + def apply_transform(self, mtransforms, uVector, vVector, origin): + origin = np.dot(mtransforms[0], origin) #rotate + uVector = np.dot(mtransforms[0], uVector) #rotate + vVector = np.dot(mtransforms[0], vVector) #rotate + origin = np.dot(mtransforms[1], origin) #scale + uVector = np.dot(mtransforms[1], uVector) #scale + vVector = np.dot(mtransforms[1], vVector) #scale + origin = np.dot(mtransforms[2], origin) + + return(uVector, vVector, origin) + + def apply_path_transform(self, path): + uVector = np.array([[1.0],[0.0],[0.0]]) + vVector = np.array([[0.0],[1.0],[0.0]]) + origin = np.array([[0.0],[0.0],[1.0]]) + + while(path): + instance = path.pop(-1) + mtransforms = self.calculate_transform(instance) + (uVector, vVector, origin) = self.apply_transform(mtransforms, uVector, vVector, origin) + + return (uVector, vVector, origin) + + def reverse_transformation_bitcell(self, cell_name): path = [] cell_paths = [] - pex_offsets = [] + origin_offsets = [] Q_offsets = [] Q_bar_offsets = [] + bl_offsets = [] + br_offsets = [] def walk_subtree(node): path.append(node) @@ -270,6 +321,7 @@ class instance(geometry): cell_paths.append(copy.copy(path)) normalized_storage_nets = node.mod.get_normalized_storage_nets_offset() + normalized_bitline_nets = node.mod.get_normalized_bitline_offset() Q_x = normalized_storage_nets[0][0] Q_y = normalized_storage_nets[0][1] @@ -277,75 +329,35 @@ class instance(geometry): Q_bar_x = normalized_storage_nets[1][0] Q_bar_y = normalized_storage_nets[1][1] + bl_x = normalized_bitline_nets[0][0] + bl_y = normalized_bitline_nets[0][1] + + br_x = normalized_bitline_nets[1][0] + br_y = normalized_bitline_nets[1][1] + if node.mirror == 'MX': Q_y = -1 * Q_y Q_bar_y = -1 * Q_bar_y + bl_y = -1 * bl_y + br_y = -1 * br_y Q_offsets.append([Q_x, Q_y]) Q_bar_offsets.append([Q_bar_x, Q_bar_y]) - + bl_offsets.append([bl_x, bl_y]) + br_offsets.append([br_x, br_y]) elif node.mod.insts is not []: for instance in node.mod.insts: walk_subtree(instance) path.pop(-1) - def calculate_transform(node): - #set up the rotation matrix - angle = math.radians(float(node.rotate)) - mRotate = np.array([[math.cos(angle),-math.sin(angle),0.0], - [math.sin(angle),math.cos(angle),0.0], - [0.0,0.0,1.0]]) - - #set up translation matrix - translateX = float(node.offset[0]) - translateY = float(node.offset[1]) - mTranslate = np.array([[1.0,0.0,translateX], - [0.0,1.0,translateY], - [0.0,0.0,1.0]]) - - #set up the scale matrix (handles mirror X) - scaleX = 1.0 - if(node.mirror == 'MX'): - scaleY = -1.0 - else: - scaleY = 1.0 - mScale = np.array([[scaleX,0.0,0.0], - [0.0,scaleY,0.0], - [0.0,0.0,1.0]]) - - return (mRotate, mScale, mTranslate) - - def apply_transform(mtransforms, uVector, vVector, origin): - origin = np.dot(mtransforms[0], origin) #rotate - uVector = np.dot(mtransforms[0], uVector) #rotate - vVector = np.dot(mtransforms[0], vVector) #rotate - origin = np.dot(mtransforms[1], origin) #scale - uVector = np.dot(mtransforms[1], uVector) #scale - vVector = np.dot(mtransforms[1], vVector) #scale - origin = np.dot(mtransforms[2], origin) - - return(uVector, vVector, origin) - - def apply_path_transform(path): - uVector = np.array([[1.0],[0.0],[0.0]]) - vVector = np.array([[0.0],[1.0],[0.0]]) - origin = np.array([[0.0],[0.0],[1.0]]) - - while(path): - instance = path.pop(-1) - mtransforms = calculate_transform(instance) - (uVector, vVector, origin) = apply_transform(mtransforms, uVector, vVector, origin) - - return (uVector, vVector, origin) - walk_subtree(self) for path in cell_paths: - vector_spaces = apply_path_transform(path) + vector_spaces = self.apply_path_transform(path) origin = vector_spaces[2] - pex_offsets.append([origin[0], origin[1]]) + origin_offsets.append([origin[0], origin[1]]) - return(pex_offsets, Q_offsets, Q_bar_offsets) + return(origin_offsets, Q_offsets, Q_bar_offsets, bl_offsets, br_offsets) def __str__(self): """ override print function output """ diff --git a/compiler/bitcells/bitcell_base.py b/compiler/bitcells/bitcell_base.py index 0a5624bd..56c36b66 100644 --- a/compiler/bitcells/bitcell_base.py +++ b/compiler/bitcells/bitcell_base.py @@ -99,6 +99,19 @@ class bitcell_base(design.design): return(self.storage_net_offsets) + def get_bitline_offset(self): + self.bitline_names = ["bl", "br"] + self.bitline_offsets = [] + for i in range(len(self.bitline_names)): + for text in self.gds.getTexts(layer["metal2"]): + if self.bitline_names[i] == text.textString.rstrip('\x00'): + self.bitline_offsets.append(text.coordinates[0]) + + for i in range(len(self.bitline_offsets)): + self.bitline_offsets[i] = tuple([self.gds.info["units"][0] * x for x in self.bitline_offsets[i]]) + + return(self.bitline_offsets) + def get_normalized_storage_nets_offset(self): """ Convert storage net offset to be relative to the bottom left corner @@ -119,6 +132,8 @@ class bitcell_base(design.design): return normalized_storage_net_offset + def get_normalized_bitline_offset(self): + return self.get_bitline_offset() def build_graph(self, graph, inst_name, port_nets): """ diff --git a/compiler/sram/sram_base.py b/compiler/sram/sram_base.py index 6a7e996e..1a8d220b 100644 --- a/compiler/sram/sram_base.py +++ b/compiler/sram/sram_base.py @@ -91,34 +91,45 @@ class sram_base(design, verilog, lef): Add pex labels at the sram level for spice analysis """ - # add pex labels for bitcell - for bank_num in range(0,len(self.bank_insts)): + # add pex labels for bitcells + for bank_num in range(len(self.bank_insts)): bank = self.bank_insts[bank_num] - pex_offsets = bank.reverse_transformation(bank.mod.bitcell.name) + pex_offsets = bank.reverse_transformation_bitcell(bank.mod.bitcell.name) bank_offset = pex_offsets[0] # offset bank relative to sram Q_offset = pex_offsets[1] # offset of storage relative to bank Q_bar_offset = pex_offsets[2] # offset of storage relative to bank + bl_offsets = pex_offsets[3] + br_offsets = pex_offsets[4] - layer_name = "metal1" + storage_layer_name = "metal1" + bitline_layer_name = "metal2" for i in range(0,len(bank_offset)): Q = [bank_offset[i][0] + Q_offset[i][0], bank_offset[i][1] + Q_offset[i][1]] Q_bar = [bank_offset[i][0] + Q_bar_offset[i][0], bank_offset[i][1] + Q_bar_offset[i][1]] + bl = [bank_offset[i][0] + bl_offsets[i][0], bank_offset[i][1] + bl_offsets[i][1]] + br = [bank_offset[i][0] + br_offsets[i][0], bank_offset[i][1] + br_offsets[i][1]] - self.add_layout_pin_rect_center("bitcell_Q_b{0}_r{1}_c{2}".format(bank_num, i % OPTS.num_words, int(i / OPTS.num_words)) , layer_name, Q) - self.add_layout_pin_rect_center("bitcell_Q_bar_b{0}_r{1}_c{2}".format(bank_num, i % OPTS.num_words, int(i / OPTS.num_words)), layer_name, Q_bar) + self.add_layout_pin_rect_center("bitcell_Q_b{0}_r{1}_c{2}".format(bank_num, i % OPTS.num_words, int(i / OPTS.num_words)) , storage_layer_name, Q) + self.add_layout_pin_rect_center("bitcell_Q_bar_b{0}_r{1}_c{2}".format(bank_num, i % OPTS.num_words, int(i / OPTS.num_words)), storage_layer_name, Q_bar) + + self.add_layout_pin_rect_center("bitcell_bl_b{0}_c{2}".format(bank_num, i % OPTS.num_words, int(i / OPTS.num_words)) , bitline_layer_name, bl) + self.add_layout_pin_rect_center("bitcell_br_b{0}_c{2}".format(bank_num, i % OPTS.num_words, int(i / OPTS.num_words)), bitline_layer_name, br) + + + # add pex labels for control logic - for i in range (0,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), "metal1", offset) + self.add_layout_pin_rect_center("{0}{1}".format(pin.name,i), storage_layer_name, offset)