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.eval_delays(des, scope, rise_expr, fall_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)
{
ivl_expr_t d0 = ivl_logic_delay(lptr, 0);
ivl_expr_t d1 = ivl_logic_delay(lptr, 1);
ivl_expr_t d2 = ivl_logic_delay(lptr, 2);
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);
if (d0 == 0 && d1 == 0 && d2 == 0)
return;
/* Calculate the width of the delay. We also use a BUFZ for real
* 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 */
assert(number_is_immediate(d0, 64, 0));
assert(number_is_immediate(d1, 64, 0));
assert(number_is_immediate(d2, 64, 0));
assert(! number_is_unknown(d0));
assert(! number_is_unknown(d1));
assert(! number_is_unknown(d2));
/* If the delays are all constants then process them here. */
if (number_is_immediate(rise_exp, 64, 0) &&
number_is_immediate(fall_exp, 64, 0) &&
number_is_immediate(decay_exp, 64, 0)) {
if (d0 == d1 && d1 == d2)
fprintf(vvp_out, " (%lu)", get_number_immediate(d0));
else
fprintf(vvp_out, " (%lu,%lu,%lu)",
get_number_immediate(d0),
get_number_immediate(d1),
get_number_immediate(d2));
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, 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)
@ -627,61 +677,64 @@ static void draw_udp_def(ivl_udp_t udp)
static void draw_udp_in_scope(ivl_net_logic_t lptr)
{
unsigned pdx;
unsigned pdx;
ivl_udp_t udp = ivl_logic_udp(lptr);
ivl_udp_t udp = ivl_logic_udp(lptr);
static ivl_udp_t *udps = 0x0;
static int nudps = 0;
int i;
unsigned ninp;
const char **input_strings;
static ivl_udp_t *udps = 0x0;
static int nudps = 0;
int i;
unsigned ninp;
const char **input_strings;
/* Do we need a delay? */
unsigned need_delay_flag = need_delay(lptr);
for (i=0; i<nudps; i++)
if (udps[i] == udp)
break;
for (i=0; i<nudps; i++) {
if (udps[i] == udp) break;
}
if (i >= nudps)
{
udps = realloc(udps, (nudps+1)*sizeof(ivl_udp_t));
assert(udps);
udps[nudps++] = udp;
draw_udp_def(udp);
}
if (i >= nudps) {
udps = realloc(udps, (nudps+1)*sizeof(ivl_udp_t));
assert(udps);
udps[nudps++] = udp;
draw_udp_def(udp);
}
/*
* We need to process the arguments first so any evaluation code
* (.resolv, etc.) can be built before we build the .udp call.
* This matches what is done for the other primitives.
*/
ninp = ivl_logic_pins(lptr) - 1;
input_strings = calloc(ninp, sizeof(char*));
for (pdx = 0 ; pdx < ninp ; pdx += 1) {
ivl_nexus_t nex = ivl_logic_pin(lptr, pdx+1);
/*
* We need to process the arguments first so any evaluation code
* (.resolv, etc.) can be built before we build the .udp call.
* This matches what is done for the other primitives.
*/
ninp = ivl_logic_pins(lptr) - 1;
input_strings = calloc(ninp, sizeof(char*));
for (pdx = 0 ; pdx < ninp ; pdx += 1) {
ivl_nexus_t nex = ivl_logic_pin(lptr, pdx+1);
/* Unlike other logic gates, primitives may have unconnected
inputs. The proper behavior is to attach a HiZ to the
port. */
if (nex == 0) {
assert(ivl_logic_width(lptr) == 1);
input_strings[pdx] = "C4<z>";
/* Unlike other logic gates, primitives may have unconnected
* inputs. The proper behavior is to attach a HiZ to the
* port. */
if (nex == 0) {
assert(ivl_logic_width(lptr) == 1);
input_strings[pdx] = "C4<z>";
} else {
input_strings[pdx] = draw_net_input(nex);
}
}
} else {
input_strings[pdx] = draw_net_input(nex);
}
}
/* Generate the UDP call. */
fprintf(vvp_out, "L_%p%s .udp UDP_%s", lptr, need_delay_flag? "/d" : "",
vvp_mangle_id(ivl_udp_name(udp)));
fprintf(vvp_out, "L_%p .udp", lptr);
fprintf(vvp_out, " UDP_%s",
vvp_mangle_id(ivl_udp_name(udp)));
draw_delay(lptr);
for (pdx = 0 ; pdx < ninp ; pdx += 1) {
fprintf(vvp_out, ", %s", input_strings[pdx]);
}
free(input_strings);
for (pdx = 0 ; pdx < ninp ; pdx += 1) {
fprintf(vvp_out, ", %s", input_strings[pdx]);
}
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)
@ -691,7 +744,8 @@ static void draw_logic_in_scope(ivl_net_logic_t lptr)
const char*lcasc = 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));
@ -882,61 +936,8 @@ static void draw_logic_in_scope(ivl_net_logic_t lptr)
persistent, held by the ivl_nexus_t objects. */
free(input_strings);
/* If there are delays, then draw the delay functor to carry
that delay. This is the final output. */
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");
}
}
}
/* Generate a delay when needed. */
if (need_delay_flag) draw_delay(lptr);
}
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);
extern void compile_udp_functor(char*label, char*type,
vvp_delay_t*delay,
unsigned argc, struct symb_s*argv);
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 <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 ';'
{ compile_udp_def(0, $1, $3, $5, 0, $7); }
| T_LABEL K_UDP T_SYMBOL delay_opt ',' symbols ';'
{ compile_udp_functor($1, $3, $4, $6.cnt, $6.vect); }
| T_LABEL K_UDP T_SYMBOL ',' symbols ';'
{ compile_udp_functor($1, $3, $5.cnt, $5.vect); }
/* Memory. Definition, port, initialization */
@ -1010,8 +1010,6 @@ signed_t_number
| '-' T_NUMBER { $$ = -$2; }
;
delay_opt : delay { $$=$1; } | /* empty */ { $$=0; } ;
delay
: '(' T_NUMBER ')'
{ $$ = 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.
*/
void compile_udp_functor(char*label, char*type,
vvp_delay_t*delay,
unsigned argc, struct symb_s*argv)
{
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);
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);
wide_inputs_connect(core, argc, argv);

View File

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