iverilog/tgt-vvp/draw_delay.c

128 lines
4.0 KiB
C
Raw Permalink Normal View History

/*
2025-10-13 02:35:15 +02:00
* Copyright (c) 2016-2025 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 <assert.h>
# include <stdlib.h>
# include <string.h>
/*
* This function draws a BUFT to drive a constant delay value.
*/
2025-10-13 02:35:15 +02:00
static char* draw_const_net(const void*ptr, const 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.
*/
2025-10-13 02:35:15 +02:00
void draw_delay(const 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);
}
}