This commit is contained in:
jcirimel 2020-06-25 06:32:29 -07:00
commit 812cf11e95
29 changed files with 265 additions and 114 deletions

View File

@ -205,7 +205,8 @@ class design(hierarchy_design):
print("poly_to_active", self.poly_to_active)
print("poly_extend_active", self.poly_extend_active)
print("poly_to_contact", self.poly_to_contact)
print("contact_to_gate", self.contact_to_gate)
print("active_contact_to_gate", self.active_contact_to_gate)
print("poly_contact_to_gate", self.poly_contact_to_gate)
print("well_enclose_active", self.well_enclose_active)
print("implant_enclose_active", self.implant_enclose_active)
print("implant_space", self.implant_space)

View File

@ -11,7 +11,7 @@ import verify
import debug
import os
from globals import OPTS
import tech
class hierarchy_design(hierarchy_spice.spice, hierarchy_layout.layout):
"""
@ -26,9 +26,12 @@ class hierarchy_design(hierarchy_spice.spice, hierarchy_layout.layout):
# If we have a separate lvs directory, then all the lvs files
# should be in there (all or nothing!)
lvs_dir = OPTS.openram_tech + "lvs_lib/"
# Calibre will do the scaling in s8
if os.path.exists(lvs_dir): # and OPTS.lvs_exe[0]!="calibre":
try:
lvs_subdir = tech.lvs_lib
except AttributeError:
lvs_subdir = "lvs_lib"
lvs_dir = OPTS.openram_tech + lvs_subdir + "/"
if os.path.exists(lvs_dir):
self.lvs_file = lvs_dir + name + ".sp"
else:
self.lvs_file = self.sp_file
@ -45,7 +48,7 @@ class hierarchy_design(hierarchy_spice.spice, hierarchy_layout.layout):
if i.name == inst.name:
break
else:
debug.error("Couldn't find instance {0}".format(inst_name), -1)
debug.error("Couldn't find instance {0}".format(inst.name), -1)
inst_map = inst.mod.pin_map
return inst_map
@ -181,7 +184,7 @@ class hierarchy_design(hierarchy_spice.spice, hierarchy_layout.layout):
"""Given a list of nets, will compare the internal alias of a mod to determine
if the nets have a connection to this mod's net (but not inst).
"""
if exclusion_set == None:
if not exclusion_set:
exclusion_set = set()
try:
self.name_dict

View File

@ -599,6 +599,10 @@ class layout():
"""
if from_layer == to_layer:
# In the case where we have no vias added, make sure that there is at least
# a metal enclosure. This helps with center-line path routing.
self.add_rect_center(layer=from_layer,
offset=offset)
return last_via
from_id = layer_indices[from_layer]

View File

