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

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
@ -436,6 +437,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

@ -56,7 +56,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):
@ -580,23 +581,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,7 +80,52 @@ 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):
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
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])
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]
@ -98,40 +154,21 @@ 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"])
self.place_inst(name=name_nor,
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"])
self.place_inst(name=name_nand,
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"])
self.place_inst(name=name_inv,
offset=[self.xoffset_inv, y_offset],
mirror=mirror)
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.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()
def create_netlist(self):
""" Create and connect the netlist """
self.add_pins()
self.cell_inst = {}
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")
for row in range(self.row_size):
name = "bit_r{0}_c{1}".format(row, col)
self.cell_inst[row,col]=self.add_inst(name=name,
mod=self.cell)
self.connect_inst(self.cell.list_bitcell_pins(col, row))
def create_layout(self):
xoffset = 0.0
@ -75,18 +75,18 @@ class bitcell_array(design.design):
self.add_layout_pins()
self.DRC_LVS()
def create_netlist(self):
""" Create and connect the netlist """
self.add_pins()
self.cell_inst = {}
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 row in range(self.row_size):
name = "bit_r{0}_c{1}".format(row, col)
self.cell_inst[row,col]=self.add_inst(name=name,
mod=self.cell)
self.connect_inst(self.cell.list_bitcell_pins(col, row))
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_layout_pins(self):

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,98 @@ 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.place_inst(name="replica_bitline",
offset=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.place_inst(name="clkbuf",
offset=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.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
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.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)
@ -256,14 +284,17 @@ 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.place_inst(name="ctrl_dffs",
offset=vector(0,0))
def get_offset(self,row):
""" Compute the y-offset and mirroring """
@ -276,48 +307,57 @@ 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.place_inst(name="nand3_w_en_bar",
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.place_inst(name="inv_pre_w_en",
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.place_inst(name="inv_pre_w_en_bar",
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.place_inst(name="inv_w_en2",
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_pins()
self.create_module()
self.add_inverters()
self.add_modules()
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
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):
""" 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)
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_dff()
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_dff(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):

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,35 @@ class dff_inv(design.design):
self.add_pin("vdd")
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
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.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):

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_dff()
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_dff(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,20 @@ 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.place_inst(name=name,
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):

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

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

@ -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):
"""
@ -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.add_mod(self.pc_cell)
self.width = self.columns * self.pc_cell.width
self.height = self.pc_cell.height
self.create_netlist()
self.create_layout()
if not OPTS.netlist_only:
self.create_layout()
def add_pins(self):
"""Adds pins for spice file"""
@ -43,6 +41,9 @@ class precharge_array(design.design):
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()

View File

@ -24,16 +24,24 @@ class replica_bitline(design.design):
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):
for pin in ["en", "out", "vdd", "gnd"]:
self.add_pin(pin)
self.add_modules()
self.create_modules()
def create_layout(self):
self.calculate_module_offsets()
self.place_modules()
self.route()
self.offset_all_coordinates()
@ -48,6 +56,7 @@ class replica_bitline(design.design):
self.DRC_LVS()
def calculate_module_offsets(self):
""" Calculate all the module offsets """
@ -74,8 +83,8 @@ class replica_bitline(design.design):
def create_modules(self):
""" Create modules for later instantiation """
def add_modules(self):
""" Add the modules for later usage """
self.bitcell = self.replica_bitcell = self.mod_replica_bitcell()
self.add_mod(self.bitcell)
@ -93,38 +102,53 @@ 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.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.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.DRC_LVS()
def add_pins(self):
# inputs to wordline_driver.
for i in range(self.rows):
@ -36,16 +47,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()

View File

@ -29,8 +29,10 @@ 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

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,36 @@ 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.place_inst(name="pinv_pmos",
offset=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.place_inst(name="pinv_nmos",
offset=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):

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,51 @@ 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.place_inst(name="pnand2_pmos1",
offset=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.place_inst(name="pnand2_pmos2",
offset=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.place_inst(name="pnand2_nmos1",
offset=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.place_inst(name="pnand2_nmos2",
offset=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,67 @@ 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=self.place_inst(name="pnand3_pmos1",
offset=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 = self.place_inst(name="pnand3_pmos2",
offset=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 = self.place_inst(name="pnand3_pmos3",
offset=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=self.place_inst(name="pnand3_nmos1",
offset=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=self.place_inst(name="pnand3_nmos2",
offset=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=self.place_inst(name="pnand3_nmos3",
offset=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,46 @@ 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.place_inst(name="lower_pmos",
offset=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.place_inst(name="upper_pmos1",
offset=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.place_inst(name="upper_pmos2",
offset=upper_pmos2_pos)
def connect_poly(self):
"""Connects the upper and lower pmos together"""
@ -131,7 +146,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 +161,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 +180,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

@ -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
@ -91,8 +89,8 @@ class sram_1bank(sram_base):
offset=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))