Merge branch 'dev' into multiport_characterization

This commit is contained in:
Hunter Nichols 2018-08-29 01:27:37 -07:00
commit 8a0411279e
46 changed files with 1241 additions and 974 deletions

View File

@ -57,6 +57,9 @@ class geometry:
def compute_boundary(self,offset=vector(0,0),mirror="",rotate=0):
""" Transform with offset, mirror and rotation to get the absolute pin location.
We must then re-find the ll and ur. The master is the cell instance. """
if OPTS.netlist_only:
return
(ll,ur) = [vector(0,0),vector(self.width,self.height)]
if mirror=="MX":
ll=ll.scale(1,-1)
@ -192,6 +195,14 @@ class instance(geometry):
mirror=self.mirror,
rotate=self.rotate)
def place(self, offset, mirror="R0", rotate=0):
""" 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 = vector(offset)
self.mirror = mirror
self.rotate = rotate
self.update_boundary()
def get_pin(self,name,index=-1):

View File

@ -5,6 +5,7 @@ import debug
from tech import drc, GDS
from tech import layer as techlayer
import os
from globals import OPTS
from vector import vector
from pin_layout import pin_layout
import lef
@ -118,17 +119,6 @@ class layout(lef.lef):
for pin in pin_list:
pin.rect = [pin.ll() - offset, pin.ur() - offset]
def place_inst(self, name, offset, mirror="R0", rotate=0):
""" This updates the placement of an instance. """
inst = self.get_inst(name)
debug.info(3, "placing instance {}".format(inst))
# Update the placement of an already added instance
inst.offset = offset
inst.mirror = mirror
inst.rotate = rotate
inst.update_boundary()
return inst
def add_inst(self, name, mod, offset=[0,0], mirror="R0",rotate=0):
"""Adds an instance of a mod to this module"""
self.insts.append(geometry.instance(name, mod, offset, mirror, rotate))
@ -436,6 +426,10 @@ class layout(lef.lef):
def gds_read(self):
"""Reads a GDSII file in the library and checks if it exists
Otherwise, start a new layout for dynamic generation."""
if OPTS.netlist_only:
self.gds = None
return
# open the gds file if it exists or else create a blank layout
if os.path.isfile(self.gds_file):
debug.info(3, "opening %s" % self.gds_file)

View File

@ -8,7 +8,7 @@ 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)
#Below are some additions to test additional ports on sram
#bitcell = "pbitcell"

View File

@ -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)

View File

@ -142,22 +142,31 @@ def init_openram(config_file, is_unit_test=True):
def get_tool(tool_type, preferences):
def get_tool(tool_type, preferences, default_name=None):
"""
Find which tool we have from a list of preferences and return the
one selected and its full path.
one selected and its full path. If default is specified,
find that one only and error otherwise.
"""
debug.info(2,"Finding {} tool...".format(tool_type))
for name in preferences:
exe_name = find_exe(name)
if exe_name != None:
debug.info(1, "Using {0}: {1}".format(tool_type,exe_name))
return(name,exe_name)
if default_name:
exe_name=find_exe(default_name)
if exe_name == None:
debug.error("{0} not found. Cannot find {1} tool.".format(default_name,tool_type),2)
else:
debug.info(1, "Could not find {0}, trying next {1} tool.".format(name,tool_type))
debug.info(1, "Using {0}: {1}".format(tool_type,exe_name))
return(default_name,exe_name)
else:
return(None,"")
for name in preferences:
exe_name = find_exe(name)
if exe_name != None:
debug.info(1, "Using {0}: {1}".format(tool_type,exe_name))
return(name,exe_name)
else:
debug.info(1, "Could not find {0}, trying next {1} tool.".format(name,tool_type))
else:
return(None,"")
def read_config(config_file, is_unit_test=True):
@ -207,7 +216,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 == ""):

View File

@ -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)
@ -56,7 +45,8 @@ class bank(design.design):
self.prefix=""
self.create_netlist()
self.create_layout()
if not OPTS.netlist_only:
self.create_layout()
def create_netlist(self):
@ -205,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,
@ -277,8 +280,7 @@ class bank(design.design):
def place_bitcell_array(self):
""" Placing Bitcell Array """
self.place_inst(name="bitcell_array",
offset=vector(0,0))
self.bitcell_array_inst.place(vector(0,0))
def create_precharge_array(self):
@ -303,8 +305,7 @@ class bank(design.design):
# The wells must be far enough apart
# The enclosure is for the well and the spacing is to the bitcell wells
y_offset = self.bitcell_array.height + self.m2_gap
self.place_inst(name=self.precharge_array_inst[k].name,
offset=vector(0,y_offset))
self.precharge_array_inst[k].place(vector(0,y_offset))
def create_column_mux_array(self):
""" Creating Column Mux when words_per_row > 1 . """
@ -338,8 +339,7 @@ class bank(design.design):
for k in range(self.total_ports):
y_offset = self.column_mux_height
self.place_inst(name=self.col_mux_array_inst[k].name,
offset=vector(0,y_offset).scale(-1,-1))
self.col_mux_array_inst[k].place(vector(0,y_offset).scale(-1,-1))
def create_sense_amp_array(self):
""" Creating Sense amp """
@ -368,8 +368,7 @@ class bank(design.design):
# FIXME: place for multiport
for k in range(self.total_read):
y_offset = self.column_mux_height + self.sense_amp_array.height + self.m2_gap
self.place_inst(name=self.sense_amp_array_inst[k].name,
offset=vector(0,y_offset).scale(-1,-1))
self.sense_amp_array_inst[k].place(vector(0,y_offset).scale(-1,-1))
def create_write_driver_array(self):
""" Creating Write Driver """
@ -399,8 +398,7 @@ class bank(design.design):
for k in range(self.total_write):
y_offset = self.sense_amp_array.height + self.column_mux_height \
+ self.m2_gap + self.write_driver_array.height
self.place_inst(name=self.write_driver_array_inst[k].name,
offset=vector(0,y_offset).scale(-1,-1))
self.write_driver_array_inst[k].place(vector(0,y_offset).scale(-1,-1))
@ -432,8 +430,7 @@ class bank(design.design):
# FIXME: place for multiport
for k in range(self.total_ports):
x_offset = -(self.row_decoder.width + self.central_bus_width + self.wordline_driver.width)
self.place_inst(name=self.row_decoder_inst[k].name,
offset=vector(x_offset,0))
self.row_decoder_inst[k].place(vector(x_offset,0))
def create_wordline_driver(self):
@ -461,8 +458,7 @@ class bank(design.design):
for k in range(self.total_ports):
# The wordline driver is placed to the right of the main decoder width.
x_offset = -(self.central_bus_width + self.wordline_driver.width) + self.m2_pitch
self.place_inst(name=self.wordline_driver_inst[k].name,
offset=vector(x_offset,0))
self.wordline_driver_inst[k].place(vector(x_offset,0))
def create_column_decoder(self):
@ -508,8 +504,7 @@ class bank(design.design):
# Place the col decoder right aligned with row decoder
x_off = -(self.central_bus_width + self.wordline_driver.width + self.col_decoder.width)
y_off = -(self.col_decoder.height + 2*drc["well_to_well"])
self.place_inst(name=self.col_decoder_inst[k].name,
offset=vector(x_off,y_off))
self.col_decoder_inst[k].place(vector(x_off,y_off))
def create_bank_select(self):
@ -545,8 +540,7 @@ class bank(design.design):
y_off = self.row_decoder_inst[0].by()
y_off -= (self.bank_select.height + drc["well_to_well"])
self.bank_select_pos = vector(x_off,y_off)
self.place_inst(name=self.bank_select_inst[k].name,
offset=self.bank_select_pos)
self.bank_select_inst[k].place(self.bank_select_pos)
def route_vdd_gnd(self):
@ -580,23 +574,25 @@ class bank(design.design):
def route_bank_select(self):
""" Route the bank select logic. """
for input_name in self.input_control_signals+["bank_sel"]:
self.copy_layout_pin(self.bank_select_inst, input_name)
for k in range(self.total_ports):
for input_name in self.input_control_signals+["bank_sel"]:
self.copy_layout_pin(self.bank_select_inst[k], input_name)
for gated_name in self.control_signals:
# Connect the inverter output to the central bus
out_pos = self.bank_select_inst[0].get_pin(gated_name).rc()
bus_pos = vector(self.bus_xoffset[gated_name].x, out_pos.y)
self.add_path("metal3",[out_pos, bus_pos])
self.add_via_center(layers=("metal2", "via2", "metal3"),
offset=bus_pos,
rotate=90)
self.add_via_center(layers=("metal1", "via1", "metal2"),
offset=out_pos,
rotate=90)
self.add_via_center(layers=("metal2", "via2", "metal3"),
offset=out_pos,
rotate=90)
for gated_name in self.control_signals:
# Connect the inverter output to the central bus
out_pos = self.bank_select_inst[k].get_pin(gated_name).rc()
bus_pos = vector(self.bus_xoffset[gated_name].x, out_pos.y)
self.add_path("metal3",[out_pos, bus_pos])
self.add_via_center(layers=("metal2", "via2", "metal3"),
offset=bus_pos,
rotate=90)
self.add_via_center(layers=("metal1", "via1", "metal2"),
offset=out_pos,
rotate=90)
self.add_via_center(layers=("metal2", "via2", "metal3"),
offset=out_pos,
rotate=90)
def setup_routing_constraints(self):

View File

@ -18,9 +18,29 @@ class bank_select(design.design):
def __init__(self, name="bank_select"):
design.design.__init__(self, name)
self.create_netlist()
if not OPTS.netlist_only:
self.create_layout()
def create_netlist(self):
self.add_pins()
self.add_modules()
self.create_modules()
def create_layout(self):
self.calculate_module_offsets()
self.place_modules()
self.route_modules()
self.DRC_LVS()
def add_pins(self):
# Number of control lines in the bus
self.num_control_lines = 4
# The order of the control signals on the control bus:
# FIXME: Update for multiport (these names are not right)
self.input_control_signals = ["clk_buf", "clk_buf_bar", "w_en0", "s_en0"]
# These will be outputs of the gaters if this is multibank
self.control_signals = ["gated_"+str for str in self.input_control_signals]
@ -31,14 +51,7 @@ class bank_select(design.design):
self.add_pin("vdd","POWER")
self.add_pin("gnd","GROUND")
self.create_modules()
self.calculate_module_offsets()
self.add_modules()
self.route_modules()
self.DRC_LVS()
def create_modules(self):
def add_modules(self):
""" Create modules for later instantiation """
# 1x Inverter
self.inv = pinv()
@ -67,15 +80,10 @@ class bank_select(design.design):
self.height = self.yoffset_maxpoint + 2*self.m1_pitch
self.width = self.xoffset_inv + self.inv4x.width
def add_modules(self):
def create_modules(self):
# bank select inverter
self.bank_select_inv_position = vector(self.xoffset_bank_sel_inv, 0)
# bank select inverter (must be made unique if more than one OR)
self.bank_sel_inv=self.add_inst(name="bank_sel_inv",
mod=self.inv,
offset=[self.xoffset_bank_sel_inv, 0])
mod=self.inv)
self.connect_inst(["bank_sel", "bank_sel_bar", "vdd", "gnd"])
self.logic_inst = []
@ -87,6 +95,51 @@ class bank_select(design.design):
name_nor = "nor_{}".format(input_name)
name_inv = "inv_{}".format(input_name)
# These require OR (nor2+inv) gates since they are active low.
# (writes occur on clk low)
if input_name in ("clk_buf"):
self.logic_inst.append(self.add_inst(name=name_nor,
mod=self.nor2))
self.connect_inst([input_name,
"bank_sel_bar",
gated_name+"_temp_bar",
"vdd",
"gnd"])
# the rest are AND (nand2+inv) gates
else:
self.logic_inst.append(self.add_inst(name=name_nand,
mod=self.nand2))
self.connect_inst([input_name,
"bank_sel",
gated_name+"_temp_bar",
"vdd",
"gnd"])
# They all get inverters on the output
self.inv_inst.append(self.add_inst(name=name_inv,
mod=self.inv4x))
self.connect_inst([gated_name+"_temp_bar",
gated_name,
"vdd",
"gnd"])
def place_modules(self):
# bank select inverter
self.bank_select_inv_position = vector(self.xoffset_bank_sel_inv, 0)
# bank select inverter (must be made unique if more than one OR)
self.bank_sel_inv.place(vector(self.xoffset_bank_sel_inv, 0))
for i in range(self.num_control_lines):
logic_inst = self.logic_inst[i]
inv_inst = self.inv_inst[i]
input_name = self.input_control_signals[i]
y_offset = self.inv.height * i
if i%2:
y_offset += self.inv.height
@ -98,40 +151,18 @@ class bank_select(design.design):
# (writes occur on clk low)
if input_name in ("clk_buf"):
self.logic_inst.append(self.add_inst(name=name_nor,
mod=self.nor2,
offset=[self.xoffset_nor, y_offset],
mirror=mirror))
self.connect_inst([input_name,
"bank_sel_bar",
gated_name+"_temp_bar",
"vdd",
"gnd"])
logic_inst.place(offset=[self.xoffset_nor, y_offset],
mirror=mirror)
# the rest are AND (nand2+inv) gates
else:
self.logic_inst.append(self.add_inst(name=name_nand,
mod=self.nand2,
offset=[self.xoffset_nand, y_offset],
mirror=mirror))
bank_sel_signal = "bank_sel"
self.connect_inst([input_name,
"bank_sel",
gated_name+"_temp_bar",
"vdd",
"gnd"])
logic_inst.place(offset=[self.xoffset_nand, y_offset],
mirror=mirror)
# They all get inverters on the output
self.inv_inst.append(self.add_inst(name=name_inv,
mod=self.inv4x,
offset=[self.xoffset_inv, y_offset],
mirror=mirror))
self.connect_inst([gated_name+"_temp_bar",
gated_name,
"vdd",
"gnd"])
inv_inst.place(offset=[self.xoffset_inv, y_offset],
mirror=mirror)
def route_modules(self):

View File

@ -21,38 +21,27 @@ 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()
self.create_layout()
if not OPTS.netlist_only:
self.create_layout()
# We don't offset this because we need to align
# the replica bitcell in the control logic
#self.offset_all_coordinates()
def add_pins(self):
row_list = self.cell.list_all_wl_names()
column_list = self.cell.list_all_bitline_names()
for col in range(self.column_size):
for cell_column in column_list:
self.add_pin(cell_column+"[{0}]".format(col))
for row in range(self.row_size):
for cell_row in row_list:
self.add_pin(cell_row+"[{0}]".format(row))
self.add_pin("vdd")
self.add_pin("gnd")
def create_netlist(self):
""" Create and connect the netlist """
self.add_modules()
self.add_pins()
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
@ -66,20 +55,38 @@ class bitcell_array(design.design):
tempy = yoffset
dir_key = ""
self.place_inst(name=name,
offset=[xoffset, tempy],
mirror=dir_key)
self.cell_inst[row,col].place(offset=[xoffset, tempy],
mirror=dir_key)
yoffset += self.cell.height
xoffset += self.cell.width
self.add_layout_pins()
self.DRC_LVS()
def create_netlist(self):
""" Create and connect the netlist """
self.add_pins()
def add_pins(self):
row_list = self.cell.list_all_wl_names()
column_list = self.cell.list_all_bitline_names()
for col in range(self.column_size):
for cell_column in column_list:
self.add_pin(cell_column+"[{0}]".format(col))
for row in range(self.row_size):
for cell_row in row_list:
self.add_pin(cell_row+"[{0}]".format(row))
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):
@ -87,8 +94,7 @@ class bitcell_array(design.design):
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 """

View File

@ -24,17 +24,26 @@ class control_logic(design.design):
debug.info(1, "Creating {}".format(self.name))
self.num_rows = num_rows
self.create_layout()
self.DRC_LVS()
self.create_netlist()
if not OPTS.netlist_only:
self.create_layout()
def create_netlist(self):
self.setup_signal_busses()
self.add_pins()
self.add_modules()
self.create_modules()
def create_layout(self):
""" Create layout and route between modules """
self.setup_layout_offsets()
self.add_pins()
self.create_modules()
self.add_rails()
self.add_modules()
self.add_routing()
self.route_rails()
self.place_modules()
self.route_all()
self.add_lvs_correspondence_points()
self.DRC_LVS()
def add_pins(self):
@ -46,8 +55,8 @@ class control_logic(design.design):
self.add_pin("vdd","POWER")
self.add_pin("gnd","GROUND")
def create_modules(self):
""" add all the required modules """
def add_modules(self):
""" Add all the required modules """
dff = dff_inv()
dff_height = dff.height
@ -83,14 +92,8 @@ class control_logic(design.design):
self.add_mod(self.replica_bitline)
def setup_layout_offsets(self):
""" Setup layout offsets, determine the size of the busses etc """
# These aren't for instantiating, but we use them to get the dimensions
#self.poly_contact_offset = vector(0.5*contact.poly.width,0.5*contact.poly.height)
# Have the cell gap leave enough room to route an M2 wire.
# Some cells may have pwell/nwell spacing problems too when the wells are different heights.
#self.cell_gap = max(self.m2_pitch,drc["pwell_to_nwell"])
def setup_signal_busses(self):
""" Setup bus names, determine the size of the busses etc """
# List of input control signals
self.input_list =["csb","web"]
@ -104,7 +107,7 @@ class control_logic(design.design):
self.supply_list = ["vdd", "gnd"]
def add_rails(self):
def route_rails(self):
""" Add the input signal inverted tracks """
height = 4*self.inv1.height - self.m2_pitch
offset = vector(self.ctrl_dff_array.width,0)
@ -112,7 +115,20 @@ class control_logic(design.design):
self.rail_offsets = self.create_vertical_bus("metal2", self.m2_pitch, offset, self.internal_bus_list, height)
def add_modules(self):
def create_modules(self):
""" Create all the modules """
self.create_dffs()
self.create_clk_row()
self.create_we_row()
# self.create_trien_row()
# self.create_trien_bar_row()
self.create_rbl_in_row()
self.create_sen_row()
self.create_rbl()
def place_modules(self):
""" Place all the modules """
# Keep track of all right-most instances to determine row boundary
# and add the vdd/gnd pins
@ -120,20 +136,18 @@ class control_logic(design.design):
# Add the control flops on the left of the bus
self.add_dffs()
self.place_dffs()
# Add the logic on the right of the bus
self.add_clk_row(row=0) # clk is a double-high cell
self.add_we_row(row=2)
# self.add_trien_row(row=3)
# self.add_trien_bar_row(row=4)
self.add_rbl_in_row(row=3)
self.add_sen_row(row=4)
self.add_rbl(row=5)
self.place_clk_row(row=0) # clk is a double-high cell
self.place_we_row(row=2)
# self.place_trien_row(row=3)
# self.place_trien_bar_row(row=4)
self.place_rbl_in_row(row=3)
self.place_sen_row(row=4)
self.place_rbl(row=5)
self.add_lvs_correspondence_points()
# This offset is used for placement of the control logic in
# the SRAM level.
self.control_logic_center = vector(self.ctrl_dff_inst.rx(), self.rbl_inst.by())
@ -142,9 +156,9 @@ class control_logic(design.design):
self.height = self.rbl_inst.uy() + self.m3_pitch
# Max of modules or logic rows
self.width = max(self.rbl_inst.rx(), max([inst.rx() for inst in self.row_end_inst])) + self.m2_pitch
def add_routing(self):
def route_all(self):
""" Routing between modules """
self.route_dffs()
#self.route_trien()
@ -156,84 +170,92 @@ class control_logic(design.design):
self.route_supply()
def add_rbl(self,row):
""" Add the replica bitline """
def create_rbl(self):
""" Create the replica bitline """
self.rbl_inst=self.add_inst(name="replica_bitline",
mod=self.replica_bitline)
self.connect_inst(["rbl_in", "pre_s_en", "vdd", "gnd"])
def place_rbl(self,row):
""" Place the replica bitline """
y_off = row * self.inv1.height + 2*self.m1_pitch
# Add the RBL above the rows
# Add to the right of the control rows and routing channel
self.replica_bitline_offset = vector(0, y_off)
self.rbl_inst=self.add_inst(name="replica_bitline",
mod=self.replica_bitline,
offset=self.replica_bitline_offset)
self.connect_inst(["rbl_in", "pre_s_en", "vdd", "gnd"])
self.rbl_inst.place(self.replica_bitline_offset)
def add_clk_row(self,row):
""" Add the multistage clock buffer below the control flops """
x_off = self.ctrl_dff_array.width + self.internal_bus_width
(y_off,mirror)=self.get_offset(row)
clkbuf_offset = vector(x_off,y_off)
def create_clk_row(self):
""" Create the multistage clock buffer """
self.clkbuf_inst = self.add_inst(name="clkbuf",
mod=self.clkbuf,
offset=clkbuf_offset)
mod=self.clkbuf)
self.connect_inst(["clk","clk_buf_bar","clk_buf","vdd","gnd"])
def place_clk_row(self,row):
""" Place the multistage clock buffer below the control flops """
x_off = self.ctrl_dff_array.width + self.internal_bus_width
(y_off,mirror)=self.get_offset(row)
clkbuf_offset = vector(x_off,y_off)
self.clkbuf_inst.place(clkbuf_offset)
self.row_end_inst.append(self.clkbuf_inst)
def add_rbl_in_row(self,row):
x_off = self.ctrl_dff_array.width + self.internal_bus_width
(y_off,mirror)=self.get_offset(row)
# input: clk_buf_bar,CS output: rbl_in_bar
self.rbl_in_bar_offset = vector(x_off, y_off)
def create_rbl_in_row(self):
self.rbl_in_bar_inst=self.add_inst(name="nand3_rbl_in_bar",
mod=self.nand2,
offset=self.rbl_in_bar_offset,
mirror=mirror)
mod=self.nand2)
self.connect_inst(["clk_buf_bar", "cs", "rbl_in_bar", "vdd", "gnd"])
x_off += self.nand2.width
# input: rbl_in_bar, output: rbl_in
self.rbl_in_offset = vector(x_off, y_off)
self.rbl_in_inst=self.add_inst(name="inv_rbl_in",
mod=self.inv1,
offset=self.rbl_in_offset,
mirror=mirror)
mod=self.inv1)
self.connect_inst(["rbl_in_bar", "rbl_in", "vdd", "gnd"])
self.row_end_inst.append(self.rbl_in_inst)
def add_sen_row(self,row):
""" The sense enable buffer gets placed to the far right of the
row. """
def place_rbl_in_row(self,row):
x_off = self.ctrl_dff_array.width + self.internal_bus_width
(y_off,mirror)=self.get_offset(row)
self.rbl_in_bar_offset = vector(x_off, y_off)
self.rbl_in_bar_inst.place(offset=self.rbl_in_bar_offset,
mirror=mirror)
x_off += self.nand2.width
self.rbl_in_offset = vector(x_off, y_off)
self.rbl_in_inst.place(offset=self.rbl_in_offset,
mirror=mirror)
self.row_end_inst.append(self.rbl_in_inst)
def create_sen_row(self):
""" Create the sense enable buffer. """
# input: pre_s_en, output: pre_s_en_bar
self.pre_s_en_bar_offset = vector(x_off, y_off)
self.pre_s_en_bar_inst=self.add_inst(name="inv_pre_s_en_bar",
mod=self.inv2,
offset=self.pre_s_en_bar_offset,
mirror=mirror)
mod=self.inv2)
self.connect_inst(["pre_s_en", "pre_s_en_bar", "vdd", "gnd"])
x_off += self.inv2.width
# BUFFER INVERTERS FOR S_EN
# input: input: pre_s_en_bar, output: s_en
self.s_en_offset = vector(x_off, y_off)
self.s_en_inst=self.add_inst(name="inv_s_en",
mod=self.inv8,
offset=self.s_en_offset,
mirror=mirror)
mod=self.inv8)
self.connect_inst(["pre_s_en_bar", "s_en0", "vdd", "gnd"])
def place_sen_row(self,row):
"""
The sense enable buffer gets placed to the far right of the
row.
"""
x_off = self.ctrl_dff_array.width + self.internal_bus_width
(y_off,mirror)=self.get_offset(row)
self.pre_s_en_bar_offset = vector(x_off, y_off)
self.pre_s_en_bar_inst.place(offset=self.pre_s_en_bar_offset,
mirror=mirror)
x_off += self.inv2.width
self.s_en_offset = vector(x_off, y_off)
self.s_en_inst.place(offset=self.s_en_offset,
mirror=mirror)
self.row_end_inst.append(self.s_en_inst)
@ -256,14 +278,16 @@ class control_logic(design.design):
self.copy_layout_pin(self.ctrl_dff_inst, "din[1]", "web")
def add_dffs(self):
def create_dffs(self):
""" Add the three input DFFs (with inverters) """
self.ctrl_dff_inst=self.add_inst(name="ctrl_dffs",
mod=self.ctrl_dff_array,
offset=vector(0,0))
mod=self.ctrl_dff_array)
self.connect_inst(self.input_list + self.dff_output_list + ["clk_buf"] + self.supply_list)
def place_dffs(self):
""" Place the input DFFs (with inverters) """
self.ctrl_dff_inst.place(vector(0,0))
def get_offset(self,row):
""" Compute the y-offset and mirroring """
@ -276,48 +300,53 @@ class control_logic(design.design):
return (y_off,mirror)
def add_we_row(self,row):
def create_we_row(self):
# input: WE, CS output: w_en_bar
self.w_en_bar_inst=self.add_inst(name="nand3_w_en_bar",
mod=self.nand3)
self.connect_inst(["clk_buf_bar", "cs", "we", "w_en_bar", "vdd", "gnd"])
# input: w_en_bar, output: pre_w_en
self.pre_w_en_inst=self.add_inst(name="inv_pre_w_en",
mod=self.inv1)
self.connect_inst(["w_en_bar", "pre_w_en", "vdd", "gnd"])
# BUFFER INVERTERS FOR W_EN
self.pre_w_en_bar_inst=self.add_inst(name="inv_pre_w_en_bar",
mod=self.inv2)
self.connect_inst(["pre_w_en", "pre_w_en_bar", "vdd", "gnd"])
self.w_en_inst=self.add_inst(name="inv_w_en2",
mod=self.inv8)
self.connect_inst(["pre_w_en_bar", "w_en0", "vdd", "gnd"])
def place_we_row(self,row):
x_off = self.ctrl_dff_inst.width + self.internal_bus_width
(y_off,mirror)=self.get_offset(row)
# input: WE, CS output: w_en_bar
w_en_bar_offset = vector(x_off, y_off)
self.w_en_bar_inst=self.add_inst(name="nand3_w_en_bar",
mod=self.nand3,
offset=w_en_bar_offset,
mirror=mirror)
self.connect_inst(["clk_buf_bar", "cs", "we", "w_en_bar", "vdd", "gnd"])
self.w_en_bar_inst.place(offset=w_en_bar_offset,
mirror=mirror)
x_off += self.nand3.width
# input: w_en_bar, output: pre_w_en
pre_w_en_offset = vector(x_off, y_off)
self.pre_w_en_inst=self.add_inst(name="inv_pre_w_en",
mod=self.inv1,
offset=pre_w_en_offset,
mirror=mirror)
self.connect_inst(["w_en_bar", "pre_w_en", "vdd", "gnd"])
self.pre_w_en_inst.place(offset=pre_w_en_offset,
mirror=mirror)
x_off += self.inv1.width
# BUFFER INVERTERS FOR W_EN
pre_w_en_bar_offset = vector(x_off, y_off)
self.pre_w_en_bar_inst=self.add_inst(name="inv_pre_w_en_bar",
mod=self.inv2,
offset=pre_w_en_bar_offset,
mirror=mirror)
self.connect_inst(["pre_w_en", "pre_w_en_bar", "vdd", "gnd"])
self.pre_w_en_bar_inst.place(offset=pre_w_en_bar_offset,
mirror=mirror)
x_off += self.inv2.width
w_en_offset = vector(x_off, y_off)
self.w_en_inst=self.add_inst(name="inv_w_en2",
mod=self.inv8,
offset=w_en_offset,
mirror=mirror)
self.connect_inst(["pre_w_en_bar", "w_en0", "vdd", "gnd"])
self.w_en_inst.place(offset=w_en_offset,
mirror=mirror)
x_off += self.inv8.width
self.row_end_inst.append(self.w_en_inst)
def route_rbl_in(self):
""" Connect the logic for the rbl_in generation """

