aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorTristan Gingold <tgingold@free.fr>2019-09-06 03:36:58 +0200
committerTristan Gingold <tgingold@free.fr>2019-09-06 19:23:26 +0200
commite53823b725ef9fe215e84fb86cb45736511dd436 (patch)
tree8dfd7387249403261bae9dcc4aae9d30c9dd793d /src
parentdb2eca37c676a54827989349e3ced9860e3aa314 (diff)
downloadghdl-e53823b725ef9fe215e84fb86cb45736511dd436.tar.gz
ghdl-e53823b725ef9fe215e84fb86cb45736511dd436.tar.bz2
ghdl-e53823b725ef9fe215e84fb86cb45736511dd436.zip
synth: abstract of Merge_Assigns.
Diffstat (limited to 'src')
-rw-r--r--src/synth/synth-environment.adb167
1 files changed, 111 insertions, 56 deletions
diff --git a/src/synth/synth-environment.adb b/src/synth/synth-environment.adb
index 3e5a65b6d..1174c204b 100644
--- a/src/synth/synth-environment.adb
+++ b/src/synth/synth-environment.adb
@@ -698,6 +698,109 @@ package body Synth.Environment is
end;
end Get_Current_Assign_Value;
+ -- P is an array of Partial_Assign. Each element is a list
+ -- of partial assign from a different basic block.
+ -- Extract the value to nets N of the maximal partial assignment starting
+ -- at offset OFF for all partial assignments. Fully handled partial
+ -- assignments are poped. Set the offset and width to OFF and WD of the
+ -- result.
+ procedure Extract_Merge_Partial_Assigns (Ctxt : Builders.Context_Acc;
+ P : in out Partial_Assign_Array;
+ N : out Net_Array;
+ Off : in out Uns32;
+ Wd : out Width)
+ is
+ Min_Off : Uns32;
+ begin
+ Min_Off := Off;
+
+ -- Look for the partial assign with the least offset (but still
+ -- greather than Min_Off). Also extract the least width.
+ Off := Uns32'Last;
+ Wd := Width'Last;
+ for I in P'Range loop
+ if P (I) /= No_Partial_Assign then
+ declare
+ Pa : Partial_Assign_Record
+ renames Partial_Assign_Table.Table (P (I));
+ begin
+ if Pa.Offset <= Off then
+ Off := Uns32'Max (Pa.Offset, Min_Off);
+ Wd := Width'Min
+ (Wd, Get_Width (Pa.Value) - (Off - Pa.Offset));
+ end if;
+ end;
+ end if;
+ end loop;
+
+ -- No more assignments.
+ if Off = Uns32'Last and Wd = Width'Last then
+ return;
+ end if;
+
+ -- Get the values for that offset/width. Update lists.
+ for I in P'Range loop
+ if P (I) /= No_Partial_Assign
+ and then Get_Partial_Offset (P (I)) <= Off
+ then
+ declare
+ Val : constant Net := Get_Partial_Value (P (I));
+ P_W : constant Width := Get_Width (Val);
+ P_Off : constant Uns32 := Get_Partial_Offset (P (I));
+ begin
+ -- There is a partial assignment.
+ if P_Off = Off and then P_W = Wd then
+ -- Full covered.
+ N (I) := Val;
+ P (I) := Get_Partial_Next (P (I));
+ else
+ N (I) := Build_Extract (Ctxt, Val, Off - P_Off, Wd);
+ if P_Off + P_W = Off + Wd then
+ P (I) := Get_Partial_Next (P (I));
+ end if;
+ end if;
+ end;
+ else
+ -- No partial assignment. Get extract previous value.
+ N (I) := No_Net;
+ end if;
+ end loop;
+ end Extract_Merge_Partial_Assigns;
+
+ type Partial_Assign_List is record
+ First, Last : Partial_Assign;
+ end record;
+
+ procedure Partial_Assign_Init (List : out Partial_Assign_List) is
+ begin
+ List := (First | Last => No_Partial_Assign);
+ end Partial_Assign_Init;
+
+ procedure Partial_Assign_Append (List : in out Partial_Assign_List;
+ Pasgn : Partial_Assign) is
+ begin
+ if List.First = No_Partial_Assign then
+ List.First := Pasgn;
+ else
+ Set_Partial_Next (List.Last, Pasgn);
+ end if;
+ List.Last := Pasgn;
+ end Partial_Assign_Append;
+
+ procedure Merge_Partial_Assigns (Ctxt : Builders.Context_Acc;
+ W : Wire_Id;
+ List : in out Partial_Assign_List)
+ is
+ Pasgn : Partial_Assign;
+ begin
+ while List.First /= No_Partial_Assign loop
+ Pasgn := Get_Partial_Next (List.First);
+ Set_Partial_Next (List.First, No_Partial_Assign);
+ Phi_Assign (Ctxt, W, List.First);
+ List.First := Pasgn;
+ end loop;
+ end Merge_Partial_Assigns;
+
procedure Merge_Assigns (Ctxt : Builders.Context_Acc;
W : Wire_Id;
Sel : Net;
@@ -710,60 +813,22 @@ package body Synth.Environment is
Off : Uns32;
Wd : Width;
Res : Net;
- First_Pasgn, Last_Pasgn : Partial_Assign;
+ List : Partial_Assign_List;
Pasgn : Partial_Assign;
begin
P := (0 => F_Asgns, 1 => T_Asgns);
- First_Pasgn := No_Partial_Assign;
- Last_Pasgn := No_Partial_Assign;
+ Partial_Assign_Init (List);
Min_Off := 0;
loop
- -- Look for the partial assign with the least offset (but still
- -- greather than Min_Off). Also extract the least width.
- Off := Uns32'Last;
- Wd := Width'Last;
- for I in P'Range loop
- if P (I) /= No_Partial_Assign then
- declare
- Pa : Partial_Assign_Record
- renames Partial_Assign_Table.Table (P (I));
- begin
- if Pa.Offset <= Off then
- Off := Uns32'Max (Pa.Offset, Min_Off);
- Wd := Width'Min
- (Wd, Get_Width (Pa.Value) - (Off - Pa.Offset));
- end if;
- end;
- end if;
- end loop;
+ Off := Min_Off;
+ Extract_Merge_Partial_Assigns (Ctxt, P, N, Off, Wd);
-- No more assignments.
exit when Off = Uns32'Last and Wd = Width'Last;
- -- Get the values for that offset/width. Update lists.
- for I in P'Range loop
- if P (I) /= No_Partial_Assign
- and then Get_Partial_Offset (P (I)) <= Off
- then
- declare
- Val : constant Net := Get_Partial_Value (P (I));
- P_W : constant Width := Get_Width (Val);
- P_Off : constant Uns32 := Get_Partial_Offset (P (I));
- begin
- -- There is a partial assignment.
- if P_Off = Off and then P_W = Wd then
- -- Full covered.
- N (I) := Val;
- P (I) := Get_Partial_Next (P (I));
- else
- N (I) := Build_Extract (Ctxt, Val, Off - P_Off, Wd);
- if P_Off + P_W = Off + Wd then
- P (I) := Get_Partial_Next (P (I));
- end if;
- end if;
- end;
- else
+ for I in N'Range loop
+ if N (I) = No_Net then
-- No partial assignment. Get extract previous value.
N (I) := Get_Current_Assign_Value (Ctxt, W, Off, Wd);
end if;
@@ -774,12 +839,7 @@ package body Synth.Environment is
-- Keep the result in a list.
Pasgn := New_Partial_Assign (Res, Off);
- if First_Pasgn = No_Partial_Assign then
- First_Pasgn := Pasgn;
- else
- Set_Partial_Next (Last_Pasgn, Pasgn);
- end if;
- Last_Pasgn := Pasgn;
+ Partial_Assign_Append (List, Pasgn);
Min_Off := Off + Wd;
end loop;
@@ -787,12 +847,7 @@ package body Synth.Environment is
-- Do the assignments from the result list.
-- It cannot be done before because the assignments will overwrite the
-- last assignments which are read to create a partial assignment.
- while First_Pasgn /= No_Partial_Assign loop
- Pasgn := Get_Partial_Next (First_Pasgn);
- Set_Partial_Next (First_Pasgn, No_Partial_Assign);
- Phi_Assign (Ctxt, W, First_Pasgn);
- First_Pasgn := Pasgn;
- end loop;
+ Merge_Partial_Assigns (Ctxt, W, List);
end Merge_Assigns;
-- Add muxes for two lists T and F of assignments.