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_drc_constants()
design.setup_layer_constants() design.setup_layer_constants()

View File

@ -1,4 +1,4 @@
#!/usr/bin/env python #!/usr/bin/env python3
# See LICENSE for licensing information. # See LICENSE for licensing information.
# #
# Copyright (c) 2016-2021 Regents of the University of California and The Board # 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 import sys
from globals import * from globals import *
from importlib import reload
(OPTS, args) = parse_args() (OPTS, args) = parse_args()
@ -41,36 +42,30 @@ slew = float(args[3])
import debug import debug
init_openram(config_file=config_file, is_unit_test=False) 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 OPTS.check_lvsdrc = False
# Put the temp output in the output path since it is what we want to generate! # Put the temp output in the output path since it is what we want to generate!
old_openram_temp = OPTS.openram_temp old_openram_temp = OPTS.openram_temp
OPTS.openram_temp = OPTS.output_path OPTS.openram_temp = OPTS.output_path
from sram import sram
s = sram(name=OPTS.output_name, sram_config=c)
import sram s.create()
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 characterizer import delay from characterizer import delay
import tech import tech
# Set up the delay and set to the nominal corner # 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 # Set the period
d.period = period d.period = period
# Set the load of outputs and slew of inputs # 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 OPTS.openram_temp = old_openram_temp
# Delete temp files, remove the dir, etc. # Delete temp files, remove the dir, etc.
end_openram() end_openram()

View File

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

View File

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

View File

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

View File

@ -14,7 +14,8 @@ from sram_factory import factory
class sram_config: class sram_config:
""" This is a structure that is used to hold the SRAM configuration options. """ """ 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.word_size = word_size
self.num_words = num_words self.num_words = num_words
# Don't add a write mask if it is the same size as the data word # 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: except ImportError:
self.array_col_multiple = 1 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 # This will get over-written when we determine the organization
self.words_per_row = words_per_row self.words_per_row = words_per_row
@ -167,3 +178,43 @@ class sram_config:
return int(words_per_row * tentative_num_rows / 16) return int(words_per_row * tentative_num_rows / 16)
return words_per_row 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