View File

@ -24,14 +24,23 @@ class delay_chain(design.design):
# number of inverters including any fanout loads.
self.fanout_list = fanout_list
from importlib import reload
c = reload(__import__(OPTS.bitcell))
self.mod_bitcell = getattr(c, OPTS.bitcell)
self.bitcell = self.mod_bitcell()
self.create_netlist()
if not OPTS.netlist_only:
self.create_layout()
def create_netlist(self):
self.add_modules()
self.add_pins()
self.create_module()
self.add_inverters()
self.create_inverters()
def create_layout(self):
# Each stage is a a row
self.height = len(self.fanout_list)*self.inv.height
# The width is determined by the largest fanout plus the driver
self.width = (max(self.fanout_list)+1) * self.inv.width
self.place_inverters()
self.route_inverters()
self.add_layout_pins()
self.DRC_LVS()
@ -43,40 +52,27 @@ class delay_chain(design.design):
self.add_pin("vdd")
self.add_pin("gnd")
def create_module(self):
""" Add the inverter logical module """
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()
self.inv = pinv(route_output=False)
self.add_mod(self.inv)
# Each stage is a a row
self.height = len(self.fanout_list)*self.inv.height
# The width is determined by the largest fanout plus the driver
self.width = (max(self.fanout_list)+1) * self.inv.width
def add_inverters(self):
""" Add the inverters and connect them based on the stage list """
def create_inverters(self):
""" Create the inverters and connect them based on the stage list """
self.driver_inst_list = []
self.rightest_load_inst = {}
self.load_inst_map = {}
for stage_num,fanout_size in zip(range(len(self.fanout_list)),self.fanout_list):
if stage_num % 2:
inv_mirror = "MX"
inv_offset = vector(0, (stage_num+1)* self.inv.height)
else:
inv_mirror = "R0"
inv_offset = vector(0, stage_num * self.inv.height)
# Add the inverter
cur_driver=self.add_inst(name="dinv{}".format(stage_num),
mod=self.inv,
offset=inv_offset,
mirror=inv_mirror)
mod=self.inv)
# keep track of the inverter instances so we can use them to get the pins
self.driver_inst_list.append(cur_driver)
# Hook up the driver
if stage_num+1==len(self.fanout_list):
stageout_name = "out"
@ -91,11 +87,8 @@ class delay_chain(design.design):
# Now add the dummy loads to the right
self.load_inst_map[cur_driver]=[]
for i in range(fanout_size):
inv_offset += vector(self.inv.width,0)
cur_load=self.add_inst(name="dload_{0}_{1}".format(stage_num,i),
mod=self.inv,
offset=inv_offset,
mirror=inv_mirror)
mod=self.inv)
# Fanout stage is always driven by driver and output is disconnected
disconnect_name = "n_{0}_{1}".format(stage_num,i)
self.connect_inst([stageout_name, disconnect_name, "vdd", "gnd"])
@ -105,6 +98,29 @@ class delay_chain(design.design):
else:
# Keep track of the last one so we can add the the wire later
self.rightest_load_inst[cur_driver]=cur_load
def place_inverters(self):
""" Place the inverters and connect them based on the stage list """
for stage_num,fanout_size in zip(range(len(self.fanout_list)),self.fanout_list):
if stage_num % 2:
inv_mirror = "MX"
inv_offset = vector(0, (stage_num+1)* self.inv.height)
else:
inv_mirror = "R0"
inv_offset = vector(0, stage_num * self.inv.height)
# Add the inverter
cur_driver=self.driver_inst_list[stage_num]
cur_driver.place(offset=inv_offset,
mirror=inv_mirror)
# Now add the dummy loads to the right
load_list = self.load_inst_map[cur_driver]
for i in range(fanout_size):
inv_offset += vector(self.inv.width,0)
load_list[i].place(offset=inv_offset,
mirror=inv_mirror)
def add_route(self, pin1, pin2):
""" This guarantees that we route from the top to bottom row correctly. """

View File

@ -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):
@ -75,9 +78,8 @@ class dff_array(design.design):
else:
base = vector(col*self.dff.width,(row+1)*self.dff.height)
mirror = "MX"
self.place_inst(name=name,
offset=base,
mirror=mirror)
self.dff_insts[row,col].place(offset=base,
mirror=mirror)
def get_din_name(self, row, col):
if self.columns == 1:

View File

@ -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")

View File

@ -20,21 +20,21 @@ class dff_buf_array(design.design):
name = "dff_buf_array_{0}x{1}".format(rows, columns)
design.design.__init__(self, name)
debug.info(1, "Creating {}".format(self.name))
self.dff = dff_buf.dff_buf(inv1_size, inv2_size)
self.add_mod(self.dff)
self.width = self.columns * self.dff.width
self.height = self.rows * self.dff.height
self.inv1_size = inv1_size
self.inv2_size = inv2_size
self.create_netlist()
self.create_layout()
if not OPTS.netlist_only:
self.create_layout()
def create_netlist(self):
self.add_pins()
self.add_modules()
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()
@ -51,6 +51,10 @@ class dff_buf_array(design.design):
self.add_pin("vdd")
self.add_pin("gnd")
def add_modules(self):
self.dff = dff_buf.dff_buf(self.inv1_size, self.inv2_size)
self.add_mod(self.dff)
def create_dff_array(self):
self.dff_insts={}
for row in range(self.rows):
@ -75,9 +79,8 @@ class dff_buf_array(design.design):
else:
base = vector(col*self.dff.width,(row+1)*self.dff.height)
mirror = "MX"
self.place_inst(name=name,
offset=base,
mirror=mirror)
self.dff_insts[row,col].place(offset=base,
mirror=mirror)
def get_din_name(self, row, col):
if self.columns == 1:

View File

@ -18,31 +18,30 @@ class dff_inv(design.design):
name = "dff_inv_{0}".format(inv_size)
design.design.__init__(self, name)
debug.info(1, "Creating {}".format(self.name))
self.inv_size = inv_size
# This is specifically for SCMOS where the DFF vdd/gnd rails are more than min width.
# This causes a DRC in the pinv which assumes min width rails. This ensures the output
# contact does not violate spacing to the rail in the NMOS.
debug.check(inv_size>=2, "Inverter must be greater than two for rail spacing DRC rules.")
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=inv_size,height=self.dff.height)
self.add_mod(self.inv1)
self.create_netlist()
if not OPTS.netlist_only:
self.create_layout()
def create_netlist(self):
self.add_pins()
self.add_modules()
self.create_modules()
def create_layout(self):
self.width = self.dff.width + self.inv1.width
self.height = self.dff.height
self.create_layout()
def create_layout(self):
self.add_pins()
self.add_insts()
self.place_modules()
self.add_wires()
self.add_layout_pins()
self.DRC_LVS()
def add_pins(self):
@ -53,18 +52,31 @@ class dff_inv(design.design):
self.add_pin("vdd")
self.add_pin("gnd")
def add_insts(self):
# Add the DFF
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=self.inv_size,height=self.dff.height)
self.add_mod(self.inv1)
def create_modules(self):
self.dff_inst=self.add_inst(name="dff_inv_dff",
mod=self.dff,
offset=vector(0,0))
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,
offset=vector(self.dff_inst.rx(),0))
mod=self.inv1)
self.connect_inst(["Q", "Qb", "vdd", "gnd"])
def place_modules(self):
# Place the DFF
self.dff_inst.place(vector(0,0))
# Place the INV1 to the right
self.inv1_inst.place(vector(self.dff_inst.rx(),0))
def add_wires(self):

View File

@ -20,21 +20,29 @@ class dff_inv_array(design.design):
name = "dff_inv_array_{0}x{1}".format(rows, columns)
design.design.__init__(self, name)
debug.info(1, "Creating {}".format(self.name))
self.inv_size = inv_size
self.create_netlist()
if not OPTS.netlist_only:
self.create_layout()
self.dff = dff_inv.dff_inv(inv_size)
self.add_mod(self.dff)
def create_netlist(self):
self.add_pins()
self.add_modules()
self.create_dff_array()
def create_layout(self):
self.width = self.columns * self.dff.width
self.height = self.rows * self.dff.height
self.create_layout()
def create_layout(self):
self.add_pins()
self.create_dff_array()
self.place_dff_array()
self.add_layout_pins()
self.DRC_LVS()
def add_modules(self):
self.dff = dff_inv.dff_inv(self.inv_size)
self.add_mod(self.dff)
def add_pins(self):
for row in range(self.rows):
for col in range(self.columns):
@ -52,16 +60,8 @@ class dff_inv_array(design.design):
for row in range(self.rows):
for col in range(self.columns):
name = "Xdff_r{0}_c{1}".format(row,col)
if (row % 2 == 0):
base = vector(col*self.dff.width,row*self.dff.height)
mirror = "R0"
else:
base = vector(col*self.dff.width,(row+1)*self.dff.height)
mirror = "MX"
self.dff_insts[row,col]=self.add_inst(name=name,
mod=self.dff,
offset=base,
mirror=mirror)
mod=self.dff)
self.connect_inst([self.get_din_name(row,col),
self.get_dout_name(row,col),
self.get_dout_bar_name(row,col),
@ -69,6 +69,19 @@ class dff_inv_array(design.design):
"vdd",
"gnd"])
def place_dff_array(self):
for row in range(self.rows):
for col in range(self.columns):
name = "Xdff_r{0}_c{1}".format(row,col)
if (row % 2 == 0):
base = vector(col*self.dff.width,row*self.dff.height)
mirror = "R0"
else:
base = vector(col*self.dff.width,(row+1)*self.dff.height)
mirror = "MX"
self.dff_insts[row,col].place(offset=base,
mirror=mirror)
def get_din_name(self, row, col):
if self.columns == 1:
din_name = "din[{0}]".format(row)

View File

@ -37,7 +37,8 @@ class hierarchical_decoder(design.design):
(self.no_of_pre2x4,self.no_of_pre3x8)=self.determine_predecodes(self.num_inputs)
self.create_netlist()
self.create_layout()
if not OPTS.netlist_only:
self.create_layout()
def create_netlist(self):
@ -302,8 +303,7 @@ class hierarchical_decoder(design.design):
else:
base= vector(-self.pre2_4.width, num * self.pre2_4.height)
self.place_inst(name="pre[{0}]".format(num),
offset=base)
self.pre2x4_inst[num].place(base)
def place_pre3x8(self,num):
@ -315,8 +315,7 @@ class hierarchical_decoder(design.design):
height = self.no_of_pre2x4*self.pre2_4.height + num*self.pre3_8.height
offset = vector(-self.pre3_8.width, height)
self.place_inst(name="pre3x8[{0}]".format(num),
offset=offset)
self.pre3x8_inst[num].place(offset)
def create_row_decoder(self):
@ -396,7 +395,6 @@ class hierarchical_decoder(design.design):
x_off = self.internal_routing_width + self.nand3.width
for row in range(self.rows):
name = self.INV_FORMAT.format(row)
if (row % 2 == 0):
inv_row_height = self.inv.height * row
mirror = "R0"
@ -407,9 +405,8 @@ class hierarchical_decoder(design.design):
y_dir = -1
y_off = inv_row_height
offset = vector(x_off,y_off)
self.place_inst(name=name,
offset=offset,
mirror=mirror)
self.inv_inst[row].place(offset=offset,
mirror=mirror)
def place_row_decoder(self):
"""
@ -448,9 +445,8 @@ class hierarchical_decoder(design.design):
y_dir = -1
mirror = "MX"
self.place_inst(name=name,
offset=[self.internal_routing_width, y_off],
mirror=mirror)
self.nand_inst[row].place(offset=[self.internal_routing_width, y_off],
mirror=mirror)

View File

@ -49,7 +49,7 @@ class hierarchical_predecode(design.design):
else:
debug.error("Invalid number of predecode inputs: {}".format(inputs),-1)
def setup_constraints(self):
def setup_layout_constraints(self):
self.height = self.number_of_outputs * self.nand.height
@ -88,7 +88,6 @@ class hierarchical_predecode(design.design):
def create_input_inverters(self):
""" Create the input inverters to invert input signals for the decode stage. """
self.in_inst = []
for inv_num in range(self.number_of_inputs):
name = "Xpre_inv[{0}]".format(inv_num)
@ -100,9 +99,7 @@ class hierarchical_predecode(design.design):
def place_input_inverters(self):
""" Place the input inverters to invert input signals for the decode stage. """
for inv_num in range(self.number_of_inputs):
name = "Xpre_inv[{0}]".format(inv_num)
if (inv_num % 2 == 0):
y_off = inv_num * (self.inv.height)
mirror = "R0"
@ -110,13 +107,11 @@ class hierarchical_predecode(design.design):
y_off = (inv_num + 1) * (self.inv.height)
mirror="MX"
offset = vector(self.x_off_inv_1, y_off)
self.place_inst(name=name,
offset=offset,
mirror=mirror)
self.in_inst[inv_num].place(offset=offset,
mirror=mirror)
def create_output_inverters(self):
""" Create inverters for the inverted output decode signals. """
self.inv_inst = []
for inv_num in range(self.number_of_outputs):
name = "Xpre_nand_inv[{}]".format(inv_num)
@ -129,9 +124,7 @@ class hierarchical_predecode(design.design):
def place_output_inverters(self):
""" Place inverters for the inverted output decode signals. """
for inv_num in range(self.number_of_outputs):
name = "Xpre_nand_inv[{}]".format(inv_num)
if (inv_num % 2 == 0):
y_off = inv_num * self.inv.height
mirror = "R0"
@ -139,9 +132,8 @@ class hierarchical_predecode(design.design):
y_off =(inv_num + 1)*self.inv.height
mirror = "MX"
offset = vector(self.x_off_inv_2, y_off)
self.place_inst(name=name,
offset=offset,
mirror=mirror)
self.inv_inst[inv_num].place(offset=offset,
mirror=mirror)
def create_nand_array(self,connections):
""" Create the NAND stage for the decodes """
@ -158,7 +150,6 @@ class hierarchical_predecode(design.design):
""" Place the NAND stage for the decodes """
for nand_input in range(self.number_of_outputs):
inout = str(self.number_of_inputs)+"x"+str(self.number_of_outputs)
name = "Xpre{0}_nand[{1}]".format(inout,nand_input)
if (nand_input % 2 == 0):
y_off = nand_input * self.inv.height
mirror = "R0"
@ -166,9 +157,8 @@ class hierarchical_predecode(design.design):
y_off = (nand_input + 1) * self.inv.height
mirror = "MX"
offset = vector(self.x_off_nand, y_off)
self.place_inst(name=name,
offset=offset,
mirror=mirror)
self.nand_inst[nand_input].place(offset=offset,
mirror=mirror)
def route(self):

View File

@ -3,6 +3,7 @@ import debug
import design
from vector import vector
from hierarchical_predecode import hierarchical_predecode
from globals import OPTS
class hierarchical_predecode2x4(hierarchical_predecode):
"""
@ -11,13 +12,13 @@ class hierarchical_predecode2x4(hierarchical_predecode):
def __init__(self):
hierarchical_predecode.__init__(self, 2)
self.add_pins()
self.create_modules()
self.setup_constraints()
self.create_netlist()
self.create_layout()
if not OPTS.netlist_only:
self.create_layout()
def create_netlist(self):
self.add_pins()
self.create_modules()
self.create_input_inverters()
self.create_output_inverters()
connections =[["inbar[0]", "inbar[1]", "Z[0]", "vdd", "gnd"],
@ -33,6 +34,7 @@ class hierarchical_predecode2x4(hierarchical_predecode):
3) a set of M2 rails for the vdd, gnd, inverted inputs, inputs
4) a set of NAND gates for inversion
"""
self.setup_layout_constraints()
self.route_rails()
self.place_input_inverters()
self.place_output_inverters()

View File

@ -3,6 +3,7 @@ import debug
import design
from vector import vector
from hierarchical_predecode import hierarchical_predecode
from globals import OPTS
class hierarchical_predecode3x8(hierarchical_predecode):
"""
@ -11,13 +12,13 @@ class hierarchical_predecode3x8(hierarchical_predecode):
def __init__(self):
hierarchical_predecode.__init__(self, 3)
self.add_pins()
self.create_modules()
self.setup_constraints()
self.create_netlist()
self.create_layout()
if not OPTS.netlist_only:
self.create_layout()
def create_netlist(self):
self.add_pins()
self.create_modules()
self.create_input_inverters()
self.create_output_inverters()
connections=[["inbar[0]", "inbar[1]", "inbar[2]", "Z[0]", "vdd", "gnd"],
@ -38,6 +39,7 @@ class hierarchical_predecode3x8(hierarchical_predecode):
3) a set of M2 rails for the vdd, gnd, inverted inputs, inputs
4) a set of NAND gates for inversion
"""
self.setup_layout_constraints()
self.route_rails()
self.place_input_inverters()
self.place_output_inverters()

View File

@ -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):
@ -67,16 +71,15 @@ class ms_flop_array(design.design):
def place_ms_flop_array(self):
for i in range(0,self.columns,self.words_per_row):
name = "Xdff{0}".format(i)
index = int(i/self.words_per_row)
if (i % 2 == 0 or self.words_per_row>1):
base = vector(i*self.ms.width,0)
mirror = "R0"
else:
base = vector((i+1)*self.ms.width,0)
mirror = "MY"
self.place_inst(name=name,
offset=base,
mirror=mirror)
self.ms_inst[index].place(offset=base,
mirror=mirror)
def add_layout_pins(self):

View File

@ -3,7 +3,7 @@ import debug
from tech import drc
from vector import vector
from precharge import precharge
from globals import OPTS
class precharge_array(design.design):
"""
@ -20,15 +20,13 @@ 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.width = self.columns * self.pc_cell.width
self.height = self.pc_cell.height
self.size = size
self.bitcell_bl = bitcell_bl
self.bitcell_br = bitcell_br
self.create_netlist()
self.create_layout()
if not OPTS.netlist_only:
self.create_layout()
def add_pins(self):
"""Adds pins for spice file"""
@ -39,15 +37,26 @@ class precharge_array(design.design):
self.add_pin("vdd")
def create_netlist(self):
self.add_modules()
self.add_pins()
self.create_insts()
def create_layout(self):
self.width = self.columns * self.pc_cell.width
self.height = self.pc_cell.height
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",
@ -91,7 +100,5 @@ class precharge_array(design.design):
def place_insts(self):
""" Places precharge array by horizontally tiling the precharge cell"""
for i in range(self.columns):
name = "pre_column_{0}".format(i)
offset = vector(self.pc_cell.width * i, 0)
inst = self.place_inst(name=name,
offset=offset)
self.local_insts[i].place(offset)

View File

@ -18,27 +18,26 @@ 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)
for pin in ["en", "out", "vdd", "gnd"]:
self.add_pin(pin)
self.bitcell_loads = bitcell_loads
self.delay_stages = delay_stages
self.delay_fanout = delay_fanout
self.create_modules()
self.calculate_module_offsets()
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.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()
@ -48,6 +47,10 @@ 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 """
@ -74,8 +77,16 @@ class replica_bitline(design.design):
def create_modules(self):
""" Create modules for later instantiation """
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)
@ -93,38 +104,48 @@ class replica_bitline(design.design):
self.access_tx = ptx(tx_type="pmos")
self.add_mod(self.access_tx)
def add_modules(self):
""" Add all of the module instances in the logical netlist """
def create_modules(self):
""" Create all of the module instances in the logical netlist """
# This is the threshold detect inverter on the output of the RBL
self.rbl_inv_inst=self.add_inst(name="rbl_inv",
mod=self.inv,
offset=self.rbl_inv_offset,
rotate=180)
mod=self.inv)
self.connect_inst(["bl[0]", "out", "vdd", "gnd"])
self.tx_inst=self.add_inst(name="rbl_access_tx",
mod=self.access_tx,
offset=self.access_tx_offset)
mod=self.access_tx)
# D, G, S, B
self.connect_inst(["vdd", "delayed_en", "bl[0]", "vdd"])
# add the well and poly contact
self.dc_inst=self.add_inst(name="delay_chain",
mod=self.delay_chain,
offset=self.delay_chain_offset)
mod=self.delay_chain)
self.connect_inst(["en", "delayed_en", "vdd", "gnd"])
self.rbc_inst=self.add_inst(name="bitcell",
mod=self.replica_bitcell,
offset=self.bitcell_offset,
mirror="MX")
mod=self.replica_bitcell)
self.connect_inst(["bl[0]", "br[0]", "delayed_en", "vdd", "gnd"])
self.rbl_inst=self.add_inst(name="load",
mod=self.rbl,
offset=self.rbl_offset)
mod=self.rbl)
self.connect_inst(["bl[0]", "br[0]"] + ["gnd"]*self.bitcell_loads + ["vdd", "gnd"])
def place_modules(self):
""" Add all of the module instances in the logical netlist """
# This is the threshold detect inverter on the output of the RBL
self.rbl_inv_inst.place(offset=self.rbl_inv_offset,
rotate=180)
self.tx_inst.place(self.access_tx_offset)
self.dc_inst.place(self.delay_chain_offset)
self.rbc_inst.place(offset=self.bitcell_offset,
mirror="MX")
self.rbl_inst.place(self.rbl_offset)
@ -248,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")
@ -269,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())

View File

@ -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):
@ -68,11 +70,8 @@ class sense_amp_array(design.design):
amp_spacing = self.amp.width * self.words_per_row
for i in range(0,self.word_size):
name = "sa_d{0}".format(i)
amp_position = vector(amp_spacing * i, 0)
self.place_inst(name=name,
offset=amp_position)
self.local_insts[i].place(amp_position)
def add_layout_pins(self):

View File

@ -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?
@ -87,8 +89,7 @@ class single_level_column_mux_array(design.design):
for col_num in range(self.columns):
name = "XMUX{0}".format(col_num)
x_off = vector(col_num * self.mux.width, self.route_height)
self.place_inst(name=name,
offset=x_off)
self.mux_inst[col_num].place(x_off)
def add_layout_pins(self):

View File

@ -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):
@ -63,10 +66,8 @@ class tri_gate_array(design.design):
def place_array(self):
""" Place the tri gate to the array """
for i in range(0,self.columns,self.words_per_row):
name = "Xtri_gate{0}".format(i)
base = vector(i*self.tri.width, 0)
self.place_inst(name=name,
offset=base)
self.tri_inst[i].place(base)
def add_layout_pins(self):

View File

@ -20,11 +20,23 @@ class wordline_driver(design.design):
design.design.__init__(self, "wordline_driver")
self.rows = rows
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_drivers()
def create_layout(self):
self.place_drivers()
self.route_layout()
self.route_vdd_gnd()
self.offset_all_coordinates()
self.DRC_LVS()
def add_pins(self):
# inputs to wordline_driver.
for i in range(self.rows):
@ -36,16 +48,6 @@ class wordline_driver(design.design):
self.add_pin("vdd")
self.add_pin("gnd")
def create_netlist(self):
self.add_pins()
self.add_modules()
self.create_drivers()
def create_layout(self):
self.place_drivers()
self.route_layout()
self.route_vdd_gnd()
def add_modules(self):
self.inv = pinv()
@ -128,10 +130,6 @@ class wordline_driver(design.design):
for row in range(self.rows):
name_inv1 = "wl_driver_inv_en{}".format(row)
name_nand = "wl_driver_nand{}".format(row)
name_inv2 = "wl_driver_inv{}".format(row)
if (row % 2):
y_offset = self.inv.height*(row + 1)
inst_mirror = "MX"
@ -144,17 +142,14 @@ class wordline_driver(design.design):
inv2_offset=[inv2_xoffset, y_offset]
# add inv1 based on the info above
self.place_inst(name=name_inv1,
offset=inv1_offset,
mirror=inst_mirror)
self.inv1_inst[row].place(offset=inv1_offset,
mirror=inst_mirror)
# add nand 2
self.place_inst(name=name_nand,
offset=nand2_offset,
mirror=inst_mirror)
self.nand_inst[row].place(offset=nand2_offset,
mirror=inst_mirror)
# add inv2
self.place_inst(name=name_inv2,
offset=inv2_offset,
mirror=inst_mirror)
self.inv2_inst[row].place(offset=inv2_offset,
mirror=inst_mirror)
def route_layout(self):

View File

@ -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 = {}
@ -66,11 +70,9 @@ class write_driver_array(design.design):
def place_write_array(self):
for i in range(0,self.columns,self.words_per_row):
name = "Xwrite_driver{}".format(i)
index = int(i/self.words_per_row)
base = vector(i * self.driver.width,0)
self.place_inst(name=name,
offset=base)
self.driver_insts[index].place(base)
def add_layout_pins(self):

View File

@ -24,14 +24,18 @@ class options(optparse.Values):
check_lvsdrc = True
# Variable to select the variant of spice
spice_name = ""
# Should we print out the banner at startup
print_banner = True
# The spice executable being used which is derived from the user PATH.
spice_exe = ""
# Variable to select the variant of drc, lvs, pex
drc_name = ""
lvs_name = ""
pex_name = ""
# The DRC/LVS/PEX executable being used which is derived from the user PATH.
drc_exe = None
lvs_exe = None
pex_exe = None
# The spice executable being used which is derived from the user PATH.
spice_exe = ""
# Should we print out the banner at startup
print_banner = True
# Run with extracted parasitics
use_pex = False
# Remove noncritical memory cells for characterization speed-up

View File

@ -29,16 +29,47 @@ class pbitcell(pgate.pgate):
self.num_read = num_read
self.create_netlist()
self.create_layout()
if not OPTS.netlist_only:
self.create_layout()
# FIXME: Why is this static set here?
pbitcell.width = self.width
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))
@ -59,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"]
@ -129,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)
@ -142,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"]
@ -264,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".
"""
@ -276,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()])
@ -327,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",
@ -350,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])
@ -366,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.
@ -376,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 \
@ -402,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)
@ -426,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"),
@ -453,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):
@ -502,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
@ -536,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 \
@ -578,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 \
@ -604,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"),
@ -631,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):
@ -680,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
@ -711,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).
@ -731,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
@ -749,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 \
@ -787,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 \
@ -802,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"),
@ -829,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
@ -874,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])
@ -882,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
@ -931,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.
@ -939,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",
@ -947,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"]
@ -973,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"]
@ -995,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"]
@ -1012,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"),

View File

@ -41,40 +41,49 @@ class pinv(pgate.pgate):
self.create_netlist()
self.create_layout()
if not OPTS.netlist_only:
self.create_layout()
# for run-time, we won't check every transitor DRC/LVS independently
# but this may be uncommented for debug purposes
#self.DRC_LVS()
def add_pins(self):
""" Adds pins for spice netlist """
self.add_pin_list(["A", "Z", "vdd", "gnd"])
def create_netlist(self):
""" Calls all functions related to the generation of the netlist """
self.add_pins()
self.determine_tx_mults()
self.add_ptx()
self.create_ptx()
def create_layout(self):
""" Calls all functions related to the generation of the layout """
self.determine_tx_mults()
self.create_ptx()
self.setup_layout_constants()
self.add_supply_rails()
self.add_ptx()
self.route_supply_rails()
self.place_ptx()
self.add_well_contacts()
self.extend_wells(self.well_pos)
self.connect_rails()
self.route_input_gate(self.pmos_inst, self.nmos_inst, self.output_pos.y, "A", rotate=0)
self.route_outputs()
def add_pins(self):
""" Adds pins for spice netlist """
self.add_pin_list(["A", "Z", "vdd", "gnd"])
def determine_tx_mults(self):
"""
Determines the number of fingers needed to achieve the size within
the height constraint. This may fail if the user has a tight height.
"""
# This may make the result differ when the layout is created...
if OPTS.netlist_only:
self.tx_mults = 1
self.nmos_width = self.nmos_size*drc["minwidth_tx"]
self.pmos_width = self.pmos_size*drc["minwidth_tx"]
return
# Do a quick sanity check and bail if unlikely feasible height
# Sanity check. can we make an inverter in the height with minimum tx sizes?
# Assume we need 3 metal 1 pitches (2 power rails, one between the tx for the drain)
@ -138,7 +147,7 @@ class pinv(pgate.pgate):
def create_ptx(self):
def add_ptx(self):
""" Create the PMOS and NMOS transistors. """
self.nmos = ptx(width=self.nmos_width,
mults=self.tx_mults,
@ -154,7 +163,7 @@ class pinv(pgate.pgate):
connect_active=True)
self.add_mod(self.pmos)
def add_supply_rails(self):
def route_supply_rails(self):
""" Add vdd/gnd rails to the top and bottom. """
self.add_layout_pin_rect_center(text="gnd",
layer="metal1",
@ -166,26 +175,34 @@ class pinv(pgate.pgate):
offset=vector(0.5*self.width,self.height),
width=self.width)
def add_ptx(self):
def create_ptx(self):
"""
Add PMOS and NMOS to the layout at the upper-most and lowest position
Create the PMOS and NMOS netlist.
"""
self.pmos_inst=self.add_inst(name="pinv_pmos",
mod=self.pmos)
self.connect_inst(["Z", "A", "vdd", "vdd"])
self.nmos_inst=self.add_inst(name="pinv_nmos",
mod=self.nmos)
self.connect_inst(["Z", "A", "gnd", "gnd"])
def place_ptx(self):
"""
Place PMOS and NMOS to the layout at the upper-most and lowest position
to provide maximum routing in channel
"""
# place PMOS so it is half a poly spacing down from the top
self.pmos_pos = self.pmos.active_offset.scale(1,0) \
+ vector(0, self.height-self.pmos.active_height-self.top_bottom_space)
self.pmos_inst=self.add_inst(name="pinv_pmos",
mod=self.pmos,
offset=self.pmos_pos)
self.connect_inst(["Z", "A", "vdd", "vdd"])
self.pmos_inst.place(self.pmos_pos)
# place NMOS so that it is half a poly spacing up from the bottom
self.nmos_pos = self.nmos.active_offset.scale(1,0) + vector(0,self.top_bottom_space)
self.nmos_inst=self.add_inst(name="pinv_nmos",
mod=self.nmos,
offset=self.nmos_pos)
self.connect_inst(["Z", "A", "gnd", "gnd"])
self.nmos_inst.place(self.nmos_pos)
# Output position will be in between the PMOS and NMOS drains

View File

@ -36,7 +36,8 @@ class pinvbuf(design.design):
debug.info(1, "Creating {}".format(self.name))
self.create_netlist()
self.create_layout()
if not OPTS.netlist_only:
self.create_layout()
def create_netlist(self):
@ -49,7 +50,7 @@ class pinvbuf(design.design):
self.width = 2*self.inv1.width + self.inv2.width
self.height = 2*self.inv1.height
self.place_insts()
self.place_modules()
self.route_wires()
self.add_layout_pins()
@ -96,23 +97,19 @@ class pinvbuf(design.design):
mod=self.inv2)
self.connect_inst(["zb_int", "Z", "vdd", "gnd"])
def place_insts(self):
def place_modules(self):
# Add INV1 to the right (capacitance shield)
self.place_inst(name="buf_inv1",
offset=vector(0,0))
self.inv1_inst.place(vector(0,0))
# Add INV2 to the right
self.place_inst(name="buf_inv2",
offset=vector(self.inv1_inst.rx(),0))
self.inv2_inst.place(vector(self.inv1_inst.rx(),0))
# Add INV3 to the right
self.place_inst(name="buf_inv3",
offset=vector(self.inv2_inst.rx(),0))
self.inv3_inst.place(vector(self.inv2_inst.rx(),0))
# Add INV4 to the bottom
self.place_inst(name="buf_inv4",
offset=vector(self.inv2_inst.rx(),2*self.inv2.height),
mirror = "MX")
self.inv4_inst.place(offset=vector(self.inv2_inst.rx(),2*self.inv2.height),
mirror = "MX")
def route_wires(self):

View File

