From 2817bf59c57619e80e17ccb04a1cf40d1b8723f2 Mon Sep 17 00:00:00 2001 From: Martin Whitaker Date: Sun, 10 Nov 2024 13:31:54 +0000 Subject: [PATCH] tgt-vlog95: fix mixed-scope multiple constant assignments to a net (issue #1181) The vlog95 code generator collects all the constant assignments to a net within each scope and then emits them. The old code only recorded the ivl_signal_t for each constant assignment, which meant it had to iterate through the nexus pointers in the assicated nexus to find the constant. When there were multiple constant assignments to the same net, it needed to record which assignments had already been emitted, which it did by keeping a count in the nexus private data and skipping that many constants on each successive assignment. However the count did not get reset after emitting all the assignments in that scope, so if there were assignments to the same net made in another scope, the count would already be positive and those assignments would also be skipped. This could probably have been fixed by clearing the nexus private data after processing the constant assignment list for each scope, but it is more efficient to record the ivl_nexus_ptr_t for each constant along with the ivl_signal_t, eliminating the need to search for the associated nexus pointer. --- tgt-vlog95/logic_lpm.c | 62 ++++++++++++++-------------------------- tgt-vlog95/scope.c | 21 +++++++++----- tgt-vlog95/vlog95_priv.h | 5 ++-- 3 files changed, 39 insertions(+), 49 deletions(-) diff --git a/tgt-vlog95/logic_lpm.c b/tgt-vlog95/logic_lpm.c index 6f86d2d42..c32c95f1a 100644 --- a/tgt-vlog95/logic_lpm.c +++ b/tgt-vlog95/logic_lpm.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2022 Cary R. (cygcary@yahoo.com) + * Copyright (C) 2011-2024 Cary R. (cygcary@yahoo.com) * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -2275,46 +2275,28 @@ void emit_tran(ivl_scope_t scope, ivl_switch_t tran) fprintf(vlog_out, "\n"); } -void emit_signal_net_const_as_ca(ivl_scope_t scope, ivl_signal_t sig) +void emit_signal_net_const_as_ca(ivl_scope_t scope, ivl_signal_t sig, + ivl_nexus_ptr_t nex_ptr) { - ivl_nexus_t nex = ivl_signal_nex(sig, 0); - unsigned idx, count = ivl_nexus_ptrs(nex); - unsigned long emitted = (uintptr_t) ivl_nexus_get_private(nex); - for (idx = 0; idx < count; idx += 1) { - ivl_nexus_ptr_t nex_ptr = ivl_nexus_ptr(nex, idx); - ivl_net_const_t net_const = ivl_nexus_ptr_con(nex_ptr); - if (! net_const) continue; - if (scope != ivl_const_scope(net_const)) continue; - /* Found the constant so emit it if it has not been emitted. */ - if (emitted) { - --emitted; - continue; - } - fprintf(vlog_out, "%*cassign", indent, ' '); - emit_strength(ivl_nexus_ptr_drive1(nex_ptr), - ivl_nexus_ptr_drive0(nex_ptr), - 2, "assign", - ivl_signal_file(sig), ivl_signal_lineno(sig)); - emit_delay(scope, - ivl_const_delay(net_const, 0), - ivl_const_delay(net_const, 1), - ivl_const_delay(net_const, 2), - 3); - fprintf(vlog_out, " "); - emit_id(ivl_signal_basename(sig)); - fprintf(vlog_out, " = "); - emit_const_nexus(scope, net_const); - fprintf(vlog_out, ";"); - emit_sig_file_line(sig); - fprintf(vlog_out, "\n"); - /* Increment the emitted constant count by one. */ - ivl_nexus_set_private(nex, - (void *) ((uintptr_t) ivl_nexus_get_private(nex) + 1U)); - return; - } - /* We must find the constant in the nexus. */ - assert(0); - + ivl_net_const_t net_const = ivl_nexus_ptr_con(nex_ptr); + assert(net_const); + fprintf(vlog_out, "%*cassign", indent, ' '); + emit_strength(ivl_nexus_ptr_drive1(nex_ptr), + ivl_nexus_ptr_drive0(nex_ptr), + 2, "assign", + ivl_signal_file(sig), ivl_signal_lineno(sig)); + emit_delay(scope, + ivl_const_delay(net_const, 0), + ivl_const_delay(net_const, 1), + ivl_const_delay(net_const, 2), + 3); + fprintf(vlog_out, " "); + emit_id(ivl_signal_basename(sig)); + fprintf(vlog_out, " = "); + emit_const_nexus(scope, net_const); + fprintf(vlog_out, ";"); + emit_sig_file_line(sig); + fprintf(vlog_out, "\n"); } static void dump_drive(ivl_drive_t drive) diff --git a/tgt-vlog95/scope.c b/tgt-vlog95/scope.c index 078a0e77f..590857a8b 100644 --- a/tgt-vlog95/scope.c +++ b/tgt-vlog95/scope.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2010-2022 Cary R. (cygcary@yahoo.com) + * Copyright (C) 2010-2024 Cary R. (cygcary@yahoo.com) * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -161,21 +161,28 @@ static void emit_var_def(ivl_signal_t sig) * Keep a list of constants that drive nets and need to be emitted as * a continuous assignment. */ -static ivl_signal_t *net_consts = 0; +typedef struct { + ivl_signal_t sig; + ivl_nexus_ptr_t nex_ptr; + } net_const_t; + +static net_const_t *net_consts = 0; static unsigned num_net_consts = 0; -static void add_net_const_to_list(ivl_signal_t net_const) +static void add_net_const_to_list(ivl_signal_t sig, ivl_nexus_ptr_t nex_ptr) { num_net_consts += 1; - net_consts = realloc(net_consts, num_net_consts * sizeof(ivl_signal_t)); - net_consts[num_net_consts-1] = net_const; + net_consts = realloc(net_consts, num_net_consts * sizeof(net_const_t)); + net_consts[num_net_consts-1].sig = sig; + net_consts[num_net_consts-1].nex_ptr = nex_ptr; } static unsigned emit_and_free_net_const_list(ivl_scope_t scope) { unsigned idx; for (idx = 0; idx < num_net_consts; idx += 1) { - emit_signal_net_const_as_ca(scope, net_consts[idx]); + emit_signal_net_const_as_ca(scope, net_consts[idx].sig, + net_consts[idx].nex_ptr); } free(net_consts); net_consts = 0; @@ -193,7 +200,7 @@ static void save_net_constants(const ivl_scope_t scope, ivl_signal_t sig) ivl_net_const_t net_const = ivl_nexus_ptr_con(nex_ptr); if (! net_const) continue; if (scope != ivl_const_scope(net_const)) continue; - add_net_const_to_list(sig); + add_net_const_to_list(sig, nex_ptr); } } diff --git a/tgt-vlog95/vlog95_priv.h b/tgt-vlog95/vlog95_priv.h index 97670f71f..e260e5969 100644 --- a/tgt-vlog95/vlog95_priv.h +++ b/tgt-vlog95/vlog95_priv.h @@ -1,7 +1,7 @@ #ifndef IVL_vlog95_priv_H #define IVL_vlog95_priv_H /* - * Copyright (C) 2010-2019 Cary R. (cygcary@yahoo.com) + * Copyright (C) 2010-2024 Cary R. (cygcary@yahoo.com) * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -105,7 +105,8 @@ extern void emit_nexus_as_ca(ivl_scope_t scope, ivl_nexus_t nex, unsigned allow_UD, unsigned sign_extend); extern void emit_nexus_port_driver_as_ca(ivl_scope_t scope, ivl_nexus_t nex); extern void emit_const_nexus(ivl_scope_t scope, ivl_net_const_t const_net); -extern void emit_signal_net_const_as_ca(ivl_scope_t scope, ivl_signal_t sig); +extern void emit_signal_net_const_as_ca(ivl_scope_t scope, ivl_signal_t sig, + ivl_nexus_ptr_t nex_ptr); extern void add_udp_to_list(ivl_udp_t udp); extern void emit_udp_list(void);