Add support for variable UDP delays.

This patch adds support for a UDP with variable delays. In the process the
intrinsic support for delays was removed from the UDP functor and replaced
with a call to the .delay functor. Both a normal gate and a UDP now use the
same code to generate the delay.
This commit is contained in:
Cary R 2010-07-23 19:19:36 -07:00 committed by Stephen Williams
parent 86653ddff9
commit 314714997f
6 changed files with 125 additions and 156 deletions

View File

@ -1753,22 +1753,6 @@ void PGModule::elaborate_udp_(Design*des, PUdp*udp, NetScope*scope) const
tmp_del.set_delays(overrides_, false); tmp_del.set_delays(overrides_, false);
tmp_del.eval_delays(des, scope, rise_expr, fall_expr, tmp_del.eval_delays(des, scope, rise_expr, fall_expr,
decay_expr); decay_expr);
if (! dynamic_cast<NetEConst*> (rise_expr)) {
cerr << get_fileline() << ": error: UDP rising delay "
"expression must be constant." << endl;
cerr << get_fileline() << ": : Cannot calculate "
<< *rise_expr << endl;
des->errors += 1;
}
if (! dynamic_cast<NetEConst*> (fall_expr)) {
cerr << get_fileline() << ": error: UDP falling delay "
"expression must be constant." << endl;
cerr << get_fileline() << ": : Cannot calculate "
<< *fall_expr << endl;
des->errors += 1;
}
} }
} }

View File

@ -561,30 +561,80 @@ static void draw_net_in_scope(ivl_signal_t sig)
} }
} }
/*
* Check to see if we need a delay.
*/
static unsigned need_delay(ivl_net_logic_t lptr)
{
/* If we have no rising delay then we do not have any delays. */
if (ivl_logic_delay(lptr, 0) == 0) {
assert(ivl_logic_delay(lptr, 1) == 0);
assert(ivl_logic_delay(lptr, 2) == 0);
return 0;
}
return 1;
}
/*
* Draw the appropriate delay statement. Returns zero if there is not a delay.
*/
static void draw_delay(ivl_net_logic_t lptr) static void draw_delay(ivl_net_logic_t lptr)
{ {
ivl_expr_t d0 = ivl_logic_delay(lptr, 0); ivl_expr_t rise_exp = ivl_logic_delay(lptr, 0);
ivl_expr_t d1 = ivl_logic_delay(lptr, 1); ivl_expr_t fall_exp = ivl_logic_delay(lptr, 1);
ivl_expr_t d2 = ivl_logic_delay(lptr, 2); ivl_expr_t decay_exp = ivl_logic_delay(lptr, 2);
if (d0 == 0 && d1 == 0 && d2 == 0) /* Calculate the width of the delay. We also use a BUFZ for real
return; * values so we need to resize if the first input is real. */
unsigned delay_wid = width_of_nexus(ivl_logic_pin(lptr, 0));
if (data_type_of_nexus(ivl_logic_pin(lptr, 0)) == IVL_VT_REAL) {
delay_wid = 0;
}
/* FIXME: Assume that the expression is a constant */ /* If the delays are all constants then process them here. */
assert(number_is_immediate(d0, 64, 0)); if (number_is_immediate(rise_exp, 64, 0) &&
assert(number_is_immediate(d1, 64, 0)); number_is_immediate(fall_exp, 64, 0) &&
assert(number_is_immediate(d2, 64, 0)); number_is_immediate(decay_exp, 64, 0)) {
assert(! number_is_unknown(d0));
assert(! number_is_unknown(d1));
assert(! number_is_unknown(d2));
if (d0 == d1 && d1 == d2) assert(! number_is_unknown(rise_exp));
fprintf(vvp_out, " (%lu)", get_number_immediate(d0)); assert(! number_is_unknown(fall_exp));
else assert(! number_is_unknown(decay_exp));
fprintf(vvp_out, " (%lu,%lu,%lu)",
get_number_immediate(d0), fprintf(vvp_out, "L_%p .delay %u "
get_number_immediate(d1), "(%" PRIu64 ",%" PRIu64 ",%" PRIu64 ") L_%p/d;\n",
get_number_immediate(d2)); lptr, delay_wid,
get_number_immediate64(rise_exp),
get_number_immediate64(fall_exp),
get_number_immediate64(decay_exp), lptr);
/* For a variable delay we indicate only two delays by setting the
* decay time to zero. */
} else {
ivl_signal_t sig;
assert(ivl_expr_type(rise_exp) == IVL_EX_SIGNAL);
assert(ivl_expr_type(fall_exp) == IVL_EX_SIGNAL);
assert((decay_exp == 0) ||
(ivl_expr_type(decay_exp) == IVL_EX_SIGNAL));
fprintf(vvp_out, "L_%p .delay %u L_%p/d", lptr, delay_wid, lptr);
sig = ivl_expr_signal(rise_exp);
assert(ivl_signal_dimensions(sig) == 0);
fprintf(vvp_out, ", %s", draw_net_input(ivl_signal_nex(sig,0)));
sig = ivl_expr_signal(fall_exp);
assert(ivl_signal_dimensions(sig) == 0);
fprintf(vvp_out, ", %s", draw_net_input(ivl_signal_nex(sig,0)));
if (decay_exp) {
sig = ivl_expr_signal(decay_exp);
assert(ivl_signal_dimensions(sig) == 0);
fprintf(vvp_out, ", %s;\n",
draw_net_input(ivl_signal_nex(sig,0)));
} else {
fprintf(vvp_out, ", 0;\n");
}
}
} }
static void draw_udp_def(ivl_udp_t udp) static void draw_udp_def(ivl_udp_t udp)
@ -637,12 +687,14 @@ static void draw_udp_in_scope(ivl_net_logic_t lptr)
unsigned ninp; unsigned ninp;
const char **input_strings; const char **input_strings;
for (i=0; i<nudps; i++) /* Do we need a delay? */
if (udps[i] == udp) unsigned need_delay_flag = need_delay(lptr);
break;
if (i >= nudps) for (i=0; i<nudps; i++) {
{ if (udps[i] == udp) break;
}
if (i >= nudps) {
udps = realloc(udps, (nudps+1)*sizeof(ivl_udp_t)); udps = realloc(udps, (nudps+1)*sizeof(ivl_udp_t));
assert(udps); assert(udps);
udps[nudps++] = udp; udps[nudps++] = udp;
@ -660,21 +712,19 @@ static void draw_udp_in_scope(ivl_net_logic_t lptr)
ivl_nexus_t nex = ivl_logic_pin(lptr, pdx+1); ivl_nexus_t nex = ivl_logic_pin(lptr, pdx+1);
/* Unlike other logic gates, primitives may have unconnected /* Unlike other logic gates, primitives may have unconnected
inputs. The proper behavior is to attach a HiZ to the * inputs. The proper behavior is to attach a HiZ to the
port. */ * port. */
if (nex == 0) { if (nex == 0) {
assert(ivl_logic_width(lptr) == 1); assert(ivl_logic_width(lptr) == 1);
input_strings[pdx] = "C4<z>"; input_strings[pdx] = "C4<z>";
} else { } else {
input_strings[pdx] = draw_net_input(nex); input_strings[pdx] = draw_net_input(nex);
} }
} }
fprintf(vvp_out, "L_%p .udp", lptr); /* Generate the UDP call. */
fprintf(vvp_out, " UDP_%s", fprintf(vvp_out, "L_%p%s .udp UDP_%s", lptr, need_delay_flag? "/d" : "",
vvp_mangle_id(ivl_udp_name(udp))); vvp_mangle_id(ivl_udp_name(udp)));
draw_delay(lptr);
for (pdx = 0 ; pdx < ninp ; pdx += 1) { for (pdx = 0 ; pdx < ninp ; pdx += 1) {
fprintf(vvp_out, ", %s", input_strings[pdx]); fprintf(vvp_out, ", %s", input_strings[pdx]);
@ -682,6 +732,9 @@ static void draw_udp_in_scope(ivl_net_logic_t lptr)
free(input_strings); free(input_strings);
fprintf(vvp_out, ";\n"); fprintf(vvp_out, ";\n");
/* Generate a delay when needed. */
if (need_delay_flag) draw_delay(lptr);
} }
static void draw_logic_in_scope(ivl_net_logic_t lptr) static void draw_logic_in_scope(ivl_net_logic_t lptr)
@ -691,7 +744,8 @@ static void draw_logic_in_scope(ivl_net_logic_t lptr)
const char*lcasc = 0; const char*lcasc = 0;
char identity_val = '0'; char identity_val = '0';
int need_delay_flag = ivl_logic_delay(lptr,0)? 1 : 0; /* Do we need a delay? */
unsigned need_delay_flag = need_delay(lptr);
unsigned vector_width = width_of_nexus(ivl_logic_pin(lptr, 0)); unsigned vector_width = width_of_nexus(ivl_logic_pin(lptr, 0));
@ -882,61 +936,8 @@ static void draw_logic_in_scope(ivl_net_logic_t lptr)
persistent, held by the ivl_nexus_t objects. */ persistent, held by the ivl_nexus_t objects. */
free(input_strings); free(input_strings);
/* If there are delays, then draw the delay functor to carry /* Generate a delay when needed. */
that delay. This is the final output. */ if (need_delay_flag) draw_delay(lptr);
if (need_delay_flag) {
ivl_expr_t rise_exp = ivl_logic_delay(lptr, 0);
ivl_expr_t fall_exp = ivl_logic_delay(lptr, 1);
ivl_expr_t decay_exp = ivl_logic_delay(lptr, 2);
unsigned dly_width = vector_width;
if (data_type_of_nexus(ivl_logic_pin(lptr,0)) == IVL_VT_REAL)
dly_width = 0;
if (number_is_immediate(rise_exp, 64, 0)
&& number_is_immediate(fall_exp, 64, 0)
&& number_is_immediate(decay_exp, 64, 0)) {
assert(! number_is_unknown(rise_exp));
assert(! number_is_unknown(fall_exp));
assert(! number_is_unknown(decay_exp));
fprintf(vvp_out, "L_%p .delay %u (%" PRIu64 ",%" PRIu64 ",%" PRIu64 ") L_%p/d;\n",
lptr, dly_width,
get_number_immediate64(rise_exp),
get_number_immediate64(fall_exp),
get_number_immediate64(decay_exp), lptr);
} else {
ivl_signal_t sig;
// We do not currently support calculating the decay from
// the rise and fall variable delays.
assert(ivl_expr_type(rise_exp) == IVL_EX_SIGNAL);
assert(ivl_expr_type(fall_exp) == IVL_EX_SIGNAL);
assert((decay_exp == 0) ||
(ivl_expr_type(decay_exp) == IVL_EX_SIGNAL));
fprintf(vvp_out, "L_%p .delay %u L_%p/d", lptr, dly_width, lptr);
sig = ivl_expr_signal(rise_exp);
assert(ivl_signal_dimensions(sig) == 0);
fprintf(vvp_out, ", %s",
draw_net_input(ivl_signal_nex(sig,0)));
sig = ivl_expr_signal(fall_exp);
assert(ivl_signal_dimensions(sig) == 0);
fprintf(vvp_out, ", %s",
draw_net_input(ivl_signal_nex(sig,0)));
if (decay_exp) {
sig = ivl_expr_signal(decay_exp);
assert(ivl_signal_dimensions(sig) == 0);
fprintf(vvp_out, ", %s;\n",
draw_net_input(ivl_signal_nex(sig,0)));
} else {
fprintf(vvp_out, ", 0;\n");
}
}
}
} }
static void draw_event_in_scope(ivl_event_t obj) static void draw_event_in_scope(ivl_event_t obj)

View File

@ -321,7 +321,6 @@ extern void compile_udp_def(int sequ, char*label, char *name,
unsigned nin, unsigned init, char **table); unsigned nin, unsigned init, char **table);
extern void compile_udp_functor(char*label, char*type, extern void compile_udp_functor(char*label, char*type,
vvp_delay_t*delay,
unsigned argc, struct symb_s*argv); unsigned argc, struct symb_s*argv);
extern char **compile_udp_table(char **table, char *row); extern char **compile_udp_table(char **table, char *row);

View File

@ -108,7 +108,7 @@ static struct __vpiModPath*modpath_dst = 0;
%type <argv> argument_opt argument_list %type <argv> argument_opt argument_list
%type <vpi> argument symbol_access %type <vpi> argument symbol_access
%type <cdelay> delay delay_opt %type <cdelay> delay
%% %%
@ -188,8 +188,8 @@ statement
| T_LABEL K_UDP_C T_STRING ',' T_NUMBER ',' udp_table ';' | T_LABEL K_UDP_C T_STRING ',' T_NUMBER ',' udp_table ';'
{ compile_udp_def(0, $1, $3, $5, 0, $7); } { compile_udp_def(0, $1, $3, $5, 0, $7); }
| T_LABEL K_UDP T_SYMBOL delay_opt ',' symbols ';' | T_LABEL K_UDP T_SYMBOL ',' symbols ';'
{ compile_udp_functor($1, $3, $4, $6.cnt, $6.vect); } { compile_udp_functor($1, $3, $5.cnt, $5.vect); }
/* Memory. Definition, port, initialization */ /* Memory. Definition, port, initialization */
@ -1010,8 +1010,6 @@ signed_t_number
| '-' T_NUMBER { $$ = -$2; } | '-' T_NUMBER { $$ = -$2; }
; ;
delay_opt : delay { $$=$1; } | /* empty */ { $$=0; } ;
delay delay
: '(' T_NUMBER ')' : '(' T_NUMBER ')'
{ $$ = new vvp_delay_t($2, $2); } { $$ = new vvp_delay_t($2, $2); }

View File

@ -971,7 +971,6 @@ void vvp_udp_fun_core::recv_vec4_from_inputs(unsigned port)
* netlist. The definition should be parsed already. * netlist. The definition should be parsed already.
*/ */
void compile_udp_functor(char*label, char*type, void compile_udp_functor(char*label, char*type,
vvp_delay_t*delay,
unsigned argc, struct symb_s*argv) unsigned argc, struct symb_s*argv)
{ {
struct vvp_udp_s *def = udp_find(type); struct vvp_udp_s *def = udp_find(type);
@ -982,18 +981,7 @@ void compile_udp_functor(char*label, char*type,
vvp_udp_fun_core*core = new vvp_udp_fun_core(ptr, def); vvp_udp_fun_core*core = new vvp_udp_fun_core(ptr, def);
ptr->fun = core; ptr->fun = core;
if (delay != 0) {
vvp_net_t*net_drv = new vvp_net_t;
vvp_fun_delay*obj_drv = new vvp_fun_delay(net_drv, 1, *delay);
delete delay;
net_drv->fun = obj_drv;
ptr->link(vvp_net_ptr_t(net_drv,0));
define_functor_symbol(label, net_drv);
} else {
define_functor_symbol(label, ptr); define_functor_symbol(label, ptr);
}
free(label); free(label);
wide_inputs_connect(core, argc, argv); wide_inputs_connect(core, argc, argv);

View File

@ -23,7 +23,6 @@
*/ */
# include "vvp_net.h" # include "vvp_net.h"
# include "delay.h"
# include "schedule.h" # include "schedule.h"
struct udp_levels_table; struct udp_levels_table;