@ -10,9 +10,9 @@ import re
import os
import math
import tech
from delay_data import *
from wire_spice_model import *
from power_data import *
from delay_data import delay_data
from wire_spice_model import wire_spice_model
from power_data import power_data
import logical_effort
@ -40,6 +40,8 @@ class spice():
# THE CONNECTIONS MUST MATCH THE ORDER OF THE PINS (restriction imposed by the
# Spice format)
self.conns = []
# If this is set, it will out output subckt or isntances of this (for row/col caps etc.)
self.no_instances = False
# Keep track of any comments to add the the spice
try:
self.commments
@ -213,7 +215,7 @@ class spice():
# We don't define self.lvs and will use self.spice if dynamically created
# or they are the same file
if self.lvs_file!=self.sp_file and os.path.isfile(self.lvs_file):
if self.lvs_file != self.sp_file and os.path.isfile(self.lvs_file):
debug.info(3, "opening {0}".format(self.lvs_file))
f = open(self.lvs_file)
self.lvs = f.readlines()
@ -263,7 +265,12 @@ class spice():
Recursive spice subcircuit write;
Writes the spice subcircuit from the library or the dynamically generated one
"""
if not self.spice:
if self.no_instances:
return
elif not self.spice:
# If spice isn't defined, we dynamically generate one.
# recursively write the modules
for i in self.mods:
if self.contains(i, usedMODS):
@ -300,6 +307,9 @@ class spice():
# these are wires and paths
if self.conns[i] == []:
continue
# Instance with no devices in it needs no subckt/instance
if self.insts[i].mod.no_instances:
continue
if lvs_netlist and hasattr(self.insts[i].mod, "lvs_device"):
sp.write(self.insts[i].mod.lvs_device.format(self.insts[i].name,
" ".join(self.conns[i])))
@ -316,7 +326,7 @@ class spice():
sp.write(".ENDS {0}\n".format(self.name))
else:
# write the subcircuit itself
# If spice is a hard module, output the spice file contents.
# Including the file path makes the unit test fail for other users.
# if os.path.isfile(self.sp_file):
# sp.write("\n* {0}\n".format(self.sp_file))
@ -356,7 +366,7 @@ class spice():
stage_effort = self.get_stage_effort(relative_cap)
# If it fails, then keep running with a valid object.
if stage_effort == None:
if not stage_effort:
return delay_data(0.0, 0.0)
abs_delay = stage_effort.get_absolute_delay()

View File

@ -10,7 +10,7 @@ import utils
from tech import GDS, layer
from tech import cell_properties as props
import bitcell_base
from globals import OPTS
class bitcell(bitcell_base.bitcell_base):
"""
@ -50,6 +50,8 @@ class bitcell(bitcell_base.bitcell_base):
self.pin_map = bitcell.pin_map
self.add_pin_types(self.type_list)
self.nets_match = self.do_nets_exist(self.storage_nets)
debug.check(OPTS.tech_name != "sky130", "sky130 does not yet support single port cells")
def get_all_wl_names(self):
""" Creates a list of all wordline pin names """

View File

@ -41,3 +41,4 @@ class col_cap_bitcell_1rw_1r(bitcell_base.bitcell_base):
self.height = col_cap_bitcell_1rw_1r.height
self.pin_map = col_cap_bitcell_1rw_1r.pin_map
self.add_pin_types(self.type_list)
self.no_instances = True

View File

@ -41,3 +41,4 @@ class row_cap_bitcell_1rw_1r(bitcell_base.bitcell_base):
self.height = row_cap_bitcell_1rw_1r.height
self.pin_map = row_cap_bitcell_1rw_1r.pin_map
self.add_pin_types(self.type_list)
self.no_instances = True

View File

@ -17,6 +17,7 @@ class col_cap_array(bitcell_base_array):
super().__init__(cols, rows, name, column_offset)
self.mirror = mirror
self.no_instances = True
self.create_netlist()
if not OPTS.netlist_only:
self.create_layout()
@ -47,8 +48,8 @@ class col_cap_array(bitcell_base_array):
for col in range(self.column_size):
for row in range(self.row_size):
name = "bit_r{0}_c{1}".format(row, col)
self.cell_inst[row,col]=self.add_inst(name=name,
mod=self.dummy_cell)
self.cell_inst[row, col]=self.add_inst(name=name,
mod=self.dummy_cell)
self.connect_inst(self.get_bitcell_pins(col, row))
def get_bitcell_pins(self, col, row):
@ -73,31 +74,20 @@ class col_cap_array(bitcell_base_array):
for col in range(self.column_size):
for cell_column in column_list:
bl_pin = self.cell_inst[0,col].get_pin(cell_column)
self.add_layout_pin(text=cell_column+"_{0}".format(col),
bl_pin = self.cell_inst[0, col].get_pin(cell_column)
self.add_layout_pin(text=cell_column + "_{0}".format(col),
layer=bl_pin.layer,
offset=bl_pin.ll().scale(1,0),
offset=bl_pin.ll().scale(1, 0),
width=bl_pin.width(),
height=self.height)
# Add vdd/gnd via stacks
for row in range(self.row_size):
for col in range(self.column_size):
inst = self.cell_inst[row,col]
inst = self.cell_inst[row, col]
for pin_name in ["vdd", "gnd"]:
for pin in inst.get_pins(pin_name):
self.add_power_pin(name=pin.name,
loc=pin.center(),
start_layer=pin.layer)
# def input_load(self):
# wl_wire = self.gen_wl_wire()
# return wl_wire.return_input_cap()
#
# def get_wordline_cin(self):
# """Get the relative input capacitance from the wordline connections in all the bitcell"""
# #A single wordline is connected to all the bitcells in a single row meaning the capacitance depends on the # of columns
# bitcell_wl_cin = self.cell.get_wl_cin()
# total_cin = bitcell_wl_cin * self.column_size
# return total_cin

View File

@ -178,10 +178,14 @@ class delay_chain(design.design):
load_list = self.load_inst_map[inst]
for pin_name in ["vdd", "gnd"]:
pin = load_list[0].get_pin(pin_name)
self.add_power_pin(pin_name, pin.rc() - vector(self.m1_pitch, 0))
self.add_power_pin(pin_name,
pin.rc() - vector(self.m1_pitch, 0),
start_layer=pin.layer)
pin = load_list[-1].get_pin(pin_name)
self.add_power_pin(pin_name, pin.rc() - vector(0.5 * self.m1_pitch, 0))
pin = load_list[-2].get_pin(pin_name)
self.add_power_pin(pin_name,
pin.rc() - vector(self.m1_pitch, 0),
start_layer=pin.layer)
def add_layout_pins(self):

View File

@ -152,7 +152,7 @@ class hierarchical_decoder(design.design):
self.predecoder_width = self.pre2_4.width
# How much space between each predecoder
self.predecoder_spacing = self.and2.height
self.predecoder_spacing = 2 * self.and2.height
self.predecoder_height = self.pre2_4.height * self.no_of_pre2x4 + self.pre3_8.height * self.no_of_pre3x8 \
+ (self.no_of_pre2x4 + self.no_of_pre3x8 - 1) * self.predecoder_spacing

View File

@ -8,6 +8,7 @@ from sram_factory import factory
from globals import OPTS
from tech import cell_properties
class row_cap_array(bitcell_base_array):
"""
Generate a dummy row/column for the replica array.
@ -15,7 +16,7 @@ class row_cap_array(bitcell_base_array):
def __init__(self, cols, rows, column_offset=0, mirror=0, name=""):
super().__init__(cols, rows, name, column_offset)
self.mirror = mirror
self.no_instances = True
self.create_netlist()
if not OPTS.netlist_only:
self.create_layout()
@ -46,8 +47,8 @@ class row_cap_array(bitcell_base_array):
for col in range(self.column_size):
for row in range(1, self.row_size - 1):
name = "bit_r{0}_c{1}".format(row, col)
self.cell_inst[row,col]=self.add_inst(name=name,
mod=self.dummy_cell)
self.cell_inst[row, col]=self.add_inst(name=name,
mod=self.dummy_cell)
self.connect_inst(self.get_bitcell_pins(col, row))
def get_bitcell_pins(self, col, row):
@ -65,8 +66,8 @@ class row_cap_array(bitcell_base_array):
def place_array(self, name_template, row_offset=0):
# We increase it by a well enclosure so the precharges don't overlap our wells
self.height = self.row_size*self.cell.height
self.width = self.column_size*self.cell.width
self.height = self.row_size * self.cell.height
self.width = self.column_size * self.cell.width
xoffset = 0.0
for col in range(self.column_size):
@ -74,7 +75,6 @@ class row_cap_array(bitcell_base_array):
tempx, dir_y = self._adjust_x_offset(xoffset, col, self.column_offset)
for row in range(1, self.row_size - 1):
name = name_template.format(row, col)
tempy, dir_x = self._adjust_y_offset(yoffset, row, row_offset)
if dir_x and dir_y:
@ -86,8 +86,8 @@ class row_cap_array(bitcell_base_array):
else:
dir_key = ""
self.cell_inst[row,col].place(offset=[tempx, tempy],
mirror=dir_key)
self.cell_inst[row, col].place(offset=[tempx, tempy],
mirror=dir_key)
yoffset += self.cell.height
xoffset += self.cell.width
@ -98,31 +98,20 @@ class row_cap_array(bitcell_base_array):
for row in range(1, self.row_size - 1):
for cell_row in row_list:
wl_pin = self.cell_inst[row,0].get_pin(cell_row)
self.add_layout_pin(text=cell_row+"_{0}".format(row),
wl_pin = self.cell_inst[row, 0].get_pin(cell_row)
self.add_layout_pin(text=cell_row + "_{0}".format(row),
layer=wl_pin.layer,
offset=wl_pin.ll().scale(0,1),
offset=wl_pin.ll().scale(0, 1),
width=self.width,
height=wl_pin.height())
# Add vdd/gnd via stacks
for row in range(1, self.row_size - 1):
for col in range(self.column_size):
inst = self.cell_inst[row,col]
inst = self.cell_inst[row, col]
for pin_name in ["vdd", "gnd"]:
for pin in inst.get_pins(pin_name):
self.add_power_pin(name=pin.name,
loc=pin.center(),
start_layer=pin.layer)
# def input_load(self):
# wl_wire = self.gen_wl_wire()
# return wl_wire.return_input_cap()
#
# def get_wordline_cin(self):
# """Get the relative input capacitance from the wordline connections in all the bitcell"""
# #A single wordline is connected to all the bitcells in a single row meaning the capacitance depends on the # of columns
# bitcell_wl_cin = self.cell.get_wl_cin()
# total_cin = bitcell_wl_cin * self.column_size
# return total_cin

View File

@ -10,7 +10,7 @@ import debug
from sram_factory import factory
from vector import vector
from globals import OPTS
from tech import layer
class write_mask_and_array(design.design):
"""
@ -93,7 +93,7 @@ class write_mask_and_array(design.design):
self.width = self.bitcell.width * self.columns
self.height = self.and2.height
for i in range(self.num_wmasks):
base = vector(i * self.wmask_en_len, 0)
self.and2_insts[i].place(base)
@ -121,16 +121,17 @@ class write_mask_and_array(design.design):
for supply in ["gnd", "vdd"]:
supply_pin=self.and2_insts[i].get_pin(supply)
self.add_power_pin(supply, supply_pin.center())
if "li" in layer:
self.add_power_pin(supply, supply_pin.center(), start_layer="li", directions = ("H", "H"))
else:
self.add_power_pin(supply, supply_pin.center())
for supply in ["gnd", "vdd"]:
supply_pin_left = self.and2_insts[0].get_pin(supply)
supply_pin_right = self.and2_insts[self.num_wmasks - 1].get_pin(supply)
self.add_path(supply_pin_left.layer, [supply_pin_left.lc(), supply_pin_right.rc()])
def get_cin(self):
"""Get the relative capacitance of all the input connections in the bank"""
# The enable is connected to an and2 for every row.
return self.and2.get_cin() * len(self.and2_insts)

View File

@ -43,6 +43,9 @@ class pgate(design.design):
self.route_layer_space = getattr(self, "{}_space".format(self.route_layer))
self.route_layer_pitch = getattr(self, "{}_pitch".format(self.route_layer))
# hack for enclosing input pin with npc
self.input_pin_vias = []
# This is the space from a S/D contact to the supply rail
contact_to_vdd_rail_space = 0.5 * self.route_layer_width + self.route_layer_space
# This is a poly-to-poly of a flipped cell
@ -132,6 +135,8 @@ class pgate(design.design):
offset=contact_offset,
directions=directions)
self.input_pin_vias.append(via)
self.add_layout_pin_rect_center(text=name,
layer=self.route_layer,
offset=contact_offset,
@ -146,11 +151,33 @@ class pgate(design.design):
height=contact.poly_contact.first_layer_width,
width=left_gate_offset.x - contact_offset.x)
def enclose_npc(self):
""" Enclose the poly contacts with npc layer """
ll = None
ur = None
for via in self.input_pin_vias:
# Find ll/ur
if not ll:
ll = via.ll()
else:
ll = ll.min(via.ll())
if not ur:
ur = via.ur()
else:
ur = ur.max(via.ur())
npc_enclose_poly = drc("npc_enclose_poly")
npc_enclose_offset = vector(npc_enclose_poly, npc_enclose_poly)
self.add_rect(layer="npc",
offset=ll - npc_enclose_offset,
width=(ur.x - ll.x) + 2 * npc_enclose_poly,
height=(ur.y - ll.y) + 2 * npc_enclose_poly)
def extend_wells(self):
""" Extend the n/p wells to cover whole cell """
# This should match the cells in the cell library
self.nwell_y_offset = 0.48 * self.height
self.nwell_yoffset = 0.48 * self.height
full_height = self.height + 0.5 * self.m1_width
# FIXME: float rounding problem
@ -158,8 +185,8 @@ class pgate(design.design):
# Add a rail width to extend the well to the top of the rail
nwell_max_offset = max(self.find_highest_layer_coords("nwell").y,
full_height)
nwell_position = vector(0, self.nwell_y_offset) - vector(self.well_extend_active, 0)
nwell_height = nwell_max_offset - self.nwell_y_offset
nwell_position = vector(0, self.nwell_yoffset) - vector(self.well_extend_active, 0)
nwell_height = nwell_max_offset - self.nwell_yoffset
self.add_rect(layer="nwell",
offset=nwell_position,
width=self.width + 2 * self.well_extend_active,
@ -175,7 +202,7 @@ class pgate(design.design):
pwell_min_offset = min(self.find_lowest_layer_coords("pwell").y,
-0.5 * self.m1_width)
pwell_position = vector(-self.well_extend_active, pwell_min_offset)
pwell_height = self.nwell_y_offset - pwell_position.y
pwell_height = self.nwell_yoffset - pwell_position.y
self.add_rect(layer="pwell",
offset=pwell_position,
width=self.width + 2 * self.well_extend_active,

View File

@ -184,7 +184,7 @@ class pnand2(pgate.pgate):
# doesn't use nmos uy because that is calculated using offset + poly height
active_top = self.nmos1_inst.by() + self.nmos1_inst.mod.active_height
active_to_poly_contact = active_top + self.poly_to_active + 0.5 * contact.poly_contact.first_layer_height
active_to_poly_contact2 = active_top + drc("contact_to_gate") + 0.5 * self.route_layer_width
active_to_poly_contact2 = active_top + self.poly_contact_to_gate + 0.5 * self.route_layer_width
self.inputA_yoffset = max(active_contact_to_poly_contact,
active_to_poly_contact,
active_to_poly_contact2)
@ -200,7 +200,7 @@ class pnand2(pgate.pgate):
# active_contact_to_poly_contact = self.output_yoffset - self.route_layer_space - 0.5 * contact.poly_contact.second_layer_height
# active_bottom = self.pmos1_inst.by()
# active_to_poly_contact = active_bottom - self.poly_to_active - 0.5 * contact.poly_contact.first_layer_height
# active_to_poly_contact2 = active_bottom - drc("contact_to_gate") - 0.5 * self.route_layer_width
# active_to_poly_contact2 = active_bottom - self.poly_contact_to_gate - 0.5 * self.route_layer_width
# self.inputB_yoffset = min(active_contact_to_poly_contact,
# active_to_poly_contact,
# active_to_poly_contact2)
@ -212,6 +212,10 @@ class pnand2(pgate.pgate):
"B",
position="center")
if OPTS.tech_name == "sky130":
self.enclose_npc()
def route_output(self):
""" Route the Z output """

View File

@ -222,7 +222,7 @@ class pnand3(pgate.pgate):
# doesn't use nmos uy because that is calculated using offset + poly height
active_top = self.nmos1_inst.by() + self.nmos1_inst.mod.active_height
active_to_poly_contact = active_top + self.poly_to_active + 0.5 * contact.poly_contact.first_layer_height
active_to_poly_contact2 = active_top + drc("contact_to_gate") + 0.5 * self.route_layer_width
active_to_poly_contact2 = active_top + self.poly_contact_to_gate + 0.5 * self.route_layer_width
self.inputA_yoffset = max(active_contact_to_poly_contact,
active_to_poly_contact,
active_to_poly_contact2)
@ -233,20 +233,22 @@ class pnand3(pgate.pgate):
"A",
position="left")
# Put B right on the well line
self.inputB_yoffset = self.inputA_yoffset + non_contact_pitch
self.inputB_yoffset = self.inputA_yoffset + self.m3_pitch
self.route_input_gate(self.pmos2_inst,
self.nmos2_inst,
self.inputB_yoffset,
"B",
position="center")
self.inputC_yoffset = self.inputB_yoffset + non_contact_pitch
self.inputC_yoffset = self.inputB_yoffset + self.m3_pitch
self.route_input_gate(self.pmos3_inst,
self.nmos3_inst,
self.inputC_yoffset,
"C",
position="right")
if OPTS.tech_name == "sky130":
self.enclose_npc()
def route_output(self):
""" Route the Z output """

