-
Notifications
You must be signed in to change notification settings - Fork 0
/
gc_frequency_meter.vhd
148 lines (125 loc) · 4.8 KB
/
gc_frequency_meter.vhd
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
--------------------------------------------------------------------------------
-- CERN BE-CO-HT
-- General Cores Library
-- https://www.ohwr.org/projects/general-cores
--------------------------------------------------------------------------------
--
-- unit name: gc_frequency_meter
--
-- description: Frequency meter with internal or external timebase.
--
--------------------------------------------------------------------------------
-- Copyright CERN 2012-2019
--------------------------------------------------------------------------------
-- Copyright and related rights are licensed under the Solderpad Hardware
-- License, Version 2.0 (the "License"); you may not use this file except
-- in compliance with the License. You may obtain a copy of the License at
-- http://solderpad.org/licenses/SHL-2.0.
-- Unless required by applicable law or agreed to in writing, software,
-- hardware and materials distributed under this License is distributed on an
-- "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
-- or implied. See the License for the specific language governing permissions
-- and limitations under the License.
--------------------------------------------------------------------------------
-- Principle of operation:
--
-- This block counts the number of pulses on CLK_IN_I during a period.
-- At the end of the period, the value is saved and the counter reset.
-- The saved value is available on FREQ_O, which is synchronized with
-- CLK_SYS_I if G_SYNC_OUT is True.
-- The width of the counter is defined by G_COUNTER_BITS.
--
-- - If g_WITH_INTERNAL_TIMEBASE is True:
-- The period is defined by an internal counter that generates a pulse
-- every G_CLK_SYS_FREQ CLK_SYS_I ticks.
--
-- - If g_WITH_INTERNAL_TIMEBASE is False:
-- The period is defined by PPS_P1_I
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
library work;
use work.gencores_pkg.all;
entity gc_frequency_meter is
generic (
g_WITH_INTERNAL_TIMEBASE : boolean := TRUE;
g_CLK_SYS_FREQ : integer;
-- if true, sync freq_o to the clk_sys domain
g_SYNC_OUT : boolean := FALSE;
g_COUNTER_BITS : integer := 32);
port (
clk_sys_i : in std_logic;
clk_in_i : in std_logic;
rst_n_i : in std_logic; -- not used, kept for backward compatibility
pps_p1_i : in std_logic;
-- synced to clk_in_i or clk_sys_i, depending on g_SYNC_OUT value
freq_o : out std_logic_vector(g_COUNTER_BITS-1 downto 0);
-- synced to clk_sys_i, always
freq_valid_o : out std_logic);
end gc_frequency_meter;
architecture arch of gc_frequency_meter is
signal gate_pulse, gate_pulse_synced : std_logic := '0';
signal cntr_gate : unsigned(g_COUNTER_BITS-1 downto 0) := (others => '0');
signal cntr_meas : unsigned(g_COUNTER_BITS-1 downto 0) := (others => '0');
signal freq_reg : std_logic_vector(g_COUNTER_BITS-1 downto 0) := (others => '0');
begin
gen_internal_timebase : if g_WITH_INTERNAL_TIMEBASE = TRUE generate
p_gate_counter : process(clk_sys_i)
begin
if rising_edge(clk_sys_i) then
if cntr_gate = g_CLK_SYS_FREQ-1 then
cntr_gate <= (others => '0');
gate_pulse <= '1';
else
cntr_gate <= cntr_gate + 1;
gate_pulse <= '0';
end if;
end if;
end process;
U_Sync_Gate : gc_pulse_synchronizer
port map (
clk_in_i => clk_sys_i,
clk_out_i => clk_in_i,
rst_n_i => '1',
d_ready_o => freq_valid_o,
d_p_i => gate_pulse,
q_p_o => gate_pulse_synced);
end generate gen_internal_timebase;
gen_external_timebase : if g_WITH_INTERNAL_TIMEBASE = FALSE generate
U_Sync_Gate : gc_pulse_synchronizer
port map (
clk_in_i => clk_sys_i,
clk_out_i => clk_in_i,
rst_n_i => '1',
d_ready_o => freq_valid_o,
d_p_i => pps_p1_i,
q_p_o => gate_pulse_synced);
end generate gen_external_timebase;
p_freq_counter : process (clk_in_i)
begin
if rising_edge(clk_in_i) then
if gate_pulse_synced = '1' then
freq_reg <= std_logic_vector(cntr_meas);
cntr_meas <= (others => '0');
else
cntr_meas <= cntr_meas + 1;
end if;
end if;
end process p_freq_counter;
gen_with_sync_out : if g_SYNC_OUT generate
cmp_gc_sync_word_wr : gc_sync_word_wr
generic map (
g_AUTO_WR => TRUE,
g_WIDTH => g_COUNTER_BITS)
port map (
clk_in_i => clk_in_i,
rst_in_n_i => '1',
clk_out_i => clk_sys_i,
rst_out_n_i => '1',
data_i => freq_reg,
data_o => freq_o);
end generate gen_with_sync_out;
gen_without_sync_out : if not g_SYNC_OUT generate
freq_o <= freq_reg;
end generate gen_without_sync_out;
end arch;