Files
iverilog/tgt-vvp/draw_delay.c
T
Martin Whitaker 20104c92c8 Fix for GitHub issue #96 - support mixed constant/variable delays in vvp.
If all three rise/fall/decay delay values are constant, we can use
the vvp .delay statement variant that takes three literal numbers.
If not, we have to use the variant that takes three net inputs. If
some of the delay values are constant, we need to create constant
drivers for those delay inputs.
2016-04-02 19:55:56 +01:00

128 lines
4.0 KiB
C

/*
* Copyright (c) 2016 Stephen Williams ([email protected])
*
* 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 <assert.h>
# include <stdlib.h>
# include <string.h>
/*
* 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);
}
}