Reworking control logic for veritcal poly. Rewrote delay line. Rewrote buffered-DFF array.

This commit is contained in:
Matt Guthaus 2018-03-12 13:14:53 -07:00
parent c020d74f26
commit ed8eaed54f
16 changed files with 1184 additions and 777 deletions

View File

@ -544,6 +544,109 @@ 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()
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 = (3,3))
def pdf_write(self, pdf_name):
# NOTE: Currently does not work (Needs further research)
#self.pdf_name = self.name + ".pdf"

View File

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

View File

@ -9,12 +9,15 @@ from pinv import pinv
from pnand2 import pnand2
from pnor2 import pnor2
from vector import vector
from pinvbuf import pinvbuf
from globals import OPTS
class bank(design.design):
"""
Dynamically generated a single Bank including bitcell array,
hierarchical_decoder, precharge, column_mux, write driver and sense amplifiers.
Dynamically generated a single bank including bitcell array,
hierarchical_decoder, precharge, (optional column_mux and column decoder),
write driver and sense amplifiers.
"""
def __init__(self, word_size, num_words, words_per_row, num_banks=1, name=""):
@ -40,7 +43,8 @@ class bank(design.design):
self.num_banks = num_banks
# The local control signals are gated when we have bank select logic,
# so this prefix will be added to all of the input signals.
# so this prefix will be added to all of the input signals to create
# the internal gated signals.
if self.num_banks>1:
self.prefix="gated_"
else:
@ -51,13 +55,14 @@ class bank(design.design):
self.create_modules()
self.add_modules()
self.setup_layout_constraints()
self.route_power_ring(self.core_bbox)
if self.num_banks > 1:
self.add_bank_select()
self.add_power_ring(self.core_bbox)
# FIXME: Move this to the add modules function
self.add_bank_select()
self.route_layout()
# Can remove the following, but it helps for debug!
self.add_lvs_correspondence_points()
@ -71,7 +76,7 @@ class bank(design.design):
for i in range(self.word_size):
self.add_pin("DATA[{0}]".format(i))
for i in range(self.addr_size):
self.add_pin("ADDR[{0}]".format(i))
self.add_pin("A[{0}]".format(i))
# For more than one bank, we have a bank select and name
# the signals gated_*.
@ -83,14 +88,14 @@ class bank(design.design):
def route_layout(self):
""" Create routing amoung the modules """
self.create_central_bus()
self.route_central_bus()
self.route_precharge_to_bitcell_array()
self.route_sense_amp_to_trigate()
self.route_tri_gate_out()
self.route_wordline_driver()
self.route_row_decoder()
self.route_address()
self.route_column_address_lines()
self.route_msf_address()
self.route_control_lines()
self.add_control_pins()
if self.num_banks > 1:
@ -101,9 +106,12 @@ class bank(design.design):
def add_modules(self):
""" Add modules. The order should not matter! """
# Above the bitcell array
self.add_bitcell_array()
self.add_precharge_array()
# Below the bitcell array
if self.col_addr_size > 0:
# The m2 width is because the 6T cell may have vias on the boundary edge for
# overlapping when making the array
@ -111,16 +119,17 @@ class bank(design.design):
self.add_column_mux_array()
else:
self.column_mux_height = 0
if self.col_addr_size > 1: # size 1 is from addr FF
self.add_column_decoder()
self.add_sense_amp_array()
self.add_write_driver_array()
self.add_msf_data_in()
self.add_tri_gate_array()
# To the left of the bitcell array
self.add_row_decoder()
self.add_wordline_driver()
self.add_msf_address()
self.add_column_decoder()
def compute_sizes(self):
""" Computes the required sizes to create the bank """
@ -143,28 +152,29 @@ class bank(design.design):
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_bar", "w_en", "s_en"]
# These will be outputs of the gaters if this is multibank
# These will be outputs of the gaters if this is multibank, if not, normal signals.
if self.num_banks > 1:
self.control_signals = ["gated_"+str for str in self.input_control_signals]
else:
self.control_signals = self.input_control_signals
# The central bus is the column address (both polarities), row address
# The central bus is the column address (one hot) and row address (binary)
if self.col_addr_size>0:
self.num_addr_lines = 2**self.col_addr_size + self.row_addr_size
self.num_col_addr_lines = 2**self.col_addr_size
self.num_addr_lines = self.num_col_addr_lines + self.row_addr_size
else:
self.num_col_addr_lines = 0
self.num_addr_lines = self.row_addr_size
# 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)
# Overall central bus gap. It includes all the column mux lines,
# control lines, and address flop to decoder lines
# 1.5 pitches on the right on the right of the control lines for vias (e.g. column mux addr lines)
self.start_of_right_central_bus = -self.m2_pitch * (self.num_control_lines + 1.5)
self.start_of_left_central_bus = self.start_of_right_central_bus - self.m2_pitch*(self.num_addr_lines)
# add a pitch on each side
self.overall_central_bus_width = self.m2_pitch * (self.num_control_lines + self.num_addr_lines + 3)
# The width of this bus is needed to place other modules (e.g. decoder)
self.central_bus_width = self.m2_pitch * (self.num_control_lines + self.num_addr_lines + 1)
# The width of the bus below the decoder to route to the central bus
self.addr_bus_height = self.m1_pitch * (self.addr_size + 1)
@ -189,20 +199,15 @@ class bank(design.design):
self.sense_amp_array = self.mod_sense_amp_array(word_size=self.word_size,
words_per_row=self.words_per_row)
words_per_row=self.words_per_row)
self.add_mod(self.sense_amp_array)
self.write_driver_array = self.mod_write_driver_array(columns=self.num_cols,
word_size=self.word_size)
self.add_mod(self.write_driver_array)
self.decoder = self.mod_decoder(rows=self.num_rows)
self.add_mod(self.decoder)
self.msf_address = self.mod_ms_flop_array(name="msf_address",
columns=self.row_addr_size+self.col_addr_size,
word_size=self.row_addr_size+self.col_addr_size)
self.add_mod(self.msf_address)
self.row_decoder = self.mod_decoder(rows=self.num_rows)
self.add_mod(self.row_decoder)
self.msf_data_in = self.mod_ms_flop_array(name="msf_data_in",
columns=self.num_cols,
@ -245,7 +250,7 @@ class bank(design.design):
""" Adding Precharge """
# The wells must be far enough apart
# The enclosure is for the well and the spacig is to the bitcell wells
# The enclosure is for the well and the spacing is to the bitcell wells
y_offset = self.bitcell_array.height + 2*drc["pwell_to_nwell"] + drc["well_enclosure_active"]
self.precharge_array_inst=self.add_inst(name="precharge_array",
mod=self.precharge_array,
@ -361,12 +366,11 @@ class bank(design.design):
# The predecoder is below the x-axis and the main decoder is above the x-axis
# The address flop and decoder are aligned in the x coord.
decoder_x_offset = self.decoder.width + self.overall_central_bus_width
addr_x_offset = self.msf_address.height
offset = vector(max(decoder_x_offset, addr_x_offset),
self.decoder.predecoder_height)
decoder_x_offset = self.row_decoder.width + self.central_bus_width
offset = vector(decoder_x_offset,
self.row_decoder.predecoder_height)
self.row_decoder_inst=self.add_inst(name="row_decoder",
mod=self.decoder,
mod=self.row_decoder,
offset=offset.scale(-1,-1))
temp = []
@ -383,7 +387,7 @@ class bank(design.design):
# The wordline driver is placed to the right of the main decoder width.
# This means that it slightly overlaps with the hierarchical decoder,
# but it shares power rails. This may differ for other decoders later...
x_offset = self.decoder.width + self.overall_central_bus_width - self.decoder.row_decoder_width
x_offset = self.row_decoder.width + self.central_bus_width - self.row_decoder.row_decoder_width
self.wordline_driver_inst=self.add_inst(name="wordline_driver",
mod=self.wordline_driver,
offset=vector(x_offset,0).scale(-1,-1))
@ -398,73 +402,54 @@ class bank(design.design):
temp.append("gnd")
self.connect_inst(temp)
def add_msf_address(self):
""" Adding address wires """
# A gap between the hierarchical decoder and addr flops
gap = max(drc["pwell_to_nwell"], 2*self.m2_pitch)
# The address flops go below the hierarchical decoder
decoder_x_offset = self.decoder.width + self.overall_central_bus_width
addr_x_offset = self.msf_address.height + self.overall_central_bus_width
# msf_address is not in the y-coord because it is rotated
offset = vector(max(decoder_x_offset, addr_x_offset),
self.decoder.predecoder_height + gap)
self.msf_address_inst=self.add_inst(name="address_flop_array",
mod=self.msf_address,
offset=offset.scale(-1,-1),
rotate=270)
temp = []
for i in range(self.row_addr_size+self.col_addr_size):
temp.append("ADDR[{0}]".format(i))
for i in range(self.row_addr_size+self.col_addr_size):
if self.col_addr_size==1 and i==self.row_addr_size:
temp.extend(["sel[1]","sel[0]"])
else:
temp.extend(["A[{0}]".format(i),"A_bar[{0}]".format(i)])
temp.append(self.prefix+"clk_buf")
temp.extend(["vdd", "gnd"])
self.connect_inst(temp)
def add_column_decoder(self):
""" Create a 2:4 decoder to decode column select lines if the col_addr_size = 4 """
if self.col_addr_size == 1:
return # This is done from the FF outputs directly
if self.col_addr_size == 2:
# FIXME: Should just load this rather than reference a level down
self.col_decoder = self.decoder.pre2_4
elif self.col_addr_size == 3:
debug.error("8 way column mux not yet supported...", -1)
# FIXME: Should just load this rather than reference a level down
self.col_decoder = self.decoder.pre3_8
else:
# No error checking before?
debug.error("Invalid column decoder?",-1)
# Place the col decoder just to the left of the control bus
gap = max(drc["pwell_to_nwell"], 2*self.m2_pitch)
x_off = gap + self.overall_central_bus_width + self.col_decoder.width
# Place the col decoder below the the address flops which are below the row decoder (lave some space for wells)
vertical_gap = max(drc["pwell_to_nwell"], 2*self.m2_pitch)
y_off = self.decoder.predecoder_height + self.msf_address.width + self.col_decoder.height + 2*vertical_gap
def add_column_decoder_module(self):
"""
Create a 2:4 or 3:8 column address decoder.
"""
# Place the col decoder aligned left to row decoder
x_off = -(self.central_bus_width + self.row_decoder.width)
y_off = -(self.row_decoder.predecoder_height + self.col_decoder.height + self.addr_bus_height)
self.col_decoder_inst=self.add_inst(name="col_address_decoder",
mod=self.col_decoder,
offset=vector(x_off,y_off).scale(-1,-1))
offset=vector(x_off,y_off))
temp = []
for i in range(self.col_addr_size):
temp.append("A[{0}]".format(i + self.row_addr_size))
for j in range(2**self.col_addr_size):
for j in range(self.num_col_addr_lines):
temp.append("sel[{0}]".format(j))
temp.extend(["vdd", "gnd"])
self.connect_inst(temp)
def add_column_decoder(self):
"""
Create a decoder to decode column select lines. This could be an inverter/buffer for 1:2,
2:4 decoder, or 3:8 decoder.
"""
if self.col_addr_size == 0:
return
elif self.col_addr_size == 1:
self.col_decoder = pinvbuf()
self.add_mod(self.col_decoder)
elif self.col_addr_size == 2:
self.col_decoder = self.row_decoder.pre2_4
elif self.col_addr_size == 3:
self.col_decoder = self.row_decoder.pre3_8
else:
# No error checking before?
debug.error("Invalid column decoder?",-1)
self.add_column_decoder_module()
def add_bank_select(self):
""" Instantiate the bank select logic. """
xoffset = self.left_vdd_x_offset + self.supply_rail_pitch
if not self.num_banks > 1:
return
xoffset = -(self.central_bus_width + self.bank_select.width)
# extra space to allow vias
yoffset = self.min_point + 2*self.supply_rail_pitch + self.m1_space
self.bank_select_pos = vector(xoffset,yoffset)
@ -492,7 +477,7 @@ class bank(design.design):
for gated_name in self.control_signals:
# Connect the inverter output to the central bus
out_pos = self.bank_select_inst.get_pin(gated_name).rc()
bus_pos = vector(self.central_line_xoffset[gated_name], out_pos.y)
bus_pos = vector(self.bus_xoffset[gated_name], out_pos.y)
self.add_path("metal3",[out_pos, bus_pos])
self.add_via_center(layers=("metal2", "via2", "metal3"),
offset=bus_pos,
@ -506,34 +491,36 @@ class bank(design.design):
def setup_layout_constraints(self):
""" Calculating layout constraints, width, height etc """
""" After the modules are instantiated, find the dimensions for the
control bus, power ring, etc. """
#The minimum point is either the bottom of the address flops,
#the column decoder (if there is one) or the tristate output
#driver.
# Leave room for the output below the tri gate.
tri_gate_min_point = self.tri_gate_array_inst.ll().y - 3*self.m2_pitch
addr_min_point = self.msf_address_inst.ll().y - 2*self.m2_pitch
if self.col_addr_size >1:
self.decoder_min_point = self.col_decoder_inst.ll().y
tri_gate_min_point = self.tri_gate_array_inst.by() - 3*self.m2_pitch
row_decoder_min_point = self.row_decoder_inst.by()
if self.col_addr_size > 0:
col_decoder_min_point = self.col_decoder_inst.by()
else:
self.decoder_min_point = addr_min_point
col_decoder_min_point = row_decoder_min_point - self.addr_bus_height
self.addr_min_point = row_decoder_min_point - self.addr_bus_height
if self.num_banks>1:
# The control gating logic is below the decoder
# Min of the control gating logic and tri gate.
self.min_point = min(self.decoder_min_point - self.bank_select.height, tri_gate_min_point)
self.min_point = min(col_decoder_min_point - self.bank_select.height, tri_gate_min_point)
else:
# Just the min of the decoder logic logic and tri gate.
self.min_point = min(self.decoder_min_point, addr_min_point, tri_gate_min_point)
self.min_point = min(col_decoder_min_point, tri_gate_min_point)
# The max point is always the top of the precharge bitlines
# Add a vdd and gnd power rail above the array
self.max_point = self.precharge_array_inst.uy() + 3*self.m1_width
# Create the core bbox for the power rings
ur = vector(self.bitcell_array_inst.ur().x + 3*self.m1_width, self.max_point)
ll = vector(min(self.msf_address_inst.ll().x, self.row_decoder_inst.ll().x), self.min_point)
ll = vector(self.row_decoder_inst.lx(), self.min_point)
self.core_bbox = [ll, ur]
# Compute the vertical rail positions for later use
@ -550,145 +537,62 @@ class bank(design.design):
self.height = self.max_point - self.min_point
self.width = self.right_vdd_x_offset - self.left_gnd_x_offset + self.supply_rail_width
def route_power_ring(self, bbox):
""" Create vdd and gnd power rings around an area of the bounding box argument.. """
[ll, ur] = bbox
# LEFT vertical rails
offset = ll.scale(1,0) + vector(-2*self.supply_rail_pitch, self.min_point)
left_gnd_pin=self.add_layout_pin(text="gnd",
layer="metal2",
offset=offset,
width=self.supply_rail_width,
height=self.height)
offset = ll.scale(1,0) + vector(-1*self.supply_rail_pitch, self.min_point)
left_vdd_pin=self.add_layout_pin(text="vdd",
layer="metal2",
offset=offset,
width=self.supply_rail_width,
height=self.height)
# RIGHT vertical rails
offset = ur.scale(1,0) + vector(0,self.min_point)
right_gnd_pin = self.add_layout_pin(text="gnd",
layer="metal2",
offset=offset,
width=self.supply_rail_width,
height=self.height)
offset = ur.scale(1,0) + vector(self.supply_rail_pitch,self.min_point)
right_vdd_pin=self.add_layout_pin(text="vdd",
layer="metal2",
offset=offset,
width=self.supply_rail_width,
height=self.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=self.width,
height=self.supply_rail_width)
offset = ll + vector(-2*self.supply_rail_pitch, -1*self.supply_rail_pitch)
bottom_vdd_pin=self.add_layout_pin(text="vdd",
layer="metal1",
offset=offset,
width=self.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=self.width,
height=self.supply_rail_width)
offset = vector(ll.x, ur.y) + vector(-2*self.supply_rail_pitch, self.supply_rail_pitch)
top_vdd_pin=self.add_layout_pin(text="vdd",
layer="metal1",
offset=offset,
width=self.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()
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 = (3,3))
def create_central_bus(self):
def route_central_bus(self):
""" Create the address, supply, and control signal central bus lines. """
# Address lines in central line connection are 2*col_addr_size
# number of connections for the column mux (for both signal and _bar) and row_addr_size (no _bar)
# Overall central bus width. It includes all the column mux lines,
# control lines, and address flop to decoder lines.
# The bank is at (0,0), so this is to the left of the y-axis.
# 2 pitches on the right for vias/jogs to access the inputs
control_bus_x_offset = -self.m2_pitch * (self.num_control_lines)
address_bus_x_offset = control_bus_x_offset - self.m2_pitch*(self.num_addr_lines)
self.central_line_xoffset = {}
# Track the bus offsets for other modules to access
self.bus_xoffset = {}
# Control lines (to the right of the GND rail)
# Control lines
for i in range(self.num_control_lines):
x_offset = self.start_of_right_central_bus + i*self.m2_pitch
self.central_line_xoffset[self.control_signals[i]]=x_offset + 0.5*self.m2_width
x_offset = control_bus_x_offset + i*self.m2_pitch
# Make the xoffset map the center of the rail
self.bus_xoffset[self.control_signals[i]]=x_offset + 0.5*self.m2_width
# Pins are added later if this is a single bank, so just add rectangle now
self.add_rect(layer="metal2",
offset=vector(x_offset, self.min_point),
width=self.m2_width,
height=self.height)
# row address lines (to the left of the column mux or GND rail)
# goes from 0 down to the bottom of the address flops
# Row address lines (to left of col address lines)
# goes from bottom of bitcell array down to the bottom of the column decoder/addresses
for i in range(self.row_addr_size):
x_offset = self.start_of_left_central_bus + i*self.m2_pitch
name = "A[{}]".format(i)
self.central_line_xoffset[name]=x_offset + 0.5*self.m2_width
addr_idx = i + self.col_addr_size
x_offset = address_bus_x_offset + i*self.m2_pitch
name = "A[{}]".format(addr_idx)
# Make the xoffset map the center of the rail
self.bus_xoffset[name]=x_offset + 0.5*self.m2_width
# Add a label pin for LVS correspondence and visual help inspecting the rail.
self.add_label_pin(text=name,
layer="metal2",
offset=vector(x_offset, self.decoder_min_point),
offset=vector(x_offset, self.addr_min_point),
width=self.m2_width,
height=-self.decoder_min_point)
height=-self.addr_min_point)
# column mux lines if there is column mux [2 or 4 lines] (to the left of the GND rail)
# goes from 0 down to the min point
# Column mux lines if there is column mux
# goes from bottom of bitcell array down to the bottom of the column decoder/addresses
if self.col_addr_size>0:
for i in range(2**self.col_addr_size):
x_offset = self.start_of_left_central_bus + (i+self.row_addr_size)*self.m2_pitch
name = "sel[{}]".format(i)
self.central_line_xoffset[name]=x_offset + 0.5*self.m2_width
for i in range(self.num_col_addr_lines):
x_offset = address_bus_x_offset + (i+self.row_addr_size)*self.m2_pitch
name = "sel[{}]".format(i) # One hot select signals
# Make the xoffset map the center of the rail
self.bus_xoffset[name]=x_offset + 0.5*self.m2_width
# Add a label pin for LVS correspondence
self.add_label_pin(text=name,
layer="metal2",
offset=vector(x_offset, self.decoder_min_point),
offset=vector(x_offset, self.col_decoder_inst.by()),
width=self.m2_width,
height=-self.decoder_min_point)
height=-self.col_decoder_inst.by())
def route_precharge_to_bitcell_array(self):
@ -758,10 +662,10 @@ class bank(design.design):
def route_row_decoder(self):
""" Routes the row decoder inputs and supplies """
for i in range(self.row_addr_size):
addr_idx = i + self.col_addr_size
# before this index, we are using 2x4 decoders
switchover_index = 2*self.decoder.no_of_pre2x4
switchover_index = 2*self.row_decoder.no_of_pre2x4
# so decide what modulus to perform the height spacing
if i < switchover_index:
position_heights = i % 2
@ -770,8 +674,10 @@ class bank(design.design):
# Connect the address rails to the decoder
# Note that the decoder inputs are long vertical rails so spread out the connections vertically.
decoder_in_position = self.row_decoder_inst.get_pin("A[{}]".format(i)).lr() + vector(0,position_heights*self.bitcell.height+self.m2_pitch)
rail_position = vector(self.central_line_xoffset["A[{}]".format(i)],decoder_in_position.y)
decoder_in_position = self.row_decoder_inst.get_pin("A[{}]".format(i)).lr() \
+ vector(0,position_heights*self.bitcell.height+self.m2_pitch)
rail_position = vector(self.bus_xoffset["A[{}]".format(addr_idx)],
decoder_in_position.y)
self.add_path("metal1",[decoder_in_position,rail_position])
decoder_in_via = decoder_in_position - vector(0,0.5*self.m2_width)
@ -841,156 +747,101 @@ class bank(design.design):
# Connect the select lines to the column mux
# These must be in metal3 so that they don't overlap any gnd lines from decoders
for i in range(2**self.col_addr_size):
for i in range(self.num_col_addr_lines):
name = "sel[{}]".format(i)
mux_addr_pos = self.col_mux_array_inst.get_pin(name).lc()
wire_pos = vector(self.central_line_xoffset[name], mux_addr_pos.y)
wire_pos = vector(self.bus_xoffset[name], mux_addr_pos.y)
self.add_path("metal1", [wire_pos,mux_addr_pos])
self.add_via_center(layers=("metal1", "via1", "metal2"),
offset=wire_pos,
rotate=90)
# Take care of the column address decoder routing
# If there is a 2:4 decoder for column select lines
# or TODO 3:8 decoder should work too!
if self.col_addr_size > 1:
# connections between outputs of decoder to the extension of
# main address bus
for i in range(2**self.col_addr_size):
if self.col_addr_size == 1:
decode_out_pos = self.col_decoder_inst.get_pin("Zb").rc()
selx_pos = vector(self.bus_xoffset["sel[0]"],decode_out_pos.y)
self.add_path("metal1",[decode_out_pos, selx_pos])
self.add_via_center(layers=("metal1", "via1", "metal2"),
offset=selx_pos,
rotate=90)
decode_out_pos = self.col_decoder_inst.get_pin("Z").rc()
selx_pos = vector(self.bus_xoffset["sel[1]"],decode_out_pos.y)
self.add_path("metal1",[decode_out_pos, selx_pos])
self.add_via_center(layers=("metal1", "via1", "metal2"),
offset=selx_pos,
rotate=90)
# The Address LSB
decode_in_pin = self.col_decoder_inst.get_pin("A")
pin_pos = vector(self.left_gnd_x_offset, decode_in_pin.cy())
self.add_layout_pin_center_segment(text="A[0]",
layer="metal1",
start=pin_pos,
end=decode_in_pin.lc())
elif self.col_addr_size > 1:
# Route the col decoder outputs to the col select bus
for i in range(self.num_col_addr_lines):
name = "sel[{}]".format(i)
x_offset = self.central_line_xoffset[name]
decode_out_pos = self.col_decoder_inst.get_pin("out[{}]".format(i)).rc()
selx_pos = vector(self.central_line_xoffset[name],decode_out_pos.y)
selx_pos = vector(self.bus_xoffset[name],decode_out_pos.y)
self.add_path("metal1",[decode_out_pos, selx_pos])
self.add_via_center(layers=("metal1", "via1", "metal2"),
offset=selx_pos,
rotate=90)
# route the gnd rails, add contact to rail as well
for gnd_pin in self.col_decoder_inst.get_pins("gnd"):
left_rail_pos = vector(self.left_gnd_x_offset, gnd_pin.cy())
self.add_path("metal1", [left_rail_pos, gnd_pin.rc()])
# Route from the col decoder up to the address bus
for i in range(self.col_addr_size):
name = "A[{}]".format(i)
decode_in_pin = self.col_decoder_inst.get_pin("in[{}]".format(i))
addr_pin = self.get_pin(name)
addr_pos = vector(decode_in_pin.cx(), addr_pin.by() + 0.5*self.m1_width)
self.add_path("metal2", [addr_pos, decode_in_pin.uc()])
self.add_via_center(layers=("metal1", "via1", "metal2"),
offset=left_rail_pos,
size = (1,3),
rotate=90)
# route the vdd rails
for vdd_pin in self.col_decoder_inst.get_pins("vdd"):
left_rail_pos = vector(self.left_vdd_x_center, vdd_pin.cy())
self.add_path("metal1", [left_rail_pos, vdd_pin.rc()])
self.add_via_center(layers=("metal1", "via1", "metal2"),
offset=left_rail_pos,
size = (1,3),
rotate=90)
offset=addr_pos,
rotate=90)
# route the gnd rails, add contact to rail as well
for gnd_pin in self.col_decoder_inst.get_pins("gnd"):
left_rail_pos = vector(self.left_gnd_x_center, gnd_pin.cy())
self.add_path("metal1", [left_rail_pos, gnd_pin.rc()])
self.add_via_center(layers=("metal1", "via1", "metal2"),
offset=left_rail_pos,
size = (1,3),
rotate=90)
# route the vdd rails
for vdd_pin in self.col_decoder_inst.get_pins("vdd"):
left_rail_pos = vector(self.left_vdd_x_center, vdd_pin.cy())
self.add_path("metal1", [left_rail_pos, vdd_pin.rc()])
self.add_via_center(layers=("metal1", "via1", "metal2"),
offset=left_rail_pos,
size = (1,3),
rotate=90)
# The connection between last address flops to the input
# of the column_mux line decoder
for i in range(self.col_addr_size):
ff_index = i + self.row_addr_size
dout_pos = self.msf_address_inst.get_pin("dout[{}]".format(ff_index)).rc()
in_pos = self.col_decoder_inst.get_pin("in[{}]".format(i)).uc()
mid_pos = vector(in_pos.x,dout_pos.y)
self.add_path("metal3",[dout_pos, mid_pos, in_pos])
self.add_via_center(layers=("metal2", "via2", "metal3"),
offset=dout_pos,
rotate=90)
self.add_via_center(layers=("metal2", "via2", "metal3"),
offset=in_pos)
# if there are only two column select lines we just connect the dout_bar of the last FF
# to only select line and dout of that FF to the other select line
elif self.col_addr_size == 1:
dout_bar_pos = self.msf_address_inst.get_pin("dout_bar[{}]".format(self.row_addr_size)).rc()
sel0_pos = vector(self.central_line_xoffset["sel[0]"],dout_bar_pos.y)
self.add_path("metal1",[dout_bar_pos, sel0_pos])
# two vias on both ends
self.add_via_center(layers=("metal1", "via1", "metal2"),
offset=dout_bar_pos,
rotate=90)
self.add_via_center(layers=("metal1", "via1", "metal2"),
offset=sel0_pos,
rotate=90)
dout_pos = self.msf_address_inst.get_pin("dout[{}]".format(self.row_addr_size)).rc()
sel1_pos = vector(self.central_line_xoffset["sel[1]"],dout_pos.y)
self.add_path("metal1",[dout_pos, sel1_pos])
# two vias on both ends
self.add_via_center(layers=("metal1", "via1", "metal2"),
offset=dout_pos,
rotate=90)
self.add_via_center(layers=("metal1", "via1", "metal2"),
offset=sel1_pos,
rotate=90)
def route_msf_address(self):
def route_address(self):
""" Routing the row address lines from the address ms-flop array to the row-decoder """
# Create the address input pins
for i in range(self.addr_size):
msf_din_pins = self.msf_address_inst.get_pins("din[{}]".format(i))
for pin in msf_din_pins:
if pin.layer=="metal3":
msf_din_pos=pin.ll()
break
address_pos = vector(self.left_gnd_x_offset, msf_din_pos.y)
self.add_layout_pin(text="ADDR[{}]".format(i),
layer="metal3",
offset=address_pos,
width=msf_din_pos.x - address_pos.x)
for i in range(self.row_addr_size):
# Connect the ff outputs to the rails
dout_pos = self.msf_address_inst.get_pin("dout[{}]".format(i)).rc()
rail_pos = vector(self.central_line_xoffset["A[{}]".format(i)],dout_pos.y)
self.add_path("metal1",[dout_pos, rail_pos])
self.add_via_center(layers=("metal1", "via1", "metal2"),
offset=dout_pos,
rotate=90)
name = "A[{}]".format(i)
address_y_offset = self.addr_min_point + (i+1)*self.m1_pitch
pin_pos = vector(self.left_gnd_x_offset, address_y_offset)
if name in self.bus_xoffset:
rail_pos = vector(self.bus_xoffset[name],pin_pos.y)
else:
# Route to right of col decoder if it's not part of central bus
rail_pos = vector(self.col_decoder_inst.rx(),pin_pos.y)
self.add_layout_pin_center_segment(text=name,
layer="metal1",
start=pin_pos,
end=rail_pos)
self.add_via_center(layers=("metal1", "via1", "metal2"),
offset=rail_pos,
rotate=90)
# Connect address FF gnd
for gnd_pin in self.msf_address_inst.get_pins("gnd"):
if gnd_pin.layer != "metal2":
continue
gnd_via = gnd_pin.ll() + vector(contact.m1m2.height,0)
self.add_via(layers=("metal1", "via1", "metal2"),
offset=gnd_via,
rotate=90)
gnd_offset = gnd_pin.lc()
rail_offset = vector(self.left_gnd_x_center, gnd_offset.y)
self.add_path("metal1",[gnd_offset,rail_offset])
self.add_via_center(layers=("metal1", "via1", "metal2"),
offset=rail_offset,
size = (1,3),
rotate=90)
# Connect address FF vdd
for vdd_pin in self.msf_address_inst.get_pins("vdd"):
if vdd_pin.layer != "metal1":
continue
vdd_offset = vdd_pin.bc()
mid = vector(vdd_offset.x, vdd_offset.y - self.m1_pitch)
rail_offset = vector(self.left_vdd_x_center, mid.y)
self.add_path("metal1", [vdd_offset,mid,rail_offset])
self.add_via_center(layers=("metal1", "via1", "metal2"),
offset=rail_offset,
size = (1,3),
rotate=90)
def add_lvs_correspondence_points(self):
""" This adds some points for easier debugging if LVS goes wrong.
@ -1051,27 +902,17 @@ class bank(design.design):
connection.append((self.prefix+"s_en", self.sense_amp_array_inst.get_pin("en").lc()))
for (control_signal, pin_pos) in connection:
control_pos = vector(self.central_line_xoffset[control_signal], pin_pos.y)
control_pos = vector(self.bus_xoffset[control_signal], pin_pos.y)
self.add_path("metal1", [control_pos, pin_pos])
self.add_via_center(layers=("metal1", "via1", "metal2"),
offset=control_pos,
rotate=90)
# clk to msf address
control_signal = self.prefix+"clk_buf"
pin_pos = self.msf_address_inst.get_pin("clk").uc()
mid_pos = pin_pos + vector(0,self.m1_pitch)
control_pos = vector(self.central_line_xoffset[control_signal], mid_pos.y)
self.add_path("metal1",[pin_pos, mid_pos, control_pos])
self.add_via_center(layers=("metal1", "via1", "metal2"),
offset=control_pos,
rotate=90)
# clk to wordline_driver
control_signal = self.prefix+"clk_buf"
pin_pos = self.wordline_driver_inst.get_pin("en").uc()
mid_pos = pin_pos + vector(0,self.m1_pitch)
control_x_offset = self.central_line_xoffset[control_signal]
control_x_offset = self.bus_xoffset[control_signal]
control_pos = vector(control_x_offset + self.m1_width, mid_pos.y)
self.add_wire(("metal1","via1","metal2"),[pin_pos, mid_pos, control_pos])
control_via_pos = vector(control_x_offset, mid_pos.y)
@ -1162,18 +1003,19 @@ class bank(design.design):
""" Add the control signal input pins """
for ctrl in self.control_signals:
x_offset = self.central_line_xoffset[ctrl]
# xoffsets are the center of the rail
x_offset = self.bus_xoffset[ctrl] - 0.5*self.m2_width
if self.num_banks > 1:
# it's not an input pin if we have multiple banks
self.add_label_pin(text=ctrl,
layer="metal2",
offset=vector(x_offset - 0.5*self.m2_width, self.min_point),
offset=vector(x_offset, self.min_point),
width=self.m2_width,
height=self.height)
else:
self.add_layout_pin(text=ctrl,
layer="metal2",
offset=vector(x_offset - 0.5*self.m2_width, self.min_point),
offset=vector(x_offset, self.min_point),
width=self.m2_width,
height=self.height)
@ -1206,9 +1048,9 @@ class bank(design.design):
def analytical_delay(self, slew, load):
""" return analytical delay of the bank"""
msf_addr_delay = self.msf_address.analytical_delay(slew, self.decoder.input_load())
msf_addr_delay = self.msf_address.analytical_delay(slew, self.row_decoder.input_load())
decoder_delay = self.decoder.analytical_delay(msf_addr_delay.slew, self.wordline_driver.input_load())
decoder_delay = self.row_decoder.analytical_delay(msf_addr_delay.slew, self.wordline_driver.input_load())
word_driver_delay = self.wordline_driver.analytical_delay(decoder_delay.slew, self.bitcell_array.input_load())

View File

@ -33,6 +33,9 @@ class bitcell_array(design.design):
self.add_pins()
self.create_layout()
self.add_layout_pins()
self.offset_all_coordinates()
self.DRC_LVS()
def add_pins(self):

View File

@ -7,6 +7,7 @@ from pinv import pinv
from pnand2 import pnand2
from pnand3 import pnand3
from pnor2 import pnor2
from pinvbuf import pinvbuf
import math
from vector import vector
from globals import OPTS
@ -30,7 +31,7 @@ class control_logic(design.design):
self.create_modules()
self.setup_layout_offsets()
self.add_modules()
self.add_routing()
#self.add_routing()
def create_modules(self):
""" add all the required modules """
@ -48,23 +49,18 @@ class control_logic(design.design):
self.add_mod(self.nor2)
# Special gates: inverters for buffering
self.clkbuf = pinvbuf(4,16)
self.add_mod(self.clkbuf)
self.inv = self.inv1 = pinv(1)
self.add_mod(self.inv1)
self.inv2 = pinv(2)
self.add_mod(self.inv2)
self.inv4 = pinv(4)
self.add_mod(self.inv4)
self.inv8 = pinv(8)
self.add_mod(self.inv8)
self.inv16 = pinv(16)
self.add_mod(self.inv16)
c = reload(__import__(OPTS.ms_flop_array))
ms_flop_array = getattr(c, OPTS.ms_flop_array)
self.msf_control = ms_flop_array(name="msf_control",
columns=3,
word_size=3)
self.add_mod(self.msf_control)
# self.inv2 = pinv(2)
# self.add_mod(self.inv2)
# self.inv4 = pinv(4)
# self.add_mod(self.inv4)
# self.inv8 = pinv(8)
# self.add_mod(self.inv8)
# self.inv16 = pinv(16)
# self.add_mod(self.inv16)
c = reload(__import__(OPTS.replica_bitline))
replica_bitline = getattr(c, OPTS.replica_bitline)
@ -91,8 +87,8 @@ class control_logic(design.design):
# First RAIL Parameters: gnd, oe, oebar, cs, we, clk_buf, clk_bar
self.rail_1_start_x = 0
self.num_rails_1 = 8
self.rail_1_names = ["clk_buf", "gnd", "oe_bar", "cs", "we", "vdd", "oe", "clk_bar"]
self.num_rails_1 = 7
self.rail_1_names = ["clk_buf", "gnd", "cs", "we", "vdd", "oe", "clk_bar"]
self.overall_rail_1_gap = (self.num_rails_1 + 2) * self.m2_pitch
self.rail_1_x_offsets = {}
@ -103,18 +99,21 @@ class control_logic(design.design):
def add_modules(self):
""" Place all the modules """
self.add_control_flops()
self.add_clk_buffer(0)
self.add_1st_row(0)
self.add_2nd_row(self.inv1.height)
self.add_3rd_row(2*self.inv1.height)
self.add_control_routing()
self.add_rbl(0)
self.add_clk_buffer(row=0) # 0 and 1st row
self.add_oe_row(row=2)
self.add_sen_row(row=3)
self.add_we_row(row=4)
#self.add_control_routing()
self.add_rbl(row=5)
self.add_layout_pins()
self.add_lvs_correspondence_points()
self.height = max(self.replica_bitline.width, 3 * self.inv1.height, self.msf_offset.y)
self.height = max(self.replica_bitline.width, 4 * self.inv1.height)
self.width = self.replica_bitline_offset.x + self.replica_bitline.height
@ -122,7 +121,7 @@ class control_logic(design.design):
def add_routing(self):
""" Routing between modules """
self.add_clk_routing()
#self.add_clk_routing()
self.add_trien_routing()
self.add_rblk_routing()
self.add_wen_routing()
@ -130,116 +129,117 @@ class control_logic(design.design):
self.add_output_routing()
self.add_supply_routing()
def add_control_flops(self):
""" Add the control signal flops for OEb, WEb, CSb. """
self.msf_offset = vector(0, self.inv.height+self.msf_control.width+2*self.m2_pitch)
self.msf_inst=self.add_inst(name="msf_control",
mod=self.msf_control,
offset=self.msf_offset,
rotate=270)
# don't change this order. This pins are meant for internal connection of msf array inside the control logic.
# These pins are connecting the msf_array inside of control_logic.
temp = ["oeb", "csb", "web",
"oe_bar", "oe",
"cs_bar", "cs",
"we_bar", "we",
"clk_buf", "vdd", "gnd"]
self.connect_inst(temp)
def add_rbl(self,y_off):
def add_rbl(self,row):
""" Add the replica bitline """
# Add to the right of the control rows and routing channel
rows_end_x = max (self.row_1_end_x, self.row_2_end_x, self.row_3_end_x)
y_off = row * self.inv1.height
self.replica_bitline_offset = vector(rows_end_x , y_off)
# Add the RBL above the rows
# Add to the right of the control rows and routing channel
self.replica_bitline_offset = vector(0, y_off)
self.rbl=self.add_inst(name="replica_bitline",
mod=self.replica_bitline,
offset=self.replica_bitline_offset,
mirror="MX",
rotate=90)
offset=self.replica_bitline_offset)
self.connect_inst(["rblk", "pre_s_en", "vdd", "gnd"])
def add_layout_pins(self):
""" Add the input/output layout pins. """
# Top to bottom: CS WE OE signal groups
pin_set = ["oeb","csb","web"]
for (i,pin_name) in zip(range(3),pin_set):
subpin_name="din[{}]".format(i)
pins=self.msf_inst.get_pins(subpin_name)
for pin in pins:
if pin.layer=="metal3":
self.add_layout_pin(text=pin_name,
layer="metal3",
offset=pin.ll(),
width=pin.width(),
height=pin.height())
# # Top to bottom: CS WE OE signal groups
# pin_set = ["oeb","csb","web"]
# for (i,pin_name) in zip(range(3),pin_set):
# subpin_name="din[{}]".format(i)
# pins=self.msf_inst.get_pins(subpin_name)
# for pin in pins:
# if pin.layer=="metal3":
# self.add_layout_pin(text=pin_name,
# layer="metal3",
# offset=pin.ll(),
# width=pin.width(),
# height=pin.height())
pin=self.clk_inv1.get_pin("A")
pin=self.clkbuf.get_pin("A")
self.add_layout_pin(text="clk",
layer="metal1",
offset=pin.ll().scale(0,1),
width=pin.rx(),
height=pin.height())
pin=self.clk_inv1.get_pin("gnd")
self.add_layout_pin(text="gnd",
layer="metal1",
offset=pin.ll(),
width=self.width)
# pin=self.clkbuf.get_pin("gnd")
# self.add_layout_pin(text="gnd",
# layer="metal1",
# offset=pin.ll(),
# width=self.width)
pin=self.clk_inv1.get_pin("vdd")
self.add_layout_pin(text="vdd",
layer="metal1",
offset=pin.ll(),
width=self.width)
# pin=self.clkbuf.get_pin("vdd")
# self.add_layout_pin(text="vdd",
# layer="metal1",
# offset=pin.ll(),
# width=self.width)
def add_clk_buffer(self,y_off):
def add_clk_buffer(self,row):
""" Add the multistage clock buffer below the control flops """
# 4 stage clock buffer
self.clk_inv1_offset = vector(0, y_off)
self.clk_inv1=self.add_inst(name="inv_clk1_bar",
mod=self.inv2,
offset=self.clk_inv1_offset)
self.connect_inst(["clk", "clk1_bar", "vdd", "gnd"])
self.clk_inv2_offset = self.clk_inv1_offset + vector(self.inv2.width,0)
self.clk_inv2=self.add_inst(name="inv_clk2",
mod=self.inv4,
offset=self.clk_inv2_offset)
self.connect_inst(["clk1_bar", "clk2", "vdd", "gnd"])
self.clk_bar_offset = self.clk_inv2_offset + vector(self.inv4.width,0)
self.clk_bar=self.add_inst(name="inv_clk_bar",
mod=self.inv8,
offset=self.clk_bar_offset)
self.connect_inst(["clk2", "clk_bar", "vdd", "gnd"])
self.clk_buf_offset = self.clk_bar_offset + vector(self.inv8.width,0)
self.clk_buf=self.add_inst(name="inv_clk_buf",
mod=self.inv16,
offset=self.clk_buf_offset)
self.connect_inst(["clk_bar", "clk_buf", "vdd", "gnd"])
y_off = row*self.inv1.height
if row % 2:
y_off += self.clkbuf.height
mirror="MX"
else:
mirror="R0"
# Connect between the inverters
self.add_path("metal1", [self.clk_inv1.get_pin("Z").center(),
self.clk_inv2.get_pin("A").center()])
self.add_path("metal1", [self.clk_inv2.get_pin("Z").center(),
self.clk_bar.get_pin("A").center()])
self.add_path("metal1", [self.clk_bar.get_pin("Z").center(),
self.clk_buf.get_pin("A").center()])
clkbuf_offset = vector(0,y_off)
self.clkbuf_inst = self.add_inst(name="clkbuf",
mod=self.clkbuf,
offset=clkbuf_offset)
self.connect_inst(["clk","clk_bar","clk","vdd","gnd"])
# # 4 stage clock buffer
# self.clk_inv1_offset = vector(self.rail_1_start_x, y_off)
# self.clk_inv1=self.add_inst(name="inv_clk1_bar",
# mod=self.inv2,
# offset=self.clk_inv1_offset)
# self.connect_inst(["clk", "clk1_bar", "vdd", "gnd"])
# self.clk_inv2_offset = self.clk_inv1_offset + vector(self.inv2.width,0)
# self.clk_inv2=self.add_inst(name="inv_clk2",
# mod=self.inv4,
# offset=self.clk_inv2_offset)
# self.connect_inst(["clk1_bar", "clk2", "vdd", "gnd"])
# self.clk_bar_offset = self.clk_inv2_offset + vector(self.inv4.width,0)
# self.clk_bar=self.add_inst(name="inv_clk_bar",
# mod=self.inv8,
# offset=self.clk_bar_offset)
# self.connect_inst(["clk2", "clk_bar", "vdd", "gnd"])
# self.clk_buf_offset = self.clk_bar_offset + vector(self.inv8.width,0)
# self.clk_buf=self.add_inst(name="inv_clk_buf",
# mod=self.inv16,
# offset=self.clk_buf_offset)
# self.connect_inst(["clk_bar", "clk_buf", "vdd", "gnd"])
# # Connect between the inverters
# self.add_path("metal1", [self.clk_inv1.get_pin("Z").center(),
# self.clk_inv2.get_pin("A").center()])
# self.add_path("metal1", [self.clk_inv2.get_pin("Z").center(),
# self.clk_bar.get_pin("A").center()])
# self.add_path("metal1", [self.clk_bar.get_pin("Z").center(),
# self.clk_buf.get_pin("A").center()])
# This is the first rail offset
self.rail_1_start_x = max(self.msf_offset.x + self.msf_control.height,self.clk_buf_offset.x+self.inv16.width) + self.m2_pitch
def add_1st_row(self,y_off):
x_off = self.rail_1_start_x + self.overall_rail_1_gap
def add_rblk_row(self,row):
x_off = 0
y_off = row*self.inv1.height
if row % 2:
y_off += self.inv1.height
mirror="MX"
else:
mirror="R0"
# input: OE, clk_bar,CS output: rblk_bar
self.rblk_bar_offset = vector(x_off, y_off)
self.rblk_bar=self.add_inst(name="nand3_rblk_bar",
mod=self.nand3,
offset=self.rblk_bar_offset)
offset=self.rblk_bar_offset,
mirror=mirror)
self.connect_inst(["clk_bar", "oe", "cs", "rblk_bar", "vdd", "gnd"])
x_off += self.nand3.width
@ -247,36 +247,21 @@ class control_logic(design.design):
self.rblk_offset = vector(x_off, y_off)
self.rblk=self.add_inst(name="inv_rblk",
mod=self.inv1,
offset=self.rblk_offset)
offset=self.rblk_offset,
mirror=mirror)
self.connect_inst(["rblk_bar", "rblk", "vdd", "gnd"])
#x_off += self.inv1.width
self.row_1_end_x = x_off
self.row_rblk_end_x = x_off
def add_2nd_row(self, y_off):
# start after first rails
x_off = self.rail_1_start_x + self.overall_rail_1_gap
y_off += self.inv1.height
# input: clk_buf, OE_bar output: tri_en
self.tri_en_offset = vector(x_off, y_off)
self.tri_en=self.add_inst(name="nor2_tri_en",
mod=self.nor2,
offset=self.tri_en_offset,
mirror="MX")
self.connect_inst(["clk_buf", "oe_bar", "tri_en", "vdd", "gnd"])
x_off += self.nor2.width + self.cell_gap
# input: OE, clk_bar output: tri_en_bar
self.tri_en_bar_offset = vector(x_off,y_off)
self.tri_en_bar=self.add_inst(name="nand2_tri_en",
mod=self.nand2,
offset=self.tri_en_bar_offset,
mirror="MX")
self.connect_inst(["clk_bar", "oe", "tri_en_bar", "vdd", "gnd"])
x_off += self.nand2.width
x_off += self.inv1.width + self.cell_gap
def add_sen_row(self,row):
x_off = 0
y_off = row*self.inv1.height
if row % 2:
y_off += self.inv1.height
mirror="MX"
else:
mirror="R0"
# BUFFER INVERTERS FOR S_EN
# input: input: pre_s_en_bar, output: s_en
@ -284,7 +269,7 @@ class control_logic(design.design):
self.s_en=self.add_inst(name="inv_s_en",
mod=self.inv1,
offset=self.s_en_offset,
mirror="XY")
mirror=mirror)
self.connect_inst(["pre_s_en_bar", "s_en", "vdd", "gnd"])
x_off += self.inv1.width
@ -293,25 +278,70 @@ class control_logic(design.design):
self.pre_s_en_bar=self.add_inst(name="inv_pre_s_en_bar",
mod=self.inv1,
offset=self.pre_s_en_bar_offset,
mirror="XY")
mirror=mirror)
self.connect_inst(["pre_s_en", "pre_s_en_bar", "vdd", "gnd"])
#x_off += self.inv1.width
self.row_sen_end_x = x_off
def add_oe_row(self, row):
x_off = 0
y_off = row*self.inv1.height
if row % 2:
y_off += self.inv1.height
mirror="MX"
else:
mirror="R0"
self.row_2_end_x = x_off
# input: oe output: oe_bar
self.oe_inv_offset = vector(x_off, y_off)
self.oe_inv=self.add_inst(name="oe_inv",
mod=self.inv1,
offset=self.oe_inv_offset,
mirror=mirror)
self.connect_inst(["oe", "oe_bar", "vdd", "gnd"])
x_off += self.inv1.width + self.cell_gap
def add_3rd_row(self, y_off):
# start after first rails
x_off = self.rail_1_start_x + self.overall_rail_1_gap
# input: clk_buf, OE_bar output: tri_en
self.tri_en_offset = vector(x_off, y_off)
self.tri_en=self.add_inst(name="nor2_tri_en",
mod=self.nor2,
offset=self.tri_en_offset,
mirror=mirror)
self.connect_inst(["clk_buf", "oe_bar", "tri_en", "vdd", "gnd"])
x_off += self.nor2.width + self.cell_gap
# input: OE, clk_bar output: tri_en_bar
self.tri_en_bar_offset = vector(x_off,y_off)
self.tri_en_bar=self.add_inst(name="nand2_tri_en",
mod=self.nand2,
offset=self.tri_en_bar_offset,
mirror=mirror)
self.connect_inst(["clk_bar", "oe", "tri_en_bar", "vdd", "gnd"])
#x_off += self.nand2.width
#x_off += self.inv1.width + self.cell_gap
# This prevents some M2 outputs from overlapping (hack)
x_off += self.inv1.width
self.row_oe_end_x = x_off
def add_we_row(self,row):
x_off = 0
y_off = row*self.inv1.height
if row % 2:
y_off += self.inv1.height
mirror="MX"
else:
mirror="R0"
# input: WE, clk_bar, CS output: w_en_bar
self.w_en_bar_offset = vector(x_off, y_off)
self.w_en_bar=self.add_inst(name="nand3_w_en_bar",
mod=self.nand3,
offset=self.w_en_bar_offset)
offset=self.w_en_bar_offset,
mirror=mirror)
self.connect_inst(["clk_bar", "cs", "we", "w_en_bar", "vdd", "gnd"])
x_off += self.nand3.width
@ -319,7 +349,9 @@ class control_logic(design.design):
self.pre_w_en_offset = vector(x_off, y_off)
self.pre_w_en=self.add_inst(name="inv_pre_w_en",
mod=self.inv1,
offset=self.pre_w_en_offset)
offset=self.pre_w_en_offset,
mirror=mirror)
self.connect_inst(["w_en_bar", "pre_w_en", "vdd", "gnd"])
x_off += self.inv1.width
@ -328,71 +360,65 @@ class control_logic(design.design):
self.pre_w_en_bar_offset = vector(x_off, y_off)
self.pre_w_en_bar=self.add_inst(name="inv_pre_w_en_bar",
mod=self.inv1,
offset=self.pre_w_en_bar_offset)
offset=self.pre_w_en_bar_offset,
mirror=mirror)
self.connect_inst(["pre_w_en", "pre_w_en_bar", "vdd", "gnd"])
x_off += self.inv1.width
self.w_en_offset = vector(x_off, y_off)
self.w_en=self.add_inst(name="inv_w_en2",
mod=self.inv1,
offset=self.w_en_offset)
offset=self.w_en_offset,
mirror=mirror)
self.connect_inst(["pre_w_en_bar", "w_en", "vdd", "gnd"])
#x_off += self.inv1.width
self.row_3_end_x = x_off
self.row_we_end_x = x_off
def add_control_routing(self):
""" Route the vertical rails for internal control signals """
# def add_control_routing(self):
# """ Route the vertical rails for internal control signals """
control_rail_height = max(3 * self.inv1.height, self.msf_offset.y)
# control_rail_height = 3*self.inv1.height
for i in range(self.num_rails_1):
offset = vector(self.rail_1_start_x + (i+1) * self.m2_pitch,0)
if self.rail_1_names[i] in ["clk_buf", "clk_bar", "vdd", "gnd"]:
self.add_layout_pin(text=self.rail_1_names[i],
layer="metal2",
offset=offset,
width=drc["minwidth_metal2"],
height=control_rail_height)
else:
# just for LVS correspondence...
self.add_label_pin(text=self.rail_1_names[i],
layer="metal2",
offset=offset,
width=drc["minwidth_metal2"],
height=control_rail_height)
self.rail_1_x_offsets[self.rail_1_names[i]]=offset.x + 0.5*drc["minwidth_metal2"] # center offset
# for i in range(self.num_rails_1):
# offset = vector(self.rail_1_start_x + (i+1) * self.m2_pitch,0)
# if self.rail_1_names[i] in ["clk_buf", "clk_bar", "vdd", "gnd"]:
# self.add_layout_pin(text=self.rail_1_names[i],
# layer="metal2",
# offset=offset,
# width=drc["minwidth_metal2"],
# height=control_rail_height)
# else:
# # just for LVS correspondence...
# self.add_label_pin(text=self.rail_1_names[i],
# layer="metal2",
# offset=offset,
# width=drc["minwidth_metal2"],
# height=control_rail_height)
# self.rail_1_x_offsets[self.rail_1_names[i]]=offset.x + 0.5*drc["minwidth_metal2"] # center offset
# pins are in order ["oeb","csb","web"] # 0 1 2
self.connect_rail_from_left_m2m3(self.msf_inst,"dout_bar[0]","oe")
self.connect_rail_from_left_m2m3(self.msf_inst,"dout[0]","oe_bar")
self.connect_rail_from_left_m2m3(self.msf_inst,"dout_bar[1]","cs")
self.connect_rail_from_left_m2m3(self.msf_inst,"dout_bar[2]","we")
# # # Connect the gnd and vdd of the control
# # gnd_pins = self.msf_inst.get_pins("gnd")
# # for p in gnd_pins:
# # if p.layer != "metal2":
# # continue
# # gnd_pin = p.rc()
# # gnd_rail_position = vector(self.rail_1_x_offsets["gnd"], gnd_pin.y)
# # self.add_wire(("metal3","via2","metal2"),[gnd_pin, gnd_rail_position])
# # self.add_via_center(layers=("metal2","via2","metal3"),
# # offset=gnd_pin,
# # rotate=90)
# # self.add_via_center(layers=("metal2","via2","metal3"),
# # offset=gnd_rail_position,
# # rotate=90)
# Connect the gnd and vdd of the control
gnd_pins = self.msf_inst.get_pins("gnd")
for p in gnd_pins:
if p.layer != "metal2":
continue
gnd_pin = p.rc()
gnd_rail_position = vector(self.rail_1_x_offsets["gnd"], gnd_pin.y)
self.add_wire(("metal3","via2","metal2"),[gnd_pin, gnd_rail_position])
self.add_via_center(layers=("metal2","via2","metal3"),
offset=gnd_pin,
rotate=90)
self.add_via_center(layers=("metal2","via2","metal3"),
offset=gnd_rail_position,
rotate=90)
# # vdd_pins = self.msf_inst.get_pins("vdd")
# # for p in vdd_pins:
# # if p.layer != "metal1":
# # continue
# # clk_vdd_position = vector(p.bc().x,self.clk_buf.get_pin("vdd").uy())
# # self.add_path("metal1",[p.bc(),clk_vdd_position])
vdd_pins = self.msf_inst.get_pins("vdd")
for p in vdd_pins:
if p.layer != "metal1":
continue
clk_vdd_position = vector(p.bc().x,self.clk_buf.get_pin("vdd").uy())
self.add_path("metal1",[p.bc(),clk_vdd_position])
def add_rblk_routing(self):
@ -482,8 +508,13 @@ class control_logic(design.design):
def add_trien_routing(self):
self.connect_rail_from_right(self.oe_inv,"A","oe")
self.connect_rail_from_right(self.tri_en,"A","clk_buf")
self.connect_rail_from_right(self.tri_en,"B","oe_bar")
oe_inv_out_pos = self.oe_inv.get_pin("Z").ul()
in_pos = self.tri_en.get_pin("B").rc()
mid1 = vector(oe_inv_out_pos.x,in_pos.y)
self.add_path("metal1",[oe_inv_out_pos,mid1,in_pos])
self.connect_rail_from_right_m2m3(self.tri_en_bar,"A","clk_bar")
self.connect_rail_from_right_m2m3(self.tri_en_bar,"B","oe")
@ -500,43 +531,43 @@ class control_logic(design.design):
self.add_path("metal1",[self.pre_s_en_bar.get_pin("Z").center(), self.s_en.get_pin("A").center()])
def add_clk_routing(self):
""" Route the clk and clk_bar signal internally """
# def add_clk_routing(self):
# """ Route the clk and clk_bar signal internally """
# clk_buf
clk_buf_pos = self.clk_buf.get_pin("Z").rc()
clk_buf_rail_position = vector(self.rail_1_x_offsets["clk_buf"], clk_buf_pos.y)
self.add_wire(("metal1","via1","metal2"),[clk_buf_pos, clk_buf_rail_position])
self.add_via_center(layers=("metal1","via1","metal2"),
offset=clk_buf_rail_position,
rotate=90)
# # clk_buf
# clk_buf_pos = self.clk_buf.get_pin("Z").rc()
# clk_buf_rail_position = vector(self.rail_1_x_offsets["clk_buf"], clk_buf_pos.y)
# self.add_wire(("metal1","via1","metal2"),[clk_buf_pos, clk_buf_rail_position])
# self.add_via_center(layers=("metal1","via1","metal2"),
# offset=clk_buf_rail_position,
# rotate=90)
# clk_bar, routes over the clock buffer vdd rail
clk_pin = self.clk_bar.get_pin("Z")
vdd_pin = self.clk_bar.get_pin("vdd")
# move the output pin up to metal2
self.add_via_center(layers=("metal1","via1","metal2"),
offset=clk_pin.rc(),
rotate=90)
# route to a position over the supply rail
in_pos = vector(clk_pin.rx(), vdd_pin.cy())
self.add_path("metal2",[clk_pin.rc(), in_pos])
# connect that position to the control bus
rail_pos = vector(self.rail_1_x_offsets["clk_bar"], in_pos.y)
self.add_wire(("metal3","via2","metal2"),[in_pos, rail_pos])
self.add_via_center(layers=("metal2","via2","metal3"),
offset=in_pos,
rotate=90)
self.add_via_center(layers=("metal2","via2","metal3"),
offset=rail_pos,
rotate=90)
# # clk_bar, routes over the clock buffer vdd rail
# clk_pin = self.clk_bar.get_pin("Z")
# vdd_pin = self.clk_bar.get_pin("vdd")
# # move the output pin up to metal2
# self.add_via_center(layers=("metal1","via1","metal2"),
# offset=clk_pin.rc(),
# rotate=90)
# # route to a position over the supply rail
# in_pos = vector(clk_pin.rx(), vdd_pin.cy())
# self.add_path("metal2",[clk_pin.rc(), in_pos])
# # connect that position to the control bus
# rail_pos = vector(self.rail_1_x_offsets["clk_bar"], in_pos.y)
# self.add_wire(("metal3","via2","metal2"),[in_pos, rail_pos])
# self.add_via_center(layers=("metal2","via2","metal3"),
# offset=in_pos,
# rotate=90)
# self.add_via_center(layers=("metal2","via2","metal3"),
# offset=rail_pos,
# rotate=90)
# clk_buf to msf control flops
msf_clk_pos = self.msf_inst.get_pin("clk").bc()
mid1 = msf_clk_pos - vector(0,self.m2_pitch)
clk_buf_rail_position = vector(self.rail_1_x_offsets["clk_buf"], mid1.y)
# route on M2 to allow vdd connection
self.add_wire(("metal2","via1","metal1"),[msf_clk_pos, mid1, clk_buf_rail_position])
# # clk_buf to msf control flops
# msf_clk_pos = self.msf_inst.get_pin("clk").bc()
# mid1 = msf_clk_pos - vector(0,self.m2_pitch)
# clk_buf_rail_position = vector(self.rail_1_x_offsets["clk_buf"], mid1.y)
# # route on M2 to allow vdd connection
# self.add_wire(("metal2","via1","metal1"),[msf_clk_pos, mid1, clk_buf_rail_position])
def connect_right_pin_to_output_pin(self, inst, pin_name, out_name):
""" Create an output pin on the bottom side from the pin of a given instance. """
@ -580,7 +611,7 @@ class control_logic(design.design):
well_width = drc["minwidth_well"]
# M1 gnd rail from inv1 to max
start_offset = self.clk_inv1.get_pin("gnd").lc()
start_offset = self.clkbuf.get_pin("gnd").lc()
row1_gnd_end_offset = vector(rows_end,start_offset.y)
self.add_path("metal1",[start_offset,row1_gnd_end_offset])
rail_position = vector(self.rail_1_x_offsets["gnd"], start_offset.y)
@ -597,7 +628,7 @@ class control_logic(design.design):
height=well_width)
# M1 vdd rail from inv1 to max
start_offset = self.clk_inv1.get_pin("vdd").lc()
start_offset = self.clkbuf.get_pin("vdd").lc()
row1_vdd_end_offset = vector(rows_end,start_offset.y)
self.add_path("metal1",[start_offset,row1_vdd_end_offset])
rail_position = vector(self.rail_1_x_offsets["vdd"], start_offset.y)
@ -667,19 +698,19 @@ class control_logic(design.design):
These should probably be turned off by default though, since extraction
will show these as ports in the extracted netlist.
"""
pin=self.clk_inv1.get_pin("Z")
self.add_label_pin(text="clk1_bar",
layer="metal1",
offset=pin.ll(),
height=pin.height(),
width=pin.width())
# pin=self.clk_inv1.get_pin("Z")
# self.add_label_pin(text="clk1_bar",
# layer="metal1",
# offset=pin.ll(),
# height=pin.height(),
# width=pin.width())
pin=self.clk_inv2.get_pin("Z")
self.add_label_pin(text="clk2",
layer="metal1",
offset=pin.ll(),
height=pin.height(),
width=pin.width())
# pin=self.clk_inv2.get_pin("Z")
# self.add_label_pin(text="clk2",
# layer="metal1",
# offset=pin.ll(),
# height=pin.height(),
# width=pin.width())
pin=self.rbl.get_pin("out")
self.add_label_pin(text="out",
@ -688,4 +719,4 @@ class control_logic(design.design):
height=pin.height(),
width=pin.width())

View File

@ -34,7 +34,7 @@ class delay_chain(design.design):
self.add_pins()
self.create_module()
self.route_inv()
self.route_inverters()
self.add_layout_pins()
self.DRC_LVS()
@ -48,82 +48,69 @@ class delay_chain(design.design):
def create_module(self):
""" Add the inverter logical module """
self.create_inv_list()
self.inv = pinv(route_output=False)
self.add_mod(self.inv)
# half chain length is the width of the layout
# invs are stacked into 2 levels so input/output are close
# extra metal is for the gnd connection U
self.width = self.num_top_half * self.inv.width + 2*drc["metal1_to_metal1"] + 0.5*drc["minwidth_metal1"]
self.height = 2 * self.inv.height
self.height = len(self.fanout_list)*self.inv.height
self.width = (max(self.fanout_list)+1) * self.inv.width
self.add_inv_list()
self.add_inverters()
def create_inv_list(self):
"""
Generate a list of inverters. Each inverter has a stage
number and a flag indicating if it is a dummy load. This is
the order that they will get placed too.
"""
# First stage is always 0 and is not a dummy load
self.inv_list=[[0,False]]
for stage_num,fanout_size in zip(range(len(self.fanout_list)),self.fanout_list):
for i in range(fanout_size-1):
# Add the dummy loads
self.inv_list.append([stage_num+1, True])
# Add the gate to drive the next stage
self.inv_list.append([stage_num+1, False])
def add_inv_list(self):
def add_inverters(self):
""" Add the inverters and connect them based on the stage list """
dummy_load_counter = 1
self.inv_inst_list = []
for i in range(self.num_inverters):
# First place the gates
if i < self.num_top_half:
# add top level that is upside down
inv_offset = vector(i * self.inv.width, 2 * self.inv.height)
inv_mirror="MX"
self.driver_inst_list = []
self.rightest_load_inst = {}
self.load_inst_map = {}
for stage_num,fanout_size in zip(range(len(self.fanout_list)),self.fanout_list):
if stage_num % 2:
inv_mirror = "MX"
inv_offset = vector(0, (stage_num+1)* self.inv.height)
else:
# add bottom level from right to left
inv_offset = vector((self.num_inverters - i) * self.inv.width, 0)
inv_mirror="MY"
cur_inv=self.add_inst(name="dinv{}".format(i),
inv_mirror = "R0"
inv_offset = vector(0, stage_num * self.inv.height)
# Add the inverter
cur_driver=self.add_inst(name="dinv{}".format(stage_num),
mod=self.inv,
offset=inv_offset,
mirror=inv_mirror)
# keep track of the inverter instances so we can use them to get the pins
self.inv_inst_list.append(cur_inv)
self.driver_inst_list.append(cur_driver)
# Second connect them logically
cur_stage = self.inv_list[i][0]
next_stage = self.inv_list[i][0]+1
if i == 0:
input = "in"
# Hook up the driver
if stage_num+1==len(self.fanout_list):
stageout_name = "out"
else:
input = "s{}".format(cur_stage)
if i == self.num_inverters-1:
output = "out"
else:
output = "s{}".format(next_stage)
# if the gate is a dummy load don't connect the output
# else reset the counter
if self.inv_list[i][1]:
output = output+"n{0}".format(dummy_load_counter)
dummy_load_counter += 1
stageout_name = "dout_{}".format(stage_num+1)
if stage_num == 0:
stagein_name = "in"
else:
dummy_load_counter = 1
self.connect_inst(args=[input, output, "vdd", "gnd"])
if i != 0:
self.add_via_center(layers=("metal1", "via1", "metal2"),
offset=cur_inv.get_pin("A").center())
stagein_name = "dout_{}".format(stage_num)
self.connect_inst([stagein_name, stageout_name, "vdd", "gnd"])
# Now add the dummy loads to the right
self.load_inst_map[cur_driver]=[]
for i in range(fanout_size):
inv_offset += vector(self.inv.width,0)
cur_load=self.add_inst(name="dload_{0}_{1}".format(stage_num,i),
mod=self.inv,
offset=inv_offset,
mirror=inv_mirror)
# Fanout stage is always driven by driver and output is disconnected
disconnect_name = "n_{0}_{1}".format(stage_num,i)
self.connect_inst([stageout_name, disconnect_name, "vdd", "gnd"])
# Keep track of all the loads to connect their inputs as a load
self.load_inst_map[cur_driver].append(cur_load)
else:
# Keep track of the last one so we can add the the wire later
self.rightest_load_inst[cur_driver]=cur_load
def add_route(self, pin1, pin2):
""" This guarantees that we route from the top to bottom row correctly. """
pin1_pos = pin1.center()
@ -135,79 +122,88 @@ 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(),
rotate=90)
self.add_via_center(layers=("metal2","via2","metal3"),
offset=a_pin.center(),
rotate=90)
# 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(),
rotate=90)
self.add_via_center(layers=("metal1","via1","metal2"),
offset=z_pin.center(),
rotate=90)
self.add_via_center(layers=("metal2","via2","metal3"),
offset=z_pin.center(),
rotate=90)
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(),
rotate=90)
self.add_layout_pin(text="in",
layer="metal1",
offset=a_pin.ll(),
layer="metal2",
offset=a_pin.ll().scale(1,0),
width=a_pin.width(),
height=a_pin.height())
height=a_pin.cy())
# output is Z pin of last inverter
z_pin = self.inv_inst_list[-1].get_pin("Z")
# 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(),
rotate=90)
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(text="out",
layer="metal1",
offset=z_pin.ll().scale(0,1),
width=z_pin.lx())
layer="metal2",
offset=mid_point.scale(1,0))

