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,
|
offset=in_pin + self.m2m3_via_offset,
|
||||||
rotate=90)
|
rotate=90)
|
||||||
|
|
||||||
def delay(self, slew, load):
|
def analytical_delay(self, slew, load):
|
||||||
""" return analytical delay of the bank"""
|
""" 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,
|
bl_t_data_out_delay = self.sense_amp_array.analytical_delay(bitcell_array_delay.slew,
|
||||||
self.bitcell_array.output_load())
|
self.bitcell_array.output_load())
|
||||||
# output load of bitcell_array is set to be only small part of bl for sense amp.
|
# 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 \
|
result = msf_addr_delay + decoder_delay + word_driver_delay \
|
||||||
+ bitcell_array_delay + bl_t_data_out_delay + data_t_DATA_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.height = bitcell.height
|
||||||
self.pin_map = bitcell.pin_map
|
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)
|
# delay of bit cell is not like a driver(from WL)
|
||||||
# so the slew used should be 0
|
# so the slew used should be 0
|
||||||
# it should not be slew dependent?
|
# it should not be slew dependent?
|
||||||
|
|
|
||||||
|
|
@ -160,7 +160,7 @@ class bitcell_array(design.design):
|
||||||
# increments to the next row height
|
# increments to the next row height
|
||||||
offset.y += self.cell.height
|
offset.y += self.cell.height
|
||||||
|
|
||||||
def delay(self, slew, load=0):
|
def analytical_delay(self, slew, load=0):
|
||||||
from tech import drc
|
from tech import drc
|
||||||
wl_wire = self.gen_wl_wire()
|
wl_wire = self.gen_wl_wire()
|
||||||
wl_wire.return_delay_over_wire(slew)
|
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
|
cell_load = 2 * bl_wire.return_input_cap() # we ingore the wire r
|
||||||
# hence just use the whole c
|
# hence just use the whole c
|
||||||
bl_swing = 0.1
|
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
|
#we do not consider the delay over the wire for now
|
||||||
return self.return_delay(cell_delay.delay+wl_to_cell_delay.delay,
|
return self.return_delay(cell_delay.delay+wl_to_cell_delay.delay,
|
||||||
|
|
|
||||||
|
|
@ -424,3 +424,31 @@ class delay():
|
||||||
t_current += period
|
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
|
self.d
|
||||||
except AttributeError:
|
except AttributeError:
|
||||||
self.d = delay.delay(self.sram, self.spfile)
|
self.d = delay.delay(self.sram, self.spfile)
|
||||||
probe_address = "1" * self.addr_size
|
|
||||||
probe_data = self.word_size - 1
|
|
||||||
if self.use_model:
|
if self.use_model:
|
||||||
self.d = True
|
self.delay = self.d.analytical_model(self.sram,self.slews,self.loads)
|
||||||
self.delay = self.sram.analytical_model(self.slews,self.loads)
|
|
||||||
else:
|
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)
|
self.delay = self.d.analyze(probe_address, probe_data, self.slews, self.loads)
|
||||||
|
|
||||||
def compute_setup_hold(self):
|
def compute_setup_hold(self):
|
||||||
|
|
|
||||||
|
|
@ -54,11 +54,12 @@ def parse_args():
|
||||||
help="Technology name"),
|
help="Technology name"),
|
||||||
optparse.make_option("-s", "--spiceversion", dest="spice_version",
|
optparse.make_option("-s", "--spiceversion", dest="spice_version",
|
||||||
help="Spice simulator name"),
|
help="Spice simulator name"),
|
||||||
# TODO: Why is this -f?
|
optparse.make_option("-r", "--reduce_netlist", action="store_true", dest="remove_noncritical",
|
||||||
optparse.make_option("-f", "--trim_noncritical", action="store_true", dest="trim_noncritical",
|
help="Remove noncritical memory cells during characterization"),
|
||||||
help="Trim noncritical memory cells during simulation"),
|
|
||||||
optparse.make_option("-a", "--analytical", action="store_true", dest="analytical_delay",
|
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.
|
# -h --help is implicit.
|
||||||
|
|
||||||
|
|
@ -238,6 +239,12 @@ def set_spice():
|
||||||
debug.info(2,"Finding spice...")
|
debug.info(2,"Finding spice...")
|
||||||
global OPTS
|
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 = ""
|
OPTS.spice_exe = ""
|
||||||
|
|
||||||
# Check if the preferred spice option exists in the path
|
# 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),
|
offset=offset + vector(self.metal2_spacing,-self.via_shift),
|
||||||
rotate=90)
|
rotate=90)
|
||||||
|
|
||||||
def delay(self, slew, load = 0.0):
|
def analytical_delay(self, slew, load = 0.0):
|
||||||
# A -> out
|
# A -> out
|
||||||
if self.determine_predecodes(self.num_inputs)[1]==0:
|
if self.determine_predecodes(self.num_inputs)[1]==0:
|
||||||
pre = self.pre2_4
|
pre = self.pre2_4
|
||||||
|
|
@ -539,15 +539,15 @@ class hierarchical_decoder(design.design):
|
||||||
else:
|
else:
|
||||||
pre = self.pre3_8
|
pre = self.pre3_8
|
||||||
nand = self.nand3
|
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 -> 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())
|
load = self.inv.input_load())
|
||||||
result = a_t_out_delay + out_t_z_delay
|
result = a_t_out_delay + out_t_z_delay
|
||||||
|
|
||||||
# Z -> decode_out
|
# 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
|
result = result + z_t_decodeout_delay
|
||||||
return result
|
return result
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -43,18 +43,17 @@ class hierarchical_predecode2x4(hierarchical_predecode):
|
||||||
return combination
|
return combination
|
||||||
|
|
||||||
|
|
||||||
def delay(self, slew, load = 0.0 ):
|
def analytical_delay(self, slew, load = 0.0 ):
|
||||||
# in -> inbar
|
# 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
|
# inbar -> z
|
||||||
b_t_z_delay = self.nand.delay(slew=a_t_b_delay.slew,load = self.inv.input_load())
|
b_t_z_delay = self.nand.analytical_delay(slew=a_t_b_delay.slew, load=self.inv.input_load())
|
||||||
result = a_t_b_delay + b_t_z_delay
|
|
||||||
|
|
||||||
# Z -> out
|
# Z -> out
|
||||||
a_t_out_delay = self.inv.delay(slew=b_t_z_delay.slew,load = load)
|
a_t_out_delay = self.inv.analytical_delay(slew=b_t_z_delay.slew, load=load)
|
||||||
result = result + a_t_out_delay
|
|
||||||
return result
|
return a_t_b_delay + b_t_z_delay + a_t_out_delay
|
||||||
|
|
||||||
def input_load(self):
|
def input_load(self):
|
||||||
return self.nand.input_load()
|
return self.nand.input_load()
|
||||||
|
|
|
||||||
|
|
@ -51,18 +51,18 @@ class hierarchical_predecode3x8(hierarchical_predecode):
|
||||||
return combination
|
return combination
|
||||||
|
|
||||||
|
|
||||||
def delay(self, slew, load = 0.0 ):
|
def analytical_delay(self, slew, load = 0.0 ):
|
||||||
# A -> Abar
|
# 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
|
# Abar -> z
|
||||||
b_t_z_delay = self.nand.delay(slew=a_t_b_delay.slew,load = self.inv.input_load())
|
b_t_z_delay = self.nand.analytical_delay(slew=a_t_b_delay.slew, load=self.inv.input_load())
|
||||||
result = a_t_b_delay + b_t_z_delay
|
|
||||||
|
|
||||||
# Z -> out
|
# Z -> out
|
||||||
a_t_out_delay = self.inv.delay(slew=b_t_z_delay.slew,load = load)
|
a_t_out_delay = self.inv.analytical_delay(slew=b_t_z_delay.slew, load=load)
|
||||||
result = result + a_t_out_delay
|
|
||||||
return result
|
return a_t_b_delay + b_t_z_delay + a_t_out_delay
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
def input_load(self):
|
def input_load(self):
|
||||||
|
|
|
||||||
|
|
@ -148,7 +148,7 @@ class spice:
|
||||||
del usedMODS
|
del usedMODS
|
||||||
spfile.close()
|
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"""
|
"""Inform users undefined delay module while building new modules"""
|
||||||
debug.warning("Design Class {0} delay function needs to be defined"
|
debug.warning("Design Class {0} delay function needs to be defined"
|
||||||
.format(self.__class__.__name__))
|
.format(self.__class__.__name__))
|
||||||
|
|
|
||||||
|
|
@ -21,8 +21,9 @@ class ms_flop(design.design):
|
||||||
self.height = ms_flop.height
|
self.height = ms_flop.height
|
||||||
self.pin_map = ms_flop.pin_map
|
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
|
# dont know how to calculate this now, use constant in tech file
|
||||||
from tech import spice
|
from tech import spice
|
||||||
result = self.return_delay(spice["msflop_delay"], spice["msflop_slew"])
|
result = self.return_delay(spice["msflop_delay"], spice["msflop_slew"])
|
||||||
return result
|
return result
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -132,7 +132,5 @@ class ms_flop_array(design.design):
|
||||||
height=drc["minwidth_metal1"])
|
height=drc["minwidth_metal1"])
|
||||||
|
|
||||||
|
|
||||||
def delay(self, slew, load=0.0):
|
def analytical_delay(self, slew, load=0.0):
|
||||||
result = self.ms.delay(slew = slew,
|
return self.ms.analytical_delay(slew=slew, load=load)
|
||||||
load = load)
|
|
||||||
return result
|
|
||||||
|
|
|
||||||
|
|
@ -419,7 +419,7 @@ class nand_2(design.design):
|
||||||
from tech import spice
|
from tech import spice
|
||||||
return ((self.nmos_size+self.pmos_size)/parameter["min_tx_size"])*spice["min_tx_gate_c"]
|
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"])
|
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
|
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)
|
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):
|
def input_load(self):
|
||||||
return ((self.nmos_size+self.pmos_size)/parameter["min_tx_size"])*spice["min_tx_gate_c"]
|
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"])
|
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
|
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)
|
return self.cal_delay_with_rc(r = r, c = c_para+load, slew = slew)
|
||||||
|
|
|
||||||
|
|
@ -59,11 +59,17 @@ if (OPTS.output_name == ""):
|
||||||
num_banks,
|
num_banks,
|
||||||
OPTS.tech_name)
|
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("Technology: {0}".format(OPTS.tech_name))
|
||||||
print("Word size: {0}\nWords: {1}\nBanks: {2}".format(word_size,num_words,num_banks))
|
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
|
# only start importing modules after we have the config file
|
||||||
import calibre
|
import calibre
|
||||||
import sram
|
import sram
|
||||||
|
|
|
||||||
|
|
@ -30,10 +30,11 @@ class options(optparse.Values):
|
||||||
spice_exe = ""
|
spice_exe = ""
|
||||||
# Run with extracted parasitics
|
# Run with extracted parasitics
|
||||||
use_pex = False
|
use_pex = False
|
||||||
# Trim noncritical memory cells for simulation speed-up
|
# Remove noncritical memory cells for characterization speed-up
|
||||||
trim_noncritical = False
|
remove_noncritical = False
|
||||||
# Define the output file paths
|
# Define the output file paths
|
||||||
output_path = ""
|
output_path = ""
|
||||||
# Define the output file base name
|
# Define the output file base name
|
||||||
output_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):
|
def input_load(self):
|
||||||
return ((self.nmos_size+self.pmos_size)/parameter["min_tx_size"])*spice["min_tx_gate_c"]
|
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
|
from tech import spice
|
||||||
r = spice["min_tx_r"]/(self.nmos_size/parameter["min_tx_size"])
|
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
|
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.height = sense_amp.height
|
||||||
self.pin_map = sense_amp.pin_map
|
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
|
from tech import spice
|
||||||
r = spice["min_tx_r"]/(10)
|
r = spice["min_tx_r"]/(10)
|
||||||
c_para = spice["min_tx_drain_c"]
|
c_para = spice["min_tx_drain_c"]
|
||||||
|
|
|
||||||
|
|
@ -117,6 +117,5 @@ class sense_amp_array(design.design):
|
||||||
width=self.width,
|
width=self.width,
|
||||||
height=drc["minwidth_metal1"])
|
height=drc["minwidth_metal1"])
|
||||||
|
|
||||||
def delay(self, slew, load=0.0):
|
def analytical_delay(self, slew, load=0.0):
|
||||||
result = self.amp.delay(slew=slew, load=load)
|
return self.amp.analytical_delay(slew=slew, load=load)
|
||||||
return result
|
|
||||||
|
|
|
||||||
|
|
@ -998,28 +998,6 @@ class sram(design.design):
|
||||||
del usedMODS
|
del usedMODS
|
||||||
sp.close()
|
sp.close()
|
||||||
|
|
||||||
def analytical_model(self,slews,loads):
|
def analytical_delay(self,slew,load):
|
||||||
LH_delay = []
|
""" LH and HL are the same in analytical model. """
|
||||||
HL_delay = []
|
return self.bank.analytical_delay(slew,load)
|
||||||
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
|
|
||||||
|
|
|
||||||
|
|
@ -24,6 +24,7 @@ class timing_sram_test(unittest.TestCase):
|
||||||
OPTS.check_lvsdrc = False
|
OPTS.check_lvsdrc = False
|
||||||
OPTS.spice_version="hspice"
|
OPTS.spice_version="hspice"
|
||||||
OPTS.force_spice = True
|
OPTS.force_spice = True
|
||||||
|
OPTS.analytical_delay = False
|
||||||
globals.set_spice()
|
globals.set_spice()
|
||||||
|
|
||||||
import sram
|
import sram
|
||||||
|
|
@ -88,6 +89,7 @@ class timing_sram_test(unittest.TestCase):
|
||||||
OPTS.check_lvsdrc = True
|
OPTS.check_lvsdrc = True
|
||||||
OPTS.spice_version="hspice"
|
OPTS.spice_version="hspice"
|
||||||
OPTS.force_spice = False
|
OPTS.force_spice = False
|
||||||
|
OPTS.analytical_delay = True
|
||||||
globals.set_spice()
|
globals.set_spice()
|
||||||
|
|
||||||
os.remove(tempspice)
|
os.remove(tempspice)
|
||||||
|
|
|
||||||
|
|
@ -22,6 +22,7 @@ class timing_sram_test(unittest.TestCase):
|
||||||
OPTS.check_lvsdrc = False
|
OPTS.check_lvsdrc = False
|
||||||
OPTS.spice_version="ngspice"
|
OPTS.spice_version="ngspice"
|
||||||
OPTS.force_spice = True
|
OPTS.force_spice = True
|
||||||
|
OPTS.analytical_delay = False
|
||||||
globals.set_spice()
|
globals.set_spice()
|
||||||
|
|
||||||
import sram
|
import sram
|
||||||
|
|
@ -84,6 +85,7 @@ class timing_sram_test(unittest.TestCase):
|
||||||
OPTS.check_lvsdrc = True
|
OPTS.check_lvsdrc = True
|
||||||
OPTS.spice_version="hspice"
|
OPTS.spice_version="hspice"
|
||||||
OPTS.force_spice = False
|
OPTS.force_spice = False
|
||||||
|
OPTS.analytical_delay = True
|
||||||
globals.set_spice()
|
globals.set_spice()
|
||||||
|
|
||||||
os.remove(tempspice)
|
os.remove(tempspice)
|
||||||
|
|
|
||||||
|
|
@ -19,10 +19,10 @@ OPTS = globals.get_opts()
|
||||||
class sram_func_test(unittest.TestCase):
|
class sram_func_test(unittest.TestCase):
|
||||||
|
|
||||||
def runTest(self):
|
def runTest(self):
|
||||||
|
OPTS.analytical_delay = False
|
||||||
globals.init_openram("config_20_{0}".format(OPTS.tech_name))
|
globals.init_openram("config_20_{0}".format(OPTS.tech_name))
|
||||||
# we will manually run lvs/drc
|
# we will manually run lvs/drc
|
||||||
OPTS.check_lvsdrc = False
|
OPTS.check_lvsdrc = False
|
||||||
|
|
||||||
import sram
|
import sram
|
||||||
|
|
||||||
debug.info(1, "Testing timing for sample 1bit, 16words SRAM with 1 bank")
|
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")
|
name="sram_func_test")
|
||||||
|
|
||||||
OPTS.check_lvsdrc = True
|
OPTS.check_lvsdrc = True
|
||||||
|
|
||||||
import delay
|
import delay
|
||||||
|
|
||||||
tempspice = OPTS.openram_temp + "temp.sp"
|
tempspice = OPTS.openram_temp + "temp.sp"
|
||||||
|
|
@ -52,7 +51,7 @@ class sram_func_test(unittest.TestCase):
|
||||||
feasible_period = d.find_feasible_period(load,slew)
|
feasible_period = d.find_feasible_period(load,slew)
|
||||||
|
|
||||||
os.remove(tempspice)
|
os.remove(tempspice)
|
||||||
|
OPTS.analytical_delay = True
|
||||||
globals.end_openram()
|
globals.end_openram()
|
||||||
|
|
||||||
# instantiate a copdsay of the class to actually run the test
|
# instantiate a copdsay of the class to actually run the test
|
||||||
|
|
|
||||||
|
|
@ -17,6 +17,7 @@ OPTS = globals.get_opts()
|
||||||
class lib_test(unittest.TestCase):
|
class lib_test(unittest.TestCase):
|
||||||
|
|
||||||
def runTest(self):
|
def runTest(self):
|
||||||
|
OPTS.analytical_delay = False
|
||||||
globals.init_openram("config_20_{0}".format(OPTS.tech_name))
|
globals.init_openram("config_20_{0}".format(OPTS.tech_name))
|
||||||
# we will manually run lvs/drc
|
# we will manually run lvs/drc
|
||||||
OPTS.check_lvsdrc = False
|
OPTS.check_lvsdrc = False
|
||||||
|
|
@ -44,9 +45,9 @@ class lib_test(unittest.TestCase):
|
||||||
self.assertEqual(isapproxdiff(libname,golden,0.10),True)
|
self.assertEqual(isapproxdiff(libname,golden,0.10),True)
|
||||||
|
|
||||||
os.system("rm {0}".format(libname))
|
os.system("rm {0}".format(libname))
|
||||||
|
OPTS.analytical_delay = True
|
||||||
globals.end_openram()
|
globals.end_openram()
|
||||||
|
|
||||||
# instantiate a copdsay of the class to actually run the test
|
# instantiate a copdsay of the class to actually run the test
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
(OPTS, args) = globals.parse_args()
|
(OPTS, args) = globals.parse_args()
|
||||||
|
|
|
||||||
|
|
@ -27,7 +27,7 @@ class tri_gate(design.design):
|
||||||
self.height = tri_gate.height
|
self.height = tri_gate.height
|
||||||
self.pin_map = tri_gate.pin_map
|
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
|
from tech import spice
|
||||||
r = spice["min_tx_r"]
|
r = spice["min_tx_r"]
|
||||||
c_para = spice["min_tx_drain_c"]
|
c_para = spice["min_tx_drain_c"]
|
||||||
|
|
|
||||||
|
|
@ -109,6 +109,5 @@ class tri_gate_array(design.design):
|
||||||
height=drc["minwidth_metal1"])
|
height=drc["minwidth_metal1"])
|
||||||
|
|
||||||
|
|
||||||
def delay(self, slew, load=0.0):
|
def analytical_delay(self, slew, load=0.0):
|
||||||
result = self.tri.delay(slew = slew, load = load)
|
return self.tri.analytical_delay(slew = slew, load = load)
|
||||||
return result
|
|
||||||
|
|
|
||||||
|
|
@ -9,7 +9,6 @@ class verilog:
|
||||||
self.word_size = sram.word_size
|
self.word_size = sram.word_size
|
||||||
self.addr_size = sram.addr_size
|
self.addr_size = sram.addr_size
|
||||||
|
|
||||||
debug.info(1,"Writing to {0}".format(verilog_name))
|
|
||||||
self.vf = open(verilog_name, "w")
|
self.vf = open(verilog_name, "w")
|
||||||
|
|
||||||
self.create()
|
self.create()
|
||||||
|
|
|
||||||
|
|
@ -191,15 +191,14 @@ class wordline_driver(design.design):
|
||||||
end=wl_offset-vector(drc["minwidth_metal1"],0))
|
end=wl_offset-vector(drc["minwidth_metal1"],0))
|
||||||
|
|
||||||
|
|
||||||
def delay(self, slew, load=0):
|
def analytical_delay(self, slew, load=0):
|
||||||
# decode -> net
|
# 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 -> 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 decode_t_net + net_t_wl
|
||||||
return result
|
|
||||||
|
|
||||||
def input_load(self):
|
def input_load(self):
|
||||||
return self.nand2.input_load()
|
return self.nand2.input_load()
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue