Skip to content
Permalink

Comparing changes

Choose two branches to see what’s changed or to start a new pull request. If you need to, you can also or learn more about diff comparisons.

Open a pull request

Create a new pull request by comparing changes across two branches. If you need to, you can also . Learn more about diff comparisons here.
base repository: bluecheetah/xbase
Failed to load repositories. Confirm that selected base ref is valid, then try again.
Loading
base: master
Choose a base ref
...
head repository: ucb-art/xbase
Failed to load repositories. Confirm that selected head ref is valid, then try again.
Loading
compare: develop
Choose a head ref
Able to merge. These branches can be automatically merged.

Commits on Sep 16, 2020

  1. add default parameters for edges of DeviceFill

    Ayan Biswas committed Sep 16, 2020
    Copy the full SHA
    18f4cbf View commit details

Commits on Dec 30, 2020

  1. Copy the full SHA
    d0f0525 View commit details
  2. ResArrayBase class

    boblinchuan committed Dec 30, 2020
    Copy the full SHA
    d3be6b3 View commit details

Commits on Jan 6, 2021

  1. Copy the full SHA
    3a7fbae View commit details

Commits on Jan 8, 2021

  1. Merge pull request #1 from hyunjaekwon/mos_char

    added schematic class to MOSCharCore layout generator
    ayan-biswas authored Jan 8, 2021
    Copy the full SHA
    9b0c8f9 View commit details

Commits on Jan 13, 2021

  1. Copy the full SHA
    132ce32 View commit details
  2. Res: adding abstract method to get width and length, adding length an…

    …d width to resistor pinfo
    boblinchuan committed Jan 13, 2021
    Copy the full SHA
    4dcaddb View commit details

Commits on Jan 14, 2021

  1. Merging develop

    boblinchuan committed Jan 14, 2021
    Copy the full SHA
    971c4e5 View commit details

Commits on Feb 1, 2021

  1. Copy the full SHA
    3472655 View commit details

Commits on Mar 17, 2021

  1. Copy the full SHA
    fb7e668 View commit details
  2. merge

    boblinchuan committed Mar 17, 2021
    Copy the full SHA
    aec92e5 View commit details

Commits on Apr 13, 2021

  1. remove Apache license

    Ayan Biswas committed Apr 13, 2021
    Copy the full SHA
    1ca6c98 View commit details

Commits on May 9, 2021

  1. add via priority

    Ayan Biswas committed May 9, 2021
    Copy the full SHA
    6c35254 View commit details

Commits on May 18, 2021

  1. merge

    boblinchuan committed May 18, 2021
    Copy the full SHA
    58c9370 View commit details
  2. Copy the full SHA
    3f9cc5f View commit details
  3. Res: some documentation

    boblinchuan committed May 18, 2021
    Copy the full SHA
    8ffff92 View commit details

Commits on May 19, 2021

  1. Minor typo

    ayan-biswas authored May 19, 2021
    Copy the full SHA
    20fb3c8 View commit details
  2. Merge pull request #3 from boblinchuan/res_array

    Res: some documentation
    ayan-biswas authored May 19, 2021
    Copy the full SHA
    e3f5a02 View commit details

Commits on May 20, 2021

  1. add res_char schematic; TODO: layout

    Ayan Biswas committed May 20, 2021
    Copy the full SHA
    b8db199 View commit details

Commits on May 21, 2021

  1. Copy the full SHA
    402c480 View commit details

Commits on Jun 3, 2021

  1. 1. add various helper methods in ResArrayBase for ease of resistor la…

    …yout generators; 2. Update res_char layout generator
    Ayan Biswas committed Jun 3, 2021
    Copy the full SHA
    4766224 View commit details
  2. update ResArrayBase helper methods with restructuring of connection d…

    …ictionary
    Ayan Biswas committed Jun 3, 2021
    Copy the full SHA
    ac62a7b View commit details

Commits on Jun 7, 2021

  1. add gr_sub_sep_col property in MOSBase and MOSTech that returns sub_s…

    …ep_col by default
    Ayan Biswas committed Jun 7, 2021
    Copy the full SHA
    823daea View commit details

Commits on Jun 10, 2021

  1. support substrate row for core cell inside guard ring

    Ayan Biswas committed Jun 10, 2021
    Copy the full SHA
    bbfcc90 View commit details

Commits on Jun 14, 2021

  1. add esd_static layout and schematic

    Ayan Biswas committed Jun 14, 2021
    Copy the full SHA
    524e653 View commit details
  2. Copy the full SHA
    76d3d97 View commit details
  3. corrections from comments

    boblinchuan committed Jun 14, 2021
    Copy the full SHA
    5e2a659 View commit details
  4. Merge pull request #4 from boblinchuan/res_array

    More helper functions for res array
    ayan-biswas authored Jun 14, 2021
    Copy the full SHA
    b9c1088 View commit details

Commits on Jun 15, 2021

  1. minor fixes in ResArrayBase helper methods

    Ayan Biswas committed Jun 15, 2021
    Copy the full SHA
    71cb99b View commit details
  2. Copy the full SHA
    08e0279 View commit details

Commits on Jun 20, 2021

  1. add esd unit with esd_vdd and esd_vss

    Ayan Biswas committed Jun 20, 2021
    Copy the full SHA
    9a60dff View commit details

Commits on Jun 30, 2021

  1. minor fixes in ESDStatic layout

    Ayan Biswas committed Jun 30, 2021
    Copy the full SHA
    9ff880a View commit details

Commits on Jul 13, 2021

  1. Copy the full SHA
    61f418a View commit details

Commits on Jul 15, 2021

  1. LayoutInfoBuilder now supports primitive instances

    Ayan Biswas committed Jul 15, 2021
    Copy the full SHA
    a904804 View commit details
  2. minor update in hm_layer routing of ResArrayBase

    Ayan Biswas committed Jul 15, 2021
    Copy the full SHA
    dc0ca3e View commit details

Commits on Jul 16, 2021

  1. minor optimization in connect_hm_vm() of ResArrayBase

    Ayan Biswas committed Jul 16, 2021
    Copy the full SHA
    d9cad60 View commit details

Commits on Jul 18, 2021

  1. add via_test script

    Ayan Biswas committed Jul 18, 2021
    Copy the full SHA
    3dda7ab View commit details

Commits on Aug 22, 2021

  1. 1. ResArrayBase: make connect_bulk_xm() return the bulk warrs on xm_l…

    …ayer; 2. Add test layout script for black box
    Ayan Biswas committed Aug 22, 2021
    Copy the full SHA
    aaaf87b View commit details

Commits on Dec 4, 2021

  1. minor style update in mos_char schematic generator

    Ayan Biswas committed Dec 4, 2021
    Copy the full SHA
    65e54d1 View commit details

Commits on Feb 6, 2022

  1. Copy the full SHA
    99e7a40 View commit details

Commits on Feb 22, 2022

  1. remove license from behavioral model templates

    Ayan Biswas committed Feb 22, 2022
    Copy the full SHA
    06a77cf View commit details
  2. Copy the full SHA
    12af6ef View commit details

Commits on Feb 28, 2022

  1. minor fix in resistor layout helper method

    Ayan Biswas committed Feb 28, 2022
    Copy the full SHA
    f48256b View commit details

Commits on Mar 6, 2022

  1. fix res_type in ResBasePlaceInfo

    Ayan Biswas committed Mar 6, 2022
    Copy the full SHA
    ebed500 View commit details

Commits on Mar 13, 2022

  1. Copy the full SHA
    2cca263 View commit details
  2. Copy the full SHA
    02902da View commit details

Commits on Apr 21, 2022

  1. Double gate features

    boblinchuan committed Apr 21, 2022
    Copy the full SHA
    e6e08ec View commit details
  2. Copy the full SHA
    9b8ab70 View commit details

Commits on Apr 24, 2022

  1. More code linting

    boblinchuan committed Apr 24, 2022
    Copy the full SHA
    a704447 View commit details

Commits on Apr 25, 2022

  1. Merge pull request #5 from boblinchuan/double_gate

    Double gate features
    ayan-biswas authored Apr 25, 2022
    Copy the full SHA
    cc4bd63 View commit details
Showing with 7,904 additions and 808 deletions.
  1. +2 −2 .idea/modules.xml
  2. +3 −2 .idea/{xbase_bcad.iml → xbase.iml}
  3. BIN OA/xbase/clamp_static/data.dm
  4. BIN OA/xbase/clamp_static/schematic/data.dm
  5. +2 −0 OA/xbase/clamp_static/schematic/master.tag
  6. BIN OA/xbase/clamp_static/schematic/sch.oa
  7. BIN OA/xbase/clamp_static/schematic/thumbnail_128x128.png
  8. +2 −0 OA/xbase/clamp_static/symbol/master.tag
  9. BIN OA/xbase/clamp_static/symbol/symbol.oa
  10. BIN OA/xbase/clamp_static/symbol/thumbnail_128x128.png
  11. BIN OA/xbase/current_summer/data.dm
  12. BIN OA/xbase/current_summer/schematic/data.dm
  13. BIN OA/xbase/current_summer/schematic/sch.oa
  14. BIN OA/xbase/current_summer/schematic/thumbnail_128x128.png
  15. BIN OA/xbase/current_summer/symbol/symbol.oa
  16. BIN OA/xbase/current_summer/symbol/thumbnail_128x128.png
  17. BIN OA/xbase/data.dm
  18. BIN OA/xbase/esd/data.dm
  19. BIN OA/xbase/esd/schematic/data.dm
  20. +2 −0 OA/xbase/esd/schematic/master.tag
  21. BIN OA/xbase/esd/schematic/sch.oa
  22. BIN OA/xbase/esd/schematic/thumbnail_128x128.png
  23. +2 −0 OA/xbase/esd/symbol/master.tag
  24. BIN OA/xbase/esd/symbol/symbol.oa
  25. BIN OA/xbase/esd/symbol/thumbnail_128x128.png
  26. BIN OA/xbase/esd_static/data.dm
  27. BIN OA/xbase/esd_static/schematic/data.dm
  28. +2 −0 OA/xbase/esd_static/schematic/master.tag
  29. BIN OA/xbase/esd_static/schematic/sch.oa
  30. BIN OA/xbase/esd_static/schematic/thumbnail_128x128.png
  31. 0 OA/xbase/esd_static/symbol/data.dm
  32. +2 −0 OA/xbase/esd_static/symbol/master.tag
  33. BIN OA/xbase/esd_static/symbol/symbol.oa
  34. BIN OA/xbase/esd_static/symbol/thumbnail_128x128.png
  35. BIN OA/xbase/mimcap/data.dm
  36. BIN OA/xbase/mimcap/schematic/data.dm
  37. +2 −0 OA/xbase/mimcap/schematic/master.tag
  38. BIN OA/xbase/mimcap/schematic/sch.oa
  39. BIN OA/xbase/mimcap/schematic/thumbnail_128x128.png
  40. 0 OA/xbase/mimcap/symbol/data.dm
  41. +2 −0 OA/xbase/mimcap/symbol/master.tag
  42. BIN OA/xbase/mimcap/symbol/symbol.oa
  43. BIN OA/xbase/mimcap/symbol/thumbnail_128x128.png
  44. BIN OA/xbase/momcap_char/data.dm
  45. BIN OA/xbase/momcap_char/schematic/data.dm
  46. +2 −0 OA/xbase/momcap_char/schematic/master.tag
  47. BIN OA/xbase/momcap_char/schematic/sch.oa
  48. BIN OA/xbase/momcap_char/schematic/thumbnail_128x128.png
  49. 0 OA/xbase/momcap_char/symbol/data.dm
  50. +2 −0 OA/xbase/momcap_char/symbol/master.tag
  51. BIN OA/xbase/momcap_char/symbol/symbol.oa
  52. BIN OA/xbase/momcap_char/symbol/thumbnail_128x128.png
  53. BIN OA/xbase/momcap_core/data.dm
  54. BIN OA/xbase/momcap_core/schematic/data.dm
  55. BIN OA/xbase/momcap_core/schematic/sch.oa
  56. BIN OA/xbase/momcap_core/schematic/thumbnail_128x128.png
  57. BIN OA/xbase/momcap_core/symbol/symbol.oa
  58. BIN OA/xbase/momcap_core/symbol/thumbnail_128x128.png
  59. BIN OA/xbase/nmos4_analog/symbol/symbol.oa
  60. BIN OA/xbase/nmos4_analog/symbol/thumbnail_128x128.png
  61. BIN OA/xbase/nmos4_stack/symbol/symbol.oa
  62. BIN OA/xbase/nmos4_stack/symbol/thumbnail_128x128.png
  63. BIN OA/xbase/pmos4_analog/symbol/symbol.oa
  64. BIN OA/xbase/pmos4_analog/symbol/thumbnail_128x128.png
  65. BIN OA/xbase/pmos4_stack/symbol/symbol.oa
  66. BIN OA/xbase/pmos4_stack/symbol/thumbnail_128x128.png
  67. BIN OA/xbase/res_char/data.dm
  68. BIN OA/xbase/res_char/schematic/data.dm
  69. +2 −0 OA/xbase/res_char/schematic/master.tag
  70. BIN OA/xbase/res_char/schematic/sch.oa
  71. BIN OA/xbase/res_char/schematic/thumbnail_128x128.png
  72. 0 OA/xbase/res_char/symbol/data.dm
  73. +2 −0 OA/xbase/res_char/symbol/master.tag
  74. BIN OA/xbase/res_char/symbol/symbol.oa
  75. BIN OA/xbase/res_char/symbol/thumbnail_128x128.png
  76. BIN OA/xbase/sch_template/data.dm
  77. BIN OA/xbase/sch_template/schematic/data.dm
  78. +2 −0 OA/xbase/sch_template/schematic/master.tag
  79. BIN OA/xbase/sch_template/schematic/sch.oa
  80. BIN OA/xbase/sch_template/schematic/thumbnail_128x128.png
  81. +2 −0 OA/xbase/sch_template/symbol/master.tag
  82. BIN OA/xbase/sch_template/symbol/symbol.oa
  83. BIN OA/xbase/sch_template/symbol/thumbnail_128x128.png
  84. +176 −20 src/xbase/layout/array/base.py
  85. +6 −3 src/xbase/layout/array/data.py
  86. +12 −5 src/xbase/layout/array/primitives.py
  87. +21 −0 src/xbase/layout/array/tech.py
  88. +28 −4 src/xbase/layout/array/top.py
  89. +86 −0 src/xbase/layout/cap/char.py
  90. +32 −27 src/xbase/layout/cap/core.py
  91. +132 −0 src/xbase/layout/cap/mim.py
  92. +158 −0 src/xbase/layout/cap/mos.py
  93. +88 −0 src/xbase/layout/cap/tech.py
  94. +206 −0 src/xbase/layout/clamp/__init__.py
  95. +30 −3 src/xbase/layout/data.py
  96. +24 −1 src/xbase/layout/enum.py
  97. +225 −0 src/xbase/layout/esd_static/__init__.py
  98. +121 −0 src/xbase/layout/esd_static/esd.py
  99. +1 −0 src/xbase/layout/fill/base.py
  100. +38 −2 src/xbase/layout/mos/base.py
  101. +76 −35 src/xbase/layout/mos/char.py
  102. +92 −22 src/xbase/layout/mos/data.py
  103. +66 −17 src/xbase/layout/mos/guardring.py
  104. +112 −34 src/xbase/layout/mos/placement/compact.py
  105. +16 −3 src/xbase/layout/mos/placement/data.py
  106. +13 −4 src/xbase/layout/mos/primitives.py
  107. +171 −0 src/xbase/layout/mos/static.py
  108. +35 −11 src/xbase/layout/mos/tech.py
  109. +61 −22 src/xbase/layout/mos/top.py
  110. +410 −8 src/xbase/layout/res/base.py
  111. +105 −0 src/xbase/layout/res/char.py
  112. +12 −0 src/xbase/layout/res/tech.py
  113. +87 −0 src/xbase/schematic/clamp_static.py
  114. +89 −0 src/xbase/schematic/esd.py
  115. +94 −0 src/xbase/schematic/esd_static.py
  116. +110 −0 src/xbase/schematic/mimcap.py
  117. +0 −16 src/xbase/schematic/models/current_summer.v
  118. +0 −16 src/xbase/schematic/models/esd_diode.v
  119. +0 −16 src/xbase/schematic/models/metal_short.v
  120. +5 −0 src/xbase/schematic/models/momcap_core.v
  121. +98 −0 src/xbase/schematic/momcap_char.py
  122. +15 −6 src/xbase/schematic/momcap_core.py
  123. +2 −0 src/xbase/schematic/mos_char.py
  124. +402 −0 src/xbase/schematic/netlist_info/clamp_static.symbol.yaml
  125. +202 −0 src/xbase/schematic/netlist_info/clamp_static.yaml
  126. +39 −28 src/xbase/schematic/netlist_info/current_summer.symbol.yaml
  127. +107 −40 src/xbase/schematic/netlist_info/current_summer.yaml
  128. +288 −0 src/xbase/schematic/netlist_info/esd.symbol.yaml
  129. +343 −0 src/xbase/schematic/netlist_info/esd.yaml
  130. +0 −15 src/xbase/schematic/netlist_info/esd_diode.symbol.yaml
  131. +0 −15 src/xbase/schematic/netlist_info/esd_diode.yaml
  132. +234 −0 src/xbase/schematic/netlist_info/esd_static.symbol.yaml
  133. +267 −0 src/xbase/schematic/netlist_info/esd_static.yaml
  134. +0 −15 src/xbase/schematic/netlist_info/metal_short.symbol.yaml
  135. +0 −15 src/xbase/schematic/netlist_info/metal_short.yaml
  136. +199 −0 src/xbase/schematic/netlist_info/mimcap.symbol.yaml
  137. +388 −0 src/xbase/schematic/netlist_info/mimcap.yaml
  138. +228 −0 src/xbase/schematic/netlist_info/momcap_char.symbol.yaml
  139. +323 −0 src/xbase/schematic/netlist_info/momcap_char.yaml
  140. +70 −78 src/xbase/schematic/netlist_info/momcap_core.symbol.yaml
  141. +12 −27 src/xbase/schematic/netlist_info/momcap_core.yaml
  142. +0 −15 src/xbase/schematic/netlist_info/mos_char.symbol.yaml
  143. +0 −15 src/xbase/schematic/netlist_info/mos_char.yaml
  144. +4 −19 src/xbase/schematic/netlist_info/nmos4_analog.symbol.yaml
  145. +0 −15 src/xbase/schematic/netlist_info/nmos4_analog.yaml
  146. +20 −38 src/xbase/schematic/netlist_info/nmos4_stack.symbol.yaml
  147. +38 −56 src/xbase/schematic/netlist_info/nmos4_stack.yaml
  148. +4 −19 src/xbase/schematic/netlist_info/pmos4_analog.symbol.yaml
  149. +0 −15 src/xbase/schematic/netlist_info/pmos4_analog.yaml
  150. +20 −38 src/xbase/schematic/netlist_info/pmos4_stack.symbol.yaml
  151. +38 −56 src/xbase/schematic/netlist_info/pmos4_stack.yaml
  152. +234 −0 src/xbase/schematic/netlist_info/res_char.symbol.yaml
  153. +272 −0 src/xbase/schematic/netlist_info/res_char.yaml
  154. +216 −0 src/xbase/schematic/netlist_info/sch_template.symbol.yaml
  155. +290 −0 src/xbase/schematic/netlist_info/sch_template.yaml
  156. +17 −1 src/xbase/schematic/nmos4_analog.py
  157. +18 −2 src/xbase/schematic/nmos4_stack.py
  158. +17 −1 src/xbase/schematic/pmos4_analog.py
  159. +18 −2 src/xbase/schematic/pmos4_stack.py
  160. +98 −0 src/xbase/schematic/res_char.py
  161. +175 −0 src/xbase/schematic/sch_template.py
  162. +30 −0 src/xbase_test/layout/blackbox_test.py
  163. +116 −0 src/xbase_test/layout/mos/doublegate.py
  164. +26 −4 src/xbase_test/layout/res.py
  165. +65 −0 src/xbase_test/layout/via_test.py
4 changes: 2 additions & 2 deletions .idea/modules.xml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

5 changes: 3 additions & 2 deletions .idea/xbase_bcad.iml → .idea/xbase.iml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Binary file added OA/xbase/clamp_static/data.dm
Binary file not shown.
Binary file added OA/xbase/clamp_static/schematic/data.dm
Binary file not shown.
2 changes: 2 additions & 0 deletions OA/xbase/clamp_static/schematic/master.tag
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
-- Master.tag File, Rev:1.0
sch.oa
Binary file added OA/xbase/clamp_static/schematic/sch.oa
Binary file not shown.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
2 changes: 2 additions & 0 deletions OA/xbase/clamp_static/symbol/master.tag
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
-- Master.tag File, Rev:1.0
symbol.oa
Binary file added OA/xbase/clamp_static/symbol/symbol.oa
Binary file not shown.
Binary file added OA/xbase/clamp_static/symbol/thumbnail_128x128.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified OA/xbase/current_summer/data.dm
Binary file not shown.
Binary file modified OA/xbase/current_summer/schematic/data.dm
Binary file not shown.
Binary file modified OA/xbase/current_summer/schematic/sch.oa
Binary file not shown.
Binary file modified OA/xbase/current_summer/schematic/thumbnail_128x128.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified OA/xbase/current_summer/symbol/symbol.oa
Binary file not shown.
Binary file modified OA/xbase/current_summer/symbol/thumbnail_128x128.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified OA/xbase/data.dm
Binary file not shown.
Binary file added OA/xbase/esd/data.dm
Binary file not shown.
Binary file added OA/xbase/esd/schematic/data.dm
Binary file not shown.
2 changes: 2 additions & 0 deletions OA/xbase/esd/schematic/master.tag
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
-- Master.tag File, Rev:1.0
sch.oa
Binary file added OA/xbase/esd/schematic/sch.oa
Binary file not shown.
Binary file added OA/xbase/esd/schematic/thumbnail_128x128.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
2 changes: 2 additions & 0 deletions OA/xbase/esd/symbol/master.tag
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
-- Master.tag File, Rev:1.0
symbol.oa
Binary file added OA/xbase/esd/symbol/symbol.oa
Binary file not shown.
Binary file added OA/xbase/esd/symbol/thumbnail_128x128.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added OA/xbase/esd_static/data.dm
Binary file not shown.
Binary file added OA/xbase/esd_static/schematic/data.dm
Binary file not shown.
2 changes: 2 additions & 0 deletions OA/xbase/esd_static/schematic/master.tag
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
-- Master.tag File, Rev:1.0
sch.oa
Binary file added OA/xbase/esd_static/schematic/sch.oa
Binary file not shown.
Binary file added OA/xbase/esd_static/schematic/thumbnail_128x128.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Empty file.
2 changes: 2 additions & 0 deletions OA/xbase/esd_static/symbol/master.tag
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
-- Master.tag File, Rev:1.0
symbol.oa
Binary file added OA/xbase/esd_static/symbol/symbol.oa
Binary file not shown.
Binary file added OA/xbase/esd_static/symbol/thumbnail_128x128.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added OA/xbase/mimcap/data.dm
Binary file not shown.
Binary file added OA/xbase/mimcap/schematic/data.dm
Binary file not shown.
2 changes: 2 additions & 0 deletions OA/xbase/mimcap/schematic/master.tag
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
-- Master.tag File, Rev:1.0
sch.oa
Binary file added OA/xbase/mimcap/schematic/sch.oa
Binary file not shown.
Binary file added OA/xbase/mimcap/schematic/thumbnail_128x128.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Empty file added OA/xbase/mimcap/symbol/data.dm
Empty file.
2 changes: 2 additions & 0 deletions OA/xbase/mimcap/symbol/master.tag
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
-- Master.tag File, Rev:1.0
symbol.oa
Binary file added OA/xbase/mimcap/symbol/symbol.oa
Binary file not shown.
Binary file added OA/xbase/mimcap/symbol/thumbnail_128x128.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added OA/xbase/momcap_char/data.dm
Binary file not shown.
Binary file added OA/xbase/momcap_char/schematic/data.dm
Binary file not shown.
2 changes: 2 additions & 0 deletions OA/xbase/momcap_char/schematic/master.tag
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
-- Master.tag File, Rev:1.0
sch.oa
Binary file added OA/xbase/momcap_char/schematic/sch.oa
Binary file not shown.
Binary file added OA/xbase/momcap_char/schematic/thumbnail_128x128.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Empty file.
2 changes: 2 additions & 0 deletions OA/xbase/momcap_char/symbol/master.tag
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
-- Master.tag File, Rev:1.0
symbol.oa
Binary file added OA/xbase/momcap_char/symbol/symbol.oa
Binary file not shown.
Binary file added OA/xbase/momcap_char/symbol/thumbnail_128x128.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified OA/xbase/momcap_core/data.dm
Binary file not shown.
Binary file modified OA/xbase/momcap_core/schematic/data.dm
Binary file not shown.
Binary file modified OA/xbase/momcap_core/schematic/sch.oa
Binary file not shown.
Binary file modified OA/xbase/momcap_core/schematic/thumbnail_128x128.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified OA/xbase/momcap_core/symbol/symbol.oa
Binary file not shown.
Binary file modified OA/xbase/momcap_core/symbol/thumbnail_128x128.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified OA/xbase/nmos4_analog/symbol/symbol.oa
Binary file not shown.
Binary file modified OA/xbase/nmos4_analog/symbol/thumbnail_128x128.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified OA/xbase/nmos4_stack/symbol/symbol.oa
Binary file not shown.
Binary file modified OA/xbase/nmos4_stack/symbol/thumbnail_128x128.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified OA/xbase/pmos4_analog/symbol/symbol.oa
Binary file not shown.
Binary file modified OA/xbase/pmos4_analog/symbol/thumbnail_128x128.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified OA/xbase/pmos4_stack/symbol/symbol.oa
Binary file not shown.
Binary file modified OA/xbase/pmos4_stack/symbol/thumbnail_128x128.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added OA/xbase/res_char/data.dm
Binary file not shown.
Binary file added OA/xbase/res_char/schematic/data.dm
Binary file not shown.
2 changes: 2 additions & 0 deletions OA/xbase/res_char/schematic/master.tag
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
-- Master.tag File, Rev:1.0
sch.oa
Binary file added OA/xbase/res_char/schematic/sch.oa
Binary file not shown.
Binary file added OA/xbase/res_char/schematic/thumbnail_128x128.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Empty file.
2 changes: 2 additions & 0 deletions OA/xbase/res_char/symbol/master.tag
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
-- Master.tag File, Rev:1.0
symbol.oa
Binary file added OA/xbase/res_char/symbol/symbol.oa
Binary file not shown.
Binary file added OA/xbase/res_char/symbol/thumbnail_128x128.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added OA/xbase/sch_template/data.dm
Binary file not shown.
Binary file added OA/xbase/sch_template/schematic/data.dm
Binary file not shown.
2 changes: 2 additions & 0 deletions OA/xbase/sch_template/schematic/master.tag
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
-- Master.tag File, Rev:1.0
sch.oa
Binary file added OA/xbase/sch_template/schematic/sch.oa
Binary file not shown.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
2 changes: 2 additions & 0 deletions OA/xbase/sch_template/symbol/master.tag
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
-- Master.tag File, Rev:1.0
symbol.oa
Binary file added OA/xbase/sch_template/symbol/symbol.oa
Binary file not shown.
Binary file added OA/xbase/sch_template/symbol/thumbnail_128x128.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
196 changes: 176 additions & 20 deletions src/xbase/layout/array/base.py
Original file line number Diff line number Diff line change
@@ -15,16 +15,18 @@

from __future__ import annotations

from typing import Any, Optional, Mapping, List, Union, Type, TypeVar, Tuple
from typing import Any, Optional, Mapping, List, Union, Type, TypeVar, Tuple, cast

import abc
import copy

from pybag.enum import Orientation
from pybag.core import Transform, BBox
from pybag.core import Transform, BBox, BBoxArray

from bag.util.math import HalfInt
from bag.util.immutable import Param, combine_hash, ImmutableSortedDict
from bag.layout.tech import TechInfo
from bag.layout.core import PyLayInstance
from bag.layout.routing.base import TrackID, TrackManager, WDictType, SpDictType, WireArray
from bag.layout.template import TemplateBase, TemplateDB
from bag.layout.routing.grid import RoutingGrid, TrackSpec
@@ -44,7 +46,8 @@ def __init__(self, parent_grid: RoutingGrid, wire_specs: Mapping[int, Any],
tr_widths: WDictType, tr_spaces: SpDictType, top_layer: int, nx: int, ny: int,
tech_cls: T, *, conn_layer: Optional[int] = None,
tr_specs: Optional[List[TrackSpec]] = None, half_space: bool = True,
ext_mode: ExtendMode = ExtendMode.AREA, **kwargs: Any) -> None:
ext_mode: ExtendMode = ExtendMode.AREA,
base_orient: Orientation = Orientation.R0, is_top: bool = True, **kwargs: Any) -> None:
self._tech_cls: ArrayTech = tech_cls

# update routing grid
@@ -62,24 +65,42 @@ def __init__(self, parent_grid: RoutingGrid, wire_specs: Mapping[int, Any],
self._blk_options = Param(kwargs)
self._nx = nx
self._ny = ny
self._base_orient = base_orient
self._is_top = is_top

tmp = self._tech_cls.size_unit_block(conn_layer, top_layer, nx, ny, self._tr_manager,
wire_specs, ext_mode, **kwargs)
self._wire_specs = wire_specs
self._ext_mode = ext_mode

self._w = None
self._h = None
self._wlookup = None
self._blk_info = None
self._hash = None

self.commit()

def commit(self):
tmp = self._tech_cls.size_unit_block(self._conn_layer, self._top_layer, self._nx, self._ny, self._tr_manager,
self._wire_specs, self._ext_mode, **self._blk_options)
self._w: int = tmp[0]
self._h: int = tmp[1]
self._wlookup: ImmutableSortedDict[int, WireLookup] = ImmutableSortedDict(tmp[2])
self._blk_info: ArrayLayInfo = tmp[3]

# compute hash
self._hash = self.compute_hash()

def compute_hash(self):
seed = combine_hash(hash(self._tr_manager), self._conn_layer)
seed = combine_hash(seed, self._top_layer)
seed = combine_hash(seed, self._nx)
seed = combine_hash(seed, self._ny)
seed = combine_hash(seed, self._base_orient)
seed = combine_hash(seed, self._is_top)
seed = combine_hash(seed, self._w)
seed = combine_hash(seed, self._h)
seed = combine_hash(seed, hash(self._wlookup))
seed = combine_hash(seed, hash(self._blk_options))
self._hash = seed
return seed

def __hash__(self) -> int:
return self._hash
@@ -138,10 +159,12 @@ def conn_layer(self) -> int:

@property
def width(self) -> int:
"""Width of a unit cell, in resolution units"""
return self._w

@property
def height(self) -> int:
"""Height of a unit cell, in resolution units"""
return self._h

@property
@@ -152,13 +175,40 @@ def nx(self) -> int:
def ny(self) -> int:
return self._ny

@property
def is_top(self) -> bool:
return self._is_top

@property
def blk_info(self) -> ArrayLayInfo:
return self._blk_info

def get_wire_track_info(self, layer: int, wire_name: str, wire_idx: int) -> Tuple[HalfInt, int]:
return self._wlookup[layer].get_track_info(wire_name, wire_idx)

def get_sub_place_info(self, nx: Optional[int] = None, ny: Optional[int] = None, top_layer: Optional[int] = None,
row: int = 0, col: int = 0, base_orient: Optional[Orientation] = None,
is_top: bool = False) -> ArrayPlaceInfo:
ans = copy.copy(self)

if nx is not None:
ans._nx = nx
if ny is not None:
ans._ny = ny
if top_layer is not None:
ans._top_layer = top_layer
if base_orient is None:
base_orient = self._base_orient
if row & 1:
base_orient = base_orient.flip_ud()
if col & 1:
base_orient = base_orient.flip_lr()
ans._base_orient = base_orient
ans._is_top = is_top

ans.commit()
return ans


class ArrayBase(TemplateBase, abc.ABC):
def __init__(self, temp_db: TemplateDB, params: Param, **kwargs: Any) -> None:
@@ -190,10 +240,16 @@ def nx(self) -> int:
def ny(self) -> int:
return self._info.ny

def draw_base(self, info: ArrayPlaceInfo) -> ArrayUnit:
def draw_base(self, info: ArrayPlaceInfo, flip_lr: bool = False, flip_ud: bool = False,
commit: bool = None) -> ArrayUnit:
self._info = info
self.grid = info.grid

# By default, only commit unit instances if info is the top ArrayPlaceInfo.
# If info is not top (i.e. a subset of another ArrayPlaceInfo), the unit array should be drawn at the top level.
if commit is None:
commit = info.is_top

self._unit = master = self.new_template(ArrayUnit, params=dict(desc=self.tech_cls.desc,
blk_info=info.blk_info))

@@ -203,18 +259,31 @@ def draw_base(self, info: ArrayPlaceInfo) -> ArrayUnit:
nye = info.ny - nyo
spx = 2 * info.width
spy = 2 * info.height
self.add_instance(master, inst_name='XLL', xform=Transform(0, 0),
nx=nxe, ny=nye, spx=spx, spy=spy)

orient_list = [Orientation.R0, Orientation.MY, Orientation.MX, Orientation.R180]

if flip_lr:
orient_list = [orient.flip_lr() for orient in orient_list]
dx_list = [spx // 2, spx // 2, spx // 2, spx // 2]
else:
dx_list = [0, spx, 0, spx]

if flip_ud:
orient_list = [orient.flip_ud() for orient in orient_list]
dy_list = [spy // 2, spy // 2, spy // 2, spy // 2]
else:
dy_list = [0, 0, spy, spy]
xform_ll, xform_lr, xform_ul, xform_ur = [Transform(dx, dy, orient) for dx, dy, orient in
zip(dx_list, dy_list, orient_list)]

self.add_instance(master, inst_name='XLL', xform=xform_ll, nx=nxe, ny=nye, spx=spx, spy=spy, commit=commit)
if nxo > 0:
self.add_instance(master, inst_name='XLR', xform=Transform(spx, 0, Orientation.MY),
nx=nxo, ny=nye, spx=spx, spy=spy)
self.add_instance(master, inst_name='XLR', xform=xform_lr, nx=nxo, ny=nye, spx=spx, spy=spy, commit=commit)
if nyo > 0:
self.add_instance(master, inst_name='XUL', xform=Transform(0, spy, Orientation.MX),
nx=nxe, ny=nyo, spx=spx, spy=spy)
self.add_instance(master, inst_name='XUL', xform=xform_ul, nx=nxe, ny=nyo, spx=spx, spy=spy, commit=commit)
if nxo > 0:
self.add_instance(master, inst_name='XUR',
xform=Transform(spx, spy, Orientation.R180),
nx=nxo, ny=nyo, spx=spx, spy=spy)
self.add_instance(master, inst_name='XUR', xform=xform_ur, nx=nxo, ny=nyo, spx=spx, spy=spy,
commit=commit)

bbox = BBox(0, 0, info.nx * info.width, info.ny * info.height)
self.set_size_from_bound_box(info.top_layer, bbox)
@@ -237,7 +306,7 @@ def get_track_index(self, wire_name: str, wire_idx: int = 0, layer: Optional[int
) -> HalfInt:
return self.get_track_info(wire_name, wire_idx=wire_idx, layer=layer)[0]

def get_device_port(self, xidx: int, yidx: int, name: str) -> WireArray:
def get_device_port(self, xidx: int, yidx: int, name: str) -> Union[WireArray, BBox, BBoxArray]:
w = self._info.width
h = self._info.height
orient = Orientation.R0
@@ -252,5 +321,92 @@ def get_device_port(self, xidx: int, yidx: int, name: str) -> WireArray:
orient = orient.flip_ud()

xform = Transform(dx, dy, orient)

return self._unit.get_port(name).get_pins()[0].get_transform(xform)
pins = self._unit.get_port(name).get_pins()
nx = ny = len(pins)
if nx == 1:
return pins[0].get_transform(xform)
else:
if isinstance(pins[0], WireArray):
# Combine into 1 WireArray with num > 1 if possible
pins = self.connect_wires(pins[0])
return pins[0].get_transform(xform)
else: # List of BBox
pins = [cast(BBox, bbox) for bbox in pins]

# First, try to make BBoxArray with nx > 1
yl = pins[0].yl
yh = pins[0].yh
w = pins[0].w
spx = pins[1].xm - pins[0].xm
for pidx, pin in enumerate(pins[1:]):
if not (pin.yl == yl and pin.yh == yh and pin.w == w):
# cannot be combined into BBoxArray if yl, yh, w are not same
break
if pidx != nx - 2:
if pins[pidx + 2].xm - pin.xm != spx:
# cannot be combined into BBoxArray if spx is not same
break
else:
return BBoxArray(pins[0], nx=nx, spx=spx).get_transform(xform)

# Next, try to make BBoxArray with ny > 1
xl = pins[0].xl
xh = pins[0].xh
h = pins[0].h
spy = pins[1].ym - pins[0].ym
for pidx, pin in enumerate(pins[1:]):
if not (pin.xl == xl and pin.xh == xh and pin.h == h):
# cannot be combined into BBoxArray if xl, xh, h are not same
break
if pidx != ny - 2:
if pins[pidx + 2].ym - pin.ym != spy:
# cannot be combined into BBoxArray if spy is not same
break
else:
return BBoxArray(pins[0], ny=ny, spy=spy).get_transform(xform)

# both the for loops encountered break
return pins[0].get_transform(xform)

def add_tile(self, master: ArrayBase, row_idx: int, col_idx: int, *,
flip_lr: bool = False, flip_ud: bool = False, commit: bool = True) -> PyLayInstance:
self._row_check(row_idx, master.ny, flip_ud)
self._col_check(col_idx, master.nx, flip_lr)

unit_h, unit_w = self._info.height, self._info.width

y0 = row_idx * unit_h
x0 = col_idx * unit_w

if flip_ud:
orient = Orientation.MX
y0 += unit_h
else:
orient = Orientation.R0

if flip_lr:
orient = orient.flip_lr()
x0 += unit_w

return self.add_instance(master, inst_name=f'XR{row_idx}C{col_idx}',
xform=Transform(x0, y0, orient), commit=commit)

def _row_check(self, row_idx: int, num_rows: int, flip: bool):
if flip:
row_bot, row_top = row_idx - num_rows + 1, row_idx
else:
row_bot, row_top = row_idx, row_idx + num_rows - 1
if row_bot < 0:
raise ValueError(f"Bottom row {row_bot} cannot be less than 0")
if row_top >= self.ny:
raise ValueError(f"Top row {row_top} cannot be greater than or equal to ny {self.ny}")

def _col_check(self, col_idx: int, num_cols: int, flip: bool):
if flip:
col_left, col_right = col_idx - num_cols + 1, col_idx
else:
col_left, col_right = col_idx, col_idx + num_cols - 1
if col_left < 0:
raise ValueError(f"left col {col_left} cannot be less than 0")
if col_right > self.nx:
raise ValueError(f"right col {col_right} cannot be greater than or equal to nx {self.nx}")
9 changes: 6 additions & 3 deletions src/xbase/layout/array/data.py
Original file line number Diff line number Diff line change
@@ -13,20 +13,23 @@
# See the License for the specific language governing permissions and
# limitations under the License.

from typing import Any
from typing import Any, Union, Sequence, Tuple

from dataclasses import dataclass

from pybag.core import BBox

from bag.util.immutable import ImmutableSortedDict

from ..data import LayoutInfo, WireArrayInfo


@dataclass(eq=True, frozen=True)
class ArrayLayInfo:
"""The transistor block layout information object."""
"""The unit array layout information object."""
lay_info: LayoutInfo
ports_info: ImmutableSortedDict[str, WireArrayInfo]
ports_info: ImmutableSortedDict[str, Union[WireArrayInfo,
Sequence[Tuple[str, Sequence[BBox]]]]]
edge_info: ImmutableSortedDict[str, Any]
end_info: ImmutableSortedDict[str, Any]

17 changes: 12 additions & 5 deletions src/xbase/layout/array/primitives.py
Original file line number Diff line number Diff line change
@@ -20,7 +20,7 @@
from bag.layout.template import TemplateBase, TemplateDB

from ..data import draw_layout_in_template
from .data import ArrayLayInfo
from .data import ArrayLayInfo, WireArrayInfo
from .tech import ArrayTech


@@ -56,10 +56,17 @@ def draw_layout(self) -> None:

draw_layout_in_template(self, blk_info.lay_info)
grid = self.grid
for key, val in blk_info.ports_info.items():
cur_warr = val.to_warr(grid)
self.add_pin(key, cur_warr)
self.prim_top_layer = cur_warr.layer_id
if isinstance(list(blk_info.ports_info.values())[0], WireArrayInfo):
for key, val in blk_info.ports_info.items():
cur_warr = val.to_warr(grid)
self.add_pin(key, cur_warr)
self.prim_top_layer = cur_warr.layer_id
else:
for port_name, port_info in blk_info.ports_info.items():
for lay_name, bbox_list in port_info:
for bbox in bbox_list:
self.add_pin_primitive(port_name, lay_name, bbox)
self.prim_top_layer = grid.bot_layer


class ArrayEnd(TemplateBase):
21 changes: 21 additions & 0 deletions src/xbase/layout/array/tech.py
Original file line number Diff line number Diff line change
@@ -115,13 +115,34 @@ def size_unit_block(self, conn_layer: int, top_layer: int, nx: int, ny: int,
tr_manager: TrackManager, wire_specs: Mapping[int, Any], mode: ExtendMode,
max_ext: int = 1000, **kwargs: Any
) -> Tuple[int, int, Dict[int, WireLookup], ArrayLayInfo]:
"""Determine the size of the ArrayUnit for constructing ArrayPlaceInfo.
A block can be sized in three ways:
(1) Binary search for the minimum area, based on the tech implementation of `get_blk_info`
(2) Wire specs, if given, can set a lower bound
(3) Manual lower bounds can be set with kwargs `min_width` and `min_height`
Based on these three, the smallest area is determined.
Returns
-------
w : int
Unit width
h : int
Unit height
wlookup : Mapping[int, WireLookup]
Wire lookup table based on wire specs
blk_info : ArrayLayInfo
Unit array info
"""
wire_specs = WireSpecs.make_wire_specs(conn_layer, top_layer, tr_manager, wire_specs,
min_size=self.min_size, blk_pitch=self.blk_pitch,
align_default=Alignment.CENTER_COMPACT)

blk_info: Optional[ArrayLayInfo] = None
w_min, h_min = wire_specs.min_size
blk_w, blk_h = wire_specs.blk_size
# Kwarg bypass
w_min = max(w_min, kwargs.get("min_width", 0))
h_min = max(h_min, kwargs.get("min_height", 0))
w = w_min
h = h_min
opt_area = COORD_MAX ** 2
32 changes: 28 additions & 4 deletions src/xbase/layout/array/top.py
Original file line number Diff line number Diff line change
@@ -13,7 +13,7 @@
# See the License for the specific language governing permissions and
# limitations under the License.

from typing import Any, Dict, Type, cast, Mapping
from typing import Any, Dict, Type, cast, Mapping, Optional

from pybag.core import BBox, Transform
from pybag.enum import Orientation
@@ -23,6 +23,7 @@
from bag.layout.data import TemplateEdgeInfo
from bag.layout.template import TemplateDB, TemplateBase
from bag.layout.core import PyLayInstance
from bag.design.module import Module

from .tech import ArrayTech
from .primitives import ArrayEnd, ArrayEdge, ArrayCorner
@@ -34,13 +35,32 @@ class ArrayBaseWrapper(TemplateBase):
def __init__(self, temp_db: TemplateDB, params: Param, **kwargs: Any) -> None:
TemplateBase.__init__(self, temp_db, params, **kwargs)

self._core: Optional[ArrayBase] = None

@property
def core(self) -> ArrayBase:
return self._core

@property
def core_xform(self) -> Transform:
return self._xform

@classmethod
def get_params_info(cls) -> Dict[str, str]:
return dict(
cls_name='wrapped class name.',
params='parameters for the wrapped class.',
half_blk_x='Defaults to True. True to allow half-block width.',
half_blk_y='Defaults to True. True to allow half-block height.',
)

@classmethod
def get_default_param_values(cls) -> Dict[str, Any]:
return dict(half_blk_x=True, half_blk_y=True)

def get_schematic_class_inst(self) -> Optional[Type[Module]]:
return self._core.get_schematic_class_inst()

def get_layout_basename(self) -> str:
cls_name: str = self.params.get('cls_name', '')
cls_name = cls_name.split('.')[-1]
@@ -55,7 +75,8 @@ def draw_layout(self):
gen_cls = cast(Type[ArrayBase], import_class(cls_name))
master = self.new_template(gen_cls, params=params)

inst = self.draw_boundaries(master, master.top_layer)
inst = self.draw_boundaries(master, master.top_layer, half_blk_x=self.params['half_blk_x'],
half_blk_y=self.params['half_blk_y'])
# pass out schematic parameters
self.sch_params = master.sch_params

@@ -65,6 +86,7 @@ def draw_layout(self):

def draw_boundaries(self, master: ArrayBase, top_layer: int, *,
half_blk_x: bool = True, half_blk_y: bool = True) -> PyLayInstance:
self._core = master
tech_cls: ArrayTech = master.tech_cls
core_box: BBox = master.bound_box
info: ArrayPlaceInfo = master.place_info
@@ -99,6 +121,8 @@ def draw_boundaries(self, master: ArrayBase, top_layer: int, *,
bbox = BBox(0, 0, tot_w, tot_h)
self.set_size_from_bound_box(top_layer, bbox)

self._xform = Transform(corner_w, corner_h)

self.add_instance(c_master, inst_name='CLL')
self.add_instance(c_master, inst_name='CLR', xform=Transform(tot_w, 0, Orientation.MY))
self.add_instance(c_master, inst_name='CUL', xform=Transform(0, tot_h, Orientation.MX))
@@ -112,10 +136,10 @@ def draw_boundaries(self, master: ArrayBase, top_layer: int, *,
self.add_instance(l_master, inst_name='ET',
xform=Transform(tot_w, corner_h, Orientation.MY), ny=ny, spy=spy)

inst = self.add_instance(master, inst_name='RES', xform=Transform(corner_w, corner_h))
inst = self.add_instance(master, inst_name='RES', xform=self._xform)

# set edge parameters
self.edge_info = TemplateEdgeInfo(c_master.left_edge, c_master.bottm_edge,
self.edge_info = TemplateEdgeInfo(c_master.left_edge, c_master.bottom_edge,
c_master.left_edge, c_master.bottom_edge)

return inst
86 changes: 86 additions & 0 deletions src/xbase/layout/cap/char.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
# BSD 3-Clause License
#
# Copyright (c) 2018, Regents of the University of California
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are met:
#
# * Redistributions of source code must retain the above copyright notice, this
# list of conditions and the following disclaimer.
#
# * Redistributions in binary form must reproduce the above copyright notice,
# this list of conditions and the following disclaimer in the documentation
# and/or other materials provided with the distribution.
#
# * Neither the name of the copyright holder nor the names of its
# contributors may be used to endorse or promote products derived from
# this software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

"""This module defines MOM cap on MOSBase with substrate contacts."""

from typing import Any, Dict, Optional, Mapping, List, Tuple, Type

from pybag.core import BBox, BBoxArray

from bag.util.immutable import Param
from bag.design.module import Module
from bag.layout.template import TemplateDB

from ...layout.mos.base import MOSBasePlaceInfo, MOSBase
from ...schematic.momcap_char import xbase__momcap_char
from .mos import MOMCapOnMOS


class MOMCapChar(MOSBase):
"""MOMCap core on MOSBase with substrate contacts
"""

def __init__(self, temp_db: TemplateDB, params: Param, **kwargs: Any) -> None:
MOSBase.__init__(self, temp_db, params, **kwargs)

@classmethod
def get_schematic_class(cls) -> Optional[Type[Module]]:
return xbase__momcap_char

@classmethod
def get_params_info(cls) -> Dict[str, str]:
return dict(
pinfo='The MOSBasePlaceInfo object.',
cap_params='Parameters for MOMCap',
)

def draw_layout(self) -> None:
pinfo = MOSBasePlaceInfo.make_place_info(self.grid, self.params['pinfo'])
self.draw_base(pinfo)

# draw cap
cap_params: Param = self.params['cap_params']
cap_tile = 1
cap_pinfo = self.get_tile_info(cap_tile)
cap_params = cap_params.copy(append=dict(pinfo=cap_pinfo))
cap_master: MOMCapOnMOS = self.new_template(MOMCapOnMOS, params=cap_params)

cap = self.add_tile(cap_master, cap_tile, 0)
for pin_name in ('plus', 'minus'):
self.reexport(cap.get_port(pin_name))

# draw substrate contacts
num_cols = cap_master.num_cols
vss0 = self.add_substrate_contact(0, 0, tile_idx=0, seg=num_cols)
vss1 = self.add_substrate_contact(0, 0, tile_idx=2, seg=num_cols)
self.add_pin('VSS', [vss0, vss1], connect=True)

self.set_mos_size()
self.sch_params = cap_master.sch_params
59 changes: 32 additions & 27 deletions src/xbase/layout/cap/core.py
Original file line number Diff line number Diff line change
@@ -122,29 +122,39 @@ def draw_layout(self) -> None:
cap_ports = self.add_mom_cap(cap_box, bot_layer, num_layer, port_widths=port_w_dict,
cap_wires_list=cw_list, **options)

# connect input/output, draw metal resistors
show_pins = self.show_pins
# connect input/output
for lay, (nport, pport) in cap_ports.items():
self.add_pin('plus', pport, show=show_pins)
self.add_pin('minus', nport, show=show_pins)

_, _, barr_n, barr_p = cw_list[-1]
box_p = barr_p.get_bbox(0)
box_n = barr_n.get_bbox(0)
top_dir = grid.get_direction(top_layer)
res_w = box_p.get_dim(top_dir.perpendicular())
coord_c = box_p.get_center(top_dir)

res_w2 = res_w // 2
res_w4 = res_w2 // 2
wl_p = coord_c - res_w2
wu_p = coord_c + res_w2
wl_n = coord_c - res_w4
wu_n = coord_c + res_w4
box_p.set_interval(top_dir, wl_p, wu_p)
box_n.set_interval(top_dir, wl_n, wu_n)
self.add_res_metal(top_layer, box_p)
self.add_res_metal(top_layer, box_n)
self.add_pin('plus', pport)
self.add_pin('minus', nport)

# draw metal resistors
if self.has_res_metal():
_, _, barr_n, barr_p = cw_list[-1]
box_p = barr_p.get_bbox(0)
box_n = barr_n.get_bbox(0)
top_dir = grid.get_direction(top_layer)
res_w = box_p.get_dim(top_dir.perpendicular())
coord_c = box_p.get_center(top_dir)

res_w2 = res_w // 2
res_w4 = res_w2 // 2
wl_p = coord_c - res_w2
wu_p = coord_c + res_w2
wl_n = coord_c - res_w4
wu_n = coord_c + res_w4
box_p.set_interval(top_dir, wl_p, wu_p)
box_n.set_interval(top_dir, wl_n, wu_n)
self.add_res_metal(top_layer, box_p)
self.add_res_metal(top_layer, box_n)

res_w = grid.get_track_info(top_layer).width
self.sch_params = dict(
has_res_metal=True,
res_p=dict(layer=top_layer, w=res_w, l=res_w2 * 2),
res_n=dict(layer=top_layer, w=res_w, l=res_w4 * 2),
)
else:
self.sch_params = dict(has_res_metal=False)

if fill_dummy:
dum_params = dict(
@@ -157,8 +167,3 @@ def draw_layout(self) -> None:
self.add_instance(master_dum)

# TODO: fill metal too
res_w = grid.get_track_info(top_layer).width
self.sch_params = dict(
res_p=dict(layer=top_layer, w=res_w, l=res_w2 * 2),
res_n=dict(layer=top_layer, w=res_w, l=res_w4 * 2),
)
132 changes: 132 additions & 0 deletions src/xbase/layout/cap/mim.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,132 @@
# BSD 3-Clause License
#
# Copyright (c) 2018, Regents of the University of California
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are met:
#
# * Redistributions of source code must retain the above copyright notice, this
# list of conditions and the following disclaimer.
#
# * Redistributions in binary form must reproduce the above copyright notice,
# this list of conditions and the following disclaimer in the documentation
# and/or other materials provided with the distribution.
#
# * Neither the name of the copyright holder nor the names of its
# contributors may be used to endorse or promote products derived from
# this software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

"""This module defines various MIM cap related templates."""

from typing import Any, Optional, Mapping, Type

from pybag.core import BBox

from bag.util.immutable import Param
from bag.design.module import Module
from bag.layout.template import TemplateDB, TemplateBase

from ..data import draw_layout_in_template
from .tech import MIMTech, MIMLayInfo
from ...schematic.mimcap import xbase__mimcap


class MIMCap(TemplateBase):
"""MIMCap array with optional dummies
"""
def __init__(self, temp_db: TemplateDB, params: Param, **kwargs: Any) -> None:
TemplateBase.__init__(self, temp_db, params, **kwargs)

@classmethod
def get_schematic_class(cls) -> Optional[Type[Module]]:
return xbase__mimcap

@classmethod
def get_params_info(cls) -> Mapping[str, str]:
return dict(
mim_type='Type of MIM cap; standard by default',
unit_width='width of single MIM unit (for array)',
unit_height='height of single MIM unit (for array)',
num_rows='number of rows',
num_cols='number of columns',
dum_row_b='number of dummy rows on bottom',
dum_row_t='number of dummy rows on top',
dum_col_l='number of dummy columns on left',
dum_col_r='number of dummy columns on right',
bot_port_tr_w='Track width of port on bottom layer',
top_port_tr_w='Track width of port on top layer',
)

@classmethod
def get_default_param_values(cls) -> Mapping[str, Any]:
return dict(
mim_type='standard',
num_rows=1,
num_cols=1,
dum_row_b=0,
dum_row_t=0,
dum_col_l=0,
dum_col_r=0,
bot_port_tr_w=1,
top_port_tr_w=1,
)

def draw_layout(self) -> None:
mim_type: str = self.params['mim_type']
unit_width: int = self.params['unit_width']
unit_height: int = self.params['unit_height']
num_rows: int = self.params['num_rows']
num_cols: int = self.params['num_cols']
dum_row_b: int = self.params['dum_row_b']
dum_row_t: int = self.params['dum_row_t']
dum_col_l: int = self.params['dum_col_l']
dum_col_r: int = self.params['dum_col_r']
bot_port_tr_w: int = self.params['bot_port_tr_w']
top_port_tr_w: int = self.params['top_port_tr_w']

tech_cls: MIMTech = self.grid.tech_info.get_device_tech('mim')

# primitive info
bot_layer, top_layer = tech_cls.get_port_layers(mim_type)
bot_w = self.grid.get_wire_total_width(bot_layer, bot_port_tr_w)
top_w = self.grid.get_wire_total_width(top_layer, top_port_tr_w)
mim_info: MIMLayInfo = tech_cls.get_mim_cap_info(bot_layer, top_layer, unit_width, unit_height,
num_rows, num_cols, dum_row_b, dum_row_t, dum_col_l, dum_col_r,
bot_w, top_w)
draw_layout_in_template(self, mim_info.lay_info)
top_bbox = mim_info.lay_info.bound_box

self.set_size_from_bound_box(top_layer, top_bbox, round_up=True)

# add primitive pins
bot_lp = self.grid.tech_info.get_lay_purp_list(bot_layer)[0]
top_lp = self.grid.tech_info.get_lay_purp_list(top_layer)[0]

self.add_pin_primitive('BOT', bot_lp[0], BBox(mim_info.pin_bot_xl, mim_info.pin_bot_y[0],
mim_info.pin_bot_xl + bot_w, mim_info.pin_bot_y[1]))
self.add_pin_primitive('TOP', top_lp[0], BBox(mim_info.pin_top_xh - top_w, mim_info.pin_top_y[0],
mim_info.pin_top_xh, mim_info.pin_top_y[1]))

# get schematic parameters
tot_rows = num_rows + dum_row_b + dum_row_t
tot_cols = num_cols + dum_col_l + dum_col_r
self.sch_params = dict(
mim_type=mim_type,
unit_width=unit_width,
unit_height=unit_height,
num_rows=num_rows,
num_cols=num_cols,
num_dum=tot_rows * tot_cols - num_rows * num_cols,
)
158 changes: 158 additions & 0 deletions src/xbase/layout/cap/mos.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,158 @@
# BSD 3-Clause License
#
# Copyright (c) 2018, Regents of the University of California
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are met:
#
# * Redistributions of source code must retain the above copyright notice, this
# list of conditions and the following disclaimer.
#
# * Redistributions in binary form must reproduce the above copyright notice,
# this list of conditions and the following disclaimer in the documentation
# and/or other materials provided with the distribution.
#
# * Neither the name of the copyright holder nor the names of its
# contributors may be used to endorse or promote products derived from
# this software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

"""This module defines MOM cap on MOSBase."""

from typing import Any, Dict, Optional, Mapping, List, Tuple, Type

from pybag.core import BBox, BBoxArray

from bag.util.immutable import Param
from bag.design.module import Module
from bag.layout.template import TemplateDB

from xbase.layout.mos.base import MOSBasePlaceInfo, MOSBase
from xbase.schematic.momcap_core import xbase__momcap_core


class MOMCapOnMOS(MOSBase):
"""MOMCap core on MOSBase
"""

def __init__(self, temp_db: TemplateDB, params: Param, **kwargs: Any) -> None:
MOSBase.__init__(self, temp_db, params, **kwargs)

@classmethod
def get_schematic_class(cls) -> Optional[Type[Module]]:
return xbase__momcap_core

@classmethod
def get_params_info(cls) -> Dict[str, str]:
return dict(
pinfo='The MOSBasePlaceInfo object.',
bot_layer='MOM cap bottom layer.',
top_layer='MOM cap top layer.',
width='MOM cap width, in resolution units.',
margin='margin between cap and boundary, in resolution units.',
port_tr_w='MOM cap port track width, in number of tracks.',
options='MOM cap layout options.',
half_blk_x='True to allow half horizontal blocks.',
half_blk_y='True to allow half vertical blocks.',
)

@classmethod
def get_default_param_values(cls) -> Dict[str, Any]:
return dict(
margin=0,
port_tr_w=1,
options=None,
half_blk_x=True,
half_blk_y=True,
)

def draw_layout(self) -> None:
pinfo = self.params['pinfo']
if isinstance(pinfo, Mapping):
pinfo = MOSBasePlaceInfo.make_place_info(self.grid, self.params['pinfo'])
else:
pinfo = pinfo[0]
self.draw_base(pinfo)

grid = self.grid

bot_layer: int = self.params['bot_layer']
top_layer: int = self.params['top_layer']
width: int = self.params['width']
margin: int = self.params['margin']
port_tr_w: int = self.params['port_tr_w']
options: Optional[Mapping[str, Any]] = self.params['options']
half_blk_x: bool = self.params['half_blk_x']
half_blk_y: bool = self.params['half_blk_y']

w_tot = width + 2 * margin
w_blk, h_blk = grid.get_block_size(top_layer, half_blk_x=half_blk_x,
half_blk_y=half_blk_y)
w_tot = -(-w_tot // w_blk) * w_blk
h_tot = self.place_info.height

# set size
num_cols = -(-w_tot // self.sd_pitch)
self.set_mos_size(num_cols)

# setup capacitor options
# get . Make sure we can via up to top_layer + 1
top_port_tr_w = port_tr_w
port_w_dict = {top_layer: top_port_tr_w}
for lay in range(top_layer - 1, bot_layer - 1, -1):
top_port_tr_w = port_w_dict[lay] = grid.get_min_track_width(lay, top_ntr=top_port_tr_w)

# draw cap
cap_xl = (self.bound_box.w - width) // 2
cap_yb = (self.bound_box.h - h_tot) // 2
cap_box = BBox(cap_xl, cap_yb, cap_xl + width, cap_yb + h_tot)
num_layer = top_layer - bot_layer + 1
options = options or {}
cw_list: List[Tuple[Tuple[str, str], Tuple[str, str], BBoxArray, BBoxArray]] = []
cap_ports = self.add_mom_cap(cap_box, bot_layer, num_layer, port_widths=port_w_dict,
cap_wires_list=cw_list, **options)

# connect input/output
for lay, (nport, pport) in cap_ports.items():
self.add_pin('plus', pport)
self.add_pin('minus', nport)

# draw metal resistors
if self.has_res_metal():
_, _, barr_n, barr_p = cw_list[-1]
box_p = barr_p.get_bbox(0)
box_n = barr_n.get_bbox(0)
top_dir = grid.get_direction(top_layer)
res_w = box_p.get_dim(top_dir.perpendicular())
coord_c = box_p.get_center(top_dir)

res_w2 = res_w // 2
res_w4 = res_w2 // 2
wl_p = coord_c - res_w2
wu_p = coord_c + res_w2
wl_n = coord_c - res_w4
wu_n = coord_c + res_w4
box_p.set_interval(top_dir, wl_p, wu_p)
box_n.set_interval(top_dir, wl_n, wu_n)
self.add_res_metal(top_layer, box_p)
self.add_res_metal(top_layer, box_n)

res_w = grid.get_track_info(top_layer).width
self.sch_params = dict(
has_res_metal=True,
res_p=dict(layer=top_layer, w=res_w, l=res_w2 * 2),
res_n=dict(layer=top_layer, w=res_w, l=res_w4 * 2),
)
else:
self.sch_params = dict(has_res_metal=False)
88 changes: 88 additions & 0 deletions src/xbase/layout/cap/tech.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
# BSD 3-Clause License
#
# Copyright (c) 2018, Regents of the University of California
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are met:
#
# * Redistributions of source code must retain the above copyright notice, this
# list of conditions and the following disclaimer.
#
# * Redistributions in binary form must reproduce the above copyright notice,
# this list of conditions and the following disclaimer in the documentation
# and/or other materials provided with the distribution.
#
# * Neither the name of the copyright holder nor the names of its
# contributors may be used to endorse or promote products derived from
# this software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

"""This module defines abstract analog mim cap template classes.
"""

from __future__ import annotations
from dataclasses import dataclass

from typing import Any, Mapping, Tuple

import abc

from bag.layout.tech import TechInfo

from ..data import LayoutInfo


@dataclass(eq=True, frozen=True)
class MIMLayInfo:
"""The mim block layout information object."""
lay_info: LayoutInfo
pin_bot_y: Tuple[int, int]
pin_top_y: Tuple[int, int]
pin_bot_xl: int
pin_top_xh: int


class MIMTech(abc.ABC):
"""An abstract class for drawing mim cap related layout
Parameters
------------------
tech_info : TechInfo
the TechInfo object
"""
def __init__(self, tech_info: TechInfo) -> None:
self._tech_info = tech_info
self._mim_config = {}
for k, v in tech_info.config['mim'].items():
self._mim_config[k] = v

@property
def mim_config(self) -> Mapping[str, Any]:
return self._mim_config

@property
def tech_info(self) -> TechInfo:
return self._tech_info

# functions getting technology information
@abc.abstractmethod
def get_port_layers(self, mim_type: str) -> Tuple[int, int]:
raise NotImplementedError

@abc.abstractmethod
def get_mim_cap_info(self, bot_layer: int, top_layer: int, unit_width: int, unit_height: int,
num_rows: int, num_cols: int, dum_row_b: int, dum_row_t: int, dum_col_l: int, dum_col_r: int,
bot_w: int, top_w: int) -> MIMLayInfo:
raise NotImplementedError

206 changes: 206 additions & 0 deletions src/xbase/layout/clamp/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,206 @@
from typing import Optional, Type, Any, Mapping, Tuple, Sequence
from itertools import chain

from bag.layout.template import TemplateBase, TemplateDB
from bag.layout.util import BlackBoxTemplate
from bag.layout.routing.base import WDictType, SpDictType, TrackManager, TrackID
from bag.design.module import Module
from bag.util.immutable import Param

from pybag.core import BBox
from pybag.enum import Orient2D, Direction, RoundMode, MinLenMode

from ...schematic.clamp_static import xbase__clamp_static


class ClampStatic(TemplateBase):
"""This class instantiates a static clamp layout as a BlackBoxTemplate and then brings up pins on routing grid."""
def __init__(self, temp_db: TemplateDB, params: Param, **kwargs: Any) -> None:
TemplateBase.__init__(self, temp_db, params, **kwargs)
tr_widths: WDictType = self.params['tr_widths']
tr_spaces: SpDictType = self.params['tr_spaces']
self._tr_manager = TrackManager(self.grid, tr_widths, tr_spaces)
self._conn_layer = -1
self._top_layer = -1

@property
def conn_layer(self) -> int:
return self._conn_layer

@property
def top_layer(self) -> int:
return self._top_layer

@property
def tr_manager(self) -> TrackManager:
return self._tr_manager

@classmethod
def get_schematic_class(cls) -> Optional[Type[Module]]:
return xbase__clamp_static

@classmethod
def get_params_info(cls) -> Mapping[str, str]:
return dict(
lib_name='The library name.',
cell_name='The layout cell name.',
tr_widths='Track widths dictionary',
tr_spaces='Track spaces dictionary',
top_layer='Optional way to specify pin layer.\
Defaults to value in tech_params.'
)

@classmethod
def get_default_param_values(cls) -> Mapping[str, Any]:
return dict(top_layer=None)

def draw_layout(self) -> None:
lib_name: str = self.params['lib_name']
cell_name: str = self.params['cell_name']
tr_manager = self._tr_manager

# --- Placement --- #
clamp_info = self.grid.tech_info.tech_params['clamp']
_top_layer = self.params.get('top_layer')
if not _top_layer:
_top_layer = clamp_info['top_layer']
top_layer = _top_layer
self._top_layer = top_layer
# if self.grid.get_direction(top_layer) is Orient2D.y:
# self._conn_layer = port_layer = top_layer
# else:
# self._conn_layer = port_layer = top_layer - 1
self._conn_layer = port_layer = top_layer
used_port_layer: int = clamp_info['used_port_layer']
assert used_port_layer < port_layer, f'top_layer={top_layer} must be greater than ' \
f'used_port_layer={used_port_layer}'
config: Mapping[str, Any] = clamp_info['types'][cell_name]
static_lib: str = config['lib_name']
static_cell: str = config['cell_name']
size: Tuple[int, int] = config['size']
ports: Mapping[str, Mapping[str, Sequence[Tuple[int, int, int, int]]]] = config['ports']

# make master
master = self.new_template(BlackBoxTemplate, params=dict(lib_name=static_lib, cell_name=static_cell,
top_layer=used_port_layer, size=size, ports=ports))

# add instance
inst = self.add_instance(master, inst_name='XINST')
bbox = inst.bound_box
self.set_size_from_bound_box(port_layer, bbox, round_up=True)

# add rectangle arrays, if any
rect_arr_list: Sequence[Mapping[str, Any]] = clamp_info['rect_arr_list']
for rect_arr in rect_arr_list:
edge_margin: Mapping[str, int] = rect_arr.get('edge_margin', {})
rect_xl = bbox.xl + edge_margin.get('xl', 0)
rect_xh = bbox.xh + edge_margin.get('xh', 0)
rect_yl = bbox.yl + edge_margin.get('yl', 0)
rect_yh = bbox.yh + edge_margin.get('yh', 0)
spx: int = rect_arr.get('spx', 0)
if spx == 0:
num_x = 1
else:
w_unit: int = rect_arr['w_unit']
num_x = (rect_xh - rect_xl - w_unit) // spx + 1
rect_xh = rect_xl + w_unit
spy: int = rect_arr.get('spy', 0)
if spy == 0:
num_y = 1
else:
h_unit: int = rect_arr['h_unit']
num_y = (rect_yh - rect_yl - h_unit) // spy + 1
rect_yh = rect_yl + h_unit
lp: Tuple[str, str] = rect_arr['lay_purp']
self.add_rect_array(lp, BBox(rect_xl, rect_yl, rect_xh, rect_yh), num_x, num_y, spx, spy)

# --- Routing --- #
# First route to (used_port_layer + 1) on RoutingGrid
tr_layer = used_port_layer + 1
# using hm for lower layer and vm for higher layer just for convenience.

vdd_idx = 0
vss_idx = 1
num_sig = 2

vdd_hm: Sequence[BBox] = inst.get_all_port_pins('VDD', used_port_layer)
vss_hm: Sequence[BBox] = inst.get_all_port_pins('VSS', used_port_layer)
hm_lp = self.grid.tech_info.get_lay_purp_list(used_port_layer)[0]

# Get extension to keep tracks + vias within the pins
w_sup_vm = tr_manager.get_width(tr_layer, 'sup')
bound_l, bound_h = self.grid.get_wire_bounds(tr_layer, 0, w_sup_vm)
ext = (bound_h - bound_l) // 2

# put pins on (used_port_layer + 1) on RoutingGrid
if self.grid.get_direction(used_port_layer) is Orient2D.y:
hm_lower = max([bbox.yl for bbox in chain(vss_hm, vdd_hm)])
hm_upper = min([bbox.yh for bbox in chain(vss_hm, vdd_hm)])

hm_lower += ext
hm_upper -= ext
else: # Orient2D.x
hm_lower = max([bbox.xl for bbox in chain(vss_hm, vdd_hm)])
hm_upper = min([bbox.xh for bbox in chain(vss_hm, vdd_hm)])

hm_lower += ext
hm_upper -= ext

vm_l_idx = self.grid.coord_to_track(tr_layer, hm_lower, RoundMode.GREATER_EQ)
vm_r_idx = self.grid.coord_to_track(tr_layer, hm_upper, RoundMode.LESS_EQ)
vm_num = tr_manager.get_num_wires_between(tr_layer, 'sup', vm_l_idx, 'sup', vm_r_idx, 'sup') + 2
if vm_num < num_sig:
raise ValueError(f'Redo routing on layer={tr_layer}')
_n = vm_num // num_sig
vm_idx_list = tr_manager.spread_wires(tr_layer, ['sup'] * num_sig * _n, vm_l_idx, vm_r_idx, ('sup', 'sup'))
_p = (vm_idx_list[1] - vm_idx_list[0]) * num_sig

plus_vm_tid = TrackID(tr_layer, vm_idx_list[vdd_idx], w_sup_vm, _n, _p)
plus_vm = []
for bbox in vdd_hm:
plus_vm.append(self.connect_bbox_to_tracks(Direction.LOWER, hm_lp, bbox, plus_vm_tid,
min_len_mode=MinLenMode.MIDDLE))

minus_vm_tid = TrackID(tr_layer, vm_idx_list[vss_idx], w_sup_vm, _n, _p)
minus_vm = []
for bbox in vss_hm:
minus_vm.append(self.connect_bbox_to_tracks(Direction.LOWER, hm_lp, bbox, minus_vm_tid,
min_len_mode=MinLenMode.MIDDLE))

plus_port = self.connect_wires(plus_vm)[0]
minus_port = self.connect_wires(minus_vm)[0]

# route up to port_layer
if port_layer > tr_layer:
for _layer in range(tr_layer + 1, port_layer + 1):
_lower = min([warr.lower for warr in [plus_port, minus_port]])
_upper = max([warr.upper for warr in [plus_port, minus_port]])
_l_idx = self.grid.coord_to_track(_layer, _lower, RoundMode.GREATER_EQ)
_r_idx = self.grid.coord_to_track(_layer, _upper, RoundMode.LESS_EQ)
_num = tr_manager.get_num_wires_between(_layer, 'sup', _l_idx, 'sup', _r_idx, 'sup') + 2
if _num < num_sig:
raise ValueError(f'Redo routing on layer={_layer}')
_n = _num // num_sig
_idx_list = tr_manager.spread_wires(_layer, ['sup'] * num_sig * _n, _l_idx, _r_idx, ('sup', 'sup'))
_p = (_idx_list[1] - _idx_list[0]) * num_sig
w_sup = tr_manager.get_width(_layer, 'sup')

plus_tid = TrackID(_layer, _idx_list[vdd_idx], w_sup, _n, _p)
plus_port = self.connect_to_tracks(plus_port, plus_tid, min_len_mode=MinLenMode.MIDDLE)
minus_tid = TrackID(_layer, _idx_list[vss_idx], w_sup, _n, _p)
minus_port = self.connect_to_tracks(minus_port, minus_tid, min_len_mode=MinLenMode.MIDDLE)

self.add_pin('VDD', plus_port, connect=True)
self.add_pin('VSS', minus_port, connect=True)

# add hidden pins on unconnected used_port_layer wires for collision checking in top level cells
nc_hm: Sequence[BBox] = inst.get_all_port_pins('NC', used_port_layer)
for bbox in nc_hm:
self.add_rect(hm_lp, bbox)
self.add_pin_primitive('NC', f'{used_port_layer}', bbox, hide=True)

# setup schematic parameters
self.sch_params = dict(
lib_name=lib_name,
cell_name=cell_name,
)
33 changes: 30 additions & 3 deletions src/xbase/layout/data.py
Original file line number Diff line number Diff line change
@@ -13,7 +13,7 @@
# See the License for the specific language governing permissions and
# limitations under the License.

from typing import Tuple, Iterable, Union, Any
from typing import Tuple, Iterable, Union, Any, Optional, Mapping

from dataclasses import dataclass

@@ -59,6 +59,21 @@ class ViaInfo:
ny: int = 1
spx: int = 0
spy: int = 0
priority: int = 0


@dataclass(eq=True, frozen=True)
class InstInfo:
"""The primitive instance information object."""
lib_name: str
cell_name: str
xform: Optional[Transform] = None
nx: int = 1
ny: int = 1
spx: int = 0
spy: int = 0
params: Optional[Mapping[str, Any]] = None
commit: bool = True


@dataclass(eq=True, frozen=True)
@@ -67,6 +82,7 @@ class LayoutInfo:
rect_dict: ImmutableSortedDict[Tuple[str, str], BBoxCollection]
warr_list: ImmutableList[WireArrayInfo]
via_list: ImmutableList[ViaInfo]
inst_list: ImmutableList[InstInfo]
bound_box: BBox


@@ -75,6 +91,7 @@ def __init__(self):
self._lp_dict = {}
self._via_list = []
self._warr_list = []
self._inst_list = []

def add_rect_arr(self, key: Tuple[str, str], box: BBox,
nx: int = 1, ny: int = 1, spx: int = 0, spy: int = 0) -> None:
@@ -99,9 +116,14 @@ def add_rect_iter(self, key: Tuple[str, str], rect_iter: Iterable[BBox]
for box in rect_iter:
r_list.add_rect_arr(box)

def add_instance_primitive(self, lib_name: str, cell_name: str, *, xform: Optional[Transform] = None,
nx: int = 1, ny: int = 1, spx: int = 0, spy: int = 0,
params: Optional[Mapping[str, Any]] = None, commit: bool = True) -> None:
self._inst_list.append(InstInfo(lib_name, cell_name, xform, nx, ny, spx, spy, params, commit))

def get_info(self, bnd_box: BBox) -> LayoutInfo:
return LayoutInfo(ImmutableSortedDict(self._lp_dict), ImmutableList(self._warr_list),
ImmutableList(self._via_list), bnd_box)
ImmutableList(self._via_list), ImmutableList(self._inst_list), bnd_box)


def draw_layout_in_template(template: TemplateBase, lay_info: LayoutInfo,
@@ -118,7 +140,12 @@ def draw_layout_in_template(template: TemplateBase, lay_info: LayoutInfo,
vinfo.h, num_rows=vinfo.vny, num_cols=vinfo.vnx,
sp_rows=vinfo.vspy, sp_cols=vinfo.vspx, enc1=vinfo.enc1,
enc2=vinfo.enc2, nx=vinfo.nx, ny=vinfo.ny, spx=vinfo.spx,
spy=vinfo.spy)
spy=vinfo.spy, priority=vinfo.priority)

for inst_info in lay_info.inst_list:
template.add_instance_primitive(inst_info.lib_name, inst_info.cell_name, xform=inst_info.xform,
nx=inst_info.nx, ny=inst_info.ny, spx=inst_info.spx, spy=inst_info.spy,
params=inst_info.params, commit=inst_info.commit)

if set_bbox:
template.prim_bound_box = lay_info.bound_box
25 changes: 24 additions & 1 deletion src/xbase/layout/enum.py
Original file line number Diff line number Diff line change
@@ -69,19 +69,42 @@ def num_cut(self) -> int:

# Note: make this IntEnum so it is sortable by ImmutableSortedDict.
class MOSWireType(IntEnum):
"""
These describe the placements of tracks above the conn_layer, relative to
the conn_layer ports.
G: tracks directly over gate connection
G_MATCH: tracks south of gate connection to match / reduce gate parasitics
DS: tracks directly over drain / source connection
DS_GATE: track over drain/source, overlapping with gate if possible
DS_MATCH: tracks north of drain/source conn to match / reduce parasitics
G2: for double gate transistors, tracks directly over the 2nd gate
G2_MATCH: similar to G_MATCH for double gate transistors
For flipped transistors, G will be at the top, DS / G2 will be at the bottom.
For not flipped transistors, G will be at the bottom, DS / G2 will be at the top.
"""
G = 0
G_MATCH = 1
DS = 2
DS_GATE = 3
DS_MATCH = 4
G2 = 5
G2_MATCH = 6

@property
def is_gate(self) -> bool:
return self is MOSWireType.G or self is MOSWireType.G_MATCH

@property
def is_gate2(self) -> bool:
return self is MOSWireType.G2 or self is MOSWireType.G2_MATCH

@property
def is_physical(self) -> bool:
return not (self is MOSWireType.G_MATCH or self is MOSWireType.DS_MATCH)
return not (self is MOSWireType.G_MATCH or self is MOSWireType.DS_MATCH
or self is MOSWireType.G2_MATCH)


class MOSPortType(Enum):
225 changes: 225 additions & 0 deletions src/xbase/layout/esd_static/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,225 @@
from typing import Optional, Type, Any, Mapping, Tuple, Sequence
from itertools import chain

from bag.layout.template import TemplateBase, TemplateDB
from bag.layout.util import BlackBoxTemplate
from bag.layout.routing.base import WDictType, SpDictType, TrackManager, TrackID
from bag.design.module import Module
from bag.util.immutable import Param

from pybag.core import BBox
from pybag.enum import Orient2D, Direction, RoundMode, MinLenMode

from ...schematic.esd_static import xbase__esd_static


class ESDStatic(TemplateBase):
"""This class instantiates a static ESD layout as a BlackBoxTemplate and then brings up pins on routing grid."""
def __init__(self, temp_db: TemplateDB, params: Param, **kwargs: Any) -> None:
TemplateBase.__init__(self, temp_db, params, **kwargs)
tr_widths: WDictType = self.params['tr_widths']
tr_spaces: SpDictType = self.params['tr_spaces']
self._tr_manager = TrackManager(self.grid, tr_widths, tr_spaces)
self._conn_layer = -1
self._top_layer = -1

@property
def conn_layer(self) -> int:
return self._conn_layer

@property
def top_layer(self) -> int:
return self._top_layer

@property
def tr_manager(self) -> TrackManager:
return self._tr_manager

@classmethod
def get_schematic_class(cls) -> Optional[Type[Module]]:
return xbase__esd_static

@classmethod
def get_params_info(cls) -> Mapping[str, str]:
return dict(
lib_name='The library name.',
cell_name='The layout cell name.',
tr_widths='Track widths dictionary',
tr_spaces='Track spaces dictionary',
top_layer='Optional way to specify pin layer.\
Defaults to value in tech_params.'
)

@classmethod
def get_default_param_values(cls) -> Mapping[str, Any]:
return dict(top_layer=None)

def draw_layout(self) -> None:
lib_name: str = self.params['lib_name']
cell_name: str = self.params['cell_name']
tr_manager = self._tr_manager

# --- Placement --- #
esd_info = self.grid.tech_info.tech_params['esd']
top_layer = self.params.get('top_layer')
if not top_layer:
top_layer = esd_info['top_layer']
self._top_layer = top_layer
if self.grid.get_direction(top_layer) is Orient2D.y:
self._conn_layer = port_layer = top_layer
else:
self._conn_layer = port_layer = top_layer - 1
used_port_layer: int = esd_info['used_port_layer']
assert used_port_layer < port_layer, f'top_layer={top_layer} must be greater than ' \
f'used_port_layer={used_port_layer}'
config: Mapping[str, Any] = esd_info['types'][cell_name]
static_lib: str = config['lib_name']
static_cell: str = config['cell_name']
size: Tuple[int, int] = config['size']
ports: Mapping[str, Mapping[str, Sequence[Tuple[int, int, int, int]]]] = config['ports']

# make master
master = self.new_template(BlackBoxTemplate, params=dict(lib_name=static_lib, cell_name=static_cell,
top_layer=used_port_layer, size=size, ports=ports))

# add instance
inst = self.add_instance(master, inst_name='XINST')
bbox = inst.bound_box
self.set_size_from_bound_box(port_layer, bbox, round_up=True)

# add rectangle arrays, if any
rect_arr_list: Sequence[Mapping[str, Any]] = esd_info['rect_arr_list']
for rect_arr in rect_arr_list:
edge_margin: Mapping[str, int] = rect_arr.get('edge_margin', {})
rect_xl = bbox.xl + edge_margin.get('xl', 0)
rect_xh = bbox.xh + edge_margin.get('xh', 0)
rect_yl = bbox.yl + edge_margin.get('yl', 0)
rect_yh = bbox.yh + edge_margin.get('yh', 0)
spx: int = rect_arr.get('spx', 0)
if spx == 0:
num_x = 1
else:
w_unit: int = rect_arr['w_unit']
num_x = (rect_xh - rect_xl - w_unit) // spx + 1
rect_xh = rect_xl + w_unit
spy: int = rect_arr.get('spy', 0)
if spy == 0:
num_y = 1
else:
h_unit: int = rect_arr['h_unit']
num_y = (rect_yh - rect_yl - h_unit) // spy + 1
rect_yh = rect_yl + h_unit
lp: Tuple[str, str] = rect_arr['lay_purp']
self.add_rect_array(lp, BBox(rect_xl, rect_yl, rect_xh, rect_yh), num_x, num_y, spx, spy)

# --- Routing --- #
# First route to (used_port_layer + 1) on RoutingGrid
tr_layer = used_port_layer + 1
# using hm for lower layer and vm for higher layer just for convenience.
plus_hm: Sequence[BBox] = inst.get_all_port_pins('plus', used_port_layer)
minus_hm: Sequence[BBox] = inst.get_all_port_pins('minus', used_port_layer)
if cell_name == 'esd_vss':
sup_name = 'VDD'
sup_idx = 0
minus_idx = 1
plus_idx = 2
elif cell_name == 'esd_vdd':
sup_name = 'VSS'
sup_idx = 2
minus_idx = 0
plus_idx = 1
else:
raise ValueError(f'Unknown cell_name={cell_name}. Use "esd_vdd" or "esd_vss".')
sup_hm: Sequence[BBox] = inst.get_all_port_pins(sup_name, used_port_layer)
hm_lp = self.grid.tech_info.get_lay_purp_list(used_port_layer)[0]

# put pins on (used_port_layer + 1) on RoutingGrid
if self.grid.get_direction(used_port_layer) is Orient2D.y:
hm_lower = max([bbox.yl for bbox in chain(plus_hm, minus_hm, sup_hm)])
hm_upper = min([bbox.yh for bbox in chain(plus_hm, minus_hm, sup_hm)])
else: # Orient2D.x
hm_lower = max([bbox.xl for bbox in chain(plus_hm, minus_hm, sup_hm)])
hm_upper = min([bbox.xh for bbox in chain(plus_hm, minus_hm, sup_hm)])
vm_l_idx = self.grid.coord_to_track(tr_layer, hm_lower, RoundMode.GREATER_EQ)
vm_r_idx = self.grid.coord_to_track(tr_layer, hm_upper, RoundMode.LESS_EQ)
vm_num = tr_manager.get_num_wires_between(tr_layer, 'sup', vm_l_idx, 'sup', vm_r_idx, 'sup') + 2
if vm_num < 3:
raise ValueError(f'Redo routing on layer={tr_layer}')
_n = vm_num // 3
vm_idx_list = tr_manager.spread_wires(tr_layer, ['sup', 'sup', 'sup'] * _n, vm_l_idx, vm_r_idx, ('sup', 'sup'))
_p = (vm_idx_list[1] - vm_idx_list[0]) * 3
w_sup_vm = tr_manager.get_width(tr_layer, 'sup')

sup_vm_tid = TrackID(tr_layer, vm_idx_list[sup_idx], w_sup_vm, _n, _p)
sup_vm = []
for idx, bbox in enumerate(sup_hm):
sup_vm.append(self.connect_bbox_to_tracks(Direction.LOWER, hm_lp, bbox, sup_vm_tid,
min_len_mode=MinLenMode.MIDDLE))

plus_vm_tid = TrackID(tr_layer, vm_idx_list[plus_idx], w_sup_vm, _n, _p)
plus_vm = []
for bbox in plus_hm:
plus_vm.append(self.connect_bbox_to_tracks(Direction.LOWER, hm_lp, bbox, plus_vm_tid,
min_len_mode=MinLenMode.MIDDLE))

minus_vm_tid = TrackID(tr_layer, vm_idx_list[minus_idx], w_sup_vm, _n, _p)
minus_vm = []
for bbox in minus_hm:
minus_vm.append(self.connect_bbox_to_tracks(Direction.LOWER, hm_lp, bbox, minus_vm_tid,
min_len_mode=MinLenMode.MIDDLE))

sup_port = self.connect_wires(sup_vm)[0]
plus_port = self.connect_wires(plus_vm)[0]
minus_port = self.connect_wires(minus_vm)[0]

# route up to port_layer
if port_layer > tr_layer:
for _layer in range(tr_layer + 1, port_layer + 1):
_lower = min([warr.lower for warr in [sup_port, plus_port, minus_port]])
_upper = max([warr.upper for warr in [sup_port, plus_port, minus_port]])
_l_idx = self.grid.coord_to_track(_layer, _lower, RoundMode.GREATER_EQ)
_r_idx = self.grid.coord_to_track(_layer, _upper, RoundMode.LESS_EQ)
_num = tr_manager.get_num_wires_between(_layer, 'sup', _l_idx, 'sup', _r_idx, 'sup') + 2
if _num < 3:
raise ValueError(f'Redo routing on layer={_layer}')
_n = _num // 3
_idx_list = tr_manager.spread_wires(_layer, ['sup', 'sup', 'sup'] * _n, _l_idx, _r_idx, ('sup', 'sup'))
_p = (_idx_list[1] - _idx_list[0]) * 3
w_sup = tr_manager.get_width(_layer, 'sup')

if cell_name == 'esd_vdd':
sup_idx = 2
plus_idx = 1
minus_idx = 0
else: # cell_name == 'esd_vss'
if self.grid.get_direction(_layer) is Orient2D.y:
sup_idx = 0
plus_idx = 2
minus_idx = 1
else:
sup_idx = 2
plus_idx = 0
minus_idx = 1

sup_tid = TrackID(_layer, _idx_list[sup_idx], w_sup, _n, _p)
sup_port = self.connect_to_tracks(sup_port, sup_tid, min_len_mode=MinLenMode.MIDDLE)
plus_tid = TrackID(_layer, _idx_list[plus_idx], w_sup, _n, _p)
plus_port = self.connect_to_tracks(plus_port, plus_tid, min_len_mode=MinLenMode.MIDDLE)
minus_tid = TrackID(_layer, _idx_list[minus_idx], w_sup, _n, _p)
minus_port = self.connect_to_tracks(minus_port, minus_tid, min_len_mode=MinLenMode.MIDDLE)

self.add_pin(sup_name, sup_port)
self.add_pin('plus', plus_port)
self.add_pin('minus', minus_port)

# add hidden pins on unconnected used_port_layer wires for collision checking in top level cells
nc_hm: Sequence[BBox] = inst.get_all_port_pins('NC', used_port_layer)
for bbox in nc_hm:
self.add_rect(hm_lp, bbox)
self.add_pin_primitive('NC', f'{used_port_layer}', bbox, hide=True)

# setup schematic parameters
self.sch_params = dict(
lib_name=lib_name,
cell_name=cell_name,
)
121 changes: 121 additions & 0 deletions src/xbase/layout/esd_static/esd.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,121 @@
from typing import Optional, Type, Any, Mapping

from bag.layout.template import TemplateBase, TemplateDB
from bag.layout.routing.base import WDictType, SpDictType, TrackManager, TrackID
from bag.design.module import Module
from bag.util.immutable import Param

from pybag.core import BBox, Transform
from pybag.enum import Orientation, RoundMode, MinLenMode

from . import ESDStatic
from ...schematic.esd import xbase__esd


class ESD(TemplateBase):
"""This class instantiates esd_vdd and esd_vss to make one complete unit ESD."""
def __init__(self, temp_db: TemplateDB, params: Param, **kwargs: Any) -> None:
TemplateBase.__init__(self, temp_db, params, **kwargs)
tr_widths: WDictType = self.params['tr_widths']
tr_spaces: SpDictType = self.params['tr_spaces']
self._tr_manager = TrackManager(self.grid, tr_widths, tr_spaces)
self._conn_layer = -1

@property
def conn_layer(self) -> int:
return self._conn_layer

@property
def tr_manager(self) -> TrackManager:
return self._tr_manager

@classmethod
def get_schematic_class(cls) -> Optional[Type[Module]]:
return xbase__esd

@classmethod
def get_params_info(cls) -> Mapping[str, str]:
return dict(
esd_p='library name and cell name for esd_p.',
esd_n='library name and cell name for esd_n.',
tr_widths='Track widths dictionary',
tr_spaces='Track spaces dictionary',
)

def draw_layout(self) -> None:
esd_p: Mapping[str, Any] = self.params['esd_p']
esd_n: Mapping[str, Any] = self.params['esd_n']
tr_widths: WDictType = self.params['tr_widths']
tr_spaces: SpDictType = self.params['tr_spaces']
tr_manager = self._tr_manager

# make masters
esd_p_master: ESDStatic = self.new_template(ESDStatic, params=dict(tr_widths=tr_widths, tr_spaces=tr_spaces,
**esd_p))
esd_p_bbox = esd_p_master.bound_box
esd_n_master: ESDStatic = self.new_template(ESDStatic, params=dict(tr_widths=tr_widths, tr_spaces=tr_spaces,
**esd_n))
esd_n_bbox = esd_n_master.bound_box

# Assume one unit ESD will have one esd_p and one esd_n. Generator can be extended to have programmable
# number of esd_p and esd_n.

tot_w = max(esd_p_bbox.w, esd_n_bbox.w)
tot_h = esd_p_bbox.h + esd_n_bbox.h
conn_layer = esd_p_master.conn_layer
assert conn_layer == esd_n_master.conn_layer
self._conn_layer = top_layer = esd_p_master.top_layer
assert top_layer == esd_n_master.top_layer

# add instances
off_n = (tot_w - esd_n_bbox.w) // 2
inst_n = self.add_instance(esd_n_master, inst_name='XN', xform=Transform(dx=off_n))
off_p = (tot_w - esd_p_bbox.w) // 2
inst_p = self.add_instance(esd_p_master, inst_name='XP', xform=Transform(dx=off_p, dy=tot_h,
mode=Orientation.MX))

self.set_size_from_bound_box(top_layer, BBox(0, 0, tot_w, tot_h), round_up=True)

# --- Routing --- #
vdd_n = inst_n.get_pin('VDD')
vss_n = inst_n.get_pin('plus')
term_n = inst_n.get_pin('minus')

vdd_p = inst_p.get_pin('minus')
vss_p = inst_p.get_pin('VSS')
term_p = inst_p.get_pin('plus')

top_ports = {}
for port_p, port_n, name in [(vdd_p, vdd_n, 'VDD'), (vss_p, vss_n, 'VSS'), (term_p, term_n, 'term')]:
assert port_p.track_id.base_index == port_n.track_id.base_index
top_ports[name] = self.connect_wires([port_p, port_n])[0]

if top_layer > conn_layer:
for _layer in range(conn_layer + 1, top_layer + 1):
_lower = min([warr.lower for warr in top_ports.values()])
_upper = max([warr.upper for warr in top_ports.values()])
_l_idx = self.grid.coord_to_track(_layer, _lower, RoundMode.GREATER_EQ)
_r_idx = self.grid.coord_to_track(_layer, _upper, RoundMode.LESS_EQ)
_num = tr_manager.get_num_wires_between(_layer, 'sup', _l_idx, 'sup', _r_idx, 'sup') + 2
if _num < 3:
raise ValueError(f'Redo routing on layer={_layer}')
_n = _num // 3
_idx_list = tr_manager.spread_wires(_layer, ['sup', 'sup', 'sup'] * _n, _l_idx, _r_idx, ('sup', 'sup'))
_p = (_idx_list[1] - _idx_list[0]) * 3
w_sup = tr_manager.get_width(_layer, 'sup')

vss_tid = TrackID(_layer, _idx_list[0], w_sup, _n, _p)
top_ports['VSS'] = self.connect_to_tracks(top_ports['VSS'], vss_tid, min_len_mode=MinLenMode.MIDDLE)
term_tid = TrackID(_layer, _idx_list[1], w_sup, _n, _p)
top_ports['term'] = self.connect_to_tracks(top_ports['term'], term_tid, min_len_mode=MinLenMode.MIDDLE)
vdd_tid = TrackID(_layer, _idx_list[2], w_sup, _n, _p)
top_ports['VDD'] = self.connect_to_tracks(top_ports['VDD'], vdd_tid, min_len_mode=MinLenMode.MIDDLE)

for pin in ('VDD', 'VSS', 'term'):
self.add_pin(pin, top_ports[pin])

# set schematic parameters
self.sch_params = dict(
esd_p=esd_p_master.sch_params,
esd_n=esd_n_master.sch_params,
)
1 change: 1 addition & 0 deletions src/xbase/layout/fill/base.py
Original file line number Diff line number Diff line change
@@ -55,6 +55,7 @@ def get_default_param_values(cls) -> Dict[str, Any]:
return dict(
mos_type='',
threshold='',
edges=(Param(), Param(), Param(), Param()),
)

def draw_layout(self):
40 changes: 38 additions & 2 deletions src/xbase/layout/mos/base.py
Original file line number Diff line number Diff line change
@@ -144,6 +144,12 @@ def sub_sep_col(self) -> int:
"""
return self.tech_cls.sub_sep_col

@property
def gr_sub_sep_col(self) -> int:
"""int: column separation needed between guard ring substrate and inner substrate.
"""
return self.tech_cls.gr_sub_sep_col

@property
def min_sub_col(self) -> int:
"""int: Minimum number of fingers for substrate contact."""
@@ -154,6 +160,34 @@ def can_short_adj_tracks(self) -> bool:
"""bool: True if you can short adjacent transistor ports using hm_layer."""
return self.tech_cls.can_short_adj_tracks(self.conn_layer)

def can_abut_mos(self, row_info: MOSRowInfo) -> bool:
"""bool: True if you can abut mos by sharing drain or source."""
return self.tech_cls.can_abut_mos(row_info)

def can_extend_ds_conn(self, g_side: bool, threshold: str) -> bool:
"""
Parameters
----------
g_side : bool
True for checking for extension on gate side, False for checking on the other side
threshold : str
Threshold of mos in the row
Returns
-------
ans : bool
True if you extend drain or source on conn_layer, on the gate side or the other side."""
return self.tech_cls.can_extend_ds_conn(g_side, threshold)

@property
def can_draw_double_gate(self) -> bool:
"""bool: True if double gates are supported."""
return self.tech_cls.can_draw_double_gate

@property
def has_double_guard_ring(self) -> bool:
"""bool: True if the PDK requires double guard ring."""
return self.tech_cls.has_double_guard_ring

def draw_base(self, obj: Union[MOSBasePlaceInfo,
TilePatternElement,
Tuple[Union[MOSBasePlaceInfo, TilePattern,
@@ -367,8 +401,10 @@ def add_mos(self, row_idx: int, col_idx: int, seg: int, *, tile_idx: int = 0, w:

# construct port object
m_pin = inst.get_pin('m') if inst.has_port('m') else None
return MOSPorts(inst.get_pin('g'), inst.get_pin('d'), inst.get_pin('s'),
master.shorted_ports, m=m_pin)
g_pin = inst.get_pin('g') if inst.has_port('g') else None
g2_pin = inst.get_pin('g2') if inst.has_port('g2') else None
return MOSPorts(g_pin, inst.get_pin('d'), inst.get_pin('s'),
master.shorted_ports, m=m_pin, g2=g2_pin)

def add_nand2(self, row_idx: int, col_idx: int, seg: int, *, tile_idx: int = 0, w: int = 0,
stack: int = 1, flip_lr: bool = False, export_mid: bool = False,
111 changes: 76 additions & 35 deletions src/xbase/layout/mos/char.py
Original file line number Diff line number Diff line change
@@ -15,8 +15,9 @@

"""This module defines the default transistor characterization layout generator."""

from typing import Any, Dict
from typing import Any, Dict, Optional, Type

from bag.design.module import Module
from bag.util.immutable import Param
from bag.layout.template import TemplateDB

@@ -26,6 +27,8 @@
from .base import MOSBase
from .top import MOSBaseWrapper

from ...schematic.mos_char import xbase__mos_char


class MOSCharCore(MOSBase):
"""A MOSBase of only rows of transistors, no connection specs.
@@ -34,6 +37,10 @@ class MOSCharCore(MOSBase):
def __init__(self, temp_db: TemplateDB, params: Param, **kwargs: Any) -> None:
MOSBase.__init__(self, temp_db, params, **kwargs)

@classmethod
def get_schematic_class(cls) -> Optional[Type[Module]]:
return xbase__mos_char

@classmethod
def get_params_info(cls) -> Dict[str, str]:
return dict(
@@ -46,11 +53,12 @@ def get_params_info(cls) -> Dict[str, str]:
stack='number of transistors in a stack.',
tr_widths='TrackManager width dictionary.',
tr_spaces='TrackManager space dictionary.',
arr_options='Optional extra array options',
)

@classmethod
def get_default_param_values(cls) -> Dict[str, Any]:
return dict(stack=1)
return dict(stack=1, arr_options=None)

def draw_layout(self):
mos_type_str: str = self.params['mos_type']
@@ -62,6 +70,11 @@ def draw_layout(self):
stack: int = self.params['stack']
tr_widths = self.params['tr_widths']
tr_spaces = self.params['tr_spaces']
arr_options: Optional[Dict[str, Any]] = self.params['arr_options']

assert seg & 1 == 0, f'This generator requires seg={seg} to be even. MOS characterization results are ' \
f'reported per finger, so this restriction is not an issue.'
assert fg_dum & 1 == 0, f'This generator requires fg_dum={fg_dum} to be even.'

mos_type: MOSType = MOSType[mos_type_str]
if mos_type.is_substrate:
@@ -94,47 +107,76 @@ def draw_layout(self):
]

row_specs = [MOSRowSpecs.make_row_specs(table) for table in row_specs_dict]
ainfo = MOSArrayPlaceInfo(self.grid, lch, tr_widths, tr_spaces)
ainfo = MOSArrayPlaceInfo(self.grid, lch, tr_widths, tr_spaces, arr_options=arr_options)
pinfo = make_pinfo_compact(ainfo, row_specs, True, True)

self.draw_base(pinfo)

fg_tot = fg_dum * 2 + seg * stack
self.set_mos_size(fg_tot)

b_bot = self.add_substrate_contact(0, 0, seg=fg_tot)
b_top = self.add_substrate_contact(2, 0, seg=fg_tot)
mos = self.add_mos(1, fg_dum, seg, stack=stack, abut=True)

tap_ncols = self.get_tap_ncol()
seg_sep = self.min_sep_col
seg_sep_sub = self.sub_sep_col
row_info = pinfo.get_row_place_info(1).row_info

# --- Placement --- #
# Row 1: tap, dum, mos, dum, tap
vdd_list, vss_list = [], []
cur_col = 0
self.add_tap(cur_col, vdd_list, vss_list)
cur_col += tap_ncols + seg_sep_sub
duml = self.add_mos(1, cur_col, fg_dum)
cur_col += fg_dum
if not self.can_abut_mos(row_info):
cur_col += seg_sep
mos = self.add_mos(1, cur_col, seg, stack=stack, abut=True)
cur_col += seg * stack
if not self.can_abut_mos(row_info):
cur_col += seg_sep
cur_col += fg_dum
dumr = self.add_mos(1, cur_col, fg_dum, flip_lr=True)
cur_col += seg_sep_sub + tap_ncols
self.add_tap(cur_col, vdd_list, vss_list, flip_lr=True)

self.set_mos_size(cur_col)

# Rows 0 and 2: substrate rows
b_bot = self.add_substrate_contact(0, 0, seg=cur_col)
b_top = self.add_substrate_contact(2, 0, seg=cur_col)

# --- Routing --- #
d_tid = self.get_track_id(1, MOSWireType.DS, 'd')
g_tid = self.get_track_id(1, MOSWireType.G, 'g')
s_tid = self.get_track_id(1, MOSWireType.DS, 's')
b_tid0 = self.get_track_id(0, MOSWireType.DS, 'b')
b_tid1 = self.get_track_id(2, MOSWireType.DS, 'b')

d = self.connect_to_tracks(mos.d, d_tid)
self.add_pin('d', d)

g_tid = self.get_track_id(1, MOSWireType.G, 'g')
g = self.connect_to_tracks(mos.g, g_tid)
self.add_pin('g', g)

s_tid = self.get_track_id(1, MOSWireType.DS, 's')
s = self.connect_to_tracks(mos.s, s_tid)
self.add_pin('s', s)

# TODO: support dummy transistors
# duml = self.add_mos(1, 0, fg_dum)
# dumr = self.add_mos(1, fg_tot, fg_dum, flip_lr=True)
# s_duml = duml.s[:-1]
# s_dumr = dumr.s[:-1]
# b_warrs0 = [b_bot, duml.d, dumr.d, s_duml, s_dumr]
# b_warrs1 = [b_top, duml.d, dumr.d, s_duml, s_dumr]
# b0 = self.connect_to_tracks(b_warrs0, b_tid0)
# b1 = self.connect_to_tracks(b_warrs1, b_tid1)
b0 = self.connect_to_tracks(b_bot, b_tid0)
b1 = self.connect_to_tracks(b_top, b_tid1)
b_tid0 = self.get_track_id(0, MOSWireType.DS, 'b')
b_tid1 = self.get_track_id(2, MOSWireType.DS, 'b')

self.add_pin('d', d)
self.add_pin('g', g)
self.add_pin('s', s)
# self.add_pin('b', b0)
# self.add_pin('b', b1)
self.add_pin('b', b0, label='b:')
self.add_pin('b', b1, label='b:')
if self.can_abut_mos(row_info):
s_duml = duml.s[:-1]
s_dumr = dumr.s[:-1]
dum_info = [((mos_type_str, w, lch, intent, '', ''), 2 * fg_dum - 2),
((mos_type_str, w, lch, intent, 's', ''), 2)]
else:
s_duml = duml.s
s_dumr = dumr.s
dum_info = [((mos_type_str, w, lch, intent, '', ''), fg_dum),
((mos_type_str, w, lch, intent, '', ''), fg_dum)]
b_warrs0 = [b_bot, duml.d, dumr.d, s_duml, s_dumr]
b_warrs1 = [b_top, duml.d, dumr.d, s_duml, s_dumr]
b_warrs0.extend(vdd_list)
b_warrs0.extend(vss_list)
b_warrs1.extend(vdd_list)
b_warrs1.extend(vss_list)
b0 = self.connect_to_tracks(b_warrs0, b_tid0)
b1 = self.connect_to_tracks(b_warrs1, b_tid1)
self.add_pin('b', [b0, b1])

self.sch_params = dict(
mos_type=mos_type_str,
@@ -143,8 +185,7 @@ def draw_layout(self):
seg=seg,
intent=intent,
stack=stack,
dum_info=[],
# dum_info=[((mos_type_str, w, lch, intent, '', 's'), 2 * fg_dum)],
dum_info=dum_info,
)


114 changes: 92 additions & 22 deletions src/xbase/layout/mos/data.py
Original file line number Diff line number Diff line change
@@ -31,20 +31,23 @@

@dataclass(eq=True, frozen=True, init=False)
class MOSRowSpecs:
"""specification for a transistor row."""
"""specification for a transistor row. Includes unit transistor dimensions and wire info
for determining track locations on conn_layer + 1"""
mos_type: MOSType
width: int
threshold: str
bot_wires: WireData
mid_wires: WireData
top_wires: WireData
options: ImmutableSortedDict[str, Any]
flip: bool
sub_width: int
double_gate: bool

def __init__(self, mos_type: MOSType, width: int, threshold: str,
bot_wires: WireData, top_wires: WireData,
bot_wires: WireData, top_wires: WireData, mid_wires: Optional[WireData] = None,
options: Optional[Mapping[str, Any]] = None,
flip: bool = False, sub_width: int = 0) -> None:
flip: bool = False, sub_width: int = 0, double_gate: bool = False) -> None:
if sub_width == 0 or mos_type.is_substrate:
sub_width = width

@@ -53,34 +56,49 @@ def __init__(self, mos_type: MOSType, width: int, threshold: str,
object.__setattr__(self, 'width', width)
object.__setattr__(self, 'threshold', threshold)
object.__setattr__(self, 'bot_wires', bot_wires)
object.__setattr__(self, 'mid_wires', mid_wires)
object.__setattr__(self, 'top_wires', top_wires)
object.__setattr__(self, 'options', ImmutableSortedDict(options))
object.__setattr__(self, 'flip', flip)
object.__setattr__(self, 'sub_width', sub_width)
object.__setattr__(self, 'double_gate', double_gate)

@classmethod
def make_row_specs(cls, val: Mapping[str, Any]) -> MOSRowSpecs:
mos_type = MOSType[val['mos_type']]
width = val['width']
threshold = val['threshold']
bot_wires = val['bot_wires']
mid_wires = val.get('mid_wires')
top_wires = val['top_wires']
options = val.get('options', None)
flip = val.get('flip', False)
sub_width = val.get('sub_width', 0)

ds_type = MOSWireType.DS_GATE.name
g_type = MOSWireType.G.name
if flip:
bot_ptype = ds_type
top_ptype = g_type
double_gate = val.get('double_gate', False)

if double_gate:
ds_type = MOSWireType.DS.name
g_type = MOSWireType.G.name
g2_type = MOSWireType.G2.name
bot_wd = WireData.make_wire_data(bot_wires, Alignment.UPPER_COMPACT, g2_type if flip else g_type)
mid_wd = WireData.make_wire_data(mid_wires, Alignment.CENTER_COMPACT, ds_type)
top_wd = WireData.make_wire_data(top_wires, Alignment.LOWER_COMPACT, g_type if flip else g2_type)
return MOSRowSpecs(mos_type, width, threshold, bot_wd, top_wd, mid_wires=mid_wd,
options=options, flip=flip, sub_width=sub_width, double_gate=double_gate)
else:
bot_ptype = g_type
top_ptype = ds_type
bot_wd = WireData.make_wire_data(bot_wires, Alignment.UPPER_COMPACT, bot_ptype)
top_wd = WireData.make_wire_data(top_wires, Alignment.LOWER_COMPACT, top_ptype)
return MOSRowSpecs(mos_type, width, threshold, bot_wd, top_wd,
options=options, flip=flip, sub_width=sub_width)
ds_type = MOSWireType.DS_GATE.name
g_type = MOSWireType.G.name
if flip:
bot_ptype = ds_type
top_ptype = g_type
else:
bot_ptype = g_type
top_ptype = ds_type
bot_wd = WireData.make_wire_data(bot_wires, Alignment.UPPER_COMPACT, bot_ptype)
mid_wd = WireData.make_wire_data({'data': []}, Alignment.CENTER_COMPACT, bot_ptype)
top_wd = WireData.make_wire_data(top_wires, Alignment.LOWER_COMPACT, top_ptype)
return MOSRowSpecs(mos_type, width, threshold, bot_wd, top_wd, mid_wires=mid_wd,
options=options, flip=flip, sub_width=sub_width, double_gate=double_gate)

@property
def ignore_bot_vm_sp_le(self) -> bool:
@@ -191,13 +209,18 @@ class MOSRowInfo:
top_ext_info: RowExtInfo
bot_ext_info: RowExtInfo
info: ImmutableSortedDict[str, Any]
# yt, yb for each connection
g_conn_y: Tuple[int, int] = (0, 0)
g_m_conn_y: Tuple[int, int] = (0, 0)
ds_conn_y: Tuple[int, int] = (0, 0)
ds_m_conn_y: Tuple[int, int] = (0, 0)
ds_g_conn_y: Tuple[int, int] = (0, 0)
sub_conn_y: Tuple[int, int] = (0, 0)
guard_ring: bool = False
guard_ring_col: bool = False
double_gate: bool = False
g2_conn_y: Tuple[int, int] = (0, 0)
g2_m_conn_y: Tuple[int, int] = (0, 0)

@classmethod
def from_dict(cls, table: Mapping[str, Any]) -> MOSRowInfo:
@@ -210,7 +233,11 @@ def from_dict(cls, table: Mapping[str, Any]) -> MOSRowInfo:
top_ext_info, bot_ext_info, ImmutableSortedDict(table['info']),
table['g_conn_y'], table['g_m_conn_y'], table['ds_conn_y'],
table['ds_m_conn_y'], table['ds_g_conn_y'], table['sub_conn_y'],
guard_ring=table.get('guard_ring', False))
guard_ring=table.get('guard_ring', False),
guard_ring_col=table.get('guard_ring_col', False),
double_gate=table.get('double_gate', False),
g2_conn_y=table.get('g2_conn_y', (0, 0)),
g2_m_conn_y=table.get('g2_m_conn_y', (0, 0)))

@property
def bot_conn_types(self) -> Sequence[MOSWireType]:
@@ -219,6 +246,8 @@ def bot_conn_types(self) -> Sequence[MOSWireType]:
index 0 is the default type.
"""
if self.flip:
if self.double_gate:
return MOSWireType.G2, MOSWireType.G2_MATCH
return MOSWireType.DS_GATE, MOSWireType.DS, MOSWireType.DS_MATCH
else:
return MOSWireType.G, MOSWireType.G_MATCH
@@ -232,8 +261,21 @@ def top_conn_types(self) -> Sequence[MOSWireType]:
if self.flip:
return MOSWireType.G, MOSWireType.G_MATCH
else:
if self.double_gate:
return MOSWireType.G2, MOSWireType.G2_MATCH
return MOSWireType.DS_GATE, MOSWireType.DS, MOSWireType.DS_MATCH

@property
def mid_conn_types(self) -> Sequence[MOSWireType]:
"""Return sequence of top wire connection types.
index 0 is the default type.
"""
if self.double_gate:
return MOSWireType.DS_GATE, MOSWireType.DS, MOSWireType.DS_MATCH

raise RuntimeError("trying to use mid conn, when its not a double gate")

def get_ext_info(self, top_edge: bool) -> RowExtInfo:
return self.top_ext_info if top_edge ^ self.flip else self.bot_ext_info

@@ -248,6 +290,10 @@ def get_conn_y(self, wtype: MOSWireType) -> Tuple[int, int]:
ans = self.ds_m_conn_y
elif wtype is MOSWireType.DS_GATE:
ans = self.ds_g_conn_y
elif wtype is MOSWireType.G2:
ans = self.g2_conn_y
elif wtype is MOSWireType.G2_MATCH:
ans = self.g2_m_conn_y
else:
raise ValueError(f'Unsupported MOSWireType: {wtype.name}')
if self.flip:
@@ -258,6 +304,8 @@ def get_all_conn_y(self, wtype: MOSWireType) -> Sequence[Tuple[int, int]]:
"""get list of all possible Y coordinates the given wire type could connect to"""
if wtype is MOSWireType.G or wtype is MOSWireType.G_MATCH:
ans = [self.g_conn_y]
elif wtype is MOSWireType.G2 or wtype is MOSWireType.G2_MATCH:
ans = [self.g2_conn_y]
elif wtype is MOSWireType.DS:
ans = [self.ds_conn_y]
elif wtype is MOSWireType.DS_MATCH or wtype is MOSWireType.DS_GATE:
@@ -274,7 +322,7 @@ def __getitem__(self, name: str) -> Any:
def to_dict(self) -> Mapping[str, Any]:
key_list = ['lch', 'width', 'sub_width', 'threshold', 'height', 'flip', 'g_conn_y',
'g_m_conn_y', 'ds_conn_y', 'ds_m_conn_y', 'ds_g_conn_y', 'sub_conn_y',
'guard_ring']
'guard_ring', 'double_gate', 'g2_conn_y', 'g2_m_conn_y']
ans = {key: getattr(self, key) for key in key_list}
ans['row_type'] = self.row_type.name
ans['top_ext_info'] = self.top_ext_info.to_dict()
@@ -290,6 +338,7 @@ class MOSPorts:
s: WireArray
shorted_ports: ImmutableList[MOSPortType]
m: Optional[WireArray] = None
g2: Optional[WireArray] = None

@property
def num_s(self) -> int:
@@ -330,7 +379,10 @@ class NAND2Ports:

@dataclass(eq=True, frozen=True)
class RowPlaceInfo:
"""Information about a transistor row, placement data included."""
"""Information about a transistor row, placement data included.
(yb_blk, yt_blk) describe the y dimensions of the block, i.e. the MOS row.
(yb, yt) describe the y dimensions of the block plus any edge extensions.
"""
row_info: MOSRowInfo
bot_wires: WireLookup = field(compare=False)
top_wires: WireLookup = field(compare=False)
@@ -339,6 +391,7 @@ class RowPlaceInfo:
yb_blk: int
yt_blk: int
y_conn: Tuple[int, int]
mid_wires: Optional[WireLookup] = None

@classmethod
def from_dict(cls, table: Mapping[str, Any]) -> RowPlaceInfo:
@@ -350,9 +403,11 @@ def from_dict(cls, table: Mapping[str, Any]) -> RowPlaceInfo:
yb_blk: int = table['yb_blk']
yt_blk: int = table['yt_blk']
y_conn: Tuple[int, int] = tuple(table['y_conn'])
mid_wires: Optional[Mapping[Tuple[str, int], Tuple[float, int]]] = table.get('mid_wires', {})

return RowPlaceInfo(MOSRowInfo.from_dict(row_info), WireLookup.from_dict(bot_wires),
WireLookup.from_dict(top_wires), yb, yt, yb_blk, yt_blk, y_conn)
WireLookup.from_dict(top_wires), yb, yt, yb_blk, yt_blk, y_conn,
WireLookup.from_dict(mid_wires))

def to_dict(self) -> Mapping[str, Any]:
return dict(
@@ -364,28 +419,43 @@ def to_dict(self) -> Mapping[str, Any]:
yb_blk=self.yb_blk,
yt_blk=self.yt_blk,
y_conn=self.y_conn,
mid_wires=self.mid_wires.to_dict()
)

def get_extend(self, tr_pitch, delta: int, top_edge: bool, shared: Sequence[str]
) -> RowPlaceInfo:
"""Returns a copy of self, with either the top or bottom edge of the bound box
extended delta in the y direction.
Uses tr_pitch to quantize delta for shifting the tracks.
`shared` lists tracks shared with block abut on the extending edge.
When top_edge==True, the top edge is shifted by delta and the top tracks are shifted.
When top_edge==False, the top edge is shifted by delta, the active area is shifted by delta,
and the tracks are shifted by delta. This maintains alignment with y=0.
"""
tr_shift = HalfInt((2 * delta) // tr_pitch)
if top_edge:
top_wires = self.top_wires.get_move_shared(tr_shift, shared)
return RowPlaceInfo(self.row_info, self.bot_wires, top_wires, self.yb,
self.yt + delta, self.yb_blk, self.yt_blk, self.y_conn)
self.yt + delta, self.yb_blk, self.yt_blk, self.y_conn,
mid_wires=self.mid_wires)
else:
return RowPlaceInfo(self.row_info, self.bot_wires.get_move(tr_shift, shared),
self.top_wires.get_move(tr_shift, []), self.yb, self.yt + delta,
self.yb_blk + delta, self.yt_blk + delta,
(self.y_conn[0] + delta, self.y_conn[1] + delta))
(self.y_conn[0] + delta, self.y_conn[1] + delta),
mid_wires=self.mid_wires.get_move(tr_shift, []))

def get_move(self, tr_pitch: int, delta: int) -> RowPlaceInfo:
"""Returns a copy of self, shifted delta in the y direction.
Uses tr_pitch to quantize delta for shifting the tracks.
"""
tr_shift = HalfInt((2 * delta) // tr_pitch)
el = []
return RowPlaceInfo(self.row_info, self.bot_wires.get_move(tr_shift, el),
self.top_wires.get_move(tr_shift, el), self.yb + delta, self.yt + delta,
self.yb_blk + delta, self.yt_blk + delta,
(self.y_conn[0] + delta, self.y_conn[1] + delta))
(self.y_conn[0] + delta, self.y_conn[1] + delta),
mid_wires=self.mid_wires.get_move(tr_shift, el))

def get_ext_margin(self, top_edge: bool) -> int:
return self.yt - self.yt_blk if top_edge else self.yb_blk - self.yb
83 changes: 66 additions & 17 deletions src/xbase/layout/mos/guardring.py
Original file line number Diff line number Diff line change
@@ -24,7 +24,7 @@
from bag.layout.routing.base import WireArray
from bag.layout.template import TemplateDB, PyLayInstance

from ..enum import MOSWireType
from ..enum import MOSWireType, MOSType

from .placement.data import TilePatternElement, TilePattern
from .base import MOSBase
@@ -90,7 +90,7 @@ def draw_layout(self) -> None:
self.add_pin(f'VDD_guard_{tile_idx}_{ridx}', warr)

def draw_guard_ring(self, master: MOSBase, pmos_gr: str, nmos_gr: str,
sep_ncol: Tuple[int, int], edge_ncol: int
sep_ncol: Tuple[int, int], edge_ncol: int, export_pins: bool = True
) -> Tuple[PyLayInstance, List[Tuple[List[WireArray], List[WireArray]]]]:
self._core = master
self._sch_cls = master.get_schematic_class_inst()
@@ -99,6 +99,8 @@ def draw_guard_ring(self, master: MOSBase, pmos_gr: str, nmos_gr: str,
# construct TilePattern object, and call draw_base()
bot_pinfo = tinfo_table[self._get_gr_name(master, False)]
top_pinfo = tinfo_table[self._get_gr_name(master, True)]

# construct TilePattern object, and call draw_base()
tile_list = [TilePatternElement(bot_pinfo), master.get_tile_pattern_element(),
TilePatternElement(top_pinfo, flip=True)]
self.draw_base((TilePattern(tile_list), tinfo_table))
@@ -118,11 +120,17 @@ def draw_guard_ring(self, master: MOSBase, pmos_gr: str, nmos_gr: str,
sep_r = tech_cls.sub_sep_col
ncol = master.num_cols + 2 * edge_ncol + sep_l + sep_r
ntile = master.num_tile_rows + 2
inst = self.add_tile(master, 1, edge_ncol + sep_l)
master_col = edge_ncol + sep_l
if self.has_double_guard_ring:
ncol += 2 * edge_ncol + sep_l + sep_r
master_col += edge_ncol + sep_l
inst = self.add_tile(master, 1, master_col)
ncol += ncol & 1 # make ncol even for symmetry
self.set_mos_size(num_cols=ncol, num_tiles=ntile)

for name in inst.port_names_iter():
self.reexport(inst.get_port(name))
if export_pins:
for name in inst.port_names_iter():
self.reexport(inst.get_port(name))

sup_list = []
vdd_vm_list = []
@@ -138,12 +146,34 @@ def draw_guard_ring(self, master: MOSBase, pmos_gr: str, nmos_gr: str,
vdd_hm_list = []
vss_hm_list = []
for ridx in range(cur_pinfo.num_rows):
row_type = cur_pinfo.get_row_place_info(ridx).row_info.row_type
if row_type.is_substrate:
row_info = cur_pinfo.get_row_place_info(ridx).row_info
row_type = row_info.row_type
if row_type.is_substrate and row_info.guard_ring:
tid = self.get_track_id(ridx, MOSWireType.DS, 'guard', tile_idx=tile_idx)
sub = self.add_substrate_contact(ridx, 0, tile_idx=tile_idx, seg=ncol)
warr = self.connect_to_tracks(sub, tid)
coord = grid.track_to_coord(hm_layer, tid.base_index)
if row_info.guard_ring_col:
# both guard_ring and guard_ring_col are True,
# so this is the top or bottom row of inner guard ring
assert self.has_double_guard_ring, 'If the PDK does not have double guard ring, the mos row ' \
'cannot have both guard_ring=True and guard_ring_col=True'
sub_col = edge_ncol + sep_l
sub_seg = ncol - 2 * edge_ncol - sep_l - sep_r
sub_lr_type = pmos_sub_type if row_type.is_n_plus else nmos_sub_type
sub_l = self.add_substrate_contact(ridx, 0, tile_idx=tile_idx, seg=edge_ncol,
guard_ring=True, sub_type=sub_lr_type)
sub_r = self.add_substrate_contact(ridx, ncol, tile_idx=tile_idx, seg=edge_ncol,
guard_ring=True, flip_lr=True, sub_type=sub_lr_type)
if sub_lr_type.is_pwell:
vss_vm_list.extend([sub_l, sub_r])
else:
vdd_vm_list.extend([sub_l, sub_r])
else:
# this is the top or bottom row of outer guard ring
sub_col = 0
sub_seg = ncol

sub = self.add_substrate_contact(ridx, sub_col, tile_idx=tile_idx, seg=sub_seg)
warr = self.connect_to_tracks(sub, tid)
if row_type.is_pwell:
vss_hm_list.append(warr)
vss_hm_keys.append(coord)
@@ -152,19 +182,34 @@ def draw_guard_ring(self, master: MOSBase, pmos_gr: str, nmos_gr: str,
vdd_hm_list.append(warr)
vdd_hm_keys.append(coord)
vdd_hm_dict[coord] = warr
else:
sub_type = nmos_sub_type if row_type.is_n_plus else pmos_sub_type
elif row_info.guard_ring_col:
if row_type.is_substrate:
sub_type = pmos_sub_type if row_type.is_n_plus else nmos_sub_type
else:
sub_type = nmos_sub_type if row_type.is_n_plus else pmos_sub_type
sub0 = self.add_substrate_contact(ridx, 0, tile_idx=tile_idx, seg=edge_ncol,
guard_ring=True, sub_type=sub_type)
sub1 = self.add_substrate_contact(ridx, ncol, tile_idx=tile_idx, seg=edge_ncol,
guard_ring=True, flip_lr=True,
sub_type=sub_type)
if sub_type.is_pwell:
vss_vm_list.append(sub0)
vss_vm_list.append(sub1)
vss_vm_list.extend([sub0, sub1])
else:
vdd_vm_list.append(sub0)
vdd_vm_list.append(sub1)
vdd_vm_list.extend([sub0, sub1])

if self.has_double_guard_ring:
sub_lr_type = MOSType.ptap if sub_type is MOSType.ntap else MOSType.ntap
sub_l = self.add_substrate_contact(ridx, edge_ncol + sep_l, tile_idx=tile_idx, seg=edge_ncol,
guard_ring=True, sub_type=sub_lr_type)
sub_r = self.add_substrate_contact(ridx, ncol - edge_ncol - sep_r, tile_idx=tile_idx,
seg=edge_ncol, guard_ring=True, flip_lr=True,
sub_type=sub_lr_type)
if sub_lr_type.is_pwell:
vss_vm_list.extend([sub_l, sub_r])
else:
vdd_vm_list.extend([sub_l, sub_r])
else:
self.error('mos row must have guard_ring=True or guard_ring_col=True.')

sup_list.append((vss_hm_list, vdd_hm_list))

@@ -193,6 +238,10 @@ def _get_gr_name(self, master: MOSBase, is_top: bool) -> str:
ridx = tinfo.num_rows - 1 if flip else 0

mos_type = tinfo.get_row_place_info(ridx).row_info.row_type
# if mos_type.is_substrate:
# raise ValueError('top and bottom row must be transistor row.')
# return self.params['nmos_gr'] if mos_type.is_n_plus else self.params['pmos_gr']
if mos_type.is_substrate:
raise ValueError('top and bottom row must be transistor row.')
return self.params['nmos_gr'] if mos_type.is_n_plus else self.params['pmos_gr']
return self.params['pmos_gr'] if mos_type.is_n_plus else self.params['nmos_gr']
else:
return self.params['nmos_gr'] if mos_type.is_n_plus else self.params['pmos_gr']
146 changes: 112 additions & 34 deletions src/xbase/layout/mos/placement/compact.py
Original file line number Diff line number Diff line change
@@ -53,15 +53,21 @@ class RowPlaceSpecs:
top_conn_y_table: ImmutableSortedDict[MOSWireType, Tuple[int, int]]
bot_ext_info: RowExtInfo
top_ext_info: RowExtInfo
mid_conn_y_table: Optional[ImmutableSortedDict[MOSWireType, Tuple[int, int]]]

def __init__(self, row_specs: MOSRowSpecs, row_info: MOSRowInfo,
bot_conn_y_table: Mapping[MOSWireType, Tuple[int, int]],
top_conn_y_table: Mapping[MOSWireType, Tuple[int, int]],
bot_ext_info: RowExtInfo, top_ext_info: RowExtInfo):
bot_ext_info: RowExtInfo, top_ext_info: RowExtInfo,
mid_conn_y_table: Optional[Mapping[MOSWireType, Tuple[int, int]]] = None):
if not mid_conn_y_table:
mid_conn_y_table = {}

# work around: this is how you set attributes for frozen data classes
object.__setattr__(self, 'row_specs', row_specs)
object.__setattr__(self, 'row_info', row_info)
object.__setattr__(self, 'bot_conn_y_table', ImmutableSortedDict(bot_conn_y_table))
object.__setattr__(self, 'mid_conn_y_table', ImmutableSortedDict(mid_conn_y_table))
object.__setattr__(self, 'top_conn_y_table', ImmutableSortedDict(top_conn_y_table))
object.__setattr__(self, 'bot_ext_info', bot_ext_info)
object.__setattr__(self, 'top_ext_info', top_ext_info)
@@ -88,6 +94,7 @@ def __call__(self, ptype: str, tr_w: int, idx: HalfInt) -> HalfInt:

def _get_row_place_specs(tcls: MOSTech, specs_list: Sequence[MOSRowSpecs],
global_options: Param) -> Sequence[RowPlaceSpecs]:
"""For each MOSRowSpecs, construct MOSRowInfo and RowPlaceSpecs"""
conn_layer = tcls.conn_layer

num_rows = len(specs_list)
@@ -114,6 +121,11 @@ def _get_row_place_specs(tcls: MOSTech, specs_list: Sequence[MOSRowSpecs],
for wtype in row_info.bot_conn_types}
top_conn_y_table = {wtype: row_info.get_conn_y(wtype)
for wtype in row_info.top_conn_types}
if specs.double_gate:
mid_conn_y_table = {wtype: row_info.get_conn_y(wtype)
for wtype in row_info.mid_conn_types}
else:
mid_conn_y_table = {}

if specs.flip:
bext_info = row_info.top_ext_info
@@ -123,17 +135,18 @@ def _get_row_place_specs(tcls: MOSTech, specs_list: Sequence[MOSRowSpecs],
text_info = row_info.top_ext_info

info_list.append(RowPlaceSpecs(specs, row_info, bot_conn_y_table, top_conn_y_table,
bext_info, text_info))
bext_info, text_info, mid_conn_y_table=mid_conn_y_table))

return info_list


def _place_mirror(tech_cls: MOSTech, ext_info: RowExtInfo, ycur: int, ignore_vm_sp_le: bool = False
) -> Tuple[int, int]:
"""Extend the current extention such that it can be mirrored"""
blk_h_pitch = tech_cls.blk_h_pitch

mirror_ext_w_info = tech_cls.get_ext_width_info(ext_info, ext_info,
ignore_vm_sp_le=ignore_vm_sp_le)
mirror_ext_w_info: ExtWidthInfo = tech_cls.get_ext_width_info(ext_info, ext_info,
ignore_vm_sp_le=ignore_vm_sp_le)

ext_w_cur = ycur // blk_h_pitch
ext_w_tot = mirror_ext_w_info.get_next_width(2 * ext_w_cur, even=True)
@@ -146,6 +159,30 @@ def _place_rows(tr_manager: TrackManager, tech_cls: MOSTech, pspecs_list: Sequen
tot_height_min: int, tot_height_pitch: int, bot_mirror: bool, top_mirror: bool,
hm_shift: Union[int, HalfInt] = 0, max_iter: int = 100
) -> Tuple[ImmutableList[RowPlaceInfo], List[Tuple[WireGraph, WireGraph]]]:
"""Used by place_rows_compact to place rows after getting RowPlaceSpecs for all rows.
Parameters
----------
tr_manager : TrackManager
the track manager of the MOSBase.
tech_cls : MOSTech
the technology specific class for drawing layout
pspecs_list : Sequence[RowPlaceSpecs]
list of RowPlaceSpecs. See _get_row_place_specs for construction details
tot_height_min: int
Minimum cell height, set by e.g. desired heigher metal tracks.
tot_height_pitch: int
Quantize the cell height to this dimension. Typically a tile height.
bot_mirror : bool
True to satisfy mirror placement constraint on the bottom edge.
top_mirror : bool
True to satisfy mirror placement constraint on the top edge.
hm_shift: Union[int, HalfInt]
Optional vertical track shift for the bottom (0th) row.
max_iter:
Maximum number of iterations to try to fix the cell bottom - active bottom extension
to fit the bottom tracks.
"""
grid = tr_manager.grid
blk_h_pitch = tech_cls.blk_h_pitch
conn_layer = tech_cls.conn_layer
@@ -160,31 +197,33 @@ def _place_rows(tr_manager: TrackManager, tech_cls: MOSTech, pspecs_list: Sequen
pinfo_list = []
prev_wg: Optional[WireGraph] = None
row_graph_list: List[Tuple[WireGraph, WireGraph]] = []
# first pass: determine Y coordinates of each row.

for idx, pspecs in enumerate(pspecs_list):
bot_ext_info = pspecs.bot_ext_info
top_ext_info = pspecs.top_ext_info
bot_conn_y_table = pspecs.bot_conn_y_table
mid_conn_y_table = pspecs.mid_conn_y_table
top_conn_y_table = pspecs.top_conn_y_table

row_specs = pspecs.row_specs
ignore_bot_vm_sp_le = row_specs.ignore_bot_vm_sp_le
ignore_top_vm_sp_le = row_specs.ignore_top_vm_sp_le

row_info = pspecs.row_info
blk_h = row_info.height

bot_wg = WireGraph.make_wire_graph(hm_layer, tr_manager, row_specs.bot_wires)
top_wg = WireGraph.make_wire_graph(hm_layer, tr_manager, row_specs.top_wires)
bot_wg: WireGraph = WireGraph.make_wire_graph(hm_layer, tr_manager, row_specs.bot_wires)
mid_wg: WireGraph = WireGraph.make_wire_graph(hm_layer, tr_manager, row_specs.mid_wires)
top_wg: WireGraph = WireGraph.make_wire_graph(hm_layer, tr_manager, row_specs.top_wires)
row_graph_list.append((bot_wg, top_wg))

if idx == 0:
# first row, place bottom wires using mirror/shift constraints
bot_wg.place_compact(hm_layer, tr_manager, bot_mirror=bot_mirror, shift=hm_shift)
else:
# subsequent rows, place bottom wires using previous wire graph
bot_wg.place_compact(hm_layer, tr_manager, prev_wg=prev_wg)

bnd_table = bot_wg.get_placement_bounds(hm_layer, grid)
bnd_table: Dict[str, List[Tuple[HalfInt, int]]] = bot_wg.get_placement_bounds(hm_layer, grid)

# find Y coordinate of MOS row
ycur = ytop_prev
@@ -254,32 +293,70 @@ def _place_rows(tr_manager: TrackManager, tech_cls: MOSTech, pspecs_list: Sequen
conn_y_bnds_bot[0], False)
conn_y_bnds_bot[1] = _update_y_conn(grid, row_info, conn_layer, ycur, bnd_table,
conn_y_bnds_bot[1], True)
# place top wires
is_top_row = (idx == num_rows - 1)
conn_y_bnds_top = [COORD_MAX, COORD_MIN]
pcons = {}
for wtype, conn_y in top_conn_y_table.items():
pcons[wtype.name] = ycur + conn_y[0]
if wtype.is_physical:
conn_y_bnds_top[0] = min(conn_y_bnds_top[0], ycur + conn_y[0])
conn_y_bnds_top[1] = max(conn_y_bnds_top[1], ycur + conn_y[1])

if bot_wg:
prev_wg = bot_wg
if top_wg:
top_wg.place_compact(hm_layer, tr_manager,
pcons=PlaceFun(conn_layer, grid, pcons, RoundMode.GREATER_EQ),
prev_wg=prev_wg, top_mirror=top_mirror and is_top_row,
ytop_conn=max(conn_y_bnds_bot[1], conn_y_bnds_top[1]))
if row_info.row_type.is_substrate:
top_wg.align_wires(hm_layer, tr_manager, ytop_prev, ycur + blk_h, top_pcons=None)

# get ytop_conn
bnd_table = top_wg.get_placement_bounds(hm_layer, grid)
conn_y_bnds_top[0] = _update_y_conn(grid, row_info, conn_layer, ycur, bnd_table,
conn_y_bnds_top[0], False)
conn_y_bnds_top[1] = _update_y_conn(grid, row_info, conn_layer, ycur, bnd_table,
conn_y_bnds_top[1], True)

is_top_row = (idx == num_rows - 1)
if row_specs.double_gate:
# place middle wires
conn_y_bnds_mid = [COORD_MAX, COORD_MIN]
pcons = {}
for wtype, conn_y in mid_conn_y_table.items():
pcons[wtype.name] = ycur + conn_y[0]
if wtype.is_physical:
conn_y_bnds_mid[0] = min(conn_y_bnds_mid[0], ycur + conn_y[0])
conn_y_bnds_mid[1] = max(conn_y_bnds_mid[1], ycur + conn_y[1])

if mid_wg:
mid_wg.place_compact(hm_layer, tr_manager,
pcons=PlaceFun(conn_layer, grid, pcons, RoundMode.GREATER_EQ),
prev_wg=prev_wg, ytop_conn=max(conn_y_bnds_bot[1], conn_y_bnds_mid[1]))
prev_wg = mid_wg

# place top wires above the middle wires
conn_y_bnds_top = [COORD_MAX, COORD_MIN]
pcons = {}
for wtype, conn_y in top_conn_y_table.items():
pcons[wtype.name] = ycur + conn_y[0]
if wtype.is_physical:
conn_y_bnds_top[0] = min(conn_y_bnds_top[0], ycur + conn_y[0])
conn_y_bnds_top[1] = max(conn_y_bnds_top[1], ycur + conn_y[1])

if top_wg:
top_wg.place_compact(hm_layer, tr_manager,
pcons=PlaceFun(conn_layer, grid, pcons, RoundMode.GREATER_EQ),
prev_wg=prev_wg, ytop_conn=max(conn_y_bnds_bot[1], conn_y_bnds_top[1]))
prev_wg = top_wg

bnd_table = top_wg.get_placement_bounds(hm_layer, grid)
conn_y_bnds_top[0] = _update_y_conn(grid, row_info, conn_layer, ycur, bnd_table,
conn_y_bnds_top[0], False)
conn_y_bnds_top[1] = _update_y_conn(grid, row_info, conn_layer, ycur, bnd_table,
conn_y_bnds_top[1], True)
else:
# place top wires
conn_y_bnds_top = [COORD_MAX, COORD_MIN]
pcons = {}
for wtype, conn_y in top_conn_y_table.items():
pcons[wtype.name] = ycur + conn_y[0]
if wtype.is_physical:
conn_y_bnds_top[0] = min(conn_y_bnds_top[0], ycur + conn_y[0])
conn_y_bnds_top[1] = max(conn_y_bnds_top[1], ycur + conn_y[1])

if top_wg:
top_wg.place_compact(hm_layer, tr_manager,
pcons=PlaceFun(conn_layer, grid, pcons, RoundMode.GREATER_EQ),
prev_wg=prev_wg, top_mirror=top_mirror and is_top_row,
ytop_conn=max(conn_y_bnds_bot[1], conn_y_bnds_top[1]))
if row_info.row_type.is_substrate:
top_wg.align_wires(hm_layer, tr_manager, ytop_prev, ycur + blk_h, top_pcons=None)

# get ytop_conn
bnd_table = top_wg.get_placement_bounds(hm_layer, grid)
conn_y_bnds_top[0] = _update_y_conn(grid, row_info, conn_layer, ycur, bnd_table,
conn_y_bnds_top[0], False)
conn_y_bnds_top[1] = _update_y_conn(grid, row_info, conn_layer, ycur, bnd_table,
conn_y_bnds_top[1], True)

# compute ytop
ytop_blk = ycur + blk_h
@@ -311,7 +388,8 @@ def _place_rows(tr_manager: TrackManager, tech_cls: MOSTech, pspecs_list: Sequen
ybot_conn = min(conn_y_bnds_bot[0], conn_y_bnds_top[0])
ytop_conn = max(conn_y_bnds_bot[1], conn_y_bnds_top[1])
pinfo_list.append(RowPlaceInfo(row_info, bot_wg.get_wire_lookup(), top_wg.get_wire_lookup(),
ytop_prev, ytop, ycur, ytop_blk, (ybot_conn, ytop_conn)))
ytop_prev, ytop, ycur, ytop_blk, (ybot_conn, ytop_conn),
mid_wires=mid_wg.get_wire_lookup()))

# update previous row information
ytop_prev = ytop
19 changes: 16 additions & 3 deletions src/xbase/layout/mos/placement/data.py
Original file line number Diff line number Diff line change
@@ -432,6 +432,10 @@ def ext_h_top(self) -> int:
def extend_priority(self) -> int:
return self._priority

@property
def wire_lookup(self) -> ImmutableSortedDict[int, WireLookup]:
return self._wire_lookup

@property
def tile_options(self) -> Param:
return self._options
@@ -936,10 +940,19 @@ def _get_wire_info(self, row_idx: int, wire_type: Union[MOSWireType, bool], tile
rpinfo = pinfo.get_row_place_info(row_idx)
if isinstance(wire_type, bool):
top = wire_type
wlookup = rpinfo.top_wires if top else rpinfo.bot_wires
else:
flip_row = rpinfo.row_info.flip
top = (wire_type.is_gate == flip_row)
wlookup = rpinfo.top_wires if top else rpinfo.bot_wires
if rpinfo.row_info.double_gate:
flip_row = rpinfo.row_info.flip
if not (wire_type.is_gate or wire_type.is_gate2):
wlookup = rpinfo.mid_wires
else:
top = (wire_type.is_gate == flip_row)
wlookup = rpinfo.top_wires if top else rpinfo.bot_wires
else:
flip_row = rpinfo.row_info.flip
top = (wire_type.is_gate == flip_row)
wlookup = rpinfo.top_wires if top else rpinfo.bot_wires

if flip_tile:
return wlookup, yb + pinfo.height, -1
17 changes: 13 additions & 4 deletions src/xbase/layout/mos/primitives.py
Original file line number Diff line number Diff line change
@@ -22,7 +22,7 @@
from ..data import draw_layout_in_template

from .tech import MOSTech
from .data import MOSEdgeInfo, RowExtInfo, BlkExtInfo, MOSRowInfo
from .data import MOSEdgeInfo, RowExtInfo, BlkExtInfo, MOSRowInfo, MOSLayInfo


class MOSConn(TemplateBase):
@@ -95,10 +95,11 @@ def draw_layout(self) -> None:
tech_cls: MOSTech = grid.tech_info.get_device_tech('mos', lch=row_info.lch,
arr_options=arr_options)

mos_info = tech_cls.get_mos_conn_info(row_info, conn_layer, seg, w, stack, g_on_s, options)
mos_info: MOSLayInfo = tech_cls.get_mos_conn_info(row_info, conn_layer, seg, w, stack, g_on_s, options)
draw_layout_in_template(self, mos_info.lay_info)

g_conn_y = row_info.g_conn_y
g2_conn_y = row_info.g2_conn_y
if g_on_s:
if (stack & 1) == 0:
d_conn_y = row_info.ds_g_conn_y
@@ -121,13 +122,21 @@ def draw_layout(self) -> None:
d_tr_p = d_pitch // pitch
s_tr_p = s_pitch // pitch

gw = self.add_wires(conn_layer, g_tr, g_conn_y[0], g_conn_y[1], num=num_g, pitch=g_tr_p)
dw = self.add_wires(conn_layer, d_tr, d_conn_y[0], d_conn_y[1], num=num_d, pitch=d_tr_p)
sw = self.add_wires(conn_layer, s_tr, s_conn_y[0], s_conn_y[1], num=num_s, pitch=s_tr_p)
self.add_pin('g', gw)
self.add_pin('d', dw)
self.add_pin('s', sw)

"""Double gate options: draw_g enables drawing g. draw_g2 enables drawing g2. Defaults to drawing both"""
draw_g = options.get('draw_g', True)
draw_g2 = options.get('draw_g2', True)
if not row_info.double_gate or draw_g:
gw = self.add_wires(conn_layer, g_tr, g_conn_y[0], g_conn_y[1], num=num_g, pitch=g_tr_p)
self.add_pin('g', gw)
if row_info.double_gate and draw_g2:
g2w = self.add_wires(conn_layer, g_tr, g2_conn_y[0], g2_conn_y[1], num=num_g, pitch=g_tr_p)
self.add_pin('g2', g2w)

if mos_info.m_info is not None:
m_xc, num_m, m_pitch = mos_info.m_info
m_tr = grid.coord_to_track(conn_layer, m_xc)
171 changes: 171 additions & 0 deletions src/xbase/layout/mos/static.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,171 @@
from typing import Optional, Type, Any, Mapping, Sequence, Tuple

from bag.layout.template import TemplateBase, TemplateDB
from bag.layout.util import BlackBoxTemplate
from bag.design.module import Module
from bag.util.immutable import Param

from pybag.core import BBox, Transform

from ...schematic.mos_char import xbase__mos_char


class MOSStatic(TemplateBase):
"""This class instantiates a static MOS layout as a BlackBoxTemplate and adds primitive pins"""
def __init__(self, temp_db: TemplateDB, params: Param, **kwargs: Any) -> None:
TemplateBase.__init__(self, temp_db, params, **kwargs)
self._conn_layer = -1

@property
def conn_layer(self) -> int:
return self._conn_layer

@classmethod
def get_schematic_class(cls) -> Optional[Type[Module]]:
return xbase__mos_char

@classmethod
def get_params_info(cls) -> Mapping[str, str]:
return dict(
mos_type='transistor type.',
w='width of the transistor, in resolution units or fins.',
lch='channel length, in resolution units.',
seg='number of segments.',
intent='threshold flavor.',
)

def draw_layout(self) -> None:
mos_type: str = self.params['mos_type']
w: int = self.params['w']
lch: int = self.params['lch']
seg: int = self.params['seg']
intent: str = self.params['intent']

mos_info = self.grid.tech_info.tech_params['mos_static']
pcell_list: Sequence[Mapping[str, Any]] = mos_info['pcell_list']
for _info in pcell_list:
if mos_type == _info['mos_type'] and w == _info['w'] and lch == _info['lch'] and seg == _info['nf'] and \
intent == _info['intent']:
pcell_info = _info['inst_info']
break
else:
raise ValueError(f'Requested pcell is not supported yet.')

# make master
master = self.new_template(BlackBoxTemplate, params=pcell_info)

# add instance
inst = self.add_instance(master, inst_name='XINST')
bbox = inst.bound_box
self._conn_layer = top_layer = pcell_info['top_layer']
self.set_size_from_bound_box(top_layer, bbox, round_up=True)

# add rectangle arrays, if any
rect_arr_list: Sequence[Mapping[str, Any]] = mos_info['rect_arr_list']
for rect_arr in rect_arr_list:
edge_margin: Mapping[str, int] = rect_arr.get('edge_margin', {})
rect_xl = bbox.xl + edge_margin.get('xl', 0)
rect_xh = bbox.xh + edge_margin.get('xh', 0)
rect_yl = bbox.yl + edge_margin.get('yl', 0)
rect_yh = bbox.yh + edge_margin.get('yh', 0)
spx: int = rect_arr.get('spx', 0)
if spx == 0:
num_x = 1
else:
w_unit: int = rect_arr['w_unit']
num_x = (rect_xh - rect_xl - w_unit) // spx + 1
rect_xh = rect_xl + w_unit
spy: int = rect_arr.get('spy', 0)
if spy == 0:
num_y = 1
else:
h_unit: int = rect_arr['h_unit']
num_y = (rect_yh - rect_yl - h_unit) // spy + 1
rect_yh = rect_yl + h_unit
lp: Tuple[str, str] = rect_arr['lay_purp']
self.add_rect_array(lp, BBox(rect_xl, rect_yl, rect_xh, rect_yh), num_x, num_y, spx, spy)

# pins
conn_lp = self.grid.tech_info.get_lay_purp_list(top_layer)[0]
for term in ('b', 'd', 'g', 's'):
_pins: Sequence[BBox] = inst.get_all_port_pins(term, top_layer)
if len(_pins) > 1:
for idx, _bbox in enumerate(_pins):
self.add_pin_primitive(f'{term}{idx}', conn_lp[0], _bbox, label=term, connect=True)
else:
self.add_pin_primitive(term, conn_lp[0], _pins[0])

self.sch_params = dict(
mos_type=mos_type,
w=w,
lch=lch,
seg=seg,
intent=intent,
)


class MOSStaticWrapper(TemplateBase):
def __init__(self, temp_db: TemplateDB, params: Param, **kwargs: Any) -> None:
TemplateBase.__init__(self, temp_db, params, **kwargs)

self._core: Optional[MOSStatic] = None
self._xform: Transform = Transform()

@property
def core(self) -> MOSStatic:
return self._core

@property
def core_xform(self) -> Transform:
return self._xform

@classmethod
def get_params_info(cls) -> Mapping[str, str]:
return dict(
params='parameters for the wrapped class.',
export_hidden='True to export hidden pins.',
half_blk_x='Defaults to True. True to allow half-block width.',
half_blk_y='Defaults to True. True to allow half-block height.',
)

@classmethod
def get_default_param_values(cls) -> Mapping[str, Any]:
return dict(export_hidden=False, half_blk_x=True, half_blk_y=True)

def get_schematic_class_inst(self) -> Optional[Type[Module]]:
return self._core.get_schematic_class_inst()

def draw_layout(self):
params = self.params
dut_params: Param = params['params']
export_hidden: bool = params['export_hidden']
half_blk_x: bool = params['half_blk_x']
half_blk_y: bool = params['half_blk_y']

master = self.new_template(MOSStatic, params=dut_params)

self.wrap_mos_static(master, export_hidden, half_blk_x=half_blk_x, half_blk_y=half_blk_y)

def wrap_mos_static(self, master: MOSStatic, export_hidden: bool, half_blk_x: bool = True,
half_blk_y: bool = True) -> None:
top_layer = master.top_layer
bbox = master.bound_box
w_blk, h_blk = self.grid.get_block_size(top_layer, half_blk_x=half_blk_x, half_blk_y=half_blk_y)

self._core = master
edge_sep = self.grid.tech_info.tech_params['mos_static']['edge_sep']
w_tot = bbox.w + 2 * edge_sep['x']
h_tot = bbox.h + 2 * edge_sep['y']
assert w_tot % w_blk == 0 and h_tot % h_blk == 0

self._xform = Transform(edge_sep['x'], edge_sep['y'])
inst = self.add_instance(master, inst_name='X0', xform=self._xform)
self.set_size_from_bound_box(top_layer, BBox(0, 0, w_tot, h_tot))

# re-export pins
for name in inst.port_names_iter():
if not master.get_port(name).hidden or export_hidden:
self.reexport(inst.get_port(name))

# pass out schematic parameters
self.sch_params = master.sch_params
46 changes: 35 additions & 11 deletions src/xbase/layout/mos/tech.py
Original file line number Diff line number Diff line change
@@ -18,7 +18,7 @@

from __future__ import annotations

from typing import TYPE_CHECKING, Tuple, Dict, Any, List, Mapping
from typing import Tuple, Dict, Any, List, Mapping

import abc
import math
@@ -34,12 +34,9 @@

from .data import (
MOSRowSpecs, MOSRowInfo, RowExtInfo, MOSEdgeInfo, MOSLayInfo, ExtWidthInfo, ExtEndLayInfo,
MOSBaseEndInfo, BlkExtInfo
MOSBaseEndInfo, BlkExtInfo, RowPlaceInfo
)

if TYPE_CHECKING:
from .base import MOSBasePlaceInfo


def _get_end_block_info(h_ext: int, h_end_min: int, blk_h: int) -> Tuple[int, int]:
h_blk = -(-max(0, h_end_min - h_ext) // blk_h) * blk_h
@@ -105,6 +102,12 @@ def sub_sep_col(self) -> int:
"""
raise NotImplementedError('Not implemented')

@property
def gr_sub_sep_col(self) -> int:
"""int: column separation needed between guard ring substrate and inner substrate.
"""
return self.sub_sep_col

@property
@abc.abstractmethod
def min_sub_col(self) -> int:
@@ -124,6 +127,23 @@ def abut_mode(self) -> MOSAbutMode:
def can_short_adj_tracks(self, conn_layer: int) -> bool:
raise NotImplementedError('Not implemented')

# noinspection PyMethodMayBeStatic
def can_abut_mos(self, row_info: MOSRowInfo) -> bool:
return True

# noinspection PyMethodMayBeStatic
def can_extend_ds_conn(self, g_side: bool, threshold: str) -> bool:
return True

@property
@abc.abstractmethod
def can_draw_double_gate(self) -> bool:
raise NotImplementedError('Not implemented')

@property
def has_double_guard_ring(self) -> bool:
return False

@abc.abstractmethod
def get_track_specs(self, conn_layer: int, top_layer: int) -> List[TrackSpec]:
return []
@@ -239,14 +259,18 @@ def sd_pitch(self) -> int:
sd_constants: Tuple[int, int] = self.mos_config['sd_pitch_constants']
return sd_constants[0] + self.lch * sd_constants[1]

def get_mos_base_end_info(self, pinfo: MOSBasePlaceInfo, blk_pitch: int) -> MOSBaseEndInfo:
def get_mos_base_end_info(self, bot_rpinfo: RowPlaceInfo, top_rpinfo: RowPlaceInfo, bot_flip: bool, top_flip: bool,
blk_pitch: int) -> MOSBaseEndInfo:
blk_pitch = lcm([self.blk_h_pitch, blk_pitch])

bot_rpinfo = pinfo.get_row_place_info(0)
top_rpinfo = pinfo.get_row_place_info(-1)

h_ext_bot = bot_rpinfo.yb_blk - bot_rpinfo.yb
h_ext_top = top_rpinfo.yt - top_rpinfo.yt_blk
if bot_flip:
h_ext_bot = bot_rpinfo.yt - bot_rpinfo.yt_blk
else:
h_ext_bot = bot_rpinfo.yb_blk - bot_rpinfo.yb
if top_flip:
h_ext_top = top_rpinfo.yb_blk - top_rpinfo.yb
else:
h_ext_top = top_rpinfo.yt - top_rpinfo.yt_blk

h_end_min = self.end_h_min
h_mos_end_bot, h_blk_bot = _get_end_block_info(h_ext_bot, h_end_min, blk_pitch)
83 changes: 61 additions & 22 deletions src/xbase/layout/mos/top.py
Original file line number Diff line number Diff line change
@@ -66,23 +66,23 @@ def draw_boundaries(self, master: MOSBase, top_layer: int, *,
tech_cls = master.tech_cls
bbox = master.bound_box
used_arr = master.used_array
num_tiles = used_arr.num_tiles

w_blk, h_blk = self.grid.get_block_size(top_layer,
half_blk_x=half_blk_x, half_blk_y=half_blk_y)

w_master = bbox.w
h_master = bbox.h
w_edge = tech_cls.get_edge_width(w_master, w_blk)
base_end_info = tech_cls.get_mos_base_end_info(master.place_info, h_blk)
bot_pinfo, _, bot_flip = used_arr.get_tile_info(0)
top_pinfo, _, top_flip = used_arr.get_tile_info(num_tiles - 1)
bot_rpinfo = bot_pinfo.get_row_place_info(-1) if bot_flip else bot_pinfo.get_row_place_info(0)
top_rpinfo = top_pinfo.get_row_place_info(0) if top_flip else top_pinfo.get_row_place_info(-1)
base_end_info = tech_cls.get_mos_base_end_info(bot_rpinfo, top_rpinfo, bot_flip, top_flip, h_blk)

# get top/bottom boundary delta/height
num_tiles = used_arr.num_tiles
idx_bot = int(used_arr.get_flip_tile(0))
idx_top = int(not used_arr.get_flip_tile(num_tiles - 1))
dy_bot = base_end_info.h_blk[idx_bot]
dy_top = base_end_info.h_blk[idx_top]
h_end_bot = base_end_info.h_mos_end[idx_bot]
h_end_top = base_end_info.h_mos_end[idx_top]
dy_bot, dy_top = base_end_info.h_blk
h_end_bot, h_end_top = base_end_info.h_mos_end

self._xform = Transform(w_edge, dy_bot)
inst = self.add_instance(master, inst_name='X0', xform=self._xform)
@@ -273,25 +273,61 @@ def _add_ext_row(self, grid: RoutingGrid, tech: MOSTech, lch: int, fg: int, re_b

cut_mode, bot_exty, top_exty = tech.get_extension_regions(re_bot, re_top, ext_h)
if cut_mode.num_cut == 2 and bot_exty == top_exty == 0:
if be_bot[0].guard_ring and be_bot[0].fg_dev[0][1] is be_top[0].fg_dev[0][1]:
if be_bot[0].guard_ring and be_top[0].guard_ring and be_bot[0].fg_dev[0][1] is be_top[0].fg_dev[0][1]:
# this is extension within a guard ring
if len(be_bot) > 1:
fg_edge = be_bot[0].fg
fg_gr = fg_edge + be_bot[1].fg_dev[0][0]
gr_sub_type = gr2_sub_type = be_bot[0].fg_dev[0][1]
if tech.has_double_guard_ring:
if len(be_bot) == 1:
# this is extension between outer guard ring and inner guard ring on the bottom
fg_edge = be_top[0].fg
fg_gr = fg_edge + be_top[1].fg_dev[0][0]
fg_edge2 = 0
fg_gr2 = 0
elif len(be_top) == 1:
# this is extension between outer guard ring and inner guard ring on the top
fg_edge = be_bot[0].fg
fg_gr = fg_edge + be_bot[1].fg_dev[0][0]
fg_edge2 = 0
fg_gr2 = 0
else:
# this is extension inside inner guard ring
_be = be_bot if len(be_bot) > len(be_top) else be_top
fg_edge = _be[0].fg
fg_gr = fg_edge + _be[1].fg_dev[0][0]
fg_edge2 = _be[2].fg
fg_gr2 = _be[2].fg + _be[3].fg_dev[0][0]
gr2_sub_type = _be[2].fg_dev[0][1]
else:
fg_edge = be_top[0].fg
fg_gr = fg_edge + be_top[1].fg_dev[0][0]

ext_dx = fg_gr * tech.sd_pitch
ext_params = dict(lch=lch, num_cols=fg - 2 * fg_gr, height=ext_h, bot_info=re_bot,
_be = be_bot if len(be_bot) > len(be_top) else be_top
fg_edge = _be[0].fg
fg_gr = fg_edge + _be[1].fg_dev[0][0]
fg_edge2 = 0
fg_gr2 = 0

ext_dx = (fg_gr + fg_edge2 + fg_gr2) * tech.sd_pitch
ext_params = dict(lch=lch, num_cols=fg - 2 * (fg_gr + fg_edge2 + fg_gr2), height=ext_h, bot_info=re_bot,
top_info=re_top, gr_info=(fg_edge, fg_gr),
arr_options=arr_options)
ext_master = self.new_template(MOSExt, params=ext_params, grid=grid)
edge_info = ext_master.edge_info

if fg_gr2 > 0:
# add inner guard ring
gr2_params = dict(lch=lch, num_cols=fg_gr2, edge_cols=fg_edge2, height=ext_h,
bot_info=re_bot, top_info=re_top, sub_type=gr2_sub_type,
einfo=edge_info, arr_options=arr_options)
gr2_master = self.new_template(MOSExtGR, params=gr2_params, grid=grid)
edge_info = gr2_master.edge_info

dx2 = dx + (fg_gr + fg_edge2) * tech.sd_pitch
self.add_instance(gr2_master, inst_name=f'{prefix}EXGRL2', xform=Transform(dx2, y0))
self.add_instance(gr2_master, inst_name=f'{prefix}EXGRR2',
xform=Transform(w_tot - dx2, y0, Orientation.MY))

# add guard ring
gr_params = dict(lch=lch, num_cols=fg_gr, edge_cols=fg_edge, height=ext_h,
bot_info=re_bot, top_info=re_top, sub_type=be_bot[0].fg_dev[0][1],
einfo=ext_master.edge_info, arr_options=arr_options)
bot_info=re_bot, top_info=re_top, sub_type=gr_sub_type,
einfo=edge_info, arr_options=arr_options)
gr_master = self.new_template(MOSExtGR, params=gr_params, grid=grid)
edge_info = gr_master.edge_info

@@ -373,15 +409,18 @@ def wrap_mos_base(self, master: MOSBase, export_hidden: bool, half_blk_x: bool =

def private_port_check(lay_id: int) -> bool:
if lay_id <= top_layer and not grid.is_horizontal(lay_id):
print(f'WARNING: ports on private layer {lay_id} detected, '
f'converting to primitive ports.')
self.warn(f'ports on private layer {lay_id} detected, converting to primitive ports.')
return True
return False

# re-export pins
for name in inst.port_names_iter():
if not master.get_port(name).hidden or export_hidden:
self.reexport(inst.get_primitive_port(name, private_port_check))
if name in self._port_params:
show = self._port_params[name]['show']
else:
show = None
self.reexport(inst.get_primitive_port(name, private_port_check), show=show)

# pass out schematic parameters
self.sch_params = master.sch_params
418 changes: 410 additions & 8 deletions src/xbase/layout/res/base.py

Large diffs are not rendered by default.

105 changes: 105 additions & 0 deletions src/xbase/layout/res/char.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@
# BSD 3-Clause License
#
# Copyright (c) 2018, Regents of the University of California
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are met:
#
# * Redistributions of source code must retain the above copyright notice, this
# list of conditions and the following disclaimer.
#
# * Redistributions in binary form must reproduce the above copyright notice,
# this list of conditions and the following disclaimer in the documentation
# and/or other materials provided with the distribution.
#
# * Neither the name of the copyright holder nor the names of its
# contributors may be used to endorse or promote products derived from
# this software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

"""This module defines programmable series / parallel combination of resistor units for characterization."""

from typing import Mapping, Any, Optional, Type, cast

from bag.util.immutable import Param
from bag.design.module import Module
from bag.layout.template import TemplateDB
from bag.layout.routing.base import TrackID

from pybag.enum import RoundMode

from .base import ResBasePlaceInfo, ResArrayBase
from ...schematic.res_char import xbase__res_char


class ResChar(ResArrayBase):
"""Programmable series / parallel combination of unit resistors"""
def __init__(self, temp_db: TemplateDB, params: Param, **kwargs: Any) -> None:
ResArrayBase.__init__(self, temp_db, params, **kwargs)

@classmethod
def get_schematic_class(cls) -> Optional[Type[Module]]:
return xbase__res_char

@classmethod
def get_params_info(cls) -> Mapping[str, str]:
return dict(
pinfo='The ResBasePlaceInfo object.',
snake_conn='True to have snaking series connection; False by default',
)

@classmethod
def get_default_param_values(cls) -> Mapping[str, Any]:
return dict(snake_conn=False)

def draw_layout(self) -> None:
pinfo = cast(ResBasePlaceInfo, ResBasePlaceInfo.make_place_info(self.grid, self.params['pinfo']))
self.draw_base(pinfo)

# Get hm_layer and vm_layer WireArrays
warrs, bulk_warrs = self.connect_hm_vm()

# Supply connections on xm_layer
self.connect_bulk_xm(bulk_warrs)

# --- Routing of unit resistors --- #
snake_conn: bool = self.params['snake_conn']
if snake_conn:
minus, plus = self.snake_connect_units(warrs, 0, pinfo.nx, 0, pinfo.ny)
nser = pinfo.ny * pinfo.nx
npar = 1
else:
minus, plus = self.connect_units(warrs, 0, pinfo.nx, 0, pinfo.ny)
nser = pinfo.ny
npar = pinfo.nx

hm_layer = self.conn_layer + 1
vm_layer = hm_layer + 1
xm_layer = vm_layer + 1
w_xm_sig = self.tr_manager.get_width(xm_layer, 'sig')
for pin_name, warr in [('minus', minus), ('plus', plus)]:
xm_idx = self.grid.coord_to_track(xm_layer, warr.middle, RoundMode.NEAREST)
xm_tid = TrackID(xm_layer, xm_idx, w_xm_sig)
self.add_pin(pin_name, self.connect_to_tracks(warr, xm_tid))

self.sch_params = dict(
unit_params=dict(
w=pinfo.w_res,
l=pinfo.l_res,
intent=pinfo.res_type,
),
nser=nser,
npar=npar,
sub_type=pinfo.res_config['sub_type_default'],
)
12 changes: 12 additions & 0 deletions src/xbase/layout/res/tech.py
Original file line number Diff line number Diff line change
@@ -47,3 +47,15 @@ def mos_type_default(self) -> str:
@property
def threshold_default(self) -> str:
return self._res_config['threshold_default']

@property
def has_substrate_port(self) -> bool:
return self._res_config['has_substrate_port']

@abc.abstractmethod
def get_width(self, **kwargs) -> int:
raise NotImplementedError()

@abc.abstractmethod
def get_length(self, **kwargs) -> int:
raise NotImplementedError()
87 changes: 87 additions & 0 deletions src/xbase/schematic/clamp_static.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
# BSD 3-Clause License
#
# Copyright (c) 2018, Regents of the University of California
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are met:
#
# * Redistributions of source code must retain the above copyright notice, this
# list of conditions and the following disclaimer.
#
# * Redistributions in binary form must reproduce the above copyright notice,
# this list of conditions and the following disclaimer in the documentation
# and/or other materials provided with the distribution.
#
# * Neither the name of the copyright holder nor the names of its
# contributors may be used to endorse or promote products derived from
# this software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

# -*- coding: utf-8 -*-

from typing import Mapping, Any

import pkg_resources
from pathlib import Path

from bag.design.module import Module
from bag.design.database import ModuleDB
from bag.util.immutable import Param


# noinspection PyPep8Naming
class xbase__clamp_static(Module):
"""Module for library xbase cell clamp_static.
Fill in high level description here.
"""

yaml_file = pkg_resources.resource_filename(__name__,
str(Path('netlist_info',
'clamp_static.yaml')))

def __init__(self, database: ModuleDB, params: Param, **kwargs: Any) -> None:
Module.__init__(self, self.yaml_file, database, params, **kwargs)

@classmethod
def get_params_info(cls) -> Mapping[str, str]:
"""Returns a dictionary from parameter names to descriptions.
Returns
-------
param_info : Optional[Mapping[str, str]]
dictionary from parameter names to descriptions.
"""
return dict(
lib_name='Library name for the esd_static cell',
cell_name="clamp",
)

def design(self, lib_name: str, cell_name: str) -> None:
"""To be overridden by subclasses to design this module.
This method should fill in values for all parameters in
self.parameters. To design instances of this module, you can
call their design() method or any other ways you coded.
To modify schematic structure, call:
rename_pin()
delete_instance()
replace_instance_master()
reconnect_instance_terminal()
restore_instance()
array_instance()
"""
self.replace_instance_master('XCLP', lib_name, cell_name, static=True, keep_connections=True)
89 changes: 89 additions & 0 deletions src/xbase/schematic/esd.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
# BSD 3-Clause License
#
# Copyright (c) 2018, Regents of the University of California
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are met:
#
# * Redistributions of source code must retain the above copyright notice, this
# list of conditions and the following disclaimer.
#
# * Redistributions in binary form must reproduce the above copyright notice,
# this list of conditions and the following disclaimer in the documentation
# and/or other materials provided with the distribution.
#
# * Neither the name of the copyright holder nor the names of its
# contributors may be used to endorse or promote products derived from
# this software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

# -*- coding: utf-8 -*-

from typing import Mapping, Any

import pkg_resources
from pathlib import Path

from bag.design.module import Module
from bag.design.database import ModuleDB
from bag.util.immutable import Param


# noinspection PyPep8Naming
class xbase__esd(Module):
"""Module for library xbase cell esd.
Fill in high level description here.
"""

yaml_file = pkg_resources.resource_filename(__name__,
str(Path('netlist_info',
'esd.yaml')))

def __init__(self, database: ModuleDB, params: Param, **kwargs: Any) -> None:
Module.__init__(self, self.yaml_file, database, params, **kwargs)

@classmethod
def get_params_info(cls) -> Mapping[str, str]:
"""Returns a dictionary from parameter names to descriptions.
Returns
-------
param_info : Optional[Mapping[str, str]]
dictionary from parameter names to descriptions.
"""
return dict(
esd_p='library name and cell name for esd_p.',
esd_n='library name and cell name for esd_n.',
)

def design(self, esd_p: Mapping[str, Any], esd_n: Mapping[str, Any]) -> None:
"""To be overridden by subclasses to design this module.
This method should fill in values for all parameters in
self.parameters. To design instances of this module, you can
call their design() method or any other ways you coded.
To modify schematic structure, call:
rename_pin()
delete_instance()
replace_instance_master()
reconnect_instance_terminal()
restore_instance()
array_instance()
"""
self.instances['XP'].design(**esd_p)
self.instances['XN'].design(**esd_n)
self.reconnect_instance_terminal('XN', 'VDD', 'VDD')
94 changes: 94 additions & 0 deletions src/xbase/schematic/esd_static.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
# BSD 3-Clause License
#
# Copyright (c) 2018, Regents of the University of California
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are met:
#
# * Redistributions of source code must retain the above copyright notice, this
# list of conditions and the following disclaimer.
#
# * Redistributions in binary form must reproduce the above copyright notice,
# this list of conditions and the following disclaimer in the documentation
# and/or other materials provided with the distribution.
#
# * Neither the name of the copyright holder nor the names of its
# contributors may be used to endorse or promote products derived from
# this software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

# -*- coding: utf-8 -*-

from typing import Mapping, Any

import pkg_resources
from pathlib import Path

from bag.design.module import Module
from bag.design.database import ModuleDB
from bag.util.immutable import Param


# noinspection PyPep8Naming
class xbase__esd_static(Module):
"""Module for library xbase cell esd_static.
Fill in high level description here.
"""

yaml_file = pkg_resources.resource_filename(__name__,
str(Path('netlist_info',
'esd_static.yaml')))

def __init__(self, database: ModuleDB, params: Param, **kwargs: Any) -> None:
Module.__init__(self, self.yaml_file, database, params, **kwargs)

@classmethod
def get_params_info(cls) -> Mapping[str, str]:
"""Returns a dictionary from parameter names to descriptions.
Returns
-------
param_info : Optional[Mapping[str, str]]
dictionary from parameter names to descriptions.
"""
return dict(
lib_name='Library name for the esd_static cell',
cell_name='"esd_vdd" or "esd_vss"',
)

def design(self, lib_name: str, cell_name: str) -> None:
"""To be overridden by subclasses to design this module.
This method should fill in values for all parameters in
self.parameters. To design instances of this module, you can
call their design() method or any other ways you coded.
To modify schematic structure, call:
rename_pin()
delete_instance()
replace_instance_master()
reconnect_instance_terminal()
restore_instance()
array_instance()
"""
if cell_name == 'esd_vss':
self.replace_instance_master('XESD', lib_name, cell_name, static=True, keep_connections=True)
self.reconnect_instance_terminal('XESD', 'GUARD_RING', 'VDD')
self.rename_pin('VSS', 'VDD')
elif cell_name == 'esd_vdd':
self.replace_instance_master('XESD', lib_name, cell_name, static=True, keep_connections=True)
else:
raise ValueError(f'Unknown cell_name={cell_name}. Use "esd_vdd" or "esd_vss".')
110 changes: 110 additions & 0 deletions src/xbase/schematic/mimcap.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,110 @@
# BSD 3-Clause License
#
# Copyright (c) 2018, Regents of the University of California
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are met:
#
# * Redistributions of source code must retain the above copyright notice, this
# list of conditions and the following disclaimer.
#
# * Redistributions in binary form must reproduce the above copyright notice,
# this list of conditions and the following disclaimer in the documentation
# and/or other materials provided with the distribution.
#
# * Neither the name of the copyright holder nor the names of its
# contributors may be used to endorse or promote products derived from
# this software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

# -*- coding: utf-8 -*-

from typing import Mapping, Any

import pkg_resources
from pathlib import Path

from bag.design.module import Module
from bag.design.database import ModuleDB
from bag.util.immutable import Param


# noinspection PyPep8Naming
class xbase__mimcap(Module):
"""Module for library xbase cell mimcap.
Fill in high level description here.
"""

yaml_file = pkg_resources.resource_filename(__name__,
str(Path('netlist_info',
'mimcap.yaml')))

def __init__(self, database: ModuleDB, params: Param, **kwargs: Any) -> None:
Module.__init__(self, self.yaml_file, database, params, **kwargs)

@classmethod
def get_params_info(cls) -> Mapping[str, str]:
"""Returns a dictionary from parameter names to descriptions.
Returns
-------
param_info : Optional[Mapping[str, str]]
dictionary from parameter names to descriptions.
"""
return dict(
mim_type='Type of MIM cap; standard by default',
unit_width='width of single MIM unit (for array)',
unit_height='height of single MIM unit (for array)',
num_rows='number of rows',
num_cols='number of columns',
num_dum='number of dummy units',
)

@classmethod
def get_default_param_values(cls) -> Mapping[str, Any]:
return dict(
mim_type='standard',
num_dum=0,
)

def design(self, mim_type: str, unit_width: int, unit_height: int, num_rows: int, num_cols: int, num_dum: int
) -> None:
"""To be overridden by subclasses to design this module.
This method should fill in values for all parameters in
self.parameters. To design instances of this module, you can
call their design() method or any other ways you coded.
To modify schematic structure, call:
rename_pin()
delete_instance()
replace_instance_master()
reconnect_instance_terminal()
restore_instance()
array_instance()
"""
self.instances['XCAP'].design(unit_width=unit_width, unit_height=unit_height, num_rows=num_rows,
num_cols=num_cols, intent=mim_type)
# dummies
if num_dum == 0:
self.remove_instance('XDUM')
self.remove_instance('XNC0')
self.remove_instance('XNC1')
else:
self.instances['XDUM'].design(unit_width=unit_width, unit_height=unit_height, num_rows=1,
num_cols=1, intent=mim_type)
suf = f'<{num_dum - 1}:0>' if num_dum > 1 else ''
self.rename_instance('XDUM', f'XDUM{suf}')
16 changes: 0 additions & 16 deletions src/xbase/schematic/models/current_summer.v
Original file line number Diff line number Diff line change
@@ -1,19 +1,3 @@
// SPDX-License-Identifier: Apache-2.0
// Copyright 2020 Blue Cheetah Analog Design Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//

{{ _header }}

{% for idx in range(_sch_params['nin']) %}
16 changes: 0 additions & 16 deletions src/xbase/schematic/models/esd_diode.v
Original file line number Diff line number Diff line change
@@ -1,19 +1,3 @@
// SPDX-License-Identifier: Apache-2.0
// Copyright 2020 Blue Cheetah Analog Design Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//

{{ _header }}

{% if _sch_params['dio_type'] == 'pdio' %}
16 changes: 0 additions & 16 deletions src/xbase/schematic/models/metal_short.v
Original file line number Diff line number Diff line change
@@ -1,19 +1,3 @@
// SPDX-License-Identifier: Apache-2.0
// Copyright 2020 Blue Cheetah Analog Design Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//

{{ _header }}

tran tr(PLUS, MINUS);
5 changes: 5 additions & 0 deletions src/xbase/schematic/models/momcap_core.v
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
{{ _header }}

// Intentionally nothing, since this does nothing logically.

endmodule
98 changes: 98 additions & 0 deletions src/xbase/schematic/momcap_char.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
# BSD 3-Clause License
#
# Copyright (c) 2018, Regents of the University of California
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are met:
#
# * Redistributions of source code must retain the above copyright notice, this
# list of conditions and the following disclaimer.
#
# * Redistributions in binary form must reproduce the above copyright notice,
# this list of conditions and the following disclaimer in the documentation
# and/or other materials provided with the distribution.
#
# * Neither the name of the copyright holder nor the names of its
# contributors may be used to endorse or promote products derived from
# this software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

# -*- coding: utf-8 -*-

from typing import Mapping, Any, Optional

import pkg_resources
from pathlib import Path

from bag.design.module import Module
from bag.design.database import ModuleDB
from bag.util.immutable import Param


# noinspection PyPep8Naming
class xbase__momcap_char(Module):
"""Module for library xbase cell momcap_char.
Fill in high level description here.
"""

yaml_file = pkg_resources.resource_filename(__name__,
str(Path('netlist_info',
'momcap_char.yaml')))

def __init__(self, database: ModuleDB, params: Param, **kwargs: Any) -> None:
Module.__init__(self, self.yaml_file, database, params, **kwargs)

@classmethod
def get_params_info(cls) -> Mapping[str, str]:
"""Returns a dictionary from parameter names to descriptions.
Returns
-------
param_info : Optional[Dict[str, str]]
dictionary from parameter names to descriptions.
"""
return dict(
has_res_metal='True if res_metal exists in the process',
res_p='Parameters for metal resistor on plus terminal',
res_n='Parameters for metal resistor on minus terminal',
)

@classmethod
def get_default_param_values(cls) -> Mapping[str, Any]:
return dict(res_p=None, res_n=None)

def design(self, res_p: Optional[Mapping[str, int]], res_n: Optional[Mapping[str, int]], has_res_metal: bool
) -> None:
"""To be overridden by subclasses to design this module.
This method should fill in values for all parameters in
self.parameters. To design instances of this module, you can
call their design() method or any other ways you coded.
To modify schematic structure, call:
rename_pin()
delete_instance()
replace_instance_master()
reconnect_instance_terminal()
restore_instance()
array_instance()
"""
if has_res_metal:
self.instances['XRESP'].design(**res_p)
self.instances['XRESN'].design(**res_n)
else:
self.remove_instance('XRESP')
self.remove_instance('XRESN')
21 changes: 15 additions & 6 deletions src/xbase/schematic/momcap_core.py
Original file line number Diff line number Diff line change
@@ -13,7 +13,7 @@
# See the License for the specific language governing permissions and
# limitations under the License.

from typing import Dict, Any
from typing import Mapping, Any, Optional

import os
import pkg_resources
@@ -38,7 +38,7 @@ def __init__(self, database: ModuleDB, params: Param, **kwargs: Any) -> None:
Module.__init__(self, self.yaml_file, database, params, **kwargs)

@classmethod
def get_params_info(cls) -> Dict[str, str]:
def get_params_info(cls) -> Mapping[str, str]:
"""Returns a dictionary from parameter names to descriptions.
Returns
@@ -47,11 +47,17 @@ def get_params_info(cls) -> Dict[str, str]:
dictionary from parameter names to descriptions.
"""
return dict(
has_res_metal='True if res_metal exists in the process',
res_p='Parameters for metal resistor on plus terminal',
res_n='Parameters for metal resistor on minus terminal',
)

def design(self, res_p: Dict[str, int], res_n: Dict[str, int]) -> None:
@classmethod
def get_default_param_values(cls) -> Mapping[str, Any]:
return dict(res_p=None, res_n=None)

def design(self, res_p: Optional[Mapping[str, int]], res_n: Optional[Mapping[str, int]], has_res_metal: bool
) -> None:
"""To be overridden by subclasses to design this module.
This method should fill in values for all parameters in
@@ -67,6 +73,9 @@ def design(self, res_p: Dict[str, int], res_n: Dict[str, int]) -> None:
restore_instance()
array_instance()
"""
self.instances['XRESP'].design(**res_p)
self.instances['XRESN'].design(**res_n)

if has_res_metal:
self.instances['XRESP'].design(**res_p)
self.instances['XRESN'].design(**res_n)
else:
self.remove_instance('XRESP')
self.remove_instance('XRESN')
2 changes: 2 additions & 0 deletions src/xbase/schematic/mos_char.py
Original file line number Diff line number Diff line change
@@ -74,3 +74,5 @@ def design(self, mos_type: str, w: int, lch: int, seg: int, intent: str, stack:
self.design_dummy_transistors(dum_info, 'XD', 'b', 'b')
else:
self.remove_instance('XD')
if intent.startswith('3_'):
self.remove_pin('b')
402 changes: 402 additions & 0 deletions src/xbase/schematic/netlist_info/clamp_static.symbol.yaml

Large diffs are not rendered by default.

202 changes: 202 additions & 0 deletions src/xbase/schematic/netlist_info/clamp_static.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,202 @@
lib_name: xbase
cell_name: clamp_static
view_name: schematic
bbox:
- -381
- 20
- -9
- 300
terminals:
VDD:
obj:
- 1
- inst:
lib_name: basic
cell_name: iopin
view_name: symbolr
xform:
- -320
- 150
- R0
bbox:
- -381
- 124
- -310
- 160
connections:
{}
params:
{}
is_primitive: true
attr:
layer: 229
purpose: 237
net: ""
origin:
- -345
- 150
alignment: 7
orient: R0
font: 5
height: 10
overbar: false
visible: true
drafting: true
attr_type: 0
format: 1
stype: 1
ttype: 2
VSS:
obj:
- 1
- inst:
lib_name: basic
cell_name: iopin
view_name: symbolr
xform:
- -320
- 110
- R0
bbox:
- -381
- 84
- -310
- 120
connections:
{}
params:
{}
is_primitive: true
attr:
layer: 229
purpose: 237
net: ""
origin:
- -345
- 110
alignment: 7
orient: R0
font: 5
height: 10
overbar: false
visible: true
drafting: true
attr_type: 0
format: 1
stype: 2
ttype: 2
shapes:
-
- 5
- layer: 228
purpose: 4294967295
net: VDD
points:
-
- -120
- 260
-
- -120
- 300
-
- 7
- layer: 228
purpose: 237
net: VDD
origin:
- -127
- 264
alignment: 2
orient: R90
font: 5
height: 10
overbar: false
visible: true
drafting: true
text: VDD
-
- 5
- layer: 228
purpose: 4294967295
net: VSS
points:
-
- -120
- 20
-
- -120
- 60
-
- 7
- layer: 228
purpose: 237
net: VSS
origin:
- -127
- 56
alignment: 8
orient: R90
font: 5
height: 10
overbar: false
visible: true
drafting: true
text: VSS
instances:
XCLP:
lib_name: BAG_prim
cell_name: clamp
view_name: symbol
xform:
- -200
- 60
- R0
bbox:
- -221
- 47
- -9
- 280
connections:
VDD: VDD
VSS: VSS
params:
{}
is_primitive: true
props:
connectivityLastUpdated:
- 0
- 513
instance#:
- 0
- 2
instancesLastChanged:
- 4
- time_val: 1686073096
lastSchematicExtraction:
- 4
- time_val: 1686073802
net#:
- 0
- 0
pin#:
- 0
- 3
schGeometryLastUpdated:
- 0
- 513
schGeometryVersion:
- 3
- sch.ds.gm.1.4
schXtrVersion:
- 3
- sch.10.0
app_defs:
_dbLastSavedCounter:
- 0
- 513
_dbvCvTimeStamp:
- 0
- 513
cdbRevision:
- 0
- 227612
67 changes: 39 additions & 28 deletions src/xbase/schematic/netlist_info/current_summer.symbol.yaml
Original file line number Diff line number Diff line change
@@ -1,18 +1,3 @@
# SPDX-License-Identifier: Apache-2.0
# Copyright 2020 Blue Cheetah Analog Design Inc.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

lib_name: xbase
cell_name: current_summer
view_name: symbol
@@ -48,6 +33,19 @@ terminals:
- 64
stype: 0
ttype: 1
NC:
obj:
- 0
- layer: 229
purpose: 4294967295
net: ""
bbox:
- -4
- 16
- 4
- 24
stype: 0
ttype: 2
shapes:
-
- 5
@@ -237,38 +235,51 @@ shapes:
-
- 240
- 60
-
- 7
- layer: 229
purpose: 237
net: ""
origin:
- 31
- 20
alignment: 7
orient: R0
font: 5
height: 10
overbar: false
visible: true
drafting: true
text: NC
instances:
{}
props:
pin#:
- 0
- 3
instNamePrefix:
- 3
- X
interfaceLastChanged:
- 4
- time_val: 1567702413
- time_val: 1675624946
vendorName:
- 3
- ""
partName:
- 3
- current_summer
pin#:
- 0
- 2
portOrder:
- 5
- name: ILList
bin_val: ("out" "in<1:0>")
vendorName:
- 3
- ""
bin_val: ("out" "in<1:0>" "NC")
app_defs:
_dbLastSavedCounter:
- 0
- 142
- 185
_dbvCvTimeStamp:
- 0
- 142
- 185
cdbRevision:
- 0
- 227612
cdnSPDesignMajorVersion:
- 0
- 2
147 changes: 107 additions & 40 deletions src/xbase/schematic/netlist_info/current_summer.yaml
Original file line number Diff line number Diff line change
@@ -1,25 +1,10 @@
# SPDX-License-Identifier: Apache-2.0
# Copyright 2020 Blue Cheetah Analog Design Inc.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

lib_name: xbase
cell_name: current_summer
view_name: schematic
bbox:
- 24
- -266
- 440
- 11
- -400
- 469
- -220
terminals:
in<1:0>:
@@ -100,6 +85,45 @@ terminals:
format: 1
stype: 0
ttype: 1
NC:
obj:
- 1
- inst:
lib_name: basic
cell_name: iopin
view_name: symbolr
xform:
- 130
- -310
- R0
bbox:
- 69
- -336
- 140
- -300
connections:
{}
params:
{}
is_primitive: true
attr:
layer: 229
purpose: 237
net: ""
origin:
- 105
- -310
alignment: 7
orient: R0
font: 5
height: 10
overbar: false
visible: true
drafting: true
attr_type: 0
format: 1
stype: 0
ttype: 2
shapes:
-
- 5
@@ -133,7 +157,7 @@ shapes:
- 5
- layer: 228
purpose: 4294967295
net: out
net: <*2>out
points:
-
- 400
@@ -145,7 +169,7 @@ shapes:
- 7
- layer: 228
purpose: 237
net: out
net: <*2>out
origin:
- 404
- -233
@@ -156,7 +180,35 @@ shapes:
overbar: false
visible: true
drafting: true
text: out
text: <*2>out
-
- 5
- layer: 228
purpose: 4294967295
net: NC
points:
-
- 230
- -350
-
- 230
- -310
-
- 7
- layer: 228
purpose: 237
net: NC
origin:
- 223
- -346
alignment: 2
orient: R90
font: 5
height: 10
overbar: false
visible: true
drafting: true
text: NC
instances:
XTH<1:0>:
lib_name: basic
@@ -172,46 +224,61 @@ instances:
- 404
- -220
connections:
dst: <*2>out
src: in<1:0>
dst: <*2>out
params:
{}
is_primitive: true
XNC:
lib_name: basic
cell_name: noConn
view_name: symbol
xform:
- 230
- -350
- R0
bbox:
- 220
- -400
- 240
- -346
connections:
noConn: NC
params:
{}
is_primitive: true
props:
connectivityLastUpdated:
- 0
- 318
instance#:
- 0
- 1
lastSchematicExtraction:
- 4
- time_val: 1567702604
net#:
- 0
- 0
pin#:
- 0
- 2
schGeometryLastUpdated:
- 0
- 318
- 401
schGeometryVersion:
- 3
- sch.ds.gm.1.4
lastSchematicExtraction:
- 4
- time_val: 1675624953
connectivityLastUpdated:
- 0
- 401
schXtrVersion:
- 3
- sch.10.0
net#:
- 0
- 0
pin#:
- 0
- 3
app_defs:
_dbLastSavedCounter:
- 0
- 318
- 401
_dbvCvTimeStamp:
- 0
- 318
- 401
cdbRevision:
- 0
- 227612
cdnSPDesignMajorVersion:
- 0
- 2
288 changes: 288 additions & 0 deletions src/xbase/schematic/netlist_info/esd.symbol.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,288 @@
lib_name: xbase
cell_name: esd
view_name: symbol
bbox:
- -23
- -4
- 218
- 244
terminals:
VDD:
obj:
- 0
- layer: 229
purpose: 4294967295
net: ""
bbox:
- 76
- 236
- 84
- 244
stype: 1
ttype: 2
VSS:
obj:
- 0
- layer: 229
purpose: 4294967295
net: ""
bbox:
- 76
- -4
- 84
- 4
stype: 2
ttype: 2
term:
obj:
- 0
- layer: 229
purpose: 4294967295
net: ""
bbox:
- -4
- 116
- 4
- 124
stype: 0
ttype: 2
shapes:
-
- 7
- layer: 229
purpose: 237
net: ""
origin:
- 6
- 130
alignment: 1
orient: R0
font: 5
height: 10
overbar: false
visible: true
drafting: true
text: term
-
- 7
- layer: 229
purpose: 237
net: ""
origin:
- 70
- 234
alignment: 1
orient: R270
font: 5
height: 10
overbar: false
visible: true
drafting: true
text: VDD
-
- 7
- layer: 229
purpose: 237
net: ""
origin:
- 70
- 6
alignment: 7
orient: R270
font: 5
height: 10
overbar: false
visible: true
drafting: true
text: VSS
-
- 0
- layer: 236
purpose: 4294967295
net: ""
bbox:
- 0
- 0
- 160
- 240
-
- 8
- layer: 236
purpose: 237
net: ""
origin:
- 90
- 230
alignment: 1
orient: R0
font: 5
height: 10
overbar: false
visible: true
drafting: true
text: "[@instanceName]"
evaluator: cdsNLPEvalText
-
- 8
- layer: 231
purpose: 237
net: ""
origin:
- 25
- 195
alignment: 4
orient: R0
font: 5
height: 10
overbar: false
visible: true
drafting: true
text: "[@partName]"
evaluator: cdsNLPEvalText
-
- 0
- layer: 231
purpose: 4294967295
net: ""
bbox:
- 20
- 20
- 140
- 220
-
- 5
- layer: 231
purpose: 4294967295
net: ""
points:
-
- 60
- 60
-
- 100
- 60
-
- 80
- 100
-
- 60
- 60
-
- 5
- layer: 231
purpose: 4294967295
net: ""
points:
-
- 60
- 100
-
- 100
- 100
-
- 5
- layer: 231
purpose: 4294967295
net: ""
points:
-
- 60
- 140
-
- 100
- 140
-
- 80
- 180
-
- 60
- 140
-
- 5
- layer: 231
purpose: 4294967295
net: ""
points:
-
- 60
- 180
-
- 100
- 180
-
- 5
- layer: 231
purpose: 4294967295
net: ""
points:
-
- 80
- 100
-
- 80
- 140
-
- 5
- layer: 231
purpose: 4294967295
net: ""
points:
-
- 80
- 120
-
- 0
- 120
-
- 5
- layer: 231
purpose: 4294967295
net: ""
points:
-
- 80
- 60
-
- 80
- 0
-
- 5
- layer: 231
purpose: 4294967295
net: ""
points:
-
- 80
- 180
-
- 80
- 240
instances:
{}
props:
interfaceLastChanged:
- 4
- time_val: 1624152161
partName:
- 3
- esd
pin#:
- 0
- 3
portOrder:
- 5
- name: ILList
bin_val: ("VDD" "VSS" "term")
vendorName:
- 3
- ""
app_defs:
_dbLastSavedCounter:
- 0
- 120
_dbvCvTimeStamp:
- 0
- 120
cdbRevision:
- 0
- 227612
343 changes: 343 additions & 0 deletions src/xbase/schematic/netlist_info/esd.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,343 @@
lib_name: xbase
cell_name: esd
view_name: schematic
bbox:
- -381
- -260
- 110
- 250
terminals:
VDD:
obj:
- 1
- inst:
lib_name: basic
cell_name: iopin
view_name: symbolr
xform:
- -320
- 150
- R0
bbox:
- -381
- 124
- -310
- 160
connections:
{}
params:
{}
is_primitive: true
attr:
layer: 229
purpose: 237
net: ""
origin:
- -345
- 150
alignment: 7
orient: R0
font: 5
height: 10
overbar: false
visible: true
drafting: true
attr_type: 0
format: 1
stype: 1
ttype: 2
VSS:
obj:
- 1
- inst:
lib_name: basic
cell_name: iopin
view_name: symbolr
xform:
- -320
- 110
- R0
bbox:
- -381
- 84
- -310
- 120
connections:
{}
params:
{}
is_primitive: true
attr:
layer: 229
purpose: 237
net: ""
origin:
- -345
- 110
alignment: 7
orient: R0
font: 5
height: 10
overbar: false
visible: true
drafting: true
attr_type: 0
format: 1
stype: 2
ttype: 2
term:
obj:
- 1
- inst:
lib_name: basic
cell_name: iopin
view_name: symbolr
xform:
- -320
- 50
- R0
bbox:
- -381
- 24
- -310
- 60
connections:
{}
params:
{}
is_primitive: true
attr:
layer: 229
purpose: 237
net: ""
origin:
- -345
- 50
alignment: 7
orient: R0
font: 5
height: 10
overbar: false
visible: true
drafting: true
attr_type: 0
format: 1
stype: 0
ttype: 2
shapes:
-
- 5
- layer: 228
purpose: 4294967295
net: VSS
points:
-
- 70
- 120
-
- 110
- 120
-
- 7
- layer: 228
purpose: 237
net: VSS
origin:
- 74
- 127
alignment: 2
orient: R0
font: 5
height: 10
overbar: false
visible: true
drafting: true
text: VSS
-
- 5
- layer: 228
purpose: 4294967295
net: VDD
points:
-
- 10
- 210
-
- 10
- 250
-
- 7
- layer: 228
purpose: 237
net: VDD
origin:
- 3
- 214
alignment: 2
orient: R90
font: 5
height: 10
overbar: false
visible: true
drafting: true
text: VDD
-
- 5
- layer: 228
purpose: 4294967295
net: term
points:
-
- 10
- -40
-
- 10
- 30
-
- 7
- layer: 228
purpose: 237
net: term
origin:
- 3
- 16
alignment: 8
orient: R90
font: 5
height: 10
overbar: false
visible: true
drafting: true
text: term
-
- 5
- layer: 228
purpose: 4294967295
net: VDD
points:
-
- 70
- -130
-
- 110
- -130
-
- 7
- layer: 228
purpose: 237
net: VDD
origin:
- 74
- -123
alignment: 2
orient: R0
font: 5
height: 10
overbar: false
visible: true
drafting: true
text: VDD
-
- 5
- layer: 228
purpose: 4294967295
net: VSS
points:
-
- 10
- -260
-
- 10
- -220
-
- 7
- layer: 228
purpose: 237
net: VSS
origin:
- 3
- -224
alignment: 8
orient: R90
font: 5
height: 10
overbar: false
visible: true
drafting: true
text: VSS
instances:
XN:
lib_name: xbase
cell_name: esd_static
view_name: symbol
xform:
- 70
- -220
- R90
bbox:
- -50
- -224
- 85
- -36
connections:
VSS: VDD
minus: term
plus: VSS
params:
{}
is_primitive: false
XP:
lib_name: xbase
cell_name: esd_static
view_name: symbol
xform:
- 70
- 30
- R90
bbox:
- -50
- 26
- 85
- 214
connections:
VSS: VSS
minus: VDD
plus: term
params:
{}
is_primitive: false
props:
connectivityLastUpdated:
- 0
- 309
instance#:
- 0
- 1
lastSchematicExtraction:
- 4
- time_val: 1624152287
net#:
- 0
- 0
pin#:
- 0
- 3
schGeometryLastUpdated:
- 0
- 309
schGeometryVersion:
- 3
- sch.ds.gm.1.4
schXtrVersion:
- 3
- sch.10.0
app_defs:
_dbLastSavedCounter:
- 0
- 309
_dbvCvTimeStamp:
- 0
- 309
cdbRevision:
- 0
- 227612
15 changes: 0 additions & 15 deletions src/xbase/schematic/netlist_info/esd_diode.symbol.yaml
Original file line number Diff line number Diff line change
@@ -1,18 +1,3 @@
# SPDX-License-Identifier: Apache-2.0
# Copyright 2020 Blue Cheetah Analog Design Inc.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

lib_name: xbase
cell_name: esd_diode
view_name: symbol
15 changes: 0 additions & 15 deletions src/xbase/schematic/netlist_info/esd_diode.yaml
Original file line number Diff line number Diff line change
@@ -1,18 +1,3 @@
# SPDX-License-Identifier: Apache-2.0
# Copyright 2020 Blue Cheetah Analog Design Inc.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

lib_name: xbase
cell_name: esd_diode
view_name: schematic
234 changes: 234 additions & 0 deletions src/xbase/schematic/netlist_info/esd_static.symbol.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,234 @@
lib_name: xbase
cell_name: esd_static
view_name: symbol
bbox:
- -4
- -20
- 184
- 120
terminals:
VSS:
obj:
- 0
- layer: 229
purpose: 4294967295
net: ""
bbox:
- 86
- -4
- 94
- 4
stype: 2
ttype: 2
minus:
obj:
- 0
- layer: 229
purpose: 4294967295
net: ""
bbox:
- 176
- 56
- 184
- 64
stype: 0
ttype: 2
plus:
obj:
- 0
- layer: 229
purpose: 4294967295
net: ""
bbox:
- -4
- 56
- 4
- 64
stype: 0
ttype: 2
shapes:
-
- 7
- layer: 229
purpose: 237
net: ""
origin:
- 6
- 70
alignment: 1
orient: R0
font: 5
height: 10
overbar: false
visible: true
drafting: true
text: plus
-
- 7
- layer: 229
purpose: 237
net: ""
origin:
- 76
- -10
alignment: 1
orient: R0
font: 5
height: 10
overbar: false
visible: true
drafting: true
text: VSS
-
- 7
- layer: 229
purpose: 237
net: ""
origin:
- 174
- 70
alignment: 7
orient: R0
font: 5
height: 10
overbar: false
visible: true
drafting: true
text: minus
-
- 0
- layer: 236
purpose: 4294967295
net: ""
bbox:
- 0
- 0
- 180
- 120
-
- 8
- layer: 236
purpose: 237
net: ""
origin:
- 50
- 110
alignment: 1
orient: R0
font: 5
height: 10
overbar: false
visible: true
drafting: true
text: "[@instanceName]"
evaluator: cdsNLPEvalText
-
- 8
- layer: 231
purpose: 237
net: ""
origin:
- 70
- 90
alignment: 4
orient: R0
font: 5
height: 10
overbar: false
visible: true
drafting: true
text: "[@partName]"
evaluator: cdsNLPEvalText
-
- 0
- layer: 231
purpose: 4294967295
net: ""
bbox:
- 20
- 20
- 160
- 100
-
- 5
- layer: 231
purpose: 4294967295
net: ""
points:
-
- 110
- 80
-
- 110
- 40
-
- 5
- layer: 231
purpose: 4294967295
net: ""
points:
-
- 70
- 80
-
- 70
- 40
-
- 110
- 60
-
- 70
- 80
-
- 5
- layer: 231
purpose: 4294967295
net: ""
points:
-
- 70
- 60
-
- 0
- 60
-
- 5
- layer: 231
purpose: 4294967295
net: ""
points:
-
- 110
- 60
-
- 180
- 60
instances:
{}
props:
interfaceLastChanged:
- 4
- time_val: 1612159919
partName:
- 3
- esd_static
pin#:
- 0
- 3
portOrder:
- 5
- name: ILList
bin_val: ("minus" "plus" "VSS")
vendorName:
- 3
- ""
app_defs:
_dbLastSavedCounter:
- 0
- 134
_dbvCvTimeStamp:
- 0
- 134
cdbRevision:
- 0
- 227612
267 changes: 267 additions & 0 deletions src/xbase/schematic/netlist_info/esd_static.yaml
15 changes: 0 additions & 15 deletions src/xbase/schematic/netlist_info/metal_short.symbol.yaml
15 changes: 0 additions & 15 deletions src/xbase/schematic/netlist_info/metal_short.yaml
199 changes: 199 additions & 0 deletions src/xbase/schematic/netlist_info/mimcap.symbol.yaml
388 changes: 388 additions & 0 deletions src/xbase/schematic/netlist_info/mimcap.yaml
228 changes: 228 additions & 0 deletions src/xbase/schematic/netlist_info/momcap_char.symbol.yaml
323 changes: 323 additions & 0 deletions src/xbase/schematic/netlist_info/momcap_char.yaml
148 changes: 70 additions & 78 deletions src/xbase/schematic/netlist_info/momcap_core.symbol.yaml
39 changes: 12 additions & 27 deletions src/xbase/schematic/netlist_info/momcap_core.yaml
15 changes: 0 additions & 15 deletions src/xbase/schematic/netlist_info/mos_char.symbol.yaml
15 changes: 0 additions & 15 deletions src/xbase/schematic/netlist_info/mos_char.yaml
23 changes: 4 additions & 19 deletions src/xbase/schematic/netlist_info/nmos4_analog.symbol.yaml
15 changes: 0 additions & 15 deletions src/xbase/schematic/netlist_info/nmos4_analog.yaml
58 changes: 20 additions & 38 deletions src/xbase/schematic/netlist_info/nmos4_stack.symbol.yaml
94 changes: 38 additions & 56 deletions src/xbase/schematic/netlist_info/nmos4_stack.yaml
23 changes: 4 additions & 19 deletions src/xbase/schematic/netlist_info/pmos4_analog.symbol.yaml
15 changes: 0 additions & 15 deletions src/xbase/schematic/netlist_info/pmos4_analog.yaml
58 changes: 20 additions & 38 deletions src/xbase/schematic/netlist_info/pmos4_stack.symbol.yaml
94 changes: 38 additions & 56 deletions src/xbase/schematic/netlist_info/pmos4_stack.yaml
234 changes: 234 additions & 0 deletions src/xbase/schematic/netlist_info/res_char.symbol.yaml
272 changes: 272 additions & 0 deletions src/xbase/schematic/netlist_info/res_char.yaml
216 changes: 216 additions & 0 deletions src/xbase/schematic/netlist_info/sch_template.symbol.yaml
290 changes: 290 additions & 0 deletions src/xbase/schematic/netlist_info/sch_template.yaml
18 changes: 17 additions & 1 deletion src/xbase/schematic/nmos4_analog.py
20 changes: 18 additions & 2 deletions src/xbase/schematic/nmos4_stack.py
18 changes: 17 additions & 1 deletion src/xbase/schematic/pmos4_analog.py
20 changes: 18 additions & 2 deletions src/xbase/schematic/pmos4_stack.py
98 changes: 98 additions & 0 deletions src/xbase/schematic/res_char.py
175 changes: 175 additions & 0 deletions src/xbase/schematic/sch_template.py
30 changes: 30 additions & 0 deletions src/xbase_test/layout/blackbox_test.py
116 changes: 116 additions & 0 deletions src/xbase_test/layout/mos/doublegate.py
30 changes: 26 additions & 4 deletions src/xbase_test/layout/res.py
65 changes: 65 additions & 0 deletions src/xbase_test/layout/via_test.py