Merging branch with PrivateRAM dev

This commit is contained in:
Michael Timothy Grimes 2018-05-18 15:15:31 -07:00
commit b5df0cc30a
84 changed files with 14871 additions and 13447 deletions

View File

@ -30,6 +30,8 @@ class design(hierarchy_spice.spice, hierarchy_layout.layout):
# These modules ensure unique names or have no changes if they
# aren't unique
ok_list = ['ms_flop.ms_flop',
'dff.dff',
'dff_buf.dff_buf',
'bitcell.bitcell',
'contact.contact',
'ptx.ptx',

View File

@ -110,6 +110,14 @@ class geometry:
""" Return the right edge """
return self.boundary[1].x
def cx(self):
""" Return the center x """
return 0.5*(self.boundary[0].x + self.boundary[1].x)
def cy(self):
""" Return the center y """
return 0.5*(self.boundary[0].y + self.boundary[1].y)
class instance(geometry):
"""

View File

@ -178,7 +178,7 @@ class layout(lef.lef):
""" Return the pin or list of pins """
try:
if len(self.pin_map[text])>1:
debug.warning("Should use a pin iterator since more than one pin {}".format(text))
debug.error("Should use a pin iterator since more than one pin {}".format(text),-1)
# If we have one pin, return it and not the list.
# Otherwise, should use get_pins()
return self.pin_map[text][0]
@ -204,7 +204,7 @@ class layout(lef.lef):
new_name = pin.name
self.add_layout_pin(new_name, pin.layer, pin.ll(), pin.width(), pin.height())
def add_layout_pin_center_segment(self, text, layer, start, end):
def add_layout_pin_segment_center(self, text, layer, start, end):
""" Creates a path like pin with center-line convention """
debug.check(start.x==end.x or start.y==end.y,"Cannot have a non-manhatten layout pin.")
@ -228,7 +228,7 @@ class layout(lef.lef):
return self.add_layout_pin(text, layer, ll_offset, width, height)
def add_layout_pin_center_rect(self, text, layer, offset, width=None, height=None):
def add_layout_pin_rect_center(self, text, layer, offset, width=None, height=None):
""" Creates a path like pin with center-line convention """
if width==None:
width=drc["minwidth_{0}".format(layer)]
@ -282,7 +282,7 @@ class layout(lef.lef):
height=height)
self.add_label(text=text,
layer=layer,
offset=offset)
offset=offset+vector(0.5*width,0.5*height))
def add_label(self, text, layer, offset=[0,0],zoom=-1):
@ -544,6 +544,120 @@ class layout(lef.lef):
width=xmax-xmin,
height=ymax-ymin)
def add_power_ring(self, bbox):
"""
Create vdd and gnd power rings around an area of the bounding box argument. Must
have a supply_rail_width and supply_rail_pitch defined as a member variable.
Defines local variables of the left/right/top/bottom vdd/gnd center offsets
for use in other modules..
"""
[ll, ur] = bbox
supply_rail_spacing = self.supply_rail_pitch - self.supply_rail_width
height = (ur.y-ll.y) + 3 * self.supply_rail_pitch - supply_rail_spacing
width = (ur.x-ll.x) + 3 * self.supply_rail_pitch - supply_rail_spacing
# LEFT vertical rails
offset = ll + vector(-2*self.supply_rail_pitch, -2*self.supply_rail_pitch)
left_gnd_pin=self.add_layout_pin(text="gnd",
layer="metal2",
offset=offset,
width=self.supply_rail_width,
height=height)
offset = ll + vector(-1*self.supply_rail_pitch, -1*self.supply_rail_pitch)
left_vdd_pin=self.add_layout_pin(text="vdd",
layer="metal2",
offset=offset,
width=self.supply_rail_width,
height=height)
# RIGHT vertical rails
offset = vector(ur.x,ll.y) + vector(0,-2*self.supply_rail_pitch)
right_gnd_pin = self.add_layout_pin(text="gnd",
layer="metal2",
offset=offset,
width=self.supply_rail_width,
height=height)
offset = vector(ur.x,ll.y) + vector(self.supply_rail_pitch,-1*self.supply_rail_pitch)
right_vdd_pin=self.add_layout_pin(text="vdd",
layer="metal2",
offset=offset,
width=self.supply_rail_width,
height=height)
# BOTTOM horizontal rails
offset = ll + vector(-2*self.supply_rail_pitch, -2*self.supply_rail_pitch)
bottom_gnd_pin=self.add_layout_pin(text="gnd",
layer="metal1",
offset=offset,
width=width,
height=self.supply_rail_width)
offset = ll + vector(-1*self.supply_rail_pitch, -1*self.supply_rail_pitch)
bottom_vdd_pin=self.add_layout_pin(text="vdd",
layer="metal1",
offset=offset,
width=width,
height=self.supply_rail_width)
# TOP horizontal rails
offset = vector(ll.x, ur.y) + vector(-2*self.supply_rail_pitch,0)
top_gnd_pin=self.add_layout_pin(text="gnd",
layer="metal1",
offset=offset,
width=width,
height=self.supply_rail_width)
offset = vector(ll.x, ur.y) + vector(-1*self.supply_rail_pitch, self.supply_rail_pitch)
top_vdd_pin=self.add_layout_pin(text="vdd",
layer="metal1",
offset=offset,
width=width,
height=self.supply_rail_width)
# Remember these for connecting things in the design
self.left_gnd_x_center = left_gnd_pin.cx()
self.left_vdd_x_center = left_vdd_pin.cx()
self.right_gnd_x_center = right_gnd_pin.cx()
self.right_vdd_x_center = right_vdd_pin.cx()
self.bottom_gnd_y_center = bottom_gnd_pin.cy()
self.bottom_vdd_y_center = bottom_vdd_pin.cy()
self.top_gnd_y_center = top_gnd_pin.cy()
self.top_vdd_y_center = top_vdd_pin.cy()
# Find the number of vias for this pitch
self.supply_vias = 1
import contact
while True:
c=contact.contact(("metal1","via1","metal2"), (self.supply_vias, self.supply_vias))
if c.second_layer_width < self.supply_rail_width and c.second_layer_height < self.supply_rail_width:
self.supply_vias += 1
else:
self.supply_vias -= 1
break
via_points = [vector(self.left_gnd_x_center, self.bottom_gnd_y_center),
vector(self.left_gnd_x_center, self.top_gnd_y_center),
vector(self.right_gnd_x_center, self.bottom_gnd_y_center),
vector(self.right_gnd_x_center, self.top_gnd_y_center),
vector(self.left_vdd_x_center, self.bottom_vdd_y_center),
vector(self.left_vdd_x_center, self.top_vdd_y_center),
vector(self.right_vdd_x_center, self.bottom_vdd_y_center),
vector(self.right_vdd_x_center, self.top_vdd_y_center)]
for pt in via_points:
self.add_via_center(layers=("metal1", "via1", "metal2"),
offset=pt,
size = (self.supply_vias, self.supply_vias))
def pdf_write(self, pdf_name):
# NOTE: Currently does not work (Needs further research)
#self.pdf_name = self.name + ".pdf"

View File

@ -60,6 +60,24 @@ class spice(verilog.verilog):
else:
return self.pin_type[name]
def get_inputs(self):
""" These use pin types to determine pin lists. These
may be over-ridden by submodules that didn't use pin directions yet."""
input_list = []
for pin in self.pins:
if self.pin_type[pin]=="INPUT":
input_list.append(pin)
return input_list
def get_outputs(self):
""" These use pin types to determine pin lists. These
may be over-ridden by submodules that didn't use pin directions yet."""
output_list = []
for pin in self.pins:
if self.pin_type[pin]=="OUTPUT":
output_list.append(pin)
return output_list
def add_mod(self, mod):
"""Adds a subckt/submodule to the subckt hierarchy"""
@ -73,6 +91,8 @@ class spice(verilog.verilog):
group of modules are generated."""
if (check and (len(self.insts[-1].mod.pins) != len(args))):
debug.error("Connections: {}".format(self.insts[-1].mod.pins))
debug.error("Connections: {}".format(args))
debug.error("Number of net connections ({0}) does not match last instance ({1})".format(len(self.insts[-1].mod.pins),
len(args)), 1)
self.conns.append(args)

View File

@ -182,10 +182,12 @@ class pin_layout:
width=self.width(),
height=self.height(),
center=False)
# Add the tet in the middle of the pin.
# This fixes some pin label offsetting when GDS gets imported into Magic.
newLayout.addText(text=self.name,
layerNumber=layer[self.layer],
purposeNumber=0,
offsetInMicrons=self.ll(),
offsetInMicrons=self.center(),
magnification=GDS["zoom"],
rotate=None)

View File

@ -51,10 +51,10 @@ def parse_args():
version="OpenRAM")
(options, args) = parser.parse_args(values=OPTS)
# If we don't specify a tech, assume freepdk45.
# If we don't specify a tech, assume scmos.
# This may be overridden when we read a config file though...
if OPTS.tech_name == "":
OPTS.tech_name = "freepdk45"
OPTS.tech_name = "scmos"
# Alias SCMOS to AMI 0.5um
if OPTS.tech_name == "scmos":
OPTS.tech_name = "scn3me_subm"
@ -208,7 +208,16 @@ def cleanup_paths():
debug.info(0,"Preserving temp directory: {}".format(OPTS.openram_temp))
return
if os.path.exists(OPTS.openram_temp):
shutil.rmtree(OPTS.openram_temp, ignore_errors=True)
# This annoyingly means you have to re-cd into the directory each debug iteration
#shutil.rmtree(OPTS.openram_temp, ignore_errors=True)
contents = [os.path.join(OPTS.openram_temp, i) for i in os.listdir(OPTS.openram_temp)]
for i in contents:
if os.path.isfile(i) or os.path.islink(i):
os.remove(i)
else:
shutil.rmtree(i)
def setup_paths():
""" Set up the non-tech related paths. """

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,263 @@
import sys
from tech import drc, parameter
import debug
import design
import contact
from pinv import pinv
from pnand2 import pnand2
from pnor2 import pnor2
from vector import vector
from globals import OPTS
class bank_select(design.design):
"""Create a bank select signal that is combined with an array of
NOR+INV gates to gate the control signals in case of multiple
banks are created in upper level SRAM module
"""
def __init__(self, name="bank_select"):
design.design.__init__(self, name)
# Number of control lines in the bus
self.num_control_lines = 6
# The order of the control signals on the control bus:
self.input_control_signals = ["clk_buf", "tri_en_bar", "tri_en", "clk_buf_bar", "w_en", "s_en"]
# These will be outputs of the gaters if this is multibank
self.control_signals = ["gated_"+str for str in self.input_control_signals]
self.add_pin_list(self.input_control_signals, "INPUT")
self.add_pin("bank_sel")
self.add_pin_list(self.control_signals, "OUTPUT")
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):
""" Create modules for later instantiation """
# 1x Inverter
self.inv = pinv()
self.add_mod(self.inv)
# 4x Inverter
self.inv4x = pinv(4)
self.add_mod(self.inv4x)
self.nor2 = pnor2()
self.add_mod(self.nor2)
self.nand2 = pnand2()
self.add_mod(self.nand2)
def calculate_module_offsets(self):
# M1/M2 routing pitch is based on contacted pitch
self.m1_pitch = contact.m1m2.height + max(self.m1_space,self.m2_space)
self.m2_pitch = contact.m2m3.height + max(self.m2_space,self.m3_space)
self.xoffset_nand = self.inv4x.width + 2*self.m2_pitch + drc["pwell_to_nwell"]
self.xoffset_nor = self.inv4x.width + 2*self.m2_pitch + drc["pwell_to_nwell"]
self.xoffset_inv = max(self.xoffset_nand + self.nand2.width, self.xoffset_nor + self.nor2.width)
self.xoffset_bank_sel_inv = 0
self.xoffset_inputs = 0
self.yoffset_maxpoint = self.num_control_lines * self.inv.height
# Include the M1 pitches for the supply rails and spacing
self.height = self.yoffset_maxpoint + 2*self.m1_pitch
self.width = self.xoffset_inv + self.inv4x.width
def add_modules(self):
# bank select inverter
self.bank_select_inv_position = vector(self.xoffset_bank_sel_inv, 0)
# bank select inverter (must be made unique if more than one OR)
self.bank_sel_inv=self.add_inst(name="bank_sel_inv",
mod=self.inv,
offset=[self.xoffset_bank_sel_inv, 0])
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)
y_offset = self.inv.height * i
if i%2:
y_offset += self.inv.height
mirror = "MX"
else:
mirror = ""
# These require OR (nor2+inv) gates since they are active low.
# (writes occur on clk low)
if input_name in ("clk_buf", "tri_en_bar"):
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"])
# 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"])
# 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"])
def route_modules(self):
# bank_sel is vertical wire
bank_sel_inv_pin = self.bank_sel_inv.get_pin("A")
xoffset_bank_sel = bank_sel_inv_pin.lx()
bank_sel_line_pos = vector(xoffset_bank_sel, 0)
bank_sel_line_end = vector(xoffset_bank_sel, self.yoffset_maxpoint)
self.add_path("metal2", [bank_sel_line_pos, bank_sel_line_end])
self.add_via_center(layers=("metal1","via1","metal2"),
offset=bank_sel_inv_pin.lc())
# Route the pin to the left edge as well
bank_sel_pin_pos=vector(0, 0)
bank_sel_pin_end=vector(bank_sel_line_pos.x, bank_sel_pin_pos.y)
self.add_layout_pin_segment_center(text="bank_sel",
layer="metal3",
start=bank_sel_pin_pos,
end=bank_sel_pin_end)
self.add_via_center(layers=("metal2","via2","metal3"),
offset=bank_sel_pin_end,
rotate=90)
# bank_sel_bar is vertical wire
bank_sel_bar_pin = self.bank_sel_inv.get_pin("Z")
xoffset_bank_sel_bar = bank_sel_bar_pin.rx()
self.add_label_pin(text="bank_sel_bar",
layer="metal2",
offset=vector(xoffset_bank_sel_bar, 0),
height=2*self.inv.height)
self.add_via_center(layers=("metal1","via1","metal2"),
offset=bank_sel_bar_pin.rc())
for i in range(self.num_control_lines):
logic_inst = self.logic_inst[i]
inv_inst = self.inv_inst[i]
input_name = self.input_control_signals[i]
gated_name = self.control_signals[i]
if input_name in ("clk_buf", "tri_en_bar"):
xoffset_bank_signal = xoffset_bank_sel_bar
else:
xoffset_bank_signal = xoffset_bank_sel
# Connect the logic output to inverter input
pre = logic_inst.get_pin("Z").lc()
out_position = logic_inst.get_pin("Z").rc() + vector(0.5*self.m1_width,0)
in_position = inv_inst.get_pin("A").lc() + vector(0.5*self.m1_width,0)
post = inv_inst.get_pin("A").rc()
self.add_path("metal1", [pre, out_position, in_position, post])
# Connect the logic B input to bank_sel/bank_sel_bar
logic_pos = logic_inst.get_pin("B").lc() - vector(0.5*contact.m1m2.height,0)
input_pos = vector(xoffset_bank_signal, logic_pos.y)
self.add_path("metal2",[logic_pos, input_pos])
self.add_via_center(layers=("metal1", "via1", "metal2"),
offset=logic_pos,
rotate=90)
# Connect the logic A input to the input pin
logic_pos = logic_inst.get_pin("A").lc()
input_pos = vector(0,logic_pos.y)
self.add_via_center(layers=("metal1", "via1", "metal2"),
offset=logic_pos,
rotate=90)
self.add_via_center(layers=("metal2", "via2", "metal3"),
offset=logic_pos,
rotate=90)
self.add_layout_pin_segment_center(text=input_name,
layer="metal3",
start=input_pos,
end=logic_pos)
# Add output pins
out_pin = inv_inst.get_pin("Z")
self.add_layout_pin(text=gated_name,
layer=out_pin.layer,
offset=out_pin.ll(),
width=inv_inst.rx() - out_pin.lx(),
height=out_pin.height())
# Find the x offsets for where the vias/pins should be placed
a_xoffset = self.logic_inst[0].lx()
b_xoffset = self.inv_inst[0].lx()
for num in range(self.num_control_lines):
# Route both supplies
for n in ["vdd", "gnd"]:
supply_pin = self.inv_inst[num].get_pin(n)
supply_offset = supply_pin.ll().scale(0,1)
self.add_rect(layer="metal1",
offset=supply_offset,
width=self.width)
# Add pins in two locations
for xoffset in [a_xoffset, b_xoffset]:
pin_pos = vector(xoffset, supply_pin.cy())
self.add_via_center(layers=("metal1", "via1", "metal2"),
offset=pin_pos,
rotate=90)
self.add_via_center(layers=("metal2", "via2", "metal3"),
offset=pin_pos,
rotate=90)
self.add_layout_pin_rect_center(text=n,
layer="metal3",
offset=pin_pos)
# Add vdd/gnd supply rails
gnd_pin = inv_inst.get_pin("gnd")
left_gnd_pos = vector(0, gnd_pin.cy())
self.add_layout_pin_segment_center(text="gnd",
layer="metal1",
start=left_gnd_pos,
end=gnd_pin.rc())
vdd_pin = inv_inst.get_pin("vdd")
left_vdd_pos = vector(0, vdd_pin.cy())
self.add_layout_pin_segment_center(text="vdd",
layer="metal1",
start=left_vdd_pos,
end=vdd_pin.rc())

View File

@ -48,43 +48,43 @@ class bitcell(design.design):
def list_row_pins(self):
# Creates a list of row pins
row_pins = ["wl"]
row_pins = ["WL"]
return row_pins
def list_read_row_pins(self):
# Creates a list of row pins
row_pins = ["wl"]
row_pins = ["WL"]
return row_pins
def list_write_row_pins(self):
# Creates a list of row pins
row_pins = ["wl"]
row_pins = ["WL"]
return row_pins
def list_column_pins(self):
# Creates a list of column pins
column_pins = ["bl", "br"]
column_pins = ["BL", "BR"]
return column_pins
def list_read_column_pins(self):
# Creates a list of column pins
column_pins = ["bl"]
column_pins = ["BL"]
return column_pins
def list_read_bar_column_pins(self):
# Creates a list of column pins
column_pins = ["br"]
column_pins = ["BR"]
return column_pins
def list_write_column_pins(self):
# Creates a list of column pins
column_pins = ["bl"]
column_pins = ["BL"]
return column_pins
def list_write_bar_column_pins(self):
# Creates a list of column pins
column_pins = ["br"]
column_pins = ["BR"]
return column_pins
def analytical_power(self, proc, vdd, temp, load):

View File

@ -179,25 +179,6 @@ class bitcell_array(design.design):
#we do not consider the delay over the wire for now
return self.return_delay(cell_delay.delay+wl_to_cell_delay.delay,
wl_to_cell_delay.slew)
def analytical_power(self, proc, vdd, temp, load):
"""Power of Bitcell array and bitline in nW."""
from tech import drc
# Dynamic Power from Bitline
bl_wire = self.gen_bl_wire()
cell_load = 2 * bl_wire.return_input_cap()
bl_swing = 0.1 #This should probably be defined in the tech file or input
freq = spice["default_event_rate"]
bitline_dynamic = bl_swing*cell_load*vdd*vdd*freq #not sure if calculation is correct
#Calculate the bitcell power which currently only includes leakage
cell_power = self.cell.analytical_power(proc, vdd, temp, load)
#Leakage power grows with entire array and bitlines.
total_power = self.return_power(cell_power.dynamic + bitline_dynamic * self.column_size,
cell_power.leakage * self.column_size * self.row_size)
return total_power
def gen_wl_wire(self):
wl_wire = self.generate_rc_net(int(self.column_size), self.width, drc["minwidth_metal1"])

File diff suppressed because it is too large Load Diff

View File

@ -34,7 +34,7 @@ class delay_chain(design.design):
self.add_pins()
self.create_module()
self.route_inv()
self.route_inverters()
self.add_layout_pins()
self.DRC_LVS()
@ -48,82 +48,69 @@ class delay_chain(design.design):
def create_module(self):
""" Add the inverter logical module """
self.create_inv_list()
self.inv = pinv(route_output=False)
self.add_mod(self.inv)
# half chain length is the width of the layout
# invs are stacked into 2 levels so input/output are close
# extra metal is for the gnd connection U
self.width = self.num_top_half * self.inv.width + 2*drc["metal1_to_metal1"] + 0.5*drc["minwidth_metal1"]
self.height = 2 * self.inv.height
self.height = len(self.fanout_list)*self.inv.height
self.width = (max(self.fanout_list)+1) * self.inv.width
self.add_inv_list()
self.add_inverters()
def create_inv_list(self):
"""
Generate a list of inverters. Each inverter has a stage
number and a flag indicating if it is a dummy load. This is
the order that they will get placed too.
"""
# First stage is always 0 and is not a dummy load
self.inv_list=[[0,False]]
for stage_num,fanout_size in zip(range(len(self.fanout_list)),self.fanout_list):
for i in range(fanout_size-1):
# Add the dummy loads
self.inv_list.append([stage_num+1, True])
# Add the gate to drive the next stage
self.inv_list.append([stage_num+1, False])
def add_inv_list(self):
def add_inverters(self):
""" Add the inverters and connect them based on the stage list """
dummy_load_counter = 1
self.inv_inst_list = []
for i in range(self.num_inverters):
# First place the gates
if i < self.num_top_half:
# add top level that is upside down
inv_offset = vector(i * self.inv.width, 2 * self.inv.height)
inv_mirror="MX"
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:
# add bottom level from right to left
inv_offset = vector((self.num_inverters - i) * self.inv.width, 0)
inv_mirror="MY"
cur_inv=self.add_inst(name="dinv{}".format(i),
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)
# keep track of the inverter instances so we can use them to get the pins
self.inv_inst_list.append(cur_inv)
self.driver_inst_list.append(cur_driver)
# Second connect them logically
cur_stage = self.inv_list[i][0]
next_stage = self.inv_list[i][0]+1
if i == 0:
input = "in"
# Hook up the driver
if stage_num+1==len(self.fanout_list):
stageout_name = "out"
else:
input = "s{}".format(cur_stage)
if i == self.num_inverters-1:
output = "out"
else:
output = "s{}".format(next_stage)
# if the gate is a dummy load don't connect the output
# else reset the counter
if self.inv_list[i][1]:
output = output+"n{0}".format(dummy_load_counter)
dummy_load_counter += 1
stageout_name = "dout_{}".format(stage_num+1)
if stage_num == 0:
stagein_name = "in"
else:
dummy_load_counter = 1
self.connect_inst(args=[input, output, "vdd", "gnd"])
if i != 0:
self.add_via_center(layers=("metal1", "via1", "metal2"),
offset=cur_inv.get_pin("A").center())
stagein_name = "dout_{}".format(stage_num)
self.connect_inst([stagein_name, stageout_name, "vdd", "gnd"])
# 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)
# 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"])
# Keep track of all the loads to connect their inputs as a load
self.load_inst_map[cur_driver].append(cur_load)
else:
# Keep track of the last one so we can add the the wire later
self.rightest_load_inst[cur_driver]=cur_load
def add_route(self, pin1, pin2):
""" This guarantees that we route from the top to bottom row correctly. """
pin1_pos = pin1.center()
@ -135,79 +122,81 @@ class delay_chain(design.design):
# Written this way to guarantee it goes right first if we are switching rows
self.add_path("metal2", [pin1_pos, vector(pin1_pos.x,mid_point.y), mid_point, vector(mid_point.x,pin2_pos.y), pin2_pos])
def route_inv(self):
def route_inverters(self):
""" Add metal routing for each of the fanout stages """
start_inv = end_inv = 0
for fanout in self.fanout_list:
# end inv number depends on the fan out number
end_inv = start_inv + fanout
start_inv_inst = self.inv_inst_list[start_inv]
self.add_via_center(layers=("metal1", "via1", "metal2"),
offset=start_inv_inst.get_pin("Z").center()),
# route from output to first load
start_inv_pin = start_inv_inst.get_pin("Z")
load_inst = self.inv_inst_list[start_inv+1]
load_pin = load_inst.get_pin("A")
self.add_route(start_inv_pin, load_pin)
next_inv = start_inv+2
while next_inv <= end_inv:
prev_load_inst = self.inv_inst_list[next_inv-1]
prev_load_pin = prev_load_inst.get_pin("A")
load_inst = self.inv_inst_list[next_inv]
load_pin = load_inst.get_pin("A")
self.add_route(prev_load_pin, load_pin)
next_inv += 1
# set the start of next one after current end
start_inv = end_inv
for i in range(len(self.driver_inst_list)):
inv = self.driver_inst_list[i]
for load in self.load_inst_map[inv]:
# Drop a via on each A pin
a_pin = load.get_pin("A")
self.add_via_center(layers=("metal1","via1","metal2"),
offset=a_pin.center())
self.add_via_center(layers=("metal2","via2","metal3"),
offset=a_pin.center())
# Route an M3 horizontal wire to the furthest
z_pin = inv.get_pin("Z")
a_pin = inv.get_pin("A")
a_max = self.rightest_load_inst[inv].get_pin("A")
self.add_via_center(layers=("metal1","via1","metal2"),
offset=a_pin.center())
self.add_via_center(layers=("metal1","via1","metal2"),
offset=z_pin.center())
self.add_via_center(layers=("metal2","via2","metal3"),
offset=z_pin.center())
self.add_path("metal3",[z_pin.center(), a_max.center()])
# Route Z to the A of the next stage
if i+1 < len(self.driver_inst_list):
z_pin = inv.get_pin("Z")
next_inv = self.driver_inst_list[i+1]
next_a_pin = next_inv.get_pin("A")
y_mid = (z_pin.cy() + next_a_pin.cy())/2
mid1_point = vector(z_pin.cx(), y_mid)
mid2_point = vector(next_a_pin.cx(), y_mid)
self.add_path("metal2",[z_pin.center(), mid1_point, mid2_point, next_a_pin.center()])
def add_layout_pins(self):
""" Add vdd and gnd rails and the input/output. Connect the gnd rails internally on
the top end with no input/output to obstruct. """
vdd_pin = self.inv.get_pin("vdd")
gnd_pin = self.inv.get_pin("gnd")
for i in range(3):
(offset,y_dir)=self.get_gate_offset(0, self.inv.height, i)
rail_width = self.num_top_half * self.inv.width
if i % 2:
self.add_layout_pin(text="vdd",
layer="metal1",
offset=offset + vdd_pin.ll().scale(1,y_dir),
width=rail_width,
height=drc["minwidth_metal1"])
else:
self.add_layout_pin(text="gnd",
layer="metal1",
offset=offset + gnd_pin.ll().scale(1,y_dir),
width=rail_width,
height=drc["minwidth_metal1"])
# Use the right most parts of the gnd rails and add a U connector
# We still have the two gnd pins, but it is an either-or connect
gnd_pins = self.get_pins("gnd")
gnd_start = gnd_pins[0].rc()
gnd_mid1 = gnd_start + vector(2*drc["metal1_to_metal1"],0)
gnd_end = gnd_pins[1].rc()
gnd_mid2 = gnd_end + vector(2*drc["metal1_to_metal1"],0)
#self.add_wire(("metal1","via1","metal2"), [gnd_start, gnd_mid1, gnd_mid2, gnd_end])
self.add_path("metal1", [gnd_start, gnd_mid1, gnd_mid2, gnd_end])
for driver in self.driver_inst_list:
vdd_pin = driver.get_pin("vdd")
self.add_layout_pin(text="vdd",
layer="metal1",
offset=vdd_pin.ll(),
width=self.width,
height=vdd_pin.height())
gnd_pin = driver.get_pin("gnd")
self.add_layout_pin(text="gnd",
layer="metal1",
offset=gnd_pin.ll(),
width=self.width,
height=gnd_pin.height())
# input is A pin of first inverter
a_pin = self.inv_inst_list[0].get_pin("A")
a_pin = self.driver_inst_list[0].get_pin("A")
self.add_via_center(layers=("metal1","via1","metal2"),
offset=a_pin.center())
self.add_layout_pin(text="in",
layer="metal1",
offset=a_pin.ll(),
width=a_pin.width(),
height=a_pin.height())
layer="metal2",
offset=a_pin.ll().scale(1,0),
height=a_pin.cy())
# output is Z pin of last inverter
z_pin = self.inv_inst_list[-1].get_pin("Z")
self.add_layout_pin(text="out",
layer="metal1",
offset=z_pin.ll().scale(0,1),
width=z_pin.lx())
# output is A pin of last load inverter
last_driver_inst = self.driver_inst_list[-1]
a_pin = self.rightest_load_inst[last_driver_inst].get_pin("A")
self.add_via_center(layers=("metal1","via1","metal2"),
offset=a_pin.center())
mid_point = vector(a_pin.cx()+3*self.m2_width,a_pin.cy())
self.add_path("metal2",[a_pin.center(), mid_point, mid_point.scale(1,0)])
self.add_layout_pin_segment_center(text="out",
layer="metal2",
start=mid_point,
end=mid_point.scale(1,0))

View File

@ -10,7 +10,7 @@ class dff(design.design):
Memory address flip-flop
"""
pin_names = ["d", "q", "clk", "vdd", "gnd"]
pin_names = ["D", "Q", "clk", "vdd", "gnd"]
(width,height) = utils.get_libcell_size("dff", GDS["unit"], layer["boundary"])
pin_map = utils.get_libcell_pins(pin_names, "dff", GDS["unit"], layer["boundary"])

View File

@ -11,7 +11,7 @@ class dff_array(design.design):
Unlike the data flops, these are never spaced out.
"""
def __init__(self, rows, columns, name=""):
def __init__(self, rows, columns, inv1_size=2, inv2_size=4, name=""):
self.rows = rows
self.columns = columns
@ -22,11 +22,11 @@ class dff_array(design.design):
c = reload(__import__(OPTS.dff))
self.mod_dff = getattr(c, OPTS.dff)
self.ms = self.mod_dff("dff")
self.add_mod(self.ms)
self.dff = self.mod_dff("dff")
self.add_mod(self.dff)
self.width = self.columns * self.ms.width
self.height = self.rows * self.ms.height
self.width = self.columns * self.dff.width
self.height = self.rows * self.dff.height
self.create_layout()
@ -37,13 +37,12 @@ class dff_array(design.design):
self.DRC_LVS()
def add_pins(self):
for row in range(self.rows):
for col in range(self.columns):
self.add_pin("din[{0}][{1}]".format(row,col))
for row in range(self.rows):
for col in range(self.columns):
self.add_pin("dout[{0}][{1}]".format(row,col))
#self.add_pin("dout_bar[{0}]".format(i))
for y in range(self.rows):
for x in range(self.columns):
self.add_pin(self.get_din_name(y,x))
for y in range(self.rows):
for x in range(self.columns):
self.add_pin(self.get_dout_name(y,x))
self.add_pin("clk")
self.add_pin("vdd")
self.add_pin("gnd")
@ -54,21 +53,42 @@ class dff_array(design.design):
for x in range(self.columns):
name = "Xdff_r{0}_c{1}".format(y,x)
if (y % 2 == 0):
base = vector(x*self.ms.width,y*self.ms.height)
base = vector(x*self.dff.width,y*self.dff.height)
mirror = "R0"
else:
base = vector(x*self.ms.width,(y+1)*self.ms.height)
base = vector(x*self.dff.width,(y+1)*self.dff.height)
mirror = "MX"
self.dff_insts[x,y]=self.add_inst(name=name,
mod=self.ms,
mod=self.dff,
offset=base,
mirror=mirror)
self.connect_inst(["din[{0}][{1}]".format(x,y),
"dout[{0}][{1}]".format(x,y),
self.connect_inst([self.get_din_name(y,x),
self.get_dout_name(y,x),
"clk",
"vdd",
"gnd"])
def get_din_name(self, row, col):
if self.columns == 1:
din_name = "din[{0}]".format(row)
elif self.rows == 1:
din_name = "din[{0}]".format(col)
else:
din_name = "din[{0}][{1}]".format(row,col)
return din_name
def get_dout_name(self, row, col):
if self.columns == 1:
dout_name = "dout[{0}]".format(row)
elif self.rows == 1:
dout_name = "dout[{0}]".format(col)
else:
dout_name = "dout[{0}][{1}]".format(row,col)
return dout_name
def add_layout_pins(self):
for y in range(self.rows):
@ -91,23 +111,24 @@ class dff_array(design.design):
for y in range(self.rows):
for x in range(self.columns):
din_pin = self.dff_insts[x,y].get_pin("d")
debug.check(din_pin.layer=="metal2","DFF d pin not on metal2")
self.add_layout_pin(text="din[{0}][{1}]".format(x,y),
din_pin = self.dff_insts[x,y].get_pin("D")
debug.check(din_pin.layer=="metal2","DFF D pin not on metal2")
self.add_layout_pin(text=self.get_din_name(y,x),
layer=din_pin.layer,
offset=din_pin.ll(),
width=din_pin.width(),
height=din_pin.height())
dout_pin = self.dff_insts[x,y].get_pin("q")
debug.check(dout_pin.layer=="metal2","DFF q pin not on metal2")
self.add_layout_pin(text="dout[{0}][{1}]".format(x,y),
dout_pin = self.dff_insts[x,y].get_pin("Q")
debug.check(dout_pin.layer=="metal2","DFF Q pin not on metal2")
self.add_layout_pin(text=self.get_dout_name(y,x),
layer=dout_pin.layer,
offset=dout_pin.ll(),
width=dout_pin.width(),
height=dout_pin.height())
# Create vertical spines to a single horizontal rail
clk_pin = self.dff_insts[0,0].get_pin("clk")
debug.check(clk_pin.layer=="metal2","DFF clk pin not on metal2")
@ -120,7 +141,7 @@ class dff_array(design.design):
else:
self.add_layout_pin(text="clk",
layer="metal3",
offset=clk_pin.ll().scale(0,1),
offset=vector(0,0),
width=self.width,
height=self.m3_width)
for x in range(self.columns):
@ -133,9 +154,9 @@ class dff_array(design.design):
height=self.height)
# Drop a via to the M3 pin
self.add_via_center(layers=("metal2","via2","metal3"),
offset=clk_pin.center())
offset=clk_pin.center().scale(1,0))
def analytical_delay(self, slew, load=0.0):
return self.ms.analytical_delay(slew=slew, load=load)
return self.dff.analytical_delay(slew=slew, load=load)

149
compiler/modules/dff_buf.py Normal file
View File

@ -0,0 +1,149 @@
import debug
import design
from tech import drc
from math import log
from vector import vector
from globals import OPTS
from pinv import pinv
class dff_buf(design.design):
"""
This is a simple buffered DFF. The output is buffered
with two inverters, of variable size, to provide q
and qbar. This is to enable driving large fanout loads.
"""
def __init__(self, inv1_size=2, inv2_size=4, name=""):
if name=="":
name = "dff_buf_{0}_{1}".format(inv1_size, inv2_size)
design.design.__init__(self, name)
debug.info(1, "Creating {}".format(self.name))
c = reload(__import__(OPTS.dff))
self.mod_dff = getattr(c, OPTS.dff)
self.dff = self.mod_dff("dff")
self.add_mod(self.dff)
self.inv1 = pinv(size=inv1_size,height=self.dff.height)
self.add_mod(self.inv1)
self.inv2 = pinv(size=inv2_size,height=self.dff.height)
self.add_mod(self.inv2)
self.width = self.dff.width + self.inv1.width + self.inv2.width
self.height = self.dff.height
self.create_layout()
def create_layout(self):
self.add_pins()
self.add_insts()
self.add_wires()
self.add_layout_pins()
self.DRC_LVS()
def add_pins(self):
self.add_pin("D")
self.add_pin("Q")
self.add_pin("Qb")
self.add_pin("clk")
self.add_pin("vdd")
self.add_pin("gnd")
def add_insts(self):
# Add the DFF
self.dff_inst=self.add_inst(name="dff_buf_dff",
mod=self.dff,
offset=vector(0,0))
self.connect_inst(["D", "qint", "clk", "vdd", "gnd"])
# Add INV1 to the right
self.inv1_inst=self.add_inst(name="dff_buf_inv1",
mod=self.inv1,
offset=vector(self.dff_inst.rx(),0))
self.connect_inst(["qint", "Qb", "vdd", "gnd"])
# Add INV2 to the right
self.inv2_inst=self.add_inst(name="dff_buf_inv2",
mod=self.inv2,
offset=vector(self.inv1_inst.rx(),0))
self.connect_inst(["Qb", "Q", "vdd", "gnd"])
def add_wires(self):
# Route dff q to inv1 a
q_pin = self.dff_inst.get_pin("Q")
a1_pin = self.inv1_inst.get_pin("A")
mid_x_offset = 0.5*(a1_pin.cx() + q_pin.cx())
mid1 = vector(mid_x_offset, q_pin.cy())
mid2 = vector(mid_x_offset, a1_pin.cy())
self.add_path("metal3",
[q_pin.center(), mid1, mid2, a1_pin.center()])
self.add_via_center(layers=("metal2","via2","metal3"),
offset=q_pin.center())
self.add_via_center(layers=("metal2","via2","metal3"),
offset=a1_pin.center())
self.add_via_center(layers=("metal1","via1","metal2"),
offset=a1_pin.center())
# Route inv1 z to inv2 a
z1_pin = self.inv1_inst.get_pin("Z")
a2_pin = self.inv2_inst.get_pin("A")
mid_point = vector(z1_pin.cx(), a2_pin.cy())
self.add_path("metal1", [z1_pin.center(), mid_point, a2_pin.center()])
def add_layout_pins(self):
# Continous vdd rail along with label.
vdd_pin=self.dff_inst.get_pin("vdd")
self.add_layout_pin(text="vdd",
layer="metal1",
offset=vdd_pin.ll(),
width=self.width,
height=vdd_pin.height())
# Continous gnd rail along with label.
gnd_pin=self.dff_inst.get_pin("gnd")
self.add_layout_pin(text="gnd",
layer="metal1",
offset=gnd_pin.ll(),
width=self.width,
height=vdd_pin.height())
clk_pin = self.dff_inst.get_pin("clk")
self.add_layout_pin(text="clk",
layer=clk_pin.layer,
offset=clk_pin.ll(),
width=clk_pin.width(),
height=clk_pin.height())
din_pin = self.dff_inst.get_pin("D")
self.add_layout_pin(text="D",
layer=din_pin.layer,
offset=din_pin.ll(),
width=din_pin.width(),
height=din_pin.height())
dout_pin = self.inv2_inst.get_pin("Z")
self.add_layout_pin_rect_center(text="Q",
layer="metal2",
offset=dout_pin.center())
self.add_via_center(layers=("metal1","via1","metal2"),
offset=dout_pin.center())
dout_pin = self.inv2_inst.get_pin("A")
self.add_layout_pin_rect_center(text="Qb",
layer="metal2",
offset=dout_pin.center())
self.add_via_center(layers=("metal1","via1","metal2"),
offset=dout_pin.center())
def analytical_delay(self, slew, load=0.0):
""" Calculate the analytical delay of DFF-> INV -> INV """
dff_delay=self.dff.analytical_delay(slew=slew, load=self.inv1.input_load())
inv1_delay = self.inv1.analytical_delay(slew=dff_delay.slew, load=self.inv2.input_load())
inv2_delay = self.inv2.analytical_delay(slew=inv1_delay.slew, load=load)
return dff_delay + inv1_delay + inv2_delay

View File

@ -0,0 +1,191 @@
import debug
import design
from tech import drc
from math import log
from vector import vector
from globals import OPTS
import dff_buf
class dff_buf_array(design.design):
"""
This is a simple row (or multiple rows) of flops.
Unlike the data flops, these are never spaced out.
"""
def __init__(self, rows, columns, inv1_size=2, inv2_size=4, name=""):
self.rows = rows
self.columns = columns
if name=="":
name = "dff_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.create_layout()
def create_layout(self):
self.add_pins()
self.create_dff_array()
self.add_layout_pins()
self.DRC_LVS()
def add_pins(self):
for y in range(self.rows):
for x in range(self.columns):
self.add_pin(self.get_din_name(y,x))
for y in range(self.rows):
for x in range(self.columns):
self.add_pin(self.get_dout_name(y,x))
self.add_pin(self.get_dout_bar_name(y,x))
self.add_pin("clk")
self.add_pin("vdd")
self.add_pin("gnd")
def create_dff_array(self):
self.dff_insts={}
for y in range(self.rows):
for x in range(self.columns):
name = "Xdff_r{0}_c{1}".format(y,x)
if (y % 2 == 0):
base = vector(x*self.dff.width,y*self.dff.height)
mirror = "R0"
else:
base = vector(x*self.dff.width,(y+1)*self.dff.height)
mirror = "MX"
self.dff_insts[x,y]=self.add_inst(name=name,
mod=self.dff,
offset=base,
mirror=mirror)
self.connect_inst([self.get_din_name(y,x),
self.get_dout_name(y,x),
self.get_dout_bar_name(y,x),
"clk",
"vdd",
"gnd"])
def get_din_name(self, row, col):
if self.columns == 1:
din_name = "din[{0}]".format(row)
elif self.rows == 1:
din_name = "din[{0}]".format(col)
else:
din_name = "din[{0}][{1}]".format(row,col)
return din_name
def get_dout_name(self, row, col):
if self.columns == 1:
dout_name = "dout[{0}]".format(row)
elif self.rows == 1:
dout_name = "dout[{0}]".format(col)
else:
dout_name = "dout[{0}][{1}]".format(row,col)
return dout_name
def get_dout_bar_name(self, row, col):
if self.columns == 1:
dout_bar_name = "dout_bar[{0}]".format(row)
elif self.rows == 1:
dout_bar_name = "dout_bar[{0}]".format(col)
else:
dout_bar_name = "dout_bar[{0}][{1}]".format(row,col)
return dout_bar_name
def add_layout_pins(self):
xoffsets = []
for x in range(self.columns):
xoffsets.append(self.dff_insts[x,0].get_pin("gnd").lx())
for y in range(self.rows):
# Route both supplies
for n in ["vdd", "gnd"]:
supply_pin = self.dff_insts[0,y].get_pin(n)
supply_offset = supply_pin.ll()
self.add_rect(layer="metal1",
offset=supply_offset,
width=self.width)
# Add pins in two locations
for xoffset in xoffsets:
pin_pos = vector(xoffset, supply_pin.cy())
self.add_via_center(layers=("metal1", "via1", "metal2"),
offset=pin_pos,
rotate=90)
self.add_via_center(layers=("metal2", "via2", "metal3"),
offset=pin_pos,
rotate=90)
self.add_layout_pin_rect_center(text=n,
layer="metal3",
offset=pin_pos)
for y in range(self.rows):
for x in range(self.columns):
din_pin = self.dff_insts[x,y].get_pin("D")
debug.check(din_pin.layer=="metal2","DFF D pin not on metal2")
self.add_layout_pin(text=self.get_din_name(y,x),
layer=din_pin.layer,
offset=din_pin.ll(),
width=din_pin.width(),
height=din_pin.height())
dout_pin = self.dff_insts[x,y].get_pin("Q")
debug.check(dout_pin.layer=="metal2","DFF Q pin not on metal2")
self.add_layout_pin(text=self.get_dout_name(y,x),
layer=dout_pin.layer,
offset=dout_pin.ll(),
width=dout_pin.width(),
height=dout_pin.height())
dout_bar_pin = self.dff_insts[x,y].get_pin("Qb")
debug.check(dout_bar_pin.layer=="metal2","DFF Qb pin not on metal2")
self.add_layout_pin(text=self.get_dout_bar_name(y,x),
layer=dout_bar_pin.layer,
offset=dout_bar_pin.ll(),
width=dout_bar_pin.width(),
height=dout_bar_pin.height())
# Create vertical spines to a single horizontal rail
clk_pin = self.dff_insts[0,0].get_pin("clk")
debug.check(clk_pin.layer=="metal2","DFF clk pin not on metal2")
if self.columns==1:
self.add_layout_pin(text="clk",
layer="metal2",
offset=clk_pin.ll().scale(1,0),
width=self.m2_width,
height=self.height)
else:
self.add_layout_pin(text="clk",
layer="metal3",
offset=vector(0,2*self.m2_width),
width=self.width,
height=self.m3_width)
for x in range(self.columns):
clk_pin = self.dff_insts[x,0].get_pin("clk")
# Make a vertical strip for each column
self.add_layout_pin(text="clk",
layer="metal2",
offset=clk_pin.ll().scale(1,0),
width=self.m2_width,
height=self.height)
# Drop a via to the M3 pin
self.add_via_center(layers=("metal2","via2","metal3"),
offset=clk_pin.center().scale(1,0) + vector(0,2*self.m2_width))
def analytical_delay(self, slew, load=0.0):
return self.dff.analytical_delay(slew=slew, load=load)

132
compiler/modules/dff_inv.py Normal file
View File

@ -0,0 +1,132 @@
import debug
import design
from tech import drc
from math import log
from vector import vector
from globals import OPTS
from pinv import pinv
class dff_inv(design.design):
"""
This is a simple DFF with an inverted output. Some DFFs
do not have Qbar, so this will create it.
"""
def __init__(self, inv_size=1, name=""):
if name=="":
name = "dff_inv_{0}".format(inv_size)
design.design.__init__(self, name)
debug.info(1, "Creating {}".format(self.name))
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.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.add_wires()
self.add_layout_pins()
self.DRC_LVS()
def add_pins(self):
self.add_pin("D")
self.add_pin("Q")
self.add_pin("Qb")
self.add_pin("clk")
self.add_pin("vdd")
self.add_pin("gnd")
def add_insts(self):
# Add the DFF
self.dff_inst=self.add_inst(name="dff_inv_dff",
mod=self.dff,
offset=vector(0,0))
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))
self.connect_inst(["Q", "Qb", "vdd", "gnd"])
def add_wires(self):
# Route dff q to inv1 a
q_pin = self.dff_inst.get_pin("Q")
a1_pin = self.inv1_inst.get_pin("A")
mid_x_offset = 0.5*(a1_pin.cx() + q_pin.cx())
mid1 = vector(mid_x_offset, q_pin.cy())
mid2 = vector(mid_x_offset, a1_pin.cy())
self.add_path("metal3",
[q_pin.center(), mid1, mid2, a1_pin.center()])
self.add_via_center(layers=("metal2","via2","metal3"),
offset=q_pin.center())
self.add_via_center(layers=("metal2","via2","metal3"),
offset=a1_pin.center())
self.add_via_center(layers=("metal1","via1","metal2"),
offset=a1_pin.center())
def add_layout_pins(self):
# Continous vdd rail along with label.
vdd_pin=self.dff_inst.get_pin("vdd")
self.add_layout_pin(text="vdd",
layer="metal1",
offset=vdd_pin.ll(),
width=self.width,
height=vdd_pin.height())
# Continous gnd rail along with label.
gnd_pin=self.dff_inst.get_pin("gnd")
self.add_layout_pin(text="gnd",
layer="metal1",
offset=gnd_pin.ll(),
width=self.width,
height=vdd_pin.height())
clk_pin = self.dff_inst.get_pin("clk")
self.add_layout_pin(text="clk",
layer=clk_pin.layer,
offset=clk_pin.ll(),
width=clk_pin.width(),
height=clk_pin.height())
din_pin = self.dff_inst.get_pin("D")
self.add_layout_pin(text="D",
layer=din_pin.layer,
offset=din_pin.ll(),
width=din_pin.width(),
height=din_pin.height())
dout_pin = self.dff_inst.get_pin("Q")
self.add_layout_pin_rect_center(text="Q",
layer=dout_pin.layer,
offset=dout_pin.center())
dout_pin = self.inv1_inst.get_pin("Z")
self.add_layout_pin_rect_center(text="Qb",
layer="metal2",
offset=dout_pin.center())
self.add_via_center(layers=("metal1","via1","metal2"),
offset=dout_pin.center())
def analytical_delay(self, slew, load=0.0):
""" Calculate the analytical delay of DFF-> INV -> INV """
dff_delay=self.dff.analytical_delay(slew=slew, load=self.inv1.input_load())
inv1_delay = self.inv1.analytical_delay(slew=dff_delay.slew, load=load)
return dff_delay + inv1_delay

View File

@ -0,0 +1,180 @@
import debug
import design
from tech import drc
from math import log
from vector import vector
from globals import OPTS
import dff_inv
class dff_inv_array(design.design):
"""
This is a simple row (or multiple rows) of flops.
Unlike the data flops, these are never spaced out.
"""
def __init__(self, rows, columns, inv_size=2, name=""):
self.rows = rows
self.columns = columns
if name=="":
name = "dff_array_{0}x{1}".format(rows, columns)
design.design.__init__(self, name)
debug.info(1, "Creating {}".format(self.name))
self.dff = dff_inv.dff_inv(inv_size)
self.add_mod(self.dff)
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.add_layout_pins()
self.DRC_LVS()
def add_pins(self):
for y in range(self.rows):
for x in range(self.columns):
self.add_pin(self.get_din_name(y,x))
for y in range(self.rows):
for x in range(self.columns):
self.add_pin(self.get_dout_name(y,x))
self.add_pin(self.get_dout_bar_name(y,x))
self.add_pin("clk")
self.add_pin("vdd")
self.add_pin("gnd")
def create_dff_array(self):
self.dff_insts={}
for y in range(self.rows):
for x in range(self.columns):
name = "Xdff_r{0}_c{1}".format(y,x)
if (y % 2 == 0):
base = vector(x*self.dff.width,y*self.dff.height)
mirror = "R0"
else:
base = vector(x*self.dff.width,(y+1)*self.dff.height)
mirror = "MX"
self.dff_insts[x,y]=self.add_inst(name=name,
mod=self.dff,
offset=base,
mirror=mirror)
self.connect_inst([self.get_din_name(y,x),
self.get_dout_name(y,x),
self.get_dout_bar_name(y,x),
"clk",
"vdd",
"gnd"])
def get_din_name(self, row, col):
if self.columns == 1:
din_name = "din[{0}]".format(row)
elif self.rows == 1:
din_name = "din[{0}]".format(col)
else:
din_name = "din[{0}][{1}]".format(row,col)
return din_name
def get_dout_name(self, row, col):
if self.columns == 1:
dout_name = "dout[{0}]".format(row)
elif self.rows == 1:
dout_name = "dout[{0}]".format(col)
else:
dout_name = "dout[{0}][{1}]".format(row,col)
return dout_name
def get_dout_bar_name(self, row, col):
if self.columns == 1:
dout_bar_name = "dout_bar[{0}]".format(row)
elif self.rows == 1:
dout_bar_name = "dout_bar[{0}]".format(col)
else:
dout_bar_name = "dout_bar[{0}][{1}]".format(row,col)
return dout_bar_name
def add_layout_pins(self):
for y in range(self.rows):
# Continous vdd rail along with label.
vdd_pin=self.dff_insts[0,y].get_pin("vdd")
self.add_layout_pin(text="vdd",
layer="metal1",
offset=vdd_pin.ll(),
width=self.width,
height=self.m1_width)
# Continous gnd rail along with label.
gnd_pin=self.dff_insts[0,y].get_pin("gnd")
self.add_layout_pin(text="gnd",
layer="metal1",
offset=gnd_pin.ll(),
width=self.width,
height=self.m1_width)
for y in range(self.rows):
for x in range(self.columns):
din_pin = self.dff_insts[x,y].get_pin("D")
debug.check(din_pin.layer=="metal2","DFF D pin not on metal2")
self.add_layout_pin(text=self.get_din_name(y,x),
layer=din_pin.layer,
offset=din_pin.ll(),
width=din_pin.width(),
height=din_pin.height())
dout_pin = self.dff_insts[x,y].get_pin("Q")
debug.check(dout_pin.layer=="metal2","DFF Q pin not on metal2")
self.add_layout_pin(text=self.get_dout_name(y,x),
layer=dout_pin.layer,
offset=dout_pin.ll(),
width=dout_pin.width(),
height=dout_pin.height())
dout_bar_pin = self.dff_insts[x,y].get_pin("Qb")
debug.check(dout_bar_pin.layer=="metal2","DFF Qb pin not on metal2")
self.add_layout_pin(text=self.get_dout_bar_name(y,x),
layer=dout_bar_pin.layer,
offset=dout_bar_pin.ll(),
width=dout_bar_pin.width(),
height=dout_bar_pin.height())
# Create vertical spines to a single horizontal rail
clk_pin = self.dff_insts[0,0].get_pin("clk")
debug.check(clk_pin.layer=="metal2","DFF clk pin not on metal2")
if self.columns==1:
self.add_layout_pin(text="clk",
layer="metal2",
offset=clk_pin.ll().scale(1,0),
width=self.m2_width,
height=self.height)
else:
self.add_layout_pin(text="clk",
layer="metal3",
offset=vector(0,0),
width=self.width,
height=self.m3_width)
for x in range(self.columns):
clk_pin = self.dff_insts[x,0].get_pin("clk")
# Make a vertical strip for each column
self.add_layout_pin(text="clk",
layer="metal2",
offset=clk_pin.ll().scale(1,0),
width=self.m2_width,
height=self.height)
# Drop a via to the M3 pin
self.add_via_center(layers=("metal2","via2","metal3"),
offset=clk_pin.center().scale(1,0))
def analytical_delay(self, slew, load=0.0):
return self.dff.analytical_delay(slew=slew, load=load)

View File

@ -31,8 +31,11 @@ class hierarchical_decoder(design.design):
self.rows = rows
self.num_inputs = int(math.log(self.rows, 2))
(self.no_of_pre2x4,self.no_of_pre3x8)=self.determine_predecodes(self.num_inputs)
self.create_layout()
self.offset_all_coordinates()
self.DRC_LVS()
def create_layout(self):
@ -51,10 +54,15 @@ class hierarchical_decoder(design.design):
self.add_mod(self.nand2)
self.nand3 = pnand3()
self.add_mod(self.nand3)
self.add_decoders()
# CREATION OF PRE-DECODER
def add_decoders(self):
""" Create the decoders based on the number of pre-decodes """
# FIXME: Only add these if needed?
self.pre2_4 = pre2x4()
self.add_mod(self.pre2_4)
self.pre3_8 = pre3x8()
self.add_mod(self.pre3_8)
@ -146,12 +154,11 @@ class hierarchical_decoder(design.design):
else:
nand_width = self.nand3.width
self.routing_width = self.metal2_pitch*self.total_number_of_predecoder_outputs
self.row_decoder_width = nand_width + self.routing_width + self.inv.width
self.row_decoder_height = self.inv.height * self.rows
# Calculates height and width of hierarchical decoder
self.height = self.predecoder_height + self.row_decoder_height
self.width = self.predecoder_width + self.routing_width
self.height = self.row_decoder_height
self.width = self.predecoder_width + self.routing_width + nand_width + self.inv.width
def create_pre_decoder(self):
""" Creates pre-decoder and places labels input address [A] """
@ -166,12 +173,10 @@ class hierarchical_decoder(design.design):
""" Add a 2x4 predecoder """
if (self.num_inputs == 2):
base = vector(self.routing_width,0)
mirror = "RO"
base = vector(-self.pre2_4.width,0)
index_off1 = index_off2 = 0
else:
base= vector(self.routing_width+self.pre2_4.width, num * self.pre2_4.height)
mirror = "MY"
base= vector(-self.pre2_4.width, num * self.pre2_4.height)
index_off1 = num * 2
index_off2 = num * 4
@ -184,8 +189,7 @@ class hierarchical_decoder(design.design):
self.pre2x4_inst.append(self.add_inst(name="pre[{0}]".format(num),
mod=self.pre2_4,
offset=base,
mirror=mirror))
offset=base))
self.connect_inst(pins)
self.add_pre2x4_pins(num)
@ -210,12 +214,11 @@ class hierarchical_decoder(design.design):
def add_pre3x8(self,num):
""" Add 3x8 numbered predecoder """
if (self.num_inputs == 3):
offset = vector(self.routing_width,0)
offset = vector(-self.pre_3_8.width,0)
mirror ="R0"
else:
height = self.no_of_pre2x4*self.pre2_4.height + num*self.pre3_8.height
offset = vector(self.routing_width+self.pre3_8.width, height)
mirror="MY"
offset = vector(-self.pre3_8.width, height)
# If we had 2x4 predecodes, those are used as the lower
# decode output bits
@ -231,8 +234,7 @@ class hierarchical_decoder(design.design):
self.pre3x8_inst.append(self.add_inst(name="pre3x8[{0}]".format(num),
mod=self.pre3_8,
offset=offset,
mirror=mirror))
offset=offset))
self.connect_inst(pins)
# The 3x8 predecoders will be stacked, so use yoffset
@ -300,11 +302,11 @@ class hierarchical_decoder(design.design):
for row in range(self.rows):
name = "DEC_NAND[{0}]".format(row)
if ((row % 2) == 0):
y_off = self.predecoder_height + nand_mod.height*row
y_off = nand_mod.height*row
y_dir = 1
mirror = "R0"
else:
y_off = self.predecoder_height + nand_mod.height*(row + 1)
y_off = nand_mod.height*(row + 1)
y_dir = -1
mirror = "MX"
@ -337,7 +339,7 @@ class hierarchical_decoder(design.design):
inv_row_height = self.inv.height * (row + 1)
mirror = "MX"
y_dir = -1
y_off = self.predecoder_height + inv_row_height
y_off = inv_row_height
offset = vector(x_off,y_off)
self.inv_inst.append(self.add_inst(name=name,
@ -403,7 +405,7 @@ class hierarchical_decoder(design.design):
index = pre_num * 4 + i
out_name = "out[{}]".format(i)
pin = self.pre2x4_inst[pre_num].get_pin(out_name)
self.connect_rail(index, pin)
self.connect_rail_m3(index, pin)
for pre_num in range(self.no_of_pre3x8):
@ -411,7 +413,7 @@ class hierarchical_decoder(design.design):
index = pre_num * 8 + i + self.no_of_pre2x4 * 4
out_name = "out[{}]".format(i)
pin = self.pre3x8_inst[pre_num].get_pin(out_name)
self.connect_rail(index, pin)
self.connect_rail_m3(index, pin)
@ -443,26 +445,34 @@ class hierarchical_decoder(design.design):
def route_vdd_gnd(self):
""" Add a pin for each row of vdd/gnd which are must-connects next level up. """
for num in range(0,self.total_number_of_predecoder_outputs + self.rows):
# Find the x offsets for where the vias/pins should be placed
a_xoffset = self.inv_inst[0].lx()
b_xoffset = self.inv_inst[0].rx()
for num in range(0,self.rows):
# this will result in duplicate polygons for rails, but who cares
# use the inverter offset even though it will be the nand's too
(gate_offset, y_dir) = self.get_gate_offset(0, self.inv.height, num)
# route vdd
vdd_offset = gate_offset + self.inv.get_pin("vdd").ll().scale(1,y_dir)
self.add_layout_pin(text="vdd",
layer="metal1",
offset=vdd_offset,
width=self.width,
height=drc["minwidth_metal1"])
# Route both supplies
for n in ["vdd", "gnd"]:
supply_pin = self.inv_inst[num].get_pin(n)
# route gnd
gnd_offset = gate_offset+self.inv.get_pin("gnd").ll().scale(1,y_dir)
self.add_layout_pin(text="gnd",
layer="metal1",
offset=gnd_offset,
width=self.width,
height=drc["minwidth_metal1"])
# Add pins in two locations
for xoffset in [a_xoffset, b_xoffset]:
pin_pos = vector(xoffset, supply_pin.cy())
self.add_via_center(layers=("metal1", "via1", "metal2"),
offset=pin_pos,
rotate=90)
self.add_via_center(layers=("metal2", "via2", "metal3"),
offset=pin_pos,
rotate=90)
self.add_layout_pin_rect_center(text=n,
layer="metal3",
offset=pin_pos)
# Copy the pins from the predecoders
for pre in self.pre2x4_inst + self.pre3x8_inst:
self.copy_layout_pin(pre, "vdd")
self.copy_layout_pin(pre, "gnd")
def connect_rail(self, rail_index, pin):
@ -473,6 +483,19 @@ class hierarchical_decoder(design.design):
offset=rail_pos,
rotate=90)
def connect_rail_m3(self, rail_index, pin):
""" Connect the routing rail to the given metal1 pin """
mid_point = vector(pin.cx(), pin.cy()+self.inv.height/2)
rail_pos = vector(self.rail_x_offsets[rail_index],mid_point.y)
self.add_via_center(layers=("metal1", "via1", "metal2"),
offset=pin.center(),
rotate=90)
self.add_wire(("metal3","via2","metal2"), [rail_pos, mid_point, pin.uc()])
self.add_via_center(layers=("metal2", "via2", "metal3"),
offset=rail_pos,
rotate=90)
def analytical_delay(self, slew, load = 0.0):
# A -> out

View File

@ -21,8 +21,6 @@ class hierarchical_predecode(design.design):
c = reload(__import__(OPTS.bitcell))
self.mod_bitcell = getattr(c, OPTS.bitcell)
self.bitcell_height = self.mod_bitcell.height
def add_pins(self):
for k in range(self.number_of_inputs):
@ -51,9 +49,9 @@ class hierarchical_predecode(design.design):
debug.error("Invalid number of predecode inputs.",-1)
def setup_constraints(self):
# we are going to use horizontal vias, so use the via height
# use a conservative douple spacing just to get rid of annoying via DRCs
self.m2_pitch = contact.m1m2.height + 2*self.m2_space
self.m1_pitch = max(contact.m1m2.width,contact.m1m2.height) + max(self.m1_space, self.m2_space)
self.m2_pitch = max(contact.m2m3.width,contact.m2m3.height) + max(self.m2_space,self.m3_space)
# The rail offsets are indexed by the label
self.rails = {}
@ -92,14 +90,14 @@ class hierarchical_predecode(design.design):
if label.startswith("in"):
self.add_layout_pin(text=label,
layer="metal2",
offset=vector(self.rails[label] - 0.5*self.m2_width, 0),
offset=vector(self.rails[label] - 0.5*self.m1_width, self.m1_width),
width=self.m2_width,
height=self.height - 2*self.m2_space)
height=self.height - 4*self.m1_width)
else:
self.add_rect(layer="metal2",
offset=vector(self.rails[label] - 0.5*self.m2_width, 0),
offset=vector(self.rails[label] - 0.5*self.m1_width, 2*self.m1_width),
width=self.m2_width,
height=self.height - 2*self.m2_space)
height=self.height - 4*self.m1_width)
def add_input_inverters(self):
""" Create the input inverters to invert input signals for the decode stage. """
@ -205,11 +203,12 @@ class hierarchical_predecode(design.design):
mid2_pos = vector(0.5*(zr_pos.x+al_pos.x), al_pos.y)
self.add_path("metal1", [zr_pos, mid1_pos, mid2_pos, al_pos])
z_pos = self.inv_inst[num].get_pin("Z").rc()
self.add_layout_pin_center_segment(text="out[{}]".format(num),
layer="metal1",
start=z_pos,
end=z_pos + vector(self.inv.width - self.inv.get_pin("Z").rx(),0))
z_pin = self.inv_inst[num].get_pin("Z")
self.add_layout_pin(text="out[{}]".format(num),
layer="metal1",
offset=z_pin.ll(),
height=z_pin.height(),
width=z_pin.width())
def route_input_inverters(self):
@ -268,25 +267,32 @@ class hierarchical_predecode(design.design):
def route_vdd_gnd(self):
""" Add a pin for each row of vdd/gnd which are must-connects next level up. """
# Find the x offsets for where the vias/pins should be placed
in_xoffset = self.in_inst[0].rx()
out_xoffset = self.inv_inst[0].lx()
for num in range(0,self.number_of_outputs):
# this will result in duplicate polygons for rails, but who cares
# use the inverter offset even though it will be the nand's too
(gate_offset, y_dir) = self.get_gate_offset(0, self.inv.height, num)
# Route both supplies
for n in ["vdd", "gnd"]:
nand_pin = self.nand_inst[num].get_pin(n)
supply_offset = nand_pin.ll().scale(0,1)
self.add_rect(layer="metal1",
offset=supply_offset,
width=self.inv_inst[num].rx())
# route vdd
vdd_offset = self.nand_inst[num].get_pin("vdd").ll().scale(0,1)
self.add_layout_pin(text="vdd",
layer="metal1",
offset=vdd_offset,
width=self.inv_inst[num].rx())
# route gnd
gnd_offset = self.nand_inst[num].get_pin("gnd").ll().scale(0,1)
self.add_layout_pin(text="gnd",
layer="metal1",
offset=gnd_offset,
width=self.inv_inst[num].rx())
# Add pins in two locations
for xoffset in [in_xoffset, out_xoffset]:
pin_pos = vector(xoffset, nand_pin.cy())
self.add_via_center(layers=("metal1", "via1", "metal2"),
offset=pin_pos,
rotate=90)
self.add_via_center(layers=("metal2", "via2", "metal3"),
offset=pin_pos,
rotate=90)
self.add_layout_pin_rect_center(text=n,
layer="metal3",
offset=pin_pos)

View File

@ -71,14 +71,16 @@ class ms_flop_array(design.design):
for i in range(self.word_size):
for gnd_pin in self.ms_inst[i].get_pins("gnd"):
if gnd_pin.layer!="metal2":
continue
self.add_layout_pin(text="gnd",
layer="metal2",
offset=gnd_pin.ll(),
width=gnd_pin.width(),
height=gnd_pin.height())
# Route both supplies
for n in ["vdd", "gnd"]:
for supply_pin in self.ms_inst[i].get_pins(n):
pin_pos = supply_pin.center()
self.add_via_center(layers=("metal2", "via2", "metal3"),
offset=pin_pos)
self.add_layout_pin_rect_center(text=n,
layer="metal3",
offset=pin_pos)
din_pins = self.ms_inst[i].get_pins("din")
for din_pin in din_pins:
@ -110,26 +112,9 @@ class ms_flop_array(design.design):
width=self.width,
height=drc["minwidth_metal1"])
# Continous vdd rail along with label.
for vdd_pin in self.ms_inst[i].get_pins("vdd"):
if vdd_pin.layer!="metal1":
continue
self.add_layout_pin(text="vdd",
layer="metal1",
offset=vdd_pin.ll().scale(0,1),
width=self.width,
height=drc["minwidth_metal1"])
# Continous gnd rail along with label.
for gnd_pin in self.ms_inst[i].get_pins("gnd"):
if gnd_pin.layer!="metal1":
continue
self.add_layout_pin(text="gnd",
layer="metal1",
offset=gnd_pin.ll().scale(0,1),
width=self.width,
height=drc["minwidth_metal1"])
def analytical_delay(self, slew, load=0.0):

View File

@ -37,28 +37,34 @@ class precharge_array(design.design):
def create_layout(self):
self.add_insts()
self.add_layout_pin(text="vdd",
layer="metal1",
offset=self.pc_cell.get_pin("vdd").ll(),
width=self.width,
height=drc["minwidth_metal1"])
self.add_layout_pins()
def add_layout_pins(self):
self.add_layout_pin(text="en",
layer="metal1",
offset=self.pc_cell.get_pin("en").ll(),
width=self.width,
height=drc["minwidth_metal1"])
for inst in self.local_insts:
self.copy_layout_pin(inst, "vdd")
def add_insts(self):
"""Creates a precharge array by horizontally tiling the precharge cell"""
self.local_insts = []
for i in range(self.columns):
name = "pre_column_{0}".format(i)
offset = vector(self.pc_cell.width * i, 0)
inst=self.add_inst(name=name,
mod=self.pc_cell,
offset=offset)
inst = self.add_inst(name=name,
mod=self.pc_cell,
offset=offset)
self.local_insts.append(inst)
self.connect_inst(["bl[{0}]".format(i), "br[{0}]".format(i), "en", "vdd"])
bl_pin = inst.get_pin("bl")
self.add_layout_pin(text="bl[{0}]".format(i),
layer="metal2",
@ -71,6 +77,4 @@ class precharge_array(design.design):
offset=br_pin.ll(),
width=drc["minwidth_metal2"],
height=bl_pin.height())
self.connect_inst(["bl[{0}]".format(i), "br[{0}]".format(i),
"en", "vdd"])

View File

@ -24,9 +24,6 @@ class replica_bitline(design.design):
g = reload(__import__(OPTS.replica_bitcell))
self.mod_replica_bitcell = getattr(g, OPTS.replica_bitcell)
c = reload(__import__(OPTS.bitcell))
self.mod_bitcell = getattr(c, OPTS.bitcell)
for pin in ["en", "out", "vdd", "gnd"]:
self.add_pin(pin)
self.bitcell_loads = bitcell_loads
@ -37,8 +34,15 @@ class replica_bitline(design.design):
self.calculate_module_offsets()
self.add_modules()
self.route()
self.offset_all_coordinates()
self.add_layout_pins()
self.add_lvs_correspondence_points()
#self.add_lvs_correspondence_points()
self.width = self.right_gnd_pin.rx() - self.left_gnd_pin.lx()
self.height = self.left_gnd_pin.uy() - self.left_gnd_pin.by()
self.DRC_LVS()
@ -51,27 +55,22 @@ class replica_bitline(design.design):
# M1/M2 routing pitch is based on contacted pitch
self.m1_pitch = max(contact.m1m2.width,contact.m1m2.height) + max(self.m1_space,self.m2_space)
self.m2_pitch = max(contact.m2m3.width,contact.m2m3.height) + max(self.m2_space,self.m3_space)
# This corrects the offset pitch difference between M2 and M1
self.offset_fix = vector(0.5*(self.m2_width-self.m1_width),0)
# delay chain will be rotated 90, so move it over a width
# we move it up a inv height just for some routing room
self.rbl_inv_offset = vector(self.delay_chain.height, self.inv.width)
# access TX goes right on top of inverter, leave space for an inverter which is
# about the same as a TX. We'll need to add rails though.
self.access_tx_offset = vector(1.25*self.inv.height,self.rbl_inv_offset.y) + vector(0,2.5*self.inv.width)
self.delay_chain_offset = self.rbl_inv_offset + vector(0,4*self.inv.width)
# Replica bitline and such are not rotated, but they must be placed far enough
# Quadrant 1: Replica bitline and such are not rotated, but they must be placed far enough
# away from the delay chain/inverter with space for three M2 tracks
self.bitcell_offset = self.rbl_inv_offset + vector(2*self.m2_pitch, 0) + vector(0, self.bitcell.height + self.inv.width)
self.rbl_offset = self.bitcell_offset
self.bitcell_offset = vector(0,self.replica_bitcell.height)
self.rbl_offset = self.bitcell_offset
self.height = self.rbl_offset.y + self.rbl.height + self.m2_pitch
self.width = self.rbl_offset.x + self.bitcell.width
# Quadrant 4: with some space below it and tracks on the right for vdd/gnd
self.delay_chain_offset = vector(-self.delay_chain.width-4*self.m2_pitch,self.replica_bitcell.height)
# Will be flipped vertically below the delay chain
self.rbl_inv_offset = self.delay_chain_offset + vector(0.5*self.delay_chain.width, 0)
# Placed next to the replica bitcell
self.access_tx_offset = vector(-4*self.m2_pitch-self.access_tx.width-self.inv.width, 0.5*self.inv.height)
def create_modules(self):
@ -98,23 +97,20 @@ class replica_bitline(design.design):
# 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+vector(0,self.inv.width),
rotate=270,
mirror="MX")
offset=self.rbl_inv_offset,
rotate=180)
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,
rotate=90)
offset=self.access_tx_offset)
# 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,
rotate=90)
offset=self.delay_chain_offset)
self.connect_inst(["en", "delayed_en", "vdd", "gnd"])
self.rbc_inst=self.add_inst(name="bitcell",
@ -128,15 +124,31 @@ class replica_bitline(design.design):
offset=self.rbl_offset)
self.connect_inst(["bl[0]", "br[0]"] + ["gnd"]*self.bitcell_loads + ["vdd", "gnd"])
def route(self):
""" Connect all the signals together """
self.route_gnd()
self.route_vdd()
self.route_gnd()
self.route_access_tx()
def route_vdd_gnd(self):
""" Route all the vdd and gnd pins to the top level """
def route_vdd_gnd(self):
""" Propagate all vdd/gnd pins up to this level for all modules """
# These are the instances that every bank has
top_instances = [self.rbl_inst,
self.rbl_inv_inst,
self.rbc_inst,
self.dc_inst]
for inst in top_instances:
self.copy_layout_pin(inst, "vdd")
self.copy_layout_pin(inst, "gnd")
def route_access_tx(self):
# GATE ROUTE
@ -145,185 +157,340 @@ class replica_bitline(design.design):
# (middle in between the pmos and nmos)
poly_pin = self.tx_inst.get_pin("G")
poly_offset = poly_pin.rc()
# This centers the contact on the poly
contact_offset = poly_offset.scale(0,1) + self.dc_inst.get_pin("out").bc().scale(1,0)
poly_offset = poly_pin.uc()
# This centers the contact above the poly by one pitch
contact_offset = poly_offset + vector(0,self.m2_pitch)
self.add_contact_center(layers=("poly", "contact", "metal1"),
offset=contact_offset)
self.add_rect(layer="poly",
offset=poly_pin.lr(),
width=contact_offset.x-poly_offset.x,
height=self.poly_width)
self.add_contact_center(layers=("metal1", "via1", "metal2"),
offset=contact_offset)
self.add_segment_center(layer="poly",
start=poly_offset,
end=contact_offset)
nwell_offset = self.rbl_inv_offset + vector(-self.inv.height,self.inv.width)
self.add_rect(layer="nwell",
offset=nwell_offset,
width=0.5*self.inv.height,
height=self.delay_chain_offset.y-nwell_offset.y)
# self.add_rect(layer="nwell",
# offset=nwell_offset,
# width=0.5*self.inv.height,
# height=self.delay_chain_offset.y-nwell_offset.y)
# 2. Route delay chain output to access tx gate
delay_en_offset = self.dc_inst.get_pin("out").bc()
self.add_path("metal1", [delay_en_offset,contact_offset])
self.add_path("metal2", [delay_en_offset,contact_offset])
# 3. Route the mid-point of previous route to the bitcell WL
# 3. Route the contact of previous route to the bitcell WL
# route bend of previous net to bitcell WL
wl_offset = self.rbc_inst.get_pin("WL").lc()
wl_mid = vector(contact_offset.x,wl_offset.y)
self.add_path("metal1", [contact_offset, wl_mid, wl_offset])
xmid_point= 0.5*(wl_offset.x+contact_offset.x)
wl_mid1 = vector(xmid_point,contact_offset.y)
wl_mid2 = vector(xmid_point,wl_offset.y)
self.add_path("metal1", [contact_offset, wl_mid1, wl_mid2, wl_offset])
# DRAIN ROUTE
# Route the drain to the vdd rail
drain_offset = self.tx_inst.get_pin("D").lc()
inv_vdd_offset = self.rbl_inv_inst.get_pin("vdd").uc()
vdd_offset = inv_vdd_offset.scale(1,0) + drain_offset.scale(0,1)
self.add_path("metal1", [drain_offset, vdd_offset])
drain_offset = self.tx_inst.get_pin("D").center()
self.add_path("metal1", [drain_offset, drain_offset.scale(1,0)])
# SOURCE ROUTE
# Route the source to the RBL inverter input
source_offset = self.tx_inst.get_pin("S").bc()
mid1 = source_offset.scale(1,0) + vector(0,self.rbl_inv_offset.y+self.inv.width+self.m2_pitch)
inv_A_offset = self.rbl_inv_inst.get_pin("A").uc()
mid2 = vector(inv_A_offset.x, mid1.y)
self.add_path("metal1",[source_offset, mid1, mid2, inv_A_offset])
# Route the connection of the source route (mid2) to the RBL bitline (left)
source_offset = mid2
# Route the M2 to the right of the vdd rail between rbl_inv and bitcell
gnd_pin = self.rbl_inv_inst.get_pin("gnd").ll()
mid1 = vector(gnd_pin.x+self.m2_pitch,source_offset.y)
# Route the drain to the RBL inverter input
source_offset = self.tx_inst.get_pin("S").center()
inv_A_offset = self.rbl_inv_inst.get_pin("A").center()
self.add_path("metal1",[source_offset, inv_A_offset])
# Route the connection of the source route to the RBL bitline (left)
# Via will go halfway down from the bitcell
bl_offset = self.rbc_inst.get_pin("BL").bc()
via_offset = bl_offset - vector(0,0.5*self.inv.width)
mid2 = vector(mid1.x,via_offset.y)
# self.add_contact(layers=("metal1", "via1", "metal2"),
# offset=via_offset - vector(0.5*self.m2_width,0.5*self.m1_width))
self.add_wire(("metal1","via1","metal2"),[source_offset,mid1,mid2,via_offset,bl_offset])
#self.add_path("metal2",[via_offset,bl_offset])
self.add_path("metal3",[source_offset, bl_offset])
self.add_via_center(layers=("metal1", "via1", "metal2"),
offset=source_offset)
self.add_via_center(layers=("metal2", "via2", "metal3"),
offset=source_offset)
self.add_via_center(layers=("metal2", "via2", "metal3"),
offset=bl_offset)
# BODY ROUTE
# Connect it to the inverter well
nwell_offset = self.rbl_inv_inst.lr()
ur_offset = self.tx_inst.ur()
self.add_rect(layer="nwell",
offset=nwell_offset,
width=ur_offset.x-nwell_offset.x,
height=ur_offset.y-nwell_offset.y)
def route_vdd(self):
# Add a rail in M2 that is to the right of the inverter gnd pin
# The replica column may not fit in a single standard cell pitch, so add the vdd rail to the
# right of it.
vdd_start = vector(self.bitcell_offset.x + self.bitcell.width + self.m1_pitch,0)
# It is the height of the entire RBL and bitcell
self.add_layout_pin(text="vdd",
layer="metal1",
offset=vdd_start,
width=self.m1_width,
height=self.rbl.height+self.bitcell.height+2*self.inv.width+0.5*self.m1_width)
# Connect the vdd pins of the bitcell load directly to vdd
vdd_pins = self.rbl_inst.get_pins("vdd")
for pin in vdd_pins:
offset = vector(vdd_start.x,pin.by())
self.add_rect(layer="metal1",
offset=offset,
width=self.rbl_offset.x-vdd_start.x,
height=self.m1_width)
# Also connect the replica bitcell vdd pin to vdd
pin = self.rbc_inst.get_pin("vdd")
offset = vector(vdd_start.x,pin.by())
self.add_rect(layer="metal1",
offset=offset,
width=self.bitcell_offset.x-vdd_start.x,
height=self.m1_width)
""" Route all signals connected to vdd """
# Route the vdd lines from left to right
# Add via for the delay chain
left_vdd_start = self.dc_inst.ll().scale(1,0) - vector(self.m2_pitch,0)
left_vdd_end = vector(left_vdd_start.x, self.rbl_inst.uy())
self.left_vdd_pin=self.add_segment_center(layer="metal2",
start=left_vdd_start,
end=left_vdd_end)
# Vdd line to the left of the replica bitline
center_vdd_start = self.rbc_inst.ll() - vector(3*self.m2_pitch,0)
center_vdd_end = vector(center_vdd_start.x, self.rbl_inst.uy())
self.center_vdd_pin=self.add_segment_center(layer="metal2",
start=center_vdd_start,
end=center_vdd_end)
# Vdd line to the right of the replica bitline
right_vdd_start = self.rbc_inst.lr() + vector(2*self.m2_pitch,0)
right_vdd_end = vector(right_vdd_start.x, self.rbl_inst.uy())
self.right_vdd_pin=self.add_segment_center(layer="metal2",
start=right_vdd_start,
end=right_vdd_end)
# Connect the WL and vdd pins directly to the center and right vdd rails
# Connect RBL vdd pins to center and right rails
rbl_vdd_pins = self.rbl_inst.get_pins("vdd")
for pin in rbl_vdd_pins:
if pin.layer != "metal1":
continue
start = vector(self.center_vdd_pin.cx(),pin.cy())
end = vector(self.right_vdd_pin.cx(),pin.cy())
self.add_layout_pin_segment_center(text="vdd",
layer="metal1",
start=start,
end=end)
self.add_via_center(layers=("metal1", "via1", "metal2"),
offset=start,
rotate=90)
self.add_via_center(layers=("metal1", "via1", "metal2"),
offset=end,
rotate=90)
# Connect the vdd pins of the delay chain to the left rails
dc_vdd_pins = self.dc_inst.get_pins("vdd")
for pin in dc_vdd_pins:
if pin.layer != "metal1":
continue
start = vector(self.left_vdd_pin.cx(),pin.cy())
# Note, we don't connect to center because of via conflicts
# with the RBL pins
#end = vector(center_vdd_pin.cx(),pin.cy())
end = pin.rc()
self.add_layout_pin_segment_center(text="vdd",
layer="metal1",
start=start,
end=end)
self.add_via_center(layers=("metal1", "via1", "metal2"),
offset=start,
rotate=90)
# Add via for the inverter
pin = self.rbl_inv_inst.get_pin("vdd")
start = vector(self.left_vdd_pin.cx(),pin.cy())
end = vector(self.center_vdd_pin.cx(),pin.cy())
self.add_segment_center(layer="metal1",
start=start,
end=end)
self.add_via_center(layers=("metal1", "via1", "metal2"),
offset=start,
rotate=90)
self.add_via_center(layers=("metal1", "via1", "metal2"),
offset=end,
rotate=90)
# Add via for the RBC
pin = self.rbc_inst.get_pin("vdd")
start = pin.lc()
end = vector(self.right_vdd_pin.cx(),pin.cy())
self.add_segment_center(layer="metal1",
start=start,
end=end)
self.add_via_center(layers=("metal1", "via1", "metal2"),
offset=end,
rotate=90)
# Create the RBL rails too
rbl_pins = self.rbl_inst.get_pins("vdd")
for pin in rbl_pins:
if pin.layer != "metal1":
continue
# If above the delay line, route the full width
left = vector(self.left_vdd_pin.cx(),pin.cy())
center = vector(self.center_vdd_pin.cx(),pin.cy())
if pin.cy() > self.dc_inst.uy() + self.m1_pitch:
start = left
self.add_via_center(layers=("metal1", "via1", "metal2"),
offset=left,
rotate=90)
else:
start = center
end = vector(self.right_vdd_pin.cx()+0.5*self.m1_width,pin.cy())
self.add_layout_pin_segment_center(text="vdd",
layer="metal1",
start=start,
end=end)
# Add a second vdd pin. No need for full length. It is must connect at the next level.
inv_vdd_offset = self.rbl_inv_inst.get_pin("vdd").ll()
self.add_layout_pin(text="vdd",
layer="metal1",
offset=inv_vdd_offset.scale(1,0),
width=self.m1_width,
height=self.delay_chain_offset.y)
def route_gnd(self):
""" Route all signals connected to gnd """
gnd_start = self.rbl_inv_inst.get_pin("gnd").bc()
gnd_end = vector(gnd_start.x, self.rbl_inst.uy()+2*self.m2_pitch)
# Add a rail in M1 from bottom of delay chain to two above the RBL
# This prevents DRC errors with vias for the WL
dc_top = self.dc_inst.ur()
self.add_segment_center(layer="metal1",
start=vector(gnd_start.x, dc_top.y),
end=gnd_end)
# Add a rail in M2 from RBL inverter to two above the RBL
self.add_segment_center(layer="metal2",
start=gnd_start,
end=gnd_end)
# Add pin from bottom to RBL inverter
self.add_layout_pin_center_segment(text="gnd",
layer="metal1",
start=gnd_start.scale(1,0),
end=gnd_start)
# Route the gnd lines from left to right
# Add via for the delay chain
left_gnd_start = self.dc_inst.ll().scale(1,0) - vector(2*self.m2_pitch,0)
left_gnd_end = vector(left_gnd_start.x, self.rbl_inst.uy()+self.m2_pitch)
self.left_gnd_pin=self.add_segment_center(layer="metal2",
start=left_gnd_start,
end=left_gnd_end)
# Gnd line to the left of the replica bitline
center_gnd_start = self.rbc_inst.ll().scale(1,0) - vector(2*self.m2_pitch,0)
center_gnd_end = vector(center_gnd_start.x, self.rbl_inst.uy()+self.m2_pitch)
self.center_gnd_pin=self.add_segment_center(layer="metal2",
start=center_gnd_start,
end=center_gnd_end)
# Gnd line to the right of the replica bitline
right_gnd_start = self.rbc_inst.lr().scale(1,0) + vector(self.m2_pitch,0)
right_gnd_end = vector(right_gnd_start.x, self.rbl_inst.uy()+self.m2_pitch)
self.right_gnd_pin=self.add_segment_center(layer="metal2",
start=right_gnd_start,
end=right_gnd_end)
# Connect the WL pins directly to gnd
gnd_pin = self.get_pin("gnd").rc()
# Connect the WL and gnd pins directly to the center and right gnd rails
for row in range(self.bitcell_loads):
wl = "wl[{}]".format(row)
pin = self.rbl_inst.get_pin(wl)
start = vector(gnd_pin.x,pin.cy())
self.add_segment_center(layer="metal1",
start=start,
end=pin.lc())
if pin.layer != "metal1":
continue
# If above the delay line, route the full width
left = vector(self.left_gnd_pin.cx(),pin.cy())
center = vector(self.center_gnd_pin.cx(),pin.cy())
if pin.cy() > self.dc_inst.uy() + self.m1_pitch:
start = left
else:
start = center
end = vector(self.right_gnd_pin.cx(),pin.cy())
self.add_layout_pin_segment_center(text="gnd",
layer="metal1",
start=start,
end=end)
if start == left:
self.add_via_center(layers=("metal1", "via1", "metal2"),
offset=left,
rotate=90)
self.add_via_center(layers=("metal1", "via1", "metal2"),
offset=start)
offset=center,
rotate=90)
self.add_via_center(layers=("metal1", "via1", "metal2"),
offset=end,
rotate=90)
# Add via for the delay chain
offset = self.dc_inst.get_pins("gnd")[0].bc() + vector(0.5*contact.m1m2.width,0.5*contact.m1m2.height)
self.add_via_center(layers=("metal1", "via1", "metal2"),
offset=offset)
# Add via for the inverter
offset = self.rbl_inv_inst.get_pin("gnd").bc() - vector(0,0.5*contact.m1m2.height)
self.add_via_center(layers=("metal1", "via1", "metal2"),
offset=offset)
# Connect the bitcell gnd pins to the rail
gnd_pins = self.get_pins("gnd")
gnd_start = gnd_pins[0].ul()
rbl_gnd_pins = self.rbl_inst.get_pins("gnd")
# Add L shapes to each vertical gnd rail
for pin in rbl_gnd_pins:
if pin.layer != "metal1":
continue
# If above the delay line, route the full width
left = vector(self.left_gnd_pin.cx(),pin.cy())
center = vector(self.center_gnd_pin.cx(),pin.cy())
if pin.cy() > self.dc_inst.uy() + self.m1_pitch:
start = left
else:
start = center
end = vector(self.right_gnd_pin.cx(),pin.cy())
self.add_segment_center(layer="metal1",
start=start,
end=end)
if start == left:
self.add_via_center(layers=("metal1", "via1", "metal2"),
offset=left,
rotate=90)
self.add_via_center(layers=("metal1", "via1", "metal2"),
offset=center,
rotate=90)
self.add_via_center(layers=("metal1", "via1", "metal2"),
offset=end,
rotate=90)
# Connect the gnd pins of the delay chain to the left rails
dc_gnd_pins = self.dc_inst.get_pins("gnd")
for pin in dc_gnd_pins:
if pin.layer != "metal1":
continue
start = vector(self.left_gnd_pin.cx(),pin.cy())
# Note, we don't connect to the center rails because of
# via conflicts with the RBL
#end = vector(self.center_gnd_pin.cx(),pin.cy())
end = pin.rc()
self.add_segment_center(layer="metal1",
start=start,
end=end)
self.add_via_center(layers=("metal1", "via1", "metal2"),
offset=start,
rotate=90)
# self.add_via_center(layers=("metal1", "via1", "metal2"),
# offset=end,
#rotate=90)
# Add via for the inverter
# pin = self.rbl_inv_inst.get_pin("gnd")
# start = vector(self.left_gnd_pin.cx(),pin.cy())
# end = vector(self.center_gnd_pin.cx(),pin.cy())
# self.add_segment_center(layer="metal1",
# start=start,
# end=end)
# self.add_via_center(layers=("metal1", "via1", "metal2"),
# offset=start,
#rotate=90)
# self.add_via_center(layers=("metal1", "via1", "metal2"),
# offset=end,
#rotate=90)
# Create RBL rails too
rbl_pins = self.rbl_inst.get_pins("gnd")
for pin in rbl_pins:
if pin.layer != "metal2":
continue
gnd_end = pin.uc()
gnd_mid = vector(gnd_end.x, gnd_start.y)
self.add_wire(("metal1","via1","metal2"), [gnd_start, gnd_mid, gnd_end])
gnd_start = gnd_mid
# Add a second gnd pin to the second delay chain rail. No need for full length.
dc_gnd_offset = self.dc_inst.get_pins("gnd")[1].ll()
self.add_layout_pin(text="gnd",
layer="metal1",
offset=dc_gnd_offset.scale(1,0),
width=self.m1_width,
height=self.delay_chain_offset.y)
start = vector(pin.cx(),self.right_gnd_pin.by())
end = vector(pin.cx(),self.right_gnd_pin.uy())
self.add_layout_pin_segment_center(text="gnd",
layer="metal2",
start=start,
end=end)
def add_layout_pins(self):
""" Route the input and output signal """
en_offset = self.dc_inst.get_pin("in").ll()
self.add_layout_pin(text="en",
layer="metal1",
offset=en_offset.scale(1,0),
width=self.m1_width,
height=en_offset.y)
en_offset = self.dc_inst.get_pin("in").bc()
self.add_layout_pin_segment_center(text="en",
layer="metal2",
start=en_offset,
end=en_offset.scale(1,0))
out_offset = self.rbl_inv_inst.get_pin("Z").ll()
self.add_layout_pin(text="out",
layer="metal1",
offset=out_offset.scale(1,0),
width=self.m1_width,
height=out_offset.y)
out_offset = self.rbl_inv_inst.get_pin("Z").center()
self.add_layout_pin_segment_center(text="out",
layer="metal2",
start=out_offset,
end=out_offset.scale(1,0))
self.add_via_center(layers=("metal1", "via1", "metal2"),
offset=out_offset)
def add_lvs_correspondence_points(self):
""" This adds some points for easier debugging if LVS goes wrong.

View File

@ -62,51 +62,49 @@ class sense_amp_array(design.design):
br_offset = amp_position + br_pin.ll().scale(1,0)
dout_offset = amp_position + dout_pin.ll()
self.add_inst(name=name,
inst = self.add_inst(name=name,
mod=self.amp,
offset=amp_position)
self.connect_inst(["bl[{0}]".format(i),"br[{0}]".format(i),
self.connect_inst(["bl[{0}]".format(i),
"br[{0}]".format(i),
"data[{0}]".format(i/self.words_per_row),
"en", "vdd", "gnd"])
self.add_layout_pin(text="bl[{0}]".format(i),
gnd_pos = inst.get_pin("gnd").center()
self.add_via_center(layers=("metal2", "via2", "metal3"),
offset=gnd_pos)
self.add_layout_pin_rect_center(text="gnd",
layer="metal3",
offset=gnd_pos)
vdd_pos = inst.get_pin("vdd").center()
self.add_via_center(layers=("metal2", "via2", "metal3"),
offset=vdd_pos)
self.add_layout_pin_rect_center(text="vdd",
layer="metal3",
offset=vdd_pos)
self.add_layout_pin(text="bl[{0}]".format(i/self.words_per_row),
layer="metal2",
offset=bl_offset,
width=bl_pin.width(),
height=bl_pin.height())
self.add_layout_pin(text="br[{0}]".format(i),
self.add_layout_pin(text="br[{0}]".format(i/self.words_per_row),
layer="metal2",
offset=br_offset,
width=br_pin.width(),
height=br_pin.height())
self.add_layout_pin(text="data[{0}]".format(i/self.words_per_row),
layer="metal3",
layer="metal2",
offset=dout_offset,
width=dout_pin.width(),
height=dout_pin.height())
def connect_rails(self):
# add vdd rail across entire array
vdd_offset = self.amp.get_pin("vdd").ll().scale(0,1)
self.add_layout_pin(text="vdd",
layer="metal1",
offset=vdd_offset,
width=self.width,
height=drc["minwidth_metal1"])
# NOTE:the gnd rails are vertical so it is not connected horizontally
# add gnd rail across entire array
gnd_offset = self.amp.get_pin("gnd").ll().scale(0,1)
self.add_layout_pin(text="gnd",
layer="metal1",
offset=gnd_offset,
width=self.width,
height=drc["minwidth_metal1"])
# add sclk rail across entire array
sclk_offset = self.amp.get_pin("en").ll().scale(0,1)
self.add_layout_pin(text="en",

View File

@ -100,16 +100,9 @@ class single_level_column_mux_array(design.design):
offset=offset,
height=self.height-offset.y)
gnd_pins = mux_inst.get_pins("gnd")
for gnd_pin in gnd_pins:
# only do even colums to avoid duplicates
offset = gnd_pin.ll()
if col_num % 2 == 0:
self.add_layout_pin(text="gnd",
layer="metal2",
offset=offset.scale(1,0),
height=self.height)
for inst in self.mux_inst:
self.copy_layout_pin(inst, "gnd")
def add_routing(self):
self.add_horizontal_input_rail()
@ -119,7 +112,7 @@ class single_level_column_mux_array(design.design):
def add_horizontal_input_rail(self):
""" Create address input rails on M1 below the mux transistors """
for j in range(self.words_per_row):
offset = vector(0, self.route_height - (j+1)*self.m1_pitch)
offset = vector(0, self.route_height + (j-self.words_per_row)*self.m1_pitch)
self.add_layout_pin(text="sel[{}]".format(j),
layer="metal1",
offset=offset,

View File

@ -77,6 +77,16 @@ class tri_gate_array(design.design):
height=out_pin.height())
# Route both supplies
for n in ["vdd", "gnd"]:
for supply_pin in self.tri_inst[i].get_pins(n):
pin_pos = supply_pin.center()
self.add_via_center(layers=("metal2", "via2", "metal3"),
offset=pin_pos)
self.add_layout_pin_rect_center(text=n,
layer="metal3",
offset=pin_pos)
width = self.tri.width * self.columns - (self.words_per_row - 1) * self.tri.width
en_pin = self.tri_inst[0].get_pin("en")
@ -93,20 +103,6 @@ class tri_gate_array(design.design):
width=width,
height=drc["minwidth_metal1"])
vdd_pin = self.tri_inst[0].get_pin("vdd")
self.add_layout_pin(text="vdd",
layer="metal1",
offset=vdd_pin.ll().scale(0, 1),
width=width,
height=drc["minwidth_metal1"])
for gnd_pin in self.tri_inst[0].get_pins("gnd"):
if gnd_pin.layer=="metal1":
self.add_layout_pin(text="gnd",
layer="metal1",
offset=gnd_pin.ll().scale(0, 1),
width=width,
height=drc["minwidth_metal1"])
def analytical_delay(self, slew, load=0.0):

View File

@ -22,6 +22,7 @@ class wordline_driver(design.design):
self.rows = rows
self.add_pins()
self.design_layout()
self.offset_all_coordinates()
self.DRC_LVS()
def add_pins(self):
@ -36,11 +37,13 @@ class wordline_driver(design.design):
self.add_pin("gnd")
def design_layout(self):
self.add_layout()
self.offsets_of_gates()
self.create_layout()
self.create_modules()
self.add_modules()
self.route_layout()
self.route_vdd_gnd()
def add_layout(self):
def create_modules(self):
self.inv = pinv()
self.add_mod(self.inv)
@ -50,18 +53,95 @@ class wordline_driver(design.design):
self.nand2 = pnand2()
self.add_mod(self.nand2)
def route_vdd_gnd(self):
""" Add a pin for each row of vdd/gnd which are must-connects next level up. """
# Find the x offsets for where the vias/pins should be placed
a_xoffset = self.inv1_inst[0].rx()
b_xoffset = self.inv2_inst[0].lx()
for num in range(self.rows):
# this will result in duplicate polygons for rails, but who cares
# use the inverter offset even though it will be the nand's too
(gate_offset, y_dir) = self.get_gate_offset(0, self.inv.height, num)
# Route both supplies
for n in ["vdd", "gnd"]:
supply_pin = self.inv2_inst[num].get_pin(n)
# Add pins in two locations
for xoffset in [a_xoffset, b_xoffset]:
pin_pos = vector(xoffset, supply_pin.cy())
self.add_via_center(layers=("metal1", "via1", "metal2"),
offset=pin_pos,
rotate=90)
self.add_via_center(layers=("metal2", "via2", "metal3"),
offset=pin_pos,
rotate=90)
self.add_layout_pin_rect_center(text=n,
layer="metal3",
offset=pin_pos)
def offsets_of_gates(self):
self.x_offset0 = 2*self.m1_width + 5*self.m1_space
self.x_offset1 = self.x_offset0 + self.inv.width
self.x_offset2 = self.x_offset1 + self.nand2.width
self.width = self.x_offset2 + self.inv.width
def add_modules(self):
inv1_xoffset = 2*self.m1_width + 5*self.m1_space
nand2_xoffset = inv1_xoffset + self.inv.width
inv2_xoffset = nand2_xoffset + self.nand2.width
self.width = inv2_xoffset + self.inv.width
self.height = self.inv.height * self.rows
def create_layout(self):
self.inv1_inst = []
self.nand_inst = []
self.inv2_inst = []
for row in range(self.rows):
name_inv1 = "wl_driver_inv_en{}".format(row)
name_nand = "wl_driver_nand{}".format(row)
name_inv2 = "wl_driver_inv{}".format(row)
if (row % 2):
y_offset = self.inv.height*(row + 1)
inst_mirror = "MX"
else:
y_offset = self.inv.height*row
inst_mirror = "R0"
inv1_offset = [inv1_xoffset, y_offset]
nand2_offset=[nand2_xoffset, y_offset]
inv2_offset=[inv2_xoffset, y_offset]
# add inv1 based on the info above
self.inv1_inst.append(self.add_inst(name=name_inv1,
mod=self.inv_no_output,
offset=inv1_offset,
mirror=inst_mirror))
self.connect_inst(["en",
"en_bar[{0}]".format(row),
"vdd", "gnd"])
# add nand 2
self.nand_inst.append(self.add_inst(name=name_nand,
mod=self.nand2,
offset=nand2_offset,
mirror=inst_mirror))
self.connect_inst(["en_bar[{0}]".format(row),
"in[{0}]".format(row),
"net[{0}]".format(row),
"vdd", "gnd"])
# add inv2
self.inv2_inst.append(self.add_inst(name=name_inv2,
mod=self.inv,
offset=inv2_offset,
mirror=inst_mirror))
self.connect_inst(["net[{0}]".format(row),
"wl[{0}]".format(row),
"vdd", "gnd"])
def route_layout(self):
""" Route all of the signals """
# Wordline enable connection
en_pin=self.add_layout_pin(text="en",
layer="metal2",
@ -69,79 +149,12 @@ class wordline_driver(design.design):
width=self.m2_width,
height=self.height)
self.add_layout_pin(text="gnd",
layer="metal1",
offset=[0, -0.5*self.m1_width],
width=self.x_offset0,
height=self.m1_width)
for row in range(self.rows):
name_inv1 = "wl_driver_inv_en{}".format(row)
name_nand = "wl_driver_nand{}".format(row)
name_inv2 = "wl_driver_inv{}".format(row)
inv_nand2B_connection_height = (abs(self.inv.get_pin("Z").ll().y
- self.nand2.get_pin("B").ll().y)
+ self.m1_width)
if (row % 2):
y_offset = self.inv.height*(row + 1)
inst_mirror = "MX"
cell_dir = vector(0,-1)
m1tm2_rotate=270
m1tm2_mirror="R0"
else:
y_offset = self.inv.height*row
inst_mirror = "R0"
cell_dir = vector(0,1)
m1tm2_rotate=90
m1tm2_mirror="MX"
name_inv1_offset = [self.x_offset0, y_offset]
nand2_offset=[self.x_offset1, y_offset]
inv2_offset=[self.x_offset2, y_offset]
base_offset = vector(self.width, y_offset)
# Extend vdd and gnd of wordline_driver
yoffset = (row + 1) * self.inv.height - 0.5 * self.m1_width
if (row % 2):
pin_name = "gnd"
else:
pin_name = "vdd"
self.add_layout_pin(text=pin_name,
layer="metal1",
offset=[0, yoffset],
width=self.x_offset0,
height=self.m1_width)
inv1_inst = self.inv1_inst[row]
nand_inst = self.nand_inst[row]
inv2_inst = self.inv2_inst[row]
# add inv1 based on the info above
inv1_inst=self.add_inst(name=name_inv1,
mod=self.inv_no_output,
offset=name_inv1_offset,
mirror=inst_mirror )
self.connect_inst(["en",
"en_bar[{0}]".format(row),
"vdd", "gnd"])
# add nand 2
nand_inst=self.add_inst(name=name_nand,
mod=self.nand2,
offset=nand2_offset,
mirror=inst_mirror)
self.connect_inst(["en_bar[{0}]".format(row),
"in[{0}]".format(row),
"net[{0}]".format(row),
"vdd", "gnd"])
# add inv2
inv2_inst=self.add_inst(name=name_inv2,
mod=self.inv,
offset=inv2_offset,
mirror=inst_mirror)
self.connect_inst(["net[{0}]".format(row),
"wl[{0}]".format(row),
"vdd", "gnd"])
# en connection
a_pin = inv1_inst.get_pin("A")
a_pos = a_pin.lc()
@ -175,7 +188,7 @@ class wordline_driver(design.design):
input_offset = vector(0,b_pos.y + up_or_down)
mid_via_offset = vector(clk_offset.x,input_offset.y) + vector(0.5*self.m2_width+self.m2_space+0.5*contact.m1m2.width,0)
# must under the clk line in M1
self.add_layout_pin_center_segment(text="in[{0}]".format(row),
self.add_layout_pin_segment_center(text="in[{0}]".format(row),
layer="metal1",
start=input_offset,
end=mid_via_offset)
@ -191,7 +204,7 @@ class wordline_driver(design.design):
# output each WL on the right
wl_offset = inv2_inst.get_pin("Z").rc()
self.add_layout_pin_center_segment(text="wl[{0}]".format(row),
self.add_layout_pin_segment_center(text="wl[{0}]".format(row),
layer="metal1",
start=wl_offset,
end=wl_offset-vector(self.m1_width,0))

View File

@ -82,7 +82,19 @@ class write_driver_array(design.design):
offset=br_pin.ll(),
width=br_pin.width(),
height=br_pin.height())
for n in ["vdd", "gnd"]:
pin_list = self.driver_insts[i].get_pins(n)
for pin in pin_list:
pin_pos = pin.center()
# Add the M2->M3 stack
self.add_via_center(layers=("metal2", "via2", "metal3"),
offset=pin_pos)
self.add_layout_pin_rect_center(text=n,
layer="metal3",
offset=pin_pos)
self.add_layout_pin(text="en",
layer="metal1",
@ -90,16 +102,5 @@ class write_driver_array(design.design):
width=self.width,
height=drc['minwidth_metal1'])
self.add_layout_pin(text="vdd",
layer="metal1",
offset=self.driver_insts[0].get_pin("vdd").ll().scale(0,1),
width=self.width,
height=drc['minwidth_metal1'])
self.add_layout_pin(text="gnd",
layer="metal1",
offset=self.driver_insts[0].get_pin("gnd").ll().scale(0,1),
width=self.width,
height=drc['minwidth_metal1'])

View File

@ -13,8 +13,8 @@ class options(optparse.Values):
# This is the name of the technology.
tech_name = ""
# This is the temp directory where all intermediate results are stored.
openram_temp = "/tmp/openram_{0}_{1}_temp/".format(getpass.getuser(),os.getpid())
#openram_temp = "/Users/{}/openram_temp/".format(getpass.getuser())
#openram_temp = "/tmp/openram_{0}_{1}_temp/".format(getpass.getuser(),os.getpid())
openram_temp = "{0}/openram_temp/".format(os.getenv("HOME"))
# This is the verbosity level to control debug information. 0 is none, 1
# is minimal, etc.
debug_level = 0
@ -60,7 +60,6 @@ class options(optparse.Values):
ms_flop = "ms_flop"
ms_flop_array = "ms_flop_array"
dff = "dff"
dff_array = "dff_array"
control_logic = "control_logic"
bitcell_array = "bitcell_array"
sense_amp = "sense_amp"
@ -76,4 +75,5 @@ class options(optparse.Values):
replica_bitcell = "replica_bitcell"
bitcell = "bitcell"
delay_chain = "delay_chain"
bank_select = "bank_select"

View File

@ -76,11 +76,11 @@ class pgate(design.design):
self.add_contact_center(layers=("poly", "contact", "metal1"),
offset=contact_offset,
rotate=rotate)
# self.add_layout_pin_center_segment(text=name,
# self.add_layout_pin_segment_center(text=name,
# layer="metal1",
# start=left_gate_offset.scale(0,1),
# end=left_gate_offset)
self.add_layout_pin_center_rect(text=name,
self.add_layout_pin_rect_center(text=name,
layer="metal1",
offset=contact_offset,
width=contact_m1_width,

View File

@ -148,12 +148,12 @@ class pinv(pgate.pgate):
def add_supply_rails(self):
""" Add vdd/gnd rails to the top and bottom. """
self.add_layout_pin_center_rect(text="gnd",
self.add_layout_pin_rect_center(text="gnd",
layer="metal1",
offset=vector(0.5*self.width,0),
width=self.width)
self.add_layout_pin_center_rect(text="vdd",
self.add_layout_pin_rect_center(text="vdd",
layer="metal1",
offset=vector(0.5*self.width,self.height),
width=self.width)
@ -208,13 +208,13 @@ class pinv(pgate.pgate):
if self.route_output == True:
# This extends the output to the edge of the cell
output_offset = mid_drain_offset.scale(0,1) + vector(self.width,0)
self.add_layout_pin_center_segment(text="Z",
self.add_layout_pin_segment_center(text="Z",
layer="metal1",
start=mid_drain_offset,
end=output_offset)
else:
# This leaves the output as an internal pin (min sized)
self.add_layout_pin_center_rect(text="Z",
self.add_layout_pin_rect_center(text="Z",
layer="metal1",
offset=mid_drain_offset + vector(0.5*self.m1_width,0))
@ -257,4 +257,4 @@ class pinv(pgate.pgate):
c_load = load
c_para = spice["min_tx_drain_c"]*(self.nmos_size/parameter["min_tx_size"])#ff
transistion_prob = spice["inv_transisition_prob"]
return transistion_prob*(c_load + c_para)
return transistion_prob*(c_load + c_para)

161
compiler/pgates/pinvbuf.py Normal file
View File

@ -0,0 +1,161 @@
import debug
import design
from tech import drc
from math import log
from vector import vector
from globals import OPTS
from pinv import pinv
class pinvbuf(design.design):
"""
This is a simple inverter/buffer used for driving loads. It is
used in the column decoder for 1:2 decoding and as the clock buffer.
"""
c = reload(__import__(OPTS.bitcell))
bitcell = getattr(c, OPTS.bitcell)
def __init__(self, inv1_size=2, inv2_size=4, height=bitcell.height, name=""):
if name=="":
name = "pinvbuf_{0}_{1}".format(inv1_size, inv2_size)
design.design.__init__(self, name)
debug.info(1, "Creating {}".format(self.name))
self.inv = pinv(size=1, height=height)
self.add_mod(self.inv)
self.inv1 = pinv(size=inv1_size, height=height)
self.add_mod(self.inv1)
self.inv2 = pinv(size=inv2_size, height=height)
self.add_mod(self.inv2)
self.width = 2*self.inv1.width + self.inv2.width
self.height = 2*self.inv1.height
self.create_layout()
self.offset_all_coordinates()
self.DRC_LVS()
def create_layout(self):
self.add_pins()
self.add_insts()
self.add_wires()
self.add_layout_pins()
def add_pins(self):
self.add_pin("A")
self.add_pin("Zb")
self.add_pin("Z")
self.add_pin("vdd")
self.add_pin("gnd")
def add_insts(self):
# Add INV1 to the right (capacitance shield)
self.inv1_inst=self.add_inst(name="buf_inv1",
mod=self.inv,
offset=vector(0,0))
self.connect_inst(["A", "zb_int", "vdd", "gnd"])
# Add INV2 to the right
self.inv2_inst=self.add_inst(name="buf_inv2",
mod=self.inv1,
offset=vector(self.inv1_inst.rx(),0))
self.connect_inst(["zb_int", "z_int", "vdd", "gnd"])
# Add INV3 to the right
self.inv3_inst=self.add_inst(name="buf_inv3",
mod=self.inv2,
offset=vector(self.inv2_inst.rx(),0))
self.connect_inst(["z_int", "Zb", "vdd", "gnd"])
# Add INV4 to the bottom
self.inv4_inst=self.add_inst(name="buf_inv4",
mod=self.inv2,
offset=vector(self.inv2_inst.rx(),2*self.inv2.height),
mirror = "MX")
self.connect_inst(["zb_int", "Z", "vdd", "gnd"])
def add_wires(self):
# inv1 Z to inv2 A
z1_pin = self.inv1_inst.get_pin("Z")
a2_pin = self.inv2_inst.get_pin("A")
mid_point = vector(z1_pin.cx(), a2_pin.cy())
self.add_path("metal1", [z1_pin.center(), mid_point, a2_pin.center()])
# inv2 Z to inv3 A
z2_pin = self.inv2_inst.get_pin("Z")
a3_pin = self.inv3_inst.get_pin("A")
mid_point = vector(z2_pin.cx(), a3_pin.cy())
self.add_path("metal1", [z2_pin.center(), mid_point, a3_pin.center()])
# inv1 Z to inv4 A (up and over)
z1_pin = self.inv1_inst.get_pin("Z")
a4_pin = self.inv4_inst.get_pin("A")
mid_point = vector(z1_pin.cx(), a4_pin.cy())
self.add_wire(("metal1","via1","metal2"), [z1_pin.center(), mid_point, a4_pin.center()])
self.add_via_center(layers=("metal1","via1","metal2"),
offset=z1_pin.center())
def add_layout_pins(self):
# Continous vdd rail along with label.
vdd_pin=self.inv1_inst.get_pin("vdd")
self.add_layout_pin(text="vdd",
layer="metal1",
offset=vdd_pin.ll().scale(0,1),
width=self.width,
height=vdd_pin.height())
# Continous vdd rail along with label.
gnd_pin=self.inv4_inst.get_pin("gnd")
self.add_layout_pin(text="gnd",
layer="metal1",
offset=gnd_pin.ll().scale(0,1),
width=self.width,
height=gnd_pin.height())
# Continous gnd rail along with label.
gnd_pin=self.inv1_inst.get_pin("gnd")
self.add_layout_pin(text="gnd",
layer="metal1",
offset=gnd_pin.ll().scale(0,1),
width=self.width,
height=vdd_pin.height())
z_pin = self.inv4_inst.get_pin("Z")
self.add_layout_pin_rect_center(text="Z",
layer="metal2",
offset=z_pin.center())
self.add_via_center(layers=("metal1","via1","metal2"),
offset=z_pin.center())
zb_pin = self.inv3_inst.get_pin("Z")
self.add_layout_pin_rect_center(text="Zb",
layer="metal2",
offset=zb_pin.center())
self.add_via_center(layers=("metal1","via1","metal2"),
offset=zb_pin.center())
a_pin = self.inv1_inst.get_pin("A")
self.add_layout_pin_rect_center(text="A",
layer="metal2",
offset=a_pin.center())
self.add_via_center(layers=("metal1","via1","metal2"),
offset=a_pin.center())
def analytical_delay(self, slew, load=0.0):
""" Calculate the analytical delay of DFF-> INV -> INV """
inv1_delay = self.inv1.analytical_delay(slew=slew, load=self.inv2.input_load())
inv2_delay = self.inv2.analytical_delay(slew=inv1_delay.slew, load=load)
return inv1_delay + inv2_delay

View File

@ -102,12 +102,12 @@ class pnand2(pgate.pgate):
def add_supply_rails(self):
""" Add vdd/gnd rails to the top and bottom. """
self.add_layout_pin_center_rect(text="gnd",
self.add_layout_pin_rect_center(text="gnd",
layer="metal1",
offset=vector(0.5*self.width,0),
width=self.width)
self.add_layout_pin_center_rect(text="vdd",
self.add_layout_pin_rect_center(text="vdd",
layer="metal1",
offset=vector(0.5*self.width,self.height),
width=self.width)
@ -197,7 +197,7 @@ class pnand2(pgate.pgate):
self.add_path("metal2",[pmos_pin.bc(), mid_offset, nmos_pin.uc()])
# This extends the output to the edge of the cell
self.add_layout_pin_center_rect(text="Z",
self.add_layout_pin_rect_center(text="Z",
layer="metal1",
offset=mid_offset,
width=contact.m1m2.first_layer_height,

View File

@ -100,12 +100,12 @@ class pnand3(pgate.pgate):
def add_supply_rails(self):
""" Add vdd/gnd rails to the top and bottom. """
self.add_layout_pin_center_rect(text="gnd",
self.add_layout_pin_rect_center(text="gnd",
layer="metal1",
offset=vector(0.5*self.width,0),
width=self.width)
self.add_layout_pin_center_rect(text="vdd",
self.add_layout_pin_rect_center(text="vdd",
layer="metal1",
offset=vector(0.5*self.width,self.height),
width=self.width)
@ -218,7 +218,7 @@ class pnand3(pgate.pgate):
# This extends the output to the edge of the cell
self.add_contact_center(layers=("metal1", "via1", "metal2"),
offset=mid_offset)
self.add_layout_pin_center_rect(text="Z",
self.add_layout_pin_rect_center(text="Z",
layer="metal1",
offset=mid_offset,
width=contact.m1m2.first_layer_width,

View File

@ -106,12 +106,12 @@ class pnor2(pgate.pgate):
def add_supply_rails(self):
""" Add vdd/gnd rails to the top and bottom. """
self.add_layout_pin_center_rect(text="gnd",
self.add_layout_pin_rect_center(text="gnd",
layer="metal1",
offset=vector(0.5*self.width,0),
width=self.width)
self.add_layout_pin_center_rect(text="vdd",
self.add_layout_pin_rect_center(text="vdd",
layer="metal1",
offset=vector(0.5*self.width,self.height),
width=self.width)
@ -208,7 +208,7 @@ class pnor2(pgate.pgate):
self.add_contact_center(layers=("metal1", "via1", "metal2"),
offset=mid3_offset,
rotate=90)
self.add_layout_pin_center_rect(text="Z",
self.add_layout_pin_rect_center(text="Z",
layer="metal1",
offset=mid3_offset,
width=contact.m1m2.first_layer_height,
@ -240,4 +240,4 @@ class pnor2(pgate.pgate):
c_para = spice["min_tx_drain_c"]*(self.nmos_size/parameter["min_tx_size"])#ff
transistion_prob = spice["nor2_transisition_prob"]
return transistion_prob*(c_load + c_para)

View File

@ -57,13 +57,25 @@ class precharge(pgate.pgate):
"""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)
self.add_layout_pin(text="vdd",
layer="metal1",
offset=vdd_position,
width=self.width,
height=self.m1_width)
self.add_rect(layer="metal1",
offset=vdd_position,
width=self.width,
height=self.m1_width)
self.connect_pin_to_rail(self.upper_pmos2_inst,"S","vdd")
pmos_pin = self.upper_pmos2_inst.get_pin("S")
# center of vdd rail
vdd_pos = vector(pmos_pin.cx(), vdd_position.y + 0.5*self.m1_width)
self.add_path("metal1", [pmos_pin.uc(), vdd_pos])
# Add the M1->M2->M3 stack at the left edge
self.add_via_center(layers=("metal1", "via1", "metal2"),
offset=vdd_pos.scale(0,1))
self.add_via_center(layers=("metal2", "via2", "metal3"),
offset=vdd_pos.scale(0,1))
self.add_layout_pin_rect_center(text="vdd",
layer="metal3",
offset=vdd_pos.scale(0,1))
def add_ptx(self):
"""Adds both the upper_pmos and lower_pmos to the module"""
@ -118,7 +130,7 @@ class precharge(pgate.pgate):
rotate=90)
# adds the en rail on metal1
self.add_layout_pin_center_segment(text="en",
self.add_layout_pin_segment_center(text="en",
layer="metal1",
start=offset.scale(0,1),
end=offset.scale(0,1)+vector(self.width,0))

View File

@ -210,7 +210,7 @@ class ptx(design.design):
for a in source_positions:
self.add_path(("metal1"), [a,a+pin_offset.scale(source_dir,source_dir)])
# Add a single horizontal pin
self.add_layout_pin_center_segment(text="S",
self.add_layout_pin_segment_center(text="S",
layer="metal1",
start=source_positions[0]+source_offset-end_offset,
end=source_positions[-1]+source_offset+end_offset)
@ -222,7 +222,7 @@ class ptx(design.design):
for a in drain_positions:
self.add_path(("metal1"), [a,a+drain_offset])
# Add a single horizontal pin
self.add_layout_pin_center_segment(text="D",
self.add_layout_pin_segment_center(text="D",
layer="metal1",
start=drain_positions[0]+drain_offset-end_offset,
end=drain_positions[-1]+drain_offset+end_offset)
@ -246,7 +246,7 @@ class ptx(design.design):
offset=poly_offset,
height=self.poly_height,
width=self.poly_width)
self.add_layout_pin_center_rect(text="G",
self.add_layout_pin_rect_center(text="G",
layer="poly",
offset=poly_offset,
height=self.poly_height,
@ -329,7 +329,7 @@ class ptx(design.design):
size=(1, self.num_contacts),
implant_type=self.implant_type,
well_type=self.well_type)
self.add_layout_pin_center_rect(text="S",
self.add_layout_pin_rect_center(text="S",
layer="metal1",
offset=pos,
width=contact.mod.second_layer_width,
@ -342,7 +342,7 @@ class ptx(design.design):
size=(1, self.num_contacts),
implant_type=self.implant_type,
well_type=self.well_type)
self.add_layout_pin_center_rect(text="D",
self.add_layout_pin_rect_center(text="D",
layer="metal1",
offset=pos,
width=contact.mod.second_layer_width,

View File

@ -32,7 +32,6 @@ class single_level_column_mux(design.design):
self.width = self.bitcell.width
self.height = self.nmos2.uy() + self.pin_height
self.connect_poly()
self.add_gnd_rail()
self.add_bitline_pins()
self.connect_bitlines()
self.add_wells()
@ -137,37 +136,28 @@ class single_level_column_mux(design.design):
self.add_path("metal2",[br_pin.bc(), mid1, mid2, nmos1_d_pin.uc()])
def add_gnd_rail(self):
""" Add the gnd rails through the cell to connect to the bitcell array """
gnd_pins = self.bitcell.get_pins("gnd")
for gnd_pin in gnd_pins:
# only use vertical gnd pins that span the whole cell
if gnd_pin.layer == "metal2" and gnd_pin.height >= self.bitcell.height:
gnd_position = vector(gnd_pin.lx(), 0)
self.add_layout_pin(text="gnd",
layer="metal2",
offset=gnd_position,
height=self.height)
def add_wells(self):
""" Add a well and implant over the whole cell. Also, add the pwell contact (if it exists) """
# find right most gnd rail
gnd_pins = self.bitcell.get_pins("gnd")
right_gnd = None
for gnd_pin in gnd_pins:
if right_gnd == None or gnd_pin.lx()>right_gnd.lx():
right_gnd = gnd_pin
# Add to the right (first) gnd rail
m1m2_offset = right_gnd.bc() + vector(0,0.5*self.nmos.poly_height)
self.add_via_center(layers=("metal1", "via1", "metal2"),
offset=m1m2_offset)
active_offset = right_gnd.bc() + vector(0,0.5*self.nmos.poly_height)
"""
Add a well and implant over the whole cell. Also, add the
pwell contact (if it exists)
"""
# Add it to the right, aligned in between the two tx
active_pos = self.nmos2.lr().scale(0,0.5) + self.nmos1.ur().scale(1,0.5)
self.add_via_center(layers=("active", "contact", "metal1"),
offset=active_offset,
offset=active_pos,
implant_type="p",
well_type="p")
# Add the M1->M2->M3 stack
self.add_via_center(layers=("metal1", "via1", "metal2"),
offset=active_pos)
self.add_via_center(layers=("metal2", "via2", "metal3"),
offset=active_pos)
self.add_layout_pin_rect_center(text="gnd",
layer="metal3",
offset=active_pos)

View File

@ -5,6 +5,8 @@ import design
from math import log,sqrt,ceil
import contact
from bank import bank
from dff_buf_array import dff_buf_array
from dff_array import dff_array
import datetime
import getpass
from vector import vector
@ -16,15 +18,11 @@ class sram(design.design):
Dynamically generated SRAM by connecting banks to control logic. The
number of banks should be 1 , 2 or 4
"""
def __init__(self, word_size, num_words, num_banks, name):
c = reload(__import__(OPTS.control_logic))
self.mod_control_logic = getattr(c, OPTS.control_logic)
c = reload(__import__(OPTS.ms_flop_array))
self.mod_ms_flop_array = getattr(c, OPTS.ms_flop_array)
c = reload(__import__(OPTS.bitcell))
self.mod_bitcell = getattr(c, OPTS.bitcell)
self.bitcell = self.mod_bitcell()
@ -49,9 +47,6 @@ class sram(design.design):
design.design.__init__(self, name)
# For different layer width vias
self.m2m3_offset_fix = vector(0,0.5*(self.m3_width-self.m2_width))
# M1/M2 routing pitch is based on contacted pitch of the biggest layer
self.m1_pitch = max(contact.m1m2.width,contact.m1m2.height) + max(self.m1_space,self.m2_space)
self.m2_pitch = max(contact.m2m3.width,contact.m2m3.height) + max(self.m2_space,self.m3_space)
@ -62,6 +57,7 @@ class sram(design.design):
self.bank_to_bus_distance = 5*self.m3_width
self.compute_sizes()
self.create_modules()
self.add_pins()
self.create_layout()
@ -146,8 +142,8 @@ class sram(design.design):
self.add_pin("ADDR[{0}]".format(i),"INPUT")
# These are used to create the physical pins too
self.control_logic_inputs=["CSb", "WEb", "OEb", "clk"]
self.control_logic_outputs=["s_en", "w_en", "tri_en", "tri_en_bar", "clk_bar", "clk_buf"]
self.control_logic_inputs=self.control_logic.get_inputs()
self.control_logic_outputs=self.control_logic.get_outputs()
self.add_pin_list(self.control_logic_inputs,"INPUT")
self.add_pin("vdd","POWER")
@ -156,8 +152,6 @@ class sram(design.design):
def create_layout(self):
""" Layout creation """
self.create_modules()
if self.num_banks == 1:
self.add_single_bank_modules()
self.add_single_bank_pins()
@ -170,15 +164,17 @@ class sram(design.design):
self.route_four_banks()
else:
debug.error("Invalid number of banks.",-1)
def add_four_bank_modules(self):
""" Adds the modules and the buses to the top level """
self.compute_four_bank_offsets()
self.compute_bus_sizes()
self.add_four_banks()
self.compute_four_bank_offsets()
self.add_busses()
self.add_four_bank_logic()
@ -190,10 +186,12 @@ class sram(design.design):
def add_two_bank_modules(self):
""" Adds the modules and the buses to the top level """
self.compute_two_bank_offsets()
self.compute_bus_sizes()
self.add_two_banks()
self.compute_two_bank_offsets()
self.add_busses()
self.add_two_bank_logic()
@ -201,13 +199,39 @@ class sram(design.design):
self.width = self.bank_inst[1].ur().x
self.height = self.control_logic_inst.uy()
def add_single_bank_modules(self):
"""
This adds the moduels for a single bank SRAM with control
logic.
"""
# No orientation or offset
self.bank_inst = self.add_bank(0, [0, 0], 1, 1)
# 3/5/18 MRG: Cannot reference positions inside submodules because boundaries
# are not recomputed using instance placement. So, place the control logic such that it aligns
# with the top of the SRAM.
control_pos = vector(-self.control_logic.width - self.m3_pitch,
3*self.supply_rail_width)
self.add_control_logic(position=control_pos)
# Leave room for the control routes to the left of the flops
addr_pos = vector(self.control_logic_inst.lx() + 4*self.m2_pitch,
control_pos.y + self.control_logic.height + self.m1_pitch)
self.add_addr_dff(addr_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
def route_shared_banks(self):
""" Route the shared signals for two and four bank configurations. """
# create the input control pins
for n in self.control_logic_inputs:
self.copy_layout_pin(self.control_logic_inst, n.lower(), n)
for n in self.control_logic_inputs + ["clk"]:
self.copy_layout_pin(self.control_logic_inst, n)
# connect the control logic to the control bus
for n in self.control_logic_outputs + ["vdd", "gnd"]:
@ -233,7 +257,6 @@ class sram(design.design):
self.add_path("metal3",[pin_pos,rail_pos])
self.add_via_center(("metal2","via2","metal3"),rail_pos)
def route_four_banks(self):
""" Route all of the signals for the four bank SRAM. """
@ -274,7 +297,7 @@ class sram(design.design):
self.add_via_center(("metal2","via2","metal3"),rail_pos)
self.route_bank_supply_rails(bottom_banks=[2,3])
self.route_bank_supply_rails(left_banks=[0,2], bottom_banks=[2,3])
@ -310,16 +333,14 @@ class sram(design.design):
# The main difference is that the four bank SRAM has the data bus in the middle of the four banks
# as opposed to the top of the banks.
self.compute_bus_sizes()
# In 4 bank SRAM, the height is determined by the bank decoder and address flop
self.vertical_bus_height = 2*self.bank.height + 4*self.bank_to_bus_distance + self.data_bus_height \
+ self.supply_bus_height + self.msb_decoder.height + self.msb_address.width
# The address bus extends down through the power rails, but control and bank_sel bus don't
self.addr_bus_height = self.vertical_bus_height + 2*self.power_rail_pitch
self.addr_bus_height = self.vertical_bus_height
self.vertical_bus_offset = vector(self.bank.width + self.bank_to_bus_distance, 2*self.power_rail_pitch)
self.data_bus_offset = vector(0, 2*self.power_rail_pitch + self.bank.height + self.bank_to_bus_distance)
self.vertical_bus_offset = vector(self.bank.width + self.bank_to_bus_distance, 0)
self.data_bus_offset = vector(0, self.bank.height + self.bank_to_bus_distance)
self.supply_bus_offset = vector(0, self.data_bus_offset.y + self.data_bus_height + self.bank.height + 2*self.bank_to_bus_distance)
self.control_bus_offset = vector(0, self.supply_bus_offset.y + self.supply_bus_height)
self.bank_sel_bus_offset = self.vertical_bus_offset + vector(self.m2_pitch*self.control_size,0)
@ -330,7 +351,7 @@ class sram(design.design):
# Bank select flops get put to the right of control logic above bank1 and the buses
# Leave a pitch to get the vdd rails up to M2
self.msb_address_position = vector(max(self.bank.width + self.vertical_bus_width + 2*self.bank_to_bus_distance, self.control_logic.width),
self.msb_address_position = vector(self.bank_inst[1].lx() + 3*self.supply_rail_pitch,
self.supply_bus_offset.y + self.supply_bus_height + 2*self.m1_pitch + self.msb_address.width)
# Decoder goes above the MSB address flops, and is flipped in Y
@ -341,15 +362,13 @@ class sram(design.design):
def compute_two_bank_offsets(self):
""" Compute the overall offsets for a two bank SRAM """
self.compute_bus_sizes()
# In 2 bank SRAM, the height is determined by the control bus which is higher than the msb address
self.vertical_bus_height = self.bank.height + 2*self.bank_to_bus_distance + self.data_bus_height + self.control_bus_height
# The address bus extends down through the power rails, but control and bank_sel bus don't
self.addr_bus_height = self.vertical_bus_height + 2*self.power_rail_pitch
self.addr_bus_height = self.vertical_bus_height
self.vertical_bus_offset = vector(self.bank.width + self.bank_to_bus_distance, 2*self.power_rail_pitch)
self.data_bus_offset = vector(0, 2*self.power_rail_pitch + self.bank.height + self.bank_to_bus_distance)
self.vertical_bus_offset = vector(self.bank.width + self.bank_to_bus_distance, 0)
self.data_bus_offset = vector(0, self.bank.height + self.bank_to_bus_distance)
self.supply_bus_offset = vector(0, self.data_bus_offset.y + self.data_bus_height)
self.control_bus_offset = vector(0, self.supply_bus_offset.y + self.supply_bus_height)
self.bank_sel_bus_offset = self.vertical_bus_offset + vector(self.m2_pitch*self.control_size,0)
@ -360,14 +379,14 @@ class sram(design.design):
# Bank select flops get put to the right of control logic above bank1 and the buses
# Leave a pitch to get the vdd rails up to M2
self.msb_address_position = vector(max(self.bank.width + self.vertical_bus_width + 2*self.bank_to_bus_distance,self.control_logic.width),
self.msb_address_position = vector(self.bank_inst[1].lx() + 3*self.supply_rail_pitch,
self.supply_bus_offset.y+self.supply_bus_height + 2*self.m1_pitch + self.msb_address.width)
def add_busses(self):
""" Add the horizontal and vertical busses """
# Vertical bus
# The order of the control signals on the control bus:
self.control_bus_names = ["clk_buf", "tri_en_bar", "tri_en", "clk_bar", "w_en", "s_en"]
self.control_bus_names = ["clk_buf", "tri_en_bar", "tri_en", "clk_buf_bar", "w_en", "s_en"]
self.vert_control_bus_positions = self.create_bus(layer="metal2",
pitch=self.m2_pitch,
offset=self.vertical_bus_offset,
@ -375,7 +394,7 @@ class sram(design.design):
length=self.vertical_bus_height,
vertical=True)
self.addr_bus_names=["ADDR[{}]".format(i) for i in range(self.addr_size)]
self.addr_bus_names=["A[{}]".format(i) for i in range(self.addr_size)]
self.vert_control_bus_positions.update(self.create_bus(layer="metal2",
pitch=self.m2_pitch,
offset=self.addr_bus_offset,
@ -391,7 +410,8 @@ class sram(design.design):
offset=self.bank_sel_bus_offset,
names=self.bank_sel_bus_names,
length=self.vertical_bus_height,
vertical=True))
vertical=True,
make_pins=True))
# Horizontal data bus
@ -419,7 +439,7 @@ class sram(design.design):
pitch=self.m1_pitch,
offset=self.supply_bus_offset+vector(0,self.m1_pitch),
names=["gnd"],
length=self.supply_bus_width-2*self.power_rail_width,
length=self.supply_bus_width,
vertical=False))
self.horz_control_bus_positions.update(self.create_bus(layer="metal1",
pitch=self.m1_pitch,
@ -431,7 +451,7 @@ class sram(design.design):
def add_two_bank_logic(self):
""" Add the control and MSB logic """
self.add_control_logic(position=self.control_logic_position, rotate=0)
self.add_control_logic(position=self.control_logic_position)
self.msb_address_inst = self.add_inst(name="msb_address",
mod=self.msb_address,
@ -444,7 +464,7 @@ class sram(design.design):
""" Add the control and MSB decode/bank select logic for four banks """
self.add_control_logic(position=self.control_logic_position, rotate=0)
self.add_control_logic(position=self.control_logic_position)
self.msb_address_inst = self.add_inst(name="msb_address",
mod=self.msb_address,
@ -497,13 +517,9 @@ class sram(design.design):
self.add_via_center(("metal2","via2","metal3"),rail_pos)
self.route_bank_supply_rails(bottom_banks=[0,1])
def route_double_msb_address(self):
""" Route two MSB address bits and the bank decoder for 4-bank SRAM """
# connect the MSB flops to the address input bus
for i in [0,1]:
@ -551,68 +567,107 @@ class sram(design.design):
self.add_wire(("metal1","via1","metal2"),[msb_pin_pos,out_pos,up_pos,in_pos])
self.add_via_center(("metal1","via1","metal2"),in_pos)
self.add_via_center(("metal1","via1","metal2"),msb_pin_pos,rotate=90)
self.route_double_msb_address_supplies()
def route_double_msb_address_supplies(self):
""" Route the vdd/gnd bits of the 2-bit bank decoder. """
# Route the right-most vdd/gnd of the right upper bank to the top of the decoder
vdd_pins = self.bank_inst[1].get_pins("vdd")
highest_x = None
for bank_vdd_pin in vdd_pins:
if highest_x == None or bank_vdd_pin.lx()>highest_x:
highest_x = bank_vdd_pin.lx()
bank_vdd_pos = bank_vdd_pin.ul()
# Route to top
self.add_rect(layer="metal1",
offset=bank_vdd_pos,
height=self.height-bank_vdd_pos.y,
width=bank_vdd_pin.width())
left_bank_vdd_pin = None
right_bank_vdd_pin = None
for vdd_pin in vdd_pins:
if vdd_pin.layer != "metal2":
continue
if left_bank_vdd_pin == None or vdd_pin.lx()<left_bank_vdd_pin.lx():
left_bank_vdd_pin = vdd_pin
if right_bank_vdd_pin == None or vdd_pin.lx()>right_bank_vdd_pin.lx():
right_bank_vdd_pin = vdd_pin
# Route to top
self.add_rect(layer="metal2",
offset=vdd_pin.ul(),
height=self.height-vdd_pin.uy(),
width=vdd_pin.width())
gnd_pins = self.bank_inst[1].get_pins("gnd")
highest_x = None
for bank_gnd_pin in gnd_pins:
if highest_x == None or bank_gnd_pin.lx()>highest_x:
highest_x = bank_gnd_pin.lx()
bank_gnd_pos = bank_gnd_pin.ul()
# Route to top
self.add_rect(layer="metal2",
offset=bank_gnd_pos,
height=self.height-bank_gnd_pos.y,
width=bank_gnd_pin.width())
left_bank_gnd_pin = None
right_bank_gnd_pin = None
for gnd_pin in gnd_pins:
if gnd_pin.layer != "metal2":
continue
if left_bank_gnd_pin == None or gnd_pin.lx()<left_bank_gnd_pin.lx():
left_bank_gnd_pin = gnd_pin
if right_bank_gnd_pin == None or gnd_pin.lx()>right_bank_gnd_pin.lx():
right_bank_gnd_pin = gnd_pin
# Route to top
self.add_rect(layer="metal2",
offset=gnd_pin.ul(),
height=self.height-gnd_pin.uy(),
width=gnd_pin.width())
# Connect bank decoder vdd/gnd supplies using the previous bank_vdd_pos and bank_gnd_pos
# Connect bank decoder vdd/gnd supplies using the previous bank pins
vdd_pins = self.msb_decoder_inst.get_pins("vdd")
for vdd_pin in vdd_pins:
if vdd_pin.layer != "metal1": continue
vdd_pos = vdd_pin.rc()
rail_pos = vector(bank_vdd_pos.x+bank_vdd_pin.width(),vdd_pos.y)
self.add_path("metal1",[vdd_pos,rail_pos])
if vdd_pin.layer != "metal1":
continue
rail1_pos = vector(left_bank_vdd_pin.cx(),vdd_pin.cy())
rail2_pos = vector(right_bank_vdd_pin.cx(),vdd_pin.cy())
self.add_path("metal1",[rail1_pos,rail2_pos])
self.add_via_center(layers=("metal1","via1","metal2"),
offset=rail1_pos,
rotate=90,
size=[1,3])
self.add_via_center(layers=("metal1","via1","metal2"),
offset=rail2_pos,
rotate=90,
size=[1,3])
gnd_pins = self.msb_decoder_inst.get_pins("gnd")
for gnd_pin in gnd_pins:
if gnd_pin.layer != "metal1": continue
gnd_pos = gnd_pin.rc()
rail_pos = vector(bank_gnd_pos.x+bank_gnd_pin.width(),gnd_pos.y)
self.add_path("metal1",[gnd_pos,rail_pos])
self.add_via(("metal1","via1","metal2"),rail_pos- vector(0,0.5*self.m1_width),rotate=90,size=[1,3])
if gnd_pin.layer != "metal1":
continue
rail1_pos = vector(left_bank_gnd_pin.cx(),gnd_pin.cy())
rail2_pos = vector(right_bank_gnd_pin.cx(),gnd_pin.cy())
self.add_path("metal1",[rail1_pos,rail2_pos])
self.add_via_center(layers=("metal1","via1","metal2"),
offset=rail1_pos,
rotate=90,
size=[1,3])
self.add_via_center(layers=("metal1","via1","metal2"),
offset=rail2_pos,
rotate=90,
size=[1,3])
# connect the bank MSB flop supplies
vdd_pins = self.msb_address_inst.get_pins("vdd")
# vdd pins go down to the rail
for vdd_pin in vdd_pins:
if vdd_pin.layer != "metal1": continue
if vdd_pin.layer != "metal1":
continue
vdd_pos = vdd_pin.bc()
down_pos = vdd_pos - vector(0,self.m1_pitch)
rail_pos = vector(vdd_pos.x,self.horz_control_bus_positions["vdd"].y)
self.add_path("metal1",[vdd_pos,down_pos])
self.add_via_center(("metal1","via1","metal2"),down_pos,rotate=90)
self.add_via_center(layers=("metal1","via1","metal2"),
offset=down_pos,
rotate=90)
self.add_path("metal2",[down_pos,rail_pos])
self.add_via_center(("metal1","via1","metal2"),rail_pos)
self.add_via_center(layers=("metal1","via1","metal2"),
offset=rail_pos)
# gnd pins go right to the rail
gnd_pins = self.msb_address_inst.get_pins("gnd")
for gnd_pin in gnd_pins:
if gnd_pin.layer != "metal2": continue
gnd_pos = gnd_pin.rc()
rail_pos = vector(bank_gnd_pos.x+bank_gnd_pin.width(),gnd_pos.y)
self.add_path("metal1",[gnd_pos,rail_pos])
self.add_via_center(("metal1","via1","metal2"),gnd_pos,rotate=90)
self.add_via(("metal1","via1","metal2"),rail_pos- vector(0,0.5*self.m1_width),rotate=90,size=[1,3])
if gnd_pin.layer != "metal2":
continue
rail1_pos = vector(left_bank_gnd_pin.cx(),gnd_pin.cy())
self.add_path("metal1",[rail1_pos,gnd_pin.lc()])
self.add_via_center(layers=("metal1","via1","metal2"),
offset=gnd_pin.lc(),
rotate=90)
self.add_via_center(layers=("metal1","via1","metal2"),
offset=rail1_pos,
rotate=90,
size=[1,3])
def route_single_msb_address(self):
""" Route one MSB address bit for 2-bank SRAM """
@ -681,61 +736,41 @@ class sram(design.design):
def route_bank_supply_rails(self, bottom_banks):
""" Create rails at bottom. Connect veritcal rails to top and bottom. """
def route_vdd_gnd(self):
""" Propagate all vdd/gnd pins up to this level for all modules """
# These are the instances that every bank has
top_instances = [self.bitcell_array_inst,
self.precharge_array_inst,
self.sense_amp_array_inst,
self.write_driver_array_inst,
self.tri_gate_array_inst,
self.row_decoder_inst,
self.wordline_driver_inst]
# Add these if we use the part...
if self.col_addr_size > 0:
top_instances.append(self.col_decoder_inst)
top_instances.append(self.col_mux_array_inst)
if self.num_banks > 1:
top_instances.append(self.bank_select_inst)
self.add_layout_pin(text="gnd",
layer="metal3",
offset=vector(0,0),
height=self.power_rail_width,
width=self.width)
self.add_layout_pin(text="vdd",
layer="metal1",
offset=vector(0,self.power_rail_pitch),
height=self.power_rail_width,
width=self.width)
# route bank vertical rails to bottom
for i in bottom_banks:
vdd_pins = self.bank_inst[i].get_pins("vdd")
for vdd_pin in vdd_pins:
vdd_pos = vdd_pin.ul()
# Route to bottom
self.add_rect(layer="metal1",
offset=vector(vdd_pos.x,self.power_rail_pitch),
height=self.horz_control_bus_positions["vdd"].y-self.power_rail_pitch,
width=vdd_pin.width())
gnd_pins = self.bank_inst[i].get_pins("gnd")
for gnd_pin in gnd_pins:
gnd_pos = gnd_pin.ul()
# Route to bottom
self.add_rect(layer="metal2",
offset=vector(gnd_pos.x,0),
height=self.horz_control_bus_positions["gnd"].y, # route to the top bank
width=gnd_pin.width())
# Add vias at top
right_rail_pos = vector(gnd_pin.ur().x,self.horz_control_bus_positions["gnd"].y)
self.add_via(layers=("metal1","via1","metal2"),
offset=right_rail_pos - vector(0,0.5*self.m1_width),
rotate=90,
size=[1,3])
# Add vias at bottom
right_rail_pos = vector(gnd_pin.lr().x,0)
self.add_via(layers=("metal2","via2","metal3"),
offset=right_rail_pos,
rotate=90,
size=[2,3])
for inst in top_instances:
# Column mux has no vdd
if self.col_addr_size==0 or (self.col_addr_size>0 and inst != self.col_mux_array_inst):
self.copy_layout_pin(inst, "vdd")
# Precharge has no gnd
if inst != self.precharge_array_inst:
self.copy_layout_pin(inst, "gnd")
def create_multi_bank_modules(self):
""" Create the multibank address flops and bank decoder """
self.msb_address = self.mod_ms_flop_array(name="msb_address",
columns=self.num_banks/2,
word_size=self.num_banks/2)
self.msb_address = dff_buf_array(name="msb_address",
rows=1,
columns=self.num_banks/2)
self.add_mod(self.msb_address)
if self.num_banks>2:
@ -749,6 +784,11 @@ class sram(design.design):
self.control_logic = self.mod_control_logic(num_rows=self.num_rows)
self.add_mod(self.control_logic)
# Create the address and control flops (but not the clk)
dff_size = self.addr_size
self.addr_dff = dff_array(name="dff_array", rows=dff_size, columns=1)
self.add_mod(self.addr_dff)
# Create the bank module (up to four are instantiated)
self.bank = bank(word_size=self.word_size,
num_words=self.num_words_per_bank,
@ -757,15 +797,14 @@ class sram(design.design):
name="bank")
self.add_mod(self.bank)
# Conditionally create the
# Create bank decoder
if(self.num_banks > 1):
self.create_multi_bank_modules()
self.bank_count = 0
self.power_rail_width = self.bank.vdd_rail_width
# Leave some extra space for the pitch
self.power_rail_pitch = self.bank.vdd_rail_width + 2*self.m3_space
self.supply_rail_width = self.bank.supply_rail_width
self.supply_rail_pitch = self.bank.supply_rail_pitch
@ -801,13 +840,15 @@ class sram(design.design):
temp = []
for i in range(self.word_size):
temp.append("DATA[{0}]".format(i))
temp.append("DOUT[{0}]".format(i))
for i in range(self.word_size):
temp.append("DIN[{0}]".format(i))
for i in range(self.bank_addr_size):
temp.append("ADDR[{0}]".format(i))
temp.append("A[{0}]".format(i))
if(self.num_banks > 1):
temp.append("bank_sel[{0}]".format(bank_num))
temp.extend(["s_en", "w_en", "tri_en_bar", "tri_en",
"clk_bar","clk_buf" , "vdd", "gnd"])
"clk_buf_bar","clk_buf" , "vdd", "gnd"])
self.connect_inst(temp)
return bank_inst
@ -852,13 +893,33 @@ class sram(design.design):
return line_positions
def add_control_logic(self, position, rotate):
def add_addr_dff(self, position):
""" Add and place address and control flops """
self.addr_dff_inst = self.add_inst(name="address",
mod=self.addr_dff,
offset=position)
# inputs, outputs/output/bar
inputs = []
outputs = []
for i in range(self.addr_size):
inputs.append("ADDR[{}]".format(i))
outputs.append("A[{}]".format(i))
self.connect_inst(inputs + outputs + ["clk_buf", "vdd", "gnd"])
def add_control_logic(self, position):
""" Add and place control logic """
inputs = []
for i in self.control_logic_inputs:
if i != "clk":
inputs.append(i+"_s")
else:
inputs.append(i)
self.control_logic_inst=self.add_inst(name="control",
mod=self.control_logic,
offset=position,
rotate=rotate)
self.connect_inst(self.control_logic_inputs + self.control_logic_outputs + ["vdd", "gnd"])
offset=position)
self.connect_inst(inputs + self.control_logic_outputs + ["vdd", "gnd"])
def add_lvs_correspondence_points(self):
@ -877,48 +938,22 @@ class sram(design.design):
layer="metal2",
offset=self.vert_control_bus_positions[n])
def add_single_bank_modules(self):
"""
This adds the moduels for a single bank SRAM with control
logic.
"""
# No orientation or offset
self.bank_inst = self.add_bank(0, [0, 0], 1, 1)
# Control logic is placed to the left of the blank even with the
# decoder bottom. A small gap is in the x-dimension.
control_gap = 2*self.m3_width
pos = vector(-control_gap,
self.bank.row_decoder_inst.by() + 2*self.m3_width)
self.add_control_logic(position=pos,
rotate=90)
self.width = self.bank.width + self.control_logic.height + control_gap
self.height = self.bank.height
def add_single_bank_pins(self):
"""
Add the top-level pins for a single bank SRAM with control.
"""
for i in range(self.word_size):
self.copy_layout_pin(self.bank_inst, "DATA[{}]".format(i))
self.copy_layout_pin(self.bank_inst, "DOUT[{}]".format(i))
for i in range(self.addr_size):
self.copy_layout_pin(self.bank_inst, "ADDR[{}]".format(i))
for (old,new) in zip(["csb","web","oeb","clk"],["CSb","WEb","OEb","clk"]):
self.copy_layout_pin(self.control_logic_inst, old, new)
self.copy_layout_pin(self.bank_inst, "vdd")
self.copy_layout_pin(self.bank_inst, "gnd")
self.copy_layout_pin(self.addr_dff_inst, "din[{}]".format(i),"ADDR[{}]".format(i))
def add_two_banks(self):
# Placement of bank 0 (left)
bank_position_0 = vector(self.bank.width,
self.bank.height + 2*self.power_rail_pitch)
self.bank.height)
self.bank_inst=[self.add_bank(0, bank_position_0, -1, -1)]
# Placement of bank 1 (right)
@ -931,7 +966,7 @@ class sram(design.design):
# Placement of bank 0 (upper left)
bank_position_0 = vector(self.bank.width,
self.bank.height + self.data_bus_height + 2*self.bank_to_bus_distance + 2*self.power_rail_pitch)
self.bank.height + self.data_bus_height + 2*self.bank_to_bus_distance)
self.bank_inst=[self.add_bank(0, bank_position_0, 1, -1)]
# Placement of bank 1 (upper right)
@ -940,7 +975,7 @@ class sram(design.design):
self.bank_inst.append(self.add_bank(1, bank_position_1, 1, 1))
# Placement of bank 2 (bottom left)
y_off = self.bank.height + 2*self.power_rail_pitch
y_off = self.bank.height
bank_position_2 = vector(bank_position_0.x, y_off)
self.bank_inst.append(self.add_bank(2, bank_position_2, -1, -1))
@ -954,9 +989,9 @@ class sram(design.design):
in_pos = src_pin.rc()
out_pos = vector(dest_pin.cx(), in_pos.y)
self.add_wire(("metal3","via2","metal2"),[in_pos, out_pos, out_pos - vector(0,self.m2_pitch)])
self.add_via(layers=("metal2","via2","metal3"),
offset=src_pin.lr() - self.m2m3_offset_fix,
rotate=90)
self.add_via_center(layers=("metal2","via2","metal3"),
offset=src_pin.rc(),
rotate=90)
def connect_rail_from_left_m2m1(self, src_pin, dest_pin):
""" Helper routine to connect an unrotated/mirrored oriented instance to the rails """
@ -966,26 +1001,48 @@ class sram(design.design):
def route_single_bank(self):
""" Route a single bank SRAM """
# Route the outputs from the control logic module
for n in self.control_logic_outputs:
src_pin = self.control_logic_inst.get_pin(n)
dest_pin = self.bank_inst.get_pin(n)
self.connect_rail_from_left_m2m3(src_pin, dest_pin)
src_pins = self.control_logic_inst.get_pins("vdd")
for src_pin in src_pins:
if src_pin.layer != "metal2":
continue
dest_pin = self.bank_inst.get_pins("vdd")[1]
self.connect_rail_from_left_m2m1(src_pin,dest_pin)
self.add_via_center(layers=("metal1","via1","metal2"),
offset=src_pin.rc(),
rotate=90)
src_pins = self.control_logic_inst.get_pins("gnd")
for src_pin in src_pins:
if src_pin.layer != "metal2":
continue
dest_pin = self.bank_inst.get_pin("gnd")
self.connect_rail_from_left_m2m3(src_pin,dest_pin)
# Connect the output of the flops to the bank pins
for i in range(self.addr_size):
flop_name = "dout[{}]".format(i)
bank_name = "A[{}]".format(i)
flop_pin = self.addr_dff_inst.get_pin(flop_name)
bank_pin = self.bank_inst.get_pin(bank_name)
flop_pos = flop_pin.center()
bank_pos = vector(bank_pin.cx(),flop_pos.y)
self.add_path("metal3",[flop_pos, bank_pos])
self.add_via_center(layers=("metal2","via2","metal3"),
offset=flop_pos,
rotate=90)
self.add_via_center(layers=("metal2","via2","metal3"),
offset=bank_pos,
rotate=90)
# Connect the control pins as inputs
for n in self.control_logic_inputs + ["clk"]:
self.copy_layout_pin(self.control_logic_inst, n)
# Connect the clock between the flops and control module
flop_pin = self.addr_dff_inst.get_pin("clk")
ctrl_pin = self.control_logic_inst.get_pin("clk_buf")
flop_pos = flop_pin.uc()
ctrl_pos = ctrl_pin.bc()
mid_ypos = 0.5*(ctrl_pos.y+flop_pos.y)
mid1_pos = vector(flop_pos.x, mid_ypos)
mid2_pos = vector(ctrl_pos.x, mid_ypos)
self.add_wire(("metal1","via1","metal2"),[flop_pin.uc(), mid1_pos, mid2_pos, ctrl_pin.bc()])
def sp_write(self, sp_name):
# Write the entire spice of the object to the file

View File

@ -0,0 +1,36 @@
#!/usr/bin/env python2.7
"""
Run a regresion test on a 2-row buffer cell
"""
import unittest
from testutils import header,openram_test
import sys,os
sys.path.append(os.path.join(sys.path[0],".."))
import globals
from globals import OPTS
import debug
class pinvbuf_test(openram_test):
def runTest(self):
globals.init_openram("config_20_{0}".format(OPTS.tech_name))
global verify
import verify
OPTS.check_lvsdrc = False
import pinvbuf
debug.info(2, "Testing inverter/buffer 4x 8x")
a = pinvbuf.pinvbuf(4,8)
self.local_check(a)
OPTS.check_lvsdrc = True
globals.end_openram()
# instantiate a copdsay of the class to actually run the test
if __name__ == "__main__":
(OPTS, args) = globals.parse_args()
del sys.argv[1:]
header(__file__, OPTS.tech_name)
unittest.main()

View File

@ -0,0 +1,39 @@
#!/usr/bin/env python2.7
"""
Run a regresion test on a wordline_driver array
"""
import unittest
from testutils import header,openram_test
import sys,os
sys.path.append(os.path.join(sys.path[0],".."))
import globals
from globals import OPTS
import debug
#@unittest.skip("SKIPPING 04_driver_test")
class single_level_column_mux_test(openram_test):
def runTest(self):
globals.init_openram("config_20_{0}".format(OPTS.tech_name))
global verify
import verify
OPTS.check_lvsdrc = False
import single_level_column_mux
import tech
debug.info(2, "Checking column mux")
tx = single_level_column_mux.single_level_column_mux(tx_size=8)
self.local_check(tx)
OPTS.check_lvsdrc = True
globals.end_openram()
# instantiate a copy of the class to actually run the test
if __name__ == "__main__":
(OPTS, args) = globals.parse_args()
del sys.argv[1:]
header(__file__, OPTS.tech_name)
unittest.main()

View File

@ -0,0 +1,44 @@
#!/usr/bin/env python2.7
"""
Run a regresion test on a dff_array.
"""
import unittest
from testutils import header,openram_test
import sys,os
sys.path.append(os.path.join(sys.path[0],".."))
import globals
from globals import OPTS
import debug
class dff_buf_array_test(openram_test):
def runTest(self):
globals.init_openram("config_20_{0}".format(OPTS.tech_name))
global verify
import verify
OPTS.check_lvsdrc = False
import dff_buf_array
debug.info(2, "Testing dff_buf_array for 3x3")
a = dff_buf_array.dff_buf_array(rows=3, columns=3)
self.local_check(a)
debug.info(2, "Testing dff_buf_array for 1x3")
a = dff_buf_array.dff_buf_array(rows=1, columns=3)
self.local_check(a)
debug.info(2, "Testing dff_buf_array for 3x1")
a = dff_buf_array.dff_buf_array(rows=3, columns=1)
self.local_check(a)
OPTS.check_lvsdrc = True
globals.end_openram()
# instantiate a copdsay of the class to actually run the test
if __name__ == "__main__":
(OPTS, args) = globals.parse_args()
del sys.argv[1:]
header(__file__, OPTS.tech_name)
unittest.main()

View File

@ -0,0 +1,36 @@
#!/usr/bin/env python2.7
"""
Run a regresion test on a dff_buf.
"""
import unittest
from testutils import header,openram_test
import sys,os
sys.path.append(os.path.join(sys.path[0],".."))
import globals
from globals import OPTS
import debug
class dff_buf_test(openram_test):
def runTest(self):
globals.init_openram("config_20_{0}".format(OPTS.tech_name))
global verify
import verify
OPTS.check_lvsdrc = False
import dff_buf
debug.info(2, "Testing dff_buf 4x 8x")
a = dff_buf.dff_buf(4, 8)
self.local_check(a)
OPTS.check_lvsdrc = True
globals.end_openram()
# instantiate a copdsay of the class to actually run the test
if __name__ == "__main__":
(OPTS, args) = globals.parse_args()
del sys.argv[1:]
header(__file__, OPTS.tech_name)
unittest.main()

View File

@ -0,0 +1,44 @@
#!/usr/bin/env python2.7
"""
Run a regresion test on a dff_array.
"""
import unittest
from testutils import header,openram_test
import sys,os
sys.path.append(os.path.join(sys.path[0],".."))
import globals
from globals import OPTS
import debug
class dff_inv_array_test(openram_test):
def runTest(self):
globals.init_openram("config_20_{0}".format(OPTS.tech_name))
global verify
import verify
OPTS.check_lvsdrc = False
import dff_inv_array
debug.info(2, "Testing dff_inv_array for 3x3")
a = dff_inv_array.dff_inv_array(rows=3, columns=3)
self.local_check(a)
debug.info(2, "Testing dff_inv_array for 1x3")
a = dff_inv_array.dff_inv_array(rows=1, columns=3)
self.local_check(a)
debug.info(2, "Testing dff_inv_array for 3x1")
a = dff_inv_array.dff_inv_array(rows=3, columns=1)
self.local_check(a)
OPTS.check_lvsdrc = True
globals.end_openram()
# instantiate a copdsay of the class to actually run the test
if __name__ == "__main__":
(OPTS, args) = globals.parse_args()
del sys.argv[1:]
header(__file__, OPTS.tech_name)
unittest.main()

View File

@ -0,0 +1,36 @@
#!/usr/bin/env python2.7
"""
Run a regresion test on a dff_inv.
"""
import unittest
from testutils import header,openram_test
import sys,os
sys.path.append(os.path.join(sys.path[0],".."))
import globals
from globals import OPTS
import debug
class dff_inv_test(openram_test):
def runTest(self):
globals.init_openram("config_20_{0}".format(OPTS.tech_name))
global verify
import verify
OPTS.check_lvsdrc = False
import dff_inv
debug.info(2, "Testing dff_inv 4x")
a = dff_inv.dff_inv(4)
self.local_check(a)
OPTS.check_lvsdrc = True
globals.end_openram()
# instantiate a copdsay of the class to actually run the test
if __name__ == "__main__":
(OPTS, args) = globals.parse_args()
del sys.argv[1:]
header(__file__, OPTS.tech_name)
unittest.main()

View File

@ -0,0 +1,36 @@
#!/usr/bin/env python2.7
"""
Run a regresion test on various srams
"""
import unittest
from testutils import header,openram_test
import sys,os
sys.path.append(os.path.join(sys.path[0],".."))
import globals
from globals import OPTS
import debug
class bank_select_test(openram_test):
def runTest(self):
globals.init_openram("config_20_{0}".format(OPTS.tech_name))
global verify
import verify
OPTS.check_lvsdrc = False
import bank_select
debug.info(1, "No column mux")
a = bank_select.bank_select()
self.local_check(a)
OPTS.check_lvsdrc = True
globals.end_openram()
# instantiate a copy of the class to actually run the test
if __name__ == "__main__":
(OPTS, args) = globals.parse_args()
del sys.argv[1:]
header(__file__, OPTS.tech_name)
unittest.main()

View File

@ -33,10 +33,9 @@ class multi_bank_test(openram_test):
a = bank.bank(word_size=4, num_words=64, words_per_row=4, num_banks=2, name="bank3")
self.local_check(a)
# Eight way has a short circuit of one column mux select to gnd rail
# debug.info(1, "Eight way column mux")
# a = bank.bank(word_size=2, num_words=128, words_per_row=8, num_banks=2, name="bank4")
# self.local_check(a)
debug.info(1, "Eight way column mux")
a = bank.bank(word_size=2, num_words=128, words_per_row=8, num_banks=2, name="bank4")
self.local_check(a)
OPTS.check_lvsdrc = True
globals.end_openram()

View File

@ -34,9 +34,9 @@ class single_bank_test(openram_test):
self.local_check(a)
# Eight way has a short circuit of one column mux select to gnd rail
# debug.info(1, "Eight way column mux")
# a = bank.bank(word_size=2, num_words=128, words_per_row=8, num_banks=1, name="bank4")
# self.local_check(a)
debug.info(1, "Eight way column mux")
a = bank.bank(word_size=2, num_words=128, words_per_row=8, num_banks=1, name="bank4")
self.local_check(a)
OPTS.check_lvsdrc = True
globals.end_openram()

View File

@ -51,7 +51,7 @@ class lib_test(openram_test):
newname = filename.replace(".lib","_pruned.lib")
libname = "{0}/{1}".format(OPTS.openram_temp,filename)
golden = "{0}/golden/{1}".format(os.path.dirname(os.path.realpath(__file__)),newname)
self.isapproxdiff(libname,golden,0.15)
self.isapproxdiff(libname,golden,0.40)
OPTS.analytical_delay = True
reload(characterizer)

View File

@ -50,7 +50,7 @@ class lib_test(openram_test):
for filename in lib_files:
libname = "{0}/{1}".format(OPTS.openram_temp,filename)
golden = "{0}/golden/{1}".format(os.path.dirname(os.path.realpath(__file__)),filename)
self.isapproxdiff(libname,golden,0.15)
self.isapproxdiff(libname,golden,0.40)
OPTS.analytical_delay = True
OPTS.trim_netlist = True

File diff suppressed because it is too large Load Diff

View File

@ -82,7 +82,7 @@ cell (sram_2_16_1_freepdk45){
leakage_power () {
when : "CSb";
value : 0.00088149731;
value : 0.0008128352;
}
cell_leakage_power : 0;
bus(DATA){
@ -103,9 +103,9 @@ cell (sram_2_16_1_freepdk45){
timing_type : setup_rising;
related_pin : "clk";
rise_constraint(CONSTRAINT_TABLE) {
values("0.009, 0.015, 0.021",\
"0.009, 0.015, 0.021",\
"0.009, 0.015, 0.021");
values("0.009, 0.015, 0.027",\
"0.009, 0.015, 0.027",\
"0.009, 0.015, 0.027");
}
fall_constraint(CONSTRAINT_TABLE) {
values("0.009, 0.009, 0.015",\
@ -137,19 +137,19 @@ cell (sram_2_16_1_freepdk45){
"0.061, 0.062, 0.069");
}
cell_fall(CELL_TABLE) {
values("0.429, 0.43, 0.439",\
"0.429, 0.431, 0.439",\
"0.435, 0.436, 0.446");
values("0.067, 0.068, 0.076",\
"0.067, 0.068, 0.077",\
"0.073, 0.074, 0.082");
}
rise_transition(CELL_TABLE) {
values("0.013, 0.015, 0.026",\
"0.013, 0.015, 0.026",\
"0.013, 0.015, 0.026");
"0.014, 0.015, 0.026");
}
fall_transition(CELL_TABLE) {
values("0.029, 0.031, 0.044",\
"0.029, 0.031, 0.044",\
"0.029, 0.031, 0.044");
values("0.023, 0.024, 0.037",\
"0.023, 0.024, 0.037",\
"0.024, 0.024, 0.037");
}
}
}
@ -165,9 +165,9 @@ cell (sram_2_16_1_freepdk45){
timing_type : setup_rising;
related_pin : "clk";
rise_constraint(CONSTRAINT_TABLE) {
values("0.009, 0.015, 0.021",\
"0.009, 0.015, 0.021",\
"0.009, 0.015, 0.021");
values("0.009, 0.015, 0.027",\
"0.009, 0.015, 0.027",\
"0.009, 0.015, 0.027");
}
fall_constraint(CONSTRAINT_TABLE) {
values("0.009, 0.009, 0.015",\
@ -199,9 +199,9 @@ cell (sram_2_16_1_freepdk45){
timing_type : setup_rising;
related_pin : "clk";
rise_constraint(CONSTRAINT_TABLE) {
values("0.009, 0.015, 0.021",\
"0.009, 0.015, 0.021",\
"0.009, 0.015, 0.021");
values("0.009, 0.015, 0.027",\
"0.009, 0.015, 0.027",\
"0.009, 0.015, 0.027");
}
fall_constraint(CONSTRAINT_TABLE) {
values("0.009, 0.009, 0.015",\
@ -232,9 +232,9 @@ cell (sram_2_16_1_freepdk45){
timing_type : setup_rising;
related_pin : "clk";
rise_constraint(CONSTRAINT_TABLE) {
values("0.009, 0.015, 0.021",\
"0.009, 0.015, 0.021",\
"0.009, 0.015, 0.021");
values("0.009, 0.015, 0.027",\
"0.009, 0.015, 0.027",\
"0.009, 0.015, 0.027");
}
fall_constraint(CONSTRAINT_TABLE) {
values("0.009, 0.009, 0.015",\
@ -265,9 +265,9 @@ cell (sram_2_16_1_freepdk45){
timing_type : setup_rising;
related_pin : "clk";
rise_constraint(CONSTRAINT_TABLE) {
values("0.009, 0.015, 0.021",\
"0.009, 0.015, 0.021",\
"0.009, 0.015, 0.021");
values("0.009, 0.015, 0.027",\
"0.009, 0.015, 0.027",\
"0.009, 0.015, 0.027");
}
fall_constraint(CONSTRAINT_TABLE) {
values("0.009, 0.009, 0.015",\
@ -298,19 +298,19 @@ cell (sram_2_16_1_freepdk45){
internal_power(){
when : "!CSb & clk & !WEb";
rise_power(scalar){
values("0.0173748762222");
values("0.0175059861111");
}
fall_power(scalar){
values("0.0173748762222");
values("0.0175059861111");
}
}
internal_power(){
when : "!CSb & !clk & WEb";
rise_power(scalar){
values("0.0261209913889");
values("0.0218644166667");
}
fall_power(scalar){
values("0.0261209913889");
values("0.0218644166667");
}
}
internal_power(){
@ -326,20 +326,20 @@ cell (sram_2_16_1_freepdk45){
timing_type :"min_pulse_width";
related_pin : clk;
rise_constraint(scalar) {
values("0.4295");
values("0.117");
}
fall_constraint(scalar) {
values("0.4295");
values("0.117");
}
}
timing(){
timing_type :"minimum_period";
related_pin : clk;
rise_constraint(scalar) {
values("0.859");
values("0.234");
}
fall_constraint(scalar) {
values("0.859");
values("0.234");
}
}
}

View File

@ -82,7 +82,7 @@ cell (sram_2_16_1_freepdk45){
leakage_power () {
when : "CSb";
value : 0.00088149731;
value : 0.0008128352;
}
cell_leakage_power : 0;
bus(DATA){
@ -103,9 +103,9 @@ cell (sram_2_16_1_freepdk45){
timing_type : setup_rising;
related_pin : "clk";
rise_constraint(CONSTRAINT_TABLE) {
values("0.009, 0.015, 0.021",\
"0.009, 0.015, 0.021",\
"0.009, 0.015, 0.021");
values("0.009, 0.015, 0.027",\
"0.009, 0.015, 0.027",\
"0.009, 0.015, 0.027");
}
fall_constraint(CONSTRAINT_TABLE) {
values("0.009, 0.009, 0.015",\
@ -133,23 +133,23 @@ cell (sram_2_16_1_freepdk45){
timing_type : falling_edge;
cell_rise(CELL_TABLE) {
values("0.054, 0.055, 0.061",\
"0.055, 0.055, 0.062",\
"0.06, 0.061, 0.067");
"0.055, 0.056, 0.062",\
"0.06, 0.061, 0.068");
}
cell_fall(CELL_TABLE) {
values("0.425, 0.426, 0.436",\
"0.426, 0.427, 0.436",\
"0.432, 0.433, 0.442");
values("0.066, 0.067, 0.075",\
"0.067, 0.068, 0.076",\
"0.072, 0.073, 0.082");
}
rise_transition(CELL_TABLE) {
values("0.013, 0.014, 0.026",\
"0.013, 0.014, 0.026",\
"0.013, 0.015, 0.026",\
"0.013, 0.015, 0.026");
}
fall_transition(CELL_TABLE) {
values("0.027, 0.029, 0.043",\
"0.027, 0.029, 0.043",\
"0.027, 0.029, 0.043");
values("0.023, 0.024, 0.037",\
"0.023, 0.024, 0.037",\
"0.024, 0.024, 0.037");
}
}
}
@ -165,9 +165,9 @@ cell (sram_2_16_1_freepdk45){
timing_type : setup_rising;
related_pin : "clk";
rise_constraint(CONSTRAINT_TABLE) {
values("0.009, 0.015, 0.021",\
"0.009, 0.015, 0.021",\
"0.009, 0.015, 0.021");
values("0.009, 0.015, 0.027",\
"0.009, 0.015, 0.027",\
"0.009, 0.015, 0.027");
}
fall_constraint(CONSTRAINT_TABLE) {
values("0.009, 0.009, 0.015",\
@ -199,9 +199,9 @@ cell (sram_2_16_1_freepdk45){
timing_type : setup_rising;
related_pin : "clk";
rise_constraint(CONSTRAINT_TABLE) {
values("0.009, 0.015, 0.021",\
"0.009, 0.015, 0.021",\
"0.009, 0.015, 0.021");
values("0.009, 0.015, 0.027",\
"0.009, 0.015, 0.027",\
"0.009, 0.015, 0.027");
}
fall_constraint(CONSTRAINT_TABLE) {
values("0.009, 0.009, 0.015",\
@ -232,9 +232,9 @@ cell (sram_2_16_1_freepdk45){
timing_type : setup_rising;
related_pin : "clk";
rise_constraint(CONSTRAINT_TABLE) {
values("0.009, 0.015, 0.021",\
"0.009, 0.015, 0.021",\
"0.009, 0.015, 0.021");
values("0.009, 0.015, 0.027",\
"0.009, 0.015, 0.027",\
"0.009, 0.015, 0.027");
}
fall_constraint(CONSTRAINT_TABLE) {
values("0.009, 0.009, 0.015",\
@ -265,9 +265,9 @@ cell (sram_2_16_1_freepdk45){
timing_type : setup_rising;
related_pin : "clk";
rise_constraint(CONSTRAINT_TABLE) {
values("0.009, 0.015, 0.021",\
"0.009, 0.015, 0.021",\
"0.009, 0.015, 0.021");
values("0.009, 0.015, 0.027",\
"0.009, 0.015, 0.027",\
"0.009, 0.015, 0.027");
}
fall_constraint(CONSTRAINT_TABLE) {
values("0.009, 0.009, 0.015",\
@ -298,19 +298,19 @@ cell (sram_2_16_1_freepdk45){
internal_power(){
when : "!CSb & clk & !WEb";
rise_power(scalar){
values("0.0158174252672");
values("0.0159801855389");
}
fall_power(scalar){
values("0.0158174252672");
values("0.0159801855389");
}
}
internal_power(){
when : "!CSb & !clk & WEb";
rise_power(scalar){
values("0.0181396362394");
values("0.0171325605389");
}
fall_power(scalar){
values("0.0181396362394");
values("0.0171325605389");
}
}
internal_power(){
@ -326,20 +326,20 @@ cell (sram_2_16_1_freepdk45){
timing_type :"min_pulse_width";
related_pin : clk;
rise_constraint(scalar) {
values("0.4295");
values("0.1125");
}
fall_constraint(scalar) {
values("0.4295");
values("0.1125");
}
}
timing(){
timing_type :"minimum_period";
related_pin : clk;
rise_constraint(scalar) {
values("0.859");
values("0.225");
}
fall_constraint(scalar) {
values("0.859");
values("0.225");
}
}
}

File diff suppressed because it is too large Load Diff

View File

@ -82,7 +82,7 @@ cell (sram_2_16_1_scn3me_subm){
leakage_power () {
when : "CSb";
value : 0.0011563287;
value : 0.0004764706;
}
cell_leakage_power : 0;
bus(DATA){
@ -108,9 +108,9 @@ cell (sram_2_16_1_scn3me_subm){
"0.076, 0.076, 0.149");
}
fall_constraint(CONSTRAINT_TABLE) {
values("0.039, 0.039, 0.027",\
"0.039, 0.039, 0.027",\
"0.039, 0.039, 0.027");
values("0.033, 0.039, 0.027",\
"0.033, 0.039, 0.027",\
"0.033, 0.039, 0.027");
}
}
timing(){
@ -132,24 +132,24 @@ cell (sram_2_16_1_scn3me_subm){
related_pin : "clk";
timing_type : falling_edge;
cell_rise(CELL_TABLE) {
values("0.473, 0.519, 0.888",\
"0.476, 0.522, 0.891",\
"0.516, 0.56, 0.928");
values("0.474, 0.52, 0.888",\
"0.477, 0.522, 0.892",\
"0.517, 0.561, 0.929");
}
cell_fall(CELL_TABLE) {
values("0.582, 0.655, 1.256",\
"0.585, 0.658, 1.259",\
"0.625, 0.697, 1.295");
values("0.582, 0.658, 1.26",\
"0.586, 0.661, 1.262",\
"0.626, 0.7, 1.298");
}
rise_transition(CELL_TABLE) {
values("0.154, 0.233, 1.086",\
"0.155, 0.234, 1.086",\
"0.158, 0.237, 1.086");
values("0.155, 0.233, 1.087",\
"0.156, 0.235, 1.086",\
"0.16, 0.239, 1.086");
}
fall_transition(CELL_TABLE) {
values("0.278, 0.359, 1.499",\
"0.278, 0.361, 1.499",\
"0.28, 0.367, 1.5");
values("0.277, 0.356, 1.502",\
"0.278, 0.358, 1.501",\
"0.279, 0.363, 1.5");
}
}
}
@ -170,9 +170,9 @@ cell (sram_2_16_1_scn3me_subm){
"0.076, 0.076, 0.149");
}
fall_constraint(CONSTRAINT_TABLE) {
values("0.039, 0.039, 0.027",\
"0.039, 0.039, 0.027",\
"0.039, 0.039, 0.027");
values("0.033, 0.039, 0.027",\
"0.033, 0.039, 0.027",\
"0.033, 0.039, 0.027");
}
}
timing(){
@ -204,9 +204,9 @@ cell (sram_2_16_1_scn3me_subm){
"0.076, 0.076, 0.149");
}
fall_constraint(CONSTRAINT_TABLE) {
values("0.039, 0.039, 0.027",\
"0.039, 0.039, 0.027",\
"0.039, 0.039, 0.027");
values("0.033, 0.039, 0.027",\
"0.033, 0.039, 0.027",\
"0.033, 0.039, 0.027");
}
}
timing(){
@ -237,9 +237,9 @@ cell (sram_2_16_1_scn3me_subm){
"0.076, 0.076, 0.149");
}
fall_constraint(CONSTRAINT_TABLE) {
values("0.039, 0.039, 0.027",\
"0.039, 0.039, 0.027",\
"0.039, 0.039, 0.027");
values("0.033, 0.039, 0.027",\
"0.033, 0.039, 0.027",\
"0.033, 0.039, 0.027");
}
}
timing(){
@ -270,9 +270,9 @@ cell (sram_2_16_1_scn3me_subm){
"0.076, 0.076, 0.149");
}
fall_constraint(CONSTRAINT_TABLE) {
values("0.039, 0.039, 0.027",\
"0.039, 0.039, 0.027",\
"0.039, 0.039, 0.027");
values("0.033, 0.039, 0.027",\
"0.033, 0.039, 0.027",\
"0.033, 0.039, 0.027");
}
}
timing(){
@ -298,19 +298,19 @@ cell (sram_2_16_1_scn3me_subm){
internal_power(){
when : "!CSb & clk & !WEb";
rise_power(scalar){
values("4.91866674167");
values("4.92665");
}
fall_power(scalar){
values("4.91866674167");
values("4.92665");
}
}
internal_power(){
when : "!CSb & !clk & WEb";
rise_power(scalar){
values("5.72315586111");
values("5.74515833333");
}
fall_power(scalar){
values("5.72315586111");
values("5.74515833333");
}
}
internal_power(){

View File

@ -82,7 +82,7 @@ cell (sram_2_16_1_scn3me_subm){
leakage_power () {
when : "CSb";
value : 0.0011563287;
value : 0.0004764706;
}
cell_leakage_power : 0;
bus(DATA){
@ -108,9 +108,9 @@ cell (sram_2_16_1_scn3me_subm){
"0.076, 0.076, 0.149");
}
fall_constraint(CONSTRAINT_TABLE) {
values("0.039, 0.039, 0.027",\
"0.039, 0.039, 0.027",\
"0.039, 0.039, 0.027");
values("0.033, 0.039, 0.027",\
"0.033, 0.039, 0.027",\
"0.033, 0.039, 0.027");
}
}
timing(){
@ -132,24 +132,24 @@ cell (sram_2_16_1_scn3me_subm){
related_pin : "clk";
timing_type : falling_edge;
cell_rise(CELL_TABLE) {
values("0.458, 0.503, 0.87",\
"0.461, 0.505, 0.873",\
"0.5, 0.544, 0.911");
values("0.458, 0.504, 0.871",\
"0.461, 0.506, 0.874",\
"0.5, 0.544, 0.912");
}
cell_fall(CELL_TABLE) {
values("0.573, 0.645, 1.246",\
"0.576, 0.648, 1.249",\
"0.616, 0.687, 1.286");
values("0.573, 0.649, 1.251",\
"0.577, 0.652, 1.254",\
"0.618, 0.69, 1.29");
}
rise_transition(CELL_TABLE) {
values("0.153, 0.232, 1.084",\
"0.153, 0.233, 1.084",\
"0.156, 0.236, 1.084");
values("0.153, 0.233, 1.085",\
"0.154, 0.234, 1.084",\
"0.158, 0.237, 1.084");
}
fall_transition(CELL_TABLE) {
values("0.277, 0.36, 1.499",\
"0.277, 0.362, 1.499",\
"0.278, 0.37, 1.5");
values("0.276, 0.356, 1.5",\
"0.277, 0.357, 1.5",\
"0.278, 0.363, 1.5");
}
}
}
@ -170,9 +170,9 @@ cell (sram_2_16_1_scn3me_subm){
"0.076, 0.076, 0.149");
}
fall_constraint(CONSTRAINT_TABLE) {
values("0.039, 0.039, 0.027",\
"0.039, 0.039, 0.027",\
"0.039, 0.039, 0.027");
values("0.033, 0.039, 0.027",\
"0.033, 0.039, 0.027",\
"0.033, 0.039, 0.027");
}
}
timing(){
@ -204,9 +204,9 @@ cell (sram_2_16_1_scn3me_subm){
"0.076, 0.076, 0.149");
}
fall_constraint(CONSTRAINT_TABLE) {
values("0.039, 0.039, 0.027",\
"0.039, 0.039, 0.027",\
"0.039, 0.039, 0.027");
values("0.033, 0.039, 0.027",\
"0.033, 0.039, 0.027",\
"0.033, 0.039, 0.027");
}
}
timing(){
@ -237,9 +237,9 @@ cell (sram_2_16_1_scn3me_subm){
"0.076, 0.076, 0.149");
}
fall_constraint(CONSTRAINT_TABLE) {
values("0.039, 0.039, 0.027",\
"0.039, 0.039, 0.027",\
"0.039, 0.039, 0.027");
values("0.033, 0.039, 0.027",\
"0.033, 0.039, 0.027",\
"0.033, 0.039, 0.027");
}
}
timing(){
@ -270,9 +270,9 @@ cell (sram_2_16_1_scn3me_subm){
"0.076, 0.076, 0.149");
}
fall_constraint(CONSTRAINT_TABLE) {
values("0.039, 0.039, 0.027",\
"0.039, 0.039, 0.027",\
"0.039, 0.039, 0.027");
values("0.033, 0.039, 0.027",\
"0.033, 0.039, 0.027",\
"0.033, 0.039, 0.027");
}
}
timing(){
@ -298,19 +298,19 @@ cell (sram_2_16_1_scn3me_subm){
internal_power(){
when : "!CSb & clk & !WEb";
rise_power(scalar){
values("4.39065104738");
values("4.42361814306");
}
fall_power(scalar){
values("4.39065104738");
values("4.42361814306");
}
}
internal_power(){
when : "!CSb & !clk & WEb";
rise_power(scalar){
values("5.00353945572");
values("4.97118480973");
}
fall_power(scalar){
values("5.00353945572");
values("4.97118480973");
}
}
internal_power(){

View File

@ -215,18 +215,26 @@ def run_lvs(cell_name, gds_name, sp_name, final_verification=False):
os.system(cmd)
os.chdir(cwd)
total_errors = 0
# check the result for these lines in the summary:
f = open(resultsfile, "r")
results = f.readlines()
f.close()
# Look for the results after the final "Subcircuit summary:"
# which will be the top-level netlist.
final_results = []
for line in reversed(results):
if "Subcircuit summary:" in line:
break
else:
final_results.insert(0,line)
# Netlists do not match.
test = re.compile("Netlists do not match.")
incorrect = filter(test.search, results)
# There were property errors.
# There were property errors in any module.
test = re.compile("Property errors were found.")
propertyerrors = filter(test.search, results)
total_errors += len(propertyerrors)
# Require pins to match?
# Cell pin lists for pnand2_1.spice and pnand2_1 altered to match.
# test = re.compile(".*altered to match.")
@ -234,17 +242,19 @@ def run_lvs(cell_name, gds_name, sp_name, final_verification=False):
# if len(pinerrors)>0:
# debug.warning("Pins altered to match in {}.".format(cell_name))
total_errors = len(propertyerrors) + len(incorrect)
# If we want to ignore property errors
#total_errors = len(incorrect)
#if len(propertyerrors)>0:
# debug.warning("Property errors found, but not checking them.")
# Netlists do not match.
test = re.compile("Netlists do not match.")
incorrect = filter(test.search, final_results)
total_errors += len(incorrect)
# Netlists match uniquely.
test = re.compile("Netlists match uniquely.")
correct = filter(test.search, results)
correct = filter(test.search, final_results)
# Fail if they don't match. Something went wrong!
if correct == 0:
if len(correct) == 0:
total_errors += 1
if total_errors>0:

Binary file not shown.

View File

@ -3,11 +3,11 @@
* Program "Calibre xRC"
* Version "v2007.2_34.24"
*
.subckt dff d q clk vdd gnd
.subckt dff D Q clk vdd gnd
*
MM21 q a_66_6# gnd gnd NMOS_VTG L=5e-08 W=5e-07
MM21 Q a_66_6# gnd gnd NMOS_VTG L=5e-08 W=5e-07
MM19 a_76_6# a_2_6# a_66_6# gnd NMOS_VTG L=5e-08 W=2.5e-07
MM20 gnd q a_76_6# gnd NMOS_VTG L=5e-08 W=2.5e-07
MM20 gnd Q a_76_6# gnd NMOS_VTG L=5e-08 W=2.5e-07
MM18 a_66_6# clk a_61_6# gnd NMOS_VTG L=5e-08 W=2.5e-07
MM17 a_61_6# a_34_4# gnd gnd NMOS_VTG L=5e-08 W=2.5e-07
MM10 gnd clk a_2_6# gnd NMOS_VTG L=5e-08 W=5e-07
@ -15,9 +15,9 @@ MM16 a_34_4# a_22_6# gnd gnd NMOS_VTG L=5e-08 W=2.5e-07
MM15 gnd a_34_4# a_31_6# gnd NMOS_VTG L=5e-08 W=2.5e-07
MM14 a_31_6# clk a_22_6# gnd NMOS_VTG L=5e-08 W=2.5e-07
MM13 a_22_6# a_2_6# a_17_6# gnd NMOS_VTG L=5e-08 W=2.5e-07
MM12 a_17_6# d gnd gnd NMOS_VTG L=5e-08 W=2.5e-07
MM11 q a_66_6# vdd vdd PMOS_VTG L=5e-08 W=1e-06
MM9 vdd q a_76_84# vdd PMOS_VTG L=5e-08 W=2.5e-07
MM12 a_17_6# D gnd gnd NMOS_VTG L=5e-08 W=2.5e-07
MM11 Q a_66_6# vdd vdd PMOS_VTG L=5e-08 W=1e-06
MM9 vdd Q a_76_84# vdd PMOS_VTG L=5e-08 W=2.5e-07
MM8 a_76_84# clk a_66_6# vdd PMOS_VTG L=5e-08 W=2.5e-07
MM7 a_66_6# a_2_6# a_61_74# vdd PMOS_VTG L=5e-08 W=5e-07
MM6 a_61_74# a_34_4# vdd vdd PMOS_VTG L=5e-08 W=5e-07
@ -26,16 +26,16 @@ MM5 a_34_4# a_22_6# vdd vdd PMOS_VTG L=5e-08 W=5e-07
MM4 vdd a_34_4# a_31_74# vdd PMOS_VTG L=5e-08 W=5e-07
MM3 a_31_74# a_2_6# a_22_6# vdd PMOS_VTG L=5e-08 W=5e-07
MM2 a_22_6# clk a_17_74# vdd PMOS_VTG L=5e-08 W=5e-07
MM1 a_17_74# d vdd vdd PMOS_VTG L=5e-08 W=5e-07
MM1 a_17_74# D vdd vdd PMOS_VTG L=5e-08 W=5e-07
* c_9 a_66_6# 0 0.271997f
* c_20 clk 0 0.350944f
* c_27 q 0 0.202617f
* c_27 Q 0 0.202617f
* c_32 a_76_84# 0 0.0210573f
* c_38 a_76_6# 0 0.0204911f
* c_45 a_34_4# 0 0.172306f
* c_55 a_2_6# 0 0.283119f
* c_59 a_22_6# 0 0.157312f
* c_64 d 0 0.0816386f
* c_64 D 0 0.0816386f
* c_73 gnd 0 0.254131f
* c_81 vdd 0 0.23624f
*

View File

@ -85,8 +85,10 @@ drc["layer_map"]=os.environ.get("OPENRAM_TECH")+"/freepdk45/layers.map"
drc["minwidth_tx"]=0.09
drc["minlength_channel"] = 0.05
# WELL.1 Minimum spacing of nwell/pwell at different potential
# WELL.2 Minimum spacing of nwell/pwell at different potential
drc["pwell_to_nwell"] = 0.225
# WELL.3 Minimum spacing of nwell/pwell at the same potential
drc["well_to_well"] = 0.135
# WELL.4 Minimum width of nwell/pwell
drc["minwidth_well"] = 0.2

Binary file not shown.

View File

@ -1,6 +1,6 @@
magic
tech scmos
timestamp 1517870584
timestamp 1521677056
<< nwell >>
rect -8 29 42 51
<< pwell >>
@ -73,7 +73,8 @@ rect 15 29 19 33
rect 21 20 25 24
rect 17 6 21 10
<< metal1 >>
rect -2 44 32 48
rect -2 44 15 48
rect 19 44 32 48
rect -2 40 2 44
rect 32 40 36 44
rect 11 36 12 40
@ -92,6 +93,7 @@ rect -2 6 17 9
rect 21 6 36 9
rect -2 5 36 6
<< m2contact >>
rect 15 44 19 48
rect -2 29 2 33
rect 32 29 36 33
rect 6 -2 10 2
@ -99,17 +101,17 @@ rect 20 -2 24 2
<< metal2 >>
rect -2 33 2 48
rect -2 -2 2 29
rect 10 -2 14 48
rect 20 2 24 48
rect 6 2 10 48
rect 24 -2 28 48
rect 32 33 36 48
rect 32 -2 36 29
<< m3p >>
rect 0 0 34 46
<< labels >>
rlabel metal1 2 6 2 6 3 WL
rlabel metal2 -1 28 -1 28 1 gnd
rlabel metal2 33 28 33 28 1 gnd
rlabel metal1 17 46 17 46 5 vdd
rlabel metal2 11 43 11 43 1 BL
rlabel metal2 21 43 21 43 1 BR
rlabel metal2 0 0 0 0 1 gnd
rlabel metal2 34 0 34 0 1 gnd
rlabel m2contact 17 46 17 46 5 vdd
rlabel metal1 4 7 4 7 1 WL
rlabel metal2 8 43 8 43 1 BL
rlabel metal2 26 43 26 43 1 BR
<< end >>

View File

@ -1,299 +1,279 @@
magic
tech scmos
timestamp 1518655545
timestamp 1518823399
<< nwell >>
rect -8 48 104 105
rect 0 48 109 103
<< pwell >>
rect -8 -5 104 48
rect 0 -3 109 48
<< ntransistor >>
rect 7 6 9 26
rect 15 6 17 16
rect 20 6 22 16
rect 29 6 31 16
rect 34 6 36 16
rect 43 6 45 16
rect 59 6 61 16
rect 64 6 66 16
rect 74 6 76 16
rect 79 6 81 16
rect 87 6 89 26
rect 11 6 13 26
rect 19 6 21 16
rect 24 6 26 16
rect 33 6 35 16
rect 38 6 40 16
rect 47 6 49 16
rect 63 6 65 16
rect 68 6 70 16
rect 78 6 80 16
rect 83 6 85 16
rect 91 6 93 26
<< ptransistor >>
rect 7 54 9 94
rect 15 74 17 94
rect 21 74 23 94
rect 29 74 31 94
rect 35 74 37 94
rect 43 74 45 94
rect 59 74 61 94
rect 64 74 66 94
rect 74 84 76 94
rect 79 84 81 94
rect 87 54 89 94
rect 11 54 13 94
rect 19 74 21 94
rect 25 74 27 94
rect 33 74 35 94
rect 39 74 41 94
rect 47 74 49 94
rect 63 74 65 94
rect 68 74 70 94
rect 78 84 80 94
rect 83 84 85 94
rect 91 54 93 94
<< ndiffusion >>
rect 2 25 7 26
rect 6 6 7 25
rect 9 25 14 26
rect 9 6 10 25
rect 82 25 87 26
rect 14 6 15 16
rect 17 6 20 16
rect 22 15 29 16
rect 22 6 24 15
rect 28 6 29 15
rect 31 6 34 16
rect 36 15 43 16
rect 36 6 37 15
rect 41 6 43 15
rect 45 15 50 16
rect 45 6 46 15
rect 54 15 59 16
rect 58 6 59 15
rect 61 6 64 16
rect 66 15 74 16
rect 66 6 68 15
rect 72 6 74 15
rect 76 6 79 16
rect 81 6 82 16
rect 86 6 87 25
rect 89 25 94 26
rect 89 6 90 25
rect 6 25 11 26
rect 10 6 11 25
rect 13 25 18 26
rect 13 6 14 25
rect 86 25 91 26
rect 18 6 19 16
rect 21 6 24 16
rect 26 15 33 16
rect 26 6 28 15
rect 32 6 33 15
rect 35 6 38 16
rect 40 15 47 16
rect 40 6 41 15
rect 45 6 47 15
rect 49 15 54 16
rect 49 6 50 15
rect 58 15 63 16
rect 62 6 63 15
rect 65 6 68 16
rect 70 15 78 16
rect 70 6 72 15
rect 76 6 78 15
rect 80 6 83 16
rect 85 6 86 16
rect 90 6 91 25
rect 93 25 98 26
rect 93 6 94 25
<< pdiffusion >>
rect 2 93 7 94
rect 6 54 7 93
rect 9 55 10 94
rect 14 74 15 94
rect 17 74 21 94
rect 23 93 29 94
rect 23 74 24 93
rect 28 74 29 93
rect 31 74 35 94
rect 37 93 43 94
rect 37 74 38 93
rect 42 74 43 93
rect 45 93 50 94
rect 45 74 46 93
rect 54 93 59 94
rect 58 74 59 93
rect 61 74 64 94
rect 66 93 74 94
rect 66 74 68 93
rect 72 84 74 93
rect 76 84 79 94
rect 81 93 87 94
rect 81 84 82 93
rect 72 74 73 84
rect 9 54 14 55
rect 86 54 87 93
rect 89 93 94 94
rect 89 54 90 93
rect 6 93 11 94
rect 10 54 11 93
rect 13 55 14 94
rect 18 74 19 94
rect 21 74 25 94
rect 27 93 33 94
rect 27 74 28 93
rect 32 74 33 93
rect 35 74 39 94
rect 41 93 47 94
rect 41 74 42 93
rect 46 74 47 93
rect 49 93 54 94
rect 49 74 50 93
rect 58 93 63 94
rect 62 74 63 93
rect 65 74 68 94
rect 70 93 78 94
rect 70 74 72 93
rect 76 84 78 93
rect 80 84 83 94
rect 85 93 91 94
rect 85 84 86 93
rect 76 74 77 84
rect 13 54 18 55
rect 90 54 91 93
rect 93 93 98 94
rect 93 54 94 93
<< ndcontact >>
rect 2 6 6 25
rect 10 6 14 25
rect 24 6 28 15
rect 37 6 41 15
rect 46 6 50 15
rect 54 6 58 15
rect 68 6 72 15
rect 82 6 86 25
rect 90 6 94 25
rect 6 6 10 25
rect 14 6 18 25
rect 28 6 32 15
rect 41 6 45 15
rect 50 6 54 15
rect 58 6 62 15
rect 72 6 76 15
rect 86 6 90 25
rect 94 6 98 25
<< pdcontact >>
rect 2 54 6 93
rect 10 55 14 94
rect 24 74 28 93
rect 38 74 42 93
rect 46 74 50 93
rect 54 74 58 93
rect 68 74 72 93
rect 82 54 86 93
rect 90 54 94 93
rect 6 54 10 93
rect 14 55 18 94
rect 28 74 32 93
rect 42 74 46 93
rect 50 74 54 93
rect 58 74 62 93
rect 72 74 76 93
rect 86 54 90 93
rect 94 54 98 93
<< psubstratepcontact >>
rect -2 -2 2 2
rect 14 -2 18 2
rect 30 -2 34 2
rect 46 -2 50 2
rect 62 -2 66 2
rect 78 -2 82 2
rect 102 6 106 10
<< nsubstratencontact >>
rect -2 98 2 102
rect 14 98 18 102
rect 30 98 34 102
rect 46 98 50 102
rect 62 98 66 102
rect 78 98 82 102
rect 102 89 106 93
<< polysilicon >>
rect 7 94 9 96
rect 15 94 17 96
rect 21 94 23 96
rect 29 94 31 96
rect 35 94 37 96
rect 43 94 45 96
rect 59 94 61 96
rect 64 94 66 96
rect 74 94 76 96
rect 79 94 81 96
rect 87 94 89 96
rect 7 37 9 54
rect 15 46 17 74
rect 7 26 9 33
rect 15 16 17 42
rect 21 38 23 74
rect 29 54 31 74
rect 29 29 31 50
rect 20 27 31 29
rect 35 71 37 74
rect 20 16 22 27
rect 35 23 37 67
rect 43 61 45 74
rect 59 73 61 74
rect 50 71 61 73
rect 30 19 31 23
rect 29 16 31 19
rect 11 94 13 96
rect 19 94 21 96
rect 25 94 27 96
rect 33 94 35 96
rect 39 94 41 96
rect 47 94 49 96
rect 63 94 65 96
rect 68 94 70 96
rect 78 94 80 96
rect 83 94 85 96
rect 91 94 93 96
rect 11 37 13 54
rect 19 46 21 74
rect 11 26 13 33
rect 19 16 21 42
rect 25 38 27 74
rect 33 54 35 74
rect 33 29 35 50
rect 24 27 35 29
rect 39 71 41 74
rect 24 16 26 27
rect 39 23 41 67
rect 47 61 49 74
rect 63 73 65 74
rect 54 71 65 73
rect 34 19 35 23
rect 34 16 36 19
rect 43 16 45 57
rect 49 19 51 67
rect 64 63 66 74
rect 74 67 76 84
rect 72 65 76 67
rect 59 61 66 63
rect 57 24 59 33
rect 64 31 66 61
rect 79 53 81 84
rect 75 51 81 53
rect 74 31 76 47
rect 87 45 89 54
rect 85 41 89 45
rect 64 29 71 31
rect 57 22 66 24
rect 49 17 61 19
rect 59 16 61 17
rect 64 16 66 22
rect 69 19 71 29
rect 74 27 75 31
rect 69 17 76 19
rect 74 16 76 17
rect 79 16 81 31
rect 87 26 89 41
rect 7 4 9 6
rect 15 4 17 6
rect 20 4 22 6
rect 29 4 31 6
rect 34 4 36 6
rect 43 4 45 6
rect 59 4 61 6
rect 64 4 66 6
rect 74 4 76 6
rect 79 4 81 6
rect 87 4 89 6
rect 33 16 35 19
rect 38 19 39 23
rect 38 16 40 19
rect 47 16 49 57
rect 53 19 55 67
rect 68 63 70 74
rect 78 67 80 84
rect 76 65 80 67
rect 63 61 70 63
rect 61 24 63 33
rect 68 31 70 61
rect 83 53 85 84
rect 79 51 85 53
rect 78 31 80 47
rect 91 45 93 54
rect 89 41 93 45
rect 68 29 75 31
rect 61 22 70 24
rect 53 17 65 19
rect 63 16 65 17
rect 68 16 70 22
rect 73 19 75 29
rect 78 27 79 31
rect 73 17 80 19
rect 78 16 80 17
rect 83 16 85 31
rect 91 26 93 41
rect 11 4 13 6
rect 19 4 21 6
rect 24 4 26 6
rect 33 4 35 6
rect 38 4 40 6
rect 47 4 49 6
rect 63 4 65 6
rect 68 4 70 6
rect 78 4 80 6
rect 83 4 85 6
rect 91 4 93 6
<< polycontact >>
rect 13 42 17 46
rect 6 33 10 37
rect 27 50 31 54
rect 21 34 25 38
rect 35 67 39 71
rect 41 57 45 61
rect 26 19 30 23
rect 35 19 39 23
rect 49 67 53 71
rect 55 59 59 63
rect 70 61 74 65
rect 55 33 59 37
rect 73 47 77 51
rect 81 41 85 45
rect 75 27 79 31
<< metal1 >>
rect -2 102 98 103
rect 2 98 14 102
rect 18 98 30 102
rect 34 98 46 102
rect 50 98 62 102
rect 66 98 78 102
rect 82 98 98 102
rect -2 97 98 98
rect 10 94 14 97
rect 2 93 6 94
rect 24 93 28 94
rect 18 74 24 77
rect 38 93 42 97
rect 46 93 50 94
rect 54 93 58 97
rect 67 93 73 94
rect 67 74 68 93
rect 72 74 73 93
rect 82 93 86 97
rect 46 71 49 74
rect 39 68 49 71
rect 22 57 41 60
rect 48 60 55 63
rect 48 54 51 60
rect 67 56 70 65
rect 6 50 27 52
rect 31 51 51 54
rect 58 53 70 56
rect 90 93 94 94
rect 2 49 30 50
rect 17 43 34 46
rect 14 34 21 37
rect 58 37 61 53
rect 90 51 94 54
rect 77 48 90 51
rect 70 41 81 44
rect 25 34 55 37
rect 2 25 6 26
rect 10 25 14 26
rect 27 23 30 34
rect 59 34 61 37
rect 90 31 94 47
rect 79 28 94 31
rect 90 25 94 28
rect 39 19 49 22
rect 46 16 49 19
rect 18 15 28 16
rect 18 13 24 15
rect 37 15 42 16
rect 41 6 42 15
rect 46 15 50 16
rect 54 15 58 16
rect 66 15 73 16
rect 66 13 68 15
rect 67 6 68 13
rect 72 6 73 15
rect 10 3 14 6
rect 37 3 42 6
rect 54 3 58 6
rect 82 3 86 6
rect -2 2 98 3
rect 2 -2 14 2
rect 18 -2 30 2
rect 34 -2 46 2
rect 50 -2 62 2
rect 66 -2 78 2
rect 82 -2 98 2
rect -2 -3 98 -2
<< m2contact >>
rect 18 70 22 74
rect 66 70 70 74
rect 18 57 22 61
rect 2 50 6 54
rect 34 43 38 47
rect 17 42 21 46
rect 10 33 14 37
rect 90 47 94 51
rect 66 40 70 44
rect 2 26 6 30
rect 18 16 22 20
rect 66 16 70 20
rect 31 50 35 54
rect 25 34 29 38
rect 39 67 43 71
rect 45 57 49 61
rect 30 19 34 23
rect 39 19 43 23
rect 53 67 57 71
rect 59 59 63 63
rect 74 61 78 65
rect 59 33 63 37
rect 77 47 81 51
rect 85 41 89 45
rect 79 27 83 31
<< metal1 >>
rect 0 97 109 103
rect 14 94 18 97
rect 6 93 10 94
rect 28 93 32 94
rect 22 74 28 77
rect 42 93 46 97
rect 50 93 54 94
rect 58 93 62 97
rect 71 93 77 94
rect 71 74 72 93
rect 76 74 77 93
rect 86 93 90 97
rect 50 71 53 74
rect 43 68 53 71
rect 26 57 45 60
rect 52 60 59 63
rect 52 54 55 60
rect 71 56 74 65
rect 10 50 31 52
rect 35 51 55 54
rect 62 53 74 56
rect 94 93 98 94
rect 102 93 106 97
rect 6 49 34 50
rect 21 43 38 46
rect 18 34 25 37
rect 62 37 65 53
rect 94 51 98 54
rect 81 48 94 51
rect 74 41 85 44
rect 29 34 59 37
rect 6 25 10 26
rect 14 25 18 26
rect 31 23 34 34
rect 63 34 65 37
rect 94 31 98 47
rect 83 28 98 31
rect 94 25 98 28
rect 43 19 53 22
rect 50 16 53 19
rect 22 15 32 16
rect 22 13 28 15
rect 41 15 46 16
rect 45 6 46 15
rect 50 15 54 16
rect 58 15 62 16
rect 70 15 77 16
rect 70 13 72 15
rect 71 6 72 13
rect 76 6 77 15
rect 14 3 18 6
rect 41 3 46 6
rect 58 3 62 6
rect 86 3 90 6
rect 102 3 106 6
rect 0 -3 109 3
<< m2contact >>
rect 22 70 26 74
rect 70 70 74 74
rect 22 57 26 61
rect 6 50 10 54
rect 38 43 42 47
rect 14 33 18 37
rect 94 47 98 51
rect 70 40 74 44
rect 6 26 10 30
rect 22 16 26 20
rect 70 16 74 20
<< metal2 >>
rect 18 61 22 70
rect 2 30 6 50
rect 18 20 22 57
rect 66 44 70 70
rect 66 20 70 40
rect 22 61 26 70
rect 6 30 10 50
rect 22 20 26 57
rect 70 44 74 70
rect 70 20 74 40
<< m3p >>
rect -2 0 98 100
rect 0 0 109 100
<< labels >>
rlabel metal1 23 100 23 100 5 vdd
rlabel metal1 38 -1 38 -1 1 gnd
rlabel m2contact 11 34 11 34 1 clk
rlabel m2contact 36 45 36 45 1 d
rlabel m2contact 91 49 91 49 1 q
rlabel m2contact 15 34 15 34 4 clk
rlabel m2contact 40 45 40 45 4 D
rlabel m2contact 96 49 96 49 4 Q
rlabel metal1 32 98 32 98 4 vdd
rlabel metal1 44 1 44 1 4 gnd
<< properties >>
string path 0.000 0.000 900.000 0.000 900.000 900.000 0.000 900.000 0.000 0.000
<< end >>

View File

@ -1,6 +1,6 @@
magic
tech scmos
timestamp 1516666526
timestamp 1523479368
<< nwell >>
rect -2 0 18 200
<< pwell >>
@ -181,14 +181,13 @@ rect 13 60 17 64
rect 16 30 20 34
rect 15 10 19 14
<< metal1 >>
rect -2 188 36 191
rect -2 177 2 188
rect 16 182 24 185
rect -2 173 6 177
rect 28 173 36 177
rect -2 161 2 173
rect -2 164 2 173
rect 12 166 20 169
rect -2 157 6 161
rect 2 160 6 161
rect -2 157 6 160
rect 33 161 36 173
rect -2 111 2 157
rect 28 157 32 161
@ -210,11 +209,12 @@ rect 6 84 20 85
rect 12 82 20 84
rect -2 72 6 76
rect 33 76 36 88
rect -2 22 2 72
rect -2 41 2 72
rect 28 72 32 76
rect 12 54 24 57
rect 12 46 20 49
rect 12 38 20 41
rect -2 22 2 37
rect 20 30 24 31
rect 16 28 24 30
rect 33 23 36 68
@ -227,6 +227,7 @@ rect -2 8 36 10
<< m2contact >>
rect 12 181 16 185
rect 20 166 24 170
rect -2 160 2 164
rect 17 155 21 159
rect 32 153 36 157
rect 6 145 10 149
@ -242,6 +243,7 @@ rect 32 68 36 72
rect 6 57 10 61
rect 17 60 21 64
rect 20 45 24 49
rect -2 37 2 41
rect 20 37 24 41
rect 12 27 16 31
<< metal2 >>
@ -256,7 +258,6 @@ rect 18 143 21 148
rect 13 140 21 143
rect 13 119 16 140
rect 24 133 27 155
rect 32 157 36 200
rect 5 100 6 104
rect 5 61 8 100
rect 15 93 19 104
@ -269,11 +270,9 @@ rect 5 57 6 61
rect 13 60 17 64
rect 13 31 16 60
rect 24 45 27 70
rect 32 72 36 153
rect 24 8 27 41
rect 19 4 27 8
rect 15 0 19 4
rect 32 0 36 68
<< m3contact >>
rect 15 4 19 8
<< metal3 >>
@ -285,9 +284,11 @@ rect 14 3 20 4
rect 0 0 34 200
<< labels >>
rlabel metal1 0 8 0 8 2 clk
rlabel metal1 -2 191 -2 191 2 vdd
rlabel metal3 15 4 15 4 1 din
rlabel metal2 6 196 6 196 5 dout_bar
rlabel metal2 15 196 15 196 5 dout
rlabel metal2 32 0 32 0 8 gnd
rlabel m2contact 34 70 34 70 1 gnd
rlabel m2contact 34 154 34 154 1 gnd
rlabel m2contact 0 162 0 162 3 vdd
rlabel m2contact 0 38 0 38 3 vdd
<< end >>

View File

@ -1,6 +1,6 @@
magic
tech scmos
timestamp 1517870621
timestamp 1521677136
<< nwell >>
rect -8 29 42 51
<< pwell >>
@ -73,19 +73,18 @@ rect 15 29 19 33
rect 21 20 25 24
rect 17 6 21 10
<< metal1 >>
rect -2 44 32 48
rect -2 44 15 48
rect 19 44 32 48
rect -2 40 2 44
rect 32 40 36 44
rect 11 36 12 40
rect 26 36 27 40
rect -2 26 2 29
rect 11 25 15 36
rect 2 22 15 25
rect 11 22 15 36
rect 23 24 27 36
rect -2 21 15 22
rect -2 16 2 21
rect 11 18 15 21
rect -2 18 15 22
rect 25 20 27 24
rect -2 16 2 18
rect 14 14 15 18
rect 23 18 27 20
rect 32 26 36 29
@ -95,6 +94,7 @@ rect -2 6 17 9
rect 21 6 36 9
rect -2 5 36 6
<< m2contact >>
rect 15 44 19 48
rect -2 29 2 33
rect 32 29 36 33
rect 6 -2 10 2
@ -102,17 +102,17 @@ rect 20 -2 24 2
<< metal2 >>
rect -2 33 2 48
rect -2 -2 2 29
rect 10 -2 14 48
rect 20 2 24 48
rect 6 2 10 48
rect 24 -2 28 48
rect 32 33 36 48
rect 32 -2 36 29
<< m3p >>
rect 0 0 34 46
<< labels >>
rlabel metal1 2 6 2 6 3 WL
rlabel metal2 -1 28 -1 28 1 gnd
rlabel metal2 33 28 33 28 1 gnd
rlabel metal1 17 46 17 46 5 vdd
rlabel metal2 11 43 11 43 1 BL
rlabel metal2 21 43 21 43 1 BR
rlabel metal2 0 0 0 0 1 gnd
rlabel metal2 34 0 34 0 1 gnd
rlabel m2contact 17 46 17 46 5 vdd
rlabel metal1 4 7 4 7 1 WL
rlabel metal2 8 43 8 43 1 BL
rlabel metal2 26 43 26 43 1 BR
<< end >>

View File

@ -1,6 +1,6 @@
magic
tech scmos
timestamp 1516827653
timestamp 1524065550
<< nwell >>
rect 0 0 40 102
<< pwell >>
@ -50,13 +50,10 @@ rect 6 20 10 44
rect 14 20 18 44
rect 22 20 26 44
rect 30 20 34 44
<< nsubstratendiff >>
rect 18 64 22 66
rect 18 58 22 60
<< psubstratepcontact >>
rect 32 138 36 142
rect 32 137 36 141
<< nsubstratencontact >>
rect 18 60 22 64
rect 27 70 31 74
<< polysilicon >>
rect 21 139 23 149
rect 21 129 23 130
@ -90,8 +87,7 @@ rect 29 51 33 55
<< metal1 >>
rect -2 149 20 153
rect 24 149 36 153
rect -2 142 32 146
rect 24 139 28 142
rect 28 133 32 137
rect 16 117 19 130
rect 7 94 11 108
rect 23 105 27 108
@ -102,50 +98,39 @@ rect 15 78 19 80
rect 23 94 27 101
rect 23 78 27 80
rect 15 75 18 78
rect 15 72 21 75
rect 15 74 31 75
rect 15 72 27 74
rect 7 65 9 69
rect 18 66 21 72
rect 18 64 22 66
rect -2 60 18 62
rect 22 60 36 62
rect -2 58 36 60
rect 6 44 9 54
rect 33 51 34 55
rect 31 44 34 51
rect 3 20 6 23
rect 3 15 7 20
<< m2contact >>
rect 32 142 36 146
rect 32 133 36 137
rect 27 66 31 70
rect 13 44 17 48
rect 22 44 26 48
rect 3 11 7 15
<< metal2 >>
rect 10 48 14 163
rect 20 48 24 163
rect 32 146 36 163
rect 32 138 36 142
rect 32 129 36 133
rect 27 62 31 66
rect 10 44 13 48
rect 20 44 22 48
rect 3 8 7 11
rect 3 0 7 4
rect 3 0 7 11
rect 10 0 14 44
rect 20 0 24 44
<< m3contact >>
rect 3 4 7 8
<< metal3 >>
rect 2 8 8 9
rect 2 4 3 8
rect 7 4 8 8
rect 2 3 8 4
<< m3p >>
rect 0 0 34 163
<< labels >>
flabel metal1 0 58 0 58 4 FreeSans 26 0 0 0 vdd
flabel metal1 0 149 0 149 4 FreeSans 26 0 0 0 en
flabel metal1 0 142 0 142 4 FreeSans 26 0 0 0 gnd
flabel metal2 10 0 10 0 4 FreeSans 26 0 0 0 bl
flabel metal2 20 0 20 0 4 FreeSans 26 0 0 0 br
flabel metal3 3 3 3 3 4 FreeSans 26 0 0 0 dout
rlabel metal2 34 131 34 131 1 gnd
rlabel metal2 29 64 29 64 1 vdd
rlabel metal2 12 161 12 161 5 bl
rlabel metal2 22 161 22 161 5 br
rlabel metal2 5 3 5 3 1 dout
<< properties >>
string path 270.000 468.000 270.000 486.000 288.000 486.000 288.000 468.000 270.000 468.000
<< end >>

View File

@ -1,6 +1,6 @@
magic
tech scmos
timestamp 1517275711
timestamp 1524499924
<< nwell >>
rect -2 45 38 73
<< pwell >>
@ -63,8 +63,7 @@ rect 16 38 20 42
rect 25 12 29 16
rect 28 4 32 8
<< metal1 >>
rect 0 65 12 69
rect 16 65 36 69
rect 16 65 23 69
rect 12 61 16 65
rect 3 53 4 61
rect 3 42 6 53
@ -74,40 +73,26 @@ rect 3 31 6 38
rect 29 31 32 53
rect 3 27 4 31
rect 12 23 16 27
rect 0 19 12 23
rect 16 19 32 23
rect 16 19 24 23
rect 0 12 25 16
rect 29 12 36 16
rect 0 4 28 8
rect 32 4 36 8
<< m2contact >>
rect 23 65 27 69
rect 15 46 19 50
rect 25 34 29 38
rect 32 19 36 23
rect 24 19 28 23
<< metal2 >>
rect 15 50 19 73
rect 13 46 15 50
rect 15 34 25 38
rect 15 9 19 34
rect 32 23 36 73
rect 19 5 20 9
rect 15 0 19 5
rect 32 0 36 19
<< m3contact >>
rect 15 5 19 9
<< metal3 >>
rect 14 9 20 10
rect 14 5 15 9
rect 19 5 20 9
rect 14 4 20 5
rect 15 0 19 34
<< m3p >>
rect 0 0 34 73
<< labels >>
rlabel metal2 32 0 32 0 8 gnd
rlabel metal1 0 65 0 65 4 vdd
rlabel metal1 0 12 0 12 3 en
rlabel metal1 0 4 0 4 2 en_bar
rlabel metal1 1 20 1 20 3 gnd
rlabel metal2 16 1 16 1 1 out
rlabel metal2 17 70 17 70 5 in
rlabel m2contact 26 21 26 21 1 gnd
rlabel m2contact 25 67 25 67 1 vdd
rlabel m2contact 17 48 17 48 1 in
<< end >>

View File

@ -1,6 +1,6 @@
magic
tech scmos
timestamp 1517448475
timestamp 1524499497
<< nwell >>
rect -3 101 37 138
rect -3 0 37 51
@ -159,13 +159,15 @@ rect 23 96 27 100
rect 3 71 7 75
rect 23 75 27 79
rect 7 24 11 28
rect 16 10 20 14
rect 15 10 19 14
<< metal1 >>
rect 5 189 8 191
rect 5 192 10 196
rect 5 189 8 192
rect 32 181 33 185
rect 13 169 16 177
rect 13 165 15 169
rect 4 148 8 163
rect 12 157 15 161
rect 12 156 16 157
rect 12 148 16 152
rect 4 132 8 144
@ -174,8 +176,6 @@ rect 30 142 33 181
rect 20 138 33 142
rect 20 132 24 138
rect 12 122 16 125
rect 0 118 8 122
rect 16 118 36 122
rect 13 114 17 118
rect 5 104 9 107
rect 21 104 25 107
@ -183,7 +183,7 @@ rect 5 101 25 104
rect 5 89 9 101
rect 21 100 25 101
rect 21 96 23 100
rect 25 82 26 86
rect 25 82 26 90
rect 4 64 7 71
rect 27 64 31 79
rect 3 51 7 57
@ -192,45 +192,33 @@ rect 11 45 15 48
rect 27 45 31 60
rect 3 35 7 38
rect 19 35 23 38
rect 0 31 3 35
rect 7 31 8 35
rect 12 31 36 35
rect 7 31 19 35
rect 0 24 7 28
rect 11 24 36 28
rect 0 17 32 21
<< m2contact >>
rect 5 191 9 195
rect 10 192 14 196
rect 20 189 24 193
rect 11 157 15 161
rect 8 118 12 122
rect 30 82 34 86
rect 23 153 27 157
rect 16 118 20 122
rect 26 86 30 90
rect 19 64 23 68
rect 8 31 12 35
rect 32 17 36 21
rect 12 10 16 14
rect 19 31 23 35
rect 15 6 19 10
<< metal2 >>
rect 10 195 14 202
rect 9 191 14 195
rect 10 196 14 202
rect 20 193 24 202
rect 20 177 24 189
rect 32 161 36 196
rect 15 157 36 161
rect 8 35 12 118
rect 32 86 36 157
rect 34 82 36 86
rect 32 72 36 82
rect 19 68 36 72
rect 32 21 36 68
rect 16 10 20 14
rect 15 0 19 10
rect 32 0 36 17
rect 15 0 19 6
<< m3p >>
rect 0 0 34 202
<< labels >>
rlabel metal1 0 31 0 31 1 vdd
rlabel metal1 0 17 0 17 7 gnd
rlabel metal2 15 1 15 1 1 din
rlabel metal1 2 25 2 25 3 en
rlabel metal2 12 200 12 200 5 bl
rlabel metal2 22 200 22 200 5 br
rlabel m2contact 21 66 21 66 1 gnd
rlabel m2contact 28 88 28 88 1 gnd
rlabel m2contact 21 33 21 33 1 vdd
rlabel m2contact 18 120 18 120 1 vdd
rlabel m2contact 25 155 25 155 1 gnd
<< end >>

View File

@ -1,8 +1,8 @@
* Positive edge-triggered FF
.subckt dff d q clk vdd gnd
.subckt dff D Q clk vdd gnd
M0 vdd clk a_2_6# vdd p w=12u l=0.6u
+ ad=0p pd=0u as=0p ps=0u
M1 a_17_74# d vdd vdd p w=6u l=0.6u
M1 a_17_74# D vdd vdd p w=6u l=0.6u
+ ad=0p pd=0u as=0p ps=0u
M2 a_22_6# clk a_17_74# vdd p w=6u l=0.6u
+ ad=0p pd=0u as=0p ps=0u
@ -18,13 +18,13 @@ M7 a_66_6# a_2_6# a_61_74# vdd p w=6u l=0.6u
+ ad=0p pd=0u as=0p ps=0u
M8 a_76_84# clk a_66_6# vdd p w=3u l=0.6u
+ ad=0p pd=0u as=0p ps=0u
M9 vdd q a_76_84# vdd p w=3u l=0.6u
M9 vdd Q a_76_84# vdd p w=3u l=0.6u
+ ad=0p pd=0u as=0p ps=0u
M10 gnd clk a_2_6# gnd n w=6u l=0.6u
+ ad=0p pd=0u as=0p ps=0u
M11 q a_66_6# vdd vdd p w=12u l=0.6u
M11 Q a_66_6# vdd vdd p w=12u l=0.6u
+ ad=0p pd=0u as=0p ps=0u
M12 a_17_6# d gnd gnd n w=3u l=0.6u
M12 a_17_6# D gnd gnd n w=3u l=0.6u
+ ad=0p pd=0u as=0p ps=0u
M13 a_22_6# a_2_6# a_17_6# gnd n w=3u l=0.6u
+ ad=0p pd=0u as=0p ps=0u
@ -40,8 +40,8 @@ M18 a_66_6# clk a_61_6# gnd n w=3u l=0.6u
+ ad=0p pd=0u as=0p ps=0u
M19 a_76_6# a_2_6# a_66_6# gnd n w=3u l=0.6u
+ ad=0p pd=0u as=0p ps=0u
M20 gnd q a_76_6# gnd n w=3u l=0.6u
M20 gnd Q a_76_6# gnd n w=3u l=0.6u
+ ad=0p pd=0u as=0p ps=0u
M21 q a_66_6# gnd gnd n w=6u l=0.6u
M21 Q a_66_6# gnd gnd n w=6u l=0.6u
+ ad=0p pd=0u as=0p ps=0u
.ends dff

View File

@ -70,10 +70,13 @@ drc["layer_map"]=os.environ.get("OPENRAM_TECH")+"/scn3me_subm/layers.map"
drc["minwidth_tx"] = 1.2
drc["minlength_channel"] = 0.6
# 1.3 Minimum spacing between wells of same type (if both are drawn)
drc["well_to_well"] = 1.8
# 1.4 Minimum spacing between wells of different type (if both are drawn)
drc["pwell_to_nwell"] = 0
# 1.1 Minimum width
drc["minwidth_well"] = 3.6
drc["minwidth_well"] = 3.6
# 3.1 Minimum width
drc["minwidth_poly"] = 0.6
# 3.2 Minimum spacing over active