1+ /*************************************************************************
2+ *
3+ * This file is part of ACT standard library
4+ *
5+ * Copyright (c) 2025 Karthi Srinivasan
6+ *
7+ * Licensed under the Apache License, Version 2.0 (the "License");
8+ * you may not use this file except in compliance with the License.
9+ * You may obtain a copy of the License at
10+ *
11+ * http://www.apache.org/licenses/LICENSE-2.0
12+ *
13+ * Unless required by applicable law or agreed to in writing, software
14+ * distributed under the License is distributed on an "AS IS" BASIS,
15+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16+ * See the License for the specific language governing permissions and
17+ * limitations under the License.
18+ *
19+ **************************************************************************
20+ */
21+
22+ import std::cells;
23+ import std::gates;
24+
25+ namespace std {
26+
27+ export namespace delay_elements {
28+
29+ // Symmetric Delay Elements -----------------------
30+
31+ /*
32+ Simple delay buffer consisting of two inverters
33+ */
34+ export defproc delay_buffer (bool? in; bool! out)
35+ {
36+ std::cells::INVX1 invs[2];
37+ invs[0].A = in;
38+ invs[0].Y = invs[1].A;
39+ invs[1].Y = out;
40+ spec {
41+ timing in+ : out+ < in-
42+ timing in- : out- < in+
43+ }
44+ }
45+
46+ /*
47+ Delay buffer consisting of two weak-inverters in series.
48+ L : Length of weak transistors
49+ */
50+ export template <pint L>
51+ defproc weak_delay_buffer (bool? in; bool! out) {
52+ bool x;
53+ prs {
54+ in<1,L> => x-
55+ x<1,L> => out-
56+ }
57+ spec {
58+ timing in+ : out+ < in-
59+ timing in- : out- < in+
60+ }
61+ }
62+ // Symmetric Delay Elements -----------------------
63+
64+ // Asymmetric Delay Elements ----------------------
65+ // Asymmetric : Different propagation delays for rising edge (1) and falling edge (0)
66+ /*
67+ Recursive asymmetric delay lines that use themselves to create long delays.
68+ REC: Recursion level
69+ L : Length of weak transistors
70+ Base case: two asymmetric inverters in series
71+ Recursive step: insert REC-1 of the correct type on the slow path to make it even slower
72+ Has additional transistor to prevent transient short and reduce power consumption
73+ */
74+ /*
75+ Fast-0, Slow-1
76+ Delay of rising edge - high
77+ Delay of falling edge - 2 transitions
78+ */
79+ export template <pint REC, L> defproc fast0_slow1_rec (bool? in; bool! out);
80+
81+ /*
82+ Fast-1, Slow-0
83+ Delay of falling edge - high
84+ Delay of rising edge - 2 transitions
85+ */
86+ export template <pint REC, L> defproc fast1_slow0_rec (bool? in; bool! out);
87+
88+ export template <pint REC, L>
89+ defproc fast0_slow1_rec (bool? in; bool! out) {
90+ { REC>=0 : "what" };
91+ bool x; bool f0s1out, f1s0out;
92+ [ REC=0 -> f0s1out = in;
93+ f1s0out = x;
94+ []REC>0 -> fast0_slow1_rec<REC-1,L> f0s1r(in); f0s1out = f0s1r.out;
95+ fast1_slow0_rec<REC-1,L> f1s0r(x); f1s0out = f1s0r.out;
96+ ]
97+ prs {
98+ [keeper=0] f0s1out<1,L> & in<1,1> -> x-
99+ [keeper=0] ~in<1,1> -> x+
100+ [keeper=0] x<1,1> -> out-
101+ [keeper=0] ~f1s0out<1,L> & ~x<1,1> -> out+
102+ }
103+ spec {
104+ timing in+ : out+ < in-
105+ timing in- : out- < in+
106+ }
107+ }
108+
109+ export template <pint REC, L>
110+ defproc fast1_slow0_rec (bool? in; bool! out) {
111+ { REC>=0 : "what" };
112+ bool x; bool f0s1out, f1s0out;
113+ [ REC=0 -> f1s0out = in;
114+ f0s1out = x;
115+ []REC>0 -> fast1_slow0_rec<REC-1,L> f1s0r(in); f1s0out = f1s0r.out;
116+ fast0_slow1_rec<REC-1,L> f0s1r(x); f0s1out = f0s1r.out;
117+ ]
118+ prs {
119+ [keeper=0] in<1,1> -> x-
120+ [keeper=0] ~f1s0out<1,L> & ~in<1,1> -> x+
121+ [keeper=0] f0s1out<1,L> & x<1,1> -> out-
122+ [keeper=0] ~x<1,1> -> out+
123+ }
124+ spec {
125+ timing in+ : out+ < in-
126+ timing in- : out- < in+
127+ }
128+ }
129+
130+ /*
131+ Meta-elements that use a symmetric delay line twice (0-delay + 1-delay)
132+ to simulate an asymmetric delay line.
133+ The symmetric delay line component must be connected between dl_in and dl_out.
134+ Slow rising edge (1) and fast falling edge (0).
135+ */
136+ /*
137+ Delay of rising edge - (0-delay + 1-delay) of symm. DL + 5 transitions
138+ Delay of falling edge - 2 transitions
139+ */
140+ export defproc reuse_1 (bool? in; bool! out; bool! dl_in; bool? dl_out) {
141+ bool x, y, _y;
142+ y = dl_in;
143+ std::cells::NOR2X1 nor;
144+ nor.A = dl_out;
145+ nor.B = x;
146+ nor.Y = out;
147+ prs {
148+ _y => y-
149+ Reset | in & x -> _y-
150+ ~Reset & ~x -> _y+
151+ dl_out & in #> x-
152+ }
153+ spec {
154+ timing in+ : out+ < in-
155+ timing in- : out- < in+
156+ }
157+ }
158+
159+ export defcell PCELEM2 (bool? A, B; bool! Y) {
160+ bool _Y;
161+ prs {
162+ A & B -> _Y-
163+ ~A & ~B -> _Y+
164+ _Y => Y-
165+ }
166+ }
167+ export defcell UACELEM2 (bool? A, B; bool! Y) {
168+ prs {
169+ A & B -> Y-
170+ ~A -> Y+
171+ }
172+ }
173+ export defcell DACELEM2 (bool? A, B; bool! Y) {
174+ prs {
175+ ~A & ~B -> Y+
176+ A -> Y-
177+ }
178+ }
179+
180+ /*
181+ Delay of rising edge - (0-delay + 1-delay) of symm. DL + 7 transitions
182+ Delay of falling edge - 2 transitions
183+ */
184+ export defproc reuse_2 (bool? in; bool! out; bool! dl_in; bool? dl_out) {
185+ bool x, _x, do;
186+
187+ std::gates::ctree<2,true> C0;
188+ UACELEM2 UAC0;
189+ DACELEM2 DAC0;
190+ std::cells::INVX1 INV0;
191+ std::cells::INVX1 INV1;
192+ std::cells::NOR2X1 NOR0;
193+
194+ C0.in[0] = in;
195+ C0.in[1] = dl_out;
196+ C0.out = x;
197+
198+ UAC0.A = NOR0.Y;
199+ UAC0.B = in;
200+ UAC0.Y = do;
201+
202+ DAC0.A = x;
203+ DAC0.B = dl_out;
204+ DAC0.Y = out;
205+
206+ INV1.A = x;
207+ INV1.Y = _x;
208+ NOR0.A = _x;
209+ NOR0.B = Reset;
210+ INV0.A = do;
211+ INV0.Y = dl_in;
212+ spec {
213+ timing in+ : out+ < in-
214+ timing in- : out- < in+
215+ }
216+ }
217+ // Asymmetric Delay Elements ----------------------
218+ }
219+
220+ export namespace delay_lines {
221+ /*
222+ Chains of delay elements.
223+ N : number of elements in series.
224+ For other parameters specific to each, see the delay elements above.
225+ */
226+
227+ // Symmetric Delay Lines -----------------------
228+ export template <pint N>
229+ defproc chain_delay_buffer (bool? in; bool! out) {
230+ std::delay_elements::delay_buffer d[N];
231+ in = d[0].in;
232+ ( i : N-1 : d[i].out = d[i+1].in; )
233+ d[N-1].out = out;
234+ spec {
235+ timing in+ : out+ < in-
236+ timing in- : out- < in+
237+ }
238+ }
239+
240+ export template <pint N, L>
241+ defproc chain_weak_delay_buffer (bool? in; bool! out) {
242+ std::delay_elements::weak_delay_buffer<L> d[N];
243+ in = d[0].in;
244+ ( i : N-1 : d[i].out = d[i+1].in; )
245+ d[N-1].out = out;
246+ spec {
247+ timing in+ : out+ < in-
248+ timing in- : out- < in+
249+ }
250+ }
251+ // Symmetric Delay Lines -----------------------
252+
253+ // Asymmetric Delay Lines ----------------------
254+ export template <pint N, REC, L>
255+ defproc chain_recursive_fast0_slow1 (bool? in; bool! out) {
256+ std::delay_elements::fast0_slow1_rec<REC, L> d[N];
257+ in = d[0].in;
258+ ( i : N-1 : d[i].out = d[i+1].in; )
259+ d[N-1].out = out;
260+ spec {
261+ timing in+ : out+ < in-
262+ timing in- : out- < in+
263+ }
264+ }
265+
266+ export template <pint N, REC, L>
267+ defproc chain_recursive_fast1_slow0 (bool? in; bool! out) {
268+ std::delay_elements::fast1_slow0_rec<REC, L> d[N];
269+ in = d[0].in;
270+ ( i : N-1 : d[i].out = d[i+1].in; )
271+ d[N-1].out = out;
272+ spec {
273+ timing in+ : out+ < in-
274+ timing in- : out- < in+
275+ }
276+ }
277+
278+ export template <pint N, L>
279+ defproc chain_reuse_1_delay_buffer (bool? in; bool! out) {
280+ std::delay_elements::reuse_1 r(in, out);
281+ chain_delay_buffer<N> d(r.dl_in, r.dl_out);
282+ spec {
283+ timing in+ : out+ < in-
284+ timing in- : out- < in+
285+ }
286+ }
287+
288+ export template <pint N, L>
289+ defproc chain_reuse_2_delay_buffer (bool? in; bool! out) {
290+ std::delay_elements::reuse_2 r(in, out);
291+ chain_delay_buffer<N> d(r.dl_in, r.dl_out);
292+ spec {
293+ timing in+ : out+ < in-
294+ timing in- : out- < in+
295+ }
296+ }
297+
298+ export template <pint N, L>
299+ defproc chain_reuse_1_weak_delay_buffer (bool? in; bool! out) {
300+ std::delay_elements::reuse_1 r(in, out);
301+ chain_weak_delay_buffer<N,L> d(r.dl_in, r.dl_out);
302+ spec {
303+ timing in+ : out+ < in-
304+ timing in- : out- < in+
305+ }
306+ }
307+
308+ export template <pint N, L>
309+ defproc chain_reuse_2_weak_delay_buffer (bool? in; bool! out) {
310+ std::delay_elements::reuse_2 r(in, out);
311+ chain_weak_delay_buffer<N,L> d(r.dl_in, r.dl_out);
312+ spec {
313+ timing in+ : out+ < in-
314+ timing in- : out- < in+
315+ }
316+ }
317+ // Asymmetric Delay Lines ----------------------
318+
319+ }
320+
321+ }