View File

@ -211,6 +211,9 @@ class pnor2(pgate.pgate):
self.output_yoffset = self.inputA_yoffset + self.m1_nonpref_pitch
if OPTS.tech_name == "sky130":
self.enclose_npc()
def route_output(self):
""" Route the Z output """
# PMOS2 (right) drain

View File

@ -196,7 +196,7 @@ class precharge(design.design):
pin_offset = self.lower_pmos_inst.get_pin("G").lr()
# This is an extra space down for some techs with contact to active spacing
contact_space = max(self.poly_space,
self.contact_to_gate) + 0.5 * contact.poly_contact.first_layer_height
self.poly_contact_to_gate) + 0.5 * contact.poly_contact.first_layer_height
offset = pin_offset - vector(0, contact_space)
self.add_via_stack_center(from_layer="poly",
to_layer=self.en_layer,

View File

@ -131,8 +131,8 @@ class ptx(design.design):
# be decided in the layout later.
area_sd = 2.5 * self.poly_width * self.tx_width
perimeter_sd = 2 * self.poly_width + 2 * self.tx_width
if OPTS.tech_name == "sky130":
# sky130 technology is in microns, also needs mult parameter
if OPTS.tech_name == "sky130" and OPTS.lvs_exe[0] == "calibre":
# sky130 simulation cannot use the mult parameter in simulation
(self.tx_width, self.mults) = pgate.bin_width(self.tx_type, self.tx_width)
main_str = "M{{0}} {{1}} {0} m={1} w={2} l={3} ".format(spice[self.tx_type],
self.mults,
@ -152,19 +152,17 @@ class ptx(design.design):
self.spice_device = main_str + area_str
self.spice.append("\n* ptx " + self.spice_device)
# LVS lib is always in SI units
if os.path.exists(OPTS.openram_tech + "lvs_lib"):
if OPTS.tech_name == "sky130":
# sky130 requires mult parameter too
self.lvs_device = "M{{0}} {{1}} {0} m={1} w={2} l={3} mult={1}".format(spice[self.tx_type],
self.mults,
self.tx_width,
drc("minwidth_poly"))
else:
self.lvs_device = "M{{0}} {{1}} {0} m={1} w={2}u l={3}u ".format(spice[self.tx_type],
self.mults,
self.tx_width,
drc("minwidth_poly"))
if OPTS.tech_name == "sky130" and OPTS.lvs_exe[0] == "calibre":
# sky130 requires mult parameter too
self.lvs_device = "M{{0}} {{1}} {0} m={1} w={2} l={3} mult={1}".format(spice[self.tx_type],
self.mults,
self.tx_width,
drc("minwidth_poly"))
else:
self.lvs_device = "M{{0}} {{1}} {0} m={1} w={2}u l={3}u ".format(spice[self.tx_type],
self.mults,
self.tx_width,
drc("minwidth_poly"))
def setup_layout_constants(self):
"""
@ -198,7 +196,7 @@ class ptx(design.design):
# This is the spacing between the poly gates
self.min_poly_pitch = self.poly_space + self.poly_width
self.contacted_poly_pitch = self.poly_space + contact.poly_contact.width
self.contact_pitch = 2 * self.contact_to_gate + self.poly_width + self.contact_width
self.contact_pitch = 2 * self.active_contact_to_gate + self.poly_width + self.contact_width
self.poly_pitch = max(self.min_poly_pitch,
self.contacted_poly_pitch,
self.contact_pitch)
@ -208,7 +206,7 @@ class ptx(design.design):
# Active width is determined by enclosure on both ends and contacted pitch,
# at least one poly and n-1 poly pitches
self.active_width = 2 * self.end_to_contact + self.active_contact.width \
+ 2 * self.contact_to_gate + self.poly_width + (self.mults - 1) * self.poly_pitch
+ 2 * self.active_contact_to_gate + self.poly_width + (self.mults - 1) * self.poly_pitch
# Active height is just the transistor width
self.active_height = self.tx_width
@ -323,7 +321,7 @@ class ptx(design.design):
"""
# poly is one contacted spacing from the end and down an extension
poly_offset = self.contact_offset \
+ vector(0.5 * self.active_contact.width + 0.5 * self.poly_width + self.contact_to_gate, 0)
+ vector(0.5 * self.active_contact.width + 0.5 * self.poly_width + self.active_contact_to_gate, 0)
# poly_positions are the bottom center of the poly gates
self.poly_positions = []

View File

@ -23,10 +23,13 @@ class and2_dec_test(openram_test):
global verify
import verify
import and2_dec
debug.info(2, "Testing and2 gate 4x")
a = and2_dec.and2_dec(name="and2x4", size=4)
OPTS.num_rw_ports = 1
OPTS.num_r_ports = 1
OPTS.num_w_ports = 0
globals.setup_bitcell()
debug.info(2, "Testing and2_dec gate")
a = factory.create(module_type="and2_dec")
self.local_check(a)
globals.end_openram()

View File

@ -23,10 +23,13 @@ class and3_dec_test(openram_test):
global verify
import verify
import and3_dec
debug.info(2, "Testing and3 gate 4x")
a = and3_dec.and3_dec(name="and3x4", size=4)
OPTS.num_rw_ports = 1
OPTS.num_r_ports = 1
OPTS.num_w_ports = 0
globals.setup_bitcell()
debug.info(2, "Testing and3_dec gate")
a = factory.create(module_type="and3_dec")
self.local_check(a)
globals.end_openram()

View File

@ -15,7 +15,9 @@ from globals import OPTS
from sram_factory import factory
import debug
class and3_dec_test(openram_test):
@unittest.skip("SKIPPING 04_and4_dec_test")
class and4_dec_test(openram_test):
def runTest(self):
config_file = "{}/tests/configs/config".format(os.getenv("OPENRAM_HOME"))
@ -23,10 +25,13 @@ class and3_dec_test(openram_test):
global verify
import verify
import and3_dec
debug.info(2, "Testing and3 gate 4x")
a = and3_dec.and3_dec(name="and3x4", size=4)
OPTS.num_rw_ports = 1
OPTS.num_r_ports = 1
OPTS.num_w_ports = 0
globals.setup_bitcell()
debug.info(2, "Testing and4_dec gate")
a = factory.create(module_type="and4_dec")
self.local_check(a)
globals.end_openram()

View File

@ -0,0 +1,44 @@
#!/usr/bin/env python3
# See LICENSE for licensing information.
#
# Copyright (c) 2016-2019 Regents of the University of California and The Board
# of Regents for the Oklahoma Agricultural and Mechanical College
# (acting for and on behalf of Oklahoma State University)
# All rights reserved.
#
import unittest
from testutils import *
import sys,os
sys.path.append(os.getenv("OPENRAM_HOME"))
import globals
from globals import OPTS
from sram_factory import factory
import debug
class write_driver_test(openram_test):
def runTest(self):
config_file = "{}/tests/configs/config".format(os.getenv("OPENRAM_HOME"))
globals.init_openram(config_file)
OPTS.num_rw_ports = 1
OPTS.num_r_ports = 1
OPTS.num_w_ports = 0
globals.setup_bitcell()
debug.info(2, "Testing write_driver_array for columns=8, word_size=8")
a = factory.create(module_type="write_driver_array", columns=8, word_size=8)
self.local_check(a)
debug.info(2, "Testing write_driver_array for columns=16, word_size=8")
a = factory.create(module_type="write_driver_array", columns=16, word_size=8)
self.local_check(a)
globals.end_openram()
# run the test from the command line
if __name__ == "__main__":
(OPTS, args) = globals.parse_args()
del sys.argv[1:]
header(__file__, OPTS.tech_name)
unittest.main(testRunner=debugTestRunner())

View File

@ -0,0 +1,51 @@
#!/usr/bin/env python3
# See LICENSE for licensing information.
#
# Copyright (c) 2016-2019 Regents of the University of California and The Board
# of Regents for the Oklahoma Agricultural and Mechanical College
# (acting for and on behalf of Oklahoma State University)
# All rights reserved.
#
import unittest
from testutils import *
import sys, os
sys.path.append(os.getenv("OPENRAM_HOME"))
import globals
from globals import OPTS
from sram_factory import factory
import debug
class write_mask_and_array_test(openram_test):
def runTest(self):
config_file = "{}/tests/configs/config".format(os.getenv("OPENRAM_HOME"))
globals.init_openram(config_file)
OPTS.num_rw_ports = 1
OPTS.num_r_ports = 1
OPTS.num_w_ports = 0
globals.setup_bitcell()
debug.info(2, "Testing write_mask_and_array for columns=8, word_size=8, write_size=4")
a = factory.create(module_type="write_mask_and_array", columns=8, word_size=8, write_size=4)
self.local_check(a)
debug.info(2, "Testing write_mask_and_array for columns=16, word_size=16, write_size=4")
a = factory.create(module_type="write_mask_and_array", columns=16, word_size=16, write_size=4)
self.local_check(a)
debug.info(2, "Testing write_mask_and_array for columns=16, word_size=8, write_size=2")
a = factory.create(module_type="write_mask_and_array", columns=16, word_size=8, write_size=2)
self.local_check(a)
globals.end_openram()
# run the test from the command line
if __name__ == "__main__":
(OPTS, args) = globals.parse_args()
del sys.argv[1:]
header(__file__, OPTS.tech_name)
unittest.main(testRunner=debugTestRunner())

View File

@ -30,8 +30,8 @@ class port_address_1rw_1r_test(openram_test):
a = factory.create("port_address", cols=16, rows=16)
self.local_check(a)
debug.info(1, "Port address 512 rows")
a = factory.create("port_address", cols=256, rows=512)
debug.info(1, "Port address 256 rows")
a = factory.create("port_address", cols=256, rows=256)
self.local_check(a)
globals.end_openram()

View File

@ -22,6 +22,11 @@ class port_data_wmask_1rw_1r_test(openram_test):
globals.init_openram(config_file)
from sram_config import sram_config
OPTS.num_rw_ports = 1
OPTS.num_r_ports = 1
OPTS.num_w_ports = 0
globals.setup_bitcell()
c = sram_config(word_size=16,
write_size=4,
num_words=16)

View File

@ -189,7 +189,7 @@ def run_drc(cell_name, gds_name, extract=False, final_verification=False):
num_drc_runs += 1
# Filter the layouts through magic as a GDS filter for nsdm/psdm/nwell merging
if OPTS.tech_name == "sky130":
if OPTS.tech_name == "sky130" and False:
shutil.copy(gds_name, OPTS.openram_temp + "temp.gds")
from magic import filter_gds
filter_gds(cell_name, OPTS.openram_temp + "temp.gds", OPTS.openram_temp + cell_name + ".gds")

View File

@ -234,9 +234,9 @@ drc.add_enclosure("active",
enclosure = 0.005)
# CONTACT.6 Minimum spacing of contact and gate
drc["contact_to_gate"] = 0.0375 #changed from 0.035
drc["active_contact_to_gate"] = 0.0375 #changed from 0.035
# CONTACT.7 Minimum spacing of contact and poly
drc["contact_to_poly"] = 0.090
drc["poly_contact_to_gate"] = 0.090
# CONTACT.1 Minimum width of contact
# CONTACT.2 Minimum spacing of contact

View File

@ -217,9 +217,9 @@ drc.add_enclosure("active",
layer = "contact",
enclosure = _lambda_)
# Reserved for other technologies
drc["contact_to_gate"] = 2*_lambda_
drc["active_contact_to_gate"] = 2*_lambda_
# 5.4 Minimum spacing to gate of transistor
drc["contact_to_poly"] = 2*_lambda_
drc["poly_contact_to_gate"] = 2*_lambda_
# 6.1 Exact contact size
# 5.3 Minimum contact spacing