Make %t with real values use specified width if given.
[iverilog.git] / syn-rules.y
blobca0937f31d0cb3a93b2a050457fab9647fef447d
2 %{
3 /*
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)
10 * any later version.
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
21 #ifdef HAVE_CVS_IDENT
22 #ident "$Id: syn-rules.y,v 1.34 2007/01/16 05:44:15 steve Exp $"
23 #endif
25 # include "config.h"
27 # include <iostream>
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.
37 # include "netlist.h"
38 # include "netmisc.h"
39 # include "functor.h"
40 # include <assert.h>
42 struct syn_token_t {
43 int token;
45 NetAssignBase*assign;
46 NetProcTop*top;
47 NetEvWait*evwait;
48 NetEvent*event;
49 NetExpr*expr;
51 syn_token_t*next_;
53 #define YYSTYPE syn_token_t*
55 static int yylex();
56 static void yyerror(const char*);
57 static Design*des_;
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
70 start
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
84 flip-flops. */
86 : S_ALWAYS '@' '(' S_EVENT ')' S_ASSIGN ';'
87 { make_DFF_CE(des_, $1->top, $2->evwait, $4->event,
88 0, $6->assign);
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. */
99 | S_INITIAL S_ASSIGN
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:
117 // lval[7:1] <= foo;
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)
143 assert(asn);
145 NetEvProbe*pclk = eclk->probe(0);
146 NetESignal*d = dynamic_cast<NetESignal*> (asn->rval());
147 NetNet*ce = cexp? cexp->synthesize(des) : 0;
149 if (d == 0) {
150 cerr << asn->get_line() << ": internal error: "
151 << " not a simple signal? " << *asn->rval() << endl;
154 assert(d);
156 NetAssign_*a;
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.
169 if (a->sig()) {
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);
174 des->add_node(ff);
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
185 * process.
187 static void make_initializer(Design*des, NetProcTop*top, NetAssignBase*asn)
189 NetESignal*rsig = dynamic_cast<NetESignal*> (asn->rval());
190 assert(rsig);
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()))
201 cur->set_init(bit);
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
216 * to the parser.
218 struct tokenize : public proc_match_t {
219 tokenize() { }
220 ~tokenize() { }
222 int assign(NetAssign*dev)
224 syn_token_t*cur;
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;
230 cur->assign = dev;
231 cur->next_ = 0;
232 last_->next_ = cur;
233 last_ = cur;
234 return 0;
237 int assign_nb(NetAssignNB*dev)
239 syn_token_t*cur;
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;
245 cur->assign = dev;
246 cur->next_ = 0;
247 last_->next_ = cur;
248 last_ = cur;
249 return 0;
252 int condit(NetCondit*dev)
254 syn_token_t*cur;
256 cur = new syn_token_t;
257 cur->token = S_IF;
258 cur->next_ = 0;
259 last_->next_ = cur;
260 last_ = cur;
262 cur = new syn_token_t;
263 cur->token = S_EXPR;
264 cur->expr = dev->expr();
265 cur->next_ = 0;
266 last_->next_ = cur;
267 last_ = cur;
269 dev -> if_clause() -> match_proc(this);
271 if (dev->else_clause()) {
272 cur = new syn_token_t;
273 cur->token = S_ELSE;
274 cur->next_ = 0;
275 last_->next_ = cur;
276 last_ = cur;
278 dev -> else_clause() -> match_proc(this);
281 cur = new syn_token_t;
282 cur->token = ';';
283 cur->next_ = 0;
284 last_->next_ = cur;
285 last_ = cur;
286 return 0;
289 int event_wait(NetEvWait*dev)
291 syn_token_t*cur;
293 cur = new syn_token_t;
294 cur->token = '@';
295 cur->evwait = dev;
296 cur->next_ = 0;
297 last_->next_ = cur;
298 last_ = cur;
300 cur = new syn_token_t;
301 cur->token = '(';
302 cur->next_ = 0;
303 last_->next_ = cur;
304 last_ = cur;
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);
310 cur->next_ = 0;
311 last_->next_ = cur;
312 last_ = cur;
315 cur = new syn_token_t;
316 cur->token = ')';
317 cur->next_ = 0;
318 last_->next_ = cur;
319 last_ = cur;
321 dev -> statement() -> match_proc(this);
323 cur = new syn_token_t;
324 cur->token = ';';
325 cur->next_ = 0;
326 last_->next_ = cur;
327 last_ = cur;
328 return 0;
332 static void syn_start_process(NetProcTop*t)
334 first_ = new syn_token_t;
335 last_ = first_;
336 ptr_ = first_;
338 first_->token = (t->type() == NetProcTop::KALWAYS)? S_ALWAYS : S_INITIAL;
339 first_->top = t;
340 first_->next_ = 0;
342 tokenize go;
343 t -> statement() -> match_proc(&go);
346 static void syn_done_process()
348 while (first_) {
349 syn_token_t*cur = first_;
350 first_ = cur->next_;
351 delete cur;
355 static int yylex()
357 if (ptr_ == 0) {
358 yylval = 0;
359 return EOF;
362 yylval = ptr_;
363 ptr_ = ptr_->next_;
364 return yylval->token;
367 struct syn_rules_f : public functor_t {
368 ~syn_rules_f() { }
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)
375 return;
377 syn_start_process(top);
378 yyparse();
379 syn_done_process();
383 void syn_rules(Design*d)
385 des_ = d;
386 syn_rules_f obj;
387 des_->functor(&obj);
390 static void yyerror(const char*)