@ -36,32 +36,34 @@ class pnand2(pgate.pgate):
self.tx_mults = 1
self.create_netlist()
self.create_layout()
if not OPTS.netlist_only:
self.create_layout()
#self.DRC_LVS()
def add_pins(self):
""" Adds pins for spice netlist """
self.add_pin_list(["A", "B", "Z", "vdd", "gnd"])
def create_netlist(self):
self.add_pins()
self.add_ptx()
self.create_ptx()
def create_layout(self):
""" Calls all functions related to the generation of the layout """
self.create_ptx()
self.setup_layout_constants()
self.add_supply_rails()
self.add_ptx()
self.route_supply_rails()
self.place_ptx()
self.connect_rails()
self.add_well_contacts()
self.extend_wells(self.well_pos)
self.route_inputs()
self.route_output()
def create_ptx(self):
def add_pins(self):
""" Adds pins for spice netlist """
self.add_pin_list(["A", "B", "Z", "vdd", "gnd"])
def add_ptx(self):
""" Create the PMOS and NMOS transistors. """
self.nmos = ptx(width=self.nmos_width,
mults=self.tx_mults,
@ -105,7 +107,7 @@ class pnand2(pgate.pgate):
self.top_bottom_space = max(0.5*self.m1_width + self.m1_space + extra_contact_space,
drc["poly_extend_active"], self.poly_space)
def add_supply_rails(self):
def route_supply_rails(self):
""" Add vdd/gnd rails to the top and bottom. """
self.add_layout_pin_rect_center(text="gnd",
layer="metal1",
@ -117,37 +119,47 @@ class pnand2(pgate.pgate):
offset=vector(0.5*self.width,self.height),
width=self.width)
def add_ptx(self):
def create_ptx(self):
"""
Add PMOS and NMOS to the layout at the upper-most and lowest position
Add PMOS and NMOS to the netlist.
"""
self.pmos1_inst=self.add_inst(name="pnand2_pmos1",
mod=self.pmos)
self.connect_inst(["vdd", "A", "Z", "vdd"])
self.pmos2_inst = self.add_inst(name="pnand2_pmos2",
mod=self.pmos)
self.connect_inst(["Z", "B", "vdd", "vdd"])
self.nmos1_inst=self.add_inst(name="pnand2_nmos1",
mod=self.nmos)
self.connect_inst(["Z", "B", "net1", "gnd"])
self.nmos2_inst=self.add_inst(name="pnand2_nmos2",
mod=self.nmos)
self.connect_inst(["net1", "A", "gnd", "gnd"])
def place_ptx(self):
"""
Place PMOS and NMOS to the layout at the upper-most and lowest position
to provide maximum routing in channel
"""
pmos1_pos = vector(self.pmos.active_offset.x,
self.height - self.pmos.active_height - self.top_bottom_space)
self.pmos1_inst=self.add_inst(name="pnand2_pmos1",
mod=self.pmos,
offset=pmos1_pos)
self.connect_inst(["vdd", "A", "Z", "vdd"])
self.pmos1_inst.place(pmos1_pos)
self.pmos2_pos = pmos1_pos + self.overlap_offset
self.pmos2_inst = self.add_inst(name="pnand2_pmos2",
mod=self.pmos,
offset=self.pmos2_pos)
self.connect_inst(["Z", "B", "vdd", "vdd"])
self.pmos2_inst.place(self.pmos2_pos)
nmos1_pos = vector(self.pmos.active_offset.x, self.top_bottom_space)
self.nmos1_inst=self.add_inst(name="pnand2_nmos1",
mod=self.nmos,
offset=nmos1_pos)
self.connect_inst(["Z", "B", "net1", "gnd"])
self.nmos1_inst.place(nmos1_pos)
self.nmos2_pos = nmos1_pos + self.overlap_offset
self.nmos2_inst=self.add_inst(name="pnand2_nmos2",
mod=self.nmos,
offset=self.nmos2_pos)
self.connect_inst(["net1", "A", "gnd", "gnd"])
self.nmos2_inst.place(self.nmos2_pos)
# Output position will be in between the PMOS and NMOS
self.output_pos = vector(0,0.5*(pmos1_pos.y+nmos1_pos.y+self.nmos.active_height))

View File

@ -39,8 +39,8 @@ class pnand3(pgate.pgate):
self.tx_mults = 1
self.create_netlist()
self.create_layout()
#self.DRC_LVS()
if not OPTS.netlist_only:
self.create_layout()
def add_pins(self):
@ -49,21 +49,22 @@ class pnand3(pgate.pgate):
def create_netlist(self):
self.add_pins()
self.add_ptx()
self.create_ptx()
def create_layout(self):
""" Calls all functions related to the generation of the layout """
self.create_ptx()
self.setup_layout_constants()
self.add_supply_rails()
self.add_ptx()
self.route_supply_rails()
self.place_ptx()
self.connect_rails()
self.add_well_contacts()
self.extend_wells(self.well_pos)
self.route_inputs()
self.route_output()
def create_ptx(self):
def add_ptx(self):
""" Create the PMOS and NMOS transistors. """
self.nmos = ptx(width=self.nmos_width,
mults=self.tx_mults,
@ -103,7 +104,7 @@ class pnand3(pgate.pgate):
self.top_bottom_space = max(0.5*self.m1_width + self.m1_space + extra_contact_space,
drc["poly_extend_active"], self.poly_space)
def add_supply_rails(self):
def route_supply_rails(self):
""" Add vdd/gnd rails to the top and bottom. """
self.add_layout_pin_rect_center(text="gnd",
layer="metal1",
@ -115,50 +116,61 @@ class pnand3(pgate.pgate):
offset=vector(0.5*self.width,self.height),
width=self.width)
def add_ptx(self):
def create_ptx(self):
"""
Add PMOS and NMOS to the layout at the upper-most and lowest position
Create the PMOS and NMOS in the netlist.
"""
self.pmos1_inst=self.add_inst(name="pnand3_pmos1",
mod=self.pmos)
self.connect_inst(["vdd", "A", "Z", "vdd"])
self.pmos2_inst = self.add_inst(name="pnand3_pmos2",
mod=self.pmos)
self.connect_inst(["Z", "B", "vdd", "vdd"])
self.pmos3_inst = self.add_inst(name="pnand3_pmos3",
mod=self.pmos)
self.connect_inst(["Z", "C", "vdd", "vdd"])
self.nmos1_inst=self.add_inst(name="pnand3_nmos1",
mod=self.nmos)
self.connect_inst(["Z", "C", "net1", "gnd"])
self.nmos2_inst=self.add_inst(name="pnand3_nmos2",
mod=self.nmos)
self.connect_inst(["net1", "B", "net2", "gnd"])
self.nmos3_inst=self.add_inst(name="pnand3_nmos3",
mod=self.nmos)
self.connect_inst(["net2", "A", "gnd", "gnd"])
def place_ptx(self):
"""
Place the PMOS and NMOS in the layout at the upper-most and lowest position
to provide maximum routing in channel
"""
pmos1_pos = vector(self.pmos.active_offset.x,
self.height - self.pmos.active_height - self.top_bottom_space)
self.pmos1_inst=self.add_inst(name="pnand3_pmos1",
mod=self.pmos,
offset=pmos1_pos)
self.connect_inst(["vdd", "A", "Z", "vdd"])
self.pmos1_inst.place(pmos1_pos)
pmos2_pos = pmos1_pos + self.overlap_offset
self.pmos2_inst = self.add_inst(name="pnand3_pmos2",
mod=self.pmos,
offset=pmos2_pos)
self.connect_inst(["Z", "B", "vdd", "vdd"])
self.pmos2_inst.place(pmos2_pos)
self.pmos3_pos = pmos2_pos + self.overlap_offset
self.pmos3_inst = self.add_inst(name="pnand3_pmos3",
mod=self.pmos,
offset=self.pmos3_pos)
self.connect_inst(["Z", "C", "vdd", "vdd"])
self.pmos3_inst.place(self.pmos3_pos)
nmos1_pos = vector(self.pmos.active_offset.x, self.top_bottom_space)
self.nmos1_inst=self.add_inst(name="pnand3_nmos1",
mod=self.nmos,
offset=nmos1_pos)
self.connect_inst(["Z", "C", "net1", "gnd"])
self.nmos1_inst.place(nmos1_pos)
nmos2_pos = nmos1_pos + self.overlap_offset
self.nmos2_inst=self.add_inst(name="pnand3_nmos2",
mod=self.nmos,
offset=nmos2_pos)
self.connect_inst(["net1", "B", "net2", "gnd"])
self.nmos2_inst.place(nmos2_pos)
self.nmos3_pos = nmos2_pos + self.overlap_offset
self.nmos3_inst=self.add_inst(name="pnand3_nmos3",
mod=self.nmos,
offset=self.nmos3_pos)
self.connect_inst(["net2", "A", "gnd", "gnd"])
self.nmos3_inst.place(self.nmos3_pos)
# This should be placed at the top of the NMOS well
self.well_pos = vector(0,self.nmos1_inst.uy())

View File

@ -32,38 +32,38 @@ class precharge(pgate.pgate):
self.bitcell_br = bitcell_br
self.create_netlist()
self.create_layout()
if not OPTS.netlist_only:
self.create_layout()
def create_netlist(self):
self.add_pins()
self.add_ptx()
self.create_ptx()
def create_layout(self):
self.place_ptx()
self.connect_poly()
self.route_en()
self.place_nwell_and_contact()
self.route_vdd_rail()
self.route_bitlines()
self.connect_to_bitlines()
self.DRC_LVS()
def add_pins(self):
self.add_pin_list(["bl", "br", "en", "vdd"])
def create_netlist(self):
self.add_pins()
def create_layout(self):
self.create_ptx()
self.add_ptx()
self.connect_poly()
self.add_en()
self.add_nwell_and_contact()
self.add_vdd_rail()
self.add_bitlines()
self.connect_to_bitlines()
self.DRC_LVS()
def create_ptx(self):
def add_ptx(self):
"""Initializes the upper and lower pmos"""
self.pmos = ptx(width=self.ptx_width,
tx_type="pmos")
self.add_mod(self.pmos)
# Compute the other pmos2 location, but determining offset to overlap the
# source and drain pins
self.overlap_offset = self.pmos.get_pin("D").ll() - self.pmos.get_pin("S").ll()
def add_vdd_rail(self):
def route_vdd_rail(self):
"""Adds a vdd rail at the top of the cell"""
# adds the rail across the width of the cell
vdd_position = vector(0, self.height - self.m1_width)
@ -87,31 +87,43 @@ class precharge(pgate.pgate):
offset=vdd_pos.scale(0,1))
def add_ptx(self):
"""Adds both the upper_pmos and lower_pmos to the module"""
def create_ptx(self):
"""Create both the upper_pmos and lower_pmos to the module"""
self.lower_pmos_inst=self.add_inst(name="lower_pmos",
mod=self.pmos)
self.connect_inst(["bl", "en", "br", "vdd"])
self.upper_pmos1_inst=self.add_inst(name="upper_pmos1",
mod=self.pmos)
self.connect_inst(["bl", "en", "vdd", "vdd"])
self.upper_pmos2_inst=self.add_inst(name="upper_pmos2",
mod=self.pmos)
self.connect_inst(["br", "en", "vdd", "vdd"])
def place_ptx(self):
"""Place both the upper_pmos and lower_pmos to the module"""
# Compute the other pmos2 location, but determining offset to overlap the
# source and drain pins
self.overlap_offset = self.pmos.get_pin("D").ll() - self.pmos.get_pin("S").ll()
# adds the lower pmos to layout
#base = vector(self.width - 2*self.pmos.width + self.overlap_offset.x, 0)
self.lower_pmos_position = vector(self.bitcell.get_pin(self.bitcell_bl).lx(),
self.pmos.active_offset.y)
self.lower_pmos_inst=self.add_inst(name="lower_pmos",
mod=self.pmos,
offset=self.lower_pmos_position)
self.connect_inst(["bl", "en", "br", "vdd"])
self.lower_pmos_inst.place(self.lower_pmos_position)
# adds the upper pmos(s) to layout
ydiff = self.pmos.height + 2*self.m1_space + contact.poly.width
self.upper_pmos1_pos = self.lower_pmos_position + vector(0, ydiff)
self.upper_pmos1_inst=self.add_inst(name="upper_pmos1",
mod=self.pmos,
offset=self.upper_pmos1_pos)
self.connect_inst(["bl", "en", "vdd", "vdd"])
self.upper_pmos1_inst.place(self.upper_pmos1_pos)
upper_pmos2_pos = self.upper_pmos1_pos + self.overlap_offset
self.upper_pmos2_inst=self.add_inst(name="upper_pmos2",
mod=self.pmos,
offset=upper_pmos2_pos)
self.connect_inst(["br", "en", "vdd", "vdd"])
self.upper_pmos2_inst.place(upper_pmos2_pos)
def connect_poly(self):
"""Connects the upper and lower pmos together"""
@ -131,7 +143,7 @@ class precharge(pgate.pgate):
width=xlength,
height=self.poly_width)
def add_en(self):
def route_en(self):
"""Adds the en input rail, en contact/vias, and connects to the pmos"""
# adds the en contact to connect the gates to the en rail on metal1
offset = self.lower_pmos_inst.get_pin("G").ul() + vector(0,0.5*self.poly_space)
@ -146,7 +158,7 @@ class precharge(pgate.pgate):
end=offset.scale(0,1)+vector(self.width,0))
def add_nwell_and_contact(self):
def place_nwell_and_contact(self):
"""Adds a nwell tap to connect to the vdd rail"""
# adds the contact from active to metal1
well_contact_pos = self.upper_pmos1_inst.get_pin("D").center().scale(1,0) \
@ -165,7 +177,7 @@ class precharge(pgate.pgate):
height=self.height)
def add_bitlines(self):
def route_bitlines(self):
"""Adds both bit-line and bit-line-bar to the module"""
# adds the BL on metal 2
offset = vector(self.bitcell.get_pin(self.bitcell_bl).cx(),0) - vector(0.5 * self.m2_width,0)

View File

@ -3,6 +3,7 @@ import debug
from tech import drc, info, spice
from vector import vector
from contact import contact
from globals import OPTS
import path
class ptx(design.design):
@ -40,13 +41,9 @@ class ptx(design.design):
self.num_contacts = num_contacts
self.create_netlist()
self.create_layout()
if not OPTS.netlist_only:
self.create_layout()
self.translate_all(self.active_offset)
# for run-time, we won't check every transitor DRC independently
# but this may be uncommented for debug purposes
#self.DRC()
def create_layout(self):
@ -56,6 +53,11 @@ class ptx(design.design):
self.add_well_implant()
self.add_poly()
self.add_active_contacts()
self.translate_all(self.active_offset)
# for run-time, we won't check every transitor DRC independently
# but this may be uncommented for debug purposes
#self.DRC()
def create_netlist(self):
self.add_pin_list(["D", "G", "S", "B"])

View File

@ -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",

View File

@ -38,18 +38,9 @@ class sram():
debug.error("Invalid number of banks.",-1)
self.s.create_netlist()
self.s.create_layout()
if not OPTS.netlist_only:
self.s.create_layout()
# Can remove the following, but it helps for debug!
self.s.add_lvs_correspondence_points()
self.s.offset_all_coordinates()
highest_coord = self.s.find_highest_coords()
self.s.width = highest_coord[0]
self.s.height = highest_coord[1]
self.s.DRC_LVS(final_verification=True)
if not OPTS.is_unit_test:
print_time("SRAM creation", datetime.datetime.now(), start_time)

View File

@ -22,18 +22,16 @@ class sram_1bank(sram_base):
def create_netlist(self):
self.compute_sizes()
self.add_modules()
# Must run this after add modules to get control pin names
self.add_pins()
sram_base.create_netlist(self)
self.create_modules()
def create_modules(self):
"""
This adds the modules for a single bank SRAM with control
logic.
"""
self.bank_inst = self.create_bank()
self.bank_inst=self.create_bank(0)
self.control_logic_inst = self.create_control_logic()
@ -43,7 +41,7 @@ class sram_1bank(sram_base):
self.col_addr_dff_inst = self.create_col_addr_dff()
self.data_dff_inst = self.create_data_dff()
def place_modules(self):
"""
This places the modules for a single bank SRAM with control
@ -60,14 +58,12 @@ class sram_1bank(sram_base):
# up to the row address DFFs.
control_pos = vector(-self.control_logic.width - 2*self.m2_pitch,
self.bank.bank_center.y - self.control_logic.control_logic_center.y)
self.place_inst(name=self.control_logic_inst.name,
offset=control_pos)
self.control_logic_inst.place(control_pos)
# The row address bits are placed above the control logic aligned on the right.
row_addr_pos = vector(self.control_logic_inst.rx() - self.row_addr_dff.width,
self.control_logic_inst.uy())
self.place_inst(name=self.row_addr_dff_inst.name,
offset=row_addr_pos)
self.row_addr_dff_inst.place(row_addr_pos)
# This is M2 pitch even though it is on M1 to help stem via spacings on the trunk
data_gap = -self.m2_pitch*(self.word_size+1)
@ -77,8 +73,7 @@ class sram_1bank(sram_base):
if self.col_addr_dff:
col_addr_pos = vector(self.bank.bank_center.x - self.col_addr_dff.width - self.bank.central_bus_width,
data_gap - self.col_addr_dff.height)
self.place_inst(name=self.col_addr_dff_inst.name,
offset=col_addr_pos)
self.col_addr_dff_inst.place(col_addr_pos)
# Add the data flops below the bank to the right of the center of bank:
# This relies on the center point of the bank:
@ -87,12 +82,11 @@ class sram_1bank(sram_base):
# sense amps.
data_pos = vector(self.bank.bank_center.x,
data_gap - self.data_dff.height)
self.place_inst(self.data_dff.name,
offset=data_pos)
self.data_dff_inst.place(data_pos)
# two supply rails are already included in the bank, so just 2 here.
self.width = self.bank.width + self.control_logic.width + 2*self.supply_rail_pitch
self.height = self.bank.height
# self.width = self.bank.width + self.control_logic.width + 2*self.supply_rail_pitch
# self.height = self.bank.height
def add_layout_pins(self):
"""

View File

@ -117,16 +117,31 @@ class sram_base(design):
def create_netlist(self):
""" Netlist creation """
""" Netlist creation """
# Must create the control logic before pins to get the pins
self.add_modules()
self.add_pins()
# This is for the lib file if we don't create layout
self.width=0
self.height=0
def create_layout(self):
""" Layout creation """
self.place_modules()
self.route()
self.add_lvs_correspondence_points()
self.offset_all_coordinates()
highest_coord = self.find_highest_coords()
self.width = highest_coord[0]
self.height = highest_coord[1]
self.DRC_LVS(final_verification=True)
def compute_bus_sizes(self):
""" Compute the independent bus widths shared between two and four bank SRAMs """
@ -296,9 +311,8 @@ class sram_base(design):
def create_bank(self):
def create_bank(self,bank_num):
""" Create a bank """
bank_num = len(self.bank_insts)
self.bank_insts.append(self.add_inst(name="bank{0}".format(bank_num),
mod=self.bank))
@ -341,8 +355,7 @@ class sram_base(design):
else:
bank_mirror = "R0"
self.place_inst(name=bank_inst.name,
offset=position,
bank_inst.place(offset=position,
mirror=bank_mirror,
rotate=bank_rotation)

View File

@ -1,4 +1,4 @@
#!/usr/bin/env python2.7
#!/usr/bin/env python3
"""
Run regresion tests on a parameterized bitcell
"""
@ -13,9 +13,7 @@ import debug
OPTS = globals.OPTS
#@unittest.skip("SKIPPING 04_pbitcell_test")
@unittest.skip("SKIPPING 04_pbitcell_test")
class pbitcell_test(openram_test):
def runTest(self):

0
compiler/tests/04_precharge_test.py Normal file → Executable file
View File

View File

@ -11,7 +11,7 @@ import globals
from globals import OPTS
import debug
#@unittest.skip("SKIPPING 05_pbitcell_array_test")
@unittest.skip("SKIPPING 05_pbitcell_array_test")
class pbitcell_array_test(openram_test):
def runTest(self):

0
compiler/tests/08_precharge_array_test.py Normal file → Executable file
View File

4
compiler/tests/19_psingle_bank_test.py Normal file → Executable file
View File

@ -11,8 +11,8 @@ import globals
from globals import OPTS
import debug
@unittest.skip("Multiported Bank not working yet")
class single_bank_test(openram_test):
@unittest.skip("SKIPPING 19_psingle_bank_test")
class psingle_bank_test(openram_test):
def runTest(self):
globals.init_openram("config_20_{0}".format(OPTS.tech_name))

View File

@ -22,9 +22,9 @@ if not OPTS.check_lvsdrc:
OPTS.pex_exe = None
else:
debug.info(1, "Finding DRC/LVS/PEX tools.")
OPTS.drc_exe = get_tool("DRC",["calibre","assura","magic"])
OPTS.lvs_exe = get_tool("LVS",["calibre","assura","netgen"])
OPTS.pex_exe = get_tool("PEX",["calibre","magic"])
OPTS.drc_exe = get_tool("DRC", ["calibre","assura","magic"], OPTS.drc_name)
OPTS.lvs_exe = get_tool("LVS", ["calibre","assura","netgen"], OPTS.lvs_name)
OPTS.pex_exe = get_tool("PEX", ["calibre","magic"], OPTS.pex_name)
if OPTS.check_lvsdrc and OPTS.tech_name == "freepdk45":
debug.check(OPTS.drc_exe[0]!="magic","Magic does not support FreePDK45 for DRC.")

View File

@ -1,59 +1,15 @@
"""
This is a DRC/LVS/PEX interface file for magic + netgen.
This assumes you have the SCMOS magic rules installed. Get these from:
ftp://ftp.mosis.edu/pub/sondeen/magic/new/beta/current.tar.gz
and install them in:
cd /opt/local/lib/magic/sys
tar zxvf current.tar.gz
ln -s 2001a current
1. magic can perform drc with the following:
#!/bin/sh
magic -dnull -noconsole << EOF
tech load SCN3ME_SUBM.30
#scalegrid 1 2
gds rescale no
gds polygon subcell true
gds warning default
gds read $1
load $1
writeall force
drc count
drc why
quit -noprompt
EOF
2. magic can perform extraction with the following:
#!/bin/sh
rm -f $1.ext
rm -f $1.spice
magic -dnull -noconsole << EOF
tech load SCN3ME_SUBM.30
#scalegrid 1 2
gds rescale no
gds polygon subcell true
gds warning default
gds read $1
extract
ext2spice scale off
ext2spice
quit -noprompt
EOF
3. netgen can perform LVS with:
#!/bin/sh
netgen -noconsole <<EOF
readnet spice $1.spice
readnet spice $1.sp
ignore class c
equate class {$1.spice nfet} {$2.sp n}
equate class {$1.spice pfet} {$2.sp p}
permute default
compare hierarchical $1.spice {$1.sp $1}
run converge
EOF
We include the tech file for SCN3ME_SUBM in the tech directory,
that is included in OpenRAM during DRC.
You can use this interactively by appending the magic system path in
your .magicrc file
path sys /Users/mrg/openram/technology/scn3me_subm/tech
We require the version 30 Magic rules which allow via stacking.
We obtained this file from Qflow ( http://opencircuitdesign.com/qflow/index.html )
and include its appropriate license.
"""
@ -300,6 +256,25 @@ def run_pex(name, gds_name, sp_name, output=None):
run_drc(name, gds_name)
run_lvs(name, gds_name, sp_name)
"""
2. magic can perform extraction with the following:
#!/bin/sh
rm -f $1.ext
rm -f $1.spice
magic -dnull -noconsole << EOF
tech load SCN3ME_SUBM.30
#scalegrid 1 2
gds rescale no
gds polygon subcell true
gds warning default
gds read $1
extract
ext2spice scale off
ext2spice
quit -noprompt
EOF
"""
pex_rules = drc["xrc_rules"]
pex_runset = {
'pexRulesFile': pex_rules,