OpenRAM 1.1.6

This commit is contained in:
mrg 2020-07-13 16:25:55 -07:00
commit b4f5dc4c6e
11 changed files with 81 additions and 69 deletions

View File

@ -36,6 +36,9 @@ class hierarchy_design(hierarchy_spice.spice, hierarchy_layout.layout):
else:
self.lvs_file = self.sp_file
self.drc_errors = "skipped"
self.lvs_errors = "skipped"
self.name = name
hierarchy_spice.spice.__init__(self, name)
hierarchy_layout.layout.__init__(self, name)
@ -58,41 +61,37 @@ class hierarchy_design(hierarchy_spice.spice, hierarchy_layout.layout):
# No layout to check
if OPTS.netlist_only:
return ("skipped", "skipped")
return
# Unit tests will check themselves.
if not force_check and OPTS.is_unit_test:
return ("skipped", "skipped")
if not force_check and not OPTS.check_lvsdrc:
return ("skipped", "skipped")
elif not force_check and OPTS.is_unit_test:
return
elif not force_check and not OPTS.check_lvsdrc:
return
# Do not run if disabled in options.
if (OPTS.inline_lvsdrc or force_check or final_verification):
elif (OPTS.inline_lvsdrc or force_check or final_verification):
tempspice = "{0}/{1}.sp".format(OPTS.openram_temp, self.name)
tempgds = "{0}/{1}.gds".format(OPTS.openram_temp, self.name)
self.lvs_write(tempspice)
self.gds_write(tempgds)
# Final verification option does not allow nets to be connected by label.
num_drc_errors = verify.run_drc(self.name, tempgds, extract=True, final_verification=final_verification)
num_lvs_errors = verify.run_lvs(self.name, tempgds, tempspice, final_verification=final_verification)
self.drc_errors = verify.run_drc(self.name, tempgds, extract=True, final_verification=final_verification)
self.lvs_errors = verify.run_lvs(self.name, tempgds, tempspice, final_verification=final_verification)
# force_check is used to determine decoder height and other things, so we shouldn't fail
# if that flag is set
if OPTS.inline_lvsdrc and not force_check:
debug.check(num_drc_errors == 0,
debug.check(self.drc_errors == 0,
"DRC failed for {0} with {1} error(s)".format(self.name,
num_drc_errors))
debug.check(num_lvs_errors == 0,
self.drc_errors))
debug.check(self.lvs_errors == 0,
"LVS failed for {0} with {1} errors(s)".format(self.name,
num_lvs_errors))
self.lvs_errors))
if OPTS.purge_temp:
os.remove(tempspice)
os.remove(tempgds)
return (num_drc_errors, num_lvs_errors)
else:
return ("skipped", "skipped")
def DRC(self, final_verification=False):
"""Checks DRC for a module"""
import verify
@ -102,9 +101,8 @@ class hierarchy_design(hierarchy_spice.spice, hierarchy_layout.layout):
# No layout to check
if OPTS.netlist_only:
return "skipped"
if (not OPTS.is_unit_test and OPTS.check_lvsdrc and (OPTS.inline_lvsdrc or final_verification)):
return
elif (not OPTS.is_unit_test and OPTS.check_lvsdrc and (OPTS.inline_lvsdrc or final_verification)):
tempgds = "{0}/{1}.gds".format(OPTS.openram_temp, self.name)
self.gds_write(tempgds)
num_errors = verify.run_drc(self.name, tempgds, final_verification=final_verification)
@ -115,10 +113,6 @@ class hierarchy_design(hierarchy_spice.spice, hierarchy_layout.layout):
if OPTS.purge_temp:
os.remove(tempgds)
return num_errors
else:
return "skipped"
def LVS(self, final_verification=False):
"""Checks LVS for a module"""
import verify
@ -128,9 +122,8 @@ class hierarchy_design(hierarchy_spice.spice, hierarchy_layout.layout):
# No layout to check
if OPTS.netlist_only:
return "skipped"
if (not OPTS.is_unit_test and OPTS.check_lvsdrc and (OPTS.inline_lvsdrc or final_verification)):
return
elif (not OPTS.is_unit_test and OPTS.check_lvsdrc and (OPTS.inline_lvsdrc or final_verification)):
tempspice = "{0}/{1}.sp".format(OPTS.openram_temp, self.name)
tempgds = "{0}/{1}.gds".format(OPTS.openram_temp, self.name)
self.lvs_write(tempspice)
@ -142,10 +135,6 @@ class hierarchy_design(hierarchy_spice.spice, hierarchy_layout.layout):
if OPTS.purge_temp:
os.remove(tempspice)
os.remove(tempgds)
return num_errors
else:
return "skipped"
def init_graph_params(self):
"""Initializes parameters relevant to the graph creation"""

View File

@ -658,11 +658,7 @@ class lib:
# information of checks
# run it only the first time
try:
datasheet.write("{0},{1},".format(self.drc_errors, self.lvs_errors))
except AttributeError:
(self.drc_errors, self.lvs_errors) = self.sram.DRC_LVS(final_verification=True)
datasheet.write("{0},{1},".format(self.drc_errors, self.lvs_errors))
datasheet.write("{0},{1},".format(self.sram.drc_errors, self.sram.lvs_errors))
# write area
datasheet.write(str(self.sram.width * self.sram.height) + ',')

View File

@ -0,0 +1,21 @@
word_size = 4
num_words = 64
words_per_row = 2
num_rw_ports = 1
num_r_ports = 0
num_w_ports = 0
tech_name = "scn4m_subm"
nominal_corners_only = False
process_corners = ["TT"]
supply_voltages = [5.0]
temperatures = [25]
# route_supplies = True
check_lvsdrc = True
output_path = "temp"
output_name = "sram_1rw_{0}_{1}_{2}".format(word_size,
num_words,
tech_name)

View File

@ -54,7 +54,10 @@ from sram_config import sram_config
c = sram_config(word_size=OPTS.word_size,
num_words=OPTS.num_words,
write_size=OPTS.write_size,
num_spare_rows=OPTS.num_spare_rows)
num_banks=OPTS.num_banks,
words_per_row=OPTS.words_per_row,
num_spare_rows=OPTS.num_spare_rows,
num_spare_cols=OPTS.num_spare_cols)
debug.print_raw("Words per row: {}".format(c.words_per_row))
output_extensions = ["lvs", "sp", "v", "lib", "py", "html", "log"]

View File

@ -44,8 +44,9 @@ class options(optparse.Values):
# word_size = 0
# You can manually specify banks, but it is better to auto-detect it.
num_banks = 1
words_per_row = None
num_spare_rows = 0
# num_spare_cols = 0
num_spare_cols = 0
###################
# Optimization options

View File

@ -13,10 +13,6 @@ from vector import vector
from globals import OPTS
from sram_factory import factory
if(OPTS.tech_name == "sky130"):
from tech import nmos_bins, pmos_bins
class pinv_dec(pinv.pinv):
"""
This is another version of pinv but with layout for the decoder.

View File

@ -12,7 +12,6 @@ from vector import vector
from sram_factory import factory
import contact
import logical_effort
import os
from globals import OPTS
from pgate import pgate
@ -120,24 +119,23 @@ class ptx(design.design):
def create_netlist(self):
pin_list = ["D", "G", "S", "B"]
if self.tx_type == "nmos":
body_dir = 'GROUND'
body_dir = "GROUND"
else:
# Assumed that the check for either pmos or nmos is done elsewhere.
body_dir = 'POWER'
dir_list = ['INOUT', 'INPUT', 'INOUT', body_dir]
body_dir = "POWER"
dir_list = ["INOUT", "INPUT", "INOUT", body_dir]
self.add_pin_list(pin_list, dir_list)
# Just make a guess since these will actually
# 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" and OPTS.lvs_exe[0] == "calibre":
if OPTS.tech_name == "sky130" and OPTS.lvs_exe 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,
self.tx_width,
drc("minwidth_poly"))
self.mults,
self.tx_width,
drc("minwidth_poly"))
# Perimeters are in microns
# Area is in u since it is microns square
area_str = "pd={0:.2f} ps={0:.2f} as={1:.2f}u ad={1:.2f}u".format(perimeter_sd,
@ -152,7 +150,7 @@ class ptx(design.design):
self.spice_device = main_str + area_str
self.spice.append("\n* ptx " + self.spice_device)
if OPTS.tech_name == "sky130" and OPTS.lvs_exe[0] == "calibre":
if OPTS.tech_name == "sky130" and OPTS.lvs_exe 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,

View File

@ -39,7 +39,6 @@ class single_level_column_mux(pgate.pgate):
return "br"
def create_netlist(self):
self.add_modules()
self.add_pins()
self.add_ptx()
@ -54,15 +53,18 @@ class single_level_column_mux(pgate.pgate):
self.pin_pitch = getattr(self, "{}_pitch".format(self.pin_layer))
self.pin_width = getattr(self, "{}_width".format(self.pin_layer))
self.pin_height = 2 * self.pin_width
self.place_ptx()
self.width = self.bitcell.width
self.height = self.nmos_upper.uy() + self.pin_height
self.connect_poly()
self.add_bitline_pins()
self.connect_bitlines()
self.add_pn_wells()
def add_modules(self):
def add_ptx(self):
self.bitcell = factory.create(module_type="bitcell")
# Adds nmos_lower,nmos_upper to the module
@ -71,6 +73,16 @@ class single_level_column_mux(pgate.pgate):
width=self.ptx_width)
self.add_mod(self.nmos)
# Space it in the center
self.nmos_lower = self.add_inst(name="mux_tx1",
mod=self.nmos)
self.connect_inst(["bl", "sel", "bl_out", "gnd"])
# This aligns it directly above the other tx with gates abutting
self.nmos_upper = self.add_inst(name="mux_tx2",
mod=self.nmos)
self.connect_inst(["br", "sel", "br_out", "gnd"])
def add_pins(self):
self.add_pin_list(["bl", "br", "bl_out", "br_out", "sel", "gnd"])
@ -99,25 +111,19 @@ class single_level_column_mux(pgate.pgate):
layer=self.pin_layer,
offset=br_pos,
height=self.pin_height)
def add_ptx(self):
def place_ptx(self):
""" Create the two pass gate NMOS transistors to switch the bitlines"""
# Space it in the center
nmos_lower_position = self.nmos.active_offset.scale(0, 1) \
+ vector(0.5 * self.bitcell.width- 0.5 * self.nmos.active_width, 0)
self.nmos_lower = self.add_inst(name="mux_tx1",
mod=self.nmos,
offset=nmos_lower_position)
self.connect_inst(["bl", "sel", "bl_out", "gnd"])
self.nmos_lower.place(nmos_lower_position)
# This aligns it directly above the other tx with gates abutting
nmos_upper_position = nmos_lower_position \
+ vector(0, self.nmos.active_height + max(self.active_space, self.poly_space))
self.nmos_upper = self.add_inst(name="mux_tx2",
mod=self.nmos,
offset=nmos_upper_position)
self.connect_inst(["br", "sel", "br_out", "gnd"])
+ vector(0, self.nmos.active_height + max(self.active_space, self.poly_space))
self.nmos_upper.place(nmos_upper_position)
if OPTS.tech_name == "sky130":
self.add_implants()

View File

@ -129,7 +129,7 @@ class sram_base(design, verilog, lef):
start_time = datetime.datetime.now()
# We only enable final verification if we have routed the design
self.DRC_LVS(final_verification=OPTS.route_supplies)
self.DRC_LVS(final_verification=OPTS.route_supplies, force_check=True)
if not OPTS.is_unit_test:
print_time("Verification", datetime.datetime.now(), start_time)

View File

@ -14,7 +14,7 @@ from sram_factory import factory
class sram_config:
""" This is a structure that is used to hold the SRAM configuration options. """
def __init__(self, word_size, num_words, write_size = None, num_banks=1, words_per_row=None, num_spare_rows=0, num_spare_cols=None):
def __init__(self, word_size, num_words, write_size = None, num_banks=1, words_per_row=None, num_spare_rows=0, num_spare_cols=0):
self.word_size = word_size
self.num_words = num_words
self.write_size = write_size

View File

@ -30,13 +30,15 @@ if not OPTS.check_lvsdrc:
OPTS.drc_exe = None
OPTS.lvs_exe = None
OPTS.pex_exe = None
if OPTS.tech_name == "sky130":
OPTS.magic_exe = None
else:
debug.info(1, "Finding DRC/LVS/PEX tools.")
OPTS.drc_exe = get_tool("DRC", ["calibre", "assura", "magic"], drc_name)
OPTS.lvs_exe = get_tool("LVS", ["calibre", "assura", "netgen"], lvs_name)
OPTS.pex_exe = get_tool("PEX", ["calibre", "magic"], pex_name)
if OPTS.tech_name == "sky130":
OPTS.magic_exe = get_tool("GDS", ["magic"], None)
OPTS.magic_exe = get_tool("GDS", ["magic"])
if not OPTS.drc_exe:
from .none import run_drc, print_drc_stats
@ -71,7 +73,7 @@ else:
debug.warning("Did not find a supported PEX tool.")
if OPTS.tech_name == "sky130":
if "magic"==OPTS.magic_exe[0]:
if OPTS.magic_exe and "magic"==OPTS.magic_exe[0]:
from .magic import filter_gds
else:
debug.warning("Did not find Magic.")