diff --git a/elaborate.cc b/elaborate.cc index d8f2e5c1a..b57f1eaea 100644 --- a/elaborate.cc +++ b/elaborate.cc @@ -769,7 +769,7 @@ void PGBuiltin::elaborate(Design*des, NetScope*scope) const if (check_delay_count(des)) return; NetExpr* rise_time, *fall_time, *decay_time; - eval_delays(des, scope, rise_time, fall_time, decay_time); + eval_delays(des, scope, rise_time, fall_time, decay_time, true); struct attrib_list_t*attrib_list; unsigned attrib_list_n = 0; @@ -1977,7 +1977,7 @@ void PGModule::elaborate_udp_(Design*des, PUdp*udp, NetScope*scope) const PDelays tmp_del; tmp_del.set_delays(overrides_, false); tmp_del.eval_delays(des, scope, rise_expr, fall_expr, - decay_expr); + decay_expr, true); } } diff --git a/tgt-vvp/Makefile.in b/tgt-vvp/Makefile.in index 82a4a78e2..d09c9e709 100644 --- a/tgt-vvp/Makefile.in +++ b/tgt-vvp/Makefile.in @@ -47,8 +47,8 @@ CPPFLAGS = $(INCLUDE_PATH) @CPPFLAGS@ @DEFS@ @PICFLAG@ CFLAGS = @WARNING_FLAGS@ @WARNING_FLAGS_CC@ @CFLAGS@ LDFLAGS = @LDFLAGS@ -O = vvp.o draw_class.o draw_enum.o draw_mux.o draw_substitute.o draw_net_input.o \ - draw_switch.o draw_ufunc.o draw_vpi.o \ +O = vvp.o draw_class.o draw_delay.o draw_enum.o draw_mux.o draw_net_input.o \ + draw_substitute.o draw_switch.o draw_ufunc.o draw_vpi.o \ eval_bool.o \ eval_condit.o \ eval_expr.o eval_object.o eval_real.o eval_string.o \ diff --git a/tgt-vvp/draw_delay.c b/tgt-vvp/draw_delay.c new file mode 100644 index 000000000..1fcc92a21 --- /dev/null +++ b/tgt-vvp/draw_delay.c @@ -0,0 +1,127 @@ +/* + * Copyright (c) 2016 Stephen Williams (steve@icarus.com) + * + * This source code is free software; you can redistribute it + * and/or modify it in source code form under the terms of the GNU + * General Public License as published by the Free Software + * Foundation; either version 2 of the License, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +# include "vvp_priv.h" +# include +# include +# include + + +/* + * This function draws a BUFT to drive a constant delay value. + */ +static char* draw_const_net(void*ptr, char*suffix, uint64_t value) +{ + char tmp[64]; + char c4_value[69]; + unsigned idx; + c4_value[0] = 'C'; + c4_value[1] = '4'; + c4_value[2] = '<'; + for (idx = 0; idx < 64; idx += 1) { + c4_value[66-idx] = (value & 1) ? '1' : '0'; + value >>= 1; + } + c4_value[67] = '>'; + c4_value[68] = 0; + + /* Make the constant an argument to a BUFT, which is + what we use to drive the value. */ + fprintf(vvp_out, "L_%p/%s .functor BUFT 1, %s, C4<0>, C4<0>, C4<0>;\n", + ptr, suffix, c4_value); + snprintf(tmp, sizeof tmp, "L_%p/%s", ptr, suffix); + return strdup(tmp); +} + +/* + * Draw the appropriate delay statement. + */ +void draw_delay(void*ptr, unsigned wid, const char*input, ivl_expr_t rise_exp, + ivl_expr_t fall_exp, ivl_expr_t decay_exp) +{ + char tmp[64]; + if (input == 0) { + snprintf(tmp, sizeof tmp, "L_%p/d", ptr); + input = tmp; + } + + /* 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)) { + + 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 ") %s;\n", + ptr, wid, + get_number_immediate64(rise_exp), + get_number_immediate64(fall_exp), + get_number_immediate64(decay_exp), + input); + + /* For a variable delay we indicate only two delays by setting the + * decay time to zero. */ + } else { + char*rise_const = 0; + char*fall_const = 0; + char*decay_const = 0; + const char*rise_str; + const char*fall_str; + const char*decay_str; + + if (number_is_immediate(rise_exp, 64, 0)) { + uint64_t value = get_number_immediate64(rise_exp); + rise_str = rise_const = draw_const_net(ptr, "tr", value); + } else { + ivl_signal_t sig = ivl_expr_signal(rise_exp); + assert(sig && ivl_signal_dimensions(sig) == 0); + rise_str = draw_net_input(ivl_signal_nex(sig,0)); + } + + if (number_is_immediate(fall_exp, 64, 0)) { + uint64_t value = get_number_immediate64(fall_exp); + fall_str = fall_const = draw_const_net(ptr, "tf", value); + } else { + ivl_signal_t sig = ivl_expr_signal(fall_exp); + assert(sig && ivl_signal_dimensions(sig) == 0); + fall_str = draw_net_input(ivl_signal_nex(sig,0)); + } + + if (decay_exp == 0) { + decay_str = "0"; + } else if (number_is_immediate(decay_exp, 64, 0)) { + uint64_t value = get_number_immediate64(decay_exp); + decay_str = decay_const = draw_const_net(ptr, "td", value); + } else { + ivl_signal_t sig = ivl_expr_signal(decay_exp); + assert(sig && ivl_signal_dimensions(sig) == 0); + decay_str = draw_net_input(ivl_signal_nex(sig,0)); + } + + fprintf(vvp_out, "L_%p .delay %u %s, %s, %s, %s;\n", + ptr, wid, input, rise_str, fall_str, decay_str); + + free(rise_const); + free(fall_const); + free(decay_const); + } +} diff --git a/tgt-vvp/draw_mux.c b/tgt-vvp/draw_mux.c index ec699ce47..16d793d73 100644 --- a/tgt-vvp/draw_mux.c +++ b/tgt-vvp/draw_mux.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2002-2015 Stephen Williams (steve@icarus.com) + * Copyright (c) 2002-2016 Stephen Williams (steve@icarus.com) * * This source code is free software; you can redistribute it * and/or modify it in source code form under the terms of the GNU @@ -51,44 +51,8 @@ static void draw_lpm_mux_ab(ivl_lpm_t net, const char*muxz) if (data_type_of_nexus(ivl_lpm_q(net)) == IVL_VT_REAL) dly_width = 0; + draw_delay(net, dly_width, 0, d_rise, d_fall, d_decay); dly = "/d"; - if (number_is_immediate(d_rise, 64, 0) && - number_is_immediate(d_fall, 64, 0) && - number_is_immediate(d_decay, 64, 0)) { - - assert( ! number_is_unknown(d_rise)); - assert( ! number_is_unknown(d_fall)); - assert( ! number_is_unknown(d_decay)); - - fprintf(vvp_out, "L_%p .delay %u (%" PRIu64 ",%" PRIu64 ",%" PRIu64 ") L_%p/d;\n", - net, dly_width, - get_number_immediate64(d_rise), - get_number_immediate64(d_fall), - get_number_immediate64(d_decay), net); - } else { - ivl_signal_t sig; - // We do not currently support calculating the decay from - // the rise and fall variable delays. - assert(d_decay != 0); - assert(ivl_expr_type(d_rise) == IVL_EX_SIGNAL); - assert(ivl_expr_type(d_fall) == IVL_EX_SIGNAL); - assert(ivl_expr_type(d_decay) == IVL_EX_SIGNAL); - - fprintf(vvp_out, "L_%p .delay %u L_%p/d", - net, dly_width, net); - - sig = ivl_expr_signal(d_rise); - assert(ivl_signal_dimensions(sig) == 0); - fprintf(vvp_out, ", v%p_0", sig); - - sig = ivl_expr_signal(d_fall); - assert(ivl_signal_dimensions(sig) == 0); - fprintf(vvp_out, ", v%p_0", sig); - - sig = ivl_expr_signal(d_decay); - assert(ivl_signal_dimensions(sig) == 0); - fprintf(vvp_out, ", v%p_0;\n", sig); - } } input[0] = draw_net_input(ivl_lpm_data(net,0)); diff --git a/tgt-vvp/draw_net_input.c b/tgt-vvp/draw_net_input.c index 2b995affa..aa43b2203 100644 --- a/tgt-vvp/draw_net_input.c +++ b/tgt-vvp/draw_net_input.c @@ -330,9 +330,11 @@ static char* draw_net_input_drive(ivl_nexus_t nex, ivl_nexus_ptr_t nptr) cptr = ivl_nexus_ptr_con(nptr); if (cptr) { + char tmp[64]; char *result = 0; ivl_expr_t d_rise, d_fall, d_decay; unsigned dly_width = 0; + char *dly; /* Constants should have exactly 1 pin, with a literal value. */ assert(nptr_pin == 0); @@ -368,68 +370,17 @@ static char* draw_net_input_drive(ivl_nexus_t nex, ivl_nexus_ptr_t nptr) d_fall = ivl_const_delay(cptr, 1); d_decay = ivl_const_delay(cptr, 2); - /* We have a delayed constant, so we need to build some code. */ + dly = ""; if (d_rise != 0) { - char tmp[128]; - fprintf(vvp_out, "L_%p/d .functor BUFT 1, %s, " - "C4<0>, C4<0>, C4<0>;\n", cptr, result); - free(result); - - /* Is this a fixed or variable delay? */ - if (number_is_immediate(d_rise, 64, 0) && - number_is_immediate(d_fall, 64, 0) && - number_is_immediate(d_decay, 64, 0)) { - - assert(! number_is_unknown(d_rise)); - assert(! number_is_unknown(d_fall)); - assert(! number_is_unknown(d_decay)); - - fprintf(vvp_out, "L_%p .delay %u " - "(%" PRIu64 ",%" PRIu64 ",%" PRIu64 ") L_%p/d;\n", - cptr, dly_width, - get_number_immediate64(d_rise), - get_number_immediate64(d_fall), - get_number_immediate64(d_decay), cptr); - - } else { - ivl_signal_t sig; - // We do not currently support calculating the decay - // from the rise and fall variable delays. - assert(d_decay != 0); - assert(ivl_expr_type(d_rise) == IVL_EX_SIGNAL); - assert(ivl_expr_type(d_fall) == IVL_EX_SIGNAL); - assert(ivl_expr_type(d_decay) == IVL_EX_SIGNAL); - - fprintf(vvp_out, "L_%p .delay %u L_%p/d", - cptr, dly_width, cptr); - - sig = ivl_expr_signal(d_rise); - assert(ivl_signal_dimensions(sig) == 0); - fprintf(vvp_out, ", v%p_0", sig); - - sig = ivl_expr_signal(d_fall); - assert(ivl_signal_dimensions(sig) == 0); - fprintf(vvp_out, ", v%p_0", sig); - - sig = ivl_expr_signal(d_decay); - assert(ivl_signal_dimensions(sig) == 0); - fprintf(vvp_out, ", v%p_0;\n", sig); - } - - snprintf(tmp, sizeof tmp, "L_%p", cptr); - result = strdup(tmp); - - } else { - char tmp[64]; - fprintf(vvp_out, "L_%p .functor BUFT 1, %s, " - "C4<0>, C4<0>, C4<0>;\n", cptr, result); - free(result); - - snprintf(tmp, sizeof tmp, "L_%p", cptr); - result = strdup(tmp); + draw_delay(cptr, dly_width, 0, d_rise, d_fall, d_decay); + dly = "/d"; } + fprintf(vvp_out, "L_%p%s .functor BUFT 1, %s, C4<0>, C4<0>, C4<0>;\n", + cptr, dly, result); + free(result); - return result; + snprintf(tmp, sizeof tmp, "L_%p", cptr); + return strdup(tmp); } lpm = ivl_nexus_ptr_lpm(nptr); diff --git a/tgt-vvp/draw_switch.c b/tgt-vvp/draw_switch.c index b53d214b0..01a6f30a5 100644 --- a/tgt-vvp/draw_switch.c +++ b/tgt-vvp/draw_switch.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2008-2010,2012 Stephen Williams (steve@icarus.com) + * Copyright (c) 2008-2016 Stephen Williams (steve@icarus.com) * * This source code is free software; you can redistribute it * and/or modify it in source code form under the terms of the GNU @@ -38,18 +38,6 @@ void draw_switch_in_scope(ivl_switch_t sw) ivl_expr_t fall_exp = ivl_switch_delay(sw, 1); ivl_expr_t decay_exp= ivl_switch_delay(sw, 2); - if ((rise_exp || fall_exp || decay_exp) && - (!number_is_immediate(rise_exp, 64, 0) || - number_is_unknown(rise_exp) || - !number_is_immediate(fall_exp, 64, 0) || - number_is_unknown(fall_exp) || - !number_is_immediate(decay_exp, 64, 0) || - number_is_unknown(decay_exp))) { - fprintf(stderr, "%s:%u: error: Invalid tranif delay expression.\n", - ivl_switch_file(sw), ivl_switch_lineno(sw)); - vvp_errors += 1; - } - island = ivl_switch_island(sw); if (ivl_island_flag_test(island, 0) == 0) draw_tran_island(island); @@ -67,24 +55,18 @@ void draw_switch_in_scope(ivl_switch_t sw) char str_e_buf[4 + 2*sizeof(void*)]; if (enable && rise_exp) { - assert(fall_exp && decay_exp); - /* If the enable has a delay, then generate a .delay node to delay the input by the specified amount. Do the delay outside of the island so that the island processing doesn't have to deal with it. */ const char*raw = draw_net_input(enable); + draw_delay(sw, 1, raw, rise_exp, fall_exp, decay_exp); + snprintf(str_e_buf, sizeof str_e_buf, "p%p", sw); str_e = str_e_buf; - fprintf(vvp_out, "%s/d .delay 1 " - "(%" PRIu64 ",%" PRIu64 ",%" PRIu64 ") %s;\n", - str_e, get_number_immediate64(rise_exp), - get_number_immediate64(fall_exp), - get_number_immediate64(decay_exp), raw); - - fprintf(vvp_out, "%s .import I%p, %s/d;\n", str_e, island, str_e); + fprintf(vvp_out, "%s .import I%p, L_%p;\n", str_e, island, sw); } else if (enable) { str_e = draw_island_net_input(island, enable); diff --git a/tgt-vvp/vvp_priv.h b/tgt-vvp/vvp_priv.h index fdffa81b8..c4e725bd9 100644 --- a/tgt-vvp/vvp_priv.h +++ b/tgt-vvp/vvp_priv.h @@ -261,6 +261,13 @@ extern void show_stmt_file_line(ivl_statement_t net, const char*desc); extern int test_immediate_vec4_ok(ivl_expr_t expr); extern void draw_immediate_vec4(ivl_expr_t expr, const char*opcode); +/* + * Draw a delay statement. + */ +extern void draw_delay(void*ptr, unsigned wid, const char*input, + ivl_expr_t rise_exp, ivl_expr_t fall_exp, + ivl_expr_t decay_exp); + /* * These functions manage word register allocation. */ diff --git a/tgt-vvp/vvp_scope.c b/tgt-vvp/vvp_scope.c index 53b56dbc6..c6e1059ee 100644 --- a/tgt-vvp/vvp_scope.c +++ b/tgt-vvp/vvp_scope.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001-2015 Stephen Williams (steve@icarus.com) + * Copyright (c) 2001-2016 Stephen Williams (steve@icarus.com) * * This source code is free software; you can redistribute it * and/or modify it in source code form under the terms of the GNU @@ -754,7 +754,7 @@ static unsigned need_delay(ivl_net_logic_t lptr) /* * 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_logic_delay(ivl_net_logic_t lptr) { ivl_expr_t rise_exp = ivl_logic_delay(lptr, 0); ivl_expr_t fall_exp = ivl_logic_delay(lptr, 1); @@ -767,49 +767,7 @@ static void draw_delay(ivl_net_logic_t lptr) delay_wid = 0; } - /* 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)) { - - 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"); - } - } + draw_delay(lptr, delay_wid, 0, rise_exp, fall_exp, decay_exp); } static void draw_udp_def(ivl_udp_t udp) @@ -945,7 +903,7 @@ static void draw_udp_in_scope(ivl_net_logic_t lptr) fprintf(vvp_out, ";\n"); /* Generate a delay when needed. */ - if (need_delay_flag) draw_delay(lptr); + if (need_delay_flag) draw_logic_delay(lptr); } static void draw_logic_in_scope(ivl_net_logic_t lptr) @@ -1149,7 +1107,7 @@ static void draw_logic_in_scope(ivl_net_logic_t lptr) free(input_strings); /* Generate a delay when needed. */ - if (need_delay_flag) draw_delay(lptr); + if (need_delay_flag) draw_logic_delay(lptr); } static void draw_event_in_scope(ivl_event_t obj) @@ -1349,20 +1307,8 @@ static const char* draw_lpm_output_delay(ivl_lpm_t net, ivl_variable_type_t dt) const char*dly = ""; if (d_rise != 0) { - assert(number_is_immediate(d_rise, 64, 0)); - assert(number_is_immediate(d_fall, 64, 0)); - assert(number_is_immediate(d_decay, 64, 0)); - - assert(! number_is_unknown(d_rise)); - assert(! number_is_unknown(d_fall)); - assert(! number_is_unknown(d_decay)); - + draw_delay(net, width, 0, d_rise, d_fall, d_decay); dly = "/d"; - fprintf(vvp_out, "L_%p .delay %u (%" PRIu64 ",%" PRIu64 ",%" PRIu64 ")" - " L_%p/d;\n", net, width, - get_number_immediate64(d_rise), - get_number_immediate64(d_fall), - get_number_immediate64(d_decay), net); } return dly;