aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorTristan Gingold <tgingold@free.fr>2019-10-18 04:55:52 +0200
committerTristan Gingold <tgingold@free.fr>2019-10-18 04:55:52 +0200
commit2e9ae6e443604c796723ba9a43ad9c73354703b8 (patch)
tree940d63a82bef604f7aad02f2494e4e776505c1ef /src
parent4111f66412d430e6770fb698870b3d0c3d1dd04f (diff)
downloadghdl-2e9ae6e443604c796723ba9a43ad9c73354703b8.tar.gz
ghdl-2e9ae6e443604c796723ba9a43ad9c73354703b8.tar.bz2
ghdl-2e9ae6e443604c796723ba9a43ad9c73354703b8.zip
netlists-memories: check ports.
Diffstat (limited to 'src')
-rw-r--r--src/synth/netlists-memories.adb168
1 files changed, 161 insertions, 7 deletions
diff --git a/src/synth/netlists-memories.adb b/src/synth/netlists-memories.adb
index beeb76444..590171f49 100644
--- a/src/synth/netlists-memories.adb
+++ b/src/synth/netlists-memories.adb
@@ -18,6 +18,8 @@
-- Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston,
-- MA 02110-1301, USA.
+with Errorout; use Errorout;
+
with Netlists.Gates; use Netlists.Gates;
with Netlists.Utils; use Netlists.Utils;
with Netlists.Locations; use Netlists.Locations;
@@ -40,6 +42,148 @@ package body Netlists.Memories is
end case;
end Is_A_Memory;
+ -- Follow signal from ORIG to discover memory ports size.
+ -- Should be the same.
+ procedure Check_Memory_Ports (Orig : Instance;
+ Data_W : out Width;
+ Size : out Width)
+ is
+ Orig_Net : constant Net := Get_Output (Orig, 0);
+ Orig_Loc : constant Location_Type := Get_Location (Orig);
+ Mem_Sz : Width;
+ W : Width;
+ Dff : Net;
+ Dff_Inst : Instance;
+ Data : Net;
+ Data_Inst : Instance;
+ Data_Inp : Input;
+ begin
+ -- By default, error.
+ Data_W := 0;
+ Size := 0;
+
+ -- The memory must come from signal/isignal.
+ case Get_Id (Orig) is
+ when Id_Isignal
+ | Id_Signal =>
+ null;
+ when others =>
+ raise Internal_Error;
+ end case;
+
+ -- The driver of the signal must be a dff/idff.
+ Dff := Get_Input_Net (Orig, 0);
+ Dff_Inst := Get_Net_Parent (Dff);
+
+ case Get_Id (Dff_Inst) is
+ when Id_Idff
+ | Id_Dff =>
+ Mem_Sz := Get_Width (Dff);
+ when others =>
+ Warning_Msg_Synth
+ (Orig_Loc,
+ "write to memory %n is not synchronous", (1 => +Orig));
+ return;
+ end case;
+
+ -- Check write ports.
+ Data_Inp := Get_Input (Dff_Inst, 1);
+ Data := Get_Driver (Data_Inp);
+ loop
+ Data_Inst := Get_Net_Parent (Data);
+
+ -- Skip muxes (that's enables).
+ while Get_Id (Data_Inst) = Id_Mux2 loop
+ declare
+ I0_Inp : constant Input := Get_Input (Data_Inst, 1);
+ I1_Inp : constant Input := Get_Input (Data_Inst, 2);
+ begin
+ if Get_Driver (I0_Inp) = Orig_Net then
+ Data := Get_Driver (I1_Inp);
+ elsif Get_Driver (I1_Inp) = Orig_Net then
+ Data := Get_Driver (I0_Inp);
+ else
+ raise Internal_Error;
+ end if;
+ Data_Inst := Get_Net_Parent (Data);
+ end;
+ end loop;
+
+ if Get_Id (Data_Inst) = Id_Dyn_Insert then
+ -- Write port.
+ W := Get_Width (Get_Input_Net (Data_Inst, 1));
+ if Data_W = 0 then
+ Data_W := W;
+ elsif Data_W /= W then
+ -- Different size.
+ Warning_Msg_Synth (Get_Location (Data_Inst),
+ "write to memory %n with different size",
+ (1 => +Orig));
+ Data_W := 0;
+ return;
+ end if;
+
+ Data := Get_Input_Net (Data_Inst, 0);
+ elsif Data = Orig_Net then
+ exit;
+ else
+ Warning_Msg_Synth (Get_Location (Data_Inst),
+ "full write to memory %n", (1 => +Orig));
+ Data_W := 0;
+ return;
+ end if;
+ end loop;
+
+ -- Check readers.
+ declare
+ Inp : Input;
+ Extr_Inst : Instance;
+ begin
+ Inp := Get_First_Sink (Orig_Net);
+ while Inp /= No_Input loop
+ Extr_Inst := Get_Input_Parent (Inp);
+ case Get_Id (Extr_Inst) is
+ when Id_Dyn_Extract =>
+ -- Check offset
+ if Get_Param_Uns32 (Extr_Inst, 0) /= 0 then
+ Warning_Msg_Synth (Get_Location (Extr_Inst),
+ "partial read from memory %n",
+ (1 => +Orig));
+ Data_W := 0;
+ return;
+ end if;
+ -- Check data width.
+ W := Get_Width (Get_Output (Extr_Inst, 0));
+ if Data_W = 0 then
+ Data_W := W;
+ elsif Data_W /= W then
+ Warning_Msg_Synth
+ (Get_Location (Extr_Inst),
+ "read from memory %n with different size",
+ (1 => +Orig));
+ Data_W := 0;
+ return;
+ end if;
+ when Id_Dyn_Insert
+ | Id_Mux2 =>
+ -- Probably a writer.
+ -- FIXME: check it has already been seen above.
+ null;
+ when others =>
+ Warning_Msg_Synth
+ (Get_Location (Extr_Inst),
+ "full read from memory %n", (1 => +Orig));
+ Data_W := 0;
+ return;
+ end case;
+
+ Inp := Get_Next_Sink (Inp);
+ end loop;
+ end;
+
+ Size := Mem_Sz / Data_W;
+ end Check_Memory_Ports;
+
-- Count the number of memidx in a memory address.
function Count_Memidx (Addr : Net) return Natural
is
@@ -220,7 +364,6 @@ package body Netlists.Memories is
procedure Replace_RAM_Memory (Ctxt : Context_Acc; Orig : Instance)
is
Orig_Net : constant Net := Get_Output (Orig, 0);
- Orig_Loc : constant Location_Type := Get_Location (Orig);
Dff : Net;
Dff_Inst : Instance;
En : Net;
@@ -229,8 +372,6 @@ package body Netlists.Memories is
Last : Net;
Data_Inp : Input;
begin
- Warning_Msg_Synth (Orig_Loc, "found memory for %n", (1 => +Orig));
-
-- The memory must come from signal/isignal.
case Get_Id (Orig) is
when Id_Isignal
@@ -246,6 +387,8 @@ package body Netlists.Memories is
case Get_Id (Dff_Inst) is
when Id_Idff =>
+ -- Disconnect the init input to isignal.
+ Disconnect (Get_Input (Orig, 1));
declare
Init_Inp : constant Input := Get_Input (Dff_Inst, 2);
Init_Net : constant Net := Get_Driver (Init_Inp);
@@ -426,7 +569,7 @@ package body Netlists.Memories is
Inst := Get_First_Instance (M);
while Inst /= No_Instance loop
- -- Walk all the instances of M:
+ -- Walk all the instances of M:
case Get_Id (Inst) is
when Id_Dyn_Insert =>
-- * For dyn_insert gates:
@@ -490,9 +633,20 @@ package body Netlists.Memories is
for I in First_Index .. Inst_Interning.Last_Index (Memories) loop
-- INST is the memorizing instance, ie isignal/signal.
Inst := Get_By_Index (Memories, I);
- if Get_Id (Inst) /= Id_Const_Bit then
- Replace_RAM_Memory (Ctxt, Inst);
- end if;
+ declare
+ Data_W : Width;
+ Size : Width;
+ begin
+ Check_Memory_Ports (Inst, Data_W, Size);
+ if Data_W /= 0 then
+ Warning_Msg_Synth (Get_Location (Inst),
+ "found memory %n, width: %v bits, depth: %v",
+ (1 => +Inst, 2 => +Data_W, 3 => +Size));
+ if Get_Id (Inst) /= Id_Const_Bit then
+ Replace_RAM_Memory (Ctxt, Inst);
+ end if;
+ end if;
+ end;
end loop;
Inst_Interning.Free (Memories);