c4m-flexcell 0.4.0.dev23__tar.gz → 0.4.2__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {c4m_flexcell-0.4.0.dev23 → c4m_flexcell-0.4.2}/.gitlab-ci.yml +0 -2
- {c4m_flexcell-0.4.0.dev23 → c4m_flexcell-0.4.2}/PKG-INFO +11 -6
- {c4m_flexcell-0.4.0.dev23 → c4m_flexcell-0.4.2}/README.md +7 -5
- {c4m_flexcell-0.4.0.dev23 → c4m_flexcell-0.4.2}/c4m/flexcell/activecolumnscell.py +169 -115
- {c4m_flexcell-0.4.0.dev23 → c4m_flexcell-0.4.2}/c4m/flexcell/canvas.py +11 -0
- {c4m_flexcell-0.4.0.dev23 → c4m_flexcell-0.4.2}/c4m/flexcell/factory.py +259 -178
- {c4m_flexcell-0.4.0.dev23 → c4m_flexcell-0.4.2}/c4m_flexcell.egg-info/PKG-INFO +12 -7
- c4m_flexcell-0.4.2/c4m_flexcell.egg-info/requires.txt +3 -0
- {c4m_flexcell-0.4.0.dev23 → c4m_flexcell-0.4.2}/dev-requirements.txt +1 -0
- {c4m_flexcell-0.4.0.dev23 → c4m_flexcell-0.4.2}/dodo.py +1 -1
- {c4m_flexcell-0.4.0.dev23 → c4m_flexcell-0.4.2}/setup.py +2 -2
- c4m_flexcell-0.4.0.dev23/c4m_flexcell.egg-info/requires.txt +0 -2
- {c4m_flexcell-0.4.0.dev23 → c4m_flexcell-0.4.2}/.gitignore +0 -0
- {c4m_flexcell-0.4.0.dev23 → c4m_flexcell-0.4.2}/COPYRIGHT.md +0 -0
- {c4m_flexcell-0.4.0.dev23 → c4m_flexcell-0.4.2}/LICENSE.md +0 -0
- {c4m_flexcell-0.4.0.dev23 → c4m_flexcell-0.4.2}/LICENSES/agpl-3.0.txt +0 -0
- {c4m_flexcell-0.4.0.dev23 → c4m_flexcell-0.4.2}/LICENSES/cern_ohl_s_v2.txt +0 -0
- {c4m_flexcell-0.4.0.dev23 → c4m_flexcell-0.4.2}/LICENSES/gpl-2.0.txt +0 -0
- {c4m_flexcell-0.4.0.dev23 → c4m_flexcell-0.4.2}/ReleaseNotes/v0.0.4.md +0 -0
- {c4m_flexcell-0.4.0.dev23 → c4m_flexcell-0.4.2}/ReleaseNotes/v0.1.0.md +0 -0
- {c4m_flexcell-0.4.0.dev23 → c4m_flexcell-0.4.2}/c4m/__init__.py +0 -0
- {c4m_flexcell-0.4.0.dev23 → c4m_flexcell-0.4.2}/c4m/cell_canvas.ipynb +0 -0
- {c4m_flexcell-0.4.0.dev23 → c4m_flexcell-0.4.2}/c4m/flexcell/__init__.py +0 -0
- {c4m_flexcell-0.4.0.dev23 → c4m_flexcell-0.4.2}/c4m/flexcell/_waiters.py +0 -0
- {c4m_flexcell-0.4.0.dev23 → c4m_flexcell-0.4.2}/c4m/flexcell/cell.py +0 -0
- {c4m_flexcell-0.4.0.dev23 → c4m_flexcell-0.4.2}/c4m_flexcell.egg-info/SOURCES.txt +0 -0
- {c4m_flexcell-0.4.0.dev23 → c4m_flexcell-0.4.2}/c4m_flexcell.egg-info/dependency_links.txt +0 -0
- {c4m_flexcell-0.4.0.dev23 → c4m_flexcell-0.4.2}/c4m_flexcell.egg-info/top_level.txt +0 -0
- {c4m_flexcell-0.4.0.dev23 → c4m_flexcell-0.4.2}/ci-requirements.txt +0 -0
- {c4m_flexcell-0.4.0.dev23 → c4m_flexcell-0.4.2}/run_unittests.sh +0 -0
- {c4m_flexcell-0.4.0.dev23 → c4m_flexcell-0.4.2}/setup.cfg +0 -0
|
@@ -19,7 +19,6 @@ before_script:
|
|
|
19
19
|
dist:
|
|
20
20
|
only:
|
|
21
21
|
- main
|
|
22
|
-
- dev_v0.4
|
|
23
22
|
variables:
|
|
24
23
|
TWINE_PASSWORD: '${CI_JOB_TOKEN}'
|
|
25
24
|
TWINE_USERNAME: 'gitlab-ci-token'
|
|
@@ -34,7 +33,6 @@ dist:
|
|
|
34
33
|
dist-test:
|
|
35
34
|
except:
|
|
36
35
|
- main
|
|
37
|
-
- dev_v0.4
|
|
38
36
|
script:
|
|
39
37
|
# Need to fetch tags
|
|
40
38
|
- git fetch --depth=1 origin +refs/tags/*:refs/tags/*
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: c4m_flexcell
|
|
3
|
-
Version: 0.4.
|
|
3
|
+
Version: 0.4.2
|
|
4
4
|
Summary: PDKMaster based scalable standard cell library
|
|
5
5
|
Author: Staf Verhaegen
|
|
6
6
|
Author-email: staf@fibraservi.eu
|
|
@@ -10,6 +10,9 @@ Project-URL: Bug Tracker, https://gitlab.com/Chips4Makers/c4m-flexcell/issues
|
|
|
10
10
|
Requires-Python: ~=3.6
|
|
11
11
|
Description-Content-Type: text/markdown
|
|
12
12
|
License-File: LICENSE.md
|
|
13
|
+
Requires-Dist: setuptools
|
|
14
|
+
Requires-Dist: nest-asyncio
|
|
15
|
+
Requires-Dist: PDKMaster~=0.10.0
|
|
13
16
|
|
|
14
17
|
# Flexible, scalable, standard cell library
|
|
15
18
|
|
|
@@ -19,9 +22,13 @@ Standard cells are introduced into an [ASIC](https://en.wikipedia.org/wiki/Appli
|
|
|
19
22
|
|
|
20
23
|
## Release History
|
|
21
24
|
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
+
* [v0.4.2](https://gitlab.com/Chips4Makers/c4m-flexcell/-/commits/v0.10.2): only internal
|
|
26
|
+
improvements
|
|
27
|
+
* v0.4.1:
|
|
28
|
+
major reworking of the code. A new class ActiveColumnsCell has been introduced to generate the layouts of the standard cells. This removes the lambda based dimensions from the cells to compute them all from the design rules.
|
|
29
|
+
All cells were converter to this new layout method and this should allow to make standard cell libraries with much lower height of the cells. Compatiblity function are provided so that layout spec can be derived as was done previously as based on a lambda value.
|
|
30
|
+
v0.4.0 had only dev releases and code was rebased and squashed for this release.
|
|
31
|
+
* v0.3.3: bug fix; remove public 0.3.2 release
|
|
25
32
|
* v0.3.2: code cleansing, bug fixing, update dependencies
|
|
26
33
|
* v0.3.1: small update for Coriolis export
|
|
27
34
|
* v0.3.0: Update for [release v0.9.0 of PDKMaster](https://gitlab.com/Chips4Makers/PDKMaster/-/blob/v0.9.0/ReleaseNotes/v0.9.0.md); replace Library-> StdCellFactory to follow common usage of a factory to generate cells.
|
|
@@ -39,7 +46,5 @@ In future options are planned so libraries can be generated for different target
|
|
|
39
46
|
## Status
|
|
40
47
|
|
|
41
48
|
This repository is currently considered experimental code with no backwards compatibility guarantees whatsoever.
|
|
42
|
-
This development is done in a development branch for new layout generation code.
|
|
43
|
-
When this development is done it will be released as version 0.4.0.
|
|
44
49
|
Current implementation is based on the topology of the Coriolis nsxlib standard cells with some area improvements but not yet with optimal area use. For v0.1 of this library a total replacement of the layout generation is planned fully based on minimized area for the technology design rules.
|
|
45
50
|
If interested head over to [gitter](https://gitter.im/Chips4Makers/community) for further discussion.
|
|
@@ -6,9 +6,13 @@ Standard cells are introduced into an [ASIC](https://en.wikipedia.org/wiki/Appli
|
|
|
6
6
|
|
|
7
7
|
## Release History
|
|
8
8
|
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
9
|
+
* [v0.4.2](https://gitlab.com/Chips4Makers/c4m-flexcell/-/commits/v0.10.2): only internal
|
|
10
|
+
improvements
|
|
11
|
+
* v0.4.1:
|
|
12
|
+
major reworking of the code. A new class ActiveColumnsCell has been introduced to generate the layouts of the standard cells. This removes the lambda based dimensions from the cells to compute them all from the design rules.
|
|
13
|
+
All cells were converter to this new layout method and this should allow to make standard cell libraries with much lower height of the cells. Compatiblity function are provided so that layout spec can be derived as was done previously as based on a lambda value.
|
|
14
|
+
v0.4.0 had only dev releases and code was rebased and squashed for this release.
|
|
15
|
+
* v0.3.3: bug fix; remove public 0.3.2 release
|
|
12
16
|
* v0.3.2: code cleansing, bug fixing, update dependencies
|
|
13
17
|
* v0.3.1: small update for Coriolis export
|
|
14
18
|
* v0.3.0: Update for [release v0.9.0 of PDKMaster](https://gitlab.com/Chips4Makers/PDKMaster/-/blob/v0.9.0/ReleaseNotes/v0.9.0.md); replace Library-> StdCellFactory to follow common usage of a factory to generate cells.
|
|
@@ -26,7 +30,5 @@ In future options are planned so libraries can be generated for different target
|
|
|
26
30
|
## Status
|
|
27
31
|
|
|
28
32
|
This repository is currently considered experimental code with no backwards compatibility guarantees whatsoever.
|
|
29
|
-
This development is done in a development branch for new layout generation code.
|
|
30
|
-
When this development is done it will be released as version 0.4.0.
|
|
31
33
|
Current implementation is based on the topology of the Coriolis nsxlib standard cells with some area improvements but not yet with optimal area use. For v0.1 of this library a total replacement of the layout generation is planned fully based on minimized area for the technology design rules.
|
|
32
34
|
If interested head over to [gitter](https://gitter.im/Chips4Makers/community) for further discussion.
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
# SPDX-License-Identifier: GPL-2.0-or-later OR AGPL-3.0-or-later OR CERN-OHL-S-2.0+
|
|
2
2
|
from itertools import chain
|
|
3
3
|
import abc
|
|
4
|
-
import asyncio
|
|
4
|
+
import asyncio, nest_asyncio
|
|
5
|
+
from threading import Thread
|
|
5
6
|
from typing import (
|
|
6
7
|
List, Tuple, Iterator, Optional, Union, Callable, TypeVar, Generic, cast,
|
|
7
8
|
)
|
|
@@ -1450,7 +1451,6 @@ class _Constraints:
|
|
|
1450
1451
|
|
|
1451
1452
|
# Place the poly pads that are not in a metal 1 row.
|
|
1452
1453
|
# self.log("_do_layout: calling _place_polypads")
|
|
1453
|
-
# tasks.append(asyncio.create_task(self._place_polypads_m1rows()))
|
|
1454
1454
|
tasks.extend((
|
|
1455
1455
|
asyncio.create_task(self._place_polypads_m1row(m1row=m1row))
|
|
1456
1456
|
for m1row in chain(*self.m1rows)
|
|
@@ -1492,11 +1492,6 @@ class _Constraints:
|
|
|
1492
1492
|
# self.log("_do_layout: calling _size_width")
|
|
1493
1493
|
self._size_width()
|
|
1494
1494
|
|
|
1495
|
-
# Add taps where possible
|
|
1496
|
-
# This assumes that the widht of the cell is known
|
|
1497
|
-
# self.log("_do_layout: calling _add_taps")
|
|
1498
|
-
self._add_taps()
|
|
1499
|
-
|
|
1500
1495
|
return True
|
|
1501
1496
|
|
|
1502
1497
|
def _set_transistor_nets(self) -> None:
|
|
@@ -1878,13 +1873,13 @@ class _Constraints:
|
|
|
1878
1873
|
cell = self.cell
|
|
1879
1874
|
canvas = cell.canvas
|
|
1880
1875
|
ac_canvas = cell.ac_canvas
|
|
1881
|
-
metal1 = canvas._metal1
|
|
1882
1876
|
|
|
1883
1877
|
x: Optional[float] = None
|
|
1884
1878
|
for multim1col in self.m1columns:
|
|
1885
1879
|
# self.log(f"_place_m1cols(): computing x of {multim1col.name}")
|
|
1886
1880
|
x = (
|
|
1887
|
-
|
|
1881
|
+
# First column can contact to polypad so use _firstcol_dx
|
|
1882
|
+
ac_canvas._firstcol_dx if (x is None)
|
|
1888
1883
|
else x + ac_canvas._min_m1col_pitch
|
|
1889
1884
|
)
|
|
1890
1885
|
assert not multim1col.is_placed, "Internal error"
|
|
@@ -1958,11 +1953,7 @@ class _Constraints:
|
|
|
1958
1953
|
def _size_width(self) -> None:
|
|
1959
1954
|
cell = self.cell
|
|
1960
1955
|
canvas = cell.canvas
|
|
1961
|
-
ac_canvas = cell.ac_canvas
|
|
1962
|
-
layouter = cell.layouter
|
|
1963
1956
|
|
|
1964
|
-
nimplant = canvas._nimplant
|
|
1965
|
-
pimplant = canvas._pimplant
|
|
1966
1957
|
active = canvas._active
|
|
1967
1958
|
|
|
1968
1959
|
lastcol = self.activecolumns[-1]
|
|
@@ -1974,105 +1965,14 @@ class _Constraints:
|
|
|
1974
1965
|
if nsd is not None:
|
|
1975
1966
|
lay = nsd._placed
|
|
1976
1967
|
bb = lay.bounds(mask=active.mask)
|
|
1977
|
-
min_widths.append(bb.right + 0.5*
|
|
1968
|
+
min_widths.append(bb.right + 0.5*canvas._min_active_space)
|
|
1978
1969
|
if psd is not None:
|
|
1979
1970
|
lay = psd._placed
|
|
1980
1971
|
bb = lay.bounds(mask=active.mask)
|
|
1981
|
-
min_widths.append(bb.right + 0.5*
|
|
1972
|
+
min_widths.append(bb.right + 0.5*canvas._min_active_space)
|
|
1982
1973
|
assert len(min_widths) > 0
|
|
1983
1974
|
|
|
1984
|
-
|
|
1985
|
-
|
|
1986
|
-
# Draw implants
|
|
1987
|
-
if nimplant is not None:
|
|
1988
|
-
assert canvas._min_active_nimplant_enc is not None
|
|
1989
|
-
assert canvas._min_nsd_enc is not None
|
|
1990
|
-
enc = canvas._min_active_nimplant_enc.first
|
|
1991
|
-
left = -enc
|
|
1992
|
-
right = width + enc
|
|
1993
|
-
bottom = ac_canvas._nact_bottom - canvas._min_nsd_enc.second
|
|
1994
|
-
top = canvas._well_edge_height
|
|
1995
|
-
shape = _geo.Rect(left=left, bottom=bottom, right=right, top=top)
|
|
1996
|
-
layouter.add_portless(prim=nimplant, shape=shape)
|
|
1997
|
-
# Draw implants
|
|
1998
|
-
if pimplant is not None:
|
|
1999
|
-
assert canvas._min_active_pimplant_enc is not None
|
|
2000
|
-
assert canvas._min_psd_enc is not None
|
|
2001
|
-
enc = canvas._min_active_pimplant_enc.first
|
|
2002
|
-
left = -enc
|
|
2003
|
-
right = width + enc
|
|
2004
|
-
top = ac_canvas._pact_top + canvas._min_psd_enc.second
|
|
2005
|
-
bottom = canvas._well_edge_height
|
|
2006
|
-
shape = _geo.Rect(left=left, bottom=bottom, right=right, top=top)
|
|
2007
|
-
layouter.add_portless(prim=pimplant, shape=shape)
|
|
2008
|
-
|
|
2009
|
-
def _add_taps(self) -> None:
|
|
2010
|
-
cell = self.cell
|
|
2011
|
-
tech = cell.tech
|
|
2012
|
-
canvas = cell.canvas
|
|
2013
|
-
layouter = cell.layouter
|
|
2014
|
-
|
|
2015
|
-
width = cell.width
|
|
2016
|
-
|
|
2017
|
-
pwell = canvas._pwell
|
|
2018
|
-
nwell = canvas._nwell
|
|
2019
|
-
active = canvas._active
|
|
2020
|
-
nimplant = canvas._nimplant
|
|
2021
|
-
if canvas._min_active_nimplant_enc is None:
|
|
2022
|
-
assert nimplant is None, "Internal error"
|
|
2023
|
-
nenc = None
|
|
2024
|
-
else:
|
|
2025
|
-
nenc = canvas._min_active_nimplant_enc.wide()
|
|
2026
|
-
if (nenc.first + _geo.epsilon) < 0.5*active.min_space:
|
|
2027
|
-
nenc = _prp.Enclosure((0.5*active.min_space, nenc.second))
|
|
2028
|
-
pimplant = canvas._pimplant
|
|
2029
|
-
if canvas._min_active_pimplant_enc is None:
|
|
2030
|
-
assert pimplant is None, "Internal error"
|
|
2031
|
-
penc = None
|
|
2032
|
-
else:
|
|
2033
|
-
penc = canvas._min_active_pimplant_enc.wide()
|
|
2034
|
-
if (penc.first + _geo.epsilon) < 0.5*active.min_space:
|
|
2035
|
-
penc = _prp.Enclosure((0.5*active.min_space, penc.second))
|
|
2036
|
-
active = canvas._active
|
|
2037
|
-
contact = canvas._contact
|
|
2038
|
-
|
|
2039
|
-
tap_height = tech.computed.min_width(active, up=True, min_enclosure=True)
|
|
2040
|
-
|
|
2041
|
-
# ptap
|
|
2042
|
-
act_left = 0.5*active.min_space
|
|
2043
|
-
act_right = width - act_left
|
|
2044
|
-
act_bottom = 0.5*active.min_space
|
|
2045
|
-
act_top = act_bottom + tap_height
|
|
2046
|
-
lay = layouter.add_wire(
|
|
2047
|
-
net=cell.vss, well_net=cell.pwell_net, wire=contact,
|
|
2048
|
-
bottom=active, bottom_well=pwell, bottom_enclosure="wide",
|
|
2049
|
-
bottom_implant=pimplant, bottom_implant_enclosure=penc,
|
|
2050
|
-
bottom_left=act_left, bottom_bottom=act_bottom,
|
|
2051
|
-
bottom_right=act_right, bottom_top=act_top,
|
|
2052
|
-
)
|
|
2053
|
-
if pimplant is not None:
|
|
2054
|
-
bb = lay.bounds(mask=pimplant.mask)
|
|
2055
|
-
if (bb.bottom - _geo.epsilon) > 0.0:
|
|
2056
|
-
shape = _geo.Rect.from_rect(rect=bb, bottom=0.0)
|
|
2057
|
-
layouter.add_portless(prim=pimplant, shape=shape)
|
|
2058
|
-
|
|
2059
|
-
# ntap
|
|
2060
|
-
act_left = 0.5*active.min_space
|
|
2061
|
-
act_right = width - act_left
|
|
2062
|
-
act_top = canvas._cell_height - 0.5*active.min_space
|
|
2063
|
-
act_bottom = act_top - tap_height
|
|
2064
|
-
lay = layouter.add_wire(
|
|
2065
|
-
net=cell.vdd, well_net=cell.nwell_net, wire=contact,
|
|
2066
|
-
bottom=active, bottom_well=nwell, bottom_enclosure="wide",
|
|
2067
|
-
bottom_implant=nimplant, bottom_implant_enclosure=nenc,
|
|
2068
|
-
bottom_left=act_left, bottom_bottom=act_bottom,
|
|
2069
|
-
bottom_right=act_right, bottom_top=act_top,
|
|
2070
|
-
)
|
|
2071
|
-
if nimplant is not None:
|
|
2072
|
-
bb = lay.bounds(mask=nimplant.mask)
|
|
2073
|
-
if (bb.top + _geo.epsilon) < canvas._cell_height:
|
|
2074
|
-
shape = _geo.Rect.from_rect(rect=bb, top=canvas._cell_height)
|
|
2075
|
-
layouter.add_portless(prim=nimplant, shape=shape)
|
|
1975
|
+
self.cell.set_width(min_width=max(min_widths))
|
|
2076
1976
|
|
|
2077
1977
|
def log(self, *args):
|
|
2078
1978
|
print(f"[{self.cell.name}:Constraints]", *args)
|
|
@@ -2142,8 +2042,14 @@ class _ActiveColumnsCanvas:
|
|
|
2142
2042
|
metal1, down=True, up=True, min_enclosure=True,
|
|
2143
2043
|
)
|
|
2144
2044
|
|
|
2145
|
-
dx_act = 0.5*
|
|
2045
|
+
dx_act = 0.5*canvas._min_active_space + 0.5*self._actcont_width
|
|
2146
2046
|
dx_poly = 0.5*poly.min_space + 0.5*self._polycont_width
|
|
2047
|
+
try:
|
|
2048
|
+
s = tech.computed.min_space(active, poly)
|
|
2049
|
+
except:
|
|
2050
|
+
pass
|
|
2051
|
+
else:
|
|
2052
|
+
dx_poly = max(dx_poly, -0.5*canvas._min_active_space + s + 0.5*self._polycont_width)
|
|
2147
2053
|
dx_m1 = 0.5*metal1.min_space + 0.5*self._m1col_width
|
|
2148
2054
|
self._firstcol_dx = tech.on_grid(
|
|
2149
2055
|
max(dx_act, dx_poly, dx_m1), rounding="ceiling",
|
|
@@ -2197,7 +2103,7 @@ class _ActiveColumnsCanvas:
|
|
|
2197
2103
|
)
|
|
2198
2104
|
# Min dx for gap in active
|
|
2199
2105
|
self._min_actgap_dx = tech.on_grid(
|
|
2200
|
-
0.5*(self._actcont_width +
|
|
2106
|
+
0.5*(self._actcont_width + canvas._min_active_space),
|
|
2201
2107
|
rounding="ceiling",
|
|
2202
2108
|
)
|
|
2203
2109
|
|
|
@@ -2260,22 +2166,170 @@ class _ActiveColumnsCanvas:
|
|
|
2260
2166
|
)
|
|
2261
2167
|
|
|
2262
2168
|
|
|
2263
|
-
class
|
|
2264
|
-
|
|
2169
|
+
class ActiveColumnsCellFrame(_Cell):
|
|
2170
|
+
"""Subclasses of this class need to call _draw_frame() after they have set
|
|
2171
|
+
the of the cell.
|
|
2172
|
+
"""
|
|
2173
|
+
def __init__(self, *, name: str, fab: "_scfab.StdCellFactory", draw_implants: bool=True):
|
|
2265
2174
|
super().__init__(name=name, fab=fab)
|
|
2266
2175
|
|
|
2267
2176
|
canvas = fab.canvas
|
|
2268
2177
|
if canvas._ac_canvas is None:
|
|
2269
2178
|
canvas._ac_canvas = _ActiveColumnsCanvas(fab=fab)
|
|
2270
2179
|
|
|
2271
|
-
self.
|
|
2272
|
-
|
|
2273
|
-
|
|
2274
|
-
asyncio.get_event_loop().run_until_complete(generator._do_layout())
|
|
2180
|
+
self._draw_implants = draw_implants
|
|
2181
|
+
self._vsstap_lay: Optional[_lay.LayoutT] = None
|
|
2182
|
+
self._vddtap_lay: Optional[_lay.LayoutT] = None
|
|
2275
2183
|
|
|
2276
2184
|
@property
|
|
2277
2185
|
def ac_canvas(self) -> _ActiveColumnsCanvas:
|
|
2278
2186
|
return self.canvas._ac_canvas
|
|
2187
|
+
@property
|
|
2188
|
+
def draw_implants(self) -> bool:
|
|
2189
|
+
return self._draw_implants
|
|
2190
|
+
@property
|
|
2191
|
+
def vsstap_lay(self) -> _lay.LayoutT:
|
|
2192
|
+
if self._vsstap_lay is None:
|
|
2193
|
+
raise TypeError(
|
|
2194
|
+
f"Accessing vsstap_lay on cell '{self.name}' before set_width has been called"
|
|
2195
|
+
)
|
|
2196
|
+
return self._vsstap_lay
|
|
2197
|
+
@property
|
|
2198
|
+
def vddtap_lay(self) -> _lay.LayoutT:
|
|
2199
|
+
if self._vddtap_lay is None:
|
|
2200
|
+
raise TypeError(
|
|
2201
|
+
f"Accessing vsstap_lay on cell '{self.name}' before set_width has been called"
|
|
2202
|
+
)
|
|
2203
|
+
return self._vddtap_lay
|
|
2204
|
+
|
|
2205
|
+
def set_width(self, **args) -> float:
|
|
2206
|
+
width = super().set_width(**args)
|
|
2207
|
+
|
|
2208
|
+
tech = self.tech
|
|
2209
|
+
canvas = self.canvas
|
|
2210
|
+
ac_canvas = self.ac_canvas
|
|
2211
|
+
layouter = self.layouter
|
|
2212
|
+
|
|
2213
|
+
pwell = canvas._pwell
|
|
2214
|
+
nwell = canvas._nwell
|
|
2215
|
+
active = canvas._active
|
|
2216
|
+
nimplant = canvas._nimplant
|
|
2217
|
+
if canvas._min_active_nimplant_enc is None:
|
|
2218
|
+
assert nimplant is None, "Internal error"
|
|
2219
|
+
nenc = None
|
|
2220
|
+
else:
|
|
2221
|
+
nenc = canvas._min_active_nimplant_enc.wide()
|
|
2222
|
+
if (nenc.first + _geo.epsilon) < 0.5*canvas._min_active_space:
|
|
2223
|
+
nenc = _prp.Enclosure((0.5*canvas._min_active_space, nenc.second))
|
|
2224
|
+
pimplant = canvas._pimplant
|
|
2225
|
+
if canvas._min_active_pimplant_enc is None:
|
|
2226
|
+
assert pimplant is None, "Internal error"
|
|
2227
|
+
penc = None
|
|
2228
|
+
else:
|
|
2229
|
+
penc = canvas._min_active_pimplant_enc.wide()
|
|
2230
|
+
if (penc.first + _geo.epsilon) < 0.5*canvas._min_active_space:
|
|
2231
|
+
penc = _prp.Enclosure((0.5*canvas._min_active_space, penc.second))
|
|
2232
|
+
active = canvas._active
|
|
2233
|
+
contact = canvas._contact
|
|
2234
|
+
|
|
2235
|
+
tap_height = tech.computed.min_width(active, up=True, min_enclosure=True)
|
|
2236
|
+
|
|
2237
|
+
# ptap
|
|
2238
|
+
act_left = 0.5*canvas._min_active_space
|
|
2239
|
+
act_right = width - act_left
|
|
2240
|
+
act_bottom = 0.5*canvas._min_active_space
|
|
2241
|
+
act_top = act_bottom + tap_height
|
|
2242
|
+
self._vsstap_lay = lay = layouter.add_wire(
|
|
2243
|
+
net=self.vss, well_net=self.pwell_net, wire=contact,
|
|
2244
|
+
bottom=active, bottom_well=pwell, bottom_enclosure="wide",
|
|
2245
|
+
bottom_implant=pimplant, bottom_implant_enclosure=penc,
|
|
2246
|
+
bottom_left=act_left, bottom_bottom=act_bottom,
|
|
2247
|
+
bottom_right=act_right, bottom_top=act_top,
|
|
2248
|
+
)
|
|
2249
|
+
if pimplant is not None:
|
|
2250
|
+
bb = lay.bounds(mask=pimplant.mask)
|
|
2251
|
+
args = {}
|
|
2252
|
+
if (bb.bottom - _geo.epsilon) > 0.0:
|
|
2253
|
+
args["bottom"] = 0.0
|
|
2254
|
+
if (bb.left - _geo.epsilon) > 0.0:
|
|
2255
|
+
args["left"] = 0.0
|
|
2256
|
+
args["right"] = width
|
|
2257
|
+
if args:
|
|
2258
|
+
shape = _geo.Rect.from_rect(rect=bb, **args)
|
|
2259
|
+
layouter.add_portless(prim=pimplant, shape=shape)
|
|
2260
|
+
|
|
2261
|
+
# ntap
|
|
2262
|
+
act_left = 0.5*canvas._min_active_space
|
|
2263
|
+
act_right = width - act_left
|
|
2264
|
+
act_top = canvas._cell_height - 0.5*canvas._min_active_space
|
|
2265
|
+
act_bottom = act_top - tap_height
|
|
2266
|
+
self._vddtap_lay = lay = layouter.add_wire(
|
|
2267
|
+
net=self.vdd, well_net=self.nwell_net, wire=contact,
|
|
2268
|
+
bottom=active, bottom_well=nwell, bottom_enclosure="wide",
|
|
2269
|
+
bottom_implant=nimplant, bottom_implant_enclosure=nenc,
|
|
2270
|
+
bottom_left=act_left, bottom_bottom=act_bottom,
|
|
2271
|
+
bottom_right=act_right, bottom_top=act_top,
|
|
2272
|
+
)
|
|
2273
|
+
if nimplant is not None:
|
|
2274
|
+
bb = lay.bounds(mask=nimplant.mask)
|
|
2275
|
+
args = {}
|
|
2276
|
+
if (bb.top + _geo.epsilon) < canvas._cell_height:
|
|
2277
|
+
args["top"] = canvas._cell_height
|
|
2278
|
+
if (bb.left - _geo.epsilon) > 0.0:
|
|
2279
|
+
args["left"] = 0.0
|
|
2280
|
+
args["right"] = width
|
|
2281
|
+
if args:
|
|
2282
|
+
shape = _geo.Rect.from_rect(rect=bb, **args)
|
|
2283
|
+
layouter.add_portless(prim=nimplant, shape=shape)
|
|
2284
|
+
|
|
2285
|
+
if self.draw_implants:
|
|
2286
|
+
# transistor nimplant
|
|
2287
|
+
if nimplant is not None:
|
|
2288
|
+
assert canvas._min_active_nimplant_enc is not None
|
|
2289
|
+
assert canvas._min_nsd_enc is not None
|
|
2290
|
+
enc = canvas._min_active_nimplant_enc.first
|
|
2291
|
+
left = min(0.0, 0.5*canvas._min_active_space - enc)
|
|
2292
|
+
right = max(width, width - 0.5*canvas._min_active_space + enc)
|
|
2293
|
+
bottom = ac_canvas._nact_bottom - canvas._min_nsd_enc.second
|
|
2294
|
+
top = canvas._well_edge_height
|
|
2295
|
+
shape = _geo.Rect(left=left, bottom=bottom, right=right, top=top)
|
|
2296
|
+
lay = layouter.add_portless(prim=nimplant, shape=shape)
|
|
2297
|
+
|
|
2298
|
+
# transistor pimplant
|
|
2299
|
+
if pimplant is not None:
|
|
2300
|
+
assert canvas._min_active_pimplant_enc is not None
|
|
2301
|
+
assert canvas._min_psd_enc is not None
|
|
2302
|
+
enc = canvas._min_active_pimplant_enc.first
|
|
2303
|
+
left = min(0.0, 0.5*canvas._min_active_space - enc)
|
|
2304
|
+
right = max(width, width - 0.5*canvas._min_active_space + enc)
|
|
2305
|
+
top = ac_canvas._pact_top + canvas._min_psd_enc.second
|
|
2306
|
+
bottom = canvas._well_edge_height
|
|
2307
|
+
shape = _geo.Rect(left=left, bottom=bottom, right=right, top=top)
|
|
2308
|
+
layouter.add_portless(prim=pimplant, shape=shape)
|
|
2309
|
+
|
|
2310
|
+
return width
|
|
2311
|
+
|
|
2312
|
+
|
|
2313
|
+
class ActiveColumnsCell(ActiveColumnsCellFrame, abc.ABC):
|
|
2314
|
+
def __init__(self, *, name: str, fab: "_scfab.StdCellFactory"):
|
|
2315
|
+
super().__init__(name=name, fab=fab)
|
|
2316
|
+
|
|
2317
|
+
self._waiterfab = _WaiterFactory(name=f"{name}:waiterfab")
|
|
2318
|
+
|
|
2319
|
+
generator = self.build_generator()
|
|
2320
|
+
loop = asyncio.get_event_loop()
|
|
2321
|
+
|
|
2322
|
+
if loop.is_running():
|
|
2323
|
+
class DoLayoutThread(Thread):
|
|
2324
|
+
def run(self):
|
|
2325
|
+
loop = asyncio.new_event_loop()
|
|
2326
|
+
loop.run_until_complete(generator._do_layout())
|
|
2327
|
+
|
|
2328
|
+
thread = DoLayoutThread()
|
|
2329
|
+
thread.start()
|
|
2330
|
+
thread.join()
|
|
2331
|
+
else:
|
|
2332
|
+
loop.run_until_complete(generator._do_layout())
|
|
2279
2333
|
|
|
2280
2334
|
@abc.abstractmethod
|
|
2281
2335
|
def build_generator(self) -> ConstraintsT:
|
|
@@ -163,6 +163,17 @@ class StdCellCanvas:
|
|
|
163
163
|
"Different poly wire for nmos and pmos transistor"
|
|
164
164
|
)
|
|
165
165
|
|
|
166
|
+
vs = [active.min_space]
|
|
167
|
+
if inside is not None:
|
|
168
|
+
for in_ in inside:
|
|
169
|
+
try:
|
|
170
|
+
s = tech.computed.min_space(active.in_(in_))
|
|
171
|
+
except:
|
|
172
|
+
pass
|
|
173
|
+
else:
|
|
174
|
+
vs.append(s)
|
|
175
|
+
self._min_active_space = max(vs)
|
|
176
|
+
|
|
166
177
|
self._min_active_poly_space = tech.computed.min_space(active, poly)
|
|
167
178
|
|
|
168
179
|
self._nactive = nactive = active if nimplant is None else active.in_(nimplant)
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
# SPDX-License-Identifier: GPL-2.0-or-later OR AGPL-3.0-or-later OR CERN-OHL-S-2.0+
|
|
2
2
|
from itertools import product
|
|
3
|
-
from typing import List, Tuple, Optional
|
|
3
|
+
from typing import List, Tuple, Dict, Iterable, Optional, Any, cast
|
|
4
4
|
|
|
5
|
-
from pdkmaster.technology import geometry as _geo
|
|
5
|
+
from pdkmaster.technology import property_ as _prp, geometry as _geo
|
|
6
6
|
from pdkmaster.design import (
|
|
7
|
-
circuit as _ckt, layout as _lay, library as _lbry, factory as _fab,
|
|
7
|
+
circuit as _ckt, layout as _lay, cell as _cell, library as _lbry, factory as _fab,
|
|
8
8
|
)
|
|
9
9
|
from pdkmaster.io.coriolis import CoriolisExportSpec
|
|
10
10
|
|
|
@@ -43,28 +43,48 @@ class _Fill(_Cell):
|
|
|
43
43
|
|
|
44
44
|
canvas = fab.canvas
|
|
45
45
|
|
|
46
|
+
nimplant = canvas._nimplant
|
|
47
|
+
pimplant = canvas._pimplant
|
|
48
|
+
|
|
46
49
|
self.set_width(width=width*canvas._cell_horplacement_grid)
|
|
47
50
|
|
|
51
|
+
layouter = self.layouter
|
|
52
|
+
|
|
53
|
+
if pimplant is not None:
|
|
54
|
+
shape = _geo.Rect(
|
|
55
|
+
left=0.0, right=self.width,
|
|
56
|
+
bottom=0.0, top=pimplant.min_width,
|
|
57
|
+
)
|
|
58
|
+
layouter.add_portless(prim=pimplant, shape=shape)
|
|
48
59
|
|
|
49
|
-
|
|
60
|
+
if nimplant is not None:
|
|
61
|
+
shape = _geo.Rect(
|
|
62
|
+
left=0.0, right=self.width,
|
|
63
|
+
bottom=(canvas._cell_height - nimplant.min_width),
|
|
64
|
+
top=canvas._cell_height,
|
|
65
|
+
)
|
|
66
|
+
layouter.add_portless(prim=nimplant, shape=shape)
|
|
67
|
+
|
|
68
|
+
|
|
69
|
+
class _Tie(_acc.ActiveColumnsCellFrame):
|
|
50
70
|
def __init__(self, *,
|
|
51
71
|
fab: "StdCellFactory", name: str, max_diff: bool=False, max_poly: bool=False, width: int=1,
|
|
52
72
|
):
|
|
53
73
|
if max_diff and max_poly:
|
|
54
74
|
raise ValueError("only one of max_diff and max_poly can be 'True'")
|
|
55
75
|
|
|
76
|
+
super().__init__(fab=fab, name=name, draw_implants=(not max_diff))
|
|
77
|
+
|
|
56
78
|
canvas = fab.canvas
|
|
79
|
+
ac_canvas = self.ac_canvas
|
|
57
80
|
tech = fab.tech
|
|
58
81
|
|
|
59
|
-
super().__init__(fab=fab, name=name)
|
|
60
|
-
|
|
61
82
|
cell_width = width*canvas._cell_horplacement_grid
|
|
62
83
|
self.set_width(width=cell_width)
|
|
63
84
|
|
|
64
85
|
active = canvas._active
|
|
65
86
|
nimplant = canvas._nimplant
|
|
66
87
|
pimplant = canvas._pimplant
|
|
67
|
-
nwell = canvas._nwell
|
|
68
88
|
poly = canvas._poly
|
|
69
89
|
contact = canvas._contact
|
|
70
90
|
metal1 = canvas._metal1
|
|
@@ -75,42 +95,21 @@ class _Tie(_Cell):
|
|
|
75
95
|
vdd = ckt.nets.vdd
|
|
76
96
|
vss = ckt.nets.vss
|
|
77
97
|
|
|
78
|
-
min_actwell_space = tech.computed.min_space(primitive1=active, primitive2=nwell)
|
|
79
98
|
min_actpoly_space = tech.computed.min_space(primitive1=active, primitive2=poly)
|
|
80
99
|
|
|
81
100
|
if not max_diff:
|
|
82
|
-
# vss min tap
|
|
83
|
-
l_ch = layouter.wire_layout(
|
|
84
|
-
net=vss, wire=contact, rows=canvas._min_tap_chs,
|
|
85
|
-
bottom=active, bottom_implant=pimplant, bottom_enclosure="wide",
|
|
86
|
-
)
|
|
87
|
-
impl_bb = l_ch.bounds(mask=pimplant.mask)
|
|
88
|
-
x = 0.5*cell_width
|
|
89
|
-
y = 0.5*pimplant.min_space - impl_bb.bottom
|
|
90
|
-
vss_tap_lay = layouter.place(object_=l_ch, x=x, y=y)
|
|
91
|
-
|
|
92
|
-
# vdd min tap
|
|
93
|
-
l_ch = layouter.wire_layout(
|
|
94
|
-
net=vdd, well_net=vdd, wire=contact, rows=canvas._min_tap_chs,
|
|
95
|
-
bottom=active, bottom_implant=nimplant, bottom_well=nwell,
|
|
96
|
-
bottom_enclosure="wide",
|
|
97
|
-
)
|
|
98
|
-
x = 0.5*cell_width
|
|
99
|
-
if nimplant is not None:
|
|
100
|
-
impl_bb = l_ch.bounds(mask=nimplant.mask)
|
|
101
|
-
y = canvas._cell_height - 0.5*nimplant.min_space - impl_bb.top
|
|
102
|
-
else:
|
|
103
|
-
# TODO: Proper value
|
|
104
|
-
act_bb = l_ch.bounds(mask=active.mask)
|
|
105
|
-
y = canvas._cell_height - active.min_space - act_bb.top
|
|
106
|
-
vdd_tap_lay = layouter.place(object_=l_ch, x=x, y=y)
|
|
107
|
-
|
|
108
101
|
if max_poly:
|
|
109
102
|
# Add big poly
|
|
110
|
-
vss_dio_tap_bb =
|
|
111
|
-
vdd_dio_tap_bb =
|
|
103
|
+
vss_dio_tap_bb = self.vsstap_lay.bounds(mask=active.mask)
|
|
104
|
+
vdd_dio_tap_bb = self.vddtap_lay.bounds(mask=active.mask)
|
|
112
105
|
left = 0.5*poly.min_space
|
|
113
|
-
|
|
106
|
+
try:
|
|
107
|
+
s = tech.computed.min_space(active, poly)
|
|
108
|
+
except:
|
|
109
|
+
pass
|
|
110
|
+
else:
|
|
111
|
+
left = max(left, -0.5*canvas._min_active_space + s)
|
|
112
|
+
right = cell_width - left
|
|
114
113
|
bottom = vss_dio_tap_bb.top + min_actpoly_space
|
|
115
114
|
top = vdd_dio_tap_bb.bottom - min_actpoly_space
|
|
116
115
|
layouter.add_wire(net=vss, wire=poly, shape=_geo.Rect(
|
|
@@ -134,96 +133,92 @@ class _Tie(_Cell):
|
|
|
134
133
|
rect=vss_polych_m1_bb, bottom=0.0,
|
|
135
134
|
))
|
|
136
135
|
else: # max_diff == True
|
|
137
|
-
|
|
138
|
-
|
|
136
|
+
args: Dict[str, Any]
|
|
137
|
+
|
|
138
|
+
# extend vss tap
|
|
139
|
+
top = canvas._well_edge_height - ac_canvas._min_nact_well_enclosure
|
|
140
|
+
s = 0.5*canvas._min_active_space
|
|
139
141
|
if pimplant is not None:
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
enc = act_bb.bottom - impl_bb.bottom
|
|
154
|
-
bottom = 0.5*pimplant.min_space + enc
|
|
155
|
-
top = canvas._well_edge_height - min_actwell_space
|
|
156
|
-
act_h = tech.on_grid(
|
|
157
|
-
top - bottom, mult=2, rounding="floor",
|
|
142
|
+
idx = active.implant.index(pimplant)
|
|
143
|
+
enc = active.min_implant_enclosure[idx].tall()
|
|
144
|
+
args = {"implant_enclosure": enc}
|
|
145
|
+
s = max(s, enc.first)
|
|
146
|
+
if (s - _geo.epsilon) > enc.first:
|
|
147
|
+
enc = _prp.Enclosure((s, enc.second))
|
|
148
|
+
top = min(top, canvas._well_edge_height - pimplant.min_space - enc.second)
|
|
149
|
+
else:
|
|
150
|
+
assert nimplant is not None
|
|
151
|
+
enc = None
|
|
152
|
+
args = {}
|
|
153
|
+
s = max(
|
|
154
|
+
s, tech.computed.min_space(primitive1=active, primitive2=nimplant),
|
|
158
155
|
)
|
|
156
|
+
if nimplant is not None:
|
|
157
|
+
impl_bb = self.vddtap_lay.bounds(mask=nimplant.mask)
|
|
158
|
+
ext = max(0.0, -impl_bb.left)
|
|
159
159
|
else:
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
160
|
+
assert pimplant is not None
|
|
161
|
+
ext = max(
|
|
162
|
+
0.0,
|
|
163
|
+
tech.computed.min_space(
|
|
164
|
+
primitive1=active, primitive2=pimplant
|
|
165
|
+
) - 0.5*canvas._min_active_space
|
|
165
166
|
)
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
167
|
+
act_w = cell_width - 2*ext - 2*s
|
|
168
|
+
if act_w + _geo.epsilon < active.min_width:
|
|
169
|
+
raise NotEnoughRoom(f"maximum Tie with w == {width}")
|
|
170
|
+
bottom = 0.5*canvas._min_active_space
|
|
171
|
+
shape = _geo.Rect(
|
|
172
|
+
left=0.5*(cell_width - act_w), bottom=bottom,
|
|
173
|
+
right=0.5*(cell_width + act_w), top=top,
|
|
174
|
+
)
|
|
175
|
+
layouter.add_wire(
|
|
176
|
+
net=vss, wire=active, shape=shape, implant=pimplant, **args,
|
|
171
177
|
)
|
|
172
|
-
x = 0.5*cell_width
|
|
173
|
-
if pimplant is not None:
|
|
174
|
-
impl_bb = l_ch.bounds(mask=pimplant.mask)
|
|
175
|
-
y = 0.5*pimplant.min_space - impl_bb.bottom
|
|
176
|
-
else:
|
|
177
|
-
act_bb = l_ch.bounds(mask=active.mask)
|
|
178
|
-
y = active.min_space - act_bb.bottom
|
|
179
|
-
layouter.place(object_=l_ch, x=x, y=y)
|
|
180
178
|
|
|
181
|
-
# vdd tap
|
|
182
|
-
|
|
179
|
+
# extend vdd tap
|
|
180
|
+
bottom = canvas._well_edge_height + ac_canvas._min_pact_well_enclosure
|
|
181
|
+
s = 0.5*canvas._min_active_space
|
|
183
182
|
if nimplant is not None:
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
)
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
assert
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
bottom = canvas._well_edge_height + canvas._min_active_well_enclosure
|
|
198
|
-
top = canvas._cell_height - 0.5*nimplant.min_space - enc
|
|
199
|
-
act_h = tech.on_grid(
|
|
200
|
-
top - bottom, mult=2, rounding="floor",
|
|
183
|
+
idx = active.implant.index(nimplant)
|
|
184
|
+
enc = active.min_implant_enclosure[idx].tall()
|
|
185
|
+
args = {"implant_enclosure": enc}
|
|
186
|
+
s = max(s, enc.first)
|
|
187
|
+
if (s - _geo.epsilon) > enc.first:
|
|
188
|
+
enc = _prp.Enclosure((s, enc.second))
|
|
189
|
+
bottom = max(bottom, canvas._well_edge_height + nimplant.min_space + enc.second)
|
|
190
|
+
else:
|
|
191
|
+
assert pimplant is not None
|
|
192
|
+
enc = None
|
|
193
|
+
args = {}
|
|
194
|
+
s = max(
|
|
195
|
+
s, tech.computed.min_space(primitive1=active, primitive2=pimplant),
|
|
201
196
|
)
|
|
197
|
+
if pimplant is not None:
|
|
198
|
+
impl_bb = self.vsstap_lay.bounds(mask=pimplant.mask)
|
|
199
|
+
ext = max(0.0, -impl_bb.left)
|
|
202
200
|
else:
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
201
|
+
assert nimplant is not None
|
|
202
|
+
ext = max(
|
|
203
|
+
0.0,
|
|
204
|
+
tech.computed.min_space(
|
|
205
|
+
primitive1=active, primitive2=nimplant
|
|
206
|
+
) - 0.5*canvas._min_active_space
|
|
208
207
|
)
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
208
|
+
act_w = cell_width - 2*ext - 2*s
|
|
209
|
+
if act_w + _geo.epsilon < active.min_width:
|
|
210
|
+
raise NotEnoughRoom(f"maximum Tie with w == {width}")
|
|
211
|
+
top = canvas._cell_height - 0.5*canvas._min_active_space
|
|
212
|
+
shape = _geo.Rect(
|
|
213
|
+
left=0.5*(cell_width - act_w), bottom=bottom,
|
|
214
|
+
right=0.5*(cell_width + act_w), top=top,
|
|
215
|
+
)
|
|
216
|
+
layouter.add_wire(
|
|
217
|
+
net=vdd, wire=active, shape=shape, implant=nimplant, **args,
|
|
215
218
|
)
|
|
216
|
-
x = 0.5*cell_width
|
|
217
|
-
if nimplant is not None:
|
|
218
|
-
impl_bb = l_ch.bounds(mask=nimplant.mask)
|
|
219
|
-
y = canvas._cell_height - 0.5*nimplant.min_space - impl_bb.top
|
|
220
|
-
else:
|
|
221
|
-
act_bb = l_ch.bounds(mask=active.mask)
|
|
222
|
-
y = canvas._cell_height - active.min_space - act_bb.top
|
|
223
|
-
layouter.place(object_=l_ch, x=x, y=y)
|
|
224
219
|
|
|
225
220
|
|
|
226
|
-
class _Diode(
|
|
221
|
+
class _Diode(_acc.ActiveColumnsCellFrame):
|
|
227
222
|
def __init__(self, *,
|
|
228
223
|
fab: "StdCellFactory", name: str,
|
|
229
224
|
):
|
|
@@ -239,6 +234,9 @@ class _Diode(_Cell):
|
|
|
239
234
|
nimplant = canvas._nimplant
|
|
240
235
|
pimplant = canvas._pimplant
|
|
241
236
|
nwell = canvas._nwell
|
|
237
|
+
nwell_net = self.nwell_net
|
|
238
|
+
pwell = canvas._pwell
|
|
239
|
+
pwell_net = self.pwell_net
|
|
242
240
|
contact = canvas._contact
|
|
243
241
|
metal1 = canvas._metal1
|
|
244
242
|
metal1pin = canvas._metal1pin
|
|
@@ -246,54 +244,25 @@ class _Diode(_Cell):
|
|
|
246
244
|
ckt = self.circuit
|
|
247
245
|
layouter = self._layouter
|
|
248
246
|
|
|
249
|
-
vdd = ckt.nets.vdd
|
|
250
|
-
vss = ckt.nets.vss
|
|
251
|
-
|
|
252
247
|
i_ = ckt.new_net(name="i", external=True)
|
|
253
248
|
|
|
254
249
|
min_actwell_space = tech.computed.min_space(primitive1=active, primitive2=nwell)
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
250
|
+
if nimplant is not None:
|
|
251
|
+
try:
|
|
252
|
+
s = tech.computed.min_space(primitive1=active.in_(nimplant), primitive2=nwell)
|
|
253
|
+
except:
|
|
254
|
+
pass
|
|
255
|
+
else:
|
|
256
|
+
min_actwell_space = max(min_actwell_space, s)
|
|
261
257
|
enc = active.min_substrate_enclosure
|
|
262
258
|
if enc is not None:
|
|
263
259
|
min_actwell_space = max(min_actwell_space, enc.max())
|
|
264
260
|
|
|
265
261
|
# Min active space without implants overlapping
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
net=vss, wire=contact, rows=canvas._min_tap_chs,
|
|
269
|
-
bottom=active, bottom_implant=pimplant,
|
|
270
|
-
)
|
|
271
|
-
x = 0.5*cell_width
|
|
272
|
-
if pimplant is not None:
|
|
273
|
-
impl_bb = l_ch.bounds(mask=pimplant.mask)
|
|
274
|
-
y = 0.5*pimplant.min_space - impl_bb.bottom
|
|
275
|
-
else:
|
|
276
|
-
act_bb = l_ch.bounds(mask=active.mask)
|
|
277
|
-
y = active.min_space - act_bb.bottom
|
|
278
|
-
vss_tap_lay = layouter.place(object_=l_ch, x=x, y=y)
|
|
279
|
-
vss_tap_act_bb = vss_tap_lay.bounds(mask=active.mask)
|
|
280
|
-
|
|
281
|
-
# vdd min tap
|
|
282
|
-
l_ch = layouter.wire_layout(
|
|
283
|
-
net=vdd, well_net=vdd, wire=contact, rows=canvas._min_tap_chs,
|
|
284
|
-
bottom=active, bottom_implant=nimplant, bottom_well=nwell
|
|
285
|
-
)
|
|
286
|
-
x = 0.5*cell_width
|
|
287
|
-
if nimplant is not None:
|
|
288
|
-
impl_bb = l_ch.bounds(mask=nimplant.mask)
|
|
289
|
-
y = canvas._cell_height - 0.5*nimplant.min_space - impl_bb.top
|
|
290
|
-
else:
|
|
291
|
-
act_bb = l_ch.bounds(mask=active.mask)
|
|
292
|
-
y = canvas._cell_height - active.min_space - act_bb.top
|
|
293
|
-
vdd_tap_lay = layouter.place(object_=l_ch, x=x, y=y)
|
|
294
|
-
vdd_tap_act_bb = vdd_tap_lay.bounds(mask=active.mask)
|
|
262
|
+
vss_tap_act_bb = self.vsstap_lay.bounds(mask=active.mask)
|
|
263
|
+
vdd_tap_act_bb = self.vddtap_lay.bounds(mask=active.mask)
|
|
295
264
|
|
|
296
|
-
#
|
|
265
|
+
# ndiode
|
|
297
266
|
bottom = max(
|
|
298
267
|
vss_tap_act_bb.top + canvas._min_nactive_pactive_space_maxenc,
|
|
299
268
|
canvas._m1_vssrail_width + metal1.min_space,
|
|
@@ -303,12 +272,13 @@ class _Diode(_Cell):
|
|
|
303
272
|
vss_dio_x = 0.5*cell_width
|
|
304
273
|
vss_dio_y = bottom + 0.5*h
|
|
305
274
|
vss_dio_lay = layouter.add_wire(
|
|
306
|
-
net=
|
|
275
|
+
net=i_, well_net=pwell_net, wire=contact,
|
|
276
|
+
bottom=active, bottom_implant=nimplant, bottom_well=pwell,
|
|
307
277
|
x=vss_dio_x, y=vss_dio_y, bottom_height=h, top_height=h,
|
|
308
278
|
)
|
|
309
279
|
vss_dio_m1_bb = vss_dio_lay.bounds(mask=metal1.mask)
|
|
310
280
|
|
|
311
|
-
#
|
|
281
|
+
# pdiode
|
|
312
282
|
bottom = canvas._well_edge_height + canvas._min_active_well_enclosure
|
|
313
283
|
top = min(
|
|
314
284
|
vdd_tap_act_bb.bottom - canvas._min_nactive_pactive_space_maxenc,
|
|
@@ -318,7 +288,7 @@ class _Diode(_Cell):
|
|
|
318
288
|
vdd_dio_x = 0.5*cell_width
|
|
319
289
|
vdd_dio_y = top - 0.5*h
|
|
320
290
|
vdd_dio_lay = layouter.add_wire(
|
|
321
|
-
net=
|
|
291
|
+
net=i_, well_net=nwell_net, wire=contact,
|
|
322
292
|
bottom=active, bottom_implant=pimplant, bottom_well=nwell,
|
|
323
293
|
x=vdd_dio_x, y=vdd_dio_y, bottom_height=h, top_height=h,
|
|
324
294
|
)
|
|
@@ -1805,19 +1775,33 @@ class _Xor2(_acc.ActiveColumnsCell):
|
|
|
1805
1775
|
name="q_pin", elements=(q_m1knot0, q_m1knot1), top=net1_psd0,
|
|
1806
1776
|
)
|
|
1807
1777
|
|
|
1778
|
+
i1_nmos0: Optional[_acc.NMOST] = None
|
|
1779
|
+
i1_nmos0pad: Optional[_acc.PolyContactT] = None
|
|
1780
|
+
i1_nmospad: Optional[_acc.PolyContactT] = None
|
|
1781
|
+
i1_pmos0: Optional[_acc.PMOST] = None
|
|
1782
|
+
i1_pmos0pad: Optional[_acc.PolyContactT] = None
|
|
1783
|
+
i1_n_nmos: Optional[_acc.NMOST] = None
|
|
1784
|
+
i1_n_nmospad: Optional[_acc.PolyContactT] = None
|
|
1785
|
+
i1_n_pmos: Optional[_acc.PMOST] = None
|
|
1786
|
+
i1_n_pmospad: Optional[_acc.PolyContactT] = None
|
|
1787
|
+
i1_nmosrow0: Optional[_acc.PolyRowT] = None
|
|
1788
|
+
i1_nmosrow1: Optional[_acc.PolyRowT] = None
|
|
1789
|
+
i1_pmosrow0: Optional[_acc.PolyRowT] = None
|
|
1790
|
+
i1_pmosrow1: Optional[_acc.PolyRowT] = None
|
|
1791
|
+
|
|
1808
1792
|
if not self.inverted:
|
|
1809
1793
|
i1_nmos0 = self.nmos(name="i1_nmos0", net=i1, w_size="min")
|
|
1810
1794
|
i1_nmos0pad = self.polypad(
|
|
1811
1795
|
name="i1_nmos0pad", net=i1, left=(i0_pass0, q_pin),
|
|
1812
1796
|
)
|
|
1813
|
-
|
|
1797
|
+
i1_nmosrow0 = self.polyrow(
|
|
1814
1798
|
name="i1_nmos0row", elements=(i1_nmos0pad, i1_nmos0),
|
|
1815
1799
|
)
|
|
1816
1800
|
i1_n_pmos = self.pmos(name="i1_n_pmos", net=_i1_n, w_size="min")
|
|
1817
1801
|
i1_n_pmospad = self.polypad(
|
|
1818
1802
|
name="i1_n_pmospad", net=_i1_n, left=(i0_pass0, q_pin),
|
|
1819
1803
|
)
|
|
1820
|
-
|
|
1804
|
+
i1_pmosrow0 = self.polyrow(
|
|
1821
1805
|
name="i1_n_pmosrow", elements=(i1_n_pmospad, i1_n_pmos),
|
|
1822
1806
|
)
|
|
1823
1807
|
i1_pass0 = self.activecolumn(
|
|
@@ -1828,20 +1812,19 @@ class _Xor2(_acc.ActiveColumnsCell):
|
|
|
1828
1812
|
i1_n_nmospad = self.polypad(
|
|
1829
1813
|
name="i1_n_nmospad", net=_i1_n, left=(i0_pass0, q_pin),
|
|
1830
1814
|
)
|
|
1831
|
-
|
|
1815
|
+
i1_nmosrow0 = self.polyrow(
|
|
1832
1816
|
name="i1_n_nmosrow", elements=(i1_n_nmospad, i1_n_nmos)
|
|
1833
1817
|
)
|
|
1834
1818
|
i1_pmos0 = self.pmos(name="i1_pmos0", net=i1, w_size="min")
|
|
1835
1819
|
i1_pmos0pad = self.polypad(
|
|
1836
1820
|
name="i1_pmos0pad", net=i1, left=(i0_pass0, q_pin),
|
|
1837
1821
|
)
|
|
1838
|
-
|
|
1822
|
+
i1_pmosrow0 = self.polyrow(
|
|
1839
1823
|
name="i1_pmos0row", elements=(i1_pmos0pad, i1_pmos0),
|
|
1840
1824
|
)
|
|
1841
1825
|
i1_pass0 = self.activecolumn(
|
|
1842
1826
|
name="i1_pass0", connect=False, elements=(i1_n_nmos, i1_pmos0),
|
|
1843
1827
|
)
|
|
1844
|
-
|
|
1845
1828
|
q_nsd = self.signal_nsd(name="q_nsd", net=q, with_contact=True)
|
|
1846
1829
|
q_psd = self.signal_psd(name="q_psd", net=q, with_contact=False)
|
|
1847
1830
|
q_nsdrow = self.m1row(name="q_nsdrow", elements=(q_m1knot0, q_nsd))
|
|
@@ -1868,6 +1851,8 @@ class _Xor2(_acc.ActiveColumnsCell):
|
|
|
1868
1851
|
i1_n_pad0 = self.polypad(name="i1_n_pad0", net=_i1_n, left=i0_n_pass)
|
|
1869
1852
|
i1_n_m1knot = self.m1knot(name="i1_n_m1knot", net=_i1_n)
|
|
1870
1853
|
if not self.inverted:
|
|
1854
|
+
assert i1_n_pmospad is not None, "Internal error"
|
|
1855
|
+
|
|
1871
1856
|
i1_n_nmos = self.nmos(name="i1_n_nmos", net=_i1_n, w_size="min")
|
|
1872
1857
|
i1_n_m1row = self.m1row(
|
|
1873
1858
|
name="i1_n_m1row", elements=(i1_n_pmospad, i1_n_m1knot),
|
|
@@ -1880,6 +1865,8 @@ class _Xor2(_acc.ActiveColumnsCell):
|
|
|
1880
1865
|
name="i1_pass1", connect=False, elements=(i1_n_nmos, i1_pmos0),
|
|
1881
1866
|
)
|
|
1882
1867
|
else:
|
|
1868
|
+
assert i1_n_nmospad is not None, "Internal error"
|
|
1869
|
+
|
|
1883
1870
|
i1_nmos0 = self.nmos(name="i1_nmos0", net=i1, w_size="min")
|
|
1884
1871
|
i1_nmospad = self.polypad(name="i1_nmospad", net=i1)
|
|
1885
1872
|
i1_n_m1row = self.m1row(
|
|
@@ -1902,24 +1889,31 @@ class _Xor2(_acc.ActiveColumnsCell):
|
|
|
1902
1889
|
i1_nmos1 = self.nmos(name="i1_nmos1", net=i1, w_size="min")
|
|
1903
1890
|
i1_pmos1 = self.pmos(name="i1_pmos1", net=i1, w_size="min")
|
|
1904
1891
|
if not self.inverted:
|
|
1892
|
+
assert i1_pmos0 is not None
|
|
1893
|
+
assert i1_nmos0pad is not None
|
|
1894
|
+
|
|
1905
1895
|
i1_nmos1pad = self.polypad(name="i1_nmos1pad", net=i1, left=i1_pass1)
|
|
1906
1896
|
i1_nmos1knot = self.m1knot(name="i1_nmos1knot", net=i1)
|
|
1907
|
-
|
|
1897
|
+
i1_nmosrow1 = self.polyrow(name="i1_nmos1row", elements=(i1_nmos1pad, i1_nmos1))
|
|
1908
1898
|
i1_m1row = self.m1row(
|
|
1909
1899
|
name="i1_m1row", elements=(i1_nmos0pad, i1_nmos1knot),
|
|
1910
1900
|
)
|
|
1911
1901
|
i1_pmospad = self.polypad(name="i1_pmospad", net=i1)
|
|
1912
|
-
|
|
1902
|
+
i1_pmosrow1 = self.polyrow(
|
|
1913
1903
|
name="i1_pmosrow", elements=(i1_pmos0, i1_pmospad, i1_pmos1),
|
|
1914
1904
|
)
|
|
1915
1905
|
i1_pin = self.m1pin(name="i1_pin", elements=(i1_nmos1pad, i1_nmos1knot, i1_pmospad))
|
|
1916
1906
|
else:
|
|
1917
|
-
|
|
1907
|
+
assert i1_nmos0 is not None
|
|
1908
|
+
assert i1_nmospad is not None
|
|
1909
|
+
assert i1_pmos0pad is not None
|
|
1910
|
+
|
|
1911
|
+
i1_nmosrow1 = self.polyrow(
|
|
1918
1912
|
name="i1_nmosrow", elements=(i1_nmos0, i1_nmospad, i1_nmos1),
|
|
1919
1913
|
)
|
|
1920
1914
|
i1_pmos1pad = self.polypad(name="i1_pmos1pad", net=i1, left=i1_pass1)
|
|
1921
1915
|
i1_pmos1knot = self.m1knot(name="i1_pmos1knot", net=i1)
|
|
1922
|
-
|
|
1916
|
+
i1_pmosrow1 = self.polyrow(name="i1_pmos1row", elements=(i1_pmos1pad, i1_pmos1))
|
|
1923
1917
|
i1_m1row = self.m1row(
|
|
1924
1918
|
name="i1_m1row", elements=(i1_pmos0pad, i1_pmos1knot),
|
|
1925
1919
|
)
|
|
@@ -1929,15 +1923,14 @@ class _Xor2(_acc.ActiveColumnsCell):
|
|
|
1929
1923
|
name="i1_inv", connect=False, elements=(i1_nmos1, i1_pmos1),
|
|
1930
1924
|
)
|
|
1931
1925
|
|
|
1926
|
+
|
|
1932
1927
|
i1_n_nsd = self.signal_nsd(name="i1_n_nsd", net=_i1_n, with_contact=True)
|
|
1933
1928
|
i1_n_psd = self.signal_psd(name="i1_n_psd", net=_i1_n, with_contact=True)
|
|
1934
1929
|
i1_n_pad = self.polypad(name="i1_n_pad", net=_i1_n)
|
|
1930
|
+
mos = i1_n_nmos if not self.inverted else i1_n_pmos
|
|
1931
|
+
assert mos is not None
|
|
1935
1932
|
i1_n_polyrow = self.polyrow(
|
|
1936
|
-
name="i1_n_polyrow", elements=(
|
|
1937
|
-
i1_n_pad0,
|
|
1938
|
-
i1_n_nmos if not self.inverted else i1_n_pmos,
|
|
1939
|
-
i1_n_pad,
|
|
1940
|
-
),
|
|
1933
|
+
name="i1_n_polyrow", elements=(i1_n_pad0, mos, i1_n_pad),
|
|
1941
1934
|
)
|
|
1942
1935
|
i1_n_m1col1 = self.m1column(
|
|
1943
1936
|
name="i1_n_m1col1", elements=(i1_n_nsd, i1_n_pad, i1_n_psd),
|
|
@@ -1955,18 +1948,15 @@ class _Xor2(_acc.ActiveColumnsCell):
|
|
|
1955
1948
|
i1_inv, i1_n_sds,
|
|
1956
1949
|
),
|
|
1957
1950
|
polyrows=(
|
|
1958
|
-
self.multipolyrow(
|
|
1959
|
-
i0_nmosrow,
|
|
1960
|
-
|
|
1961
|
-
i1_nmos1row if not self.inverted else i1_nmosrow,
|
|
1962
|
-
)),
|
|
1951
|
+
self.multipolyrow(
|
|
1952
|
+
name="nmos_multirow", rows=(i0_nmosrow, i1_nmosrow0, i1_nmosrow1),
|
|
1953
|
+
),
|
|
1963
1954
|
self.multipolyrow(name="conn_multirow", rows=(
|
|
1964
1955
|
i0_n_polyrow, i1_n_polyrow,
|
|
1965
1956
|
)),
|
|
1966
|
-
|
|
1957
|
+
i1_pmosrow0.multipolyrow,
|
|
1967
1958
|
self.multipolyrow(name="pmos_multirow", rows=(
|
|
1968
|
-
i0_pmosrow,
|
|
1969
|
-
i1_pmosrow if not self.inverted else i1_pmos1row,
|
|
1959
|
+
i0_pmosrow, i1_pmosrow1,
|
|
1970
1960
|
)),
|
|
1971
1961
|
),
|
|
1972
1962
|
m1rows=(
|
|
@@ -3171,6 +3161,93 @@ class _DFFnR(_acc.ActiveColumnsCell):
|
|
|
3171
3161
|
)
|
|
3172
3162
|
|
|
3173
3163
|
|
|
3164
|
+
class _Gallery(_fab.FactoryCell["StdCellFactory"]):
|
|
3165
|
+
def __init__(self, *, name: str, fab: "StdCellFactory", cells: Iterable[_cell.Cell]):
|
|
3166
|
+
cells = tuple(cells)
|
|
3167
|
+
|
|
3168
|
+
canvas = fab.canvas
|
|
3169
|
+
|
|
3170
|
+
super().__init__(name=name, fab=fab)
|
|
3171
|
+
|
|
3172
|
+
ckt = self.new_circuit()
|
|
3173
|
+
layouter = self.new_circuitlayouter()
|
|
3174
|
+
|
|
3175
|
+
l = len(cells)
|
|
3176
|
+
|
|
3177
|
+
cells2 = tuple(reversed(cells))
|
|
3178
|
+
|
|
3179
|
+
# Make a shuffled row of cells for more DRC checking
|
|
3180
|
+
def shuffled_i(i: int) -> int:
|
|
3181
|
+
is_odd = (i%2) == 1
|
|
3182
|
+
if not is_odd:
|
|
3183
|
+
return l - (i//2) - 1
|
|
3184
|
+
else:
|
|
3185
|
+
return (i//2)
|
|
3186
|
+
cells3 = tuple(cells[shuffled_i(i)] for i in range(l))
|
|
3187
|
+
|
|
3188
|
+
vss_ports = []
|
|
3189
|
+
vdd_ports = []
|
|
3190
|
+
x0 = x1 = x2 = 0.0
|
|
3191
|
+
for i, cell in enumerate(cells):
|
|
3192
|
+
inst = ckt.instantiate(cell, name=f"{cell.name}[0]")
|
|
3193
|
+
|
|
3194
|
+
for port in inst.ports:
|
|
3195
|
+
if port.name == "vss":
|
|
3196
|
+
vss_ports.append(port)
|
|
3197
|
+
elif port.name == "vdd":
|
|
3198
|
+
vdd_ports.append(port)
|
|
3199
|
+
else:
|
|
3200
|
+
ckt.new_net(
|
|
3201
|
+
name=f"{inst.name}.{port,name}", external=False, childports=port,
|
|
3202
|
+
)
|
|
3203
|
+
|
|
3204
|
+
layouter.place(inst, x=x0, y=0.0)
|
|
3205
|
+
x0 += cast(_Cell, cell).width
|
|
3206
|
+
|
|
3207
|
+
cell2 = cells2[i]
|
|
3208
|
+
inst = ckt.instantiate(cell2, name=f"{cell2.name}[1]")
|
|
3209
|
+
|
|
3210
|
+
for port in inst.ports:
|
|
3211
|
+
if port.name == "vss":
|
|
3212
|
+
vss_ports.append(port)
|
|
3213
|
+
elif port.name == "vdd":
|
|
3214
|
+
vdd_ports.append(port)
|
|
3215
|
+
else:
|
|
3216
|
+
ckt.new_net(
|
|
3217
|
+
name=f"{inst.name}.{port,name}", external=False, childports=port,
|
|
3218
|
+
)
|
|
3219
|
+
|
|
3220
|
+
layouter.place(inst, x=x1, y=0.0, rotation=_geo.Rotation.MX)
|
|
3221
|
+
x1 += cast(_Cell, cell2).width
|
|
3222
|
+
|
|
3223
|
+
cell3 = cells3[i]
|
|
3224
|
+
inst = ckt.instantiate(cell3, name=f"{cell3.name}[2]")
|
|
3225
|
+
|
|
3226
|
+
for port in inst.ports:
|
|
3227
|
+
if port.name == "vss":
|
|
3228
|
+
vss_ports.append(port)
|
|
3229
|
+
elif port.name == "vdd":
|
|
3230
|
+
vdd_ports.append(port)
|
|
3231
|
+
else:
|
|
3232
|
+
ckt.new_net(
|
|
3233
|
+
name=f"{inst.name}.{port,name}", external=False, childports=port,
|
|
3234
|
+
)
|
|
3235
|
+
|
|
3236
|
+
layouter.place(inst, x=x2, y=2*canvas._cell_height, rotation=_geo.Rotation.MX)
|
|
3237
|
+
x2 += cast(_Cell, cell3).width
|
|
3238
|
+
|
|
3239
|
+
ckt.new_net(name="vss", external=True, childports=vss_ports)
|
|
3240
|
+
ckt.new_net(name="vdd", external=True, childports=vdd_ports)
|
|
3241
|
+
|
|
3242
|
+
# Set boundary
|
|
3243
|
+
assert abs(x0 - x1) < _geo.epsilon, "Internal error"
|
|
3244
|
+
assert abs(x0 - x2) < _geo.epsilon, "Internal error"
|
|
3245
|
+
layouter.layout.boundary = _geo.Rect(
|
|
3246
|
+
left=0.0, bottom=-canvas._cell_height,
|
|
3247
|
+
right=x0, top=2*canvas._cell_height,
|
|
3248
|
+
)
|
|
3249
|
+
|
|
3250
|
+
|
|
3174
3251
|
class StdCellFactory(_fab.CellFactory[_Cell]):
|
|
3175
3252
|
def __init__(self, *,
|
|
3176
3253
|
lib: _lbry.RoutingGaugeLibrary, cktfab: _ckt.CircuitFactory,
|
|
@@ -3208,6 +3285,7 @@ class StdCellFactory(_fab.CellFactory[_Cell]):
|
|
|
3208
3285
|
self.add_xors()
|
|
3209
3286
|
self.add_latches()
|
|
3210
3287
|
self.add_flops()
|
|
3288
|
+
self.add_gallery()
|
|
3211
3289
|
|
|
3212
3290
|
def add_fillers(self):
|
|
3213
3291
|
"""Add a set of fill cells to the library.
|
|
@@ -3301,3 +3379,6 @@ class StdCellFactory(_fab.CellFactory[_Cell]):
|
|
|
3301
3379
|
def add_flops(self):
|
|
3302
3380
|
self.new_cell(name="dff_x1", cell_class=_DFF, drive=1)
|
|
3303
3381
|
self.new_cell(name="dffnr_x1", cell_class=_DFFnR, drive=1)
|
|
3382
|
+
|
|
3383
|
+
def add_gallery(self):
|
|
3384
|
+
self.new_cell(name="Gallery", cell_class=_Gallery, cells=self.lib.cells)
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
|
-
Name:
|
|
3
|
-
Version: 0.4.
|
|
2
|
+
Name: c4m_flexcell
|
|
3
|
+
Version: 0.4.2
|
|
4
4
|
Summary: PDKMaster based scalable standard cell library
|
|
5
5
|
Author: Staf Verhaegen
|
|
6
6
|
Author-email: staf@fibraservi.eu
|
|
@@ -10,6 +10,9 @@ Project-URL: Bug Tracker, https://gitlab.com/Chips4Makers/c4m-flexcell/issues
|
|
|
10
10
|
Requires-Python: ~=3.6
|
|
11
11
|
Description-Content-Type: text/markdown
|
|
12
12
|
License-File: LICENSE.md
|
|
13
|
+
Requires-Dist: setuptools
|
|
14
|
+
Requires-Dist: nest-asyncio
|
|
15
|
+
Requires-Dist: PDKMaster~=0.10.0
|
|
13
16
|
|
|
14
17
|
# Flexible, scalable, standard cell library
|
|
15
18
|
|
|
@@ -19,9 +22,13 @@ Standard cells are introduced into an [ASIC](https://en.wikipedia.org/wiki/Appli
|
|
|
19
22
|
|
|
20
23
|
## Release History
|
|
21
24
|
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
+
* [v0.4.2](https://gitlab.com/Chips4Makers/c4m-flexcell/-/commits/v0.10.2): only internal
|
|
26
|
+
improvements
|
|
27
|
+
* v0.4.1:
|
|
28
|
+
major reworking of the code. A new class ActiveColumnsCell has been introduced to generate the layouts of the standard cells. This removes the lambda based dimensions from the cells to compute them all from the design rules.
|
|
29
|
+
All cells were converter to this new layout method and this should allow to make standard cell libraries with much lower height of the cells. Compatiblity function are provided so that layout spec can be derived as was done previously as based on a lambda value.
|
|
30
|
+
v0.4.0 had only dev releases and code was rebased and squashed for this release.
|
|
31
|
+
* v0.3.3: bug fix; remove public 0.3.2 release
|
|
25
32
|
* v0.3.2: code cleansing, bug fixing, update dependencies
|
|
26
33
|
* v0.3.1: small update for Coriolis export
|
|
27
34
|
* v0.3.0: Update for [release v0.9.0 of PDKMaster](https://gitlab.com/Chips4Makers/PDKMaster/-/blob/v0.9.0/ReleaseNotes/v0.9.0.md); replace Library-> StdCellFactory to follow common usage of a factory to generate cells.
|
|
@@ -39,7 +46,5 @@ In future options are planned so libraries can be generated for different target
|
|
|
39
46
|
## Status
|
|
40
47
|
|
|
41
48
|
This repository is currently considered experimental code with no backwards compatibility guarantees whatsoever.
|
|
42
|
-
This development is done in a development branch for new layout generation code.
|
|
43
|
-
When this development is done it will be released as version 0.4.0.
|
|
44
49
|
Current implementation is based on the topology of the Coriolis nsxlib standard cells with some area improvements but not yet with optimal area use. For v0.1 of this library a total replacement of the layout generation is planned fully based on minimized area for the technology design rules.
|
|
45
50
|
If interested head over to [gitter](https://gitter.im/Chips4Makers/community) for further discussion.
|
|
@@ -86,7 +86,7 @@ def task_install():
|
|
|
86
86
|
|
|
87
87
|
return {
|
|
88
88
|
"title": lambda _: "Installing python module",
|
|
89
|
-
"file_dep": c4m_py_files,
|
|
89
|
+
"file_dep": (top_dir.joinpath("setup.py"), *c4m_py_files),
|
|
90
90
|
"targets": (flexcell_inst_dir,),
|
|
91
91
|
"actions": (
|
|
92
92
|
f"{pip} install --no-deps {top_dir}",
|
|
@@ -5,7 +5,7 @@ def local_scheme(version):
|
|
|
5
5
|
if version.tag and not version.distance:
|
|
6
6
|
return version.format_with("")
|
|
7
7
|
else:
|
|
8
|
-
return version.format_choice("", "+{node}.dirty")
|
|
8
|
+
return version.format_choice("+{node}", "+{node}.dirty")
|
|
9
9
|
|
|
10
10
|
# Don't seem to have much success with exclude parameter of find_packages()
|
|
11
11
|
_packages = list(filter(lambda pkg: pkg[:4] != "test", find_packages()))
|
|
@@ -28,7 +28,7 @@ setup(
|
|
|
28
28
|
license="GPL-2.0-or-later OR AGPL-3.0-or-later OR CERN-OHL-S-2.0+",
|
|
29
29
|
python_requires="~=3.6",
|
|
30
30
|
setup_requires=["setuptools_scm"],
|
|
31
|
-
install_requires=["setuptools", "PDKMaster~=0.
|
|
31
|
+
install_requires=["setuptools", "nest-asyncio", "PDKMaster~=0.10.0"],
|
|
32
32
|
include_package_data=True,
|
|
33
33
|
packages=_packages,
|
|
34
34
|
project_urls={
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|