From bc10b035f5998d1cc9ec2aa0122ee1c24099ca05 Mon Sep 17 00:00:00 2001 From: Tristan Gingold Date: Mon, 30 Jan 2017 21:09:19 +0100 Subject: Add netlist generation infrastructure. --- src/synth/netlists-dump.adb | 489 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 489 insertions(+) create mode 100644 src/synth/netlists-dump.adb (limited to 'src/synth/netlists-dump.adb') diff --git a/src/synth/netlists-dump.adb b/src/synth/netlists-dump.adb new file mode 100644 index 000000000..7db8f850e --- /dev/null +++ b/src/synth/netlists-dump.adb @@ -0,0 +1,489 @@ +-- Routine to dump (for debugging purpose) a netlist. +-- Copyright (C) 2017 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 Ada.Text_IO; use Ada.Text_IO; +with Name_Table; +with Netlists.Utils; use Netlists.Utils; +with Netlists.Iterators; use Netlists.Iterators; +with Netlists.Gates; use Netlists.Gates; + +package body Netlists.Dump is + procedure Put_Indent (Indent : Natural) is + begin + Put (String'(1 .. Indent * 2 => ' ')); + end Put_Indent; + + -- Like Put, but without the leading space (if any). + procedure Put_Trim (S : String) is + begin + if S'First <= S'Last and then S (S'First) = ' ' then + Put (S (S'First + 1 .. S'Last)); + else + Put (S); + end if; + end Put_Trim; + + procedure Dump_Name (N : Sname) + is + use Name_Table; + Prefix : Sname; + begin + -- Do not crash on No_Name. + if N = No_Sname then + Put ("*nil*"); + return; + end if; + + Prefix := Get_Sname_Prefix (N); + + case Get_Sname_Kind (N) is + when Sname_User => + if Prefix = No_Sname then + Put ("\"); + else + Dump_Name (Prefix); + Put ("."); + end if; + Put (Image (Get_Sname_Suffix (N))); + when Sname_Artificial => + if Prefix = No_Sname then + Put ("$"); + else + Dump_Name (Prefix); + Put ("."); + end if; + Put (Image (Get_Sname_Suffix (N))); + when Sname_Version => + Dump_Name (Prefix); + Put ("%"); + Put_Trim (Uns32'Image (Get_Sname_Version (N))); + end case; + end Dump_Name; + + procedure Dump_Input_Name (I : Input; With_Id : Boolean := False) + is + Inst : constant Instance := Get_Parent (I); + Idx : constant Port_Idx := Get_Port_Idx (I); + begin + Dump_Name (Get_Name (Inst)); + Put ('.'); + if Is_Self_Instance (Inst) then + Dump_Name (Get_Output_Desc (Get_Module (Inst), Idx).Name); + else + Dump_Name (Get_Input_Desc (Get_Module (Inst), Idx).Name); + end if; + if With_Id then + Put ('('); + Put_Trim (Input'Image (I)); + Put (')'); + end if; + end Dump_Input_Name; + + procedure Dump_Net_Name (N : Net; With_Id : Boolean := False) + is + Inst : constant Instance := Get_Parent (N); + Idx : constant Port_Idx := Get_Port_Idx (N); + begin + Dump_Name (Get_Name (Inst)); + Put ('.'); + if Is_Self_Instance (Inst) then + Dump_Name (Get_Input_Desc (Get_Module (Inst), Idx).Name); + else + Dump_Name (Get_Output_Desc (Get_Module (Inst), Idx).Name); + end if; + if With_Id then + Put ('('); + Put_Trim (Net'Image (N)); + Put (')'); + end if; + end Dump_Net_Name; + + procedure Dump_Parameter (Inst : Instance; Idx : Param_Idx) + is + Desc : constant Param_Desc := Get_Param_Desc (Inst, Idx); + begin + Dump_Name (Desc.Name); + Put ('='); + case Desc.Typ is + when Param_Invalid => + Put ("invalid"); + when Param_Uns32 => + Put_Trim (Uns32'Image (Get_Param_Uns32 (Inst, Idx))); + end case; + end Dump_Parameter; + + procedure Dump_Instance (Inst : Instance; Indent : Natural := 0) is + begin + Put_Indent (Indent); + Put ("instance "); + Dump_Name (Get_Name (Inst)); + Put (" ("); + Put_Trim (Instance'Image (Inst)); + Put (')'); + Put (": "); + Dump_Name (Get_Name (Get_Module (Inst))); + New_Line; + + if Get_Nbr_Params (Inst) > 0 then + Put_Indent (Indent + 1); + Put ("parameters"); + for P in Params (Inst) loop + pragma Warnings (Off, P); + Put (' '); + Dump_Parameter (Inst, Get_Param_Idx (P)); + end loop; + New_Line; + end if; + + if Get_Nbr_Inputs (Inst) > 0 then + Put_Indent (Indent + 1); + Put ("inputs"); + for I of Inputs (Inst) loop + Put (' '); + Dump_Input_Name (I, True); + end loop; + New_Line; + end if; + + if Get_Nbr_Outputs (Inst) > 0 then + Put_Indent (Indent + 1); + Put ("outputs"); + for I of Outputs (Inst) loop + Put (' '); + Dump_Net_Name (I, True); + end loop; + New_Line; + end if; + end Dump_Instance; + + procedure Disp_Width (W : Width) is + begin + if W /= 1 then + Put ('['); + if W = 0 then + Put ('?'); + else + Put_Trim (Width'Image (W - 1)); + Put (":0"); + end if; + Put (']'); + end if; + end Disp_Width; + + procedure Dump_Module_Header (M : Module; Indent : Natural := 0) is + begin + Put_Indent (Indent); + Put ("module ("); + Put_Trim (Module'Image (M)); + Put (") "); + Dump_Name (Get_Name (M)); + New_Line; + + for P of Params_Desc (M) loop + Put_Indent (Indent + 1); + Put ("parameter"); + Put (' '); + Dump_Name (P.Name); + Put (": "); + case P.Typ is + when Param_Invalid => + Put ("invalid"); + when Param_Uns32 => + Put ("uns32"); + end case; + New_Line; + end loop; + + for P of Ports_Desc (M) loop + Put_Indent (Indent + 1); + case P.Dir is + when Port_In => + Put ("input"); + when Port_Out => + Put ("output"); + when Port_Inout => + Put ("inout"); + end case; + Put (' '); + Dump_Name (P.Name); + Disp_Width (P.W); + Put (';'); + New_Line; + end loop; + end Dump_Module_Header; + + procedure Dump_Module (M : Module; Indent : Natural := 0) is + begin + Dump_Module_Header (M, Indent); + + for S of Sub_Modules (M) loop + Dump_Module (S, Indent + 1); + end loop; + + declare + Self : constant Instance := Get_Self_Instance (M); + begin + if Self /= No_Instance then + Dump_Instance (Self, Indent + 1); + end if; + end; + + for Inst of Instances (M) loop + Dump_Instance (Inst, Indent + 1); + end loop; + + for N of Nets (M) loop + Put_Indent (Indent + 1); + Put ("connect "); + Dump_Net_Name (N, True); + + declare + First : Boolean; + begin + First := True; + for S of Sinks (N) loop + if First then + Put (" -> "); + First := False; + else + Put (", "); + end if; + Dump_Input_Name (S, True); + end loop; + end; + New_Line; + end loop; + end Dump_Module; + + procedure Disp_Net_Name (N : Net) is + begin + if N = No_Net then + Put ("?"); + else + declare + Inst : constant Instance := Get_Parent (N); + Idx : constant Port_Idx := Get_Port_Idx (N); + begin + if Is_Self_Instance (Inst) then + Dump_Name (Get_Input_Desc (Get_Module (Inst), Idx).Name); + else + Dump_Name (Get_Name (Inst)); + Put ('.'); + Dump_Name (Get_Output_Desc (Get_Module (Inst), Idx).Name); + end if; + end; + end if; + end Disp_Net_Name; + + procedure Dump_Net_Name_And_Width (N : Net) is + begin + if N = No_Net then + Put ("?"); + else + Disp_Net_Name (N); + Disp_Width (Get_Width (N)); + end if; + end Dump_Net_Name_And_Width; + + Flag_Disp_Inline : constant Boolean := True; + + function Can_Inline (Inst : Instance) return Boolean is + begin + case Get_Id (Inst) is + when Id_Signal + | Id_Output => + return False; + when others => + return not Is_Self_Instance (Inst) + and then Get_Nbr_Outputs (Inst) = 1 + and then Has_One_Connection (Get_Output (Inst, 0)); + end case; + end Can_Inline; + + procedure Disp_Driver (Drv : Net) + is + Drv_Inst : Instance; + begin + if Drv = No_Net then + Put ('?'); + else + Drv_Inst := Get_Parent (Drv); + if Flag_Disp_Inline and then Can_Inline (Drv_Inst) then + Disp_Instance (Drv_Inst, False); + else + Disp_Net_Name (Drv); + end if; + end if; + end Disp_Driver; + + -- Debug routine: disp net driver + procedure Debug_Net (N : Net) is + begin + if N = No_Net then + Put ('?'); + else + Disp_Instance (Get_Parent (N), False); + end if; + New_Line; + end Debug_Net; + + pragma Unreferenced (Debug_Net); + + procedure Disp_Instance (Inst : Instance; With_Name : Boolean) + is + M : constant Module := Get_Module (Inst); + begin + if True then + -- Pretty-print for some gates + case Get_Id (M) is + when Id_Const_UB32 => + declare + W : constant Width := Get_Width (Get_Output (Inst, 0)); + V : Uns32; + begin + Put_Trim (Width'Image (W)); + Put ("'ub"); + V := Get_Param_Uns32 (Inst, 0); + for I in reverse 0 .. W - 1 loop + if (Shift_Right (V, Natural (I)) and 1) = 0 then + Put ('0'); + else + Put ('1'); + end if; + end loop; + end; + return; + + when Id_Extract => + Disp_Driver (Get_Driver (Get_Input (Inst, 0))); + Put ('['); + Put_Trim (Uns32'Image (Get_Param_Uns32 (Inst, 0))); + Put (']'); + return; + + when others => + null; + end case; + end if; + + Dump_Name (Get_Name (M)); + + if Get_Nbr_Params (M) > 0 then + declare + First : Boolean; + begin + First := True; + Put (" #("); + for P in Params (Inst) loop + pragma Warnings (Off, P); + if not First then + Put (", "); + end if; + First := False; + Dump_Parameter (Inst, Get_Param_Idx (P)); + end loop; + Put (")"); + end; + end if; + + if With_Name then + Put (' '); + Dump_Name (Get_Name (Inst)); + end if; + + if Get_Nbr_Inputs (M) > 0 then + declare + First : Boolean; + begin + First := True; + Put (" ("); + for I of Inputs (Inst) loop + if not First then + Put (", "); + end if; + First := False; + Disp_Driver (Get_Driver (I)); + end loop; + Put (')'); + end; + end if; + end Disp_Instance; + + procedure Disp_Instance_Assign (Inst : Instance; Indent : Natural := 0) is + begin + Put_Indent (Indent); + case Get_Nbr_Outputs (Inst) is + when 0 => + null; + when 1 => + Dump_Net_Name_And_Width (Get_Output (Inst, 0)); + Put (" := "); + when others => + declare + First : Boolean; + begin + First := True; + Put ('('); + for O of Outputs (Inst) loop + if not First then + Put (", "); + end if; + First := False; + Dump_Net_Name_And_Width (O); + end loop; + Put (") := "); + end; + end case; + + Disp_Instance (Inst, False); + New_Line; + end Disp_Instance_Assign; + + procedure Disp_Module (M : Module; Indent : Natural := 0) is + begin + Dump_Module_Header (M, Indent); + + for S of Sub_Modules (M) loop + if Get_Id (S) >= Id_User_None then + Disp_Module (S, Indent + 1); + end if; + end loop; + + for Inst of Instances (M) loop + if not (Flag_Disp_Inline and then Can_Inline (Inst)) then + Disp_Instance_Assign (Inst, Indent + 1); + end if; + end loop; + + declare + Self : constant Instance := Get_Self_Instance (M); + begin + if Self /= No_Instance then + for I of Inputs (Self) loop + Put_Indent (Indent + 1); + Dump_Name (Get_Output_Desc (M, Get_Port_Idx (I)).Name); + Put (" := "); + Disp_Net_Name (Get_Driver (I)); + New_Line; + end loop; + end if; + end; + end Disp_Module; +end Netlists.Dump; -- cgit v1.2.3