-
Pieter Donker authoredPieter Donker authored
Code owners
Assign users and groups as approvers for specific file changes. Learn more.
common_counter.vhd 4.47 KiB
-------------------------------------------------------------------------------
--
-- Copyright (C) 2009
-- ASTRON (Netherlands Institute for Radio Astronomy) <http://www.astron.nl/>
-- P.O.Box 2, 7990 AA Dwingeloo, The Netherlands
--
-- This program 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 program 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/>.
--
-------------------------------------------------------------------------------
-- Purpose : Counter with extra options
-- Description:
-- - default wrap at 2**g_width or special wrap at fixed g_max or dynamically via cnt_max
-- - count can be clipped instead of wrapped by setting g_clip to True.
-- - default increment +1 or other g_step_size
-- - external clr
-- - external load with g_init or dynamically via load
-- Remarks:
-- . If g_max = 2**g_width then use g_max=0 for default wrap and avoid truncation warning.
-- The check g_max = 2**g_width does not work for g_width >= 31 due to that the INTEGER
-- range in VHDL is limited to -2**31 to +2**31-1. Therefore detect that g_max = 2**g_width
-- via ceil_log2(g_max+1)>g_width and use this to init the cnt_max input.
library IEEE;
use IEEE.std_logic_1164.all;
use work.common_pkg.all;
entity common_counter is
generic (
g_latency : natural := 1; -- default 1 for registered count output, use 0 for immediate combinatorial count output
g_init : integer := 0;
g_width : natural := 32;
g_max : natural := 0; -- default 0 to disable the g_max setting.
g_step_size : integer := 1; -- counting in steps of g_step_size, can be + or -
g_clip : boolean := false -- when True, counter will clip at g_max, if g_max = 0 and g_step_size > 0, the counter clips at 2**g_width -1.
);
port (
rst : in std_logic := '0'; -- either use asynchronous rst or synchronous cnt_clr
clk : in std_logic;
clken : in std_logic := '1';
cnt_clr : in std_logic := '0'; -- synchronous cnt_clr is only interpreted when clken is active
cnt_ld : in std_logic := '0'; -- cnt_ld loads the output count with the input load value, independent of cnt_en
cnt_en : in std_logic := '1';
cnt_max : in std_logic_vector(g_width - 1 downto 0) := sel_a_b( g_step_size > 0 and g_max = 0, array_init('1', g_width),
sel_a_b( ceil_log2(g_max + 1) > g_width, array_init('1', g_width), TO_UVEC(g_max, g_width) )); -- see remarks
load : in std_logic_vector(g_width - 1 downto 0) := TO_SVEC(g_init, g_width);
count : out std_logic_vector(g_width - 1 downto 0)
);
end common_counter;
architecture rtl of common_counter is
signal reg_count : std_logic_vector(count'range) := TO_SVEC(g_init, g_width); -- in case rst is not used
signal nxt_count : std_logic_vector(count'range) := TO_SVEC(g_init, g_width); -- to avoid Warning: NUMERIC_STD.">=": metavalue detected, returning FALSE, when using unsigned()
signal comb_count : std_logic_vector(count'range) := TO_SVEC(g_init, g_width); -- to avoid Warning: NUMERIC_STD.">=": metavalue detected, returning FALSE, when using unsigned()
begin
comb_count <= nxt_count;
count <= comb_count when g_latency = 0 else reg_count;
assert g_step_size /= 0 report "common_counter: g_step_size must be /= 0" severity FAILURE;
p_clk : process (rst, clk)
begin
if rst = '1' then
reg_count <= TO_SVEC(g_init, g_width);
elsif rising_edge(clk) then
if clken = '1' then
reg_count <= nxt_count;
end if;
end if;
end process;
p_count : process(reg_count, cnt_clr, cnt_en, cnt_ld, load, cnt_max)
begin
nxt_count <= reg_count;
if cnt_clr = '1' then
nxt_count <= (others => '0');
elsif cnt_ld = '1' then
nxt_count <= load;
elsif cnt_en = '1' and reg_count = cnt_max then
if not g_clip then
nxt_count <= (others => '0');
end if;
elsif cnt_en = '1' then
nxt_count <= INCR_UVEC(reg_count, g_step_size);
end if;
end process;
end rtl;