Add support for text macros with arguments.
[iverilog.git] / tgt-vvp / draw_vpi.c
blob73e6e5f305ddf5179233636672f3d79f2d5d6796
1 /*
2 * Copyright (c) 2003 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: draw_vpi.c,v 1.17 2007/02/14 05:59:24 steve Exp $"
21 #endif
23 # include "vvp_priv.h"
24 # include <string.h>
25 #ifdef HAVE_MALLOC_H
26 # include <malloc.h>
27 #endif
28 # include <stdlib.h>
29 # include <assert.h>
31 static const char* magic_sfuncs[] = {
32 "$time",
33 "$stime",
34 "$realtime",
35 "$simtime",
39 static int is_magic_sfunc(const char*name)
41 int idx;
42 for (idx = 0 ; magic_sfuncs[idx] ; idx += 1)
43 if (strcmp(magic_sfuncs[idx],name) == 0)
44 return 1;
46 return 0;
49 static int is_fixed_memory_word(ivl_expr_t net)
51 ivl_signal_t sig;
53 if (ivl_expr_type(net) != IVL_EX_SIGNAL)
54 return 0;
56 sig = ivl_expr_signal(net);
58 if (ivl_signal_array_count(sig) == 1)
59 return 1;
61 if (number_is_immediate(ivl_expr_oper1(net), 8*sizeof(unsigned)))
62 return 1;
64 return 0;
67 static void draw_vpi_taskfunc_args(const char*call_string,
68 ivl_statement_t tnet,
69 ivl_expr_t fnet)
71 unsigned idx;
72 unsigned parm_count = tnet
73 ? ivl_stmt_parm_count(tnet)
74 : ivl_expr_parms(fnet);
75 struct vector_info *vec = 0x0;
76 unsigned int vecs= 0;
77 unsigned int veci= 0;
79 ivl_parameter_t par;
81 /* Figure out how many expressions are going to be evaluated
82 for this task call. I won't need to evaluate expressions
83 for items that are VPI objects directly. */
84 for (idx = 0 ; idx < parm_count ; idx += 1) {
85 ivl_expr_t expr = tnet
86 ? ivl_stmt_parm(tnet, idx)
87 : ivl_expr_parm(fnet, idx);
89 switch (ivl_expr_type(expr)) {
91 /* These expression types can be handled directly,
92 with VPI handles of their own. Therefore, skip
93 them in the process of evaluating expressions. */
94 case IVL_EX_NONE:
95 case IVL_EX_ARRAY:
96 case IVL_EX_NUMBER:
97 case IVL_EX_STRING:
98 case IVL_EX_EVENT:
99 case IVL_EX_SCOPE:
100 continue;
102 case IVL_EX_SFUNC:
103 if (is_magic_sfunc(ivl_expr_name(expr)))
104 continue;
106 break;
108 case IVL_EX_SIGNAL:
109 /* If the signal node is narrower then the signal
110 itself, then this is a part select so I'm going
111 to need to evaluate the expression.
113 Also, if the signedness of the expression is
114 different from the signedness of the
115 signal. This could be caused by a $signed or
116 $unsigned system function.
118 If I don't need to do any evaluating, then skip
119 it as I'll be passing the handle to the signal
120 itself. */
121 if (ivl_expr_width(expr) !=
122 ivl_signal_width(ivl_expr_signal(expr))) {
123 break;
125 } else if (ivl_expr_signed(expr) !=
126 ivl_signal_signed(ivl_expr_signal(expr))) {
127 break;
128 } else if (! is_fixed_memory_word(expr)){
129 break;
130 } else {
131 /* Some array selects need to be evaluated. */
132 ivl_expr_t word_ex = ivl_expr_oper1(expr);
133 if (word_ex && !number_is_immediate(word_ex,
134 8*sizeof(unsigned))) {
135 break;
137 continue;
141 case IVL_EX_MEMORY:
142 if (!ivl_expr_oper1(expr)) {
143 continue;
146 /* Everything else will need to be evaluated and
147 passed as a constant to the vpi task. */
148 default:
149 break;
152 vec = (struct vector_info *)
153 realloc(vec, (vecs+1)*sizeof(struct vector_info));
155 switch (ivl_expr_value(expr)) {
156 case IVL_VT_LOGIC:
157 case IVL_VT_BOOL:
158 vec[vecs] = draw_eval_expr(expr, 0);
159 break;
160 case IVL_VT_REAL:
161 vec[vecs].base = draw_eval_real(expr);
162 vec[vecs].wid = 0;
163 break;
164 default:
165 assert(0);
167 vecs++;
170 fprintf(vvp_out, "%s", call_string);
172 for (idx = 0 ; idx < parm_count ; idx += 1) {
173 ivl_expr_t expr = tnet
174 ? ivl_stmt_parm(tnet, idx)
175 : ivl_expr_parm(fnet, idx);
177 switch (ivl_expr_type(expr)) {
178 case IVL_EX_NONE:
179 fprintf(vvp_out, ", \" \"");
180 continue;
182 case IVL_EX_ARRAY:
183 fprintf(vvp_out, ", v%p", ivl_expr_signal(expr));
184 continue;
186 case IVL_EX_NUMBER: {
187 unsigned bit, wid = ivl_expr_width(expr);
188 const char*bits = ivl_expr_bits(expr);
190 fprintf(vvp_out, ", %u'%sb", wid,
191 ivl_expr_signed(expr)? "s" : "");
192 for (bit = wid ; bit > 0 ; bit -= 1)
193 fputc(bits[bit-1], vvp_out);
194 continue;
197 case IVL_EX_SIGNAL:
198 /* If this is a part select, then the value was
199 calculated above. Otherwise, just pass the
200 signal. */
201 if (ivl_expr_width(expr) !=
202 ivl_signal_width(ivl_expr_signal(expr))) {
203 break;
205 } else if (ivl_expr_signed(expr) !=
206 ivl_signal_signed(ivl_expr_signal(expr))) {
207 break;
209 } else if (! is_fixed_memory_word(expr)){
210 break;
212 } else {
213 ivl_signal_t sig = ivl_expr_signal(expr);
214 unsigned use_word = 0;
215 ivl_expr_t word_ex = ivl_expr_oper1(expr);
216 if (word_ex) {
217 /* Some array select have been evaluated. */
218 if (!number_is_immediate(word_ex,
219 8*sizeof(unsigned))) {
220 break;
222 use_word = get_number_immediate(word_ex);
224 fprintf(vvp_out, ", v%p_%u", sig, use_word);
225 continue;
227 assert(0);
228 continue;
230 case IVL_EX_STRING:
231 if (( par = ivl_expr_parameter(expr) )) {
232 fprintf(vvp_out, ", P_%p", par);
234 } else {
235 fprintf(vvp_out, ", \"%s\"",
236 ivl_expr_string(expr));
238 continue;
240 case IVL_EX_EVENT:
241 fprintf(vvp_out, ", E_%p", ivl_expr_event(expr));
242 continue;
244 case IVL_EX_SCOPE:
245 fprintf(vvp_out, ", S_%p", ivl_expr_scope(expr));
246 continue;
248 case IVL_EX_SFUNC:
249 if (is_magic_sfunc(ivl_expr_name(expr))) {
250 fprintf(vvp_out, ", %s", ivl_expr_name(expr));
251 continue;
253 break;
255 default:
256 break;
258 assert(veci < vecs);
260 switch (ivl_expr_value(expr)) {
262 case IVL_VT_LOGIC:
263 case IVL_VT_BOOL:
264 fprintf(vvp_out, ", T<%u,%u,%s>", vec[veci].base,
265 vec[veci].wid, ivl_expr_signed(expr)? "s" : "u");
266 break;
268 case IVL_VT_REAL:
269 fprintf(vvp_out, ", W<%u,r>", vec[veci].base);
270 break;
272 default:
273 assert(0);
275 veci++;
278 assert(veci == vecs);
280 if (vecs) {
281 for (idx = 0; idx < vecs; idx++) {
282 if (vec[idx].wid > 0)
283 clr_vector(vec[idx]);
284 else if (vec[idx].wid == 0)
285 clr_word(vec[idx].base);
287 free(vec);
290 fprintf(vvp_out, ";\n");
293 void draw_vpi_task_call(ivl_statement_t tnet)
295 char call_string[1024];
296 sprintf(call_string, " %%vpi_call \"%s\"", ivl_stmt_name(tnet));
297 draw_vpi_taskfunc_args(call_string, tnet, 0);
300 struct vector_info draw_vpi_func_call(ivl_expr_t fnet, unsigned wid)
302 char call_string[1024];
303 struct vector_info res;
305 res.base = allocate_vector(wid);
306 res.wid = wid;
307 sprintf(call_string, " %%vpi_func \"%s\", %u, %u",
308 ivl_expr_name(fnet), res.base, res.wid);
310 draw_vpi_taskfunc_args(call_string, 0, fnet);
312 return res;
315 int draw_vpi_rfunc_call(ivl_expr_t fnet)
317 char call_string[1024];
318 int res = allocate_word();
320 sprintf(call_string, " %%vpi_func/r \"%s\", %d",
321 ivl_expr_name(fnet), res);
323 draw_vpi_taskfunc_args(call_string, 0, fnet);
325 return res;