2 * Copyright (c) 2000 Stephen Williams (steve@icarus.com)
4 * This source code is free software; you can redistribute it
5 * and/or modify it in source code form under the terms of the GNU
6 * General Public License as published by the Free Software
7 * Foundation; either version 2 of the License, or (at your option)
8 * any later version.will need a Picture Elements Binary Software
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
29 # include "ivl_target.h"
30 # include "compiler.h"
38 bool dll_target::process(const NetProcTop
*net
)
40 ivl_process_t obj
= (struct ivl_process_s
*)
41 calloc(1, sizeof(struct ivl_process_s
));
43 switch (net
->type()) {
44 case NetProcTop::KINITIAL
:
45 obj
->type_
= IVL_PR_INITIAL
;
47 case NetProcTop::KALWAYS
:
48 obj
->type_
= IVL_PR_ALWAYS
;
54 /* Save the scope of the process. */
55 obj
->scope_
= lookup_scope_(net
->scope());
57 obj
->nattr
= net
->attr_cnt();
58 obj
->attr
= fill_in_attributes(net
);
60 /* This little bit causes the process to be completely
61 generated so that it can be passed to the DLL. The
62 stmt_cur_ member us used to hold a pointer to the current
63 statement in progress, and the emit_proc() method fills in
66 We know a few things about the current statement: we are
67 not in the middle of one, and when we are done, we have our
68 statement back. The asserts check these conditions. */
70 assert(stmt_cur_
== 0);
71 stmt_cur_
= (struct ivl_statement_s
*)calloc(1, sizeof*stmt_cur_
);
73 net
->statement()->emit_proc(this);
76 obj
->stmt_
= stmt_cur_
;
79 /* Save the process in the design. */
80 obj
->next_
= des_
.threads_
;
86 void dll_target::task_def(const NetScope
*net
)
88 ivl_scope_t scope
= lookup_scope_(net
);
89 const NetTaskDef
*def
= net
->task_def();
91 assert(stmt_cur_
== 0);
92 stmt_cur_
= (struct ivl_statement_s
*)calloc(1, sizeof*stmt_cur_
);
94 def
->proc()->emit_proc(this);
97 scope
->def
= stmt_cur_
;
102 bool dll_target::func_def(const NetScope
*net
)
104 ivl_scope_t scope
= lookup_scope_(net
);
105 const NetFuncDef
*def
= net
->func_def();
107 assert(stmt_cur_
== 0);
108 stmt_cur_
= (struct ivl_statement_s
*)calloc(1, sizeof*stmt_cur_
);
110 def
->proc()->emit_proc(this);
113 scope
->def
= stmt_cur_
;
116 scope
->ports
= def
->port_count() + 1;
117 if (scope
->ports
> 0) {
118 scope
->port
= new ivl_signal_t
[scope
->ports
];
119 for (unsigned idx
= 1 ; idx
< scope
->ports
; idx
+= 1)
120 scope
->port
[idx
] = find_signal(des_
, def
->port(idx
-1));
123 /* FIXME: the ivl_target API expects port-0 to be the output
124 port. This assumes that the return value is a signal, which
125 is *not* correct. Someday, I'm going to have to change
126 this, but that will break code generators that use this
128 if (const NetNet
*ret_sig
= def
->return_sig()) {
129 scope
->port
[0] = find_signal(des_
, ret_sig
);
133 cerr
<< "?:0" << ": internal error: "
134 << "Function " << net
->basename() << " has a return type"
135 << " that I do not understand." << endl
;
141 * This private function makes the assignment lvals for the various
142 * kinds of assignment statements.
144 void dll_target::make_assign_lvals_(const NetAssignBase
*net
)
148 unsigned cnt
= net
->l_val_count();
150 stmt_cur_
->u_
.assign_
.lvals_
= cnt
;
151 stmt_cur_
->u_
.assign_
.lval_
= new struct ivl_lval_s
[cnt
];
152 stmt_cur_
->u_
.assign_
.delay
= 0;
154 for (unsigned idx
= 0 ; idx
< cnt
; idx
+= 1) {
155 struct ivl_lval_s
*cur
= stmt_cur_
->u_
.assign_
.lval_
+ idx
;
156 const NetAssign_
*asn
= net
->l_val(idx
);
157 const NetExpr
*loff
= asn
->get_base();
162 loff
->expr_scan(this);
167 cur
->width_
= asn
->lwidth();
170 cur
->type_
= IVL_LVAL_REG
;
171 cur
->n
.sig
= find_signal(des_
, asn
->sig());
174 // If there is a word select expression, it is
175 // really an array index. Note that the word index
176 // expression is already converted to canonical
177 // form by elaboration.
180 asn
->word()->expr_scan(this);
181 cur
->type_
= IVL_LVAL_ARR
;
193 void dll_target::proc_assign(const NetAssign
*net
)
196 assert(stmt_cur_
->type_
== IVL_ST_NONE
);
198 stmt_cur_
->type_
= IVL_ST_ASSIGN
;
200 stmt_cur_
->u_
.assign_
.delay
= 0;
202 /* Make the lval fields. */
203 make_assign_lvals_(net
);
206 net
->rval()->expr_scan(this);
207 stmt_cur_
->u_
.assign_
.rval_
= expr_
;
210 const NetExpr
*del
= net
->get_delay();
212 del
->expr_scan(this);
213 stmt_cur_
->u_
.assign_
.delay
= expr_
;
219 void dll_target::proc_assign_nb(const NetAssignNB
*net
)
221 const NetExpr
* delay_exp
= net
->get_delay();
223 assert(stmt_cur_
->type_
== IVL_ST_NONE
);
225 stmt_cur_
->type_
= IVL_ST_ASSIGN_NB
;
226 stmt_cur_
->u_
.assign_
.delay
= 0;
228 /* Make the lval fields. */
229 make_assign_lvals_(net
);
231 /* Make the rval field. */
233 net
->rval()->expr_scan(this);
234 stmt_cur_
->u_
.assign_
.rval_
= expr_
;
237 if (const NetEConst
*delay_num
= dynamic_cast<const NetEConst
*>(delay_exp
)) {
238 verinum val
= delay_num
->value();
239 ivl_expr_t de
= new struct ivl_expr_s
;
240 de
->type_
= IVL_EX_ULONG
;
241 de
->width_
= 8 * sizeof(unsigned long);
243 de
->u_
.ulong_
.value
= val
.as_ulong();
244 stmt_cur_
->u_
.assign_
.delay
= de
;
246 } else if (delay_exp
!= 0) {
247 delay_exp
->expr_scan(this);
248 stmt_cur_
->u_
.assign_
.delay
= expr_
;
253 bool dll_target::proc_block(const NetBlock
*net
)
256 assert(stmt_cur_
->type_
== IVL_ST_NONE
);
258 /* First, count the statements in the block. */
260 for (const NetProc
*cur
= net
->proc_first()
261 ; cur
; cur
= net
->proc_next(cur
))
264 /* If the block has no statements, then turn it into a no-op */
266 stmt_cur_
->type_
= IVL_ST_NOOP
;
270 /* If there is exactly one statement, there is no need for the
271 block wrapper, generate the contained statement instead. */
272 if ((count
== 1) && (net
->subscope() == 0)) {
273 return net
->proc_first()->emit_proc(this);
277 /* Handle the general case. The block has some statements in
278 it, so fill in the block fields of the existing statement,
279 and generate the contents for the statement array. */
281 stmt_cur_
->type_
= (net
->type() == NetBlock::SEQU
)
284 stmt_cur_
->u_
.block_
.nstmt_
= count
;
285 stmt_cur_
->u_
.block_
.stmt_
= (struct ivl_statement_s
*)
286 calloc(count
, sizeof(struct ivl_statement_s
));
289 stmt_cur_
->u_
.block_
.scope
= lookup_scope_(net
->subscope());
291 stmt_cur_
->u_
.block_
.scope
= 0;
293 struct ivl_statement_s
*save_cur_
= stmt_cur_
;
297 for (const NetProc
*cur
= net
->proc_first()
298 ; cur
; cur
= net
->proc_next(cur
), idx
+= 1) {
300 stmt_cur_
= save_cur_
->u_
.block_
.stmt_
+ idx
;
301 bool rc
= cur
->emit_proc(this);
304 assert(idx
== count
);
306 stmt_cur_
= save_cur_
;
312 * A case statement is in turn an array of statements with gate
313 * expressions. This builds arrays of the right size and builds the
314 * ivl_expr_t and ivl_statement_s arrays for the substatements.
316 void dll_target::proc_case(const NetCase
*net
)
319 assert(stmt_cur_
->type_
== IVL_ST_NONE
);
321 switch (net
->type()) {
323 stmt_cur_
->type_
= IVL_ST_CASE
;
326 stmt_cur_
->type_
= IVL_ST_CASEX
;
329 stmt_cur_
->type_
= IVL_ST_CASEZ
;
332 assert(stmt_cur_
->type_
!= IVL_ST_NONE
);
336 net
->expr()->expr_scan(this);
337 stmt_cur_
->u_
.case_
.cond
= expr_
;
340 /* If the condition expression is a real valued expression,
341 then change the case statement to a CASER statement. */
342 if (stmt_cur_
->u_
.case_
.cond
->value_
== IVL_VT_REAL
)
343 stmt_cur_
->type_
= IVL_ST_CASER
;
345 unsigned ncase
= net
->nitems();
346 stmt_cur_
->u_
.case_
.ncase
= ncase
;
348 stmt_cur_
->u_
.case_
.case_ex
= new ivl_expr_t
[ncase
];
349 stmt_cur_
->u_
.case_
.case_st
= new struct ivl_statement_s
[ncase
];
351 ivl_statement_t save_cur
= stmt_cur_
;
353 for (unsigned idx
= 0 ; idx
< ncase
; idx
+= 1) {
354 const NetExpr
*ex
= net
->expr(idx
);
357 save_cur
->u_
.case_
.case_ex
[idx
] = expr_
;
360 save_cur
->u_
.case_
.case_ex
[idx
] = 0;
363 stmt_cur_
= save_cur
->u_
.case_
.case_st
+ idx
;
364 stmt_cur_
->type_
= IVL_ST_NONE
;
365 if (net
->stat(idx
) == 0) {
366 stmt_cur_
->type_
= IVL_ST_NOOP
;
368 net
->stat(idx
)->emit_proc(this);
372 stmt_cur_
= save_cur
;
375 bool dll_target::proc_cassign(const NetCAssign
*net
)
379 assert(stmt_cur_
->type_
== IVL_ST_NONE
);
381 stmt_cur_
->type_
= IVL_ST_CASSIGN
;
383 /* Make the l-value fields. */
384 make_assign_lvals_(net
);
387 net
->rval()->expr_scan(this);
388 stmt_cur_
->u_
.assign_
.rval_
= expr_
;
394 bool dll_target::proc_condit(const NetCondit
*net
)
397 assert(stmt_cur_
->type_
== IVL_ST_NONE
);
399 stmt_cur_
->type_
= IVL_ST_CONDIT
;
400 stmt_cur_
->u_
.condit_
.stmt_
= (struct ivl_statement_s
*)
401 calloc(2, sizeof(struct ivl_statement_s
));
404 net
->expr()->expr_scan(this);
405 stmt_cur_
->u_
.condit_
.cond_
= expr_
;
408 ivl_statement_t save_cur_
= stmt_cur_
;
410 stmt_cur_
= save_cur_
->u_
.condit_
.stmt_
+0;
411 bool flag
= net
->emit_recurse_if(this);
413 stmt_cur_
= save_cur_
->u_
.condit_
.stmt_
+1;
414 flag
= flag
&& net
->emit_recurse_else(this);
416 stmt_cur_
= save_cur_
;
420 bool dll_target::proc_deassign(const NetDeassign
*net
)
423 assert(stmt_cur_
->type_
== IVL_ST_NONE
);
425 stmt_cur_
->type_
= IVL_ST_DEASSIGN
;
427 /* Make the l-value fields. */
428 make_assign_lvals_(net
);
433 bool dll_target::proc_delay(const NetPDelay
*net
)
436 assert(stmt_cur_
->type_
== IVL_ST_NONE
);
438 ivl_statement_t tmp
= (struct ivl_statement_s
*)
439 calloc(1, sizeof(struct ivl_statement_s
));
441 if (const NetExpr
*expr
= net
->expr()) {
443 stmt_cur_
->type_
= IVL_ST_DELAYX
;
445 expr
->expr_scan(this);
446 stmt_cur_
->u_
.delayx_
.expr
= expr_
;
449 stmt_cur_
->u_
.delayx_
.stmt_
= tmp
;
452 stmt_cur_
->type_
= IVL_ST_DELAY
;
453 stmt_cur_
->u_
.delay_
.stmt_
= tmp
;
454 stmt_cur_
->u_
.delay_
.delay_
= net
->delay();
457 ivl_statement_t save_cur_
= stmt_cur_
;
459 bool flag
= net
->emit_proc_recurse(this);
461 /* If the recurse doesn't turn this new item into something,
462 then either it failed or there is no statement
463 there. Either way, draw a no-op into the statement. */
464 if (stmt_cur_
->type_
== IVL_ST_NONE
) {
465 stmt_cur_
->type_
= IVL_ST_NOOP
;
468 stmt_cur_
= save_cur_
;
473 bool dll_target::proc_disable(const NetDisable
*net
)
476 assert(stmt_cur_
->type_
== IVL_ST_NONE
);
478 stmt_cur_
->type_
= IVL_ST_DISABLE
;
479 stmt_cur_
->u_
.disable_
.scope
= lookup_scope_(net
->target());
483 bool dll_target::proc_force(const NetForce
*net
)
487 assert(stmt_cur_
->type_
== IVL_ST_NONE
);
489 stmt_cur_
->type_
= IVL_ST_FORCE
;
491 /* Make the l-value fields. */
492 make_assign_lvals_(net
);
495 net
->rval()->expr_scan(this);
496 stmt_cur_
->u_
.assign_
.rval_
= expr_
;
502 void dll_target::proc_forever(const NetForever
*net
)
505 assert(stmt_cur_
->type_
== IVL_ST_NONE
);
507 stmt_cur_
->type_
= IVL_ST_FOREVER
;
509 ivl_statement_t tmp
= (struct ivl_statement_s
*)
510 calloc(1, sizeof(struct ivl_statement_s
));
512 ivl_statement_t save_cur_
= stmt_cur_
;
515 net
->emit_recurse(this);
517 save_cur_
->u_
.forever_
.stmt_
= stmt_cur_
;
518 stmt_cur_
= save_cur_
;
521 bool dll_target::proc_release(const NetRelease
*net
)
524 assert(stmt_cur_
->type_
== IVL_ST_NONE
);
526 stmt_cur_
->type_
= IVL_ST_RELEASE
;
528 /* Make the l-value fields. */
529 make_assign_lvals_(net
);
534 void dll_target::proc_repeat(const NetRepeat
*net
)
537 assert(stmt_cur_
->type_
== IVL_ST_NONE
);
539 stmt_cur_
->type_
= IVL_ST_REPEAT
;
542 net
->expr()->expr_scan(this);
543 stmt_cur_
->u_
.while_
.cond_
= expr_
;
546 ivl_statement_t tmp
= (struct ivl_statement_s
*)
547 calloc(1, sizeof(struct ivl_statement_s
));
549 ivl_statement_t save_cur_
= stmt_cur_
;
552 net
->emit_recurse(this);
554 save_cur_
->u_
.while_
.stmt_
= stmt_cur_
;
555 stmt_cur_
= save_cur_
;
558 void dll_target::proc_stask(const NetSTask
*net
)
560 unsigned nparms
= net
->nparms();
562 assert(stmt_cur_
->type_
== IVL_ST_NONE
);
564 stmt_cur_
->type_
= IVL_ST_STASK
;
565 /* System task names are lex_strings strings. */
566 stmt_cur_
->u_
.stask_
.name_
= net
->name();
567 stmt_cur_
->u_
.stask_
.nparm_
= nparms
;
568 stmt_cur_
->u_
.stask_
.parms_
= (ivl_expr_t
*)
569 calloc(nparms
, sizeof(ivl_expr_t
));
571 for (unsigned idx
= 0 ; idx
< nparms
; idx
+= 1) {
573 net
->parm(idx
)->expr_scan(this);
574 stmt_cur_
->u_
.stask_
.parms_
[idx
] = expr_
;
580 bool dll_target::proc_trigger(const NetEvTrig
*net
)
583 assert(stmt_cur_
->type_
== IVL_ST_NONE
);
585 stmt_cur_
->type_
= IVL_ST_TRIGGER
;
586 stmt_cur_
->u_
.wait_
.nevent
= 1;
588 /* Locate the event by name. Save the ivl_event_t in the
589 statement so that the generator can find it easily. */
590 const NetEvent
*ev
= net
->event();
591 ivl_scope_t ev_scope
= lookup_scope_(ev
->scope());
593 for (unsigned idx
= 0 ; idx
< ev_scope
->nevent_
; idx
+= 1) {
594 const char*ename
= ivl_event_basename(ev_scope
->event_
[idx
]);
595 if (strcmp(ev
->name(), ename
) == 0) {
596 stmt_cur_
->u_
.wait_
.event
= ev_scope
->event_
[idx
];
605 void dll_target::proc_utask(const NetUTask
*net
)
608 assert(stmt_cur_
->type_
== IVL_ST_NONE
);
610 stmt_cur_
->type_
= IVL_ST_UTASK
;
611 stmt_cur_
->u_
.utask_
.def
= lookup_scope_(net
->task());
614 bool dll_target::proc_wait(const NetEvWait
*net
)
617 assert(stmt_cur_
->type_
== IVL_ST_NONE
);
619 stmt_cur_
->type_
= IVL_ST_WAIT
;
620 stmt_cur_
->u_
.wait_
.stmt_
= (struct ivl_statement_s
*)
621 calloc(1, sizeof(struct ivl_statement_s
));
623 stmt_cur_
->u_
.wait_
.nevent
= net
->nevents();
624 if (net
->nevents() > 1) {
625 stmt_cur_
->u_
.wait_
.events
= (ivl_event_t
*)
626 calloc(net
->nevents(), sizeof(ivl_event_t
*));
629 for (unsigned edx
= 0 ; edx
< net
->nevents() ; edx
+= 1) {
631 /* Locate the event by name. Save the ivl_event_t in the
632 statement so that the generator can find it easily. */
633 const NetEvent
*ev
= net
->event(edx
);
634 ivl_scope_t ev_scope
= lookup_scope_(ev
->scope());
635 ivl_event_t ev_tmp
=0;
638 assert(ev_scope
->nevent_
> 0);
639 for (unsigned idx
= 0 ; idx
< ev_scope
->nevent_
; idx
+= 1) {
640 const char*ename
= ivl_event_basename(ev_scope
->event_
[idx
]);
641 if (strcmp(ev
->name(), ename
) == 0) {
642 ev_tmp
= ev_scope
->event_
[idx
];
646 // XXX should we assert(ev_tmp)?
648 if (net
->nevents() == 1)
649 stmt_cur_
->u_
.wait_
.event
= ev_tmp
;
651 stmt_cur_
->u_
.wait_
.events
[edx
] = ev_tmp
;
653 /* If this is an event with a probe, then connect up the
654 pins. This wasn't done during the ::event method because
655 the signals weren't scanned yet. */
657 if (ev
->nprobe() >= 1) {
659 unsigned ineg
= ev_tmp
->nany
;
660 unsigned ipos
= ineg
+ ev_tmp
->nneg
;
662 for (unsigned idx
= 0 ; idx
< ev
->nprobe() ; idx
+= 1) {
663 const NetEvProbe
*pr
= ev
->probe(idx
);
666 switch (pr
->edge()) {
667 case NetEvProbe::ANYEDGE
:
669 iany
+= pr
->pin_count();
671 case NetEvProbe::NEGEDGE
:
673 ineg
+= pr
->pin_count();
675 case NetEvProbe::POSEDGE
:
677 ipos
+= pr
->pin_count();
681 for (unsigned bit
= 0
682 ; bit
< pr
->pin_count()
684 ivl_nexus_t nex
= (ivl_nexus_t
)
685 pr
->pin(bit
).nexus()->t_cookie();
687 ev_tmp
->pins
[base
+bit
] = nex
;
693 /* The ivl_statement_t for the wait statement is not complete
694 until we calculate the sub-statement. */
696 ivl_statement_t save_cur_
= stmt_cur_
;
697 stmt_cur_
= stmt_cur_
->u_
.wait_
.stmt_
;
698 bool flag
= net
->emit_recurse(this);
699 if (flag
&& (stmt_cur_
->type_
== IVL_ST_NONE
))
700 stmt_cur_
->type_
= IVL_ST_NOOP
;
702 stmt_cur_
= save_cur_
;
707 void dll_target::proc_while(const NetWhile
*net
)
710 assert(stmt_cur_
->type_
== IVL_ST_NONE
);
712 stmt_cur_
->type_
= IVL_ST_WHILE
;
713 stmt_cur_
->u_
.while_
.stmt_
= (struct ivl_statement_s
*)
714 calloc(1, sizeof(struct ivl_statement_s
));
717 net
->expr()->expr_scan(this);
718 stmt_cur_
->u_
.while_
.cond_
= expr_
;
721 /* Now generate the statement of the while loop. We know it is
722 a single statement, and we know that the
723 emit_proc_recurse() will call emit_proc() for it. */
725 ivl_statement_t save_cur_
= stmt_cur_
;
726 stmt_cur_
= save_cur_
->u_
.while_
.stmt_
;
727 net
->emit_proc_recurse(this);
728 stmt_cur_
= save_cur_
;