mirror of https://github.com/VLSIDA/OpenRAM.git
OpenRAM 1.1.6
This commit is contained in:
commit
b4f5dc4c6e
|
|
@ -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"""
|
||||
|
|
|
|||
|
|
@ -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) + ',')
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
@ -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"]
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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()
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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.")
|
||||
|
|
|
|||
Loading…
Reference in New Issue