---------------------------------------------------------------------------------------------------------
--
-- Name:            sfd700_pkg.vhd
-- Created:         July 2023
-- Author(s):       Philip Smart
-- Description:     SFD700 CPLD package file.
--                                                     
--                  This module contains static declarations and functions for the SFD700 Floopy Disk
--                  Interface project.
--
-- Credits:         
-- Copyright:       (c) 2018-23 Philip Smart <philip.smart@net2net.org>
--
-- History:         July 2023 - Initial write.
--                  Apr  2026 - Synchroniser bug fixes.
--
---------------------------------------------------------------------------------------------------------
-- This source file 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 3 of the License, or
-- (at your option) any later version.
--
-- This source file 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 <http:--www.gnu.org-licenses->.
---------------------------------------------------------------------------------------------------------

library ieee;
library pkgs;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
use ieee.math_real.all;

package sfd700_pkg is

    ------------------------------------------------------------ 
    -- Constants
    ------------------------------------------------------------ 

    -- Potential logic state constants.
    constant YES                      : std_logic := '1';
    constant NO                       : std_logic := '0';
    constant HI                       : std_logic := '1';
    constant LO                       : std_logic := '0';
    constant ONE                      : std_logic := '1';
    constant ZERO                     : std_logic := '0';
    constant HIZ                      : std_logic := 'Z';

    -- Target hardware modes.
    constant MODE_MZ1200              : integer   := 0;
    constant MODE_MZ80A               : integer   := 0;
    constant MODE_MZ700               : integer   := 1;
    constant MODE_MZ80B               : integer   := 2;
    constant MODE_MZ800               : integer   := 3;
    constant MODE_MZ1500              : integer   := 4;
    constant MODE_MZ2000              : integer   := 5;
    constant MODE_MZ2200              : integer   := 6;

    ------------------------------------------------------------ 
    -- Configurable parameters.
    ------------------------------------------------------------ 

    -- Version of hdl.
    constant CPLD_VERSION             : integer   := 1;

    ------------------------------------------------------------ 
    -- Function prototypes
    ------------------------------------------------------------ 
    -- Find the maximum of two integers.
    function IntMax(a : in integer; b : in integer) return integer;

    -- Find the number of bits required to represent an integer.
    function log2ceil(arg : positive) return natural;

    -- Function to calculate the number of whole 'clock' cycles in a given time period, the period being in ns.
    function clockTicks(period : in integer; clock : in integer) return integer;

    -- Function to reverse the order of the bits in a standard logic vector.
    -- ie. 1010 becomes 0101
    function reverse_vector(slv:std_logic_vector) return std_logic_vector; 

    -- Function to convert an integer (0 or 1) into std_logic.
    --
    function to_std_logic(i : in integer) return std_logic;

    -- Function to return the value of a bit as an integer for array indexing etc.
    function bit_to_integer( s : std_logic ) return natural;    

    ------------------------------------------------------------ 
    -- Records
    ------------------------------------------------------------ 

    ------------------------------------------------------------ 
    -- Components
    ------------------------------------------------------------

end sfd700_pkg;

------------------------------------------------------------ 
-- Function definitions.
------------------------------------------------------------ 
package body sfd700_pkg is
    
    -- Find the maximum of two integers.
    function IntMax(a : in integer; b : in integer) return integer is
    begin
        if a > b then
            return a;
        else
            return b;
        end if;
    end function IntMax;

    -- Find the number of bits required to represent an integer.
    function log2ceil(arg : positive) return natural is
        variable tmp : positive     := 1;
        variable log : natural      := 0;
    begin
        if arg = 1 then
            return 0;
        end if;

        while arg > tmp loop
            tmp := tmp * 2;
            log := log + 1;
        end loop;
        return log;
    end function;

    -- Function to calculate the number of whole 'clock' cycles in a given time period, the period being in ns.
    -- Returns CEIL(period * clock / 1e9), i.e. the minimum number of clock ticks that span the period.
    function clockTicks(period : in integer; clock : in integer) return integer is
        variable ticks         : real;
        variable fracTicks     : real;
    begin
        ticks         := (Real(period) * Real(clock)) / 1000000000.0;
        fracTicks     := ticks - FLOOR(ticks);
        if fracTicks > 0.0001 then
            return Integer(FLOOR(ticks)) + 1;
        else
            return Integer(FLOOR(ticks));
        end if;
    end function;

    function reverse_vector(slv:std_logic_vector) return std_logic_vector is 
       variable target : std_logic_vector(slv'high downto slv'low); 
    begin 
      for idx in slv'high downto slv'low loop 
        target(idx) := slv(slv'low + (slv'high-idx)); 
      end loop; 
      return target; 
    end reverse_vector;

    function to_std_logic(i : in integer) return std_logic is
    begin
      if i = 0 then
        return '0';
      end if;
      return '1';
    end function;

    -- Function to return the value of a bit as an integer for array indexing etc.
    function bit_to_integer( s : std_logic ) return natural is
    begin
        if s = '1' then
            return 1;
        else
            return 0;
        end if;
    end function;
end package body;
