aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorTristan Gingold <tgingold@free.fr>2020-03-09 18:18:35 +0100
committerTristan Gingold <tgingold@free.fr>2020-03-09 18:18:39 +0100
commit71c4894dbf62645eaaab0e0b6d9f1d893577a3c8 (patch)
tree826e9495aca0b1463cc3c4193d631a05f4aef1c3 /src
parent6e91117be871ec51d7f154eafbb349ca4d790227 (diff)
downloadghdl-yosys-plugin-71c4894dbf62645eaaab0e0b6d9f1d893577a3c8.tar.gz
ghdl-yosys-plugin-71c4894dbf62645eaaab0e0b6d9f1d893577a3c8.tar.bz2
ghdl-yosys-plugin-71c4894dbf62645eaaab0e0b6d9f1d893577a3c8.zip
ghdl.cc: avoid infinite recursion due to concatenation.
Diffstat (limited to 'src')
-rw-r--r--src/ghdl.cc52
1 files changed, 50 insertions, 2 deletions
diff --git a/src/ghdl.cc b/src/ghdl.cc
index af2cd58..3d0f2d2 100644
--- a/src/ghdl.cc
+++ b/src/ghdl.cc
@@ -65,6 +65,7 @@ static Wire *get_wire(std::vector<RTLIL::Wire *> &net_map, Net n)
}
static RTLIL::SigSpec get_src(std::vector<RTLIL::Wire *> &net_map, Net n);
+static RTLIL::SigSpec get_src_extract(std::vector<RTLIL::Wire *> &net_map, Net n, unsigned off, unsigned wd);
static RTLIL::SigSpec get_src_concat(std::vector<RTLIL::Wire *> &net_map, Instance inst, unsigned nbr_in)
{
@@ -76,10 +77,57 @@ static RTLIL::SigSpec get_src_concat(std::vector<RTLIL::Wire *> &net_map, Instan
return res;
}
+// Extract WD bits at OFF from concatenation INST. Do not compute unused bits.
+static RTLIL::SigSpec get_src_concat_extract(std::vector<RTLIL::Wire *> &net_map, Instance inst, unsigned nbr_in, unsigned off, unsigned wd)
+{
+ RTLIL::SigSpec res;
+
+ // ConcatN means { I0; I1; .. IN}, but append() adds
+ // bits to the MSB side.
+ for (unsigned i = nbr_in; i > 0; i--) {
+ Net p = get_input_net(inst, (i - 1));
+ unsigned pw = get_width(p);
+ if (off < pw) {
+ unsigned sub_wd = (off + wd < pw ? wd : pw - off);
+ res.append(get_src_extract(net_map, p, off, sub_wd));
+ // sub_wd bits have been extracted.
+ wd -= sub_wd;
+ if (wd == 0)
+ break;
+ off = 0;
+ }
+ else {
+ off -= pw;
+ }
+ }
+ return res;
+}
+
+// Extract WD bits at OFF from N. Try to avoid computing unused bits as it may result in an infinite recursion if parts of a concatenation are defined by the concatenation.
static RTLIL::SigSpec get_src_extract(std::vector<RTLIL::Wire *> &net_map, Net n, unsigned off, unsigned wd)
{
- RTLIL::SigSpec res = get_src(net_map, n);
- return res.extract(off, wd);
+ Instance inst = get_net_parent(n);
+ switch(get_id(inst)) {
+ case Id_Signal:
+ case Id_Isignal:
+ case Id_Port:
+ case Id_Output:
+ return get_src_extract(net_map, get_input_net(inst, 0), off, wd);
+ case Id_Extract:
+ log_assert(wd <= get_width(n));
+ return get_src_extract(net_map, get_input_net(inst, 0), get_param_uns32(inst, 0) + off, wd);
+ case Id_Concat2:
+ return get_src_concat_extract(net_map, inst, 2, off, wd);
+ case Id_Concat3:
+ return get_src_concat_extract(net_map, inst, 3, off, wd);
+ case Id_Concat4:
+ return get_src_concat_extract(net_map, inst, 4, off, wd);
+ case Id_Concatn:
+ return get_src_concat_extract(net_map, inst, get_param_uns32(inst, 0), off, wd);
+ default:
+ RTLIL::SigSpec res = get_src(net_map, n);
+ return res.extract(off, wd);
+ }
}
static RTLIL::SigSpec get_src(std::vector<RTLIL::Wire *> &net_map, Net n)