mirror of https://github.com/VLSIDA/OpenRAM.git
Update local bitcell array for dual port
This commit is contained in:
parent
e215c0e016
commit
593a98e29a
|
|
@ -29,6 +29,9 @@ class local_bitcell_array(bitcell_base_array.bitcell_base_array):
|
||||||
self.add_rbl = rbl
|
self.add_rbl = rbl
|
||||||
else:
|
else:
|
||||||
self.add_rbl = add_rbl
|
self.add_rbl = add_rbl
|
||||||
|
|
||||||
|
debug.check(len(self.all_ports) < 3, "Local bitcell array only supports dual port or less.")
|
||||||
|
|
||||||
self.create_netlist()
|
self.create_netlist()
|
||||||
if not OPTS.netlist_only:
|
if not OPTS.netlist_only:
|
||||||
self.create_layout()
|
self.create_layout()
|
||||||
|
|
@ -68,7 +71,7 @@ class local_bitcell_array(bitcell_base_array.bitcell_base_array):
|
||||||
self.add_mod(self.bitcell_array)
|
self.add_mod(self.bitcell_array)
|
||||||
|
|
||||||
self.wl_array = factory.create(module_type="wordline_buffer_array",
|
self.wl_array = factory.create(module_type="wordline_buffer_array",
|
||||||
rows=self.rows + len(self.all_ports),
|
rows=self.rows + 1,
|
||||||
cols=self.cols)
|
cols=self.cols)
|
||||||
self.add_mod(self.wl_array)
|
self.add_mod(self.wl_array)
|
||||||
|
|
||||||
|
|
@ -76,18 +79,48 @@ class local_bitcell_array(bitcell_base_array.bitcell_base_array):
|
||||||
|
|
||||||
self.bitline_names = self.bitcell_array.get_all_bitline_names()
|
self.bitline_names = self.bitcell_array.get_all_bitline_names()
|
||||||
|
|
||||||
self.driver_wordline_inputs = [x for x in self.bitcell_array.get_all_wordline_names() if not x.startswith("dummy")]
|
self.driver_wordline_inputs = []
|
||||||
self.driver_wordline_outputs = [x + "i" for x in self.driver_wordline_inputs]
|
self.driver_wordline_outputs = []
|
||||||
self.array_wordline_inputs = [x + "i" if not x.startswith("dummy") else "gnd" for x in self.bitcell_array.get_all_wordline_names()]
|
self.array_wordline_inputs = []
|
||||||
|
|
||||||
|
# Port 0
|
||||||
|
wordline_inputs = [x for x in self.bitcell_array.get_wordline_names(0) if not x.startswith("dummy")]
|
||||||
|
if len(self.all_ports) > 1:
|
||||||
|
# Drop off the RBL for port 1
|
||||||
|
self.driver_wordline_inputs.append(wordline_inputs[:-1])
|
||||||
|
else:
|
||||||
|
self.driver_wordline_inputs.append(wordline_inputs)
|
||||||
|
self.driver_wordline_outputs.append([x + "i" for x in self.driver_wordline_inputs[-1]])
|
||||||
|
self.array_wordline_inputs.append([x + "i" if not x.startswith("dummy") else "gnd" for x in self.bitcell_array.get_wordline_names(0)])
|
||||||
|
|
||||||
|
# Port 1
|
||||||
|
if len(self.all_ports) > 1:
|
||||||
|
self.driver_wordline_inputs.append([x for x in self.bitcell_array.get_wordline_names(1) if not x.startswith("dummy")][1:])
|
||||||
|
self.driver_wordline_outputs.append([x + "i" for x in self.driver_wordline_inputs[-1]])
|
||||||
|
self.array_wordline_inputs.append([x + "i" if not x.startswith("dummy") else "gnd" for x in self.bitcell_array.get_wordline_names(1)])
|
||||||
|
|
||||||
|
self.all_driver_wordline_inputs = [x for x in self.bitcell_array.get_wordline_names() if not x.startswith("dummy")]
|
||||||
self.replica_names = self.bitcell_array.get_rbl_wordline_names()
|
self.replica_names = self.bitcell_array.get_rbl_wordline_names()
|
||||||
|
|
||||||
|
self.gnd_wl_names = []
|
||||||
|
|
||||||
|
# Connect unused RBL WL to gnd
|
||||||
|
array_rbl_names = set([x for x in self.bitcell_array.get_all_wordline_names() if x.startswith("rbl")])
|
||||||
|
dummy_rbl_names = set([x for x in self.bitcell_array.get_all_wordline_names() if x.startswith("dummy")])
|
||||||
|
rbl_wl_names = set([self.bitcell_array.get_rbl_wordline_names(x) for x in self.all_ports])
|
||||||
|
self.gnd_wl_names = list((array_rbl_names - rbl_wl_names) | dummy_rbl_names)
|
||||||
|
|
||||||
|
self.all_array_wordline_inputs = [x + "i" if x not in self.gnd_wl_names else "gnd" for x in self.bitcell_array.get_wordline_names()]
|
||||||
|
|
||||||
|
|
||||||
self.bitline_names = self.bitcell_array.get_inouts()
|
self.bitline_names = self.bitcell_array.get_inouts()
|
||||||
# Arrays are always:
|
# Arrays are always:
|
||||||
# word lines (bottom to top)
|
# word lines (bottom to top)
|
||||||
# bit lines (left to right)
|
# bit lines (left to right)
|
||||||
# vdd
|
# vdd
|
||||||
# gnd
|
# gnd
|
||||||
self.add_pin_list(self.driver_wordline_inputs, "INPUT")
|
for port in self.all_ports:
|
||||||
|
self.add_pin_list(self.all_driver_wordline_inputs, "INPUT")
|
||||||
self.add_pin_list(self.bitline_names, "INOUT")
|
self.add_pin_list(self.bitline_names, "INOUT")
|
||||||
self.add_pin("vdd", "POWER")
|
self.add_pin("vdd", "POWER")
|
||||||
self.add_pin("gnd", "GROUND")
|
self.add_pin("gnd", "GROUND")
|
||||||
|
|
@ -95,39 +128,39 @@ class local_bitcell_array(bitcell_base_array.bitcell_base_array):
|
||||||
def create_instances(self):
|
def create_instances(self):
|
||||||
""" Create the module instances used in this design """
|
""" Create the module instances used in this design """
|
||||||
|
|
||||||
self.wl_inst = self.add_inst(name="wl_driver",
|
self.wl_insts = []
|
||||||
mod=self.wl_array)
|
for port in self.all_ports:
|
||||||
self.connect_inst(self.driver_wordline_inputs + self.driver_wordline_outputs + ["vdd", "gnd"])
|
self.wl_insts.append(self.add_inst(name="wl_driver",
|
||||||
|
mod=self.wl_array))
|
||||||
|
self.connect_inst(self.driver_wordline_inputs[port] + self.driver_wordline_outputs[port] + ["vdd", "gnd"])
|
||||||
|
|
||||||
self.bitcell_array_inst = self.add_inst(name="array",
|
self.bitcell_array_inst = self.add_inst(name="array",
|
||||||
mod=self.bitcell_array,
|
mod=self.bitcell_array)
|
||||||
offset=self.wl_inst.lr())
|
|
||||||
self.connect_inst(self.array_wordline_inputs + self.bitline_names + ["vdd", "gnd"])
|
self.connect_inst(self.all_array_wordline_inputs + self.bitline_names + ["vdd", "gnd"])
|
||||||
|
|
||||||
def place(self):
|
def place(self):
|
||||||
""" Place the bitcelll array to the right of the wl driver. """
|
""" Place the bitcelll array to the right of the wl driver. """
|
||||||
|
|
||||||
self.wl_inst.place(vector(0, self.cell.height))
|
|
||||||
# FIXME: Replace this with a tech specific paramter
|
# FIXME: Replace this with a tech specific paramter
|
||||||
driver_to_array_spacing = 3 * self.m3_pitch
|
driver_to_array_spacing = 3 * self.m3_pitch
|
||||||
self.bitcell_array_inst.place(vector(self.wl_inst.rx() + driver_to_array_spacing,
|
|
||||||
|
self.wl_insts[0].place(vector(0, self.cell.height))
|
||||||
|
|
||||||
|
self.bitcell_array_inst.place(vector(self.wl_insts[0].rx() + driver_to_array_spacing,
|
||||||
0))
|
0))
|
||||||
|
|
||||||
|
if len(self.all_ports) > 1:
|
||||||
|
self.wl_insts[1].place(vector(self.bitcell_array_inst.rx() + self.wl_array.width + driver_to_array_spacing,
|
||||||
|
2 * self.cell.height),
|
||||||
|
mirror="MY")
|
||||||
|
|
||||||
self.height = self.bitcell_array.height
|
self.height = self.bitcell_array.height
|
||||||
self.width = self.bitcell_array_inst.rx()
|
self.width = self.bitcell_array_inst.rx()
|
||||||
|
|
||||||
def route_unused_wordlines(self):
|
def route_unused_wordlines(self):
|
||||||
""" Connect the unused RBL and dummy wordlines to gnd """
|
""" Connect the unused RBL and dummy wordlines to gnd """
|
||||||
gnd_wl_names = []
|
|
||||||
|
|
||||||
# Connect unused RBL WL to gnd
|
for wl_name in self.gnd_wl_names:
|
||||||
array_rbl_names = set([x for x in self.bitcell_array.get_all_wordline_names() if x.startswith("rbl")])
|
|
||||||
dummy_rbl_names = set([x for x in self.bitcell_array.get_all_wordline_names() if x.startswith("dummy")])
|
|
||||||
rbl_wl_names = set([self.bitcell_array.get_rbl_wordline_names(x) for x in self.all_ports])
|
|
||||||
|
|
||||||
gnd_wl_names = list((array_rbl_names - rbl_wl_names) | dummy_rbl_names)
|
|
||||||
|
|
||||||
for wl_name in gnd_wl_names:
|
|
||||||
pin = self.bitcell_array_inst.get_pin(wl_name)
|
pin = self.bitcell_array_inst.get_pin(wl_name)
|
||||||
pin_layer = pin.layer
|
pin_layer = pin.layer
|
||||||
layer_pitch = 1.5 * getattr(self, "{}_pitch".format(pin_layer))
|
layer_pitch = 1.5 * getattr(self, "{}_pitch".format(pin_layer))
|
||||||
|
|
@ -149,10 +182,11 @@ class local_bitcell_array(bitcell_base_array.bitcell_base_array):
|
||||||
for (x, y) in zip(self.bitline_names, self.bitcell_array.get_inouts()):
|
for (x, y) in zip(self.bitline_names, self.bitcell_array.get_inouts()):
|
||||||
self.copy_layout_pin(self.bitcell_array_inst, y, x)
|
self.copy_layout_pin(self.bitcell_array_inst, y, x)
|
||||||
|
|
||||||
for (x, y) in zip(self.driver_wordline_inputs, self.wl_array.get_inputs()):
|
for port in self.all_ports:
|
||||||
self.copy_layout_pin(self.wl_inst, y, x)
|
for (x, y) in zip(self.driver_wordline_inputs[port], self.wl_array.get_inputs()):
|
||||||
|
self.copy_layout_pin(self.wl_insts[port], y, x)
|
||||||
|
|
||||||
supply_insts = [self.wl_inst, self.bitcell_array_inst]
|
supply_insts = [*self.wl_insts, self.bitcell_array_inst]
|
||||||
for pin_name in ["vdd", "gnd"]:
|
for pin_name in ["vdd", "gnd"]:
|
||||||
for inst in supply_insts:
|
for inst in supply_insts:
|
||||||
pin_list = inst.get_pins(pin_name)
|
pin_list = inst.get_pins(pin_name)
|
||||||
|
|
@ -162,12 +196,28 @@ class local_bitcell_array(bitcell_base_array.bitcell_base_array):
|
||||||
start_layer=pin.layer)
|
start_layer=pin.layer)
|
||||||
|
|
||||||
def route(self):
|
def route(self):
|
||||||
array_names = [x for x in self.bitcell_array.get_all_wordline_names() if not x.startswith("dummy")]
|
|
||||||
|
for port in self.all_ports:
|
||||||
|
if port == 0:
|
||||||
|
array_names = [x for x in self.bitcell_array.get_wordline_names(port) if not x.startswith("dummy")]
|
||||||
|
if len(self.all_ports) > 1:
|
||||||
|
# Drop off the RBL for port 1
|
||||||
|
array_names = array_names[:-1]
|
||||||
|
else:
|
||||||
|
array_names = [x for x in self.bitcell_array.get_wordline_names(port) if not x.startswith("dummy")][1:]
|
||||||
|
|
||||||
for (driver_name, array_name) in zip(self.wl_array.get_outputs(), array_names):
|
for (driver_name, array_name) in zip(self.wl_array.get_outputs(), array_names):
|
||||||
out_pin = self.wl_inst.get_pin(driver_name)
|
out_pin = self.wl_insts[port].get_pin(driver_name)
|
||||||
in_pin = self.bitcell_array_inst.get_pin(array_name)
|
in_pin = self.bitcell_array_inst.get_pin(array_name)
|
||||||
mid_loc = self.wl_inst.rx() + 1.5 * self.m3_pitch
|
if port == 0:
|
||||||
self.add_path(out_pin.layer, [out_pin.rc(), vector(mid_loc, out_pin.cy()), in_pin.lc()])
|
out_loc = out_pin.rc()
|
||||||
|
mid_loc = vector(self.wl_insts[port].rx() + 1.5 * self.m3_pitch, out_loc.y)
|
||||||
|
in_loc = in_pin.lc()
|
||||||
|
else:
|
||||||
|
out_loc = out_pin.lc()
|
||||||
|
mid_loc = vector(self.wl_insts[port].lx() - 1.5 * self.m3_pitch, out_loc.y)
|
||||||
|
in_loc = in_pin.rc()
|
||||||
|
self.add_path(out_pin.layer, [out_loc, mid_loc, in_loc])
|
||||||
|
|
||||||
self.route_unused_wordlines()
|
self.route_unused_wordlines()
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -219,7 +219,9 @@ class replica_bitcell_array(bitcell_base_array.bitcell_base_array):
|
||||||
|
|
||||||
def add_wordline_pins(self):
|
def add_wordline_pins(self):
|
||||||
|
|
||||||
# All wordline names for all ports
|
# Regular wordline names
|
||||||
|
self.main_wordline_names = []
|
||||||
|
# Create the full WL names include dummy, replica, and regular bit cells
|
||||||
self.wordline_names = []
|
self.wordline_names = []
|
||||||
# Wordline names for each port
|
# Wordline names for each port
|
||||||
self.wordline_names_by_port = [[] for x in self.all_ports]
|
self.wordline_names_by_port = [[] for x in self.all_ports]
|
||||||
|
|
@ -234,9 +236,6 @@ class replica_bitcell_array(bitcell_base_array.bitcell_base_array):
|
||||||
# These are the non-indexed names
|
# These are the non-indexed names
|
||||||
dummy_cell_wl_names = ["dummy_" + x for x in self.cell.get_all_wl_names()]
|
dummy_cell_wl_names = ["dummy_" + x for x in self.cell.get_all_wl_names()]
|
||||||
|
|
||||||
# Create the full WL names include dummy, replica, and regular bit cells
|
|
||||||
self.wordline_names = []
|
|
||||||
|
|
||||||
self.dummy_wordline_names["bot"] = ["{0}_bot".format(x) for x in dummy_cell_wl_names]
|
self.dummy_wordline_names["bot"] = ["{0}_bot".format(x) for x in dummy_cell_wl_names]
|
||||||
self.wordline_names.extend(self.dummy_wordline_names["bot"])
|
self.wordline_names.extend(self.dummy_wordline_names["bot"])
|
||||||
|
|
||||||
|
|
@ -250,6 +249,7 @@ class replica_bitcell_array(bitcell_base_array.bitcell_base_array):
|
||||||
|
|
||||||
# Regular WLs
|
# Regular WLs
|
||||||
self.wordline_names.extend(self.bitcell_array_wordline_names)
|
self.wordline_names.extend(self.bitcell_array_wordline_names)
|
||||||
|
self.main_wordline_names = self.bitcell_array_wordline_names
|
||||||
|
|
||||||
# Right port WLs
|
# Right port WLs
|
||||||
for port in range(self.left_rbl, self.left_rbl + self.right_rbl):
|
for port in range(self.left_rbl, self.left_rbl + self.right_rbl):
|
||||||
|
|
@ -490,9 +490,14 @@ class replica_bitcell_array(bitcell_base_array.bitcell_base_array):
|
||||||
bl_names = self.replica_bitline_names[port]
|
bl_names = self.replica_bitline_names[port]
|
||||||
return bl_names[2 * port:2 * port + 2]
|
return bl_names[2 * port:2 * port + 2]
|
||||||
|
|
||||||
def get_wordline_names(self):
|
def get_wordline_names(self, port=None):
|
||||||
""" Return the wordline names """
|
""" Return the wordline names """
|
||||||
|
if port == None:
|
||||||
return self.wordline_names
|
return self.wordline_names
|
||||||
|
else:
|
||||||
|
wl_name = self.cell.get_all_wl_names()[port]
|
||||||
|
temp = [x for x in self.wordline_names if wl_name in x]
|
||||||
|
return temp
|
||||||
|
|
||||||
def get_bitline_names(self):
|
def get_bitline_names(self):
|
||||||
""" Return the bitline names """
|
""" Return the bitline names """
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue