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:
parent
86653ddff9
commit
314714997f
16
elaborate.cc
16
elaborate.cc
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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); }
|
||||
|
|
|
|||
14
vvp/udp.cc
14
vvp/udp.cc
|
|
@ -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);
|
||||
|
|
|
|||
Loading…
Reference in New Issue