mirror of https://github.com/VLSIDA/OpenRAM.git
Initial work on separate delay and func simulation
This commit is contained in:
parent
47690e0076
commit
dd2effd28d
|
|
@ -318,4 +318,3 @@ class design(hierarchy_design):
|
||||||
|
|
||||||
design.setup_drc_constants()
|
design.setup_drc_constants()
|
||||||
design.setup_layer_constants()
|
design.setup_layer_constants()
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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()
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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)
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue