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)
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
20 #ident "$Id: vvp_process.c,v 1.133 2007/02/27 05:13:34 steve Exp $"
23 # include "vvp_priv.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
)
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
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) {
89 } else if (number_is_immediate(part_off_ex
, 64)) {
90 part_off
= get_number_immediate(part_off_ex
);
94 /* If the word index is a constant expression, then evaluate
95 it to select the word, and pay no further heed to the
97 if (word_ix
&& number_is_immediate(word_ix
, 8*sizeof(use_word
))) {
98 use_word
= get_number_immediate(word_ix
);
102 if (ivl_lval_mux(lval
))
103 part_off_ex
= ivl_lval_mux(lval
);
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. */
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
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
);
130 /* If the word index is a constant, then we can write
131 directly to the word and save the index calculation. */
133 fprintf(vvp_out
, " %%ix/load 0, %u;\n", part_off
);
134 fprintf(vvp_out
, " %%set/x0 v%p_%lu, %u, %u;\n",
135 sig
, use_word
, bit
, wid
);
138 unsigned skip_set
= transient_id
++;
139 unsigned index_reg
= 3;
140 draw_eval_expr_into_integer(word_ix
, index_reg
);
141 fprintf(vvp_out
, " %%jmp/1 t_%u, 4;\n", skip_set
);
142 fprintf(vvp_out
, " %%ix/load 1, %u;\n", part_off
);
143 fprintf(vvp_out
, " %%set/av v%p, %u, %u;\n",
145 fprintf(vvp_out
, "t_%u ;\n", skip_set
);
147 /* save_signal width of 0 CLEARS the signal from the
149 save_signal_lookaside(bit
, sig
, use_word
, 0);
151 } else if (ivl_signal_array_count(sig
) > 1) {
153 /* If the word index is a constant, then we can write
154 directly to the word and save the index calculation. */
156 if (use_word
< ivl_signal_array_count(sig
)) {
157 fprintf(vvp_out
, " %%set/v v%p_%lu, %u, %u;\n",
158 sig
, use_word
, bit
, wid
);
160 fprintf(vvp_out
, " ; %%set/v v%p_%lu, %u, %u "
161 "OUT OF BOUNDS\n", sig
, use_word
, bit
, wid
);
165 unsigned skip_set
= transient_id
++;
166 unsigned index_reg
= 3;
167 draw_eval_expr_into_integer(word_ix
, index_reg
);
168 fprintf(vvp_out
, " %%jmp/1 t_%u, 4;\n", skip_set
);
169 fprintf(vvp_out
, " %%ix/load 1, 0;\n");
170 fprintf(vvp_out
, " %%set/av v%p, %u, %u;\n",
172 fprintf(vvp_out
, "t_%u ;\n", skip_set
);
174 /* save_signal width of 0 CLEARS the signal from the
176 save_signal_lookaside(bit
, sig
, use_word
, 0);
180 save_signal_lookaside(bit
, sig
, use_word
, wid
);
181 fprintf(vvp_out
, " %%set/v v%p_%lu, %u, %u;\n",
182 sig
, use_word
, bit
, wid
);
187 static void assign_to_array_word(ivl_signal_t lsig
, ivl_expr_t word_ix
,
188 unsigned bit
, unsigned delay
, unsigned width
)
190 unsigned skip_assign
= transient_id
++;
192 /* Calculate array word index into index register 3 */
193 draw_eval_expr_into_integer(word_ix
, 3);
194 /* Skip assignment if word expression is not defined. */
195 fprintf(vvp_out
, " %%jmp/1 t_%u, 4;\n", skip_assign
);
197 /* Store expression width into index word 0 */
198 fprintf(vvp_out
, " %%ix/load 0, %u; // word width\n", width
);
199 /* Store constant (0) word part select into index 1 */
200 fprintf(vvp_out
, " %%ix/load 1, 0;\n");
202 fprintf(vvp_out
, " %%assign/av v%p, %u, %u;\n", lsig
, delay
, bit
);
203 fprintf(vvp_out
, "t_%u ;\n", skip_assign
);
205 clear_expression_lookaside();
208 static void assign_to_lvector(ivl_lval_t lval
, unsigned bit
,
209 unsigned delay
, ivl_expr_t dexp
,
212 ivl_signal_t sig
= ivl_lval_sig(lval
);
213 ivl_expr_t part_off_ex
= ivl_lval_part_off(lval
);
214 unsigned part_off
= 0;
216 ivl_expr_t word_ix
= ivl_lval_idx(lval
);
217 unsigned long use_word
= 0;
219 if (ivl_signal_array_count(sig
) > 1) {
221 if (! number_is_immediate(word_ix
, 8*sizeof(use_word
))) {
223 assign_to_array_word(sig
, word_ix
, bit
, delay
, width
);
227 use_word
= get_number_immediate(word_ix
);
230 if (part_off_ex
== 0) {
232 } else if (number_is_immediate(part_off_ex
, 64)) {
233 part_off
= get_number_immediate(part_off_ex
);
237 if (ivl_lval_mux(lval
))
238 part_off_ex
= ivl_lval_mux(lval
);
241 unsigned skip_assign
= transient_id
++;
243 draw_eval_expr_into_integer(part_off_ex
, 1);
244 /* If the index expression has XZ bits, skip the assign. */
245 fprintf(vvp_out
, " %%jmp/1 t_%u, 4;\n", skip_assign
);
246 fprintf(vvp_out
, " %%ix/load 0, %u;\n", width
);
247 fprintf(vvp_out
, " %%assign/v0/x1 v%p_%lu, %u, %u;\n",
248 sig
, use_word
, delay
, bit
);
249 fprintf(vvp_out
, "t_%u ;\n", skip_assign
);
251 } else if (part_off
>0 || ivl_lval_width(lval
)!=ivl_signal_width(sig
)) {
252 /* There is no mux expression, but a constant part
253 offset. Load that into index x1 and generate a
254 single-bit set instruction. */
255 assert(ivl_lval_width(lval
) == width
);
258 /* Constant delay... */
259 fprintf(vvp_out
, " %%ix/load 0, %u;\n", width
);
260 fprintf(vvp_out
, " %%ix/load 1, %u;\n", part_off
);
261 fprintf(vvp_out
, " %%assign/v0/x1 v%p_%lu, %u, %u;\n",
262 sig
, use_word
, delay
, bit
);
265 /* Calculated delay... */
266 int delay_index
= allocate_word();
267 draw_eval_expr_into_integer(dexp
, delay_index
);
268 fprintf(vvp_out
, " %%ix/load 0, %u;\n", width
);
269 fprintf(vvp_out
, " %%ix/load 1, %u;\n", part_off
);
270 fprintf(vvp_out
, " %%assign/v0/x1/d v%p_%lu, %u, %u;\n",
271 sig
, use_word
, delay_index
, bit
);
272 clr_word(delay_index
);
275 } else if (dexp
!= 0) {
276 draw_eval_expr_into_integer(dexp
, 1);
277 fprintf(vvp_out
, " %%ix/load 0, %u;\n", width
);
278 fprintf(vvp_out
, " %%assign/v0/d v%p_%lu, 1, %u;\n",
281 fprintf(vvp_out
, " %%ix/load 0, %u;\n", width
);
282 fprintf(vvp_out
, " %%assign/v0 v%p_%lu, %u, %u;\n",
283 sig
, use_word
, delay
, bit
);
289 * This is a private function to generate %set code for the
290 * statement. At this point, the r-value is evaluated and stored in
291 * the res vector, I just need to generate the %set statements for the
292 * l-values of the assignment.
294 static void set_vec_to_lval(ivl_statement_t net
, struct vector_info res
)
298 unsigned wid
= res
.wid
;
300 unsigned cur_rbit
= 0;
302 for (lidx
= 0 ; lidx
< ivl_stmt_lvals(net
) ; lidx
+= 1) {
304 unsigned bit_limit
= wid
- cur_rbit
;
306 lval
= ivl_stmt_lval(net
, lidx
);
308 /* Reduce bit_limit to the width of this l-value. */
309 if (bit_limit
> ivl_lval_width(lval
))
310 bit_limit
= ivl_lval_width(lval
);
312 /* This is the address within the larger r-value of the
313 bit that this l-value takes. */
314 bidx
= res
.base
< 4? res
.base
: (res
.base
+cur_rbit
);
316 set_to_lvariable(lval
, bidx
, bit_limit
);
318 /* Now we've consumed this many r-value bits for the
320 cur_rbit
+= bit_limit
;
324 static int show_stmt_assign_vector(ivl_statement_t net
)
326 ivl_expr_t rval
= ivl_stmt_rval(net
);
328 /* Handle the special case that the expression is a real
329 value. Evaluate the real expression, then convert the
330 result to a vector. Then store that vector into the
332 if (ivl_expr_value(rval
) == IVL_VT_REAL
) {
333 int word
= draw_eval_real(rval
);
334 /* This is the accumulated with of the l-value of the
336 unsigned wid
= ivl_stmt_lwidth(net
);
338 struct vector_info vec
;
340 vec
.base
= allocate_vector(wid
);
343 fprintf(vvp_out
, " %%cvt/vr %u, %d, %u;\n",
344 vec
.base
, word
, vec
.wid
);
348 set_vec_to_lval(net
, vec
);
355 { struct vector_info res
= draw_eval_expr(rval
, 0);
356 set_vec_to_lval(net
, res
);
366 * This function assigns a value to a real .variable. This is destined
367 * for /dev/null when typed ivl_signal_t takes over all the real
370 static int show_stmt_assign_sig_real(ivl_statement_t net
)
376 res
= draw_eval_real(ivl_stmt_rval(net
));
379 assert(ivl_stmt_lvals(net
) == 1);
380 lval
= ivl_stmt_lval(net
, 0);
381 var
= ivl_lval_sig(lval
);
384 assert(ivl_signal_array_count(var
) == 1);
386 fprintf(vvp_out
, " %%set/wr v%p_0, %d;\n", var
, res
);
391 static int show_stmt_assign(ivl_statement_t net
)
396 lval
= ivl_stmt_lval(net
, 0);
398 sig
= ivl_lval_sig(lval
);
399 if (sig
) switch (ivl_signal_data_type(sig
)) {
402 return show_stmt_assign_sig_real(net
);
405 return show_stmt_assign_vector(net
);
408 return show_stmt_assign_vector(net
);
415 * This function handles the case of non-blocking assign to word
416 * variables such as real, i.e:
421 * In this case we know (by Verilog syntax) that there is only exactly
422 * 1 l-value, the target identifier, so it should be relatively easy.
424 static int show_stmt_assign_nb_real(ivl_statement_t net
)
428 ivl_expr_t rval
= ivl_stmt_rval(net
);
429 ivl_expr_t del
= ivl_stmt_delay_expr(net
);
430 /* variables for the selection of word from an array. */
432 unsigned long use_word
= 0;
433 /* thread address for a word value. */
437 /* Must be exactly 1 l-value. */
438 assert(ivl_stmt_lvals(net
) == 1);
440 lval
= ivl_stmt_lval(net
, 0);
441 sig
= ivl_lval_sig(lval
);
444 if (ivl_signal_array_count(sig
) > 1) {
445 word_ix
= ivl_lval_idx(lval
);
447 assert(number_is_immediate(word_ix
, 8*sizeof(use_word
)));
448 use_word
= get_number_immediate(word_ix
);
452 if (del
&& (ivl_expr_type(del
) == IVL_EX_ULONG
)) {
453 delay
= ivl_expr_uvalue(del
);
457 /* XXXX For now, presume delays are constant. */
460 /* Evaluate the r-value */
461 word
= draw_eval_real(rval
);
463 fprintf(vvp_out
, " %%assign/wr v%p_%lu, %lu, %u;\n",
464 sig
, use_word
, delay
, word
);
471 static int show_stmt_assign_nb(ivl_statement_t net
)
474 ivl_expr_t rval
= ivl_stmt_rval(net
);
475 ivl_expr_t del
= ivl_stmt_delay_expr(net
);
478 unsigned long delay
= 0;
480 /* Detect special cases that are handled elsewhere. */
481 lval
= ivl_stmt_lval(net
,0);
482 if ((sig
= ivl_lval_sig(lval
))) {
483 switch (ivl_signal_data_type(sig
)) {
485 return show_stmt_assign_nb_real(net
);
491 if (del
&& (ivl_expr_type(del
) == IVL_EX_ULONG
)) {
492 delay
= ivl_expr_uvalue(del
);
497 { struct vector_info res
= draw_eval_expr(rval
, 0);
498 unsigned wid
= res
.wid
;
500 unsigned cur_rbit
= 0;
502 for (lidx
= 0 ; lidx
< ivl_stmt_lvals(net
) ; lidx
+= 1) {
503 unsigned bit_limit
= wid
- cur_rbit
;
504 lval
= ivl_stmt_lval(net
, lidx
);
506 if (bit_limit
> ivl_lval_width(lval
))
507 bit_limit
= ivl_lval_width(lval
);
511 bidx
= res
.base
< 4? res
.base
: (res
.base
+cur_rbit
);
512 assign_to_lvector(lval
, bidx
, delay
, del
, bit_limit
);
514 cur_rbit
+= bit_limit
;
525 static int show_stmt_block(ivl_statement_t net
, ivl_scope_t sscope
)
529 unsigned cnt
= ivl_stmt_block_count(net
);
531 for (idx
= 0 ; idx
< cnt
; idx
+= 1) {
532 rc
+= show_statement(ivl_stmt_block_stmt(net
, idx
), sscope
);
539 * This draws an invocation of a named block. This is a little
540 * different because a subscope is created. We do that by creating
541 * a thread to deal with this.
543 static int show_stmt_block_named(ivl_statement_t net
, ivl_scope_t scope
)
547 ivl_scope_t subscope
= ivl_stmt_block_scope(net
);
549 out_id
= transient_id
++;
550 sub_id
= transient_id
++;
552 fprintf(vvp_out
, " %%fork t_%u, S_%p;\n",
554 fprintf(vvp_out
, " %%jmp t_%u;\n", out_id
);
555 fprintf(vvp_out
, "t_%u ;\n", sub_id
);
557 /* The statement within the fork is in a new thread, so no
558 expression lookaside is valid. */
559 clear_expression_lookaside();
561 rc
= show_stmt_block(net
, subscope
);
562 fprintf(vvp_out
, " %%end;\n");
564 fprintf(vvp_out
, "t_%u %%join;\n", out_id
);
565 clear_expression_lookaside();
571 static int show_stmt_case(ivl_statement_t net
, ivl_scope_t sscope
)
573 ivl_expr_t exp
= ivl_stmt_cond_expr(net
);
574 struct vector_info cond
= draw_eval_expr(exp
, 0);
575 unsigned count
= ivl_stmt_case_count(net
);
577 unsigned local_base
= local_count
;
579 unsigned idx
, default_case
;
581 local_count
+= count
+ 1;
583 /* First draw the branch table. All the non-default cases
584 generate a branch out of here, to the code that implements
585 the case. The default will fall through all the tests. */
586 default_case
= count
;
588 for (idx
= 0 ; idx
< count
; idx
+= 1) {
589 ivl_expr_t cex
= ivl_stmt_case_expr(net
, idx
);
590 struct vector_info cvec
;
597 /* Is the guard expression something I can pass to a
598 %cmpi/u instruction? If so, use that instead. */
600 if ((ivl_statement_type(net
) == IVL_ST_CASE
)
601 && (ivl_expr_type(cex
) == IVL_EX_NUMBER
)
602 && (! number_is_unknown(cex
))
603 && number_is_immediate(cex
, 16)) {
605 unsigned long imm
= get_number_immediate(cex
);
607 fprintf(vvp_out
, " %%cmpi/u %u, %lu, %u;\n",
608 cond
.base
, imm
, cond
.wid
);
609 fprintf(vvp_out
, " %%jmp/1 T_%d.%d, 6;\n",
610 thread_count
, local_base
+idx
);
615 /* Oh well, do this case the hard way. */
617 cvec
= draw_eval_expr_wid(cex
, cond
.wid
, STUFF_OK_RO
);
618 assert(cvec
.wid
== cond
.wid
);
620 switch (ivl_statement_type(net
)) {
623 fprintf(vvp_out
, " %%cmp/u %u, %u, %u;\n",
624 cond
.base
, cvec
.base
, cond
.wid
);
625 fprintf(vvp_out
, " %%jmp/1 T_%d.%d, 6;\n",
626 thread_count
, local_base
+idx
);
630 fprintf(vvp_out
, " %%cmp/x %u, %u, %u;\n",
631 cond
.base
, cvec
.base
, cond
.wid
);
632 fprintf(vvp_out
, " %%jmp/1 T_%d.%d, 4;\n",
633 thread_count
, local_base
+idx
);
637 fprintf(vvp_out
, " %%cmp/z %u, %u, %u;\n",
638 cond
.base
, cvec
.base
, cond
.wid
);
639 fprintf(vvp_out
, " %%jmp/1 T_%d.%d, 4;\n",
640 thread_count
, local_base
+idx
);
647 /* Done with the case expression */
651 /* Done with the condition expression */
654 /* Emit code for the default case. */
655 if (default_case
< count
) {
656 ivl_statement_t cst
= ivl_stmt_case_stmt(net
, default_case
);
657 show_statement(cst
, sscope
);
660 /* Jump to the out of the case. */
661 fprintf(vvp_out
, " %%jmp T_%d.%d;\n", thread_count
,
664 for (idx
= 0 ; idx
< count
; idx
+= 1) {
665 ivl_statement_t cst
= ivl_stmt_case_stmt(net
, idx
);
667 if (idx
== default_case
)
670 fprintf(vvp_out
, "T_%d.%d ;\n", thread_count
, local_base
+idx
);
671 clear_expression_lookaside();
672 show_statement(cst
, sscope
);
674 fprintf(vvp_out
, " %%jmp T_%d.%d;\n", thread_count
,
680 /* The out of the case. */
681 fprintf(vvp_out
, "T_%d.%d ;\n", thread_count
, local_base
+count
);
682 clear_expression_lookaside();
687 static int show_stmt_case_r(ivl_statement_t net
, ivl_scope_t sscope
)
689 ivl_expr_t exp
= ivl_stmt_cond_expr(net
);
690 int cond
= draw_eval_real(exp
);
691 unsigned count
= ivl_stmt_case_count(net
);
693 unsigned local_base
= local_count
;
695 unsigned idx
, default_case
;
697 local_count
+= count
+ 1;
700 /* First draw the branch table. All the non-default cases
701 generate a branch out of here, to the code that implements
702 the case. The default will fall through all the tests. */
703 default_case
= count
;
705 for (idx
= 0 ; idx
< count
; idx
+= 1) {
706 ivl_expr_t cex
= ivl_stmt_case_expr(net
, idx
);
714 cvec
= draw_eval_real(cex
);
716 fprintf(vvp_out
, " %%cmp/wr %d, %d;\n", cond
, cvec
);
717 fprintf(vvp_out
, " %%jmp/1 T_%d.%d, 4;\n",
718 thread_count
, local_base
+idx
);
720 /* Done with the guard expression value. */
724 /* Done with the case expression. */
727 /* Emit code for the case default. The above jump table will
728 fall through to this statement. */
729 if (default_case
< count
) {
730 ivl_statement_t cst
= ivl_stmt_case_stmt(net
, default_case
);
731 show_statement(cst
, sscope
);
734 /* Jump to the out of the case. */
735 fprintf(vvp_out
, " %%jmp T_%d.%d;\n", thread_count
,
738 for (idx
= 0 ; idx
< count
; idx
+= 1) {
739 ivl_statement_t cst
= ivl_stmt_case_stmt(net
, idx
);
741 if (idx
== default_case
)
744 fprintf(vvp_out
, "T_%d.%d ;\n", thread_count
, local_base
+idx
);
745 clear_expression_lookaside();
746 show_statement(cst
, sscope
);
748 fprintf(vvp_out
, " %%jmp T_%d.%d;\n", thread_count
,
754 /* The out of the case. */
755 fprintf(vvp_out
, "T_%d.%d ;\n", thread_count
, local_base
+count
);
760 static void force_vector_to_lval(ivl_statement_t net
, struct vector_info rvec
)
765 const char*command_name
;
766 const char*command_name_x0
;
768 switch (ivl_statement_type(net
)) {
770 command_name
= "%cassign/v";
771 command_name_x0
= "ERROR";
774 command_name
= "%force/v";
775 command_name_x0
= "%force/x0";
778 command_name
= "ERROR";
783 for (lidx
= 0 ; lidx
< ivl_stmt_lvals(net
) ; lidx
+= 1) {
784 ivl_lval_t lval
= ivl_stmt_lval(net
, lidx
);
785 ivl_signal_t lsig
= ivl_lval_sig(lval
);
787 unsigned use_wid
= ivl_lval_width(lval
);
788 ivl_expr_t part_off_ex
= ivl_lval_part_off(lval
);
790 ivl_expr_t word_idx
= ivl_lval_idx(lval
);
791 unsigned long use_word
= 0;
793 if (part_off_ex
== 0) {
796 assert(number_is_immediate(part_off_ex
, 64));
797 part_off
= get_number_immediate(part_off_ex
);
801 assert(number_is_immediate(word_idx
, 8*sizeof(unsigned long)));
802 use_word
= get_number_immediate(word_idx
);
805 /* L-Value must be a signal: reg or wire */
808 if (part_off
!= 0 || use_wid
!= ivl_signal_width(lsig
)) {
810 command_name
= command_name_x0
;
811 fprintf(vvp_out
, " %%ix/load 0, %u;\n", part_off
);
814 /* Do not support bit or part selects of l-values yet. */
815 assert(ivl_lval_mux(lval
) == 0);
816 assert(ivl_lval_part_off(lval
) == 0);
817 assert(ivl_lval_width(lval
) == ivl_signal_width(lsig
));
819 assert((roff
+ use_wid
) <= rvec
.wid
);
822 fprintf(vvp_out
, " %s v%p_%lu, %u, %u;\n", command_name
,
823 lsig
, use_word
, rvec
.base
+roff
, use_wid
);
830 static void force_link_rval(ivl_statement_t net
, ivl_expr_t rval
)
835 const char*command_name
;
837 ivl_expr_t lword_idx
, rword_idx
;
838 unsigned long use_lword
= 0, use_rword
= 0;
840 if (ivl_expr_type(rval
) != IVL_EX_SIGNAL
)
843 switch (ivl_statement_type(net
)) {
845 command_name
= "%cassign";
848 command_name
= "%force";
851 command_name
= "ERROR";
856 rsig
= ivl_expr_signal(rval
);
857 assert(ivl_stmt_lvals(net
) == 1);
858 lval
= ivl_stmt_lval(net
, 0);
859 lsig
= ivl_lval_sig(lval
);
861 /* At least for now, only handle force to fixed words of an array. */
862 if ((lword_idx
= ivl_lval_idx(lval
)) != 0) {
863 assert(number_is_immediate(lword_idx
, 8*sizeof(unsigned long)));
864 use_lword
= get_number_immediate(lword_idx
);
867 if ((rword_idx
= ivl_expr_oper1(rval
)) != 0) {
868 assert(number_is_immediate(rword_idx
, 8*sizeof(unsigned long)));
869 use_rword
= get_number_immediate(rword_idx
);
872 assert(ivl_signal_array_count(rsig
) == 1);
875 fprintf(vvp_out
, " %s/link", command_name
);
876 fprintf(vvp_out
, " v%p_%lu", lsig
, use_lword
);
877 fprintf(vvp_out
, ", v%p_%lu;\n", rsig
, use_rword
);
880 static int show_stmt_cassign(ivl_statement_t net
)
883 struct vector_info rvec
;
885 rval
= ivl_stmt_rval(net
);
888 rvec
= draw_eval_expr(rval
, STUFF_OK_47
);
890 /* Write out initial continuous assign instructions to assign
891 the expression value to the l-value. */
892 force_vector_to_lval(net
, rvec
);
894 force_link_rval(net
, rval
);
900 * Handle the deassign similar to cassign. The lvals must all be
901 * vectors without bit or part selects. Simply call %deassign for all
904 static int show_stmt_deassign(ivl_statement_t net
)
908 for (lidx
= 0 ; lidx
< ivl_stmt_lvals(net
) ; lidx
+= 1) {
909 ivl_lval_t lval
= ivl_stmt_lval(net
, lidx
);
910 ivl_signal_t lsig
= ivl_lval_sig(lval
);
912 ivl_expr_t word_idx
= ivl_lval_idx(lval
);
913 unsigned long use_word
= 0;
916 assert(ivl_lval_mux(lval
) == 0);
917 assert(ivl_lval_part_off(lval
) == 0);
920 assert(number_is_immediate(word_idx
, 8*sizeof(use_word
)));
921 use_word
= get_number_immediate(word_idx
);
925 fprintf(vvp_out
, " %%deassign v%p_%lu;\n", lsig
, use_word
);
931 static int show_stmt_condit(ivl_statement_t net
, ivl_scope_t sscope
)
934 unsigned lab_false
, lab_out
;
935 ivl_expr_t exp
= ivl_stmt_cond_expr(net
);
936 struct vector_info cond
937 = draw_eval_expr(exp
, STUFF_OK_XZ
|STUFF_OK_47
|STUFF_OK_RO
);
939 assert(cond
.wid
== 1);
941 lab_false
= local_count
++;
942 lab_out
= local_count
++;
944 fprintf(vvp_out
, " %%jmp/0xz T_%d.%d, %u;\n",
945 thread_count
, lab_false
, cond
.base
);
947 /* Done with the condition expression. */
951 if (ivl_stmt_cond_true(net
))
952 rc
+= show_statement(ivl_stmt_cond_true(net
), sscope
);
955 if (ivl_stmt_cond_false(net
)) {
956 fprintf(vvp_out
, " %%jmp T_%d.%d;\n", thread_count
, lab_out
);
957 fprintf(vvp_out
, "T_%d.%u ;\n", thread_count
, lab_false
);
958 clear_expression_lookaside();
960 rc
+= show_statement(ivl_stmt_cond_false(net
), sscope
);
962 fprintf(vvp_out
, "T_%d.%u ;\n", thread_count
, lab_out
);
963 clear_expression_lookaside();
966 fprintf(vvp_out
, "T_%d.%u ;\n", thread_count
, lab_false
);
967 clear_expression_lookaside();
974 * The delay statement is easy. Simply write a ``%delay <n>''
975 * instruction to delay the thread, then draw the included statement.
976 * The delay statement comes from verilog code like this:
981 static int show_stmt_delay(ivl_statement_t net
, ivl_scope_t sscope
)
984 uint64_t delay
= ivl_stmt_delay_val(net
);
985 ivl_statement_t stmt
= ivl_stmt_sub_stmt(net
);
987 unsigned long low
= delay
% UINT64_C(0x100000000);
988 unsigned long hig
= delay
/ UINT64_C(0x100000000);
990 fprintf(vvp_out
, " %%delay %lu, %lu;\n", low
, hig
);
991 /* Lots of things can happen during a delay. */
992 clear_expression_lookaside();
994 rc
+= show_statement(stmt
, sscope
);
1000 * The delayx statement is slightly more complex in that it is
1001 * necessary to calculate the delay first. Load the calculated delay
1002 * into and index register and use the %delayx instruction to do the
1005 static int show_stmt_delayx(ivl_statement_t net
, ivl_scope_t sscope
)
1008 ivl_expr_t exp
= ivl_stmt_delay_expr(net
);
1009 ivl_statement_t stmt
= ivl_stmt_sub_stmt(net
);
1011 switch (ivl_expr_value(exp
)) {
1014 case IVL_VT_LOGIC
: {
1015 struct vector_info del
= draw_eval_expr(exp
, 0);
1016 fprintf(vvp_out
, " %%ix/get 0, %u, %u;\n",
1023 int word
= draw_eval_real(exp
);
1024 fprintf(vvp_out
, " %%cvt/ir 0, %d;\n", word
);
1033 fprintf(vvp_out
, " %%delayx 0;\n");
1034 /* Lots of things can happen during a delay. */
1035 clear_expression_lookaside();
1037 rc
+= show_statement(stmt
, sscope
);
1041 static int show_stmt_disable(ivl_statement_t net
, ivl_scope_t sscope
)
1045 ivl_scope_t target
= ivl_stmt_call(net
);
1046 fprintf(vvp_out
, " %%disable S_%p;\n", target
);
1051 static int show_stmt_force(ivl_statement_t net
)
1054 struct vector_info rvec
;
1056 rval
= ivl_stmt_rval(net
);
1059 rvec
= draw_eval_expr(rval
, STUFF_OK_47
);
1061 /* Write out initial continuous assign instructions to assign
1062 the expression value to the l-value. */
1063 force_vector_to_lval(net
, rvec
);
1065 force_link_rval(net
, rval
);
1070 static int show_stmt_forever(ivl_statement_t net
, ivl_scope_t sscope
)
1073 ivl_statement_t stmt
= ivl_stmt_sub_stmt(net
);
1074 unsigned lab_top
= local_count
++;
1076 fprintf(vvp_out
, "T_%u.%u ;\n", thread_count
, lab_top
);
1077 rc
+= show_statement(stmt
, sscope
);
1078 fprintf(vvp_out
, " %%jmp T_%u.%u;\n", thread_count
, lab_top
);
1083 static int show_stmt_fork(ivl_statement_t net
, ivl_scope_t sscope
)
1087 unsigned cnt
= ivl_stmt_block_count(net
);
1088 ivl_scope_t scope
= ivl_stmt_block_scope(net
);
1090 unsigned out
= transient_id
++;
1091 unsigned id_base
= transient_id
;
1093 /* cnt is the number of sub-threads. If the fork-join has no
1094 name, then we can put one of the sub-threads in the current
1095 thread, so decrement the count by one. */
1101 transient_id
+= cnt
;
1103 /* If no subscope use provided */
1104 if (!scope
) scope
= sscope
;
1106 /* Draw a fork statement for all but one of the threads of the
1107 fork/join. Send the threads off to a bit of code where they
1109 for (idx
= 0 ; idx
< cnt
; idx
+= 1) {
1110 fprintf(vvp_out
, " %%fork t_%u, S_%p;\n",
1111 id_base
+idx
, scope
);
1114 /* If we are putting one sub-thread into the current thread,
1115 then draw its code here. */
1116 if (ivl_stmt_block_scope(net
) == 0)
1117 rc
+= show_statement(ivl_stmt_block_stmt(net
, cnt
), scope
);
1120 /* Generate enough joins to collect all the sub-threads. */
1121 for (idx
= 0 ; idx
< cnt
; idx
+= 1) {
1122 fprintf(vvp_out
, " %%join;\n");
1124 fprintf(vvp_out
, " %%jmp t_%u;\n", out
);
1126 /* Generate the sub-threads themselves. */
1127 for (idx
= 0 ; idx
< cnt
; idx
+= 1) {
1128 fprintf(vvp_out
, "t_%u ;\n", id_base
+idx
);
1129 clear_expression_lookaside();
1130 rc
+= show_statement(ivl_stmt_block_stmt(net
, idx
), scope
);
1131 fprintf(vvp_out
, " %%end;\n");
1134 /* This is the label for the out. Use this to branch around
1135 the implementations of all the child threads. */
1136 clear_expression_lookaside();
1137 fprintf(vvp_out
, "t_%u ;\n", out
);
1143 * noop statements are implemented by doing nothing.
1145 static int show_stmt_noop(ivl_statement_t net
)
1150 static int show_stmt_release(ivl_statement_t net
)
1154 for (lidx
= 0 ; lidx
< ivl_stmt_lvals(net
) ; lidx
+= 1) {
1155 ivl_lval_t lval
= ivl_stmt_lval(net
, lidx
);
1156 ivl_signal_t lsig
= ivl_lval_sig(lval
);
1157 const char*opcode
= 0;
1159 ivl_expr_t word_idx
= ivl_lval_idx(lval
);
1160 unsigned long use_word
= 0;
1162 assert(ivl_lval_mux(lval
) == 0);
1163 assert(ivl_lval_part_off(lval
) == 0);
1165 switch (ivl_signal_type(lsig
)) {
1174 if (word_idx
!= 0) {
1175 assert(number_is_immediate(word_idx
, 8*sizeof(use_word
)));
1176 use_word
= get_number_immediate(word_idx
);
1179 /* Generate the appropriate release statement for this
1181 fprintf(vvp_out
, " %%release/%s v%p_%lu;\n",
1182 opcode
, lsig
, use_word
);
1188 static int show_stmt_repeat(ivl_statement_t net
, ivl_scope_t sscope
)
1191 unsigned lab_top
= local_count
++, lab_out
= local_count
++;
1192 ivl_expr_t exp
= ivl_stmt_cond_expr(net
);
1193 struct vector_info cnt
= draw_eval_expr(exp
, 0);
1195 /* Test that 0 < expr */
1196 fprintf(vvp_out
, "T_%u.%u %%cmp/u 0, %u, %u;\n", thread_count
,
1197 lab_top
, cnt
.base
, cnt
.wid
);
1198 clear_expression_lookaside();
1199 fprintf(vvp_out
, " %%jmp/0xz T_%u.%u, 5;\n", thread_count
, lab_out
);
1200 /* This adds -1 (all ones in 2's complement) to the count. */
1201 fprintf(vvp_out
, " %%add %u, 1, %u;\n", cnt
.base
, cnt
.wid
);
1203 rc
+= show_statement(ivl_stmt_sub_stmt(net
), sscope
);
1205 fprintf(vvp_out
, " %%jmp T_%u.%u;\n", thread_count
, lab_top
);
1206 fprintf(vvp_out
, "T_%u.%u ;\n", thread_count
, lab_out
);
1207 clear_expression_lookaside();
1215 * The trigger statement is straight forward. All we have to do is
1216 * write a single bit of fake data to the event object.
1218 static int show_stmt_trigger(ivl_statement_t net
)
1220 ivl_event_t ev
= ivl_stmt_events(net
, 0);
1222 fprintf(vvp_out
, " %%set/v E_%p, 0,1;\n", ev
);
1226 static int show_stmt_utask(ivl_statement_t net
)
1228 ivl_scope_t task
= ivl_stmt_call(net
);
1230 fprintf(vvp_out
, " %%fork TD_%s",
1231 vvp_mangle_id(ivl_scope_name(task
)));
1232 fprintf(vvp_out
, ", S_%p;\n", task
);
1233 fprintf(vvp_out
, " %%join;\n");
1234 clear_expression_lookaside();
1238 static int show_stmt_wait(ivl_statement_t net
, ivl_scope_t sscope
)
1240 if (ivl_stmt_nevent(net
) == 1) {
1241 ivl_event_t ev
= ivl_stmt_events(net
, 0);
1242 fprintf(vvp_out
, " %%wait E_%p;\n", ev
);
1246 static unsigned int cascade_counter
= 0;
1247 ivl_event_t ev
= ivl_stmt_events(net
, 0);
1248 fprintf(vvp_out
, "Ewait_%u .event/or E_%p", cascade_counter
, ev
);
1250 for (idx
= 1 ; idx
< ivl_stmt_nevent(net
) ; idx
+= 1) {
1251 ev
= ivl_stmt_events(net
, idx
);
1252 fprintf(vvp_out
, ", E_%p", ev
);
1254 fprintf(vvp_out
, ";\n %%wait Ewait_%u;\n", cascade_counter
);
1255 cascade_counter
+= 1;
1257 /* Always clear the expression lookaside after a
1258 %wait. Anything can happen while the thread is waiting. */
1259 clear_expression_lookaside();
1261 return show_statement(ivl_stmt_sub_stmt(net
), sscope
);
1264 static struct vector_info
reduction_or(struct vector_info cvec
)
1266 struct vector_info result
;
1268 switch (cvec
.base
) {
1284 result
.base
= allocate_vector(1);
1286 fprintf(vvp_out
, " %%or/r %u, %u, %u;\n", result
.base
,
1287 cvec
.base
, cvec
.wid
);
1294 static int show_stmt_while(ivl_statement_t net
, ivl_scope_t sscope
)
1297 struct vector_info cvec
;
1299 unsigned top_label
= local_count
++;
1300 unsigned out_label
= local_count
++;
1302 /* Start the loop. The top of the loop starts a basic block
1303 because it can be entered from above or from the bottom of
1305 fprintf(vvp_out
, "T_%d.%d ;\n", thread_count
, top_label
);
1306 clear_expression_lookaside();
1308 /* Draw the evaluation of the condition expression, and test
1309 the result. If the expression evaluates to false, then
1310 branch to the out label. */
1311 cvec
= draw_eval_expr(ivl_stmt_cond_expr(net
), STUFF_OK_XZ
|STUFF_OK_47
);
1313 cvec
= reduction_or(cvec
);
1315 fprintf(vvp_out
, " %%jmp/0xz T_%d.%d, %u;\n",
1316 thread_count
, out_label
, cvec
.base
);
1320 /* Draw the body of the loop. */
1321 rc
+= show_statement(ivl_stmt_sub_stmt(net
), sscope
);
1323 /* This is the bottom of the loop. branch to the top where the
1324 test is repeated, and also draw the out label. */
1325 fprintf(vvp_out
, " %%jmp T_%d.%d;\n", thread_count
, top_label
);
1326 fprintf(vvp_out
, "T_%d.%d ;\n", thread_count
, out_label
);
1327 clear_expression_lookaside();
1331 static int show_system_task_call(ivl_statement_t net
)
1333 unsigned parm_count
= ivl_stmt_parm_count(net
);
1335 if (parm_count
== 0) {
1336 fprintf(vvp_out
, " %%vpi_call \"%s\";\n", ivl_stmt_name(net
));
1337 clear_expression_lookaside();
1341 draw_vpi_task_call(net
);
1343 /* VPI calls can manipulate anything, so clear the expression
1344 lookahead table after the call. */
1345 clear_expression_lookaside();
1351 * This function draws a statement as vvp assembly. It basically
1352 * switches on the statement type and draws code based on the type and
1353 * further specifics.
1355 static int show_statement(ivl_statement_t net
, ivl_scope_t sscope
)
1357 const ivl_statement_type_t code
= ivl_statement_type(net
);
1363 rc
+= show_stmt_assign(net
);
1366 case IVL_ST_ASSIGN_NB
:
1367 rc
+= show_stmt_assign_nb(net
);
1371 if (ivl_stmt_block_scope(net
))
1372 rc
+= show_stmt_block_named(net
, sscope
);
1374 rc
+= show_stmt_block(net
, sscope
);
1380 rc
+= show_stmt_case(net
, sscope
);
1384 rc
+= show_stmt_case_r(net
, sscope
);
1387 case IVL_ST_CASSIGN
:
1388 rc
+= show_stmt_cassign(net
);
1392 rc
+= show_stmt_condit(net
, sscope
);
1395 case IVL_ST_DEASSIGN
:
1396 rc
+= show_stmt_deassign(net
);
1400 rc
+= show_stmt_delay(net
, sscope
);
1404 rc
+= show_stmt_delayx(net
, sscope
);
1407 case IVL_ST_DISABLE
:
1408 rc
+= show_stmt_disable(net
, sscope
);
1412 rc
+= show_stmt_force(net
);
1415 case IVL_ST_FOREVER
:
1416 rc
+= show_stmt_forever(net
, sscope
);
1420 rc
+= show_stmt_fork(net
, sscope
);
1424 rc
+= show_stmt_noop(net
);
1427 case IVL_ST_RELEASE
:
1428 rc
+= show_stmt_release(net
);
1432 rc
+= show_stmt_repeat(net
, sscope
);
1436 rc
+= show_system_task_call(net
);
1439 case IVL_ST_TRIGGER
:
1440 rc
+= show_stmt_trigger(net
);
1444 rc
+= show_stmt_utask(net
);
1448 rc
+= show_stmt_wait(net
, sscope
);
1452 rc
+= show_stmt_while(net
, sscope
);
1456 fprintf(stderr
, "vvp.tgt: Unable to draw statement type %u\n",
1467 * The process as a whole is surrounded by this code. We generate a
1468 * start label that the .thread statement can use, and we generate
1469 * code to terminate the thread.
1472 int draw_process(ivl_process_t net
, void*x
)
1476 ivl_scope_t scope
= ivl_process_scope(net
);
1477 ivl_statement_t stmt
= ivl_process_stmt(net
);
1481 for (idx
= 0 ; idx
< ivl_process_attr_cnt(net
) ; idx
+= 1) {
1483 ivl_attribute_t attr
= ivl_process_attr_val(net
, idx
);
1485 if (strcmp(attr
->key
, "_ivl_schedule_push") == 0) {
1489 } else if (strcmp(attr
->key
, "ivl_combinational") == 0) {
1497 fprintf(vvp_out
, " .scope S_%p;\n", scope
);
1499 /* Generate the entry label. Just give the thread a number so
1500 that we ar certain the label is unique. */
1501 fprintf(vvp_out
, "T_%d ;\n", thread_count
);
1502 clear_expression_lookaside();
1504 /* Draw the contents of the thread. */
1505 rc
+= show_statement(stmt
, scope
);
1508 /* Terminate the thread with either an %end instruction (initial
1509 statements) or a %jmp back to the beginning of the thread. */
1511 switch (ivl_process_type(net
)) {
1513 case IVL_PR_INITIAL
:
1514 fprintf(vvp_out
, " %%end;\n");
1518 fprintf(vvp_out
, " %%jmp T_%d;\n", thread_count
);
1522 /* Now write out the .thread directive that tells vvp where
1523 the thread starts. */
1526 fprintf(vvp_out
, " .thread T_%d, $push;\n", thread_count
);
1528 fprintf(vvp_out
, " .thread T_%d;\n", thread_count
);
1535 int draw_task_definition(ivl_scope_t scope
)
1538 ivl_statement_t def
= ivl_scope_def(scope
);
1540 fprintf(vvp_out
, "TD_%s ;\n", vvp_mangle_id(ivl_scope_name(scope
)));
1541 clear_expression_lookaside();
1544 rc
+= show_statement(def
, scope
);
1546 fprintf(vvp_out
, " %%end;\n");
1552 int draw_func_definition(ivl_scope_t scope
)
1555 ivl_statement_t def
= ivl_scope_def(scope
);
1557 fprintf(vvp_out
, "TD_%s ;\n", vvp_mangle_id(ivl_scope_name(scope
)));
1558 clear_expression_lookaside();
1561 rc
+= show_statement(def
, scope
);
1563 fprintf(vvp_out
, " %%end;\n");