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.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;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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)
|
||||||
|
|
@ -627,61 +677,64 @@ static void draw_udp_def(ivl_udp_t udp)
|
||||||
|
|
||||||
static void draw_udp_in_scope(ivl_net_logic_t lptr)
|
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 ivl_udp_t *udps = 0x0;
|
||||||
static int nudps = 0;
|
static int nudps = 0;
|
||||||
int i;
|
int i;
|
||||||
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;
|
||||||
udps = realloc(udps, (nudps+1)*sizeof(ivl_udp_t));
|
}
|
||||||
assert(udps);
|
|
||||||
udps[nudps++] = udp;
|
|
||||||
draw_udp_def(udp);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
if (i >= nudps) {
|
||||||
* We need to process the arguments first so any evaluation code
|
udps = realloc(udps, (nudps+1)*sizeof(ivl_udp_t));
|
||||||
* (.resolv, etc.) can be built before we build the .udp call.
|
assert(udps);
|
||||||
* This matches what is done for the other primitives.
|
udps[nudps++] = udp;
|
||||||
*/
|
draw_udp_def(udp);
|
||||||
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
|
* We need to process the arguments first so any evaluation code
|
||||||
port. */
|
* (.resolv, etc.) can be built before we build the .udp call.
|
||||||
if (nex == 0) {
|
* This matches what is done for the other primitives.
|
||||||
assert(ivl_logic_width(lptr) == 1);
|
*/
|
||||||
input_strings[pdx] = "C4<z>";
|
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);
|
||||||
|
|
||||||
} else {
|
/* Unlike other logic gates, primitives may have unconnected
|
||||||
input_strings[pdx] = draw_net_input(nex);
|
* 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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
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]);
|
||||||
}
|
}
|
||||||
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)
|
||||||
|
|
|
||||||
|
|
@ -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);
|
||||||
|
|
|
||||||
|
|
@ -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); }
|
||||||
|
|
|
||||||
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.
|
* 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) {
|
define_functor_symbol(label, ptr);
|
||||||
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);
|
|
||||||
}
|
|
||||||
free(label);
|
free(label);
|
||||||
|
|
||||||
wide_inputs_connect(core, argc, argv);
|
wide_inputs_connect(core, argc, argv);
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue