----------------------------------------------------------------------------------
-- Company:       Gunnar Johannsen (gjo)
-- Engineer:      Uni Kiel RTsys
-- 
-- Create Date:    08:46:21 04/30/2013 
-- Design Name: 
-- Module Name:    ABO - Behavioral 
-- Project Name: 
-- Target Devices: 
-- Tool versions: 
-- Description: ABO with hugh multiplexers to choose the correct value at 
--              the end of each tick. One of the first ABO-versions.
--              This Abo is directly implemtened into a process and if cases
--              for multiplexers were generated.
--
-- Dependencies: 
--
-- Revision: 
-- Revision 0.01 - File Created
-- Additional Comments: 
--
----------------------------------------------------------------------------------
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;

-- Uncomment the following library declaration if using
-- arithmetic functions with Signed or Unsigned values
--use IEEE.NUMERIC_STD.ALL;

-- Uncomment the following library declaration if instantiating
-- any Xilinx primitives in this code.
--library UNISIM;
--use UNISIM.VComponents.all;

entity abo is
    Port ( tick_in : in STD_LOGIC;
           A_in : in  STD_LOGIC;
           B_in : in  STD_LOGIC;
           O1 : out  STD_LOGIC;
           O2 : out  STD_LOGIC;
           A_out: out STD_LOGIC;
			  B_out: out STD_LOGIC
           );
end abo;

architecture Behavioral of abo is
 begin  
 
   abo_pr: process(tick_in)
      
   
     
   -- Variable declaration
   -- ****************************************************************************

   -- bool _entry, _go0_HandleA, _surf_HandleA_WaitA, _exit_HandleA, _surf_HandleB_WaitB, _exit_HandleB, _exit;
   variable u_entry : std_logic ;
   variable u_go0_HandleA: std_logic ;
   variable u_surf_HandleA_WaitA : std_logic ;
   variable u_exit_HandleA : std_logic ;
   variable u_surf_HandleB_WaitB : std_logic ;
   variable u_exit_HandleB : std_logic ;
   variable u_exit : std_logic ;

   -- static bool _depth_HandleA_WaitA = false, _depth_HandleB_WaitB = false;
   variable u_depth_HandleA_WaitA : std_logic ;
   variable u_depth_HandleB_WaitB : std_logic ;

   --  bool _empty_HandleA, _empty_HandleB;
   variable u_empty_HandleA : std_logic ;
   variable u_empty_HandleB : std_logic ;

   -- bool O1_entry, O1_exit_HandleA, O1_exit_HandleB, O1_exit, O2_entry, O2_exit, B_exit_HandleA;
--   variable O1_entry : std_logic := '0';
--   variable O1_exit_HandleA: std_logic := '0';
--   variable O1_exit_HandleB : std_logic := '0';
--   variable O1_exit : std_logic := '0';
--   variable O2_entry : std_logic := '0';
--   variable O2_exit : std_logic := '0';
--   variable B_exit_HandleA : std_logic := '0';
   
   variable O1_entry : std_logic;
   variable O1_exit_HandleA: std_logic;
   variable O1_exit_HandleB : std_logic;
   variable O1_exit : std_logic;
   variable O2_entry : std_logic;
   variable O2_exit : std_logic;
   variable B_exit_HandleA : std_logic;

   -- static bool _preO1 = UNDEFINED, _preO2 = UNDEFINED
   variable u_preO1 : std_logic ;
   variable u_preO2 : std_logic ;

   -- bool B_depth_HandleB_WaitB;
   variable B_depth_HandleB_WaitB : std_logic ;

   variable u_notInitial : std_logic := '0';
   variable u_notInitialDetect : std_logic:= '1';

   variable O1_int : std_logic ;
   variable O2_int : std_logic ;
   
   
   -- ****************************************************************************

   --  //tickstart(2);
   --  _signals2vars       --this is not needed in HW Syn.

   begin
     
    if (rising_edge(tick_in)) then
     
      -- RESET() initializes _notInitial = 0;
      u_entry := not(u_notInitial);   -- _entry indicates initial tick
      if ((not u_notInitial) = '1') then
        u_notInitial := u_notInitialDetect;
      end if;	 

--      u_notInitial <= u_notInitialDetect when (u_notInitial nand u_notInitial);

--    //O1 = false;
--    //O2 = false;      
      O1_entry := '0';
      O2_entry := '0';

--    //fork1(HandleB, 1) {
--    //HandleA:

--    // Merge paths before reaching conditional
      u_go0_HandleA := (u_entry or u_depth_HandleA_WaitA);

--    //  if (!A) {

--    //  pause;  // WaitA
--    // Replace this pause with a register "_surf_HandleA_WaitA" that indicates an active pause
      u_surf_HandleA_WaitA := (u_go0_HandleA and (not A_in)); -- // _depth_HandleA_WaitA is registered value

--    //  goto HandleA;
--    //}

      u_exit_HandleA := (u_go0_HandleA and A_in);

--    // The input B constitutes a "0th" copy of B that is always present
--    // Therefore, must create copy for following write to B
--    // B = true;
--    // O1 = true;
      B_exit_HandleA := '1';
      O1_exit_HandleA := '1';

--    // Compute "output pins" of thread HandleA
--    // This is analogous to the K0 and LEM/REM pins [1, Fig. 11.1]
--    // HandleA_term = _exit_HandleA;             // Just terminated
      u_empty_HandleA := not(u_entry or u_surf_HandleA_WaitA); --  // Dead thread - neither just started nor any active register

--    //} par {
--    //  HandleB:
--    //  pause;

--    // Must compute B here to include path coming from conditional testing B (depth_HandleB_WaitB) into WaitB-surface

--     B_depth_HandleB_WaitB <= _exit_HandleA ? B_exit_HandleA : B;  --// Pick right value of B; plain "B" is input value
      if (u_exit_HandleA = '1') then
         B_depth_HandleB_WaitB := B_exit_HandleA;
      else
         B_depth_HandleB_WaitB := B_in;
      end if;
      
      u_surf_HandleB_WaitB := (u_entry or (u_depth_HandleB_WaitB and (not B_depth_HandleB_WaitB)));  --// Set register _surf_HandleB_WaitB

--    //  if (!B) {
--    //    goto HandleB;
--    //  }
--    //  O1 = true;
      u_exit_HandleB := (u_depth_HandleB_WaitB and B_depth_HandleB_WaitB);
      O1_exit_HandleB := '1';

--    // Compute "output pins" of thread HandleB
      u_empty_HandleB := not(u_entry or u_surf_HandleB_WaitB);

--    //} join1(2);
--    // This corresponds to output K0 of Sychronizer circuit [1, Fig. 11.10]
--    // If this were not the basic block corresponding to the top-level exit node,
--    // we would have called this "_join_WaitAB"
      u_exit := (u_exit_HandleA or u_exit_HandleB)  -- // At least one thread must have just terminated
         and (u_exit_HandleA or u_empty_HandleA)    -- // HandleA has terminated or was already dead
         and (u_exit_HandleB or u_empty_HandleB);   -- // HandleB has terminated or was already dead

--    //O1 = false;
--    //O2 = true;
      O1_exit := '0';
      O2_exit := '1';

--    // Compute output values.
--    // This is where the nature of sequentiality becomes apparent:
--    // we always use the "last" write to a variable.
--    // For HW synthesis, would have to replace these by A_out, B_out, O1_out, O2_out
--    //A = A;       // Input A is not overwritten
--    B = B_depth_HandleB_WaitB;  // Possible optimization: replace B_depth_HandleB_WaitB by just B, as it is the final value of B
      B_out <= B_depth_HandleB_WaitB;  
--    O1 = _exit ? O1_exit : (_exit_HandleB ? O1_exit_HandleB : (_exit_HandleA ? O1_exit_HandleA : (_entry ? O1_entry : _preO1)));
      
      if (u_exit = '1') then
         O1 <= O1_exit;
         O1_int := O1_exit;
         else if (u_exit_HandleB = '1') then
            O1 <= O1_exit_HandleB;
            O1_int := O1_exit_HandleB;
            else if(u_exit_HandleA = '1') then
               O1 <= O1_exit_HandleA;
               O1_int := O1_exit_HandleA;
               else if(u_entry = '1') then
                  O1 <= O1_entry;
                  O1_int := O1_entry;
                  else
                  O1 <= u_preO1;
                  O1_int := u_preO1;
               end if;
            end if;
         end if;
      end if;
      
--     O2 = _exit ? O2_exit : (_entry ? O2_entry : _preO2);   
      if(u_exit = '1') then
         O2 <= O2_exit;
         O2_int := O2_exit;
         else if(u_entry = '1') then
            O2 <=  O2_entry;
            O2_int :=  O2_entry;
         else
            O2 <= u_preO2;
            O2_int := u_preO2;
         end if;
      end if;
       
      A_out <= A_in;
       
      -- FF are generated to save these values for the next tick
      u_depth_HandleA_WaitA := u_surf_HandleA_WaitA;
      u_depth_HandleB_WaitB := u_surf_HandleB_WaitB;
      u_preO1 := O1_int;
      u_preO2 := O2_int;
  
   end if;
   end process abo_pr;
end Behavioral;








