4 * Copyright (c) 2000-2005 Stephen Williams (steve@icarus.com)
6 * This source code is free software; you can redistribute it
7 * and/or modify it in source code form under the terms of the GNU
8 * General Public License as published by the Free Software
9 * Foundation; either version 2 of the License, or (at your option)
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
22 #ident "$Id: syn-rules.y,v 1.34 2007/01/16 05:44:15 steve Exp $"
30 * This file implements synthesis based on matching threads and
31 * converting them to equivalent devices. The trick here is that the
32 * proc_match_t functor can be used to scan a process and generate a
33 * string of tokens. That string of tokens can then be matched by the
34 * rules to determine what kind of device is to be made.
53 #define YYSTYPE syn_token_t*
56 static void yyerror(const char*);
59 static void make_DFF_CE
(Design
*des
, NetProcTop
*top
, NetEvWait
*wclk
,
60 NetEvent
*eclk
, NetExpr
*cexp
, NetAssignBase
*asn
);
61 static void make_initializer
(Design
*des
, NetProcTop
*top
, NetAssignBase
*asn
);
65 %token S_ALWAYS S_ASSIGN S_ASSIGN_MEM S_ASSIGN_MUX S_ELSE S_EVENT
66 %token S_EXPR S_IF S_INITIAL
72 /* These rules match simple DFF devices. Clocked assignments are
73 simply implemented as DFF, and a CE is easily expressed with a
74 conditional statement. The typical Verilog that get these are:
76 always @(posedge CLK) Q = D
77 always @(negedge CLK) Q = D
79 always @(posedge CLK) if (CE) Q = D;
80 always @(negedge CLK) if (CE) Q = D;
82 The width of Q and D cause a wide register to be created. The
83 code generators generally implement that as an array of
86 : S_ALWAYS
'@' '(' S_EVENT
')' S_ASSIGN
';'
87 { make_DFF_CE
(des_
, $1->top
, $2->evwait
, $4->event
,
91 | S_ALWAYS
'@' '(' S_EVENT
')' S_IF S_EXPR S_ASSIGN
';' ';'
92 { make_DFF_CE
(des_
, $1->top
, $2->evwait
, $4->event
,
93 $7->expr
, $8->assign
);
96 /* Unconditional assignments in initial blocks should be made into
97 initializers wherever possible. */
100 { make_initializer
(des_
, $1->top
, $2->assign
);
107 /* Various actions. */
109 static void hookup_DFF_CE
(NetFF
*ff
, NetESignal
*d
, NetEvProbe
*pclk
,
110 NetNet
*ce
, NetAssign_
*a
, unsigned rval_pinoffset
)
113 // a->sig() is a *NetNet, which doesn't have the loff_ and
114 // lwid_ context. Add the correction for loff_ ourselves.
116 // This extra calculation allows for assignments like:
118 // where lval is really a "reg [7:0]". In other words, part
119 // selects in the l-value are handled by loff and the lwidth().
121 connect
(ff
->pin_Data
(), d
->sig
()->pin
(0));
122 connect
(ff
->pin_Q
(), a
->sig
()->pin
(0));
124 connect
(ff
->pin_Clock
(), pclk
->pin
(0));
125 if
(ce
) connect
(ff
->pin_Enable
(), ce
->pin
(0));
127 ff
->attribute
(perm_string
::literal
("LPM_FFType"), verinum
("DFF"));
128 if
(pclk
->edge
() == NetEvProbe
::NEGEDGE
)
129 ff
->attribute
(perm_string
::literal
("Clock:LPM_Polarity"), verinum
("INVERT"));
132 /* This lval_ represents a reg that is a WIRE in the
133 synthesized results. This function signals the destructor
134 to change the REG that this l-value refers to into a
135 WIRE. It is done then, at the last minute, so that pending
136 synthesis can continue to work with it as a WIRE. */
137 a
->turn_sig_to_wire_on_release
();
140 static void make_DFF_CE
(Design
*des
, NetProcTop
*top
, NetEvWait
*wclk
,
141 NetEvent
*eclk
, NetExpr
*cexp
, NetAssignBase
*asn
)
145 NetEvProbe
*pclk
= eclk
->probe
(0);
146 NetESignal
*d
= dynamic_cast
<NetESignal
*> (asn
->rval
());
147 NetNet
*ce
= cexp? cexp
->synthesize
(des
) : 0;
150 cerr
<< asn
->get_line
() << ": internal error: "
151 << " not a simple signal? " << *asn
->rval
() << endl
;
157 unsigned rval_pinoffset
=0;
158 for
(unsigned i
=0; (a
=asn
->l_val
(i
)); i
++) {
160 // asn->l_val(i) are the set of *NetAssign_'s that form the list
161 // of lval expressions. Treat each one independently, keeping
162 // track of which bits of rval to use for each set of DFF inputs.
163 // For example, given:
164 // {carry,data} <= x + y + z;
165 // run through this loop twice, where a and rval_pinoffset are
166 // first data and 0, then carry and 1.
167 // FIXME: ff gets its pin names wrong when loff_ is nonzero.
170 // cerr << "new NetFF named " << a->name() << endl;
171 NetFF
*ff
= new NetFF
(top
->scope
(), a
->name
(),
172 a
->sig
()->vector_width
());
173 hookup_DFF_CE
(ff
, d
, pclk
, ce
, a
, rval_pinoffset
);
176 rval_pinoffset
+= a
->lwidth
();
178 des
->delete_process
(top
);
182 * An assignment in an initial statement is the same as giving the
183 * nexus an initial value. For synthesized netlists, we can just set
184 * the initial value for the link and get rid of the assignment
187 static void make_initializer
(Design
*des
, NetProcTop
*top
, NetAssignBase
*asn
)
189 NetESignal
*rsig
= dynamic_cast
<NetESignal
*> (asn
->rval
());
192 for
(unsigned idx
= 0 ; idx
< asn
->l_val
(0)->lwidth
() ; idx
+= 1) {
194 verinum
::V bit
= rsig
->sig
()->pin
(idx
).nexus
()->driven_value
();
196 Nexus
*nex
= asn
->l_val
(0)->sig
()->pin
(idx
).nexus
();
197 for
(Link
*cur
= nex
->first_nlink
()
198 ; cur
; cur
= cur
->next_nlink
()) {
200 if
(dynamic_cast
<NetNet
*> (cur
->get_obj
()))
206 des
->delete_process
(top
);
209 static syn_token_t
*first_
= 0;
210 static syn_token_t
*last_
= 0;
211 static syn_token_t
*ptr_
= 0;
214 * The match class is used to take a process and turn it into a stream
215 * of tokens. This stream is used by the yylex function to feed tokens
218 struct tokenize
: public proc_match_t
{
222 int assign
(NetAssign
*dev
)
225 cur
= new syn_token_t
;
226 // Bit Muxes can't be synthesized (yet), but it's too much
227 // work to detect them now.
228 // cur->token = dev->l_val(0)->bmux() ? S_ASSIGN_MUX : S_ASSIGN;
229 cur
->token
= S_ASSIGN
;
237 int assign_nb
(NetAssignNB
*dev
)
240 cur
= new syn_token_t
;
241 // Bit Muxes can't be synthesized (yet), but it's too much
242 // work to detect them now.
243 // cur->token = dev->l_val(0)->bmux() ? S_ASSIGN_MUX : S_ASSIGN;
244 cur
->token
= S_ASSIGN
;
252 int condit
(NetCondit
*dev
)
256 cur
= new syn_token_t
;
262 cur
= new syn_token_t
;
264 cur
->expr
= dev
->expr
();
269 dev
-> if_clause
() -> match_proc
(this
);
271 if
(dev
->else_clause
()) {
272 cur
= new syn_token_t
;
278 dev
-> else_clause
() -> match_proc
(this
);
281 cur
= new syn_token_t
;
289 int event_wait
(NetEvWait
*dev
)
293 cur
= new syn_token_t
;
300 cur
= new syn_token_t
;
306 for
(unsigned idx
= 0; idx
< dev
->nevents
(); idx
+= 1) {
307 cur
= new syn_token_t
;
308 cur
->token
= S_EVENT
;
309 cur
->event
= dev
->event
(idx
);
315 cur
= new syn_token_t
;
321 dev
-> statement
() -> match_proc
(this
);
323 cur
= new syn_token_t
;
332 static void syn_start_process
(NetProcTop
*t
)
334 first_
= new syn_token_t
;
338 first_
->token
= (t
->type
() == NetProcTop
::KALWAYS
)? S_ALWAYS
: S_INITIAL
;
343 t
-> statement
() -> match_proc
(&go
);
346 static void syn_done_process
()
349 syn_token_t
*cur
= first_
;
364 return
yylval->token
;
367 struct syn_rules_f
: public functor_t
{
370 void process
(class Design
*des
, class NetProcTop
*top
)
372 /* If the scope that contains this process as a cell
373 attribute attached to it, then skip synthesis. */
374 if
(top
->scope
()->attribute
(perm_string
::literal
("ivl_synthesis_cell")).len
() > 0)
377 syn_start_process
(top
);
383 void syn_rules
(Design
*d
)
390 static void yyerror(const char*)