--  GHDL Run Time (GRT) -  Callbacks.
--  Copyright (C) 2015 Tristan Gingold
--
--  GHDL 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, or (at your option) any later
--  version.
--
--  GHDL 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 GCC; see the file COPYING.  If not, write to the Free
--  Software Foundation, 59 Temple Place - Suite 330, Boston, MA
--  02111-1307, USA.
--
--  As a special exception, if other files instantiate generics from this
--  unit, or you link this unit with other files to produce an executable,
--  this unit does not by itself cause the resulting executable to be
--  covered by the GNU General Public License. This exception does not
--  however invalidate any other reasons why the executable file might be
--  covered by the GNU Public License.
with System;
with Grt.Types; use Grt.Types;

--  Callbacks are user registered procedures that are called during simulation.
--  They are used to implement vpi/vhpi callbacks, but also some features like
--  vcd or fst.

package Grt.Callbacks is
   pragma Preelaborate (Grt.Callbacks);

   --  It would be nice to use OOP (tagged types and overriding), but this is
   --  not anymore available in the context of pragma No_Run_Time.
   --  Furthermore, that wouldn't be that convenient because of lack of
   --  multiple inheritance.
   --
   --  Thus the use of a 'generic' callback type.  The type Address is used for
   --  any pointer type.
   type Callback_Acc is access procedure (Arg : System.Address);

   type Callback_Handle is private;

   type Callback_List is limited private;
   pragma Preelaborable_Initialization (Callback_List);

   type Callback_Time_List is limited private;
   pragma Preelaborable_Initialization (Callback_Time_List);

   --  Register a timeout: PROC will be called with parameter ARG at time T
   --  at the beginning of the cycle (before any process).  Insertion is O(n).
   procedure Register_Callback_At
     (List : in out Callback_Time_List;
      Handle : out Callback_Handle;
      T : Std_Time;
      Proc : Callback_Acc;
      Arg : System.Address := System.Null_Address);

   type Callback_Mode is (Timed, Repeat, Oneshot);
   subtype Callback_Non_Timed_Mode is Callback_Mode range Repeat .. Oneshot;

   procedure Register_Callback
     (List : in out Callback_List;
      Handle : out Callback_Handle;
      Mode : Callback_Mode;
      Proc : Callback_Acc;
      Arg : System.Address := System.Null_Address);

   --  Delete callback.
   --  In fact the callback is just marked as deleted, but will be removed
   --  only at the point it would be called.
   procedure Delete_Callback (Handle : Callback_Handle);

   --  Call the callbacks.
   procedure Call_Callbacks (List : in out Callback_List);
   procedure Call_Time_Callbacks (List : in out Callback_Time_List);

   --  Return the date of the earliest callbacks (or Std_Time'Last if none).
   function Get_First_Time (List : Callback_Time_List) return Std_Time;
   pragma Inline (Get_First_Time);

   --  Return True if there is at least one callback in the list.
   function Has_Callbacks (List : Callback_List) return Boolean;
   pragma Inline (Has_Callbacks);
private
   type Cb_Cell;
   type Callback_Handle is access Cb_Cell;

   type Cb_Cell is record
      T : Std_Time;
      Mode : Callback_Mode;
      Proc : Callback_Acc;
      Arg : System.Address;
      Next : Callback_Handle;
   end record;

   type Callback_List is limited record
      First, Last : Callback_Handle := null;
   end record;

   type Callback_Time_List is limited record
      First : Callback_Handle := null;
      First_Timeout : Std_Time := Std_Time'Last;
   end record;
end Grt.Callbacks;
