mirror of
https://github.com/VLSIDA/OpenRAM.git
synced 2026-08-30 09:58:33 +02:00
Merge branch 'dev' into bisr
This commit is contained in:
@@ -19,7 +19,7 @@ class port_data(design.design):
|
||||
"""
|
||||
|
||||
def __init__(self, sram_config, port, name=""):
|
||||
|
||||
|
||||
sram_config.set_local_config(self)
|
||||
self.port = port
|
||||
if self.write_size is not None:
|
||||
@@ -189,13 +189,17 @@ class port_data(design.design):
|
||||
|
||||
# Extra column +1 is for RBL
|
||||
# Precharge will be shifted left if needed
|
||||
# Column offset is set to port so extra column can be on left or right
|
||||
# and mirroring happens correctly
|
||||
self.precharge_array = factory.create(module_type="precharge_array",
|
||||
columns=self.num_cols + self.num_spare_cols + 1,
|
||||
bitcell_bl=self.bl_names[self.port],
|
||||
bitcell_br=self.br_names[self.port])
|
||||
bitcell_br=self.br_names[self.port],
|
||||
column_offset=self.port - 1)
|
||||
self.add_mod(self.precharge_array)
|
||||
|
||||
if self.port in self.read_ports:
|
||||
# RBLs don't get a sense amp
|
||||
self.sense_amp_array = factory.create(module_type="sense_amp_array",
|
||||
word_size=self.word_size,
|
||||
words_per_row=self.words_per_row,
|
||||
@@ -205,6 +209,7 @@ class port_data(design.design):
|
||||
self.sense_amp_array = None
|
||||
|
||||
if self.col_addr_size > 0:
|
||||
# RBLs dont get a col mux
|
||||
self.column_mux_array = factory.create(module_type="column_mux_array",
|
||||
columns=self.num_cols,
|
||||
word_size=self.word_size,
|
||||
@@ -215,6 +220,7 @@ class port_data(design.design):
|
||||
self.column_mux_array = None
|
||||
|
||||
if self.port in self.write_ports:
|
||||
# RBLs dont get a write driver
|
||||
self.write_driver_array = factory.create(module_type="write_driver_array",
|
||||
columns=self.num_cols,
|
||||
word_size=self.word_size,
|
||||
@@ -222,11 +228,11 @@ class port_data(design.design):
|
||||
num_spare_cols=self.num_spare_cols)
|
||||
self.add_mod(self.write_driver_array)
|
||||
if self.write_size is not None:
|
||||
# RBLs don't get a write mask
|
||||
self.write_mask_and_array = factory.create(module_type="write_mask_and_array",
|
||||
columns=self.num_cols,
|
||||
word_size=self.word_size,
|
||||
write_size=self.write_size,
|
||||
port = self.port)
|
||||
write_size=self.write_size)
|
||||
self.add_mod(self.write_mask_and_array)
|
||||
else:
|
||||
self.write_mask_and_array = None
|
||||
@@ -259,12 +265,6 @@ class port_data(design.design):
|
||||
self.precharge = factory.create(module_type="precharge",
|
||||
bitcell_bl=self.bl_names[0],
|
||||
bitcell_br=self.br_names[0])
|
||||
# We create a dummy here to get bl/br names to add those pins to this
|
||||
# module, which happens before we create the real precharge_array
|
||||
self.precharge_array = factory.create(module_type="precharge_array",
|
||||
columns=self.num_cols + self.num_spare_cols + 1,
|
||||
bitcell_bl=self.bl_names[self.port],
|
||||
bitcell_br=self.br_names[self.port])
|
||||
|
||||
def create_precharge_array(self):
|
||||
""" Creating Precharge """
|
||||
@@ -477,7 +477,6 @@ class port_data(design.design):
|
||||
|
||||
def route_sense_amp_out(self, port):
|
||||
""" Add pins for the sense amp output """
|
||||
|
||||
for bit in range(self.word_size + self.num_spare_cols):
|
||||
data_pin = self.sense_amp_array_inst.get_pin("data_{}".format(bit))
|
||||
self.add_layout_pin_rect_center(text="dout_{0}".format(bit),
|
||||
@@ -502,45 +501,37 @@ class port_data(design.design):
|
||||
bank_wmask_name = "bank_wmask_{}".format(bit)
|
||||
self.copy_layout_pin(self.write_mask_and_array_inst, wmask_in_name, bank_wmask_name)
|
||||
|
||||
def route_write_mask_and_array_to_write_driver(self,port):
|
||||
""" Routing of wdriver_sel_{} between write mask AND array and write driver array. Adds layout pin for write
|
||||
mask AND array output and via for write driver enable """
|
||||
def route_write_mask_and_array_to_write_driver(self, port):
|
||||
"""
|
||||
Routing of wdriver_sel_{} between write mask AND array and
|
||||
write driver array. Adds layout pin for write
|
||||
mask AND array output and via for write driver enable
|
||||
"""
|
||||
|
||||
inst1 = self.write_mask_and_array_inst
|
||||
inst2 = self.write_driver_array_inst
|
||||
wmask_inst = self.write_mask_and_array_inst
|
||||
wdriver_inst = self.write_driver_array_inst
|
||||
|
||||
loc = 0
|
||||
for bit in range(self.num_wmasks):
|
||||
# Bring write mask AND array output pin to port data level
|
||||
self.copy_layout_pin(inst1, "wmask_out_{0}".format(bit), "wdriver_sel_{0}".format(bit))
|
||||
self.copy_layout_pin(wmask_inst, "wmask_out_{0}".format(bit), "wdriver_sel_{0}".format(bit))
|
||||
|
||||
wmask_out_pin = inst1.get_pin("wmask_out_{0}".format(bit))
|
||||
wdriver_en_pin = inst2.get_pin("en_{0}".format(bit))
|
||||
wmask_out_pin = wmask_inst.get_pin("wmask_out_{0}".format(bit))
|
||||
wdriver_en_pin = wdriver_inst.get_pin("en_{0}".format(bit))
|
||||
|
||||
# The metal2 wdriver_sel_{} wire must hit the en_{} pin after the closest bitline pin that's right of the
|
||||
# the wdriver_sel_{} pin in the write driver AND array.
|
||||
if bit == 0:
|
||||
# When the write mask output pin is right of the bitline, the target is found
|
||||
while (wmask_out_pin.lx() + self.m2_pitch > inst2.get_pin("data_{0}".format(loc)).rx()):
|
||||
loc += 1
|
||||
length = inst2.get_pin("data_{0}".format(loc)).rx() + self.m2_pitch
|
||||
debug.check(loc<=self.num_wmasks,
|
||||
"Couldn't route the write mask select.")
|
||||
else:
|
||||
# Stride by the write size rather than finding the next pin to the right
|
||||
loc += self.write_size
|
||||
length = inst2.get_pin("data_{0}".format(loc)).rx() + self.m2_pitch
|
||||
wmask_pos = wmask_out_pin.center()
|
||||
wdriver_pos = wdriver_en_pin.rc() - vector(self.m2_pitch, 0)
|
||||
mid_pos = vector(wdriver_pos.x, wmask_pos.y)
|
||||
|
||||
beg_pos = wmask_out_pin.center()
|
||||
middle_pos = vector(length, wmask_out_pin.cy())
|
||||
end_pos = vector(length, wdriver_en_pin.cy())
|
||||
|
||||
# Add driver on mask output
|
||||
self.add_via_center(layers=self.m1_stack,
|
||||
offset=wmask_pos)
|
||||
# Add via for the write driver array's enable input
|
||||
self.add_via_center(layers=self.m1_stack,
|
||||
offset=end_pos)
|
||||
offset=wdriver_pos)
|
||||
|
||||
# Route between write mask AND array and write driver array
|
||||
self.add_wire(self.m1_stack, [beg_pos, middle_pos, end_pos])
|
||||
self.add_wire(self.m1_stack, [wmask_pos, mid_pos, wdriver_pos])
|
||||
|
||||
def route_column_mux_to_precharge_array(self, port):
|
||||
""" Routing of BL and BR between col mux and precharge array """
|
||||
@@ -549,15 +540,12 @@ class port_data(design.design):
|
||||
if self.col_addr_size==0:
|
||||
return
|
||||
|
||||
inst1 = self.column_mux_array_inst
|
||||
inst2 = self.precharge_array_inst
|
||||
start_bit = 1 if self.port == 0 else 0
|
||||
|
||||
insn2_start_bit = 1 if self.port == 0 else 0
|
||||
|
||||
self.connect_bitlines(inst1=inst1,
|
||||
inst2=inst2,
|
||||
self.connect_bitlines(inst1=self.column_mux_array_inst,
|
||||
inst2=self.precharge_array_inst,
|
||||
num_bits=self.num_cols,
|
||||
inst2_start_bit=insn2_start_bit)
|
||||
inst2_start_bit=start_bit)
|
||||
|
||||
def route_sense_amp_to_column_mux_or_precharge_array(self, port):
|
||||
""" Routing of BL and BR between sense_amp and column mux or precharge array """
|
||||
@@ -578,13 +566,13 @@ class port_data(design.design):
|
||||
else:
|
||||
start_bit=0
|
||||
|
||||
if self.port==0:
|
||||
off = 1
|
||||
else:
|
||||
off = 0
|
||||
|
||||
|
||||
if self.num_spare_cols != 0 and self.col_addr_size>0:
|
||||
# spare cols connected to precharge array since they are read independently
|
||||
if self.num_spare_cols and self.col_addr_size>0:
|
||||
if self.port==0:
|
||||
off = 1
|
||||
else:
|
||||
off = 0
|
||||
|
||||
self.channel_route_bitlines(inst1=self.column_mux_array_inst,
|
||||
inst1_bls_template="{inst}_out_{bit}",
|
||||
inst2=inst2,
|
||||
@@ -598,15 +586,20 @@ class port_data(design.design):
|
||||
inst1_start_bit=self.num_cols + off,
|
||||
inst2_start_bit=self.word_size)
|
||||
|
||||
# This could be a channel route, but in some techs the bitlines
|
||||
# are too close together.
|
||||
elif OPTS.tech_name == "s8":
|
||||
self.connect_bitlines(inst1=inst1,
|
||||
inst1_bls_template=inst1_bls_templ,
|
||||
inst2=inst2,
|
||||
num_bits=self.word_size,
|
||||
inst1_start_bit=start_bit)
|
||||
else:
|
||||
self.channel_route_bitlines(inst1=inst1,
|
||||
inst1_bls_template=inst1_bls_templ,
|
||||
inst2=inst2,
|
||||
num_bits=self.word_size + self.num_spare_cols,
|
||||
inst1_start_bit=start_bit)
|
||||
|
||||
|
||||
# spare cols connected to precharge array since they are read independently
|
||||
|
||||
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 """
|
||||
@@ -631,8 +624,13 @@ class port_data(design.design):
|
||||
else:
|
||||
off = 0
|
||||
|
||||
|
||||
if self.num_spare_cols != 0 and self.col_addr_size>0:
|
||||
# Channel route spare columns' bitlines
|
||||
if self.num_spare_cols and self.col_addr_size>0:
|
||||
if self.port==0:
|
||||
off = 1
|
||||
else:
|
||||
off = 0
|
||||
|
||||
self.channel_route_bitlines(inst1=self.column_mux_array_inst,
|
||||
inst1_bls_template="{inst}_out_{bit}",
|
||||
inst2=inst2,
|
||||
@@ -646,13 +644,19 @@ class port_data(design.design):
|
||||
inst1_start_bit=self.num_cols + off,
|
||||
inst2_start_bit=self.word_size)
|
||||
|
||||
# This could be a channel route, but in some techs the bitlines
|
||||
# are too close together.
|
||||
elif OPTS.tech_name == "s8":
|
||||
self.connect_bitlines(inst1=inst1, inst2=inst2,
|
||||
num_bits=self.word_size,
|
||||
inst1_bls_template=inst1_bls_templ,
|
||||
inst1_start_bit=start_bit)
|
||||
else:
|
||||
self.channel_route_bitlines(inst1=inst1,
|
||||
self.channel_route_bitlines(inst1=inst1, inst2=inst2,
|
||||
num_bits=self.word_size+self.num_spare_cols,
|
||||
inst1_bls_template=inst1_bls_templ,
|
||||
inst2=inst2,
|
||||
num_bits=self.word_size + self.num_spare_cols,
|
||||
inst1_start_bit=start_bit)
|
||||
|
||||
|
||||
|
||||
def route_write_driver_to_sense_amp(self, port):
|
||||
""" Routing of BL and BR between write driver and sense amp """
|
||||
@@ -660,11 +664,11 @@ class port_data(design.design):
|
||||
inst1 = self.write_driver_array_inst
|
||||
inst2 = self.sense_amp_array_inst
|
||||
|
||||
# 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.num_spare_cols)
|
||||
# This could be a channel route, but in some techs the bitlines
|
||||
# are too close together.
|
||||
self.connect_bitlines(inst1=inst1,
|
||||
inst2=inst2,
|
||||
num_bits=self.word_size + self.num_spare_cols)
|
||||
|
||||
def route_bitline_pins(self):
|
||||
""" Add the bitline pins for the given port """
|
||||
@@ -787,10 +791,9 @@ class port_data(design.design):
|
||||
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)
|
||||
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!
|
||||
@@ -799,13 +802,8 @@ class port_data(design.design):
|
||||
bottom_names = self._get_bitline_pins(bot_inst_group, bit)
|
||||
top_names = self._get_bitline_pins(top_inst_group, bit)
|
||||
|
||||
if bottom_names[0].layer == "m2":
|
||||
bitline_dirs = ("H", "V")
|
||||
elif bottom_names[0].layer == "m1":
|
||||
bitline_dirs = ("V", "H")
|
||||
|
||||
route_map = list(zip(bottom_names, top_names))
|
||||
self.create_horizontal_channel_route(route_map, offset, self.m1_stack, bitline_dirs)
|
||||
self.create_horizontal_channel_route(route_map, offset, self.m1_stack)
|
||||
|
||||
def connect_bitlines(self, inst1, inst2, num_bits,
|
||||
inst1_bls_template="{inst}_{bit}",
|
||||
@@ -817,11 +815,10 @@ class port_data(design.design):
|
||||
This assumes that they have sufficient space to create a jog
|
||||
in the middle between the two modules (if needed).
|
||||
"""
|
||||
|
||||
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)
|
||||
|
||||
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)
|
||||
|
||||
for col in range(num_bits):
|
||||
bot_bl_pin, bot_br_pin = self._get_bitline_pins(bot_inst_group, col)
|
||||
@@ -829,18 +826,11 @@ class port_data(design.design):
|
||||
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 + 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", [bot_br,
|
||||
vector(bot_br.x, yoffset),
|
||||
vector(top_br.x, yoffset),
|
||||
top_br])
|
||||
|
||||
layer_pitch = getattr(self, "{}_pitch".format(top_bl_pin.layer))
|
||||
self.add_zjog(bot_bl_pin.layer, bot_bl, top_bl, "V", fixed_offset=top_bl_pin.by() - layer_pitch)
|
||||
self.add_zjog(bot_br_pin.layer, bot_br, top_br, "V", fixed_offset=top_bl_pin.by() - 2 * layer_pitch)
|
||||
|
||||
def graph_exclude_precharge(self):
|
||||
"""Precharge adds a loop between bitlines, can be excluded to reduce complexity"""
|
||||
if self.precharge_array_inst:
|
||||
self.graph_inst_exclude.add(self.precharge_array_inst)
|
||||
|
||||
|
||||
Reference in New Issue
Block a user