mirror of
https://github.com/steveicarus/iverilog.git
synced 2026-08-29 01:03:29 +02:00
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.
128 lines
4.0 KiB
C
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);
|
|
}
|
|
}
|