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_layer_constants()
|
||||
|
||||
|
|
|
|||
|
|
@ -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()
|
||||
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
Loading…
Reference in New Issue