--    FoxBone_TimeBase1.vhd
--    release 1.0  06/08/2006
--    FoxBone_TimeBase1 realizes 1 precise 32 bit timer acting on the FREE16 line of the JP3 extension 
--    connector of the FoxVHDL Board as an example of the Hard Real Time 
--    possibilities for the coupling of logic FPGA components and the Linux operating system 
--    It uses the FoxBone specifications release 0.7.
--    It uses the 32 bit TimeBase1.vhd file as a component.
--		For more info see: http://www.acmesystems.it/?id=120
--      Author: Roberto Asquini
--		Copyright (C) 2006 Acme Systems srl (http://www.acmesystems.it)
--		
--		This 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 example 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.
--		
--		To have a copy of the GNU General Public License write to the Free Software
--		Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA

library ieee;
use ieee.std_logic_1164.all;
use ieee.std_logic_unsigned.all;
library proasic3;

-- The 16 bit registers enabled in this FoxBone example are:
-- 0x0004: readable register returning the FoxBone release (presently 0x0070 or 0.7.0)
-- 0x0005: first hardware application word returning 0x2323 (FoxBoneExamples)
-- 0x0006: second hardware application word returning 0x0001 (stands for example 1)
-- 0x0007: third hardware application word returning 0x0001 (release 1 of example 1)

-- 0x0100: read/write register with the bit 0 meaning enable for the TimeBase: 1 = enabled
-- 0x0102: read/write register with the low 16 bit part of the time base preset value
-- 0x0103: read/write register with the high 16 bit part of the time base preset value

entity FoxBone_TimeBase1 is
  port(-- Fox Bone Interface signals
    FOXBONE_BUS : inout std_logic_vector(15 downto 0); -- FoxBone data bus input/output lines. 
    ADDRESS_WRITE : in std_logic;       -- to strobe the actual address to be used.  
    DATA_WRITE : in std_logic;          -- to strobe the actual data in the previously addressed register. 
    DATA_READ : in std_logic;           -- to enable the addressed register to drive the FoxBone data lines.
                                        -- as to be read from the Fox Board software
    RESETN : in std_logic;              -- active low (resets the eventcounter and the Alarm line
    CLOCK : in std_logic; -- main clock input 64MHz
    TIMEBASEOUT : out std_logic;        -- Time Base main output
    TIMEBASEHALFOUT : out std_logic  -- TimeBase divided by two with 50% duty cycle.

 );     
end FoxBone_TimeBase1;

architecture Mixed of FoxBone_TimeBase1 is 

  constant RELEASE_REGISTER_0_ADDRESS : std_logic_vector := x"0004"; 
  constant RELEASE_REGISTER_1_ADDRESS : std_logic_vector := x"0005"; 
  constant RELEASE_REGISTER_2_ADDRESS : std_logic_vector := x"0006"; 
  constant RELEASE_REGISTER_3_ADDRESS : std_logic_vector := x"0007"; 

  constant RELEASE_REGISTER_0_VALUE : std_logic_vector := x"0070"; 
  constant RELEASE_REGISTER_1_VALUE : std_logic_vector := x"2323"; 
  constant RELEASE_REGISTER_2_VALUE : std_logic_vector := x"0001"; 
  constant RELEASE_REGISTER_3_VALUE : std_logic_vector := x"0001"; 

  constant TIMEBASE_ENABLE_CONTROL_REGISTER_ADDRESS  : std_logic_vector := x"0100"; 
  constant TIMEBASE_LOW_VALUE_CONTROL_REGISTER_ADDRESS  : std_logic_vector := x"0102"; 
  constant TIMEBASE_HIGH_VALUE_CONTROL_REGISTER_ADDRESS  : std_logic_vector := x"0103"; 

  component TimeBase1
    port(
      CLOCK : in std_logic;          -- input clock 64 MHz. 
      TIMEBASEOUT : out std_logic; -- out timebase signal.  
      RESETN : in std_logic;         -- master reset signal (active low)
      DIVIDERVALUE : in std_logic_vector(31 downto 0); -- 32 bit divider value
      RUNCOUNTER : out std_logic_vector(31 downto 0) -- 32 bit testing output of the running counter
    );     
  end component;
 
-- internal signals (going between components)   
  signal Address : std_logic_vector (15 downto 0); -- lines between the FoxBoneAddrLatch outputs 
                                                   -- and all the FoxBone registers decoding logic

  -- registers for the 32 bit timebase divider value (0 stops timebase; always write subtracting 1 from the desired value)
  signal TimeBaseLow : std_logic_vector(15 downto 0);
  signal TimeBaseHigh : std_logic_vector(15 downto 0);

  signal TimeBaseValue : std_logic_vector(31 downto 0);

  -- register to control the TimeBase on/off state: 
  --    bit 0='0' -> Timebase off;  
  --    bit 0='1' -> TimeBase on (starting from 00000000 count)
  signal TimeBaseEnable : std_logic_vector(15 downto 0);

  signal TimeBaseOutput : std_logic; -- internal signal for the TimeBase output
  signal TimeBaseHalf50Duty : std_logic; -- internal signal (Time Base divided by two with 50 % duty cycle)

  signal stopTimeBase : std_logic; -- internal signal

  signal dummyRunCounter : std_logic_vector(31 downto 0); -- dummy signal to accommodate the testing running 
                                                          -- counter output of the TimeBase component.

-- here are the interconnections, the functional logic code blocks and the instantiation of all the 
-- required components of this VHDL source code file.
begin 
  
  -- this is the address register 
  Address <= (others => '0') when RESETN = '0' else
             FOXBONE_BUS when ADDRESS_WRITE = '1';

-------------------------------------------
  
  -- input from release registers
  FOXBONE_BUS <= RELEASE_REGISTER_0_VALUE when Address = RELEASE_REGISTER_0_ADDRESS and DATA_READ = '1' else
               (others=>'Z');         
  FOXBONE_BUS <= RELEASE_REGISTER_1_VALUE when Address = RELEASE_REGISTER_1_ADDRESS and DATA_READ = '1' else
               (others=>'Z');         
  FOXBONE_BUS <= RELEASE_REGISTER_2_VALUE when Address = RELEASE_REGISTER_2_ADDRESS and DATA_READ = '1' else
               (others=>'Z');         
  FOXBONE_BUS <= RELEASE_REGISTER_3_VALUE when Address = RELEASE_REGISTER_3_ADDRESS and DATA_READ = '1' else
               (others=>'Z');         

-------------------------------------------
  
  -- write operation to the TimeBase Enable Register to set its value
  TimeBaseEnable <= x"0001" when RESETN = '0' else
                    FOXBONE_BUS when Address = TIMEBASE_ENABLE_CONTROL_REGISTER_ADDRESS and DATA_WRITE = '1';

  -- write operation to the TimeBase Low Value Register to set its value
  TimeBaseLow <= x"8fff" when RESETN = '0' else 
                 FOXBONE_BUS when Address = TIMEBASE_LOW_VALUE_CONTROL_REGISTER_ADDRESS and DATA_WRITE = '1';
                    
  -- write operation to the TimeBase High Value Register to set its value
  TimeBaseHigh <= x"03d0" when RESETN = '0' else 
                  FOXBONE_BUS when Address = TIMEBASE_HIGH_VALUE_CONTROL_REGISTER_ADDRESS and DATA_WRITE = '1';
                 
  -- read from the TimeBase Enable Register to read its value
  FOXBONE_BUS <= TimeBaseEnable when Address = TIMEBASE_ENABLE_CONTROL_REGISTER_ADDRESS and DATA_READ = '1' else
               (others=>'Z');         
  -- read from the TimeBase Low Value Register to read its value
  FOXBONE_BUS <= TimeBaseLow when Address = TIMEBASE_LOW_VALUE_CONTROL_REGISTER_ADDRESS and DATA_READ = '1' else
               (others=>'Z');         
  -- read from the TimeBase High Value Register to read its value
  FOXBONE_BUS <= TimeBaseHigh when Address = TIMEBASE_HIGH_VALUE_CONTROL_REGISTER_ADDRESS and DATA_READ = '1' else
               (others=>'Z');         

-------------------------------------------
  -- the TimeBase will be stopped (stopTimeBase<='0') when either RESETN or bit 0 of TimeBaseEnable are at '0' value.
  stopTimeBase <= RESETN and TimeBaseEnable(0);  -- we are operating with negative logic so we need 'and' here!! 

  -- here is the join of the two 16 bit TimeBase values to form the complete 32 bit TimeBase signal value
  TimeBaseValue <= TimeBaseHigh & TimeBaselow;

  -- this is the instantiation of the TimeBase component.
  myTimeBase : TimeBase1
  port map (
    CLOCK => CLOCK,                -- input clock 64 MHz. 
    TIMEBASEOUT => TimeBaseOutput, -- out timebase signal.  
    RESETN => stopTimeBase,        -- reset signal (active low)
    DIVIDERVALUE => TimeBaseValue, -- 32 bit divider value
    RUNCOUNTER => dummyRunCounter
  );

  -- this process takes the output of the TimeBase and divide it by two obtaining a 50 % duty cycle signal 
  -- with half the frequency of the original TimeBase signal.
  timebaseDividerProcess : process (stopTimeBase, CLOCK, TimeBaseOutput)
  begin
    if ( stopTimeBase = '0' ) then 
      TimeBaseHalf50Duty <= '0';  -- initialization
    elsif ( CLOCK'event and CLOCK = '1') then
      if (TimeBaseOutput = '1') then
        TimeBaseHalf50Duty <= not TimeBaseHalf50Duty;
      end if;
    end if;
  end process;

  TIMEBASEOUT <= TimeBaseOutput;
  TIMEBASEHALFOUT <= TimeBaseHalf50Duty;

end Mixed; 