Initial work on separate delay and func simulation

This commit is contained in:
mrg 2022-02-16 10:54:39 -08:00
parent 47690e0076
commit dd2effd28d
6 changed files with 116 additions and 75 deletions

View File

@ -318,4 +318,3 @@ class design(hierarchy_design):
design.setup_drc_constants()
design.setup_layer_constants()

View File

@ -1,4 +1,4 @@
#!/usr/bin/env python
#!/usr/bin/env python3
# See LICENSE for licensing information.
#
# Copyright (c) 2016-2021 Regents of the University of California and The Board
@ -15,6 +15,7 @@ corner, but should probably be extended.
import sys
from globals import *
from importlib import reload
(OPTS, args) = parse_args()
@ -41,36 +42,30 @@ slew = float(args[3])
import debug
init_openram(config_file=config_file, is_unit_test=False)
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_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)
OPTS.netlist_only = True
OPTS.check_lvsdrc = False
# Put the temp output in the output path since it is what we want to generate!
old_openram_temp = OPTS.openram_temp
OPTS.openram_temp = OPTS.output_path
import sram
class fake_sram(sram.sram):
""" This is an SRAM that doesn't actually create itself, just computes
the sizes. """
def __init__(self, word_size, num_words, num_banks, name, num_spare_rows):
self.name = name
self.word_size = word_size
self.num_words = num_words
self.num_banks = num_banks
self.num_spare_rows = num_spare_rows
c = reload(__import__(OPTS.bitcell))
self.mod_bitcell = getattr(c, OPTS.bitcell)
self.bitcell = self.mod_bitcell()
# to get the row, col, etc.
self.compute_sizes()
sram = fake_sram(OPTS.word_size, OPTS.num_words, OPTS.num_banks, OPTS.output_name)
sp_file = OPTS.output_path+OPTS.output_name + ".sp"
from sram import sram
s = sram(name=OPTS.output_name, sram_config=c)
s.create()
from characterizer import delay
import tech
# Set up the delay and set to the nominal corner
d = delay.delay(sram, sp_file, ("TT", tech.spice["nom_supply_voltage"], tech.spice["nom_temperature"]))
d = delay(s, s.get_sp_name(), ("TT", tech.spice["nom_supply_voltage"], tech.spice["nom_temperature"]))
# Set the period
d.period = period
# Set the load of outputs and slew of inputs
@ -91,4 +86,3 @@ print("Output files are:\n{0}stim.sp\n{0}sram.sp\n{0}reduced.sp".format(OPTS.out
OPTS.openram_temp = old_openram_temp
# Delete temp files, remove the dir, etc.
end_openram()

View File

@ -48,7 +48,7 @@ g.print_time("Start", start_time)
g.report_status()
from sram_config import sram_config
from sram import sram
# Configure the SRAM organization
c = sram_config(word_size=OPTS.word_size,
@ -73,9 +73,10 @@ for path in output_files:
debug.print_raw(path)
from sram import sram
s = sram(sram_config=c,
name=OPTS.output_name)
s = sram(name=OPTS.output_name, sram_config=c)
# Actually build the SRAM
s.create()
# Output the files for the resulting SRAM
s.save()
@ -83,5 +84,3 @@ s.save()
# Delete temp files etc.
g.end_openram()
g.print_time("End", datetime.datetime.now(), start_time)

View File

@ -21,30 +21,39 @@ class sram():
results.
We can later add visualizer and other high-level functions as needed.
"""
def __init__(self, sram_config, name):
def __init__(self, name, sram_config):
self.name = name
self.config = sram_config
sram_config.set_local_config(self)
self.sp_name = OPTS.output_path + self.name + ".sp"
self.lvs_name = OPTS.output_path + self.name + ".lvs.sp"
self.pex_name = OPTS.output_path + self.name + ".pex.sp"
self.gds_name = OPTS.output_path + self.name + ".gds"
self.lef_name = OPTS.output_path + self.name + ".lef"
self.v_name = OPTS.output_path + self.name + ".v"
# reset the static duplicate name checker for unit tests
# in case we create more than one SRAM
from design import design
design.name_map=[]
def create(self):
debug.info(2, "create sram of size {0} with {1} num of words {2} banks".format(self.word_size,
self.num_words,
self.num_banks))
start_time = datetime.datetime.now()
self.name = name
if self.num_banks == 1:
from sram_1bank import sram_1bank as sram
from sram_1bank import sram_1bank as sram_banked
elif self.num_banks == 2:
from sram_2bank import sram_2bank as sram
from sram_2bank import sram_2bank as sram_banked
else:
debug.error("Invalid number of banks.", -1)
self.s = sram(name, sram_config)
self.s = sram_banked(name=self.name,
sram_config=self.config)
self.s.create_netlist()
if not OPTS.netlist_only:
self.s.create_layout()
@ -52,6 +61,14 @@ class sram():
if not OPTS.is_unit_test:
print_time("SRAM creation", datetime.datetime.now(), start_time)
def get_sp_name(self):
if OPTS.use_pex:
# Use the extracted spice file
return self.pex_name
else:
# Use generated spice file for characterization
return self.sp_name
def sp_write(self, name, lvs=False, trim=False):
self.s.sp_write(name, lvs, trim)
@ -101,11 +118,10 @@ class sram():
# Save the spice file
start_time = datetime.datetime.now()
spname = OPTS.output_path + self.s.name + ".sp"
debug.print_raw("SP: Writing to {0}".format(spname))
self.sp_write(spname)
debug.print_raw("SP: Writing to {0}".format(self.sp_name))
self.sp_write(self.sp_name)
functional(self.s,
os.path.basename(spname),
os.path.basename(self.sp_name),
cycles=200,
output_path=OPTS.output_path)
print_time("Spice writing", datetime.datetime.now(), start_time)
@ -113,12 +129,11 @@ class sram():
if not OPTS.netlist_only:
# Write the layout
start_time = datetime.datetime.now()
gdsname = OPTS.output_path + self.s.name + ".gds"
debug.print_raw("GDS: Writing to {0}".format(gdsname))
self.gds_write(gdsname)
debug.print_raw("GDS: Writing to {0}".format(self.gds_name))
self.gds_write(self.gds_name)
if OPTS.check_lvsdrc:
verify.write_drc_script(cell_name=self.s.name,
gds_name=os.path.basename(gdsname),
gds_name=os.path.basename(self.gds_name),
extract=True,
final_verification=True,
output_path=OPTS.output_path)
@ -126,20 +141,18 @@ class sram():
# Create a LEF physical model
start_time = datetime.datetime.now()
lefname = OPTS.output_path + self.s.name + ".lef"
debug.print_raw("LEF: Writing to {0}".format(lefname))
self.lef_write(lefname)
debug.print_raw("LEF: Writing to {0}".format(self.lef_name))
self.lef_write(self.lef_name)
print_time("LEF", datetime.datetime.now(), start_time)
# Save the LVS file
start_time = datetime.datetime.now()
lvsname = OPTS.output_path + self.s.name + ".lvs.sp"
debug.print_raw("LVS: Writing to {0}".format(lvsname))
self.sp_write(lvsname, lvs=True)
debug.print_raw("LVS: Writing to {0}".format(self.lvs_name))
self.sp_write(self.lvs_name, lvs=True)
if not OPTS.netlist_only and OPTS.check_lvsdrc:
verify.write_lvs_script(cell_name=self.s.name,
gds_name=os.path.basename(gdsname),
sp_name=os.path.basename(lvsname),
gds_name=os.path.basename(self.gds_name),
sp_name=os.path.basename(self.lvs_name),
final_verification=True,
output_path=OPTS.output_path)
print_time("LVS writing", datetime.datetime.now(), start_time)
@ -148,14 +161,8 @@ class sram():
if OPTS.use_pex:
start_time = datetime.datetime.now()
# Output the extracted design if requested
pexname = OPTS.output_path + self.s.name + ".pex.sp"
spname = OPTS.output_path + self.s.name + ".sp"
verify.run_pex(self.s.name, gdsname, spname, output=pexname)
sp_file = pexname
verify.run_pex(self.s.name, self.gds_name, self.sp_name, output=self.pex_name)
print_time("Extraction", datetime.datetime.now(), start_time)
else:
# Use generated spice file for characterization
sp_file = spname
# Save a functional simulation file
@ -163,7 +170,7 @@ class sram():
start_time = datetime.datetime.now()
from characterizer import lib
debug.print_raw("LIB: Characterizing... ")
lib(out_dir=OPTS.output_path, sram=self.s, sp_file=sp_file)
lib(out_dir=OPTS.output_path, sram=self.s, sp_file=self.get_sp_name())
print_time("Characterization", datetime.datetime.now(), start_time)
# Write the config file
@ -183,9 +190,8 @@ class sram():
# Write a verilog model
start_time = datetime.datetime.now()
vname = OPTS.output_path + self.s.name + ".v"
debug.print_raw("Verilog: Writing to {0}".format(vname))
self.verilog_write(vname)
debug.print_raw("Verilog: Writing to {0}".format(self.v_name))
self.verilog_write(self.v_name)
print_time("Verilog", datetime.datetime.now(), start_time)
# Write out options if specified

View File

@ -7,7 +7,7 @@
#
import datetime
import debug
from math import log, ceil
from math import log
from importlib import reload
from vector import vector
from globals import OPTS, print_time
@ -20,8 +20,7 @@ from tech import spice
class sram_base(design, verilog, lef):
"""
Dynamically generated SRAM by connecting banks to control logic. The
number of banks should be 1 , 2 or 4
Dynamically generated SRAM by connecting banks to control logic.
"""
def __init__(self, name, sram_config):
design.__init__(self, name)
@ -30,17 +29,10 @@ class sram_base(design, verilog, lef):
self.sram_config = sram_config
sram_config.set_local_config(self)
sram_config.compute_sizes()
self.bank_insts = []
if self.write_size:
self.num_wmasks = int(ceil(self.word_size / self.write_size))
else:
self.num_wmasks = 0
if not self.num_spare_cols:
self.num_spare_cols = 0
try:
from tech import power_grid
self.supply_stack = power_grid

View File

@ -14,7 +14,8 @@ 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=0):
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
# Don't add a write mask if it is the same size as the data word
@ -37,6 +38,16 @@ class sram_config:
except ImportError:
self.array_col_multiple = 1
if self.write_size:
self.num_wmasks = int(ceil(self.word_size / self.write_size))
else:
self.num_wmasks = 0
if not self.num_spare_cols:
self.num_spare_cols = 0
if not self.num_spare_rows:
self.num_spare_rows = 0
# This will get over-written when we determine the organization
self.words_per_row = words_per_row
@ -167,3 +178,43 @@ class sram_config:
return int(words_per_row * tentative_num_rows / 16)
return words_per_row
def setup_multiport_constants(self):
"""
These are contants and lists that aid multiport design.
Ports are always in the order RW, W, R.
Port indices start from 0 and increment.
A first RW port will have clk0, csb0, web0, addr0, data0
A first W port (with no RW ports) will be: clk0, csb0, addr0, data0
"""
total_ports = OPTS.num_rw_ports + OPTS.num_w_ports + OPTS.num_r_ports
# These are the read/write port indices.
self.readwrite_ports = []
# These are the read/write and write-only port indices
self.write_ports = []
# These are the write-only port indices.
self.writeonly_ports = []
# These are the read/write and read-only port indices
self.read_ports = []
# These are the read-only port indices.
self.readonly_ports = []
# These are all the ports
self.all_ports = list(range(total_ports))
# The order is always fixed as RW, W, R
port_number = 0
for port in range(OPTS.num_rw_ports):
self.readwrite_ports.append(port_number)
self.write_ports.append(port_number)
self.read_ports.append(port_number)
port_number += 1
for port in range(OPTS.num_w_ports):
self.write_ports.append(port_number)
self.writeonly_ports.append(port_number)
port_number += 1
for port in range(OPTS.num_r_ports):
self.read_ports.append(port_number)
self.readonly_ports.append(port_number)
port_number += 1