aboutsummaryrefslogtreecommitdiffstats
path: root/src/synth
diff options
context:
space:
mode:
authorTristan Gingold <tgingold@free.fr>2019-10-10 18:29:07 +0200
committerTristan Gingold <tgingold@free.fr>2019-10-10 18:29:07 +0200
commitbb55e3201f211ed7176993cbf1622ad4592f95e0 (patch)
tree2f2f2e75d58f6ebd7b5ad8bd021dc7bc59918791 /src/synth
parent5d43f82f6afe21cc874309e280e31a4f51439502 (diff)
downloadghdl-bb55e3201f211ed7176993cbf1622ad4592f95e0.tar.gz
ghdl-bb55e3201f211ed7176993cbf1622ad4592f95e0.tar.bz2
ghdl-bb55e3201f211ed7176993cbf1622ad4592f95e0.zip
synth: rewrite cleanup pass.
Diffstat (limited to 'src/synth')
-rw-r--r--src/synth/netlists-cleanup.adb107
-rw-r--r--src/synth/netlists-cleanup.ads26
-rw-r--r--src/synth/netlists-utils.adb59
-rw-r--r--src/synth/netlists-utils.ads7
-rw-r--r--src/synth/netlists.adb40
-rw-r--r--src/synth/netlists.ads13
-rw-r--r--src/synth/synth-insts.adb4
7 files changed, 188 insertions, 68 deletions
diff --git a/src/synth/netlists-cleanup.adb b/src/synth/netlists-cleanup.adb
new file mode 100644
index 000000000..207a8a63e
--- /dev/null
+++ b/src/synth/netlists-cleanup.adb
@@ -0,0 +1,107 @@
+-- Netlist cleanup.
+-- Copyright (C) 2019 Tristan Gingold
+--
+-- This file is part of GHDL.
+--
+-- 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
+-- the Free Software Foundation; either version 2 of the License, or
+-- (at your option) any later version.
+--
+-- This program is distributed in the hope that it will be useful,
+-- but WITHOUT ANY WARRANTY; without even the implied warranty of
+-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+-- GNU General Public License for more details.
+--
+-- You should have received a copy of the GNU General Public License
+-- along with this program; if not, write to the Free Software
+-- Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston,
+-- MA 02110-1301, USA.
+
+with Netlists.Utils; use Netlists.Utils;
+
+package body Netlists.Cleanup is
+ function Is_Unused_Instance (Inst : Instance) return Boolean
+ is
+ Nbr_Outputs : constant Port_Idx := Get_Nbr_Outputs (Inst);
+ N : Net;
+ begin
+ -- An instance without outputs is considered as used.
+ if Nbr_Outputs = 0 then
+ return Get_Module (Inst) = Free_Module;
+ end if;
+
+ for Idx in 0 .. Nbr_Outputs - 1 loop
+ N := Get_Output (Inst, Idx);
+ if Is_Connected (N) then
+ -- Connected output.
+ return False;
+ end if;
+ end loop;
+
+ -- All outputs are unconnected.
+ return True;
+ end Is_Unused_Instance;
+
+ procedure Extract_If_Unused (Inst : Instance; List : in out Instance) is
+ begin
+ if Is_Unused_Instance (Inst) then
+ Extract_Instance (Inst);
+ Set_Next_Instance (Inst, List);
+ List := Inst;
+ end if;
+ end Extract_If_Unused;
+
+ -- TODO: use mark & sweep to remove unused assignments ?
+ procedure Remove_Unconnected_Instances (M : Module)
+ is
+ Inst : Instance;
+ Next_Inst : Instance;
+ List : Instance;
+ begin
+ -- Extract from instances of M all unconnected instances. Put them
+ -- in a list.
+ List := No_Instance;
+
+ Inst := Get_First_Instance (M);
+ while Inst /= No_Instance loop
+ Next_Inst := Get_Next_Instance (Inst);
+ Extract_If_Unused (Inst, List);
+ Inst := Next_Inst;
+ end loop;
+
+ -- While the list is not empty:
+ -- extract the first instance of the list.
+ -- unconnect all inputs of the instance, free the instance.
+ -- if unconnected an input resulted in an instance without connected
+ -- output, extract it from M and append it in the list.
+ while List /= No_Instance loop
+ Inst := List;
+ List := Get_Next_Instance (Inst);
+
+ declare
+ Nbr_Inputs : constant Port_Nbr := Get_Nbr_Inputs (Inst);
+ Inp : Input;
+ Drv : Net;
+ Inst2 : Instance;
+ begin
+ if Nbr_Inputs > 0 then
+ for K in 0 .. Nbr_Inputs - 1 loop
+ Inp := Get_Input (Inst, K);
+ Drv := Get_Driver (Inp);
+ if Drv /= No_Net then
+ -- The input was already unconnected.
+ Disconnect (Inp);
+ if Get_First_Sink (Drv) = No_Input then
+ Inst2 := Get_Net_Parent (Drv);
+ Extract_If_Unused (Inst2, List);
+ end if;
+ end if;
+ end loop;
+ end if;
+ end;
+
+ Free_Instance (Inst);
+ end loop;
+ end Remove_Unconnected_Instances;
+end Netlists.Cleanup;
diff --git a/src/synth/netlists-cleanup.ads b/src/synth/netlists-cleanup.ads
new file mode 100644
index 000000000..7f373130d
--- /dev/null
+++ b/src/synth/netlists-cleanup.ads
@@ -0,0 +1,26 @@
+-- Netlist cleanup.
+-- Copyright (C) 2019 Tristan Gingold
+--
+-- This file is part of GHDL.
+--
+-- 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
+-- the Free Software Foundation; either version 2 of the License, or
+-- (at your option) any later version.
+--
+-- This program is distributed in the hope that it will be useful,
+-- but WITHOUT ANY WARRANTY; without even the implied warranty of
+-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+-- GNU General Public License for more details.
+--
+-- You should have received a copy of the GNU General Public License
+-- along with this program; if not, write to the Free Software
+-- Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston,
+-- MA 02110-1301, USA.
+
+package Netlists.Cleanup is
+ -- Remove instances of module M whose outputs are not connected.
+ -- Their inputs will be deconnected, which can result in new instances
+ -- that are also removed.
+ procedure Remove_Unconnected_Instances (M : Module);
+end Netlists.Cleanup;
diff --git a/src/synth/netlists-utils.adb b/src/synth/netlists-utils.adb
index 02e1ea24a..d5a1f2edd 100644
--- a/src/synth/netlists-utils.adb
+++ b/src/synth/netlists-utils.adb
@@ -175,63 +175,4 @@ package body Netlists.Utils is
-- Free Inst
Free_Instance (Inst);
end Disconnect_And_Free;
-
- function Is_Unused_Instance (Inst : Instance) return Boolean
- is
- Nbr_Outputs : constant Port_Idx := Get_Nbr_Outputs (Inst);
- N : Net;
- begin
- -- An instance without outputs is considered as used.
- if Nbr_Outputs = 0 then
- return False;
- end if;
-
- for Idx in 0 .. Nbr_Outputs - 1 loop
- N := Get_Output (Inst, Idx);
- if Is_Connected (N) then
- -- Connected output.
- return False;
- end if;
- end loop;
-
- -- All outputs are unconnected.
- return True;
- end Is_Unused_Instance;
-
- procedure Remove_Unused_Instances (M : Module)
- is
- pragma Assert (Is_Valid (M));
- Inst : Instance;
- begin
- Extract_All_Instances (M, Inst);
-
- -- Add the self instance (the first one).
- Append_Instance (M, Inst);
- Inst := Get_Next_Instance (Inst);
-
- while Inst /= No_Instance loop
- if not (Get_Id (Inst) = Id_Free
- or else Is_Unused_Instance (Inst))
- then
- -- Keep this used instance.
- Append_Instance (M, Inst);
- end if;
- Inst := Get_Next_Instance (Inst);
- end loop;
- end Remove_Unused_Instances;
-
- procedure Remove_Free_Instances (M : Module)
- is
- pragma Assert (Is_Valid (M));
- Inst : Instance;
- begin
- Extract_All_Instances (M, Inst);
-
- while Inst /= No_Instance loop
- if Get_Id (Inst) /= Id_Free then
- Append_Instance (M, Inst);
- end if;
- Inst := Get_Next_Instance (Inst);
- end loop;
- end Remove_Free_Instances;
end Netlists.Utils;
diff --git a/src/synth/netlists-utils.ads b/src/synth/netlists-utils.ads
index 165e986d8..10406500d 100644
--- a/src/synth/netlists-utils.ads
+++ b/src/synth/netlists-utils.ads
@@ -56,11 +56,4 @@ package Netlists.Utils is
-- Disconnect input I. If the driver of I has no output(s) connected,
-- disconnect and free it.
procedure Disconnect_And_Free (I : Input);
-
- -- Unlink all free instances of M.
- procedure Remove_Free_Instances (M : Module);
-
- -- Unlink all unused instances of M.
- procedure Remove_Unused_Instances (M : Module);
-
end Netlists.Utils;
diff --git a/src/synth/netlists.adb b/src/synth/netlists.adb
index 6597be8ed..b152dccd5 100644
--- a/src/synth/netlists.adb
+++ b/src/synth/netlists.adb
@@ -322,9 +322,35 @@ package body Netlists is
else
Instances_Table.Table (M_Ent.Last_Instance).Next_Instance := Inst;
end if;
+ Instances_Table.Table (Inst).Prev_Instance := M_Ent.Last_Instance;
M_Ent.Last_Instance := Inst;
end Append_Instance;
+ procedure Extract_Instance (Inst : Instance)
+ is
+ pragma Assert (Is_Valid (Inst));
+ Inst_Ent : Instance_Record renames Instances_Table.Table (Inst);
+ M : constant Module := Inst_Ent.Parent;
+ M_Ent : Module_Record renames Modules_Table.Table (M);
+ begin
+ if Inst_Ent.Prev_Instance /= No_Instance then
+ Set_Next_Instance (Inst_Ent.Prev_Instance, Inst_Ent.Next_Instance);
+ else
+ pragma Assert (M_Ent.First_Instance = Inst);
+ M_Ent.First_Instance := Inst_Ent.Next_Instance;
+ end if;
+
+ if Inst_Ent.Next_Instance /= No_Instance then
+ Set_Prev_Instance (Inst_Ent.Next_Instance, Inst_Ent.Prev_Instance);
+ else
+ pragma Assert (M_Ent.Last_Instance = Inst);
+ M_Ent.Last_Instance := Inst_Ent.Prev_Instance;
+ end if;
+
+ Inst_Ent.Prev_Instance := No_Instance;
+ Inst_Ent.Next_Instance := No_Instance;
+ end Extract_Instance;
+
function New_Instance_Internal (Parent : Module;
M : Module;
Name : Sname;
@@ -343,6 +369,7 @@ package body Netlists is
begin
Instances_Table.Append ((Parent => Parent,
Next_Instance => No_Instance,
+ Prev_Instance => No_Instance,
Klass => M,
Name => Name,
First_Param => Params,
@@ -491,6 +518,18 @@ package body Netlists is
return Instances_Table.Table (Inst).Next_Instance;
end Get_Next_Instance;
+ procedure Set_Next_Instance (Inst : Instance; Next : Instance) is
+ begin
+ pragma Assert (Is_Valid (Inst));
+ Instances_Table.Table (Inst).Next_Instance := Next;
+ end Set_Next_Instance;
+
+ procedure Set_Prev_Instance (Inst : Instance; Prev : Instance) is
+ begin
+ pragma Assert (Is_Valid (Inst));
+ Instances_Table.Table (Inst).Prev_Instance := Prev;
+ end Set_Prev_Instance;
+
function Get_First_Output (Inst : Instance) return Net is
begin
pragma Assert (Is_Valid (Inst));
@@ -831,6 +870,7 @@ begin
Instances_Table.Append ((Parent => No_Module,
Next_Instance => No_Instance,
+ Prev_Instance => No_Instance,
Klass => No_Module,
Name => No_Sname,
First_Param => No_Param_Idx,
diff --git a/src/synth/netlists.ads b/src/synth/netlists.ads
index 4580edb89..c1371c835 100644
--- a/src/synth/netlists.ads
+++ b/src/synth/netlists.ads
@@ -320,7 +320,9 @@ private
-- Sub-module brother.
Next_Sub_Module : Module;
+ -- List of instances.
-- The self instance is the first instance.
+ -- FIXME: use an array instead ?
First_Instance : Instance;
Last_Instance : Instance;
end record;
@@ -337,6 +339,9 @@ private
type Instance_Record is record
-- The instance is instantiated in Parent.
Parent : Module;
+
+ -- Instances are in a doubly-linked list.
+ Prev_Instance : Instance;
Next_Instance : Instance;
-- For a self-instance, Klass is equal to Parent, and Name is No_Sname.
@@ -348,6 +353,9 @@ private
First_Output : Net;
end record;
+ procedure Set_Next_Instance (Inst : Instance; Next : Instance);
+ procedure Set_Prev_Instance (Inst : Instance; Prev : Instance);
+
-- Procedures to rewrite the list of instances of a module:
-- * first extract the chain of instances from module M (and reset the
-- list of instances - so there is none),
@@ -356,6 +364,11 @@ private
procedure Extract_All_Instances (M : Module; First_Instance : out Instance);
procedure Append_Instance (M : Module; Inst : Instance);
+ -- Extract INST from the list of instance of its module.
+ -- Will still be connected, but won't appear anymore in the list of
+ -- instances.
+ procedure Extract_Instance (Inst : Instance);
+
type Input is new Uns32;
No_Input : constant Input := 0;
diff --git a/src/synth/synth-insts.adb b/src/synth/synth-insts.adb
index f2d67b4d7..c636cc497 100644
--- a/src/synth/synth-insts.adb
+++ b/src/synth/synth-insts.adb
@@ -27,7 +27,7 @@ with Std_Names;
with Netlists; use Netlists;
with Netlists.Builders;
-with Netlists.Utils;
+with Netlists.Cleanup;
with Vhdl.Utils; use Vhdl.Utils;
with Vhdl.Errors;
@@ -916,7 +916,7 @@ package body Synth.Insts is
-- a correctness point: there might be some unsynthesizable gates, like
-- the one created for 'rising_egde (clk) and not rst'.
if not Flags.Flag_Debug_Nocleanup then
- Netlists.Utils.Remove_Unused_Instances
+ Netlists.Cleanup.Remove_Unconnected_Instances
(Get_Instance_Module (Syn_Inst));
end if;
end Synth_Instance;