mirror of https://github.com/VLSIDA/OpenRAM.git
pull bitline labels to top level spice
This commit is contained in:
parent
364842569a
commit
5778901cfe
|
|
@ -255,13 +255,64 @@ class instance(geometry):
|
||||||
p.transform(self.offset,self.mirror,self.rotate)
|
p.transform(self.offset,self.mirror,self.rotate)
|
||||||
new_pins.append(p)
|
new_pins.append(p)
|
||||||
return new_pins
|
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 = []
|
path = []
|
||||||
cell_paths = []
|
cell_paths = []
|
||||||
pex_offsets = []
|
origin_offsets = []
|
||||||
Q_offsets = []
|
Q_offsets = []
|
||||||
Q_bar_offsets = []
|
Q_bar_offsets = []
|
||||||
|
bl_offsets = []
|
||||||
|
br_offsets = []
|
||||||
|
|
||||||
def walk_subtree(node):
|
def walk_subtree(node):
|
||||||
path.append(node)
|
path.append(node)
|
||||||
|
|
@ -270,6 +321,7 @@ class instance(geometry):
|
||||||
cell_paths.append(copy.copy(path))
|
cell_paths.append(copy.copy(path))
|
||||||
|
|
||||||
normalized_storage_nets = node.mod.get_normalized_storage_nets_offset()
|
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_x = normalized_storage_nets[0][0]
|
||||||
Q_y = normalized_storage_nets[0][1]
|
Q_y = normalized_storage_nets[0][1]
|
||||||
|
|
@ -277,75 +329,35 @@ class instance(geometry):
|
||||||
Q_bar_x = normalized_storage_nets[1][0]
|
Q_bar_x = normalized_storage_nets[1][0]
|
||||||
Q_bar_y = normalized_storage_nets[1][1]
|
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':
|
if node.mirror == 'MX':
|
||||||
Q_y = -1 * Q_y
|
Q_y = -1 * Q_y
|
||||||
Q_bar_y = -1 * Q_bar_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_offsets.append([Q_x, Q_y])
|
||||||
Q_bar_offsets.append([Q_bar_x, Q_bar_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 []:
|
elif node.mod.insts is not []:
|
||||||
for instance in node.mod.insts:
|
for instance in node.mod.insts:
|
||||||
walk_subtree(instance)
|
walk_subtree(instance)
|
||||||
path.pop(-1)
|
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)
|
walk_subtree(self)
|
||||||
for path in cell_paths:
|
for path in cell_paths:
|
||||||
vector_spaces = apply_path_transform(path)
|
vector_spaces = self.apply_path_transform(path)
|
||||||
origin = vector_spaces[2]
|
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):
|
def __str__(self):
|
||||||
""" override print function output """
|
""" override print function output """
|
||||||
|
|
|
||||||
|
|
@ -99,6 +99,19 @@ class bitcell_base(design.design):
|
||||||
|
|
||||||
return(self.storage_net_offsets)
|
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):
|
def get_normalized_storage_nets_offset(self):
|
||||||
"""
|
"""
|
||||||
Convert storage net offset to be relative to the bottom left corner
|
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
|
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):
|
def build_graph(self, graph, inst_name, port_nets):
|
||||||
"""
|
"""
|
||||||
|
|
|
||||||
|
|
@ -91,34 +91,45 @@ class sram_base(design, verilog, lef):
|
||||||
Add pex labels at the sram level for spice analysis
|
Add pex labels at the sram level for spice analysis
|
||||||
"""
|
"""
|
||||||
|
|
||||||
# add pex labels for bitcell
|
# add pex labels for bitcells
|
||||||
for bank_num in range(0,len(self.bank_insts)):
|
for bank_num in range(len(self.bank_insts)):
|
||||||
bank = self.bank_insts[bank_num]
|
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
|
bank_offset = pex_offsets[0] # offset bank relative to sram
|
||||||
Q_offset = pex_offsets[1] # offset of storage relative to bank
|
Q_offset = pex_offsets[1] # offset of storage relative to bank
|
||||||
Q_bar_offset = pex_offsets[2] # 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)):
|
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 = [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]]
|
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_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)), layer_name, Q_bar)
|
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
|
# 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]
|
instance = self.control_logic_insts[i]
|
||||||
control_logic_offset = instance.offset
|
control_logic_offset = instance.offset
|
||||||
for output in instance.mod.output_list:
|
for output in instance.mod.output_list:
|
||||||
pin = instance.mod.get_pin(output)
|
pin = instance.mod.get_pin(output)
|
||||||
pin.transform([0,0], instance.mirror, instance.rotate)
|
pin.transform([0,0], instance.mirror, instance.rotate)
|
||||||
offset = [control_logic_offset[0] + pin.center()[0], control_logic_offset[1] + pin.center()[1]]
|
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)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue