diff --git a/README b/README deleted file mode 100644 index ccf848a2..00000000 --- a/README +++ /dev/null @@ -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 " 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//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 - - git commit -m "Useful comment" - -OR (sparingly, to commit all changes): - git status - - 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. - diff --git a/compiler/bank.py b/compiler/bank.py index 92999ad3..89e47abf 100644 --- a/compiler/bank.py +++ b/compiler/bank.py @@ -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 diff --git a/compiler/bitcell.py b/compiler/bitcell.py index 2aabde07..a79af868 100644 --- a/compiler/bitcell.py +++ b/compiler/bitcell.py @@ -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? diff --git a/compiler/bitcell_array.py b/compiler/bitcell_array.py index fce9d884..c3800cea 100644 --- a/compiler/bitcell_array.py +++ b/compiler/bitcell_array.py @@ -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, diff --git a/compiler/characterizer/delay.py b/compiler/characterizer/delay.py index fcfaf8d6..2d39a08c 100644 --- a/compiler/characterizer/delay.py +++ b/compiler/characterizer/delay.py @@ -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 + diff --git a/compiler/characterizer/lib.py b/compiler/characterizer/lib.py index 124cb91a..448fd4a0 100644 --- a/compiler/characterizer/lib.py +++ b/compiler/characterizer/lib.py @@ -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): diff --git a/compiler/globals.py b/compiler/globals.py index a1f8d8fe..99161541 100644 --- a/compiler/globals.py +++ b/compiler/globals.py @@ -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 diff --git a/compiler/hierarchical_decoder.py b/compiler/hierarchical_decoder.py index 0be07e06..3bf2e9b6 100644 --- a/compiler/hierarchical_decoder.py +++ b/compiler/hierarchical_decoder.py @@ -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 diff --git a/compiler/hierarchical_predecode2x4.py b/compiler/hierarchical_predecode2x4.py index f6fafedb..90f86f45 100644 --- a/compiler/hierarchical_predecode2x4.py +++ b/compiler/hierarchical_predecode2x4.py @@ -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() diff --git a/compiler/hierarchical_predecode3x8.py b/compiler/hierarchical_predecode3x8.py index f5e2cc4f..3f18661d 100644 --- a/compiler/hierarchical_predecode3x8.py +++ b/compiler/hierarchical_predecode3x8.py @@ -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): diff --git a/compiler/hierarchy_spice.py b/compiler/hierarchy_spice.py index 0d90940f..8b48345d 100644 --- a/compiler/hierarchy_spice.py +++ b/compiler/hierarchy_spice.py @@ -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__)) diff --git a/compiler/ms_flop.py b/compiler/ms_flop.py index cf53b439..01928790 100644 --- a/compiler/ms_flop.py +++ b/compiler/ms_flop.py @@ -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 + diff --git a/compiler/ms_flop_array.py b/compiler/ms_flop_array.py index 32373afe..2c837c20 100644 --- a/compiler/ms_flop_array.py +++ b/compiler/ms_flop_array.py @@ -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) diff --git a/compiler/nand_2.py b/compiler/nand_2.py index 7b8d3a0e..07b764d7 100644 --- a/compiler/nand_2.py +++ b/compiler/nand_2.py @@ -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) diff --git a/compiler/nand_3.py b/compiler/nand_3.py index c23f4b3f..23256ef3 100644 --- a/compiler/nand_3.py +++ b/compiler/nand_3.py @@ -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) diff --git a/compiler/openram.py b/compiler/openram.py index 21c8d37f..23ece9c0 100755 --- a/compiler/openram.py +++ b/compiler/openram.py @@ -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 diff --git a/compiler/options.py b/compiler/options.py index ae3b2bf6..53587578 100644 --- a/compiler/options.py +++ b/compiler/options.py @@ -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 diff --git a/compiler/pinv.py b/compiler/pinv.py index 64093dca..076042c5 100644 --- a/compiler/pinv.py +++ b/compiler/pinv.py @@ -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 diff --git a/compiler/sense_amp.py b/compiler/sense_amp.py index d640b76b..5155f05e 100644 --- a/compiler/sense_amp.py +++ b/compiler/sense_amp.py @@ -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"] diff --git a/compiler/sense_amp_array.py b/compiler/sense_amp_array.py index 85ac949c..6dbaab3e 100644 --- a/compiler/sense_amp_array.py +++ b/compiler/sense_amp_array.py @@ -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) diff --git a/compiler/sram.py b/compiler/sram.py index 20521105..6fe33811 100644 --- a/compiler/sram.py +++ b/compiler/sram.py @@ -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) diff --git a/compiler/tests/21_hspice_delay_test.py b/compiler/tests/21_hspice_delay_test.py index 1ec89e06..2069c6e1 100644 --- a/compiler/tests/21_hspice_delay_test.py +++ b/compiler/tests/21_hspice_delay_test.py @@ -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) diff --git a/compiler/tests/21_ngspice_delay_test.py b/compiler/tests/21_ngspice_delay_test.py index 2db69a38..3f0e9e5d 100644 --- a/compiler/tests/21_ngspice_delay_test.py +++ b/compiler/tests/21_ngspice_delay_test.py @@ -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) diff --git a/compiler/tests/22_sram_func_test.py b/compiler/tests/22_sram_func_test.py index 45fc7160..3a7ff5a3 100644 --- a/compiler/tests/22_sram_func_test.py +++ b/compiler/tests/22_sram_func_test.py @@ -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 diff --git a/compiler/tests/23_lib_sram_test.py b/compiler/tests/23_lib_sram_test.py index ecc82abf..7c1e0209 100644 --- a/compiler/tests/23_lib_sram_test.py +++ b/compiler/tests/23_lib_sram_test.py @@ -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() diff --git a/compiler/tri_gate.py b/compiler/tri_gate.py index 138953c6..e6debc4a 100644 --- a/compiler/tri_gate.py +++ b/compiler/tri_gate.py @@ -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"] diff --git a/compiler/tri_gate_array.py b/compiler/tri_gate_array.py index ef8bd4f4..cb12a449 100644 --- a/compiler/tri_gate_array.py +++ b/compiler/tri_gate_array.py @@ -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) diff --git a/compiler/verilog.py b/compiler/verilog.py index cbbe6fa3..27534b7c 100644 --- a/compiler/verilog.py +++ b/compiler/verilog.py @@ -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() diff --git a/compiler/wordline_driver.py b/compiler/wordline_driver.py index 8affab72..69ff291d 100644 --- a/compiler/wordline_driver.py +++ b/compiler/wordline_driver.py @@ -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()