Converted all modules to not run create_layout when netlist_only

mode is enabled.
This commit is contained in:
Matt Guthaus 2018-08-27 16:42:48 -07:00
parent 9f051df18d
commit 8664f7a0b8
27 changed files with 711 additions and 466 deletions

View File

@ -57,6 +57,9 @@ class geometry:
def compute_boundary(self,offset=vector(0,0),mirror="",rotate=0): def compute_boundary(self,offset=vector(0,0),mirror="",rotate=0):
""" Transform with offset, mirror and rotation to get the absolute pin location. """ 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. """ 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)] (ll,ur) = [vector(0,0),vector(self.width,self.height)]
if mirror=="MX": if mirror=="MX":
ll=ll.scale(1,-1) ll=ll.scale(1,-1)

View File

@ -5,6 +5,7 @@ import debug
from tech import drc, GDS from tech import drc, GDS
from tech import layer as techlayer from tech import layer as techlayer
import os import os
from globals import OPTS
from vector import vector from vector import vector
from pin_layout import pin_layout from pin_layout import pin_layout
import lef import lef
@ -436,6 +437,10 @@ class layout(lef.lef):
def gds_read(self): def gds_read(self):
"""Reads a GDSII file in the library and checks if it exists """Reads a GDSII file in the library and checks if it exists
Otherwise, start a new layout for dynamic generation.""" 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 # open the gds file if it exists or else create a blank layout
if os.path.isfile(self.gds_file): if os.path.isfile(self.gds_file):
debug.info(3, "opening %s" % self.gds_file) debug.info(3, "opening %s" % self.gds_file)

View File