View File

@ -4,7 +4,6 @@ from tech import drc
from math import log
from vector import vector
from globals import OPTS
import dff_buf
class dff_array(design.design):
"""
@ -21,7 +20,9 @@ class dff_array(design.design):
design.design.__init__(self, name)
debug.info(1, "Creating {}".format(self.name))
self.dff = dff_buf.dff_buf(inv1_size, inv2_size)
c = reload(__import__(OPTS.dff))
self.mod_dff = getattr(c, OPTS.dff)
self.dff = self.mod_dff("dff")
self.add_mod(self.dff)
self.width = self.columns * self.dff.width
@ -42,7 +43,6 @@ class dff_array(design.design):
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")
@ -64,7 +64,6 @@ class dff_array(design.design):
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"])
@ -89,15 +88,6 @@ class dff_array(design.design):
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):
@ -138,14 +128,6 @@ class dff_array(design.design):
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")

View File

@ -0,0 +1,180 @@
import debug
import design
from tech import drc
from math import log
from vector import vector
from globals import OPTS
import dff_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):
for y in range(self.rows):
# Continous vdd rail along with label.
vdd_pin=self.dff_insts[0,y].get_pin("vdd")
self.add_layout_pin(text="vdd",
layer="metal1",
offset=vdd_pin.ll(),
width=self.width,
height=self.m1_width)
# Continous gnd rail along with label.
gnd_pin=self.dff_insts[0,y].get_pin("gnd")
self.add_layout_pin(text="gnd",
layer="metal1",
offset=gnd_pin.ll(),
width=self.width,
height=self.m1_width)
for y in range(self.rows):
for x in range(self.columns):
din_pin = self.dff_insts[x,y].get_pin("D")
debug.check(din_pin.layer=="metal2","DFF D pin not on metal2")
self.add_layout_pin(text=self.get_din_name(y,x),
layer=din_pin.layer,
offset=din_pin.ll(),
width=din_pin.width(),
height=din_pin.height())
dout_pin = self.dff_insts[x,y].get_pin("Q")
debug.check(dout_pin.layer=="metal2","DFF Q pin not on metal2")
self.add_layout_pin(text=self.get_dout_name(y,x),
layer=dout_pin.layer,
offset=dout_pin.ll(),
width=dout_pin.width(),
height=dout_pin.height())
dout_bar_pin = self.dff_insts[x,y].get_pin("Qb")
debug.check(dout_bar_pin.layer=="metal2","DFF Qb pin not on metal2")
self.add_layout_pin(text=self.get_dout_bar_name(y,x),
layer=dout_bar_pin.layer,
offset=dout_bar_pin.ll(),
width=dout_bar_pin.width(),
height=dout_bar_pin.height())
# Create vertical spines to a single horizontal rail
clk_pin = self.dff_insts[0,0].get_pin("clk")
debug.check(clk_pin.layer=="metal2","DFF clk pin not on metal2")
if self.columns==1:
self.add_layout_pin(text="clk",
layer="metal2",
offset=clk_pin.ll().scale(1,0),
width=self.m2_width,
height=self.height)
else:
self.add_layout_pin(text="clk",
layer="metal3",
offset=vector(0,0),
width=self.width,
height=self.m3_width)
for x in range(self.columns):
clk_pin = self.dff_insts[x,0].get_pin("clk")
# Make a vertical strip for each column
self.add_layout_pin(text="clk",
layer="metal2",
offset=clk_pin.ll().scale(1,0),
width=self.m2_width,
height=self.height)
# Drop a via to the M3 pin
self.add_via_center(layers=("metal2","via2","metal3"),
offset=clk_pin.center().scale(1,0))
def analytical_delay(self, slew, load=0.0):
return self.dff.analytical_delay(slew=slew, load=load)

View File

@ -31,7 +31,7 @@ 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.DRC_LVS()
@ -51,10 +51,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)

View File

@ -21,8 +21,6 @@ class hierarchical_predecode(design.design):
c = reload(__import__(OPTS.bitcell))
self.mod_bitcell = getattr(c, OPTS.bitcell)
self.bitcell_height = self.mod_bitcell.height
def add_pins(self):
for k in range(self.number_of_inputs):

View File

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

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

@ -0,0 +1,159 @@
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.
"""
def __init__(self, inv1_size=2, inv2_size=4, 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)
self.add_mod(self.inv)
self.inv1 = pinv(size=inv1_size)
self.add_mod(self.inv1)
self.inv2 = pinv(size=inv2_size)
self.add_mod(self.inv2)
self.width = 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_center_rect(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_center_rect(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_center_rect(text="A",
layer="metal2",
offset=a_pin.center())
self.add_via_center(layers=("metal1","via1","metal2"),
offset=a_pin.center())
def analytical_delay(self, slew, load=0.0):
""" Calculate the analytical delay of DFF-> INV -> INV """
inv1_delay = self.inv1.analytical_delay(slew=slew, load=self.inv2.input_load())
inv2_delay = self.inv2.analytical_delay(slew=inv1_delay.slew, load=load)
return inv1_delay + inv2_delay

View File

@ -22,8 +22,8 @@ class sram(design.design):
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.dff_array))
self.mod_dff_array = getattr(c, OPTS.dff_array)
c = reload(__import__(OPTS.bitcell))
self.mod_bitcell = getattr(c, OPTS.bitcell)
@ -146,10 +146,10 @@ 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_inputs=["CSb", "WEb", "OEb"]
self.control_logic_outputs=["s_en", "w_en", "tri_en", "tri_en_bar", "clk_bar", "clk_buf"]
self.add_pin_list(self.control_logic_inputs,"INPUT")
self.add_pin_list(self.control_logic_inputs + ["clk"],"INPUT")
self.add_pin("vdd","POWER")
self.add_pin("gnd","GROUND")
@ -210,7 +210,7 @@ class sram(design.design):
""" Route the shared signals for two and four bank configurations. """
# create the input control pins
for n in self.control_logic_inputs:
for n in self.control_logic_inputs + ["clk"]:
self.copy_layout_pin(self.control_logic_inst, n.lower(), n)
# connect the control logic to the control bus
@ -374,7 +374,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,
@ -797,6 +797,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
dff_size = self.addr_size + len(self.control_logic_inputs)
self.addr_ctrl_dff = self.mod_dff_array(rows=dff_size, columns=1)
self.add_mod(self.addr_ctrl_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,
@ -805,14 +810,13 @@ 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.supply_rail_width = self.bank.supply_rail_width
# Leave some extra space for the pitch
self.supply_rail_pitch = self.bank.supply_rail_pitch
@ -900,13 +904,32 @@ class sram(design.design):
return line_positions
def add_control_addr_dff(self, position, rotate=0):
""" Add and place address and control flops """
self.addr_ctrl_dff_inst = self.add_inst(name="address",
mod=self.addr_ctrl_dff,
offset=position,
rotate=rotate)
# inputs, outputs/output/bar
inputs = []
outputs = []
for i in range(self.addr_size):
inputs.append("ADDR[{}]".format(i))
outputs.append("A[{}]".format(i))
for i in self.control_logic_inputs:
inputs.append(i)
outputs.append(i+"_s")
self.connect_inst(inputs + outputs + ["clk", "vdd", "gnd"])
def add_control_logic(self, position, rotate):
""" Add and place control logic """
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"])
self.connect_inst(self.control_logic_inputs + ["clk"] + self.control_logic_outputs + ["vdd", "gnd"])
def add_lvs_correspondence_points(self):
@ -938,11 +961,14 @@ class sram(design.design):
# are not recomputed using instance placement. So, place the control logic such that it aligns
# with the top of the SRAM.
control_gap = 2*self.m3_width
pos = vector(-control_gap,
self.bank.height-self.control_logic.width)
self.add_control_logic(position=pos,
rotate=90)
control_pos = vector(-control_gap,
self.bank.height-self.control_logic.width)
self.add_control_logic(position=control_pos, rotate=90)
addr_pos = vector(self.control_logic_inst.lx(),
2*self.supply_rail_pitch)
self.add_control_addr_dff(addr_pos)
self.width = self.bank.width + self.control_logic.height + control_gap
self.height = self.bank.height
@ -955,7 +981,7 @@ class sram(design.design):
self.copy_layout_pin(self.bank_inst, "DATA[{}]".format(i))
for i in range(self.addr_size):
self.copy_layout_pin(self.bank_inst, "ADDR[{}]".format(i))
self.copy_layout_pin(self.bank_inst, "A[{}]".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)

View File

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

View File

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

View File

@ -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()