2001-03-19 02:20:46 +01:00
|
|
|
/*
|
2005-05-02 00:04:12 +02:00
|
|
|
* Copyright (c) 2001-2005 Stephen Williams (steve@icarus.com)
|
2001-03-19 02:20:46 +01:00
|
|
|
*
|
|
|
|
|
* This source code is free software; you can redistribute it
|
|
|
|
|
* and/or modify it in source code form under the terms of the GNU
|
|
|
|
|
* General Public License as published by the Free Software
|
|
|
|
|
* Foundation; either version 2 of the License, or (at your option)
|
|
|
|
|
* any later version.
|
|
|
|
|
*
|
|
|
|
|
* This program is distributed in the hope that it will be useful,
|
|
|
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
|
* GNU General Public License for more details.
|
|
|
|
|
*
|
|
|
|
|
* You should have received a copy of the GNU General Public License
|
|
|
|
|
* along with this program; if not, write to the Free Software
|
|
|
|
|
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
|
|
|
|
|
*/
|
2002-08-12 03:34:58 +02:00
|
|
|
#ifdef HAVE_CVS_IDENT
|
2005-06-14 03:44:09 +02:00
|
|
|
#ident "$Id: vvp_process.c,v 1.112 2005/06/14 01:45:05 steve Exp $"
|
2001-03-19 02:20:46 +01:00
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
# include "vvp_priv.h"
|
2001-04-18 07:12:03 +02:00
|
|
|
# include <string.h>
|
2001-03-21 02:49:43 +01:00
|
|
|
# include <assert.h>
|
2001-09-15 20:27:04 +02:00
|
|
|
#ifdef HAVE_MALLOC_H
|
2001-05-10 02:26:53 +02:00
|
|
|
# include <malloc.h>
|
2001-09-15 20:27:04 +02:00
|
|
|
#endif
|
|
|
|
|
# include <stdlib.h>
|
2001-03-21 02:49:43 +01:00
|
|
|
|
2001-04-18 07:12:03 +02:00
|
|
|
static int show_statement(ivl_statement_t net, ivl_scope_t sscope);
|
2005-03-03 05:33:10 +01:00
|
|
|
static void draw_eval_expr_into_integer(ivl_expr_t expr, unsigned ix);
|
2001-03-19 02:20:46 +01:00
|
|
|
|
2001-05-17 06:37:02 +02:00
|
|
|
unsigned local_count = 0;
|
|
|
|
|
unsigned thread_count = 0;
|
2001-03-22 06:06:21 +01:00
|
|
|
|
2002-05-27 02:08:45 +02:00
|
|
|
static unsigned transient_id = 0;
|
|
|
|
|
|
2001-03-19 02:20:46 +01:00
|
|
|
/*
|
|
|
|
|
* This file includes the code needed to generate VVP code for
|
|
|
|
|
* processes. Scopes are already declared, we generate here the
|
|
|
|
|
* executable code for the processes.
|
|
|
|
|
*/
|
|
|
|
|
|
2001-03-23 02:54:32 +01:00
|
|
|
unsigned bitchar_to_idx(char bit)
|
|
|
|
|
{
|
|
|
|
|
switch (bit) {
|
|
|
|
|
case '0':
|
|
|
|
|
return 0;
|
|
|
|
|
case '1':
|
|
|
|
|
return 1;
|
|
|
|
|
case 'x':
|
|
|
|
|
return 2;
|
|
|
|
|
case 'z':
|
|
|
|
|
return 3;
|
|
|
|
|
default:
|
|
|
|
|
assert(0);
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2001-03-21 02:49:43 +01:00
|
|
|
/*
|
|
|
|
|
* These functions handle the blocking assignment. Use the %set
|
|
|
|
|
* instruction to perform the actual assignment, and calculate any
|
|
|
|
|
* lvalues and rvalues that need calculating.
|
|
|
|
|
*
|
2001-08-26 01:50:02 +02:00
|
|
|
* The set_to_lvariable function takes a particular nexus and generates
|
2001-03-21 02:49:43 +01:00
|
|
|
* the %set statements to assign the value.
|
|
|
|
|
*
|
|
|
|
|
* The show_stmt_assign function looks at the assign statement, scans
|
|
|
|
|
* the l-values, and matches bits of the r-value with the correct
|
|
|
|
|
* nexus.
|
|
|
|
|
*/
|
|
|
|
|
|
2005-03-03 05:33:10 +01:00
|
|
|
static void set_to_lvariable(ivl_lval_t lval,
|
2002-11-07 04:12:17 +01:00
|
|
|
unsigned bit, unsigned wid)
|
2001-03-21 02:49:43 +01:00
|
|
|
{
|
2001-08-26 01:50:02 +02:00
|
|
|
ivl_signal_t sig = ivl_lval_sig(lval);
|
|
|
|
|
unsigned part_off = ivl_lval_part_off(lval);
|
2001-03-21 02:49:43 +01:00
|
|
|
|
2002-11-07 04:12:17 +01:00
|
|
|
if (ivl_lval_mux(lval)) {
|
2005-02-15 08:12:55 +01:00
|
|
|
unsigned skip_set = transient_id++;
|
|
|
|
|
|
|
|
|
|
/* There is a mux expression, so this must be a write to
|
|
|
|
|
a bit-select leval. Presumably, the x0 index register
|
|
|
|
|
has been loaded wit the result of the evaluated
|
|
|
|
|
ivl_lval_mux expression. */
|
|
|
|
|
|
|
|
|
|
draw_eval_expr_into_integer(ivl_lval_mux(lval), 0);
|
|
|
|
|
fprintf(vvp_out, " %%jmp/1 t_%u, 4;\n", skip_set);
|
|
|
|
|
|
2005-03-22 06:18:34 +01:00
|
|
|
fprintf(vvp_out, " %%set/x0 V_%s, %u, %u;\n",
|
|
|
|
|
vvp_signal_label(sig), bit, wid);
|
2005-02-15 08:12:55 +01:00
|
|
|
fprintf(vvp_out, "t_%u ;\n", skip_set);
|
|
|
|
|
|
2005-05-17 22:55:42 +02:00
|
|
|
} else if (part_off>0 || ivl_lval_width(lval)!=ivl_signal_width(sig)) {
|
2005-02-15 08:12:55 +01:00
|
|
|
/* There is no mux expression, but a constant part
|
|
|
|
|
offset. Load that into index x0 and generate a
|
|
|
|
|
single-bit set instruction. */
|
2005-03-22 06:18:34 +01:00
|
|
|
assert(ivl_lval_width(lval) == wid);
|
2005-02-15 08:12:55 +01:00
|
|
|
|
|
|
|
|
fprintf(vvp_out, " %%ix/load 0, %u;\n", part_off);
|
2005-03-22 06:18:34 +01:00
|
|
|
fprintf(vvp_out, " %%set/x0 V_%s, %u, %u;\n",
|
|
|
|
|
vvp_signal_label(sig), bit, wid);
|
2004-10-04 03:10:51 +02:00
|
|
|
|
2002-11-07 04:12:17 +01:00
|
|
|
} else {
|
2004-12-11 03:31:25 +01:00
|
|
|
fprintf(vvp_out, " %%set/v V_%s, %u, %u;\n",
|
|
|
|
|
vvp_signal_label(sig), bit, wid);
|
2002-11-07 04:12:17 +01:00
|
|
|
|
|
|
|
|
}
|
2001-03-21 02:49:43 +01:00
|
|
|
}
|
|
|
|
|
|
2005-03-03 05:33:10 +01:00
|
|
|
/*
|
|
|
|
|
* This function writes the code to set a vector to a memory word. The
|
|
|
|
|
* idx is the thread register that contains the address of the word in
|
|
|
|
|
* the memory, and bit is the base of the thread vector. The wid is
|
|
|
|
|
* the width of the vector to be written to the word.
|
|
|
|
|
*/
|
|
|
|
|
static void set_to_memory_word(ivl_memory_t mem, unsigned idx,
|
|
|
|
|
unsigned bit, unsigned wid)
|
|
|
|
|
{
|
|
|
|
|
fprintf(vvp_out, " %%set/mv M_%s, %u, %u;\n",
|
|
|
|
|
vvp_memory_label(mem), bit, wid);
|
|
|
|
|
}
|
2001-05-09 01:59:33 +02:00
|
|
|
|
2005-06-14 03:44:09 +02:00
|
|
|
static void assign_to_lvector(ivl_lval_t lval, unsigned bit,
|
|
|
|
|
unsigned delay, ivl_expr_t dexp,
|
|
|
|
|
unsigned width)
|
2002-11-08 06:00:31 +01:00
|
|
|
{
|
|
|
|
|
ivl_signal_t sig = ivl_lval_sig(lval);
|
|
|
|
|
unsigned part_off = ivl_lval_part_off(lval);
|
2005-05-07 05:16:31 +02:00
|
|
|
ivl_expr_t mux = ivl_lval_mux(lval);
|
2002-11-08 06:00:31 +01:00
|
|
|
|
2004-12-11 03:31:25 +01:00
|
|
|
|
2005-05-07 05:16:31 +02:00
|
|
|
if (mux != 0) {
|
2005-05-09 02:38:12 +02:00
|
|
|
unsigned skip_assign = transient_id++;
|
2005-06-14 03:44:09 +02:00
|
|
|
assert(dexp == 0);
|
2005-05-07 05:16:31 +02:00
|
|
|
draw_eval_expr_into_integer(mux, 1);
|
2005-05-09 02:38:12 +02:00
|
|
|
/* If the index expression has XZ bits, skip the assign. */
|
|
|
|
|
fprintf(vvp_out, " %%jmp/1 t_%u, 4;\n", skip_assign);
|
2005-05-07 05:16:31 +02:00
|
|
|
fprintf(vvp_out, " %%ix/load 0, %u;\n", width);
|
|
|
|
|
fprintf(vvp_out, " %%assign/v0/x1 V_%s, %u, %u;\n",
|
|
|
|
|
vvp_signal_label(sig), delay, bit);
|
2005-05-09 02:38:12 +02:00
|
|
|
fprintf(vvp_out, "t_%u ;\n", skip_assign);
|
|
|
|
|
|
2005-05-24 04:31:18 +02:00
|
|
|
} else if (part_off>0 || ivl_lval_width(lval)!=ivl_signal_width(sig)) {
|
|
|
|
|
/* There is no mux expression, but a constant part
|
|
|
|
|
offset. Load that into index x1 and generate a
|
|
|
|
|
single-bit set instruction. */
|
|
|
|
|
assert(ivl_lval_width(lval) == width);
|
2005-06-14 03:44:09 +02:00
|
|
|
assert(dexp == 0);
|
2005-05-24 04:31:18 +02:00
|
|
|
|
|
|
|
|
fprintf(vvp_out, " %%ix/load 0, %u;\n", width);
|
|
|
|
|
fprintf(vvp_out, " %%ix/load 1, %u;\n", part_off);
|
|
|
|
|
fprintf(vvp_out, " %%assign/v0/x1 V_%s, %u, %u;\n",
|
|
|
|
|
vvp_signal_label(sig), delay, bit);
|
|
|
|
|
|
2005-06-14 03:44:09 +02:00
|
|
|
} else if (dexp != 0) {
|
|
|
|
|
draw_eval_expr_into_integer(dexp, 1);
|
|
|
|
|
fprintf(vvp_out, " %%ix/load 0, %u;\n", width);
|
|
|
|
|
fprintf(vvp_out, " %%assign/v0/d V_%s, 1, %u;\n",
|
|
|
|
|
vvp_signal_label(sig), bit);
|
2005-05-07 05:16:31 +02:00
|
|
|
} else {
|
|
|
|
|
fprintf(vvp_out, " %%ix/load 0, %u;\n", width);
|
|
|
|
|
fprintf(vvp_out, " %%assign/v0 V_%s, %u, %u;\n",
|
|
|
|
|
vvp_signal_label(sig), delay, bit);
|
|
|
|
|
}
|
2002-11-08 06:00:31 +01:00
|
|
|
}
|
|
|
|
|
|
2005-03-06 18:07:48 +01:00
|
|
|
static void assign_to_memory_word(ivl_memory_t mem, unsigned bit,
|
|
|
|
|
unsigned delay, unsigned wid)
|
2001-05-09 01:59:33 +02:00
|
|
|
{
|
2005-03-06 18:07:48 +01:00
|
|
|
assert(wid = ivl_memory_width(mem));
|
|
|
|
|
|
|
|
|
|
fprintf(vvp_out, " %%ix/load 0, %u;\n", wid);
|
|
|
|
|
fprintf(vvp_out, " %%assign/mv M_%s, %u, %u;\n",
|
2002-08-04 20:28:14 +02:00
|
|
|
vvp_memory_label(mem), delay, bit);
|
2001-05-09 01:59:33 +02:00
|
|
|
}
|
|
|
|
|
|
2002-08-27 07:39:57 +02:00
|
|
|
/*
|
|
|
|
|
* This function, in addition to setting the value into index 0, sets
|
|
|
|
|
* bit 4 to 1 if the value is unknown.
|
|
|
|
|
*/
|
2005-03-03 05:33:10 +01:00
|
|
|
static void draw_eval_expr_into_integer(ivl_expr_t expr, unsigned ix)
|
2005-01-28 20:39:03 +01:00
|
|
|
{
|
|
|
|
|
struct vector_info vec;
|
|
|
|
|
int word;
|
|
|
|
|
|
|
|
|
|
switch (ivl_expr_value(expr)) {
|
|
|
|
|
|
|
|
|
|
case IVL_VT_VECTOR:
|
|
|
|
|
vec = draw_eval_expr(expr, 0);
|
|
|
|
|
fprintf(vvp_out, " %%ix/get %u, %u, %u;\n",
|
|
|
|
|
ix, vec.base, vec.wid);
|
|
|
|
|
clr_vector(vec);
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case IVL_VT_REAL:
|
|
|
|
|
word = draw_eval_real(expr);
|
|
|
|
|
clr_word(word);
|
|
|
|
|
fprintf(vvp_out, " %%cvt/ir %u, %u;\n", ix, word);
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
default:
|
|
|
|
|
assert(0);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2002-04-22 00:31:02 +02:00
|
|
|
static void calculate_into_x1(ivl_expr_t expr)
|
|
|
|
|
{
|
2005-01-28 20:39:03 +01:00
|
|
|
draw_eval_expr_into_integer(expr, 1);
|
2002-04-22 00:31:02 +02:00
|
|
|
}
|
|
|
|
|
|
2003-02-27 21:38:12 +01:00
|
|
|
/*
|
|
|
|
|
* This is a private function to generate %set code for the
|
|
|
|
|
* statement. At this point, the r-value is evaluated and stored in
|
|
|
|
|
* the res vector, I just need to generate the %set statements for the
|
|
|
|
|
* l-values of the assignment.
|
|
|
|
|
*/
|
|
|
|
|
static void set_vec_to_lval(ivl_statement_t net, struct vector_info res)
|
|
|
|
|
{
|
|
|
|
|
ivl_lval_t lval;
|
|
|
|
|
ivl_memory_t mem;
|
|
|
|
|
|
|
|
|
|
unsigned wid = res.wid;
|
|
|
|
|
unsigned lidx;
|
|
|
|
|
unsigned cur_rbit = 0;
|
|
|
|
|
|
|
|
|
|
for (lidx = 0 ; lidx < ivl_stmt_lvals(net) ; lidx += 1) {
|
|
|
|
|
unsigned skip_set = transient_id++;
|
|
|
|
|
unsigned skip_set_flag = 0;
|
2005-03-05 06:47:42 +01:00
|
|
|
unsigned bidx;
|
2003-02-27 21:38:12 +01:00
|
|
|
unsigned bit_limit = wid - cur_rbit;
|
|
|
|
|
lval = ivl_stmt_lval(net, lidx);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
mem = ivl_lval_mem(lval);
|
|
|
|
|
if (mem) {
|
2005-02-15 08:12:55 +01:00
|
|
|
/* If a memory, then the idx expression is the
|
|
|
|
|
memory index, and the ivl_lval_mux should be
|
|
|
|
|
absent. */
|
|
|
|
|
assert(! ivl_lval_mux(lval));
|
2003-02-27 21:38:12 +01:00
|
|
|
draw_memory_index_expr(mem, ivl_lval_idx(lval));
|
|
|
|
|
fprintf(vvp_out, " %%jmp/1 t_%u, 4;\n", skip_set);
|
|
|
|
|
skip_set_flag = 1;
|
|
|
|
|
}
|
|
|
|
|
|
2005-03-05 06:47:42 +01:00
|
|
|
/* Reduce bit_limit to the width of this l-value. */
|
2004-12-11 03:31:25 +01:00
|
|
|
if (bit_limit > ivl_lval_width(lval))
|
|
|
|
|
bit_limit = ivl_lval_width(lval);
|
2003-02-27 21:38:12 +01:00
|
|
|
|
2005-03-05 06:47:42 +01:00
|
|
|
/* This is the address within the larger r-value of the
|
|
|
|
|
bit that this l-value takes. */
|
|
|
|
|
bidx = res.base < 4? res.base : (res.base+cur_rbit);
|
|
|
|
|
|
2003-02-27 21:38:12 +01:00
|
|
|
if (mem) {
|
2005-03-05 06:47:42 +01:00
|
|
|
set_to_memory_word(mem, 3, bidx, bit_limit);
|
2005-03-03 05:33:10 +01:00
|
|
|
|
2003-02-27 21:38:12 +01:00
|
|
|
} else {
|
2005-03-03 05:33:10 +01:00
|
|
|
set_to_lvariable(lval, bidx, bit_limit);
|
2003-02-27 21:38:12 +01:00
|
|
|
}
|
|
|
|
|
|
2005-03-05 06:47:42 +01:00
|
|
|
/* Now we've consumed this many r-value bits for the
|
|
|
|
|
current l-value. */
|
|
|
|
|
cur_rbit += bit_limit;
|
2003-02-27 21:38:12 +01:00
|
|
|
|
|
|
|
|
if (skip_set_flag) {
|
|
|
|
|
fprintf(vvp_out, "t_%u ;\n", skip_set);
|
|
|
|
|
clear_expression_lookaside();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2003-01-26 22:15:58 +01:00
|
|
|
static int show_stmt_assign_vector(ivl_statement_t net)
|
2001-03-21 02:49:43 +01:00
|
|
|
{
|
|
|
|
|
ivl_expr_t rval = ivl_stmt_rval(net);
|
|
|
|
|
|
2003-02-27 21:38:12 +01:00
|
|
|
/* Handle the special case that the expression is a real
|
|
|
|
|
value. Evaluate the real expression, then convert the
|
|
|
|
|
result to a vector. Then store that vector into the
|
|
|
|
|
l-value. */
|
|
|
|
|
if (ivl_expr_value(rval) == IVL_VT_REAL) {
|
|
|
|
|
int word = draw_eval_real(rval);
|
|
|
|
|
/* This is the accumulated with of the l-value of the
|
|
|
|
|
assignment. */
|
|
|
|
|
unsigned wid = ivl_stmt_lwidth(net);
|
|
|
|
|
|
|
|
|
|
struct vector_info vec;
|
|
|
|
|
|
|
|
|
|
vec.base = allocate_vector(wid);
|
|
|
|
|
vec.wid = wid;
|
|
|
|
|
|
|
|
|
|
fprintf(vvp_out, " %%cvt/vr %u, %d, %u;\n",
|
|
|
|
|
vec.base, word, vec.wid);
|
|
|
|
|
|
|
|
|
|
clr_word(word);
|
|
|
|
|
|
|
|
|
|
set_vec_to_lval(net, vec);
|
|
|
|
|
|
|
|
|
|
clr_vector(vec);
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
2001-03-21 02:49:43 +01:00
|
|
|
|
2002-09-13 05:12:50 +02:00
|
|
|
{ struct vector_info res = draw_eval_expr(rval, 0);
|
2003-02-27 21:38:12 +01:00
|
|
|
set_vec_to_lval(net, res);
|
2002-08-31 05:48:50 +02:00
|
|
|
if (res.base > 3)
|
|
|
|
|
clr_vector(res);
|
2001-03-23 02:54:32 +01:00
|
|
|
}
|
|
|
|
|
|
2001-08-26 01:50:02 +02:00
|
|
|
|
2001-03-27 05:31:06 +02:00
|
|
|
return 0;
|
2001-03-21 02:49:43 +01:00
|
|
|
}
|
|
|
|
|
|
2003-01-26 22:15:58 +01:00
|
|
|
static int show_stmt_assign_real(ivl_statement_t net)
|
|
|
|
|
{
|
|
|
|
|
int res;
|
|
|
|
|
ivl_lval_t lval;
|
|
|
|
|
ivl_variable_t var;
|
|
|
|
|
|
|
|
|
|
res = draw_eval_real(ivl_stmt_rval(net));
|
|
|
|
|
clr_word(res);
|
|
|
|
|
|
|
|
|
|
assert(ivl_stmt_lvals(net) == 1);
|
|
|
|
|
lval = ivl_stmt_lval(net, 0);
|
|
|
|
|
var = ivl_lval_var(lval);
|
|
|
|
|
assert(var != 0);
|
|
|
|
|
|
|
|
|
|
fprintf(vvp_out, " %%set/wr W_%s, %d;\n",
|
|
|
|
|
vvp_word_label(var), res);
|
|
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static int show_stmt_assign(ivl_statement_t net)
|
|
|
|
|
{
|
|
|
|
|
ivl_lval_t lval;
|
|
|
|
|
ivl_variable_t var;
|
|
|
|
|
|
|
|
|
|
lval = ivl_stmt_lval(net, 0);
|
|
|
|
|
|
|
|
|
|
if ( (var = ivl_lval_var(lval)) != 0 ) {
|
|
|
|
|
switch (ivl_variable_type(var)) {
|
|
|
|
|
case IVL_VT_VOID:
|
|
|
|
|
assert(0);
|
|
|
|
|
return 1;
|
|
|
|
|
|
|
|
|
|
case IVL_VT_VECTOR:
|
|
|
|
|
/* Can't happen. */
|
|
|
|
|
assert(0);
|
|
|
|
|
return 1;
|
|
|
|
|
|
|
|
|
|
case IVL_VT_REAL:
|
|
|
|
|
return show_stmt_assign_real(net);
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
} else {
|
|
|
|
|
return show_stmt_assign_vector(net);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
2004-05-19 05:25:42 +02:00
|
|
|
/*
|
|
|
|
|
* This function handles the case of non-blocking assign to word
|
|
|
|
|
* variables such as real, i.e:
|
|
|
|
|
*
|
2005-01-28 20:39:03 +01:00
|
|
|
* real foo;
|
2004-05-19 05:25:42 +02:00
|
|
|
* foo <= 1.0;
|
|
|
|
|
*
|
|
|
|
|
* In this case we know (by Verilog syntax) that there is only exactly
|
|
|
|
|
* 1 l-value, the target identifier, so it should be relatively easy.
|
|
|
|
|
*/
|
|
|
|
|
static int show_stmt_assign_nb_var(ivl_statement_t net)
|
|
|
|
|
{
|
|
|
|
|
ivl_lval_t lval;
|
|
|
|
|
ivl_variable_t var;
|
|
|
|
|
ivl_expr_t rval = ivl_stmt_rval(net);
|
|
|
|
|
ivl_expr_t del = ivl_stmt_delay_expr(net);
|
|
|
|
|
|
|
|
|
|
int word;
|
|
|
|
|
unsigned long delay;
|
|
|
|
|
|
|
|
|
|
/* Must be exactly 1 l-value. */
|
|
|
|
|
assert(ivl_stmt_lvals(net) == 1);
|
|
|
|
|
|
|
|
|
|
delay = 0;
|
|
|
|
|
if (del && (ivl_expr_type(del) == IVL_EX_ULONG)) {
|
|
|
|
|
delay = ivl_expr_uvalue(del);
|
|
|
|
|
del = 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* XXXX For now, presume delays are constant. */
|
|
|
|
|
assert(del == 0);
|
|
|
|
|
|
|
|
|
|
/* Evaluate the r-value */
|
|
|
|
|
word = draw_eval_real(rval);
|
|
|
|
|
|
|
|
|
|
lval = ivl_stmt_lval(net, 0);
|
|
|
|
|
var = ivl_lval_var(lval);
|
|
|
|
|
assert(var != 0);
|
|
|
|
|
|
|
|
|
|
fprintf(vvp_out, " %%assign/wr W_%s, %lu, %u;\n",
|
|
|
|
|
vvp_word_label(var), delay, word);
|
|
|
|
|
|
2005-01-28 20:39:03 +01:00
|
|
|
clr_word(word);
|
|
|
|
|
|
2004-05-19 05:25:42 +02:00
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
2001-04-03 06:50:37 +02:00
|
|
|
static int show_stmt_assign_nb(ivl_statement_t net)
|
|
|
|
|
{
|
|
|
|
|
ivl_lval_t lval;
|
|
|
|
|
ivl_expr_t rval = ivl_stmt_rval(net);
|
2001-04-15 04:58:11 +02:00
|
|
|
ivl_expr_t del = ivl_stmt_delay_expr(net);
|
2001-05-09 01:59:33 +02:00
|
|
|
ivl_memory_t mem;
|
2001-04-15 04:58:11 +02:00
|
|
|
|
|
|
|
|
unsigned long delay = 0;
|
2004-05-19 05:25:42 +02:00
|
|
|
|
|
|
|
|
/* Catch the case we are assigning to a real/word
|
|
|
|
|
l-value. Handle that elsewhere. */
|
|
|
|
|
if (ivl_lval_var(ivl_stmt_lval(net, 0))) {
|
|
|
|
|
return show_stmt_assign_nb_var(net);
|
|
|
|
|
}
|
|
|
|
|
|
2002-04-22 00:31:02 +02:00
|
|
|
if (del && (ivl_expr_type(del) == IVL_EX_ULONG)) {
|
2001-04-15 04:58:11 +02:00
|
|
|
delay = ivl_expr_uvalue(del);
|
2002-04-22 00:31:02 +02:00
|
|
|
del = 0;
|
2001-04-15 04:58:11 +02:00
|
|
|
}
|
2001-04-03 06:50:37 +02:00
|
|
|
|
2001-08-26 01:50:02 +02:00
|
|
|
|
2002-09-13 05:12:50 +02:00
|
|
|
{ struct vector_info res = draw_eval_expr(rval, 0);
|
2001-04-03 06:50:37 +02:00
|
|
|
unsigned wid = res.wid;
|
2001-08-26 01:50:02 +02:00
|
|
|
unsigned lidx;
|
|
|
|
|
unsigned cur_rbit = 0;
|
|
|
|
|
|
2002-04-22 00:31:02 +02:00
|
|
|
if (del != 0)
|
|
|
|
|
calculate_into_x1(del);
|
|
|
|
|
|
2001-08-26 01:50:02 +02:00
|
|
|
for (lidx = 0 ; lidx < ivl_stmt_lvals(net) ; lidx += 1) {
|
2002-09-01 02:19:35 +02:00
|
|
|
unsigned skip_set = transient_id++;
|
|
|
|
|
unsigned skip_set_flag = 0;
|
2001-08-26 01:50:02 +02:00
|
|
|
unsigned bit_limit = wid - cur_rbit;
|
|
|
|
|
lval = ivl_stmt_lval(net, lidx);
|
|
|
|
|
|
|
|
|
|
mem = ivl_lval_mem(lval);
|
2002-09-01 02:19:35 +02:00
|
|
|
if (mem) {
|
2001-08-26 01:50:02 +02:00
|
|
|
draw_memory_index_expr(mem, ivl_lval_idx(lval));
|
2002-09-01 02:19:35 +02:00
|
|
|
fprintf(vvp_out, " %%jmp/1 t_%u, 4;\n", skip_set);
|
|
|
|
|
skip_set_flag = 1;
|
|
|
|
|
}
|
2001-08-26 01:50:02 +02:00
|
|
|
|
2004-12-11 03:31:25 +01:00
|
|
|
if (bit_limit > ivl_lval_width(lval))
|
|
|
|
|
bit_limit = ivl_lval_width(lval);
|
2001-08-26 01:50:02 +02:00
|
|
|
|
2005-06-14 03:44:09 +02:00
|
|
|
if (mem == 0) {
|
2002-11-08 06:00:31 +01:00
|
|
|
|
2001-08-26 01:50:02 +02:00
|
|
|
unsigned bidx = res.base < 4
|
|
|
|
|
? res.base
|
|
|
|
|
: (res.base+cur_rbit);
|
2005-06-14 03:44:09 +02:00
|
|
|
assign_to_lvector(lval, bidx, delay, del, bit_limit);
|
2002-11-08 06:00:31 +01:00
|
|
|
cur_rbit += bit_limit;
|
|
|
|
|
|
2005-06-14 03:44:09 +02:00
|
|
|
} else {
|
|
|
|
|
assert(mem);
|
2005-03-06 18:07:48 +01:00
|
|
|
/* XXXX don't yes know what to do with a delay
|
|
|
|
|
in an index variable. */
|
|
|
|
|
assert(del == 0);
|
|
|
|
|
assign_to_memory_word(mem, res.base, delay, bit_limit);
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
2002-09-01 02:19:35 +02:00
|
|
|
|
2002-09-27 22:24:42 +02:00
|
|
|
if (skip_set_flag) {
|
2002-09-01 02:19:35 +02:00
|
|
|
fprintf(vvp_out, "t_%u ;\n", skip_set);
|
2002-09-27 22:24:42 +02:00
|
|
|
clear_expression_lookaside();
|
|
|
|
|
}
|
2001-05-09 01:59:33 +02:00
|
|
|
}
|
2001-04-03 06:50:37 +02:00
|
|
|
|
2002-08-31 05:48:50 +02:00
|
|
|
if (res.base > 3)
|
|
|
|
|
clr_vector(res);
|
2001-04-03 06:50:37 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
2001-04-21 02:55:46 +02:00
|
|
|
static int show_stmt_block(ivl_statement_t net, ivl_scope_t sscope)
|
|
|
|
|
{
|
|
|
|
|
int rc = 0;
|
|
|
|
|
unsigned idx;
|
|
|
|
|
unsigned cnt = ivl_stmt_block_count(net);
|
|
|
|
|
|
|
|
|
|
for (idx = 0 ; idx < cnt ; idx += 1) {
|
|
|
|
|
rc += show_statement(ivl_stmt_block_stmt(net, idx), sscope);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return rc;
|
|
|
|
|
}
|
|
|
|
|
|
2002-05-27 02:08:45 +02:00
|
|
|
/*
|
|
|
|
|
* This draws an invocation of a named block. This is a little
|
|
|
|
|
* different because a subscope is created. We do that by creating
|
|
|
|
|
* a thread to deal with this.
|
|
|
|
|
*/
|
|
|
|
|
static int show_stmt_block_named(ivl_statement_t net, ivl_scope_t scope)
|
|
|
|
|
{
|
|
|
|
|
int rc;
|
|
|
|
|
int out_id, sub_id;
|
|
|
|
|
ivl_scope_t subscope = ivl_stmt_block_scope(net);
|
|
|
|
|
|
|
|
|
|
out_id = transient_id++;
|
|
|
|
|
sub_id = transient_id++;
|
|
|
|
|
|
2003-03-25 03:15:48 +01:00
|
|
|
fprintf(vvp_out, " %%fork t_%u, S_%p;\n",
|
|
|
|
|
sub_id, subscope);
|
2002-05-27 02:08:45 +02:00
|
|
|
fprintf(vvp_out, " %%jmp t_%u;\n", out_id);
|
|
|
|
|
fprintf(vvp_out, "t_%u ;\n", sub_id);
|
|
|
|
|
|
|
|
|
|
rc = show_stmt_block(net, subscope);
|
|
|
|
|
fprintf(vvp_out, " %%end;\n");
|
|
|
|
|
|
|
|
|
|
fprintf(vvp_out, "t_%u %%join;\n", out_id);
|
2002-09-27 18:33:34 +02:00
|
|
|
clear_expression_lookaside();
|
2002-05-27 02:08:45 +02:00
|
|
|
|
|
|
|
|
return rc;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2001-04-18 07:12:03 +02:00
|
|
|
static int show_stmt_case(ivl_statement_t net, ivl_scope_t sscope)
|
2001-03-31 19:36:38 +02:00
|
|
|
{
|
|
|
|
|
ivl_expr_t exp = ivl_stmt_cond_expr(net);
|
2002-09-13 05:12:50 +02:00
|
|
|
struct vector_info cond = draw_eval_expr(exp, 0);
|
2001-03-31 19:36:38 +02:00
|
|
|
unsigned count = ivl_stmt_case_count(net);
|
|
|
|
|
|
|
|
|
|
unsigned local_base = local_count;
|
|
|
|
|
|
|
|
|
|
unsigned idx, default_case;
|
|
|
|
|
|
|
|
|
|
local_count += count + 1;
|
|
|
|
|
|
|
|
|
|
/* First draw the branch table. All the non-default cases
|
|
|
|
|
generate a branch out of here, to the code that implements
|
|
|
|
|
the case. The default will fall through all the tests. */
|
|
|
|
|
default_case = count;
|
|
|
|
|
|
|
|
|
|
for (idx = 0 ; idx < count ; idx += 1) {
|
|
|
|
|
ivl_expr_t cex = ivl_stmt_case_expr(net, idx);
|
|
|
|
|
struct vector_info cvec;
|
|
|
|
|
|
|
|
|
|
if (cex == 0) {
|
|
|
|
|
default_case = idx;
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
2002-06-02 20:57:17 +02:00
|
|
|
/* Is the guard expression something I can pass to a
|
|
|
|
|
%cmpi/u instruction? If so, use that instead. */
|
|
|
|
|
|
|
|
|
|
if ((ivl_statement_type(net) == IVL_ST_CASE)
|
|
|
|
|
&& (ivl_expr_type(cex) == IVL_EX_NUMBER)
|
|
|
|
|
&& (! number_is_unknown(cex))
|
|
|
|
|
&& number_is_immediate(cex, 16)) {
|
|
|
|
|
|
|
|
|
|
unsigned long imm = get_number_immediate(cex);
|
|
|
|
|
|
|
|
|
|
fprintf(vvp_out, " %%cmpi/u %u, %lu, %u;\n",
|
|
|
|
|
cond.base, imm, cond.wid);
|
|
|
|
|
fprintf(vvp_out, " %%jmp/1 T_%d.%d, 6;\n",
|
|
|
|
|
thread_count, local_base+idx);
|
|
|
|
|
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Oh well, do this case the hard way. */
|
|
|
|
|
|
2002-09-13 05:12:50 +02:00
|
|
|
cvec = draw_eval_expr_wid(cex, cond.wid, 0);
|
2001-03-31 21:02:13 +02:00
|
|
|
assert(cvec.wid == cond.wid);
|
2001-03-31 19:36:38 +02:00
|
|
|
|
2001-04-01 06:34:59 +02:00
|
|
|
switch (ivl_statement_type(net)) {
|
2001-03-31 19:36:38 +02:00
|
|
|
|
2001-04-01 06:34:59 +02:00
|
|
|
case IVL_ST_CASE:
|
|
|
|
|
fprintf(vvp_out, " %%cmp/u %u, %u, %u;\n",
|
|
|
|
|
cond.base, cvec.base, cond.wid);
|
|
|
|
|
fprintf(vvp_out, " %%jmp/1 T_%d.%d, 6;\n",
|
|
|
|
|
thread_count, local_base+idx);
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case IVL_ST_CASEX:
|
|
|
|
|
fprintf(vvp_out, " %%cmp/x %u, %u, %u;\n",
|
|
|
|
|
cond.base, cvec.base, cond.wid);
|
|
|
|
|
fprintf(vvp_out, " %%jmp/1 T_%d.%d, 4;\n",
|
|
|
|
|
thread_count, local_base+idx);
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case IVL_ST_CASEZ:
|
|
|
|
|
fprintf(vvp_out, " %%cmp/z %u, %u, %u;\n",
|
|
|
|
|
cond.base, cvec.base, cond.wid);
|
|
|
|
|
fprintf(vvp_out, " %%jmp/1 T_%d.%d, 4;\n",
|
|
|
|
|
thread_count, local_base+idx);
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
default:
|
|
|
|
|
assert(0);
|
|
|
|
|
}
|
2004-10-04 03:10:51 +02:00
|
|
|
|
2001-03-31 19:36:38 +02:00
|
|
|
/* Done with the case expression */
|
|
|
|
|
clr_vector(cvec);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Done with the condition expression */
|
|
|
|
|
clr_vector(cond);
|
|
|
|
|
|
|
|
|
|
/* Emit code for the default case. */
|
|
|
|
|
if (default_case < count) {
|
|
|
|
|
ivl_statement_t cst = ivl_stmt_case_stmt(net, default_case);
|
2001-04-18 07:12:03 +02:00
|
|
|
show_statement(cst, sscope);
|
2001-03-31 19:36:38 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Jump to the out of the case. */
|
|
|
|
|
fprintf(vvp_out, " %%jmp T_%d.%d;\n", thread_count,
|
|
|
|
|
local_base+count);
|
|
|
|
|
|
|
|
|
|
for (idx = 0 ; idx < count ; idx += 1) {
|
|
|
|
|
ivl_statement_t cst = ivl_stmt_case_stmt(net, idx);
|
|
|
|
|
|
|
|
|
|
if (idx == default_case)
|
|
|
|
|
continue;
|
|
|
|
|
|
2001-05-24 06:31:00 +02:00
|
|
|
fprintf(vvp_out, "T_%d.%d ;\n", thread_count, local_base+idx);
|
2002-09-27 22:24:42 +02:00
|
|
|
clear_expression_lookaside();
|
2001-04-18 07:12:03 +02:00
|
|
|
show_statement(cst, sscope);
|
2001-03-31 19:36:38 +02:00
|
|
|
|
|
|
|
|
fprintf(vvp_out, " %%jmp T_%d.%d;\n", thread_count,
|
|
|
|
|
local_base+count);
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
2002-09-27 18:33:34 +02:00
|
|
|
|
2001-03-31 19:36:38 +02:00
|
|
|
/* The out of the case. */
|
2001-05-24 06:31:00 +02:00
|
|
|
fprintf(vvp_out, "T_%d.%d ;\n", thread_count, local_base+count);
|
2002-09-27 22:24:42 +02:00
|
|
|
clear_expression_lookaside();
|
2001-03-31 19:36:38 +02:00
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
2003-05-14 07:26:41 +02:00
|
|
|
static int show_stmt_case_r(ivl_statement_t net, ivl_scope_t sscope)
|
|
|
|
|
{
|
|
|
|
|
ivl_expr_t exp = ivl_stmt_cond_expr(net);
|
|
|
|
|
int cond = draw_eval_real(exp);
|
|
|
|
|
unsigned count = ivl_stmt_case_count(net);
|
|
|
|
|
|
|
|
|
|
unsigned local_base = local_count;
|
|
|
|
|
|
|
|
|
|
unsigned idx, default_case;
|
|
|
|
|
|
|
|
|
|
local_count += count + 1;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* First draw the branch table. All the non-default cases
|
|
|
|
|
generate a branch out of here, to the code that implements
|
|
|
|
|
the case. The default will fall through all the tests. */
|
|
|
|
|
default_case = count;
|
|
|
|
|
|
|
|
|
|
for (idx = 0 ; idx < count ; idx += 1) {
|
|
|
|
|
ivl_expr_t cex = ivl_stmt_case_expr(net, idx);
|
|
|
|
|
int cvec;
|
|
|
|
|
|
|
|
|
|
if (cex == 0) {
|
|
|
|
|
default_case = idx;
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
cvec = draw_eval_real(cex);
|
|
|
|
|
|
|
|
|
|
fprintf(vvp_out, " %%cmp/wr %d, %d;\n", cond, cvec);
|
|
|
|
|
fprintf(vvp_out, " %%jmp/1 T_%d.%d, 4;\n",
|
|
|
|
|
thread_count, local_base+idx);
|
|
|
|
|
|
|
|
|
|
/* Done with the guard expression value. */
|
|
|
|
|
clr_word(cvec);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Done with the case expression. */
|
|
|
|
|
clr_word(cond);
|
|
|
|
|
|
|
|
|
|
/* Emit code for the case default. The above jump table will
|
|
|
|
|
fall through to this statement. */
|
|
|
|
|
if (default_case < count) {
|
|
|
|
|
ivl_statement_t cst = ivl_stmt_case_stmt(net, default_case);
|
|
|
|
|
show_statement(cst, sscope);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Jump to the out of the case. */
|
|
|
|
|
fprintf(vvp_out, " %%jmp T_%d.%d;\n", thread_count,
|
|
|
|
|
local_base+count);
|
|
|
|
|
|
|
|
|
|
for (idx = 0 ; idx < count ; idx += 1) {
|
|
|
|
|
ivl_statement_t cst = ivl_stmt_case_stmt(net, idx);
|
|
|
|
|
|
|
|
|
|
if (idx == default_case)
|
|
|
|
|
continue;
|
|
|
|
|
|
|
|
|
|
fprintf(vvp_out, "T_%d.%d ;\n", thread_count, local_base+idx);
|
|
|
|
|
clear_expression_lookaside();
|
|
|
|
|
show_statement(cst, sscope);
|
|
|
|
|
|
|
|
|
|
fprintf(vvp_out, " %%jmp T_%d.%d;\n", thread_count,
|
|
|
|
|
local_base+count);
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* The out of the case. */
|
|
|
|
|
fprintf(vvp_out, "T_%d.%d ;\n", thread_count, local_base+count);
|
|
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
2004-12-17 05:46:40 +01:00
|
|
|
static void force_vector_to_lval(ivl_statement_t net, struct vector_info rvec)
|
2001-11-01 05:26:57 +01:00
|
|
|
{
|
2004-12-17 05:46:40 +01:00
|
|
|
unsigned lidx;
|
2004-12-11 06:43:30 +01:00
|
|
|
unsigned roff = 0;
|
2001-11-01 05:26:57 +01:00
|
|
|
|
2004-12-17 05:46:40 +01:00
|
|
|
const char*command_name;
|
2001-11-01 05:26:57 +01:00
|
|
|
|
2004-12-17 05:46:40 +01:00
|
|
|
switch (ivl_statement_type(net)) {
|
|
|
|
|
case IVL_ST_CASSIGN:
|
|
|
|
|
command_name = "%cassign/v";
|
|
|
|
|
break;
|
|
|
|
|
case IVL_ST_FORCE:
|
|
|
|
|
command_name = "%force/v";
|
|
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
|
command_name = "ERROR";
|
|
|
|
|
assert(0);
|
|
|
|
|
break;
|
|
|
|
|
}
|
2001-11-01 05:26:57 +01:00
|
|
|
|
2004-12-11 06:43:30 +01:00
|
|
|
for (lidx = 0 ; lidx < ivl_stmt_lvals(net) ; lidx += 1) {
|
|
|
|
|
ivl_lval_t lval = ivl_stmt_lval(net, lidx);
|
|
|
|
|
ivl_signal_t lsig = ivl_lval_sig(lval);
|
|
|
|
|
unsigned use_wid;
|
2004-12-11 03:31:25 +01:00
|
|
|
|
2004-12-11 06:43:30 +01:00
|
|
|
assert(lsig != 0);
|
|
|
|
|
assert(ivl_lval_mux(lval) == 0);
|
|
|
|
|
assert(ivl_lval_part_off(lval) == 0);
|
2004-12-11 03:31:25 +01:00
|
|
|
|
2004-12-11 06:43:30 +01:00
|
|
|
use_wid = ivl_signal_width(lsig);
|
|
|
|
|
assert(roff + use_wid <= rvec.wid);
|
2004-12-11 03:31:25 +01:00
|
|
|
|
2004-12-17 05:46:40 +01:00
|
|
|
fprintf(vvp_out, " %s V_%s, %u, %u;\n", command_name,
|
2004-12-11 06:43:30 +01:00
|
|
|
vvp_signal_label(lsig), rvec.base+roff, use_wid);
|
|
|
|
|
|
|
|
|
|
if (rvec.base >= 4)
|
|
|
|
|
roff += use_wid;
|
2001-11-01 05:26:57 +01:00
|
|
|
}
|
2004-12-17 05:46:40 +01:00
|
|
|
}
|
|
|
|
|
|
2005-06-02 18:03:47 +02:00
|
|
|
static void force_link_rval(ivl_statement_t net, ivl_expr_t rval)
|
|
|
|
|
{
|
|
|
|
|
ivl_signal_t rsig;;
|
|
|
|
|
ivl_lval_t lval;
|
|
|
|
|
ivl_signal_t lsig;
|
|
|
|
|
const char*command_name;
|
|
|
|
|
|
|
|
|
|
if (ivl_expr_type(rval) != IVL_EX_SIGNAL)
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
switch (ivl_statement_type(net)) {
|
|
|
|
|
case IVL_ST_CASSIGN:
|
|
|
|
|
command_name = "%cassign";
|
|
|
|
|
break;
|
|
|
|
|
case IVL_ST_FORCE:
|
|
|
|
|
command_name = "%force";
|
|
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
|
command_name = "ERROR";
|
|
|
|
|
assert(0);
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
rsig = ivl_expr_signal(rval);
|
|
|
|
|
assert(ivl_stmt_lvals(net) == 1);
|
|
|
|
|
lval = ivl_stmt_lval(net, 0);
|
|
|
|
|
lsig = ivl_lval_sig(lval);
|
|
|
|
|
|
|
|
|
|
fprintf(vvp_out, " %s/link", command_name);
|
|
|
|
|
fprintf(vvp_out, " V_%s", vvp_signal_label(lsig));
|
|
|
|
|
fprintf(vvp_out, ", V_%s;\n", vvp_signal_label(rsig));
|
|
|
|
|
}
|
|
|
|
|
|
2004-12-17 05:46:40 +01:00
|
|
|
static int show_stmt_cassign(ivl_statement_t net)
|
|
|
|
|
{
|
|
|
|
|
ivl_expr_t rval;
|
|
|
|
|
struct vector_info rvec;
|
|
|
|
|
|
|
|
|
|
rval = ivl_stmt_rval(net);
|
|
|
|
|
assert(rval);
|
|
|
|
|
|
|
|
|
|
rvec = draw_eval_expr(rval, STUFF_OK_47);
|
2001-11-01 05:26:57 +01:00
|
|
|
|
2004-12-17 05:46:40 +01:00
|
|
|
/* Write out initial continuous assign instructions to assign
|
|
|
|
|
the expression value to the l-value. */
|
|
|
|
|
force_vector_to_lval(net, rvec);
|
|
|
|
|
|
2005-06-02 18:03:47 +02:00
|
|
|
force_link_rval(net, rval);
|
2004-12-11 06:43:30 +01:00
|
|
|
|
2001-11-01 05:26:57 +01:00
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
2004-12-11 06:43:30 +01:00
|
|
|
/*
|
|
|
|
|
* Handle the deassign similar to cassign. The lvals must all be
|
|
|
|
|
* vectors without bit or part selects. Simply call %deassign for all
|
|
|
|
|
* the values.
|
|
|
|
|
*/
|
2001-11-01 05:26:57 +01:00
|
|
|
static int show_stmt_deassign(ivl_statement_t net)
|
|
|
|
|
{
|
2004-12-11 06:43:30 +01:00
|
|
|
unsigned lidx;
|
2001-11-01 05:26:57 +01:00
|
|
|
|
2004-12-11 06:43:30 +01:00
|
|
|
for (lidx = 0 ; lidx < ivl_stmt_lvals(net) ; lidx += 1) {
|
|
|
|
|
ivl_lval_t lval = ivl_stmt_lval(net, lidx);
|
|
|
|
|
ivl_signal_t lsig = ivl_lval_sig(lval);
|
2001-11-01 05:26:57 +01:00
|
|
|
|
2004-12-11 06:43:30 +01:00
|
|
|
assert(lsig != 0);
|
|
|
|
|
assert(ivl_lval_mux(lval) == 0);
|
|
|
|
|
assert(ivl_lval_part_off(lval) == 0);
|
2001-11-01 05:26:57 +01:00
|
|
|
|
2004-12-11 06:43:30 +01:00
|
|
|
fprintf(vvp_out, " %%deassign V_%s;\n", vvp_signal_label(lsig));
|
|
|
|
|
}
|
2004-12-11 03:31:25 +01:00
|
|
|
|
2001-11-01 05:26:57 +01:00
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
2001-04-18 07:12:03 +02:00
|
|
|
static int show_stmt_condit(ivl_statement_t net, ivl_scope_t sscope)
|
2001-03-22 06:06:21 +01:00
|
|
|
{
|
2001-03-27 05:31:06 +02:00
|
|
|
int rc = 0;
|
2001-03-22 06:06:21 +01:00
|
|
|
unsigned lab_false, lab_out;
|
|
|
|
|
ivl_expr_t exp = ivl_stmt_cond_expr(net);
|
2002-09-24 06:20:32 +02:00
|
|
|
struct vector_info cond = draw_eval_expr(exp, STUFF_OK_XZ|STUFF_OK_47);
|
2001-03-22 06:06:21 +01:00
|
|
|
|
|
|
|
|
assert(cond.wid == 1);
|
|
|
|
|
|
|
|
|
|
lab_false = local_count++;
|
|
|
|
|
lab_out = local_count++;
|
|
|
|
|
|
2001-03-27 08:27:40 +02:00
|
|
|
fprintf(vvp_out, " %%jmp/0xz T_%d.%d, %u;\n",
|
2001-03-22 06:06:21 +01:00
|
|
|
thread_count, lab_false, cond.base);
|
|
|
|
|
|
2001-03-31 21:02:13 +02:00
|
|
|
/* Done with the condition expression. */
|
2002-09-24 06:20:32 +02:00
|
|
|
if (cond.base >= 8)
|
|
|
|
|
clr_vector(cond);
|
2001-03-31 21:02:13 +02:00
|
|
|
|
2002-04-14 21:19:21 +02:00
|
|
|
if (ivl_stmt_cond_true(net))
|
|
|
|
|
rc += show_statement(ivl_stmt_cond_true(net), sscope);
|
2001-03-22 06:06:21 +01:00
|
|
|
|
2002-09-27 18:33:34 +02:00
|
|
|
|
2001-03-22 06:06:21 +01:00
|
|
|
if (ivl_stmt_cond_false(net)) {
|
2001-03-27 08:27:40 +02:00
|
|
|
fprintf(vvp_out, " %%jmp T_%d.%d;\n", thread_count, lab_out);
|
2001-05-03 06:55:28 +02:00
|
|
|
fprintf(vvp_out, "T_%d.%u ;\n", thread_count, lab_false);
|
2002-09-27 22:24:42 +02:00
|
|
|
clear_expression_lookaside();
|
2001-03-22 06:06:21 +01:00
|
|
|
|
2001-04-18 07:12:03 +02:00
|
|
|
rc += show_statement(ivl_stmt_cond_false(net), sscope);
|
2001-03-22 06:06:21 +01:00
|
|
|
|
2001-05-03 06:55:28 +02:00
|
|
|
fprintf(vvp_out, "T_%d.%u ;\n", thread_count, lab_out);
|
2002-09-27 22:24:42 +02:00
|
|
|
clear_expression_lookaside();
|
2001-03-22 06:06:21 +01:00
|
|
|
|
|
|
|
|
} else {
|
2001-05-03 06:55:28 +02:00
|
|
|
fprintf(vvp_out, "T_%d.%u ;\n", thread_count, lab_false);
|
2002-09-27 22:24:42 +02:00
|
|
|
clear_expression_lookaside();
|
2001-03-22 06:06:21 +01:00
|
|
|
}
|
2001-03-27 05:31:06 +02:00
|
|
|
|
|
|
|
|
return rc;
|
2001-03-22 06:06:21 +01:00
|
|
|
}
|
|
|
|
|
|
2001-03-21 02:49:43 +01:00
|
|
|
/*
|
|
|
|
|
* The delay statement is easy. Simply write a ``%delay <n>''
|
|
|
|
|
* instruction to delay the thread, then draw the included statement.
|
|
|
|
|
* The delay statement comes from verilog code like this:
|
|
|
|
|
*
|
|
|
|
|
* ...
|
|
|
|
|
* #<delay> <stmt>;
|
|
|
|
|
*/
|
2001-04-18 07:12:03 +02:00
|
|
|
static int show_stmt_delay(ivl_statement_t net, ivl_scope_t sscope)
|
2001-03-21 02:49:43 +01:00
|
|
|
{
|
2001-03-27 05:31:06 +02:00
|
|
|
int rc = 0;
|
2001-03-21 02:49:43 +01:00
|
|
|
unsigned long delay = ivl_stmt_delay_val(net);
|
|
|
|
|
ivl_statement_t stmt = ivl_stmt_sub_stmt(net);
|
|
|
|
|
|
|
|
|
|
fprintf(vvp_out, " %%delay %lu;\n", delay);
|
2002-09-27 18:33:34 +02:00
|
|
|
/* Lots of things can happen during a delay. */
|
|
|
|
|
clear_expression_lookaside();
|
|
|
|
|
|
2001-04-18 07:12:03 +02:00
|
|
|
rc += show_statement(stmt, sscope);
|
2001-03-27 05:31:06 +02:00
|
|
|
|
|
|
|
|
return rc;
|
2001-03-21 02:49:43 +01:00
|
|
|
}
|
|
|
|
|
|
2001-07-19 06:55:06 +02:00
|
|
|
/*
|
|
|
|
|
* The delayx statement is slightly more complex in that it is
|
|
|
|
|
* necessary to calculate the delay first. Load the calculated delay
|
|
|
|
|
* into and index register and use the %delayx instruction to do the
|
|
|
|
|
* actual delay.
|
|
|
|
|
*/
|
|
|
|
|
static int show_stmt_delayx(ivl_statement_t net, ivl_scope_t sscope)
|
|
|
|
|
{
|
|
|
|
|
int rc = 0;
|
|
|
|
|
ivl_expr_t exp = ivl_stmt_delay_expr(net);
|
|
|
|
|
ivl_statement_t stmt = ivl_stmt_sub_stmt(net);
|
|
|
|
|
|
2003-01-26 22:15:58 +01:00
|
|
|
switch (ivl_expr_value(exp)) {
|
|
|
|
|
|
|
|
|
|
case IVL_VT_VECTOR: {
|
|
|
|
|
struct vector_info del = draw_eval_expr(exp, 0);
|
|
|
|
|
fprintf(vvp_out, " %%ix/get 0, %u, %u;\n",
|
|
|
|
|
del.base, del.wid);
|
|
|
|
|
clr_vector(del);
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
case IVL_VT_REAL: {
|
|
|
|
|
int word = draw_eval_real(exp);
|
|
|
|
|
fprintf(vvp_out, " %%cvt/ir 0, %d;\n", word);
|
|
|
|
|
clr_word(word);
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
default:
|
|
|
|
|
assert(0);
|
2001-07-19 06:55:06 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fprintf(vvp_out, " %%delayx 0;\n");
|
2002-09-27 18:33:34 +02:00
|
|
|
/* Lots of things can happen during a delay. */
|
|
|
|
|
clear_expression_lookaside();
|
2001-07-19 06:55:06 +02:00
|
|
|
|
|
|
|
|
rc += show_statement(stmt, sscope);
|
|
|
|
|
return rc;
|
|
|
|
|
}
|
|
|
|
|
|
2001-04-21 02:55:46 +02:00
|
|
|
static int show_stmt_disable(ivl_statement_t net, ivl_scope_t sscope)
|
|
|
|
|
{
|
|
|
|
|
int rc = 0;
|
|
|
|
|
|
|
|
|
|
ivl_scope_t target = ivl_stmt_call(net);
|
2003-03-25 03:15:48 +01:00
|
|
|
fprintf(vvp_out, " %%disable S_%p;\n", target);
|
2001-04-21 02:55:46 +02:00
|
|
|
|
|
|
|
|
return rc;
|
|
|
|
|
}
|
|
|
|
|
|
2001-11-14 04:28:49 +01:00
|
|
|
static int show_stmt_force(ivl_statement_t net)
|
|
|
|
|
{
|
2004-12-17 05:46:40 +01:00
|
|
|
ivl_expr_t rval;
|
|
|
|
|
struct vector_info rvec;
|
2001-11-18 02:28:18 +01:00
|
|
|
|
2004-12-17 05:46:40 +01:00
|
|
|
rval = ivl_stmt_rval(net);
|
|
|
|
|
assert(rval);
|
2001-11-18 02:28:18 +01:00
|
|
|
|
2004-12-17 05:46:40 +01:00
|
|
|
rvec = draw_eval_expr(rval, STUFF_OK_47);
|
|
|
|
|
|
|
|
|
|
/* Write out initial continuous assign instructions to assign
|
|
|
|
|
the expression value to the l-value. */
|
|
|
|
|
force_vector_to_lval(net, rvec);
|
|
|
|
|
|
2005-06-02 18:03:47 +02:00
|
|
|
force_link_rval(net, rval);
|
2001-11-18 02:28:18 +01:00
|
|
|
|
2001-11-14 04:28:49 +01:00
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
2001-04-18 07:12:03 +02:00
|
|
|
static int show_stmt_forever(ivl_statement_t net, ivl_scope_t sscope)
|
2001-04-04 06:50:35 +02:00
|
|
|
{
|
|
|
|
|
int rc = 0;
|
|
|
|
|
ivl_statement_t stmt = ivl_stmt_sub_stmt(net);
|
|
|
|
|
unsigned lab_top = local_count++;
|
|
|
|
|
|
|
|
|
|
fprintf(vvp_out, "T_%u.%u ;\n", thread_count, lab_top);
|
2001-04-18 07:12:03 +02:00
|
|
|
rc += show_statement(stmt, sscope);
|
2001-04-04 06:50:35 +02:00
|
|
|
fprintf(vvp_out, " %%jmp T_%u.%u;\n", thread_count, lab_top);
|
|
|
|
|
|
|
|
|
|
return rc;
|
|
|
|
|
}
|
|
|
|
|
|
2001-04-18 07:12:03 +02:00
|
|
|
static int show_stmt_fork(ivl_statement_t net, ivl_scope_t sscope)
|
2001-03-30 07:49:52 +02:00
|
|
|
{
|
|
|
|
|
unsigned idx;
|
|
|
|
|
int rc = 0;
|
|
|
|
|
unsigned cnt = ivl_stmt_block_count(net);
|
2003-05-17 06:38:19 +02:00
|
|
|
ivl_scope_t scope = ivl_stmt_block_scope(net);
|
2001-03-30 07:49:52 +02:00
|
|
|
|
2002-05-27 02:08:45 +02:00
|
|
|
unsigned out = transient_id++;
|
2002-08-27 07:39:57 +02:00
|
|
|
unsigned id_base = transient_id;
|
2003-07-29 07:12:10 +02:00
|
|
|
|
|
|
|
|
/* cnt is the number of sub-threads. If the fork-join has no
|
|
|
|
|
name, then we can put one of the sub-threads in the current
|
|
|
|
|
thread, so decrement the count by one. */
|
|
|
|
|
if (scope == 0) {
|
|
|
|
|
cnt -= 1;
|
|
|
|
|
scope = sscope;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
transient_id += cnt;
|
2002-08-27 07:39:57 +02:00
|
|
|
|
2003-05-17 06:38:19 +02:00
|
|
|
/* If no subscope use provided */
|
|
|
|
|
if (!scope) scope = sscope;
|
2001-03-30 07:49:52 +02:00
|
|
|
|
|
|
|
|
/* Draw a fork statement for all but one of the threads of the
|
|
|
|
|
fork/join. Send the threads off to a bit of code where they
|
|
|
|
|
are implemented. */
|
2003-07-29 07:12:10 +02:00
|
|
|
for (idx = 0 ; idx < cnt ; idx += 1) {
|
2003-03-25 03:15:48 +01:00
|
|
|
fprintf(vvp_out, " %%fork t_%u, S_%p;\n",
|
2003-05-17 06:38:19 +02:00
|
|
|
id_base+idx, scope);
|
2001-03-30 07:49:52 +02:00
|
|
|
}
|
|
|
|
|
|
2003-07-29 07:12:10 +02:00
|
|
|
/* If we are putting one sub-thread into the current thread,
|
|
|
|
|
then draw its code here. */
|
|
|
|
|
if (ivl_stmt_block_scope(net) == 0)
|
|
|
|
|
rc += show_statement(ivl_stmt_block_stmt(net, cnt), scope);
|
2001-03-30 07:49:52 +02:00
|
|
|
|
2003-07-29 07:12:10 +02:00
|
|
|
|
|
|
|
|
/* Generate enough joins to collect all the sub-threads. */
|
|
|
|
|
for (idx = 0 ; idx < cnt ; idx += 1) {
|
2001-03-30 07:49:52 +02:00
|
|
|
fprintf(vvp_out, " %%join;\n");
|
|
|
|
|
}
|
|
|
|
|
fprintf(vvp_out, " %%jmp t_%u;\n", out);
|
|
|
|
|
|
2003-07-29 07:12:10 +02:00
|
|
|
/* Generate the sub-threads themselves. */
|
|
|
|
|
for (idx = 0 ; idx < cnt ; idx += 1) {
|
2002-08-27 07:39:57 +02:00
|
|
|
fprintf(vvp_out, "t_%u ;\n", id_base+idx);
|
2002-09-27 18:33:34 +02:00
|
|
|
clear_expression_lookaside();
|
2003-05-17 06:38:19 +02:00
|
|
|
rc += show_statement(ivl_stmt_block_stmt(net, idx), scope);
|
2001-03-30 07:49:52 +02:00
|
|
|
fprintf(vvp_out, " %%end;\n");
|
|
|
|
|
}
|
|
|
|
|
|
2001-04-18 07:12:03 +02:00
|
|
|
/* This is the label for the out. Use this to branch around
|
2001-03-30 07:49:52 +02:00
|
|
|
the implementations of all the child threads. */
|
2002-09-27 18:33:34 +02:00
|
|
|
clear_expression_lookaside();
|
2001-10-20 01:52:36 +02:00
|
|
|
fprintf(vvp_out, "t_%u ;\n", out);
|
2001-03-30 07:49:52 +02:00
|
|
|
|
|
|
|
|
return rc;
|
|
|
|
|
}
|
|
|
|
|
|
2001-03-21 02:49:43 +01:00
|
|
|
/*
|
|
|
|
|
* noop statements are implemented by doing nothing.
|
|
|
|
|
*/
|
2001-03-27 05:31:06 +02:00
|
|
|
static int show_stmt_noop(ivl_statement_t net)
|
2001-03-21 02:49:43 +01:00
|
|
|
{
|
2001-03-27 05:31:06 +02:00
|
|
|
return 0;
|
2001-03-21 02:49:43 +01:00
|
|
|
}
|
2001-03-19 02:20:46 +01:00
|
|
|
|
2001-11-14 04:28:49 +01:00
|
|
|
static int show_stmt_release(ivl_statement_t net)
|
|
|
|
|
{
|
2004-12-17 05:46:40 +01:00
|
|
|
unsigned lidx;
|
2001-11-18 02:28:18 +01:00
|
|
|
|
2004-12-17 05:46:40 +01:00
|
|
|
for (lidx = 0 ; lidx < ivl_stmt_lvals(net) ; lidx += 1) {
|
|
|
|
|
ivl_lval_t lval = ivl_stmt_lval(net, lidx);
|
|
|
|
|
ivl_signal_t lsig = ivl_lval_sig(lval);
|
|
|
|
|
const char*opcode = 0;
|
2001-11-18 02:28:18 +01:00
|
|
|
|
2004-12-17 05:46:40 +01:00
|
|
|
assert(lsig != 0);
|
|
|
|
|
assert(ivl_lval_mux(lval) == 0);
|
|
|
|
|
assert(ivl_lval_part_off(lval) == 0);
|
|
|
|
|
|
|
|
|
|
switch (ivl_signal_type(lsig)) {
|
|
|
|
|
case IVL_SIT_REG:
|
|
|
|
|
opcode = "reg";
|
|
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
|
opcode = "net";
|
|
|
|
|
break;
|
2002-08-07 02:54:39 +02:00
|
|
|
}
|
2004-12-17 05:46:40 +01:00
|
|
|
|
|
|
|
|
/* Generate the appropriate release statement for this
|
|
|
|
|
l-value. */
|
|
|
|
|
fprintf(vvp_out, " %%release/%s V_%s;\n",
|
|
|
|
|
opcode, vvp_signal_label(lsig));
|
2001-11-18 02:28:18 +01:00
|
|
|
}
|
2004-12-17 05:46:40 +01:00
|
|
|
|
2001-11-14 04:28:49 +01:00
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
2001-04-18 07:12:03 +02:00
|
|
|
static int show_stmt_repeat(ivl_statement_t net, ivl_scope_t sscope)
|
2001-04-05 05:20:57 +02:00
|
|
|
{
|
|
|
|
|
int rc = 0;
|
|
|
|
|
unsigned lab_top = local_count++, lab_out = local_count++;
|
|
|
|
|
ivl_expr_t exp = ivl_stmt_cond_expr(net);
|
2002-09-13 05:12:50 +02:00
|
|
|
struct vector_info cnt = draw_eval_expr(exp, 0);
|
2001-04-05 05:20:57 +02:00
|
|
|
|
|
|
|
|
/* Test that 0 < expr */
|
|
|
|
|
fprintf(vvp_out, "T_%u.%u %%cmp/u 0, %u, %u;\n", thread_count,
|
|
|
|
|
lab_top, cnt.base, cnt.wid);
|
2002-09-27 22:24:42 +02:00
|
|
|
clear_expression_lookaside();
|
2001-04-05 05:20:57 +02:00
|
|
|
fprintf(vvp_out, " %%jmp/0xz T_%u.%u, 5;\n", thread_count, lab_out);
|
|
|
|
|
/* This adds -1 (all ones in 2's complement) to the count. */
|
|
|
|
|
fprintf(vvp_out, " %%add %u, 1, %u;\n", cnt.base, cnt.wid);
|
|
|
|
|
|
2001-04-18 07:12:03 +02:00
|
|
|
rc += show_statement(ivl_stmt_sub_stmt(net), sscope);
|
2001-04-05 05:20:57 +02:00
|
|
|
|
|
|
|
|
fprintf(vvp_out, " %%jmp T_%u.%u;\n", thread_count, lab_top);
|
|
|
|
|
fprintf(vvp_out, "T_%u.%u ;\n", thread_count, lab_out);
|
2002-09-27 22:24:42 +02:00
|
|
|
clear_expression_lookaside();
|
2001-04-05 05:20:57 +02:00
|
|
|
|
|
|
|
|
clr_vector(cnt);
|
|
|
|
|
|
|
|
|
|
return rc;
|
|
|
|
|
}
|
|
|
|
|
|
2004-12-18 19:53:26 +01:00
|
|
|
/*
|
|
|
|
|
* The trigger statement is straight forward. All we have to do is
|
|
|
|
|
* write a single bit of fake data to the event object.
|
|
|
|
|
*/
|
2001-03-29 05:47:38 +02:00
|
|
|
static int show_stmt_trigger(ivl_statement_t net)
|
|
|
|
|
{
|
2003-12-03 03:46:23 +01:00
|
|
|
ivl_event_t ev = ivl_stmt_events(net, 0);
|
2001-03-29 05:47:38 +02:00
|
|
|
assert(ev);
|
2004-12-18 19:53:26 +01:00
|
|
|
fprintf(vvp_out, " %%set/v E_%p, 0,1;\n", ev);
|
2001-03-29 05:47:38 +02:00
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
2001-04-02 04:28:12 +02:00
|
|
|
static int show_stmt_utask(ivl_statement_t net)
|
|
|
|
|
{
|
|
|
|
|
ivl_scope_t task = ivl_stmt_call(net);
|
|
|
|
|
|
2001-06-18 05:10:34 +02:00
|
|
|
fprintf(vvp_out, " %%fork TD_%s",
|
|
|
|
|
vvp_mangle_id(ivl_scope_name(task)));
|
2003-03-25 03:15:48 +01:00
|
|
|
fprintf(vvp_out, ", S_%p;\n", task);
|
2001-04-02 04:28:12 +02:00
|
|
|
fprintf(vvp_out, " %%join;\n");
|
2002-09-27 18:33:34 +02:00
|
|
|
clear_expression_lookaside();
|
2001-04-02 04:28:12 +02:00
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
2001-04-18 07:12:03 +02:00
|
|
|
static int show_stmt_wait(ivl_statement_t net, ivl_scope_t sscope)
|
2001-03-27 08:27:40 +02:00
|
|
|
{
|
2003-12-03 03:46:23 +01:00
|
|
|
if (ivl_stmt_nevent(net) == 1) {
|
|
|
|
|
ivl_event_t ev = ivl_stmt_events(net, 0);
|
|
|
|
|
fprintf(vvp_out, " %%wait E_%p;\n", ev);
|
2001-03-27 08:27:40 +02:00
|
|
|
|
2003-12-03 03:46:23 +01:00
|
|
|
} else {
|
|
|
|
|
unsigned idx;
|
|
|
|
|
static unsigned int cascade_counter = 0;
|
|
|
|
|
ivl_event_t ev = ivl_stmt_events(net, 0);
|
|
|
|
|
fprintf(vvp_out, "Ewait_%u .event/or E_%p", cascade_counter, ev);
|
|
|
|
|
|
|
|
|
|
for (idx = 1 ; idx < ivl_stmt_nevent(net) ; idx += 1) {
|
|
|
|
|
ev = ivl_stmt_events(net, idx);
|
|
|
|
|
fprintf(vvp_out, ", E_%p", ev);
|
|
|
|
|
}
|
|
|
|
|
fprintf(vvp_out, ";\n %%wait Ewait_%u;\n", cascade_counter);
|
|
|
|
|
cascade_counter += 1;
|
|
|
|
|
}
|
2002-09-27 22:24:42 +02:00
|
|
|
/* Always clear the expression lookaside after a
|
|
|
|
|
%wait. Anything can happen while the thread is waiting. */
|
2002-09-27 18:33:34 +02:00
|
|
|
clear_expression_lookaside();
|
|
|
|
|
|
2001-04-18 07:12:03 +02:00
|
|
|
return show_statement(ivl_stmt_sub_stmt(net), sscope);
|
2001-03-27 08:27:40 +02:00
|
|
|
}
|
|
|
|
|
|
2002-04-22 04:41:30 +02:00
|
|
|
static struct vector_info reduction_or(struct vector_info cvec)
|
|
|
|
|
{
|
|
|
|
|
struct vector_info result;
|
|
|
|
|
|
|
|
|
|
switch (cvec.base) {
|
|
|
|
|
case 0:
|
|
|
|
|
result.base = 0;
|
|
|
|
|
result.wid = 1;
|
|
|
|
|
break;
|
|
|
|
|
case 1:
|
|
|
|
|
result.base = 1;
|
|
|
|
|
result.wid = 1;
|
|
|
|
|
break;
|
|
|
|
|
case 2:
|
|
|
|
|
case 3:
|
|
|
|
|
result.base = 0;
|
|
|
|
|
result.wid = 1;
|
|
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
|
clr_vector(cvec);
|
|
|
|
|
result.base = allocate_vector(1);
|
|
|
|
|
result.wid = 1;
|
|
|
|
|
fprintf(vvp_out, " %%or/r %u, %u, %u;\n", result.base,
|
|
|
|
|
cvec.base, cvec.wid);
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return result;
|
|
|
|
|
}
|
|
|
|
|
|
2001-04-18 07:12:03 +02:00
|
|
|
static int show_stmt_while(ivl_statement_t net, ivl_scope_t sscope)
|
2001-04-01 08:49:04 +02:00
|
|
|
{
|
|
|
|
|
int rc = 0;
|
|
|
|
|
struct vector_info cvec;
|
|
|
|
|
|
|
|
|
|
unsigned top_label = local_count++;
|
|
|
|
|
unsigned out_label = local_count++;
|
|
|
|
|
|
2002-09-27 22:24:42 +02:00
|
|
|
/* Start the loop. The top of the loop starts a basic block
|
|
|
|
|
because it can be entered from above or from the bottom of
|
|
|
|
|
the loop. */
|
2001-08-16 05:45:17 +02:00
|
|
|
fprintf(vvp_out, "T_%d.%d ;\n", thread_count, top_label);
|
2002-09-27 22:24:42 +02:00
|
|
|
clear_expression_lookaside();
|
2001-04-01 08:49:04 +02:00
|
|
|
|
|
|
|
|
/* Draw the evaluation of the condition expression, and test
|
|
|
|
|
the result. If the expression evaluates to false, then
|
|
|
|
|
branch to the out label. */
|
2002-09-24 06:20:32 +02:00
|
|
|
cvec = draw_eval_expr(ivl_stmt_cond_expr(net), STUFF_OK_XZ|STUFF_OK_47);
|
2002-04-22 04:41:30 +02:00
|
|
|
if (cvec.wid > 1)
|
|
|
|
|
cvec = reduction_or(cvec);
|
|
|
|
|
|
2001-04-01 08:49:04 +02:00
|
|
|
fprintf(vvp_out, " %%jmp/0xz T_%d.%d, %u;\n",
|
|
|
|
|
thread_count, out_label, cvec.base);
|
2002-09-24 06:20:32 +02:00
|
|
|
if (cvec.base >= 8)
|
|
|
|
|
clr_vector(cvec);
|
2001-04-01 08:49:04 +02:00
|
|
|
|
|
|
|
|
/* Draw the body of the loop. */
|
2001-04-18 07:12:03 +02:00
|
|
|
rc += show_statement(ivl_stmt_sub_stmt(net), sscope);
|
2001-04-01 08:49:04 +02:00
|
|
|
|
|
|
|
|
/* This is the bottom of the loop. branch to the top where the
|
|
|
|
|
test is repeased, and also draw the out label. */
|
|
|
|
|
fprintf(vvp_out, " %%jmp T_%d.%d;\n", thread_count, top_label);
|
2001-08-16 05:45:17 +02:00
|
|
|
fprintf(vvp_out, "T_%d.%d ;\n", thread_count, out_label);
|
2002-09-27 22:24:42 +02:00
|
|
|
clear_expression_lookaside();
|
2001-04-01 08:49:04 +02:00
|
|
|
return rc;
|
|
|
|
|
}
|
|
|
|
|
|
2001-03-27 05:31:06 +02:00
|
|
|
static int show_system_task_call(ivl_statement_t net)
|
2001-03-19 02:20:46 +01:00
|
|
|
{
|
|
|
|
|
unsigned parm_count = ivl_stmt_parm_count(net);
|
2004-10-04 03:10:51 +02:00
|
|
|
|
2001-03-19 02:20:46 +01:00
|
|
|
if (parm_count == 0) {
|
|
|
|
|
fprintf(vvp_out, " %%vpi_call \"%s\";\n", ivl_stmt_name(net));
|
2002-09-27 18:33:34 +02:00
|
|
|
clear_expression_lookaside();
|
2001-03-27 05:31:06 +02:00
|
|
|
return 0;
|
2001-03-19 02:20:46 +01:00
|
|
|
}
|
|
|
|
|
|
2003-03-15 05:45:18 +01:00
|
|
|
draw_vpi_task_call(net);
|
2001-05-10 02:26:53 +02:00
|
|
|
|
2002-09-27 22:24:42 +02:00
|
|
|
/* VPI calls can manipulate anything, so clear the expression
|
|
|
|
|
lookahead table after the call. */
|
2002-09-27 18:33:34 +02:00
|
|
|
clear_expression_lookaside();
|
|
|
|
|
|
2001-03-27 05:31:06 +02:00
|
|
|
return 0;
|
2001-03-19 02:20:46 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* This function draws a statement as vvp assembly. It basically
|
|
|
|
|
* switches on the statement type and draws code based on the type and
|
|
|
|
|
* further specifics.
|
|
|
|
|
*/
|
2001-04-18 07:12:03 +02:00
|
|
|
static int show_statement(ivl_statement_t net, ivl_scope_t sscope)
|
2001-03-19 02:20:46 +01:00
|
|
|
{
|
|
|
|
|
const ivl_statement_type_t code = ivl_statement_type(net);
|
2001-03-27 05:31:06 +02:00
|
|
|
int rc = 0;
|
2001-03-19 02:20:46 +01:00
|
|
|
|
|
|
|
|
switch (code) {
|
|
|
|
|
|
2001-03-21 02:49:43 +01:00
|
|
|
case IVL_ST_ASSIGN:
|
2001-03-27 05:31:06 +02:00
|
|
|
rc += show_stmt_assign(net);
|
2001-03-21 02:49:43 +01:00
|
|
|
break;
|
|
|
|
|
|
2001-04-03 06:50:37 +02:00
|
|
|
case IVL_ST_ASSIGN_NB:
|
|
|
|
|
rc += show_stmt_assign_nb(net);
|
|
|
|
|
break;
|
|
|
|
|
|
2001-04-21 02:55:46 +02:00
|
|
|
case IVL_ST_BLOCK:
|
2002-05-27 02:08:45 +02:00
|
|
|
if (ivl_stmt_block_scope(net))
|
|
|
|
|
rc += show_stmt_block_named(net, sscope);
|
|
|
|
|
else
|
|
|
|
|
rc += show_stmt_block(net, sscope);
|
2001-04-21 02:55:46 +02:00
|
|
|
break;
|
2001-03-19 02:20:46 +01:00
|
|
|
|
2001-03-31 19:36:38 +02:00
|
|
|
case IVL_ST_CASE:
|
2001-04-01 06:34:59 +02:00
|
|
|
case IVL_ST_CASEX:
|
|
|
|
|
case IVL_ST_CASEZ:
|
2001-04-18 07:12:03 +02:00
|
|
|
rc += show_stmt_case(net, sscope);
|
2001-03-31 19:36:38 +02:00
|
|
|
break;
|
|
|
|
|
|
2003-05-14 07:26:41 +02:00
|
|
|
case IVL_ST_CASER:
|
|
|
|
|
rc += show_stmt_case_r(net, sscope);
|
|
|
|
|
break;
|
|
|
|
|
|
2001-11-01 05:26:57 +01:00
|
|
|
case IVL_ST_CASSIGN:
|
|
|
|
|
rc += show_stmt_cassign(net);
|
|
|
|
|
break;
|
|
|
|
|
|
2001-03-22 06:06:21 +01:00
|
|
|
case IVL_ST_CONDIT:
|
2001-04-18 07:12:03 +02:00
|
|
|
rc += show_stmt_condit(net, sscope);
|
2001-03-22 06:06:21 +01:00
|
|
|
break;
|
|
|
|
|
|
2001-11-01 05:26:57 +01:00
|
|
|
case IVL_ST_DEASSIGN:
|
|
|
|
|
rc += show_stmt_deassign(net);
|
|
|
|
|
break;
|
|
|
|
|
|
2001-03-21 02:49:43 +01:00
|
|
|
case IVL_ST_DELAY:
|
2001-04-18 07:12:03 +02:00
|
|
|
rc += show_stmt_delay(net, sscope);
|
2001-03-21 02:49:43 +01:00
|
|
|
break;
|
|
|
|
|
|
2001-07-19 06:55:06 +02:00
|
|
|
case IVL_ST_DELAYX:
|
|
|
|
|
rc += show_stmt_delayx(net, sscope);
|
|
|
|
|
break;
|
|
|
|
|
|
2001-04-21 02:55:46 +02:00
|
|
|
case IVL_ST_DISABLE:
|
|
|
|
|
rc += show_stmt_disable(net, sscope);
|
|
|
|
|
break;
|
|
|
|
|
|
2001-11-14 04:28:49 +01:00
|
|
|
case IVL_ST_FORCE:
|
|
|
|
|
rc += show_stmt_force(net);
|
|
|
|
|
break;
|
|
|
|
|
|
2001-04-04 06:50:35 +02:00
|
|
|
case IVL_ST_FOREVER:
|
2001-04-18 07:12:03 +02:00
|
|
|
rc += show_stmt_forever(net, sscope);
|
2001-04-04 06:50:35 +02:00
|
|
|
break;
|
|
|
|
|
|
2001-03-30 07:49:52 +02:00
|
|
|
case IVL_ST_FORK:
|
2001-04-18 07:12:03 +02:00
|
|
|
rc += show_stmt_fork(net, sscope);
|
2001-03-30 07:49:52 +02:00
|
|
|
break;
|
|
|
|
|
|
2001-03-21 02:49:43 +01:00
|
|
|
case IVL_ST_NOOP:
|
2001-03-27 05:31:06 +02:00
|
|
|
rc += show_stmt_noop(net);
|
2001-03-21 02:49:43 +01:00
|
|
|
break;
|
|
|
|
|
|
2001-11-14 04:28:49 +01:00
|
|
|
case IVL_ST_RELEASE:
|
|
|
|
|
rc += show_stmt_release(net);
|
|
|
|
|
break;
|
|
|
|
|
|
2001-04-05 05:20:57 +02:00
|
|
|
case IVL_ST_REPEAT:
|
2001-04-18 07:12:03 +02:00
|
|
|
rc += show_stmt_repeat(net, sscope);
|
2001-04-05 05:20:57 +02:00
|
|
|
break;
|
|
|
|
|
|
2001-03-19 02:20:46 +01:00
|
|
|
case IVL_ST_STASK:
|
2001-03-27 05:31:06 +02:00
|
|
|
rc += show_system_task_call(net);
|
2001-03-19 02:20:46 +01:00
|
|
|
break;
|
|
|
|
|
|
2001-03-29 05:47:38 +02:00
|
|
|
case IVL_ST_TRIGGER:
|
|
|
|
|
rc += show_stmt_trigger(net);
|
|
|
|
|
break;
|
|
|
|
|
|
2001-04-02 04:28:12 +02:00
|
|
|
case IVL_ST_UTASK:
|
|
|
|
|
rc += show_stmt_utask(net);
|
|
|
|
|
break;
|
|
|
|
|
|
2001-03-27 08:27:40 +02:00
|
|
|
case IVL_ST_WAIT:
|
2001-04-18 07:12:03 +02:00
|
|
|
rc += show_stmt_wait(net, sscope);
|
2001-03-27 08:27:40 +02:00
|
|
|
break;
|
|
|
|
|
|
2001-04-01 08:49:04 +02:00
|
|
|
case IVL_ST_WHILE:
|
2001-04-18 07:12:03 +02:00
|
|
|
rc += show_stmt_while(net, sscope);
|
2001-04-01 08:49:04 +02:00
|
|
|
break;
|
|
|
|
|
|
2001-03-19 02:20:46 +01:00
|
|
|
default:
|
|
|
|
|
fprintf(stderr, "vvp.tgt: Unable to draw statement type %u\n",
|
|
|
|
|
code);
|
2001-03-27 05:31:06 +02:00
|
|
|
rc += 1;
|
2001-03-19 02:20:46 +01:00
|
|
|
break;
|
|
|
|
|
}
|
2001-03-27 05:31:06 +02:00
|
|
|
|
|
|
|
|
return rc;
|
2001-03-19 02:20:46 +01:00
|
|
|
}
|
2001-03-27 08:27:40 +02:00
|
|
|
|
|
|
|
|
|
2001-03-19 02:20:46 +01:00
|
|
|
/*
|
|
|
|
|
* The process as a whole is surrounded by this code. We generate a
|
|
|
|
|
* start label that the .thread statement can use, and we generate
|
|
|
|
|
* code to terminate the thread.
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
int draw_process(ivl_process_t net, void*x)
|
|
|
|
|
{
|
2001-03-27 05:31:06 +02:00
|
|
|
int rc = 0;
|
2003-09-04 22:28:05 +02:00
|
|
|
unsigned idx;
|
2001-03-20 02:44:13 +01:00
|
|
|
ivl_scope_t scope = ivl_process_scope(net);
|
2001-03-27 08:27:40 +02:00
|
|
|
ivl_statement_t stmt = ivl_process_stmt(net);
|
2001-03-20 02:44:13 +01:00
|
|
|
|
2003-09-04 22:28:05 +02:00
|
|
|
int push_flag = 0;
|
|
|
|
|
|
|
|
|
|
for (idx = 0 ; idx < ivl_process_attr_cnt(net) ; idx += 1) {
|
|
|
|
|
|
|
|
|
|
ivl_attribute_t attr = ivl_process_attr_val(net, idx);
|
|
|
|
|
|
|
|
|
|
if (strcmp(attr->key, "_ivl_schedule_push") == 0) {
|
|
|
|
|
|
|
|
|
|
push_flag = 1;
|
|
|
|
|
|
|
|
|
|
} else if (strcmp(attr->key, "ivl_combinational") == 0) {
|
|
|
|
|
|
|
|
|
|
push_flag = 1;
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2001-03-22 06:06:21 +01:00
|
|
|
local_count = 0;
|
2003-03-25 03:15:48 +01:00
|
|
|
fprintf(vvp_out, " .scope S_%p;\n", scope);
|
2001-03-30 07:49:52 +02:00
|
|
|
|
2001-03-19 02:20:46 +01:00
|
|
|
/* Generate the entry label. Just give the thread a number so
|
|
|
|
|
that we ar certain the label is unique. */
|
2001-04-01 08:49:04 +02:00
|
|
|
fprintf(vvp_out, "T_%d ;\n", thread_count);
|
2002-09-27 18:33:34 +02:00
|
|
|
clear_expression_lookaside();
|
2001-03-19 02:20:46 +01:00
|
|
|
|
|
|
|
|
/* Draw the contents of the thread. */
|
2001-04-18 07:12:03 +02:00
|
|
|
rc += show_statement(stmt, scope);
|
2001-03-19 02:20:46 +01:00
|
|
|
|
|
|
|
|
|
|
|
|
|
/* Terminate the thread with either an %end instruction (initial
|
|
|
|
|
statements) or a %jmp back to the beginning of the thread. */
|
|
|
|
|
|
|
|
|
|
switch (ivl_process_type(net)) {
|
|
|
|
|
|
|
|
|
|
case IVL_PR_INITIAL:
|
|
|
|
|
fprintf(vvp_out, " %%end;\n");
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case IVL_PR_ALWAYS:
|
2001-03-27 08:27:40 +02:00
|
|
|
fprintf(vvp_out, " %%jmp T_%d;\n", thread_count);
|
2001-03-19 02:20:46 +01:00
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Now write out the .thread directive that tells vvp where
|
|
|
|
|
the thread starts. */
|
|
|
|
|
|
2003-09-04 22:28:05 +02:00
|
|
|
if (push_flag) {
|
|
|
|
|
fprintf(vvp_out, " .thread T_%d, $push;\n", thread_count);
|
|
|
|
|
} else {
|
|
|
|
|
fprintf(vvp_out, " .thread T_%d;\n", thread_count);
|
|
|
|
|
}
|
2001-03-19 02:20:46 +01:00
|
|
|
|
|
|
|
|
thread_count += 1;
|
2001-03-27 05:31:06 +02:00
|
|
|
return rc;
|
2001-03-19 02:20:46 +01:00
|
|
|
}
|
|
|
|
|
|
2001-04-02 04:28:12 +02:00
|
|
|
int draw_task_definition(ivl_scope_t scope)
|
|
|
|
|
{
|
|
|
|
|
int rc = 0;
|
|
|
|
|
ivl_statement_t def = ivl_scope_def(scope);
|
|
|
|
|
|
2001-06-18 05:10:34 +02:00
|
|
|
fprintf(vvp_out, "TD_%s ;\n", vvp_mangle_id(ivl_scope_name(scope)));
|
2002-09-27 18:33:34 +02:00
|
|
|
clear_expression_lookaside();
|
2001-04-02 04:28:12 +02:00
|
|
|
|
|
|
|
|
assert(def);
|
2001-04-18 07:12:03 +02:00
|
|
|
rc += show_statement(def, scope);
|
2001-04-02 04:28:12 +02:00
|
|
|
|
|
|
|
|
fprintf(vvp_out, " %%end;\n");
|
|
|
|
|
|
|
|
|
|
thread_count += 1;
|
|
|
|
|
return rc;
|
|
|
|
|
}
|
|
|
|
|
|
2001-04-06 04:28:02 +02:00
|
|
|
int draw_func_definition(ivl_scope_t scope)
|
|
|
|
|
{
|
|
|
|
|
int rc = 0;
|
|
|
|
|
ivl_statement_t def = ivl_scope_def(scope);
|
|
|
|
|
|
2001-06-18 05:10:34 +02:00
|
|
|
fprintf(vvp_out, "TD_%s ;\n", vvp_mangle_id(ivl_scope_name(scope)));
|
2002-09-27 18:33:34 +02:00
|
|
|
clear_expression_lookaside();
|
2001-04-06 04:28:02 +02:00
|
|
|
|
|
|
|
|
assert(def);
|
2001-04-18 07:12:03 +02:00
|
|
|
rc += show_statement(def, scope);
|
2001-04-06 04:28:02 +02:00
|
|
|
|
|
|
|
|
fprintf(vvp_out, " %%end;\n");
|
|
|
|
|
|
|
|
|
|
thread_count += 1;
|
|
|
|
|
return rc;
|
|
|
|
|
}
|
|
|
|
|
|
2001-03-19 02:20:46 +01:00
|
|
|
/*
|
|
|
|
|
* $Log: vvp_process.c,v $
|
2005-06-14 03:44:09 +02:00
|
|
|
* Revision 1.112 2005/06/14 01:45:05 steve
|
|
|
|
|
* Add the assign_v0_d instruction.
|
|
|
|
|
*
|
2005-06-02 18:03:47 +02:00
|
|
|
* Revision 1.111 2005/06/02 16:03:47 steve
|
|
|
|
|
* Support %force/link
|
|
|
|
|
*
|
2005-05-24 04:31:18 +02:00
|
|
|
* Revision 1.110 2005/05/24 02:31:18 steve
|
|
|
|
|
* Handle assignments to part-select l-values.
|
|
|
|
|
*
|
2005-05-17 22:55:42 +02:00
|
|
|
* Revision 1.109 2005/05/17 20:55:42 steve
|
|
|
|
|
* Detect bit selects that need special handling.
|
|
|
|
|
*
|
2005-05-09 02:38:12 +02:00
|
|
|
* Revision 1.108 2005/05/09 00:38:12 steve
|
|
|
|
|
* Skip assign if index is invalid.
|
|
|
|
|
*
|
2005-05-07 05:16:31 +02:00
|
|
|
* Revision 1.107 2005/05/07 03:16:31 steve
|
|
|
|
|
* Better handle assignment to bit/part select.
|
|
|
|
|
*
|
2005-05-02 00:04:12 +02:00
|
|
|
* Revision 1.106 2005/05/01 22:04:12 steve
|
|
|
|
|
* Link signals that are source of procedural continuous assign.
|
|
|
|
|
*
|
2005-03-22 06:18:34 +01:00
|
|
|
* Revision 1.105 2005/03/22 05:18:34 steve
|
|
|
|
|
* The indexed set can write a vector, not just a bit.
|
|
|
|
|
*
|
2005-03-06 18:07:48 +01:00
|
|
|
* Revision 1.104 2005/03/06 17:07:48 steve
|
|
|
|
|
* Non blocking assign to memory words.
|
|
|
|
|
*
|
2005-03-05 06:47:42 +01:00
|
|
|
* Revision 1.103 2005/03/05 05:47:42 steve
|
|
|
|
|
* Handle memory words in l-value concatenations.
|
|
|
|
|
*
|
2005-03-03 05:33:10 +01:00
|
|
|
* Revision 1.102 2005/03/03 04:34:42 steve
|
|
|
|
|
* Rearrange how memories are supported as vvp_vector4 arrays.
|
|
|
|
|
*
|
2005-02-15 08:12:55 +01:00
|
|
|
* Revision 1.101 2005/02/15 07:12:55 steve
|
|
|
|
|
* Support constant part select writes to l-values, and large part select reads from signals.
|
|
|
|
|
*
|
2005-02-14 06:00:11 +01:00
|
|
|
* Revision 1.100 2005/02/14 05:00:11 steve
|
|
|
|
|
* Handle bitmux lvalues for constant r-values.
|
|
|
|
|
*
|
2005-02-14 02:51:39 +01:00
|
|
|
* Revision 1.99 2005/02/14 01:51:39 steve
|
|
|
|
|
* Handle bit selects in l-values to assignments.
|
|
|
|
|
*
|
2005-01-28 20:39:03 +01:00
|
|
|
* Revision 1.98 2005/01/28 19:39:03 steve
|
|
|
|
|
* Integrate fixes from 0.8 branch.
|
2004-12-17 05:46:40 +01:00
|
|
|
*
|
2005-01-28 20:39:03 +01:00
|
|
|
* Revision 1.93.2.2 2005/01/28 18:29:29 steve
|
|
|
|
|
* Add ability to compile real values into index registers.
|
2004-12-11 06:43:30 +01:00
|
|
|
*
|
2005-01-28 20:39:03 +01:00
|
|
|
* Revision 1.93.2.1 2004/12/12 04:25:10 steve
|
|
|
|
|
* Fix leak of word registers in code generator.
|
2004-12-11 03:31:25 +01:00
|
|
|
*
|
2004-10-04 03:10:51 +02:00
|
|
|
* Revision 1.93 2004/10/04 01:10:57 steve
|
|
|
|
|
* Clean up spurious trailing white space.
|
|
|
|
|
*
|
2004-05-19 05:25:42 +02:00
|
|
|
* Revision 1.92 2004/05/19 03:25:42 steve
|
|
|
|
|
* Generate code for nb assign to reals.
|
|
|
|
|
*
|
2003-12-03 03:46:23 +01:00
|
|
|
* Revision 1.91 2003/12/03 02:46:24 steve
|
|
|
|
|
* Add support for wait on list of named events.
|
|
|
|
|
*
|
2003-10-25 04:07:57 +02:00
|
|
|
* Revision 1.90 2003/10/25 02:07:57 steve
|
|
|
|
|
* vvp_signal_label does not return a unique string.
|
|
|
|
|
*
|
2003-09-04 22:28:05 +02:00
|
|
|
* Revision 1.89 2003/09/04 20:28:06 steve
|
|
|
|
|
* Support time0 resolution of combinational threads.
|
|
|
|
|
*
|
2003-07-29 07:12:10 +02:00
|
|
|
* Revision 1.88 2003/07/29 05:12:10 steve
|
|
|
|
|
* All the threads of a named fork go into sub-scope.
|
|
|
|
|
*
|
2003-05-26 06:45:37 +02:00
|
|
|
* Revision 1.87 2003/05/26 04:45:37 steve
|
|
|
|
|
* Use set/x0/x if the target vector is too wide for set/x0.
|
|
|
|
|
*
|
2003-05-17 06:38:19 +02:00
|
|
|
* Revision 1.86 2003/05/17 04:38:19 steve
|
|
|
|
|
* Account for nested fork scopes in disable.
|
|
|
|
|
*
|
2003-05-14 07:26:41 +02:00
|
|
|
* Revision 1.85 2003/05/14 05:26:41 steve
|
|
|
|
|
* Support real expressions in case statements.
|
|
|
|
|
*
|
2003-03-25 03:15:48 +01:00
|
|
|
* Revision 1.84 2003/03/25 02:15:48 steve
|
|
|
|
|
* Use hash code for scope labels.
|
|
|
|
|
*
|
2003-03-15 05:45:18 +01:00
|
|
|
* Revision 1.83 2003/03/15 04:45:18 steve
|
|
|
|
|
* Allow real-valued vpi functions to have arguments.
|
|
|
|
|
*
|
2003-03-06 02:17:46 +01:00
|
|
|
* Revision 1.82 2003/03/06 01:17:46 steve
|
|
|
|
|
* Use number for event labels.
|
2001-03-19 02:20:46 +01:00
|
|
|
*/
|
|
|
|
|
|