Implement $ftell, $fseek and $rewind system functions.
[iverilog.git] / t-dll-proc.cc
blob0fa9b2de9c243f84590984a7dbf3fcd19b761abd
1 /*
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
9 * License.
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
20 #ifdef HAVE_CVS_IDENT
21 #ident "$Id: $"
22 #endif
24 # include "config.h"
26 # include <iostream>
28 # include "target.h"
29 # include "ivl_target.h"
30 # include "compiler.h"
31 # include "t-dll.h"
32 #ifdef HAVE_MALLOC_H
33 # include <malloc.h>
34 #endif
35 # include <stdlib.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;
46 break;
47 case NetProcTop::KALWAYS:
48 obj->type_ = IVL_PR_ALWAYS;
49 break;
50 default:
51 assert(0);
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
64 that object.
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_);
72 assert(stmt_cur_);
73 net->statement()->emit_proc(this);
75 assert(stmt_cur_);
76 obj->stmt_ = stmt_cur_;
77 stmt_cur_ = 0;
79 /* Save the process in the design. */
80 obj->next_ = des_.threads_;
81 des_.threads_ = obj;
83 return true;
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_);
93 assert(stmt_cur_);
94 def->proc()->emit_proc(this);
96 assert(stmt_cur_);
97 scope->def = stmt_cur_;
98 stmt_cur_ = 0;
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_);
109 assert(stmt_cur_);
110 def->proc()->emit_proc(this);
112 assert(stmt_cur_);
113 scope->def = stmt_cur_;
114 stmt_cur_ = 0;
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
127 result. */
128 if (const NetNet*ret_sig = def->return_sig()) {
129 scope->port[0] = find_signal(des_, ret_sig);
130 return true;
133 cerr << "?:0" << ": internal error: "
134 << "Function " << net->basename() << " has a return type"
135 << " that I do not understand." << endl;
137 return false;
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)
146 assert(stmt_cur_);
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();
159 if (loff == 0) {
160 cur->loff = 0;
161 } else {
162 loff->expr_scan(this);
163 cur->loff = expr_;
164 expr_ = 0;
167 cur->width_ = asn->lwidth();
169 if (asn->sig()) {
170 cur->type_ = IVL_LVAL_REG;
171 cur->n.sig = find_signal(des_, asn->sig());
173 cur->idx = 0;
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.
178 if (asn->word()) {
179 assert(expr_ == 0);
180 asn->word()->expr_scan(this);
181 cur->type_ = IVL_LVAL_ARR;
182 cur->idx = expr_;
183 expr_ = 0;
185 } else {
186 assert(0);
193 void dll_target::proc_assign(const NetAssign*net)
195 assert(stmt_cur_);
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);
205 assert(expr_ == 0);
206 net->rval()->expr_scan(this);
207 stmt_cur_->u_.assign_.rval_ = expr_;
208 expr_ = 0;
210 const NetExpr*del = net->get_delay();
211 if (del) {
212 del->expr_scan(this);
213 stmt_cur_->u_.assign_.delay = expr_;
214 expr_ = 0;
219 void dll_target::proc_assign_nb(const NetAssignNB*net)
221 const NetExpr* delay_exp = net->get_delay();
222 assert(stmt_cur_);
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. */
232 assert(expr_ == 0);
233 net->rval()->expr_scan(this);
234 stmt_cur_->u_.assign_.rval_ = expr_;
235 expr_ = 0;
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);
242 de->signed_ = 0;
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_;
249 expr_ = 0;
253 bool dll_target::proc_block(const NetBlock*net)
255 assert(stmt_cur_);
256 assert(stmt_cur_->type_ == IVL_ST_NONE);
258 /* First, count the statements in the block. */
259 unsigned count = 0;
260 for (const NetProc*cur = net->proc_first()
261 ; cur ; cur = net->proc_next(cur))
262 count += 1;
264 /* If the block has no statements, then turn it into a no-op */
265 if (count == 0) {
266 stmt_cur_->type_ = IVL_ST_NOOP;
267 return true;
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)
282 ? IVL_ST_BLOCK
283 : IVL_ST_FORK;
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));
288 if (net->subscope())
289 stmt_cur_->u_.block_.scope = lookup_scope_(net->subscope());
290 else
291 stmt_cur_->u_.block_.scope = 0;
293 struct ivl_statement_s*save_cur_ = stmt_cur_;
294 unsigned idx = 0;
295 bool flag = true;
297 for (const NetProc*cur = net->proc_first()
298 ; cur ; cur = net->proc_next(cur), idx += 1) {
299 assert(idx < count);
300 stmt_cur_ = save_cur_->u_.block_.stmt_ + idx;
301 bool rc = cur->emit_proc(this);
302 flag = flag && rc;
304 assert(idx == count);
306 stmt_cur_ = save_cur_;
308 return flag;
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)
318 assert(stmt_cur_);
319 assert(stmt_cur_->type_ == IVL_ST_NONE);
321 switch (net->type()) {
322 case NetCase::EQ:
323 stmt_cur_->type_ = IVL_ST_CASE;
324 break;
325 case NetCase::EQX:
326 stmt_cur_->type_ = IVL_ST_CASEX;
327 break;
328 case NetCase::EQZ:
329 stmt_cur_->type_ = IVL_ST_CASEZ;
330 break;
332 assert(stmt_cur_->type_ != IVL_ST_NONE);
334 assert(expr_ == 0);
335 assert(net->expr());
336 net->expr()->expr_scan(this);
337 stmt_cur_->u_.case_.cond = expr_;
338 expr_ = 0;
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);
355 if (ex) {
356 ex->expr_scan(this);
357 save_cur->u_.case_.case_ex[idx] = expr_;
358 expr_ = 0;
359 } else {
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;
367 } else {
368 net->stat(idx)->emit_proc(this);
372 stmt_cur_ = save_cur;
375 bool dll_target::proc_cassign(const NetCAssign*net)
378 assert(stmt_cur_);
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);
386 assert(expr_ == 0);
387 net->rval()->expr_scan(this);
388 stmt_cur_->u_.assign_.rval_ = expr_;
389 expr_ = 0;
391 return true;
394 bool dll_target::proc_condit(const NetCondit*net)
396 assert(stmt_cur_);
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));
403 assert(expr_ == 0);
404 net->expr()->expr_scan(this);
405 stmt_cur_->u_.condit_.cond_ = expr_;
406 expr_ = 0;
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_;
417 return flag;
420 bool dll_target::proc_deassign(const NetDeassign*net)
422 assert(stmt_cur_);
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);
430 return true;
433 bool dll_target::proc_delay(const NetPDelay*net)
435 assert(stmt_cur_);
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;
444 assert(expr_ == 0);
445 expr->expr_scan(this);
446 stmt_cur_->u_.delayx_.expr = expr_;
447 expr_ = 0;
449 stmt_cur_->u_.delayx_.stmt_ = tmp;
451 } else {
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_;
458 stmt_cur_ = tmp;
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_;
470 return flag;
473 bool dll_target::proc_disable(const NetDisable*net)
475 assert(stmt_cur_);
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());
480 return true;
483 bool dll_target::proc_force(const NetForce*net)
486 assert(stmt_cur_);
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);
494 assert(expr_ == 0);
495 net->rval()->expr_scan(this);
496 stmt_cur_->u_.assign_.rval_ = expr_;
497 expr_ = 0;
499 return true;
502 void dll_target::proc_forever(const NetForever*net)
504 assert(stmt_cur_);
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_;
513 stmt_cur_ = tmp;
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)
523 assert(stmt_cur_);
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);
531 return true;
534 void dll_target::proc_repeat(const NetRepeat*net)
536 assert(stmt_cur_);
537 assert(stmt_cur_->type_ == IVL_ST_NONE);
539 stmt_cur_->type_ = IVL_ST_REPEAT;
541 assert(expr_ == 0);
542 net->expr()->expr_scan(this);
543 stmt_cur_->u_.while_.cond_ = expr_;
544 expr_ = 0;
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_;
550 stmt_cur_ = tmp;
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();
561 assert(stmt_cur_);
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) {
572 if (net->parm(idx))
573 net->parm(idx)->expr_scan(this);
574 stmt_cur_->u_.stask_.parms_[idx] = expr_;
575 expr_ = 0;
580 bool dll_target::proc_trigger(const NetEvTrig*net)
582 assert(stmt_cur_);
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];
597 break;
602 return true;
605 void dll_target::proc_utask(const NetUTask*net)
607 assert(stmt_cur_);
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)
616 assert(stmt_cur_);
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;
637 assert(ev_scope);
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];
643 break;
646 // XXX should we assert(ev_tmp)?
648 if (net->nevents() == 1)
649 stmt_cur_->u_.wait_.event = ev_tmp;
650 else
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) {
658 unsigned iany = 0;
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);
664 unsigned base = 0;
666 switch (pr->edge()) {
667 case NetEvProbe::ANYEDGE:
668 base = iany;
669 iany += pr->pin_count();
670 break;
671 case NetEvProbe::NEGEDGE:
672 base = ineg;
673 ineg += pr->pin_count();
674 break;
675 case NetEvProbe::POSEDGE:
676 base = ipos;
677 ipos += pr->pin_count();
678 break;
681 for (unsigned bit = 0
682 ; bit < pr->pin_count()
683 ; bit += 1) {
684 ivl_nexus_t nex = (ivl_nexus_t)
685 pr->pin(bit).nexus()->t_cookie();
686 assert(nex);
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_;
704 return flag;
707 void dll_target::proc_while(const NetWhile*net)
709 assert(stmt_cur_);
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));
716 assert(expr_ == 0);
717 net->expr()->expr_scan(this);
718 stmt_cur_->u_.while_.cond_ = expr_;
719 expr_ = 0;
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_;