aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorTristan Gingold <tgingold@free.fr>2021-10-09 20:55:36 +0200
committerTristan Gingold <tgingold@free.fr>2021-10-09 20:55:36 +0200
commit7a6fab44f771aa839fd17645c427d6de4b1d7fce (patch)
treee221ff5c09ad91028da6e1eeeba070c3657ca95e /src
parent9eeaf238a467c15149452ced197320f72d34556f (diff)
downloadghdl-7a6fab44f771aa839fd17645c427d6de4b1d7fce.tar.gz
ghdl-7a6fab44f771aa839fd17645c427d6de4b1d7fce.tar.bz2
ghdl-7a6fab44f771aa839fd17645c427d6de4b1d7fce.zip
synth-vhdl_expr: fix handling of negative factor in slice. For #1886
Diffstat (limited to 'src')
-rw-r--r--src/synth/synth-vhdl_expr.adb86
1 files changed, 61 insertions, 25 deletions
diff --git a/src/synth/synth-vhdl_expr.adb b/src/synth/synth-vhdl_expr.adb
index 3db969c50..92a9cd918 100644
--- a/src/synth/synth-vhdl_expr.adb
+++ b/src/synth/synth-vhdl_expr.adb
@@ -1381,38 +1381,74 @@ package body Synth.Vhdl_Expr is
(+Loc, "cannot extract same constant factor for dynamic slice");
return;
end if;
- if L_Fac < 0 then
- Step := Uns32 (-L_Fac);
- Inp := Build_Monadic (Ctxt, Id_Neg, Inp);
- Set_Location (Inp, Loc);
- else
- Step := Uns32 (L_Fac);
- end if;
+ -- Compute step and width.
+ Step := Uns32 (abs L_Fac);
case Pfx_Bnd.Dir is
when Dir_To =>
- Width := Uns32 (R_Add - L_Add + 1);
- Off := Uns32 (L_Add - Pfx_Bnd.Left);
+ if R_Add < L_Add then
+ Width := 0;
+ else
+ Width := Uns32 (R_Add - L_Add + 1);
+ end if;
when Dir_Downto =>
- Width := Uns32 (L_Add - R_Add + 1);
- if R_Add >= Pfx_Bnd.Right then
- Off := Uns32 (R_Add - Pfx_Bnd.Right);
+ if L_Add < R_Add then
+ Width := 0;
else
- -- Handle biased values.
- declare
- Bias : constant Uns32 :=
- (Uns32 (Pfx_Bnd.Right - R_Add) + Step - 1) / Step;
- Bias_Net : Net;
- begin
- -- Add bias to INP and adjust the offset.
- Bias_Net := Build2_Const_Uns
- (Ctxt, Uns64 (Bias), Get_Width (Inp));
- Inp := Build_Dyadic (Ctxt, Id_Add, Inp, Bias_Net);
- Set_Location (Inp, Loc);
- Off := Uns32 (Int32 (Bias * Step) + R_Add - Pfx_Bnd.Right);
- end;
+ Width := Uns32 (L_Add - R_Add + 1);
end if;
end case;
+
+ -- TODO: degenerated dynamic slice.
+ pragma Assert (L_Fac /= 0);
+
+ -- Assume input width large enough to cover all the values of the
+ -- bounds.
+ if (Pfx_Bnd.Dir = Dir_Downto and then L_Fac < 0)
+ or else (Pfx_Bnd.Dir = Dir_To and then L_Fac > 0)
+ then
+ -- TODO: Assume in range.
+ case Pfx_Bnd.Dir is
+ when Dir_To =>
+ Off := Uns32 (L_Add - Pfx_Bnd.Left);
+ when Dir_Downto =>
+ Off := Uns32 (R_Add - Pfx_Bnd.Right);
+ end case;
+ declare
+ Bias : constant Uns32 := Off / Step;
+ Bias_Net : Net;
+ begin
+ Bias_Net := Build2_Const_Uns
+ (Ctxt, Uns64 (Bias), Get_Width (Inp));
+ Inp := Build_Dyadic (Ctxt, Id_Sub, Bias_Net, Inp);
+ Set_Location (Inp, Loc);
+ Off := Off - Bias * Step;
+ end;
+ else
+ case Pfx_Bnd.Dir is
+ when Dir_To =>
+ Off := Uns32 (L_Add - Pfx_Bnd.Left);
+ when Dir_Downto =>
+ if R_Add >= Pfx_Bnd.Right then
+ Off := Uns32 (R_Add - Pfx_Bnd.Right);
+ else
+ -- Handle biased values.
+ declare
+ Bias : constant Uns32 :=
+ (Uns32 (Pfx_Bnd.Right - R_Add) + Step - 1) / Step;
+ Bias_Net : Net;
+ begin
+ -- Add bias to INP and adjust the offset.
+ Bias_Net := Build2_Const_Uns
+ (Ctxt, Uns64 (Bias), Get_Width (Inp));
+ Inp := Build_Dyadic (Ctxt, Id_Add, Inp, Bias_Net);
+ Set_Location (Inp, Loc);
+ Off :=
+ Uns32 (Int32 (Bias * Step) + R_Add - Pfx_Bnd.Right);
+ end;
+ end if;
+ end case;
+ end if;
end Synth_Extract_Dyn_Suffix;
procedure Synth_Slice_Const_Suffix (Syn_Inst: Synth_Instance_Acc;