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
30 # include "ivl_target.h"
31 # 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
;
199 FILE_NAME(stmt_cur_
, net
);
201 stmt_cur_
->u_
.assign_
.delay
= 0;
203 /* Make the lval fields. */
204 make_assign_lvals_(net
);
207 net
->rval()->expr_scan(this);
208 stmt_cur_
->u_
.assign_
.rval_
= expr_
;
211 const NetExpr
*del
= net
->get_delay();
213 del
->expr_scan(this);
214 stmt_cur_
->u_
.assign_
.delay
= expr_
;
220 void dll_target::proc_assign_nb(const NetAssignNB
*net
)
222 const NetExpr
* delay_exp
= net
->get_delay();
224 assert(stmt_cur_
->type_
== IVL_ST_NONE
);
226 stmt_cur_
->type_
= IVL_ST_ASSIGN_NB
;
227 FILE_NAME(stmt_cur_
, net
);
229 stmt_cur_
->u_
.assign_
.delay
= 0;
231 /* Make the lval fields. */
232 make_assign_lvals_(net
);
234 /* Make the rval field. */
236 net
->rval()->expr_scan(this);
237 stmt_cur_
->u_
.assign_
.rval_
= expr_
;
240 if (const NetEConst
*delay_num
= dynamic_cast<const NetEConst
*>(delay_exp
)) {
241 verinum val
= delay_num
->value();
242 ivl_expr_t de
= new struct ivl_expr_s
;
243 de
->type_
= IVL_EX_ULONG
;
244 de
->width_
= 8 * sizeof(unsigned long);
246 de
->u_
.ulong_
.value
= val
.as_ulong();
247 stmt_cur_
->u_
.assign_
.delay
= de
;
249 } else if (delay_exp
!= 0) {
250 delay_exp
->expr_scan(this);
251 stmt_cur_
->u_
.assign_
.delay
= expr_
;
256 bool dll_target::proc_block(const NetBlock
*net
)
259 assert(stmt_cur_
->type_
== IVL_ST_NONE
);
260 FILE_NAME(stmt_cur_
, net
);
262 /* First, count the statements in the block. */
264 for (const NetProc
*cur
= net
->proc_first()
265 ; cur
; cur
= net
->proc_next(cur
))
268 /* If the block has no statements, then turn it into a no-op */
270 stmt_cur_
->type_
= IVL_ST_NOOP
;
274 /* If there is exactly one statement, there is no need for the
275 block wrapper, generate the contained statement instead. */
276 if ((count
== 1) && (net
->subscope() == 0)) {
277 return net
->proc_first()->emit_proc(this);
281 /* Handle the general case. The block has some statements in
282 it, so fill in the block fields of the existing statement,
283 and generate the contents for the statement array. */
285 stmt_cur_
->type_
= (net
->type() == NetBlock::SEQU
)
288 stmt_cur_
->u_
.block_
.nstmt_
= count
;
289 stmt_cur_
->u_
.block_
.stmt_
= (struct ivl_statement_s
*)
290 calloc(count
, sizeof(struct ivl_statement_s
));
293 stmt_cur_
->u_
.block_
.scope
= lookup_scope_(net
->subscope());
295 stmt_cur_
->u_
.block_
.scope
= 0;
297 struct ivl_statement_s
*save_cur_
= stmt_cur_
;
301 for (const NetProc
*cur
= net
->proc_first()
302 ; cur
; cur
= net
->proc_next(cur
), idx
+= 1) {
304 stmt_cur_
= save_cur_
->u_
.block_
.stmt_
+ idx
;
305 bool rc
= cur
->emit_proc(this);
308 assert(idx
== count
);
310 stmt_cur_
= save_cur_
;
316 * A case statement is in turn an array of statements with gate
317 * expressions. This builds arrays of the right size and builds the
318 * ivl_expr_t and ivl_statement_s arrays for the substatements.
320 void dll_target::proc_case(const NetCase
*net
)
323 assert(stmt_cur_
->type_
== IVL_ST_NONE
);
324 FILE_NAME(stmt_cur_
, net
);
326 switch (net
->type()) {
328 stmt_cur_
->type_
= IVL_ST_CASE
;
331 stmt_cur_
->type_
= IVL_ST_CASEX
;
334 stmt_cur_
->type_
= IVL_ST_CASEZ
;
337 assert(stmt_cur_
->type_
!= IVL_ST_NONE
);
341 net
->expr()->expr_scan(this);
342 stmt_cur_
->u_
.case_
.cond
= expr_
;
345 /* If the condition expression is a real valued expression,
346 then change the case statement to a CASER statement. */
347 if (stmt_cur_
->u_
.case_
.cond
->value_
== IVL_VT_REAL
)
348 stmt_cur_
->type_
= IVL_ST_CASER
;
350 unsigned ncase
= net
->nitems();
351 stmt_cur_
->u_
.case_
.ncase
= ncase
;
353 stmt_cur_
->u_
.case_
.case_ex
= new ivl_expr_t
[ncase
];
354 stmt_cur_
->u_
.case_
.case_st
= new struct ivl_statement_s
[ncase
];
356 ivl_statement_t save_cur
= stmt_cur_
;
358 for (unsigned idx
= 0 ; idx
< ncase
; idx
+= 1) {
359 const NetExpr
*ex
= net
->expr(idx
);
362 save_cur
->u_
.case_
.case_ex
[idx
] = expr_
;
365 save_cur
->u_
.case_
.case_ex
[idx
] = 0;
368 stmt_cur_
= save_cur
->u_
.case_
.case_st
+ idx
;
369 stmt_cur_
->type_
= IVL_ST_NONE
;
370 if (net
->stat(idx
) == 0) {
371 stmt_cur_
->type_
= IVL_ST_NOOP
;
373 net
->stat(idx
)->emit_proc(this);
377 stmt_cur_
= save_cur
;
380 bool dll_target::proc_cassign(const NetCAssign
*net
)
384 assert(stmt_cur_
->type_
== IVL_ST_NONE
);
385 FILE_NAME(stmt_cur_
, net
);
387 stmt_cur_
->type_
= IVL_ST_CASSIGN
;
389 /* Make the l-value fields. */
390 make_assign_lvals_(net
);
393 net
->rval()->expr_scan(this);
394 stmt_cur_
->u_
.assign_
.rval_
= expr_
;
400 bool dll_target::proc_condit(const NetCondit
*net
)
403 assert(stmt_cur_
->type_
== IVL_ST_NONE
);
404 FILE_NAME(stmt_cur_
, net
);
406 stmt_cur_
->type_
= IVL_ST_CONDIT
;
407 stmt_cur_
->u_
.condit_
.stmt_
= (struct ivl_statement_s
*)
408 calloc(2, sizeof(struct ivl_statement_s
));
411 net
->expr()->expr_scan(this);
412 stmt_cur_
->u_
.condit_
.cond_
= expr_
;
415 ivl_statement_t save_cur_
= stmt_cur_
;
417 stmt_cur_
= save_cur_
->u_
.condit_
.stmt_
+0;
418 bool flag
= net
->emit_recurse_if(this);
420 stmt_cur_
= save_cur_
->u_
.condit_
.stmt_
+1;
421 flag
= flag
&& net
->emit_recurse_else(this);
423 stmt_cur_
= save_cur_
;
427 bool dll_target::proc_deassign(const NetDeassign
*net
)
430 assert(stmt_cur_
->type_
== IVL_ST_NONE
);
431 FILE_NAME(stmt_cur_
, net
);
433 stmt_cur_
->type_
= IVL_ST_DEASSIGN
;
435 /* Make the l-value fields. */
436 make_assign_lvals_(net
);
441 bool dll_target::proc_delay(const NetPDelay
*net
)
444 assert(stmt_cur_
->type_
== IVL_ST_NONE
);
445 FILE_NAME(stmt_cur_
, net
);
447 ivl_statement_t tmp
= (struct ivl_statement_s
*)
448 calloc(1, sizeof(struct ivl_statement_s
));
450 if (const NetExpr
*expr
= net
->expr()) {
452 stmt_cur_
->type_
= IVL_ST_DELAYX
;
454 expr
->expr_scan(this);
455 stmt_cur_
->u_
.delayx_
.expr
= expr_
;
458 stmt_cur_
->u_
.delayx_
.stmt_
= tmp
;
461 stmt_cur_
->type_
= IVL_ST_DELAY
;
462 stmt_cur_
->u_
.delay_
.stmt_
= tmp
;
463 stmt_cur_
->u_
.delay_
.delay_
= net
->delay();
466 ivl_statement_t save_cur_
= stmt_cur_
;
468 bool flag
= net
->emit_proc_recurse(this);
470 /* If the recurse doesn't turn this new item into something,
471 then either it failed or there is no statement
472 there. Either way, draw a no-op into the statement. */
473 if (stmt_cur_
->type_
== IVL_ST_NONE
) {
474 stmt_cur_
->type_
= IVL_ST_NOOP
;
477 stmt_cur_
= save_cur_
;
482 bool dll_target::proc_disable(const NetDisable
*net
)
485 assert(stmt_cur_
->type_
== IVL_ST_NONE
);
486 FILE_NAME(stmt_cur_
, net
);
488 stmt_cur_
->type_
= IVL_ST_DISABLE
;
489 stmt_cur_
->u_
.disable_
.scope
= lookup_scope_(net
->target());
493 bool dll_target::proc_force(const NetForce
*net
)
497 assert(stmt_cur_
->type_
== IVL_ST_NONE
);
499 stmt_cur_
->type_
= IVL_ST_FORCE
;
501 /* Make the l-value fields. */
502 make_assign_lvals_(net
);
505 net
->rval()->expr_scan(this);
506 stmt_cur_
->u_
.assign_
.rval_
= expr_
;
512 void dll_target::proc_forever(const NetForever
*net
)
515 assert(stmt_cur_
->type_
== IVL_ST_NONE
);
516 FILE_NAME(stmt_cur_
, net
);
518 stmt_cur_
->type_
= IVL_ST_FOREVER
;
520 ivl_statement_t tmp
= (struct ivl_statement_s
*)
521 calloc(1, sizeof(struct ivl_statement_s
));
523 ivl_statement_t save_cur_
= stmt_cur_
;
526 net
->emit_recurse(this);
528 save_cur_
->u_
.forever_
.stmt_
= stmt_cur_
;
529 stmt_cur_
= save_cur_
;
532 bool dll_target::proc_release(const NetRelease
*net
)
535 assert(stmt_cur_
->type_
== IVL_ST_NONE
);
536 FILE_NAME(stmt_cur_
, net
);
538 stmt_cur_
->type_
= IVL_ST_RELEASE
;
540 /* Make the l-value fields. */
541 make_assign_lvals_(net
);
546 void dll_target::proc_repeat(const NetRepeat
*net
)
549 assert(stmt_cur_
->type_
== IVL_ST_NONE
);
550 FILE_NAME(stmt_cur_
, net
);
552 stmt_cur_
->type_
= IVL_ST_REPEAT
;
555 net
->expr()->expr_scan(this);
556 stmt_cur_
->u_
.while_
.cond_
= expr_
;
559 ivl_statement_t tmp
= (struct ivl_statement_s
*)
560 calloc(1, sizeof(struct ivl_statement_s
));
562 ivl_statement_t save_cur_
= stmt_cur_
;
565 net
->emit_recurse(this);
567 save_cur_
->u_
.while_
.stmt_
= stmt_cur_
;
568 stmt_cur_
= save_cur_
;
571 void dll_target::proc_stask(const NetSTask
*net
)
573 unsigned nparms
= net
->nparms();
575 assert(stmt_cur_
->type_
== IVL_ST_NONE
);
576 FILE_NAME(stmt_cur_
, net
);
578 stmt_cur_
->type_
= IVL_ST_STASK
;
579 /* System task names are lex_strings strings. */
580 stmt_cur_
->u_
.stask_
.name_
= net
->name();
581 stmt_cur_
->u_
.stask_
.nparm_
= nparms
;
582 stmt_cur_
->u_
.stask_
.parms_
= (ivl_expr_t
*)
583 calloc(nparms
, sizeof(ivl_expr_t
));
585 for (unsigned idx
= 0 ; idx
< nparms
; idx
+= 1) {
587 net
->parm(idx
)->expr_scan(this);
588 stmt_cur_
->u_
.stask_
.parms_
[idx
] = expr_
;
594 bool dll_target::proc_trigger(const NetEvTrig
*net
)
597 assert(stmt_cur_
->type_
== IVL_ST_NONE
);
598 FILE_NAME(stmt_cur_
, net
);
600 stmt_cur_
->type_
= IVL_ST_TRIGGER
;
601 stmt_cur_
->u_
.wait_
.nevent
= 1;
603 /* Locate the event by name. Save the ivl_event_t in the
604 statement so that the generator can find it easily. */
605 const NetEvent
*ev
= net
->event();
606 ivl_scope_t ev_scope
= lookup_scope_(ev
->scope());
608 for (unsigned idx
= 0 ; idx
< ev_scope
->nevent_
; idx
+= 1) {
609 const char*ename
= ivl_event_basename(ev_scope
->event_
[idx
]);
610 if (strcmp(ev
->name(), ename
) == 0) {
611 stmt_cur_
->u_
.wait_
.event
= ev_scope
->event_
[idx
];
620 void dll_target::proc_utask(const NetUTask
*net
)
623 assert(stmt_cur_
->type_
== IVL_ST_NONE
);
624 FILE_NAME(stmt_cur_
, net
);
626 stmt_cur_
->type_
= IVL_ST_UTASK
;
627 stmt_cur_
->u_
.utask_
.def
= lookup_scope_(net
->task());
630 bool dll_target::proc_wait(const NetEvWait
*net
)
633 assert(stmt_cur_
->type_
== IVL_ST_NONE
);
634 FILE_NAME(stmt_cur_
, net
);
636 stmt_cur_
->type_
= IVL_ST_WAIT
;
637 stmt_cur_
->u_
.wait_
.stmt_
= (struct ivl_statement_s
*)
638 calloc(1, sizeof(struct ivl_statement_s
));
640 stmt_cur_
->u_
.wait_
.nevent
= net
->nevents();
641 if (net
->nevents() > 1) {
642 stmt_cur_
->u_
.wait_
.events
= (ivl_event_t
*)
643 calloc(net
->nevents(), sizeof(ivl_event_t
*));
646 for (unsigned edx
= 0 ; edx
< net
->nevents() ; edx
+= 1) {
648 /* Locate the event by name. Save the ivl_event_t in the
649 statement so that the generator can find it easily. */
650 const NetEvent
*ev
= net
->event(edx
);
651 ivl_scope_t ev_scope
= lookup_scope_(ev
->scope());
652 ivl_event_t ev_tmp
=0;
655 assert(ev_scope
->nevent_
> 0);
656 for (unsigned idx
= 0 ; idx
< ev_scope
->nevent_
; idx
+= 1) {
657 const char*ename
= ivl_event_basename(ev_scope
->event_
[idx
]);
658 if (strcmp(ev
->name(), ename
) == 0) {
659 ev_tmp
= ev_scope
->event_
[idx
];
663 // XXX should we assert(ev_tmp)?
665 if (net
->nevents() == 1)
666 stmt_cur_
->u_
.wait_
.event
= ev_tmp
;
668 stmt_cur_
->u_
.wait_
.events
[edx
] = ev_tmp
;
670 /* If this is an event with a probe, then connect up the
671 pins. This wasn't done during the ::event method because
672 the signals weren't scanned yet. */
674 if (ev
->nprobe() >= 1) {
676 unsigned ineg
= ev_tmp
->nany
;
677 unsigned ipos
= ineg
+ ev_tmp
->nneg
;
679 for (unsigned idx
= 0 ; idx
< ev
->nprobe() ; idx
+= 1) {
680 const NetEvProbe
*pr
= ev
->probe(idx
);
683 switch (pr
->edge()) {
684 case NetEvProbe::ANYEDGE
:
686 iany
+= pr
->pin_count();
688 case NetEvProbe::NEGEDGE
:
690 ineg
+= pr
->pin_count();
692 case NetEvProbe::POSEDGE
:
694 ipos
+= pr
->pin_count();
698 for (unsigned bit
= 0
699 ; bit
< pr
->pin_count()
701 ivl_nexus_t nex
= (ivl_nexus_t
)
702 pr
->pin(bit
).nexus()->t_cookie();
704 ev_tmp
->pins
[base
+bit
] = nex
;
710 /* The ivl_statement_t for the wait statement is not complete
711 until we calculate the sub-statement. */
713 ivl_statement_t save_cur_
= stmt_cur_
;
714 stmt_cur_
= stmt_cur_
->u_
.wait_
.stmt_
;
715 bool flag
= net
->emit_recurse(this);
716 if (flag
&& (stmt_cur_
->type_
== IVL_ST_NONE
))
717 stmt_cur_
->type_
= IVL_ST_NOOP
;
719 stmt_cur_
= save_cur_
;
724 void dll_target::proc_while(const NetWhile
*net
)
727 assert(stmt_cur_
->type_
== IVL_ST_NONE
);
728 FILE_NAME(stmt_cur_
, net
);
730 stmt_cur_
->type_
= IVL_ST_WHILE
;
731 stmt_cur_
->u_
.while_
.stmt_
= (struct ivl_statement_s
*)
732 calloc(1, sizeof(struct ivl_statement_s
));
735 net
->expr()->expr_scan(this);
736 stmt_cur_
->u_
.while_
.cond_
= expr_
;
739 /* Now generate the statement of the while loop. We know it is
740 a single statement, and we know that the
741 emit_proc_recurse() will call emit_proc() for it. */
743 ivl_statement_t save_cur_
= stmt_cur_
;
744 stmt_cur_
= save_cur_
->u_
.while_
.stmt_
;
745 net
->emit_proc_recurse(this);
746 stmt_cur_
= save_cur_
;