diff --git a/lib/lpp/lfr_time_management/apb_lfr_time_management.vhd b/lib/lpp/lfr_time_management/apb_lfr_time_management.vhd new file mode 100644 --- /dev/null +++ b/lib/lpp/lfr_time_management/apb_lfr_time_management.vhd @@ -0,0 +1,174 @@ +---------------------------------------------------------------------------------- +-- Company: +-- Engineer: +-- +-- Create Date: 11:17:05 07/02/2012 +-- Design Name: +-- Module Name: apb_lfr_time_management - Behavioral +-- Project Name: +-- Target Devices: +-- Tool versions: +-- Description: +-- +-- Dependencies: +-- +-- Revision: +-- Revision 0.01 - File Created +-- Additional Comments: +-- +---------------------------------------------------------------------------------- +library IEEE; +use IEEE.STD_LOGIC_1164.ALL; +use IEEE.NUMERIC_STD.ALL; +library grlib; +use grlib.amba.all; +use grlib.stdlib.all; +use grlib.devices.all; +library lpp; +use lpp.apb_devices_list.all; +use lpp.lpp_lfr_time_management.all; + +entity apb_lfr_time_management is + +generic( + pindex : integer := 0; --! APB slave index + paddr : integer := 0; --! ADDR field of the APB BAR + pmask : integer := 16#fff#; --! MASK field of the APB BAR + pirq : integer := 0; --! 2 consecutive IRQ lines are used + masterclk : integer := 25000000; --! master clock in Hz + otherclk : integer := 49152000; --! other clock in Hz + finetimeclk : integer := 65536 --! divided clock used for the fine time counter + ); + +Port ( + clk25MHz : in STD_LOGIC; --! Clock + clk49_152MHz : in STD_LOGIC; --! secondary clock + resetn : in STD_LOGIC; --! Reset + grspw_tick : in STD_LOGIC; --! grspw signal asserted when a valid time-code is received + apbi : in apb_slv_in_type; --! APB slave input signals + apbo : out apb_slv_out_type; --! APB slave output signals + coarse_time : out std_logic_vector(31 downto 0); --! coarse time + fine_time : out std_logic_vector(31 downto 0) --! fine time + ); + +end apb_lfr_time_management; + +architecture Behavioral of apb_lfr_time_management is + +constant REVISION : integer := 1; + +--! the following types are defined in the grlib amba package +--! subtype amba_config_word is std_logic_vector(31 downto 0); +--! type apb_config_type is array (0 to NAPBCFG-1) of amba_config_word; +constant pconfig : apb_config_type := ( +--! 0 => ahb_device_reg (VENDOR_LPP, LPP_ROTARY, 0, REVISION, 0), + 0 => ahb_device_reg (19, 14, 0, REVISION, pirq), + 1 => apb_iobar(paddr, pmask)); + +type apb_lfr_time_management_Reg is record + ctrl : std_logic_vector(31 downto 0); + coarse_time_load : std_logic_vector(31 downto 0); + coarse_time : std_logic_vector(31 downto 0); + fine_time : std_logic_vector(31 downto 0); + next_commutation : std_logic_vector(31 downto 0); +end record; + +signal r : apb_lfr_time_management_Reg; +signal Rdata : std_logic_vector(31 downto 0); +signal force_tick : std_logic; +signal previous_force_tick : std_logic; +signal soft_tick : std_logic; +signal reset_next_commutation : std_logic; + +begin + +lfrtimemanagement0: lfr_time_management +generic map(masterclk => masterclk, timeclk => otherclk, finetimeclk => finetimeclk) +Port map( master_clock => clk25MHz, time_clock => clk49_152MHz, resetn => resetn, + grspw_tick => grspw_tick, soft_tick => soft_tick, + coarse_time_load => r.coarse_time_load, coarse_time => r.coarse_time, fine_time => r.fine_time, + next_commutation => r.next_commutation, reset_next_commutation => reset_next_commutation, + irq1 => apbo.pirq(pirq), irq2 => apbo.pirq(pirq+1) ); + +process(resetn,clk25MHz, reset_next_commutation) +begin + + if resetn = '0' then + r.coarse_time_load <= x"80000000"; + r.ctrl <= x"00000000"; + r.next_commutation <= x"ffffffff"; + force_tick <= '0'; + previous_force_tick <= '0'; + soft_tick <= '0'; + + elsif reset_next_commutation = '1' then + r.next_commutation <= x"ffffffff"; + + elsif clk25MHz'event and clk25MHz = '1' then + + previous_force_tick <= force_tick; + force_tick <= r.ctrl(0); + if (previous_force_tick = '0') and (force_tick = '1') then + soft_tick <= '1'; + else + soft_tick <= '0'; + end if; + +--APB Write OP + if (apbi.psel(pindex) and apbi.penable and apbi.pwrite) = '1' then + case apbi.paddr(7 downto 2) is + when "000000" => + r.ctrl <= apbi.pwdata(31 downto 0); + when "000001" => + r.coarse_time_load <= apbi.pwdata(31 downto 0); + when "000100" => + r.next_commutation <= apbi.pwdata(31 downto 0); + when others => + r.coarse_time_load <= x"00000000"; + end case; + elsif r.ctrl(0) = '1' then + r.ctrl(0) <= '0'; + end if; + +--APB READ OP + if (apbi.psel(pindex) and (not apbi.pwrite)) = '1' then + case apbi.paddr(7 downto 2) is + when "000000" => + Rdata(31 downto 24) <= r.ctrl(31 downto 24); + Rdata(23 downto 16) <= r.ctrl(23 downto 16); + Rdata(15 downto 8) <= r.ctrl(15 downto 8); + Rdata(7 downto 0) <= r.ctrl(7 downto 0); + when "000001" => + Rdata(31 downto 24) <= r.coarse_time_load(31 downto 24); + Rdata(23 downto 16) <= r.coarse_time_load(23 downto 16); + Rdata(15 downto 8) <= r.coarse_time_load(15 downto 8); + Rdata(7 downto 0) <= r.coarse_time_load(7 downto 0); + when "000010" => + Rdata(31 downto 24) <= r.coarse_time(31 downto 24); + Rdata(23 downto 16) <= r.coarse_time(23 downto 16); + Rdata(15 downto 8) <= r.coarse_time(15 downto 8); + Rdata(7 downto 0) <= r.coarse_time(7 downto 0); + when "000011" => + Rdata(31 downto 24) <= r.fine_time(31 downto 24); + Rdata(23 downto 16) <= r.fine_time(23 downto 16); + Rdata(15 downto 8) <= r.fine_time(15 downto 8); + Rdata(7 downto 0) <= r.fine_time(7 downto 0); + when "000100" => + Rdata(31 downto 24) <= r.next_commutation(31 downto 24); + Rdata(23 downto 16) <= r.next_commutation(23 downto 16); + Rdata(15 downto 8) <= r.next_commutation(15 downto 8); + Rdata(7 downto 0) <= r.next_commutation(7 downto 0); + when others => + Rdata(31 downto 0) <= x"00000000"; + end case; + end if; + + end if; + apbo.pconfig <= pconfig; +end process; + +apbo.prdata <= Rdata when apbi.penable = '1' ; +coarse_time <= r.coarse_time; +fine_time <= r.fine_time; + +end Behavioral; \ No newline at end of file diff --git a/lib/lpp/lfr_time_management/lfr_time_management.vhd b/lib/lpp/lfr_time_management/lfr_time_management.vhd new file mode 100644 --- /dev/null +++ b/lib/lpp/lfr_time_management/lfr_time_management.vhd @@ -0,0 +1,240 @@ +---------------------------------------------------------------------------------- +-- Company: +-- Engineer: +-- +-- Create Date: 11:14:05 07/02/2012 +-- Design Name: +-- Module Name: lfr_time_management - Behavioral +-- Project Name: +-- Target Devices: +-- Tool versions: +-- Description: +-- +-- Dependencies: +-- +-- Revision: +-- Revision 0.01 - File Created +-- Additional Comments: +-- +---------------------------------------------------------------------------------- +library IEEE; +use IEEE.STD_LOGIC_1164.ALL; +use IEEE.NUMERIC_STD.ALL; +library lpp; +use lpp.general_purpose.Clk_divider; + +entity lfr_time_management is + generic ( + masterclk : integer := 25000000; -- master clock in Hz + timeclk : integer := 49152000; -- 2nd clock in Hz + finetimeclk : integer := 65536; -- divided clock used for the fine time counter + nb_clk_div_ticks : integer := 1 -- nb ticks before commutation to AUTO state + ); + Port ( + master_clock : in std_logic; --! Clock + time_clock : in std_logic; --! 2nd Clock + resetn : in std_logic; --! Reset + grspw_tick : in std_logic; + soft_tick : in std_logic; --! soft tick, load the coarse_time value + coarse_time_load : in std_logic_vector(31 downto 0); + coarse_time : out std_logic_vector(31 downto 0); + fine_time : out std_logic_vector(31 downto 0); + next_commutation : in std_logic_vector(31 downto 0); + reset_next_commutation: out std_logic; + irq1 : out std_logic; + irq2 : out std_logic + ); +end lfr_time_management; + +architecture Behavioral of lfr_time_management is + +signal resetn_clk_div : std_logic; +signal clk_div : std_logic; +-- +signal flag : std_logic; +signal s_coarse_time : std_logic_vector(31 downto 0); +signal previous_coarse_time_load : std_logic_vector(31 downto 0); +signal cpt : integer range 0 to 100000; +signal secondary_cpt : integer range 0 to 72000; +-- +signal sirq1 : std_logic; +signal sirq2 : std_logic; +signal cpt_next_commutation : integer range 0 to 100000; +signal p_next_commutation : std_logic_vector(31 downto 0); +signal latched_next_commutation : std_logic_vector(31 downto 0); +signal p_clk_div : std_logic; +-- +type state_type is (auto, slave); +signal state : state_type; +type timer_type is (idle, engaged); +signal commutation_timer : timer_type; + +begin + +--******************************************* +-- COMMUTATION TIMER AND INTERRUPT GENERATION +process(master_clock, resetn) +begin + + if resetn = '0' then + commutation_timer <= idle; + cpt_next_commutation <= 0; + sirq1 <= '0'; + sirq2 <= '0'; + latched_next_commutation <= x"ffffffff"; + + elsif master_clock'event and master_clock = '1' then + + case commutation_timer is + + when idle => + sirq1 <= '0'; + sirq2 <= '0'; + if s_coarse_time = latched_next_commutation then + commutation_timer <= engaged; -- transition to state "engaged" + sirq1 <= '1'; -- start the pulse on sirq1 + latched_next_commutation <= x"ffffffff"; + elsif not(p_next_commutation = next_commutation) then -- next_commutation has changed + latched_next_commutation <= next_commutation; -- latch the value + else + commutation_timer <= idle; + end if; + + when engaged => + sirq1 <= '0'; -- stop the pulse on sirq1 + if not(p_clk_div = clk_div) and clk_div = '1' then -- detect a clk_div raising edge + if cpt_next_commutation = 65536 then + cpt_next_commutation <= 0; + commutation_timer <= idle; + sirq2 <= '1'; -- start the pulse on sirq2 + else + cpt_next_commutation <= cpt_next_commutation + 1; + end if; + end if; + + when others => + commutation_timer <= idle; + + end case; + + p_next_commutation <= next_commutation; + p_clk_div <= clk_div; + + end if; + +end process; + +irq1 <= sirq1; +irq2 <= sirq2; +reset_next_commutation <= '0'; + +-- +--******************************************* + +--********************** +-- synchronization stage +process(master_clock, resetn) -- resynchronisation with clk +begin + + if resetn = '0' then + coarse_time(31 downto 0) <= x"80000000"; -- set the most significant bit of the coarse time to 1 on reset + + elsif master_clock'event and master_clock = '1' then + coarse_time(31 downto 0) <= s_coarse_time(31 downto 0); -- coarse_time is changed synchronously with clk + end if; + +end process; +-- +--********************** + + +process(clk_div, resetn, grspw_tick, soft_tick, flag, coarse_time_load) -- +begin + + if resetn = '0' then + flag <= '0'; + cpt <= 0; + secondary_cpt <= 0; + s_coarse_time <= x"80000000"; -- set the most significant bit of the coarse time to 1 on reset + previous_coarse_time_load <= x"80000000"; + state <= auto; + + elsif grspw_tick = '1' or soft_tick = '1' then + if flag = '1' then -- coarse_time_load shall change at least 1/65536 s before the timecode + s_coarse_time <= coarse_time_load; + flag <= '0'; + else -- if coarse_time_load has not changed, increment the value autonomously + s_coarse_time <= std_logic_vector(unsigned(s_coarse_time) + 1); + end if; + cpt <= 0; + secondary_cpt <= 0; + state <= slave; + + elsif clk_div'event and clk_div = '1' then + + case state is + + when auto => + if cpt = 65535 then + if flag = '1' then + s_coarse_time <= coarse_time_load; + flag <= '0'; + else + s_coarse_time <= std_logic_vector(unsigned(s_coarse_time) + 1); + end if; + cpt <= 0; + secondary_cpt <= secondary_cpt + 1; + else + cpt <= cpt + 1 ; + end if; + + when slave => + if cpt = 65536 + nb_clk_div_ticks then -- 1 / 65536 = 15.259 us + state <= auto; -- commutation to AUTO state + if flag = '1' then + s_coarse_time <= coarse_time_load; + flag <= '0'; + else + s_coarse_time <= std_logic_vector(unsigned(s_coarse_time) + 1); + end if; + cpt <= nb_clk_div_ticks; -- reset cpt at nb_clk_div_ticks + secondary_cpt <= secondary_cpt + 1; + else + cpt <= cpt + 1; + end if; + + when others => + state <= auto; + + end case; + + if secondary_cpt > 60 then + s_coarse_time(31) <= '1'; + end if; + + if not(previous_coarse_time_load = coarse_time_load) then + flag <= '1'; + end if; + + previous_coarse_time_load <= coarse_time_load; + + end if; + +end process; + +fine_time <= std_logic_vector(to_unsigned(cpt, 32)); + +-- resetn grspw_tick soft_tick resetn_clk_div +-- 0 0 0 0 +-- 0 0 1 0 +-- 0 1 0 0 +-- 0 1 1 0 +-- 1 0 0 1 +-- 1 0 1 0 +-- 1 1 0 0 +-- 1 1 1 0 +resetn_clk_div <= '1' when ( (resetn='1') and (grspw_tick='0') and (soft_tick='0') ) else '0'; +Clk_divider0 : Clk_divider -- the target frequency is 65536 Hz +generic map (timeclk,finetimeclk) port map ( time_clock, resetn_clk_div, clk_div); + +end Behavioral; \ No newline at end of file diff --git a/lib/lpp/lfr_time_management/lpp_lfr_time_management.vhd b/lib/lpp/lfr_time_management/lpp_lfr_time_management.vhd new file mode 100644 --- /dev/null +++ b/lib/lpp/lfr_time_management/lpp_lfr_time_management.vhd @@ -0,0 +1,83 @@ +---------------------------------------------------------------------------------- +-- Company: +-- Engineer: +-- +-- Create Date: 13:04:01 07/02/2012 +-- Design Name: +-- Module Name: lpp_lfr_time_management - Behavioral +-- Project Name: +-- Target Devices: +-- Tool versions: +-- Description: +-- +-- Dependencies: +-- +-- Revision: +-- Revision 0.01 - File Created +-- Additional Comments: +-- +---------------------------------------------------------------------------------- +library IEEE; +use IEEE.STD_LOGIC_1164.all; +library grlib; +use grlib.amba.all; +use grlib.stdlib.all; +use grlib.devices.all; + +package lpp_lfr_time_management is + +--*************************** +-- APB_LFR_TIME_MANAGEMENT + +component apb_lfr_time_management is + + generic( + pindex : integer := 0; --! APB slave index + paddr : integer := 0; --! ADDR field of the APB BAR + pmask : integer := 16#fff#; --! MASK field of the APB BAR + pirq : integer := 0; --! 2 consecutive IRQ lines are used + masterclk : integer := 25000000; --! master clock in Hz + timeclk : integer := 49152000; --! other clock in Hz + finetimeclk : integer := 65536 --! divided clock used for the fine time counter + ); + + Port ( + clk25MHz : in STD_LOGIC; --! Clock + clk49_152MHz : in STD_LOGIC; --! secondary clock + resetn : in STD_LOGIC; --! Reset + grspw_tick : in STD_LOGIC; --! grspw signal asserted when a valid time-code is received + apbi : in apb_slv_in_type; --! APB slave input signals + apbo : out apb_slv_out_type; --! APB slave output signals + coarse_time : out std_logic_vector(31 downto 0); --! coarse time + fine_time : out std_logic_vector(31 downto 0) --! fine time + ); + +end component; + +component lfr_time_management is + + generic ( + masterclk : integer := 25000000; -- master clock in Hz + timeclk : integer := 49152000; -- 2nd clock in Hz + finetimeclk : integer := 65536; -- divided clock used for the fine time counter + nb_clk_div_ticks : integer := 1 -- nb ticks before commutation to AUTO state + ); + Port ( + master_clock : in std_logic; --! Clock + time_clock : in std_logic; --! 2nd Clock + resetn : in std_logic; --! Reset + grspw_tick : in std_logic; + soft_tick : in std_logic; --! soft tick, load the coarse_time value + coarse_time_load : in std_logic_vector(31 downto 0); + coarse_time : out std_logic_vector(31 downto 0); + fine_time : out std_logic_vector(31 downto 0); + next_commutation : in std_logic_vector(31 downto 0); + reset_next_commutation: out std_logic; + irq1 : out std_logic; + irq2 : out std_logic + ); + +end component; + +end lpp_lfr_time_management; + diff --git a/lib/lpp/lfr_time_management/vhdlsyn.txt b/lib/lpp/lfr_time_management/vhdlsyn.txt new file mode 100644 --- /dev/null +++ b/lib/lpp/lfr_time_management/vhdlsyn.txt @@ -0,0 +1,3 @@ +apb_lfr_time_management.vhd +lfr_time_management.vhd +lpp_lfr_time_management.vhd