@ -56,7 +56,8 @@ class bank(design.design):
self.prefix="" self.prefix=""
self.create_netlist() self.create_netlist()
self.create_layout() if not OPTS.netlist_only:
self.create_layout()
def create_netlist(self): def create_netlist(self):
@ -580,23 +581,25 @@ class bank(design.design):
def route_bank_select(self): def route_bank_select(self):
""" Route the bank select logic. """ """ 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: for gated_name in self.control_signals:
# Connect the inverter output to the central bus # Connect the inverter output to the central bus
out_pos = self.bank_select_inst[0].get_pin(gated_name).rc() out_pos = self.bank_select_inst[k].get_pin(gated_name).rc()
bus_pos = vector(self.bus_xoffset[gated_name].x, out_pos.y) bus_pos = vector(self.bus_xoffset[gated_name].x, out_pos.y)
self.add_path("metal3",[out_pos, bus_pos]) self.add_path("metal3",[out_pos, bus_pos])
self.add_via_center(layers=("metal2", "via2", "metal3"), self.add_via_center(layers=("metal2", "via2", "metal3"),
offset=bus_pos, offset=bus_pos,
rotate=90) rotate=90)
self.add_via_center(layers=("metal1", "via1", "metal2"), self.add_via_center(layers=("metal1", "via1", "metal2"),
offset=out_pos, offset=out_pos,
rotate=90) rotate=90)
self.add_via_center(layers=("metal2", "via2", "metal3"), self.add_via_center(layers=("metal2", "via2", "metal3"),
offset=out_pos, offset=out_pos,
rotate=90) rotate=90)
def setup_routing_constraints(self): def setup_routing_constraints(self):

View File

@ -18,9 +18,29 @@ class bank_select(design.design):
def __init__(self, name="bank_select"): def __init__(self, name="bank_select"):
design.design.__init__(self, name) 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 # Number of control lines in the bus
self.num_control_lines = 4 self.num_control_lines = 4
# The order of the control signals on the control bus: # 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"] self.input_control_signals = ["clk_buf", "clk_buf_bar", "w_en0", "s_en0"]
# These will be outputs of the gaters if this is multibank # These will be outputs of the gaters if this is multibank
self.control_signals = ["gated_"+str for str in self.input_control_signals] 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("vdd","POWER")
self.add_pin("gnd","GROUND") self.add_pin("gnd","GROUND")
self.create_modules() def add_modules(self):
self.calculate_module_offsets()
self.add_modules()
self.route_modules()
self.DRC_LVS()
def create_modules(self):
""" Create modules for later instantiation """ """ Create modules for later instantiation """
# 1x Inverter # 1x Inverter
self.inv = pinv() self.inv = pinv()
@ -67,7 +80,52 @@ class bank_select(design.design):
self.height = self.yoffset_maxpoint + 2*self.m1_pitch self.height = self.yoffset_maxpoint + 2*self.m1_pitch
self.width = self.xoffset_inv + self.inv4x.width self.width = self.xoffset_inv + self.inv4x.width
def add_modules(self): def create_modules(self):
self.bank_sel_inv=self.add_inst(name="bank_sel_inv",
mod=self.inv)
self.connect_inst(["bank_sel", "bank_sel_bar", "vdd", "gnd"])
self.logic_inst = []
self.inv_inst = []
for i in range(self.num_control_lines):
input_name = self.input_control_signals[i]
gated_name = self.control_signals[i]
name_nand = "nand_{}".format(input_name)
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 # bank select inverter
self.bank_select_inv_position = vector(self.xoffset_bank_sel_inv, 0) self.bank_select_inv_position = vector(self.xoffset_bank_sel_inv, 0)
@ -78,8 +136,6 @@ class bank_select(design.design):
offset=[self.xoffset_bank_sel_inv, 0]) offset=[self.xoffset_bank_sel_inv, 0])
self.connect_inst(["bank_sel", "bank_sel_bar", "vdd", "gnd"]) self.connect_inst(["bank_sel", "bank_sel_bar", "vdd", "gnd"])
self.logic_inst = []
self.inv_inst = []
for i in range(self.num_control_lines): for i in range(self.num_control_lines):
input_name = self.input_control_signals[i] input_name = self.input_control_signals[i]
gated_name = self.control_signals[i] gated_name = self.control_signals[i]
@ -98,40 +154,21 @@ class bank_select(design.design):
# (writes occur on clk low) # (writes occur on clk low)
if input_name in ("clk_buf"): if input_name in ("clk_buf"):
self.logic_inst.append(self.add_inst(name=name_nor, self.place_inst(name=name_nor,
mod=self.nor2, offset=[self.xoffset_nor, y_offset],
offset=[self.xoffset_nor, y_offset], mirror=mirror)
mirror=mirror))
self.connect_inst([input_name,
"bank_sel_bar",
gated_name+"_temp_bar",
"vdd",
"gnd"])
# the rest are AND (nand2+inv) gates # the rest are AND (nand2+inv) gates
else: else:
self.logic_inst.append(self.add_inst(name=name_nand, self.place_inst(name=name_nand,
mod=self.nand2, offset=[self.xoffset_nand, y_offset],
offset=[self.xoffset_nand, y_offset], mirror=mirror)
mirror=mirror))
bank_sel_signal = "bank_sel"
self.connect_inst([input_name,
"bank_sel",
gated_name+"_temp_bar",
"vdd",
"gnd"])
# They all get inverters on the output # They all get inverters on the output
self.inv_inst.append(self.add_inst(name=name_inv, self.place_inst(name=name_inv,
mod=self.inv4x, offset=[self.xoffset_inv, y_offset],
offset=[self.xoffset_inv, y_offset], mirror=mirror)
mirror=mirror))
self.connect_inst([gated_name+"_temp_bar",
gated_name,
"vdd",
"gnd"])
def route_modules(self): def route_modules(self):

View File

@ -32,25 +32,25 @@ class bitcell_array(design.design):
self.width = self.column_size*self.cell.width + self.m1_width self.width = self.column_size*self.cell.width + self.m1_width
self.create_netlist() self.create_netlist()
if not OPTS.netlist_only:
self.create_layout() self.create_layout()
# We don't offset this because we need to align # We don't offset this because we need to align
# the replica bitcell in the control logic # the replica bitcell in the control logic
#self.offset_all_coordinates() #self.offset_all_coordinates()
def add_pins(self): def create_netlist(self):
row_list = self.cell.list_all_wl_names() """ Create and connect the netlist """
column_list = self.cell.list_all_bitline_names() self.add_pins()
self.cell_inst = {}
for col in range(self.column_size): for col in range(self.column_size):
for cell_column in column_list: for row in range(self.row_size):
self.add_pin(cell_column+"[{0}]".format(col)) name = "bit_r{0}_c{1}".format(row, col)
for row in range(self.row_size): self.cell_inst[row,col]=self.add_inst(name=name,
for cell_row in row_list: mod=self.cell)
self.add_pin(cell_row+"[{0}]".format(row)) self.connect_inst(self.cell.list_bitcell_pins(col, row))
self.add_pin("vdd")
self.add_pin("gnd")
def create_layout(self): def create_layout(self):
xoffset = 0.0 xoffset = 0.0
@ -75,18 +75,18 @@ class bitcell_array(design.design):
self.add_layout_pins() self.add_layout_pins()
self.DRC_LVS() self.DRC_LVS()
def create_netlist(self): def add_pins(self):
""" Create and connect the netlist """ row_list = self.cell.list_all_wl_names()
self.add_pins() column_list = self.cell.list_all_bitline_names()
self.cell_inst = {}
for col in range(self.column_size): for col in range(self.column_size):
for row in range(self.row_size): for cell_column in column_list:
name = "bit_r{0}_c{1}".format(row, col) self.add_pin(cell_column+"[{0}]".format(col))
self.cell_inst[row,col]=self.add_inst(name=name, for row in range(self.row_size):
mod=self.cell) for cell_row in row_list:
self.connect_inst(self.cell.list_bitcell_pins(col, row)) self.add_pin(cell_row+"[{0}]".format(row))
self.add_pin("vdd")
self.add_pin("gnd")
def add_layout_pins(self): def add_layout_pins(self):

View File

@ -24,17 +24,26 @@ class control_logic(design.design):
debug.info(1, "Creating {}".format(self.name)) debug.info(1, "Creating {}".format(self.name))
self.num_rows = num_rows 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): def create_layout(self):
""" Create layout and route between modules """ """ Create layout and route between modules """
self.setup_layout_offsets() self.route_rails()
self.add_pins() self.place_modules()
self.create_modules() self.route_all()
self.add_rails()
self.add_modules() self.add_lvs_correspondence_points()
self.add_routing()
self.DRC_LVS()
def add_pins(self): def add_pins(self):
@ -46,8 +55,8 @@ class control_logic(design.design):
self.add_pin("vdd","POWER") self.add_pin("vdd","POWER")
self.add_pin("gnd","GROUND") self.add_pin("gnd","GROUND")
def create_modules(self): def add_modules(self):
""" add all the required modules """ """ Add all the required modules """
dff = dff_inv() dff = dff_inv()
dff_height = dff.height dff_height = dff.height
@ -83,14 +92,8 @@ class control_logic(design.design):
self.add_mod(self.replica_bitline) self.add_mod(self.replica_bitline)
def setup_layout_offsets(self): def setup_signal_busses(self):
""" Setup layout offsets, determine the size of the busses etc """ """ Setup bus names, 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"])
# List of input control signals # List of input control signals
self.input_list =["csb","web"] self.input_list =["csb","web"]
@ -104,7 +107,7 @@ class control_logic(design.design):
self.supply_list = ["vdd", "gnd"] self.supply_list = ["vdd", "gnd"]
def add_rails(self): def route_rails(self):
""" Add the input signal inverted tracks """ """ Add the input signal inverted tracks """
height = 4*self.inv1.height - self.m2_pitch height = 4*self.inv1.height - self.m2_pitch
offset = vector(self.ctrl_dff_array.width,0) 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) 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 """ """ Place all the modules """
# Keep track of all right-most instances to determine row boundary # Keep track of all right-most instances to determine row boundary
# and add the vdd/gnd pins # 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 # 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 # Add the logic on the right of the bus
self.add_clk_row(row=0) # clk is a double-high cell self.place_clk_row(row=0) # clk is a double-high cell
self.add_we_row(row=2) self.place_we_row(row=2)
# self.add_trien_row(row=3) # self.place_trien_row(row=3)
# self.add_trien_bar_row(row=4) # self.place_trien_bar_row(row=4)
self.add_rbl_in_row(row=3) self.place_rbl_in_row(row=3)
self.add_sen_row(row=4) self.place_sen_row(row=4)
self.add_rbl(row=5) self.place_rbl(row=5)
self.add_lvs_correspondence_points()
# This offset is used for placement of the control logic in # This offset is used for placement of the control logic in
# the SRAM level. # the SRAM level.
self.control_logic_center = vector(self.ctrl_dff_inst.rx(), self.rbl_inst.by()) 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 self.height = self.rbl_inst.uy() + self.m3_pitch
# Max of modules or logic rows # 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 self.width = max(self.rbl_inst.rx(), max([inst.rx() for inst in self.row_end_inst])) + self.m2_pitch
def route_all(self):
def add_routing(self):
""" Routing between modules """ """ Routing between modules """
self.route_dffs() self.route_dffs()
#self.route_trien() #self.route_trien()
@ -156,84 +170,98 @@ class control_logic(design.design):
self.route_supply() self.route_supply()
def add_rbl(self,row): def create_rbl(self):
""" Add the replica bitline """ """ 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 y_off = row * self.inv1.height + 2*self.m1_pitch
# Add the RBL above the rows # Add the RBL above the rows
# Add to the right of the control rows and routing channel # Add to the right of the control rows and routing channel
self.replica_bitline_offset = vector(0, y_off) self.replica_bitline_offset = vector(0, y_off)
self.rbl_inst=self.add_inst(name="replica_bitline", self.place_inst(name="replica_bitline",
mod=self.replica_bitline, offset=self.replica_bitline_offset)
offset=self.replica_bitline_offset)
self.connect_inst(["rbl_in", "pre_s_en", "vdd", "gnd"])
def add_clk_row(self,row): def create_clk_row(self):
""" Add the multistage clock buffer below the control flops """ """ Create the multistage clock buffer """
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 = self.add_inst(name="clkbuf", self.clkbuf_inst = self.add_inst(name="clkbuf",
mod=self.clkbuf, mod=self.clkbuf)
offset=clkbuf_offset)
self.connect_inst(["clk","clk_buf_bar","clk_buf","vdd","gnd"]) 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.place_inst(name="clkbuf",
offset=clkbuf_offset)
self.row_end_inst.append(self.clkbuf_inst) self.row_end_inst.append(self.clkbuf_inst)
def add_rbl_in_row(self,row): def create_rbl_in_row(self):
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)
self.rbl_in_bar_inst=self.add_inst(name="nand3_rbl_in_bar", self.rbl_in_bar_inst=self.add_inst(name="nand3_rbl_in_bar",
mod=self.nand2, mod=self.nand2)
offset=self.rbl_in_bar_offset,
mirror=mirror)
self.connect_inst(["clk_buf_bar", "cs", "rbl_in_bar", "vdd", "gnd"]) self.connect_inst(["clk_buf_bar", "cs", "rbl_in_bar", "vdd", "gnd"])
x_off += self.nand2.width
# input: rbl_in_bar, output: rbl_in # 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", self.rbl_in_inst=self.add_inst(name="inv_rbl_in",
mod=self.inv1, mod=self.inv1)
offset=self.rbl_in_offset,
mirror=mirror)
self.connect_inst(["rbl_in_bar", "rbl_in", "vdd", "gnd"]) self.connect_inst(["rbl_in_bar", "rbl_in", "vdd", "gnd"])
self.row_end_inst.append(self.rbl_in_inst)
def place_rbl_in_row(self,row):
def add_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 x_off = self.ctrl_dff_array.width + self.internal_bus_width
(y_off,mirror)=self.get_offset(row) (y_off,mirror)=self.get_offset(row)
self.rbl_in_bar_offset = vector(x_off, y_off)
self.place_inst(name="nand3_rbl_in_bar",
offset=self.rbl_in_bar_offset,
mirror=mirror)
x_off += self.nand2.width
self.rbl_in_offset = vector(x_off, y_off)
self.place_inst(name="inv_rbl_in",
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 # 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", self.pre_s_en_bar_inst=self.add_inst(name="inv_pre_s_en_bar",
mod=self.inv2, mod=self.inv2)
offset=self.pre_s_en_bar_offset,
mirror=mirror)
self.connect_inst(["pre_s_en", "pre_s_en_bar", "vdd", "gnd"]) self.connect_inst(["pre_s_en", "pre_s_en_bar", "vdd", "gnd"])
x_off += self.inv2.width
# BUFFER INVERTERS FOR S_EN # BUFFER INVERTERS FOR S_EN
# input: input: pre_s_en_bar, output: 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", self.s_en_inst=self.add_inst(name="inv_s_en",
mod=self.inv8, mod=self.inv8)
offset=self.s_en_offset,
mirror=mirror)
self.connect_inst(["pre_s_en_bar", "s_en0", "vdd", "gnd"]) 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.place_inst(name="inv_pre_s_en_bar",
offset=self.pre_s_en_bar_offset,
mirror=mirror)
x_off += self.inv2.width
self.s_en_offset = vector(x_off, y_off)
self.place_inst(name="inv_s_en",
offset=self.s_en_offset,
mirror=mirror)
self.row_end_inst.append(self.s_en_inst) self.row_end_inst.append(self.s_en_inst)
@ -256,14 +284,17 @@ class control_logic(design.design):
self.copy_layout_pin(self.ctrl_dff_inst, "din[1]", "web") 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) """ """ Add the three input DFFs (with inverters) """
self.ctrl_dff_inst=self.add_inst(name="ctrl_dffs", self.ctrl_dff_inst=self.add_inst(name="ctrl_dffs",
mod=self.ctrl_dff_array, mod=self.ctrl_dff_array)
offset=vector(0,0))
self.connect_inst(self.input_list + self.dff_output_list + ["clk_buf"] + self.supply_list) 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.place_inst(name="ctrl_dffs",
offset=vector(0,0))
def get_offset(self,row): def get_offset(self,row):
""" Compute the y-offset and mirroring """ """ Compute the y-offset and mirroring """
@ -276,48 +307,57 @@ class control_logic(design.design):
return (y_off,mirror) 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 x_off = self.ctrl_dff_inst.width + self.internal_bus_width
(y_off,mirror)=self.get_offset(row) (y_off,mirror)=self.get_offset(row)
# input: WE, CS output: w_en_bar
w_en_bar_offset = vector(x_off, y_off) w_en_bar_offset = vector(x_off, y_off)
self.w_en_bar_inst=self.add_inst(name="nand3_w_en_bar", self.place_inst(name="nand3_w_en_bar",
mod=self.nand3, offset=w_en_bar_offset,
offset=w_en_bar_offset, mirror=mirror)
mirror=mirror)
self.connect_inst(["clk_buf_bar", "cs", "we", "w_en_bar", "vdd", "gnd"])
x_off += self.nand3.width x_off += self.nand3.width
# input: w_en_bar, output: pre_w_en
pre_w_en_offset = vector(x_off, y_off) pre_w_en_offset = vector(x_off, y_off)
self.pre_w_en_inst=self.add_inst(name="inv_pre_w_en", self.place_inst(name="inv_pre_w_en",
mod=self.inv1, offset=pre_w_en_offset,
offset=pre_w_en_offset, mirror=mirror)
mirror=mirror)
self.connect_inst(["w_en_bar", "pre_w_en", "vdd", "gnd"])
x_off += self.inv1.width x_off += self.inv1.width
# BUFFER INVERTERS FOR W_EN
pre_w_en_bar_offset = vector(x_off, y_off) 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", self.place_inst(name="inv_pre_w_en_bar",
mod=self.inv2, offset=pre_w_en_bar_offset,
offset=pre_w_en_bar_offset, mirror=mirror)
mirror=mirror)
self.connect_inst(["pre_w_en", "pre_w_en_bar", "vdd", "gnd"])
x_off += self.inv2.width x_off += self.inv2.width
w_en_offset = vector(x_off, y_off) w_en_offset = vector(x_off, y_off)
self.w_en_inst=self.add_inst(name="inv_w_en2", self.place_inst(name="inv_w_en2",
mod=self.inv8, offset=w_en_offset,
offset=w_en_offset, mirror=mirror)
mirror=mirror)
self.connect_inst(["pre_w_en_bar", "w_en0", "vdd", "gnd"])
x_off += self.inv8.width x_off += self.inv8.width
self.row_end_inst.append(self.w_en_inst) self.row_end_inst.append(self.w_en_inst)
def route_rbl_in(self): def route_rbl_in(self):
""" Connect the logic for the rbl_in generation """ """ 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. # number of inverters including any fanout loads.
self.fanout_list = fanout_list self.fanout_list = fanout_list
from importlib import reload self.create_netlist()
c = reload(__import__(OPTS.bitcell)) if not OPTS.netlist_only:
self.mod_bitcell = getattr(c, OPTS.bitcell) self.create_layout()
self.bitcell = self.mod_bitcell()
def create_netlist(self):
self.add_pins() self.add_pins()
self.create_module() self.add_modules()
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.route_inverters()
self.add_layout_pins() self.add_layout_pins()
self.DRC_LVS() self.DRC_LVS()
@ -43,40 +52,27 @@ class delay_chain(design.design):
self.add_pin("vdd") self.add_pin("vdd")
self.add_pin("gnd") self.add_pin("gnd")
def create_module(self): def add_modules(self):
""" Add the inverter logical module """ 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.inv = pinv(route_output=False)
self.add_mod(self.inv) self.add_mod(self.inv)
# Each stage is a a row def create_inverters(self):
self.height = len(self.fanout_list)*self.inv.height """ Create the inverters and connect them based on the stage list """
# 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 """
self.driver_inst_list = [] self.driver_inst_list = []
self.rightest_load_inst = {} self.rightest_load_inst = {}
self.load_inst_map = {} self.load_inst_map = {}
for stage_num,fanout_size in zip(range(len(self.fanout_list)),self.fanout_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 # Add the inverter
cur_driver=self.add_inst(name="dinv{}".format(stage_num), cur_driver=self.add_inst(name="dinv{}".format(stage_num),
mod=self.inv, mod=self.inv)
offset=inv_offset,
mirror=inv_mirror)
# keep track of the inverter instances so we can use them to get the pins # keep track of the inverter instances so we can use them to get the pins
self.driver_inst_list.append(cur_driver) self.driver_inst_list.append(cur_driver)
# Hook up the driver # Hook up the driver
if stage_num+1==len(self.fanout_list): if stage_num+1==len(self.fanout_list):
stageout_name = "out" stageout_name = "out"
@ -91,11 +87,8 @@ class delay_chain(design.design):
# Now add the dummy loads to the right # Now add the dummy loads to the right
self.load_inst_map[cur_driver]=[] self.load_inst_map[cur_driver]=[]
for i in range(fanout_size): 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), cur_load=self.add_inst(name="dload_{0}_{1}".format(stage_num,i),
mod=self.inv, mod=self.inv)
offset=inv_offset,
mirror=inv_mirror)
# Fanout stage is always driven by driver and output is disconnected # Fanout stage is always driven by driver and output is disconnected
disconnect_name = "n_{0}_{1}".format(stage_num,i) disconnect_name = "n_{0}_{1}".format(stage_num,i)
self.connect_inst([stageout_name, disconnect_name, "vdd", "gnd"]) self.connect_inst([stageout_name, disconnect_name, "vdd", "gnd"])
@ -105,6 +98,29 @@ class delay_chain(design.design):
else: else:
# Keep track of the last one so we can add the the wire later # Keep track of the last one so we can add the the wire later
self.rightest_load_inst[cur_driver]=cur_load 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
self.place_inst(name="dinv{}".format(stage_num),
offset=inv_offset,
mirror=inv_mirror)
# Now add the dummy loads to the right
for i in range(fanout_size):
inv_offset += vector(self.inv.width,0)
self.place_inst(name="dload_{0}_{1}".format(stage_num,i),
offset=inv_offset,
mirror=inv_mirror)
def add_route(self, pin1, pin2): def add_route(self, pin1, pin2):
""" This guarantees that we route from the top to bottom row correctly. """ """ This guarantees that we route from the top to bottom row correctly. """

View File

@ -20,21 +20,21 @@ class dff_buf_array(design.design):
name = "dff_buf_array_{0}x{1}".format(rows, columns) name = "dff_buf_array_{0}x{1}".format(rows, columns)
design.design.__init__(self, name) design.design.__init__(self, name)
debug.info(1, "Creating {}".format(self.name)) debug.info(1, "Creating {}".format(self.name))
self.inv1_size = inv1_size
self.dff = dff_buf.dff_buf(inv1_size, inv2_size) self.inv2_size = inv2_size
self.add_mod(self.dff)
self.width = self.columns * self.dff.width
self.height = self.rows * self.dff.height
self.create_netlist() self.create_netlist()
self.create_layout() if not OPTS.netlist_only:
self.create_layout()
def create_netlist(self): def create_netlist(self):
self.add_pins() self.add_pins()
self.add_dff()
self.create_dff_array() self.create_dff_array()
def create_layout(self): def create_layout(self):
self.width = self.columns * self.dff.width
self.height = self.rows * self.dff.height
self.place_dff_array() self.place_dff_array()
self.add_layout_pins() self.add_layout_pins()
self.DRC_LVS() self.DRC_LVS()
@ -51,6 +51,10 @@ class dff_buf_array(design.design):
self.add_pin("vdd") self.add_pin("vdd")
self.add_pin("gnd") self.add_pin("gnd")
def add_dff(self):
self.dff = dff_buf.dff_buf(self.inv1_size, self.inv2_size)
self.add_mod(self.dff)
def create_dff_array(self): def create_dff_array(self):
self.dff_insts={} self.dff_insts={}
for row in range(self.rows): for row in range(self.rows):

