Compare commits

...

504 Commits

Author SHA1 Message Date
Matt Guthaus ea15a81443
Merge pull request #270 from hpretl/stable
Switching from `volare` to `ciel` and bumping the version number
2025-06-26 13:15:50 -07:00
Harald Pretl 9492349d7a Bump version 2025-06-26 21:21:13 +02:00
Harald Pretl 01686a2005 Switch from `volare` to `ciel` 2025-06-26 21:21:06 +02:00
Matthew Guthaus e63f70da5e Update README by removing slack and email group. Update website. 2025-04-01 10:44:49 -07:00
Jesse Cirimelli-Low 8104a42f0e
Update artifact action 2024-11-13 22:45:31 -08:00
mrg bc1cc36ade Merge branch 'whitespace_fix' of github.com:TristanRobitaille/OpenRAM into dev 2024-11-12 09:49:00 -08:00
mrg 3184e1d0e4 Merge branch 'add-doc' of github.com:FriedrichWu/OpenRAM into dev 2024-11-12 09:47:57 -08:00
FriedrichWu 7ec407314a add documentation 2024-11-11 16:18:45 +01:00
Tristan Robitaille 1f5fe62456 Added whitespace between : and 'minimum_period', '1kOhm' and 'min_pulse_width' as required by Liberty file standard 2024-11-10 14:31:52 +01:00
mrg 3f1f58065d Add nand4 leakage to sky130 tech 2024-07-01 10:14:43 -07:00
mole99 0937f86761 Disable check_lvsdrc for gf180mcu 2024-02-03 12:15:11 +01:00
mole99 85e242fa27 Add gf180mcu ROM example 2024-02-03 11:31:58 +01:00
vlsida-bot b6a6f12642 Bump version: 1.2.47 -> 1.2.48 2024-01-21 17:32:32 +00:00
Eren Dogan 306da8a895 Merge branch 'sky130_regress' into dev 2024-01-20 21:05:22 -08:00
Eren Dogan 0cf60a6a18 Give u+x permissions for rom tests 2024-01-20 17:49:52 -08:00
Eren Dogan 55e5c425e9 Fix same file error and enable passing tests 2024-01-20 08:38:18 -08:00
Eren Dogan 14c219d9f1 Enable working tests from disabled stamps 2024-01-19 15:16:30 -08:00
Eren Dogan 855139bc4e Add Makefile target to run broken tests only 2024-01-19 15:15:52 -08:00
vlsida-bot 0423f10926 Bump version: 1.2.46 -> 1.2.47 2024-01-19 15:39:54 +00:00
Eren Dogan 156eb4f0f7 Force install requirements in miniconda 2024-01-18 20:17:14 -08:00
Eren Dogan 18b19b8d9d Install dependencies before running regression 2024-01-18 14:59:33 -08:00
Eren Dogan 5081cf2383 Fix make target in regression 2024-01-18 14:45:44 -08:00
mole99 84020f13c6 Clarify OpenRAM installation 2024-01-18 23:24:22 +01:00
mole99 0861ea5632 Update documentation 2024-01-18 18:48:11 +01:00
mole99 daa6286a3a Use volare as PDK version manager 2024-01-18 18:44:03 +01:00
vlsida-bot e7dbf7443e Bump version: 1.2.45 -> 1.2.46 2024-01-04 11:31:14 +00:00
Eren Dogan 0a1de57cae Update copyright year 2024-01-03 14:32:44 -08:00
vlsida-bot fc37bf6859 Bump version: 1.2.44 -> 1.2.45 2023-12-21 20:03:42 +00:00
mole99 8032fa75a4 Add LEF output for ROM 2023-12-21 08:07:49 +01:00
vlsida-bot 05884cf6a7 Bump version: 1.2.43 -> 1.2.44 2023-12-21 01:03:55 +00:00
Hadir Khan 9d6052b86c fix for matching the layout vs verilog port names for rom 2023-12-20 15:30:07 -08:00
vlsida-bot caa9b2a2d8 Bump version: 1.2.42 -> 1.2.43 2023-12-20 18:07:25 +00:00
Eren Dogan e35f060d32 Use newer builds for trilinos and xyce 2023-12-20 08:30:36 -08:00
Eren Dogan efd43c3191 Merge branch 'dev' into issue_fix 2023-12-06 13:30:22 -08:00
Eren Dogan 7531e38cad Remove unused local variable 2023-12-05 11:18:58 -08:00
Eren Dogan 39a66fcb87 Fix some lint errors 2023-12-05 11:16:22 -08:00
Eren Dogan 6cfb22959c Remove unused imports 2023-12-05 11:08:32 -08:00
Eren Dogan 02810a0740 Prevent import error 2023-12-05 10:31:18 -08:00
vlsida-bot e73ff401fb Bump version: 1.2.41 -> 1.2.42 2023-11-08 03:28:12 +00:00
SWalker 6bd437cfa8 Fixed bug that made metal-metal vias think they were well contacts 2023-11-07 14:27:11 -08:00
SWalker d59a60eaf3 Update gitignore for gf180 2023-11-07 01:18:21 -08:00
SWalker b9570b8ddf removed gf180 specific code from ptx 2023-11-07 01:01:05 -08:00
SWalker 6e2dadeff5 added some documentation for GF180 usage 2023-11-07 01:00:44 -08:00
SWalker fc1a9a9a2b revert change to Openpdks commit 2023-11-07 00:56:16 -08:00
SWalker ce1861f342 proper output rom bank output layer 2023-10-31 23:24:21 -07:00
SWalker d161cc55a5 fixed missing broken stamp 2023-10-31 23:24:21 -07:00
SWalker a45e16bff5 re-added rom tests to regression ignore for freepdk45 2023-10-31 23:24:21 -07:00
SWalker 26068fd2e1 more ptx fixes 2023-10-31 23:24:21 -07:00
SWalker b453aa23c2 fix ptx minwidth calculation for freepdk45 2023-10-31 23:24:21 -07:00
SWalker 5378a308c1 updated gitignore and regression make to ignore gf180. Fixed issue with rom decoder routing 2023-10-31 23:24:21 -07:00
Hadir Khan bd9ebc3300 updated the spice file 2023-10-31 23:24:21 -07:00
hadirkhan10 561e0c228c updated the cell name for layout and schematic 2023-10-31 23:24:21 -07:00
hadirkhan10 4b4153bdea renamed the gds and sp file to reflect the cell name 2023-10-31 23:24:21 -07:00
hadirkhan10 98a4210b06 added the gds and spice of the bitcell 2023-10-31 23:24:21 -07:00
hadirkhan10 042bfcabea added the custom cell definition 2023-10-31 23:24:21 -07:00
Hadir Khan b65ebc6160 corrected the import statement and removed strap variant attribute which is no longer needed 2023-10-31 23:24:21 -07:00
SWalker 1f35855c6d remove old rom test 2023-10-31 23:24:21 -07:00
SWalker 9b99e6c124 bunch of cleanups to core rom classes 2023-10-31 23:24:21 -07:00
SWalker ddba3b3718 move vdd pins around to make routing nice 2023-10-31 23:24:21 -07:00
SWalker 5c22e382b5 add parameter to make routing horizonal vdd rails easier 2023-10-31 23:24:21 -07:00
SWalker 4b3af38727 change min rail to contact spacing for long gf180 contact extend 2023-10-31 23:24:21 -07:00
SWalker 565e3f6814 flatten ptx in extraction and renumber test based on importance 2023-10-31 23:24:21 -07:00
SWalker 3271c5e73c fixing drc on rom bank, mostly spacing tweaks 2023-10-31 23:24:21 -07:00
SWalker 75f7a5847f fixing contact placement for gf180 in rom 2023-10-31 23:24:21 -07:00
Sage Walker b279791762 added control buf test 2023-10-31 23:24:21 -07:00
SWalker a544abebf7 fixed contact area issue 2023-10-31 23:24:21 -07:00
SWalker 20d0df2947 more boundary on the other side 2023-10-31 23:24:21 -07:00
Sage Walker cb8567c66f spacing tweaks for gf180 address control gate 2023-10-31 23:24:21 -07:00
SWalker d940c0e03d little more boundary 2023-10-31 23:24:21 -07:00
SWalker 23611f8fac little more nwell 2023-10-31 23:24:21 -07:00
SWalker e3b51360f3 extend nwell on nand 2023-10-31 23:24:21 -07:00
SWalker ea703d124f switched input pins on nand 2023-10-31 23:24:21 -07:00
SWalker 07fa78e00c boundary shift for implant spacing 2023-10-31 23:24:21 -07:00
SWalker dba75fc57c boundary and alignment of nand 2023-10-31 23:24:21 -07:00
SWalker 9ac94d1744 even more nand 2023-10-31 23:24:21 -07:00
SWalker 0aa9c47f89 more nand 2023-10-31 23:24:21 -07:00
SWalker 8ac30f4ef5 proper gds for nand 2023-10-31 23:24:21 -07:00
SWalker 416140d04a nand dup pin 2023-10-31 23:24:21 -07:00
SWalker 8c56478df3 more nand tweaks 2023-10-31 23:24:21 -07:00
SWalker 13459cb6dd boundary box tweaks on dec nand 2023-10-31 23:24:21 -07:00
SWalker 88782b0a58 rotated nand2_dec 2023-10-31 23:24:21 -07:00
SWalker 4bb586c949 decoder nand custom cell 2023-10-31 23:24:21 -07:00
Sage Walker d6cb15c82d Switched to GF180D for extra metal layers, Fixed drc parameters so contacts are valid. ptx.py modified to achieve proper layer placement with gf180. ROM array and precharge DRC clean. 2023-10-31 23:24:21 -07:00
Sage Walker 0040efb86f workaround for magic drc in gf180 2023-10-31 23:24:21 -07:00
Sage Walker b0a0226e87 rom array compatability changes 2023-10-31 23:24:21 -07:00
Sage Walker 1255a81487 ROM binary file support 2023-10-31 23:24:21 -07:00
Sage Walker c09a981734 make pdk uses conda for gf180 with configure options for local pdk sources 2023-10-31 23:24:21 -07:00
Hadir Khan 698020301c updates to add the port order overwrite attribute, ignore drc/lvs attribute and pwell as a non-routing layer 2023-10-31 23:24:21 -07:00
Hadir Khan 7ce11eba52 added pwell as a non-routing layer 2023-10-31 23:24:21 -07:00
hadirkhan10 b9fd172e44 corrected the pin mapping 2023-10-31 23:24:21 -07:00
hadirkhan10 de7a248ff0 added the cell property definitions 2023-10-31 23:24:21 -07:00
Hadir Khan 81b62ab13b added gf180mcu as the test tech target 2023-10-31 23:24:21 -07:00
Hadir Khan 8a5b0b4898 updated the open_pdks commit and added the gf180 pdk build target 2023-10-31 23:24:21 -07:00
Jesse Cirimelli-Low a904874978 passing gf180 parameterized gate tests 2023-10-31 23:24:21 -07:00
Jesse Cirimelli-Low d18a4f8c7c additional tech commits 2023-10-31 23:24:21 -07:00
Jesse Cirimelli-Low a18d62c430 rename gf180 to gf180mcu 2023-10-31 23:24:21 -07:00
mrg 06058e1b87 Initial files for gf180 2023-10-31 23:24:21 -07:00
vlsida-bot decfd7ff4f Bump version: 1.2.40 -> 1.2.41 2023-11-01 02:31:22 +00:00
Jesse Cirimelli-Low 788d7e5474 fix VPB/VNB pins not being found 2023-10-31 18:07:35 -07:00
vlsida-bot 3113798b13 Bump version: 1.2.39 -> 1.2.40 2023-10-06 02:12:26 +00:00
Eren Dogan fe379297be Add timestamps to the log file 2023-10-05 14:55:05 -07:00
vlsida-bot 6a6ac026db Bump version: 1.2.38 -> 1.2.39 2023-09-28 19:50:40 +00:00
Sam Crow a5412902c6 all control logic tests pass now 2023-09-27 16:38:57 -07:00
vlsida-bot 1b13d4369e Bump version: 1.2.37 -> 1.2.38 2023-09-27 23:25:24 +00:00
Sam Crow bf49ea744e force multi-delay chain pinouts to be user configurable 2023-09-27 13:15:45 -07:00
vlsida-bot c47ec37473 Bump version: 1.2.36 -> 1.2.37 2023-09-26 20:04:03 +00:00
Sam Crow 0a3889a2a6 Revert "use new magic version with drc catchup fix"
This reverts commit ad2468cc26.
2023-09-26 11:37:34 -07:00
Sam Crow 5b282df667 Revert "add drc style drc(full) to run_drc.sh on Tim Edwards recommondation"
This reverts commit c4a14b9354.
2023-09-26 11:37:04 -07:00
Sam Crow c4a14b9354 add drc style drc(full) to run_drc.sh on Tim Edwards recommondation 2023-09-25 14:14:27 -07:00
Sam Crow ad2468cc26 use new magic version with drc catchup fix 2023-09-25 14:08:38 -07:00
vlsida-bot 2e55385cd6 Bump version: 1.2.35 -> 1.2.36 2023-09-20 23:25:59 +00:00
Eren Dogan 3b6cc2f3a8 Hardcode tool versions in install_conda.sh 2023-09-20 14:58:58 -07:00
vlsida-bot 1a8c27c549 Bump version: 1.2.34 -> 1.2.35 2023-09-09 22:09:16 +00:00
Eren Dogan b3e1a163d0 Fix derouting wires in the gridless router 2023-09-09 13:32:16 -07:00
vlsida-bot 9c66473cc9 Bump version: 1.2.33 -> 1.2.34 2023-09-07 06:07:59 +00:00
Eren Dogan 995cc4f60f Fix typo 2023-09-06 21:38:19 -07:00
Eren Dogan 099869d4c9 Fix typos 2023-09-03 18:35:07 -07:00
Eren Dogan 3f2d61a0fa Prevent same file error when copying the config file (VLSIDA/PrivateRAM#108) 2023-09-03 18:21:31 -07:00
vlsida-bot 1a25fcf9a5 Bump version: 1.2.32 -> 1.2.33 2023-09-02 18:43:35 +00:00
Eren Dogan abb12bd785 Increase non-preferred direction cost in router 2023-09-02 08:00:58 -07:00
Eren Dogan 775922774a Use bbox trees to iterate over shapes in routing region efficiently 2023-09-01 20:37:07 -07:00
Eren Dogan d9004f6de6 Print more info for the routing processes 2023-08-31 19:03:31 -07:00
Eren Dogan 8a60684e51 Increase the routing region inflation to be safer 2023-08-31 18:26:45 -07:00
Eren Dogan a9e63efad7 Increase via cost in router 2023-08-31 18:26:04 -07:00
vlsida-bot b281771753 Bump version: 1.2.31 -> 1.2.32 2023-08-30 16:52:07 +00:00
Eren Dogan 56bee27ee3 Don't write/read gds files unnecessarily for router 2023-08-29 21:45:52 -07:00
vlsida-bot b525ba60a0 Bump version: 1.2.30 -> 1.2.31 2023-08-28 21:12:21 +00:00
Eren Dogan e12ab68362 Simplify closest edge calculation in signal escape router 2023-08-28 10:38:53 -07:00
Eren Dogan fa5de05be3 Merge branch 'dev' into gridless_router 2023-08-27 21:17:58 -07:00
Eren Dogan 53cc99f5c1 Perform signal escape routing in smaller regions 2023-08-27 21:16:34 -07:00
Eren Dogan 9df3c2ac59 Return the path in source-to-target order 2023-08-27 21:15:25 -07:00
Eren Dogan 141a4e3380 Don't scale the routing region if no path is found 2023-08-27 15:42:09 -07:00
vlsida-bot 0ac2922573 Bump version: 1.2.29 -> 1.2.30 2023-08-26 22:17:23 +00:00
Jesse Cirimelli-Low ca5ca0c7a8 bump sram library commit to fix colenda gds 2023-08-26 15:29:08 -05:00
vlsida-bot 3eaf973d89 Bump version: 1.2.28 -> 1.2.29 2023-08-11 02:14:32 +00:00
Bugra Onal 230454d567 Merge changes from subprocess_fix 2023-08-10 16:21:45 -07:00
Bugra Onal 3f08c848d7 Force to use bash for simulators 2023-08-10 16:05:24 -07:00
vlsida-bot cc8161afc1 Bump version: 1.2.27 -> 1.2.28 2023-08-10 05:09:47 +00:00
Eren Dogan ea02aae40f Find blocked nodes and probes faster 2023-08-09 17:45:49 -07:00
Eren Dogan 9ac82060b9 Simplify 'remove' attribute of graph_node 2023-08-08 11:54:12 -07:00
vlsida-bot ad05fde099 Bump version: 1.2.26 -> 1.2.27 2023-08-04 01:45:27 +00:00
Eren Dogan fa1b2fc96e Delete unused file 2023-08-02 21:54:45 -07:00
Eren Dogan f8b2c1e9b9 Change OPTS.route_supplies option since there's only one router now 2023-08-02 21:48:29 -07:00
Eren Dogan 8fff4e2635 Organize imports of the new router 2023-08-02 21:35:13 -07:00
Eren Dogan 54fc34392d Remove unnecessary imports 2023-08-02 21:28:21 -07:00
Eren Dogan e1d0902680 Cleanup the new router 2023-08-02 21:26:24 -07:00
Eren Dogan ba8e80d205 Replace layout pins in the new signal escape router 2023-08-02 19:33:48 -07:00
Eren Dogan 87eca6b7db Use the initial bbox to route supply and signals 2023-08-02 18:01:09 -07:00
Eren Dogan 08dad81214 Use the same inflating rules for all shapes in router 2023-08-02 17:48:56 -07:00
Eren Dogan 5b0f97860a Calculate bbox inside the router 2023-08-02 09:30:50 -07:00
Eren Dogan 937585d23c Route signals to the perimeter in sorted order 2023-08-01 21:17:43 -07:00
Eren Dogan 877f20e071 Use the new routers in ROMs 2023-08-01 19:10:02 -07:00
Eren Dogan 887a66553b Implement signal escape router using the new gridless router 2023-08-01 12:46:02 -07:00
Eren Dogan dd152da5c2 Change signal escape router's high-level function name 2023-08-01 11:26:25 -07:00
Eren Dogan 42257fb7f8 Export router_tech again 2023-08-01 11:25:12 -07:00
Eren Dogan 993b47be4c Remove old routers from sram_1bank 2023-08-01 11:22:50 -07:00
Eren Dogan 93a6549539 Fix typo 2023-08-01 11:10:32 -07:00
Eren Dogan 6c70396a05 Remove grid-based routers and replace them with the gridless router 2023-08-01 10:59:55 -07:00
Eren Dogan da24c52c52 Cleanup graph router 2023-07-31 21:49:14 -07:00
Eren Dogan db2a276077 Split graph router class to use it for signal escaping later 2023-07-31 19:43:09 -07:00
Eren Dogan 7be6f2783b Refix logic mistake in graph router 2023-07-31 12:24:31 -07:00
Eren Dogan 4b2659a5e2 Fix another logic typo 2023-07-30 18:27:17 -07:00
Eren Dogan 5cf774b53e Remove unnecessary lines 2023-07-30 10:09:13 -07:00
Eren Dogan e5bc7b4e95 Fix logic typo 2023-07-30 10:08:57 -07:00
Eren Dogan d487f788e3 Add constant cost for all non-preferred edges 2023-07-29 21:48:33 -07:00
Eren Dogan 821c763a1e Cleanup graph router 2023-07-29 20:01:58 -07:00
Eren Dogan 3b0997e7cf Implement custom add_route() for the graph router 2023-07-29 08:18:49 -07:00
Eren Dogan 4c73d3aa7c Use safe regions to protect pin nodes 2023-07-29 08:17:00 -07:00
Eren Dogan 091d0f8775 Convert pins and blockages for graph router 2023-07-26 21:46:30 -07:00
Eren Dogan 8522e0108c Add center nodes for existing vias 2023-07-26 21:45:35 -07:00
Eren Dogan 4d835e98b7 Simplify merging new shapes in graph router 2023-07-26 16:44:57 -07:00
Eren Dogan 53505e2ed2 Add "pin safe" functionality to is_node_blocked() 2023-07-26 16:41:46 -07:00
Eren Dogan d609ef9243 Make sure via probes can also be blocked by other blockages 2023-07-25 22:21:26 -07:00
Eren Dogan 62a04ce874 Add get_lpp() function to router_tech 2023-07-25 21:01:32 -07:00
Eren Dogan 54ce1377c5 Merge branch 'dev' into gridless_router 2023-07-25 20:03:59 -07:00
vlsida-bot b1f4f0887e Bump version: 1.2.25 -> 1.2.26 2023-07-26 01:44:26 +00:00
Eren Dogan 6cda5415a4 Try routing in larger regions if no path is found 2023-07-25 18:40:07 -07:00
Bugra Onal 1de6b9a0f6 Add func random seed as input option and log out 2023-07-25 13:06:31 -07:00
Eren Dogan ed404a3ad2 Rename 'inflated_from' to 'core' 2023-07-25 10:26:23 -07:00
Eren Dogan 47185f6085 Generate cartesian values for pins correctly 2023-07-25 10:18:43 -07:00
Eren Dogan 587d44e536 Include pins as blockages properly 2023-07-24 21:15:15 -07:00
Eren Dogan 2b15289daf Enable power routing for failing FreePDK45 tests (VLSIDA/PrivateRAM#97) 2023-07-24 19:21:31 -07:00
Eren Dogan fa74a45d8c Fix spacing rule for wider blockages 2023-07-24 13:08:02 -07:00
Eren Dogan 5de7b9cda7 Make graph router the default supply router 2023-07-24 13:07:43 -07:00
Eren Dogan 947e94323d Cleanup graph router 2023-07-24 08:03:08 -07:00
Eren Dogan 54f2e73214 Simplify inflating shapes in graph router 2023-07-23 21:09:15 -07:00
Eren Dogan 7119f9a131 Fix spacing rule for non-max-width layer in router_tech 2023-07-23 18:45:02 -07:00
Eren Dogan 542e1a5e03 Use half pin's size difference for new spacing rule 2023-07-23 18:43:26 -07:00
Eren Dogan a90fd36f57 Change spacing rule for pins 2023-07-23 10:43:02 -07:00
Eren Dogan 7a7ddebcca Add more spacing to inflated pins to prevent unroutables 2023-07-23 10:22:43 -07:00
Eren Dogan 1c274afa46 Include blockages in the routing area after generating nodes 2023-07-22 21:30:40 -07:00
Eren Dogan 06b8f3b2be Prevent supply ring from overlapping existing pins 2023-07-22 19:25:26 -07:00
Eren Dogan 48b556c43a Fix even more DRC errors in graph router 2023-07-22 14:07:27 -07:00
vlsida-bot ecd486e050 Bump version: 1.2.24 -> 1.2.25 2023-07-22 02:19:20 +00:00
Bugra Onal f86d1dbdf9 Add spare col changes to characterizer 2023-07-21 17:20:02 -07:00
Eren Dogan 8354de654f Fix precision of blockage node centers 2023-07-21 12:24:20 -07:00
Eren Dogan 3e3265c416 Add new snap_to_grid function for graph router 2023-07-21 09:55:36 -07:00
Eren Dogan 44b2e4589c Don't use multiple when inflating shapes 2023-07-21 08:30:46 -07:00
Eren Dogan 7ee1dcef54 Simplify inflated_from logic 2023-07-21 08:26:54 -07:00
Bugra Onal 93182d525d Added sky130 golden spice file 2023-07-20 15:20:15 -07:00
Bugra Onal 5b1544ad45 Sky130 tests will use 1 spare row and col 2023-07-20 15:18:32 -07:00
vlsida-bot 7aceadf9ba Bump version: 1.2.23 -> 1.2.24 2023-07-20 18:48:38 +00:00
Bugra Onal 78e5b60380 Fix fake_sram bit sizes 2023-07-20 10:43:09 -07:00
mrg f800b50813 Fix wrong bit size in fake_sram. 2023-07-20 10:11:49 -07:00
vlsida-bot f246e5a521 Bump version: 1.2.22 -> 1.2.23 2023-07-20 01:33:51 +00:00
Eren Dogan 5ce193c2dd Snap node vectors to grid to prevent precision errors 2023-07-19 18:32:22 -07:00
Bugra Onal 6751442d35 account for spare cols in char 2023-07-19 16:09:28 -07:00
Sam Crow 2051f54f70 Merge branch 'STA-refactor' into dev 2023-07-19 15:14:20 -07:00
Bugra Onal 0b2196a3e4 cleaned logs 2023-07-19 14:50:49 -07:00
Sam Crow 6e3e964c12 cleanup net_spice docstrings 2023-07-19 12:45:41 -07:00
Sam Crow f41537b508 Merge branch 'char' into STA-refactor 2023-07-19 12:35:22 -07:00
Sam Crow b30dfa03e7 Merge branch 'dev' into STA-refactor 2023-07-19 12:19:28 -07:00
Sam Crow 2ced895b32 add BIAS pin type back to valid types 2023-07-19 12:15:47 -07:00
Sam Crow c67fdd8bd8 fix insts typo 2023-07-19 12:15:21 -07:00
Bugra Onal d53353b5be Merge branch 'dev' into char 2023-07-19 12:06:34 -07:00
Bugra Onal 9fa25690ce Added pins for spare_cols 2023-07-19 11:35:09 -07:00
Sam Crow 2b9e70d318 remove line ending whitespace from comment 2023-07-19 10:51:19 -07:00
Eren Dogan e8c3cf0a94 Remove nodes inside routables that can cause DRC errors 2023-07-18 22:36:14 -07:00
Eren Dogan 44e21dacba Merge branch 'dev' into gridless_router 2023-07-18 22:35:48 -07:00
vlsida-bot 5dbc22091c Bump version: 1.2.21 -> 1.2.22 2023-07-19 00:29:46 +00:00
Sam Crow bfabe64f33 fix pin/net dictionary deepcopy-ing 2023-07-18 16:14:38 -07:00
Sam Crow 09aa395174 cast pins dict to list 2023-07-18 16:13:29 -07:00
Sam Crow 5907cbb3e2 remove pins overwrite from contact class 2023-07-18 16:12:42 -07:00
mrg 54c2710aea Add OPENRAM_TMP back to macro Makefiles to save results. 2023-07-18 15:45:15 -07:00
vlsida-bot 3ef61a298f Bump version: 1.2.20 -> 1.2.21 2023-07-18 22:18:17 +00:00
Sam Crow aa71785bd5 fix circular import with pin and net 2023-07-18 11:28:30 -07:00
mrg 699f7b311e Add DIRS back to Makefile so we can use targets without .ok extension. 2023-07-18 10:58:04 -07:00
Sam Crow 478c76c1ca get connections from spice objects in instances 2023-07-18 10:50:50 -07:00
mrg 148d80531e Add fetch to remove error when re-installing PDK cells. 2023-07-18 10:48:22 -07:00
Eren Dogan 53d00f5b34 Merge branch 'dev' into gridless_router 2023-07-18 10:00:00 -07:00
Eren Dogan 5ef964d01f Merge branch 'dev' into gridless_router 2023-07-18 09:31:20 -07:00
vlsida-bot 7bd312faff Bump version: 1.2.19 -> 1.2.20 2023-07-18 00:59:02 +00:00
Sam Crow 8a441bc68b Merge branch 'dev' into STA-refactor 2023-07-17 16:35:31 -07:00
Eren Dogan b5983fbfd6 Prevent via DRC errors 2023-07-17 16:30:19 -07:00
Sam Crow b1b6886bac Merge branch 'delay_ctrl' into dev 2023-07-17 16:05:57 -07:00
Sam Crow 45b88889e4 use pin and net objects in connect_inst 2023-07-17 16:04:56 -07:00
Eren Dogan 6e051e7f06 Avoid DRC errors when routing the same type of pin 2023-07-17 15:43:48 -07:00
Sam Crow d0339a90e6 change spice_nets and spice_pins to dicts 2023-07-17 15:36:57 -07:00
Sam Crow e15feb2361 change nets list to dictionary 2023-07-17 15:36:22 -07:00
Sam Crow 7581df2255 change pins to OrderedDict 2023-07-17 15:22:35 -07:00
Eren Dogan 38110a55e1 Connect graph nodes better by hopping over removed nodes 2023-07-17 15:02:36 -07:00
Eren Dogan e501e0ef4f Cleanup graph for gridless router 2023-07-16 20:41:58 -07:00
Eren Dogan 983cf13ccf Fix spacing for gridless router 2023-07-16 20:25:15 -07:00
Sam Crow c8c43f75d9 add spice nets and a way to connect them to pins 2023-07-14 16:18:10 -07:00
Sam Crow 146efc5070 implement pin_spice object 2023-07-13 16:45:05 -07:00
Eren Dogan 094e71764a Change option name for the gridless router 2023-07-13 12:16:58 -07:00
Eren Dogan 71e4a5ab6c Rename gridless router files 2023-07-13 12:07:55 -07:00
Eren Dogan 813a67fea9 Add more comments for gridless router 2023-07-13 11:29:51 -07:00
Bugra Onal 833d4c12a6 skip 30_tests for sky130 2023-07-11 10:15:26 -07:00
vlsida-bot 37b7de4653 Bump version: 1.2.18 -> 1.2.19 2023-07-11 00:25:28 +00:00
Sam Crow 89d8441108 Merge branch 'dev' into delay_ctrl 2023-07-10 14:31:26 -07:00
Samuel Crow 042a3ed14f
skip non-scmos delay control tests for now 2023-07-10 14:28:19 -07:00
Bugra Onal ed0c93ba55 Only add drc errors from compiler 2023-07-10 14:05:44 -07:00
Bugra Onal eddc9af45b Merge branch 'dev' into char 2023-07-10 13:55:50 -07:00
Sam Crow 4e649aad6b fix typo bug in spice comments code 2023-07-10 13:21:24 -07:00
Jesse Cirimelli-Low 513c7e9f71 update sram library commit 2023-07-10 13:12:13 -07:00
Bugra Onal 0ad619f04c Added bl, sen and cell format options 2023-07-10 12:32:58 -07:00
Eren Dogan 6b0b4c2def Create fake pins on the ring and route others to them 2023-07-10 09:24:16 -07:00
Eren Dogan 4a61874888 Add supply ring pins around the layout area 2023-07-09 18:53:21 -07:00
Bugra Onal 7220e0a483 sim_exe will be found everytime with func and char 2023-07-07 12:39:19 -07:00
Sam Crow b91c628acf Merge branch 'dev' into delay_ctrl 2023-07-06 08:45:03 -07:00
Sam Crow 468c972acb add optional guard band to delay chain sizing 2023-07-05 16:34:42 -07:00
Bugra Onal 071670bef0 Removed import global 2023-07-05 14:29:51 -07:00
Sam Crow d65ccfcc95 fix column mux without rbl start_bit to 0 2023-07-05 13:17:46 -07:00
Sam Crow b4a9784835 model vth delay swing delay 2023-07-05 12:17:48 -07:00
Sam Crow 5235cf9667 model p_en and wl_en delays in delay chain sizing 2023-07-03 17:02:11 -07:00
Eren Dogan bb35ac2f90 Include new wires while routing the pins 2023-07-03 14:04:26 -07:00
Eren Dogan 0938e7ec9a Fix probes not being blocked correctly 2023-07-03 13:34:27 -07:00
Eren Dogan 78be525ea0 Use minimum spanning tree to route same type of pins together 2023-07-01 16:14:56 -07:00
Sam Crow e1865083d7 incomplete work on improved delay modeling 2023-06-29 14:44:42 -07:00
Eren Dogan 5bf629f3e5 Prevent DRC violations for vdd and gnd pins 2023-06-28 20:55:49 -07:00
Sam Crow 91694fdae3 add fixme note for unit conversion 2023-06-28 14:05:42 -07:00
vlsida-bot 3620d56790 Bump version: 1.2.17 -> 1.2.18 2023-06-27 00:22:04 +00:00
Jesse Cirimelli-Low 14f8008c4f
Update index.md
fix typo in index.md
2023-06-26 15:37:42 -07:00
Sam Crow 28ea93bd0a convert 1-indexing to 0-indexing 2023-06-25 11:03:10 -07:00
Sam Crow 006eacd6d0 add pinout message output 2023-06-25 10:46:58 -07:00
vlsida-bot 3cd3a63419 Bump version: 1.2.16 -> 1.2.17 2023-06-24 16:55:37 +00:00
Eren Dogan 3ada5347eb Set shell in the Makefile 2023-06-23 20:59:28 -07:00
Eren Dogan 92c8770472 Fix publications 2023-06-23 20:38:49 -07:00
Sam Crow 8992c0fb68 first approximation of delay values 2023-06-20 16:22:03 -07:00
Eren Dogan a47bc7ebee Prevent multiple dog-legs in non-preferred direction 2023-06-15 11:08:13 -07:00
Sam Crow dbc9de6c9a implement relationship between delay pinouts 2023-06-14 17:10:07 -07:00
vlsida-bot 542df33878 Bump version: 1.2.15 -> 1.2.16 2023-06-14 23:14:13 +00:00
Gary Mejia 9a36cce7ae Fixed formatting on all files 2023-06-14 12:28:36 -07:00
Gary Mejia b9e61f346a Merge branch 'dev' into openROM-verilogoutput
To test recent changes with ROM verilog output
2023-06-14 12:26:07 -07:00
Gary Mejia a3284e8b47 Fixed module from writing syntax issues 2023-06-13 17:30:38 -07:00
Sam Crow bf516a927d add skeleton for delay chain sizing 2023-06-13 13:44:32 -07:00
Sam Crow fee90283b9 add spacing and a comment 2023-06-12 16:56:44 -07:00
Gary Mejia 692acd2066 Verilog ROM model created for testing 2023-06-12 15:35:54 -07:00
Sam Crow 96a1d400fa add single port bank test for norbl 2023-06-12 12:50:50 -07:00
Sam Crow 266bcd9cf2 consolidate failing xyce delay tests to one in skip list 2023-06-11 14:52:26 -07:00
Sam Crow 854bff9dce add norbl bank tests to sky130 skipped tests 2023-06-08 13:22:12 -07:00
Sam Crow 7048a072e2 add local/global array sky130 skipped tests 2023-06-08 13:16:27 -07:00
Sam Crow 44ed72b50d add has_rbl=True arg to tests 2023-06-08 13:10:03 -07:00
Sam Crow ce622952ef route rbl conditionally 2023-06-08 12:36:31 -07:00
Sam Crow a51b71d460 update copyright 2023-06-08 12:36:12 -07:00
Sam Crow 539dfc979a conform default behavior for sky130 custom modules to unit test 2023-06-07 17:31:12 -07:00
Sam Crow 973b5512f0 add new failing sky130 tests to skip list 2023-06-07 17:29:58 -07:00
Sam Crow dcf95460d0 sort sky130 skipped tests numerically 2023-06-07 16:09:18 -07:00
Sam Crow 9256ae8c00 fix typos and standardize multiport control logic tests 2023-06-07 16:04:54 -07:00
samuelkcrow afd3b782b9 remove cs_bar signal bus from all control logics 2023-06-07 15:53:15 -07:00
samuelkcrow a48842ff72 fix code format issues from 00 test 2023-06-07 15:52:25 -07:00
samuelkcrow b9492051b6 use control_logic_base in control_logic_delay 2023-06-07 15:51:19 -07:00
Sam Crow a70dcc5c85 reword comments in replica bitcell array module 2023-06-06 14:43:18 -07:00
Sam Crow 9fdf8a8341 ommit rbl pins in sram_1bank when appropriate 2023-06-06 13:15:17 -07:00
Sam Crow 157935c915 update test/module imports related to delay control 2023-06-06 13:12:20 -07:00
Eren Dogan 15b4e4dbe8 Fix DRC spacing in Hanan router 2023-06-05 19:33:45 -07:00
Sam Crow 5fef78dbfa Merge branch 'no_rbl' into delay_ctrl 2023-06-05 16:31:07 -07:00
Sam Crow 2f5d3b6faf Merge branch 'dev' into delay_ctrl 2023-06-05 16:24:48 -07:00
Sam Crow df827fbd3d add norbl whole sram test 2023-06-05 15:26:26 -07:00
Sam Crow 5b10f06be6 place wl_en pin on wl drivers in absence of rbl_wl driver 2023-06-05 15:26:11 -07:00
Sam Crow 0b5039cc89 make norbl bank test executable 2023-06-05 12:08:22 -07:00
Eren Dogan 48a148003a Include other pins as blockages in Hanan router 2023-06-05 11:27:05 -07:00
Sam Crow 23232fd376 Merge branch 'dev' into no_rbl 2023-06-05 11:03:22 -07:00
Eren Dogan 8f1af0ebb7 Reduce the number of shapes on Hanan paths 2023-06-04 10:56:50 -07:00
Eren Dogan 021da25cd6 Include all blockages inside the routing region 2023-06-04 08:46:59 -07:00
Eren Dogan 4fe5aa49e4 Reorganize utility functions for Hanan router 2023-06-01 14:24:40 -07:00
Eren Dogan e3d8ad13b2 Remove blocked Hanan node connections 2023-05-30 20:09:10 -07:00
Eren Dogan 2799c106bd Divide long code into sub-functions 2023-05-30 13:36:38 -07:00
Eren Dogan 136d4564a2 Use less memory when removing blocked Hanan points 2023-05-30 11:10:34 -07:00
Eren Dogan 9f75e68a92 Simplify Hanan graph generation 2023-05-29 21:49:00 -07:00
Eren Dogan 6079152092 Cleanup Hanan router 2023-05-29 12:43:43 -07:00
Eren Dogan e1e24f6d06 Rename gridless router 2023-05-29 09:18:55 -07:00
Eren Dogan 533c1c9472 Fix gridless router for tall and fat pins 2023-05-28 21:25:11 -07:00
Bugra Onal abd18ab832 Moved freepdk sense amp dout pin away from gnd pin 2023-05-23 15:08:06 -07:00
Bugra Onal 054b7cd47d Fixed code format 2023-05-23 13:47:02 -07:00
Bugra Onal f16a40af02 Renamed char and func unit tests 2023-05-23 13:46:05 -07:00
Bugra Onal 15c5e57d77 functional should use full sp file path 2023-05-23 10:58:43 -07:00
Bugra Onal e13cc76ac3 Fix Python 3.11 random change 2023-05-23 10:58:17 -07:00
Bugra Onal 6841de4a50 reflect the changes to sram.py from dev 2023-05-23 10:36:49 -07:00
Eren Dogan 33f1b924a4 Avoid blockages when connecting Hanan points 2023-05-22 18:16:49 -07:00
Eren Dogan 648a631a28 Use Hanan points to generate the routing graph 2023-05-22 13:08:21 -07:00
Bugra Onal 49efff3384 Added description for stand-alone characterizer 2023-05-16 16:44:58 -07:00
Bugra Onal 5cdecd781b Update functional script usage tip 2023-05-16 15:08:21 -07:00
Bugra Onal 217b0981a2 Use subprocess.run instead of subprocess.call 2023-05-16 15:07:31 -07:00
Bugra Onal b9123571f4 Fix functional script spice file name and unit test 2023-05-16 15:06:49 -07:00
Sam Crow 2709f61317 fix index out of bounds bug 2023-05-16 14:38:51 -07:00
Sam Crow 79e5c1ad86 add dp norbl bank test 2023-05-16 14:36:58 -07:00
Bugra Onal dbb8bb85cb Fixed golden values for ngspice delay tests 2023-05-15 16:28:35 -07:00
Eren Dogan cd339ebbd0 Add A* algorithm for navigation router 2023-05-09 13:23:01 -07:00
Eren Dogan 909ac6ce68 Add initial files for navigation router 2023-05-04 20:51:30 -07:00
Sage Walker bb8f3f7eb8 add rom to index 2023-05-03 21:12:09 -07:00
Sam Crow f5bc031d83 Merge branch 'dev' into no_rbl 2023-05-03 15:24:03 -07:00
Sam Crow 123149503b add a bank test with no rbl 2023-04-25 09:27:56 -07:00
Sam Crow 744ba0e892 fix precharge bit offsets in no rbl case 2023-04-25 09:24:18 -07:00
Sage Walker a5a0cffe65 basic rom usage info 2023-04-19 23:32:06 -07:00
Bugra Onal afe37e5915 sp file sram instance name fix 2023-04-19 18:57:38 -07:00
Bugra Onal b2b7e1fa4d fixed the test name 2023-04-19 18:51:34 -07:00
Bugra Onal 3f94e22860 Fixed memchar test output name 2023-04-19 18:44:09 -07:00
Bugra Onal 07411892c1 Moved memchar test tmp dir to results 2023-04-19 18:33:43 -07:00
Bugra Onal 44ca70bd16 Updated golden values for freepdk 2023-04-19 17:23:46 -07:00
Bugra Onal bd7b2c22c7 Added spice files for the command line char 2023-04-19 17:23:00 -07:00
Bugra Onal 7ed99278bd Sense amp fixes 2023-04-19 12:42:02 -07:00
Bugra Onal 6af9c556a9 Fix char tests 2023-04-19 12:41:39 -07:00
Bugra Onal 773ea1af0d include statement position fixed 2023-04-12 15:45:19 -07:00
Bugra Onal dae275c508 Merge branch 'dev' into char 2023-04-12 12:00:31 -07:00
Bugra Onal 027b93ab83 Added buff to sense_amp in freepdk45 2023-04-12 11:49:55 -07:00
Bugra Onal 0ff1d1a23d Added buff to sense_amp in scmos 2023-04-12 11:49:32 -07:00
Bugra Onal 8d0c46d069 Fix import issue 2023-04-12 11:48:20 -07:00
Sam Crow eea748ff3e remove test for unsupported config 2023-04-10 11:16:10 -07:00
Sam Crow 670b40642b add no rbl tests to 15 global array tests 2023-04-10 10:38:52 -07:00
Sam Crow dff94a032e fix bug in right rbl dual port replica array test 2023-04-07 11:30:15 -07:00
Sam Crow 5b701d828e remove unused function 2023-04-07 10:32:11 -07:00
Sam Crow 3c7f35d295 add no rbl support to bank module 2023-04-07 10:02:38 -07:00
Sam Crow efbb658784 add no rbl support to port address 2023-04-05 16:04:20 -07:00
Sam Crow ae6d271602 add support for no rbl to port data 2023-04-05 15:33:45 -07:00
Sam Crow d00ba73bc9 add no rbl support to global array 2023-04-05 14:47:15 -07:00
Sage Walker 7ed7ff4e9a fixed bug with tempdir in macros makefile 2023-04-03 17:06:09 -07:00
Sage Walker b2bcbddd01 ROM binary file support 2023-04-03 16:04:12 -07:00
Sam Crow 83b25138d0 apply 14* standard to 15_local tests 2023-04-03 10:11:49 -07:00
Sam Crow 9181f6a218 standardize 14* test structure 2023-04-03 10:08:57 -07:00
Sam Crow 299512eba2 standardize array tests 2023-03-22 18:56:52 -07:00
Sam Crow e20f28580f support no rbls in local array 2023-03-09 14:44:05 -08:00
Sam Crow 710f0fbae5 update local/global tests for no rbls 2023-03-09 14:37:07 -08:00
Sam Crow 41344a980b change array modules to allow rbl=[0, 0] 2023-03-09 10:23:28 -08:00
Sam Crow 7abaf0463e create no rbl no dummy tests 2023-03-09 10:05:17 -08:00
Bugra Onal 249d1b9c1d Moved sram_op and bit_polarity 2023-02-24 16:42:39 -08:00
Bugra Onal c447ec49eb Added the new import method 2023-02-23 15:14:39 -08:00
Bugra Onal 613146520e Merge branch 'library' into char 2023-02-23 15:11:39 -08:00
Bugra Onal f7f61fee27 Format fixes 2023-02-22 12:38:47 -08:00
Bugra Onal 6eb0ecd82b fixed copyright again 2023-02-21 14:07:08 -08:00
Bugra Onal 8650315179 Updated copyright headers 2023-02-21 13:52:21 -08:00
Bugra Onal bce71af0ad Moved main scripts to root dir 2023-02-21 13:51:13 -08:00
Bugra Onal 3496ac8f5a Added buffer to sense_amp output (need to resize) 2023-02-21 13:23:29 -08:00
Bugra Onal 6bdcdb8f37 Merge branch 'dev' into char 2023-02-21 13:00:47 -08:00
Bugra Onal 3b69cafde7 Update Xyce char tests 2023-02-17 19:15:14 -08:00
Bugra Onal 4436c61a39 discard if precharge delay is captured 2023-02-17 14:35:09 -08:00
Bugra Onal c8a06a1317 Properly trim wrapped instances 2023-02-17 14:27:15 -08:00
Bugra Onal 7a62ec0030 Fixed typo 2023-02-16 19:36:14 -08:00
Bugra Onal 9002a8ac70 Merge branch 'dev' into char 2023-02-14 15:05:27 -08:00
Bugra Onal 4ec2dd2d1f Format fixes 2023-02-14 12:44:57 -08:00
Bugra Onal b70f919a2b Characterize only nom corner 2023-02-14 12:01:14 -08:00
Bugra Onal 39104fa9d8 Delay measure always measure from clk neg edge 2023-02-06 14:13:56 -08:00
Bugra Onal 0d60c76e3b Fixed naming issues in trim_spice 2023-02-03 16:36:14 -08:00
Bugra Onal da86d50766 Guess the bitcell name format 2023-01-31 13:08:40 -08:00
Bugra Onal 5695cd69c6 removed html report requirement for sram_char.py 2023-01-31 13:08:13 -08:00
Bugra Onal 8de3be8529 Changed the standalone characterizer interface 2023-01-23 17:48:30 -08:00
Bugra Onal 149abe1dbd expose fake_sram to library 2023-01-23 17:44:38 -08:00
Bugra Onal 817dc8a063 Guess the bl format 2023-01-20 12:50:09 -08:00
Bugra Onal a7cbf254be Merge branch 'dev' into char 2023-01-19 12:18:38 -08:00
Bugra Onal bcb0f379fe Merge branch 'char' of github.com:VLSIDA/PrivateRAM into char 2023-01-19 11:40:13 -08:00
Bugra Onal 7fdc5cc782 modify char to work with older macro 2023-01-19 11:39:16 -08:00
Bugra Onal d27d77bcf8 fix din size in fake sram 2023-01-17 10:40:44 -08:00
Bugra Onal 8a67626e55 add back the characterizer to save function 2022-12-13 08:32:44 -08:00
Bugra Onal db85e8ecd6 standalone char and func 2022-12-13 07:53:58 -08:00
Bugra Onal c6485277f3 New import method into memchar script 2022-11-29 14:53:02 -08:00
Bugra Onal b9f16ea490 Merge branch 'dev' into char 2022-11-29 14:50:00 -08:00
Bugra Onal 816eff711d Recover function for measures 2022-11-29 14:48:35 -08:00
Bugra Onal 6603220258 Fake sram using sram class as base 2022-10-04 15:05:38 -07:00
Bugra Onal 2b79646b8f Merge branch 'dev' into char 2022-10-04 09:09:52 -07:00
Bugra Onal c6440dc16d restore netlist on memchar 2022-09-27 13:44:28 -07:00
Bugra Onal 2d8d90952e Fix measure functions 2022-09-14 14:34:50 -07:00
Bugra Onal 214f55f8d7 Save trimmed spice and stimulus 2022-09-14 14:34:22 -07:00
Bugra Onal b1e4c83373 Move measure functions from stimuli to measure 2022-09-09 12:51:53 -07:00
Bugra Onal b9dbad4750 Separate measure statements from stimulus 2022-09-09 11:48:13 -07:00
Bugra Onal fcfb9391f6 Code formatting 2022-09-01 16:19:14 -07:00
Bugra Onal 05ab45f39b Added graph store and read functionality 2022-08-30 09:15:35 -07:00
Bugra Onal d3753556c1 Pin generation instead of parsing 2022-08-18 21:09:48 -07:00
Bugra Onal eceb35f205 Skip graph exclusions on memchar 2022-08-18 20:38:09 -07:00
Bugra Onal 56879bf48b Cleanup 2022-08-18 20:35:34 -07:00
Bugra Onal f0a4665953 Add top process averness 2022-08-18 20:35:02 -07:00
Bugra Onal efd6da5300 Parse pins from HTML 2022-08-18 12:54:39 -07:00
Bugra Onal 9fba946f18 Characterizer use_model set to false 2022-08-18 12:54:09 -07:00
Bugra Onal f602c6b263 HTML parsing for fake_sram added 2022-08-12 23:29:33 -07:00
Bugra Onal bd6621cb88 Increase random value range by 1 2022-08-10 14:21:54 -07:00
Bugra Onal 3f941d2fff Copy over the CSV read function to fake_sram 2022-08-10 12:59:54 -07:00
Bugra Onal f8c80999bd Merge branch 'char' of github.com:VLSIDA/PrivateRAM into char 2022-08-10 12:31:13 -07:00
Bugra Onal c7975e3274 Use fake sram in memchar 2022-08-10 12:22:47 -07:00
Bugra Onal ae107b635f Enable datasheet generation by default 2022-08-10 12:22:47 -07:00
Bugra Onal 2101067e4a Characterizer options 2022-08-10 12:22:47 -07:00
Bugra Onal 219b29a833 Fake SRAM and Xyce RAW file option 2022-08-10 12:22:47 -07:00
samuelkcrow 8872a3e312 add tests 2022-08-10 12:22:47 -07:00
samuelkcrow 8d1d3c0e90 disable lvs/drc in char and func scripts 2022-08-10 12:22:47 -07:00
samuelkcrow e621890f78 force netlist only mode in memchar memfunc, rename char and func scripts, add description for func script 2022-08-10 12:22:47 -07:00
samuelkcrow 3e528a3e75 log sim result after func_sim 2022-08-10 12:22:47 -07:00
samuelkcrow 9e29391992 clarify file location message for user 2022-08-10 12:17:14 -07:00
mrg 2adab1ea1a Initial work on separate delay and func simulation 2022-08-10 12:14:47 -07:00
samuelkcrow ebe4393d66 reorder sram __init__() argument order for tests that rely on the order 2022-08-10 12:07:09 -07:00
samuelkcrow 34ee709c69 call create() function from sram/__init__ 2022-08-10 12:07:07 -07:00
samuelkcrow 2bbd293bf2 clarify file location message for user 2022-08-10 12:06:18 -07:00
samuelkcrow 8793dda40a characterizer and functional simulator working from command line 2022-08-10 12:06:18 -07:00
samuelkcrow e2a52ec0f3 Adding characterizer executable 2022-08-10 12:06:18 -07:00
mrg 28128157c0 Initial work on separate delay and func simulation 2022-08-10 12:06:14 -07:00
samuelkcrow f01e73328d remove superfluous imports from multiport test 2022-07-22 13:12:03 -07:00
samuelkcrow b82213caff use packages for imports in modules 2022-07-22 12:56:47 -07:00
samuelkcrow 480862c765 remove sys.path.append calls from tests 2022-07-22 11:24:54 -07:00
samuelkcrow 75efc476f7 add remaining tests 2022-07-21 19:35:02 -07:00
samuelkcrow 5fa0689c02 fix drc error in wlen_row 2022-07-21 19:35:02 -07:00
samuelkcrow 08ac1c176a connect in pin via m2 instead of m3, passes lvs now 2022-07-21 19:35:02 -07:00
samuelkcrow 12c58b0457 use spice names for delay chain output pins in layout 2022-07-21 19:35:02 -07:00
samuelkcrow 73021be8eb copy vertical bus spacing from control_logic.py 2022-07-21 19:35:02 -07:00
samuelkcrow 2611468dd7 replace route_supply with route supplies from control_logic.py 2022-07-21 19:35:02 -07:00
samuelkcrow 9182ad7c61 add m4 spacing for route_rails same as control_logic.py 2022-07-21 19:35:02 -07:00
samuelkcrow 7f52e63aca route glitch3 to inverter on wen row 2022-07-21 19:35:02 -07:00
samuelkcrow 231dca5b51 route w_en A and B inputs via M3, fix delay chain outputs connection to vertical bus 2022-07-21 19:35:02 -07:00
samuelkcrow 74bf3770d9 move pins to m3, route in pin down to avoid m3 collision 2022-07-21 19:35:02 -07:00
samuelkcrow 7567db6fe9 add rw port unit test for delay control 2022-07-21 19:35:02 -07:00
samuelkcrow 96046096b4 delete unnecessary dirs 2022-07-21 19:35:02 -07:00
samuelkcrow fd7a7c2564 routing mistake in route_wlen 2022-07-21 19:35:02 -07:00
samuelkcrow 1e1ec54275 fix indentation errors, typos, and missing iterator 2022-07-21 19:35:02 -07:00
samuelkcrow 3526a57864 don't route rbl to conrol logic 2022-07-21 19:35:02 -07:00
samuelkcrow 1d6bd78612 multi-delay layout pins and routing for them in control logic 2022-07-21 19:35:01 -07:00
samuelkcrow d7b1368115 all route functions except for delay 2022-07-21 19:35:01 -07:00
samuelkcrow 63ea1588c1 more consise glitch names, remove pre_sen from vertical bus, typo in glitch2 placement 2022-07-21 19:35:01 -07:00
samuelkcrow 0a3c1dd9b8 remove pre_sen entirely, move inverter to wl_en row, complete placement functions 2022-07-21 19:35:01 -07:00
samuelkcrow 7b4af87fda remove the cs_buf function call... smh 2022-07-21 19:35:01 -07:00
samuelkcrow 5edb511dab try it without pre_sen 2022-07-21 19:35:01 -07:00
samuelkcrow 71f241f660 remove remaining cs_buf functions 2022-07-21 19:35:01 -07:00
samuelkcrow 67c1560df0 forgot other place with cs_buf 2022-07-21 19:35:01 -07:00
samuelkcrow fede082b80 cs instead of cs_buf now that everything else is working 2022-07-21 19:35:01 -07:00
samuelkcrow 30b9c2fc25 remove glitch inverters from placement functions, move glitch1 to pen row 2022-07-21 19:35:01 -07:00
samuelkcrow 606260dd68 use odd number inverter chains from delay chain for delay instead of external inverters 2022-07-21 19:35:01 -07:00
samuelkcrow b9b57ab6b3 double length of delay chain as well 2022-07-21 19:35:01 -07:00
samuelkcrow 06254fae72 forgot to multiply all delay chain pinouts by 2 because of previous design that only exposed pins for even numbered inverters in delay chain... oops 2022-07-21 19:35:01 -07:00
samuelkcrow 1d0741baa4 temporariliy commenting out path code that's making simulation fail. 2022-07-21 19:35:01 -07:00
samuelkcrow ef2c9fe296 exclude rbl connection in sram base for delay control logic 2022-07-21 19:35:01 -07:00
samuelkcrow 7d4b718344 add most functions needed for delay control logic, fix multi-delay pin order issue 2022-07-21 19:35:01 -07:00
samuelkcrow 45239ca2a9 use cs_buf for sense amp on r ports instead of cs 2022-07-21 19:35:01 -07:00
samuelkcrow c4138c9f9b typo in cs buf netlist function 2022-07-21 19:35:01 -07:00
samuelkcrow 2b72fbee4e bug fix list vs set 2022-07-21 19:35:01 -07:00
samuelkcrow 11ea82e782 check delay chain pinout list, add cs_buf to control logic 2022-07-21 19:35:01 -07:00
samuelkcrow 78013d32b7 hard-code multi-delay stages 2022-07-21 19:35:01 -07:00
samuelkcrow 62a65f8053 all remaining spice for delay control 2022-07-21 19:35:01 -07:00
samuelkcrow 66502fc5dc new control logic module with no more rbl logic, added glitches so far 2022-07-21 19:35:01 -07:00
samuelkcrow b05a721fb5 spice for delay chain with all inverter outputs as pins 2022-07-21 19:35:01 -07:00
samuelkcrow e1fcd90b59 backing up spice attempts 2022-07-21 19:35:01 -07:00
Bugra Onal 471f68fab2 Characterizer options 2022-05-23 10:56:22 -07:00
Bugra Onal 9aafada1ab Fake SRAM and Xyce RAW file option 2022-05-19 09:07:45 -07:00
samuelkcrow 45df34c774 add tests 2022-04-21 13:06:13 -07:00
samuelkcrow 9ec87c4d52 disable lvs/drc in char and func scripts 2022-04-14 10:13:48 -07:00
samuelkcrow 06cd2620f5 force netlist only mode in memchar memfunc, rename char and func scripts, add description for func script 2022-04-14 10:04:07 -07:00
samuelkcrow 4514927a7b log sim result after func_sim 2022-03-09 09:43:00 -08:00
samuelkcrow 8bbe39f5d1 Merge branch 'char' of https://github.com/VLSIDA/PrivateRAM into char 2022-03-04 13:54:09 -08:00
samuelkcrow ef710eae7a reorder sram __init__() argument order for tests that rely on the order 2022-03-04 13:53:20 -08:00
samuelkcrow 043e93e75e call create() function from sram/__init__ 2022-03-04 13:47:09 -08:00
samuelkcrow b216552c3f clarify file location message for user 2022-03-04 13:47:09 -08:00
samuelkcrow a89cd4deee characterizer and functional simulator working from command line 2022-03-04 13:47:09 -08:00
samuelkcrow f9bec36da5 Adding characterizer executable 2022-03-04 13:47:09 -08:00
mrg 353ff7859c Initial work on separate delay and func simulation 2022-03-04 13:47:09 -08:00
samuelkcrow 1acc6be3ce call create() function from sram/__init__ 2022-03-02 16:38:39 -08:00
samuelkcrow 910980328c clarify file location message for user 2022-03-02 12:47:05 -08:00
samuelkcrow d47b5612d5 characterizer and functional simulator working from command line 2022-03-02 12:18:54 -08:00
samuelkcrow a87b2e9446 Adding characterizer executable 2022-03-01 15:12:03 -08:00
mrg dd2effd28d Initial work on separate delay and func simulation 2022-02-16 10:54:39 -08:00
581 changed files with 18791 additions and 5858 deletions

View File

@ -12,6 +12,9 @@ jobs:
steps: steps:
- name: Checkout code - name: Checkout code
uses: actions/checkout@v1 uses: actions/checkout@v1
- name: Install dependencies
run: |
pip3 install -r requirements.txt
- name: Library build - name: Library build
run: | run: |
rm -rf ~/.local/lib/python3.8/site-packages/openram* rm -rf ~/.local/lib/python3.8/site-packages/openram*
@ -24,8 +27,9 @@ jobs:
export OPENRAM_HOME="${{ github.workspace }}/compiler" export OPENRAM_HOME="${{ github.workspace }}/compiler"
export OPENRAM_TECH="${{ github.workspace }}/technology" export OPENRAM_TECH="${{ github.workspace }}/technology"
export PDK_ROOT="${{ github.workspace }}/pdk" export PDK_ROOT="${{ github.workspace }}/pdk"
make pdk # Add make targets to install PDKs of all technologies that need it
make install make sky130-pdk
make sky130-install
- name: Regress - name: Regress
run: | run: |
export OPENRAM_HOME="${{ github.workspace }}/compiler" export OPENRAM_HOME="${{ github.workspace }}/compiler"
@ -43,7 +47,7 @@ jobs:
make -k -j 48 make -k -j 48
- name: Archive - name: Archive
if: ${{ failure() }} if: ${{ failure() }}
uses: actions/upload-artifact@v2 uses: actions/upload-artifact@v4
with: with:
name: Regress Archives name: Regress Archives
path: ${{ github.workspace }}/compiler/tests/results/* path: ${{ github.workspace }}/compiler/tests/results/*

11
.gitignore vendored
View File

@ -13,13 +13,20 @@ outputs
technology/freepdk45/ncsu_basekit technology/freepdk45/ncsu_basekit
technology/sky130/*_lib technology/sky130/*_lib
technology/sky130/tech/.magicrc technology/sky130/tech/.magicrc
technology/gf180mcu/*_lib
.idea .idea
compiler/tests/results/ compiler/tests/results/
open_pdks/ open_pdks/
dist/ dist/
openram.egg-info/ openram.egg-info/
miniconda/ miniconda/
sky130A/ sky130A
sky130B/ sky130B
gf180mcuA
gf180mcuB
gf180mcuC
gf180mcuD
skywater-pdk/ skywater-pdk/
sky130_fd_bd_sram/ sky130_fd_bd_sram/
docker/openram-ubuntu.log
ciel/

View File

@ -3,6 +3,9 @@ include $(TOP_DIR)/openram.mk
.DEFAULT_GOAL := install .DEFAULT_GOAL := install
# Set the shell here
SHELL := /bin/bash
# Skywater PDK SRAM library # Skywater PDK SRAM library
SRAM_LIB_DIR ?= $(PDK_ROOT)/sky130_fd_bd_sram SRAM_LIB_DIR ?= $(PDK_ROOT)/sky130_fd_bd_sram
# Use this for release # Use this for release
@ -10,20 +13,27 @@ SRAM_LIB_GIT_REPO ?= https://github.com/vlsida/sky130_fd_bd_sram.git
# Use this for development # Use this for development
#SRAM_LIB_GIT_REPO ?= git@github.com:VLSIDA/sky130_fd_bd_sram.git #SRAM_LIB_GIT_REPO ?= git@github.com:VLSIDA/sky130_fd_bd_sram.git
#SRAM_LIB_GIT_REPO ?= https://github.com/google/skywater-pdk-libs-sky130_fd_bd_sram.git #SRAM_LIB_GIT_REPO ?= https://github.com/google/skywater-pdk-libs-sky130_fd_bd_sram.git
SRAM_LIB_GIT_COMMIT ?= a83b6468c48434d927b90058b22047843c58027b SRAM_LIB_GIT_COMMIT ?= dd64256961317205343a3fd446908b42bafba388
# Open PDKs
OPEN_PDKS_DIR ?= $(PDK_ROOT)/open_pdks
OPEN_PDKS_GIT_REPO ?= https://github.com/RTimothyEdwards/open_pdks.git
OPEN_PDKS_GIT_COMMIT ?= 1.0.311
#OPEN_PDKS_GIT_COMMIT ?= 7ea416610339d3c29af9d0d748ceadd3fd368608
SKY130_PDK ?= $(PDK_ROOT)/sky130A SKY130_PDK ?= $(PDK_ROOT)/sky130A
GF180_PDK ?= $(PDK_ROOT)/gf180mcuD
# Ciel SKY130 PDK
SKY130_CIEL = e8294524e5f67c533c5d0c3afa0bcc5b2a5fa066 # 2022.07.29
# Ciel GF180 PDK
GF180_CIEL = cd1748bb197f9b7af62a54507de6624e30363943 # 2023.12.04
# Skywater PDK # Skywater PDK
SKY130_PDKS_DIR ?= $(PDK_ROOT)/skywater-pdk SKY130_PDKS_DIR ?= $(PDK_ROOT)/skywater-pdk
SKY130_PDKS_GIT_REPO ?= https://github.com/google/skywater-pdk.git SKY130_PDKS_GIT_REPO ?= https://github.com/google/skywater-pdk.git
SKY130_PDKS_GIT_COMMIT ?= f70d8ca46961ff92719d8870a18a076370b85f6c SKY130_PDKS_GIT_COMMIT ?= f70d8ca46961ff92719d8870a18a076370b85f6c
# GF180 PDK
GF180_PDKS_DIR ?= $(PDK_ROOT)/gf180mcu-pdk
GF180_PDKS_GIT_REPO ?= https://github.com/google/gf180mcu-pdk.git
GF180_PDKS_GIT_COMMIT ?= main
# Create lists of all the files to copy/link # Create lists of all the files to copy/link
GDS_FILES := $(sort $(wildcard $(SRAM_LIB_DIR)/cells/*/*.gds)) GDS_FILES := $(sort $(wildcard $(SRAM_LIB_DIR)/cells/*/*.gds))
GDS_FILES := $(GDS_FILES) $(PDK_ROOT)/skywater-pdk/libraries/sky130_fd_sc_hd/latest/cells/dlxtn/sky130_fd_sc_hd__dlxtn_1.gds GDS_FILES := $(GDS_FILES) $(PDK_ROOT)/skywater-pdk/libraries/sky130_fd_sc_hd/latest/cells/dlxtn/sky130_fd_sc_hd__dlxtn_1.gds
@ -44,12 +54,11 @@ MAGICRC_FILE := $(SKY130_PDK)/libs.tech/magic/sky130A.magicrc
ALL_FILES := $(ALL_SPICE_FILES) $(GDS_FILES) $(MAG_FILES) $(MAGLEF_FILES) ALL_FILES := $(ALL_SPICE_FILES) $(GDS_FILES) $(MAG_FILES) $(MAGLEF_FILES)
INSTALL_BASE_DIRS := gds_lib mag_lib sp_lib lvs_lib calibre_lvs_lib klayout_lvs_lib maglef_lib INSTALL_BASE_DIRS := gds_lib mag_lib sp_lib lvs_lib calibre_lvs_lib klayout_lvs_lib maglef_lib
INSTALL_BASE := $(OPENRAM_HOME)/../technology/sky130 INSTALL_BASE := $(OPENRAM_HOME)/../technology/sky130
INSTALL_DIRS := $(addprefix $(INSTALL_BASE)/,$(INSTALL_BASE_DIRS)) INSTALL_DIRS := $(addprefix $(INSTALL_BASE)/,$(INSTALL_BASE_DIRS))
# If conda is installed, we will use Magic from there # If conda is installed, we will use ciel from there
CONDA_DIR := $(wildcard $(TOP_DIR)/miniconda) CONDA_DIR := $(wildcard $(TOP_DIR)/miniconda)
check-pdk-root: check-pdk-root:
@ -64,53 +73,55 @@ $(SKY130_PDKS_DIR): check-pdk-root
@git -C $(SKY130_PDKS_DIR) checkout $(SKY130_PDKS_GIT_COMMIT) && \ @git -C $(SKY130_PDKS_DIR) checkout $(SKY130_PDKS_GIT_COMMIT) && \
git -C $(SKY130_PDKS_DIR) submodule update --init libraries/sky130_fd_pr/latest libraries/sky130_fd_sc_hd/latest git -C $(SKY130_PDKS_DIR) submodule update --init libraries/sky130_fd_pr/latest libraries/sky130_fd_sc_hd/latest
$(OPEN_PDKS_DIR): $(SKY130_PDKS_DIR) $(GF180_PDKS_DIR): check-pdk-root
@echo "Cloning open_pdks..." @echo "Cloning gf PDK..."
@[ -d $(OPEN_PDKS_DIR) ] || \ @[ -d $(PDK_ROOT)/gf180mcu-pdk ] || \
git clone $(OPEN_PDKS_GIT_REPO) $(OPEN_PDKS_DIR) git clone https://github.com/google/gf180mcu-pdk.git $(PDK_ROOT)/gf180mcu-pdk
@git -C $(OPEN_PDKS_DIR) checkout $(OPEN_PDKS_GIT_COMMIT) @cd $(GF180_PDKS_DIR) && \
git checkout main && git pull && \
$(SKY130_PDK): $(OPEN_PDKS_DIR) $(SKY130_PDKS_DIR) git checkout -qf $(GF180_PDKS_GIT_COMMIT) && \
@echo "Installing open_pdks..." git submodule update --init libraries/gf180mcu_fd_pr/latest libraries/gf180mcu_fd_sc_mcu7t5v0/latest libraries/gf180mcu_fd_sc_mcu9t5v0/latest
ifeq ($(CONDA_DIR),"")
@cd $(PDK_ROOT)/open_pdks && \
./configure --enable-sky130-pdk=$(PDK_ROOT)/skywater-pdk/libraries --with-sky130-local-path=$(PDK_ROOT) && \
cd sky130 && \
make veryclean && \
make && \
make SHARED_PDKS_PATH=$(PDK_ROOT) install
else
@source $(TOP_DIR)/miniconda/bin/activate && \
cd $(PDK_ROOT)/open_pdks && \
./configure --enable-sky130-pdk=$(PDK_ROOT)/skywater-pdk/libraries --with-sky130-local-path=$(PDK_ROOT) && \
cd sky130 && \
make veryclean && \
make && \
make SHARED_PDKS_PATH=$(PDK_ROOT) install && \
conda deactivate
endif
$(SRAM_LIB_DIR): check-pdk-root $(SRAM_LIB_DIR): check-pdk-root
@echo "Cloning SRAM library..." @echo "Cloning SRAM library..."
@[ -d $(SRAM_LIB_DIR) ] || \ @[ -d $(SRAM_LIB_DIR) ] || \
git clone $(SRAM_LIB_GIT_REPO) $(SRAM_LIB_DIR) git clone $(SRAM_LIB_GIT_REPO) $(SRAM_LIB_DIR)
@git -C $(SRAM_LIB_DIR) fetch
@git -C $(SRAM_LIB_DIR) checkout $(SRAM_LIB_GIT_COMMIT) @git -C $(SRAM_LIB_DIR) checkout $(SRAM_LIB_GIT_COMMIT)
install: $(SRAM_LIB_DIR) sky130-install: $(SRAM_LIB_DIR)
@[ -d $(PDK_ROOT)/sky130A ] || \ @[ -d $(PDK_ROOT)/sky130A ] || \
(echo "Warning: $(PDK_ROOT)/sky130A not found!! Run make pdk first." && false) (echo "Warning: $(PDK_ROOT)/sky130A not found!! Run make sky130-pdk first." && false)
@[ -d $(PDK_ROOT)/skywater-pdk ] || \ @[ -d $(PDK_ROOT)/skywater-pdk ] || \
(echo "Warning: $(PDK_ROOT)/skywater-pdk not found!! Run make pdk first." && false) (echo "Warning: $(PDK_ROOT)/skywater-pdk not found!! Run make sky130-pdk first." && false)
@echo "Installing sky130 SRAM PDK..." @echo "Installing sky130 SRAM PDK..."
@echo "PDK_ROOT='$(PDK_ROOT)'" @echo "PDK_ROOT='$(PDK_ROOT)'"
@echo "SRAM_LIB_DIR='$(SRAM_LIB_DIR)'" @echo "SRAM_LIB_DIR='$(SRAM_LIB_DIR)'"
@echo "SKY130_PDK='$(SKY130_PDK)'" @echo "SKY130_PDK='$(SKY130_PDK)'"
@make $(INSTALL_DIRS) @make $(INSTALL_DIRS)
.PHONY: install .PHONY: sky130-install
pdk: $(SKY130_PDK) sky130-pdk: $(SKY130_PDKS_DIR)
@true @echo "Installing SKY130 via ciel..."
.PHONY: pdk ifeq ($(CONDA_DIR),)
ciel enable --pdk sky130 $(SKY130_CIEL)
else
source $(TOP_DIR)/miniconda/bin/activate && \
ciel enable --pdk sky130 $(SKY130_CIEL) && \
conda deactivate
endif
.PHONY: sky130-pdk
gf180mcu-pdk:
@echo "Installing GF180 via ciel..."
ifeq ($(CONDA_DIR),)
ciel enable --pdk gf180mcu $(GF180_CIEL)
else
source $(TOP_DIR)/miniconda/bin/activate && \
ciel enable --pdk gf180mcu $(GF180_CIEL) && \
conda deactivate
endif
.PHONY: gf180mcu-pdk
$(INSTALL_BASE)/gds_lib: $(GDS_FILES) $(INSTALL_BASE)/gds_lib: $(GDS_FILES)
@echo @echo

View File

@ -42,10 +42,6 @@ updating.
# Further Help # Further Help
+ [Documentation][documentation] + [Documentation][documentation]
+ [OpenRAM Slack Workspace][Slack]
+ [OpenRAM Users Group][user-group] ([subscribe here][user-group-subscribe])
+ [OpenRAM Developers Group][dev-group] ([subscribe here][dev-group-subscribe])
# License # License
@ -57,13 +53,13 @@ OpenRAM is licensed under the [BSD 3-Clause License](./LICENSE).
# Publications # Publications
+ [M. R. Guthaus, J. E. Stine, S. Ataei, B. Chen, B. Wu, M. Sarwar, "OpenRAM: An Open-Source Memory Compiler," Proceedings of the 35th International Conference on Computer-Aided Design (ICCAD), 2016.](https://escholarship.org/content/qt8x19c778/qt8x19c778_noSplash_b2b3fbbb57f1269f86d0de77865b0691.pdf) + [M. R. Guthaus, J. E. Stine, S. Ataei, B. Chen, B. Wu, M. Sarwar, "OpenRAM: An Open-Source Memory Compiler," Proceedings of the 35th International Conference on Computer-Aided Design (ICCAD), 2016.](https://escholarship.org/content/qt8x19c778/qt8x19c778_noSplash_b2b3fbbb57f1269f86d0de77865b0691.pdf)
+ [S. Ataei, J. Stine, M. Guthaus, A 64 kb differential single-port 12T SRAM design with a bit-interleaving scheme for low-voltage operation in 32 nm SOI CMOS, International Conference on Computer Design (ICCD), 2016, pp. 499-506.](https://escholarship.org/uc/item/99f6q9c9) + [S. Ataei, J. Stine, M. Guthaus, "A 64 kb differential single-port 12T SRAM design with a bit-interleaving scheme for low-voltage operation in 32 nm SOI CMOS," International Conference on Computer Design (ICCD), 2016, pp. 499-506.](https://escholarship.org/uc/item/99f6q9c9)
+ [E. Ebrahimi, M. Guthaus, J. Renau, “Timing Speculative SRAM”, IEEE International Symposium on Circuits and Systems (ISCAS), 2017.](https://escholarship.org/content/qt7nn0j5x3/qt7nn0j5x3_noSplash_172457455e1aceba20694c3d7aa489b4.pdf) + [E. Ebrahimi, M. Guthaus, J. Renau, "Timing Speculative SRAM," IEEE International Symposium on Circuits and Systems (ISCAS), 2017.](https://escholarship.org/content/qt7nn0j5x3/qt7nn0j5x3_noSplash_172457455e1aceba20694c3d7aa489b4.pdf)
+ [B. Wu, J.E. Stine, M.R. Guthaus, "Fast and Area-Efficient Word-Line Optimization", IEEE International Symposium on Circuits and Systems (ISCAS), 2019.](https://escholarship.org/content/qt98s4c1hp/qt98s4c1hp_noSplash_753dcc3e218f60aafff98ef77fb56384.pdf) + [B. Wu, J.E. Stine, M.R. Guthaus, "Fast and Area-Efficient Word-Line Optimization," IEEE International Symposium on Circuits and Systems (ISCAS), 2019.](https://escholarship.org/content/qt98s4c1hp/qt98s4c1hp_noSplash_753dcc3e218f60aafff98ef77fb56384.pdf)
+ [B. Wu, M. Guthaus, "Bottom Up Approach for High Speed SRAM Word-line Buffer Insertion Optimization", IFIP/IEEE International Conference on Very Large Scale Integration (VLSI-SoC), 2019.](https://ieeexplore.ieee.org/document/8920325) + [B. Wu, M. Guthaus, "Bottom Up Approach for High Speed SRAM Word-line Buffer Insertion Optimization," IFIP/IEEE International Conference on Very Large Scale Integration (VLSI-SoC), 2019.](https://ieeexplore.ieee.org/document/8920325)
+ [H. Nichols, M. Grimes, J. Sowash, J. Cirimelli-Low, M. Guthaus "Automated Synthesis of Multi-Port Memories and Control", IFIP/IEEE International Conference on Very Large Scale Integration (VLSI-SoC), 2019.](https://escholarship.org/content/qt7047n3k0/qt7047n3k0.pdf?t=q4gcij) + [H. Nichols, M. Grimes, J. Sowash, J. Cirimelli-Low, M. Guthaus "Automated Synthesis of Multi-Port Memories and Control," IFIP/IEEE International Conference on Very Large Scale Integration (VLSI-SoC), 2019.](https://escholarship.org/content/qt7047n3k0/qt7047n3k0.pdf?t=q4gcij)
+ [H. Nichols, "Statistical Modeling of SRAMs", M.S. Thesis, UCSC, 2022.](https://escholarship.org/content/qt7vx9n089/qt7vx9n089_noSplash_cfc4ba479d8eb1b6ec25d7c92357bc18.pdf?t=ra9wzr) + [M. Guthaus, H. Nichols, J. Cirimelli-Low, J. Kunzler, B. Wu, "Enabling Design Technology Co-Optimization of SRAMs though Open-Source Software," IEEE International Electron Devices Meeting (IEDM), 2020.](https://ieeexplore.ieee.org/stamp/stamp.jsp?arnumber=9372047)
+ [M. Guthaus, H. Nichols, J. Cirimelli-Low, J. Kunzler, B. Wu, "Enabling Design Technology Co-Optimization of SRAMs though Open-Source Software", IEEE International Electron Devices Meeting (IEDM), 2020.](https://ieeexplore.ieee.org/stamp/stamp.jsp?arnumber=9372047) + [H. Nichols, "Statistical Modeling of SRAMs," M.S. Thesis, UCSC, 2022.](https://escholarship.org/content/qt7vx9n089/qt7vx9n089_noSplash_cfc4ba479d8eb1b6ec25d7c92357bc18.pdf?t=ra9wzr)
@ -71,13 +67,13 @@ OpenRAM is licensed under the [BSD 3-Clause License](./LICENSE).
- [Matthew Guthaus] from [VLSIDA] created the OpenRAM project and is the lead architect. - [Matthew Guthaus] from [VLSIDA] created the OpenRAM project and is the lead architect.
- [James Stine] from [VLSIARCH] co-founded the project. - [James Stine] from [VLSIARCH] co-founded the project.
- Many students: Hunter Nichols, Michael Grimes, Jennifer Sowash, Yusu Wang, Joey Kunzler, Jesse Cirimelli-Low, Samira Ataei, Bin Wu, Brian Chen, Jeff Butera - Many students: Hunter Nichols, Michael Grimes, Jennifer Sowash, Yusu Wang, Joey Kunzler, Jesse Cirimelli-Low, Samira Ataei, Bin Wu, Brian Chen, Jeff Butera, Sage Walker
If I forgot to add you, please let me know! If I forgot to add you, please let me know!
[Matthew Guthaus]: https://users.soe.ucsc.edu/~mrg [Matthew Guthaus]: https://vlsida.github.io
[James Stine]: https://ece.okstate.edu/content/stine-james-e-jr-phd [James Stine]: https://ece.okstate.edu/content/stine-james-e-jr-phd
[VLSIDA]: https://vlsida.soe.ucsc.edu [VLSIDA]: https://vlsida.soe.ucsc.edu
[VLSIARCH]: https://vlsiarch.ecen.okstate.edu/ [VLSIARCH]: https://vlsiarch.ecen.okstate.edu/
@ -88,10 +84,6 @@ If I forgot to add you, please let me know!
[Github project]: https://github.com/VLSIDA/OpenRAM [Github project]: https://github.com/VLSIDA/OpenRAM
[documentation]: docs/source/index.md [documentation]: docs/source/index.md
[dev-group]: mailto:openram-dev-group@ucsc.edu
[user-group]: mailto:openram-user-group@ucsc.edu
[dev-group-subscribe]: mailto:openram-dev-group+subscribe@ucsc.edu
[user-group-subscribe]: mailto:openram-user-group+subscribe@ucsc.edu
[Klayout]: https://www.klayout.de/ [Klayout]: https://www.klayout.de/
[Magic]: http://opencircuitdesign.com/magic/ [Magic]: http://opencircuitdesign.com/magic/
@ -105,6 +97,5 @@ If I forgot to add you, please let me know!
[SCMOS]: https://www.mosis.com/files/scmos/scmos.pdf [SCMOS]: https://www.mosis.com/files/scmos/scmos.pdf
[Sky130]: https://github.com/google/skywater-pdk-libs-sky130_fd_bd_sram.git [Sky130]: https://github.com/google/skywater-pdk-libs-sky130_fd_bd_sram.git
[Slack]: https://join.slack.com/t/openram/shared_invite/zt-onim74ue-zlttW5XI30xvdBlJGJF6JA

View File

@ -1 +1 @@
1.2.15 1.2.49

View File

@ -1,11 +1,12 @@
# See LICENSE for licensing information. # See LICENSE for licensing information.
# #
# Copyright (c) 2016-2023 Regents of the University of California and The Board # Copyright (c) 2016-2024 Regents of the University of California and The Board
# of Regents for the Oklahoma Agricultural and Mechanical College # of Regents for the Oklahoma Agricultural and Mechanical College
# (acting for and on behalf of Oklahoma State University) # (acting for and on behalf of Oklahoma State University)
# All rights reserved. # All rights reserved.
# #
import os import os
import sys
# Attempt to add the source code to the PYTHONPATH here before running globals.init_openram() # Attempt to add the source code to the PYTHONPATH here before running globals.init_openram()

View File

@ -1,6 +1,6 @@
# See LICENSE for licensing information. # See LICENSE for licensing information.
# #
# Copyright (c) 2016-2023 Regents of the University of California, Santa Cruz # Copyright (c) 2016-2024 Regents of the University of California, Santa Cruz
# All rights reserved. # All rights reserved.
# #
""" """

View File

@ -1,6 +1,6 @@
# See LICENSE for licensing information. # See LICENSE for licensing information.
# #
# Copyright (c) 2016-2023 Regents of the University of California, Santa Cruz # Copyright (c) 2016-2024 Regents of the University of California, Santa Cruz
# All rights reserved. # All rights reserved.
# #
from .channel_route import * from .channel_route import *
@ -16,6 +16,7 @@ from .lef import *
from .logical_effort import * from .logical_effort import *
from .pin_layout import * from .pin_layout import *
from .power_data import * from .power_data import *
from .rom_verilog import *
from .route import * from .route import *
from .timing_graph import * from .timing_graph import *
from .utils import * from .utils import *

View File

@ -1,6 +1,6 @@
# See LICENSE for licensing information. # See LICENSE for licensing information.
# #
# Copyright (c) 2016-2023 Regents of the University of California and The Board # Copyright (c) 2016-2024 Regents of the University of California and The Board
# of Regents for the Oklahoma Agricultural and Mechanical College # of Regents for the Oklahoma Agricultural and Mechanical College
# (acting for and on behalf of Oklahoma State University) # (acting for and on behalf of Oklahoma State University)
# All rights reserved. # All rights reserved.

View File

@ -1,6 +1,6 @@
# See LICENSE for licensing information. # See LICENSE for licensing information.
# #
# Copyright (c) 2016-2023 Regents of the University of California and The Board # Copyright (c) 2016-2024 Regents of the University of California and The Board
# of Regents for the Oklahoma Agricultural and Mechanical College # of Regents for the Oklahoma Agricultural and Mechanical College
# (acting for and on behalf of Oklahoma State University) # (acting for and on behalf of Oklahoma State University)
# All rights reserved. # All rights reserved.
@ -10,7 +10,7 @@ from openram.tech import drc, layer, preferred_directions
from openram.tech import layer as tech_layers from openram.tech import layer as tech_layers
from .hierarchy_design import hierarchy_design from .hierarchy_design import hierarchy_design
from .vector import vector from .vector import vector
from .utils import ceil
class contact(hierarchy_design): class contact(hierarchy_design):
""" """
@ -41,7 +41,7 @@ class contact(hierarchy_design):
self.add_comment("implant type: {}\n".format(implant_type)) self.add_comment("implant type: {}\n".format(implant_type))
self.add_comment("well_type: {}\n".format(well_type)) self.add_comment("well_type: {}\n".format(well_type))
self.is_well_contact = implant_type == well_type self.is_well_contact = (implant_type == well_type) and implant_type is not None
# If we have a special tap layer, use it # If we have a special tap layer, use it
self.layer_stack = layer_stack self.layer_stack = layer_stack
@ -66,8 +66,6 @@ class contact(hierarchy_design):
self.offset = vector(0, 0) self.offset = vector(0, 0)
self.implant_type = implant_type self.implant_type = implant_type
self.well_type = well_type self.well_type = well_type
# Module does not have pins, but has empty pin list.
self.pins = []
self.create_layout() self.create_layout()
def create_layout(self): def create_layout(self):
@ -127,6 +125,8 @@ class contact(hierarchy_design):
self.first_layer_minwidth = drc("minwidth_{0}".format(self.first_layer_name)) self.first_layer_minwidth = drc("minwidth_{0}".format(self.first_layer_name))
self.first_layer_enclosure = drc("{0}_enclose_{1}".format(self.first_layer_name, self.via_layer_name)) self.first_layer_enclosure = drc("{0}_enclose_{1}".format(self.first_layer_name, self.via_layer_name))
self.first_layer_minarea = drc("minarea_{0}".format(self.first_layer_name))
# If there's a different rule for active # If there's a different rule for active
# FIXME: Make this more elegant # FIXME: Make this more elegant
if self.is_well_contact and self.first_layer_name == "active" and "tap_extend_contact" in drc.keys(): if self.is_well_contact and self.first_layer_name == "active" and "tap_extend_contact" in drc.keys():
@ -137,7 +137,7 @@ class contact(hierarchy_design):
self.second_layer_minwidth = drc("minwidth_{0}".format(self.second_layer_name)) self.second_layer_minwidth = drc("minwidth_{0}".format(self.second_layer_name))
self.second_layer_enclosure = drc("{0}_enclose_{1}".format(self.second_layer_name, self.via_layer_name)) self.second_layer_enclosure = drc("{0}_enclose_{1}".format(self.second_layer_name, self.via_layer_name))
self.second_layer_extend = drc("{0}_extend_{1}".format(self.second_layer_name, self.via_layer_name)) self.second_layer_extend = drc("{0}_extend_{1}".format(self.second_layer_name, self.via_layer_name))
self.second_layer_minarea = drc("minarea_{0}".format(self.second_layer_name))
# In some technologies, the minimum width may be larger # In some technologies, the minimum width may be larger
# than the overlap requirement around the via, so # than the overlap requirement around the via, so
# check this for each dimension. # check this for each dimension.
@ -168,7 +168,7 @@ class contact(hierarchy_design):
self.second_layer_vertical_enclosure = max(self.second_layer_enclosure, self.second_layer_vertical_enclosure = max(self.second_layer_enclosure,
(self.second_layer_minwidth - self.contact_array_width) / 2) (self.second_layer_minwidth - self.contact_array_width) / 2)
else: else:
debug.error("Invalid secon layer direction: ".format(self.directions[1]), -1) debug.error("Invalid second layer direction: ".format(self.directions[1]), -1)
def create_contact_array(self): def create_contact_array(self):
""" Create the contact array at the origin""" """ Create the contact array at the origin"""
@ -223,6 +223,18 @@ class contact(hierarchy_design):
first_layer_name = "tap" first_layer_name = "tap"
else: else:
first_layer_name = self.first_layer_name first_layer_name = self.first_layer_name
area = self.first_layer_width * self.first_layer_height
if area < self.first_layer_minarea and self.is_well_contact:
if self.directions[0] == "V":
area_extend = (self.first_layer_minarea / self.first_layer_width) - self.first_layer_height
self.first_layer_height = ceil(self.first_layer_height + area_extend)
self.first_layer_position = self.first_layer_position - vector(0, area_extend / 2)
elif self.directions[0] == "H":
area_extend = (self.first_layer_minarea / self.first_layer_height) - self.first_layer_width
self.first_layer_width = ceil(self.first_layer_height + area_extend)
self.first_layer_position = self.first_layer_position - vector(area_extend / 2, 0)
self.add_rect(layer=first_layer_name, self.add_rect(layer=first_layer_name,
offset=self.first_layer_position, offset=self.first_layer_position,
width=self.first_layer_width, width=self.first_layer_width,
@ -238,6 +250,7 @@ class contact(hierarchy_design):
self.second_layer_minwidth) self.second_layer_minwidth)
self.second_layer_height = max(self.contact_array_height + 2 * self.second_layer_vertical_enclosure, self.second_layer_height = max(self.contact_array_height + 2 * self.second_layer_vertical_enclosure,
self.second_layer_minwidth) self.second_layer_minwidth)
self.add_rect(layer=self.second_layer_name, self.add_rect(layer=self.second_layer_name,
offset=self.second_layer_position, offset=self.second_layer_position,
width=self.second_layer_width, width=self.second_layer_width,

View File

@ -1,6 +1,6 @@
# See LICENSE for licensing information. # See LICENSE for licensing information.
# #
# Copyright (c) 2016-2023 Regents of the University of California and The Board # Copyright (c) 2016-2024 Regents of the University of California and The Board
# of Regents for the Oklahoma Agricultural and Mechanical College # of Regents for the Oklahoma Agricultural and Mechanical College
# (acting for and on behalf of Oklahoma State University) # (acting for and on behalf of Oklahoma State University)
# All rights reserved. # All rights reserved.

View File

@ -1,6 +1,6 @@
# See LICENSE for licensing information. # See LICENSE for licensing information.
# #
# Copyright (c) 2016-2023 Regents of the University of California and The Board # Copyright (c) 2016-2024 Regents of the University of California and The Board
# of Regents for the Oklahoma Agricultural and Mechanical College # of Regents for the Oklahoma Agricultural and Mechanical College
# (acting for and on behalf of Oklahoma State University) # (acting for and on behalf of Oklahoma State University)
# All rights reserved. # All rights reserved.
@ -41,17 +41,17 @@ class design(hierarchy_design):
if prop and prop.hard_cell: if prop and prop.hard_cell:
# The pins get added from the spice file, so just check # The pins get added from the spice file, so just check
# that they matched here # that they matched here
debug.check(prop.port_names == self.pins, debug.check(prop.port_names == list(self.pins),
"Custom cell pin names do not match spice file:\n{0} vs {1}".format(prop.port_names, self.pins)) "Custom cell pin names do not match spice file:\n{0} vs {1}".format(prop.port_names, list(self.pins)))
self.add_pin_indices(prop.port_indices) self.add_pin_indices(prop.port_indices)
self.add_pin_names(prop.port_map) self.add_pin_names(prop.port_map)
self.add_pin_types(prop.port_types) self.update_pin_types(prop.port_types)
(width, height) = utils.get_libcell_size(self.cell_name, (width, height) = utils.get_libcell_size(self.cell_name,
GDS["unit"], GDS["unit"],
layer[prop.boundary_layer]) layer[prop.boundary_layer])
self.pin_map = utils.get_libcell_pins(self.pins, self.pin_map = utils.get_libcell_pins(list(self.pins),
self.cell_name, self.cell_name,
GDS["unit"]) GDS["unit"])
@ -126,5 +126,3 @@ class design(hierarchy_design):
for inst in self.insts: for inst in self.insts:
total_module_power += inst.mod.analytical_power(corner, load) total_module_power += inst.mod.analytical_power(corner, load)
return total_module_power return total_module_power

View File

@ -1,6 +1,6 @@
# See LICENSE for licensing information. # See LICENSE for licensing information.
# #
# Copyright (c) 2016-2023 Regents of the University of California, Santa Cruz # Copyright (c) 2016-2024 Regents of the University of California, Santa Cruz
# All rights reserved. # All rights reserved.
# #

View File

@ -1,6 +1,6 @@
# See LICENSE for licensing information. # See LICENSE for licensing information.
# #
# Copyright (c) 2016-2023 Regents of the University of California and The Board # Copyright (c) 2016-2024 Regents of the University of California and The Board
# of Regents for the Oklahoma Agricultural and Mechanical College # of Regents for the Oklahoma Agricultural and Mechanical College
# (acting for and on behalf of Oklahoma State University) # (acting for and on behalf of Oklahoma State University)
# All rights reserved. # All rights reserved.
@ -161,8 +161,8 @@ class geometry:
class instance(geometry): class instance(geometry):
""" """
An instance of an instance/module with a specified location and An instance of a module with a specified location, rotation,
rotation spice pins, and spice nets
""" """
def __init__(self, name, mod, offset=[0, 0], mirror="R0", rotate=0): def __init__(self, name, mod, offset=[0, 0], mirror="R0", rotate=0):
"""Initializes an instance to represent a module""" """Initializes an instance to represent a module"""
@ -176,6 +176,18 @@ class instance(geometry):
self.rotate = rotate self.rotate = rotate
self.offset = vector(offset).snap_to_grid() self.offset = vector(offset).snap_to_grid()
self.mirror = mirror self.mirror = mirror
# track if the instance's spice pin connections have been made
self.connected = False
# deepcopy because this instance needs to
# change attributes in these spice objects
self.spice_pins = copy.deepcopy(self.mod.pins)
self.spice_nets = copy.deepcopy(self.mod.nets)
for pin in self.spice_pins.values():
pin.set_inst(self)
for net in self.spice_nets.values():
net.set_inst(self)
if OPTS.netlist_only: if OPTS.netlist_only:
self.width = 0 self.width = 0
self.height = 0 self.height = 0
@ -274,6 +286,34 @@ class instance(geometry):
new_pins.append(p) new_pins.append(p)
return new_pins return new_pins
def connect_spice_pins(self, nets_list):
"""
add the connection between instance pins and module nets
to both of their respective objects
nets_list must be the same length as self.spice_pins
"""
if len(nets_list) == 0 and len(self.spice_pins) == 0:
# this is the only valid case to skip the following debug check
# because this with no pins are often connected arbitrarily
self.connected = True
return
debug.check(not self.connected,
"instance {} has already been connected".format(self.name))
debug.check(len(self.spice_pins) == len(nets_list),
"must provide list of nets the same length as pin list\
when connecting an instance")
for pin in self.spice_pins.values():
net = nets_list.pop(0)
pin.set_inst_net(net)
net.connect_pin(pin)
self.connected = True
def get_connections(self):
conns = []
for pin in self.spice_pins.values():
conns.append(pin.inst_net.name)
return conns
def calculate_transform(self, node): def calculate_transform(self, node):
#set up the rotation matrix #set up the rotation matrix
angle = math.radians(float(node.rotate)) angle = math.radians(float(node.rotate))

View File

@ -1,6 +1,6 @@
# See LICENSE for licensing information. # See LICENSE for licensing information.
# #
# Copyright (c) 2016-2023 Regents of the University of California and The Board # Copyright (c) 2016-2024 Regents of the University of California and The Board
# of Regents for the Oklahoma Agricultural and Mechanical College # of Regents for the Oklahoma Agricultural and Mechanical College
# (acting for and on behalf of Oklahoma State University) # (acting for and on behalf of Oklahoma State University)
# All rights reserved. # All rights reserved.
@ -135,11 +135,11 @@ class hierarchy_design(spice, layout):
# Translate port names to external nets # Translate port names to external nets
if len(port_nets) != len(self.pins): if len(port_nets) != len(self.pins):
debug.error("Port length mismatch:\nExt nets={}, Ports={}".format(port_nets, debug.error("Port length mismatch:\nExt nets={}, Ports={}".format(port_nets,
self.pins), list(self.pins)),
1) 1)
port_dict = {pin: port for pin, port in zip(self.pins, port_nets)} port_dict = {pin: port for pin, port in zip(list(self.pins), port_nets)}
debug.info(3, "Instance name={}".format(inst_name)) debug.info(3, "Instance name={}".format(inst_name))
for subinst, conns in zip(self.insts, self.conns): for subinst, conns in zip(self.insts, self.get_instance_connections()):
if subinst in self.graph_inst_exclude: if subinst in self.graph_inst_exclude:
continue continue
subinst_name = inst_name + "{}x".format(OPTS.hier_seperator) + subinst.name subinst_name = inst_name + "{}x".format(OPTS.hier_seperator) + subinst.name
@ -153,11 +153,11 @@ class hierarchy_design(spice, layout):
# Translate port names to external nets # Translate port names to external nets
if len(port_nets) != len(self.pins): if len(port_nets) != len(self.pins):
debug.error("Port length mismatch:\nExt nets={}, Ports={}".format(port_nets, debug.error("Port length mismatch:\nExt nets={}, Ports={}".format(port_nets,
self.pins), list(self.pins)),
1) 1)
port_dict = {pin: port for pin, port in zip(self.pins, port_nets)} port_dict = {pin: port for pin, port in zip(list(self.pins), port_nets)}
debug.info(3, "Instance name={}".format(inst_name)) debug.info(3, "Instance name={}".format(inst_name))
for subinst, conns in zip(self.insts, self.conns): for subinst, conns in zip(self.insts, self.get_instance_connections()):
subinst_name = inst_name + "{}x".format(OPTS.hier_seperator) + subinst.name subinst_name = inst_name + "{}x".format(OPTS.hier_seperator) + subinst.name
subinst_ports = self.translate_nets(conns, port_dict, inst_name) subinst_ports = self.translate_nets(conns, port_dict, inst_name)
for si_port, conn in zip(subinst_ports, conns): for si_port, conn in zip(subinst_ports, conns):
@ -186,7 +186,7 @@ class hierarchy_design(spice, layout):
""" """
# The final pin names will depend on the spice hierarchy, so # The final pin names will depend on the spice hierarchy, so
# they are passed as an input. # they are passed as an input.
pin_dict = {pin: port for pin, port in zip(self.pins, port_nets)} pin_dict = {pin: port for pin, port in zip(list(self.pins), port_nets)}
input_pins = self.get_inputs() input_pins = self.get_inputs()
output_pins = self.get_outputs() output_pins = self.get_outputs()
inout_pins = self.get_inouts() inout_pins = self.get_inouts()
@ -197,7 +197,7 @@ class hierarchy_design(spice, layout):
def __str__(self): def __str__(self):
""" override print function output """ """ override print function output """
pins = ",".join(self.pins) pins = ",".join(list(self.pins))
insts = [" {}".format(x) for x in self.insts] insts = [" {}".format(x) for x in self.insts]
objs = [" {}".format(x) for x in self.objs] objs = [" {}".format(x) for x in self.objs]
s = "********** design {0} **********".format(self.cell_name) s = "********** design {0} **********".format(self.cell_name)
@ -208,7 +208,7 @@ class hierarchy_design(spice, layout):
def __repr__(self): def __repr__(self):
""" override print function output """ """ override print function output """
text="( design: " + self.name + " pins=" + str(self.pins) + " " + str(self.width) + "x" + str(self.height) + " )\n" text="( design: " + self.name + " pins=" + str(list(self.pins)) + " " + str(self.width) + "x" + str(self.height) + " )\n"
for i in self.objs: for i in self.objs:
text+=str(i) + ",\n" text+=str(i) + ",\n"
for i in self.insts: for i in self.insts:

View File

@ -1,6 +1,6 @@
# See LICENSE for licensing information. # See LICENSE for licensing information.
# #
# Copyright (c) 2016-2023 Regents of the University of California and The Board # Copyright (c) 2016-2024 Regents of the University of California and The Board
# of Regents for the Oklahoma Agricultural and Mechanical College # of Regents for the Oklahoma Agricultural and Mechanical College
# (acting for and on behalf of Oklahoma State University) # (acting for and on behalf of Oklahoma State University)
# All rights reserved. # All rights reserved.
@ -22,7 +22,7 @@ from openram.sram_factory import factory
from openram import OPTS from openram import OPTS
from .vector import vector from .vector import vector
from .pin_layout import pin_layout from .pin_layout import pin_layout
from .utils import round_to_grid from .utils import round_to_grid, ceil
from . import geometry from . import geometry
try: try:
@ -187,7 +187,7 @@ class layout():
pass pass
# Skip computing the pitch for non-routing layers # Skip computing the pitch for non-routing layers
if layer_id in ["active", "nwell"]: if layer_id in ["active", "nwell", "pwell"]:
continue continue
# Add the pitch # Add the pitch
@ -259,8 +259,7 @@ class layout():
contact_width = contact1.first_layer_width contact_width = contact1.first_layer_width
layer_space = getattr(layout, layer1 + "_space") layer_space = getattr(layout, layer1 + "_space")
#print(layer_stack)
#print(contact1)
pitch = contact_width + layer_space pitch = contact_width + layer_space
return round_to_grid(pitch) return round_to_grid(pitch)
@ -629,7 +628,7 @@ class layout():
""" """
Return a pin list of all pins Return a pin list of all pins
""" """
return self.pins return list(self.pins)
def copy_layout_pin(self, instance, pin_name, new_name="", relative_offset=vector(0, 0)): def copy_layout_pin(self, instance, pin_name, new_name="", relative_offset=vector(0, 0)):
""" """
@ -838,8 +837,7 @@ class layout():
from_id = tech_layer_indices[from_layer] from_id = tech_layer_indices[from_layer]
to_id = tech_layer_indices[to_layer] to_id = tech_layer_indices[to_layer]
layer_list = [x for x in tech_layer_indices.keys() if tech_layer_indices[x] > from_id and tech_layer_indices[x] < to_id]
layer_list = [x for x in tech_layer_indices.keys() if tech_layer_indices[x] >= from_id and tech_layer_indices[x] < to_id]
return layer_list return layer_list
@ -944,14 +942,19 @@ class layout():
return (bot_rect, top_rect) return (bot_rect, top_rect)
def route_horizontal_pins(self, name, insts=None, layer=None, xside="cx", yside="cy", full_width=True): def route_horizontal_pins(self, name, insts=None, layer=None, xside="cx", yside="cy", full_width=True, new_name=None):
""" """
Route together all of the pins of a given name that horizontally align. Route together all of the pins of a given name that horizontally align.
Uses local_insts if insts not specified. Uses local_insts if insts not specified.
Uses center of pin by default, or top or botom if specified. Uses center of pin by default, or top or botom if specified.
New top level pin can be renamed with new_name, otherwise the new pin will keep the same name as old pins
TODO: Add equally spaced option for IR drop min, right now just 2 TODO: Add equally spaced option for IR drop min, right now just 2
""" """
if new_name is not None:
pin_name = new_name
else:
pin_name = name
bins = {} bins = {}
if not insts: if not insts:
@ -1016,7 +1019,8 @@ class layout():
# start=left_pos, # start=left_pos,
# end=right_pos, # end=right_pos,
# width=via_height) # width=via_height)
self.add_layout_pin_segment_center(text=name,
self.add_layout_pin_segment_center(text=pin_name,
layer=pin_layer, layer=pin_layer,
start=left_pos, start=left_pos,
end=right_pos, end=right_pos,
@ -1368,12 +1372,11 @@ class layout():
min_width = drc("minwidth_{}".format(layer)) min_width = drc("minwidth_{}".format(layer))
if preferred_directions[layer] == "V": if preferred_directions[layer] == "V":
new_height = max(min_area / width, min_width) new_height = ceil(max(min_area / width, min_width))
new_width = width new_width = width
else: else:
new_width = max(min_area / height, min_width) new_width = ceil(max(min_area / height, min_width))
new_height = height new_height = height
debug.check(min_area <= round_to_grid(new_height*new_width), "Min area violated.") debug.check(min_area <= round_to_grid(new_height*new_width), "Min area violated.")
self.add_rect_center(layer=layer, self.add_rect_center(layer=layer,
@ -1523,6 +1526,7 @@ class layout():
""" Return the pin shapes as blockages for non-top-level blocks. """ """ Return the pin shapes as blockages for non-top-level blocks. """
# FIXME: We don't have a body contact in ptx, so just ignore it for now # FIXME: We don't have a body contact in ptx, so just ignore it for now
import copy import copy
# FIXME: this may not work now that self.pins is a dict as defined in hierarchy_spice
pin_names = copy.deepcopy(self.pins) pin_names = copy.deepcopy(self.pins)
if self.name.startswith("pmos") or self.name.startswith("nmos"): if self.name.startswith("pmos") or self.name.startswith("nmos"):
pin_names.remove("B") pin_names.remove("B")

View File

@ -1,6 +1,6 @@
# See LICENSE for licensing information. # See LICENSE for licensing information.
# #
# Copyright (c) 2016-2023 Regents of the University of California and The Board # Copyright (c) 2016-2024 Regents of the University of California and The Board
# of Regents for the Oklahoma Agricultural and Mechanical College # of Regents for the Oklahoma Agricultural and Mechanical College
# (acting for and on behalf of Oklahoma State University) # (acting for and on behalf of Oklahoma State University)
# All rights reserved. # All rights reserved.
@ -13,6 +13,7 @@ from pprint import pformat
from openram import debug from openram import debug
from openram import tech from openram import tech
from openram import OPTS from openram import OPTS
from collections import OrderedDict
from .delay_data import delay_data from .delay_data import delay_data
from .wire_spice_model import wire_spice_model from .wire_spice_model import wire_spice_model
from .power_data import power_data from .power_data import power_data
@ -49,26 +50,24 @@ class spice():
if not os.path.exists(self.lvs_file): if not os.path.exists(self.lvs_file):
self.lvs_file = self.sp_file self.lvs_file = self.sp_file
self.valid_signal_types = ["INOUT", "INPUT", "OUTPUT", "BIAS", "POWER", "GROUND"]
# Holds subckts/mods for this module # Holds subckts/mods for this module
self.mods = set() self.mods = set()
# Holds the pins for this module (in order) # Holds the pins for this module (in order)
self.pins = [] # on Python3.7+ regular dictionaries guarantee order too, but we allow use of v3.5+
# The type map of each pin: INPUT, OUTPUT, INOUT, POWER, GROUND self.pins = OrderedDict()
# for each instance, this is the set of nets/nodes that map to the pins for this instance
self.pin_type = {}
# An (optional) list of indices to reorder the pins to match the spice. # An (optional) list of indices to reorder the pins to match the spice.
self.pin_indices = [] self.pin_indices = []
# THE CONNECTIONS MUST MATCH THE ORDER OF THE PINS (restriction imposed by the # THE CONNECTIONS MUST MATCH THE ORDER OF THE PINS (restriction imposed by the
# Spice format) # Spice format)
self.conns = [] # internal nets, which may or may not be connected to pins of the same name
# If this is set, it will out output subckt or isntances of this (for row/col caps etc.) self.nets = {}
# If this is set, it will not output subckt or instances of this (for row/col caps etc.)
self.no_instances = False self.no_instances = False
# If we are doing a trimmed netlist, these are the instance that will be filtered # If we are doing a trimmed netlist, these are the instance that will be filtered
self.trim_insts = set() self.trim_insts = set()
# Keep track of any comments to add the the spice # Keep track of any comments to add the the spice
try: try:
self.commments self.comments
except AttributeError: except AttributeError:
self.comments = [] self.comments = []
@ -82,7 +81,7 @@ class spice():
""" Add a comment to the spice file """ """ Add a comment to the spice file """
try: try:
self.commments self.comments
except AttributeError: except AttributeError:
self.comments = [] self.comments = []
@ -90,128 +89,114 @@ class spice():
def add_pin(self, name, pin_type="INOUT"): def add_pin(self, name, pin_type="INOUT"):
""" Adds a pin to the pins list. Default type is INOUT signal. """ """ Adds a pin to the pins list. Default type is INOUT signal. """
self.pins.append(name) debug.check(name not in self.pins, "cannot add duplicate spice pin {}".format(name))
self.pin_type[name]=pin_type self.pins[name] = pin_spice(name, pin_type, self)
debug.check(pin_type in self.valid_signal_types,
"Invalid signaltype for {0}: {1}".format(name,
pin_type))
def add_pin_list(self, pin_list, pin_type="INOUT"): def add_pin_list(self, pin_list, pin_type="INOUT"):
""" Adds a pin_list to the pins list """ """ Adds a pin_list to the pins list """
# The type list can be a single type for all pins # The pin type list can be a single type for all pins
# or a list that is the same length as the pin list. # or a list that is the same length as the pin list.
if type(pin_type)==str: if isinstance(pin_type, str):
for pin in pin_list: for pin in pin_list:
debug.check(pin_type in self.valid_signal_types,
"Invalid signaltype for {0}: {1}".format(pin,
pin_type))
self.add_pin(pin, pin_type) self.add_pin(pin, pin_type)
elif len(pin_type)==len(pin_list): elif len(pin_type)==len(pin_list):
for (pin, ptype) in zip(pin_list, pin_type): for (pin, type) in zip(pin_list, pin_type):
debug.check(ptype in self.valid_signal_types, self.add_pin(pin, type)
"Invalid signaltype for {0}: {1}".format(pin,
ptype))
self.add_pin(pin, ptype)
else: else:
debug.error("Mismatch in type and pin list lengths.", -1) debug.error("Pin type must be a string or list of strings the same length as pin_list", -1)
def add_pin_indices(self, index_list): def add_pin_indices(self, index_list):
""" """ Add pin indices for all the cell's pins. """
Add pin indices for all the cell's pins.
"""
self.pin_indices = index_list self.pin_indices = index_list
def get_ordered_inputs(self, input_list): def get_ordered_inputs(self, input_list):
""" """ Return the inputs reordered to match the pins. """
Return the inputs reordered to match the pins.
"""
if not self.pin_indices: if not self.pin_indices:
return input_list return input_list
new_list = [input_list[x] for x in self.pin_indices] new_list = [input_list[x] for x in self.pin_indices]
return new_list return new_list
def add_pin_types(self, type_list): def update_pin_types(self, type_list):
""" """ Change pin types for all the cell's pins. """
Add pin types for all the cell's pins. debug.check(len(type_list) == len(self.pins),
""" "{} spice subcircuit number of port types does not match number of pins\
# This only works if self.pins == bitcell.pin_names \n pin names={}\n port types={}".format(self.name, list(self.pins), type_list))
if len(type_list) != len(self.pins): for pin, type in zip(self.pins.values(), type_list):
debug.error("{} spice subcircuit number of port types does not match number of pins\ pin.set_type(type)
\n SPICE names={}\
\n Module names={}\
".format(self.name, self.pins, type_list), 1)
self.pin_type = {pin: type for pin, type in zip(self.pins, type_list)}
def get_pin_type(self, name): def get_pin_type(self, name):
""" Returns the type of the signal pin. """ """ Returns the type of the signal pin. """
pin_type = self.pin_type[name] pin = self.pins.get(name)
debug.check(pin_type in self.valid_signal_types, debug.check(pin is not None, "Spice pin {} not found".format(name))
"Invalid signaltype for {0}: {1}".format(name, pin_type)) return pin.type
return pin_type
def get_pin_dir(self, name): def get_pin_dir(self, name):
""" Returns the direction of the pin. (Supply/ground are INOUT). """ """ Returns the direction of the pin. (Supply/ground are INOUT). """
if self.pin_type[name] in ["POWER", "GROUND"]: pin_type = self.get_pin_type(name)
if pin_type in ["POWER", "GROUND"]:
return "INOUT" return "INOUT"
else: else:
return self.pin_type[name] return pin_type
def get_inputs(self): def get_inputs(self):
""" These use pin types to determine pin lists. These """
may be over-ridden by submodules that didn't use pin directions yet.""" These use pin types to determine pin lists.
Returns names only, to maintain historical interface.
"""
input_list = [] input_list = []
for pin in self.pins: for pin in self.pins.values():
if self.pin_type[pin]=="INPUT": if pin.type == "INPUT":
input_list.append(pin) input_list.append(pin.name)
return input_list return input_list
def get_outputs(self): def get_outputs(self):
""" These use pin types to determine pin lists. These """
may be over-ridden by submodules that didn't use pin directions yet.""" These use pin types to determine pin lists.
Returns names only, to maintain historical interface.
"""
output_list = [] output_list = []
for pin in self.pins: for pin in self.pins.values():
if self.pin_type[pin]=="OUTPUT": if pin.type == "OUTPUT":
output_list.append(pin) output_list.append(pin.name)
return output_list return output_list
def get_inouts(self):
"""
These use pin types to determine pin lists.
Returns names only, to maintain historical interface.
"""
inout_list = []
for pin in self.pins.values():
if pin.type == "INOUT":
inout_list.append(pin.name)
return inout_list
def copy_pins(self, other_module, suffix=""): def copy_pins(self, other_module, suffix=""):
""" This will copy all of the pins from the other module and add an optional suffix.""" """ This will copy all of the pins from the other module and add an optional suffix."""
for pin in other_module.pins: for pin in other_module.pins.values():
self.add_pin(pin + suffix, other_module.get_pin_type(pin)) self.add_pin(pin.name + suffix, pin.type)
def get_inouts(self): def connect_inst(self, args):
""" These use pin types to determine pin lists. These
may be over-ridden by submodules that didn't use pin directions yet."""
inout_list = []
for pin in self.pins:
if self.pin_type[pin]=="INOUT":
inout_list.append(pin)
return inout_list
def connect_inst(self, args, check=True):
""" """
Connects the pins of the last instance added Connects the pins of the last instance added
It is preferred to use the function with the check to find if
there is a problem. The check option can be set to false
where we dynamically generate groups of connections after a
group of modules are generated.
""" """
num_pins = len(self.insts[-1].mod.pins) spice_pins = list(self.insts[-1].spice_pins)
num_pins = len(spice_pins)
num_args = len(args) num_args = len(args)
# Order the arguments if the hard cell has a custom port order # Order the arguments if the hard cell has a custom port order
ordered_args = self.get_ordered_inputs(args) ordered_args = self.get_ordered_inputs(args)
if (check and num_pins != num_args): if (num_pins != num_args):
if num_pins < num_args: if num_pins < num_args:
mod_pins = self.insts[-1].mod.pins + [""] * (num_args - num_pins) mod_pins = spice_pins + [""] * (num_args - num_pins)
arg_pins = ordered_args arg_pins = ordered_args
else: else:
arg_pins = ordered_args + [""] * (num_pins - num_args) arg_pins = ordered_args + [""] * (num_pins - num_args)
mod_pins = self.insts[-1].mod.pins mod_pins = spice_pins
modpins_string = "\n".join(["{0} -> {1}".format(arg, mod) for (arg, mod) in zip(arg_pins, mod_pins)]) modpins_string = "\n".join(["{0} -> {1}".format(arg, mod) for (arg, mod) in zip(arg_pins, mod_pins)])
debug.error("Connection mismatch:\nInst ({0}) -> Mod ({1})\n{2}".format(num_args, debug.error("Connection mismatch:\nInst ({0}) -> Mod ({1})\n{2}".format(num_args,
@ -219,27 +204,17 @@ class spice():
modpins_string), modpins_string),
1) 1)
self.conns.append(ordered_args) ordered_nets = self.create_nets(ordered_args)
self.insts[-1].connect_spice_pins(ordered_nets)
# This checks if we don't have enough instance port connections for the number of insts def create_nets(self, names_list):
if check and (len(self.insts)!=len(self.conns)): nets = []
insts_string=pformat(self.insts) for name in names_list:
conns_string=pformat(self.conns) # setdefault adds to the dict if it doesn't find the net in it already
# then it returns the net it found or created, a net_spice object
debug.error("{0} : Not all instance pins ({1}) are connected ({2}).".format(self.name, net = self.nets.setdefault(name, net_spice(name, self))
len(self.insts), nets.append(net)
len(self.conns))) return nets
debug.error("Instances: \n" + str(insts_string))
debug.error("-----")
debug.error("Connections: \n" + str(conns_string), 1)
def get_conns(self, inst):
"""Returns the connections of a given instance."""
for i in range(len(self.insts)):
if inst is self.insts[i]:
return self.conns[i]
# If not found, returns None
return None
def sp_read(self): def sp_read(self):
""" """
@ -258,7 +233,7 @@ class spice():
subckt = re.compile("^.subckt {}".format(self.cell_name), re.IGNORECASE) subckt = re.compile("^.subckt {}".format(self.cell_name), re.IGNORECASE)
subckt_line = list(filter(subckt.search, self.spice))[0] subckt_line = list(filter(subckt.search, self.spice))[0]
# parses line into ports and remove subckt # parses line into ports and remove subckt
self.pins = subckt_line.split(" ")[2:] self.add_pin_list(subckt_line.split(" ")[2:])
else: else:
debug.info(4, "no spfile {0}".format(self.sp_file)) debug.info(4, "no spfile {0}".format(self.sp_file))
self.spice = [] self.spice = []
@ -279,10 +254,10 @@ class spice():
subckt_line = list(filter(subckt.search, self.lvs))[0] subckt_line = list(filter(subckt.search, self.lvs))[0]
# parses line into ports and remove subckt # parses line into ports and remove subckt
lvs_pins = subckt_line.split(" ")[2:] lvs_pins = subckt_line.split(" ")[2:]
debug.check(lvs_pins == self.pins, debug.check(lvs_pins == list(self.pins),
"Spice netlists for LVS and simulation have port mismatches:\n{0} (LVS {1})\nvs\n{2} (sim {3})".format(lvs_pins, "Spice netlists for LVS and simulation have port mismatches:\n{0} (LVS {1})\nvs\n{2} (sim {3})".format(lvs_pins,
self.lvs_file, self.lvs_file,
self.pins, list(self.pins),
self.sp_file)) self.sp_file))
def check_net_in_spice(self, net_name): def check_net_in_spice(self, net_name):
@ -327,78 +302,72 @@ class spice():
# If spice isn't defined, we dynamically generate one. # If spice isn't defined, we dynamically generate one.
# recursively write the modules # recursively write the modules
for i in self.mods: for mod in self.mods:
if self.contains(i, usedMODS): if self.contains(mod, usedMODS):
continue continue
usedMODS.append(i) usedMODS.append(mod)
i.sp_write_file(sp, usedMODS, lvs, trim) mod.sp_write_file(sp, usedMODS, lvs, trim)
if len(self.insts) == 0: if len(self.insts) == 0:
return return
if self.pins == []: if len(self.pins) == 0:
return return
# write out the first spice line (the subcircuit) # write out the first spice line (the subcircuit)
wrapped_pins = "\n+ ".join(tr.wrap(" ".join(self.pins))) wrapped_pins = "\n+ ".join(tr.wrap(" ".join(list(self.pins))))
sp.write("\n.SUBCKT {0}\n+ {1}\n".format(self.cell_name, sp.write("\n.SUBCKT {0}\n+ {1}\n".format(self.cell_name,
wrapped_pins)) wrapped_pins))
# write a PININFO line
if False:
pin_info = "*.PININFO"
for pin in self.pins:
if self.pin_type[pin] == "INPUT":
pin_info += " {0}:I".format(pin)
elif self.pin_type[pin] == "OUTPUT":
pin_info += " {0}:O".format(pin)
else:
pin_info += " {0}:B".format(pin)
sp.write(pin_info + "\n")
# Also write pins as comments # Also write pins as comments
for pin in self.pins: for pin in self.pins.values():
sp.write("* {1:6}: {0} \n".format(pin, self.pin_type[pin])) sp.write("* {1:6}: {0} \n".format(pin.name, pin.type))
for line in self.comments: for line in self.comments:
sp.write("* {}\n".format(line)) sp.write("* {}\n".format(line))
# every instance must have a set of connections, even if it is empty. # every instance must be connected with the connect_inst function
if len(self.insts) != len(self.conns): # TODO: may run into empty pin lists edge case, not sure yet
debug.error("{0} : Not all instance pins ({1}) are connected ({2}).".format(self.cell_name, connected = True
len(self.insts), for inst in self.insts:
len(self.conns))) if inst.connected:
debug.error("Instances: \n" + str(self.insts)) continue
debug.error("-----") debug.error("Instance {} spice pins not connected".format(str(inst)))
debug.error("Connections: \n" + str(self.conns), 1) connected = False
debug.check(connected, "{0} : Not all instance spice pins are connected.".format(self.cell_name))
for i in range(len(self.insts)): for inst in self.insts:
# we don't need to output connections of empty instances. # we don't need to output connections of empty instances.
# these are wires and paths # these are wires and paths
if self.conns[i] == []: if len(inst.spice_pins) == 0:
continue continue
# Instance with no devices in it needs no subckt/instance # Instance with no devices in it needs no subckt/instance
if self.insts[i].mod.no_instances: if inst.mod.no_instances:
continue continue
# If this is a trimmed netlist, skip it by adding comment char # If this is a trimmed netlist, skip it by adding comment char
if trim and self.insts[i].name in self.trim_insts: if trim and inst.name in self.trim_insts:
sp.write("* ") sp.write("* ")
if lvs and hasattr(self.insts[i].mod, "lvs_device"): if lvs and hasattr(inst.mod, "lvs_device"):
sp.write(self.insts[i].mod.lvs_device.format(self.insts[i].name, sp.write(inst.mod.lvs_device.format(inst.name,
" ".join(self.conns[i]))) " ".join(inst.get_connections())))
sp.write("\n") sp.write("\n")
elif hasattr(self.insts[i].mod, "spice_device"): elif hasattr(inst.mod, "spice_device"):
sp.write(self.insts[i].mod.spice_device.format(self.insts[i].name, sp.write(inst.mod.spice_device.format(inst.name,
" ".join(self.conns[i]))) " ".join(inst.get_connections())))
sp.write("\n") sp.write("\n")
else: else:
wrapped_connections = "\n+ ".join(tr.wrap(" ".join(self.conns[i]))) if trim and inst.name in self.trim_insts:
wrapped_connections = "\n*+ ".join(tr.wrap(" ".join(inst.get_connections())))
sp.write("X{0}\n+ {1}\n+ {2}\n".format(self.insts[i].name, sp.write("X{0}\n*+ {1}\n*+ {2}\n".format(inst.name,
wrapped_connections, wrapped_connections,
self.insts[i].mod.cell_name)) inst.mod.cell_name))
else:
wrapped_connections = "\n+ ".join(tr.wrap(" ".join(inst.get_connections())))
sp.write("X{0}\n+ {1}\n+ {2}\n".format(inst.name,
wrapped_connections,
inst.mod.cell_name))
sp.write(".ENDS {0}\n".format(self.cell_name)) sp.write(".ENDS {0}\n".format(self.cell_name))
@ -727,6 +696,12 @@ class spice():
aliases.append(net) aliases.append(net)
return aliases return aliases
def get_instance_connections(self):
conns = []
for inst in self.insts:
conns.append(inst.get_connections())
return conns
def is_net_alias(self, known_net, net_alias, mod, exclusion_set): def is_net_alias(self, known_net, net_alias, mod, exclusion_set):
""" """
Checks if the alias_net in input mod is the same as the input net for this mod (self). Checks if the alias_net in input mod is the same as the input net for this mod (self).
@ -739,7 +714,7 @@ class spice():
return True return True
# Check connections of all other subinsts # Check connections of all other subinsts
mod_set = set() mod_set = set()
for subinst, inst_conns in zip(self.insts, self.conns): for subinst, inst_conns in zip(self.insts, self.get_instance_connections()):
for inst_conn, mod_pin in zip(inst_conns, subinst.mod.pins): for inst_conn, mod_pin in zip(inst_conns, subinst.mod.pins):
if self.is_net_alias_name_check(known_net, inst_conn, net_alias, mod): if self.is_net_alias_name_check(known_net, inst_conn, net_alias, mod):
return True return True
@ -756,3 +731,149 @@ class spice():
return self == mod and \ return self == mod and \
child_net.lower() == alias_net.lower() and \ child_net.lower() == alias_net.lower() and \
parent_net.lower() == alias_net.lower() parent_net.lower() == alias_net.lower()
class pin_spice():
"""
A class to represent a spice netlist pin.
mod is the parent module that created this pin.
mod_net is the net object of this pin's parent module. It must have the same name as the pin.
inst is the instance this pin is a part of, if any.
inst_net is the net object from mod's nets which connects to this pin.
"""
valid_pin_types = ["INOUT", "INPUT", "OUTPUT", "POWER", "GROUND", "BIAS"]
def __init__(self, name, type, mod):
self.name = name
self.set_type(type)
self.mod = mod
self.mod_net = None
self.inst = None
self.inst_net = None
# TODO: evaluate if this makes sense... and works
self._hash = hash(self.name)
def set_type(self, type):
debug.check(type in pin_spice.valid_pin_types,
"Invalid pin type for {0}: {1}".format(self.name, type))
self.type = type
def set_mod_net(self, net):
debug.check(isinstance(net, net_spice), "net must be a net_spice object")
debug.check(net.name == self.name, "module spice net must have same name as spice pin")
self.mod_net = net
def set_inst(self, inst):
self.inst = inst
def set_inst_net(self, net):
if self.inst_net is not None:
debug.error("pin {} is already connected to net {}\
so it cannot also be connected to net {}\
".format(self.name, self.inst_net.name, net.name), 1)
debug.check(isinstance(net, net_spice), "net must be a net_spice object")
self.inst_net = net
def __str__(self):
""" override print function output """
return "(pin_name={} type={})".format(self.name, self.type)
def __repr__(self):
""" override repr function output """
return self.name
def __eq__(self, name):
return (name == self.name) if isinstance(name, str) else super().__eq__(name)
def __hash__(self):
"""
Implement the hash function for sets etc.
Only hash name since spice does not allow two pins to share a name.
Provides a speedup if pin_spice is used as a key for dicts.
"""
return self._hash
def __deepcopy__(original, memo):
"""
This function is defined so that instances of modules can make deep
copies of their parent module's pins dictionary. It is only expected
to be called by the instance class __init__ function. Mod and mod_net
should not be deep copies but references to the existing mod and net
objects they refer to in the original. If inst is already defined this
function will throw an error because that means it was called on a pin
from an instance, which is not defined behavior.
"""
debug.check(original.inst is None,
"cannot make a deepcopy of a spice pin from an inst")
pin = pin_spice(original.name, original.type, original.mod)
if original.mod_net is not None:
pin.set_mod_net(original.mod_net)
return pin
class net_spice():
"""
A class to represent a spice net.
mod is the parent module that created this net.
pins are all the pins connected to this net.
inst is the instance this net is a part of, if any.
"""
def __init__(self, name, mod):
self.name = name
self.pins = []
self.mod = mod
self.inst = None
# TODO: evaluate if this makes sense... and works
self._hash = hash(self.name)
def connect_pin(self, pin):
debug.check(isinstance(pin, pin_spice), "pin must be a pin_spice object")
if pin in self.pins:
debug.warning("pin {} was already connected to net {} ... why was it connected again?".format(pin.name, self.name))
else:
self.pins.append(pin)
def set_inst(self, inst):
self.inst = inst
def __str__(self):
""" override print function output """
return "(net_name={} type={})".format(self.name, self.type)
def __repr__(self):
""" override repr function output """
return self.name
def __eq__(self, name):
return (name == self.name) if isinstance(name, str) else super().__eq__(name)
def __hash__(self):
"""
Implement the hash function for sets etc.
Only hash name since spice does not allow two nets to share a name
(on the same level of hierarchy, or rather they will be the same net).
Provides a speedup if net_spice is used as a key for dicts.
"""
return self._hash
def __deepcopy__(original, memo):
"""
This function is defined so that instances of modules can make deep
copies of their parent module's nets dictionary. It is only expected
to be called by the instance class __init__ function. Mod
should not be a deep copy but a reference to the existing mod
object it refers to in the original. If inst is already defined this
function will throw an error because that means it was called on a net
from an instance, which is not defined behavior.
"""
debug.check(original.inst is None,
"cannot make a deepcopy of a spice net from an inst")
net = net_spice(original.name, original.mod)
if original.pins != []:
# TODO: honestly I'm not sure if this is right but we'll see...
net.pins = original.pins
return net

View File

@ -1,6 +1,6 @@
# See LICENSE for licensing information. # See LICENSE for licensing information.
# #
# Copyright (c) 2016-2023 Regents of the University of California and The Board # Copyright (c) 2016-2024 Regents of the University of California and The Board
# of Regents for the Oklahoma Agricultural and Mechanical College # of Regents for the Oklahoma Agricultural and Mechanical College
# (acting for and on behalf of Oklahoma State University) # (acting for and on behalf of Oklahoma State University)
# All rights reserved. # All rights reserved.
@ -18,7 +18,7 @@ class lef:
""" """
SRAM LEF Class open GDS file, read pins information, obstruction SRAM LEF Class open GDS file, read pins information, obstruction
and write them to LEF file. and write them to LEF file.
This is inherited by the sram_base class. This is inherited by the sram_1bank class.
""" """
def __init__(self, layers): def __init__(self, layers):
# LEF db units per micron # LEF db units per micron

View File

@ -1,6 +1,6 @@
# See LICENSE for licensing information. # See LICENSE for licensing information.
# #
# Copyright (c) 2016-2023 Regents of the University of California and The Board # Copyright (c) 2016-2024 Regents of the University of California and The Board
# of Regents for the Oklahoma Agricultural and Mechanical College # of Regents for the Oklahoma Agricultural and Mechanical College
# (acting for and on behalf of Oklahoma State University) # (acting for and on behalf of Oklahoma State University)
# All rights reserved. # All rights reserved.

View File

@ -1,6 +1,6 @@
# See LICENSE for licensing information. # See LICENSE for licensing information.
# #
# Copyright (c) 2016-2023 Regents of the University of California and The Board # Copyright (c) 2016-2024 Regents of the University of California and The Board
# of Regents for the Oklahoma Agricultural and Mechanical College # of Regents for the Oklahoma Agricultural and Mechanical College
# (acting for and on behalf of Oklahoma State University) # (acting for and on behalf of Oklahoma State University)
# All rights reserved. # All rights reserved.

View File

@ -1,6 +1,6 @@
# See LICENSE for licensing information. # See LICENSE for licensing information.
# #
# Copyright (c) 2016-2023 Regents of the University of California and The Board # Copyright (c) 2016-2024 Regents of the University of California and The Board
# of Regents for the Oklahoma Agricultural and Mechanical College # of Regents for the Oklahoma Agricultural and Mechanical College
# (acting for and on behalf of Oklahoma State University) # (acting for and on behalf of Oklahoma State University)
# All rights reserved. # All rights reserved.

View File

@ -0,0 +1,173 @@
# See LICENSE for licensing information.
#
# Copyright (c) 2016-2024 Regents of the University of California and The Board
# of Regents for the Oklahoma Agricultural and Mechanical College
# (acting for and on behalf of Oklahoma State University)
# All rights reserved.
#
import math
from openram.tech import spice
class rom_verilog:
"""
Create a behavioral Verilog file for simulation.
This is inherited by the rom_base class.
"""
def __init__(self):
pass
def verilog_write(self, verilog_name):
""" Write a behavioral Verilog model. """
self.vf = open(verilog_name, "w")
self.vf.write("// OpenROM ROM model\n")
#basic info
self.vf.write("// Words: {0}\n".format(self.num_words))
self.vf.write("// Word size: {0}\n".format(self.word_size))
self.vf.write("// Word per Row: {0}\n".format(self.words_per_row))
self.vf.write("// Data Type: {0}\n".format(self.data_type))
self.vf.write("// Data File: {0}\n".format(self.rom_data))
self.vf.write("\n")
try:
self.vdd_name = spice["power"]
except KeyError:
self.vdd_name = "vdd"
try:
self.gnd_name = spice["ground"]
except KeyError:
self.gnd_name = "gnd"
#add multiple banks later
self.vf.write("module {0}(\n".format(self.name))
self.vf.write("`ifdef USE_POWER_PINS\n")
self.vf.write(" {},\n".format(self.vdd_name))
self.vf.write(" {},\n".format(self.gnd_name))
self.vf.write("`endif\n")
for port in self.all_ports:
if port in self.read_ports:
self.vf.write("// Port {0}: R\n".format(port))
self.vf.write(" clk{0},cs{0},addr{0},dout{0}".format(port))
# Continue for every port on a new line
if port != self.all_ports[-1]:
self.vf.write(",\n")
self.vf.write("\n );\n\n")
self.vf.write(" parameter DATA_WIDTH = {0} ;\n".format(self.word_size))
self.vf.write(" parameter ADDR_WIDTH = {0} ;\n".format(math.ceil(math.log(self.num_words,2))))
self.vf.write(" parameter ROM_DEPTH = 1 << ADDR_WIDTH;\n")
self.vf.write(" // FIXME: This delay is arbitrary.\n")
self.vf.write(" parameter DELAY = 3 ;\n")
self.vf.write(" parameter VERBOSE = 1 ; //Set to 0 to only display warnings\n")
self.vf.write(" parameter T_HOLD = 1 ; //Delay to hold dout value after posedge. Value is arbitrary\n")
self.vf.write("\n")
self.vf.write("`ifdef USE_POWER_PINS\n")
self.vf.write(" inout {};\n".format(self.vdd_name))
self.vf.write(" inout {};\n".format(self.gnd_name))
self.vf.write("`endif\n")
for port in self.all_ports:
self.add_inputs_outputs(port)
self.vf.write("\n")
# This is the memory array itself
self.vf.write(" reg [DATA_WIDTH-1:0] mem [0:ROM_DEPTH-1];\n\n")
#write memory init here
self.vf.write(f" initial begin\n")
if self.data_type == "bin":
self.vf.write(f" $readmemb(\"{self.rom_data}\",mem,0,ROM_DEPTH-1);\n")
elif self.data_type == "hex":
self.vf.write(f" $readmemh(\"{self.rom_data}\",mem,0, ROM_DEPTH-1);\n")
else:
raise ValueError(f"Data type: {self.data_type} is not supported!")
self.vf.write(f" end\n\n")
for port in self.all_ports:
self.register_inputs(port)
for port in self.all_ports:
if port in self.read_ports:
self.add_read_block(port)
self.vf.write("\n")
self.vf.write("endmodule\n")
self.vf.close()
def register_inputs(self, port):
"""
Register the control signal, address and data inputs.
"""
self.add_regs(port)
self.add_flops(port)
def add_regs(self, port):
"""
Create the input regs for the given port.
"""
self.vf.write(" reg cs{0}_reg;\n".format(port))
self.vf.write(" reg [ADDR_WIDTH-1:0] addr{0}_reg;\n".format(port))
if port in self.read_ports:
self.vf.write(" reg [DATA_WIDTH-1:0] dout{0};\n".format(port))
def add_flops(self, port):
"""
Add the flop behavior logic for a port.
"""
self.vf.write("\n")
self.vf.write(" // All inputs are registers\n")
self.vf.write(" always @(posedge clk{0})\n".format(port))
self.vf.write(" begin\n")
self.vf.write(" cs{0}_reg = cs{0};\n".format(port))
self.vf.write(" addr{0}_reg = addr{0};\n".format(port))
if port in self.read_ports:
self.add_write_read_checks(port)
if port in self.read_ports:
self.vf.write(" #(T_HOLD) dout{0} = {1}'bx;\n".format(port, self.word_size))
self.vf.write(" if ( cs{0}_reg && VERBOSE ) \n".format(port))
self.vf.write(" $display($time,\" Reading %m addr{0}=%b dout{0}=%b\",addr{0}_reg,mem[addr{0}_reg]);\n".format(port))
self.vf.write(" end\n\n")
def add_inputs_outputs(self, port):
"""
Add the module input and output declaration for a port.
"""
self.vf.write(" input clk{0}; // clock\n".format(port))
self.vf.write(" input cs{0}; // active high chip select\n".format(port))
self.vf.write(" input [ADDR_WIDTH-1:0] addr{0};\n".format(port))
if port in self.read_ports:
self.vf.write(" output [DATA_WIDTH-1:0] dout{0};\n".format(port))
def add_write_block(self, port):
"""
ROM does not take writes thus this function does nothing
"""
self.vf.write("\n")
def add_read_block(self, port):
"""
Add a read port block.
"""
self.vf.write("\n")
self.vf.write(" // Memory Read Block Port {0}\n".format(port))
self.vf.write(" // Read Operation : When cs{0} = 1\n".format(port))
self.vf.write(" always @ (negedge clk{0})\n".format(port))
self.vf.write(" begin : MEM_READ{0}\n".format(port))
self.vf.write(" if (cs{0}_reg)\n".format(port))
self.vf.write(" dout{0} <= #(DELAY) mem[addr{0}_reg];\n".format(port))
self.vf.write(" end\n")
def add_write_read_checks(self, rport):
"""
Since ROMs dont have write ports this does nothing
"""
pass

View File

@ -1,6 +1,6 @@
# See LICENSE for licensing information. # See LICENSE for licensing information.
# #
# Copyright (c) 2016-2023 Regents of the University of California and The Board # Copyright (c) 2016-2024 Regents of the University of California and The Board
# of Regents for the Oklahoma Agricultural and Mechanical College # of Regents for the Oklahoma Agricultural and Mechanical College
# (acting for and on behalf of Oklahoma State University) # (acting for and on behalf of Oklahoma State University)
# All rights reserved. # All rights reserved.

View File

@ -1,6 +1,6 @@
# See LICENSE for licensing information. # See LICENSE for licensing information.
# #
# Copyright (c) 2016-2023 Regents of the University of California, Santa Cruz # Copyright (c) 2016-2024 Regents of the University of California, Santa Cruz
# All rights reserved. # All rights reserved.
# #
import copy import copy

View File

@ -1,6 +1,6 @@
# See LICENSE for licensing information. # See LICENSE for licensing information.
# #
# Copyright (c) 2016-2023 Regents of the University of California and The Board # Copyright (c) 2016-2024 Regents of the University of California and The Board
# of Regents for the Oklahoma Agricultural and Mechanical College # of Regents for the Oklahoma Agricultural and Mechanical College
# (acting for and on behalf of Oklahoma State University) # (acting for and on behalf of Oklahoma State University)
# All rights reserved. # All rights reserved.

View File

@ -1,6 +1,6 @@
# See LICENSE for licensing information. # See LICENSE for licensing information.
# #
# Copyright (c) 2016-2023 Regents of the University of California and The Board # Copyright (c) 2016-2024 Regents of the University of California and The Board
# of Regents for the Oklahoma Agricultural and Mechanical College # of Regents for the Oklahoma Agricultural and Mechanical College
# (acting for and on behalf of Oklahoma State University) # (acting for and on behalf of Oklahoma State University)
# All rights reserved. # All rights reserved.

View File

@ -1,6 +1,6 @@
# See LICENSE for licensing information. # See LICENSE for licensing information.
# #
# Copyright (c) 2016-2023 Regents of the University of California and The Board # Copyright (c) 2016-2024 Regents of the University of California and The Board
# of Regents for the Oklahoma Agricultural and Mechanical College # of Regents for the Oklahoma Agricultural and Mechanical College
# (acting for and on behalf of Oklahoma State University) # (acting for and on behalf of Oklahoma State University)
# All rights reserved. # All rights reserved.

View File

@ -1,6 +1,6 @@
# See LICENSE for licensing information. # See LICENSE for licensing information.
# #
# Copyright (c) 2016-2023 Regents of the University of California and The Board # Copyright (c) 2016-2024 Regents of the University of California and The Board
# of Regents for the Oklahoma Agricultural and Mechanical College # of Regents for the Oklahoma Agricultural and Mechanical College
# (acting for and on behalf of Oklahoma State University) # (acting for and on behalf of Oklahoma State University)
# All rights reserved. # All rights reserved.

View File

@ -1,6 +1,6 @@
# See LICENSE for licensing information. # See LICENSE for licensing information.
# #
# Copyright (c) 2016-2023 Regents of the University of California and The Board # Copyright (c) 2016-2024 Regents of the University of California and The Board
# of Regents for the Oklahoma Agricultural and Mechanical College # of Regents for the Oklahoma Agricultural and Mechanical College
# (acting for and on behalf of Oklahoma State University) # (acting for and on behalf of Oklahoma State University)
# All rights reserved. # All rights reserved.

View File

@ -1,6 +1,6 @@
# See LICENSE for licensing information. # See LICENSE for licensing information.
# #
# Copyright (c) 2016-2023 Regents of the University of California and The Board # Copyright (c) 2016-2024 Regents of the University of California and The Board
# of Regents for the Oklahoma Agricultural and Mechanical College # of Regents for the Oklahoma Agricultural and Mechanical College
# (acting for and on behalf of Oklahoma State University) # (acting for and on behalf of Oklahoma State University)
# All rights reserved. # All rights reserved.

View File

@ -1,6 +1,6 @@
# See LICENSE for licensing information. # See LICENSE for licensing information.
# #
# Copyright (c) 2016-2023 Regents of the University of California and The Board # Copyright (c) 2016-2024 Regents of the University of California and The Board
# of Regents for the Oklahoma Agricultural and Mechanical College # of Regents for the Oklahoma Agricultural and Mechanical College
# (acting for and on behalf of Oklahoma State University) # (acting for and on behalf of Oklahoma State University)
# All rights reserved. # All rights reserved.
@ -18,6 +18,7 @@ class wire_spice_model():
def cal_wire_c(self, wire_length, wire_width): def cal_wire_c(self, wire_length, wire_width):
from openram.tech import spice from openram.tech import spice
# Convert the F/um^2 to fF/um^2 then multiple by width and length # Convert the F/um^2 to fF/um^2 then multiple by width and length
# FIXME: shouldn't it be 1e15?
total_c = (spice["wire_unit_c"]*1e12) * wire_length * wire_width total_c = (spice["wire_unit_c"]*1e12) * wire_length * wire_width
wire_c = total_c / self.lump_num wire_c = total_c / self.lump_num
return wire_c return wire_c

View File

@ -1,6 +1,6 @@
# See LICENSE for licensing information. # See LICENSE for licensing information.
# #
# Copyright (c) 2016-2023 Regents of the University of California and The Board # Copyright (c) 2016-2024 Regents of the University of California and The Board
# of Regents for the Oklahoma Agricultural and Mechanical College # of Regents for the Oklahoma Agricultural and Mechanical College
# (acting for and on behalf of Oklahoma State University) # (acting for and on behalf of Oklahoma State University)
# All rights reserved. # All rights reserved.
@ -19,11 +19,12 @@ from .simulation import *
from .measurements import * from .measurements import *
from .model_check import * from .model_check import *
from .analytical_util import * from .analytical_util import *
from .fake_sram import *
debug.info(1, "Initializing characterizer...") debug.info(1, "Initializing characterizer...")
OPTS.spice_exe = "" OPTS.spice_exe = ""
if not OPTS.analytical_delay: if not OPTS.analytical_delay or OPTS.top_process in ["memfunc", "memchar"]:
if OPTS.spice_name: if OPTS.spice_name:
# Capitalize Xyce # Capitalize Xyce
if OPTS.spice_name == "xyce": if OPTS.spice_name == "xyce":

View File

@ -1,6 +1,6 @@
# See LICENSE for licensing information. # See LICENSE for licensing information.
# #
# Copyright (c) 2016-2023 Regents of the University of California and The Board # Copyright (c) 2016-2024 Regents of the University of California and The Board
# of Regents for the Oklahoma Agricultural and Mechanical College # of Regents for the Oklahoma Agricultural and Mechanical College
# (acting for and on behalf of Oklahoma State University) # (acting for and on behalf of Oklahoma State University)
# All rights reserved. # All rights reserved.

View File

@ -1,6 +1,6 @@
# See LICENSE for licensing information. # See LICENSE for licensing information.
# #
# Copyright (c) 2016-2023 Regents of the University of California and The Board # Copyright (c) 2016-2024 Regents of the University of California and The Board
# of Regents for the Oklahoma Agricultural and Mechanical College # of Regents for the Oklahoma Agricultural and Mechanical College
# (acting for and on behalf of Oklahoma State University) # (acting for and on behalf of Oklahoma State University)
# All rights reserved. # All rights reserved.

View File

@ -1,12 +1,13 @@
# See LICENSE for licensing information. # See LICENSE for licensing information.
# #
# Copyright (c) 2016-2023 Regents of the University of California and The Board # Copyright (c) 2016-2024 Regents of the University of California and The Board
# of Regents for the Oklahoma Agricultural and Mechanical College # of Regents for the Oklahoma Agricultural and Mechanical College
# (acting for and on behalf of Oklahoma State University) # (acting for and on behalf of Oklahoma State University)
# All rights reserved. # All rights reserved.
# #
import os import os
import re import re
from enum import Enum
from openram import debug from openram import debug
from openram import OPTS from openram import OPTS
@ -107,3 +108,33 @@ def check_dict_values_is_float(dict):
if type(value)!=float: if type(value)!=float:
return False return False
return True return True
def bidir_search(func, upper, lower, time_out=9):
"""
Performs bidirectional search over given function with given
upper and lower bounds.
"""
time_count = 0
while time_count < time_out:
val = (upper + lower) / 2
if func(val):
return (True, val)
time_count += 1
return (False, 0)
class bit_polarity(Enum):
NONINVERTING = 0
INVERTING = 1
class sram_op(Enum):
READ_ZERO = 0
READ_ONE = 1
WRITE_ZERO = 2
WRITE_ONE = 3
DISABLED_READ_ZERO = 4
DISABLED_READ_ONE = 5
DISABLED_WRITE_ZERO = 6
DISABLED_WRITE_ONE = 7

View File

@ -1,6 +1,6 @@
# See LICENSE for licensing information. # See LICENSE for licensing information.
# #
# Copyright (c) 2016-2023 Regents of the University of California and The Board # Copyright (c) 2016-2024 Regents of the University of California and The Board
# of Regents for the Oklahoma Agricultural and Mechanical College # of Regents for the Oklahoma Agricultural and Mechanical College
# (acting for and on behalf of Oklahoma State University) # (acting for and on behalf of Oklahoma State University)
# All rights reserved. # All rights reserved.
@ -13,10 +13,10 @@ from openram import OPTS
from .stimuli import * from .stimuli import *
from .trim_spice import * from .trim_spice import *
from .charutils import * from .charutils import *
from .sram_op import *
from .bit_polarity import *
from .simulation import simulation from .simulation import simulation
from .measurements import * from .measurements import *
from os import path
import re
class delay(simulation): class delay(simulation):
@ -37,7 +37,7 @@ class delay(simulation):
""" """
def __init__(self, sram, spfile, corner): def __init__(self, sram, spfile, corner, output_path=None):
super().__init__(sram, spfile, corner) super().__init__(sram, spfile, corner)
self.targ_read_ports = [] self.targ_read_ports = []
@ -47,10 +47,17 @@ class delay(simulation):
self.num_wmasks = int(math.ceil(self.word_size / self.write_size)) self.num_wmasks = int(math.ceil(self.word_size / self.write_size))
else: else:
self.num_wmasks = 0 self.num_wmasks = 0
if output_path is None:
self.output_path = OPTS.openram_temp
else:
self.output_path = output_path
self.set_load_slew(0, 0) self.set_load_slew(0, 0)
self.set_corner(corner) self.set_corner(corner)
self.create_signal_names() self.create_signal_names()
self.add_graph_exclusions() self.add_graph_exclusions()
self.meas_id = 0
def create_measurement_objects(self): def create_measurement_objects(self):
""" Create the measurements used for read and write ports """ """ Create the measurements used for read and write ports """
@ -79,10 +86,12 @@ class delay(simulation):
self.clk_frmt = "clk{0}" # Unformatted clock name self.clk_frmt = "clk{0}" # Unformatted clock name
targ_name = "{0}{{}}_{1}".format(self.dout_name, self.probe_data) # Empty values are the port and probe data bit targ_name = "{0}{{}}_{1}".format(self.dout_name, self.probe_data) # Empty values are the port and probe data bit
self.delay_meas = [] self.delay_meas = []
self.delay_meas.append(delay_measure("delay_lh", self.clk_frmt, targ_name, "RISE", "RISE", measure_scale=1e9)) self.delay_meas.append(delay_measure("delay_lh", self.clk_frmt, targ_name, "FALL", "RISE", measure_scale=1e9))
self.delay_meas[-1].meta_str = sram_op.READ_ONE # Used to index time delay values when measurements written to spice file. self.delay_meas[-1].meta_str = sram_op.READ_ONE # Used to index time delay values when measurements written to spice file.
self.delay_meas[-1].meta_add_delay = False
self.delay_meas.append(delay_measure("delay_hl", self.clk_frmt, targ_name, "FALL", "FALL", measure_scale=1e9)) self.delay_meas.append(delay_measure("delay_hl", self.clk_frmt, targ_name, "FALL", "FALL", measure_scale=1e9))
self.delay_meas[-1].meta_str = sram_op.READ_ZERO self.delay_meas[-1].meta_str = sram_op.READ_ZERO
self.delay_meas[-1].meta_add_delay = False
self.read_lib_meas+=self.delay_meas self.read_lib_meas+=self.delay_meas
self.slew_meas = [] self.slew_meas = []
@ -103,9 +112,10 @@ class delay(simulation):
self.read_lib_meas[-1].meta_str = "disabled_read0" self.read_lib_meas[-1].meta_str = "disabled_read0"
# This will later add a half-period to the spice time delay. Only for reading 0. # This will later add a half-period to the spice time delay. Only for reading 0.
for obj in self.read_lib_meas: # FIXME: Removed this to check, see if it affects anything
if obj.meta_str is sram_op.READ_ZERO: #for obj in self.read_lib_meas:
obj.meta_add_delay = True # if obj.meta_str is sram_op.READ_ZERO:
# obj.meta_add_delay = True
read_measures = [] read_measures = []
read_measures.append(self.read_lib_meas) read_measures.append(self.read_lib_meas)
@ -113,6 +123,8 @@ class delay(simulation):
read_measures.append(self.create_bitline_measurement_objects()) read_measures.append(self.create_bitline_measurement_objects())
read_measures.append(self.create_debug_measurement_objects()) read_measures.append(self.create_debug_measurement_objects())
read_measures.append(self.create_read_bit_measures()) read_measures.append(self.create_read_bit_measures())
# TODO: Maybe don't do this here (?)
if OPTS.top_process != "memchar":
read_measures.append(self.create_sen_and_bitline_path_measures()) read_measures.append(self.create_sen_and_bitline_path_measures())
return read_measures return read_measures
@ -158,6 +170,7 @@ class delay(simulation):
write_measures = [] write_measures = []
write_measures.append(self.write_lib_meas) write_measures.append(self.write_lib_meas)
write_measures.append(self.create_write_bit_measures()) write_measures.append(self.create_write_bit_measures())
return write_measures return write_measures
def create_debug_measurement_objects(self): def create_debug_measurement_objects(self):
@ -216,6 +229,10 @@ class delay(simulation):
bit_col = self.get_data_bit_column_number(probe_address, probe_data) bit_col = self.get_data_bit_column_number(probe_address, probe_data)
bit_row = self.get_address_row_number(probe_address) bit_row = self.get_address_row_number(probe_address)
if OPTS.top_process == "memchar":
cell_name = self.cell_name.format(bit_row, bit_col)
storage_names = ("Q", "Q_bar")
else:
(cell_name, cell_inst) = self.sram.get_cell_name(self.sram.name, bit_row, bit_col) (cell_name, cell_inst) = self.sram.get_cell_name(self.sram.name, bit_row, bit_col)
storage_names = cell_inst.mod.get_storage_net_names() storage_names = cell_inst.mod.get_storage_net_names()
debug.check(len(storage_names) == 2, ("Only inverting/non-inverting storage nodes" debug.check(len(storage_names) == 2, ("Only inverting/non-inverting storage nodes"
@ -239,8 +256,8 @@ class delay(simulation):
def create_sen_and_bitline_path_measures(self): def create_sen_and_bitline_path_measures(self):
"""Create measurements for the s_en and bitline paths for individual delays per stage.""" """Create measurements for the s_en and bitline paths for individual delays per stage."""
# FIXME: There should be a default_read_port variable in this case, pathing is done with this # # FIXME: There should be a default_read_port variable in this case, pathing is done with this
# but is never mentioned otherwise # # but is never mentioned otherwise
port = self.read_ports[0] port = self.read_ports[0]
sen_and_port = self.sen_name + str(port) sen_and_port = self.sen_name + str(port)
bl_and_port = self.bl_name.format(port) # bl_name contains a '{}' for the port bl_and_port = self.bl_name.format(port) # bl_name contains a '{}' for the port
@ -255,8 +272,8 @@ class delay(simulation):
bitline_path = bl_paths[0] bitline_path = bl_paths[0]
# Get the measures # Get the measures
self.sen_path_meas = self.create_delay_path_measures(sen_path) self.sen_path_meas = self.create_delay_path_measures(sen_path, "sen")
self.bl_path_meas = self.create_delay_path_measures(bitline_path) self.bl_path_meas = self.create_delay_path_measures(bitline_path, "bl")
all_meas = self.sen_path_meas + self.bl_path_meas all_meas = self.sen_path_meas + self.bl_path_meas
# Paths could have duplicate measurements, remove them before they go to the stim file # Paths could have duplicate measurements, remove them before they go to the stim file
@ -278,7 +295,7 @@ class delay(simulation):
return unique_measures return unique_measures
def create_delay_path_measures(self, path): def create_delay_path_measures(self, path, process):
"""Creates measurements for each net along given path.""" """Creates measurements for each net along given path."""
# Determine the directions (RISE/FALL) of signals # Determine the directions (RISE/FALL) of signals
@ -290,6 +307,8 @@ class delay(simulation):
cur_net, next_net = path[i], path[i + 1] cur_net, next_net = path[i], path[i + 1]
cur_dir, next_dir = path_dirs[i], path_dirs[i + 1] cur_dir, next_dir = path_dirs[i], path_dirs[i + 1]
meas_name = "delay_{0}_to_{1}".format(cur_net, next_net) meas_name = "delay_{0}_to_{1}".format(cur_net, next_net)
meas_name += "_" + process + "_id" + str(self.meas_id)
self.meas_id += 1
if i + 1 != len(path) - 1: if i + 1 != len(path) - 1:
path_meas.append(delay_measure(meas_name, cur_net, next_net, cur_dir, next_dir, measure_scale=1e9, has_port=False)) path_meas.append(delay_measure(meas_name, cur_net, next_net, cur_dir, next_dir, measure_scale=1e9, has_port=False))
else: # Make the last measurement always measure on FALL because is a read 0 else: # Make the last measurement always measure on FALL because is a read 0
@ -368,7 +387,7 @@ class delay(simulation):
self.sf.write("\n* SRAM output loads\n") self.sf.write("\n* SRAM output loads\n")
for port in self.read_ports: for port in self.read_ports:
for i in range(self.word_size): for i in range(self.word_size + self.num_spare_cols):
self.sf.write("CD{0}{1} {2}{0}_{1} 0 {3}f\n".format(port, i, self.dout_name, self.load)) self.sf.write("CD{0}{1} {2}{0}_{1} 0 {3}f\n".format(port, i, self.dout_name, self.load))
def write_delay_stimulus(self): def write_delay_stimulus(self):
@ -385,15 +404,20 @@ class delay(simulation):
# creates and opens stimulus file for writing # creates and opens stimulus file for writing
self.delay_stim_sp = "delay_stim.sp" self.delay_stim_sp = "delay_stim.sp"
temp_stim = "{0}/{1}".format(OPTS.openram_temp, self.delay_stim_sp) temp_stim = path.join(self.output_path, self.delay_stim_sp)
self.sf = open(temp_stim, "w") self.sf = open(temp_stim, "w")
# creates and opens measure file for writing
self.delay_meas_sp = "delay_meas.sp"
temp_meas = path.join(self.output_path, self.delay_meas_sp)
self.mf = open(temp_meas, "w")
if OPTS.spice_name == "spectre": if OPTS.spice_name == "spectre":
self.sf.write("simulator lang=spice\n") self.sf.write("simulator lang=spice\n")
self.sf.write("* Delay stimulus for period of {0}n load={1}fF slew={2}ns\n\n".format(self.period, self.sf.write("* Delay stimulus for period of {0}n load={1}fF slew={2}ns\n\n".format(self.period,
self.load, self.load,
self.slew)) self.slew))
self.stim = stimuli(self.sf, self.corner) self.stim = stimuli(self.sf, self.mf, self.corner)
# include files in stimulus file # include files in stimulus file
self.stim.write_include(self.trim_sp_file) self.stim.write_include(self.trim_sp_file)
@ -418,6 +442,7 @@ class delay(simulation):
t_rise=self.slew, t_rise=self.slew,
t_fall=self.slew) t_fall=self.slew)
self.sf.write(".include {0}".format(temp_meas))
# self.load_all_measure_nets() # self.load_all_measure_nets()
self.write_delay_measures() self.write_delay_measures()
# self.write_simulation_saves() # self.write_simulation_saves()
@ -426,6 +451,7 @@ class delay(simulation):
self.stim.write_control(self.cycle_times[-1] + self.period) self.stim.write_control(self.cycle_times[-1] + self.period)
self.sf.close() self.sf.close()
self.mf.close()
def write_power_stimulus(self, trim): def write_power_stimulus(self, trim):
""" Creates a stimulus file to measure leakage power only. """ Creates a stimulus file to measure leakage power only.
@ -435,10 +461,15 @@ class delay(simulation):
# creates and opens stimulus file for writing # creates and opens stimulus file for writing
self.power_stim_sp = "power_stim.sp" self.power_stim_sp = "power_stim.sp"
temp_stim = "{0}/{1}".format(OPTS.openram_temp, self.power_stim_sp) temp_stim = path.join(self.output_path, self.power_stim_sp)
self.sf = open(temp_stim, "w") self.sf = open(temp_stim, "w")
self.sf.write("* Power stimulus for period of {0}n\n\n".format(self.period)) self.sf.write("* Power stimulus for period of {0}n\n\n".format(self.period))
self.stim = stimuli(self.sf, self.corner)
# creates and opens measure file for writing
self.power_meas_sp = "power_meas.sp"
temp_meas = path.join(self.output_path, self.power_meas_sp)
self.mf = open(temp_meas, "w")
self.stim = stimuli(self.sf, self.mf, self.corner)
# include UNTRIMMED files in stimulus file # include UNTRIMMED files in stimulus file
if trim: if trim:
@ -451,7 +482,7 @@ class delay(simulation):
# generate data and addr signals # generate data and addr signals
self.sf.write("\n* Generation of data and address signals\n") self.sf.write("\n* Generation of data and address signals\n")
for write_port in self.write_ports: for write_port in self.write_ports:
for i in range(self.word_size): for i in range(self.word_size + self.num_spare_cols):
self.stim.gen_constant(sig_name="{0}{1}_{2} ".format(self.din_name, write_port, i), self.stim.gen_constant(sig_name="{0}{1}_{2} ".format(self.din_name, write_port, i),
v_val=0) v_val=0)
for port in self.all_ports: for port in self.all_ports:
@ -470,12 +501,14 @@ class delay(simulation):
for port in self.all_ports: for port in self.all_ports:
self.stim.gen_constant(sig_name="CLK{0}".format(port), v_val=0) self.stim.gen_constant(sig_name="CLK{0}".format(port), v_val=0)
self.sf.write(".include {}".format(temp_meas))
self.write_power_measures() self.write_power_measures()
# run until the end of the cycle time # run until the end of the cycle time
self.stim.write_control(2 * self.period) self.stim.write_control(2 * self.period)
self.sf.close() self.sf.close()
self.mf.close()
def get_measure_variants(self, port, measure_obj, measure_type=None): def get_measure_variants(self, port, measure_obj, measure_type=None):
""" """
@ -587,15 +620,15 @@ class delay(simulation):
# Output some comments to aid where cycles start and # Output some comments to aid where cycles start and
# what is happening # what is happening
for comment in self.cycle_comments: for comment in self.cycle_comments:
self.sf.write("* {0}\n".format(comment)) self.mf.write("* {0}\n".format(comment))
self.sf.write("\n") self.sf.write("\n")
for read_port in self.targ_read_ports: for read_port in self.targ_read_ports:
self.sf.write("* Read ports {0}\n".format(read_port)) self.mf.write("* Read ports {0}\n".format(read_port))
self.write_delay_measures_read_port(read_port) self.write_delay_measures_read_port(read_port)
for write_port in self.targ_write_ports: for write_port in self.targ_write_ports:
self.sf.write("* Write ports {0}\n".format(write_port)) self.mf.write("* Write ports {0}\n".format(write_port))
self.write_delay_measures_write_port(write_port) self.write_delay_measures_write_port(write_port)
def load_pex_net(self, net: str): def load_pex_net(self, net: str):
@ -605,8 +638,8 @@ class delay(simulation):
return net return net
original_net = net original_net = net
net = net[len(prefix):] net = net[len(prefix):]
net = net.replace(".", "_").replace("[", "\[").replace("]", "\]") net = net.replace(".", "_").replace("[", r"\[").replace("]", r"\]")
for pattern in ["\sN_{}_[MXmx]\S+_[gsd]".format(net), net]: for pattern in [r"\sN_{}_[MXmx]\S+_[gsd]".format(net), net]:
try: try:
match = check_output(["grep", "-m1", "-o", "-iE", pattern, self.sp_file]) match = check_output(["grep", "-m1", "-o", "-iE", pattern, self.sp_file])
return prefix + match.decode().strip() return prefix + match.decode().strip()
@ -616,8 +649,8 @@ class delay(simulation):
def load_all_measure_nets(self): def load_all_measure_nets(self):
measurement_nets = set() measurement_nets = set()
for port, meas in zip(self.targ_read_ports * len(self.read_meas_lists) + for port, meas in zip(self.targ_read_ports * len(self.read_meas_lists)
self.targ_write_ports * len(self.write_meas_lists), + self.targ_write_ports * len(self.write_meas_lists),
self.read_meas_lists + self.write_meas_lists): self.read_meas_lists + self.write_meas_lists):
for measurement in meas: for measurement in meas:
visited = getattr(measurement, 'pex_visited', False) visited = getattr(measurement, 'pex_visited', False)
@ -684,6 +717,8 @@ class delay(simulation):
self.sf.write("\n* Measure statements for idle leakage power\n") self.sf.write("\n* Measure statements for idle leakage power\n")
# add measure statements for power # add measure statements for power
# TODO: Convert to measure statement insted of using stimuli
# measure = power_measure('leakage_power',
t_initial = self.period t_initial = self.period
t_final = 2 * self.period t_final = 2 * self.period
self.stim.gen_meas_power(meas_name="leakage_power", self.stim.gen_meas_power(meas_name="leakage_power",
@ -828,6 +863,7 @@ class delay(simulation):
result[port].update(read_port_dict) result[port].update(read_port_dict)
if self.sen_path_meas and self.bl_path_meas:
self.path_delays = self.check_path_measures() self.path_delays = self.check_path_measures()
return (True, result) return (True, result)
@ -919,7 +955,7 @@ class delay(simulation):
def check_bitline_meas(self, v_discharged_bl, v_charged_bl): def check_bitline_meas(self, v_discharged_bl, v_charged_bl):
""" """
Checks the value of the discharging bitline. Confirms s_en timing errors. Checks the value of the discharging bitline. Confirms s_en timing errors.
Returns true if the bitlines are at there expected value. Returns true if the bitlines are at there their value.
""" """
# The inputs looks at discharge/charged bitline rather than left or right (bl/br) # The inputs looks at discharge/charged bitline rather than left or right (bl/br)
# Performs two checks, discharging bitline is at least 10% away from vdd and there is a # Performs two checks, discharging bitline is at least 10% away from vdd and there is a
@ -992,8 +1028,8 @@ class delay(simulation):
slews_str = "slew_hl={0} slew_lh={1}".format(slew_hl, slew_lh) slews_str = "slew_hl={0} slew_lh={1}".format(slew_hl, slew_lh)
# high-to-low delays start at neg. clk edge, so they need to be less than half_period # high-to-low delays start at neg. clk edge, so they need to be less than half_period
half_period = self.period / 2 half_period = self.period / 2
if abs(delay_hl)>half_period or abs(delay_lh)>self.period or abs(slew_hl)>half_period or abs(slew_lh)>self.period \ if abs(delay_hl)>half_period or abs(delay_lh)>half_period or abs(slew_hl)>half_period or abs(slew_lh)>self.period \
or delay_hl<0 or delay_lh<0 or slew_hl<0 or slew_lh<0: or (delay_hl<0 and delay_lh<0) or slew_hl<0 or slew_lh<0:
debug.info(2, "UNsuccessful simulation (in ns):\n\t\t{0}\n\t\t{1}\n\t\t{2}".format(period_load_slew_str, debug.info(2, "UNsuccessful simulation (in ns):\n\t\t{0}\n\t\t{1}\n\t\t{2}".format(period_load_slew_str,
delays_str, delays_str,
slews_str)) slews_str))
@ -1003,6 +1039,13 @@ class delay(simulation):
delays_str, delays_str,
slews_str)) slews_str))
if delay_lh < 0 and delay_hl > 0:
result_dict["delay_lh"] = result_dict["delay_hl"]
debug.info(2, "delay_lh captured precharge, using delay_hl instead")
elif delay_hl < 0 and delay_lh > 0:
result_dict["delay_hl"] = result_dict["delay_lh"]
debug.info(2, "delay_hl captured precharge, using delay_lh instead")
return True return True
def find_min_period(self, feasible_delays): def find_min_period(self, feasible_delays):
@ -1108,28 +1151,139 @@ class delay(simulation):
Netlist reduced for simulation. Netlist reduced for simulation.
""" """
super().set_probe(probe_address, probe_data) super().set_probe(probe_address, probe_data)
self.prepare_netlist()
def prepare_netlist(self): def prepare_netlist(self):
""" Prepare a trimmed netlist and regular netlist. """ """ Prepare a trimmed netlist and regular netlist. """
# Set up to trim the netlist here if that is enabled # Set up to trim the netlist here if that is enabled
# TODO: Copy old netlist if memchar
if OPTS.trim_netlist: if OPTS.trim_netlist:
#self.trim_sp_file = "{0}trimmed.sp".format(self.output_path)
self.trim_sp_file = "{0}trimmed.sp".format(OPTS.openram_temp) self.trim_sp_file = "{0}trimmed.sp".format(OPTS.openram_temp)
# Only genrate spice when running openram process
if OPTS.top_process != "memchar":
self.sram.sp_write(self.trim_sp_file, lvs=False, trim=True) self.sram.sp_write(self.trim_sp_file, lvs=False, trim=True)
else: else:
# The non-reduced netlist file when it is disabled # The non-reduced netlist file when it is disabled
self.trim_sp_file = "{0}sram.sp".format(OPTS.openram_temp) self.trim_sp_file = "{0}sram.sp".format(self.output_path)
# The non-reduced netlist file for power simulation # The non-reduced netlist file for power simulation
self.sim_sp_file = "{0}sram.sp".format(OPTS.openram_temp) self.sim_sp_file = "{0}sram.sp".format(self.output_path)
# Make a copy in temp for debugging # Make a copy in temp for debugging
if self.sp_file != self.sim_sp_file:
shutil.copy(self.sp_file, self.sim_sp_file) shutil.copy(self.sp_file, self.sim_sp_file)
def recover_measurment_objects(self):
mf_path = path.join(OPTS.output_path, "delay_meas.sp")
self.sen_path_meas = None
self.bl_path_meas = None
if not path.exists(mf_path):
debug.info(1, "Delay measure file not found. Skipping measure recovery")
return
mf = open(mf_path, "r")
measure_text = mf.read()
port_iter = re.finditer(r"\* (Read|Write) ports (\d*)", measure_text)
port_measure_lines = []
loc = 0
port_name = ''
for port in port_iter:
port_measure_lines.append((port_name, measure_text[loc:port.end(0)]))
loc = port.start(0)
port_name = port.group(1) + port.group(2)
mf.close()
# Cycle comments, not sure if i need this
# cycle_lines = port_measure_lines.pop(0)[1]
# For now just recover the bit_measures and sen_and_bitline_path_measures
self.read_meas_lists.append([])
self.read_bit_meas = {bit_polarity.NONINVERTING: [], bit_polarity.INVERTING: []}
self.write_bit_meas = {bit_polarity.NONINVERTING: [], bit_polarity.INVERTING: []}
# bit_measure_rule = re.compile(r"\.meas tran (v_q_a\d+_b\d+_(read|write)_(zero|one)\d+) FIND v\((.*)\) AT=(\d+(\.\d+)?)n")
# for measures in port_measure_lines:
# port_name = measures[0]
# text = measures[1]
# bit_measure_iter = bit_measure_rule.finditer(text)
# for bit_measure in bit_measure_iter:
# meas_name = bit_measure.group(1)
# read = bit_measure.group(2) == "read"
# cycle = bit_measure.group(3)
# probe = bit_measure.group(4)
# polarity = bit_polarity.NONINVERTING
# if "q_bar" in meas_name:
# polarity = bit_polarity.INVERTING
# meas = voltage_at_measure(meas_name, probe)
# if read:
# if cycle == "one":
# meas.meta_str = sram_op.READ_ONE
# else:
# meas.meta_str = sram_op.READ_ZERO
# self.read_bit_meas[polarity].append(meas)
# self.read_meas_lists[-1].append(meas)
# else:
# if cycle == "one":
# meas.meta_str = sram_op.WRITE_ONE
# else:
# meas.meta_str = sram_op.WRITE_ZERO
# self.write_bit_meas[polarity].append(meas)
# self.write_meas_lists[-1].append(meas)
delay_path_rule = re.compile(r"\.meas tran delay_(.*)_to_(.*)_(sen|bl)_(id\d*) TRIG v\((.*)\) VAL=(\d+(\.\d+)?) (RISE|FALL)=(\d+) TD=(\d+(\.\d+)?)n TARG v\((.*)\) VAL=(\d+(\.\d+)?) (RISE|FALL)=(\d+) TD=(\d+(\.\d+)?)n")
port = self.read_ports[0]
meas_buff = []
self.sen_path_meas = []
self.bl_path_meas = []
for measures in port_measure_lines:
text = measures[1]
delay_path_iter = delay_path_rule.finditer(text)
for delay_path_measure in delay_path_iter:
from_ = delay_path_measure.group(1)
to_ = delay_path_measure.group(2)
path_ = delay_path_measure.group(3)
id_ = delay_path_measure.group(4)
trig_rise = delay_path_measure.group(8)
targ_rise = delay_path_measure.group(15)
meas_name = "delay_{0}_to_{1}_{2}_{3}".format(from_, to_, path_, id_)
meas = delay_measure(meas_name, from_, to_, trig_rise, targ_rise, measure_scale=1e9, has_port=False)
meas.meta_str = sram_op.READ_ZERO
meas.meta_add_delay = True
meas_buff.append(meas)
if path_ == "sen":
self.sen_path_meas.extend(meas_buff.copy())
meas_buff.clear()
elif path_ == "bl":
self.bl_path_meas.extend(meas_buff.copy())
meas_buff.clear()
self.read_meas_lists.append(self.sen_path_meas + self.bl_path_meas)
def set_spice_names(self):
"""This is run in place of set_internal_spice_names function from
simulation.py when running stand-alone characterizer."""
self.bl_name = OPTS.bl_format.format(name=self.sram.name,
hier_sep=OPTS.hier_seperator,
row="{}",
col=self.bitline_column)
self.br_name = OPTS.br_format.format(name=self.sram.name,
hier_sep=OPTS.hier_seperator,
row="{}",
col=self.bitline_column)
self.sen_name = OPTS.sen_format.format(name=self.sram.name,
hier_sep=OPTS.hier_seperator)
self.cell_name = OPTS.cell_format.format(name=self.sram.name,
hier_sep=OPTS.hier_seperator,
row="{}",
col="{}")
def analysis_init(self, probe_address, probe_data): def analysis_init(self, probe_address, probe_data):
"""Sets values which are dependent on the data address/bit being tested.""" """Sets values which are dependent on the data address/bit being tested."""
self.set_probe(probe_address, probe_data) self.set_probe(probe_address, probe_data)
self.prepare_netlist()
if OPTS.top_process == "memchar":
self.set_spice_names()
self.create_measurement_names()
self.create_measurement_objects()
self.recover_measurment_objects()
else:
self.create_graph() self.create_graph()
self.set_internal_spice_names() self.set_internal_spice_names()
self.create_measurement_names() self.create_measurement_names()
@ -1168,9 +1322,10 @@ class delay(simulation):
# 4) At the minimum period, measure the delay, slew and power for all slew/load pairs. # 4) At the minimum period, measure the delay, slew and power for all slew/load pairs.
self.period = min_period self.period = min_period
char_port_data = self.simulate_loads_and_slews(load_slews, leakage_offset) char_port_data = self.simulate_loads_and_slews(load_slews, leakage_offset)
if OPTS.use_specified_load_slew != None and len(load_slews) > 1: if OPTS.use_specified_load_slew is not None and len(load_slews) > 1:
debug.warning("Path delay lists not correctly generated for characterizations of more than 1 load,slew") debug.warning("Path delay lists not correctly generated for characterizations of more than 1 load,slew")
# Get and save the path delays # Get and save the path delays
if self.sen_path_meas and self.bl_path_meas:
bl_names, bl_delays, sen_names, sen_delays = self.get_delay_lists(self.path_delays) bl_names, bl_delays, sen_names, sen_delays = self.get_delay_lists(self.path_delays)
# Removed from characterization output temporarily # Removed from characterization output temporarily
# char_sram_data["bl_path_measures"] = bl_delays # char_sram_data["bl_path_measures"] = bl_delays
@ -1194,7 +1349,6 @@ class delay(simulation):
"""Simulate all specified output loads and input slews pairs of all ports""" """Simulate all specified output loads and input slews pairs of all ports"""
measure_data = self.get_empty_measure_data_dict() measure_data = self.get_empty_measure_data_dict()
path_dict = {}
# Set the target simulation ports to all available ports. This make sims slower but failed sims exit anyways. # Set the target simulation ports to all available ports. This make sims slower but failed sims exit anyways.
self.targ_read_ports = self.read_ports self.targ_read_ports = self.read_ports
self.targ_write_ports = self.write_ports self.targ_write_ports = self.write_ports
@ -1255,8 +1409,8 @@ class delay(simulation):
inverse_address = self.calculate_inverse_address() inverse_address = self.calculate_inverse_address()
# For now, ignore data patterns and write ones or zeros # For now, ignore data patterns and write ones or zeros
data_ones = "1" * self.word_size data_ones = "1" * (self.word_size + self.num_spare_cols)
data_zeros = "0" * self.word_size data_zeros = "0" * (self.word_size + self.num_spare_cols)
wmask_ones = "1" * self.num_wmasks wmask_ones = "1" * self.num_wmasks
if self.t_current == 0: if self.t_current == 0:
@ -1352,9 +1506,9 @@ class delay(simulation):
# Get any available read/write port in case only a single write or read ports is being characterized. # Get any available read/write port in case only a single write or read ports is being characterized.
cur_read_port = self.get_available_port(get_read_port=True) cur_read_port = self.get_available_port(get_read_port=True)
cur_write_port = self.get_available_port(get_read_port=False) cur_write_port = self.get_available_port(get_read_port=False)
debug.check(cur_read_port != None, debug.check(cur_read_port is not None,
"Characterizer requires at least 1 read port") "Characterizer requires at least 1 read port")
debug.check(cur_write_port != None, debug.check(cur_write_port is not None,
"Characterizer requires at least 1 write port") "Characterizer requires at least 1 write port")
# Create test cycles for specified target ports. # Create test cycles for specified target ports.
@ -1380,7 +1534,7 @@ class delay(simulation):
""" Generates the PWL data inputs for a simulation timing test. """ """ Generates the PWL data inputs for a simulation timing test. """
for write_port in self.write_ports: for write_port in self.write_ports:
for i in range(self.word_size): for i in range(self.word_size + self.num_spare_cols):
sig_name="{0}{1}_{2} ".format(self.din_name, write_port, i) sig_name="{0}{1}_{2} ".format(self.din_name, write_port, i)
self.stim.gen_pwl(sig_name, self.cycle_times, self.data_values[write_port][i], self.period, self.slew, 0.05) self.stim.gen_pwl(sig_name, self.cycle_times, self.data_values[write_port][i], self.period, self.slew, 0.05)
@ -1402,3 +1556,6 @@ class delay(simulation):
self.stim.gen_pwl("CSB{0}".format(port), self.cycle_times, self.csb_values[port], self.period, self.slew, 0.05) self.stim.gen_pwl("CSB{0}".format(port), self.cycle_times, self.csb_values[port], self.period, self.slew, 0.05)
if port in self.readwrite_ports: if port in self.readwrite_ports:
self.stim.gen_pwl("WEB{0}".format(port), self.cycle_times, self.web_values[port], self.period, self.slew, 0.05) self.stim.gen_pwl("WEB{0}".format(port), self.cycle_times, self.web_values[port], self.period, self.slew, 0.05)
if self.sram.num_wmasks:
for bit in range(self.sram.num_wmasks):
self.stim.gen_pwl("WMASK{0}_{1}".format(port, bit), self.cycle_times, self.wmask_values[port][bit], self.period, self.slew, 0.05)

View File

@ -1,6 +1,6 @@
# See LICENSE for licensing information. # See LICENSE for licensing information.
# #
# Copyright (c) 2016-2023 Regents of the University of California and The Board # Copyright (c) 2016-2024 Regents of the University of California and The Board
# of Regents for the Oklahoma Agricultural and Mechanical College # of Regents for the Oklahoma Agricultural and Mechanical College
# (acting for and on behalf of Oklahoma State University) # (acting for and on behalf of Oklahoma State University)
# All rights reserved. # All rights reserved.

View File

@ -0,0 +1,108 @@
# See LICENSE for licensing information.
#
# Copyright (c) 2016-2024 Regents of the University of California, Santa Cruz
# All rights reserved.
#
from openram import sram_config
from math import ceil
from openram import OPTS
class fake_sram(sram_config):
"""
This is an SRAM class that doesn't actually create an instance.
It will read neccessary members from HTML file from a previous run.
"""
def __init__(self, name, word_size, num_words, write_size=None, num_banks=1,
words_per_row=None, num_spare_rows=0, num_spare_cols=0):
sram_config.__init__(self, word_size, num_words, write_size,
num_banks, words_per_row, num_spare_rows,
num_spare_cols)
self.name = name
if write_size and self.write_size != self.word_size:
self.num_wmasks = int(ceil(self.word_size / self.write_size))
else:
self.num_wmasks = 0
def setup_multiport_constants(self):
"""
Taken from ../base/design.py
These are contants and lists that aid multiport design.
Ports are always in the order RW, W, R.
Port indices start from 0 and increment.
A first RW port will have clk0, csb0, web0, addr0, data0
A first W port (with no RW ports) will be: clk0, csb0, addr0, data0
"""
total_ports = OPTS.num_rw_ports + OPTS.num_w_ports + OPTS.num_r_ports
# These are the read/write port indices.
self.readwrite_ports = []
# These are the read/write and write-only port indices
self.write_ports = []
# These are the write-only port indices.
self.writeonly_ports = []
# These are the read/write and read-only port indices
self.read_ports = []
# These are the read-only port indices.
self.readonly_ports = []
# These are all the ports
self.all_ports = list(range(total_ports))
# The order is always fixed as RW, W, R
port_number = 0
for port in range(OPTS.num_rw_ports):
self.readwrite_ports.append(port_number)
self.write_ports.append(port_number)
self.read_ports.append(port_number)
port_number += 1
for port in range(OPTS.num_w_ports):
self.write_ports.append(port_number)
self.writeonly_ports.append(port_number)
port_number += 1
for port in range(OPTS.num_r_ports):
self.read_ports.append(port_number)
self.readonly_ports.append(port_number)
port_number += 1
def generate_pins(self):
self.pins = ['vdd', 'gnd']
self.pins.extend(['clk{}'.format(port) for port in range(
OPTS.num_rw_ports + OPTS.num_r_ports + OPTS.num_w_ports)])
for port in range(OPTS.num_rw_ports):
self.pins.extend(['din{0}[{1}]'.format(port, bit)
for bit in range(self.word_size + self.num_spare_cols)])
self.pins.extend(['dout{0}[{1}]'.format(port, bit)
for bit in range(self.word_size + self.num_spare_cols)])
self.pins.extend(['addr{0}[{1}]'.format(port, bit)
for bit in range(self.addr_size)])
self.pins.extend(['spare_wen{0}[{1}]'.format(port, bit)
for bit in range(self.num_spare_cols)])
if self.num_wmasks != 0:
self.pins.extend(['wmask{0}[{1}]'.format(port, bit)
for bit in range(self.num_wmasks)])
self.pins.extend(['csb{}'.format(port), 'web{}'.format(port)])
start_port = OPTS.num_rw_ports
for port in range(start_port, start_port + OPTS.num_r_ports):
self.pins.extend(['dout{0}[{1}]'.format(port, bit)
for bit in range(self.word_size + self.num_spare_cols)])
self.pins.extend(['addr{0}[{1}]'.format(port, bit)
for bit in range(self.addr_size)])
self.pins.extend(['csb{}'.format(port)])
start_port += OPTS.num_r_ports
for port in range(start_port, start_port + OPTS.num_w_ports):
self.pins.extend(['din{0}[{1}]'.format(port, bit)
for bit in range(self.word_size + self.num_spare_cols)])
self.pins.extend(['spare_wen{0}[{1}]'.format(port, bit)
for bit in range(self.num_spare_cols)])
self.pins.extend(['addr{0}[{1}]'.format(port, bit)
for bit in range(self.addr_size)])
if self.num_wmasks != 0:
self.pins.extend(['wmask{0}[{1}]'.format(port, bit)
for bit in range(self.num_wmasks)])
self.pins.extend(['csb{}'.format(port), 'web{}'.format(port)])

View File

@ -1,19 +1,23 @@
# See LICENSE for licensing information. # See LICENSE for licensing information.
# #
# Copyright (c) 2016-2023 Regents of the University of California and The Board # Copyright (c) 2016-2024 Regents of the University of California and The Board
# of Regents for the Oklahoma Agricultural and Mechanical College # of Regents for the Oklahoma Agricultural and Mechanical College
# (acting for and on behalf of Oklahoma State University) # (acting for and on behalf of Oklahoma State University)
# All rights reserved. # All rights reserved.
# #
import math import math
import random import random
import time
import collections import collections
from os import path
import shutil
from numpy import binary_repr from numpy import binary_repr
from openram import debug from openram import debug
from openram import OPTS from openram import OPTS
from .stimuli import * from .stimuli import *
from .charutils import * from .charutils import *
from .simulation import simulation from .simulation import simulation
from .measurements import voltage_at_measure
class functional(simulation): class functional(simulation):
@ -28,17 +32,27 @@ class functional(simulation):
# Seed the characterizer with a constant seed for unit tests # Seed the characterizer with a constant seed for unit tests
if OPTS.is_unit_test: if OPTS.is_unit_test:
random.seed(12345) random.seed(12345)
elif OPTS.functional_seed:
random.seed(OPTS.functional_seed)
else:
seed = time.time_ns()
random.seed(seed)
debug.info(1, "Random seed for functional simulation: {}".format(seed))
if not spfile: if not spfile:
# self.sp_file is assigned in base class # self.sp_file is assigned in base class
sram.sp_write(self.sp_file, trim=OPTS.trim_netlist) sram.sp_write(self.sp_file, trim=OPTS.trim_netlist)
# Copy sp file to temp dir
self.temp_spice = path.join(OPTS.openram_temp, "sram.sp")
try:
shutil.copy(self.sp_file, self.temp_spice)
except shutil.SameFileError: # skip if the same
pass
if not corner: if not corner:
corner = (OPTS.process_corners[0], OPTS.supply_voltages[0], OPTS.temperatures[0]) corner = (OPTS.process_corners[0], OPTS.supply_voltages[0], OPTS.temperatures[0])
if period:
self.period = period
if not output_path: if not output_path:
self.output_path = OPTS.openram_temp self.output_path = OPTS.openram_temp
else: else:
@ -73,13 +87,20 @@ class functional(simulation):
self.set_spice_constants() self.set_spice_constants()
self.set_stimulus_variables() self.set_stimulus_variables()
# Override default period
if period:
self.period = period
# For the debug signal names # For the debug signal names
self.wordline_row = 0 self.wordline_row = 0
self.bitline_column = 0 self.bitline_column = 0
self.create_signal_names() self.create_signal_names()
self.add_graph_exclusions() #self.add_graph_exclusions()
self.create_graph() #self.create_graph()
self.set_internal_spice_names() #self.set_internal_spice_names()
self.bl_name = "xsram:xbank0:bl_0_{}"
self.br_name = "xsram:xbank0:br_0_{}"
self.sen_name = "xsram:s_en"
self.q_name, self.qbar_name = self.get_bit_name() self.q_name, self.qbar_name = self.get_bit_name()
debug.info(2, "q:\t\t{0}".format(self.q_name)) debug.info(2, "q:\t\t{0}".format(self.q_name))
debug.info(2, "qbar:\t{0}".format(self.qbar_name)) debug.info(2, "qbar:\t{0}".format(self.qbar_name))
@ -145,7 +166,6 @@ class functional(simulation):
comment = self.gen_cycle_comment("noop", "0" * self.word_size, "0" * self.bank_addr_size, "0" * self.num_wmasks, 0, self.t_current) comment = self.gen_cycle_comment("noop", "0" * self.word_size, "0" * self.bank_addr_size, "0" * self.num_wmasks, 0, self.t_current)
self.add_noop_all_ports(comment) self.add_noop_all_ports(comment)
# 1. Write all the write ports 2x to seed a bunch of locations. # 1. Write all the write ports 2x to seed a bunch of locations.
for i in range(3): for i in range(3):
for port in self.write_ports: for port in self.write_ports:
@ -275,7 +295,8 @@ class functional(simulation):
sp_read_value = "" sp_read_value = ""
for bit in range(self.word_size + self.num_spare_cols): for bit in range(self.word_size + self.num_spare_cols):
measure_name = "v{0}_{1}ck{2}".format(dout_port.lower(), bit, cycle) measure_name = "v{0}_{1}ck{2}".format(dout_port.lower(), bit, cycle)
value = parse_spice_list("timing", measure_name) # value = parse_spice_list("timing", measure_name)
value = self.measures[measure_name].retrieve_measure(port=0)
# FIXME: Ignore the spare columns for now # FIXME: Ignore the spare columns for now
if bit >= self.word_size: if bit >= self.word_size:
value = 0 value = 0
@ -294,10 +315,11 @@ class functional(simulation):
self.v_low, self.v_low,
self.v_high) self.v_high)
except ValueError: except ValueError:
error ="FAILED: {0}_{1} value {2} at time {3}n is not a float.".format(dout_port, error ="FAILED: {0}_{1} value {2} at time {3}n is not a float. Measure: {4}".format(dout_port,
bit, bit,
value, value,
eo_period) eo_period,
measure_name)
return (0, error) return (0, error)
self.read_results.append([sp_read_value, dout_port, eo_period, cycle]) self.read_results.append([sp_read_value, dout_port, eo_period, cycle])
@ -347,7 +369,7 @@ class functional(simulation):
def gen_data(self): def gen_data(self):
""" Generates a random word to write. """ """ Generates a random word to write. """
# Don't use 0 or max value # Don't use 0 or max value
random_value = random.randint(1, self.max_data - 1) random_value = random.randint(1, self.max_data)
data_bits = binary_repr(random_value, self.word_size) data_bits = binary_repr(random_value, self.word_size)
if self.num_spare_cols>0: if self.num_spare_cols>0:
random_value = random.randint(0, self.max_col_data) random_value = random.randint(0, self.max_col_data)
@ -380,13 +402,16 @@ class functional(simulation):
def write_functional_stimulus(self): def write_functional_stimulus(self):
""" Writes SPICE stimulus. """ """ Writes SPICE stimulus. """
self.stim_sp = "functional_stim.sp" self.stim_sp = "functional_stim.sp"
temp_stim = "{0}/{1}".format(self.output_path, self.stim_sp) temp_stim = path.join(self.output_path, self.stim_sp)
self.sf = open(temp_stim, "w") self.sf = open(temp_stim, "w")
self.sf.write("* Functional test stimulus file for {0}ns period\n\n".format(self.period)) self.sf.write("* Functional test stimulus file for {0}ns period\n\n".format(self.period))
self.stim = stimuli(self.sf, self.corner) self.meas_sp = "functional_meas.sp"
temp_meas = path.join(self.output_path, self.meas_sp)
self.mf = open(temp_meas, "w")
self.stim = stimuli(self.sf, self.mf, self.corner)
# Write include statements # Write include statements
self.stim.write_include(self.sp_file) self.stim.write_include(self.temp_spice)
# Write Vdd/Gnd statements # Write Vdd/Gnd statements
self.sf.write("\n* Global Power Supplies\n") self.sf.write("\n* Global Power Supplies\n")
@ -470,6 +495,7 @@ class functional(simulation):
# Generate dout value measurements # Generate dout value measurements
self.sf.write("\n * Generation of dout measurements\n") self.sf.write("\n * Generation of dout measurements\n")
self.measures = {}
for (word, dout_port, eo_period, cycle) in self.read_check: for (word, dout_port, eo_period, cycle) in self.read_check:
t_initial = eo_period t_initial = eo_period
@ -477,28 +503,37 @@ class functional(simulation):
num_bits = self.word_size + self.num_spare_cols num_bits = self.word_size + self.num_spare_cols
for bit in range(num_bits): for bit in range(num_bits):
signal_name = "{0}_{1}".format(dout_port, bit) signal_name = "{0}_{1}".format(dout_port, bit)
measure_name = "V{0}ck{1}".format(signal_name, cycle) measure_name = "v{0}ck{1}".format(signal_name, cycle)
voltage_value = self.stim.get_voltage(word[num_bits - bit - 1]) voltage_value = self.stim.get_voltage(word[num_bits - bit - 1])
self.stim.add_comment("* CHECK {0} {1} = {2} time = {3}".format(signal_name, self.stim.add_comment("* CHECK {0} {1} = {2} time = {3}".format(signal_name,
measure_name, measure_name,
voltage_value, voltage_value,
eo_period)) eo_period))
self.stim.gen_meas_value(meas_name=measure_name, # TODO: Convert to measurement statement instead of stimuli
dout=signal_name, meas = voltage_at_measure(measure_name, signal_name)
t_initial=t_initial, self.measures[measure_name] = meas
t_final=t_final) meas.write_measure(self.stim, ((t_initial + t_final) / 2, 0))
# self.stim.gen_meas_value(meas_name=measure_name,
# dout=signal_name,
# t_initial=t_initial,
# t_final=t_final
self.sf.write(".include {0}\n".format(temp_meas))
self.stim.write_control(self.cycle_times[-1] + self.period) self.stim.write_control(self.cycle_times[-1] + self.period)
self.sf.close() self.sf.close()
self.mf.close()
# FIXME: Similar function to delay.py, refactor this # FIXME: Similar function to delay.py, refactor this
def get_bit_name(self): def get_bit_name(self):
""" Get a bit cell name """ """ Get a bit cell name """
(cell_name, cell_inst) = self.sram.get_cell_name(self.sram.name, 0, 0) # TODO: Find a way to get the cell_name and storage_names statically
storage_names = cell_inst.mod.get_storage_net_names() # (cell_name, cell_inst) = self.sram.get_cell_name(self.sram.name, 0, 0)
debug.check(len(storage_names) == 2, ("Only inverting/non-inverting storage nodes" # storage_names = cell_inst.mod.get_storage_net_names()
"supported for characterization. Storage nets={0}").format(storage_names)) # debug.check(len(storage_names) == 2, ("Only inverting/non-inverting storage nodes"
# "supported for characterization. Storage nets={0}").format(storage_names))
cell_name = "xsram:xbank0:xbitcell_array:xbitcell_array:xbit_r0_c0"
storage_names = ("Q", "Q_bar")
q_name = cell_name + OPTS.hier_seperator + str(storage_names[0]) q_name = cell_name + OPTS.hier_seperator + str(storage_names[0])
qbar_name = cell_name + OPTS.hier_seperator + str(storage_names[1]) qbar_name = cell_name + OPTS.hier_seperator + str(storage_names[1])

View File

@ -1,6 +1,6 @@
# See LICENSE for licensing information. # See LICENSE for licensing information.
# #
# Copyright (c) 2016-2023 Regents of the University of California and The Board # Copyright (c) 2016-2024 Regents of the University of California and The Board
# of Regents for the Oklahoma Agricultural and Mechanical College # of Regents for the Oklahoma Agricultural and Mechanical College
# (acting for and on behalf of Oklahoma State University) # (acting for and on behalf of Oklahoma State University)
# All rights reserved. # All rights reserved.
@ -82,6 +82,7 @@ class lib:
debug.info(1, "Slews: {0}".format(self.slews)) debug.info(1, "Slews: {0}".format(self.slews))
debug.info(1, "Loads: {0}".format(self.loads)) debug.info(1, "Loads: {0}".format(self.loads))
debug.info(1, "self.load_slews : {0}".format(self.load_slews)) debug.info(1, "self.load_slews : {0}".format(self.load_slews))
def create_corners(self): def create_corners(self):
""" Create corners for characterization. """ """ Create corners for characterization. """
# Get the corners from the options file # Get the corners from the options file
@ -801,6 +802,7 @@ class lib:
# information of checks # information of checks
# run it only the first time # run it only the first time
if OPTS.top_process != "memchar":
datasheet.write("{0},{1},".format(self.sram.drc_errors, self.sram.lvs_errors)) datasheet.write("{0},{1},".format(self.sram.drc_errors, self.sram.lvs_errors))
# write area # write area

View File

@ -1,6 +1,6 @@
# See LICENSE for licensing information. # See LICENSE for licensing information.
# #
# Copyright (c) 2016-2023 Regents of the University of California and The Board # Copyright (c) 2016-2024 Regents of the University of California and The Board
# of Regents for the Oklahoma Agricultural and Mechanical College # of Regents for the Oklahoma Agricultural and Mechanical College
# (acting for and on behalf of Oklahoma State University) # (acting for and on behalf of Oklahoma State University)
# All rights reserved. # All rights reserved.

View File

@ -1,6 +1,6 @@
# See LICENSE for licensing information. # See LICENSE for licensing information.
# #
# Copyright (c) 2016-2023 Regents of the University of California and The Board # Copyright (c) 2016-2024 Regents of the University of California and The Board
# of Regents for the Oklahoma Agricultural and Mechanical College # of Regents for the Oklahoma Agricultural and Mechanical College
# (acting for and on behalf of Oklahoma State University) # (acting for and on behalf of Oklahoma State University)
# All rights reserved. # All rights reserved.
@ -22,8 +22,9 @@ class spice_measurement(ABC):
# Some meta values used externally. variables are added here for consistency accross the objects # Some meta values used externally. variables are added here for consistency accross the objects
self.meta_str = None self.meta_str = None
self.meta_add_delay = False self.meta_add_delay = False
@abstractmethod @abstractmethod
def get_measure_function(self): def measure_function(self):
return None return None
@abstractmethod @abstractmethod
@ -31,27 +32,24 @@ class spice_measurement(ABC):
return None return None
def write_measure(self, stim_obj, input_tuple): def write_measure(self, stim_obj, input_tuple):
measure_func = self.get_measure_function()
if measure_func == None:
debug.error("Did not set measure function",1)
measure_vals = self.get_measure_values(*input_tuple) measure_vals = self.get_measure_values(*input_tuple)
measure_func(stim_obj, *measure_vals) self.measure_function(stim_obj, *measure_vals)
def retrieve_measure(self, port=None): def retrieve_measure(self, port=None):
self.port_error_check(port) self.port_error_check(port)
if port != None: if port is not None:
value = parse_spice_list("timing", "{0}{1}".format(self.name.lower(), port)) value = parse_spice_list("timing", "{0}{1}".format(self.name.lower(), port))
else: else:
value = parse_spice_list("timing", "{0}".format(self.name.lower())) value = parse_spice_list("timing", "{0}".format(self.name.lower()))
if type(value)!=float or self.measure_scale == None: if type(value)!=float or self.measure_scale is None:
return value return value
else: else:
return value * self.measure_scale return value * self.measure_scale
def port_error_check(self, port): def port_error_check(self, port):
if self.has_port and port == None: if self.has_port and port is None:
debug.error("Cannot retrieve measurement, port input was expected.", 1) debug.error("Cannot retrieve measurement, port input was expected.", 1)
elif not self.has_port and port != None: elif not self.has_port and port is not None:
debug.error("Unexpected port input received during measure retrieval.", 1) debug.error("Unexpected port input received during measure retrieval.", 1)
@ -71,8 +69,18 @@ class delay_measure(spice_measurement):
spice_measurement.__init__(self, measure_name, measure_scale, has_port) spice_measurement.__init__(self, measure_name, measure_scale, has_port)
self.set_meas_constants(trig_name, targ_name, trig_dir_str, targ_dir_str, trig_vdd, targ_vdd) self.set_meas_constants(trig_name, targ_name, trig_dir_str, targ_dir_str, trig_vdd, targ_vdd)
def get_measure_function(self): def measure_function(self, stim_obj, meas_name, trig_name, targ_name, trig_val, targ_val, trig_dir, targ_dir, trig_td, targ_td):
return stimuli.gen_meas_delay """ Creates the .meas statement for the measurement of delay """
measure_string=".meas tran {0} TRIG v({1}) VAL={2} {3}=1 TD={4}n TARG v({5}) VAL={6} {7}=1 TD={8}n\n\n"
stim_obj.mf.write(measure_string.format(meas_name.lower(),
trig_name,
trig_val,
trig_dir,
trig_td,
targ_name,
targ_val,
targ_dir,
targ_td))
def set_meas_constants(self, trig_name, targ_name, trig_dir_str, targ_dir_str, trig_vdd, targ_vdd): def set_meas_constants(self, trig_name, targ_name, trig_dir_str, targ_dir_str, trig_vdd, targ_vdd):
"""Set the constants for this measurement: signal names, directions, and trigger scales""" """Set the constants for this measurement: signal names, directions, and trigger scales"""
@ -91,7 +99,7 @@ class delay_measure(spice_measurement):
trig_val = self.trig_val_of_vdd * vdd_voltage trig_val = self.trig_val_of_vdd * vdd_voltage
targ_val = self.targ_val_of_vdd * vdd_voltage targ_val = self.targ_val_of_vdd * vdd_voltage
if port != None: if port is not None:
# For dictionary indexing reasons, the name is formatted differently than the signals # For dictionary indexing reasons, the name is formatted differently than the signals
meas_name = "{}{}".format(self.name, port) meas_name = "{}{}".format(self.name, port)
trig_name = self.trig_name_no_port.format(port) trig_name = self.trig_name_no_port.format(port)
@ -135,8 +143,18 @@ class power_measure(spice_measurement):
spice_measurement.__init__(self, measure_name, measure_scale, has_port) spice_measurement.__init__(self, measure_name, measure_scale, has_port)
self.set_meas_constants(power_type) self.set_meas_constants(power_type)
def get_measure_function(self): def measure_function(self, stim_obj, meas_name, t_initial, t_final):
return stimuli.gen_meas_power """ Creates the .meas statement for the measurement of avg power """
# power mea cmd is different in different spice:
if OPTS.spice_name == "hspice":
power_exp = "power"
else:
# FIXME: Obtain proper vdd and gnd name
power_exp = "par('(-1*v(" + "vdd" + ")*I(v" + "vdd" + "))')"
stim_obj.mf.write(".meas tran {0} avg {1} from={2}n to={3}n\n\n".format(meas_name.lower(),
power_exp,
t_initial,
t_final))
def set_meas_constants(self, power_type): def set_meas_constants(self, power_type):
"""Sets values useful for power simulations. This value is only meta related to the lib file (rise/fall)""" """Sets values useful for power simulations. This value is only meta related to the lib file (rise/fall)"""
@ -146,7 +164,7 @@ class power_measure(spice_measurement):
def get_measure_values(self, t_initial, t_final, port=None): def get_measure_values(self, t_initial, t_final, port=None):
"""Constructs inputs to stimulus measurement function. Variant values are inputs here.""" """Constructs inputs to stimulus measurement function. Variant values are inputs here."""
self.port_error_check(port) self.port_error_check(port)
if port != None: if port is not None:
meas_name = "{}{}".format(self.name, port) meas_name = "{}{}".format(self.name, port)
else: else:
meas_name = self.name meas_name = self.name
@ -160,8 +178,15 @@ class voltage_when_measure(spice_measurement):
spice_measurement.__init__(self, measure_name, measure_scale, has_port) spice_measurement.__init__(self, measure_name, measure_scale, has_port)
self.set_meas_constants(trig_name, targ_name, trig_dir_str, trig_vdd) self.set_meas_constants(trig_name, targ_name, trig_dir_str, trig_vdd)
def get_measure_function(self): def measure_function(self, stim_obj, meas_name, trig_name, targ_name, trig_val, trig_dir, trig_td):
return stimuli.gen_meas_find_voltage """ Creates the .meas statement for the measurement of delay """
measure_string=".meas tran {0} FIND v({1}) WHEN v({2})={3}v {4}=1 TD={5}n \n\n"
stim_obj.mf.write(measure_string.format(meas_name.lower(),
targ_name,
trig_name,
trig_val,
trig_dir,
trig_td))
def set_meas_constants(self, trig_name, targ_name, trig_dir_str, trig_vdd): def set_meas_constants(self, trig_name, targ_name, trig_dir_str, trig_vdd):
"""Sets values useful for power simulations. This value is only meta related to the lib file (rise/fall)""" """Sets values useful for power simulations. This value is only meta related to the lib file (rise/fall)"""
@ -173,7 +198,7 @@ class voltage_when_measure(spice_measurement):
def get_measure_values(self, trig_td, vdd_voltage, port=None): def get_measure_values(self, trig_td, vdd_voltage, port=None):
"""Constructs inputs to stimulus measurement function. Variant values are inputs here.""" """Constructs inputs to stimulus measurement function. Variant values are inputs here."""
self.port_error_check(port) self.port_error_check(port)
if port != None: if port is not None:
# For dictionary indexing reasons, the name is formatted differently than the signals # For dictionary indexing reasons, the name is formatted differently than the signals
meas_name = "{}{}".format(self.name, port) meas_name = "{}{}".format(self.name, port)
trig_name = self.trig_name_no_port.format(port) trig_name = self.trig_name_no_port.format(port)
@ -194,8 +219,12 @@ class voltage_at_measure(spice_measurement):
spice_measurement.__init__(self, measure_name, measure_scale, has_port) spice_measurement.__init__(self, measure_name, measure_scale, has_port)
self.set_meas_constants(targ_name) self.set_meas_constants(targ_name)
def get_measure_function(self): def measure_function(self, stim_obj, meas_name, targ_name, time_at):
return stimuli.gen_meas_find_voltage_at_time """ Creates the .meas statement for voltage at time"""
measure_string=".meas tran {0} FIND v({1}) AT={2}n \n\n"
stim_obj.mf.write(measure_string.format(meas_name.lower(),
targ_name,
time_at))
def set_meas_constants(self, targ_name): def set_meas_constants(self, targ_name):
"""Sets values useful for power simulations. This value is only meta related to the lib file (rise/fall)""" """Sets values useful for power simulations. This value is only meta related to the lib file (rise/fall)"""
@ -204,7 +233,7 @@ class voltage_at_measure(spice_measurement):
def get_measure_values(self, time_at, port=None): def get_measure_values(self, time_at, port=None):
"""Constructs inputs to stimulus measurement function. Variant values are inputs here.""" """Constructs inputs to stimulus measurement function. Variant values are inputs here."""
self.port_error_check(port) self.port_error_check(port)
if port != None: if port is not None:
# For dictionary indexing reasons, the name is formatted differently than the signals # For dictionary indexing reasons, the name is formatted differently than the signals
meas_name = "{}{}".format(self.name, port) meas_name = "{}{}".format(self.name, port)
targ_name = self.targ_name_no_port.format(port) targ_name = self.targ_name_no_port.format(port)

View File

@ -1,6 +1,6 @@
# See LICENSE for licensing information. # See LICENSE for licensing information.
# #
# Copyright (c) 2016-2023 Regents of the University of California and The Board # Copyright (c) 2016-2024 Regents of the University of California and The Board
# of Regents for the Oklahoma Agricultural and Mechanical College # of Regents for the Oklahoma Agricultural and Mechanical College
# (acting for and on behalf of Oklahoma State University) # (acting for and on behalf of Oklahoma State University)
# All rights reserved. # All rights reserved.

View File

@ -1,6 +1,6 @@
# See LICENSE for licensing information. # See LICENSE for licensing information.
# #
# Copyright (c) 2016-2023 Regents of the University of California and The Board # Copyright (c) 2016-2024 Regents of the University of California and The Board
# of Regents for the Oklahoma Agricultural and Mechanical College # of Regents for the Oklahoma Agricultural and Mechanical College
# (acting for and on behalf of Oklahoma State University) # (acting for and on behalf of Oklahoma State University)
# All rights reserved. # All rights reserved.

View File

@ -1,6 +1,6 @@
# See LICENSE for licensing information. # See LICENSE for licensing information.
# #
# Copyright (c) 2016-2023 Regents of the University of California and The Board # Copyright (c) 2016-2024 Regents of the University of California and The Board
# of Regents for the Oklahoma Agricultural and Mechanical College # of Regents for the Oklahoma Agricultural and Mechanical College
# (acting for and on behalf of Oklahoma State University) # (acting for and on behalf of Oklahoma State University)
# All rights reserved. # All rights reserved.

View File

@ -1,6 +1,6 @@
# See LICENSE for licensing information. # See LICENSE for licensing information.
# #
# Copyright (c) 2016-2023 Regents of the University of California and The Board # Copyright (c) 2016-2024 Regents of the University of California and The Board
# of Regents for the Oklahoma Agricultural and Mechanical College # of Regents for the Oklahoma Agricultural and Mechanical College
# (acting for and on behalf of Oklahoma State University) # (acting for and on behalf of Oklahoma State University)
# All rights reserved. # All rights reserved.
@ -42,7 +42,13 @@ class setup_hold():
self.stim_sp = "sh_stim.sp" self.stim_sp = "sh_stim.sp"
temp_stim = OPTS.openram_temp + self.stim_sp temp_stim = OPTS.openram_temp + self.stim_sp
self.sf = open(temp_stim, "w") self.sf = open(temp_stim, "w")
self.stim = stimuli(self.sf, self.corner)
# creates and opens the measure file for writing
self.meas_sp = "sh_meas.sp"
temp_meas = OPTS.openram_temp + self.meas_sp
self.mf = open(temp_meas, "w")
self.stim = stimuli(self.sf, self.mf, self.corner)
self.write_header(correct_value) self.write_header(correct_value)
@ -56,6 +62,7 @@ class setup_hold():
correct_value=correct_value) correct_value=correct_value)
self.write_clock() self.write_clock()
self.sf.write(".include {}\n".format(temp_meas))
self.write_measures(mode=mode, self.write_measures(mode=mode,
correct_value=correct_value) correct_value=correct_value)
@ -63,6 +70,7 @@ class setup_hold():
self.stim.write_control(4 * self.period) self.stim.write_control(4 * self.period)
self.sf.close() self.sf.close()
self.mf.close()
def write_header(self, correct_value): def write_header(self, correct_value):
""" Write the header file with all the models and the power supplies. """ """ Write the header file with all the models and the power supplies. """
@ -131,7 +139,7 @@ class setup_hold():
else: else:
dout_rise_or_fall = "FALL" dout_rise_or_fall = "FALL"
self.sf.write("\n* Measure statements for pass/fail verification\n") self.mf.write("\n* Measure statements for pass/fail verification\n")
trig_name = "clk" trig_name = "clk"
targ_name = "Q" targ_name = "Q"
trig_val = targ_val = 0.5 * self.vdd_voltage trig_val = targ_val = 0.5 * self.vdd_voltage
@ -168,26 +176,30 @@ class setup_hold():
target_time=feasible_bound, target_time=feasible_bound,
correct_value=correct_value) correct_value=correct_value)
self.stim.run_sim(self.stim_sp) self.stim.run_sim(self.stim_sp)
ideal_clk_to_q = convert_to_float(parse_spice_list("timing", "clk2q_delay")) ideal_clk_to_q = convert_to_float(parse_spice_list("timing",
"clk2q_delay"))
# We use a 1/2 speed clock for some reason... # We use a 1/2 speed clock for some reason...
setuphold_time = (feasible_bound - 2 * self.period) setuphold_time = (feasible_bound - 2 * self.period)
if mode == "SETUP": # SETUP is clk-din, not din-clk if mode == "SETUP": # SETUP is clk-din, not din-clk
passing_setuphold_time = -1 * setuphold_time passing_setuphold_time = -1 * setuphold_time
else: else:
passing_setuphold_time = setuphold_time passing_setuphold_time = setuphold_time
debug.info(2, "*** {0} CHECK: {1} Ideal Clk-to-Q: {2} Setup/Hold: {3}".format(mode, debug.info(2, "*** {0} CHECK: {1} Ideal Clk-to-Q: {2} Setup/Hold: {3}"
.format(mode,
correct_value, correct_value,
ideal_clk_to_q, ideal_clk_to_q,
setuphold_time)) setuphold_time))
if type(ideal_clk_to_q)!=float: if type(ideal_clk_to_q)!=float:
debug.error("Initial hold time fails for data value feasible " debug.error("Initial hold time fails for data value feasible "
"bound {0} Clk-to-Q {1} Setup/Hold {2}".format(feasible_bound, "bound {0} Clk-to-Q {1} Setup/Hold {2}"
.format(feasible_bound,
ideal_clk_to_q, ideal_clk_to_q,
setuphold_time), setuphold_time),
2) 2)
debug.info(2, "Checked initial {0} time {1}, data at {2}, clock at {3} ".format(mode, debug.info(2, "Checked initial {0} time {1}, data at {2}, clock at {3} "
.format(mode,
setuphold_time, setuphold_time,
feasible_bound, feasible_bound,
2 * self.period)) 2 * self.period))
@ -198,7 +210,8 @@ class setup_hold():
target_time=target_time, target_time=target_time,
correct_value=correct_value) correct_value=correct_value)
debug.info(2, "{0} value: {1} Target time: {2} Infeasible: {3} Feasible: {4}".format(mode, debug.info(2, "{0} value: {1} Target time: {2} Infeasible: {3} Feasible: {4}"
.format(mode,
correct_value, correct_value,
target_time, target_time,
infeasible_bound, infeasible_bound,

View File

@ -1,6 +1,6 @@
# See LICENSE for licensing information. # See LICENSE for licensing information.
# #
# Copyright (c) 2016-2023 Regents of the University of California and The Board # Copyright (c) 2016-2024 Regents of the University of California and The Board
# of Regents for the Oklahoma Agricultural and Mechanical College # of Regents for the Oklahoma Agricultural and Mechanical College
# (acting for and on behalf of Oklahoma State University) # (acting for and on behalf of Oklahoma State University)
# All rights reserved. # All rights reserved.
@ -493,6 +493,7 @@ class simulation():
# other initializations can only be done during analysis when a bit has been selected # other initializations can only be done during analysis when a bit has been selected
# for testing. # for testing.
if OPTS.top_process != 'memchar':
self.sram.bank.graph_exclude_precharge() self.sram.bank.graph_exclude_precharge()
self.sram.graph_exclude_addr_dff() self.sram.graph_exclude_addr_dff()
self.sram.graph_exclude_data_dff() self.sram.graph_exclude_data_dff()
@ -515,9 +516,9 @@ class simulation():
self.sen_name = sen_with_port self.sen_name = sen_with_port
debug.warning("Error occurred while determining SEN name. Can cause faults in simulation.") debug.warning("Error occurred while determining SEN name. Can cause faults in simulation.")
column_addr = self.get_column_addr() # column_addr = self.get_column_addr()
bl_name_port, br_name_port = self.get_bl_name(self.graph.all_paths, port) bl_name_port, br_name_port = self.get_bl_name(self.graph.all_paths, port)
port_pos = -1 - len(str(column_addr)) - len(str(port)) # port_pos = -1 - len(str(column_addr)) - len(str(port))
if bl_name_port.endswith(str(port) + "_" + str(self.bitline_column)): # single port SRAM case, bl will not be numbered eg bl_0 if bl_name_port.endswith(str(port) + "_" + str(self.bitline_column)): # single port SRAM case, bl will not be numbered eg bl_0
self.bl_name = bl_name_port self.bl_name = bl_name_port
@ -594,7 +595,7 @@ class simulation():
for path in paths: for path in paths:
aliases = self.sram.find_aliases(self.sram_instance_name, self.pins, path, internal_net, mod, exclusion_set) aliases = self.sram.find_aliases(self.sram_instance_name, self.pins, path, internal_net, mod, exclusion_set)
if net_found and len(aliases) >= 1: if net_found and len(aliases) >= 1:
debug.error('Found multiple paths with {} net.'.format(internal_net), 1) pass #debug.error('Found multiple paths with {} net.'.format(internal_net), 1)
elif len(aliases) > 1: elif len(aliases) > 1:
debug.error('Found multiple {} nets in single path.'.format(internal_net), 1) debug.error('Found multiple {} nets in single path.'.format(internal_net), 1)
elif not net_found and len(aliases) == 1: elif not net_found and len(aliases) == 1:

View File

@ -1,15 +0,0 @@
# See LICENSE for licensing information.
#
# Copyright (c) 2016-2023 Regents of the University of California and The Board
# of Regents for the Oklahoma Agricultural and Mechanical College
# (acting for and on behalf of Oklahoma State University)
# All rights reserved.
#
from enum import Enum
class sram_op(Enum):
READ_ZERO = 0
READ_ONE = 1
WRITE_ZERO = 2
WRITE_ONE = 3

View File

@ -1,6 +1,6 @@
# See LICENSE for licensing information. # See LICENSE for licensing information.
# #
# Copyright (c) 2016-2023 Regents of the University of California and The Board # Copyright (c) 2016-2024 Regents of the University of California and The Board
# of Regents for the Oklahoma Agricultural and Mechanical College # of Regents for the Oklahoma Agricultural and Mechanical College
# (acting for and on behalf of Oklahoma State University) # (acting for and on behalf of Oklahoma State University)
# All rights reserved. # All rights reserved.
@ -22,7 +22,7 @@ from openram import OPTS
class stimuli(): class stimuli():
""" Class for providing stimuli functions """ """ Class for providing stimuli functions """
def __init__(self, stim_file, corner): def __init__(self, stim_file, meas_file, corner):
self.vdd_name = "vdd" self.vdd_name = "vdd"
self.gnd_name = "gnd" self.gnd_name = "gnd"
self.pmos_name = tech.spice["pmos"] self.pmos_name = tech.spice["pmos"]
@ -31,6 +31,7 @@ class stimuli():
self.tx_length = tech.drc["minlength_channel"] self.tx_length = tech.drc["minlength_channel"]
self.sf = stim_file self.sf = stim_file
self.mf = meas_file
(self.process, self.voltage, self.temperature) = corner (self.process, self.voltage, self.temperature) = corner
found = False found = False
@ -181,7 +182,7 @@ class stimuli():
def gen_meas_delay(self, meas_name, trig_name, targ_name, trig_val, targ_val, trig_dir, targ_dir, trig_td, targ_td): def gen_meas_delay(self, meas_name, trig_name, targ_name, trig_val, targ_val, trig_dir, targ_dir, trig_td, targ_td):
""" Creates the .meas statement for the measurement of delay """ """ Creates the .meas statement for the measurement of delay """
measure_string=".meas tran {0} TRIG v({1}) VAL={2} {3}=1 TD={4}n TARG v({5}) VAL={6} {7}=1 TD={8}n\n\n" measure_string=".meas tran {0} TRIG v({1}) VAL={2} {3}=1 TD={4}n TARG v({5}) VAL={6} {7}=1 TD={8}n\n\n"
self.sf.write(measure_string.format(meas_name.lower(), self.mf.write(measure_string.format(meas_name.lower(),
trig_name, trig_name,
trig_val, trig_val,
trig_dir, trig_dir,
@ -194,7 +195,7 @@ class stimuli():
def gen_meas_find_voltage(self, meas_name, trig_name, targ_name, trig_val, trig_dir, trig_td): def gen_meas_find_voltage(self, meas_name, trig_name, targ_name, trig_val, trig_dir, trig_td):
""" Creates the .meas statement for the measurement of delay """ """ Creates the .meas statement for the measurement of delay """
measure_string=".meas tran {0} FIND v({1}) WHEN v({2})={3}v {4}=1 TD={5}n \n\n" measure_string=".meas tran {0} FIND v({1}) WHEN v({2})={3}v {4}=1 TD={5}n \n\n"
self.sf.write(measure_string.format(meas_name.lower(), self.mf.write(measure_string.format(meas_name.lower(),
targ_name, targ_name,
trig_name, trig_name,
trig_val, trig_val,
@ -204,7 +205,7 @@ class stimuli():
def gen_meas_find_voltage_at_time(self, meas_name, targ_name, time_at): def gen_meas_find_voltage_at_time(self, meas_name, targ_name, time_at):
""" Creates the .meas statement for voltage at time""" """ Creates the .meas statement for voltage at time"""
measure_string=".meas tran {0} FIND v({1}) AT={2}n \n\n" measure_string=".meas tran {0} FIND v({1}) AT={2}n \n\n"
self.sf.write(measure_string.format(meas_name.lower(), self.mf.write(measure_string.format(meas_name.lower(),
targ_name, targ_name,
time_at)) time_at))
@ -215,7 +216,7 @@ class stimuli():
power_exp = "power" power_exp = "power"
else: else:
power_exp = "par('(-1*v(" + str(self.vdd_name) + ")*I(v" + str(self.vdd_name) + "))')" power_exp = "par('(-1*v(" + str(self.vdd_name) + ")*I(v" + str(self.vdd_name) + "))')"
self.sf.write(".meas tran {0} avg {1} from={2}n to={3}n\n\n".format(meas_name.lower(), self.mf.write(".meas tran {0} avg {1} from={2}n to={3}n\n\n".format(meas_name.lower(),
power_exp, power_exp,
t_initial, t_initial,
t_final)) t_final))
@ -223,7 +224,7 @@ class stimuli():
def gen_meas_value(self, meas_name, dout, t_initial, t_final): def gen_meas_value(self, meas_name, dout, t_initial, t_final):
measure_string=".meas tran {0} FIND v({1}) AT={2}n\n\n".format(meas_name.lower(), dout, (t_initial + t_final) / 2) measure_string=".meas tran {0} FIND v({1}) AT={2}n\n\n".format(meas_name.lower(), dout, (t_initial + t_final) / 2)
# measure_string=".meas tran {0} AVG v({1}) FROM={2}n TO={3}n\n\n".format(meas_name.lower(), dout, t_initial, t_final) # measure_string=".meas tran {0} AVG v({1}) FROM={2}n TO={3}n\n\n".format(meas_name.lower(), dout, t_initial, t_final)
self.sf.write(measure_string) self.mf.write(measure_string)
def write_control(self, end_time, runlvl=4): def write_control(self, end_time, runlvl=4):
""" Write the control cards to run and end the simulation """ """ Write the control cards to run and end the simulation """
@ -278,7 +279,7 @@ class stimuli():
self.sf.write(".OPTIONS DEVICE TEMP={}\n".format(self.temperature)) self.sf.write(".OPTIONS DEVICE TEMP={}\n".format(self.temperature))
self.sf.write(".OPTIONS MEASURE MEASFAIL=1\n") self.sf.write(".OPTIONS MEASURE MEASFAIL=1\n")
self.sf.write(".OPTIONS LINSOL type=klu\n") self.sf.write(".OPTIONS LINSOL type=klu\n")
self.sf.write(".OPTIONS TIMEINT RELTOL=1e-6 ABSTOL=1e-10 method=gear minorder=2\n") self.sf.write(".OPTIONS TIMEINT RELTOL=1e-3 ABSTOL=1e-6 method=gear minorder=2\n")
# Format: .TRAN <initial step> <final time> <start time> <step ceiling> # Format: .TRAN <initial step> <final time> <start time> <step ceiling>
self.sf.write(".TRAN {0}p {1}n 0n {0}p\n".format(timestep, end_time)) self.sf.write(".TRAN {0}p {1}n 0n {0}p\n".format(timestep, end_time))
elif OPTS.spice_name: elif OPTS.spice_name:
@ -409,14 +410,14 @@ class stimuli():
# FIXME: Should use verify/run_script.py here but run_script doesn't return # FIXME: Should use verify/run_script.py here but run_script doesn't return
# the return code of the subprocess. File names might also mismatch. # the return code of the subprocess. File names might also mismatch.
from openram import CONDA_HOME from openram import CONDA_HOME
cmd = "source {0}/bin/activate && {1} && conda deactivate".format(CONDA_HOME, cmd) cmd = "/bin/bash -c 'source {0}/bin/activate && {1} && conda deactivate'".format(CONDA_HOME, cmd)
debug.info(2, cmd) debug.info(2, cmd)
retcode = subprocess.call(cmd, stdout=spice_stdout, stderr=spice_stderr, shell=True) proc = subprocess.run(cmd, stdout=spice_stdout, stderr=spice_stderr, shell=True)
spice_stdout.close() spice_stdout.close()
spice_stderr.close() spice_stderr.close()
if (retcode > valid_retcode): if (proc.returncode > valid_retcode):
debug.error("Spice simulation error: " + cmd, -1) debug.error("Spice simulation error: " + cmd, -1)
else: else:
end_time = datetime.datetime.now() end_time = datetime.datetime.now()

View File

@ -1,6 +1,6 @@
# See LICENSE for licensing information. # See LICENSE for licensing information.
# #
# Copyright (c) 2016-2023 Regents of the University of California and The Board # Copyright (c) 2016-2024 Regents of the University of California and The Board
# of Regents for the Oklahoma Agricultural and Mechanical College # of Regents for the Oklahoma Agricultural and Mechanical College
# (acting for and on behalf of Oklahoma State University) # (acting for and on behalf of Oklahoma State University)
# All rights reserved. # All rights reserved.
@ -85,14 +85,15 @@ class trim_spice():
wl_regex = r"wl\d*_{}".format(wl_address) wl_regex = r"wl\d*_{}".format(wl_address)
bl_regex = r"bl\d*_{}".format(int(self.words_per_row*data_bit + col_address)) bl_regex = r"bl\d*_{}".format(int(self.words_per_row*data_bit + col_address))
bl_no_port_regex = r"bl_{}".format(int(self.words_per_row*data_bit + col_address))
self.remove_insts("bitcell_array",[wl_regex,bl_regex]) self.remove_insts("bitcell_array",[wl_regex,bl_regex])
# 2. Keep sense amps basd on BL # 2. Keep sense amps basd on BL
# FIXME: The bit lines are not indexed the same in sense_amp_array self.remove_insts("sense_amp_array",[bl_no_port_regex])
#self.remove_insts("sense_amp_array",[bl_regex])
# 3. Keep column muxes basd on BL # 3. Keep column muxes basd on BL
self.remove_insts("column_mux_array", [bl_regex]) self.remove_insts("single_level_column_mux_array", [bl_no_port_regex])
# 4. Keep write driver based on DATA # 4. Keep write driver based on DATA
data_regex = r"data_{}".format(data_bit) data_regex = r"data_{}".format(data_bit)

View File

@ -1,6 +1,6 @@
# See LICENSE for licensing information. # See LICENSE for licensing information.
# #
# Copyright (c) 2016-2023 Regents of the University of California, Santa Cruz # Copyright (c) 2016-2024 Regents of the University of California, Santa Cruz
# All rights reserved. # All rights reserved.
# #
from .datasheet_gen import datasheet_gen from .datasheet_gen import datasheet_gen

View File

@ -1,6 +1,6 @@
# See LICENSE for licensing information. # See LICENSE for licensing information.
# #
# Copyright (c) 2016-2023 Regents of the University of California and The Board # Copyright (c) 2016-2024 Regents of the University of California and The Board
# of Regents for the Oklahoma Agricultural and Mechanical College # of Regents for the Oklahoma Agricultural and Mechanical College
# (acting for and on behalf of Oklahoma State University) # (acting for and on behalf of Oklahoma State University)
# All rights reserved. # All rights reserved.

View File

@ -1,6 +1,6 @@
# See LICENSE for licensing information. # See LICENSE for licensing information.
# #
# Copyright (c) 2016-2023 Regents of the University of California and The Board # Copyright (c) 2016-2024 Regents of the University of California and The Board
# of Regents for the Oklahoma Agricultural and Mechanical College # of Regents for the Oklahoma Agricultural and Mechanical College
# (acting for and on behalf of Oklahoma State University) # (acting for and on behalf of Oklahoma State University)
# All rights reserved. # All rights reserved.

View File

@ -1,6 +1,6 @@
# See LICENSE for licensing information. # See LICENSE for licensing information.
# #
# Copyright (c) 2016-2023 Regents of the University of California and The Board # Copyright (c) 2016-2024 Regents of the University of California and The Board
# of Regents for the Oklahoma Agricultural and Mechanical College # of Regents for the Oklahoma Agricultural and Mechanical College
# (acting for and on behalf of Oklahoma State University) # (acting for and on behalf of Oklahoma State University)
# All rights reserved. # All rights reserved.

View File

@ -1,6 +1,6 @@
# See LICENSE for licensing information. # See LICENSE for licensing information.
# #
# Copyright (c) 2016-2023 Regents of the University of California and The Board # Copyright (c) 2016-2024 Regents of the University of California and The Board
# of Regents for the Oklahoma Agricultural and Mechanical College # of Regents for the Oklahoma Agricultural and Mechanical College
# (acting for and on behalf of Oklahoma State University) # (acting for and on behalf of Oklahoma State University)
# All rights reserved. # All rights reserved.

View File

@ -1,12 +1,13 @@
# See LICENSE for licensing information. # See LICENSE for licensing information.
# #
# Copyright (c) 2016-2023 Regents of the University of California and The Board # Copyright (c) 2016-2024 Regents of the University of California and The Board
# of Regents for the Oklahoma Agricultural and Mechanical College # of Regents for the Oklahoma Agricultural and Mechanical College
# (acting for and on behalf of Oklahoma State University) # (acting for and on behalf of Oklahoma State University)
# All rights reserved. # All rights reserved.
# #
import sys import sys
import os import os
import datetime
import pdb import pdb
import inspect import inspect
from openram import globals from openram import globals
@ -62,6 +63,9 @@ def print_raw(str):
def log(str): def log(str):
# Add timestamp at the beginning of the string
timestr = datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S.%f")
str = "[{}] {}".format(timestr, str)
if globals.OPTS.output_name != '': if globals.OPTS.output_name != '':
if log.create_file: if log.create_file:
# We may have not yet read the config, so we need to ensure # We may have not yet read the config, so we need to ensure

View File

@ -1,6 +1,6 @@
# See LICENSE for licensing information. # See LICENSE for licensing information.
# #
# Copyright (c) 2016-2023 Regents of the University of California, Santa Cruz # Copyright (c) 2016-2024 Regents of the University of California, Santa Cruz
# All rights reserved. # All rights reserved.
# #
from .custom_cell_properties import * from .custom_cell_properties import *

View File

@ -1,6 +1,6 @@
# See LICENSE for licensing information. # See LICENSE for licensing information.
# #
# Copyright (c) 2016-2023 Regents of the University of California and The Board # Copyright (c) 2016-2024 Regents of the University of California and The Board
# of Regents for the Oklahoma Agricultural and Mechanical College # of Regents for the Oklahoma Agricultural and Mechanical College
# (acting for and on behalf of Oklahoma State University) # (acting for and on behalf of Oklahoma State University)
# All rights reserved. # All rights reserved.

View File

@ -1,6 +1,6 @@
# See LICENSE for licensing information. # See LICENSE for licensing information.
# #
# Copyright (c) 2016-2023 Regents of the University of California and The Board # Copyright (c) 2016-2024 Regents of the University of California and The Board
# of Regents for the Oklahoma Agricultural and Mechanical College # of Regents for the Oklahoma Agricultural and Mechanical College
# (acting for and on behalf of Oklahoma State University) # (acting for and on behalf of Oklahoma State University)
# All rights reserved. # All rights reserved.

View File

@ -1,6 +1,6 @@
# See LICENSE for licensing information. # See LICENSE for licensing information.
# #
# Copyright (c) 2016-2023 Regents of the University of California and The Board # Copyright (c) 2016-2024 Regents of the University of California and The Board
# of Regents for the Oklahoma Agricultural and Mechanical College # of Regents for the Oklahoma Agricultural and Mechanical College
# (acting for and on behalf of Oklahoma State University) # (acting for and on behalf of Oklahoma State University)
# All rights reserved. # All rights reserved.

View File

@ -1,6 +1,6 @@
# See LICENSE for licensing information. # See LICENSE for licensing information.
# #
# Copyright (c) 2016-2023 Regents of the University of California and The Board # Copyright (c) 2016-2024 Regents of the University of California and The Board
# of Regents for the Oklahoma Agricultural and Mechanical College # of Regents for the Oklahoma Agricultural and Mechanical College
# (acting for and on behalf of Oklahoma State University) # (acting for and on behalf of Oklahoma State University)
# All rights reserved. # All rights reserved.

View File

@ -1,6 +1,6 @@
# See LICENSE for licensing information. # See LICENSE for licensing information.
# #
# Copyright (c) 2016-2023 Regents of the University of California and The Board # Copyright (c) 2016-2024 Regents of the University of California and The Board
# of Regents for the Oklahoma Agricultural and Mechanical College # of Regents for the Oklahoma Agricultural and Mechanical College
# (acting for and on behalf of Oklahoma State University) # (acting for and on behalf of Oklahoma State University)
# All rights reserved. # All rights reserved.

View File

@ -1,6 +1,6 @@
# See LICENSE for licensing information. # See LICENSE for licensing information.
# #
# Copyright (c) 2016-2023 Regents of the University of California and The Board # Copyright (c) 2016-2024 Regents of the University of California and The Board
# of Regents for the Oklahoma Agricultural and Mechanical College # of Regents for the Oklahoma Agricultural and Mechanical College
# (acting for and on behalf of Oklahoma State University) # (acting for and on behalf of Oklahoma State University)
# All rights reserved. # All rights reserved.

View File

@ -1,7 +1,7 @@
#!/usr/bin/env python #!/usr/bin/env python3
# See LICENSE for licensing information. # See LICENSE for licensing information.
# #
# Copyright (c) 2016-2023 Regents of the University of California and The Board # Copyright (c) 2016-2024 Regents of the University of California and The Board
# of Regents for the Oklahoma Agricultural and Mechanical College # of Regents for the Oklahoma Agricultural and Mechanical College
# (acting for and on behalf of Oklahoma State University) # (acting for and on behalf of Oklahoma State University)
# All rights reserved. # All rights reserved.
@ -15,6 +15,7 @@ corner, but should probably be extended.
import sys import sys
from globals import * from globals import *
from importlib import reload
(OPTS, args) = parse_args() (OPTS, args) = parse_args()
@ -41,36 +42,29 @@ slew = float(args[3])
import debug import debug
init_openram(config_file=config_file, is_unit_test=False) init_openram(config_file=config_file, is_unit_test=False)
from sram_config import sram_config
c = sram_config(word_size=OPTS.word_size,
num_words=OPTS.num_words,
write_size=OPTS.write_size,
num_banks=OPTS.num_banks,
words_per_row=OPTS.words_per_row,
num_spare_rows=OPTS.num_spare_rows,
num_spare_cols=OPTS.num_spare_cols)
OPTS.netlist_only = True
OPTS.check_lvsdrc = False OPTS.check_lvsdrc = False
# Put the temp output in the output path since it is what we want to generate! # Put the temp output in the output path since it is what we want to generate!
old_openram_temp = OPTS.openram_temp old_openram_temp = OPTS.openram_temp
OPTS.openram_temp = OPTS.output_path OPTS.openram_temp = OPTS.output_path
from sram import sram
s = sram(name=OPTS.output_name, sram_config=c)
import sram
class fake_sram(sram.sram):
""" This is an SRAM that doesn't actually create itself, just computes
the sizes. """
def __init__(self, word_size, num_words, num_banks, name, num_spare_rows):
self.name = name
self.word_size = word_size
self.num_words = num_words
self.num_banks = num_banks
self.num_spare_rows = num_spare_rows
c = reload(__import__(OPTS.bitcell))
self.mod_bitcell = getattr(c, OPTS.bitcell)
self.bitcell = self.mod_bitcell()
# to get the row, col, etc.
self.compute_sizes()
sram = fake_sram(OPTS.word_size, OPTS.num_words, OPTS.num_banks, OPTS.output_name)
sp_file = OPTS.output_path+OPTS.output_name + ".sp"
from characterizer import delay from characterizer import delay
import tech import tech
# Set up the delay and set to the nominal corner # Set up the delay and set to the nominal corner
d = delay.delay(sram, sp_file, ("TT", tech.spice["nom_supply_voltage"], tech.spice["nom_temperature"])) d = delay(s, s.get_sp_name(), ("TT", tech.spice["nom_supply_voltage"], tech.spice["nom_temperature"]))
# Set the period # Set the period
d.period = period d.period = period
# Set the load of outputs and slew of inputs # Set the load of outputs and slew of inputs
@ -91,4 +85,3 @@ print("Output files are:\n{0}stim.sp\n{0}sram.sp\n{0}reduced.sp".format(OPTS.out
OPTS.openram_temp = old_openram_temp OPTS.openram_temp = old_openram_temp
# Delete temp files, remove the dir, etc. # Delete temp files, remove the dir, etc.
end_openram() end_openram()

View File

@ -1,6 +1,6 @@
# See LICENSE for licensing information. # See LICENSE for licensing information.
# #
# Copyright (c) 2016-2023 Regents of the University of California and The Board # Copyright (c) 2016-2024 Regents of the University of California and The Board
# of Regents for the Oklahoma Agricultural and Mechanical College # of Regents for the Oklahoma Agricultural and Mechanical College
# (acting for and on behalf of Oklahoma State University) # (acting for and on behalf of Oklahoma State University)
# All rights reserved. # All rights reserved.
@ -146,7 +146,7 @@ def check_versions():
if not (major_python_version == major_required and minor_python_version >= minor_required): if not (major_python_version == major_required and minor_python_version >= minor_required):
debug.error("Python {0}.{1} or greater is required.".format(major_required, minor_required), -1) debug.error("Python {0}.{1} or greater is required.".format(major_required, minor_required), -1)
# Verify any version of git is isntalled before proceeding # Verify any version of git is installed before proceeding
try: try:
subprocess.check_output(["git", "--version"]) subprocess.check_output(["git", "--version"])
except: except:
@ -482,7 +482,6 @@ def init_paths():
#pprint(s) #pprint(s)
#print("Test {0} in dir {1}".format(s[2].filename, OPTS.openram_temp)) #print("Test {0} in dir {1}".format(s[2].filename, OPTS.openram_temp))
# Don't delete the output dir, it may have other files! # Don't delete the output dir, it may have other files!
# make the directory if it doesn't exist # make the directory if it doesn't exist
try: try:

View File

@ -1,6 +1,6 @@
# See LICENSE for licensing information. # See LICENSE for licensing information.
# #
# Copyright (c) 2016-2023 Regents of the University of California, Santa Cruz # Copyright (c) 2016-2024 Regents of the University of California, Santa Cruz
# All rights reserved. # All rights reserved.
# #
model_name = "cacti" model_name = "cacti"

View File

@ -1,6 +1,6 @@
# See LICENSE for licensing information. # See LICENSE for licensing information.
# #
# Copyright (c) 2016-2023 Regents of the University of California, Santa Cruz # Copyright (c) 2016-2024 Regents of the University of California, Santa Cruz
# All rights reserved. # All rights reserved.
# #
from .shared_config import * from .shared_config import *

View File

@ -1,6 +1,6 @@
# See LICENSE for licensing information. # See LICENSE for licensing information.
# #
# Copyright (c) 2016-2023 Regents of the University of California, Santa Cruz # Copyright (c) 2016-2024 Regents of the University of California, Santa Cruz
# All rights reserved. # All rights reserved.
# #
from .shared_config import * from .shared_config import *

View File

@ -1,6 +1,6 @@
# See LICENSE for licensing information. # See LICENSE for licensing information.
# #
# Copyright (c) 2016-2023 Regents of the University of California, Santa Cruz # Copyright (c) 2016-2024 Regents of the University of California, Santa Cruz
# All rights reserved. # All rights reserved.
# #
from .shared_config import * from .shared_config import *

View File

@ -1,6 +1,6 @@
# See LICENSE for licensing information. # See LICENSE for licensing information.
# #
# Copyright (c) 2016-2023 Regents of the University of California, Santa Cruz # Copyright (c) 2016-2024 Regents of the University of California, Santa Cruz
# All rights reserved. # All rights reserved.
# #
from .shared_config import * from .shared_config import *

View File

@ -1,6 +1,6 @@
# See LICENSE for licensing information. # See LICENSE for licensing information.
# #
# Copyright (c) 2016-2023 Regents of the University of California, Santa Cruz # Copyright (c) 2016-2024 Regents of the University of California, Santa Cruz
# All rights reserved. # All rights reserved.
# #
from .shared_config import * from .shared_config import *

View File

@ -1,6 +1,6 @@
# See LICENSE for licensing information. # See LICENSE for licensing information.
# #
# Copyright (c) 2016-2023 Regents of the University of California, Santa Cruz # Copyright (c) 2016-2024 Regents of the University of California, Santa Cruz
# All rights reserved. # All rights reserved.
# #
from .shared_config import * from .shared_config import *

View File

@ -1,6 +1,6 @@
# See LICENSE for licensing information. # See LICENSE for licensing information.
# #
# Copyright (c) 2016-2023 Regents of the University of California, Santa Cruz # Copyright (c) 2016-2024 Regents of the University of California, Santa Cruz
# All rights reserved. # All rights reserved.
# #
from .shared_config import * from .shared_config import *

View File

@ -1,6 +1,6 @@
# See LICENSE for licensing information. # See LICENSE for licensing information.
# #
# Copyright (c) 2016-2023 Regents of the University of California, Santa Cruz # Copyright (c) 2016-2024 Regents of the University of California, Santa Cruz
# All rights reserved. # All rights reserved.
# #
from .shared_config import * from .shared_config import *

View File

@ -1,6 +1,6 @@
# See LICENSE for licensing information. # See LICENSE for licensing information.
# #
# Copyright (c) 2016-2023 Regents of the University of California, Santa Cruz # Copyright (c) 2016-2024 Regents of the University of California, Santa Cruz
# All rights reserved. # All rights reserved.
# #
from .shared_config import * from .shared_config import *

View File

@ -1,6 +1,6 @@
# See LICENSE for licensing information. # See LICENSE for licensing information.
# #
# Copyright (c) 2016-2023 Regents of the University of California, Santa Cruz # Copyright (c) 2016-2024 Regents of the University of California, Santa Cruz
# All rights reserved. # All rights reserved.
# #
from .shared_config import * from .shared_config import *

View File

@ -1,6 +1,6 @@
# See LICENSE for licensing information. # See LICENSE for licensing information.
# #
# Copyright (c) 2016-2023 Regents of the University of California, Santa Cruz # Copyright (c) 2016-2024 Regents of the University of California, Santa Cruz
# All rights reserved. # All rights reserved.
# #
from .shared_config import * from .shared_config import *

View File

@ -1,6 +1,6 @@
# See LICENSE for licensing information. # See LICENSE for licensing information.
# #
# Copyright (c) 2016-2023 Regents of the University of California, Santa Cruz # Copyright (c) 2016-2024 Regents of the University of California, Santa Cruz
# All rights reserved. # All rights reserved.
# #
from .shared_config import * from .shared_config import *

View File

@ -1,6 +1,6 @@
# See LICENSE for licensing information. # See LICENSE for licensing information.
# #
# Copyright (c) 2016-2023 Regents of the University of California, Santa Cruz # Copyright (c) 2016-2024 Regents of the University of California, Santa Cruz
# All rights reserved. # All rights reserved.
# #
from .shared_config import * from .shared_config import *

View File

@ -1,6 +1,6 @@
# See LICENSE for licensing information. # See LICENSE for licensing information.
# #
# Copyright (c) 2016-2023 Regents of the University of California, Santa Cruz # Copyright (c) 2016-2024 Regents of the University of California, Santa Cruz
# All rights reserved. # All rights reserved.
# #
from .shared_config import * from .shared_config import *

View File

@ -1,6 +1,6 @@
# See LICENSE for licensing information. # See LICENSE for licensing information.
# #
# Copyright (c) 2016-2023 Regents of the University of California, Santa Cruz # Copyright (c) 2016-2024 Regents of the University of California, Santa Cruz
# All rights reserved. # All rights reserved.
# #
from .shared_config import * from .shared_config import *

View File

@ -1,6 +1,6 @@
# See LICENSE for licensing information. # See LICENSE for licensing information.
# #
# Copyright (c) 2016-2023 Regents of the University of California, Santa Cruz # Copyright (c) 2016-2024 Regents of the University of California, Santa Cruz
# All rights reserved. # All rights reserved.
# #
from .shared_config import * from .shared_config import *

View File

@ -1,6 +1,6 @@
# See LICENSE for licensing information. # See LICENSE for licensing information.
# #
# Copyright (c) 2016-2023 Regents of the University of California, Santa Cruz # Copyright (c) 2016-2024 Regents of the University of California, Santa Cruz
# All rights reserved. # All rights reserved.
# #
from .shared_config import * from .shared_config import *

View File

@ -1,6 +1,6 @@
# See LICENSE for licensing information. # See LICENSE for licensing information.
# #
# Copyright (c) 2016-2023 Regents of the University of California, Santa Cruz # Copyright (c) 2016-2024 Regents of the University of California, Santa Cruz
# All rights reserved. # All rights reserved.
# #
from .shared_config import * from .shared_config import *

View File

@ -1,6 +1,6 @@
# See LICENSE for licensing information. # See LICENSE for licensing information.
# #
# Copyright (c) 2016-2023 Regents of the University of California, Santa Cruz # Copyright (c) 2016-2024 Regents of the University of California, Santa Cruz
# All rights reserved. # All rights reserved.
# #
from .shared_config import * from .shared_config import *

View File

@ -1,6 +1,6 @@
# See LICENSE for licensing information. # See LICENSE for licensing information.
# #
# Copyright (c) 2016-2023 Regents of the University of California, Santa Cruz # Copyright (c) 2016-2024 Regents of the University of California, Santa Cruz
# All rights reserved. # All rights reserved.
# #
from .shared_config import * from .shared_config import *

View File

@ -1,6 +1,6 @@
# See LICENSE for licensing information. # See LICENSE for licensing information.
# #
# Copyright (c) 2016-2023 Regents of the University of California, Santa Cruz # Copyright (c) 2016-2024 Regents of the University of California, Santa Cruz
# All rights reserved. # All rights reserved.
# #
from shared_config import * from shared_config import *

View File

@ -1,6 +1,6 @@
# See LICENSE for licensing information. # See LICENSE for licensing information.
# #
# Copyright (c) 2016-2023 Regents of the University of California, Santa Cruz # Copyright (c) 2016-2024 Regents of the University of California, Santa Cruz
# All rights reserved. # All rights reserved.
# #
from .shared_config import * from .shared_config import *

View File

@ -1,6 +1,6 @@
# See LICENSE for licensing information. # See LICENSE for licensing information.
# #
# Copyright (c) 2016-2023 Regents of the University of California, Santa Cruz # Copyright (c) 2016-2024 Regents of the University of California, Santa Cruz
# All rights reserved. # All rights reserved.
# #
from .shared_config import * from .shared_config import *

View File

@ -1,6 +1,6 @@
# See LICENSE for licensing information. # See LICENSE for licensing information.
# #
# Copyright (c) 2016-2023 Regents of the University of California, Santa Cruz # Copyright (c) 2016-2024 Regents of the University of California, Santa Cruz
# All rights reserved. # All rights reserved.
# #
from .shared_config import * from .shared_config import *

View File

@ -1,6 +1,6 @@
# See LICENSE for licensing information. # See LICENSE for licensing information.
# #
# Copyright (c) 2016-2023 Regents of the University of California, Santa Cruz # Copyright (c) 2016-2024 Regents of the University of California, Santa Cruz
# All rights reserved. # All rights reserved.
# #
from .shared_config import * from .shared_config import *

View File

@ -1,6 +1,6 @@
# See LICENSE for licensing information. # See LICENSE for licensing information.
# #
# Copyright (c) 2016-2023 Regents of the University of California, Santa Cruz # Copyright (c) 2016-2024 Regents of the University of California, Santa Cruz
# All rights reserved. # All rights reserved.
# #
from .shared_config import * from .shared_config import *

View File

@ -1,6 +1,6 @@
# See LICENSE for licensing information. # See LICENSE for licensing information.
# #
# Copyright (c) 2016-2023 Regents of the University of California, Santa Cruz # Copyright (c) 2016-2024 Regents of the University of California, Santa Cruz
# All rights reserved. # All rights reserved.
# #
from .shared_config import * from .shared_config import *

View File

@ -1,6 +1,6 @@
# See LICENSE for licensing information. # See LICENSE for licensing information.
# #
# Copyright (c) 2016-2023 Regents of the University of California, Santa Cruz # Copyright (c) 2016-2024 Regents of the University of California, Santa Cruz
# All rights reserved. # All rights reserved.
# #
from .shared_config import * from .shared_config import *

View File

@ -1,6 +1,6 @@
# See LICENSE for licensing information. # See LICENSE for licensing information.
# #
# Copyright (c) 2016-2023 Regents of the University of California, Santa Cruz # Copyright (c) 2016-2024 Regents of the University of California, Santa Cruz
# All rights reserved. # All rights reserved.
# #
from .shared_config import * from .shared_config import *

View File

@ -1,6 +1,6 @@
# See LICENSE for licensing information. # See LICENSE for licensing information.
# #
# Copyright (c) 2016-2023 Regents of the University of California, Santa Cruz # Copyright (c) 2016-2024 Regents of the University of California, Santa Cruz
# All rights reserved. # All rights reserved.
# #
from .shared_config import * from .shared_config import *

View File

@ -1,6 +1,6 @@
# See LICENSE for licensing information. # See LICENSE for licensing information.
# #
# Copyright (c) 2016-2023 Regents of the University of California, Santa Cruz # Copyright (c) 2016-2024 Regents of the University of California, Santa Cruz
# All rights reserved. # All rights reserved.
# #
from .shared_config import * from .shared_config import *

View File

@ -1,6 +1,6 @@
# See LICENSE for licensing information. # See LICENSE for licensing information.
# #
# Copyright (c) 2016-2023 Regents of the University of California, Santa Cruz # Copyright (c) 2016-2024 Regents of the University of California, Santa Cruz
# All rights reserved. # All rights reserved.
# #
from .shared_config import * from .shared_config import *

View File

@ -1,6 +1,6 @@
# See LICENSE for licensing information. # See LICENSE for licensing information.
# #
# Copyright (c) 2016-2023 Regents of the University of California, Santa Cruz # Copyright (c) 2016-2024 Regents of the University of California, Santa Cruz
# All rights reserved. # All rights reserved.
# #
from .shared_config import * from .shared_config import *

View File

@ -1,6 +1,6 @@
# See LICENSE for licensing information. # See LICENSE for licensing information.
# #
# Copyright (c) 2016-2023 Regents of the University of California, Santa Cruz # Copyright (c) 2016-2024 Regents of the University of California, Santa Cruz
# All rights reserved. # All rights reserved.
# #
from .shared_config import * from .shared_config import *

Some files were not shown because too many files have changed in this diff Show More