mirror of https://github.com/VLSIDA/OpenRAM.git
Merging branch with PrivateRAM dev
This commit is contained in:
commit
b5df0cc30a
|
|
@ -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',
|
||||
|
|
|
|||
|
|
@ -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):
|
||||
"""
|
||||
|
|
|
|||
|
|
@ -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"
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
|
@ -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())
|
||||
|
|
@ -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):
|
||||
|
|
|
|||
|
|
@ -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
|
|
@ -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))
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -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"])
|
||||
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
||||
|
|
@ -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)
|
||||
|
|
@ -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
|
||||
|
||||
|
|
@ -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)
|
||||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -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):
|
||||
|
|
|
|||
|
|
@ -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"])
|
||||
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
|
|
|||
|
|
@ -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",
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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):
|
||||
|
|
|
|||
|
|
@ -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))
|
||||
|
|
|
|||
|
|
@ -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'])
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -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"
|
||||
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
||||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -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))
|
||||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
||||
|
||||
|
||||
437
compiler/sram.py
437
compiler/sram.py
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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()
|
||||
|
|
@ -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()
|
||||
|
|
@ -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()
|
||||
|
|
@ -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()
|
||||
|
|
@ -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()
|
||||
|
|
@ -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()
|
||||
|
|
@ -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()
|
||||
|
|
@ -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()
|
||||
|
|
|
|||
|
|
@ -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()
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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
|
|
@ -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");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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
|
|
@ -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(){
|
||||
|
|
|
|||
|
|
@ -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(){
|
||||
|
|
|
|||
|
|
@ -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.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
|
|
@ -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
|
||||
*
|
||||
|
|
|
|||
|
|
@ -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.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
|
|
@ -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 >>
|
||||
|
|
|
|||
|
|
@ -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 >>
|
||||
|
|
|
|||
|
|
@ -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 >>
|
||||
|
|
|
|||
|
|
@ -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 >>
|
||||
|
|
|
|||
|
|
@ -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 >>
|
||||
|
|
|
|||
|
|
@ -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 >>
|
||||
|
|
|
|||
|
|
@ -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 >>
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
Loading…
Reference in New Issue