View File

@ -18,31 +18,30 @@ class dff_inv(design.design):
name = "dff_inv_{0}".format(inv_size) name = "dff_inv_{0}".format(inv_size)
design.design.__init__(self, name) design.design.__init__(self, name)
debug.info(1, "Creating {}".format(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 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 # 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. # 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.") debug.check(inv_size>=2, "Inverter must be greater than two for rail spacing DRC rules.")
from importlib import reload self.create_netlist()
c = reload(__import__(OPTS.dff)) if not OPTS.netlist_only:
self.mod_dff = getattr(c, OPTS.dff) self.create_layout()
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)
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.width = self.dff.width + self.inv1.width
self.height = self.dff.height self.height = self.dff.height
self.create_layout() self.place_modules()
def create_layout(self):
self.add_pins()
self.add_insts()
self.add_wires() self.add_wires()
self.add_layout_pins() self.add_layout_pins()
self.DRC_LVS() self.DRC_LVS()
def add_pins(self): def add_pins(self):
@ -53,18 +52,35 @@ class dff_inv(design.design):
self.add_pin("vdd") self.add_pin("vdd")
self.add_pin("gnd") self.add_pin("gnd")
def add_insts(self): 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):
# Add the DFF # Add the DFF
self.dff_inst=self.add_inst(name="dff_inv_dff", self.dff_inst=self.add_inst(name="dff_inv_dff",
mod=self.dff, mod=self.dff)
offset=vector(0,0))
self.connect_inst(["D", "Q", "clk", "vdd", "gnd"]) self.connect_inst(["D", "Q", "clk", "vdd", "gnd"])
# Add INV1 to the right # Add INV1 to the right
self.inv1_inst=self.add_inst(name="dff_inv_inv1", self.inv1_inst=self.add_inst(name="dff_inv_inv1",
mod=self.inv1, mod=self.inv1)
offset=vector(self.dff_inst.rx(),0))
self.connect_inst(["Q", "Qb", "vdd", "gnd"]) self.connect_inst(["Q", "Qb", "vdd", "gnd"])
def place_modules(self):
# Place the DFF
self.place_inst(name="dff_inv_dff",
offset=vector(0,0))
# Place the INV1 to the right
self.place_inst(name="dff_inv_inv1",
offset=vector(self.dff_inst.rx(),0))
def add_wires(self): 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) name = "dff_inv_array_{0}x{1}".format(rows, columns)
design.design.__init__(self, name) design.design.__init__(self, name)
debug.info(1, "Creating {}".format(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) def create_netlist(self):
self.add_mod(self.dff) self.add_pins()
self.add_dff()
self.create_dff_array()
def create_layout(self):
self.width = self.columns * self.dff.width self.width = self.columns * self.dff.width
self.height = self.rows * self.dff.height self.height = self.rows * self.dff.height
self.create_layout() self.place_dff_array()
def create_layout(self):
self.add_pins()
self.create_dff_array()
self.add_layout_pins() self.add_layout_pins()
self.DRC_LVS() self.DRC_LVS()
def add_dff(self):
self.dff = dff_inv.dff_inv(self.inv_size)
self.add_mod(self.dff)
def add_pins(self): def add_pins(self):
for row in range(self.rows): for row in range(self.rows):
for col in range(self.columns): for col in range(self.columns):
@ -52,16 +60,8 @@ class dff_inv_array(design.design):
for row in range(self.rows): for row in range(self.rows):
for col in range(self.columns): for col in range(self.columns):
name = "Xdff_r{0}_c{1}".format(row,col) 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, self.dff_insts[row,col]=self.add_inst(name=name,
mod=self.dff, mod=self.dff)
offset=base,
mirror=mirror)
self.connect_inst([self.get_din_name(row,col), self.connect_inst([self.get_din_name(row,col),
self.get_dout_name(row,col), self.get_dout_name(row,col),
self.get_dout_bar_name(row,col), self.get_dout_bar_name(row,col),
@ -69,6 +69,20 @@ class dff_inv_array(design.design):
"vdd", "vdd",
"gnd"]) "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.place_inst(name=name,
offset=base,
mirror=mirror)
def get_din_name(self, row, col): def get_din_name(self, row, col):
if self.columns == 1: if self.columns == 1:
din_name = "din[{0}]".format(row) 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.no_of_pre2x4,self.no_of_pre3x8)=self.determine_predecodes(self.num_inputs)
self.create_netlist() self.create_netlist()
self.create_layout() if not OPTS.netlist_only:
self.create_layout()
def create_netlist(self): def create_netlist(self):

View File

@ -49,7 +49,7 @@ class hierarchical_predecode(design.design):
else: else:
debug.error("Invalid number of predecode inputs: {}".format(inputs),-1) 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 self.height = self.number_of_outputs * self.nand.height

View File

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

View File

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

View File

@ -3,7 +3,7 @@ import debug
from tech import drc from tech import drc
from vector import vector from vector import vector
from precharge import precharge from precharge import precharge
from globals import OPTS
class precharge_array(design.design): class precharge_array(design.design):
""" """
@ -24,11 +24,9 @@ class precharge_array(design.design):
self.pc_cell = precharge(name="precharge", size=size, bitcell_bl=bitcell_bl, bitcell_br=bitcell_br) self.pc_cell = precharge(name="precharge", size=size, bitcell_bl=bitcell_bl, bitcell_br=bitcell_br)
self.add_mod(self.pc_cell) self.add_mod(self.pc_cell)
self.width = self.columns * self.pc_cell.width
self.height = self.pc_cell.height
self.create_netlist() self.create_netlist()
self.create_layout() if not OPTS.netlist_only:
self.create_layout()
def add_pins(self): def add_pins(self):
"""Adds pins for spice file""" """Adds pins for spice file"""
@ -43,6 +41,9 @@ class precharge_array(design.design):
self.create_insts() self.create_insts()
def create_layout(self): def create_layout(self):
self.width = self.columns * self.pc_cell.width
self.height = self.pc_cell.height
self.place_insts() self.place_insts()
self.add_layout_pins() self.add_layout_pins()
self.DRC_LVS() self.DRC_LVS()

View File

@ -24,16 +24,24 @@ class replica_bitline(design.design):
g = reload(__import__(OPTS.replica_bitcell)) g = reload(__import__(OPTS.replica_bitcell))
self.mod_replica_bitcell = getattr(g, 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.bitcell_loads = bitcell_loads
self.delay_stages = delay_stages self.delay_stages = delay_stages
self.delay_fanout = delay_fanout self.delay_fanout = delay_fanout
self.create_modules() self.create_netlist()
self.calculate_module_offsets() if not OPTS.netlist_only:
self.create_layout()
def create_netlist(self):
for pin in ["en", "out", "vdd", "gnd"]:
self.add_pin(pin)
self.add_modules() self.add_modules()
self.create_modules()
def create_layout(self):
self.calculate_module_offsets()
self.place_modules()
self.route() self.route()
self.offset_all_coordinates() self.offset_all_coordinates()
@ -48,6 +56,7 @@ class replica_bitline(design.design):
self.DRC_LVS() self.DRC_LVS()
def calculate_module_offsets(self): def calculate_module_offsets(self):
""" Calculate all the module offsets """ """ Calculate all the module offsets """
@ -74,8 +83,8 @@ class replica_bitline(design.design):
def create_modules(self): def add_modules(self):
""" Create modules for later instantiation """ """ Add the modules for later usage """
self.bitcell = self.replica_bitcell = self.mod_replica_bitcell() self.bitcell = self.replica_bitcell = self.mod_replica_bitcell()
self.add_mod(self.bitcell) self.add_mod(self.bitcell)
@ -93,38 +102,53 @@ class replica_bitline(design.design):
self.access_tx = ptx(tx_type="pmos") self.access_tx = ptx(tx_type="pmos")
self.add_mod(self.access_tx) self.add_mod(self.access_tx)
def add_modules(self): def create_modules(self):
""" Add all of the module instances in the logical netlist """ """ Create all of the module instances in the logical netlist """
# This is the threshold detect inverter on the output of the RBL # This is the threshold detect inverter on the output of the RBL
self.rbl_inv_inst=self.add_inst(name="rbl_inv", self.rbl_inv_inst=self.add_inst(name="rbl_inv",
mod=self.inv, mod=self.inv)
offset=self.rbl_inv_offset,
rotate=180)
self.connect_inst(["bl[0]", "out", "vdd", "gnd"]) self.connect_inst(["bl[0]", "out", "vdd", "gnd"])
self.tx_inst=self.add_inst(name="rbl_access_tx", self.tx_inst=self.add_inst(name="rbl_access_tx",
mod=self.access_tx, mod=self.access_tx)
offset=self.access_tx_offset)
# D, G, S, B # D, G, S, B
self.connect_inst(["vdd", "delayed_en", "bl[0]", "vdd"]) self.connect_inst(["vdd", "delayed_en", "bl[0]", "vdd"])
# add the well and poly contact # add the well and poly contact
self.dc_inst=self.add_inst(name="delay_chain", self.dc_inst=self.add_inst(name="delay_chain",
mod=self.delay_chain, mod=self.delay_chain)
offset=self.delay_chain_offset)
self.connect_inst(["en", "delayed_en", "vdd", "gnd"]) self.connect_inst(["en", "delayed_en", "vdd", "gnd"])
self.rbc_inst=self.add_inst(name="bitcell", self.rbc_inst=self.add_inst(name="bitcell",
mod=self.replica_bitcell, mod=self.replica_bitcell)
offset=self.bitcell_offset,
mirror="MX")
self.connect_inst(["bl[0]", "br[0]", "delayed_en", "vdd", "gnd"]) self.connect_inst(["bl[0]", "br[0]", "delayed_en", "vdd", "gnd"])
self.rbl_inst=self.add_inst(name="load", self.rbl_inst=self.add_inst(name="load",
mod=self.rbl, mod=self.rbl)
offset=self.rbl_offset)
self.connect_inst(["bl[0]", "br[0]"] + ["gnd"]*self.bitcell_loads + ["vdd", "gnd"]) 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.place_inst(name="rbl_inv",
offset=self.rbl_inv_offset,
rotate=180)
self.place_inst(name="rbl_access_tx",
offset=self.access_tx_offset)
self.place_inst(name="delay_chain",
offset=self.delay_chain_offset)
self.place_inst(name="bitcell",
offset=self.bitcell_offset,
mirror="MX")
self.place_inst(name="load",
offset=self.rbl_offset)

View File

@ -21,10 +21,21 @@ class wordline_driver(design.design):
self.rows = rows self.rows = rows
self.create_netlist() 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_drivers()
def create_layout(self):
self.place_drivers()
self.route_layout()
self.route_vdd_gnd()
self.offset_all_coordinates() self.offset_all_coordinates()
self.DRC_LVS() self.DRC_LVS()
def add_pins(self): def add_pins(self):
# inputs to wordline_driver. # inputs to wordline_driver.
for i in range(self.rows): for i in range(self.rows):
@ -36,16 +47,6 @@ class wordline_driver(design.design):
self.add_pin("vdd") self.add_pin("vdd")
self.add_pin("gnd") 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): def add_modules(self):
self.inv = pinv() self.inv = pinv()

View File

@ -29,8 +29,10 @@ class pbitcell(pgate.pgate):
self.num_read = num_read self.num_read = num_read
self.create_netlist() 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.width = self.width
pbitcell.height = self.height pbitcell.height = self.height

View File

@ -41,40 +41,49 @@ class pinv(pgate.pgate):
self.create_netlist() 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 # for run-time, we won't check every transitor DRC/LVS independently
# but this may be uncommented for debug purposes # but this may be uncommented for debug purposes
#self.DRC_LVS() #self.DRC_LVS()
def add_pins(self):
""" Adds pins for spice netlist """
self.add_pin_list(["A", "Z", "vdd", "gnd"])
def create_netlist(self): def create_netlist(self):
""" Calls all functions related to the generation of the netlist """ """ Calls all functions related to the generation of the netlist """
self.add_pins() self.add_pins()
self.determine_tx_mults()
self.add_ptx()
self.create_ptx()
def create_layout(self): def create_layout(self):
""" Calls all functions related to the generation of the layout """ """ Calls all functions related to the generation of the layout """
self.determine_tx_mults()
self.create_ptx()
self.setup_layout_constants() self.setup_layout_constants()
self.add_supply_rails() self.route_supply_rails()
self.add_ptx() self.place_ptx()
self.add_well_contacts() self.add_well_contacts()
self.extend_wells(self.well_pos) self.extend_wells(self.well_pos)
self.connect_rails() self.connect_rails()
self.route_input_gate(self.pmos_inst, self.nmos_inst, self.output_pos.y, "A", rotate=0) self.route_input_gate(self.pmos_inst, self.nmos_inst, self.output_pos.y, "A", rotate=0)
self.route_outputs() 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): def determine_tx_mults(self):
""" """
Determines the number of fingers needed to achieve the size within Determines the number of fingers needed to achieve the size within
the height constraint. This may fail if the user has a tight height. 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 # 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? # 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) # 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. """ """ Create the PMOS and NMOS transistors. """
self.nmos = ptx(width=self.nmos_width, self.nmos = ptx(width=self.nmos_width,
mults=self.tx_mults, mults=self.tx_mults,
@ -154,7 +163,7 @@ class pinv(pgate.pgate):
connect_active=True) connect_active=True)
self.add_mod(self.pmos) self.add_mod(self.pmos)
def add_supply_rails(self): def route_supply_rails(self):
""" Add vdd/gnd rails to the top and bottom. """ """ Add vdd/gnd rails to the top and bottom. """
self.add_layout_pin_rect_center(text="gnd", self.add_layout_pin_rect_center(text="gnd",
layer="metal1", layer="metal1",
@ -166,26 +175,36 @@ class pinv(pgate.pgate):
offset=vector(0.5*self.width,self.height), offset=vector(0.5*self.width,self.height),
width=self.width) 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 to provide maximum routing in channel
""" """
# place PMOS so it is half a poly spacing down from the top # place PMOS so it is half a poly spacing down from the top
self.pmos_pos = self.pmos.active_offset.scale(1,0) \ self.pmos_pos = self.pmos.active_offset.scale(1,0) \
+ vector(0, self.height-self.pmos.active_height-self.top_bottom_space) + vector(0, self.height-self.pmos.active_height-self.top_bottom_space)
self.pmos_inst=self.add_inst(name="pinv_pmos", self.place_inst(name="pinv_pmos",
mod=self.pmos, offset=self.pmos_pos)
offset=self.pmos_pos)
self.connect_inst(["Z", "A", "vdd", "vdd"])
# place NMOS so that it is half a poly spacing up from the bottom # 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_pos = self.nmos.active_offset.scale(1,0) + vector(0,self.top_bottom_space)
self.nmos_inst=self.add_inst(name="pinv_nmos", self.place_inst(name="pinv_nmos",
mod=self.nmos, offset=self.nmos_pos)
offset=self.nmos_pos)
self.connect_inst(["Z", "A", "gnd", "gnd"])
# Output position will be in between the PMOS and NMOS drains # 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)) debug.info(1, "Creating {}".format(self.name))
self.create_netlist() self.create_netlist()
self.create_layout() if not OPTS.netlist_only:
self.create_layout()
def create_netlist(self): def create_netlist(self):

View File

@ -36,32 +36,34 @@ class pnand2(pgate.pgate):
self.tx_mults = 1 self.tx_mults = 1
self.create_netlist() self.create_netlist()
self.create_layout() if not OPTS.netlist_only:
self.create_layout()
#self.DRC_LVS() #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): def create_netlist(self):
self.add_pins() self.add_pins()
self.add_ptx()
self.create_ptx()
def create_layout(self): def create_layout(self):
""" Calls all functions related to the generation of the layout """ """ Calls all functions related to the generation of the layout """
self.create_ptx()
self.setup_layout_constants() self.setup_layout_constants()
self.add_supply_rails() self.route_supply_rails()
self.add_ptx() self.place_ptx()
self.connect_rails() self.connect_rails()
self.add_well_contacts() self.add_well_contacts()
self.extend_wells(self.well_pos) self.extend_wells(self.well_pos)
self.route_inputs() self.route_inputs()
self.route_output() 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. """ """ Create the PMOS and NMOS transistors. """
self.nmos = ptx(width=self.nmos_width, self.nmos = ptx(width=self.nmos_width,
mults=self.tx_mults, 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, self.top_bottom_space = max(0.5*self.m1_width + self.m1_space + extra_contact_space,
drc["poly_extend_active"], self.poly_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. """ """ Add vdd/gnd rails to the top and bottom. """
self.add_layout_pin_rect_center(text="gnd", self.add_layout_pin_rect_center(text="gnd",
layer="metal1", layer="metal1",
@ -117,37 +119,51 @@ class pnand2(pgate.pgate):
offset=vector(0.5*self.width,self.height), offset=vector(0.5*self.width,self.height),
width=self.width) 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 to provide maximum routing in channel
""" """
pmos1_pos = vector(self.pmos.active_offset.x, pmos1_pos = vector(self.pmos.active_offset.x,
self.height - self.pmos.active_height - self.top_bottom_space) self.height - self.pmos.active_height - self.top_bottom_space)
self.pmos1_inst=self.add_inst(name="pnand2_pmos1", self.place_inst(name="pnand2_pmos1",
mod=self.pmos, offset=pmos1_pos)
offset=pmos1_pos)
self.connect_inst(["vdd", "A", "Z", "vdd"])
self.pmos2_pos = pmos1_pos + self.overlap_offset self.pmos2_pos = pmos1_pos + self.overlap_offset
self.pmos2_inst = self.add_inst(name="pnand2_pmos2", self.place_inst(name="pnand2_pmos2",
mod=self.pmos, offset=self.pmos2_pos)
offset=self.pmos2_pos)
self.connect_inst(["Z", "B", "vdd", "vdd"])
nmos1_pos = vector(self.pmos.active_offset.x, self.top_bottom_space) nmos1_pos = vector(self.pmos.active_offset.x, self.top_bottom_space)
self.nmos1_inst=self.add_inst(name="pnand2_nmos1", self.place_inst(name="pnand2_nmos1",
mod=self.nmos, offset=nmos1_pos)
offset=nmos1_pos)
self.connect_inst(["Z", "B", "net1", "gnd"])
self.nmos2_pos = nmos1_pos + self.overlap_offset self.nmos2_pos = nmos1_pos + self.overlap_offset
self.nmos2_inst=self.add_inst(name="pnand2_nmos2", self.place_inst(name="pnand2_nmos2",
mod=self.nmos, offset=self.nmos2_pos)
offset=self.nmos2_pos)
self.connect_inst(["net1", "A", "gnd", "gnd"])
# Output position will be in between the PMOS and NMOS # 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)) 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.tx_mults = 1
self.create_netlist() self.create_netlist()
self.create_layout() if not OPTS.netlist_only:
#self.DRC_LVS() self.create_layout()
def add_pins(self): def add_pins(self):
@ -49,21 +49,22 @@ class pnand3(pgate.pgate):
def create_netlist(self): def create_netlist(self):
self.add_pins() self.add_pins()
self.add_ptx()
self.create_ptx()
def create_layout(self): def create_layout(self):
""" Calls all functions related to the generation of the layout """ """ Calls all functions related to the generation of the layout """
self.create_ptx()
self.setup_layout_constants() self.setup_layout_constants()
self.add_supply_rails() self.route_supply_rails()
self.add_ptx() self.place_ptx()
self.connect_rails() self.connect_rails()
self.add_well_contacts() self.add_well_contacts()
self.extend_wells(self.well_pos) self.extend_wells(self.well_pos)
self.route_inputs() self.route_inputs()
self.route_output() self.route_output()
def create_ptx(self): def add_ptx(self):
""" Create the PMOS and NMOS transistors. """ """ Create the PMOS and NMOS transistors. """
self.nmos = ptx(width=self.nmos_width, self.nmos = ptx(width=self.nmos_width,
mults=self.tx_mults, 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, self.top_bottom_space = max(0.5*self.m1_width + self.m1_space + extra_contact_space,
drc["poly_extend_active"], self.poly_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. """ """ Add vdd/gnd rails to the top and bottom. """
self.add_layout_pin_rect_center(text="gnd", self.add_layout_pin_rect_center(text="gnd",
layer="metal1", layer="metal1",
@ -115,50 +116,67 @@ class pnand3(pgate.pgate):
offset=vector(0.5*self.width,self.height), offset=vector(0.5*self.width,self.height),
width=self.width) 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 to provide maximum routing in channel
""" """
pmos1_pos = vector(self.pmos.active_offset.x, pmos1_pos = vector(self.pmos.active_offset.x,
self.height - self.pmos.active_height - self.top_bottom_space) self.height - self.pmos.active_height - self.top_bottom_space)
self.pmos1_inst=self.add_inst(name="pnand3_pmos1", self.pmos1_inst=self.place_inst(name="pnand3_pmos1",
mod=self.pmos, offset=pmos1_pos)
offset=pmos1_pos)
self.connect_inst(["vdd", "A", "Z", "vdd"])
pmos2_pos = pmos1_pos + self.overlap_offset pmos2_pos = pmos1_pos + self.overlap_offset
self.pmos2_inst = self.add_inst(name="pnand3_pmos2", self.pmos2_inst = self.place_inst(name="pnand3_pmos2",
mod=self.pmos, offset=pmos2_pos)
offset=pmos2_pos)
self.connect_inst(["Z", "B", "vdd", "vdd"])
self.pmos3_pos = pmos2_pos + self.overlap_offset self.pmos3_pos = pmos2_pos + self.overlap_offset
self.pmos3_inst = self.add_inst(name="pnand3_pmos3", self.pmos3_inst = self.place_inst(name="pnand3_pmos3",
mod=self.pmos, offset=self.pmos3_pos)
offset=self.pmos3_pos)
self.connect_inst(["Z", "C", "vdd", "vdd"])
nmos1_pos = vector(self.pmos.active_offset.x, self.top_bottom_space) nmos1_pos = vector(self.pmos.active_offset.x, self.top_bottom_space)
self.nmos1_inst=self.add_inst(name="pnand3_nmos1", self.nmos1_inst=self.place_inst(name="pnand3_nmos1",
mod=self.nmos, offset=nmos1_pos)
offset=nmos1_pos)
self.connect_inst(["Z", "C", "net1", "gnd"])
nmos2_pos = nmos1_pos + self.overlap_offset nmos2_pos = nmos1_pos + self.overlap_offset
self.nmos2_inst=self.add_inst(name="pnand3_nmos2", self.nmos2_inst=self.place_inst(name="pnand3_nmos2",
mod=self.nmos, offset=nmos2_pos)
offset=nmos2_pos)
self.connect_inst(["net1", "B", "net2", "gnd"])
self.nmos3_pos = nmos2_pos + self.overlap_offset self.nmos3_pos = nmos2_pos + self.overlap_offset
self.nmos3_inst=self.add_inst(name="pnand3_nmos3", self.nmos3_inst=self.place_inst(name="pnand3_nmos3",
mod=self.nmos, offset=self.nmos3_pos)
offset=self.nmos3_pos)
self.connect_inst(["net2", "A", "gnd", "gnd"])
# This should be placed at the top of the NMOS well # This should be placed at the top of the NMOS well
self.well_pos = vector(0,self.nmos1_inst.uy()) 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.bitcell_br = bitcell_br
self.create_netlist() 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): def add_pins(self):
self.add_pin_list(["bl", "br", "en", "vdd"]) self.add_pin_list(["bl", "br", "en", "vdd"])
def create_netlist(self): def add_ptx(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):
"""Initializes the upper and lower pmos""" """Initializes the upper and lower pmos"""
self.pmos = ptx(width=self.ptx_width, self.pmos = ptx(width=self.ptx_width,
tx_type="pmos") tx_type="pmos")
self.add_mod(self.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 a vdd rail at the top of the cell"""
# adds the rail across the width of the cell # adds the rail across the width of the cell
vdd_position = vector(0, self.height - self.m1_width) vdd_position = vector(0, self.height - self.m1_width)
@ -87,31 +87,46 @@ class precharge(pgate.pgate):
offset=vdd_pos.scale(0,1)) offset=vdd_pos.scale(0,1))
def add_ptx(self): def create_ptx(self):
"""Adds both the upper_pmos and lower_pmos to the module""" """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 # adds the lower pmos to layout
#base = vector(self.width - 2*self.pmos.width + self.overlap_offset.x, 0) #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.lower_pmos_position = vector(self.bitcell.get_pin(self.bitcell_bl).lx(),
self.pmos.active_offset.y) self.pmos.active_offset.y)
self.lower_pmos_inst=self.add_inst(name="lower_pmos", self.place_inst(name="lower_pmos",
mod=self.pmos, offset=self.lower_pmos_position)
offset=self.lower_pmos_position)
self.connect_inst(["bl", "en", "br", "vdd"])
# adds the upper pmos(s) to layout # adds the upper pmos(s) to layout
ydiff = self.pmos.height + 2*self.m1_space + contact.poly.width 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_pos = self.lower_pmos_position + vector(0, ydiff)
self.upper_pmos1_inst=self.add_inst(name="upper_pmos1", self.place_inst(name="upper_pmos1",
mod=self.pmos, offset=self.upper_pmos1_pos)
offset=self.upper_pmos1_pos)
self.connect_inst(["bl", "en", "vdd", "vdd"])
upper_pmos2_pos = self.upper_pmos1_pos + self.overlap_offset upper_pmos2_pos = self.upper_pmos1_pos + self.overlap_offset
self.upper_pmos2_inst=self.add_inst(name="upper_pmos2", self.place_inst(name="upper_pmos2",
mod=self.pmos, offset=upper_pmos2_pos)
offset=upper_pmos2_pos)
self.connect_inst(["br", "en", "vdd", "vdd"])
def connect_poly(self): def connect_poly(self):
"""Connects the upper and lower pmos together""" """Connects the upper and lower pmos together"""
@ -131,7 +146,7 @@ class precharge(pgate.pgate):
width=xlength, width=xlength,
height=self.poly_width) 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 input rail, en contact/vias, and connects to the pmos"""
# adds the en contact to connect the gates to the en rail on metal1 # 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) offset = self.lower_pmos_inst.get_pin("G").ul() + vector(0,0.5*self.poly_space)
@ -146,7 +161,7 @@ class precharge(pgate.pgate):
end=offset.scale(0,1)+vector(self.width,0)) 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 a nwell tap to connect to the vdd rail"""
# adds the contact from active to metal1 # adds the contact from active to metal1
well_contact_pos = self.upper_pmos1_inst.get_pin("D").center().scale(1,0) \ well_contact_pos = self.upper_pmos1_inst.get_pin("D").center().scale(1,0) \
@ -165,7 +180,7 @@ class precharge(pgate.pgate):
height=self.height) height=self.height)
def add_bitlines(self): def route_bitlines(self):
"""Adds both bit-line and bit-line-bar to the module""" """Adds both bit-line and bit-line-bar to the module"""
# adds the BL on metal 2 # adds the BL on metal 2
offset = vector(self.bitcell.get_pin(self.bitcell_bl).cx(),0) - vector(0.5 * self.m2_width,0) 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 tech import drc, info, spice
from vector import vector from vector import vector
from contact import contact from contact import contact
from globals import OPTS
import path import path
class ptx(design.design): class ptx(design.design):
@ -40,13 +41,9 @@ class ptx(design.design):
self.num_contacts = num_contacts self.num_contacts = num_contacts
self.create_netlist() 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): def create_layout(self):
@ -56,6 +53,11 @@ class ptx(design.design):
self.add_well_implant() self.add_well_implant()
self.add_poly() self.add_poly()
self.add_active_contacts() 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): def create_netlist(self):
self.add_pin_list(["D", "G", "S", "B"]) self.add_pin_list(["D", "G", "S", "B"])

View File

@ -38,18 +38,9 @@ class sram():
debug.error("Invalid number of banks.",-1) debug.error("Invalid number of banks.",-1)
self.s.create_netlist() 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: if not OPTS.is_unit_test:
print_time("SRAM creation", datetime.datetime.now(), start_time) print_time("SRAM creation", datetime.datetime.now(), start_time)

View File

@ -22,18 +22,16 @@ class sram_1bank(sram_base):
def create_netlist(self): def create_netlist(self):
self.compute_sizes() self.compute_sizes()
self.add_modules() sram_base.create_netlist(self)
# Must run this after add modules to get control pin names
self.add_pins()
self.create_modules() self.create_modules()
def create_modules(self): def create_modules(self):
""" """
This adds the modules for a single bank SRAM with control This adds the modules for a single bank SRAM with control
logic. logic.
""" """
self.bank_inst = self.create_bank() self.bank_inst=self.create_bank(0)
self.control_logic_inst = self.create_control_logic() 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.col_addr_dff_inst = self.create_col_addr_dff()
self.data_dff_inst = self.create_data_dff() self.data_dff_inst = self.create_data_dff()
def place_modules(self): def place_modules(self):
""" """
This places the modules for a single bank SRAM with control This places the modules for a single bank SRAM with control
@ -91,8 +89,8 @@ class sram_1bank(sram_base):
offset=data_pos) offset=data_pos)
# two supply rails are already included in the bank, so just 2 here. # 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.width = self.bank.width + self.control_logic.width + 2*self.supply_rail_pitch
self.height = self.bank.height # self.height = self.bank.height
def add_layout_pins(self): def add_layout_pins(self):
""" """

View File

@ -117,16 +117,31 @@ class sram_base(design):
def create_netlist(self): def create_netlist(self):
""" Netlist creation """ """ Netlist creation """
# Must create the control logic before pins to get the pins
self.add_modules() self.add_modules()
self.add_pins() 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): def create_layout(self):
""" Layout creation """ """ Layout creation """
self.place_modules() self.place_modules()
self.route() self.route()
self.add_lvs_correspondence_points() 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): def compute_bus_sizes(self):
""" Compute the independent bus widths shared between two and four bank SRAMs """ """ 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 """ """ Create a bank """
bank_num = len(self.bank_insts)
self.bank_insts.append(self.add_inst(name="bank{0}".format(bank_num), self.bank_insts.append(self.add_inst(name="bank{0}".format(bank_num),
mod=self.bank)) mod=self.bank))