@@ -19,6 +19,18 @@ use crate::constants::{
19
19
use crate :: Sky130Pdk ;
20
20
21
21
impl Sky130Pdk {
22
+ /// Fold MOS devices to avoid MOS devices wider than 100 microns.
23
+ pub fn fold_mos ( w : i64 ) -> Vec < i64 > {
24
+ let grid_w = w / 5 ;
25
+ const MAX_WIDTH : i64 = 100_000 ;
26
+ let n = grid_w / MAX_WIDTH + 1 ;
27
+ let div = grid_w / n;
28
+ let rem = grid_w % n;
29
+ let mut out = vec ! [ 5 * ( div + 1 ) ; rem as usize ] ;
30
+ out. extend ( vec ! [ 5 * div; ( n - rem) as usize ] ) ;
31
+ out
32
+ }
33
+
22
34
pub fn mos_layout ( ctx : & mut LayoutCtx , params : & LayoutMosParams ) -> Result < ( ) > {
23
35
params. validate ( ) ?;
24
36
@@ -48,60 +60,64 @@ impl Sky130Pdk {
48
60
let mut prev_nsdm: Option < Rect > = None ;
49
61
50
62
for d in params. devices . iter ( ) {
51
- if let Some ( mt) = prev {
52
- if mt != d. kind ( & ctx. mos_db ( ) ) {
53
- cx += DIFF_TO_OPPOSITE_DIFF ;
54
- } else {
55
- cx += DIFF_SPACE ;
63
+ let mut d_diff_xs = Vec :: new ( ) ;
64
+ for w in Self :: fold_mos ( d. w ) {
65
+ if let Some ( mt) = prev {
66
+ if mt != d. kind ( & ctx. mos_db ( ) ) {
67
+ cx += DIFF_TO_OPPOSITE_DIFF ;
68
+ } else {
69
+ cx += DIFF_SPACE ;
70
+ }
56
71
}
57
- }
58
72
59
- diff_xs . push ( cx) ;
73
+ d_diff_xs . push ( cx) ;
60
74
61
- let rect = Rect :: new ( Point :: new ( cx, y0) , Point :: new ( cx + d . w , y0 + diff_perp) ) ;
75
+ let rect = Rect :: new ( Point :: new ( cx, y0) , Point :: new ( cx + w, y0 + diff_perp) ) ;
62
76
63
- if d. kind ( & ctx. mos_db ( ) ) == MosKind :: Pmos {
64
- let mut psdm_box = rect;
65
- psdm_box = psdm_box. expand ( DIFF_PSDM_ENCLOSURE ) ;
77
+ if d. kind ( & ctx. mos_db ( ) ) == MosKind :: Pmos {
78
+ let mut psdm_box = rect;
79
+ psdm_box = psdm_box. expand ( DIFF_PSDM_ENCLOSURE ) ;
66
80
67
- let psdm = layers. get ( Selector :: Name ( "psdm" ) ) ?;
81
+ let psdm = layers. get ( Selector :: Name ( "psdm" ) ) ?;
68
82
69
- if let Some ( prev_psdm) = prev_psdm {
70
- psdm_box = psdm_box. union ( prev_psdm. into ( ) ) . into_rect ( ) ;
71
- }
83
+ if let Some ( prev_psdm) = prev_psdm {
84
+ psdm_box = psdm_box. union ( prev_psdm. into ( ) ) . into_rect ( ) ;
85
+ }
72
86
73
- ctx. draw_rect ( psdm, psdm_box) ;
87
+ ctx. draw_rect ( psdm, psdm_box) ;
74
88
75
- prev_psdm = Some ( psdm_box) ;
76
- prev_nsdm = None ;
89
+ prev_psdm = Some ( psdm_box) ;
90
+ prev_nsdm = None ;
77
91
78
- let mut well_box = rect;
79
- well_box = well_box. expand ( DIFF_NWELL_ENCLOSURE ) ;
92
+ let mut well_box = rect;
93
+ well_box = well_box. expand ( DIFF_NWELL_ENCLOSURE ) ;
80
94
81
- let nwell = layers. get ( Selector :: Name ( "nwell" ) ) ?;
95
+ let nwell = layers. get ( Selector :: Name ( "nwell" ) ) ?;
82
96
83
- ctx. draw_rect ( nwell, well_box) ;
84
- } else {
85
- let mut nsdm_box = rect;
86
- nsdm_box = nsdm_box. expand ( DIFF_NSDM_ENCLOSURE ) ;
97
+ ctx. draw_rect ( nwell, well_box) ;
98
+ } else {
99
+ let mut nsdm_box = rect;
100
+ nsdm_box = nsdm_box. expand ( DIFF_NSDM_ENCLOSURE ) ;
87
101
88
- let nsdm = layers. get ( Selector :: Name ( "nsdm" ) ) ?;
102
+ let nsdm = layers. get ( Selector :: Name ( "nsdm" ) ) ?;
89
103
90
- if let Some ( prev_nsdm) = prev_nsdm {
91
- nsdm_box = nsdm_box. union ( prev_nsdm. into ( ) ) . into_rect ( ) ;
92
- }
104
+ if let Some ( prev_nsdm) = prev_nsdm {
105
+ nsdm_box = nsdm_box. union ( prev_nsdm. into ( ) ) . into_rect ( ) ;
106
+ }
93
107
94
- prev_nsdm = Some ( nsdm_box) ;
95
- prev_psdm = None ;
108
+ prev_nsdm = Some ( nsdm_box) ;
109
+ prev_psdm = None ;
96
110
97
- ctx. draw_rect ( nsdm, nsdm_box) ;
98
- }
111
+ ctx. draw_rect ( nsdm, nsdm_box) ;
112
+ }
99
113
100
- ctx. draw_rect ( diff, rect) ;
114
+ ctx. draw_rect ( diff, rect) ;
101
115
102
- cx += d . w ;
116
+ cx += w;
103
117
104
- prev = Some ( d. kind ( & ctx. mos_db ( ) ) ) ;
118
+ prev = Some ( d. kind ( & ctx. mos_db ( ) ) ) ;
119
+ }
120
+ diff_xs. push ( d_diff_xs) ;
105
121
}
106
122
107
123
let empty_rect = Rect :: new ( Point :: zero ( ) , Point :: zero ( ) ) ;
@@ -197,32 +213,40 @@ impl Sky130Pdk {
197
213
. collect :: < Vec < _ > > ( ) ;
198
214
199
215
for i in 0 ..=nf {
200
- for ( ( device, skip_sd_metal) , ( j, x ) ) in params
216
+ for ( ( device, skip_sd_metal) , ( j, xs ) ) in params
201
217
. devices
202
218
. iter ( )
203
219
. zip ( params. skip_sd_metal . iter ( ) )
204
220
. zip ( diff_xs. iter ( ) . enumerate ( ) )
205
221
{
206
- if skip_sd_metal. contains ( & ( i as usize ) ) {
222
+ if Self :: fold_mos ( device . w ) . len ( ) == 1 && skip_sd_metal. contains ( & ( i as usize ) ) {
207
223
continue ;
208
224
}
209
225
210
- let via_rect = Rect :: new ( Point :: zero ( ) , Point :: new ( device. w , 0 ) ) ;
211
- let via_params = ViaParams :: builder ( )
212
- . layers ( diff, sd_metal)
213
- . geometry ( via_rect, via_rect)
214
- . expand ( ViaExpansion :: LongerDirection )
215
- . bot_extension ( Dir :: Horiz )
216
- . top_extension ( Dir :: Horiz )
217
- . build ( ) ;
218
- let mut inst = ctx. instantiate :: < Via > ( & via_params) ?;
219
- let bbox = inst. layer_bbox ( diff) ;
220
- let ofsx = ( device. w - bbox. width ( ) ) / 2 ;
221
- let loc = Point :: new ( x - bbox. p0 . x + ofsx, cy - bbox. p0 . y ) ;
222
- inst. translate ( loc) ;
223
- let sd_rect = inst. layer_bbox ( sd_metal) . into_rect ( ) ;
224
- ctx. draw ( inst) ?;
226
+ let mut sd_rects = Vec :: new ( ) ;
227
+ for ( w, x) in Sky130Pdk :: fold_mos ( device. w ) . into_iter ( ) . zip ( xs) {
228
+ let via_rect = Rect :: new ( Point :: zero ( ) , Point :: new ( w, 0 ) ) ;
229
+ let via_params = ViaParams :: builder ( )
230
+ . layers ( diff, sd_metal)
231
+ . geometry ( via_rect, via_rect)
232
+ . expand ( ViaExpansion :: LongerDirection )
233
+ . bot_extension ( Dir :: Horiz )
234
+ . top_extension ( Dir :: Horiz )
235
+ . build ( ) ;
236
+ let mut inst = ctx. instantiate :: < Via > ( & via_params) ?;
237
+ let bbox = inst. layer_bbox ( diff) ;
238
+ let ofsx = ( w - bbox. width ( ) ) / 2 ;
239
+ let loc = Point :: new ( x - bbox. p0 . x + ofsx, cy - bbox. p0 . y ) ;
240
+ inst. translate ( loc) ;
241
+ sd_rects. push ( inst. layer_bbox ( sd_metal) ) ;
242
+ ctx. draw ( inst) ?;
243
+ }
225
244
245
+ let sd_rect = sd_rects
246
+ . into_iter ( )
247
+ . reduce ( |a, b| a. union ( b) )
248
+ . unwrap ( )
249
+ . into_rect ( ) ;
226
250
let mut port = CellPort :: new ( format ! ( "sd_{j}_{i}" ) ) ;
227
251
port. add ( sd_metal, Shape :: Rect ( sd_rect) ) ;
228
252
ctx. add_port ( port) . unwrap ( ) ;
0 commit comments