Add dummy bitcell module.

Modify bitcell logic to guess if bitcell is not "bitcell"
No longer need to specify replica (and dummy) bitcell explicitly
Add support for 1 or 2 port replica array.
This commit is contained in:
mrg 2019-07-05 12:57:12 -07:00
parent f542613d78
commit b9d993c88b
12 changed files with 208 additions and 76 deletions

View File

@ -0,0 +1,53 @@
# See LICENSE for licensing information.
#
# Copyright (c) 2016-2019 Regents of the University of California and The Board
# of Regents for the Oklahoma Agricultural and Mechanical College
# (acting for and on behalf of Oklahoma State University)
# All rights reserved.
#
import design
import debug
import utils
from tech import GDS,layer,drc,parameter
class dummy_bitcell_1rw_1r(design.design):
"""
A single bit cell which is forced to store a 0.
This module implements the single memory cell used in the design. It
is a hand-made cell, so the layout and netlist should be available in
the technology library. """
pin_names = ["bl0", "br0", "bl1", "br1", "wl0", "wl1", "vdd", "gnd"]
type_list = ["OUTPUT", "OUTPUT", "OUTPUT", "OUTPUT", "INPUT", "INPUT", "POWER", "GROUND"]
(width,height) = utils.get_libcell_size("dummy_cell_1rw_1r", GDS["unit"], layer["boundary"])
pin_map = utils.get_libcell_pins(pin_names, "dummy_cell_1rw_1r", GDS["unit"])
def __init__(self, name=""):
# Ignore the name argument
design.design.__init__(self, "dummy_cell_1rw_1r")
debug.info(2, "Create dummy bitcell 1rw+1r object")
self.width = dummy_bitcell_1rw_1r.width
self.height = dummy_bitcell_1rw_1r.height
self.pin_map = dummy_bitcell_1rw_1r.pin_map
self.add_pin_types(self.type_list)
def get_wl_cin(self):
"""Return the relative capacitance of the access transistor gates"""
#This is a handmade cell so the value must be entered in the tech.py file or estimated.
#Calculated in the tech file by summing the widths of all the related gates and dividing by the minimum width.
#FIXME: sizing is not accurate with the handmade cell. Change once cell widths are fixed.
access_tx_cin = parameter["6T_access_size"]/drc["minwidth_tx"]
return 2*access_tx_cin
def build_graph(self, graph, inst_name, port_nets):
"""Adds edges to graph. Multiport bitcell timing graph is too complex
to use the add_graph_edges function."""
pin_dict = {pin:port for pin,port in zip(self.pins, port_nets)}
#Edges hardcoded here. Essentially wl->bl/br for both ports.
# Port 0 edges
graph.add_edge(pin_dict["wl0"], pin_dict["bl0"])
graph.add_edge(pin_dict["wl0"], pin_dict["br0"])
# Port 1 edges
graph.add_edge(pin_dict["wl1"], pin_dict["bl1"])
graph.add_edge(pin_dict["wl1"], pin_dict["br1"])

View File

@ -0,0 +1,51 @@
# See LICENSE for licensing information.
#
# Copyright (c) 2016-2019 Regents of the University of California and The Board
# of Regents for the Oklahoma Agricultural and Mechanical College
# (acting for and on behalf of Oklahoma State University)
# All rights reserved.
#
import design
import debug
import utils
from tech import GDS,layer,drc,parameter
class dummy_bitcell_1w_1r(design.design):
"""
A single bit cell which is forced to store a 0.
This module implements the single memory cell used in the design. It
is a hand-made cell, so the layout and netlist should be available in
the technology library. """
pin_names = ["bl0", "br0", "bl1", "br1", "wl0", "wl1", "vdd", "gnd"]
type_list = ["OUTPUT", "OUTPUT", "INPUT", "INPUT", "INPUT", "INPUT", "POWER", "GROUND"]
(width,height) = utils.get_libcell_size("dummy_cell_1w_1r", GDS["unit"], layer["boundary"])
pin_map = utils.get_libcell_pins(pin_names, "dummy_cell_1w_1r", GDS["unit"])
def __init__(self, name=""):
# Ignore the name argument
design.design.__init__(self, "dummy_cell_1w_1r")
debug.info(2, "Create dummy bitcell 1w+1r object")
self.width = dummy_bitcell_1w_1r.width
self.height = dummy_bitcell_1w_1r.height
self.pin_map = dummy_bitcell_1w_1r.pin_map
self.add_pin_types(self.type_list)
def get_wl_cin(self):
"""Return the relative capacitance of the access transistor gates"""
#This is a handmade cell so the value must be entered in the tech.py file or estimated.
#Calculated in the tech file by summing the widths of all the related gates and dividing by the minimum width.
#FIXME: sizing is not accurate with the handmade cell. Change once cell widths are fixed.
access_tx_cin = parameter["6T_access_size"]/drc["minwidth_tx"]
return 2*access_tx_cin
def build_graph(self, graph, inst_name, port_nets):
"""Adds edges to graph. Multiport bitcell timing graph is too complex
to use the add_graph_edges function."""
pin_dict = {pin:port for pin,port in zip(self.pins, port_nets)}
#Edges hardcoded here. Essentially wl->bl/br for both ports.
# Port 0 edges
graph.add_edge(pin_dict["wl0"], pin_dict["bl0"])
graph.add_edge(pin_dict["wl0"], pin_dict["br0"])
# Port 1 is a write port, so its timing is not considered here.

View File

@ -169,11 +169,12 @@ def setup_bitcell():
# If we have non-1rw ports,
# and the user didn't over-ride the bitcell manually,
# figure out the right bitcell to use
if (OPTS.bitcell=="bitcell" and OPTS.replica_bitcell=="replica_bitcell"):
if (OPTS.bitcell=="bitcell"):
if (OPTS.num_rw_ports==1 and OPTS.num_w_ports==0 and OPTS.num_r_ports==0):
OPTS.bitcell = "bitcell"
OPTS.replica_bitcell = "replica_bitcell"
OPTS.dummy_bitcell = "dummy_bitcell"
else:
ports = ""
if OPTS.num_rw_ports>0:
@ -185,21 +186,26 @@ def setup_bitcell():
OPTS.bitcell = "bitcell_"+ports
OPTS.replica_bitcell = "replica_bitcell_"+ports
# See if a custom bitcell exists
from importlib import find_loader
try:
__import__(OPTS.bitcell)
__import__(OPTS.replica_bitcell)
except ImportError:
# Use the pbitcell if we couldn't find a custom bitcell
# or its custom replica bitcell
# Use the pbitcell (and give a warning if not in unit test mode)
OPTS.bitcell = "pbitcell"
OPTS.replica_bitcell = "replica_pbitcell"
if not OPTS.is_unit_test:
debug.warning("Using the parameterized bitcell which may have suboptimal density.")
OPTS.dummy_bitcell = "dummy_bitcell_"+ports
else:
OPTS.replica_bitcell = "replica_" + OPTS.bitcell
OPTS.replica_bitcell = "dummy_" + OPTS.bitcell
# See if bitcell exists
from importlib import find_loader
try:
__import__(OPTS.bitcell)
__import__(OPTS.replica_bitcell)
__import__(OPTS.dummy_bitcell)
except ImportError:
# Use the pbitcell if we couldn't find a custom bitcell
# or its custom replica bitcell
# Use the pbitcell (and give a warning if not in unit test mode)
OPTS.bitcell = "pbitcell"
OPTS.replica_bitcell = "replica_pbitcell"
OPTS.replica_bitcell = "dummy_pbitcell"
if not OPTS.is_unit_test:
debug.warning("Using the parameterized bitcell which may have suboptimal density.")
debug.info(1,"Using bitcell: {}".format(OPTS.bitcell))

View File

@ -148,11 +148,12 @@ class bank(design.design):
# The center point for these cells are the upper-right corner of
# the bitcell array.
# The decoder/driver logic is placed on the right and mirrored on Y-axis.
# The write/sense/precharge/mux is placed on the top and mirrored on the X-axis.
# The port address decoder/driver logic is placed on the right and mirrored on X- and Y-axis.
# The port data write/sense/precharge/mux is placed on the top and mirrored on the X-axis.
self.bitcell_array_top = self.bitcell_array.height
self.bitcell_array_right = self.bitcell_array.width + self.m1_width + self.m2_gap
self.bitcell_array_right = self.bitcell_array.width + self.m1_width + self.m2_gap
# Offset past the dummy/RBL column
self.bitcell_array_left = 2*self.bitcell.width
self.compute_instance_port0_offsets()
if len(self.all_ports)==2:
@ -161,7 +162,7 @@ class bank(design.design):
def compute_instance_port0_offsets(self):
"""
Compute the instance offsets for port0.
Compute the instance offsets for port0 on the left/bottom of the bank.
"""
port = 0
@ -172,17 +173,15 @@ class bank(design.design):
# LOWER RIGHT QUADRANT
# Below the bitcell array
self.port_data_offsets[port] = vector(0,0)
self.port_data_offsets[port] = vector(self.bitcell_array_left,0)
# UPPER LEFT QUADRANT
# To the left of the bitcell array
# The wordline driver is placed to the right of the main decoder width.
x_offset = self.m2_gap + self.port_address.width
self.port_address_offsets[port] = vector(-x_offset,0)
# LOWER LEFT QUADRANT
# Place the col decoder left aligned with wordline driver plus halfway under row decoder
# Place the col decoder left aligned with row decoder (x_offset doesn't change)
# Place the col decoder left aligned with wordline driver
# Below the bitcell array with well spacing
x_offset = self.central_bus_width[port] + self.port_address.wordline_driver.width
if self.col_addr_size > 0:
@ -204,7 +203,7 @@ class bank(design.design):
def compute_instance_port1_offsets(self):
"""
Compute the instance offsets for port1 on the top of the bank.
Compute the instance offsets for port1 on the right/top of the bank.
"""
port=1
@ -218,12 +217,11 @@ class bank(design.design):
# LOWER RIGHT QUADRANT
# To the left of the bitcell array
# The wordline driver is placed to the right of the main decoder width.
x_offset = self.bitcell_array_right + self.port_address.width + self.m2_gap
self.port_address_offsets[port] = vector(x_offset,0)
# UPPER RIGHT QUADRANT
# Place the col decoder right aligned with wordline driver plus halfway under row decoder
# Place the col decoder right aligned with wordline driver
# Above the bitcell array with a well spacing
x_offset = self.bitcell_array_right + self.central_bus_width[port] + self.port_address.wordline_driver.width
if self.col_addr_size > 0:
@ -247,16 +245,12 @@ class bank(design.design):
self.compute_instance_offsets()
# UPPER RIGHT QUADRANT
self.place_bitcell_array(self.bitcell_array_offset)
# LOWER RIGHT QUADRANT
self.place_port_data(self.port_data_offsets)
# UPPER LEFT QUADRANT
self.place_port_address(self.port_address_offsets)
# LOWER LEFT QUADRANT
self.place_column_decoder(self.column_decoder_offsets)
self.place_bank_select(self.bank_select_offsets)
@ -274,11 +268,6 @@ class bank(design.design):
debug.check(self.num_rows*self.num_cols==self.word_size*self.num_words,"Invalid bank sizes.")
debug.check(self.addr_size==self.col_addr_size + self.row_addr_size,"Invalid address break down.")
# Width for the vdd/gnd rails
self.supply_rail_width = 4*self.m2_width
# FIXME: This spacing should be width dependent...
self.supply_rail_pitch = self.supply_rail_width + 4*self.m2_space
# The order of the control signals on the control bus:
self.input_control_signals = []
port_num = 0
@ -328,7 +317,7 @@ class bank(design.design):
self.wl_names = self.bitcell.list_all_wl_names()
self.bitline_names = self.bitcell.list_all_bitline_names()
self.bitcell_array = factory.create(module_type="bitcell_array",
self.bitcell_array = factory.create(module_type="replica_bitcell_array",
cols=self.num_cols,
rows=self.num_rows)
self.add_mod(self.bitcell_array)
@ -358,11 +347,14 @@ class bank(design.design):
self.bitcell_array_inst=self.add_inst(name="bitcell_array",
mod=self.bitcell_array)
print(self.bitcell_array.pins)
temp = []
for col in range(self.num_cols):
for bitline in self.bitline_names:
temp.append(bitline+"_{0}".format(col))
for col in range(2):
for bitline in self.bitline_names:
temp.append("replica_"+bitline+"_{0}".format(col))
for row in range(self.num_rows):
for wordline in self.wl_names:
temp.append(wordline+"_{0}".format(row))

View File

@ -22,13 +22,18 @@ class replica_bitcell_array(design.design):
Dummy are the outside columns/rows with WL and BL tied to gnd.
Requires a regular bitcell array, replica bitcell, and dummy bitcell (Bl/BR disconnected).
"""
def __init__(self, cols, rows, name):
def __init__(self, cols, rows, num_ports, name):
design.design.__init__(self, name)
debug.info(1, "Creating {0} {1} x {2}".format(self.name, rows, cols))
self.add_comment("rows: {0} cols: {1}".format(rows, cols))
self.column_size = cols
self.row_size = rows
self.num_ports = num_ports
# Two dummy rows/cols plus replica for each port
self.extra_rows = 2 + self.num_ports
self.extra_cols = 2 + self.num_ports
self.create_netlist()
if not OPTS.netlist_only:
@ -80,19 +85,20 @@ class replica_bitcell_array(design.design):
# Replica bitline
self.replica_column = factory.create(module_type="replica_column",
rows=self.row_size + 4)
rows=self.row_size + self.extra_rows,
num_ports = self.num_ports)
self.add_mod(self.replica_column)
# Dummy row
self.dummy_row = factory.create(module_type="dummy_array",
rows=1,
cols=self.column_size)
cols=self.column_size,
rows=1)
self.add_mod(self.dummy_row)
# Dummy col
self.dummy_col = factory.create(module_type="dummy_array",
cols=1,
rows=self.row_size + 4)
rows=self.row_size + self.extra_rows)
self.add_mod(self.dummy_col)
@ -103,27 +109,33 @@ class replica_bitcell_array(design.design):
self.bl_names = [x for x in self.bitcell_array.pins if x.startswith("b")]
# top/bottom rows (in the middle)
self.replica_wl_names = ["replica_"+x for x in self.cell.pins if x.startswith("w")]
self.dummy_wl_names = ["dummy_"+x for x in self.cell.pins if x.startswith("w")]
self.dummy_bl_names = ["dummy_"+x for x in self.cell.pins if x.startswith("b")]
self.replica_wl_names = ["replica_"+x for x in self.cell.list_all_wl_names()]
self.dummy_wl_names = ["dummy_"+x for x in self.cell.list_all_wl_names()]
self.dummy_bl_names = ["dummy_"+x for x in self.cell.list_all_bitline_names()]
self.dummy_row_bl_names = self.bl_names
# dummy row and replica on each side of the bitcell rows
self.replica_col_wl_names = [x+"_0" for x in self.dummy_wl_names] \
+ ["replica_"+x+"_0" for x in self.cell.list_all_wl_names()] \
+ self.wl_names \
+ ["replica_"+x+"_1" for x in self.cell.list_all_wl_names()] \
+ [x+"_1" for x in self.dummy_wl_names]
self.replica_bl_names = ["replica_"+x for x in self.cell.pins if x.startswith("b")]
+ self.wl_names
if self.num_ports==2:
self.replica_col_wl_names.extend(["replica_"+x+"_1" for x in self.cell.list_all_wl_names()])
self.replica_col_wl_names.extend([x+"_1" for x in self.dummy_wl_names])
self.replica_bl_names = ["replica_"+x for x in self.cell.list_all_bitline_names()]
self.replica_bl0_names = [x+"_0" for x in self.replica_bl_names]
self.replica_bl1_names = [x+"_1" for x in self.replica_bl_names]
# left/right rows
self.dummy_col_wl_names = self.replica_col_wl_names
self.add_pin_list(self.bl_names)
self.add_pin_list([x+"_0" for x in self.replica_bl_names])
self.add_pin_list([x+"_1" for x in self.replica_bl_names])
self.add_pin_list([x for x in self.replica_col_wl_names if not x.startswith("dummy")])
self.add_pin_list(self.replica_bl0_names)
if self.num_ports==2:
self.add_pin_list(self.replica_bl1_names)
self.add_pin_list(self.wl_names)
self.add_pin_list(self.replica_wl_names)
#self.add_pin_list([x for x in self.replica_col_wl_names if not x.startswith("dummy")])
self.add_pin("vdd")
self.add_pin("gnd")
@ -142,10 +154,11 @@ class replica_bitcell_array(design.design):
self.replica_col_left_inst=self.add_inst(name="replica_col_left",
mod=self.replica_column)
self.connect_inst([x+"_0" for x in self.replica_bl_names] + self.replica_col_wl_names + supplies)
self.replica_col_right_inst=self.add_inst(name="replica_col_right",
mod=self.replica_column)
self.connect_inst([x+"_1" for x in self.replica_bl_names] + self.replica_col_wl_names[::-1] + supplies)
if self.num_ports==2:
self.replica_col_right_inst=self.add_inst(name="replica_col_right",
mod=self.replica_column)
self.connect_inst([x+"_1" for x in self.replica_bl_names] + self.replica_col_wl_names[::-1] + supplies)
# Replica rows with replica bitcell
self.dummy_row_bottop_inst=self.add_inst(name="dummy_row_bottop",
@ -177,16 +190,17 @@ class replica_bitcell_array(design.design):
def create_layout(self):
self.height = (self.row_size+4)*self.dummy_row.height
self.width = (self.column_size+4)*self.replica_column.width
self.height = (self.row_size+self.extra_rows)*self.dummy_row.height
self.width = (self.column_size+self.extra_cols)*self.replica_column.width
# This is a bitcell x bitcell offset to scale
offset = vector(self.replica_column.width, self.dummy_row.height)
self.bitcell_array_inst.place(offset=[0,0])
self.replica_col_left_inst.place(offset=offset.scale(-1,-2))
self.replica_col_right_inst.place(offset=offset.scale(0,2)+self.bitcell_array_inst.ur(),
mirror="MX")
if self.num_ports==2:
self.replica_col_right_inst.place(offset=offset.scale(0,2)+self.bitcell_array_inst.ur(),
mirror="MX")
self.dummy_row_toptop_inst.place(offset=offset.scale(0,2)+self.bitcell_array_inst.ul(),
mirror="MX")
@ -196,7 +210,11 @@ class replica_bitcell_array(design.design):
self.dummy_row_botbot_inst.place(offset=offset.scale(0,-2))
self.dummy_col_left_inst.place(offset=offset.scale(-2,-2))
self.dummy_col_right_inst.place(offset=offset.scale(1,-2)+self.bitcell_array_inst.lr())
if self.num_ports==2:
self.dummy_col_right_inst.place(offset=offset.scale(1,-2)+self.bitcell_array_inst.lr())
else:
self.dummy_col_right_inst.place(offset=offset.scale(0,-2)+self.bitcell_array_inst.lr())
self.translate_all(offset.scale(-2,-2))
@ -246,7 +264,10 @@ class replica_bitcell_array(design.design):
height=pin.height())
# Replica columns
for index,side in enumerate(["left","right"]):
replica_sides = ["left"]
if self.num_ports==2:
replica_sides.append("right")
for index,side in enumerate(replica_sides):
inst = getattr(self, "replica_col_{}_inst".format(side))
pin_names = inst.mod.get_pin_names()
for pin_name in pin_names:
@ -262,11 +283,7 @@ class replica_bitcell_array(design.design):
for pin_name in ["vdd","gnd"]:
for inst in [self.bitcell_array_inst,
self.replica_col_left_inst, self.replica_col_right_inst,
self.dummy_col_left_inst, self.dummy_col_right_inst,
self.dummy_row_toptop_inst, self.dummy_row_topbot_inst,
self.dummy_row_bottop_inst, self.dummy_row_botbot_inst]:
for inst in self.insts:
pin_list = inst.get_pins(pin_name)
for pin in pin_list:
self.add_power_pin(name=pin_name, loc=pin.center(), vertical=True, start_layer=pin.layer)

View File

@ -16,10 +16,11 @@ class replica_column(design.design):
Generate a replica bitline column for the replica array.
"""
def __init__(self, name, rows):
def __init__(self, name, rows, num_ports):
design.design.__init__(self, name)
self.row_size = rows
self.num_ports = num_ports
self.create_netlist()
if not OPTS.netlist_only:
@ -64,7 +65,7 @@ class replica_column(design.design):
self.cell_inst = {}
for row in range(self.row_size):
name="rbc_{0}".format(row)
if row>0 and row<self.row_size-2:
if row>0 and row<self.row_size - self.num_ports:
self.cell_inst[row]=self.add_inst(name=name,
mod=self.replica_cell)
else:

View File

@ -127,6 +127,7 @@ class options(optparse.Values):
delay_chain = "delay_chain"
dff_array = "dff_array"
dff = "dff"
dummy_bitcell = "dummy_bitcell"
precharge_array = "precharge_array"
ptx = "ptx"
replica_bitcell = "replica_bitcell"

View File

@ -292,9 +292,6 @@ class sram_base(design, verilog, lef):
self.bank_count = 0
self.supply_rail_width = self.bank.supply_rail_width
self.supply_rail_pitch = self.bank.supply_rail_pitch
#The control logic can resize itself based on the other modules. Requires all other modules added before control logic.
self.all_mods_except_control_done = True

View File

@ -23,7 +23,6 @@ class bitcell_1rw_1r_array_test(openram_test):
globals.init_openram("config_{0}".format(OPTS.tech_name))
debug.info(2, "Testing 4x4 array for cell_1rw_1r")
OPTS.bitcell = "bitcell_1rw_1r"
OPTS.num_rw_ports = 1
OPTS.num_r_ports = 1
OPTS.num_w_ports = 0

View File

@ -19,9 +19,18 @@ class replica_bitcell_array_test(openram_test):
globals.init_openram("config_{0}".format(OPTS.tech_name))
debug.info(2, "Testing 4x4 array for 6t_cell")
a = factory.create(module_type="replica_bitcell_array", cols=4, rows=4)
a = factory.create(module_type="replica_bitcell_array", cols=4, rows=4, num_ports=1)
self.local_check(a)
OPTS.num_rw_ports = 1
OPTS.num_r_ports = 1
OPTS.num_w_ports = 0
factory.reset()
debug.info(2, "Testing 4x4 array for 6t_cell")
a = factory.create(module_type="replica_bitcell_array", cols=4, rows=4, num_ports=2)
self.local_check(a)
globals.end_openram()
# run the test from the command line

View File

@ -19,9 +19,13 @@ class replica_column_test(openram_test):
globals.init_openram("config_{0}".format(OPTS.tech_name))
debug.info(2, "Testing replica column for 6t_cell")
a = factory.create(module_type="replica_column", rows=4)
a = factory.create(module_type="replica_column", rows=4, num_ports=1)
self.local_check(a)
debug.info(2, "Testing replica column for 6t_cell")
a = factory.create(module_type="replica_column", rows=4, num_ports=2)
self.local_check(a)
globals.end_openram()
# run the test from the command line

View File

@ -26,6 +26,7 @@ class replica_bitline_multiport_test(openram_test):
OPTS.bitcell = "bitcell_1rw_1r"
OPTS.replica_bitcell = "replica_bitcell_1rw_1r"
OPTS.dummy_bitcell = "dummy_bitcell_1rw_1r"
OPTS.num_rw_ports = 1
OPTS.num_r_ports = 1
OPTS.num_w_ports = 0
@ -38,6 +39,7 @@ class replica_bitline_multiport_test(openram_test):
# check replica bitline in pbitcell multi-port
OPTS.bitcell = "pbitcell"
OPTS.replica_bitcell = "replica_pbitcell"
OPTS.dummy_bitcell = "dummy_pbitcell"
OPTS.num_rw_ports = 1
OPTS.num_w_ports = 0
OPTS.num_r_ports = 0