Document the predefined __ICARUS__ macro
[iverilog.git] / tgt-vvp / vvp_process.c
blob6070eeae5de70aef95771e0ae8d4689c2fdaa3d8
1 /*
2 * Copyright (c) 2001-2007 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.
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
19 #ifdef HAVE_CVS_IDENT
20 #ident "$Id: vvp_process.c,v 1.133 2007/02/27 05:13:34 steve Exp $"
21 #endif
23 # include "vvp_priv.h"
24 # include <string.h>
25 # include <assert.h>
26 #ifdef HAVE_MALLOC_H
27 # include <malloc.h>
28 #endif
29 # include <stdlib.h>
31 static int show_statement(ivl_statement_t net, ivl_scope_t sscope);
33 unsigned local_count = 0;
34 unsigned thread_count = 0;
36 static unsigned transient_id = 0;
39 * This file includes the code needed to generate VVP code for
40 * processes. Scopes are already declared, we generate here the
41 * executable code for the processes.
44 unsigned bitchar_to_idx(char bit)
46 switch (bit) {
47 case '0':
48 return 0;
49 case '1':
50 return 1;
51 case 'x':
52 return 2;
53 case 'z':
54 return 3;
55 default:
56 assert(0);
57 return 0;
62 * These functions handle the blocking assignment. Use the %set
63 * instruction to perform the actual assignment, and calculate any
64 * lvalues and rvalues that need calculating.
66 * The set_to_lvariable function takes a particular nexus and generates
67 * the %set statements to assign the value.
69 * The show_stmt_assign function looks at the assign statement, scans
70 * the l-values, and matches bits of the r-value with the correct
71 * nexus.
74 static void set_to_lvariable(ivl_lval_t lval,
75 unsigned bit, unsigned wid)
77 ivl_signal_t sig = ivl_lval_sig(lval);
78 ivl_expr_t part_off_ex = ivl_lval_part_off(lval);
79 unsigned part_off = 0;
81 /* Although Verilog doesn't support it, we'll handle
82 here the case of an l-value part select of an array
83 word if the address is constant. */
84 ivl_expr_t word_ix = ivl_lval_idx(lval);
85 unsigned long use_word = 0;
87 if (part_off_ex == 0) {
88 part_off = 0;
89 } else if (number_is_immediate(part_off_ex, 64)) {
90 part_off = get_number_immediate(part_off_ex);
91 part_off_ex = 0;
94 /* If the word index is a constant expression, then evaluate
95 it to select the word, and pay no further heed to the
96 expression itself. */
97 if (word_ix && number_is_immediate(word_ix, 8*sizeof(use_word))) {
98 use_word = get_number_immediate(word_ix);
99 word_ix = 0;
102 if (ivl_lval_mux(lval))
103 part_off_ex = ivl_lval_mux(lval);
105 if (part_off_ex) {
106 unsigned skip_set = transient_id++;
108 /* There is a mux expression, so this must be a write to
109 a bit-select l-val. Presumably, the x0 index register
110 has been loaded wit the result of the evaluated
111 part select base expression. */
112 assert(!word_ix);
114 draw_eval_expr_into_integer(part_off_ex, 0);
115 fprintf(vvp_out, " %%jmp/1 t_%u, 4;\n", skip_set);
117 fprintf(vvp_out, " %%set/x0 v%p_%lu, %u, %u;\n",
118 sig, use_word, bit, wid);
119 fprintf(vvp_out, "t_%u ;\n", skip_set);
120 /* save_signal width of 0 CLEARS the signal from the
121 lookaside. */
122 save_signal_lookaside(bit, sig, use_word, 0);
124 } else if (part_off>0 || ivl_lval_width(lval)!=ivl_signal_width(sig)) {
125 /* There is no mux expression, but a constant part
126 offset. Load that into index x0 and generate a
127 vector set instruction. */
128 assert(ivl_lval_width(lval) == wid);
129 assert(!word_ix);
131 fprintf(vvp_out, " %%ix/load 0, %u;\n", part_off);
132 fprintf(vvp_out, " %%set/x0 v%p_%lu, %u, %u;\n",
133 sig, use_word, bit, wid);
135 /* save_signal width of 0 CLEARS the signal from the
136 lookaside. */
137 save_signal_lookaside(bit, sig, use_word, 0);
139 } else if (ivl_signal_array_count(sig) > 1) {
141 /* If the word index is a constant, then we can write
142 directly to the word and save the index calculation. */
143 if (word_ix == 0) {
144 if (use_word < ivl_signal_array_count(sig)) {
145 fprintf(vvp_out, " %%set/v v%p_%lu, %u, %u;\n",
146 sig, use_word, bit, wid);
147 } else {
148 fprintf(vvp_out, " ; %%set/v v%p_%lu, %u, %u "
149 "OUT OF BOUNDS\n", sig, use_word, bit, wid);
152 } else {
153 unsigned skip_set = transient_id++;
154 unsigned index_reg = 3;
155 draw_eval_expr_into_integer(word_ix, index_reg);
156 fprintf(vvp_out, " %%jmp/1 t_%u, 4;\n", skip_set);
157 fprintf(vvp_out, " %%ix/load 1, 0;\n");
158 fprintf(vvp_out, " %%set/av v%p, %u, %u;\n",
159 sig, bit, wid);
160 fprintf(vvp_out, "t_%u ;\n", skip_set);
162 /* save_signal width of 0 CLEARS the signal from the
163 lookaside. */
164 save_signal_lookaside(bit, sig, use_word, 0);
167 } else {
168 save_signal_lookaside(bit, sig, use_word, wid);
169 fprintf(vvp_out, " %%set/v v%p_%lu, %u, %u;\n",
170 sig, use_word, bit, wid);
175 static void assign_to_array_word(ivl_signal_t lsig, ivl_expr_t word_ix,
176 unsigned bit, unsigned delay, unsigned width)
178 unsigned skip_assign = transient_id++;
180 /* Calculate array word index into index register 3 */
181 draw_eval_expr_into_integer(word_ix, 3);
182 /* Skip assignment if word expression is not defined. */
183 fprintf(vvp_out, " %%jmp/1 t_%u, 4;\n", skip_assign);
185 /* Store expression width into index word 0 */
186 fprintf(vvp_out, " %%ix/load 0, %u; // word width\n", width);
187 /* Store constant (0) word part select into index 1 */
188 fprintf(vvp_out, " %%ix/load 1, 0;\n");
190 fprintf(vvp_out, " %%assign/av v%p, %u, %u;\n", lsig, delay, bit);
191 fprintf(vvp_out, "t_%u ;\n", skip_assign);
193 clear_expression_lookaside();
196 static void assign_to_lvector(ivl_lval_t lval, unsigned bit,
197 unsigned delay, ivl_expr_t dexp,
198 unsigned width)
200 ivl_signal_t sig = ivl_lval_sig(lval);
201 ivl_expr_t part_off_ex = ivl_lval_part_off(lval);
202 unsigned part_off = 0;
204 ivl_expr_t word_ix = ivl_lval_idx(lval);
205 unsigned long use_word = 0;
207 if (ivl_signal_array_count(sig) > 1) {
208 assert(word_ix);
209 if (! number_is_immediate(word_ix, 8*sizeof(use_word))) {
210 assert(!dexp);
211 assign_to_array_word(sig, word_ix, bit, delay, width);
212 return;
215 use_word = get_number_immediate(word_ix);
218 if (part_off_ex == 0) {
219 part_off = 0;
220 } else if (number_is_immediate(part_off_ex, 64)) {
221 part_off = get_number_immediate(part_off_ex);
222 part_off_ex = 0;
225 if (ivl_lval_mux(lval))
226 part_off_ex = ivl_lval_mux(lval);
228 if (part_off_ex) {
229 unsigned skip_assign = transient_id++;
230 assert(dexp == 0);
231 draw_eval_expr_into_integer(part_off_ex, 1);
232 /* If the index expression has XZ bits, skip the assign. */
233 fprintf(vvp_out, " %%jmp/1 t_%u, 4;\n", skip_assign);
234 fprintf(vvp_out, " %%ix/load 0, %u;\n", width);
235 fprintf(vvp_out, " %%assign/v0/x1 v%p_%lu, %u, %u;\n",
236 sig, use_word, delay, bit);
237 fprintf(vvp_out, "t_%u ;\n", skip_assign);
239 } else if (part_off>0 || ivl_lval_width(lval)!=ivl_signal_width(sig)) {
240 /* There is no mux expression, but a constant part
241 offset. Load that into index x1 and generate a
242 single-bit set instruction. */
243 assert(ivl_lval_width(lval) == width);
245 if (dexp == 0) {
246 /* Constant delay... */
247 fprintf(vvp_out, " %%ix/load 0, %u;\n", width);
248 fprintf(vvp_out, " %%ix/load 1, %u;\n", part_off);
249 fprintf(vvp_out, " %%assign/v0/x1 v%p_%lu, %u, %u;\n",
250 sig, use_word, delay, bit);
252 } else {
253 /* Calculated delay... */
254 int delay_index = allocate_word();
255 draw_eval_expr_into_integer(dexp, delay_index);
256 fprintf(vvp_out, " %%ix/load 0, %u;\n", width);
257 fprintf(vvp_out, " %%ix/load 1, %u;\n", part_off);
258 fprintf(vvp_out, " %%assign/v0/x1/d v%p_%lu, %u, %u;\n",
259 sig, use_word, delay_index, bit);
260 clr_word(delay_index);
263 } else if (dexp != 0) {
264 draw_eval_expr_into_integer(dexp, 1);
265 fprintf(vvp_out, " %%ix/load 0, %u;\n", width);
266 fprintf(vvp_out, " %%assign/v0/d v%p_%lu, 1, %u;\n",
267 sig, use_word, bit);
268 } else {
269 fprintf(vvp_out, " %%ix/load 0, %u;\n", width);
270 fprintf(vvp_out, " %%assign/v0 v%p_%lu, %u, %u;\n",
271 sig, use_word, delay, bit);
277 * This is a private function to generate %set code for the
278 * statement. At this point, the r-value is evaluated and stored in
279 * the res vector, I just need to generate the %set statements for the
280 * l-values of the assignment.
282 static void set_vec_to_lval(ivl_statement_t net, struct vector_info res)
284 ivl_lval_t lval;
286 unsigned wid = res.wid;
287 unsigned lidx;
288 unsigned cur_rbit = 0;
290 for (lidx = 0 ; lidx < ivl_stmt_lvals(net) ; lidx += 1) {
291 unsigned bidx;
292 unsigned bit_limit = wid - cur_rbit;
294 lval = ivl_stmt_lval(net, lidx);
296 /* Reduce bit_limit to the width of this l-value. */
297 if (bit_limit > ivl_lval_width(lval))
298 bit_limit = ivl_lval_width(lval);
300 /* This is the address within the larger r-value of the
301 bit that this l-value takes. */
302 bidx = res.base < 4? res.base : (res.base+cur_rbit);
304 set_to_lvariable(lval, bidx, bit_limit);
306 /* Now we've consumed this many r-value bits for the
307 current l-value. */
308 cur_rbit += bit_limit;
312 static int show_stmt_assign_vector(ivl_statement_t net)
314 ivl_expr_t rval = ivl_stmt_rval(net);
316 /* Handle the special case that the expression is a real
317 value. Evaluate the real expression, then convert the
318 result to a vector. Then store that vector into the
319 l-value. */
320 if (ivl_expr_value(rval) == IVL_VT_REAL) {
321 int word = draw_eval_real(rval);
322 /* This is the accumulated with of the l-value of the
323 assignment. */
324 unsigned wid = ivl_stmt_lwidth(net);
326 struct vector_info vec;
328 vec.base = allocate_vector(wid);
329 vec.wid = wid;
331 fprintf(vvp_out, " %%cvt/vr %u, %d, %u;\n",
332 vec.base, word, vec.wid);
334 clr_word(word);
336 set_vec_to_lval(net, vec);
338 clr_vector(vec);
339 return 0;
343 { struct vector_info res = draw_eval_expr(rval, 0);
344 set_vec_to_lval(net, res);
345 if (res.base > 3)
346 clr_vector(res);
350 return 0;
354 * This function assigns a value to a real .variable. This is destined
355 * for /dev/null when typed ivl_signal_t takes over all the real
356 * variable support.
358 static int show_stmt_assign_sig_real(ivl_statement_t net)
360 int res;
361 ivl_lval_t lval;
362 ivl_signal_t var;
364 res = draw_eval_real(ivl_stmt_rval(net));
365 clr_word(res);
367 assert(ivl_stmt_lvals(net) == 1);
368 lval = ivl_stmt_lval(net, 0);
369 var = ivl_lval_sig(lval);
370 assert(var != 0);
372 assert(ivl_signal_array_count(var) == 1);
374 fprintf(vvp_out, " %%set/wr v%p_0, %d;\n", var, res);
376 return 0;
379 static int show_stmt_assign(ivl_statement_t net)
381 ivl_lval_t lval;
382 ivl_signal_t sig;
384 lval = ivl_stmt_lval(net, 0);
386 sig = ivl_lval_sig(lval);
387 if (sig) switch (ivl_signal_data_type(sig)) {
389 case IVL_VT_REAL:
390 return show_stmt_assign_sig_real(net);
392 default:
393 return show_stmt_assign_vector(net);
395 } else {
396 return show_stmt_assign_vector(net);
399 return 0;
403 * This function handles the case of non-blocking assign to word
404 * variables such as real, i.e:
406 * real foo;
407 * foo <= 1.0;
409 * In this case we know (by Verilog syntax) that there is only exactly
410 * 1 l-value, the target identifier, so it should be relatively easy.
412 static int show_stmt_assign_nb_real(ivl_statement_t net)
414 ivl_lval_t lval;
415 ivl_signal_t sig;
416 ivl_expr_t rval = ivl_stmt_rval(net);
417 ivl_expr_t del = ivl_stmt_delay_expr(net);
418 /* variables for the selection of word from an array. */
419 ivl_expr_t word_ix;
420 unsigned long use_word = 0;
421 /* thread address for a word value. */
422 int word;
423 unsigned long delay;
425 /* Must be exactly 1 l-value. */
426 assert(ivl_stmt_lvals(net) == 1);
428 lval = ivl_stmt_lval(net, 0);
429 sig = ivl_lval_sig(lval);
430 assert(sig);
432 if (ivl_signal_array_count(sig) > 1) {
433 word_ix = ivl_lval_idx(lval);
434 assert(word_ix);
435 assert(number_is_immediate(word_ix, 8*sizeof(use_word)));
436 use_word = get_number_immediate(word_ix);
439 delay = 0;
440 if (del && (ivl_expr_type(del) == IVL_EX_ULONG)) {
441 delay = ivl_expr_uvalue(del);
442 del = 0;
445 /* XXXX For now, presume delays are constant. */
446 assert(del == 0);
448 /* Evaluate the r-value */
449 word = draw_eval_real(rval);
451 fprintf(vvp_out, " %%assign/wr v%p_%lu, %lu, %u;\n",
452 sig, use_word, delay, word);
454 clr_word(word);
456 return 0;
459 static int show_stmt_assign_nb(ivl_statement_t net)
461 ivl_lval_t lval;
462 ivl_expr_t rval = ivl_stmt_rval(net);
463 ivl_expr_t del = ivl_stmt_delay_expr(net);
464 ivl_signal_t sig;
466 unsigned long delay = 0;
468 /* Detect special cases that are handled elsewhere. */
469 lval = ivl_stmt_lval(net,0);
470 if ((sig = ivl_lval_sig(lval))) {
471 switch (ivl_signal_data_type(sig)) {
472 case IVL_VT_REAL:
473 return show_stmt_assign_nb_real(net);
474 default:
475 break;
479 if (del && (ivl_expr_type(del) == IVL_EX_ULONG)) {
480 delay = ivl_expr_uvalue(del);
481 del = 0;
485 { struct vector_info res = draw_eval_expr(rval, 0);
486 unsigned wid = res.wid;
487 unsigned lidx;
488 unsigned cur_rbit = 0;
490 for (lidx = 0 ; lidx < ivl_stmt_lvals(net) ; lidx += 1) {
491 unsigned bit_limit = wid - cur_rbit;
492 lval = ivl_stmt_lval(net, lidx);
494 if (bit_limit > ivl_lval_width(lval))
495 bit_limit = ivl_lval_width(lval);
497 unsigned bidx;
499 bidx = res.base < 4? res.base : (res.base+cur_rbit);
500 assign_to_lvector(lval, bidx, delay, del, bit_limit);
502 cur_rbit += bit_limit;
506 if (res.base > 3)
507 clr_vector(res);
510 return 0;
513 static int show_stmt_block(ivl_statement_t net, ivl_scope_t sscope)
515 int rc = 0;
516 unsigned idx;
517 unsigned cnt = ivl_stmt_block_count(net);
519 for (idx = 0 ; idx < cnt ; idx += 1) {
520 rc += show_statement(ivl_stmt_block_stmt(net, idx), sscope);
523 return rc;
527 * This draws an invocation of a named block. This is a little
528 * different because a subscope is created. We do that by creating
529 * a thread to deal with this.
531 static int show_stmt_block_named(ivl_statement_t net, ivl_scope_t scope)
533 int rc;
534 int out_id, sub_id;
535 ivl_scope_t subscope = ivl_stmt_block_scope(net);
537 out_id = transient_id++;
538 sub_id = transient_id++;
540 fprintf(vvp_out, " %%fork t_%u, S_%p;\n",
541 sub_id, subscope);
542 fprintf(vvp_out, " %%jmp t_%u;\n", out_id);
543 fprintf(vvp_out, "t_%u ;\n", sub_id);
545 /* The statement within the fork is in a new thread, so no
546 expression lookaside is valid. */
547 clear_expression_lookaside();
549 rc = show_stmt_block(net, subscope);
550 fprintf(vvp_out, " %%end;\n");
552 fprintf(vvp_out, "t_%u %%join;\n", out_id);
553 clear_expression_lookaside();
555 return rc;
559 static int show_stmt_case(ivl_statement_t net, ivl_scope_t sscope)
561 ivl_expr_t exp = ivl_stmt_cond_expr(net);
562 struct vector_info cond = draw_eval_expr(exp, 0);
563 unsigned count = ivl_stmt_case_count(net);
565 unsigned local_base = local_count;
567 unsigned idx, default_case;
569 local_count += count + 1;
571 /* First draw the branch table. All the non-default cases
572 generate a branch out of here, to the code that implements
573 the case. The default will fall through all the tests. */
574 default_case = count;
576 for (idx = 0 ; idx < count ; idx += 1) {
577 ivl_expr_t cex = ivl_stmt_case_expr(net, idx);
578 struct vector_info cvec;
580 if (cex == 0) {
581 default_case = idx;
582 continue;
585 /* Is the guard expression something I can pass to a
586 %cmpi/u instruction? If so, use that instead. */
588 if ((ivl_statement_type(net) == IVL_ST_CASE)
589 && (ivl_expr_type(cex) == IVL_EX_NUMBER)
590 && (! number_is_unknown(cex))
591 && number_is_immediate(cex, 16)) {
593 unsigned long imm = get_number_immediate(cex);
595 fprintf(vvp_out, " %%cmpi/u %u, %lu, %u;\n",
596 cond.base, imm, cond.wid);
597 fprintf(vvp_out, " %%jmp/1 T_%d.%d, 6;\n",
598 thread_count, local_base+idx);
600 continue;
603 /* Oh well, do this case the hard way. */
605 cvec = draw_eval_expr_wid(cex, cond.wid, STUFF_OK_RO);
606 assert(cvec.wid == cond.wid);
608 switch (ivl_statement_type(net)) {
610 case IVL_ST_CASE:
611 fprintf(vvp_out, " %%cmp/u %u, %u, %u;\n",
612 cond.base, cvec.base, cond.wid);
613 fprintf(vvp_out, " %%jmp/1 T_%d.%d, 6;\n",
614 thread_count, local_base+idx);
615 break;
617 case IVL_ST_CASEX:
618 fprintf(vvp_out, " %%cmp/x %u, %u, %u;\n",
619 cond.base, cvec.base, cond.wid);
620 fprintf(vvp_out, " %%jmp/1 T_%d.%d, 4;\n",
621 thread_count, local_base+idx);
622 break;
624 case IVL_ST_CASEZ:
625 fprintf(vvp_out, " %%cmp/z %u, %u, %u;\n",
626 cond.base, cvec.base, cond.wid);
627 fprintf(vvp_out, " %%jmp/1 T_%d.%d, 4;\n",
628 thread_count, local_base+idx);
629 break;
631 default:
632 assert(0);
635 /* Done with the case expression */
636 clr_vector(cvec);
639 /* Done with the condition expression */
640 clr_vector(cond);
642 /* Emit code for the default case. */
643 if (default_case < count) {
644 ivl_statement_t cst = ivl_stmt_case_stmt(net, default_case);
645 show_statement(cst, sscope);
648 /* Jump to the out of the case. */
649 fprintf(vvp_out, " %%jmp T_%d.%d;\n", thread_count,
650 local_base+count);
652 for (idx = 0 ; idx < count ; idx += 1) {
653 ivl_statement_t cst = ivl_stmt_case_stmt(net, idx);
655 if (idx == default_case)
656 continue;
658 fprintf(vvp_out, "T_%d.%d ;\n", thread_count, local_base+idx);
659 clear_expression_lookaside();
660 show_statement(cst, sscope);
662 fprintf(vvp_out, " %%jmp T_%d.%d;\n", thread_count,
663 local_base+count);
668 /* The out of the case. */
669 fprintf(vvp_out, "T_%d.%d ;\n", thread_count, local_base+count);
670 clear_expression_lookaside();
672 return 0;
675 static int show_stmt_case_r(ivl_statement_t net, ivl_scope_t sscope)
677 ivl_expr_t exp = ivl_stmt_cond_expr(net);
678 int cond = draw_eval_real(exp);
679 unsigned count = ivl_stmt_case_count(net);
681 unsigned local_base = local_count;
683 unsigned idx, default_case;
685 local_count += count + 1;
688 /* First draw the branch table. All the non-default cases
689 generate a branch out of here, to the code that implements
690 the case. The default will fall through all the tests. */
691 default_case = count;
693 for (idx = 0 ; idx < count ; idx += 1) {
694 ivl_expr_t cex = ivl_stmt_case_expr(net, idx);
695 int cvec;
697 if (cex == 0) {
698 default_case = idx;
699 continue;
702 cvec = draw_eval_real(cex);
704 fprintf(vvp_out, " %%cmp/wr %d, %d;\n", cond, cvec);
705 fprintf(vvp_out, " %%jmp/1 T_%d.%d, 4;\n",
706 thread_count, local_base+idx);
708 /* Done with the guard expression value. */
709 clr_word(cvec);
712 /* Done with the case expression. */
713 clr_word(cond);
715 /* Emit code for the case default. The above jump table will
716 fall through to this statement. */
717 if (default_case < count) {
718 ivl_statement_t cst = ivl_stmt_case_stmt(net, default_case);
719 show_statement(cst, sscope);
722 /* Jump to the out of the case. */
723 fprintf(vvp_out, " %%jmp T_%d.%d;\n", thread_count,
724 local_base+count);
726 for (idx = 0 ; idx < count ; idx += 1) {
727 ivl_statement_t cst = ivl_stmt_case_stmt(net, idx);
729 if (idx == default_case)
730 continue;
732 fprintf(vvp_out, "T_%d.%d ;\n", thread_count, local_base+idx);
733 clear_expression_lookaside();
734 show_statement(cst, sscope);
736 fprintf(vvp_out, " %%jmp T_%d.%d;\n", thread_count,
737 local_base+count);
742 /* The out of the case. */
743 fprintf(vvp_out, "T_%d.%d ;\n", thread_count, local_base+count);
745 return 0;
748 static void force_vector_to_lval(ivl_statement_t net, struct vector_info rvec)
750 unsigned lidx;
751 unsigned roff = 0;
753 const char*command_name;
754 const char*command_name_x0;
756 switch (ivl_statement_type(net)) {
757 case IVL_ST_CASSIGN:
758 command_name = "%cassign/v";
759 command_name_x0 = "ERROR";
760 break;
761 case IVL_ST_FORCE:
762 command_name = "%force/v";
763 command_name_x0 = "%force/x0";
764 break;
765 default:
766 command_name = "ERROR";
767 assert(0);
768 break;
771 for (lidx = 0 ; lidx < ivl_stmt_lvals(net) ; lidx += 1) {
772 ivl_lval_t lval = ivl_stmt_lval(net, lidx);
773 ivl_signal_t lsig = ivl_lval_sig(lval);
775 unsigned use_wid = ivl_lval_width(lval);
776 ivl_expr_t part_off_ex = ivl_lval_part_off(lval);
777 unsigned part_off;
778 ivl_expr_t word_idx = ivl_lval_idx(lval);
779 unsigned long use_word = 0;
781 if (part_off_ex == 0) {
782 part_off = 0;
783 } else {
784 assert(number_is_immediate(part_off_ex, 64));
785 part_off = get_number_immediate(part_off_ex);
788 if (word_idx != 0) {
789 assert(number_is_immediate(word_idx, 8*sizeof(unsigned long)));
790 use_word = get_number_immediate(word_idx);
793 /* L-Value must be a signal: reg or wire */
794 assert(lsig != 0);
796 if (part_off != 0 || use_wid != ivl_signal_width(lsig)) {
798 command_name = command_name_x0;
799 fprintf(vvp_out, " %%ix/load 0, %u;\n", part_off);
801 } else {
802 /* Do not support bit or part selects of l-values yet. */
803 assert(ivl_lval_mux(lval) == 0);
804 assert(ivl_lval_part_off(lval) == 0);
805 assert(ivl_lval_width(lval) == ivl_signal_width(lsig));
807 assert((roff + use_wid) <= rvec.wid);
810 fprintf(vvp_out, " %s v%p_%lu, %u, %u;\n", command_name,
811 lsig, use_word, rvec.base+roff, use_wid);
813 if (rvec.base >= 4)
814 roff += use_wid;
818 static void force_link_rval(ivl_statement_t net, ivl_expr_t rval)
820 ivl_signal_t rsig;;
821 ivl_lval_t lval;
822 ivl_signal_t lsig;
823 const char*command_name;
825 ivl_expr_t lword_idx, rword_idx;
826 unsigned long use_lword = 0, use_rword = 0;
828 if (ivl_expr_type(rval) != IVL_EX_SIGNAL)
829 return;
831 switch (ivl_statement_type(net)) {
832 case IVL_ST_CASSIGN:
833 command_name = "%cassign";
834 break;
835 case IVL_ST_FORCE:
836 command_name = "%force";
837 break;
838 default:
839 command_name = "ERROR";
840 assert(0);
841 break;
844 rsig = ivl_expr_signal(rval);
845 assert(ivl_stmt_lvals(net) == 1);
846 lval = ivl_stmt_lval(net, 0);
847 lsig = ivl_lval_sig(lval);
849 /* At least for now, only handle force to fixed words of an array. */
850 if ((lword_idx = ivl_lval_idx(lval)) != 0) {
851 assert(number_is_immediate(lword_idx, 8*sizeof(unsigned long)));
852 use_lword = get_number_immediate(lword_idx);
855 if ((rword_idx = ivl_expr_oper1(rval)) != 0) {
856 assert(number_is_immediate(rword_idx, 8*sizeof(unsigned long)));
857 use_rword = get_number_immediate(rword_idx);
860 assert(ivl_signal_array_count(rsig) == 1);
861 use_rword = 0;
863 fprintf(vvp_out, " %s/link", command_name);
864 fprintf(vvp_out, " v%p_%lu", lsig, use_lword);
865 fprintf(vvp_out, ", v%p_%lu;\n", rsig, use_rword);
868 static int show_stmt_cassign(ivl_statement_t net)
870 ivl_expr_t rval;
871 struct vector_info rvec;
873 rval = ivl_stmt_rval(net);
874 assert(rval);
876 rvec = draw_eval_expr(rval, STUFF_OK_47);
878 /* Write out initial continuous assign instructions to assign
879 the expression value to the l-value. */
880 force_vector_to_lval(net, rvec);
882 force_link_rval(net, rval);
884 return 0;
888 * Handle the deassign similar to cassign. The lvals must all be
889 * vectors without bit or part selects. Simply call %deassign for all
890 * the values.
892 static int show_stmt_deassign(ivl_statement_t net)
894 unsigned lidx;
896 for (lidx = 0 ; lidx < ivl_stmt_lvals(net) ; lidx += 1) {
897 ivl_lval_t lval = ivl_stmt_lval(net, lidx);
898 ivl_signal_t lsig = ivl_lval_sig(lval);
900 ivl_expr_t word_idx = ivl_lval_idx(lval);
901 unsigned long use_word = 0;
903 assert(lsig != 0);
904 assert(ivl_lval_mux(lval) == 0);
905 assert(ivl_lval_part_off(lval) == 0);
907 if (word_idx != 0) {
908 assert(number_is_immediate(word_idx, 8*sizeof(use_word)));
909 use_word = get_number_immediate(word_idx);
913 fprintf(vvp_out, " %%deassign v%p_%lu;\n", lsig, use_word);
916 return 0;
919 static int show_stmt_condit(ivl_statement_t net, ivl_scope_t sscope)
921 int rc = 0;
922 unsigned lab_false, lab_out;
923 ivl_expr_t exp = ivl_stmt_cond_expr(net);
924 struct vector_info cond
925 = draw_eval_expr(exp, STUFF_OK_XZ|STUFF_OK_47|STUFF_OK_RO);
927 assert(cond.wid == 1);
929 lab_false = local_count++;
930 lab_out = local_count++;
932 fprintf(vvp_out, " %%jmp/0xz T_%d.%d, %u;\n",
933 thread_count, lab_false, cond.base);
935 /* Done with the condition expression. */
936 if (cond.base >= 8)
937 clr_vector(cond);
939 if (ivl_stmt_cond_true(net))
940 rc += show_statement(ivl_stmt_cond_true(net), sscope);
943 if (ivl_stmt_cond_false(net)) {
944 fprintf(vvp_out, " %%jmp T_%d.%d;\n", thread_count, lab_out);
945 fprintf(vvp_out, "T_%d.%u ;\n", thread_count, lab_false);
946 clear_expression_lookaside();
948 rc += show_statement(ivl_stmt_cond_false(net), sscope);
950 fprintf(vvp_out, "T_%d.%u ;\n", thread_count, lab_out);
951 clear_expression_lookaside();
953 } else {
954 fprintf(vvp_out, "T_%d.%u ;\n", thread_count, lab_false);
955 clear_expression_lookaside();
958 return rc;
962 * The delay statement is easy. Simply write a ``%delay <n>''
963 * instruction to delay the thread, then draw the included statement.
964 * The delay statement comes from verilog code like this:
966 * ...
967 * #<delay> <stmt>;
969 static int show_stmt_delay(ivl_statement_t net, ivl_scope_t sscope)
971 int rc = 0;
972 uint64_t delay = ivl_stmt_delay_val(net);
973 ivl_statement_t stmt = ivl_stmt_sub_stmt(net);
975 unsigned long low = delay % UINT64_C(0x100000000);
976 unsigned long hig = delay / UINT64_C(0x100000000);
978 fprintf(vvp_out, " %%delay %lu, %lu;\n", low, hig);
979 /* Lots of things can happen during a delay. */
980 clear_expression_lookaside();
982 rc += show_statement(stmt, sscope);
984 return rc;
988 * The delayx statement is slightly more complex in that it is
989 * necessary to calculate the delay first. Load the calculated delay
990 * into and index register and use the %delayx instruction to do the
991 * actual delay.
993 static int show_stmt_delayx(ivl_statement_t net, ivl_scope_t sscope)
995 int rc = 0;
996 ivl_expr_t exp = ivl_stmt_delay_expr(net);
997 ivl_statement_t stmt = ivl_stmt_sub_stmt(net);
999 switch (ivl_expr_value(exp)) {
1001 case IVL_VT_BOOL:
1002 case IVL_VT_LOGIC: {
1003 struct vector_info del = draw_eval_expr(exp, 0);
1004 fprintf(vvp_out, " %%ix/get 0, %u, %u;\n",
1005 del.base, del.wid);
1006 clr_vector(del);
1007 break;
1010 case IVL_VT_REAL: {
1011 int word = draw_eval_real(exp);
1012 fprintf(vvp_out, " %%cvt/ir 0, %d;\n", word);
1013 clr_word(word);
1014 break;
1017 default:
1018 assert(0);
1021 fprintf(vvp_out, " %%delayx 0;\n");
1022 /* Lots of things can happen during a delay. */
1023 clear_expression_lookaside();
1025 rc += show_statement(stmt, sscope);
1026 return rc;
1029 static int show_stmt_disable(ivl_statement_t net, ivl_scope_t sscope)
1031 int rc = 0;
1033 ivl_scope_t target = ivl_stmt_call(net);
1034 fprintf(vvp_out, " %%disable S_%p;\n", target);
1036 return rc;
1039 static int show_stmt_force(ivl_statement_t net)
1041 ivl_expr_t rval;
1042 struct vector_info rvec;
1044 rval = ivl_stmt_rval(net);
1045 assert(rval);
1047 rvec = draw_eval_expr(rval, STUFF_OK_47);
1049 /* Write out initial continuous assign instructions to assign
1050 the expression value to the l-value. */
1051 force_vector_to_lval(net, rvec);
1053 force_link_rval(net, rval);
1055 return 0;
1058 static int show_stmt_forever(ivl_statement_t net, ivl_scope_t sscope)
1060 int rc = 0;
1061 ivl_statement_t stmt = ivl_stmt_sub_stmt(net);
1062 unsigned lab_top = local_count++;
1064 fprintf(vvp_out, "T_%u.%u ;\n", thread_count, lab_top);
1065 rc += show_statement(stmt, sscope);
1066 fprintf(vvp_out, " %%jmp T_%u.%u;\n", thread_count, lab_top);
1068 return rc;
1071 static int show_stmt_fork(ivl_statement_t net, ivl_scope_t sscope)
1073 unsigned idx;
1074 int rc = 0;
1075 unsigned cnt = ivl_stmt_block_count(net);
1076 ivl_scope_t scope = ivl_stmt_block_scope(net);
1078 unsigned out = transient_id++;
1079 unsigned id_base = transient_id;
1081 /* cnt is the number of sub-threads. If the fork-join has no
1082 name, then we can put one of the sub-threads in the current
1083 thread, so decrement the count by one. */
1084 if (scope == 0) {
1085 cnt -= 1;
1086 scope = sscope;
1089 transient_id += cnt;
1091 /* If no subscope use provided */
1092 if (!scope) scope = sscope;
1094 /* Draw a fork statement for all but one of the threads of the
1095 fork/join. Send the threads off to a bit of code where they
1096 are implemented. */
1097 for (idx = 0 ; idx < cnt ; idx += 1) {
1098 fprintf(vvp_out, " %%fork t_%u, S_%p;\n",
1099 id_base+idx, scope);
1102 /* If we are putting one sub-thread into the current thread,
1103 then draw its code here. */
1104 if (ivl_stmt_block_scope(net) == 0)
1105 rc += show_statement(ivl_stmt_block_stmt(net, cnt), scope);
1108 /* Generate enough joins to collect all the sub-threads. */
1109 for (idx = 0 ; idx < cnt ; idx += 1) {
1110 fprintf(vvp_out, " %%join;\n");
1112 fprintf(vvp_out, " %%jmp t_%u;\n", out);
1114 /* Generate the sub-threads themselves. */
1115 for (idx = 0 ; idx < cnt ; idx += 1) {
1116 fprintf(vvp_out, "t_%u ;\n", id_base+idx);
1117 clear_expression_lookaside();
1118 rc += show_statement(ivl_stmt_block_stmt(net, idx), scope);
1119 fprintf(vvp_out, " %%end;\n");
1122 /* This is the label for the out. Use this to branch around
1123 the implementations of all the child threads. */
1124 clear_expression_lookaside();
1125 fprintf(vvp_out, "t_%u ;\n", out);
1127 return rc;
1131 * noop statements are implemented by doing nothing.
1133 static int show_stmt_noop(ivl_statement_t net)
1135 return 0;
1138 static int show_stmt_release(ivl_statement_t net)
1140 unsigned lidx;
1142 for (lidx = 0 ; lidx < ivl_stmt_lvals(net) ; lidx += 1) {
1143 ivl_lval_t lval = ivl_stmt_lval(net, lidx);
1144 ivl_signal_t lsig = ivl_lval_sig(lval);
1145 const char*opcode = 0;
1147 ivl_expr_t word_idx = ivl_lval_idx(lval);
1148 unsigned long use_word = 0;
1149 assert(lsig != 0);
1150 assert(ivl_lval_mux(lval) == 0);
1151 assert(ivl_lval_part_off(lval) == 0);
1153 switch (ivl_signal_type(lsig)) {
1154 case IVL_SIT_REG:
1155 opcode = "reg";
1156 break;
1157 default:
1158 opcode = "net";
1159 break;
1162 if (word_idx != 0) {
1163 assert(number_is_immediate(word_idx, 8*sizeof(use_word)));
1164 use_word = get_number_immediate(word_idx);
1167 /* Generate the appropriate release statement for this
1168 l-value. */
1169 fprintf(vvp_out, " %%release/%s v%p_%lu;\n",
1170 opcode, lsig, use_word);
1173 return 0;
1176 static int show_stmt_repeat(ivl_statement_t net, ivl_scope_t sscope)
1178 int rc = 0;
1179 unsigned lab_top = local_count++, lab_out = local_count++;
1180 ivl_expr_t exp = ivl_stmt_cond_expr(net);
1181 struct vector_info cnt = draw_eval_expr(exp, 0);
1183 /* Test that 0 < expr */
1184 fprintf(vvp_out, "T_%u.%u %%cmp/u 0, %u, %u;\n", thread_count,
1185 lab_top, cnt.base, cnt.wid);
1186 clear_expression_lookaside();
1187 fprintf(vvp_out, " %%jmp/0xz T_%u.%u, 5;\n", thread_count, lab_out);
1188 /* This adds -1 (all ones in 2's complement) to the count. */
1189 fprintf(vvp_out, " %%add %u, 1, %u;\n", cnt.base, cnt.wid);
1191 rc += show_statement(ivl_stmt_sub_stmt(net), sscope);
1193 fprintf(vvp_out, " %%jmp T_%u.%u;\n", thread_count, lab_top);
1194 fprintf(vvp_out, "T_%u.%u ;\n", thread_count, lab_out);
1195 clear_expression_lookaside();
1197 clr_vector(cnt);
1199 return rc;
1203 * The trigger statement is straight forward. All we have to do is
1204 * write a single bit of fake data to the event object.
1206 static int show_stmt_trigger(ivl_statement_t net)
1208 ivl_event_t ev = ivl_stmt_events(net, 0);
1209 assert(ev);
1210 fprintf(vvp_out, " %%set/v E_%p, 0,1;\n", ev);
1211 return 0;
1214 static int show_stmt_utask(ivl_statement_t net)
1216 ivl_scope_t task = ivl_stmt_call(net);
1218 fprintf(vvp_out, " %%fork TD_%s",
1219 vvp_mangle_id(ivl_scope_name(task)));
1220 fprintf(vvp_out, ", S_%p;\n", task);
1221 fprintf(vvp_out, " %%join;\n");
1222 clear_expression_lookaside();
1223 return 0;
1226 static int show_stmt_wait(ivl_statement_t net, ivl_scope_t sscope)
1228 if (ivl_stmt_nevent(net) == 1) {
1229 ivl_event_t ev = ivl_stmt_events(net, 0);
1230 fprintf(vvp_out, " %%wait E_%p;\n", ev);
1232 } else {
1233 unsigned idx;
1234 static unsigned int cascade_counter = 0;
1235 ivl_event_t ev = ivl_stmt_events(net, 0);
1236 fprintf(vvp_out, "Ewait_%u .event/or E_%p", cascade_counter, ev);
1238 for (idx = 1 ; idx < ivl_stmt_nevent(net) ; idx += 1) {
1239 ev = ivl_stmt_events(net, idx);
1240 fprintf(vvp_out, ", E_%p", ev);
1242 fprintf(vvp_out, ";\n %%wait Ewait_%u;\n", cascade_counter);
1243 cascade_counter += 1;
1245 /* Always clear the expression lookaside after a
1246 %wait. Anything can happen while the thread is waiting. */
1247 clear_expression_lookaside();
1249 return show_statement(ivl_stmt_sub_stmt(net), sscope);
1252 static struct vector_info reduction_or(struct vector_info cvec)
1254 struct vector_info result;
1256 switch (cvec.base) {
1257 case 0:
1258 result.base = 0;
1259 result.wid = 1;
1260 break;
1261 case 1:
1262 result.base = 1;
1263 result.wid = 1;
1264 break;
1265 case 2:
1266 case 3:
1267 result.base = 0;
1268 result.wid = 1;
1269 break;
1270 default:
1271 clr_vector(cvec);
1272 result.base = allocate_vector(1);
1273 result.wid = 1;
1274 fprintf(vvp_out, " %%or/r %u, %u, %u;\n", result.base,
1275 cvec.base, cvec.wid);
1276 break;
1279 return result;
1282 static int show_stmt_while(ivl_statement_t net, ivl_scope_t sscope)
1284 int rc = 0;
1285 struct vector_info cvec;
1287 unsigned top_label = local_count++;
1288 unsigned out_label = local_count++;
1290 /* Start the loop. The top of the loop starts a basic block
1291 because it can be entered from above or from the bottom of
1292 the loop. */
1293 fprintf(vvp_out, "T_%d.%d ;\n", thread_count, top_label);
1294 clear_expression_lookaside();
1296 /* Draw the evaluation of the condition expression, and test
1297 the result. If the expression evaluates to false, then
1298 branch to the out label. */
1299 cvec = draw_eval_expr(ivl_stmt_cond_expr(net), STUFF_OK_XZ|STUFF_OK_47);
1300 if (cvec.wid > 1)
1301 cvec = reduction_or(cvec);
1303 fprintf(vvp_out, " %%jmp/0xz T_%d.%d, %u;\n",
1304 thread_count, out_label, cvec.base);
1305 if (cvec.base >= 8)
1306 clr_vector(cvec);
1308 /* Draw the body of the loop. */
1309 rc += show_statement(ivl_stmt_sub_stmt(net), sscope);
1311 /* This is the bottom of the loop. branch to the top where the
1312 test is repeated, and also draw the out label. */
1313 fprintf(vvp_out, " %%jmp T_%d.%d;\n", thread_count, top_label);
1314 fprintf(vvp_out, "T_%d.%d ;\n", thread_count, out_label);
1315 clear_expression_lookaside();
1316 return rc;
1319 static int show_system_task_call(ivl_statement_t net)
1321 unsigned parm_count = ivl_stmt_parm_count(net);
1323 if (parm_count == 0) {
1324 fprintf(vvp_out, " %%vpi_call \"%s\";\n", ivl_stmt_name(net));
1325 clear_expression_lookaside();
1326 return 0;
1329 draw_vpi_task_call(net);
1331 /* VPI calls can manipulate anything, so clear the expression
1332 lookahead table after the call. */
1333 clear_expression_lookaside();
1335 return 0;
1339 * This function draws a statement as vvp assembly. It basically
1340 * switches on the statement type and draws code based on the type and
1341 * further specifics.
1343 static int show_statement(ivl_statement_t net, ivl_scope_t sscope)
1345 const ivl_statement_type_t code = ivl_statement_type(net);
1346 int rc = 0;
1348 switch (code) {
1350 case IVL_ST_ASSIGN:
1351 rc += show_stmt_assign(net);
1352 break;
1354 case IVL_ST_ASSIGN_NB:
1355 rc += show_stmt_assign_nb(net);
1356 break;
1358 case IVL_ST_BLOCK:
1359 if (ivl_stmt_block_scope(net))
1360 rc += show_stmt_block_named(net, sscope);
1361 else
1362 rc += show_stmt_block(net, sscope);
1363 break;
1365 case IVL_ST_CASE:
1366 case IVL_ST_CASEX:
1367 case IVL_ST_CASEZ:
1368 rc += show_stmt_case(net, sscope);
1369 break;
1371 case IVL_ST_CASER:
1372 rc += show_stmt_case_r(net, sscope);
1373 break;
1375 case IVL_ST_CASSIGN:
1376 rc += show_stmt_cassign(net);
1377 break;
1379 case IVL_ST_CONDIT:
1380 rc += show_stmt_condit(net, sscope);
1381 break;
1383 case IVL_ST_DEASSIGN:
1384 rc += show_stmt_deassign(net);
1385 break;
1387 case IVL_ST_DELAY:
1388 rc += show_stmt_delay(net, sscope);
1389 break;
1391 case IVL_ST_DELAYX:
1392 rc += show_stmt_delayx(net, sscope);
1393 break;
1395 case IVL_ST_DISABLE:
1396 rc += show_stmt_disable(net, sscope);
1397 break;
1399 case IVL_ST_FORCE:
1400 rc += show_stmt_force(net);
1401 break;
1403 case IVL_ST_FOREVER:
1404 rc += show_stmt_forever(net, sscope);
1405 break;
1407 case IVL_ST_FORK:
1408 rc += show_stmt_fork(net, sscope);
1409 break;
1411 case IVL_ST_NOOP:
1412 rc += show_stmt_noop(net);
1413 break;
1415 case IVL_ST_RELEASE:
1416 rc += show_stmt_release(net);
1417 break;
1419 case IVL_ST_REPEAT:
1420 rc += show_stmt_repeat(net, sscope);
1421 break;
1423 case IVL_ST_STASK:
1424 rc += show_system_task_call(net);
1425 break;
1427 case IVL_ST_TRIGGER:
1428 rc += show_stmt_trigger(net);
1429 break;
1431 case IVL_ST_UTASK:
1432 rc += show_stmt_utask(net);
1433 break;
1435 case IVL_ST_WAIT:
1436 rc += show_stmt_wait(net, sscope);
1437 break;
1439 case IVL_ST_WHILE:
1440 rc += show_stmt_while(net, sscope);
1441 break;
1443 default:
1444 fprintf(stderr, "vvp.tgt: Unable to draw statement type %u\n",
1445 code);
1446 rc += 1;
1447 break;
1450 return rc;
1455 * The process as a whole is surrounded by this code. We generate a
1456 * start label that the .thread statement can use, and we generate
1457 * code to terminate the thread.
1460 int draw_process(ivl_process_t net, void*x)
1462 int rc = 0;
1463 unsigned idx;
1464 ivl_scope_t scope = ivl_process_scope(net);
1465 ivl_statement_t stmt = ivl_process_stmt(net);
1467 int push_flag = 0;
1469 for (idx = 0 ; idx < ivl_process_attr_cnt(net) ; idx += 1) {
1471 ivl_attribute_t attr = ivl_process_attr_val(net, idx);
1473 if (strcmp(attr->key, "_ivl_schedule_push") == 0) {
1475 push_flag = 1;
1477 } else if (strcmp(attr->key, "ivl_combinational") == 0) {
1479 push_flag = 1;
1484 local_count = 0;
1485 fprintf(vvp_out, " .scope S_%p;\n", scope);
1487 /* Generate the entry label. Just give the thread a number so
1488 that we ar certain the label is unique. */
1489 fprintf(vvp_out, "T_%d ;\n", thread_count);
1490 clear_expression_lookaside();
1492 /* Draw the contents of the thread. */
1493 rc += show_statement(stmt, scope);
1496 /* Terminate the thread with either an %end instruction (initial
1497 statements) or a %jmp back to the beginning of the thread. */
1499 switch (ivl_process_type(net)) {
1501 case IVL_PR_INITIAL:
1502 fprintf(vvp_out, " %%end;\n");
1503 break;
1505 case IVL_PR_ALWAYS:
1506 fprintf(vvp_out, " %%jmp T_%d;\n", thread_count);
1507 break;
1510 /* Now write out the .thread directive that tells vvp where
1511 the thread starts. */
1513 if (push_flag) {
1514 fprintf(vvp_out, " .thread T_%d, $push;\n", thread_count);
1515 } else {
1516 fprintf(vvp_out, " .thread T_%d;\n", thread_count);
1519 thread_count += 1;
1520 return rc;
1523 int draw_task_definition(ivl_scope_t scope)
1525 int rc = 0;
1526 ivl_statement_t def = ivl_scope_def(scope);
1528 fprintf(vvp_out, "TD_%s ;\n", vvp_mangle_id(ivl_scope_name(scope)));
1529 clear_expression_lookaside();
1531 assert(def);
1532 rc += show_statement(def, scope);
1534 fprintf(vvp_out, " %%end;\n");
1536 thread_count += 1;
1537 return rc;
1540 int draw_func_definition(ivl_scope_t scope)
1542 int rc = 0;
1543 ivl_statement_t def = ivl_scope_def(scope);
1545 fprintf(vvp_out, "TD_%s ;\n", vvp_mangle_id(ivl_scope_name(scope)));
1546 clear_expression_lookaside();
1548 assert(def);
1549 rc += show_statement(def, scope);
1551 fprintf(vvp_out, " %%end;\n");
1553 thread_count += 1;
1554 return rc;
1558 * $Log: vvp_process.c,v $
1559 * Revision 1.133 2007/02/27 05:13:34 steve
1560 * Do not assign to words constant-indexed out of range.
1562 * Revision 1.132 2007/02/26 19:49:50 steve
1563 * Spelling fixes (larry doolittle)
1565 * Revision 1.131 2007/02/26 01:51:40 steve
1566 * Prevent lost of width while calculation address.
1568 * Revision 1.130 2007/02/02 04:48:49 steve
1569 * Lookaside is invalid when working a new scope.
1571 * Revision 1.129 2007/01/19 02:30:19 steve
1572 * Fix bad lookaside references in vvp thread code generator.
1574 * Revision 1.128 2007/01/17 04:39:18 steve
1575 * Remove dead code related to memories.
1577 * Revision 1.127 2007/01/16 05:44:16 steve
1578 * Major rework of array handling. Memories are replaced with the
1579 * more general concept of arrays. The NetMemory and NetEMemory
1580 * classes are removed from the ivl core program, and the IVL_LPM_RAM
1581 * lpm type is removed from the ivl_target API.
1583 * Revision 1.126 2006/10/05 01:37:34 steve
1584 * Remove dead code.
1586 * Revision 1.125 2006/10/05 01:23:53 steve
1587 * Handle non-constant delays on indexed non-blocking assignments.
1589 * Revision 1.124 2006/08/08 05:11:37 steve
1590 * Handle 64bit delay constants.
1592 * Revision 1.123 2006/04/16 00:15:43 steve
1593 * Fix part selects in l-values.
1595 * Revision 1.122 2006/02/02 02:43:59 steve
1596 * Allow part selects of memory words in l-values.
1598 * Revision 1.121 2005/11/26 17:23:17 steve
1599 * Handle indexed l-value to force.
1601 * Revision 1.120 2005/11/26 00:35:44 steve
1602 * More precise about r-value width of constants.
1604 * Revision 1.119 2005/10/12 17:26:01 steve
1605 * force l-values do not support bit/part select.
1607 * Revision 1.118 2005/10/11 18:30:50 steve
1608 * Remove obsolete vvp_memory_label function.
1610 * Revision 1.117 2005/09/17 01:01:00 steve
1611 * More robust use of precalculated expressions, and
1612 * Separate lookaside for written variables that can
1613 * also be reused.
1615 * Revision 1.116 2005/09/14 02:53:15 steve
1616 * Support bool expressions and compares handle them optimally.
1618 * Revision 1.115 2005/07/11 16:56:51 steve
1619 * Remove NetVariable and ivl_variable_t structures.
1621 * Revision 1.114 2005/07/07 16:22:50 steve
1622 * Generalize signals to carry types.
1624 * Revision 1.113 2005/06/15 01:33:33 steve
1625 * Fix bit offsets when processing lval concatenation.
1627 * Revision 1.112 2005/06/14 01:45:05 steve
1628 * Add the assign_v0_d instruction.
1630 * Revision 1.111 2005/06/02 16:03:47 steve
1631 * Support %force/link
1633 * Revision 1.110 2005/05/24 02:31:18 steve
1634 * Handle assignments to part-select l-values.
1636 * Revision 1.109 2005/05/17 20:55:42 steve
1637 * Detect bit selects that need special handling.
1639 * Revision 1.108 2005/05/09 00:38:12 steve
1640 * Skip assign if index is invalid.
1642 * Revision 1.107 2005/05/07 03:16:31 steve
1643 * Better handle assignment to bit/part select.
1645 * Revision 1.106 2005/05/01 22:04:12 steve
1646 * Link signals that are source of procedural continuous assign.
1648 * Revision 1.105 2005/03/22 05:18:34 steve
1649 * The indexed set can write a vector, not just a bit.
1651 * Revision 1.104 2005/03/06 17:07:48 steve
1652 * Non blocking assign to memory words.
1654 * Revision 1.103 2005/03/05 05:47:42 steve
1655 * Handle memory words in l-value concatenations.
1657 * Revision 1.102 2005/03/03 04:34:42 steve
1658 * Rearrange how memories are supported as vvp_vector4 arrays.
1660 * Revision 1.101 2005/02/15 07:12:55 steve
1661 * Support constant part select writes to l-values, and large part select reads from signals.
1663 * Revision 1.100 2005/02/14 05:00:11 steve
1664 * Handle bitmux lvalues for constant r-values.
1666 * Revision 1.99 2005/02/14 01:51:39 steve
1667 * Handle bit selects in l-values to assignments.
1669 * Revision 1.98 2005/01/28 19:39:03 steve
1670 * Integrate fixes from 0.8 branch.
1672 * Revision 1.93.2.2 2005/01/28 18:29:29 steve
1673 * Add ability to compile real values into index registers.
1675 * Revision 1.93.2.1 2004/12/12 04:25:10 steve
1676 * Fix leak of word registers in code generator.
1678 * Revision 1.93 2004/10/04 01:10:57 steve
1679 * Clean up spurious trailing white space.
1681 * Revision 1.92 2004/05/19 03:25:42 steve
1682 * Generate code for nb assign to reals.
1684 * Revision 1.91 2003/12/03 02:46:24 steve
1685 * Add support for wait on list of named events.
1687 * Revision 1.90 2003/10/25 02:07:57 steve
1688 * vvp_signal_label does not return a unique string.
1690 * Revision 1.89 2003/09/04 20:28:06 steve
1691 * Support time0 resolution of combinational threads.
1693 * Revision 1.88 2003/07/29 05:12:10 steve
1694 * All the threads of a named fork go into sub-scope.
1696 * Revision 1.87 2003/05/26 04:45:37 steve
1697 * Use set/x0/x if the target vector is too wide for set/x0.
1699 * Revision 1.86 2003/05/17 04:38:19 steve
1700 * Account for nested fork scopes in disable.
1702 * Revision 1.85 2003/05/14 05:26:41 steve
1703 * Support real expressions in case statements.
1705 * Revision 1.84 2003/03/25 02:15:48 steve
1706 * Use hash code for scope labels.
1708 * Revision 1.83 2003/03/15 04:45:18 steve
1709 * Allow real-valued vpi functions to have arguments.
1711 * Revision 1.82 2003/03/06 01:17:46 steve
1712 * Use number for event labels.