mirror of https://github.com/VLSIDA/OpenRAM.git
Clean up new code for add_modules, add_pins and netlist/layouts.
This commit is contained in:
parent
6401cbf2a6
commit
e17c69be3e
|
|
@ -199,7 +199,7 @@ class instance(geometry):
|
|||
""" This updates the placement of an instance. """
|
||||
debug.info(3, "placing instance {}".format(self.name))
|
||||
# Update the placement of an already added instance
|
||||
self.offset = offset
|
||||
self.offset = vector(offset)
|
||||
self.mirror = mirror
|
||||
self.rotate = rotate
|
||||
self.update_boundary()
|
||||
|
|
|
|||
|
|
@ -8,5 +8,5 @@ supply_voltages = [1.0]
|
|||
temperatures = [25]
|
||||
|
||||
output_path = "temp"
|
||||
output_name = "sram_2_16_1_freepdk45"
|
||||
output_name = "sram_{0}_{1}_{2}_{3}".format(word_size,num_words,num_banks,tech_name)
|
||||
|
||||
|
|
|
|||
|
|
@ -7,7 +7,6 @@ process_corners = ["TT"]
|
|||
supply_voltages = [ 5.0 ]
|
||||
temperatures = [ 25 ]
|
||||
|
||||
|
||||
output_path = "temp"
|
||||
output_name = "sram_2_16_1_scn3me_subm"
|
||||
output_name = "sram_{0}_{1}_{2}_{3}".format(word_size,num_words,num_banks,tech_name)
|
||||
|
||||
|
|
|
|||
|
|
@ -207,7 +207,6 @@ def read_config(config_file, is_unit_test=True):
|
|||
# If we are only generating a netlist, we can't do DRC/LVS
|
||||
if OPTS.netlist_only:
|
||||
OPTS.check_lvsdrc=False
|
||||
|
||||
|
||||
# If config didn't set output name, make a reasonable default.
|
||||
if (OPTS.output_name == ""):
|
||||
|
|
|
|||
|
|
@ -22,17 +22,6 @@ class bank(design.design):
|
|||
|
||||
def __init__(self, word_size, num_words, words_per_row, num_banks=1, name=""):
|
||||
|
||||
mod_list = ["bitcell", "decoder", "ms_flop_array", "wordline_driver",
|
||||
"bitcell_array", "sense_amp_array", "precharge_array",
|
||||
"column_mux_array", "write_driver_array",
|
||||
"dff", "bank_select"]
|
||||
from importlib import reload
|
||||
for mod_name in mod_list:
|
||||
config_mod_name = getattr(OPTS, mod_name)
|
||||
class_file = reload(__import__(config_mod_name))
|
||||
mod_class = getattr(class_file , config_mod_name)
|
||||
setattr (self, "mod_"+mod_name, mod_class)
|
||||
|
||||
if name == "":
|
||||
name = "bank_{0}_{1}".format(word_size, num_words)
|
||||
design.design.__init__(self, name)
|
||||
|
|
@ -206,6 +195,19 @@ class bank(design.design):
|
|||
|
||||
def add_modules(self):
|
||||
""" Create all the modules using the class loader """
|
||||
|
||||
mod_list = ["bitcell", "decoder", "ms_flop_array", "wordline_driver",
|
||||
"bitcell_array", "sense_amp_array", "precharge_array",
|
||||
"column_mux_array", "write_driver_array",
|
||||
"dff", "bank_select"]
|
||||
from importlib import reload
|
||||
for mod_name in mod_list:
|
||||
config_mod_name = getattr(OPTS, mod_name)
|
||||
class_file = reload(__import__(config_mod_name))
|
||||
mod_class = getattr(class_file , config_mod_name)
|
||||
setattr (self, "mod_"+mod_name, mod_class)
|
||||
|
||||
|
||||
self.bitcell = self.mod_bitcell()
|
||||
|
||||
self.bitcell_array = self.mod_bitcell_array(cols=self.num_cols,
|
||||
|
|
|
|||
|
|
@ -21,16 +21,6 @@ class bitcell_array(design.design):
|
|||
self.column_size = cols
|
||||
self.row_size = rows
|
||||
|
||||
from importlib import reload
|
||||
c = reload(__import__(OPTS.bitcell))
|
||||
self.mod_bitcell = getattr(c, OPTS.bitcell)
|
||||
self.cell = self.mod_bitcell()
|
||||
self.add_mod(self.cell)
|
||||
|
||||
# We increase it by a well enclosure so the precharges don't overlap our wells
|
||||
self.height = self.row_size*self.cell.height + drc["well_enclosure_active"] + self.m1_width
|
||||
self.width = self.column_size*self.cell.width + self.m1_width
|
||||
|
||||
self.create_netlist()
|
||||
if not OPTS.netlist_only:
|
||||
self.create_layout()
|
||||
|
|
@ -42,17 +32,16 @@ class bitcell_array(design.design):
|
|||
|
||||
def create_netlist(self):
|
||||
""" Create and connect the netlist """
|
||||
self.add_modules()
|
||||
self.add_pins()
|
||||
|
||||
self.cell_inst = {}
|
||||
for col in range(self.column_size):
|
||||
for row in range(self.row_size):
|
||||
name = "bit_r{0}_c{1}".format(row, col)
|
||||
self.cell_inst[row,col]=self.add_inst(name=name,
|
||||
mod=self.cell)
|
||||
self.connect_inst(self.cell.list_bitcell_pins(col, row))
|
||||
self.create_modules()
|
||||
|
||||
def create_layout(self):
|
||||
|
||||
# We increase it by a well enclosure so the precharges don't overlap our wells
|
||||
self.height = self.row_size*self.cell.height + drc["well_enclosure_active"] + self.m1_width
|
||||
self.width = self.column_size*self.cell.width + self.m1_width
|
||||
|
||||
xoffset = 0.0
|
||||
for col in range(self.column_size):
|
||||
yoffset = 0.0
|
||||
|
|
@ -87,7 +76,25 @@ class bitcell_array(design.design):
|
|||
self.add_pin("vdd")
|
||||
self.add_pin("gnd")
|
||||
|
||||
|
||||
def add_modules(self):
|
||||
""" Add the modules used in this design """
|
||||
|
||||
from importlib import reload
|
||||
c = reload(__import__(OPTS.bitcell))
|
||||
self.mod_bitcell = getattr(c, OPTS.bitcell)
|
||||
self.cell = self.mod_bitcell()
|
||||
self.add_mod(self.cell)
|
||||
|
||||
def create_modules(self):
|
||||
""" Create the module instances used in this design """
|
||||
self.cell_inst = {}
|
||||
for col in range(self.column_size):
|
||||
for row in range(self.row_size):
|
||||
name = "bit_r{0}_c{1}".format(row, col)
|
||||
self.cell_inst[row,col]=self.add_inst(name=name,
|
||||
mod=self.cell)
|
||||
self.connect_inst(self.cell.list_bitcell_pins(col, row))
|
||||
|
||||
def add_layout_pins(self):
|
||||
""" Add the layout pins """
|
||||
|
||||
|
|
|
|||
|
|
@ -30,8 +30,8 @@ class delay_chain(design.design):
|
|||
|
||||
|
||||
def create_netlist(self):
|
||||
self.add_pins()
|
||||
self.add_modules()
|
||||
self.add_pins()
|
||||
self.create_inverters()
|
||||
|
||||
def create_layout(self):
|
||||
|
|
|
|||
|
|
@ -20,27 +20,30 @@ class dff_array(design.design):
|
|||
design.design.__init__(self, name)
|
||||
debug.info(1, "Creating {0} rows={1} cols={2}".format(self.name, self.rows, self.columns))
|
||||
|
||||
self.create_netlist()
|
||||
if not OPTS.netlist_only:
|
||||
self.create_layout()
|
||||
|
||||
def create_netlist(self):
|
||||
self.add_modules()
|
||||
self.add_pins()
|
||||
self.create_dff_array()
|
||||
|
||||
def create_layout(self):
|
||||
self.width = self.columns * self.dff.width
|
||||
self.height = self.rows * self.dff.height
|
||||
|
||||
self.place_dff_array()
|
||||
self.add_layout_pins()
|
||||
self.DRC_LVS()
|
||||
|
||||
def add_modules(self):
|
||||
from importlib import reload
|
||||
c = reload(__import__(OPTS.dff))
|
||||
self.mod_dff = getattr(c, OPTS.dff)
|
||||
self.dff = self.mod_dff("dff")
|
||||
self.add_mod(self.dff)
|
||||
|
||||
self.width = self.columns * self.dff.width
|
||||
self.height = self.rows * self.dff.height
|
||||
|
||||
self.create_netlist()
|
||||
self.create_layout()
|
||||
|
||||
def create_netlist(self):
|
||||
self.add_pins()
|
||||
self.create_dff_array()
|
||||
|
||||
def create_layout(self):
|
||||
self.place_dff_array()
|
||||
self.add_layout_pins()
|
||||
self.DRC_LVS()
|
||||
|
||||
def add_pins(self):
|
||||
for row in range(self.rows):
|
||||
for col in range(self.columns):
|
||||
|
|
|
|||
|
|
@ -26,29 +26,41 @@ class dff_buf(design.design):
|
|||
debug.check(inv1_size>=2, "Inverter must be greater than two for rail spacing DRC rules.")
|
||||
debug.check(inv2_size>=2, "Inverter must be greater than two for rail spacing DRC rules.")
|
||||
|
||||
self.inv1_size=inv1_size
|
||||
self.inv2_size=inv2_size
|
||||
|
||||
self.create_netlist()
|
||||
if not OPTS.netlist_only:
|
||||
self.create_layout()
|
||||
|
||||
def create_netlist(self):
|
||||
self.add_modules()
|
||||
self.add_pins()
|
||||
self.create_modules()
|
||||
|
||||
def create_layout(self):
|
||||
self.width = self.dff.width + self.inv1.width + self.inv2.width
|
||||
self.height = self.dff.height
|
||||
|
||||
self.place_modules()
|
||||
self.route_wires()
|
||||
self.add_layout_pins()
|
||||
self.DRC_LVS()
|
||||
|
||||
def add_modules(self):
|
||||
from importlib import reload
|
||||
c = reload(__import__(OPTS.dff))
|
||||
self.mod_dff = getattr(c, OPTS.dff)
|
||||
self.dff = self.mod_dff("dff")
|
||||
self.add_mod(self.dff)
|
||||
|
||||
self.inv1 = pinv(size=inv1_size,height=self.dff.height)
|
||||
self.inv1 = pinv(size=self.inv1_size,height=self.dff.height)
|
||||
self.add_mod(self.inv1)
|
||||
|
||||
self.inv2 = pinv(size=inv2_size,height=self.dff.height)
|
||||
self.inv2 = pinv(size=self.inv2_size,height=self.dff.height)
|
||||
self.add_mod(self.inv2)
|
||||
|
||||
self.width = self.dff.width + self.inv1.width + self.inv2.width
|
||||
self.height = self.dff.height
|
||||
|
||||
self.create_layout()
|
||||
|
||||
def create_layout(self):
|
||||
self.add_pins()
|
||||
self.add_insts()
|
||||
self.add_wires()
|
||||
self.add_layout_pins()
|
||||
self.DRC_LVS()
|
||||
|
||||
|
||||
def add_pins(self):
|
||||
self.add_pin("D")
|
||||
|
|
@ -58,26 +70,30 @@ class dff_buf(design.design):
|
|||
self.add_pin("vdd")
|
||||
self.add_pin("gnd")
|
||||
|
||||
def add_insts(self):
|
||||
# Add the DFF
|
||||
def create_modules(self):
|
||||
self.dff_inst=self.add_inst(name="dff_buf_dff",
|
||||
mod=self.dff,
|
||||
offset=vector(0,0))
|
||||
mod=self.dff)
|
||||
self.connect_inst(["D", "qint", "clk", "vdd", "gnd"])
|
||||
|
||||
# Add INV1 to the right
|
||||
self.inv1_inst=self.add_inst(name="dff_buf_inv1",
|
||||
mod=self.inv1,
|
||||
offset=vector(self.dff_inst.rx(),0))
|
||||
mod=self.inv1)
|
||||
self.connect_inst(["qint", "Qb", "vdd", "gnd"])
|
||||
|
||||
# Add INV2 to the right
|
||||
self.inv2_inst=self.add_inst(name="dff_buf_inv2",
|
||||
mod=self.inv2,
|
||||
offset=vector(self.inv1_inst.rx(),0))
|
||||
mod=self.inv2)
|
||||
self.connect_inst(["Qb", "Q", "vdd", "gnd"])
|
||||
|
||||
def place_modules(self):
|
||||
# Add the DFF
|
||||
self.dff_inst.place(vector(0,0))
|
||||
|
||||
# Add INV1 to the right
|
||||
self.inv1_inst.place(vector(self.dff_inst.rx(),0))
|
||||
|
||||
def add_wires(self):
|
||||
# Add INV2 to the right
|
||||
self.inv2_inst.place(vector(self.inv1_inst.rx(),0))
|
||||
|
||||
def route_wires(self):
|
||||
# Route dff q to inv1 a
|
||||
q_pin = self.dff_inst.get_pin("Q")
|
||||
a1_pin = self.inv1_inst.get_pin("A")
|
||||
|
|
|
|||
|
|
@ -29,7 +29,7 @@ class dff_buf_array(design.design):
|
|||
|
||||
def create_netlist(self):
|
||||
self.add_pins()
|
||||
self.add_dff()
|
||||
self.add_modules()
|
||||
self.create_dff_array()
|
||||
|
||||
def create_layout(self):
|
||||
|
|
@ -51,7 +51,7 @@ class dff_buf_array(design.design):
|
|||
self.add_pin("vdd")
|
||||
self.add_pin("gnd")
|
||||
|
||||
def add_dff(self):
|
||||
def add_modules(self):
|
||||
self.dff = dff_buf.dff_buf(self.inv1_size, self.inv2_size)
|
||||
self.add_mod(self.dff)
|
||||
|
||||
|
|
|
|||
|
|
@ -63,12 +63,10 @@ class dff_inv(design.design):
|
|||
self.add_mod(self.inv1)
|
||||
|
||||
def create_modules(self):
|
||||
# Add the DFF
|
||||
self.dff_inst=self.add_inst(name="dff_inv_dff",
|
||||
mod=self.dff)
|
||||
self.connect_inst(["D", "Q", "clk", "vdd", "gnd"])
|
||||
|
||||
# Add INV1 to the right
|
||||
self.inv1_inst=self.add_inst(name="dff_inv_inv1",
|
||||
mod=self.inv1)
|
||||
self.connect_inst(["Q", "Qb", "vdd", "gnd"])
|
||||
|
|
|
|||
|
|
@ -28,7 +28,7 @@ class dff_inv_array(design.design):
|
|||
|
||||
def create_netlist(self):
|
||||
self.add_pins()
|
||||
self.add_dff()
|
||||
self.add_modules()
|
||||
self.create_dff_array()
|
||||
|
||||
def create_layout(self):
|
||||
|
|
@ -39,7 +39,7 @@ class dff_inv_array(design.design):
|
|||
self.add_layout_pins()
|
||||
self.DRC_LVS()
|
||||
|
||||
def add_dff(self):
|
||||
def add_modules(self):
|
||||
self.dff = dff_inv.dff_inv(self.inv_size)
|
||||
self.add_mod(self.dff)
|
||||
|
||||
|
|
|
|||
|
|
@ -20,27 +20,31 @@ class ms_flop_array(design.design):
|
|||
design.design.__init__(self, name)
|
||||
debug.info(1, "Creating {}".format(self.name))
|
||||
|
||||
self.words_per_row = int(self.columns / self.word_size)
|
||||
|
||||
self.create_netlist()
|
||||
if not OPTS.netlist_only:
|
||||
self.create_layout()
|
||||
|
||||
def create_netlist(self):
|
||||
self.add_modules()
|
||||
self.add_pins()
|
||||
self.create_ms_flop_array()
|
||||
|
||||
def create_layout(self):
|
||||
self.width = self.columns * self.ms.width
|
||||
self.height = self.ms.height
|
||||
|
||||
self.place_ms_flop_array()
|
||||
self.add_layout_pins()
|
||||
self.DRC_LVS()
|
||||
|
||||
def add_modules(self):
|
||||
from importlib import reload
|
||||
c = reload(__import__(OPTS.ms_flop))
|
||||
self.mod_ms_flop = getattr(c, OPTS.ms_flop)
|
||||
self.ms = self.mod_ms_flop("ms_flop")
|
||||
self.add_mod(self.ms)
|
||||
|
||||
self.width = self.columns * self.ms.width
|
||||
self.height = self.ms.height
|
||||
self.words_per_row = int(self.columns / self.word_size)
|
||||
|
||||
self.create_netlist()
|
||||
self.create_layout()
|
||||
|
||||
def create_netlist(self):
|
||||
self.add_pins()
|
||||
self.create_ms_flop_array()
|
||||
|
||||
def create_layout(self):
|
||||
self.place_ms_flop_array()
|
||||
self.add_layout_pins()
|
||||
self.DRC_LVS()
|
||||
|
||||
def add_pins(self):
|
||||
for i in range(self.word_size):
|
||||
|
|
|
|||
|
|
@ -20,9 +20,9 @@ class precharge_array(design.design):
|
|||
debug.info(1, "Creating {0}".format(self.name))
|
||||
|
||||
self.columns = columns
|
||||
|
||||
self.pc_cell = precharge(name="precharge", size=size, bitcell_bl=bitcell_bl, bitcell_br=bitcell_br)
|
||||
self.add_mod(self.pc_cell)
|
||||
self.size = size
|
||||
self.bitcell_bl = bitcell_bl
|
||||
self.bitcell_br = bitcell_br
|
||||
|
||||
self.create_netlist()
|
||||
if not OPTS.netlist_only:
|
||||
|
|
@ -37,6 +37,7 @@ class precharge_array(design.design):
|
|||
self.add_pin("vdd")
|
||||
|
||||
def create_netlist(self):
|
||||
self.add_modules()
|
||||
self.add_pins()
|
||||
self.create_insts()
|
||||
|
||||
|
|
@ -47,8 +48,15 @@ class precharge_array(design.design):
|
|||
self.place_insts()
|
||||
self.add_layout_pins()
|
||||
self.DRC_LVS()
|
||||
|
||||
|
||||
def add_modules(self):
|
||||
self.pc_cell = precharge(name="precharge",
|
||||
size=self.size,
|
||||
bitcell_bl=self.bitcell_bl,
|
||||
bitcell_br=self.bitcell_br)
|
||||
self.add_mod(self.pc_cell)
|
||||
|
||||
|
||||
def add_layout_pins(self):
|
||||
|
||||
self.add_layout_pin(text="en",
|
||||
|
|
|
|||
|
|
@ -18,13 +18,6 @@ class replica_bitline(design.design):
|
|||
def __init__(self, delay_stages, delay_fanout, bitcell_loads, name="replica_bitline"):
|
||||
design.design.__init__(self, name)
|
||||
|
||||
from importlib import reload
|
||||
g = reload(__import__(OPTS.delay_chain))
|
||||
self.mod_delay_chain = getattr(g, OPTS.delay_chain)
|
||||
|
||||
g = reload(__import__(OPTS.replica_bitcell))
|
||||
self.mod_replica_bitcell = getattr(g, OPTS.replica_bitcell)
|
||||
|
||||
self.bitcell_loads = bitcell_loads
|
||||
self.delay_stages = delay_stages
|
||||
self.delay_fanout = delay_fanout
|
||||
|
|
@ -34,19 +27,17 @@ class replica_bitline(design.design):
|
|||
self.create_layout()
|
||||
|
||||
def create_netlist(self):
|
||||
for pin in ["en", "out", "vdd", "gnd"]:
|
||||
self.add_pin(pin)
|
||||
self.add_modules()
|
||||
self.add_pins()
|
||||
self.create_modules()
|
||||
|
||||
def create_layout(self):
|
||||
self.calculate_module_offsets()
|
||||
self.place_modules()
|
||||
self.route()
|
||||
self.add_layout_pins()
|
||||
|
||||
self.offset_all_coordinates()
|
||||
|
||||
self.add_layout_pins()
|
||||
|
||||
#self.add_lvs_correspondence_points()
|
||||
|
||||
|
|
@ -56,6 +47,9 @@ class replica_bitline(design.design):
|
|||
|
||||
self.DRC_LVS()
|
||||
|
||||
def add_pins(self):
|
||||
for pin in ["en", "out", "vdd", "gnd"]:
|
||||
self.add_pin(pin)
|
||||
|
||||
def calculate_module_offsets(self):
|
||||
""" Calculate all the module offsets """
|
||||
|
|
@ -85,6 +79,14 @@ class replica_bitline(design.design):
|
|||
|
||||
def add_modules(self):
|
||||
""" Add the modules for later usage """
|
||||
|
||||
from importlib import reload
|
||||
g = reload(__import__(OPTS.delay_chain))
|
||||
self.mod_delay_chain = getattr(g, OPTS.delay_chain)
|
||||
|
||||
g = reload(__import__(OPTS.replica_bitcell))
|
||||
self.mod_replica_bitcell = getattr(g, OPTS.replica_bitcell)
|
||||
|
||||
self.bitcell = self.replica_bitcell = self.mod_replica_bitcell()
|
||||
self.add_mod(self.bitcell)
|
||||
|
||||
|
|
@ -267,8 +269,6 @@ class replica_bitline(design.design):
|
|||
self.copy_layout_pin(self.dc_inst,"vdd")
|
||||
self.copy_layout_pin(self.rbc_inst,"vdd")
|
||||
|
||||
|
||||
|
||||
# Connect the WL and vdd pins directly to the center and right vdd rails
|
||||
# Connect RBL vdd pins to center and right rails
|
||||
rbl_vdd_pins = self.rbl_inst.get_pins("vdd")
|
||||
|
|
@ -288,9 +288,6 @@ class replica_bitline(design.design):
|
|||
offset=end,
|
||||
rotate=90)
|
||||
|
||||
|
||||
|
||||
|
||||
# Add via for the inverter
|
||||
pin = self.rbl_inv_inst.get_pin("vdd")
|
||||
start = vector(self.left_vdd_pin.cx(),pin.cy())
|
||||
|
|
|
|||
|
|
@ -14,44 +14,46 @@ class sense_amp_array(design.design):
|
|||
design.design.__init__(self, "sense_amp_array")
|
||||
debug.info(1, "Creating {0}".format(self.name))
|
||||
|
||||
self.word_size = word_size
|
||||
self.words_per_row = words_per_row
|
||||
self.row_size = self.word_size * self.words_per_row
|
||||
|
||||
self.create_netlist()
|
||||
if not OPTS.netlist_only:
|
||||
self.create_layout()
|
||||
|
||||
|
||||
def create_netlist(self):
|
||||
self.add_modules()
|
||||
self.add_pins()
|
||||
self.create_sense_amp_array()
|
||||
|
||||
def create_layout(self):
|
||||
self.height = self.amp.height
|
||||
self.width = self.amp.width * self.word_size * self.words_per_row
|
||||
|
||||
self.place_sense_amp_array()
|
||||
self.add_layout_pins()
|
||||
self.route_rails()
|
||||
self.DRC_LVS()
|
||||
|
||||
def add_pins(self):
|
||||
for i in range(0,self.word_size):
|
||||
self.add_pin("data[{0}]".format(i))
|
||||
self.add_pin("bl[{0}]".format(i))
|
||||
self.add_pin("br[{0}]".format(i))
|
||||
self.add_pin("en")
|
||||
self.add_pin("vdd")
|
||||
self.add_pin("gnd")
|
||||
|
||||
def add_modules(self):
|
||||
from importlib import reload
|
||||
c = reload(__import__(OPTS.sense_amp))
|
||||
self.mod_sense_amp = getattr(c, OPTS.sense_amp)
|
||||
self.amp = self.mod_sense_amp("sense_amp")
|
||||
self.add_mod(self.amp)
|
||||
|
||||
self.word_size = word_size
|
||||
self.words_per_row = words_per_row
|
||||
self.row_size = self.word_size * self.words_per_row
|
||||
|
||||
self.height = self.amp.height
|
||||
self.width = self.amp.width * self.word_size * self.words_per_row
|
||||
|
||||
self.create_netlist()
|
||||
self.create_layout()
|
||||
self.DRC_LVS()
|
||||
|
||||
def add_pins(self):
|
||||
|
||||
for i in range(0,self.word_size):
|
||||
self.add_pin("data[{0}]".format(i))
|
||||
self.add_pin("bl[{0}]".format(i))
|
||||
self.add_pin("br[{0}]".format(i))
|
||||
|
||||
self.add_pin("en")
|
||||
self.add_pin("vdd")
|
||||
self.add_pin("gnd")
|
||||
|
||||
def create_netlist(self):
|
||||
self.add_pins()
|
||||
self.create_sense_amp_array()
|
||||
|
||||
def create_layout(self):
|
||||
self.place_sense_amp_array()
|
||||
self.add_layout_pins()
|
||||
self.route_rails()
|
||||
|
||||
|
||||
def create_sense_amp_array(self):
|
||||
self.local_insts = []
|
||||
for i in range(0,self.word_size):
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@ from tech import drc
|
|||
import debug
|
||||
import math
|
||||
from vector import vector
|
||||
|
||||
from globals import OPTS
|
||||
|
||||
class single_level_column_mux_array(design.design):
|
||||
"""
|
||||
|
|
@ -20,23 +20,14 @@ class single_level_column_mux_array(design.design):
|
|||
self.columns = columns
|
||||
self.word_size = word_size
|
||||
self.words_per_row = int(self.columns / self.word_size)
|
||||
|
||||
self.create_netlist()
|
||||
self.create_layout()
|
||||
|
||||
def add_pins(self):
|
||||
for i in range(self.columns):
|
||||
self.add_pin("bl[{}]".format(i))
|
||||
self.add_pin("br[{}]".format(i))
|
||||
for i in range(self.words_per_row):
|
||||
self.add_pin("sel[{}]".format(i))
|
||||
for i in range(self.word_size):
|
||||
self.add_pin("bl_out[{}]".format(i))
|
||||
self.add_pin("br_out[{}]".format(i))
|
||||
self.add_pin("gnd")
|
||||
if not OPTS.netlist_only:
|
||||
self.create_layout()
|
||||
|
||||
def create_netlist(self):
|
||||
self.add_pins()
|
||||
self.add_modules()
|
||||
self.add_pins()
|
||||
self.create_array()
|
||||
|
||||
def create_layout(self):
|
||||
|
|
@ -51,6 +42,17 @@ class single_level_column_mux_array(design.design):
|
|||
|
||||
self.DRC_LVS()
|
||||
|
||||
def add_pins(self):
|
||||
for i in range(self.columns):
|
||||
self.add_pin("bl[{}]".format(i))
|
||||
self.add_pin("br[{}]".format(i))
|
||||
for i in range(self.words_per_row):
|
||||
self.add_pin("sel[{}]".format(i))
|
||||
for i in range(self.word_size):
|
||||
self.add_pin("bl_out[{}]".format(i))
|
||||
self.add_pin("br_out[{}]".format(i))
|
||||
self.add_pin("gnd")
|
||||
|
||||
|
||||
def add_modules(self):
|
||||
# FIXME: Why is this 8x?
|
||||
|
|
|
|||
|
|
@ -14,31 +14,34 @@ class tri_gate_array(design.design):
|
|||
design.design.__init__(self, "tri_gate_array")
|
||||
debug.info(1, "Creating {0}".format(self.name))
|
||||
|
||||
self.columns = columns
|
||||
self.word_size = word_size
|
||||
self.words_per_row = int(self.columns / self.word_size)
|
||||
|
||||
self.create_netlist()
|
||||
if not OPTS.netlist_only:
|
||||
self.create_layout()
|
||||
|
||||
def create_netlist(self):
|
||||
self.add_modules()
|
||||
self.add_pins()
|
||||
self.create_array()
|
||||
|
||||
def create_layout(self):
|
||||
self.width = (self.columns / self.words_per_row) * self.tri.width
|
||||
self.height = self.tri.height
|
||||
|
||||
self.place_array()
|
||||
self.add_layout_pins()
|
||||
self.DRC_LVS()
|
||||
|
||||
def add_modules(self):
|
||||
from importlib import reload
|
||||
c = reload(__import__(OPTS.tri_gate))
|
||||
self.mod_tri_gate = getattr(c, OPTS.tri_gate)
|
||||
self.tri = self.mod_tri_gate("tri_gate")
|
||||
self.add_mod(self.tri)
|
||||
|
||||
self.columns = columns
|
||||
self.word_size = word_size
|
||||
|
||||
self.words_per_row = int(self.columns / self.word_size)
|
||||
self.width = (self.columns / self.words_per_row) * self.tri.width
|
||||
self.height = self.tri.height
|
||||
|
||||
self.create_netlist()
|
||||
self.create_layout()
|
||||
|
||||
def create_netlist(self):
|
||||
self.add_pins()
|
||||
self.create_array()
|
||||
|
||||
def create_layout(self):
|
||||
self.place_array()
|
||||
self.add_layout_pins()
|
||||
self.DRC_LVS()
|
||||
|
||||
def add_pins(self):
|
||||
"""create the name of pins depend on the word size"""
|
||||
for i in range(self.word_size):
|
||||
|
|
|
|||
|
|
@ -20,13 +20,14 @@ class wordline_driver(design.design):
|
|||
design.design.__init__(self, "wordline_driver")
|
||||
|
||||
self.rows = rows
|
||||
|
||||
self.create_netlist()
|
||||
if not OPTS.netlist_only:
|
||||
self.create_layout()
|
||||
|
||||
def create_netlist(self):
|
||||
self.add_pins()
|
||||
self.add_modules()
|
||||
self.add_pins()
|
||||
self.create_drivers()
|
||||
|
||||
def create_layout(self):
|
||||
|
|
|
|||
|
|
@ -15,21 +15,27 @@ class write_driver_array(design.design):
|
|||
design.design.__init__(self, "write_driver_array")
|
||||
debug.info(1, "Creating {0}".format(self.name))
|
||||
|
||||
from importlib import reload
|
||||
c = reload(__import__(OPTS.write_driver))
|
||||
self.mod_write_driver = getattr(c, OPTS.write_driver)
|
||||
self.driver = self.mod_write_driver("write_driver")
|
||||
self.add_mod(self.driver)
|
||||
|
||||
self.columns = columns
|
||||
self.word_size = word_size
|
||||
self.words_per_row = int(columns / word_size)
|
||||
|
||||
self.width = self.columns * self.driver.width
|
||||
self.height = self.height = self.driver.height
|
||||
|
||||
self.create_netlist()
|
||||
self.create_layout()
|
||||
if not OPTS.netlist_only:
|
||||
self.create_layout()
|
||||
|
||||
|
||||
def create_netlist(self):
|
||||
self.add_modules()
|
||||
self.add_pins()
|
||||
self.create_write_array()
|
||||
|
||||
def create_layout(self):
|
||||
self.width = self.columns * self.driver.width
|
||||
self.height = self.driver.height
|
||||
|
||||
self.place_write_array()
|
||||
self.add_layout_pins()
|
||||
self.DRC_LVS()
|
||||
|
||||
def add_pins(self):
|
||||
for i in range(self.word_size):
|
||||
|
|
@ -41,14 +47,12 @@ class write_driver_array(design.design):
|
|||
self.add_pin("vdd")
|
||||
self.add_pin("gnd")
|
||||
|
||||
def create_netlist(self):
|
||||
self.add_pins()
|
||||
self.create_write_array()
|
||||
|
||||
def create_layout(self):
|
||||
self.place_write_array()
|
||||
self.add_layout_pins()
|
||||
self.DRC_LVS()
|
||||
def add_modules(self):
|
||||
from importlib import reload
|
||||
c = reload(__import__(OPTS.write_driver))
|
||||
self.mod_write_driver = getattr(c, OPTS.write_driver)
|
||||
self.driver = self.mod_write_driver("write_driver")
|
||||
self.add_mod(self.driver)
|
||||
|
||||
def create_write_array(self):
|
||||
self.driver_insts = {}
|
||||
|
|
|
|||
|
|
@ -37,10 +37,39 @@ class pbitcell(pgate.pgate):
|
|||
pbitcell.height = self.height
|
||||
|
||||
|
||||
|
||||
def create_netlist(self):
|
||||
self.add_pins()
|
||||
self.add_modules()
|
||||
self.create_storage()
|
||||
|
||||
if(self.num_readwrite > 0):
|
||||
self.create_readwrite_ports()
|
||||
if(self.num_write > 0):
|
||||
self.create_write_ports()
|
||||
if(self.num_read > 0):
|
||||
self.create_read_ports()
|
||||
|
||||
def create_layout(self):
|
||||
self.calculate_spacing()
|
||||
self.calculate_postions()
|
||||
|
||||
self.place_storage()
|
||||
self.route_storage()
|
||||
self.route_rails()
|
||||
|
||||
if(self.num_readwrite > 0):
|
||||
self.place_readwrite_ports()
|
||||
if(self.num_write > 0):
|
||||
self.place_write_ports()
|
||||
if(self.num_read > 0):
|
||||
self.place_read_ports()
|
||||
self.extend_well()
|
||||
|
||||
self.offset_all_coordinates()
|
||||
self.DRC_LVS()
|
||||
|
||||
def add_pins(self):
|
||||
"""
|
||||
Adding pins for pbitcell module
|
||||
"""
|
||||
for k in range(self.num_readwrite):
|
||||
self.add_pin("rwbl{}".format(k))
|
||||
self.add_pin("rwbl_bar{}".format(k))
|
||||
|
|
@ -61,33 +90,8 @@ class pbitcell(pgate.pgate):
|
|||
self.add_pin("vdd")
|
||||
self.add_pin("gnd")
|
||||
|
||||
|
||||
def create_netlist(self):
|
||||
self.add_pins()
|
||||
|
||||
def create_layout(self):
|
||||
self.create_ptx()
|
||||
self.calculate_spacing()
|
||||
self.calculate_postions()
|
||||
self.add_storage()
|
||||
self.add_rails()
|
||||
if(self.num_readwrite > 0):
|
||||
self.add_readwrite_ports()
|
||||
if(self.num_write > 0):
|
||||
self.add_write_ports()
|
||||
if(self.num_read > 0):
|
||||
self.add_read_ports()
|
||||
self.extend_well()
|
||||
self.offset_all_coordinates()
|
||||
self.DRC_LVS()
|
||||
|
||||
|
||||
def create_ptx(self):
|
||||
"""
|
||||
Calculate transistor sizes and create ptx for read/write, write, and read ports
|
||||
"""
|
||||
|
||||
""" calculate transistor sizes """
|
||||
def add_modules(self):
|
||||
# if there are any read/write ports, then the inverter nmos is sized based the number of them
|
||||
if(self.num_readwrite > 0):
|
||||
inverter_nmos_width = self.num_readwrite*3*parameter["min_tx_size"]
|
||||
|
|
@ -131,11 +135,9 @@ class pbitcell(pgate.pgate):
|
|||
|
||||
|
||||
def calculate_spacing(self):
|
||||
"""
|
||||
Calculate transistor spacings
|
||||
"""
|
||||
""" Calculate transistor spacings """
|
||||
|
||||
""" calculate metal contact extensions over transistor active """
|
||||
# calculate metal contact extensions over transistor active
|
||||
self.inverter_pmos_contact_extension = 0.5*(self.inverter_pmos.active_contact.height - self.inverter_pmos.active_height)
|
||||
self.readwrite_nmos_contact_extension = 0.5*(self.readwrite_nmos.active_contact.height - self.readwrite_nmos.active_height)
|
||||
self.write_nmos_contact_extension = 0.5*(self.write_nmos.active_contact.height - self.write_nmos.active_height)
|
||||
|
|
@ -144,7 +146,7 @@ class pbitcell(pgate.pgate):
|
|||
# calculate the distance threshold for different gate contact spacings
|
||||
self.gate_contact_thres = drc["poly_to_active"] - drc["minwidth_metal2"]
|
||||
|
||||
""" calculations for horizontal transistor to tansistor spacing """
|
||||
#calculations for horizontal transistor to tansistor spacing
|
||||
# inverter spacings
|
||||
self.inverter_to_inverter_spacing = contact.poly.height + drc["minwidth_metal1"]
|
||||
self.inverter_to_write_spacing = drc["pwell_to_nwell"] + 2*drc["well_enclosure_active"]
|
||||
|
|
@ -266,9 +268,9 @@ class pbitcell(pgate.pgate):
|
|||
self.height = self.topmost_ypos - self.botmost_ypos - array_vdd_overlap
|
||||
|
||||
|
||||
def add_storage(self):
|
||||
def place_storage(self):
|
||||
"""
|
||||
Creates the crossed coupled inverters that act as storage for the bitcell.
|
||||
Places the crossed coupled inverters that act as storage for the bitcell.
|
||||
The stored value of the cell is denoted as "Q", and the inverted value as "Q_bar".
|
||||
"""
|
||||
|
||||
|
|
@ -278,26 +280,14 @@ class pbitcell(pgate.pgate):
|
|||
inverter_pmos_ypos = self.inverter_nmos.active_height + self.inverter_gap
|
||||
|
||||
# create active for nmos
|
||||
self.inverter_nmos_left = self.add_inst(name="inverter_nmos_left",
|
||||
mod=self.inverter_nmos,
|
||||
offset=[left_inverter_xpos,0])
|
||||
self.connect_inst(["Q_bar", "Q", "gnd", "gnd"])
|
||||
|
||||
self.inverter_nmos_right = self.add_inst(name="inverter_nmos_right",
|
||||
mod=self.inverter_nmos,
|
||||
offset=[right_inverter_xpos,0])
|
||||
self.connect_inst(["gnd", "Q_bar", "Q", "gnd"])
|
||||
self.inverter_nmos_left.place([left_inverter_xpos,0])
|
||||
self.inverter_nmos_right.place([right_inverter_xpos,0])
|
||||
|
||||
# create active for pmos
|
||||
self.inverter_pmos_left = self.add_inst(name="inverter_pmos_left",
|
||||
mod=self.inverter_pmos,
|
||||
offset=[left_inverter_xpos, inverter_pmos_ypos])
|
||||
self.connect_inst(["Q_bar", "Q", "vdd", "vdd"])
|
||||
|
||||
self.inverter_pmos_right = self.add_inst(name="inverter_pmos_right",
|
||||
mod=self.inverter_pmos,
|
||||
offset=[right_inverter_xpos, inverter_pmos_ypos])
|
||||
self.connect_inst(["vdd", "Q_bar", "Q", "vdd"])
|
||||
self.inverter_pmos_left.place([left_inverter_xpos, inverter_pmos_ypos])
|
||||
self.inverter_pmos_right.place([right_inverter_xpos, inverter_pmos_ypos])
|
||||
|
||||
def route_storage(self):
|
||||
|
||||
# connect input (gate) of inverters
|
||||
self.add_path("poly", [self.inverter_nmos_left.get_pin("G").uc(), self.inverter_pmos_left.get_pin("G").bc()])
|
||||
|
|
@ -329,13 +319,38 @@ class pbitcell(pgate.pgate):
|
|||
self.left_building_edge = -self.inverter_tile_width
|
||||
self.right_building_edge = self.inverter_tile_width
|
||||
|
||||
|
||||
def add_rails(self):
|
||||
|
||||
def create_storage(self):
|
||||
"""
|
||||
Creates the crossed coupled inverters that act as storage for the bitcell.
|
||||
The stored value of the cell is denoted as "Q", and the inverted value as "Q_bar".
|
||||
"""
|
||||
|
||||
# create active for nmos
|
||||
self.inverter_nmos_left = self.add_inst(name="inverter_nmos_left",
|
||||
mod=self.inverter_nmos)
|
||||
self.connect_inst(["Q_bar", "Q", "gnd", "gnd"])
|
||||
|
||||
self.inverter_nmos_right = self.add_inst(name="inverter_nmos_right",
|
||||
mod=self.inverter_nmos)
|
||||
self.connect_inst(["gnd", "Q_bar", "Q", "gnd"])
|
||||
|
||||
# create active for pmos
|
||||
self.inverter_pmos_left = self.add_inst(name="inverter_pmos_left",
|
||||
mod=self.inverter_pmos)
|
||||
self.connect_inst(["Q_bar", "Q", "vdd", "vdd"])
|
||||
|
||||
self.inverter_pmos_right = self.add_inst(name="inverter_pmos_right",
|
||||
mod=self.inverter_pmos)
|
||||
self.connect_inst(["vdd", "Q_bar", "Q", "vdd"])
|
||||
|
||||
|
||||
def route_rails(self):
|
||||
"""
|
||||
Add gnd and vdd rails and connects them to the inverters
|
||||
"""
|
||||
|
||||
""" Add rails for vdd and gnd """
|
||||
# Add rails for vdd and gnd
|
||||
self.gnd_position = vector(self.leftmost_xpos, -self.rail_tile_height)
|
||||
self.gnd = self.add_layout_pin(text="gnd",
|
||||
layer="metal1",
|
||||
|
|
@ -352,7 +367,7 @@ class pbitcell(pgate.pgate):
|
|||
width=self.width,
|
||||
height=drc["minwidth_metal1"])
|
||||
|
||||
""" Connect inverters to rails """
|
||||
# Connect inverters to rails
|
||||
# connect inverter nmos to gnd
|
||||
gnd_pos_left = vector(self.inverter_nmos_left.get_pin("S").bc().x, self.gnd_position.y)
|
||||
self.add_path("metal1", [self.inverter_nmos_left.get_pin("S").bc(), gnd_pos_left])
|
||||
|
|
@ -368,9 +383,9 @@ class pbitcell(pgate.pgate):
|
|||
self.add_path("metal1", [self.inverter_pmos_right.get_pin("D").uc(), vdd_pos_right])
|
||||
|
||||
|
||||
def add_readwrite_ports(self):
|
||||
def create_readwrite_ports(self):
|
||||
"""
|
||||
Adds read/write ports to the bit cell. A differential pair of transistor can both read and write, like in a 6T cell.
|
||||
Creates read/write ports to the bit cell. A differential pair of transistor can both read and write, like in a 6T cell.
|
||||
A read or write is enabled by setting a Read-Write-Wordline (RWWL) high, subsequently turning on the transistor.
|
||||
The transistor is connected between a Read-Write-Bitline (RWBL) and the storage component of the cell (Q).
|
||||
In a write operation, driving RWBL high or low sets the value of the cell.
|
||||
|
|
@ -378,20 +393,38 @@ class pbitcell(pgate.pgate):
|
|||
This is a differential design, so each write port has a mirrored port that connects RWBL_bar to Q_bar.
|
||||
"""
|
||||
|
||||
""" Define variables relevant to write transistors """
|
||||
# define offset correction due to rotation of the ptx module
|
||||
readwrite_rotation_correct = self.readwrite_nmos.active_height
|
||||
|
||||
# define write transistor variables as empty arrays based on the number of write ports
|
||||
self.readwrite_nmos_left = [None] * self.num_readwrite
|
||||
self.readwrite_nmos_right = [None] * self.num_readwrite
|
||||
|
||||
# iterate over the number of read/write ports
|
||||
for k in range(0,self.num_readwrite):
|
||||
# add read/write transistors
|
||||
self.readwrite_nmos_left[k] = self.add_inst(name="readwrite_nmos_left{}".format(k),
|
||||
mod=self.readwrite_nmos)
|
||||
self.connect_inst(["Q", "rwwl{}".format(k), "rwbl{}".format(k), "gnd"])
|
||||
|
||||
self.readwrite_nmos_right[k] = self.add_inst(name="readwrite_nmos_right{}".format(k),
|
||||
mod=self.readwrite_nmos)
|
||||
self.connect_inst(["Q_bar", "rwwl{}".format(k), "rwbl_bar{}".format(k), "gnd"])
|
||||
|
||||
|
||||
def place_readwrite_ports(self):
|
||||
"""
|
||||
Places read/write ports in the bit cell.
|
||||
"""
|
||||
|
||||
# Define variables relevant to write transistors
|
||||
self.rwwl_positions = [None] * self.num_readwrite
|
||||
self.rwbl_positions = [None] * self.num_readwrite
|
||||
self.rwbl_bar_positions = [None] * self.num_readwrite
|
||||
|
||||
# define offset correction due to rotation of the ptx module
|
||||
readwrite_rotation_correct = self.readwrite_nmos.active_height
|
||||
|
||||
# iterate over the number of read/write ports
|
||||
for k in range(0,self.num_readwrite):
|
||||
""" Add transistors """
|
||||
# Add transistors
|
||||
# calculate read/write transistor offsets
|
||||
left_readwrite_transistor_xpos = self.left_building_edge \
|
||||
- self.inverter_to_write_spacing \
|
||||
|
|
@ -404,19 +437,13 @@ class pbitcell(pgate.pgate):
|
|||
+ readwrite_rotation_correct
|
||||
|
||||
# add read/write transistors
|
||||
self.readwrite_nmos_left[k] = self.add_inst(name="readwrite_nmos_left{}".format(k),
|
||||
mod=self.readwrite_nmos,
|
||||
offset=[left_readwrite_transistor_xpos,0],
|
||||
rotate=90)
|
||||
self.connect_inst(["Q", "rwwl{}".format(k), "rwbl{}".format(k), "gnd"])
|
||||
self.readwrite_nmos_left[k].place(offset=[left_readwrite_transistor_xpos,0],
|
||||
rotate=90)
|
||||
|
||||
self.readwrite_nmos_right[k] = self.add_inst(name="readwrite_nmos_right{}".format(k),
|
||||
mod=self.readwrite_nmos,
|
||||
offset=[right_readwrite_transistor_xpos,0],
|
||||
rotate=90)
|
||||
self.connect_inst(["Q_bar", "rwwl{}".format(k), "rwbl_bar{}".format(k), "gnd"])
|
||||
self.readwrite_nmos_right[k].place(offset=[right_readwrite_transistor_xpos,0],
|
||||
rotate=90)
|
||||
|
||||
""" Add RWWL lines """
|
||||
# Add RWWL lines
|
||||
# calculate RWWL position
|
||||
rwwl_ypos = self.gnd_position.y - (k+1)*self.rowline_tile_height
|
||||
self.rwwl_positions[k] = vector(self.leftmost_xpos, rwwl_ypos)
|
||||
|
|
@ -428,7 +455,7 @@ class pbitcell(pgate.pgate):
|
|||
width=self.width,
|
||||
height=contact.m1m2.width)
|
||||
|
||||
""" Source/RWBL/RWBL_bar connections """
|
||||
# Source/RWBL/RWBL_bar connections
|
||||
# add metal1-to-metal2 contacts on top of read/write transistor source pins for connection to WBL and WBL_bar
|
||||
offset_left = self.readwrite_nmos_left[k].get_pin("S").center()
|
||||
self.add_contact_center(layers=("metal1", "via1", "metal2"),
|
||||
|
|
@ -455,7 +482,7 @@ class pbitcell(pgate.pgate):
|
|||
width=drc["minwidth_metal2"],
|
||||
height=self.height)
|
||||
|
||||
""" Gate/RWWL connections """
|
||||
# Gate/RWWL connections
|
||||
# add poly-to-meltal2 contacts to connect gate of read/write transistors to RWWL (contact next to gate)
|
||||
# contact must be placed a metal1 width below the source pin to avoid drc from source pin routings
|
||||
if(self.readwrite_nmos_contact_extension > self.gate_contact_thres):
|
||||
|
|
@ -504,7 +531,7 @@ class pbitcell(pgate.pgate):
|
|||
self.add_path("metal2", [left_gate_contact, left_rwwl_contact])
|
||||
self.add_path("metal2", [right_gate_contact, right_rwwl_contact])
|
||||
|
||||
""" Drain/Storage connections """
|
||||
# Drain/Storage connections
|
||||
# this path only needs to be drawn once on the last iteration of the loop
|
||||
if(k == self.num_readwrite-1):
|
||||
# add contacts to connect gate of inverters to drain of read/write transistors
|
||||
|
|
@ -538,34 +565,56 @@ class pbitcell(pgate.pgate):
|
|||
# end if
|
||||
# end for
|
||||
|
||||
""" update furthest left and right transistor edges """
|
||||
# update furthest left and right transistor edges
|
||||
self.left_building_edge = left_readwrite_transistor_xpos - self.readwrite_nmos.active_height
|
||||
self.right_building_edge = right_readwrite_transistor_xpos
|
||||
|
||||
|
||||
|
||||
def add_write_ports(self):
|
||||
def create_write_ports(self):
|
||||
"""
|
||||
Adds write ports to the bit cell. A differential pair of transistors can write only.
|
||||
Creates write ports in the bit cell. A differential pair of transistors can write only.
|
||||
A write is enabled by setting a Write-Rowline (WWL) high, subsequently turning on the transistor.
|
||||
The transistor is connected between a Write-Bitline (WBL) and the storage component of the cell (Q).
|
||||
In a write operation, driving WBL high or low sets the value of the cell.
|
||||
This is a differential design, so each write port has a mirrored port that connects WBL_bar to Q_bar.
|
||||
"""
|
||||
|
||||
""" Define variables relevant to write transistors """
|
||||
# Define variables relevant to write transistors
|
||||
# define offset correction due to rotation of the ptx module
|
||||
write_rotation_correct = self.write_nmos.active_height
|
||||
|
||||
# define write transistor variables as empty arrays based on the number of write ports
|
||||
self.write_nmos_left = [None] * self.num_write
|
||||
self.write_nmos_right = [None] * self.num_write
|
||||
self.wwl_positions = [None] * self.num_write
|
||||
self.wbl_positions = [None] * self.num_write
|
||||
self.wbl_bar_positions = [None] * self.num_write
|
||||
|
||||
# iterate over the number of write ports
|
||||
for k in range(0,self.num_write):
|
||||
""" Add transistors """
|
||||
# add write transistors
|
||||
self.write_nmos_left[k] = self.add_inst(name="write_nmos_left{}".format(k),
|
||||
mod=self.write_nmos)
|
||||
self.connect_inst(["Q", "wwl{}".format(k), "wbl{}".format(k), "gnd"])
|
||||
|
||||
self.write_nmos_right[k] = self.add_inst(name="write_nmos_right{}".format(k),
|
||||
mod=self.write_nmos)
|
||||
self.connect_inst(["Q_bar", "wwl{}".format(k), "wbl_bar{}".format(k), "gnd"])
|
||||
|
||||
|
||||
def place_write_ports(self):
|
||||
"""
|
||||
Places write ports in the bit cell.
|
||||
"""
|
||||
|
||||
# Define variables relevant to write transistors
|
||||
self.wwl_positions = [None] * self.num_write
|
||||
self.wbl_positions = [None] * self.num_write
|
||||
self.wbl_bar_positions = [None] * self.num_write
|
||||
|
||||
# define offset correction due to rotation of the ptx module
|
||||
write_rotation_correct = self.write_nmos.active_height
|
||||
|
||||
# iterate over the number of write ports
|
||||
for k in range(0,self.num_write):
|
||||
# Add transistors
|
||||
# calculate write transistor offsets
|
||||
left_write_transistor_xpos = self.left_building_edge \
|
||||
- (not self.readwrite_port_flag)*self.inverter_to_write_spacing \
|
||||
|
|
@ -580,19 +629,13 @@ class pbitcell(pgate.pgate):
|
|||
+ write_rotation_correct
|
||||
|
||||
# add write transistors
|
||||
self.write_nmos_left[k] = self.add_inst(name="write_nmos_left{}".format(k),
|
||||
mod=self.write_nmos,
|
||||
offset=[left_write_transistor_xpos,0],
|
||||
rotate=90)
|
||||
self.connect_inst(["Q", "wwl{}".format(k), "wbl{}".format(k), "gnd"])
|
||||
self.write_nmos_left[k].place(offset=[left_write_transistor_xpos,0],
|
||||
rotate=90)
|
||||
|
||||
self.write_nmos_right[k] = self.add_inst(name="write_nmos_right{}".format(k),
|
||||
mod=self.write_nmos,
|
||||
offset=[right_write_transistor_xpos,0],
|
||||
rotate=90)
|
||||
self.connect_inst(["Q_bar", "wwl{}".format(k), "wbl_bar{}".format(k), "gnd"])
|
||||
self.write_nmos_right[k].place(offset=[right_write_transistor_xpos,0],
|
||||
rotate=90)
|
||||
|
||||
""" Add WWL lines """
|
||||
# Add WWL lines
|
||||
# calculate WWL position
|
||||
wwl_ypos = self.gnd_position.y \
|
||||
- self.num_readwrite*self.rowline_tile_height \
|
||||
|
|
@ -606,7 +649,7 @@ class pbitcell(pgate.pgate):
|
|||
width=self.width,
|
||||
height=contact.m1m2.width)
|
||||
|
||||
""" Source/WBL/WBL_bar connections """
|
||||
# Source/WBL/WBL_bar connections
|
||||
# add metal1-to-metal2 contacts on top of write transistor source pins for connection to WBL and WBL_bar
|
||||
offset_left = self.write_nmos_left[k].get_pin("S").center()
|
||||
self.add_contact_center(layers=("metal1", "via1", "metal2"),
|
||||
|
|
@ -633,7 +676,7 @@ class pbitcell(pgate.pgate):
|
|||
width=drc["minwidth_metal2"],
|
||||
height=self.height)
|
||||
|
||||
""" Gate/WWL connections """
|
||||
# Gate/WWL connections
|
||||
# add poly-to-meltal2 contacts to connect gate of write transistors to WWL (contact next to gate)
|
||||
# contact must be placed a metal width below the source pin to avoid drc from source pin routings
|
||||
if(self.write_nmos_contact_extension > self.gate_contact_thres):
|
||||
|
|
@ -682,7 +725,7 @@ class pbitcell(pgate.pgate):
|
|||
self.add_path("metal2", [left_gate_contact, left_wwl_contact])
|
||||
self.add_path("metal2", [right_gate_contact, right_wwl_contact])
|
||||
|
||||
""" Drain/Storage connections """
|
||||
# Drain/Storage connections
|
||||
# this path only needs to be drawn once on the last iteration of the loop
|
||||
if(k == self.num_write-1):
|
||||
# add contacts to connect gate of inverters to drain of write transistors
|
||||
|
|
@ -713,17 +756,15 @@ class pbitcell(pgate.pgate):
|
|||
midR1 = vector(self.inverter_nmos_right.get_pin("D").rc().x + 1.5*drc["minwidth_metal1"], self.write_nmos_right[k].get_pin("D").rc().y)
|
||||
self.add_path("metal1", [right_storage_contact, midR0], width=contact.poly.second_layer_width)
|
||||
self.add_path("metal1", [midR0+vector(0,0.5*contact.poly.second_layer_width), midR1, self.write_nmos_right[k].get_pin("D").rc()])
|
||||
# end if
|
||||
# end for
|
||||
|
||||
""" update furthest left and right transistor edges """
|
||||
# update furthest left and right transistor edges
|
||||
self.left_building_edge = left_write_transistor_xpos - self.write_nmos.active_height
|
||||
self.right_building_edge = right_write_transistor_xpos
|
||||
|
||||
|
||||
def add_read_ports(self):
|
||||
def create_read_ports(self):
|
||||
"""
|
||||
Adds read ports to the bit cell. A differential pair of ports can read only.
|
||||
Creates read ports in the bit cell. A differential pair of ports can read only.
|
||||
Two transistors function as a read port, denoted as the "read transistor" and the "read-access transistor".
|
||||
The read transistor is connected to RWL (gate), RBL (drain), and the read-access transistor (source).
|
||||
The read-access transistor is connected to Q_bar (gate), gnd (source), and the read transistor (drain).
|
||||
|
|
@ -733,7 +774,42 @@ class pbitcell(pgate.pgate):
|
|||
using sense amps. This is a differential design, so each read port has a mirrored port that connects RBL_bar to Q.
|
||||
"""
|
||||
|
||||
""" Define variables relevant to read transistors """
|
||||
# define read transistor variables as empty arrays based on the number of read ports
|
||||
self.read_nmos_left = [None] * self.num_read
|
||||
self.read_nmos_right = [None] * self.num_read
|
||||
self.read_access_nmos_left = [None] * self.num_read
|
||||
self.read_access_nmos_right = [None] * self.num_read
|
||||
|
||||
# iterate over the number of read ports
|
||||
for k in range(0,self.num_read):
|
||||
# add read-access transistors
|
||||
self.read_access_nmos_left[k] = self.add_inst(name="read_access_nmos_left{}".format(k),
|
||||
mod=self.read_nmos)
|
||||
self.connect_inst(["RA_to_R_left{}".format(k), " Q_bar", "gnd", "gnd"])
|
||||
|
||||
self.read_access_nmos_right[k] = self.add_inst(name="read_access_nmos_right{}".format(k),
|
||||
mod=self.read_nmos)
|
||||
self.connect_inst(["RA_to_R_right{}".format(k), "Q", "gnd", "gnd"])
|
||||
|
||||
# add read transistors
|
||||
self.read_nmos_left[k] = self.add_inst(name="read_nmos_left{}".format(k),
|
||||
mod=self.read_nmos)
|
||||
self.connect_inst(["rbl{}".format(k), "rwl{}".format(k), "RA_to_R_left{}".format(k), "gnd"])
|
||||
|
||||
self.read_nmos_right[k] = self.add_inst(name="read_nmos_right{}".format(k),
|
||||
mod=self.read_nmos)
|
||||
self.connect_inst(["rbl_bar{}".format(k), "rwl{}".format(k), "RA_to_R_right{}".format(k), "gnd"])
|
||||
|
||||
def place_read_ports(self):
|
||||
"""
|
||||
Places the read ports in the bit cell.
|
||||
"""
|
||||
|
||||
# Define variables relevant to read transistors
|
||||
self.rwl_positions = [None] * self.num_read
|
||||
self.rbl_positions = [None] * self.num_read
|
||||
self.rbl_bar_positions = [None] * self.num_read
|
||||
|
||||
# define offset correction due to rotation of the ptx module
|
||||
read_rotation_correct = self.read_nmos.active_height
|
||||
|
||||
|
|
@ -751,7 +827,7 @@ class pbitcell(pgate.pgate):
|
|||
|
||||
# iterate over the number of read ports
|
||||
for k in range(0,self.num_read):
|
||||
""" Add transistors """
|
||||
# Add transistors
|
||||
# calculate transistor offsets
|
||||
left_read_transistor_xpos = self.left_building_edge \
|
||||
- self.write_to_read_spacing \
|
||||
|
|
@ -789,7 +865,7 @@ class pbitcell(pgate.pgate):
|
|||
rotate=90)
|
||||
self.connect_inst(["rbl_bar{}".format(k), "rwl{}".format(k), "RA_to_R_right{}".format(k), "gnd"])
|
||||
|
||||
""" Add RWL lines """
|
||||
# Add RWL lines
|
||||
# calculate RWL position
|
||||
rwl_ypos = self.gnd_position.y \
|
||||
- self.num_readwrite*self.rowline_tile_height \
|
||||
|
|
@ -804,7 +880,7 @@ class pbitcell(pgate.pgate):
|
|||
width=self.width,
|
||||
height=contact.m1m2.width)
|
||||
|
||||
""" Drain of read transistor / RBL & RBL_bar connection """
|
||||
# Drain of read transistor / RBL & RBL_bar connection
|
||||
# add metal1-to-metal2 contacts on top of read transistor drain pins for connection to RBL and RBL_bar
|
||||
offset_left = self.read_nmos_left[k].get_pin("D").center()
|
||||
self.add_contact_center(layers=("metal1", "via1", "metal2"),
|
||||
|
|
@ -831,7 +907,7 @@ class pbitcell(pgate.pgate):
|
|||
width=drc["minwidth_metal2"],
|
||||
height=self.height)
|
||||
|
||||
""" Gate of read transistor / RWL connection """
|
||||
# Gate of read transistor / RWL connection
|
||||
# add poly-to-meltal2 contacts to connect gate of read transistors to RWL (contact next to gate)
|
||||
if(self.read_nmos_contact_extension > self.gate_contact_thres):
|
||||
contact_xpos = self.read_nmos_left[k].get_pin("S").lc().x - drc["minwidth_metal2"] - 0.5*contact.m1m2.width
|
||||
|
|
@ -876,7 +952,7 @@ class pbitcell(pgate.pgate):
|
|||
self.add_path("metal2", [left_gate_contact, left_rwl_contact])
|
||||
self.add_path("metal2", [right_gate_contact, right_rwl_contact])
|
||||
|
||||
""" Source of read-access transistor / GND connection """
|
||||
# Source of read-access transistor / GND connection
|
||||
# connect source of read-access transistor to GND (metal1 path)
|
||||
gnd_offset_left = vector(self.read_access_nmos_left[k].get_pin("S").bc().x, self.gnd_position.y)
|
||||
self.add_path("metal1", [self.read_access_nmos_left[k].get_pin("S").bc(), gnd_offset_left])
|
||||
|
|
@ -884,7 +960,7 @@ class pbitcell(pgate.pgate):
|
|||
gnd_offset_right = vector(self.read_access_nmos_right[k].get_pin("S").bc().x, self.gnd_position.y)
|
||||
self.add_path("metal1", [self.read_access_nmos_right[k].get_pin("S").bc(), gnd_offset_right])
|
||||
|
||||
""" Gate of read-access transistor / storage connection """
|
||||
# Gate of read-access transistor / storage connection
|
||||
# add poly-to-metal1 contacts to connect gate of read-access transistors to output of inverters (contact next to gate)
|
||||
if(self.read_nmos_contact_extension > self.gate_contact_thres):
|
||||
contact_xpos = self.read_nmos_left[k].get_pin("S").rc().x + drc["minwidth_metal2"] + 0.5*contact.m1m2.width
|
||||
|
|
@ -933,7 +1009,7 @@ class pbitcell(pgate.pgate):
|
|||
self.add_path("metal1", [right_gate_contact, midR0, midR1, midR2, right_inverter_offset])
|
||||
# end for
|
||||
|
||||
|
||||
|
||||
def extend_well(self):
|
||||
"""
|
||||
Connects wells between ptx modules to avoid drc spacing issues.
|
||||
|
|
@ -941,7 +1017,7 @@ class pbitcell(pgate.pgate):
|
|||
the well connections must be done piecewise to avoid pwell and nwell overlap.
|
||||
"""
|
||||
|
||||
""" extend pwell to encompass entire nmos region of the cell up to the height of the inverter nmos well """
|
||||
# extend pwell to encompass entire nmos region of the cell up to the height of the inverter nmos well
|
||||
offset = vector(self.leftmost_xpos, self.botmost_ypos)
|
||||
well_height = -self.botmost_ypos + self.inverter_nmos.cell_well_height - drc["well_enclosure_active"]
|
||||
self.add_rect(layer="pwell",
|
||||
|
|
@ -949,7 +1025,9 @@ class pbitcell(pgate.pgate):
|
|||
width=self.width,
|
||||
height=well_height)
|
||||
|
||||
""" extend pwell over read/write and write transistors to the height of the write transistor well (read/write and write transistors are the same height) """
|
||||
# extend pwell over read/write and write transistors to the
|
||||
# height of the write transistor well (read/write and write
|
||||
# transistors are the same height)
|
||||
if(self.num_write > 0):
|
||||
# calculate the edge of the write transistor well closest to the center
|
||||
left_write_well_xpos = self.write_nmos_left[0].offset.x + drc["well_enclosure_active"]
|
||||
|
|
@ -975,7 +1053,7 @@ class pbitcell(pgate.pgate):
|
|||
width=write_well_width,
|
||||
height=write_well_height)
|
||||
|
||||
""" extend pwell over the read transistors to the height of the bitcell """
|
||||
# extend pwell over the read transistors to the height of the bitcell
|
||||
if(self.num_read > 0):
|
||||
# calculate the edge of the read transistor well clostest to the center
|
||||
left_read_well_xpos = self.read_nmos_left[0].offset.x + drc["well_enclosure_active"]
|
||||
|
|
@ -997,7 +1075,7 @@ class pbitcell(pgate.pgate):
|
|||
width=read_well_width,
|
||||
height=read_well_height)
|
||||
|
||||
""" extend nwell to encompass inverter_pmos """
|
||||
# extend nwell to encompass inverter_pmos
|
||||
# calculate offset of the left pmos well
|
||||
inverter_well_xpos = -self.inverter_tile_width - drc["well_enclosure_active"]
|
||||
inverter_well_ypos = self.inverter_nmos.active_height + self.inverter_gap - drc["well_enclosure_active"]
|
||||
|
|
@ -1014,7 +1092,7 @@ class pbitcell(pgate.pgate):
|
|||
height=well_height)
|
||||
|
||||
|
||||
""" add well contacts """
|
||||
# add well contacts
|
||||
# connect pimplants to gnd
|
||||
offset = vector(0, self.gnd_position.y + 0.5*contact.well.second_layer_width)
|
||||
self.add_contact_center(layers=("active", "contact", "metal1"),
|
||||
|
|
|
|||
|
|
@ -17,21 +17,19 @@ class single_level_column_mux(design.design):
|
|||
design.design.__init__(self, name)
|
||||
debug.info(2, "create single column mux cell: {0}".format(name))
|
||||
|
||||
from importlib import reload
|
||||
c = reload(__import__(OPTS.bitcell))
|
||||
self.mod_bitcell = getattr(c, OPTS.bitcell)
|
||||
self.bitcell = self.mod_bitcell()
|
||||
|
||||
self.ptx_width = tx_size * drc["minwidth_tx"]
|
||||
self.tx_size = tx_size
|
||||
|
||||
self.create_netlist()
|
||||
self.create_layout()
|
||||
if not OPTS.netlist_only:
|
||||
self.create_layout()
|
||||
|
||||
def create_netlist(self):
|
||||
self.add_pin_list(["bl", "br", "bl_out", "br_out", "sel", "gnd"])
|
||||
self.add_modules()
|
||||
self.add_pins()
|
||||
self.add_ptx()
|
||||
|
||||
def create_layout(self):
|
||||
|
||||
self.pin_height = 2*self.m2_width
|
||||
self.width = self.bitcell.width
|
||||
self.height = self.nmos_upper.uy() + self.pin_height
|
||||
|
|
@ -39,7 +37,23 @@ class single_level_column_mux(design.design):
|
|||
self.add_bitline_pins()
|
||||
self.connect_bitlines()
|
||||
self.add_wells()
|
||||
|
||||
def add_modules(self):
|
||||
from importlib import reload
|
||||
c = reload(__import__(OPTS.bitcell))
|
||||
self.mod_bitcell = getattr(c, OPTS.bitcell)
|
||||
self.bitcell = self.mod_bitcell()
|
||||
|
||||
# Adds nmos_lower,nmos_upper to the module
|
||||
self.ptx_width = self.tx_size * drc["minwidth_tx"]
|
||||
self.nmos = ptx(width=self.ptx_width)
|
||||
self.add_mod(self.nmos)
|
||||
|
||||
|
||||
|
||||
def add_pins(self):
|
||||
self.add_pin_list(["bl", "br", "bl_out", "br_out", "sel", "gnd"])
|
||||
|
||||
def add_bitline_pins(self):
|
||||
""" Add the top and bottom pins to this cell """
|
||||
|
||||
|
|
@ -70,10 +84,6 @@ class single_level_column_mux(design.design):
|
|||
def add_ptx(self):
|
||||
""" Create the two pass gate NMOS transistors to switch the bitlines"""
|
||||
|
||||
# Adds nmos_lower,nmos_upper to the module
|
||||
self.nmos = ptx(width=self.ptx_width)
|
||||
self.add_mod(self.nmos)
|
||||
|
||||
# Space it in the center
|
||||
nmos_lower_position = self.nmos.active_offset.scale(0,1) + vector(0.5*self.bitcell.width-0.5*self.nmos.active_width,0)
|
||||
self.nmos_lower=self.add_inst(name="mux_tx1",
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
#!/usr/bin/env python2.7
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
Run regresion tests on a parameterized bitcell
|
||||
"""
|
||||
|
|
|
|||
Loading…
Reference in New Issue