diff options
Diffstat (limited to 'src/simul/simul-vhdl_simul.adb')
-rw-r--r-- | src/simul/simul-vhdl_simul.adb | 1992 |
1 files changed, 1992 insertions, 0 deletions
diff --git a/src/simul/simul-vhdl_simul.adb b/src/simul/simul-vhdl_simul.adb new file mode 100644 index 000000000..5ae5a8c1b --- /dev/null +++ b/src/simul/simul-vhdl_simul.adb @@ -0,0 +1,1992 @@ +-- Simulation of VHDL +-- Copyright (C) 2022 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, see <gnu.org/licenses>. + +with System; +with Ada.Unchecked_Conversion; + +with Simple_IO; +with Utils_IO; + +with Vhdl.Errors; +with Vhdl.Sem_Inst; +with Vhdl.Canon; + +with Elab.Vhdl_Objtypes; use Elab.Vhdl_Objtypes; +with Elab.Vhdl_Values; use Elab.Vhdl_Values; +with Elab.Vhdl_Decls; +with Elab.Debugger; + +with Trans_Analyzes; + +with Synth.Errors; +with Synth.Vhdl_Stmts; use Synth.Vhdl_Stmts; +with Synth.Vhdl_Expr; +with Synth.Vhdl_Oper; +with Synth.Vhdl_Static_Proc; +with Synth.Flags; +with Synth.Ieee.Std_Logic_1164; use Synth.Ieee.Std_Logic_1164; + +with Grt.Types; use Grt.Types; +with Grt.Signals; use Grt.Signals; +with Grt.Options; +with Grt.Stdio; +with Grt.Processes; +with Grt.Main; +with Grt.Errors; +with Grt.Lib; +with Grt.Analog_Solver; + +package body Simul.Vhdl_Simul is + function To_Instance_Acc is new Ada.Unchecked_Conversion + (System.Address, Grt.Processes.Instance_Acc); + + procedure Process_Executer (Self : Grt.Processes.Instance_Acc); + pragma Convention (C, Process_Executer); + + type Ghdl_Signal_Ptr_Ptr is access all Ghdl_Signal_Ptr; + function To_Ghdl_Signal_Ptr_Ptr is + new Ada.Unchecked_Conversion (Memory_Ptr, Ghdl_Signal_Ptr_Ptr); + + Sig_Size : constant Size_Type := Ghdl_Signal_Ptr'Size / 8; + + subtype F64_C_Arr_Ptr is Grt.Analog_Solver.F64_C_Arr_Ptr; + + procedure Residues (T : Ghdl_F64; + Y : F64_C_Arr_Ptr; + Yp : F64_C_Arr_Ptr; + Res : F64_C_Arr_Ptr); + pragma Export (C, Residues, "grt__analog_solver__residues"); + + procedure Set_Quantities_Values (Y : F64_C_Arr_Ptr; Yp: F64_C_Arr_Ptr); + pragma Export (C, Set_Quantities_Values, "grt__analog_solver__set_values"); + + function Sig_Index (Base : Memory_Ptr; Idx : Uns32) return Memory_Ptr is + begin + return Base + Size_Type (Idx) * Sig_Size; + end Sig_Index; + + procedure Write_Sig (Mem : Memory_Ptr; Val : Ghdl_Signal_Ptr) is + begin + To_Ghdl_Signal_Ptr_Ptr (Mem).all := Val; + end Write_Sig; + + function Read_Sig (Mem : Memory_Ptr) return Ghdl_Signal_Ptr is + begin + return To_Ghdl_Signal_Ptr_Ptr (Mem).all; + end Read_Sig; + + function Exec_Sig_Sig (Val : Value_Acc) return Memory_Ptr + is + E : Signal_Entry renames Signals_Table.Table (Val.S); + begin + return E.Sig; + end Exec_Sig_Sig; + + function Hook_Signal_Expr (Val : Valtyp) return Valtyp is + begin + if Val.Val.Kind = Value_Alias then + declare + E : Signal_Entry renames Signals_Table.Table (Val.Val.A_Obj.S); + begin + return Create_Value_Memtyp + ((Val.Typ, E.Val + Val.Val.A_Off.Mem_Off)); + end; + else + declare + E : Signal_Entry renames Signals_Table.Table (Val.Val.S); + begin + return Create_Value_Memtyp ((E.Typ, E.Val)); + end; + end if; + end Hook_Signal_Expr; + + function Hook_Quantity_Expr (Val : Valtyp) return Valtyp is + begin + if Val.Val.Kind = Value_Alias then + declare + E : Quantity_Entry renames Quantity_Table.Table (Val.Val.A_Obj.Q); + begin + return Create_Value_Memtyp + ((Val.Typ, E.Val + Val.Val.A_Off.Mem_Off)); + end; + else + declare + E : Quantity_Entry renames Quantity_Table.Table (Val.Val.Q); + begin + return Create_Value_Memtyp ((E.Typ, E.Val)); + end; + end if; + end Hook_Quantity_Expr; + + procedure Disp_Iir_Location (N : Iir) + is + use Simple_IO; + begin + if N = Null_Iir then + Put_Err ("??:??:??"); + else + Put_Err (Vhdl.Errors.Disp_Location (N)); + end if; + Put_Err (": "); + end Disp_Iir_Location; + + + procedure Error_Msg_Exec (Loc : Iir; Msg : String) + is + use Simple_IO; + begin + Disp_Iir_Location (Loc); + Put_Line_Err (Msg); + Grt.Errors.Fatal_Error; + end Error_Msg_Exec; + + procedure Start_Assign_Value_To_Signal (Target: Memtyp; + Rej : Std_Time; + After : Std_Time; + Val : Memtyp) is + begin + case Target.Typ.Kind is + when Type_Logic + | Type_Bit => + Ghdl_Signal_Start_Assign_E8 + (Read_Sig (Target.Mem), Rej, Read_U8 (Val), After); + when Type_Discrete => + if Target.Typ.Sz = 1 then + Ghdl_Signal_Start_Assign_E8 + (Read_Sig (Target.Mem), Rej, Read_U8 (Val), After); + elsif Target.Typ.Sz = 4 then + Ghdl_Signal_Start_Assign_I32 + (Read_Sig (Target.Mem), Rej, Read_I32 (Val.Mem), After); + elsif Target.Typ.Sz = 8 then + Ghdl_Signal_Start_Assign_I64 + (Read_Sig (Target.Mem), Rej, Read_I64 (Val.Mem), After); + else + raise Internal_Error; + end if; + when Type_Vector + | Type_Array => + declare + Len : constant Uns32 := Target.Typ.Abound.Len; + El : constant Type_Acc := Target.Typ.Arr_El; + begin + pragma Assert (Val.Typ.Abound.Len = Len); + for I in 1 .. Len loop + Start_Assign_Value_To_Signal + ((El, Sig_Index (Target.Mem, (Len - I) * El.W)), + Rej, After, + (Val.Typ.Arr_El, Val.Mem + Size_Type (I - 1) * El.Sz)); + end loop; + end; + when Type_Record => + for I in Val.Typ.Rec.E'Range loop + declare + E : Rec_El_Type renames Val.Typ.Rec.E (I); + begin + Start_Assign_Value_To_Signal + ((E.Typ, Sig_Index (Target.Mem, E.Offs.Net_Off)), + Rej, After, + (E.Typ, Val.Mem + E.Offs.Mem_Off)); + end; + end loop; + when others => + raise Internal_Error; + end case; + end Start_Assign_Value_To_Signal; + + procedure Add_Source (Typ : Type_Acc; Sig : Memory_Ptr; Val : Memory_Ptr) is + begin + case Typ.Kind is + when Type_Logic + | Type_Bit => + Grt.Signals.Ghdl_Signal_Add_Port_Driver_E8 + (Read_Sig (Sig), Read_U8 (Val)); + when Type_Discrete => + if Typ.Sz = 1 then + Grt.Signals.Ghdl_Signal_Add_Port_Driver_E8 + (Read_Sig (Sig), Read_U8 (Val)); + elsif Typ.Sz = 4 then + Grt.Signals.Ghdl_Signal_Add_Port_Driver_I32 + (Read_Sig (Sig), Read_I32 (Val)); + elsif Typ.Sz = 8 then + Grt.Signals.Ghdl_Signal_Add_Port_Driver_I64 + (Read_Sig (Sig), Read_I64 (Val)); + else + raise Internal_Error; + end if; + when Type_Vector + | Type_Array => + declare + Len : constant Uns32 := Typ.Abound.Len; + begin + for I in 1 .. Len loop + Add_Source (Typ.Arr_El, + Sig_Index (Sig, (Len - I) * Typ.Arr_El.W), + Val + Size_Type (I - 1) * Typ.Arr_El.Sz); + end loop; + end; + when Type_Record => + for I in Typ.Rec.E'Range loop + Add_Source (Typ.Rec.E (I).Typ, + Sig_Index (Sig, Typ.Rec.E (I).Offs.Net_Off), + Val + Typ.Rec.E (I).Offs.Mem_Off); + end loop; + when others => + raise Internal_Error; + end case; + end Add_Source; + + procedure Create_Process_Drivers (Inst : Synth_Instance_Acc; + Proc : Node; + Driver_List : Iir_List) + is + pragma Unreferenced (Proc); + It : List_Iterator; + El: Iir; + Info : Target_Info; + begin + -- Some processes have no driver list (assertion). + It := List_Iterate_Safe (Driver_List); + while Is_Valid (It) loop + El := Get_Element (It); + + -- Mark (Marker, Expr_Pool); + Info := Synth_Target (Inst, El); + declare + E : Signal_Entry renames Signals_Table.Table (Info.Obj.Val.S); + begin + Add_Source (Info.Targ_Type, + Sig_Index (E.Sig, Info.Off.Net_Off), + E.Val + Info.Off.Mem_Off); + end; + + -- Release (Marker, Expr_Pool); + + Next (It); + end loop; + end Create_Process_Drivers; + + procedure Create_Process_Drivers (Proc : Process_Index_Type) + is + Drv : Driver_Index_Type; + begin + Drv := Processes_Table.Table (Proc).Drivers; + while Drv /= No_Driver_Index loop + declare + D : Driver_Entry renames Drivers_Table.Table (Drv); + S : Signal_Entry renames Signals_Table.Table (D.Sig); + begin + pragma Assert (D.Off = No_Value_Offsets); + Add_Source (S.Typ, S.Sig, S.Val); + + Drv := D.Prev_Proc; + end; + end loop; + end Create_Process_Drivers; + + function Exec_Event_Attribute (Sig : Memtyp) return Boolean is + begin + case Sig.Typ.Kind is + when Type_Logic + | Type_Bit + | Type_Discrete => + return Read_Sig (Sig.Mem).Event; + when others => + raise Internal_Error; + return False; + end case; + end Exec_Event_Attribute; + + function Exec_Event_Attribute (Inst : Synth_Instance_Acc; + Expr : Node) return Valtyp + is + Res : Valtyp; + Pfx : Target_Info; + E : Boolean; + begin + Pfx := Synth_Target (Inst, Get_Prefix (Expr)); + pragma Assert (Pfx.Kind = Target_Simple); + -- TODO: alias. + pragma Assert (Pfx.Obj.Val /= null + and then Pfx.Obj.Val.Kind = Value_Signal); + E := Exec_Event_Attribute + ((Pfx.Targ_Type, + Sig_Index (Signals_Table.Table (Pfx.Obj.Val.S).Sig, + Pfx.Off.Net_Off))); + Res := Create_Value_Memory (Boolean_Type); + Write_U8 (Res.Val.Mem, Boolean'Pos (E)); + return Res; + end Exec_Event_Attribute; + + function Exec_Dot_Attribute (Inst : Synth_Instance_Acc; + Expr : Node) return Valtyp + is + Pfx : Target_Info; + begin + Pfx := Synth_Target (Inst, Expr); + pragma Assert (Pfx.Kind = Target_Simple); + -- TODO: alias. + pragma Assert (Pfx.Obj.Val /= null + and then Pfx.Obj.Val.Kind = Value_Quantity); + return Hook_Quantity_Expr (Pfx.Obj); + end Exec_Dot_Attribute; + + procedure Execute_Sequential_Statements (Process : Process_State_Acc); + + function Execute_Condition (Inst : Synth_Instance_Acc; + Cond : Node) return Boolean + is + Cond_Val : Valtyp; + begin + if Cond = Null_Node then + return True; + end if; + Cond_Val := Synth.Vhdl_Expr.Synth_Expression (Inst, Cond); + return Read_Discrete (Cond_Val) = 1; + end Execute_Condition; + + function Get_Suspend_State_Var (Inst : Synth_Instance_Acc) return Memory_Ptr + is + Src : Node; + Var : Node; + State_Mem : Memory_Ptr; + begin + Src := Get_Source_Scope (Inst); + Var := Get_Declaration_Chain (Src); + pragma Assert (Var /= Null_Node); + pragma Assert (Get_Kind (Var) = Iir_Kind_Suspend_State_Declaration); + State_Mem := Get_Value (Inst, Var).Val.Mem; + return State_Mem; + end Get_Suspend_State_Var; + + -- Return the statement STMT corresponding to the current state from INST. + procedure Get_Suspend_State_Statement + (Inst : Synth_Instance_Acc; Stmt : out Node; Resume : out Boolean) + is + Src : Node; + Var : Node; + State_Mem : Memory_Ptr; + State : Int32; + begin + State_Mem := Get_Suspend_State_Var (Inst); + State := Int32 (Read_I32 (State_Mem)); + Src := Get_Source_Scope (Inst); + if State = 0 then + Stmt := Get_Sequential_Statement_Chain (Src); + Resume := False; + else + Var := Get_Declaration_Chain (Src); + Stmt := Get_Suspend_State_Chain (Var); + loop + pragma Assert (Stmt /= Null_Node); + exit when Get_Suspend_State_Index (Stmt) = State; + Stmt := Get_Suspend_State_Chain (Stmt); + end loop; + Resume := True; + end if; + end Get_Suspend_State_Statement; + + procedure Finish_Procedure_Call (Process : Process_State_Acc; + Bod : Node; + Stmt : out Node) + is + Imp : constant Node := Get_Subprogram_Specification (Bod); + Caller_Inst : constant Synth_Instance_Acc := + Get_Caller_Instance (Process.Instance); + Resume : Boolean; + begin + if not Get_Suspend_Flag (Bod) then + Process.Instance := Caller_Inst; + -- TODO: free old inst. + Stmt := Null_Node; + return; + end if; + Get_Suspend_State_Statement (Caller_Inst, Stmt, Resume); + pragma Assert (Resume); + -- Skip the resume statement. + Stmt := Get_Chain (Stmt); + pragma Assert (Get_Kind (Stmt) = Iir_Kind_Procedure_Call_Statement); + Synth_Subprogram_Back_Association + (Process.Instance, Caller_Inst, + Get_Interface_Declaration_Chain (Imp), + Get_Parameter_Association_Chain + (Get_Procedure_Call (Stmt))); + Process.Instance := Caller_Inst; + -- TODO: free old inst. + end Finish_Procedure_Call; + + procedure Next_Parent_Statement (Process : Process_State_Acc; + First_Parent : Node; + Stmt : out Node) + is + N_Stmt : Node; + Parent : Node; + begin + Parent := First_Parent; + loop + case Get_Kind (Parent) is + when Iir_Kind_Sensitized_Process_Statement => + Stmt := Null_Node; + return; + when Iir_Kind_Process_Statement => + Stmt := Get_Sequential_Statement_Chain (Parent); + return; + when Iir_Kind_If_Statement + | Iir_Kind_Case_Statement => + Stmt := Parent; + when Iir_Kind_For_Loop_Statement => + declare + Param : constant Node := + Get_Parameter_Specification (Parent); + Val : Valtyp; + begin + -- Update index + Val := Get_Value (Process.Instance, Param); + Update_Index (Val.Typ.Drange, Val); + + -- Test. + if Elab.Vhdl_Objtypes.In_Range (Val.Typ.Drange, + Read_Discrete (Val)) + then + Stmt := Get_Sequential_Statement_Chain (Parent); + return; + end if; + + -- End of loop. + Synth.Vhdl_Stmts.Finish_For_Loop_Statement + (Process.Instance, Parent); + Stmt := Parent; + end; + when Iir_Kind_While_Loop_Statement => + if Execute_Condition (Process.Instance, Get_Condition (Parent)) + then + Stmt := Get_Sequential_Statement_Chain (Parent); + return; + else + Stmt := Parent; + end if; + when Iir_Kind_Procedure_Body => + Finish_Procedure_Call (Process, Parent, Stmt); + exit when Stmt = Null_Node; + when others => + Vhdl.Errors.Error_Kind ("next_statement", Parent); + end case; + + N_Stmt := Get_Chain (Stmt); + if N_Stmt /= Null_Node then + Stmt := N_Stmt; + return; + end if; + + Parent := Get_Parent (Stmt); + end loop; + end Next_Parent_Statement; + + procedure Next_Statement (Process : Process_State_Acc; + Stmt : in out Node) + is + N_Stmt : Node; + begin + N_Stmt := Get_Chain (Stmt); + if N_Stmt /= Null_Node then + Stmt := N_Stmt; + return; + end if; + + Next_Parent_Statement (Process, Get_Parent (Stmt), Stmt); + end Next_Statement; + + procedure Add_Wait_Sensitivity (Typ : Type_Acc; Sig : Memory_Ptr) is + begin + case Typ.Kind is + when Type_Logic + | Type_Bit + | Type_Discrete => + Grt.Processes.Ghdl_Process_Wait_Add_Sensitivity (Read_Sig (Sig)); + when Type_Vector + | Type_Array => + declare + Len : constant Uns32 := Typ.Abound.Len; + begin + for I in 1 .. Len loop + Add_Wait_Sensitivity + (Typ.Arr_El, Sig_Index (Sig, (Len - I) * Typ.Arr_El.W)); + end loop; + end; + when Type_Record => + for I in Typ.Rec.E'Range loop + Add_Wait_Sensitivity + (Typ.Rec.E (I).Typ, + Sig_Index (Sig, Typ.Rec.E (I).Offs.Net_Off)); + end loop; + when others => + raise Internal_Error; + end case; + end Add_Wait_Sensitivity; + + procedure Execute_Wait_Statement (Inst : Synth_Instance_Acc; + Stmt : Node) + is + Expr : Node; + List : Node_List; + Val : Valtyp; + Timeout : Int64; + begin + -- LRM93 8.1 + -- The execution of a wait statement causes the time expression to + -- be evaluated to determine the timeout interval. + Expr := Get_Timeout_Clause (Stmt); + if Expr /= Null_Node then + Val := Synth.Vhdl_Expr.Synth_Expression (Inst, Expr); + Timeout := Read_Discrete (Val); + if Timeout < 0 then + Error_Msg_Exec (Stmt, "negative timeout value"); + end if; + Grt.Processes.Ghdl_Process_Wait_Set_Timeout + (Std_Time (Timeout), null, 0); + end if; + + List := Get_Sensitivity_List (Stmt); + + Expr := Get_Condition_Clause (Stmt); + if Expr /= Null_Node and then List = Null_Iir_List then + List := Create_Iir_List; + Vhdl.Canon.Canon_Extract_Sensitivity_Expression (Expr, List); + Set_Sensitivity_List (Stmt, List); + Set_Is_Ref (Stmt, True); + end if; + + if List /= Null_Iir_List then + declare + It : List_Iterator; + El : Node; + Info : Target_Info; + Sig : Memory_Ptr; + begin + It := List_Iterate (List); + while Is_Valid (It) loop + El := Get_Element (It); + Info := Synth_Target (Inst, El); + Sig := Signals_Table.Table (Info.Obj.Val.S).Sig; + Add_Wait_Sensitivity + (Info.Targ_Type, Sig_Index (Sig, Info.Off.Net_Off)); + Next (It); + end loop; + end; + end if; + + -- LRM93 8.1 + -- It also causes the execution of the corresponding process + -- statement to be suspended. + Grt.Processes.Ghdl_Process_Wait_Suspend; + end Execute_Wait_Statement; + + function Resume_Wait_Statement (Inst : Synth_Instance_Acc; + Stmt : Node) return Boolean is + begin + -- LRM93 8.1 + -- The suspended process will resume, at the latest, immediately + -- after the timeout interval has expired. + if not Grt.Processes.Ghdl_Process_Wait_Timed_Out then + -- Compute the condition clause only if the timeout has not + -- expired. + + -- LRM93 8.1 + -- If such an event occurs, the condition in the condition clause + -- is evaluated. + -- + -- if no condition clause appears, the condition clause until true + -- is assumed. + if not Execute_Condition (Inst, Get_Condition_Clause (Stmt)) then + -- LRM93 8.1 + -- If the value of the condition is FALSE, the process will + -- re-suspend. + -- Such re-suspension does not involve the recalculation of + -- the timeout interval. + Grt.Processes.Ghdl_Process_Wait_Suspend; + return True; + end if; + end if; + + -- LRM93 8.1 + -- If the value of the condition is TRUE, the process will resume. + -- next statement. + Grt.Processes.Ghdl_Process_Wait_Close; + + return False; + end Resume_Wait_Statement; + + procedure Execute_Procedure_Call_Statement (Process : Process_State_Acc; + Stmt : Node; + Next_Stmt : out Node) + is + use Vhdl.Errors; + Inst : constant Synth_Instance_Acc := Process.Instance; + Call : constant Node := Get_Procedure_Call (Stmt); + Imp : constant Node := Get_Implementation (Call); + + Assoc_Chain : constant Node := Get_Parameter_Association_Chain (Call); + + Area_Mark : Areapools.Mark_Type; + Sub_Inst : Synth_Instance_Acc; + begin + Areapools.Mark (Area_Mark, Instance_Pool.all); + + if Get_Implicit_Definition (Imp) /= Iir_Predefined_None then + declare + Inter_Chain : constant Node := + Get_Interface_Declaration_Chain (Imp); + begin + Sub_Inst := Synth_Subprogram_Call_Instance (Inst, Imp, Imp); + Synth_Subprogram_Association + (Sub_Inst, Inst, Inter_Chain, Assoc_Chain); + + Synth.Vhdl_Static_Proc.Synth_Static_Procedure + (Sub_Inst, Imp, Call); + Synth_Subprogram_Back_Association + (Sub_Inst, Inst, Inter_Chain, Assoc_Chain); + + Next_Stmt := Null_Node; + end; + else + declare + Bod : constant Node := + Vhdl.Sem_Inst.Get_Subprogram_Body_Origin (Imp); + Inter_Chain : constant Node := + Get_Interface_Declaration_Chain (Imp); + begin + if Get_Foreign_Flag (Imp) then + Synth.Errors.Error_Msg_Synth + (+Stmt, "call to foreign %n is not supported", +Imp); + Next_Stmt := Null_Node; + return; + end if; + + Sub_Inst := Synth_Subprogram_Call_Instance (Inst, Imp, Bod); + -- Note: in fact the uninstantiated scope is the instantiated + -- one! + Set_Uninstantiated_Scope (Sub_Inst, Imp); + Synth_Subprogram_Association + (Sub_Inst, Inst, Inter_Chain, Assoc_Chain); + + Process.Instance := Sub_Inst; + Elab.Vhdl_Decls.Elab_Declarations + (Sub_Inst, Get_Declaration_Chain (Bod), True); + + if Get_Suspend_Flag (Bod) then + Next_Stmt := Get_Sequential_Statement_Chain (Bod); + return; + -- TODO: end of call. + else + Execute_Sequential_Statements (Process); + Synth_Subprogram_Back_Association + (Sub_Inst, Inst, Inter_Chain, Assoc_Chain); + Next_Stmt := Null_Node; + end if; + end; + end if; + + if Elab.Debugger.Flag_Need_Debug then + Elab.Debugger.Debug_Leave (Sub_Inst); + end if; + + Free_Elab_Instance (Sub_Inst); + Areapools.Release (Area_Mark, Instance_Pool.all); + end Execute_Procedure_Call_Statement; + + procedure Execute_Signal_Assignment (Inst : Synth_Instance_Acc; + Target : Target_Info; + Val : Valtyp; + Loc : Node); + + procedure Execute_Aggregate_Signal_Assignment is + new Assign_Aggregate (Execute_Signal_Assignment); + + procedure Execute_Signal_Assignment (Inst : Synth_Instance_Acc; + Target : Target_Info; + Val : Valtyp; + Loc : Node) + is + use Synth.Vhdl_Expr; + V : Valtyp; + Sig : Memtyp; + begin + V := Synth_Subtype_Conversion (Inst, Val, Target.Targ_Type, False, Loc); + pragma Unreferenced (Val); + + case Target.Kind is + when Target_Aggregate => + Execute_Aggregate_Signal_Assignment + (Inst, Target.Aggr, Target.Targ_Type, V, Loc); + + when Target_Simple => + declare + E : Signal_Entry renames Signals_Table.Table (Target.Obj.Val.S); + begin + Sig := (Target.Targ_Type, + Sig_Index (E.Sig, Target.Off.Net_Off)); + end; + + Start_Assign_Value_To_Signal (Sig, 0, 0, Get_Value_Memtyp (V)); + + when Target_Memory => + raise Internal_Error; + end case; + end Execute_Signal_Assignment; + + procedure Execute_Waveform_Assignment (Inst : Synth_Instance_Acc; + Target : Target_Info; + Waveform : Node) + is + use Synth.Vhdl_Expr; + Wf : Node; + Val : Valtyp; + begin + Wf := Waveform; + Val := Synth_Expression_With_Type + (Inst, Get_We_Value (Wf), Target.Targ_Type); + Execute_Signal_Assignment (Inst, Target, Val, Wf); + Wf := Get_Chain (Wf); + + if Wf /= Null_Node then + raise Internal_Error; + end if; + end Execute_Waveform_Assignment; + + procedure Execute_Simple_Signal_Assignment (Inst : Synth_Instance_Acc; + Stmt : Node) + is + use Synth.Vhdl_Expr; + Target : constant Node := Get_Target (Stmt); + Info : Target_Info; + begin + Info := Synth_Target (Inst, Target); + + Execute_Waveform_Assignment (Inst, Info, Get_Waveform_Chain (Stmt)); + end Execute_Simple_Signal_Assignment; + + procedure Execute_Conditional_Signal_Assignment (Inst : Synth_Instance_Acc; + Stmt : Node) + is + use Synth.Vhdl_Expr; + Target : constant Node := Get_Target (Stmt); + Cw : Node; + Cond : Node; + Info : Target_Info; + begin + Info := Synth_Target (Inst, Target); + + Cw := Get_Conditional_Waveform_Chain (Stmt); + while Cw /= Null_Node loop + Cond := Get_Condition (Cw); + if Cond = Null_Node + or else Execute_Condition (Inst, Cond) + then + Execute_Waveform_Assignment + (Inst, Info, Get_Waveform_Chain (Cw)); + exit; + end if; + Cw := Get_Chain (Cw); + end loop; + end Execute_Conditional_Signal_Assignment; + + procedure Execute_Selected_Signal_Assignment (Inst : Synth_Instance_Acc; + Stmt : Node) + is + use Synth.Vhdl_Expr; + Target : constant Node := Get_Target (Stmt); + Sel : Memtyp; + Sw : Node; + Wf : Node; + Info : Target_Info; + Eq : Boolean; + begin + Info := Synth_Target (Inst, Target); + + Sel := Get_Memtyp (Synth_Expression (Inst, Get_Expression (Stmt))); + + Sw := Get_Selected_Waveform_Chain (Stmt); + while Sw /= Null_Node loop + if not Get_Same_Alternative_Flag (Sw) then + Wf := Get_Associated_Chain (Sw); + else + pragma Assert (Get_Associated_Chain (Sw) = Null_Node); + null; + end if; + case Iir_Kinds_Choice (Get_Kind (Sw)) is + when Iir_Kind_Choice_By_Expression => + declare + Ch : Valtyp; + begin + Ch := Synth_Expression (Inst, Get_Choice_Expression (Sw)); + Eq := Is_Equal (Sel, Get_Memtyp (Ch)); + end; + when Iir_Kind_Choice_By_Others => + Eq := True; + when others => + raise Internal_Error; + end case; + if Eq then + Execute_Waveform_Assignment (Inst, Info, Wf); + exit; + end if; + Sw := Get_Chain (Sw); + end loop; + end Execute_Selected_Signal_Assignment; + + procedure Execute_Sequential_Statements (Process : Process_State_Acc) + is + Inst : Synth_Instance_Acc; + Src : Node; + Stmt : Node; + Resume : Boolean; + begin + Inst := Process.Instance; + Src := Get_Source_Scope (Inst); + if Get_Kind (Src) = Iir_Kind_Sensitized_Process_Statement + or else (Get_Kind (Src) = Iir_Kind_Procedure_Body + and then not Get_Suspend_Flag (Src)) + then + Stmt := Get_Sequential_Statement_Chain (Src); + Resume := True; + else + Get_Suspend_State_Statement (Inst, Stmt, Resume); + end if; + + loop + Inst := Process.Instance; + if Elab.Debugger.Flag_Need_Debug then + Elab.Debugger.Debug_Break (Inst, Stmt); + end if; + + case Get_Kind (Stmt) is + when Iir_Kind_Null_Statement => + Next_Statement (Process, Stmt); + + when Iir_Kind_For_Loop_Statement => + declare + Val : Valtyp; + begin + Synth.Vhdl_Stmts.Init_For_Loop_Statement (Inst, Stmt, Val); + if Elab.Vhdl_Objtypes.In_Range (Val.Typ.Drange, + Read_Discrete (Val)) + then + Stmt := Get_Sequential_Statement_Chain (Stmt); + else + Synth.Vhdl_Stmts.Finish_For_Loop_Statement (Inst, Stmt); + Next_Statement (Process, Stmt); + end if; + end; + when Iir_Kind_While_Loop_Statement => + if Execute_Condition (Inst, Get_Condition (Stmt)) then + Stmt := Get_Sequential_Statement_Chain (Stmt); + else + Next_Statement (Process, Stmt); + end if; + when Iir_Kind_Exit_Statement => + if Execute_Condition (Inst, Get_Condition (Stmt)) then + declare + Label : constant Node := Get_Loop_Label (Stmt); + begin + loop + Stmt := Get_Parent (Stmt); + case Get_Kind (Stmt) is + when Iir_Kind_For_Loop_Statement => + -- Need to finalize for-loop statements. + Synth.Vhdl_Stmts.Finish_For_Loop_Statement + (Inst, Stmt); + exit when Label = Null_Node + or else Label = Stmt; + when Iir_Kind_While_Loop_Statement => + exit when Label = Null_Node + or else Label = Stmt; + when others => + null; + end case; + end loop; + end; + end if; + Next_Statement (Process, Stmt); + when Iir_Kind_Next_Statement => + if Execute_Condition (Inst, Get_Condition (Stmt)) then + declare + Label : constant Node := Get_Loop_Label (Stmt); + begin + loop + Stmt := Get_Parent (Stmt); + case Get_Kind (Stmt) is + when Iir_Kind_For_Loop_Statement => + -- Need to finalize for-loop statements. + if Label = Null_Node or else Label = Stmt + then + Next_Parent_Statement (Process, Stmt, Stmt); + exit; + else + Synth.Vhdl_Stmts.Finish_For_Loop_Statement + (Inst, Stmt); + end if; + when Iir_Kind_While_Loop_Statement => + if Label = Null_Node or else Label = Stmt + then + Next_Parent_Statement (Process, Stmt, Stmt); + exit; + end if; + when others => + null; + end case; + end loop; + end; + else + Next_Statement (Process, Stmt); + end if; + when Iir_Kind_Return_Statement => + pragma Assert (Get_Expression (Stmt) = Null_Node); + loop + Stmt := Get_Parent (Stmt); + case Get_Kind (Stmt) is + when Iir_Kind_For_Loop_Statement => + -- Need to finalize for-loop statements. + Synth.Vhdl_Stmts.Finish_For_Loop_Statement + (Inst, Stmt); + when Iir_Kind_Procedure_Body => + exit; + when others => + null; + end case; + end loop; + Finish_Procedure_Call (Process, Stmt, Stmt); + -- For a non-suspend procedure, return now to the caller. + exit when Stmt = Null_Node; + Next_Statement (Process, Stmt); + + when Iir_Kind_If_Statement => + declare + Els : Node; + begin + Els := Stmt; + loop + if Execute_Condition (Inst, Get_Condition (Els)) then + Stmt := Get_Sequential_Statement_Chain (Els); + exit; + end if; + + Els := Get_Else_Clause (Els); + if Els = Null_Node then + Next_Statement (Process, Stmt); + exit; + end if; + end loop; + end; + when Iir_Kind_Case_Statement => + declare + use Synth.Vhdl_Expr; + Expr : constant Node := Get_Expression (Stmt); + Sel : Valtyp; + begin + Sel := Synth_Expression_With_Basetype (Inst, Expr); + Stmt := Synth.Vhdl_Stmts.Execute_Static_Case_Statement + (Inst, Stmt, Sel); + end; + + when Iir_Kind_Assertion_Statement => + Synth.Vhdl_Stmts.Execute_Assertion_Statement (Inst, Stmt); + Next_Statement (Process, Stmt); + when Iir_Kind_Report_Statement => + Synth.Vhdl_Stmts.Execute_Report_Statement (Inst, Stmt); + Next_Statement (Process, Stmt); + + when Iir_Kind_Variable_Assignment_Statement => + Synth.Vhdl_Stmts.Synth_Variable_Assignment (Inst, Stmt); + Next_Statement (Process, Stmt); + when Iir_Kind_Conditional_Variable_Assignment_Statement => + Synth.Vhdl_Stmts.Synth_Conditional_Variable_Assignment + (Inst, Stmt); + Next_Statement (Process, Stmt); + + when Iir_Kind_Simple_Signal_Assignment_Statement => + Execute_Simple_Signal_Assignment (Inst, Stmt); + Next_Statement (Process, Stmt); + when Iir_Kind_Conditional_Signal_Assignment_Statement => + Execute_Conditional_Signal_Assignment (Inst, Stmt); + Next_Statement (Process, Stmt); + + when Iir_Kind_Wait_Statement => + -- The suspend state is executed instead. + raise Internal_Error; + + when Iir_Kind_Procedure_Call_Statement => + -- Call of a procedure without suspend state. + declare + Next_Stmt : Node; + begin + Execute_Procedure_Call_Statement (Process, Stmt, Next_Stmt); + pragma Assert (Next_Stmt = Null_Node); + Next_Statement (Process, Stmt); + end; + + when Iir_Kind_Suspend_State_Statement => + declare + Stmt2 : constant Node := Get_Chain (Stmt); + Next_Stmt : Node; + State : Int32; + State_Mem : Memory_Ptr; + begin + case Get_Kind (Stmt2) is + when Iir_Kind_Wait_Statement => + if Resume then + Resume := Resume_Wait_Statement + (Process.Instance, Stmt2); + else + Execute_Wait_Statement (Process.Instance, Stmt2); + Resume := True; + end if; + if Resume then + -- Will resume, so first stop! + State_Mem := Get_Suspend_State_Var (Inst); + State := Get_Suspend_State_Index (Stmt); + Write_I32 (State_Mem, Ghdl_I32 (State)); + exit; + else + -- Continue execution + Stmt := Stmt2; + Next_Statement (Process, Stmt); + end if; + when Iir_Kind_Procedure_Call_Statement => + if Resume then + raise Internal_Error; + end if; + Execute_Procedure_Call_Statement + (Process, Stmt2, Next_Stmt); + if Next_Stmt /= Null_Node then + -- User procedure. + -- Save current state. + State_Mem := Get_Suspend_State_Var (Inst); + State := Get_Suspend_State_Index (Stmt); + Write_I32 (State_Mem, Ghdl_I32 (State)); + + -- Start to execute the user procedure. + Inst := Process.Instance; + Stmt := Next_Stmt; + else + -- Implicit procedure, was already executed. + -- Continue execution + Stmt := Stmt2; + Next_Statement (Process, Stmt); + end if; + when others => + raise Internal_Error; + end case; + end; + + when others => + Vhdl.Errors.Error_Kind ("execute_sequential_statements", Stmt); + end case; + + exit when Stmt = Null_Node; + end loop; + end Execute_Sequential_Statements; + + procedure Execute_Expression_Association (Proc_Idx : Process_Index_Type) + is + use Synth.Vhdl_Expr; + Proc : Proc_Record_Type renames Processes_Table.Table (Proc_Idx); + Drv : Driver_Entry renames Drivers_Table.Table (Proc.Drivers); + Sig : Signal_Entry renames Signals_Table.Table (Drv.Sig); + Val : Valtyp; + begin + Val := Synth_Expression_With_Type + (Proc.Inst, Get_Actual (Proc.Proc), Drv.Typ); + Start_Assign_Value_To_Signal + ((Drv.Typ, Sig.Sig), 0, 0, Get_Value_Memtyp (Val)); + end Execute_Expression_Association; + + procedure Process_Executer (Self : Grt.Processes.Instance_Acc) + is + use Simple_IO; + + function To_Process_State_Acc is new Ada.Unchecked_Conversion + (Grt.Processes.Instance_Acc, Process_State_Acc); + + Process : Process_State_Acc renames + To_Process_State_Acc (Self); + begin + -- For debugger + Current_Process := Process; + +-- Instance_Pool := Process.Pool'Access; + + if Synth.Flags.Flag_Trace_Statements then + Put (" run process: "); +-- Disp_Instance_Name (Process.Top_Instance); + Put_Line (" (" & Vhdl.Errors.Disp_Location (Process.Proc) & ")"); + end if; + +-- Execute_Sequential_Statements (Process); + + -- Sanity checks. +-- if not Is_Empty (Expr_Pool) then +-- raise Internal_Error; +-- end if; + + case Get_Kind (Process.Proc) is + when Iir_Kind_Sensitized_Process_Statement => +-- if Process.Instance.In_Wait_Flag then +-- raise Internal_Error; +-- end if; + Execute_Sequential_Statements (Process); + when Iir_Kind_Process_Statement => + Execute_Sequential_Statements (Process); + when Iir_Kind_Concurrent_Assertion_Statement => + if Elab.Debugger.Flag_Need_Debug then + Elab.Debugger.Debug_Break (Process.Instance, Process.Proc); + end if; + Synth.Vhdl_Stmts.Execute_Assertion_Statement + (Process.Instance, Process.Proc); + when Iir_Kind_Concurrent_Simple_Signal_Assignment => + if Elab.Debugger.Flag_Need_Debug then + Elab.Debugger.Debug_Break (Process.Instance, Process.Proc); + end if; + Execute_Simple_Signal_Assignment (Process.Instance, Process.Proc); + when Iir_Kind_Concurrent_Conditional_Signal_Assignment => + if Elab.Debugger.Flag_Need_Debug then + Elab.Debugger.Debug_Break (Process.Instance, Process.Proc); + end if; + Execute_Conditional_Signal_Assignment + (Process.Instance, Process.Proc); + when Iir_Kind_Concurrent_Selected_Signal_Assignment => + if Elab.Debugger.Flag_Need_Debug then + Elab.Debugger.Debug_Break (Process.Instance, Process.Proc); + end if; + Execute_Selected_Signal_Assignment + (Process.Instance, Process.Proc); + when Iir_Kind_Association_Element_By_Expression => + if Elab.Debugger.Flag_Need_Debug then + Elab.Debugger.Debug_Break (Process.Instance, Process.Proc); + end if; + Execute_Expression_Association (Process.Idx); + when others => + raise Internal_Error; + end case; + +-- Instance_Pool := null; + Current_Process := null; + end Process_Executer; + + procedure Add_Sensitivity (Typ : Type_Acc; Sig : Memory_Ptr) is + begin + case Typ.Kind is + when Type_Logic + | Type_Bit + | Type_Discrete => + Grt.Processes.Ghdl_Process_Add_Sensitivity (Read_Sig (Sig)); + when Type_Vector + | Type_Array => + declare + Len : constant Uns32 := Typ.Abound.Len; + begin + for I in 1 .. Len loop + Add_Sensitivity + (Typ.Arr_El, Sig_Index (Sig, (Len - I) * Typ.Arr_El.W)); + end loop; + end; + when Type_Record => + for I in Typ.Rec.E'Range loop + Add_Sensitivity (Typ.Rec.E (I).Typ, + Sig_Index (Sig, Typ.Rec.E (I).Offs.Net_Off)); + end loop; + when others => + raise Internal_Error; + end case; + end Add_Sensitivity; + + procedure Register_Sensitivity (Proc_Idx : Process_Index_Type) + is + Sens : Sensitivity_Index_Type; + begin + Sens := Processes_Table.Table (Proc_Idx).Sensitivity; + while Sens /= No_Sensitivity_Index loop + declare + S : Sensitivity_Entry renames Sensitivity_Table.Table (Sens); + Base : constant Memory_Ptr := Signals_Table.Table (S.Sig).Sig; + begin + Add_Sensitivity (S.Typ, Sig_Index (Base, S.Off.Net_Off)); + Sens := S.Prev_Proc; + end; + end loop; + end Register_Sensitivity; + + function To_Address is new Ada.Unchecked_Conversion + (Process_State_Acc, System.Address); + + procedure Create_Process_Sensitized (Proc : Process_State_Acc) + is + use Grt.Processes; + Instance_Grt : Grt.Processes.Instance_Acc; + begin + Instance_Grt := To_Instance_Acc (Proc.all'Address); + if Get_Postponed_Flag (Proc.Proc) then + Ghdl_Postponed_Sensitized_Process_Register + (Instance_Grt, + Process_Executer'Access, + null, To_Address (Proc)); + else + Ghdl_Sensitized_Process_Register + (Instance_Grt, + Process_Executer'Access, + null, To_Address (Proc)); + end if; + end Create_Process_Sensitized; + + procedure Create_Processes + is + use Grt.Processes; + Proc : Node; + Instance : Synth_Instance_Acc; + Instance_Grt : Grt.Processes.Instance_Acc; + Instance_Addr : System.Address; + begin + Processes_State := new Process_State_Array (1 .. Processes_Table.Last); + + for I in Processes_Table.First .. Processes_Table.Last loop + Instance := Processes_Table.Table (I).Inst; + Proc := Processes_Table.Table (I).Proc; + +-- Instance_Pool := Processes_State (I).Pool'Access; +-- Instance.Stmt := Get_Sequential_Statement_Chain (Proc); + + Processes_State (I).Top_Instance := Instance; + Processes_State (I).Proc := Proc; + Processes_State (I).Idx := I; + Processes_State (I).Instance := Instance; + + Current_Process := Processes_State (I)'Access; + Instance_Addr := Processes_State (I)'Address; + Instance_Grt := To_Instance_Acc (Instance_Addr); + case Get_Kind (Proc) is + when Iir_Kind_Concurrent_Assertion_Statement => + Create_Process_Sensitized (Current_Process); + Register_Sensitivity (I); + + when Iir_Kind_Sensitized_Process_Statement + | Iir_Kind_Concurrent_Simple_Signal_Assignment + | Iir_Kind_Concurrent_Conditional_Signal_Assignment + | Iir_Kind_Concurrent_Selected_Signal_Assignment => + declare + Driver_List: Iir_List; + begin + Driver_List := Trans_Analyzes.Extract_Drivers (Proc); + Create_Process_Sensitized (Current_Process); + Register_Sensitivity (I); + Create_Process_Drivers (Instance, Proc, Driver_List); + Trans_Analyzes.Free_Drivers_List (Driver_List); + end; + + when Iir_Kind_Association_Element_By_Expression => + Ghdl_Sensitized_Process_Register + (Instance_Grt, + Process_Executer'Access, + null, Instance_Addr); + Register_Sensitivity (I); + Create_Process_Drivers (I); + + when Iir_Kind_Process_Statement => + declare + Driver_List: Iir_List; + begin + Driver_List := Trans_Analyzes.Extract_Drivers (Proc); + + if Get_Postponed_Flag (Proc) then + Ghdl_Postponed_Process_Register + (Instance_Grt, + Process_Executer'Access, + null, Instance_Addr); + else + Ghdl_Process_Register + (Instance_Grt, + Process_Executer'Access, + null, Instance_Addr); + end if; + Create_Process_Drivers (Instance, Proc, Driver_List); + Trans_Analyzes.Free_Drivers_List (Driver_List); + end; + + when others => + Vhdl.Errors.Error_Kind ("create_processes", Proc); + end case; + + -- LRM93 12.4.4 Other Concurrent Statements + -- All other concurrent statements are either process + -- statements or are statements for which there is an + -- equivalent process statement. + -- Elaboration of a process statement proceeds as follows: + -- 1. The process declarative part is elaborated. +-- Elaborate_Declarative_Part +-- (Instance, Get_Declaration_Chain (Proc)); + + -- 2. The drivers required by the process statement + -- are created. + -- 3. The initial transaction defined by the default value + -- associated with each scalar signal driven by the + -- process statement is inserted into the corresponding + -- driver. + -- FIXME: do it for drivers in called subprograms too. +-- Elaborate_Drivers (Instance, Proc); + +-- if not Is_Empty (Expr_Pool) then +-- raise Internal_Error; +-- end if; + + -- Elaboration of all concurrent signal assignment + -- statements and concurrent assertion statements consists + -- of the construction of the equivalent process statement + -- followed by the elaboration of the equivalent process + -- statement. + -- [GHDL: this is done by canonicalize. ] + + -- FIXME: check passive statements, + -- check no wait statement in sensitized processes. + +-- Instance_Pool := null; + end loop; + +-- if Trace_Simulation then +-- Disp_Signals_Value; +-- end if; + end Create_Processes; + + type Resolv_Instance_Type is record + Func : Iir; + Inst : Synth_Instance_Acc; + Sig : Memory_Ptr; + end record; + type Resolv_Instance_Acc is access Resolv_Instance_Type; + + -- The resolution procedure for GRT. + procedure Resolution_Proc (Instance_Addr : System.Address; + Val : System.Address; + Bool_Vec : System.Address; + Vec_Len : Ghdl_Index_Type; + Nbr_Drv : Ghdl_Index_Type; + Nbr_Ports : Ghdl_Index_Type); + pragma Convention (C, Resolution_Proc); + + procedure Resolution_Proc (Instance_Addr : System.Address; + Val : System.Address; + Bool_Vec : System.Address; + Vec_Len : Ghdl_Index_Type; + Nbr_Drv : Ghdl_Index_Type; + Nbr_Ports : Ghdl_Index_Type) is + begin + raise Internal_Error; + end Resolution_Proc; + + -- Create a new signal, using DEFAULT as initial value. + -- Set its number. + procedure Create_User_Signal (Inst : Synth_Instance_Acc; + Mode : Mode_Signal_Type; + Signal: Node; + Typ : Type_Acc; + Sig : Memory_Ptr; + Val : Memory_Ptr) + is +-- use Grt.Signals; + + procedure Create_Signal (Val : Memory_Ptr; + Sig : Memory_Ptr; + Sig_Type: Iir; + Typ : Type_Acc; + Already_Resolved : Boolean) + is + Sub_Resolved : Boolean := Already_Resolved; + Resolv_Func : Iir; + Resolv_Instance : Resolv_Instance_Acc; + S : Ghdl_Signal_Ptr; + begin + if not Already_Resolved + and then Get_Kind (Sig_Type) in Iir_Kinds_Subtype_Definition + then + Resolv_Func := Get_Resolution_Indication (Sig_Type); + else + Resolv_Func := Null_Iir; + end if; + if False and Resolv_Func /= Null_Iir then + Sub_Resolved := True; + Resolv_Instance := new Resolv_Instance_Type' + (Func => Get_Named_Entity (Resolv_Func), + Inst => Inst, + Sig => Sig); + Grt.Signals.Ghdl_Signal_Create_Resolution + (Resolution_Proc'Access, + Resolv_Instance.all'Address, + System.Null_Address, + Ghdl_Index_Type (Typ.W)); + end if; + case Typ.Kind is + when Type_Bit => + S := Grt.Signals.Ghdl_Create_Signal_B1 + (To_Ghdl_Value_Ptr (To_Address (Val)), + null, System.Null_Address); + Write_Sig (Sig, S); + when Type_Logic => + S := Grt.Signals.Ghdl_Create_Signal_E8 + (To_Ghdl_Value_Ptr (To_Address (Val)), + null, System.Null_Address); + Write_Sig (Sig, S); + when Type_Float => + S := Grt.Signals.Ghdl_Create_Signal_F64 + (To_Ghdl_Value_Ptr (To_Address (Val)), + null, System.Null_Address); + Write_Sig (Sig, S); + when Type_Discrete => + if Typ.Sz = 1 then + S := Grt.Signals.Ghdl_Create_Signal_E8 + (To_Ghdl_Value_Ptr (To_Address (Val)), + null, System.Null_Address); + elsif Typ.Sz = 4 then + S := Grt.Signals.Ghdl_Create_Signal_I32 + (To_Ghdl_Value_Ptr (To_Address (Val)), + null, System.Null_Address); + elsif Typ.Sz = 8 then + S := Grt.Signals.Ghdl_Create_Signal_I64 + (To_Ghdl_Value_Ptr (To_Address (Val)), + null, System.Null_Address); + else + raise Internal_Error; + end if; + Write_Sig (Sig, S); + when Type_Vector + | Type_Array => + declare + Len : constant Uns32 := Typ.Abound.Len; + El_Type : Node; + begin + if Typ.Alast then + El_Type := Get_Element_Subtype (Sig_Type); + else + El_Type := Sig_Type; + end if; + for I in 1 .. Len loop + Create_Signal (Val + Size_Type (I - 1) * Typ.Arr_El.Sz, + Sig_Index (Sig, (Len - I) * Typ.Arr_El.W), + El_Type, Typ.Arr_El, Already_Resolved); + end loop; + end; + when Type_Record => + declare + List : constant Iir_Flist := Get_Elements_Declaration_List + (Sig_Type); + El : Iir_Element_Declaration; + begin + for I in Typ.Rec.E'Range loop + El := Get_Nth_Element (List, Natural (I - 1)); + Create_Signal + (Val + Typ.Rec.E (I).Offs.Mem_Off, + Sig_Index (Sig, Typ.Rec.E (I).Offs.Net_Off), + Get_Type (El), Typ.Rec.E (I).Typ, + Sub_Resolved); + end loop; + end; + + when Type_Slice + | Type_Access + | Type_Unbounded_Vector + | Type_Unbounded_Array + | Type_Unbounded_Record + | Type_File + | Type_Protected => + raise Internal_Error; + end case; + end Create_Signal; + + Sig_Type: constant Iir := Get_Type (Signal); + Kind : Kind_Signal_Type; + + type Iir_Kind_To_Kind_Signal_Type is + array (Iir_Signal_Kind) of Kind_Signal_Type; + Iir_Kind_To_Kind_Signal : constant Iir_Kind_To_Kind_Signal_Type := + (Iir_Register_Kind => Kind_Signal_Register, + Iir_Bus_Kind => Kind_Signal_Bus); + begin + if Get_Guarded_Signal_Flag (Signal) then + Kind := Iir_Kind_To_Kind_Signal (Get_Signal_Kind (Signal)); + else + Kind := Kind_Signal_No; + end if; + + Grt.Signals.Ghdl_Signal_Set_Mode (Mode, Kind, True); + + Create_Signal (Val, Sig, Sig_Type, Typ, False); + end Create_User_Signal; + + function Alloc_Signal_Memory (Vtype : Type_Acc) return Memory_Ptr + is + function To_Memory_Ptr is new Ada.Unchecked_Conversion + (System.Address, Memory_Ptr); + M : System.Address; + begin + Areapools.Allocate (Current_Pool.all, + M, Sig_Size * Size_Type (Vtype.W), Sig_Size); + return To_Memory_Ptr (M); + end Alloc_Signal_Memory; + + procedure Create_Signal (E : in out Signal_Entry) is + begin + E.Sig := Alloc_Signal_Memory (E.Typ); + case E.Kind is + when Mode_Guard => + -- Create_Guard_Signal (E.Instance, E.Sig, E.Val, E.Decl); + raise Internal_Error; + when Mode_Stable | Mode_Quiet | Mode_Transaction => + -- Create_Implicit_Signal + -- (E.Sig, E.Val, E.Time, E.Prefix, E.Kind); + raise Internal_Error; + when Mode_Delayed => + -- Create_Delayed_Signal (E.Sig, E.Val, E.Prefix, E.Time); + raise Internal_Error; + when Mode_Above => + raise Internal_Error; + when Mode_Signal_User => + Create_User_Signal (E.Inst, E.Kind, E.Decl, E.Typ, E.Sig, E.Val); + when Mode_Conv_In | Mode_Conv_Out | Mode_End => + raise Internal_Error; + end case; + end Create_Signal; + + procedure Create_Signals is + begin + for I in Signals_Table.First .. Signals_Table.Last loop + declare + E : Signal_Entry renames Signals_Table.Table (I); + begin + pragma Assert (E.Sig = null); + if E.Collapsed_By /= No_Signal_Index then + E.Sig := Signals_Table.Table (E.Collapsed_By).Sig; + -- TODO: keep val ? + E.Val := Signals_Table.Table (E.Collapsed_By).Val; + else + Create_Signal (E); + end if; + end; + end loop; + end Create_Signals; + + -- Compute solver variables, allocate memory for quantities. + procedure Create_Quantities + is + use Grt.Analog_Solver; + Num : Natural; + Vec : F64_C_Arr_Ptr; + begin + -- Compute number of scalar quantities. + Num := 0; + for I in Quantity_Table.First .. Quantity_Table.Last loop + declare + Q : Quantity_Entry renames Quantity_Table.Table (I); + Def : Node; + Pfx_Info : Target_Info; + begin + case Get_Kind (Q.Decl) is + when Iir_Kind_Free_Quantity_Declaration => + -- For a free or branch quantity: + -- * if it is the actual of a OUT formal, then use the + -- variable from the formal. + -- TODO: handle OUT associations. + pragma Assert (Q.Typ.Kind = Type_Float); -- TODO + Q.Idx := Scalar_Quantities_Table.Last + 1; + Scalar_Quantities_Table.Append + ((Idx => Num, + Deriv => No_Scalar_Quantity, + Integ => No_Scalar_Quantity)); + Num := Num + Natural (Q.Typ.W); + + Def := Get_Default_Value (Q.Decl); + if Def /= Null_Node then + -- TODO + raise Internal_Error; + end if; + Q.Val := Alloc_Memory (Q.Typ); + Write_Fp64 (Q.Val, 0.0); + + when Iir_Kind_Dot_Attribute => + Pfx_Info := Synth_Target (Q.Inst, Get_Prefix (Q.Decl)); + pragma Assert (Pfx_Info.Kind = Target_Simple); + pragma Assert (Pfx_Info.Off = (0, 0)); + pragma Assert (Pfx_Info.Targ_Type.Kind = Type_Float); + declare + Pfx : constant Scalar_Quantity_Index := + Quantity_Table.Table (Pfx_Info.Obj.Val.Q).Idx; + Pfx_Ent : Scalar_Quantity_Record renames + Scalar_Quantities_Table.Table (Pfx); + begin + if Pfx_Ent.Deriv /= No_Scalar_Quantity then + -- There is already a 'Dot, reuse it and done. + Q.Idx := Pfx_Ent.Deriv; + else + -- Create a 'Dot. + Pfx_Ent.Deriv := Scalar_Quantities_Table.Last + 1; + Q.Idx := Pfx_Ent.Deriv; + Scalar_Quantities_Table.Append + ((Idx => Num, + Deriv => No_Scalar_Quantity, + Integ => Pfx)); + Num := Num + 1; + + Augmentations_Set.Append + ((Kind => Aug_Dot, Q => Q.Idx)); + end if; + + Q.Val := Alloc_Memory (Q.Typ); + Write_Fp64 (Q.Val, 0.0); + end; + + when others => + Vhdl.Errors.Error_Kind ("create_quantities", Q.Decl); + end case; + end; + end loop; + + -- TODO: also for the reference quantity of terminals. + + Nbr_Solver_Variables := Num; + + if Num = 0 then + -- No AMS + return; + end if; + + -- AMS simulation. + Grt.Processes.Flag_AMS := True; + + -- + -- For 'Dot: + -- * if the prefix is a quantity, use its corresponding prime. + -- * if the prefix is 'Dot, create an intermediate variable. + + -- Initialize solver. + Grt.Analog_Solver.Init (Ghdl_I32 (Num)); + + -- LRM 1076.1-2007 12.6.4 Simulation cycle + -- The value of each implicit quantity of the form ... Q'Dot ... is + -- set to 0.0 + Vec := Grt.Analog_Solver.Get_Init_Der_Ptr; + for I in 0 .. Num - 1 loop + Vec (I) := 0.0; + end loop; + + -- Set initial values. + Vec := Grt.Analog_Solver.Get_Init_Val_Ptr; + for I in Quantity_Table.First .. Quantity_Table.Last loop + declare + Q : Quantity_Entry renames Quantity_Table.Table (I); + begin + pragma Assert (Q.Typ.Kind = Type_Float); -- TODO + Vec (Scalar_Quantities_Table.Table (Q.Idx).Idx) := + Ghdl_F64 (Read_Fp64 (Q.Val)); + end; + end loop; + end Create_Quantities; + + function Exec_Bit_Edge (Param : Valtyp; Res_Typ : Type_Acc; Val : Ghdl_U8) + return Memtyp + is + Sig : Ghdl_Signal_Ptr; + Res : Boolean; + begin + Sig := Read_Sig (Sig_Index (Exec_Sig_Sig (Param.Val.A_Obj), + Param.Val.A_Off.Net_Off)); + Res := Sig.Event and then Sig.Value_Ptr.E8 = Val; + return Create_Memory_U8 (Boolean'Pos (Res), Res_Typ); + end Exec_Bit_Edge; + + function Exec_Bit_Rising_Edge (Param : Valtyp; Res_Typ : Type_Acc) + return Memtyp is + begin + return Exec_Bit_Edge (Param, Res_Typ, 1); + end Exec_Bit_Rising_Edge; + + function Exec_Bit_Falling_Edge (Param : Valtyp; Res_Typ : Type_Acc) + return Memtyp is + begin + return Exec_Bit_Edge (Param, Res_Typ, 0); + end Exec_Bit_Falling_Edge; + + function Exec_Std_Edge (Param : Valtyp; + Res_Typ : Type_Acc; + Prev : Std_Ulogic; + Curr : Std_Ulogic) return Memtyp + is + Sig : Ghdl_Signal_Ptr; + Res : Boolean; + begin + Sig := Read_Sig (Sig_Index (Exec_Sig_Sig (Param.Val.A_Obj), + Param.Val.A_Off.Net_Off)); + Res := Sig.Event + and then To_X01 (Std_Ulogic'Val (Sig.Value_Ptr.E8)) = Curr + and then To_X01 (Std_Ulogic'Val (Sig.Last_Value.E8)) = Prev; + return Create_Memory_U8 (Boolean'Pos (Res), Res_Typ); + end Exec_Std_Edge; + + function Exec_Std_Rising_Edge (Param : Valtyp; Res_Typ : Type_Acc) + return Memtyp is + begin + return Exec_Std_Edge (Param, Res_Typ, '0', '1'); + end Exec_Std_Rising_Edge; + + function Exec_Std_Falling_Edge (Param : Valtyp; Res_Typ : Type_Acc) + return Memtyp is + begin + return Exec_Std_Edge (Param, Res_Typ, '1', '0'); + end Exec_Std_Falling_Edge; + + procedure Exec_Finish (Inst : Synth_Instance_Acc; Imp : Node) + is + use Grt.Lib; + Inter : constant Node := Get_Interface_Declaration_Chain (Imp); + Param : Valtyp; + Status : Int64; + begin + if Inter /= Null_Node then + Param := Get_Value (Inst, Inter); + Status := Read_Discrete (Param); + Ghdl_Control_Simulation (False, True, Std_Integer (Status)); + else + Ghdl_Control_Simulation (False, False, 0); + end if; + end Exec_Finish; + + procedure Set_Quantities_Values (Y : F64_C_Arr_Ptr; Yp: F64_C_Arr_Ptr) + is + pragma Unreferenced (Yp); + begin + for I in Quantity_Table.First .. Quantity_Table.Last loop + declare + Q : Quantity_Entry renames Quantity_Table.Table (I); + Idx : Natural; + begin + pragma Assert (Q.Typ.Kind = Type_Float); + Idx := Scalar_Quantities_Table.Table (Q.Idx).Idx; + Write_Fp64 (Q.Val, Fp64 (Y (Idx))); + end; + end loop; + end Set_Quantities_Values; + + procedure Residues (T : Ghdl_F64; + Y : F64_C_Arr_Ptr; + Yp : F64_C_Arr_Ptr; + Res : F64_C_Arr_Ptr) + is + Num : Natural; + L, R : Valtyp; + Prev_Time : Ghdl_F64; + begin + Set_Quantities_Values (Y, Yp); + + -- Apply time. + -- TODO: physical time too. + Prev_Time := Current_Time_AMS; + Current_Time_AMS := T; + + Num := 0; + for I in Simultaneous_Table.First .. Simultaneous_Table.Last loop + declare + S : Simultaneous_Record renames Simultaneous_Table.Table (I); + begin + case Get_Kind (S.Stmt) is + when Iir_Kind_Simple_Simultaneous_Statement => + L := Synth.Vhdl_Expr.Synth_Expression + (S.Inst, Get_Simultaneous_Left (S.Stmt)); + R := Synth.Vhdl_Expr.Synth_Expression + (S.Inst, Get_Simultaneous_Right (S.Stmt)); + pragma Assert (R.Typ.Kind = Type_Float); + pragma Assert (L.Typ.Kind = Type_Float); + Res (Num) := Ghdl_F64 + (Read_Fp64 (L.Val.Mem) - Read_Fp64 (R.Val.Mem)); + Num := Num + 1; + when others => + Vhdl.Errors.Error_Kind ("residues", S.Stmt); + end case; + end; + end loop; + + for I in Augmentations_Set.First .. Augmentations_Set.Last loop + declare + A : Augmentation_Entry renames Augmentations_Set.Table (I); + begin + case A.Kind is + when Aug_Dot => + declare + Q : Scalar_Quantity_Record renames + Scalar_Quantities_Table.Table (A.Q); + pragma Assert (Q.Integ /= No_Scalar_Quantity); + Qi : Scalar_Quantity_Record renames + Scalar_Quantities_Table.Table (Q.Integ); + begin + Res (Num) := Y (Q.Idx) - Yp (Qi.Idx); + Num := Num + 1; + end; + when others => + raise Internal_Error; + end case; + end; + end loop; + + pragma Assert (Nbr_Solver_Variables = Num); + + if Trace_Residues then + declare + use Simple_IO; + use Utils_IO; + begin + Put ("Residues at "); + Put_Fp64 (Fp64 (Current_Time_AMS)); + New_Line; + for I in 0 .. Num -1 loop + Put ("Y"); + Put_Uns32 (Uns32 (I)); + Put ("="); + Put_Fp64 (Fp64 (Y (I))); + Put (", Yp("); + Put_Uns32 (Uns32 (I)); + Put (")="); + Put_Fp64 (Fp64 (Yp (I))); + Put (", R("); + Put_Uns32 (Uns32 (I)); + Put (")="); + Put_Fp64 (Fp64 (Res (I))); + New_Line; + end loop; + end; + end if; + + Current_Time_AMS := Prev_Time; + end Residues; + + procedure Runtime_Elaborate is + begin +-- if Disp_Stats then +-- Disp_Design_Stats; +-- end if; + + -- There is no inputs. + -- All the simulation is done via time, so it must be displayed. + Disp_Time_Before_Values := True; + + Create_Signals; + -- Create_Connects; + -- Create_Disconnections; + Create_Processes; + -- Create_PSL; + Create_Quantities; + + -- Allow Synth_Expression to handle signals. + Synth.Vhdl_Expr.Hook_Signal_Expr := Hook_Signal_Expr'Access; + Synth.Vhdl_Expr.Hook_Event_Attribute := Exec_Event_Attribute'Access; + + Synth.Vhdl_Oper.Hook_Bit_Rising_Edge := Exec_Bit_Rising_Edge'Access; + Synth.Vhdl_Oper.Hook_Bit_Falling_Edge := Exec_Bit_Falling_Edge'Access; + + Synth.Vhdl_Oper.Hook_Std_Rising_Edge := Exec_Std_Rising_Edge'Access; + Synth.Vhdl_Oper.Hook_Std_Falling_Edge := Exec_Std_Falling_Edge'Access; + + Synth.Vhdl_Expr.Hook_Quantity_Expr := Hook_Quantity_Expr'Access; + Synth.Vhdl_Expr.Hook_Dot_Attribute := Exec_Dot_Attribute'Access; + + Synth.Vhdl_Static_Proc.Hook_Finish := Exec_Finish'Access; + + -- if Flag_Interractive then + -- Debug (Reason_Elab); + -- end if; + end Runtime_Elaborate; + + procedure Ghdl_Elaborate; + pragma Export (C, Ghdl_Elaborate, "__ghdl_ELABORATE"); + + procedure Ghdl_Elaborate is + begin + Runtime_Elaborate; + end Ghdl_Elaborate; + + Ghdl_Progname : constant String := "ghdl" & ASCII.Nul; + + procedure Simulation + is + Ok : C_Boolean; + Status : Integer; + begin + Break_Time := Std_Time'Last; + + Grt.Options.Progname := To_Ghdl_C_String (Ghdl_Progname'Address); + Grt.Errors.Set_Error_Stream (Grt.Stdio.stdout); + +-- Grt.Errors.Error_Hook := Debug_Error'Access; + +-- if Flag_Interractive then +-- Debug (Reason_Start); +-- end if; + + Ok := Grt.Main.Run_Elab; + if not Ok then + return; + end if; + + Synth.Flags.Severity_Level := Grt.Options.Severity_Level; + + if Flag_Interractive then + Elab.Debugger.Debug_Elab (Vhdl_Elab.Top_Instance); + end if; + + Status := Grt.Main.Run_Through_Longjump + (Grt.Processes.Simulation_Init'Access); + + if Status = 0 then + if Grt.Processes.Flag_AMS then + Grt.Analog_Solver.Start; + end if; + + loop + if Break_Time < Grt.Processes.Next_Time then + Grt.Processes.Next_Time := Break_Time; + end if; + + Status := Grt.Main.Run_Through_Longjump + (Grt.Processes.Simulation_Cycle'Access); + exit when Status < 0 + or Status = Grt.Errors.Run_Stop + or Status = Grt.Errors.Run_Finished; + + if Current_Time >= Break_Time + and then Break_Time /= Std_Time'Last + then + -- No not break anymore on time, + Break_Time := Std_Time'Last; + Elab.Debugger.Debug_Time; + end if; + + exit when Grt.Processes.Has_Simulation_Timeout; + end loop; + end if; + + Grt.Processes.Simulation_Finish; + + Grt.Main.Run_Finish (Status); + exception +-- when Debugger_Quit => +-- null; + when Simulation_Finished => + null; + end Simulation; +end Simul.Vhdl_Simul; |