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):
|
||||
""" Transform with offset, mirror and rotation to get the absolute pin location.
|
||||
We must then re-find the ll and ur. The master is the cell instance. """
|
||||
if OPTS.netlist_only:
|
||||
return
|
||||
|
||||
(ll,ur) = [vector(0,0),vector(self.width,self.height)]
|
||||
if mirror=="MX":
|
||||
ll=ll.scale(1,-1)
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@ import debug
|
|||
from tech import drc, GDS
|
||||
from tech import layer as techlayer
|
||||
import os
|
||||
from globals import OPTS
|
||||
from vector import vector
|
||||
from pin_layout import pin_layout
|
||||
import lef
|
||||
|
|
@ -436,6 +437,10 @@ class layout(lef.lef):
|
|||
def gds_read(self):
|
||||
"""Reads a GDSII file in the library and checks if it exists
|
||||
Otherwise, start a new layout for dynamic generation."""
|
||||
if OPTS.netlist_only:
|
||||
self.gds = None
|
||||
return
|
||||
|
||||
# open the gds file if it exists or else create a blank layout
|
||||
if os.path.isfile(self.gds_file):
|
||||
debug.info(3, "opening %s" % self.gds_file)
|
||||
|
|
|
|||
|
|
@ -56,7 +56,8 @@ class bank(design.design):
|
|||
self.prefix=""
|
||||
|
||||
self.create_netlist()
|
||||
self.create_layout()
|
||||
if not OPTS.netlist_only:
|
||||
self.create_layout()
|
||||
|
||||
|
||||
def create_netlist(self):
|
||||
|
|
@ -580,23 +581,25 @@ class bank(design.design):
|
|||
|
||||
def route_bank_select(self):
|
||||
""" Route the bank select logic. """
|
||||
for input_name in self.input_control_signals+["bank_sel"]:
|
||||
self.copy_layout_pin(self.bank_select_inst, input_name)
|
||||
|
||||
for k in range(self.total_ports):
|
||||
for input_name in self.input_control_signals+["bank_sel"]:
|
||||
self.copy_layout_pin(self.bank_select_inst[k], input_name)
|
||||
|
||||
for gated_name in self.control_signals:
|
||||
# Connect the inverter output to the central bus
|
||||
out_pos = self.bank_select_inst[0].get_pin(gated_name).rc()
|
||||
bus_pos = vector(self.bus_xoffset[gated_name].x, out_pos.y)
|
||||
self.add_path("metal3",[out_pos, bus_pos])
|
||||
self.add_via_center(layers=("metal2", "via2", "metal3"),
|
||||
offset=bus_pos,
|
||||
rotate=90)
|
||||
self.add_via_center(layers=("metal1", "via1", "metal2"),
|
||||
offset=out_pos,
|
||||
rotate=90)
|
||||
self.add_via_center(layers=("metal2", "via2", "metal3"),
|
||||
offset=out_pos,
|
||||
rotate=90)
|
||||
for gated_name in self.control_signals:
|
||||
# Connect the inverter output to the central bus
|
||||
out_pos = self.bank_select_inst[k].get_pin(gated_name).rc()
|
||||
bus_pos = vector(self.bus_xoffset[gated_name].x, out_pos.y)
|
||||
self.add_path("metal3",[out_pos, bus_pos])
|
||||
self.add_via_center(layers=("metal2", "via2", "metal3"),
|
||||
offset=bus_pos,
|
||||
rotate=90)
|
||||
self.add_via_center(layers=("metal1", "via1", "metal2"),
|
||||
offset=out_pos,
|
||||
rotate=90)
|
||||
self.add_via_center(layers=("metal2", "via2", "metal3"),
|
||||
offset=out_pos,
|
||||
rotate=90)
|
||||
|
||||
|
||||
def setup_routing_constraints(self):
|
||||
|
|
|
|||
|
|
@ -18,9 +18,29 @@ class bank_select(design.design):
|
|||
def __init__(self, name="bank_select"):
|
||||
design.design.__init__(self, name)
|
||||
|
||||
self.create_netlist()
|
||||
if not OPTS.netlist_only:
|
||||
self.create_layout()
|
||||
|
||||
def create_netlist(self):
|
||||
self.add_pins()
|
||||
self.add_modules()
|
||||
self.create_modules()
|
||||
|
||||
def create_layout(self):
|
||||
self.calculate_module_offsets()
|
||||
self.place_modules()
|
||||
self.route_modules()
|
||||
|
||||
self.DRC_LVS()
|
||||
|
||||
|
||||
def add_pins(self):
|
||||
|
||||
# Number of control lines in the bus
|
||||
self.num_control_lines = 4
|
||||
# The order of the control signals on the control bus:
|
||||
# FIXME: Update for multiport (these names are not right)
|
||||
self.input_control_signals = ["clk_buf", "clk_buf_bar", "w_en0", "s_en0"]
|
||||
# These will be outputs of the gaters if this is multibank
|
||||
self.control_signals = ["gated_"+str for str in self.input_control_signals]
|
||||
|
|
@ -31,14 +51,7 @@ class bank_select(design.design):
|
|||
self.add_pin("vdd","POWER")
|
||||
self.add_pin("gnd","GROUND")
|
||||
|
||||
self.create_modules()
|
||||
self.calculate_module_offsets()
|
||||
self.add_modules()
|
||||
self.route_modules()
|
||||
|
||||
self.DRC_LVS()
|
||||
|
||||
def create_modules(self):
|
||||
def add_modules(self):
|
||||
""" Create modules for later instantiation """
|
||||
# 1x Inverter
|
||||
self.inv = pinv()
|
||||
|
|
@ -67,7 +80,52 @@ class bank_select(design.design):
|
|||
self.height = self.yoffset_maxpoint + 2*self.m1_pitch
|
||||
self.width = self.xoffset_inv + self.inv4x.width
|
||||
|
||||
def add_modules(self):
|
||||
def create_modules(self):
|
||||
|
||||
self.bank_sel_inv=self.add_inst(name="bank_sel_inv",
|
||||
mod=self.inv)
|
||||
self.connect_inst(["bank_sel", "bank_sel_bar", "vdd", "gnd"])
|
||||
|
||||
self.logic_inst = []
|
||||
self.inv_inst = []
|
||||
for i in range(self.num_control_lines):
|
||||
input_name = self.input_control_signals[i]
|
||||
gated_name = self.control_signals[i]
|
||||
name_nand = "nand_{}".format(input_name)
|
||||
name_nor = "nor_{}".format(input_name)
|
||||
name_inv = "inv_{}".format(input_name)
|
||||
|
||||
# These require OR (nor2+inv) gates since they are active low.
|
||||
# (writes occur on clk low)
|
||||
if input_name in ("clk_buf"):
|
||||
|
||||
self.logic_inst.append(self.add_inst(name=name_nor,
|
||||
mod=self.nor2))
|
||||
self.connect_inst([input_name,
|
||||
"bank_sel_bar",
|
||||
gated_name+"_temp_bar",
|
||||
"vdd",
|
||||
"gnd"])
|
||||
|
||||
# the rest are AND (nand2+inv) gates
|
||||
else:
|
||||
self.logic_inst.append(self.add_inst(name=name_nand,
|
||||
mod=self.nand2))
|
||||
self.connect_inst([input_name,
|
||||
"bank_sel",
|
||||
gated_name+"_temp_bar",
|
||||
"vdd",
|
||||
"gnd"])
|
||||
|
||||
# They all get inverters on the output
|
||||
self.inv_inst.append(self.add_inst(name=name_inv,
|
||||
mod=self.inv4x))
|
||||
self.connect_inst([gated_name+"_temp_bar",
|
||||
gated_name,
|
||||
"vdd",
|
||||
"gnd"])
|
||||
|
||||
def place_modules(self):
|
||||
|
||||
# bank select inverter
|
||||
self.bank_select_inv_position = vector(self.xoffset_bank_sel_inv, 0)
|
||||
|
|
@ -78,8 +136,6 @@ class bank_select(design.design):
|
|||
offset=[self.xoffset_bank_sel_inv, 0])
|
||||
self.connect_inst(["bank_sel", "bank_sel_bar", "vdd", "gnd"])
|
||||
|
||||
self.logic_inst = []
|
||||
self.inv_inst = []
|
||||
for i in range(self.num_control_lines):
|
||||
input_name = self.input_control_signals[i]
|
||||
gated_name = self.control_signals[i]
|
||||
|
|
@ -98,40 +154,21 @@ class bank_select(design.design):
|
|||
# (writes occur on clk low)
|
||||
if input_name in ("clk_buf"):
|
||||
|
||||
self.logic_inst.append(self.add_inst(name=name_nor,
|
||||
mod=self.nor2,
|
||||
offset=[self.xoffset_nor, y_offset],
|
||||
mirror=mirror))
|
||||
self.connect_inst([input_name,
|
||||
"bank_sel_bar",
|
||||
gated_name+"_temp_bar",
|
||||
"vdd",
|
||||
"gnd"])
|
||||
|
||||
self.place_inst(name=name_nor,
|
||||
offset=[self.xoffset_nor, y_offset],
|
||||
mirror=mirror)
|
||||
|
||||
# the rest are AND (nand2+inv) gates
|
||||
else:
|
||||
self.logic_inst.append(self.add_inst(name=name_nand,
|
||||
mod=self.nand2,
|
||||
offset=[self.xoffset_nand, y_offset],
|
||||
mirror=mirror))
|
||||
bank_sel_signal = "bank_sel"
|
||||
self.connect_inst([input_name,
|
||||
"bank_sel",
|
||||
gated_name+"_temp_bar",
|
||||
"vdd",
|
||||
"gnd"])
|
||||
self.place_inst(name=name_nand,
|
||||
offset=[self.xoffset_nand, y_offset],
|
||||
mirror=mirror)
|
||||
|
||||
# They all get inverters on the output
|
||||
self.inv_inst.append(self.add_inst(name=name_inv,
|
||||
mod=self.inv4x,
|
||||
offset=[self.xoffset_inv, y_offset],
|
||||
mirror=mirror))
|
||||
self.connect_inst([gated_name+"_temp_bar",
|
||||
gated_name,
|
||||
"vdd",
|
||||
"gnd"])
|
||||
|
||||
self.place_inst(name=name_inv,
|
||||
offset=[self.xoffset_inv, y_offset],
|
||||
mirror=mirror)
|
||||
|
||||
|
||||
def route_modules(self):
|
||||
|
||||
|
|
|
|||
|
|
@ -32,25 +32,25 @@ class bitcell_array(design.design):
|
|||
self.width = self.column_size*self.cell.width + self.m1_width
|
||||
|
||||
self.create_netlist()
|
||||
|
||||
self.create_layout()
|
||||
if not OPTS.netlist_only:
|
||||
self.create_layout()
|
||||
|
||||
# We don't offset this because we need to align
|
||||
# the replica bitcell in the control logic
|
||||
#self.offset_all_coordinates()
|
||||
|
||||
|
||||
def add_pins(self):
|
||||
row_list = self.cell.list_all_wl_names()
|
||||
column_list = self.cell.list_all_bitline_names()
|
||||
|
||||
def create_netlist(self):
|
||||
""" Create and connect the netlist """
|
||||
self.add_pins()
|
||||
|
||||
self.cell_inst = {}
|
||||
for col in range(self.column_size):
|
||||
for cell_column in column_list:
|
||||
self.add_pin(cell_column+"[{0}]".format(col))
|
||||
for row in range(self.row_size):
|
||||
for cell_row in row_list:
|
||||
self.add_pin(cell_row+"[{0}]".format(row))
|
||||
self.add_pin("vdd")
|
||||
self.add_pin("gnd")
|
||||
for row in range(self.row_size):
|
||||
name = "bit_r{0}_c{1}".format(row, col)
|
||||
self.cell_inst[row,col]=self.add_inst(name=name,
|
||||
mod=self.cell)
|
||||
self.connect_inst(self.cell.list_bitcell_pins(col, row))
|
||||
|
||||
def create_layout(self):
|
||||
xoffset = 0.0
|
||||
|
|
@ -75,18 +75,18 @@ class bitcell_array(design.design):
|
|||
self.add_layout_pins()
|
||||
|
||||
self.DRC_LVS()
|
||||
|
||||
def create_netlist(self):
|
||||
""" Create and connect the netlist """
|
||||
self.add_pins()
|
||||
|
||||
self.cell_inst = {}
|
||||
|
||||
def add_pins(self):
|
||||
row_list = self.cell.list_all_wl_names()
|
||||
column_list = self.cell.list_all_bitline_names()
|
||||
for col in range(self.column_size):
|
||||
for row in range(self.row_size):
|
||||
name = "bit_r{0}_c{1}".format(row, col)
|
||||
self.cell_inst[row,col]=self.add_inst(name=name,
|
||||
mod=self.cell)
|
||||
self.connect_inst(self.cell.list_bitcell_pins(col, row))
|
||||
for cell_column in column_list:
|
||||
self.add_pin(cell_column+"[{0}]".format(col))
|
||||
for row in range(self.row_size):
|
||||
for cell_row in row_list:
|
||||
self.add_pin(cell_row+"[{0}]".format(row))
|
||||
self.add_pin("vdd")
|
||||
self.add_pin("gnd")
|
||||
|
||||
|
||||
def add_layout_pins(self):
|
||||
|
|
|
|||
|
|
@ -24,17 +24,26 @@ class control_logic(design.design):
|
|||
debug.info(1, "Creating {}".format(self.name))
|
||||
|
||||
self.num_rows = num_rows
|
||||
self.create_layout()
|
||||
self.DRC_LVS()
|
||||
|
||||
self.create_netlist()
|
||||
if not OPTS.netlist_only:
|
||||
self.create_layout()
|
||||
|
||||
def create_netlist(self):
|
||||
self.setup_signal_busses()
|
||||
self.add_pins()
|
||||
self.add_modules()
|
||||
self.create_modules()
|
||||
|
||||
def create_layout(self):
|
||||
""" Create layout and route between modules """
|
||||
self.setup_layout_offsets()
|
||||
self.add_pins()
|
||||
self.create_modules()
|
||||
self.add_rails()
|
||||
self.add_modules()
|
||||
self.add_routing()
|
||||
self.route_rails()
|
||||
self.place_modules()
|
||||
self.route_all()
|
||||
|
||||
self.add_lvs_correspondence_points()
|
||||
|
||||
self.DRC_LVS()
|
||||
|
||||
|
||||
def add_pins(self):
|
||||
|
|
@ -46,8 +55,8 @@ class control_logic(design.design):
|
|||
self.add_pin("vdd","POWER")
|
||||
self.add_pin("gnd","GROUND")
|
||||
|
||||
def create_modules(self):
|
||||
""" add all the required modules """
|
||||
def add_modules(self):
|
||||
""" Add all the required modules """
|
||||
|
||||
dff = dff_inv()
|
||||
dff_height = dff.height
|
||||
|
|
@ -83,14 +92,8 @@ class control_logic(design.design):
|
|||
self.add_mod(self.replica_bitline)
|
||||
|
||||
|
||||
def setup_layout_offsets(self):
|
||||
""" Setup layout offsets, determine the size of the busses etc """
|
||||
# These aren't for instantiating, but we use them to get the dimensions
|
||||
#self.poly_contact_offset = vector(0.5*contact.poly.width,0.5*contact.poly.height)
|
||||
|
||||
# Have the cell gap leave enough room to route an M2 wire.
|
||||
# Some cells may have pwell/nwell spacing problems too when the wells are different heights.
|
||||
#self.cell_gap = max(self.m2_pitch,drc["pwell_to_nwell"])
|
||||
def setup_signal_busses(self):
|
||||
""" Setup bus names, determine the size of the busses etc """
|
||||
|
||||
# List of input control signals
|
||||
self.input_list =["csb","web"]
|
||||
|
|
@ -104,7 +107,7 @@ class control_logic(design.design):
|
|||
self.supply_list = ["vdd", "gnd"]
|
||||
|
||||
|
||||
def add_rails(self):
|
||||
def route_rails(self):
|
||||
""" Add the input signal inverted tracks """
|
||||
height = 4*self.inv1.height - self.m2_pitch
|
||||
offset = vector(self.ctrl_dff_array.width,0)
|
||||
|
|
@ -112,7 +115,20 @@ class control_logic(design.design):
|
|||
self.rail_offsets = self.create_vertical_bus("metal2", self.m2_pitch, offset, self.internal_bus_list, height)
|
||||
|
||||
|
||||
def add_modules(self):
|
||||
def create_modules(self):
|
||||
""" Create all the modules """
|
||||
self.create_dffs()
|
||||
self.create_clk_row()
|
||||
self.create_we_row()
|
||||
# self.create_trien_row()
|
||||
# self.create_trien_bar_row()
|
||||
self.create_rbl_in_row()
|
||||
self.create_sen_row()
|
||||
self.create_rbl()
|
||||
|
||||
|
||||
|
||||
def place_modules(self):
|
||||
""" Place all the modules """
|
||||
# Keep track of all right-most instances to determine row boundary
|
||||
# and add the vdd/gnd pins
|
||||
|
|
@ -120,20 +136,18 @@ class control_logic(design.design):
|
|||
|
||||
|
||||
# Add the control flops on the left of the bus
|
||||
self.add_dffs()
|
||||
self.place_dffs()
|
||||
|
||||
# Add the logic on the right of the bus
|
||||
self.add_clk_row(row=0) # clk is a double-high cell
|
||||
self.add_we_row(row=2)
|
||||
# self.add_trien_row(row=3)
|
||||
# self.add_trien_bar_row(row=4)
|
||||
self.add_rbl_in_row(row=3)
|
||||
self.add_sen_row(row=4)
|
||||
self.add_rbl(row=5)
|
||||
self.place_clk_row(row=0) # clk is a double-high cell
|
||||
self.place_we_row(row=2)
|
||||
# self.place_trien_row(row=3)
|
||||
# self.place_trien_bar_row(row=4)
|
||||
self.place_rbl_in_row(row=3)
|
||||
self.place_sen_row(row=4)
|
||||
self.place_rbl(row=5)
|
||||
|
||||
|
||||
self.add_lvs_correspondence_points()
|
||||
|
||||
# This offset is used for placement of the control logic in
|
||||
# the SRAM level.
|
||||
self.control_logic_center = vector(self.ctrl_dff_inst.rx(), self.rbl_inst.by())
|
||||
|
|
@ -142,9 +156,9 @@ class control_logic(design.design):
|
|||
self.height = self.rbl_inst.uy() + self.m3_pitch
|
||||
# Max of modules or logic rows
|
||||
self.width = max(self.rbl_inst.rx(), max([inst.rx() for inst in self.row_end_inst])) + self.m2_pitch
|
||||
|
||||
|
||||
|
||||
def add_routing(self):
|
||||
def route_all(self):
|
||||
""" Routing between modules """
|
||||
self.route_dffs()
|
||||
#self.route_trien()
|
||||
|
|
@ -156,84 +170,98 @@ class control_logic(design.design):
|
|||
self.route_supply()
|
||||
|
||||
|
||||
def add_rbl(self,row):
|
||||
""" Add the replica bitline """
|
||||
def create_rbl(self):
|
||||
""" Create the replica bitline """
|
||||
self.rbl_inst=self.add_inst(name="replica_bitline",
|
||||
mod=self.replica_bitline)
|
||||
self.connect_inst(["rbl_in", "pre_s_en", "vdd", "gnd"])
|
||||
|
||||
def place_rbl(self,row):
|
||||
""" Place the replica bitline """
|
||||
y_off = row * self.inv1.height + 2*self.m1_pitch
|
||||
|
||||
# Add the RBL above the rows
|
||||
# Add to the right of the control rows and routing channel
|
||||
self.replica_bitline_offset = vector(0, y_off)
|
||||
self.rbl_inst=self.add_inst(name="replica_bitline",
|
||||
mod=self.replica_bitline,
|
||||
offset=self.replica_bitline_offset)
|
||||
self.connect_inst(["rbl_in", "pre_s_en", "vdd", "gnd"])
|
||||
self.place_inst(name="replica_bitline",
|
||||
offset=self.replica_bitline_offset)
|
||||
|
||||
|
||||
def add_clk_row(self,row):
|
||||
""" Add the multistage clock buffer below the control flops """
|
||||
x_off = self.ctrl_dff_array.width + self.internal_bus_width
|
||||
(y_off,mirror)=self.get_offset(row)
|
||||
|
||||
clkbuf_offset = vector(x_off,y_off)
|
||||
def create_clk_row(self):
|
||||
""" Create the multistage clock buffer """
|
||||
self.clkbuf_inst = self.add_inst(name="clkbuf",
|
||||
mod=self.clkbuf,
|
||||
offset=clkbuf_offset)
|
||||
|
||||
mod=self.clkbuf)
|
||||
self.connect_inst(["clk","clk_buf_bar","clk_buf","vdd","gnd"])
|
||||
|
||||
def place_clk_row(self,row):
|
||||
""" Place the multistage clock buffer below the control flops """
|
||||
x_off = self.ctrl_dff_array.width + self.internal_bus_width
|
||||
(y_off,mirror)=self.get_offset(row)
|
||||
clkbuf_offset = vector(x_off,y_off)
|
||||
self.place_inst(name="clkbuf",
|
||||
offset=clkbuf_offset)
|
||||
self.row_end_inst.append(self.clkbuf_inst)
|
||||
|
||||
|
||||
def add_rbl_in_row(self,row):
|
||||
x_off = self.ctrl_dff_array.width + self.internal_bus_width
|
||||
(y_off,mirror)=self.get_offset(row)
|
||||
|
||||
|
||||
# input: clk_buf_bar,CS output: rbl_in_bar
|
||||
self.rbl_in_bar_offset = vector(x_off, y_off)
|
||||
def create_rbl_in_row(self):
|
||||
self.rbl_in_bar_inst=self.add_inst(name="nand3_rbl_in_bar",
|
||||
mod=self.nand2,
|
||||
offset=self.rbl_in_bar_offset,
|
||||
mirror=mirror)
|
||||
mod=self.nand2)
|
||||
self.connect_inst(["clk_buf_bar", "cs", "rbl_in_bar", "vdd", "gnd"])
|
||||
x_off += self.nand2.width
|
||||
|
||||
# input: rbl_in_bar, output: rbl_in
|
||||
self.rbl_in_offset = vector(x_off, y_off)
|
||||
self.rbl_in_inst=self.add_inst(name="inv_rbl_in",
|
||||
mod=self.inv1,
|
||||
offset=self.rbl_in_offset,
|
||||
mirror=mirror)
|
||||
mod=self.inv1)
|
||||
self.connect_inst(["rbl_in_bar", "rbl_in", "vdd", "gnd"])
|
||||
|
||||
self.row_end_inst.append(self.rbl_in_inst)
|
||||
|
||||
def add_sen_row(self,row):
|
||||
""" The sense enable buffer gets placed to the far right of the
|
||||
row. """
|
||||
|
||||
def place_rbl_in_row(self,row):
|
||||
x_off = self.ctrl_dff_array.width + self.internal_bus_width
|
||||
(y_off,mirror)=self.get_offset(row)
|
||||
|
||||
|
||||
self.rbl_in_bar_offset = vector(x_off, y_off)
|
||||
self.place_inst(name="nand3_rbl_in_bar",
|
||||
offset=self.rbl_in_bar_offset,
|
||||
mirror=mirror)
|
||||
x_off += self.nand2.width
|
||||
|
||||
self.rbl_in_offset = vector(x_off, y_off)
|
||||
self.place_inst(name="inv_rbl_in",
|
||||
offset=self.rbl_in_offset,
|
||||
mirror=mirror)
|
||||
self.row_end_inst.append(self.rbl_in_inst)
|
||||
|
||||
def create_sen_row(self):
|
||||
""" Create the sense enable buffer. """
|
||||
# input: pre_s_en, output: pre_s_en_bar
|
||||
self.pre_s_en_bar_offset = vector(x_off, y_off)
|
||||
self.pre_s_en_bar_inst=self.add_inst(name="inv_pre_s_en_bar",
|
||||
mod=self.inv2,
|
||||
offset=self.pre_s_en_bar_offset,
|
||||
mirror=mirror)
|
||||
mod=self.inv2)
|
||||
self.connect_inst(["pre_s_en", "pre_s_en_bar", "vdd", "gnd"])
|
||||
|
||||
x_off += self.inv2.width
|
||||
|
||||
# BUFFER INVERTERS FOR S_EN
|
||||
# input: input: pre_s_en_bar, output: s_en
|
||||
self.s_en_offset = vector(x_off, y_off)
|
||||
self.s_en_inst=self.add_inst(name="inv_s_en",
|
||||
mod=self.inv8,
|
||||
offset=self.s_en_offset,
|
||||
mirror=mirror)
|
||||
mod=self.inv8)
|
||||
self.connect_inst(["pre_s_en_bar", "s_en0", "vdd", "gnd"])
|
||||
|
||||
def place_sen_row(self,row):
|
||||
"""
|
||||
The sense enable buffer gets placed to the far right of the
|
||||
row.
|
||||
"""
|
||||
x_off = self.ctrl_dff_array.width + self.internal_bus_width
|
||||
(y_off,mirror)=self.get_offset(row)
|
||||
|
||||
self.pre_s_en_bar_offset = vector(x_off, y_off)
|
||||
self.place_inst(name="inv_pre_s_en_bar",
|
||||
offset=self.pre_s_en_bar_offset,
|
||||
mirror=mirror)
|
||||
x_off += self.inv2.width
|
||||
|
||||
self.s_en_offset = vector(x_off, y_off)
|
||||
self.place_inst(name="inv_s_en",
|
||||
offset=self.s_en_offset,
|
||||
mirror=mirror)
|
||||
self.row_end_inst.append(self.s_en_inst)
|
||||
|
||||
|
||||
|
|
@ -256,14 +284,17 @@ class control_logic(design.design):
|
|||
self.copy_layout_pin(self.ctrl_dff_inst, "din[1]", "web")
|
||||
|
||||
|
||||
def add_dffs(self):
|
||||
def create_dffs(self):
|
||||
""" Add the three input DFFs (with inverters) """
|
||||
self.ctrl_dff_inst=self.add_inst(name="ctrl_dffs",
|
||||
mod=self.ctrl_dff_array,
|
||||
offset=vector(0,0))
|
||||
|
||||
mod=self.ctrl_dff_array)
|
||||
self.connect_inst(self.input_list + self.dff_output_list + ["clk_buf"] + self.supply_list)
|
||||
|
||||
def place_dffs(self):
|
||||
""" Place the input DFFs (with inverters) """
|
||||
self.place_inst(name="ctrl_dffs",
|
||||
offset=vector(0,0))
|
||||
|
||||
|
||||
def get_offset(self,row):
|
||||
""" Compute the y-offset and mirroring """
|
||||
|
|
@ -276,48 +307,57 @@ class control_logic(design.design):
|
|||
|
||||
return (y_off,mirror)
|
||||
|
||||
def add_we_row(self,row):
|
||||
def create_we_row(self):
|
||||
# input: WE, CS output: w_en_bar
|
||||
self.w_en_bar_inst=self.add_inst(name="nand3_w_en_bar",
|
||||
mod=self.nand3)
|
||||
self.connect_inst(["clk_buf_bar", "cs", "we", "w_en_bar", "vdd", "gnd"])
|
||||
|
||||
# input: w_en_bar, output: pre_w_en
|
||||
self.pre_w_en_inst=self.add_inst(name="inv_pre_w_en",
|
||||
mod=self.inv1)
|
||||
self.connect_inst(["w_en_bar", "pre_w_en", "vdd", "gnd"])
|
||||
|
||||
# BUFFER INVERTERS FOR W_EN
|
||||
self.pre_w_en_bar_inst=self.add_inst(name="inv_pre_w_en_bar",
|
||||
mod=self.inv2)
|
||||
self.connect_inst(["pre_w_en", "pre_w_en_bar", "vdd", "gnd"])
|
||||
|
||||
self.w_en_inst=self.add_inst(name="inv_w_en2",
|
||||
mod=self.inv8)
|
||||
self.connect_inst(["pre_w_en_bar", "w_en0", "vdd", "gnd"])
|
||||
|
||||
|
||||
def place_we_row(self,row):
|
||||
x_off = self.ctrl_dff_inst.width + self.internal_bus_width
|
||||
(y_off,mirror)=self.get_offset(row)
|
||||
|
||||
# input: WE, CS output: w_en_bar
|
||||
w_en_bar_offset = vector(x_off, y_off)
|
||||
self.w_en_bar_inst=self.add_inst(name="nand3_w_en_bar",
|
||||
mod=self.nand3,
|
||||
offset=w_en_bar_offset,
|
||||
mirror=mirror)
|
||||
self.connect_inst(["clk_buf_bar", "cs", "we", "w_en_bar", "vdd", "gnd"])
|
||||
self.place_inst(name="nand3_w_en_bar",
|
||||
offset=w_en_bar_offset,
|
||||
mirror=mirror)
|
||||
x_off += self.nand3.width
|
||||
|
||||
# input: w_en_bar, output: pre_w_en
|
||||
pre_w_en_offset = vector(x_off, y_off)
|
||||
self.pre_w_en_inst=self.add_inst(name="inv_pre_w_en",
|
||||
mod=self.inv1,
|
||||
offset=pre_w_en_offset,
|
||||
mirror=mirror)
|
||||
|
||||
self.connect_inst(["w_en_bar", "pre_w_en", "vdd", "gnd"])
|
||||
self.place_inst(name="inv_pre_w_en",
|
||||
offset=pre_w_en_offset,
|
||||
mirror=mirror)
|
||||
x_off += self.inv1.width
|
||||
|
||||
# BUFFER INVERTERS FOR W_EN
|
||||
pre_w_en_bar_offset = vector(x_off, y_off)
|
||||
self.pre_w_en_bar_inst=self.add_inst(name="inv_pre_w_en_bar",
|
||||
mod=self.inv2,
|
||||
offset=pre_w_en_bar_offset,
|
||||
mirror=mirror)
|
||||
self.connect_inst(["pre_w_en", "pre_w_en_bar", "vdd", "gnd"])
|
||||
self.place_inst(name="inv_pre_w_en_bar",
|
||||
offset=pre_w_en_bar_offset,
|
||||
mirror=mirror)
|
||||
x_off += self.inv2.width
|
||||
|
||||
w_en_offset = vector(x_off, y_off)
|
||||
self.w_en_inst=self.add_inst(name="inv_w_en2",
|
||||
mod=self.inv8,
|
||||
offset=w_en_offset,
|
||||
mirror=mirror)
|
||||
self.connect_inst(["pre_w_en_bar", "w_en0", "vdd", "gnd"])
|
||||
self.place_inst(name="inv_w_en2",
|
||||
offset=w_en_offset,
|
||||
mirror=mirror)
|
||||
x_off += self.inv8.width
|
||||
|
||||
self.row_end_inst.append(self.w_en_inst)
|
||||
|
||||
|
||||
|
||||
def route_rbl_in(self):
|
||||
""" Connect the logic for the rbl_in generation """
|
||||
|
|
|
|||
|
|
@ -24,14 +24,23 @@ class delay_chain(design.design):
|
|||
# number of inverters including any fanout loads.
|
||||
self.fanout_list = fanout_list
|
||||
|
||||
from importlib import reload
|
||||
c = reload(__import__(OPTS.bitcell))
|
||||
self.mod_bitcell = getattr(c, OPTS.bitcell)
|
||||
self.bitcell = self.mod_bitcell()
|
||||
self.create_netlist()
|
||||
if not OPTS.netlist_only:
|
||||
self.create_layout()
|
||||
|
||||
|
||||
def create_netlist(self):
|
||||
self.add_pins()
|
||||
self.create_module()
|
||||
self.add_inverters()
|
||||
self.add_modules()
|
||||
self.create_inverters()
|
||||
|
||||
def create_layout(self):
|
||||
# Each stage is a a row
|
||||
self.height = len(self.fanout_list)*self.inv.height
|
||||
# The width is determined by the largest fanout plus the driver
|
||||
self.width = (max(self.fanout_list)+1) * self.inv.width
|
||||
|
||||
self.place_inverters()
|
||||
self.route_inverters()
|
||||
self.add_layout_pins()
|
||||
self.DRC_LVS()
|
||||
|
|
@ -43,40 +52,27 @@ class delay_chain(design.design):
|
|||
self.add_pin("vdd")
|
||||
self.add_pin("gnd")
|
||||
|
||||
def create_module(self):
|
||||
""" Add the inverter logical module """
|
||||
def add_modules(self):
|
||||
from importlib import reload
|
||||
c = reload(__import__(OPTS.bitcell))
|
||||
self.mod_bitcell = getattr(c, OPTS.bitcell)
|
||||
self.bitcell = self.mod_bitcell()
|
||||
|
||||
self.inv = pinv(route_output=False)
|
||||
self.add_mod(self.inv)
|
||||
|
||||
# Each stage is a a row
|
||||
self.height = len(self.fanout_list)*self.inv.height
|
||||
# The width is determined by the largest fanout plus the driver
|
||||
self.width = (max(self.fanout_list)+1) * self.inv.width
|
||||
|
||||
|
||||
def add_inverters(self):
|
||||
""" Add the inverters and connect them based on the stage list """
|
||||
def create_inverters(self):
|
||||
""" Create the inverters and connect them based on the stage list """
|
||||
self.driver_inst_list = []
|
||||
self.rightest_load_inst = {}
|
||||
self.load_inst_map = {}
|
||||
for stage_num,fanout_size in zip(range(len(self.fanout_list)),self.fanout_list):
|
||||
if stage_num % 2:
|
||||
inv_mirror = "MX"
|
||||
inv_offset = vector(0, (stage_num+1)* self.inv.height)
|
||||
else:
|
||||
inv_mirror = "R0"
|
||||
inv_offset = vector(0, stage_num * self.inv.height)
|
||||
|
||||
# Add the inverter
|
||||
cur_driver=self.add_inst(name="dinv{}".format(stage_num),
|
||||
mod=self.inv,
|
||||
offset=inv_offset,
|
||||
mirror=inv_mirror)
|
||||
mod=self.inv)
|
||||
# keep track of the inverter instances so we can use them to get the pins
|
||||
self.driver_inst_list.append(cur_driver)
|
||||
|
||||
|
||||
# Hook up the driver
|
||||
if stage_num+1==len(self.fanout_list):
|
||||
stageout_name = "out"
|
||||
|
|
@ -91,11 +87,8 @@ class delay_chain(design.design):
|
|||
# Now add the dummy loads to the right
|
||||
self.load_inst_map[cur_driver]=[]
|
||||
for i in range(fanout_size):
|
||||
inv_offset += vector(self.inv.width,0)
|
||||
cur_load=self.add_inst(name="dload_{0}_{1}".format(stage_num,i),
|
||||
mod=self.inv,
|
||||
offset=inv_offset,
|
||||
mirror=inv_mirror)
|
||||
mod=self.inv)
|
||||
# Fanout stage is always driven by driver and output is disconnected
|
||||
disconnect_name = "n_{0}_{1}".format(stage_num,i)
|
||||
self.connect_inst([stageout_name, disconnect_name, "vdd", "gnd"])
|
||||
|
|
@ -105,6 +98,29 @@ class delay_chain(design.design):
|
|||
else:
|
||||
# Keep track of the last one so we can add the the wire later
|
||||
self.rightest_load_inst[cur_driver]=cur_load
|
||||
|
||||
def place_inverters(self):
|
||||
""" Place the inverters and connect them based on the stage list """
|
||||
for stage_num,fanout_size in zip(range(len(self.fanout_list)),self.fanout_list):
|
||||
if stage_num % 2:
|
||||
inv_mirror = "MX"
|
||||
inv_offset = vector(0, (stage_num+1)* self.inv.height)
|
||||
else:
|
||||
inv_mirror = "R0"
|
||||
inv_offset = vector(0, stage_num * self.inv.height)
|
||||
|
||||
# Add the inverter
|
||||
self.place_inst(name="dinv{}".format(stage_num),
|
||||
offset=inv_offset,
|
||||
mirror=inv_mirror)
|
||||
|
||||
# Now add the dummy loads to the right
|
||||
for i in range(fanout_size):
|
||||
inv_offset += vector(self.inv.width,0)
|
||||
self.place_inst(name="dload_{0}_{1}".format(stage_num,i),
|
||||
offset=inv_offset,
|
||||
mirror=inv_mirror)
|
||||
|
||||
|
||||
def add_route(self, pin1, pin2):
|
||||
""" This guarantees that we route from the top to bottom row correctly. """
|
||||
|
|
|
|||
|
|
@ -20,21 +20,21 @@ class dff_buf_array(design.design):
|
|||
name = "dff_buf_array_{0}x{1}".format(rows, columns)
|
||||
design.design.__init__(self, name)
|
||||
debug.info(1, "Creating {}".format(self.name))
|
||||
|
||||
self.dff = dff_buf.dff_buf(inv1_size, inv2_size)
|
||||
self.add_mod(self.dff)
|
||||
|
||||
self.width = self.columns * self.dff.width
|
||||
self.height = self.rows * self.dff.height
|
||||
|
||||
self.inv1_size = inv1_size
|
||||
self.inv2_size = inv2_size
|
||||
|
||||
self.create_netlist()
|
||||
self.create_layout()
|
||||
if not OPTS.netlist_only:
|
||||
self.create_layout()
|
||||
|
||||
def create_netlist(self):
|
||||
self.add_pins()
|
||||
self.add_dff()
|
||||
self.create_dff_array()
|
||||
|
||||
def create_layout(self):
|
||||
self.width = self.columns * self.dff.width
|
||||
self.height = self.rows * self.dff.height
|
||||
self.place_dff_array()
|
||||
self.add_layout_pins()
|
||||
self.DRC_LVS()
|
||||
|
|
@ -51,6 +51,10 @@ class dff_buf_array(design.design):
|
|||
self.add_pin("vdd")
|
||||
self.add_pin("gnd")
|
||||
|
||||
def add_dff(self):
|
||||
self.dff = dff_buf.dff_buf(self.inv1_size, self.inv2_size)
|
||||
self.add_mod(self.dff)
|
||||
|
||||
def create_dff_array(self):
|
||||
self.dff_insts={}
|
||||
for row in range(self.rows):
|
||||
|
|
|
|||
|
|
@ -18,31 +18,30 @@ class dff_inv(design.design):
|
|||
name = "dff_inv_{0}".format(inv_size)
|
||||
design.design.__init__(self, name)
|
||||
debug.info(1, "Creating {}".format(self.name))
|
||||
|
||||
self.inv_size = inv_size
|
||||
|
||||
# This is specifically for SCMOS where the DFF vdd/gnd rails are more than min width.
|
||||
# This causes a DRC in the pinv which assumes min width rails. This ensures the output
|
||||
# contact does not violate spacing to the rail in the NMOS.
|
||||
debug.check(inv_size>=2, "Inverter must be greater than two for rail spacing DRC rules.")
|
||||
|
||||
from importlib import reload
|
||||
c = reload(__import__(OPTS.dff))
|
||||
self.mod_dff = getattr(c, OPTS.dff)
|
||||
self.dff = self.mod_dff("dff")
|
||||
self.add_mod(self.dff)
|
||||
|
||||
self.inv1 = pinv(size=inv_size,height=self.dff.height)
|
||||
self.add_mod(self.inv1)
|
||||
self.create_netlist()
|
||||
if not OPTS.netlist_only:
|
||||
self.create_layout()
|
||||
|
||||
def create_netlist(self):
|
||||
self.add_pins()
|
||||
self.add_modules()
|
||||
self.create_modules()
|
||||
|
||||
def create_layout(self):
|
||||
self.width = self.dff.width + self.inv1.width
|
||||
self.height = self.dff.height
|
||||
|
||||
self.create_layout()
|
||||
|
||||
def create_layout(self):
|
||||
self.add_pins()
|
||||
self.add_insts()
|
||||
self.place_modules()
|
||||
self.add_wires()
|
||||
self.add_layout_pins()
|
||||
|
||||
self.DRC_LVS()
|
||||
|
||||
def add_pins(self):
|
||||
|
|
@ -53,18 +52,35 @@ class dff_inv(design.design):
|
|||
self.add_pin("vdd")
|
||||
self.add_pin("gnd")
|
||||
|
||||
def add_insts(self):
|
||||
def add_modules(self):
|
||||
from importlib import reload
|
||||
c = reload(__import__(OPTS.dff))
|
||||
self.mod_dff = getattr(c, OPTS.dff)
|
||||
self.dff = self.mod_dff("dff")
|
||||
self.add_mod(self.dff)
|
||||
|
||||
self.inv1 = pinv(size=self.inv_size,height=self.dff.height)
|
||||
self.add_mod(self.inv1)
|
||||
|
||||
def create_modules(self):
|
||||
# Add the DFF
|
||||
self.dff_inst=self.add_inst(name="dff_inv_dff",
|
||||
mod=self.dff,
|
||||
offset=vector(0,0))
|
||||
mod=self.dff)
|
||||
self.connect_inst(["D", "Q", "clk", "vdd", "gnd"])
|
||||
|
||||
# Add INV1 to the right
|
||||
self.inv1_inst=self.add_inst(name="dff_inv_inv1",
|
||||
mod=self.inv1,
|
||||
offset=vector(self.dff_inst.rx(),0))
|
||||
mod=self.inv1)
|
||||
self.connect_inst(["Q", "Qb", "vdd", "gnd"])
|
||||
|
||||
def place_modules(self):
|
||||
# Place the DFF
|
||||
self.place_inst(name="dff_inv_dff",
|
||||
offset=vector(0,0))
|
||||
|
||||
# Place the INV1 to the right
|
||||
self.place_inst(name="dff_inv_inv1",
|
||||
offset=vector(self.dff_inst.rx(),0))
|
||||
|
||||
|
||||
def add_wires(self):
|
||||
|
|
|
|||
|
|
@ -20,21 +20,29 @@ class dff_inv_array(design.design):
|
|||
name = "dff_inv_array_{0}x{1}".format(rows, columns)
|
||||
design.design.__init__(self, name)
|
||||
debug.info(1, "Creating {}".format(self.name))
|
||||
self.inv_size = inv_size
|
||||
|
||||
self.create_netlist()
|
||||
if not OPTS.netlist_only:
|
||||
self.create_layout()
|
||||
|
||||
self.dff = dff_inv.dff_inv(inv_size)
|
||||
self.add_mod(self.dff)
|
||||
|
||||
def create_netlist(self):
|
||||
self.add_pins()
|
||||
self.add_dff()
|
||||
self.create_dff_array()
|
||||
|
||||
def create_layout(self):
|
||||
self.width = self.columns * self.dff.width
|
||||
self.height = self.rows * self.dff.height
|
||||
|
||||
self.create_layout()
|
||||
|
||||
def create_layout(self):
|
||||
self.add_pins()
|
||||
self.create_dff_array()
|
||||
self.place_dff_array()
|
||||
self.add_layout_pins()
|
||||
self.DRC_LVS()
|
||||
|
||||
def add_dff(self):
|
||||
self.dff = dff_inv.dff_inv(self.inv_size)
|
||||
self.add_mod(self.dff)
|
||||
|
||||
def add_pins(self):
|
||||
for row in range(self.rows):
|
||||
for col in range(self.columns):
|
||||
|
|
@ -52,16 +60,8 @@ class dff_inv_array(design.design):
|
|||
for row in range(self.rows):
|
||||
for col in range(self.columns):
|
||||
name = "Xdff_r{0}_c{1}".format(row,col)
|
||||
if (row % 2 == 0):
|
||||
base = vector(col*self.dff.width,row*self.dff.height)
|
||||
mirror = "R0"
|
||||
else:
|
||||
base = vector(col*self.dff.width,(row+1)*self.dff.height)
|
||||
mirror = "MX"
|
||||
self.dff_insts[row,col]=self.add_inst(name=name,
|
||||
mod=self.dff,
|
||||
offset=base,
|
||||
mirror=mirror)
|
||||
mod=self.dff)
|
||||
self.connect_inst([self.get_din_name(row,col),
|
||||
self.get_dout_name(row,col),
|
||||
self.get_dout_bar_name(row,col),
|
||||
|
|
@ -69,6 +69,20 @@ class dff_inv_array(design.design):
|
|||
"vdd",
|
||||
"gnd"])
|
||||
|
||||
def place_dff_array(self):
|
||||
for row in range(self.rows):
|
||||
for col in range(self.columns):
|
||||
name = "Xdff_r{0}_c{1}".format(row,col)
|
||||
if (row % 2 == 0):
|
||||
base = vector(col*self.dff.width,row*self.dff.height)
|
||||
mirror = "R0"
|
||||
else:
|
||||
base = vector(col*self.dff.width,(row+1)*self.dff.height)
|
||||
mirror = "MX"
|
||||
self.place_inst(name=name,
|
||||
offset=base,
|
||||
mirror=mirror)
|
||||
|
||||
def get_din_name(self, row, col):
|
||||
if self.columns == 1:
|
||||
din_name = "din[{0}]".format(row)
|
||||
|
|
|
|||
|
|
@ -37,7 +37,8 @@ class hierarchical_decoder(design.design):
|
|||
(self.no_of_pre2x4,self.no_of_pre3x8)=self.determine_predecodes(self.num_inputs)
|
||||
|
||||
self.create_netlist()
|
||||
self.create_layout()
|
||||
if not OPTS.netlist_only:
|
||||
self.create_layout()
|
||||
|
||||
|
||||
def create_netlist(self):
|
||||
|
|
|
|||
|
|
@ -49,7 +49,7 @@ class hierarchical_predecode(design.design):
|
|||
else:
|
||||
debug.error("Invalid number of predecode inputs: {}".format(inputs),-1)
|
||||
|
||||
def setup_constraints(self):
|
||||
def setup_layout_constraints(self):
|
||||
|
||||
self.height = self.number_of_outputs * self.nand.height
|
||||
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@ import debug
|
|||
import design
|
||||
from vector import vector
|
||||
from hierarchical_predecode import hierarchical_predecode
|
||||
from globals import OPTS
|
||||
|
||||
class hierarchical_predecode2x4(hierarchical_predecode):
|
||||
"""
|
||||
|
|
@ -11,13 +12,13 @@ class hierarchical_predecode2x4(hierarchical_predecode):
|
|||
def __init__(self):
|
||||
hierarchical_predecode.__init__(self, 2)
|
||||
|
||||
self.add_pins()
|
||||
self.create_modules()
|
||||
self.setup_constraints()
|
||||
self.create_netlist()
|
||||
self.create_layout()
|
||||
if not OPTS.netlist_only:
|
||||
self.create_layout()
|
||||
|
||||
def create_netlist(self):
|
||||
self.add_pins()
|
||||
self.create_modules()
|
||||
self.create_input_inverters()
|
||||
self.create_output_inverters()
|
||||
connections =[["inbar[0]", "inbar[1]", "Z[0]", "vdd", "gnd"],
|
||||
|
|
@ -33,6 +34,7 @@ class hierarchical_predecode2x4(hierarchical_predecode):
|
|||
3) a set of M2 rails for the vdd, gnd, inverted inputs, inputs
|
||||
4) a set of NAND gates for inversion
|
||||
"""
|
||||
self.setup_layout_constraints()
|
||||
self.route_rails()
|
||||
self.place_input_inverters()
|
||||
self.place_output_inverters()
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@ import debug
|
|||
import design
|
||||
from vector import vector
|
||||
from hierarchical_predecode import hierarchical_predecode
|
||||
from globals import OPTS
|
||||
|
||||
class hierarchical_predecode3x8(hierarchical_predecode):
|
||||
"""
|
||||
|
|
@ -11,13 +12,13 @@ class hierarchical_predecode3x8(hierarchical_predecode):
|
|||
def __init__(self):
|
||||
hierarchical_predecode.__init__(self, 3)
|
||||
|
||||
self.add_pins()
|
||||
self.create_modules()
|
||||
self.setup_constraints()
|
||||
self.create_netlist()
|
||||
self.create_layout()
|
||||
if not OPTS.netlist_only:
|
||||
self.create_layout()
|
||||
|
||||
def create_netlist(self):
|
||||
self.add_pins()
|
||||
self.create_modules()
|
||||
self.create_input_inverters()
|
||||
self.create_output_inverters()
|
||||
connections=[["inbar[0]", "inbar[1]", "inbar[2]", "Z[0]", "vdd", "gnd"],
|
||||
|
|
@ -38,6 +39,7 @@ class hierarchical_predecode3x8(hierarchical_predecode):
|
|||
3) a set of M2 rails for the vdd, gnd, inverted inputs, inputs
|
||||
4) a set of NAND gates for inversion
|
||||
"""
|
||||
self.setup_layout_constraints()
|
||||
self.route_rails()
|
||||
self.place_input_inverters()
|
||||
self.place_output_inverters()
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@ import debug
|
|||
from tech import drc
|
||||
from vector import vector
|
||||
from precharge import precharge
|
||||
|
||||
from globals import OPTS
|
||||
|
||||
class precharge_array(design.design):
|
||||
"""
|
||||
|
|
@ -24,11 +24,9 @@ class precharge_array(design.design):
|
|||
self.pc_cell = precharge(name="precharge", size=size, bitcell_bl=bitcell_bl, bitcell_br=bitcell_br)
|
||||
self.add_mod(self.pc_cell)
|
||||
|
||||
self.width = self.columns * self.pc_cell.width
|
||||
self.height = self.pc_cell.height
|
||||
|
||||
self.create_netlist()
|
||||
self.create_layout()
|
||||
if not OPTS.netlist_only:
|
||||
self.create_layout()
|
||||
|
||||
def add_pins(self):
|
||||
"""Adds pins for spice file"""
|
||||
|
|
@ -43,6 +41,9 @@ class precharge_array(design.design):
|
|||
self.create_insts()
|
||||
|
||||
def create_layout(self):
|
||||
self.width = self.columns * self.pc_cell.width
|
||||
self.height = self.pc_cell.height
|
||||
|
||||
self.place_insts()
|
||||
self.add_layout_pins()
|
||||
self.DRC_LVS()
|
||||
|
|
|
|||
|
|
@ -24,16 +24,24 @@ class replica_bitline(design.design):
|
|||
|
||||
g = reload(__import__(OPTS.replica_bitcell))
|
||||
self.mod_replica_bitcell = getattr(g, OPTS.replica_bitcell)
|
||||
|
||||
for pin in ["en", "out", "vdd", "gnd"]:
|
||||
self.add_pin(pin)
|
||||
|
||||
self.bitcell_loads = bitcell_loads
|
||||
self.delay_stages = delay_stages
|
||||
self.delay_fanout = delay_fanout
|
||||
|
||||
self.create_modules()
|
||||
self.calculate_module_offsets()
|
||||
self.create_netlist()
|
||||
if not OPTS.netlist_only:
|
||||
self.create_layout()
|
||||
|
||||
def create_netlist(self):
|
||||
for pin in ["en", "out", "vdd", "gnd"]:
|
||||
self.add_pin(pin)
|
||||
self.add_modules()
|
||||
self.create_modules()
|
||||
|
||||
def create_layout(self):
|
||||
self.calculate_module_offsets()
|
||||
self.place_modules()
|
||||
self.route()
|
||||
|
||||
self.offset_all_coordinates()
|
||||
|
|
@ -48,6 +56,7 @@ class replica_bitline(design.design):
|
|||
|
||||
self.DRC_LVS()
|
||||
|
||||
|
||||
def calculate_module_offsets(self):
|
||||
""" Calculate all the module offsets """
|
||||
|
||||
|
|
@ -74,8 +83,8 @@ class replica_bitline(design.design):
|
|||
|
||||
|
||||
|
||||
def create_modules(self):
|
||||
""" Create modules for later instantiation """
|
||||
def add_modules(self):
|
||||
""" Add the modules for later usage """
|
||||
self.bitcell = self.replica_bitcell = self.mod_replica_bitcell()
|
||||
self.add_mod(self.bitcell)
|
||||
|
||||
|
|
@ -93,38 +102,53 @@ class replica_bitline(design.design):
|
|||
self.access_tx = ptx(tx_type="pmos")
|
||||
self.add_mod(self.access_tx)
|
||||
|
||||
def add_modules(self):
|
||||
""" Add all of the module instances in the logical netlist """
|
||||
def create_modules(self):
|
||||
""" Create all of the module instances in the logical netlist """
|
||||
|
||||
# This is the threshold detect inverter on the output of the RBL
|
||||
self.rbl_inv_inst=self.add_inst(name="rbl_inv",
|
||||
mod=self.inv,
|
||||
offset=self.rbl_inv_offset,
|
||||
rotate=180)
|
||||
mod=self.inv)
|
||||
self.connect_inst(["bl[0]", "out", "vdd", "gnd"])
|
||||
|
||||
self.tx_inst=self.add_inst(name="rbl_access_tx",
|
||||
mod=self.access_tx,
|
||||
offset=self.access_tx_offset)
|
||||
mod=self.access_tx)
|
||||
# D, G, S, B
|
||||
self.connect_inst(["vdd", "delayed_en", "bl[0]", "vdd"])
|
||||
# add the well and poly contact
|
||||
|
||||
self.dc_inst=self.add_inst(name="delay_chain",
|
||||
mod=self.delay_chain,
|
||||
offset=self.delay_chain_offset)
|
||||
mod=self.delay_chain)
|
||||
self.connect_inst(["en", "delayed_en", "vdd", "gnd"])
|
||||
|
||||
self.rbc_inst=self.add_inst(name="bitcell",
|
||||
mod=self.replica_bitcell,
|
||||
offset=self.bitcell_offset,
|
||||
mirror="MX")
|
||||
mod=self.replica_bitcell)
|
||||
self.connect_inst(["bl[0]", "br[0]", "delayed_en", "vdd", "gnd"])
|
||||
|
||||
self.rbl_inst=self.add_inst(name="load",
|
||||
mod=self.rbl,
|
||||
offset=self.rbl_offset)
|
||||
mod=self.rbl)
|
||||
self.connect_inst(["bl[0]", "br[0]"] + ["gnd"]*self.bitcell_loads + ["vdd", "gnd"])
|
||||
|
||||
def place_modules(self):
|
||||
""" Add all of the module instances in the logical netlist """
|
||||
|
||||
# This is the threshold detect inverter on the output of the RBL
|
||||
self.place_inst(name="rbl_inv",
|
||||
offset=self.rbl_inv_offset,
|
||||
rotate=180)
|
||||
|
||||
self.place_inst(name="rbl_access_tx",
|
||||
offset=self.access_tx_offset)
|
||||
|
||||
self.place_inst(name="delay_chain",
|
||||
offset=self.delay_chain_offset)
|
||||
|
||||
self.place_inst(name="bitcell",
|
||||
offset=self.bitcell_offset,
|
||||
mirror="MX")
|
||||
|
||||
self.place_inst(name="load",
|
||||
offset=self.rbl_offset)
|
||||
|
||||
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -21,10 +21,21 @@ class wordline_driver(design.design):
|
|||
|
||||
self.rows = rows
|
||||
self.create_netlist()
|
||||
self.create_layout()
|
||||
if not OPTS.netlist_only:
|
||||
self.create_layout()
|
||||
|
||||
def create_netlist(self):
|
||||
self.add_pins()
|
||||
self.add_modules()
|
||||
self.create_drivers()
|
||||
|
||||
def create_layout(self):
|
||||
self.place_drivers()
|
||||
self.route_layout()
|
||||
self.route_vdd_gnd()
|
||||
self.offset_all_coordinates()
|
||||
self.DRC_LVS()
|
||||
|
||||
|
||||
def add_pins(self):
|
||||
# inputs to wordline_driver.
|
||||
for i in range(self.rows):
|
||||
|
|
@ -36,16 +47,6 @@ class wordline_driver(design.design):
|
|||
self.add_pin("vdd")
|
||||
self.add_pin("gnd")
|
||||
|
||||
def create_netlist(self):
|
||||
self.add_pins()
|
||||
self.add_modules()
|
||||
self.create_drivers()
|
||||
|
||||
def create_layout(self):
|
||||
self.place_drivers()
|
||||
self.route_layout()
|
||||
self.route_vdd_gnd()
|
||||
|
||||
|
||||
def add_modules(self):
|
||||
self.inv = pinv()
|
||||
|
|
|
|||
|
|
@ -29,8 +29,10 @@ class pbitcell(pgate.pgate):
|
|||
self.num_read = num_read
|
||||
|
||||
self.create_netlist()
|
||||
self.create_layout()
|
||||
|
||||
if not OPTS.netlist_only:
|
||||
self.create_layout()
|
||||
|
||||
# FIXME: Why is this static set here?
|
||||
pbitcell.width = self.width
|
||||
pbitcell.height = self.height
|
||||
|
||||
|
|
|
|||
|
|
@ -41,40 +41,49 @@ class pinv(pgate.pgate):
|
|||
|
||||
|
||||
self.create_netlist()
|
||||
self.create_layout()
|
||||
if not OPTS.netlist_only:
|
||||
self.create_layout()
|
||||
|
||||
# for run-time, we won't check every transitor DRC/LVS independently
|
||||
# but this may be uncommented for debug purposes
|
||||
#self.DRC_LVS()
|
||||
|
||||
def add_pins(self):
|
||||
""" Adds pins for spice netlist """
|
||||
self.add_pin_list(["A", "Z", "vdd", "gnd"])
|
||||
|
||||
def create_netlist(self):
|
||||
""" Calls all functions related to the generation of the netlist """
|
||||
self.add_pins()
|
||||
self.determine_tx_mults()
|
||||
self.add_ptx()
|
||||
self.create_ptx()
|
||||
|
||||
def create_layout(self):
|
||||
""" Calls all functions related to the generation of the layout """
|
||||
|
||||
self.determine_tx_mults()
|
||||
self.create_ptx()
|
||||
self.setup_layout_constants()
|
||||
self.add_supply_rails()
|
||||
self.add_ptx()
|
||||
self.route_supply_rails()
|
||||
self.place_ptx()
|
||||
self.add_well_contacts()
|
||||
self.extend_wells(self.well_pos)
|
||||
self.connect_rails()
|
||||
self.route_input_gate(self.pmos_inst, self.nmos_inst, self.output_pos.y, "A", rotate=0)
|
||||
self.route_outputs()
|
||||
|
||||
def add_pins(self):
|
||||
""" Adds pins for spice netlist """
|
||||
self.add_pin_list(["A", "Z", "vdd", "gnd"])
|
||||
|
||||
|
||||
def determine_tx_mults(self):
|
||||
"""
|
||||
Determines the number of fingers needed to achieve the size within
|
||||
the height constraint. This may fail if the user has a tight height.
|
||||
"""
|
||||
|
||||
# This may make the result differ when the layout is created...
|
||||
if OPTS.netlist_only:
|
||||
self.tx_mults = 1
|
||||
self.nmos_width = self.nmos_size*drc["minwidth_tx"]
|
||||
self.pmos_width = self.pmos_size*drc["minwidth_tx"]
|
||||
return
|
||||
|
||||
# Do a quick sanity check and bail if unlikely feasible height
|
||||
# Sanity check. can we make an inverter in the height with minimum tx sizes?
|
||||
# Assume we need 3 metal 1 pitches (2 power rails, one between the tx for the drain)
|
||||
|
|
@ -138,7 +147,7 @@ class pinv(pgate.pgate):
|
|||
|
||||
|
||||
|
||||
def create_ptx(self):
|
||||
def add_ptx(self):
|
||||
""" Create the PMOS and NMOS transistors. """
|
||||
self.nmos = ptx(width=self.nmos_width,
|
||||
mults=self.tx_mults,
|
||||
|
|
@ -154,7 +163,7 @@ class pinv(pgate.pgate):
|
|||
connect_active=True)
|
||||
self.add_mod(self.pmos)
|
||||
|
||||
def add_supply_rails(self):
|
||||
def route_supply_rails(self):
|
||||
""" Add vdd/gnd rails to the top and bottom. """
|
||||
self.add_layout_pin_rect_center(text="gnd",
|
||||
layer="metal1",
|
||||
|
|
@ -166,26 +175,36 @@ class pinv(pgate.pgate):
|
|||
offset=vector(0.5*self.width,self.height),
|
||||
width=self.width)
|
||||
|
||||
def add_ptx(self):
|
||||
def create_ptx(self):
|
||||
"""
|
||||
Add PMOS and NMOS to the layout at the upper-most and lowest position
|
||||
Create the PMOS and NMOS netlist.
|
||||
"""
|
||||
|
||||
self.pmos_inst=self.add_inst(name="pinv_pmos",
|
||||
mod=self.pmos)
|
||||
self.connect_inst(["Z", "A", "vdd", "vdd"])
|
||||
|
||||
self.nmos_inst=self.add_inst(name="pinv_nmos",
|
||||
mod=self.nmos)
|
||||
self.connect_inst(["Z", "A", "gnd", "gnd"])
|
||||
|
||||
|
||||
def place_ptx(self):
|
||||
"""
|
||||
Place PMOS and NMOS to the layout at the upper-most and lowest position
|
||||
to provide maximum routing in channel
|
||||
"""
|
||||
|
||||
# place PMOS so it is half a poly spacing down from the top
|
||||
self.pmos_pos = self.pmos.active_offset.scale(1,0) \
|
||||
+ vector(0, self.height-self.pmos.active_height-self.top_bottom_space)
|
||||
self.pmos_inst=self.add_inst(name="pinv_pmos",
|
||||
mod=self.pmos,
|
||||
offset=self.pmos_pos)
|
||||
self.connect_inst(["Z", "A", "vdd", "vdd"])
|
||||
self.place_inst(name="pinv_pmos",
|
||||
offset=self.pmos_pos)
|
||||
|
||||
# place NMOS so that it is half a poly spacing up from the bottom
|
||||
self.nmos_pos = self.nmos.active_offset.scale(1,0) + vector(0,self.top_bottom_space)
|
||||
self.nmos_inst=self.add_inst(name="pinv_nmos",
|
||||
mod=self.nmos,
|
||||
offset=self.nmos_pos)
|
||||
self.connect_inst(["Z", "A", "gnd", "gnd"])
|
||||
self.place_inst(name="pinv_nmos",
|
||||
offset=self.nmos_pos)
|
||||
|
||||
|
||||
# Output position will be in between the PMOS and NMOS drains
|
||||
|
|
|
|||
|
|
@ -36,7 +36,8 @@ class pinvbuf(design.design):
|
|||
debug.info(1, "Creating {}".format(self.name))
|
||||
|
||||
self.create_netlist()
|
||||
self.create_layout()
|
||||
if not OPTS.netlist_only:
|
||||
self.create_layout()
|
||||
|
||||
|
||||
def create_netlist(self):
|
||||
|
|
|
|||
|
|
@ -36,32 +36,34 @@ class pnand2(pgate.pgate):
|
|||
self.tx_mults = 1
|
||||
|
||||
self.create_netlist()
|
||||
self.create_layout()
|
||||
if not OPTS.netlist_only:
|
||||
self.create_layout()
|
||||
#self.DRC_LVS()
|
||||
|
||||
|
||||
def add_pins(self):
|
||||
""" Adds pins for spice netlist """
|
||||
self.add_pin_list(["A", "B", "Z", "vdd", "gnd"])
|
||||
|
||||
|
||||
def create_netlist(self):
|
||||
self.add_pins()
|
||||
self.add_ptx()
|
||||
self.create_ptx()
|
||||
|
||||
def create_layout(self):
|
||||
""" Calls all functions related to the generation of the layout """
|
||||
|
||||
self.create_ptx()
|
||||
self.setup_layout_constants()
|
||||
self.add_supply_rails()
|
||||
self.add_ptx()
|
||||
self.route_supply_rails()
|
||||
self.place_ptx()
|
||||
self.connect_rails()
|
||||
self.add_well_contacts()
|
||||
self.extend_wells(self.well_pos)
|
||||
self.route_inputs()
|
||||
self.route_output()
|
||||
|
||||
def create_ptx(self):
|
||||
def add_pins(self):
|
||||
""" Adds pins for spice netlist """
|
||||
self.add_pin_list(["A", "B", "Z", "vdd", "gnd"])
|
||||
|
||||
|
||||
def add_ptx(self):
|
||||
""" Create the PMOS and NMOS transistors. """
|
||||
self.nmos = ptx(width=self.nmos_width,
|
||||
mults=self.tx_mults,
|
||||
|
|
@ -105,7 +107,7 @@ class pnand2(pgate.pgate):
|
|||
self.top_bottom_space = max(0.5*self.m1_width + self.m1_space + extra_contact_space,
|
||||
drc["poly_extend_active"], self.poly_space)
|
||||
|
||||
def add_supply_rails(self):
|
||||
def route_supply_rails(self):
|
||||
""" Add vdd/gnd rails to the top and bottom. """
|
||||
self.add_layout_pin_rect_center(text="gnd",
|
||||
layer="metal1",
|
||||
|
|
@ -117,37 +119,51 @@ class pnand2(pgate.pgate):
|
|||
offset=vector(0.5*self.width,self.height),
|
||||
width=self.width)
|
||||
|
||||
def add_ptx(self):
|
||||
def create_ptx(self):
|
||||
"""
|
||||
Add PMOS and NMOS to the layout at the upper-most and lowest position
|
||||
Add PMOS and NMOS to the netlist.
|
||||
"""
|
||||
|
||||
self.pmos1_inst=self.add_inst(name="pnand2_pmos1",
|
||||
mod=self.pmos)
|
||||
self.connect_inst(["vdd", "A", "Z", "vdd"])
|
||||
|
||||
self.pmos2_inst = self.add_inst(name="pnand2_pmos2",
|
||||
mod=self.pmos)
|
||||
self.connect_inst(["Z", "B", "vdd", "vdd"])
|
||||
|
||||
self.nmos1_inst=self.add_inst(name="pnand2_nmos1",
|
||||
mod=self.nmos)
|
||||
self.connect_inst(["Z", "B", "net1", "gnd"])
|
||||
|
||||
self.nmos2_inst=self.add_inst(name="pnand2_nmos2",
|
||||
mod=self.nmos)
|
||||
self.connect_inst(["net1", "A", "gnd", "gnd"])
|
||||
|
||||
|
||||
def place_ptx(self):
|
||||
"""
|
||||
Place PMOS and NMOS to the layout at the upper-most and lowest position
|
||||
to provide maximum routing in channel
|
||||
"""
|
||||
|
||||
pmos1_pos = vector(self.pmos.active_offset.x,
|
||||
self.height - self.pmos.active_height - self.top_bottom_space)
|
||||
self.pmos1_inst=self.add_inst(name="pnand2_pmos1",
|
||||
mod=self.pmos,
|
||||
offset=pmos1_pos)
|
||||
self.connect_inst(["vdd", "A", "Z", "vdd"])
|
||||
self.place_inst(name="pnand2_pmos1",
|
||||
offset=pmos1_pos)
|
||||
|
||||
self.pmos2_pos = pmos1_pos + self.overlap_offset
|
||||
self.pmos2_inst = self.add_inst(name="pnand2_pmos2",
|
||||
mod=self.pmos,
|
||||
offset=self.pmos2_pos)
|
||||
self.connect_inst(["Z", "B", "vdd", "vdd"])
|
||||
self.place_inst(name="pnand2_pmos2",
|
||||
offset=self.pmos2_pos)
|
||||
|
||||
|
||||
nmos1_pos = vector(self.pmos.active_offset.x, self.top_bottom_space)
|
||||
self.nmos1_inst=self.add_inst(name="pnand2_nmos1",
|
||||
mod=self.nmos,
|
||||
offset=nmos1_pos)
|
||||
self.connect_inst(["Z", "B", "net1", "gnd"])
|
||||
self.place_inst(name="pnand2_nmos1",
|
||||
offset=nmos1_pos)
|
||||
|
||||
self.nmos2_pos = nmos1_pos + self.overlap_offset
|
||||
self.nmos2_inst=self.add_inst(name="pnand2_nmos2",
|
||||
mod=self.nmos,
|
||||
offset=self.nmos2_pos)
|
||||
self.connect_inst(["net1", "A", "gnd", "gnd"])
|
||||
self.place_inst(name="pnand2_nmos2",
|
||||
offset=self.nmos2_pos)
|
||||
|
||||
# Output position will be in between the PMOS and NMOS
|
||||
self.output_pos = vector(0,0.5*(pmos1_pos.y+nmos1_pos.y+self.nmos.active_height))
|
||||
|
|
|
|||
|
|
@ -39,8 +39,8 @@ class pnand3(pgate.pgate):
|
|||
self.tx_mults = 1
|
||||
|
||||
self.create_netlist()
|
||||
self.create_layout()
|
||||
#self.DRC_LVS()
|
||||
if not OPTS.netlist_only:
|
||||
self.create_layout()
|
||||
|
||||
|
||||
def add_pins(self):
|
||||
|
|
@ -49,21 +49,22 @@ class pnand3(pgate.pgate):
|
|||
|
||||
def create_netlist(self):
|
||||
self.add_pins()
|
||||
self.add_ptx()
|
||||
self.create_ptx()
|
||||
|
||||
def create_layout(self):
|
||||
""" Calls all functions related to the generation of the layout """
|
||||
|
||||
self.create_ptx()
|
||||
self.setup_layout_constants()
|
||||
self.add_supply_rails()
|
||||
self.add_ptx()
|
||||
self.route_supply_rails()
|
||||
self.place_ptx()
|
||||
self.connect_rails()
|
||||
self.add_well_contacts()
|
||||
self.extend_wells(self.well_pos)
|
||||
self.route_inputs()
|
||||
self.route_output()
|
||||
|
||||
def create_ptx(self):
|
||||
def add_ptx(self):
|
||||
""" Create the PMOS and NMOS transistors. """
|
||||
self.nmos = ptx(width=self.nmos_width,
|
||||
mults=self.tx_mults,
|
||||
|
|
@ -103,7 +104,7 @@ class pnand3(pgate.pgate):
|
|||
self.top_bottom_space = max(0.5*self.m1_width + self.m1_space + extra_contact_space,
|
||||
drc["poly_extend_active"], self.poly_space)
|
||||
|
||||
def add_supply_rails(self):
|
||||
def route_supply_rails(self):
|
||||
""" Add vdd/gnd rails to the top and bottom. """
|
||||
self.add_layout_pin_rect_center(text="gnd",
|
||||
layer="metal1",
|
||||
|
|
@ -115,50 +116,67 @@ class pnand3(pgate.pgate):
|
|||
offset=vector(0.5*self.width,self.height),
|
||||
width=self.width)
|
||||
|
||||
def add_ptx(self):
|
||||
def create_ptx(self):
|
||||
"""
|
||||
Add PMOS and NMOS to the layout at the upper-most and lowest position
|
||||
Create the PMOS and NMOS in the netlist.
|
||||
"""
|
||||
|
||||
self.pmos1_inst=self.add_inst(name="pnand3_pmos1",
|
||||
mod=self.pmos)
|
||||
self.connect_inst(["vdd", "A", "Z", "vdd"])
|
||||
|
||||
self.pmos2_inst = self.add_inst(name="pnand3_pmos2",
|
||||
mod=self.pmos)
|
||||
self.connect_inst(["Z", "B", "vdd", "vdd"])
|
||||
|
||||
self.pmos3_inst = self.add_inst(name="pnand3_pmos3",
|
||||
mod=self.pmos)
|
||||
self.connect_inst(["Z", "C", "vdd", "vdd"])
|
||||
|
||||
self.nmos1_inst=self.add_inst(name="pnand3_nmos1",
|
||||
mod=self.nmos)
|
||||
self.connect_inst(["Z", "C", "net1", "gnd"])
|
||||
|
||||
self.nmos2_inst=self.add_inst(name="pnand3_nmos2",
|
||||
mod=self.nmos)
|
||||
self.connect_inst(["net1", "B", "net2", "gnd"])
|
||||
|
||||
self.nmos3_inst=self.add_inst(name="pnand3_nmos3",
|
||||
mod=self.nmos)
|
||||
self.connect_inst(["net2", "A", "gnd", "gnd"])
|
||||
|
||||
|
||||
def place_ptx(self):
|
||||
"""
|
||||
Place the PMOS and NMOS in the layout at the upper-most and lowest position
|
||||
to provide maximum routing in channel
|
||||
"""
|
||||
|
||||
pmos1_pos = vector(self.pmos.active_offset.x,
|
||||
self.height - self.pmos.active_height - self.top_bottom_space)
|
||||
self.pmos1_inst=self.add_inst(name="pnand3_pmos1",
|
||||
mod=self.pmos,
|
||||
offset=pmos1_pos)
|
||||
self.connect_inst(["vdd", "A", "Z", "vdd"])
|
||||
self.pmos1_inst=self.place_inst(name="pnand3_pmos1",
|
||||
offset=pmos1_pos)
|
||||
|
||||
pmos2_pos = pmos1_pos + self.overlap_offset
|
||||
self.pmos2_inst = self.add_inst(name="pnand3_pmos2",
|
||||
mod=self.pmos,
|
||||
offset=pmos2_pos)
|
||||
self.connect_inst(["Z", "B", "vdd", "vdd"])
|
||||
self.pmos2_inst = self.place_inst(name="pnand3_pmos2",
|
||||
offset=pmos2_pos)
|
||||
|
||||
self.pmos3_pos = pmos2_pos + self.overlap_offset
|
||||
self.pmos3_inst = self.add_inst(name="pnand3_pmos3",
|
||||
mod=self.pmos,
|
||||
offset=self.pmos3_pos)
|
||||
self.connect_inst(["Z", "C", "vdd", "vdd"])
|
||||
self.pmos3_inst = self.place_inst(name="pnand3_pmos3",
|
||||
offset=self.pmos3_pos)
|
||||
|
||||
|
||||
nmos1_pos = vector(self.pmos.active_offset.x, self.top_bottom_space)
|
||||
self.nmos1_inst=self.add_inst(name="pnand3_nmos1",
|
||||
mod=self.nmos,
|
||||
offset=nmos1_pos)
|
||||
self.connect_inst(["Z", "C", "net1", "gnd"])
|
||||
self.nmos1_inst=self.place_inst(name="pnand3_nmos1",
|
||||
offset=nmos1_pos)
|
||||
|
||||
nmos2_pos = nmos1_pos + self.overlap_offset
|
||||
self.nmos2_inst=self.add_inst(name="pnand3_nmos2",
|
||||
mod=self.nmos,
|
||||
offset=nmos2_pos)
|
||||
self.connect_inst(["net1", "B", "net2", "gnd"])
|
||||
self.nmos2_inst=self.place_inst(name="pnand3_nmos2",
|
||||
offset=nmos2_pos)
|
||||
|
||||
|
||||
self.nmos3_pos = nmos2_pos + self.overlap_offset
|
||||
self.nmos3_inst=self.add_inst(name="pnand3_nmos3",
|
||||
mod=self.nmos,
|
||||
offset=self.nmos3_pos)
|
||||
self.connect_inst(["net2", "A", "gnd", "gnd"])
|
||||
self.nmos3_inst=self.place_inst(name="pnand3_nmos3",
|
||||
offset=self.nmos3_pos)
|
||||
|
||||
# This should be placed at the top of the NMOS well
|
||||
self.well_pos = vector(0,self.nmos1_inst.uy())
|
||||
|
|
|
|||
|
|
@ -32,38 +32,38 @@ class precharge(pgate.pgate):
|
|||
self.bitcell_br = bitcell_br
|
||||
|
||||
self.create_netlist()
|
||||
self.create_layout()
|
||||
if not OPTS.netlist_only:
|
||||
self.create_layout()
|
||||
|
||||
def create_netlist(self):
|
||||
self.add_pins()
|
||||
self.add_ptx()
|
||||
self.create_ptx()
|
||||
|
||||
def create_layout(self):
|
||||
self.place_ptx()
|
||||
self.connect_poly()
|
||||
self.route_en()
|
||||
self.place_nwell_and_contact()
|
||||
self.route_vdd_rail()
|
||||
self.route_bitlines()
|
||||
self.connect_to_bitlines()
|
||||
self.DRC_LVS()
|
||||
|
||||
def add_pins(self):
|
||||
self.add_pin_list(["bl", "br", "en", "vdd"])
|
||||
|
||||
def create_netlist(self):
|
||||
self.add_pins()
|
||||
|
||||
def create_layout(self):
|
||||
self.create_ptx()
|
||||
self.add_ptx()
|
||||
self.connect_poly()
|
||||
self.add_en()
|
||||
self.add_nwell_and_contact()
|
||||
self.add_vdd_rail()
|
||||
self.add_bitlines()
|
||||
self.connect_to_bitlines()
|
||||
self.DRC_LVS()
|
||||
|
||||
def create_ptx(self):
|
||||
def add_ptx(self):
|
||||
"""Initializes the upper and lower pmos"""
|
||||
self.pmos = ptx(width=self.ptx_width,
|
||||
tx_type="pmos")
|
||||
self.add_mod(self.pmos)
|
||||
|
||||
# Compute the other pmos2 location, but determining offset to overlap the
|
||||
# source and drain pins
|
||||
self.overlap_offset = self.pmos.get_pin("D").ll() - self.pmos.get_pin("S").ll()
|
||||
|
||||
|
||||
|
||||
def add_vdd_rail(self):
|
||||
def route_vdd_rail(self):
|
||||
|
||||
"""Adds a vdd rail at the top of the cell"""
|
||||
# adds the rail across the width of the cell
|
||||
vdd_position = vector(0, self.height - self.m1_width)
|
||||
|
|
@ -87,31 +87,46 @@ class precharge(pgate.pgate):
|
|||
offset=vdd_pos.scale(0,1))
|
||||
|
||||
|
||||
def add_ptx(self):
|
||||
"""Adds both the upper_pmos and lower_pmos to the module"""
|
||||
def create_ptx(self):
|
||||
"""Create both the upper_pmos and lower_pmos to the module"""
|
||||
|
||||
self.lower_pmos_inst=self.add_inst(name="lower_pmos",
|
||||
mod=self.pmos)
|
||||
self.connect_inst(["bl", "en", "br", "vdd"])
|
||||
|
||||
self.upper_pmos1_inst=self.add_inst(name="upper_pmos1",
|
||||
mod=self.pmos)
|
||||
self.connect_inst(["bl", "en", "vdd", "vdd"])
|
||||
|
||||
self.upper_pmos2_inst=self.add_inst(name="upper_pmos2",
|
||||
mod=self.pmos)
|
||||
self.connect_inst(["br", "en", "vdd", "vdd"])
|
||||
|
||||
|
||||
def place_ptx(self):
|
||||
"""Place both the upper_pmos and lower_pmos to the module"""
|
||||
|
||||
# Compute the other pmos2 location, but determining offset to overlap the
|
||||
# source and drain pins
|
||||
self.overlap_offset = self.pmos.get_pin("D").ll() - self.pmos.get_pin("S").ll()
|
||||
|
||||
# adds the lower pmos to layout
|
||||
#base = vector(self.width - 2*self.pmos.width + self.overlap_offset.x, 0)
|
||||
self.lower_pmos_position = vector(self.bitcell.get_pin(self.bitcell_bl).lx(),
|
||||
self.pmos.active_offset.y)
|
||||
self.lower_pmos_inst=self.add_inst(name="lower_pmos",
|
||||
mod=self.pmos,
|
||||
offset=self.lower_pmos_position)
|
||||
self.connect_inst(["bl", "en", "br", "vdd"])
|
||||
self.place_inst(name="lower_pmos",
|
||||
offset=self.lower_pmos_position)
|
||||
|
||||
# adds the upper pmos(s) to layout
|
||||
ydiff = self.pmos.height + 2*self.m1_space + contact.poly.width
|
||||
self.upper_pmos1_pos = self.lower_pmos_position + vector(0, ydiff)
|
||||
self.upper_pmos1_inst=self.add_inst(name="upper_pmos1",
|
||||
mod=self.pmos,
|
||||
offset=self.upper_pmos1_pos)
|
||||
self.connect_inst(["bl", "en", "vdd", "vdd"])
|
||||
self.place_inst(name="upper_pmos1",
|
||||
offset=self.upper_pmos1_pos)
|
||||
|
||||
upper_pmos2_pos = self.upper_pmos1_pos + self.overlap_offset
|
||||
self.upper_pmos2_inst=self.add_inst(name="upper_pmos2",
|
||||
mod=self.pmos,
|
||||
offset=upper_pmos2_pos)
|
||||
self.connect_inst(["br", "en", "vdd", "vdd"])
|
||||
|
||||
self.place_inst(name="upper_pmos2",
|
||||
offset=upper_pmos2_pos)
|
||||
|
||||
def connect_poly(self):
|
||||
"""Connects the upper and lower pmos together"""
|
||||
|
||||
|
|
@ -131,7 +146,7 @@ class precharge(pgate.pgate):
|
|||
width=xlength,
|
||||
height=self.poly_width)
|
||||
|
||||
def add_en(self):
|
||||
def route_en(self):
|
||||
"""Adds the en input rail, en contact/vias, and connects to the pmos"""
|
||||
# adds the en contact to connect the gates to the en rail on metal1
|
||||
offset = self.lower_pmos_inst.get_pin("G").ul() + vector(0,0.5*self.poly_space)
|
||||
|
|
@ -146,7 +161,7 @@ class precharge(pgate.pgate):
|
|||
end=offset.scale(0,1)+vector(self.width,0))
|
||||
|
||||
|
||||
def add_nwell_and_contact(self):
|
||||
def place_nwell_and_contact(self):
|
||||
"""Adds a nwell tap to connect to the vdd rail"""
|
||||
# adds the contact from active to metal1
|
||||
well_contact_pos = self.upper_pmos1_inst.get_pin("D").center().scale(1,0) \
|
||||
|
|
@ -165,7 +180,7 @@ class precharge(pgate.pgate):
|
|||
height=self.height)
|
||||
|
||||
|
||||
def add_bitlines(self):
|
||||
def route_bitlines(self):
|
||||
"""Adds both bit-line and bit-line-bar to the module"""
|
||||
# adds the BL on metal 2
|
||||
offset = vector(self.bitcell.get_pin(self.bitcell_bl).cx(),0) - vector(0.5 * self.m2_width,0)
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@ import debug
|
|||
from tech import drc, info, spice
|
||||
from vector import vector
|
||||
from contact import contact
|
||||
from globals import OPTS
|
||||
import path
|
||||
|
||||
class ptx(design.design):
|
||||
|
|
@ -40,13 +41,9 @@ class ptx(design.design):
|
|||
self.num_contacts = num_contacts
|
||||
|
||||
self.create_netlist()
|
||||
self.create_layout()
|
||||
if not OPTS.netlist_only:
|
||||
self.create_layout()
|
||||
|
||||
self.translate_all(self.active_offset)
|
||||
|
||||
# for run-time, we won't check every transitor DRC independently
|
||||
# but this may be uncommented for debug purposes
|
||||
#self.DRC()
|
||||
|
||||
|
||||
def create_layout(self):
|
||||
|
|
@ -56,6 +53,11 @@ class ptx(design.design):
|
|||
self.add_well_implant()
|
||||
self.add_poly()
|
||||
self.add_active_contacts()
|
||||
self.translate_all(self.active_offset)
|
||||
|
||||
# for run-time, we won't check every transitor DRC independently
|
||||
# but this may be uncommented for debug purposes
|
||||
#self.DRC()
|
||||
|
||||
def create_netlist(self):
|
||||
self.add_pin_list(["D", "G", "S", "B"])
|
||||
|
|
|
|||
|
|
@ -38,18 +38,9 @@ class sram():
|
|||
debug.error("Invalid number of banks.",-1)
|
||||
|
||||
self.s.create_netlist()
|
||||
self.s.create_layout()
|
||||
if not OPTS.netlist_only:
|
||||
self.s.create_layout()
|
||||
|
||||
# Can remove the following, but it helps for debug!
|
||||
self.s.add_lvs_correspondence_points()
|
||||
|
||||
self.s.offset_all_coordinates()
|
||||
highest_coord = self.s.find_highest_coords()
|
||||
self.s.width = highest_coord[0]
|
||||
self.s.height = highest_coord[1]
|
||||
|
||||
self.s.DRC_LVS(final_verification=True)
|
||||
|
||||
if not OPTS.is_unit_test:
|
||||
print_time("SRAM creation", datetime.datetime.now(), start_time)
|
||||
|
||||
|
|
|
|||
|
|
@ -22,18 +22,16 @@ class sram_1bank(sram_base):
|
|||
|
||||
def create_netlist(self):
|
||||
self.compute_sizes()
|
||||
self.add_modules()
|
||||
# Must run this after add modules to get control pin names
|
||||
self.add_pins()
|
||||
sram_base.create_netlist(self)
|
||||
self.create_modules()
|
||||
|
||||
|
||||
def create_modules(self):
|
||||
"""
|
||||
This adds the modules for a single bank SRAM with control
|
||||
logic.
|
||||
"""
|
||||
|
||||
self.bank_inst = self.create_bank()
|
||||
self.bank_inst=self.create_bank(0)
|
||||
|
||||
self.control_logic_inst = self.create_control_logic()
|
||||
|
||||
|
|
@ -43,7 +41,7 @@ class sram_1bank(sram_base):
|
|||
self.col_addr_dff_inst = self.create_col_addr_dff()
|
||||
|
||||
self.data_dff_inst = self.create_data_dff()
|
||||
|
||||
|
||||
def place_modules(self):
|
||||
"""
|
||||
This places the modules for a single bank SRAM with control
|
||||
|
|
@ -91,8 +89,8 @@ class sram_1bank(sram_base):
|
|||
offset=data_pos)
|
||||
|
||||
# two supply rails are already included in the bank, so just 2 here.
|
||||
self.width = self.bank.width + self.control_logic.width + 2*self.supply_rail_pitch
|
||||
self.height = self.bank.height
|
||||
# self.width = self.bank.width + self.control_logic.width + 2*self.supply_rail_pitch
|
||||
# self.height = self.bank.height
|
||||
|
||||
def add_layout_pins(self):
|
||||
"""
|
||||
|
|
|
|||
|
|
@ -117,16 +117,31 @@ class sram_base(design):
|
|||
|
||||
|
||||
def create_netlist(self):
|
||||
""" Netlist creation """
|
||||
""" Netlist creation """
|
||||
|
||||
# Must create the control logic before pins to get the pins
|
||||
self.add_modules()
|
||||
self.add_pins()
|
||||
|
||||
|
||||
# This is for the lib file if we don't create layout
|
||||
self.width=0
|
||||
self.height=0
|
||||
|
||||
def create_layout(self):
|
||||
""" Layout creation """
|
||||
self.place_modules()
|
||||
self.route()
|
||||
self.add_lvs_correspondence_points()
|
||||
|
||||
self.offset_all_coordinates()
|
||||
|
||||
highest_coord = self.find_highest_coords()
|
||||
self.width = highest_coord[0]
|
||||
self.height = highest_coord[1]
|
||||
|
||||
self.DRC_LVS(final_verification=True)
|
||||
|
||||
|
||||
def compute_bus_sizes(self):
|
||||
""" Compute the independent bus widths shared between two and four bank SRAMs """
|
||||
|
||||
|
|
@ -296,9 +311,8 @@ class sram_base(design):
|
|||
|
||||
|
||||
|
||||
def create_bank(self):
|
||||
def create_bank(self,bank_num):
|
||||
""" Create a bank """
|
||||
bank_num = len(self.bank_insts)
|
||||
self.bank_insts.append(self.add_inst(name="bank{0}".format(bank_num),
|
||||
mod=self.bank))
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue