From 314714997f17439d79005667e7d1a04a5fd0916d Mon Sep 17 00:00:00 2001 From: Cary R Date: Fri, 23 Jul 2010 19:19:36 -0700 Subject: [PATCH] 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. --- elaborate.cc | 16 --- tgt-vvp/vvp_scope.c | 241 ++++++++++++++++++++++---------------------- vvp/compile.h | 1 - vvp/parse.y | 8 +- vvp/udp.cc | 14 +-- vvp/udp.h | 1 - 6 files changed, 125 insertions(+), 156 deletions(-) diff --git a/elaborate.cc b/elaborate.cc index 4937bf1fc..365d2cc75 100644 --- a/elaborate.cc +++ b/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 (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 (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; - } } } diff --git a/tgt-vvp/vvp_scope.c b/tgt-vvp/vvp_scope.c index 1bc13e741..ba01d3aae 100644 --- a/tgt-vvp/vvp_scope.c +++ b/tgt-vvp/vvp_scope.c @@ -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) - { - 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"; + /* 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"; + } 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) diff --git a/vvp/compile.h b/vvp/compile.h index fcd82144a..57d1bf111 100644 --- a/vvp/compile.h +++ b/vvp/compile.h @@ -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); diff --git a/vvp/parse.y b/vvp/parse.y index cd09833dd..274207098 100644 --- a/vvp/parse.y +++ b/vvp/parse.y @@ -108,7 +108,7 @@ static struct __vpiModPath*modpath_dst = 0; %type argument_opt argument_list %type argument symbol_access -%type delay delay_opt +%type 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); } diff --git a/vvp/udp.cc b/vvp/udp.cc index d24c3a9d0..44e5d5591 100644 --- a/vvp/udp.cc +++ b/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); diff --git a/vvp/udp.h b/vvp/udp.h index 81202cf98..484cde19a 100644 --- a/vvp/udp.h +++ b/vvp/udp.h @@ -23,7 +23,6 @@ */ # include "vvp_net.h" -# include "delay.h" # include "schedule.h" struct udp_levels_table;