mirror of https://github.com/VLSIDA/OpenRAM.git
Change default delay modeling to analytical. Add command-line option characterization by simulation (-c).
This commit is contained in:
parent
03c274c319
commit
95f1a24f72
323
README
323
README
|
|
@ -1,323 +0,0 @@
|
|||
###############################################################################
|
||||
BASIC SETUP
|
||||
|
||||
- Please look at the OpenRAM ICCAD paper and presentation in the repository:
|
||||
https://github.com/mguthaus/OpenRAM/blob/master/OpenRAM_ICCAD_2016_paper.pdf
|
||||
https://github.com/mguthaus/OpenRAM/blob/master/OpenRAM_ICCAD_2016_presentation.pdf
|
||||
|
||||
-The OpenRAM compiler has very few dependencies:
|
||||
1) ngspice-26 or later or HSpice I-2013.12-1 or later
|
||||
2) Python 2.7 and higher (currently excludes Python 3 and up)
|
||||
3) a setup script for each technology
|
||||
4) a technology directory for each technology with the base cells
|
||||
|
||||
- You must set two environment variables: OPENRAM_HOME should point to
|
||||
the compiler source directory. OPENERAM_TECH should point to a root
|
||||
technology directory that contains subdirs of all other technologies.
|
||||
For example, in bash, add to your .bashrc:
|
||||
|
||||
export OPENRAM_HOME="$HOME/OpenRAM/compiler"
|
||||
export OPENRAM_TECH="$HOME/OpenRAM/technology"
|
||||
|
||||
For example, in csh/tcsh, add to your .cshrc/.tcshrc:
|
||||
|
||||
setenv OPENRAM_HOME "$HOME/OpenRAM/compiler"
|
||||
setenv OPENRAM_TECH "$HOME/OpenRAM/technology"
|
||||
|
||||
- If you are using FreePDK, you should also have that set up and have the
|
||||
environment variable point to the PDK.
|
||||
For example, in bash, add to your .bashrc:
|
||||
|
||||
export FREEPDK45="/bsoe/software/design-kits/FreePDK45"
|
||||
|
||||
For example, in csh/tcsh, add to your .tcshrc:
|
||||
|
||||
setenv FREEPDK45 "/bsoe/software/design-kits/FreePDK45"
|
||||
|
||||
We do not distribute the PDK, but you may get it from:
|
||||
|
||||
https://www.eda.ncsu.edu/wiki/FreePDK45:Contents
|
||||
|
||||
|
||||
###############################################################################
|
||||
DIRECTORY STRUCTURE
|
||||
|
||||
compiler - openram compiler itself (pointed to by OPENRAM_HOME)
|
||||
compiler/characterizer - timing characterization code
|
||||
compiler/gdsMill - GDSII reader/writer
|
||||
compiler/router - detailed router
|
||||
compiler/tests - unit tests
|
||||
technology - openram technology directory (pointed to by OPENRAM_TECH)
|
||||
technology/freepdk45 - example configuration library for freepdk45 technology node
|
||||
technology/scn3me_subm - example configuration library SCMOS technology node
|
||||
technology/setup_scripts - setup scripts to customize your PDKs and OpenRAM technologies
|
||||
|
||||
|
||||
###############################################################################
|
||||
UNIT TESTS
|
||||
|
||||
Regression testing performs a number of tests for all modules in OpenRAM.
|
||||
|
||||
Use the command:
|
||||
|
||||
python regress.py
|
||||
|
||||
To run a specific test:
|
||||
|
||||
python {unit test}.py
|
||||
|
||||
The unit tests take the same arguments as openram.py itself.
|
||||
|
||||
To increase the verbosity of the test, add one (or more) -v options:
|
||||
|
||||
python tests/00_code_format_check_test.py -v -t freepdk45
|
||||
|
||||
To specify a particular technology use "-t <techname>" such as
|
||||
"-t scn3me_subm". The default for a unit test is freepdk45 whereas
|
||||
the default for openram.py is specified in the configuration file.
|
||||
|
||||
A regression daemon script that can be used with cron is included:
|
||||
|
||||
regress_daemon.py
|
||||
regress_daemon.sh
|
||||
|
||||
This updates a git repository, checks out code, and sends an email
|
||||
report with status information.
|
||||
|
||||
###############################################################################
|
||||
CREATING CUSTOM TECHNOLOGIES
|
||||
|
||||
-All setup scripts should be in the setup_scripts directory under the
|
||||
$OPENRAM_TECH directory. Please look at the following file for an
|
||||
example of what is needed for OpenRAM:
|
||||
|
||||
$OPENRAM_TECH/setup_scripts/setup_openram_freepdk45.py
|
||||
|
||||
Each setup script should be named as: setup_openram_{tech name}.py.
|
||||
|
||||
-Each specific technology (e.g., freepdk45) should be a subdirectory
|
||||
(e.g., $OPENRAM_TECH/freepdk45) and include certain folders and files:
|
||||
|
||||
1) gds_lib folder with all the .gds (premade) library cells. At a
|
||||
minimum this includes:
|
||||
ms_flop.gds
|
||||
sense_amp.gds
|
||||
write_driver.gds
|
||||
cell_6t.gds
|
||||
replica_cell_6t.gds
|
||||
tri_gate.gds
|
||||
|
||||
2) sp_lib folder with all the .sp (premade) library netlists for the above cells.
|
||||
|
||||
3) layers.map
|
||||
|
||||
4) A valid tech Python module (tech directory with __init__.py and tech.py) with:
|
||||
References in tech.py to spice models
|
||||
DRC/LVS rules needed for dynamic cells and routing
|
||||
Layer information
|
||||
etc.
|
||||
|
||||
###############################################################################
|
||||
DEBUGGING
|
||||
|
||||
When OpenRAM runs, it puts files in a temporary directory that is
|
||||
shown in the banner at the top. Like:
|
||||
|
||||
/tmp/openram_mrg_18128_temp/
|
||||
|
||||
This is where simulations and DRC/LVS get run so there is no network
|
||||
traffic. The directory name is unique for each person and run of
|
||||
OpenRAM to not clobber any files and allow simultaneous runs. If it
|
||||
passes, the files are deleted. If it fails, you will see these files:
|
||||
* _calibreDRC.rul_ is the DRC rule file.
|
||||
* dc_runset is the command file for caliber.
|
||||
* temp.gds is the layout
|
||||
* test1.drc.err is the std err output of the command
|
||||
* test1.drc.out is the standard output of the command
|
||||
* test1.drc.db is the DRC results file
|
||||
|
||||
If DRC/LVS fails, the first thing is to check if it ran in the .out and
|
||||
.err file. This shows the standard output and error output from
|
||||
running DRC/LVS. If there is a setup problem it will be shown here.
|
||||
|
||||
If DRC/LVS runs, but doesn't pass, you then should look at the .db
|
||||
file. If the DRC fails, it will typically show you the command that was used
|
||||
to run caliber. It is something like this:
|
||||
|
||||
calibre -gui -drc /tmp/openram_mrg_28781_temp/drc_runset -batch 2>
|
||||
/tmp/openram_mrg_28781_temp/test1.drc.err 1>
|
||||
/tmp/openram_mrg_28781_temp/test1.drc.out
|
||||
|
||||
To debug, you will need a layout viewer. I prefer to use glade on my
|
||||
Mac, but you can also use Calibre, Magic, etc.
|
||||
|
||||
1) Calibre
|
||||
|
||||
Start the Calibre DESIGNrev viewer in the temp directory and load your GDS file:
|
||||
|
||||
calibredrv temp.gds
|
||||
|
||||
Select Verification->Start RVE and select the results database file in
|
||||
the new form (e.g., test1.drc.db). This will start the RVE (results
|
||||
viewer). Scroll through the check pane and find the DRC check with an
|
||||
error. Select it and it will open some numbers to the right. Double
|
||||
click on any of the errors in the result browser. These will be
|
||||
labelled as numbers "1 2 3 4" for example will be 4 DRC errors.
|
||||
|
||||
In the viewer ">" opens the layout down a level.
|
||||
|
||||
2) Glade
|
||||
|
||||
You can view errors in Glade as well. I like this because it is on my laptop.
|
||||
You can get it from:
|
||||
|
||||
http://www.peardrop.co.uk/glade/
|
||||
|
||||
To remote display over X windows, you need to disable OpenGL acceleration or use vnc
|
||||
or something. You can disable by adding this to your .bashrc in bash:
|
||||
|
||||
export GLADE_USE_OPENGL=no
|
||||
|
||||
or in .cshrc/.tcshrc in csh/tcsh:
|
||||
|
||||
setenv GLADE_USE_OPENGAL no
|
||||
|
||||
To use this with the FreePDK45 or SCMOS layer views you should use the
|
||||
tech files. Then create a .glade.py file in your user directory with
|
||||
these commands to load the technology layers:
|
||||
|
||||
ui().importCds("default",
|
||||
"/Users/mrg/techfiles/freepdk45/display.drf",
|
||||
"/Users/mrg/techfiles/freepdk45/FreePDK45.tf", 1000, 1,
|
||||
"/Users/mrg/techfiles/freepdk45/layers.map")
|
||||
|
||||
Obviously, edit the paths to point to your directory. To switch
|
||||
between processes, you have to change the importCds command (or you
|
||||
can manually run the command each time you start glade).
|
||||
|
||||
To load the errors, you simply do:
|
||||
|
||||
Verify->Import Caliber Errors
|
||||
|
||||
select the .db file from calibre.
|
||||
|
||||
It is possible to use other viewers as well, such as:
|
||||
|
||||
LayoutEditor http://www.layouteditor.net/
|
||||
Magic http://opencircuitdesign.com/magic/
|
||||
|
||||
|
||||
###############################################################################
|
||||
CONTRIBUTING TO OPENRAM
|
||||
|
||||
How to get the code and add contributions to OpenRAM.
|
||||
|
||||
0) One time, create a GitHub account.
|
||||
|
||||
1) Create a fork of the OpenRAM project on the github web page:
|
||||
|
||||
https://github.com/mguthaus/OpenRAM
|
||||
|
||||
It is on the upper right and says "Fork": This will make your own
|
||||
OpenRAM repository on GitHub in your account.
|
||||
|
||||
|
||||
2) Clone your repository (or use an existing cloned copy if you've
|
||||
already done this once):
|
||||
git clone https://github.com/<youruser>/OpenRAM.git
|
||||
cd OpenRAM
|
||||
|
||||
3) Set up a new upstream that points to MY OpenRAM repository that you
|
||||
forked (only first time):
|
||||
git remote add upstream https://github.com/mguthaus/OpenRAM.git
|
||||
|
||||
You now have two remotes for this project:
|
||||
origin which points to your GitHub fork of the project. You can read
|
||||
and write to this remote.
|
||||
upstream which points to the main project's GitHub repository. You can
|
||||
only read from this remote.
|
||||
|
||||
You can remove remotes with
|
||||
git remote remove upstream
|
||||
if you previously added the one with the git@github that required
|
||||
authentication.
|
||||
|
||||
4) Make your own branch. The number one rule is to put each piece of
|
||||
work on its own branch:
|
||||
git checkout -b useful-branch-name
|
||||
|
||||
Note that this is shorthand for:
|
||||
git branch useful-branch-name
|
||||
git checkout useful-branch-name
|
||||
|
||||
"master" is the name of the branch that is the release version of the
|
||||
code (in your fork of the repository). You can check out the released
|
||||
code with "git checkout master" or go back to your ranch with
|
||||
"gitcheckout useful-branch-name".
|
||||
|
||||
5) Edit your code and make commits like normal:
|
||||
git add <new files>
|
||||
<edit files>
|
||||
git commit -m "Useful comment" <files changed>
|
||||
|
||||
OR (sparingly, to commit all changes):
|
||||
git status
|
||||
<check that all the changed files are correct and should be commited>
|
||||
git commit -a -m "Useful comment"
|
||||
|
||||
Run the unit tests entirely. Fix all bugs.
|
||||
|
||||
6) After you are done (or while you are editing and you see changes in
|
||||
MY master branch) make sure you have the most recent from MY master
|
||||
and merge any changes. Pull the updated copy from MY master branch in
|
||||
MY repository:
|
||||
git pull upstream master
|
||||
|
||||
This is important because we may have had other updates that conflict
|
||||
with your changes and you must resolve them with current state of
|
||||
master (the released, working code). You may have to merge changes if
|
||||
they overlap your changes, so do this often to avoid the problem. You
|
||||
now need to push this to the master of YOUR forked repository as well:
|
||||
git push origin master
|
||||
if you are on your master branch. Otherwise, just git push.
|
||||
|
||||
|
||||
7) Push your branch to YOUR repository:
|
||||
git push -u origin useful-branch-name
|
||||
|
||||
Remember origin is your copy on github and useful-branch-name is the
|
||||
branch that you made to contain all your changes.
|
||||
|
||||
The -u flag links this branch with the remote one, so that in the
|
||||
future, you can simply type git push origin.
|
||||
|
||||
8) When you are done, go to GitHub and you will see a button to notify
|
||||
me. Press the button and it will notify me of your pushed branch.
|
||||
This will have you fill in a form for the contribution that gets sent
|
||||
to me.
|
||||
|
||||
9) I will review the request and may have you fix stuff if the tests
|
||||
don't pass, you didn't merge all my changes in master from other
|
||||
contributions, or your style of code is bad.
|
||||
|
||||
10) Go back to step 3 for your next contribution. Remember, you can
|
||||
push/pull work to your repository all the time and can pull from my
|
||||
master as well. Make sure to add large features so that You don't have
|
||||
to add lots of pull requests.
|
||||
|
||||
###############################################################################
|
||||
Example to output/input .gds layout files from/to Cadence
|
||||
|
||||
1) To create your component layouts, you should stream them to
|
||||
individual gds files using our provided layermap and flatten
|
||||
cells. For example,
|
||||
|
||||
strmout -layerMap layers.map -library sram -topCell $i -view layout -flattenVias -flattenPcells -strmFile ../gds_lib/$i.gds
|
||||
|
||||
2) To stream a layout back into Cadence, do this:
|
||||
|
||||
strmin -layerMap layers.map -attachTechFileOfLib NCSU_TechLib_FreePDK45 -library sram_4_32 -strmFile sram_4_32.gds
|
||||
|
||||
When you import a gds file, make sure to attach the correct tech lib
|
||||
or you will get incorrect layers in the resulting library.
|
||||
|
||||
|
|
@ -1243,21 +1243,21 @@ class bank(design.design):
|
|||
offset=in_pin + self.m2m3_via_offset,
|
||||
rotate=90)
|
||||
|
||||
def delay(self, slew, load):
|
||||
def analytical_delay(self, slew, load):
|
||||
""" return analytical delay of the bank"""
|
||||
msf_addr_delay = self.msf_address.delay(slew, self.decoder.input_load())
|
||||
msf_addr_delay = self.msf_address.analytical_delay(slew, self.decoder.input_load())
|
||||
|
||||
decoder_delay = self.decoder.delay(msf_addr_delay.slew, self.wordline_driver.input_load())
|
||||
decoder_delay = self.decoder.analytical_delay(msf_addr_delay.slew, self.wordline_driver.input_load())
|
||||
|
||||
word_driver_delay = self.wordline_driver.delay(decoder_delay.slew, self.bitcell_array.input_load())
|
||||
word_driver_delay = self.wordline_driver.analytical_delay(decoder_delay.slew, self.bitcell_array.input_load())
|
||||
|
||||
bitcell_array_delay = self.bitcell_array.delay(word_driver_delay.slew)
|
||||
bitcell_array_delay = self.bitcell_array.analytical_delay(word_driver_delay.slew)
|
||||
|
||||
bl_t_data_out_delay = self.sense_amp_array.delay(bitcell_array_delay.slew,
|
||||
self.bitcell_array.output_load())
|
||||
bl_t_data_out_delay = self.sense_amp_array.analytical_delay(bitcell_array_delay.slew,
|
||||
self.bitcell_array.output_load())
|
||||
# output load of bitcell_array is set to be only small part of bl for sense amp.
|
||||
|
||||
data_t_DATA_delay = self.tri_gate_array.delay(bl_t_data_out_delay.slew, load)
|
||||
data_t_DATA_delay = self.tri_gate_array.analytical_delay(bl_t_data_out_delay.slew, load)
|
||||
|
||||
result = msf_addr_delay + decoder_delay + word_driver_delay \
|
||||
+ bitcell_array_delay + bl_t_data_out_delay + data_t_DATA_delay
|
||||
|
|
|
|||
|
|
@ -23,7 +23,7 @@ class bitcell(design.design):
|
|||
self.height = bitcell.height
|
||||
self.pin_map = bitcell.pin_map
|
||||
|
||||
def delay(self, slew, load=0, swing = 0.5):
|
||||
def analytical_delay(self, slew, load=0, swing = 0.5):
|
||||
# delay of bit cell is not like a driver(from WL)
|
||||
# so the slew used should be 0
|
||||
# it should not be slew dependent?
|
||||
|
|
|
|||
|
|
@ -160,7 +160,7 @@ class bitcell_array(design.design):
|
|||
# increments to the next row height
|
||||
offset.y += self.cell.height
|
||||
|
||||
def delay(self, slew, load=0):
|
||||
def analytical_delay(self, slew, load=0):
|
||||
from tech import drc
|
||||
wl_wire = self.gen_wl_wire()
|
||||
wl_wire.return_delay_over_wire(slew)
|
||||
|
|
@ -171,7 +171,7 @@ class bitcell_array(design.design):
|
|||
cell_load = 2 * bl_wire.return_input_cap() # we ingore the wire r
|
||||
# hence just use the whole c
|
||||
bl_swing = 0.1
|
||||
cell_delay = self.cell.delay(wl_to_cell_delay.slew, cell_load, swing = bl_swing)
|
||||
cell_delay = self.cell.analytical_delay(wl_to_cell_delay.slew, cell_load, swing = bl_swing)
|
||||
|
||||
#we do not consider the delay over the wire for now
|
||||
return self.return_delay(cell_delay.delay+wl_to_cell_delay.delay,
|
||||
|
|
|
|||
|
|
@ -424,3 +424,31 @@ class delay():
|
|||
t_current += period
|
||||
|
||||
|
||||
def analytical_model(self,sram, slews, loads):
|
||||
""" Just return the analytical model results for the SRAM.
|
||||
"""
|
||||
LH_delay = []
|
||||
HL_delay = []
|
||||
LH_slew = []
|
||||
HL_slew = []
|
||||
for slew in slews:
|
||||
for load in loads:
|
||||
bank_delay = sram.analytical_delay(slew,load)
|
||||
# Convert from ps to ns
|
||||
LH_delay.append(bank_delay.delay/1e3)
|
||||
HL_delay.append(bank_delay.delay/1e3)
|
||||
LH_slew.append(bank_delay.slew/1e3)
|
||||
HL_slew.append(bank_delay.slew/1e3)
|
||||
|
||||
data = {"min_period": 0,
|
||||
"delay1": LH_delay,
|
||||
"delay0": HL_delay,
|
||||
"slew1": LH_slew,
|
||||
"slew0": HL_slew,
|
||||
"read0_power": 0,
|
||||
"read1_power": 0,
|
||||
"write0_power": 0,
|
||||
"write1_power": 0
|
||||
}
|
||||
return data
|
||||
|
||||
|
|
|
|||
|
|
@ -379,12 +379,11 @@ class lib:
|
|||
self.d
|
||||
except AttributeError:
|
||||
self.d = delay.delay(self.sram, self.spfile)
|
||||
probe_address = "1" * self.addr_size
|
||||
probe_data = self.word_size - 1
|
||||
if self.use_model:
|
||||
self.d = True
|
||||
self.delay = self.sram.analytical_model(self.slews,self.loads)
|
||||
self.delay = self.d.analytical_model(self.sram,self.slews,self.loads)
|
||||
else:
|
||||
probe_address = "1" * self.addr_size
|
||||
probe_data = self.word_size - 1
|
||||
self.delay = self.d.analyze(probe_address, probe_data, self.slews, self.loads)
|
||||
|
||||
def compute_setup_hold(self):
|
||||
|
|
|
|||
|
|
@ -54,11 +54,12 @@ def parse_args():
|
|||
help="Technology name"),
|
||||
optparse.make_option("-s", "--spiceversion", dest="spice_version",
|
||||
help="Spice simulator name"),
|
||||
# TODO: Why is this -f?
|
||||
optparse.make_option("-f", "--trim_noncritical", action="store_true", dest="trim_noncritical",
|
||||
help="Trim noncritical memory cells during simulation"),
|
||||
optparse.make_option("-r", "--reduce_netlist", action="store_true", dest="remove_noncritical",
|
||||
help="Remove noncritical memory cells during characterization"),
|
||||
optparse.make_option("-a", "--analytical", action="store_true", dest="analytical_delay",
|
||||
help="Use analytical model to calculate delay")
|
||||
help="Use analytical models to calculate delays (default)"),
|
||||
optparse.make_option("-c", "--characterize", action="store_false", dest="analytical_delay",
|
||||
help="Perform characterization to calculate delays (default is analytical models)")
|
||||
}
|
||||
# -h --help is implicit.
|
||||
|
||||
|
|
@ -238,6 +239,12 @@ def set_spice():
|
|||
debug.info(2,"Finding spice...")
|
||||
global OPTS
|
||||
|
||||
if OPTS.analytical_delay:
|
||||
debug.info(1,"Using analytical delay models (no characterization)")
|
||||
return
|
||||
else:
|
||||
debug.info(1,"Performing simulation-based characterization (may be slow!)")
|
||||
|
||||
OPTS.spice_exe = ""
|
||||
|
||||
# Check if the preferred spice option exists in the path
|
||||
|
|
|
|||
|
|
@ -531,7 +531,7 @@ class hierarchical_decoder(design.design):
|
|||
offset=offset + vector(self.metal2_spacing,-self.via_shift),
|
||||
rotate=90)
|
||||
|
||||
def delay(self, slew, load = 0.0):
|
||||
def analytical_delay(self, slew, load = 0.0):
|
||||
# A -> out
|
||||
if self.determine_predecodes(self.num_inputs)[1]==0:
|
||||
pre = self.pre2_4
|
||||
|
|
@ -539,15 +539,15 @@ class hierarchical_decoder(design.design):
|
|||
else:
|
||||
pre = self.pre3_8
|
||||
nand = self.nand3
|
||||
a_t_out_delay = pre.delay(slew=slew,load = nand.input_load())
|
||||
a_t_out_delay = pre.analytical_delay(slew=slew,load = nand.input_load())
|
||||
|
||||
# out -> z
|
||||
out_t_z_delay = nand.delay(slew= a_t_out_delay.slew,
|
||||
out_t_z_delay = nand.analytical_delay(slew= a_t_out_delay.slew,
|
||||
load = self.inv.input_load())
|
||||
result = a_t_out_delay + out_t_z_delay
|
||||
|
||||
# Z -> decode_out
|
||||
z_t_decodeout_delay = self.inv.delay(slew = out_t_z_delay.slew , load = load)
|
||||
z_t_decodeout_delay = self.inv.analytical_delay(slew = out_t_z_delay.slew , load = load)
|
||||
result = result + z_t_decodeout_delay
|
||||
return result
|
||||
|
||||
|
|
|
|||
|
|
@ -43,18 +43,17 @@ class hierarchical_predecode2x4(hierarchical_predecode):
|
|||
return combination
|
||||
|
||||
|
||||
def delay(self, slew, load = 0.0 ):
|
||||
def analytical_delay(self, slew, load = 0.0 ):
|
||||
# in -> inbar
|
||||
a_t_b_delay = self.inv.delay(slew=slew,load = self.nand.input_load())
|
||||
a_t_b_delay = self.inv.analytical_delay(slew=slew, load=self.nand.input_load())
|
||||
|
||||
# inbar -> z
|
||||
b_t_z_delay = self.nand.delay(slew=a_t_b_delay.slew,load = self.inv.input_load())
|
||||
result = a_t_b_delay + b_t_z_delay
|
||||
b_t_z_delay = self.nand.analytical_delay(slew=a_t_b_delay.slew, load=self.inv.input_load())
|
||||
|
||||
# Z -> out
|
||||
a_t_out_delay = self.inv.delay(slew=b_t_z_delay.slew,load = load)
|
||||
result = result + a_t_out_delay
|
||||
return result
|
||||
a_t_out_delay = self.inv.analytical_delay(slew=b_t_z_delay.slew, load=load)
|
||||
|
||||
return a_t_b_delay + b_t_z_delay + a_t_out_delay
|
||||
|
||||
def input_load(self):
|
||||
return self.nand.input_load()
|
||||
|
|
|
|||
|
|
@ -51,18 +51,18 @@ class hierarchical_predecode3x8(hierarchical_predecode):
|
|||
return combination
|
||||
|
||||
|
||||
def delay(self, slew, load = 0.0 ):
|
||||
def analytical_delay(self, slew, load = 0.0 ):
|
||||
# A -> Abar
|
||||
a_t_b_delay = self.inv.delay(slew=slew,load = self.nand.input_load())
|
||||
a_t_b_delay = self.inv.analytical_delay(slew=slew, load=self.nand.input_load())
|
||||
|
||||
# Abar -> z
|
||||
b_t_z_delay = self.nand.delay(slew=a_t_b_delay.slew,load = self.inv.input_load())
|
||||
result = a_t_b_delay + b_t_z_delay
|
||||
b_t_z_delay = self.nand.analytical_delay(slew=a_t_b_delay.slew, load=self.inv.input_load())
|
||||
|
||||
# Z -> out
|
||||
a_t_out_delay = self.inv.delay(slew=b_t_z_delay.slew,load = load)
|
||||
result = result + a_t_out_delay
|
||||
return result
|
||||
a_t_out_delay = self.inv.analytical_delay(slew=b_t_z_delay.slew, load=load)
|
||||
|
||||
return a_t_b_delay + b_t_z_delay + a_t_out_delay
|
||||
|
||||
|
||||
|
||||
def input_load(self):
|
||||
|
|
|
|||
|
|
@ -148,7 +148,7 @@ class spice:
|
|||
del usedMODS
|
||||
spfile.close()
|
||||
|
||||
def delay(self, slew, load=0.0):
|
||||
def analytical_delay(self, slew, load=0.0):
|
||||
"""Inform users undefined delay module while building new modules"""
|
||||
debug.warning("Design Class {0} delay function needs to be defined"
|
||||
.format(self.__class__.__name__))
|
||||
|
|
|
|||
|
|
@ -21,8 +21,9 @@ class ms_flop(design.design):
|
|||
self.height = ms_flop.height
|
||||
self.pin_map = ms_flop.pin_map
|
||||
|
||||
def delay(self, slew, load = 0.0):
|
||||
def analytical_delay(self, slew, load = 0.0):
|
||||
# dont know how to calculate this now, use constant in tech file
|
||||
from tech import spice
|
||||
result = self.return_delay(spice["msflop_delay"], spice["msflop_slew"])
|
||||
return result
|
||||
|
||||
|
|
|
|||
|
|
@ -132,7 +132,5 @@ class ms_flop_array(design.design):
|
|||
height=drc["minwidth_metal1"])
|
||||
|
||||
|
||||
def delay(self, slew, load=0.0):
|
||||
result = self.ms.delay(slew = slew,
|
||||
load = load)
|
||||
return result
|
||||
def analytical_delay(self, slew, load=0.0):
|
||||
return self.ms.analytical_delay(slew=slew, load=load)
|
||||
|
|
|
|||
|
|
@ -419,7 +419,7 @@ class nand_2(design.design):
|
|||
from tech import spice
|
||||
return ((self.nmos_size+self.pmos_size)/parameter["min_tx_size"])*spice["min_tx_gate_c"]
|
||||
|
||||
def delay(self, slew, load=0.0):
|
||||
def analytical_delay(self, slew, load=0.0):
|
||||
r = spice["min_tx_r"]/(self.nmos_size/parameter["min_tx_size"])
|
||||
c_para = spice["min_tx_drain_c"]*(self.nmos_size/parameter["min_tx_size"])#ff
|
||||
return self.cal_delay_with_rc(r = r, c = c_para+load, slew = slew)
|
||||
|
|
|
|||
|
|
@ -435,7 +435,7 @@ class nand_3(design.design):
|
|||
def input_load(self):
|
||||
return ((self.nmos_size+self.pmos_size)/parameter["min_tx_size"])*spice["min_tx_gate_c"]
|
||||
|
||||
def delay(self, slew, load=0.0):
|
||||
def analytical_delay(self, slew, load=0.0):
|
||||
r = spice["min_tx_r"]/(self.nmos_size/parameter["min_tx_size"])
|
||||
c_para = spice["min_tx_drain_c"]*(self.nmos_size/parameter["min_tx_size"])#ff
|
||||
return self.cal_delay_with_rc(r = r, c = c_para+load, slew = slew)
|
||||
|
|
|
|||
|
|
@ -59,11 +59,17 @@ if (OPTS.output_name == ""):
|
|||
num_banks,
|
||||
OPTS.tech_name)
|
||||
|
||||
debug.info(1, "Output file is " + OPTS.output_name + ".(sp|gds|v|lib|lef)")
|
||||
debug.info(1, "Output files are " + OPTS.output_name + ".(sp|gds|v|lib|lef)")
|
||||
|
||||
print("Technology: {0}".format(OPTS.tech_name))
|
||||
print("Word size: {0}\nWords: {1}\nBanks: {2}".format(word_size,num_words,num_banks))
|
||||
|
||||
|
||||
if OPTS.analytical_delay:
|
||||
print("Using analytical delay models (no characterization)")
|
||||
else:
|
||||
print("Performing simulation-based characterization (may be slow!)")
|
||||
|
||||
# only start importing modules after we have the config file
|
||||
import calibre
|
||||
import sram
|
||||
|
|
|
|||
|
|
@ -30,10 +30,11 @@ class options(optparse.Values):
|
|||
spice_exe = ""
|
||||
# Run with extracted parasitics
|
||||
use_pex = False
|
||||
# Trim noncritical memory cells for simulation speed-up
|
||||
trim_noncritical = False
|
||||
# Remove noncritical memory cells for characterization speed-up
|
||||
remove_noncritical = False
|
||||
# Define the output file paths
|
||||
output_path = ""
|
||||
# Define the output file base name
|
||||
output_name = ""
|
||||
analytical_delay = False
|
||||
# Use analytical delay models by default rather than (slow) characterization
|
||||
analytical_delay = True
|
||||
|
|
|
|||
|
|
@ -406,7 +406,7 @@ class pinv(design.design):
|
|||
def input_load(self):
|
||||
return ((self.nmos_size+self.pmos_size)/parameter["min_tx_size"])*spice["min_tx_gate_c"]
|
||||
|
||||
def delay(self, slew, load=0.0):
|
||||
def analytical_delay(self, slew, load=0.0):
|
||||
from tech import spice
|
||||
r = spice["min_tx_r"]/(self.nmos_size/parameter["min_tx_size"])
|
||||
c_para = spice["min_tx_drain_c"]*(self.nmos_size/parameter["min_tx_size"])#ff
|
||||
|
|
|
|||
|
|
@ -23,7 +23,7 @@ class sense_amp(design.design):
|
|||
self.height = sense_amp.height
|
||||
self.pin_map = sense_amp.pin_map
|
||||
|
||||
def delay(self, slew, load=0.0):
|
||||
def analytical_delay(self, slew, load=0.0):
|
||||
from tech import spice
|
||||
r = spice["min_tx_r"]/(10)
|
||||
c_para = spice["min_tx_drain_c"]
|
||||
|
|
|
|||
|
|
@ -117,6 +117,5 @@ class sense_amp_array(design.design):
|
|||
width=self.width,
|
||||
height=drc["minwidth_metal1"])
|
||||
|
||||
def delay(self, slew, load=0.0):
|
||||
result = self.amp.delay(slew=slew, load=load)
|
||||
return result
|
||||
def analytical_delay(self, slew, load=0.0):
|
||||
return self.amp.analytical_delay(slew=slew, load=load)
|
||||
|
|
|
|||
|
|
@ -998,28 +998,6 @@ class sram(design.design):
|
|||
del usedMODS
|
||||
sp.close()
|
||||
|
||||
def analytical_model(self,slews,loads):
|
||||
LH_delay = []
|
||||
HL_delay = []
|
||||
LH_slew = []
|
||||
HL_slew = []
|
||||
for slew in slews:
|
||||
for load in loads:
|
||||
bank_delay = self.bank.delay(slew,load)
|
||||
# Convert from ps to ns
|
||||
LH_delay.append(bank_delay.delay/1e3)
|
||||
HL_delay.append(bank_delay.delay/1e3)
|
||||
LH_slew.append(bank_delay.slew/1e3)
|
||||
HL_slew.append(bank_delay.slew/1e3)
|
||||
|
||||
data = {"min_period": 0,
|
||||
"delay1": LH_delay,
|
||||
"delay0": HL_delay,
|
||||
"slew1": LH_slew,
|
||||
"slew0": HL_slew,
|
||||
"read0_power": 0,
|
||||
"read1_power": 0,
|
||||
"write0_power": 0,
|
||||
"write1_power": 0
|
||||
}
|
||||
return data
|
||||
def analytical_delay(self,slew,load):
|
||||
""" LH and HL are the same in analytical model. """
|
||||
return self.bank.analytical_delay(slew,load)
|
||||
|
|
|
|||
|
|
@ -24,6 +24,7 @@ class timing_sram_test(unittest.TestCase):
|
|||
OPTS.check_lvsdrc = False
|
||||
OPTS.spice_version="hspice"
|
||||
OPTS.force_spice = True
|
||||
OPTS.analytical_delay = False
|
||||
globals.set_spice()
|
||||
|
||||
import sram
|
||||
|
|
@ -88,6 +89,7 @@ class timing_sram_test(unittest.TestCase):
|
|||
OPTS.check_lvsdrc = True
|
||||
OPTS.spice_version="hspice"
|
||||
OPTS.force_spice = False
|
||||
OPTS.analytical_delay = True
|
||||
globals.set_spice()
|
||||
|
||||
os.remove(tempspice)
|
||||
|
|
|
|||
|
|
@ -22,6 +22,7 @@ class timing_sram_test(unittest.TestCase):
|
|||
OPTS.check_lvsdrc = False
|
||||
OPTS.spice_version="ngspice"
|
||||
OPTS.force_spice = True
|
||||
OPTS.analytical_delay = False
|
||||
globals.set_spice()
|
||||
|
||||
import sram
|
||||
|
|
@ -84,6 +85,7 @@ class timing_sram_test(unittest.TestCase):
|
|||
OPTS.check_lvsdrc = True
|
||||
OPTS.spice_version="hspice"
|
||||
OPTS.force_spice = False
|
||||
OPTS.analytical_delay = True
|
||||
globals.set_spice()
|
||||
|
||||
os.remove(tempspice)
|
||||
|
|
|
|||
|
|
@ -19,10 +19,10 @@ OPTS = globals.get_opts()
|
|||
class sram_func_test(unittest.TestCase):
|
||||
|
||||
def runTest(self):
|
||||
OPTS.analytical_delay = False
|
||||
globals.init_openram("config_20_{0}".format(OPTS.tech_name))
|
||||
# we will manually run lvs/drc
|
||||
OPTS.check_lvsdrc = False
|
||||
|
||||
import sram
|
||||
|
||||
debug.info(1, "Testing timing for sample 1bit, 16words SRAM with 1 bank")
|
||||
|
|
@ -32,7 +32,6 @@ class sram_func_test(unittest.TestCase):
|
|||
name="sram_func_test")
|
||||
|
||||
OPTS.check_lvsdrc = True
|
||||
|
||||
import delay
|
||||
|
||||
tempspice = OPTS.openram_temp + "temp.sp"
|
||||
|
|
@ -52,7 +51,7 @@ class sram_func_test(unittest.TestCase):
|
|||
feasible_period = d.find_feasible_period(load,slew)
|
||||
|
||||
os.remove(tempspice)
|
||||
|
||||
OPTS.analytical_delay = True
|
||||
globals.end_openram()
|
||||
|
||||
# instantiate a copdsay of the class to actually run the test
|
||||
|
|
|
|||
|
|
@ -17,6 +17,7 @@ OPTS = globals.get_opts()
|
|||
class lib_test(unittest.TestCase):
|
||||
|
||||
def runTest(self):
|
||||
OPTS.analytical_delay = False
|
||||
globals.init_openram("config_20_{0}".format(OPTS.tech_name))
|
||||
# we will manually run lvs/drc
|
||||
OPTS.check_lvsdrc = False
|
||||
|
|
@ -44,9 +45,9 @@ class lib_test(unittest.TestCase):
|
|||
self.assertEqual(isapproxdiff(libname,golden,0.10),True)
|
||||
|
||||
os.system("rm {0}".format(libname))
|
||||
|
||||
OPTS.analytical_delay = True
|
||||
globals.end_openram()
|
||||
|
||||
|
||||
# instantiate a copdsay of the class to actually run the test
|
||||
if __name__ == "__main__":
|
||||
(OPTS, args) = globals.parse_args()
|
||||
|
|
|
|||
|
|
@ -27,7 +27,7 @@ class tri_gate(design.design):
|
|||
self.height = tri_gate.height
|
||||
self.pin_map = tri_gate.pin_map
|
||||
|
||||
def delay(self, slew, load=0.0):
|
||||
def analytical_delay(self, slew, load=0.0):
|
||||
from tech import spice
|
||||
r = spice["min_tx_r"]
|
||||
c_para = spice["min_tx_drain_c"]
|
||||
|
|
|
|||
|
|
@ -109,6 +109,5 @@ class tri_gate_array(design.design):
|
|||
height=drc["minwidth_metal1"])
|
||||
|
||||
|
||||
def delay(self, slew, load=0.0):
|
||||
result = self.tri.delay(slew = slew, load = load)
|
||||
return result
|
||||
def analytical_delay(self, slew, load=0.0):
|
||||
return self.tri.analytical_delay(slew = slew, load = load)
|
||||
|
|
|
|||
|
|
@ -9,7 +9,6 @@ class verilog:
|
|||
self.word_size = sram.word_size
|
||||
self.addr_size = sram.addr_size
|
||||
|
||||
debug.info(1,"Writing to {0}".format(verilog_name))
|
||||
self.vf = open(verilog_name, "w")
|
||||
|
||||
self.create()
|
||||
|
|
|
|||
|
|
@ -191,15 +191,14 @@ class wordline_driver(design.design):
|
|||
end=wl_offset-vector(drc["minwidth_metal1"],0))
|
||||
|
||||
|
||||
def delay(self, slew, load=0):
|
||||
def analytical_delay(self, slew, load=0):
|
||||
# decode -> net
|
||||
decode_t_net = self.nand2.delay(slew, self.inv.input_load())
|
||||
decode_t_net = self.nand2.analytical_delay(slew, self.inv.input_load())
|
||||
|
||||
# net -> wl
|
||||
net_t_wl = self.inv.delay(decode_t_net.slew, load)
|
||||
net_t_wl = self.inv.analytical_delay(decode_t_net.slew, load)
|
||||
|
||||
result = decode_t_net + net_t_wl
|
||||
return result
|
||||
return decode_t_net + net_t_wl
|
||||
|
||||
def input_load(self):
|
||||
return self.nand2.input_load()
|
||||
|
|
|
|||
Loading…
Reference in New Issue