mirror of https://github.com/VLSIDA/OpenRAM.git
Converted all modules to not run create_layout when netlist_only
mode is enabled.
This commit is contained in:
parent
9f051df18d
commit
8664f7a0b8
|
|
@ -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)
|
||||||
|
|
|
||||||
|
|
@ -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)
|
||||||
|
|
|
||||||
|
|
@ -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 gated_name in self.control_signals:
|
for k in range(self.total_ports):
|
||||||
# Connect the inverter output to the central bus
|
for input_name in self.input_control_signals+["bank_sel"]:
|
||||||
out_pos = self.bank_select_inst[0].get_pin(gated_name).rc()
|
self.copy_layout_pin(self.bank_select_inst[k], input_name)
|
||||||
bus_pos = vector(self.bus_xoffset[gated_name].x, out_pos.y)
|
|
||||||
self.add_path("metal3",[out_pos, bus_pos])
|
for gated_name in self.control_signals:
|
||||||
self.add_via_center(layers=("metal2", "via2", "metal3"),
|
# Connect the inverter output to the central bus
|
||||||
offset=bus_pos,
|
out_pos = self.bank_select_inst[k].get_pin(gated_name).rc()
|
||||||
rotate=90)
|
bus_pos = vector(self.bus_xoffset[gated_name].x, out_pos.y)
|
||||||
self.add_via_center(layers=("metal1", "via1", "metal2"),
|
self.add_path("metal3",[out_pos, bus_pos])
|
||||||
offset=out_pos,
|
self.add_via_center(layers=("metal2", "via2", "metal3"),
|
||||||
rotate=90)
|
offset=bus_pos,
|
||||||
self.add_via_center(layers=("metal2", "via2", "metal3"),
|
rotate=90)
|
||||||
offset=out_pos,
|
self.add_via_center(layers=("metal1", "via1", "metal2"),
|
||||||
rotate=90)
|
offset=out_pos,
|
||||||
|
rotate=90)
|
||||||
|
self.add_via_center(layers=("metal2", "via2", "metal3"),
|
||||||
|
offset=out_pos,
|
||||||
|
rotate=90)
|
||||||
|
|
||||||
|
|
||||||
def setup_routing_constraints(self):
|
def setup_routing_constraints(self):
|
||||||
|
|
|
||||||
|
|
@ -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,39 +154,20 @@ 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):
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
@ -76,17 +76,17 @@ class bitcell_array(design.design):
|
||||||
|
|
||||||
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):
|
||||||
|
|
|
||||||
|
|
@ -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())
|
||||||
|
|
@ -144,7 +158,7 @@ class control_logic(design.design):
|
||||||
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 add_routing(self):
|
def route_all(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 add_sen_row(self,row):
|
def place_rbl_in_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)
|
||||||
|
|
||||||
# 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)
|
|
||||||
self.connect_inst(["pre_s_en", "pre_s_en_bar", "vdd", "gnd"])
|
|
||||||
|
|
||||||
x_off += self.inv2.width
|
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_inst=self.add_inst(name="inv_pre_s_en_bar",
|
||||||
|
mod=self.inv2)
|
||||||
|
self.connect_inst(["pre_s_en", "pre_s_en_bar", "vdd", "gnd"])
|
||||||
|
|
||||||
# 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,44 +307,53 @@ 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)
|
||||||
|
|
|
||||||
|
|
@ -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"])
|
||||||
|
|
@ -106,6 +99,29 @@ class delay_chain(design.design):
|
||||||
# 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. """
|
||||||
pin1_pos = pin1.center()
|
pin1_pos = pin1.center()
|
||||||
|
|
|
||||||
|
|
@ -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):
|
||||||
|
|
|
||||||
|
|
@ -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)
|
def create_netlist(self):
|
||||||
self.add_mod(self.inv1)
|
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,19 +52,36 @@ 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):
|
||||||
# Route dff q to inv1 a
|
# Route dff q to inv1 a
|
||||||
|
|
|
||||||
|
|
@ -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.dff = dff_inv.dff_inv(inv_size)
|
self.create_netlist()
|
||||||
self.add_mod(self.dff)
|
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.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)
|
||||||
|
|
|
||||||
|
|
@ -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):
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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()
|
||||||
|
|
|
||||||
|
|
@ -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()
|
||||||
|
|
|
||||||
|
|
@ -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()
|
||||||
|
|
|
||||||
|
|
@ -25,15 +25,23 @@ 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)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -21,7 +21,18 @@ 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()
|
||||||
|
|
||||||
|
|
@ -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()
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -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):
|
||||||
|
|
|
||||||
|
|
@ -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))
|
||||||
|
|
|
||||||
|
|
@ -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())
|
||||||
|
|
|
||||||
|
|
@ -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,30 +87,45 @@ 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)
|
||||||
|
|
|
||||||
|
|
@ -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"])
|
||||||
|
|
|
||||||
|
|
@ -38,17 +38,8 @@ 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)
|
||||||
|
|
|
||||||
|
|
@ -22,9 +22,7 @@ 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):
|
||||||
|
|
@ -33,7 +31,7 @@ class sram_1bank(sram_base):
|
||||||
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()
|
||||||
|
|
||||||
|
|
@ -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):
|
||||||
"""
|
"""
|
||||||
|
|
|
||||||
|
|
@ -118,15 +118,30 @@ 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))
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue