aboutsummaryrefslogtreecommitdiffstats
path: root/src/synth/synth-environment.adb
diff options
context:
space:
mode:
Diffstat (limited to 'src/synth/synth-environment.adb')
-rw-r--r--src/synth/synth-environment.adb306
1 files changed, 195 insertions, 111 deletions
diff --git a/src/synth/synth-environment.adb b/src/synth/synth-environment.adb
index f170d6093..ec11d4ba2 100644
--- a/src/synth/synth-environment.adb
+++ b/src/synth/synth-environment.adb
@@ -31,6 +31,7 @@ with Errorout; use Errorout;
with Synth.Flags;
with Synth.Errors; use Synth.Errors;
with Synth.Source; use Synth.Source;
+with Synth.Context;
with Vhdl.Nodes;
@@ -136,9 +137,22 @@ package body Synth.Environment is
Assign_Table.Table (Asgn).Chain := Chain;
end Set_Assign_Chain;
+ function Get_Assign_Is_Static (Asgn : Seq_Assign) return Boolean is
+ begin
+ return Assign_Table.Table (Asgn).Val.Is_Static;
+ end Get_Assign_Is_Static;
+
+ function Get_Assign_Static_Val (Asgn : Seq_Assign) return Memtyp is
+ begin
+ return Assign_Table.Table (Asgn).Val.Val;
+ end Get_Assign_Static_Val;
+
function Get_Assign_Partial (Asgn : Seq_Assign) return Partial_Assign is
begin
- return Assign_Table.Table (Asgn).Asgns;
+ -- Note: fails if the value is static.
+ -- Use Get_Assign_Partial_Force if you want to automatically convert
+ -- the value to a Partial_Assign (a net).
+ return Assign_Table.Table (Asgn).Val.Asgns;
end Get_Assign_Partial;
function New_Partial_Assign (Val : Net; Offset : Uns32)
@@ -332,28 +346,34 @@ package body Synth.Environment is
-- Must be connected to an Id_Output or Id_Signal
pragma Assert (Outport /= No_Net);
P : Partial_Assign;
+ Res : Net;
begin
-- Check output is not already assigned.
pragma Assert (Get_Input_Net (Get_Net_Parent (Outport), 0) = No_Net);
- P := Asgn_Rec.Asgns;
- pragma Assert (P /= No_Partial_Assign);
- while P /= No_Partial_Assign loop
- declare
- Pa : Partial_Assign_Record renames Partial_Assign_Table.Table (P);
- Res : Net;
- begin
- if Synth.Flags.Flag_Debug_Noinference then
- Res := Pa.Value;
- else
- Res := Inference.Infere
- (Ctxt, Pa.Value, Pa.Offset, Outport, Stmt);
- end if;
+ if Asgn_Rec.Val.Is_Static then
+ Res := Synth.Context.Get_Memtyp_Net (Asgn_Rec.Val.Val);
+ Add_Conc_Assign (Wid, Res, 0, Stmt);
+ else
+ P := Asgn_Rec.Val.Asgns;
+ pragma Assert (P /= No_Partial_Assign);
+ while P /= No_Partial_Assign loop
+ declare
+ Pa : Partial_Assign_Record renames
+ Partial_Assign_Table.Table (P);
+ begin
+ if Synth.Flags.Flag_Debug_Noinference then
+ Res := Pa.Value;
+ else
+ Res := Inference.Infere
+ (Ctxt, Pa.Value, Pa.Offset, Outport, Stmt);
+ end if;
- Add_Conc_Assign (Wid, Res, Pa.Offset, Stmt);
- P := Pa.Next;
- end;
- end loop;
+ Add_Conc_Assign (Wid, Res, Pa.Offset, Stmt);
+ P := Pa.Next;
+ end;
+ end loop;
+ end if;
end Pop_And_Merge_Phi_Wire;
-- This procedure is called after each concurrent statement to assign
@@ -385,27 +405,29 @@ package body Synth.Environment is
Asgn_Rec : Seq_Assign_Record renames Assign_Table.Table (Asgn);
P : Partial_Assign;
begin
- P := Asgn_Rec.Asgns;
- pragma Assert (P /= No_Partial_Assign);
- while P /= No_Partial_Assign loop
- declare
- Pa : Partial_Assign_Record
- renames Partial_Assign_Table.Table (P);
- Res_Inst : constant Instance := Get_Net_Parent (Pa.Value);
- begin
- if Get_Mark_Flag (Res_Inst)
- and then Get_Id (Res_Inst) = Gates.Id_Mux2
- then
- -- A nop is needed iff the value is reused and will be
- -- inferred (which is only possible for Id_Mux2).
- Pa.Value := Build_Nop (Ctxt, Pa.Value);
- else
- Set_Mark_Flag (Res_Inst, True);
- end if;
+ if not Asgn_Rec.Val.Is_Static then
+ P := Asgn_Rec.Val.Asgns;
+ pragma Assert (P /= No_Partial_Assign);
+ while P /= No_Partial_Assign loop
+ declare
+ Pa : Partial_Assign_Record
+ renames Partial_Assign_Table.Table (P);
+ Res_Inst : constant Instance := Get_Net_Parent (Pa.Value);
+ begin
+ if Get_Mark_Flag (Res_Inst)
+ and then Get_Id (Res_Inst) = Gates.Id_Mux2
+ then
+ -- A nop is needed iff the value is reused and will be
+ -- inferred (which is only possible for Id_Mux2).
+ Pa.Value := Build_Nop (Ctxt, Pa.Value);
+ else
+ Set_Mark_Flag (Res_Inst, True);
+ end if;
- P := Pa.Next;
- end;
- end loop;
+ P := Pa.Next;
+ end;
+ end loop;
+ end if;
Asgn := Asgn_Rec.Chain;
end;
end loop;
@@ -417,19 +439,21 @@ package body Synth.Environment is
Asgn_Rec : Seq_Assign_Record renames Assign_Table.Table (Asgn);
P : Partial_Assign;
begin
- P := Asgn_Rec.Asgns;
- pragma Assert (P /= No_Partial_Assign);
- while P /= No_Partial_Assign loop
- declare
- Pa : Partial_Assign_Record
- renames Partial_Assign_Table.Table (P);
- Res_Inst : constant Instance := Get_Net_Parent (Pa.Value);
- begin
- Set_Mark_Flag (Res_Inst, False);
-
- P := Pa.Next;
- end;
- end loop;
+ if not Asgn_Rec.Val.Is_Static then
+ P := Asgn_Rec.Val.Asgns;
+ pragma Assert (P /= No_Partial_Assign);
+ while P /= No_Partial_Assign loop
+ declare
+ Pa : Partial_Assign_Record
+ renames Partial_Assign_Table.Table (P);
+ Res_Inst : constant Instance := Get_Net_Parent (Pa.Value);
+ begin
+ Set_Mark_Flag (Res_Inst, False);
+
+ P := Pa.Next;
+ end;
+ end loop;
+ end if;
Asgn := Asgn_Rec.Chain;
end;
end loop;
@@ -465,13 +489,17 @@ package body Synth.Environment is
-- Phi_Assign.
Next_Asgn := Asgn_Rec.Chain;
if Wid <= Mark then
- Pasgn := Asgn_Rec.Asgns;
- while Pasgn /= No_Partial_Assign loop
- Next_Pasgn := Get_Partial_Next (Pasgn);
- Set_Partial_Next (Pasgn, No_Partial_Assign);
- Phi_Assign (Ctxt, Wid, Pasgn);
- Pasgn := Next_Pasgn;
- end loop;
+ if Asgn_Rec.Val.Is_Static then
+ Phi_Assign_Static (Wid, Asgn_Rec.Val.Val);
+ else
+ Pasgn := Asgn_Rec.Val.Asgns;
+ while Pasgn /= No_Partial_Assign loop
+ Next_Pasgn := Get_Partial_Next (Pasgn);
+ Set_Partial_Next (Pasgn, No_Partial_Assign);
+ Phi_Assign (Ctxt, Wid, Pasgn);
+ Pasgn := Next_Pasgn;
+ end loop;
+ end if;
end if;
Asgn := Next_Asgn;
end;
@@ -846,13 +874,17 @@ package body Synth.Environment is
raise Internal_Error;
end case;
+ if Asgn_Rec.Val.Is_Static then
+ return Synth.Context.Get_Memtyp_Net (Asgn_Rec.Val.Val);
+ end if;
+
-- Cannot be empty.
- pragma Assert (Asgn_Rec.Asgns /= No_Partial_Assign);
+ pragma Assert (Asgn_Rec.Val.Asgns /= No_Partial_Assign);
-- Simple case: fully assigned.
declare
Pasgn : Partial_Assign_Record renames
- Partial_Assign_Table.Table (Asgn_Rec.Asgns);
+ Partial_Assign_Table.Table (Asgn_Rec.Val.Asgns);
begin
if Pasgn.Offset = 0 and then Get_Width (Pasgn.Value) = W then
return Pasgn.Value;
@@ -903,6 +935,12 @@ package body Synth.Environment is
return Build2_Extract (Ctxt, Wire_Rec.Gate, Off, Wd);
end if;
+ -- If the current value is static, just return it.
+ if Get_Assign_Is_Static (First_Seq) then
+ return Context.Get_Partial_Memtyp_Net
+ (Get_Assign_Static_Val (First_Seq), Off, Wd);
+ end if;
+
-- If the range is the same as the seq assign, return the value.
declare
P : constant Partial_Assign := Get_Assign_Partial (First_Seq);
@@ -931,7 +969,8 @@ package body Synth.Environment is
Cur_Wd := Wd;
pragma Assert (Wd > 0);
loop
- -- Find value at CUR_OFF from assignment.
+ -- Find value at CUR_OFF from assignment. Start at the top
+ -- phi (which is not a static value).
Seq := First_Seq;
P := Get_Assign_Partial (Seq);
loop
@@ -959,15 +998,19 @@ package body Synth.Environment is
exit;
end if;
if Pr.Offset + Pw <= Cur_Off then
- -- Next partial;
+ -- Skip this partial, it is before what we are searching.
P := Pr.Next;
elsif Pr.Offset > Cur_Off
and then Pr.Offset < Cur_Off + Cur_Wd
then
+ -- There is a partial assignment that should be
+ -- considered, but first we need some values before it.
-- Reduce WD and continue to search in previous;
Cur_Wd := Pr.Offset - Cur_Off;
P := No_Partial_Assign;
else
+ -- The next partial assignment is beyond what we are
+ -- searching.
-- Continue to search in previous.
P := No_Partial_Assign;
end if;
@@ -979,6 +1022,13 @@ package body Synth.Environment is
Cur_Off, Cur_Wd));
exit;
end if;
+ if Get_Assign_Is_Static (Seq) then
+ -- Extract from static value.
+ Append
+ (Vec, Context.Get_Partial_Memtyp_Net
+ (Get_Assign_Static_Val (Seq), Cur_Off, Cur_Wd));
+ exit;
+ end if;
P := Get_Assign_Partial (Seq);
end if;
end;
@@ -1097,7 +1147,7 @@ package body Synth.Environment is
end Partial_Assign_Append;
procedure Merge_Partial_Assigns (Ctxt : Builders.Context_Acc;
- W : Wire_Id;
+ Wid : Wire_Id;
List : in out Partial_Assign_List)
is
Pasgn : Partial_Assign;
@@ -1105,7 +1155,7 @@ package body Synth.Environment is
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);
+ Phi_Assign (Ctxt, Wid, List.First);
List.First := Pasgn;
end loop;
end Merge_Partial_Assigns;
@@ -1200,6 +1250,27 @@ package body Synth.Environment is
Merge_Partial_Assigns (Ctxt, W, List);
end Merge_Assigns;
+ -- Force the value of a Seq_Assign to be a net if needed, return it.
+ function Get_Assign_Partial_Force (Asgn : Seq_Assign) return Partial_Assign
+ is
+ Asgn_Rec : Seq_Assign_Record renames Assign_Table.Table (Asgn);
+ N : Net;
+ Res : Partial_Assign;
+ begin
+ if Asgn_Rec.Val.Is_Static then
+ N := Synth.Context.Get_Memtyp_Net (Asgn_Rec.Val.Val);
+ Res := New_Partial_Assign (N, 0);
+ if False then
+ -- Overwrite ?
+ Asgn_Rec.Val := (Is_Static => False,
+ Asgns => Res);
+ end if;
+ else
+ Res := Asgn_Rec.Val.Asgns;
+ end if;
+ return Res;
+ end Get_Assign_Partial_Force;
+
-- Add muxes for two lists T and F of assignments.
procedure Merge_Phis (Ctxt : Builders.Context_Acc;
Sel : Net;
@@ -1222,7 +1293,7 @@ package body Synth.Environment is
then
-- Has an assignment only for the false branch.
W := Get_Wire_Id (F_Asgns);
- Fp := Get_Assign_Partial (F_Asgns);
+ Fp := Get_Assign_Partial_Force (F_Asgns);
Tp := No_Partial_Assign;
F_Asgns := Get_Assign_Chain (F_Asgns);
elsif F_Asgns = No_Seq_Assign
@@ -1232,14 +1303,14 @@ package body Synth.Environment is
-- Has an assignment only for the true branch.
W := Get_Wire_Id (T_Asgns);
Fp := No_Partial_Assign;
- Tp := Get_Assign_Partial (T_Asgns);
+ Tp := Get_Assign_Partial_Force (T_Asgns);
T_Asgns := Get_Assign_Chain (T_Asgns);
else
-- Has assignments for both the true and the false branch.
pragma Assert (Get_Wire_Id (F_Asgns) = Get_Wire_Id (T_Asgns));
W := Get_Wire_Id (F_Asgns);
- Fp := Get_Assign_Partial (F_Asgns);
- Tp := Get_Assign_Partial (T_Asgns);
+ Fp := Get_Assign_Partial_Force (F_Asgns);
+ Tp := Get_Assign_Partial_Force (T_Asgns);
T_Asgns := Get_Assign_Chain (T_Asgns);
F_Asgns := Get_Assign_Chain (F_Asgns);
end if;
@@ -1278,7 +1349,7 @@ package body Synth.Environment is
Seq_Asgn : Seq_Assign_Record renames Assign_Table.Table (Seq);
Prev_El : Partial_Assign;
begin
- Prev_El := Seq_Asgn.Asgns;
+ Prev_El := Seq_Asgn.Val.Asgns;
if Prev_El = No_Partial_Assign then
-- It's empty!
return;
@@ -1320,7 +1391,7 @@ package body Synth.Environment is
begin
Inserted := False;
Last_El := No_Partial_Assign;
- El := Seq_Asgn.Asgns;
+ El := Seq_Asgn.Val.Asgns;
while El /= No_Partial_Assign loop
declare
P : Partial_Assign_Record renames Partial_Assign_Table.Table (El);
@@ -1340,7 +1411,7 @@ package body Synth.Environment is
if Last_El /= No_Partial_Assign then
Partial_Assign_Table.Table (Last_El).Next := Asgn;
else
- Seq_Asgn.Asgns := Asgn;
+ Seq_Asgn.Val.Asgns := Asgn;
end if;
V.Next := P.Next;
Inserted := True;
@@ -1364,7 +1435,7 @@ package body Synth.Environment is
if Last_El /= No_Partial_Assign then
Partial_Assign_Table.Table (Last_El).Next := Asgn;
else
- Seq_Asgn.Asgns := Asgn;
+ Seq_Asgn.Val.Asgns := Asgn;
end if;
V.Next := El;
Inserted := True;
@@ -1419,7 +1490,7 @@ package body Synth.Environment is
if Last_El /= No_Partial_Assign then
Partial_Assign_Table.Table (Last_El).Next := Asgn;
else
- Seq_Asgn.Asgns := Asgn;
+ Seq_Asgn.Val.Asgns := Asgn;
end if;
V.Next := El;
Inserted := True;
@@ -1459,16 +1530,30 @@ package body Synth.Environment is
Id => Dest,
Prev => Cur_Asgn,
Chain => No_Seq_Assign,
- Asgns => Pasgn));
+ Val => (Is_Static => False, Asgns => Pasgn)));
Wire_Rec.Cur_Assign := Assign_Table.Last;
Phi_Append_Assign (Assign_Table.Last);
else
-- Overwrite.
+ if Get_Assign_Is_Static (Cur_Asgn) then
+ -- Force seq_assign to be a net.
+ declare
+ Asgn_Rec : Seq_Assign_Record renames
+ Assign_Table.Table (Cur_Asgn);
+ N : Net;
+ Pa : Partial_Assign;
+ begin
+ N := Synth.Context.Get_Memtyp_Net (Asgn_Rec.Val.Val);
+ Pa := New_Partial_Assign (N, 0);
+ Asgn_Rec.Val := (Is_Static => False, Asgns => Pa);
+ end;
+ end if;
+
Insert_Partial_Assign (Ctxt, Cur_Asgn, Pasgn);
end if;
end Phi_Assign;
- procedure Phi_Assign
+ procedure Phi_Assign_Net
(Ctxt : Builders.Context_Acc; Dest : Wire_Id; Val : Net; Offset : Uns32)
is
Pasgn : Partial_Assign;
@@ -1476,52 +1561,50 @@ package body Synth.Environment is
Pasgn := New_Partial_Assign (Val, Offset);
Phi_Assign (Ctxt, Dest, Pasgn);
- end Phi_Assign;
+ end Phi_Assign_Net;
+
+ procedure Phi_Assign_Static (Dest : Wire_Id; Val : Memtyp) is
+ Wire_Rec : Wire_Id_Record renames Wire_Id_Table.Table (Dest);
+ pragma Assert (Wire_Rec.Kind /= Wire_None);
+ Cur_Asgn : constant Seq_Assign := Wire_Rec.Cur_Assign;
+ begin
+ if Cur_Asgn = No_Seq_Assign
+ or else Assign_Table.Table (Cur_Asgn).Phi < Current_Phi
+ then
+ -- Never assigned, or first assignment in that level
+ Assign_Table.Append ((Phi => Current_Phi,
+ Id => Dest,
+ Prev => Cur_Asgn,
+ Chain => No_Seq_Assign,
+ Val => (Is_Static => True, Val => Val)));
+ Wire_Rec.Cur_Assign := Assign_Table.Last;
+ Phi_Append_Assign (Assign_Table.Last);
+ else
+ Assign_Table.Table (Cur_Asgn).Val := (Is_Static => True, Val => Val);
+ end if;
+ end Phi_Assign_Static;
-- Return the net driving WID when it is known to be possibly constant.
-- Return No_Net is not constant.
- function Get_Const_Net_Maybe (Wid : Wire_Id) return Net
+ function Is_Static_Wire (Wid : Wire_Id) return Boolean
is
Wire_Rec : Wire_Id_Record renames Wire_Id_Table.Table (Wid);
- Pasgn : Partial_Assign;
- N : Net;
begin
if Wire_Rec.Kind /= Wire_Variable then
- return No_Net;
+ return False;
end if;
if Wire_Rec.Cur_Assign = No_Seq_Assign then
- return No_Net;
- end if;
- Pasgn := Get_Assign_Partial (Wire_Rec.Cur_Assign);
- pragma Assert (Pasgn /= No_Partial_Assign);
- if Get_Partial_Offset (Pasgn) /= 0 then
- return No_Net;
- end if;
- N := Get_Partial_Value (Pasgn);
- if Get_Width (N) /= Get_Width (Wire_Rec.Gate) then
- return No_Net;
- end if;
- return N;
- end Get_Const_Net_Maybe;
-
- function Is_Const_Wire (Wid : Wire_Id) return Boolean
- is
- N : constant Net := Get_Const_Net_Maybe (Wid);
- begin
- if N = No_Net then
return False;
- else
- return Is_Const_Net (N);
end if;
- end Is_Const_Wire;
+ return Get_Assign_Is_Static (Wire_Rec.Cur_Assign);
+ end Is_Static_Wire;
- function Get_Const_Wire (Wid : Wire_Id) return Net
+ function Get_Static_Wire (Wid : Wire_Id) return Memtyp
is
- N : constant Net := Get_Const_Net_Maybe (Wid);
+ Wire_Rec : Wire_Id_Record renames Wire_Id_Table.Table (Wid);
begin
- pragma Assert (N /= No_Net);
- return N;
- end Get_Const_Wire;
+ return Get_Assign_Static_Val (Wire_Rec.Cur_Assign);
+ end Get_Static_Wire;
begin
Wire_Id_Table.Append ((Kind => Wire_None,
Mark_Flag => False,
@@ -1533,10 +1616,11 @@ begin
pragma Assert (Wire_Id_Table.Last = No_Wire_Id);
Assign_Table.Append ((Phi => No_Phi_Id,
- Id => No_Wire_Id,
- Prev => No_Seq_Assign,
- Chain => No_Seq_Assign,
- Asgns => No_Partial_Assign));
+ Id => No_Wire_Id,
+ Prev => No_Seq_Assign,
+ Chain => No_Seq_Assign,
+ Val => (Is_Static => False,
+ Asgns => No_Partial_Assign)));
pragma Assert (Assign_Table.Last = No_Seq_Assign);
Partial_Assign_Table.Append ((Next => No_Partial_Assign,