mirror of https://github.com/VLSIDA/OpenRAM.git
port_data: Refactor channel_route/connect_bitlines()
both functions share a lot of code and are passing around a lot of data
under similar names (inst1, inst1_start_bit, inst1_bl_name, ...). Thus
we group all these elements in a named tuple to ease passing around
these elements.
All callers of channel_route/connect_bitlines() either pass in the bl/br
names or rely on "br_{}"/"bl_{}" as defaults. These hard coded values
should be determined by the instances. Thus we get the bitline names
based on the instances passed in. The callers only provide a template
string, to take care of the case that bitlines are called "bl_out_{}".
Signed-off-by: Bastian Koppelmann <kbastian@mail.uni-paderborn.de>
This commit is contained in:
parent
5e1f64c8f9
commit
656fdd1008
|
|
@ -8,6 +8,7 @@ from tech import drc, parameter
|
|||
import debug
|
||||
import design
|
||||
from sram_factory import factory
|
||||
from collections import namedtuple
|
||||
from vector import vector
|
||||
|
||||
from globals import OPTS
|
||||
|
|
@ -535,13 +536,16 @@ class port_data(design.design):
|
|||
# Only do this if we have a column mux!
|
||||
if self.col_addr_size==0:
|
||||
return
|
||||
|
||||
|
||||
inst1 = self.column_mux_array_inst
|
||||
inst2 = self.precharge_array_inst
|
||||
if self.port==0:
|
||||
self.connect_bitlines(inst1, inst2, self.num_cols, inst2_start_bit=1)
|
||||
else:
|
||||
self.connect_bitlines(inst1, inst2, self.num_cols)
|
||||
|
||||
insn2_start_bit = 1 if self.port == 0 else 0
|
||||
|
||||
self.connect_bitlines(inst1=inst1,
|
||||
inst2=inst2,
|
||||
num_bits=self.num_cols,
|
||||
inst2_start_bit=insn2_start_bit)
|
||||
|
||||
|
||||
def route_sense_amp_to_column_mux_or_precharge_array(self, port):
|
||||
|
|
@ -551,46 +555,49 @@ class port_data(design.design):
|
|||
if self.col_addr_size>0:
|
||||
# Sense amp is connected to the col mux
|
||||
inst1 = self.column_mux_array_inst
|
||||
inst1_bl_name = "bl_out_{}"
|
||||
inst1_br_name = "br_out_{}"
|
||||
inst1_bls_templ = "{inst}_out_{bit}"
|
||||
start_bit = 0
|
||||
else:
|
||||
# Sense amp is directly connected to the precharge array
|
||||
inst1 = self.precharge_array_inst
|
||||
inst1_bl_name = "bl_{}"
|
||||
inst1_br_name = "br_{}"
|
||||
inst1_bls_templ="{inst}_{bit}"
|
||||
|
||||
if self.port==0:
|
||||
start_bit=1
|
||||
else:
|
||||
start_bit=0
|
||||
|
||||
|
||||
self.channel_route_bitlines(inst1=inst1, inst2=inst2, num_bits=self.word_size,
|
||||
inst1_bl_name=inst1_bl_name, inst1_br_name=inst1_br_name, inst1_start_bit=start_bit)
|
||||
self.channel_route_bitlines(inst1=inst1,
|
||||
inst1_bls_template=inst1_bls_templ,
|
||||
inst2=inst2,
|
||||
num_bits=self.word_size,
|
||||
inst1_start_bit=start_bit)
|
||||
|
||||
|
||||
def route_write_driver_to_column_mux_or_precharge_array(self, port):
|
||||
""" Routing of BL and BR between sense_amp and column mux or precharge array """
|
||||
inst2 = self.write_driver_array_inst
|
||||
|
||||
inst2_bl_name = inst2.mod.get_bl_name()
|
||||
inst2_br_name = inst2.mod.get_br_name()
|
||||
|
||||
if self.col_addr_size>0:
|
||||
# Write driver is connected to the col mux
|
||||
inst1 = self.column_mux_array_inst
|
||||
inst1_bl_name = "bl_out_{}"
|
||||
inst1_br_name = "br_out_{}"
|
||||
inst1_bls_templ = "{inst}_out_{bit}"
|
||||
start_bit = 0
|
||||
else:
|
||||
# Sense amp is directly connected to the precharge array
|
||||
inst1 = self.precharge_array_inst
|
||||
inst1_bl_name = "bl_{}"
|
||||
inst1_br_name = "br_{}"
|
||||
inst1_bls_templ="{inst}_{bit}"
|
||||
if self.port==0:
|
||||
start_bit=1
|
||||
else:
|
||||
start_bit=0
|
||||
|
||||
self.channel_route_bitlines(inst1=inst1, inst2=inst2, num_bits=self.word_size,
|
||||
inst1_bl_name=inst1_bl_name, inst1_br_name=inst1_br_name, inst1_start_bit=start_bit)
|
||||
|
||||
self.channel_route_bitlines(inst1=inst1, inst2=inst2,
|
||||
num_bits=self.word_size,
|
||||
inst1_bls_template=inst1_bls_templ,
|
||||
inst1_start_bit=start_bit)
|
||||
|
||||
|
||||
def route_write_driver_to_sense_amp(self, port):
|
||||
|
|
@ -601,7 +608,9 @@ class port_data(design.design):
|
|||
|
||||
# These should be pitch matched in the cell library,
|
||||
# but just in case, do a channel route.
|
||||
self.channel_route_bitlines(inst1=inst1, inst2=inst2, num_bits=self.word_size)
|
||||
self.channel_route_bitlines(inst1=inst1,
|
||||
inst2=inst2,
|
||||
num_bits=self.word_size)
|
||||
|
||||
|
||||
def route_bitline_pins(self):
|
||||
|
|
@ -647,64 +656,108 @@ class port_data(design.design):
|
|||
if self.write_mask_and_array_inst:
|
||||
self.copy_layout_pin(self.write_mask_and_array_inst, "en", "w_en")
|
||||
|
||||
|
||||
|
||||
def channel_route_bitlines(self, inst1, inst2, num_bits,
|
||||
inst1_bl_name="bl_{}", inst1_br_name="br_{}", inst1_start_bit=0,
|
||||
inst2_bl_name="bl_{}", inst2_br_name="br_{}", inst2_start_bit=0):
|
||||
|
||||
|
||||
def _group_bitline_instances(self, inst1, inst2, num_bits,
|
||||
inst1_bls_template,
|
||||
inst1_start_bit,
|
||||
inst2_bls_template,
|
||||
inst2_start_bit):
|
||||
"""
|
||||
Route the bl and br of two modules using the channel router.
|
||||
Groups all the parameters into a named tuple and seperates them into
|
||||
top and bottom instances.
|
||||
"""
|
||||
|
||||
inst_group = namedtuple('InstanceGroup', ('inst', 'bls_template',
|
||||
'bl_name', 'br_name', 'start_bit'))
|
||||
|
||||
inst1_group = inst_group(inst1, inst1_bls_template,
|
||||
inst1.mod.get_bl_name(),
|
||||
inst1.mod.get_br_name(),
|
||||
inst1_start_bit)
|
||||
inst2_group = inst_group(inst2, inst2_bls_template,
|
||||
inst2.mod.get_bl_name(),
|
||||
inst2.mod.get_br_name(),
|
||||
inst2_start_bit)
|
||||
# determine top and bottom automatically.
|
||||
# since they don't overlap, we can just check the bottom y coordinate.
|
||||
if inst1.by() < inst2.by():
|
||||
(bottom_inst, bottom_bl_name, bottom_br_name, bottom_start_bit) = (inst1, inst1_bl_name, inst1_br_name, inst1_start_bit)
|
||||
(top_inst, top_bl_name, top_br_name, top_start_bit) = (inst2, inst2_bl_name, inst2_br_name, inst2_start_bit)
|
||||
bot_inst_group = inst1_group
|
||||
top_inst_group = inst2_group
|
||||
else:
|
||||
(bottom_inst, bottom_bl_name, bottom_br_name, bottom_start_bit) = (inst2, inst2_bl_name, inst2_br_name, inst2_start_bit)
|
||||
(top_inst, top_bl_name, top_br_name, top_start_bit) = (inst1, inst1_bl_name, inst1_br_name, inst1_start_bit)
|
||||
bot_inst_group = inst2_group
|
||||
top_inst_group = inst1_group
|
||||
|
||||
return (bot_inst_group, top_inst_group)
|
||||
|
||||
def _get_bitline_pins(self, inst_group, bit):
|
||||
"""
|
||||
Extracts bl/br pins from an InstanceGroup based on the bit modifier.
|
||||
"""
|
||||
full_bl_name = inst_group.bls_template.format(
|
||||
**{'inst' : inst_group.bl_name,
|
||||
'bit' : inst_group.start_bit + bit}
|
||||
)
|
||||
full_br_name = inst_group.bls_template.format(
|
||||
**{'inst' : inst_group.br_name,
|
||||
'bit' : inst_group.start_bit + bit}
|
||||
)
|
||||
return (inst_group.inst.get_pin(full_bl_name),
|
||||
inst_group.inst.get_pin(full_br_name))
|
||||
|
||||
|
||||
def channel_route_bitlines(self, inst1, inst2, num_bits,
|
||||
inst1_bls_template="{inst}_{bit}",
|
||||
inst1_start_bit=0,
|
||||
inst2_bls_template="{inst}_{bit}",
|
||||
inst2_start_bit=0):
|
||||
"""
|
||||
Route the bl and br of two modules using the channel router.
|
||||
"""
|
||||
|
||||
bot_inst_group, top_inst_group = self._group_bitline_instances(
|
||||
inst1, inst2, num_bits,
|
||||
inst1_bls_template, inst1_start_bit,
|
||||
inst2_bls_template, inst2_start_bit)
|
||||
|
||||
# Channel route each mux separately since we don't minimize the number
|
||||
# of tracks in teh channel router yet. If we did, we could route all the bits at once!
|
||||
offset = bottom_inst.ul() + vector(0,self.m1_pitch)
|
||||
offset = bot_inst_group.inst.ul() + vector(0,self.m1_pitch)
|
||||
for bit in range(num_bits):
|
||||
bottom_names = [bottom_inst.get_pin(bottom_bl_name.format(bit+bottom_start_bit)), bottom_inst.get_pin(bottom_br_name.format(bit+bottom_start_bit))]
|
||||
top_names = [top_inst.get_pin(top_bl_name.format(bit+top_start_bit)), top_inst.get_pin(top_br_name.format(bit+top_start_bit))]
|
||||
bottom_names = self._get_bitline_pins(bot_inst_group, bit)
|
||||
top_names = self._get_bitline_pins(top_inst_group, bit)
|
||||
|
||||
route_map = list(zip(bottom_names, top_names))
|
||||
self.create_horizontal_channel_route(route_map, offset, self.m1_stack)
|
||||
|
||||
|
||||
def connect_bitlines(self, inst1, inst2, num_bits,
|
||||
inst1_bl_name="bl_{}", inst1_br_name="br_{}", inst1_start_bit=0,
|
||||
inst2_bl_name="bl_{}", inst2_br_name="br_{}", inst2_start_bit=0):
|
||||
|
||||
inst1_bls_template="{inst}_{bit}",
|
||||
inst1_start_bit=0,
|
||||
inst2_bls_template="{inst}_{bit}",
|
||||
inst2_start_bit=0):
|
||||
"""
|
||||
Connect the bl and br of two modules.
|
||||
This assumes that they have sufficient space to create a jog
|
||||
in the middle between the two modules (if needed).
|
||||
"""
|
||||
|
||||
# determine top and bottom automatically.
|
||||
# since they don't overlap, we can just check the bottom y coordinate.
|
||||
if inst1.by() < inst2.by():
|
||||
(bottom_inst, bottom_bl_name, bottom_br_name, bottom_start_bit) = (inst1, inst1_bl_name, inst1_br_name, inst1_start_bit)
|
||||
(top_inst, top_bl_name, top_br_name, top_start_bit) = (inst2, inst2_bl_name, inst2_br_name, inst2_start_bit)
|
||||
else:
|
||||
(bottom_inst, bottom_bl_name, bottom_br_name, bottom_start_bit) = (inst2, inst2_bl_name, inst2_br_name, inst2_start_bit)
|
||||
(top_inst, top_bl_name, top_br_name, top_start_bit) = (inst1, inst1_bl_name, inst1_br_name, inst1_start_bit)
|
||||
bot_inst_group, top_inst_group = self._group_bitline_instances(
|
||||
inst1, inst2, num_bits,
|
||||
inst1_bls_template, inst1_start_bit,
|
||||
inst2_bls_template, inst2_start_bit)
|
||||
bottom_inst = bot_inst_group.inst
|
||||
top_inst = top_inst_group.inst
|
||||
|
||||
for col in range(num_bits):
|
||||
bottom_bl = bottom_inst.get_pin(bottom_bl_name.format(col+bottom_start_bit)).uc()
|
||||
bottom_br = bottom_inst.get_pin(bottom_br_name.format(col+bottom_start_bit)).uc()
|
||||
top_bl = top_inst.get_pin(top_bl_name.format(col+top_start_bit)).bc()
|
||||
top_br = top_inst.get_pin(top_br_name.format(col+top_start_bit)).bc()
|
||||
bot_bl_pin, bot_br_pin = self._get_bitline_pins(bot_inst_group, col)
|
||||
top_bl_pin, top_br_pin = self._get_bitline_pins(top_inst_group, col)
|
||||
bot_bl, bot_br = bot_bl_pin.uc(), bot_br_pin.uc()
|
||||
top_bl, top_br = top_bl_pin.bc(), top_br_pin.bc()
|
||||
|
||||
yoffset = 0.5*(top_bl.y+bottom_bl.y)
|
||||
self.add_path("m2",[bottom_bl, vector(bottom_bl.x,yoffset),
|
||||
yoffset = 0.5*(top_bl.y+bot_bl.y)
|
||||
self.add_path("m2",[bot_bl, vector(bot_bl.x,yoffset),
|
||||
vector(top_bl.x,yoffset), top_bl])
|
||||
self.add_path("m2",[bottom_br, vector(bottom_br.x,yoffset),
|
||||
self.add_path("m2",[bot_br, vector(bot_br.x,yoffset),
|
||||
vector(top_br.x,yoffset), top_br])
|
||||
|
||||
def graph_exclude_precharge(self):
|
||||
|
|
|
|||
Loading…
Reference in New Issue