436 lines
13 KiB
VHDL
Executable File
436 lines
13 KiB
VHDL
Executable File
library IEEE;
|
|
use IEEE.std_logic_1164.ALL;
|
|
use IEEE.std_logic_ARITH.ALL;
|
|
use IEEE.std_logic_UNSIGNED.ALL;
|
|
--
|
|
-- Copyright (C) 2007, Peter C. Wallace, Mesa Electronics
|
|
-- http://www.mesanet.com
|
|
--
|
|
-- This program is is licensed under a disjunctive dual license giving you
|
|
-- the choice of one of the two following sets of free software/open source
|
|
-- licensing terms:
|
|
--
|
|
-- * GNU General Public License (GPL), version 2.0 or later
|
|
-- * 3-clause BSD License
|
|
--
|
|
--
|
|
-- The GNU GPL License:
|
|
--
|
|
-- 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 2 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, write to the Free Software
|
|
-- Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
|
--
|
|
--
|
|
-- The 3-clause BSD License:
|
|
--
|
|
-- Redistribution and use in source and binary forms, with or without
|
|
-- modification, are permitted provided that the following conditions
|
|
-- are met:
|
|
--
|
|
-- * Redistributions of source code must retain the above copyright
|
|
-- notice, this list of conditions and the following disclaimer.
|
|
--
|
|
-- * Redistributions in binary form must reproduce the above
|
|
-- copyright notice, this list of conditions and the following
|
|
-- disclaimer in the documentation and/or other materials
|
|
-- provided with the distribution.
|
|
--
|
|
-- * Neither the name of Mesa Electronics nor the names of its
|
|
-- contributors may be used to endorse or promote products
|
|
-- derived from this software without specific prior written
|
|
-- permission.
|
|
--
|
|
--
|
|
-- Disclaimer:
|
|
--
|
|
-- THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
|
-- "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
|
-- LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
|
|
-- FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
|
|
-- COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
|
|
-- INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
|
-- BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
|
-- LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
|
-- CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
|
-- LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
|
|
-- ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
|
-- POSSIBILITY OF SUCH DAMAGE.
|
|
--
|
|
|
|
entity qcounter is
|
|
generic (
|
|
buswidth : integer := 32
|
|
);
|
|
port (
|
|
obus: out std_logic_vector (buswidth-1 downto 0);
|
|
ibus: in std_logic_vector (buswidth-1 downto 0);
|
|
quada: in std_logic;
|
|
quadb: in std_logic;
|
|
index: in std_logic;
|
|
loadccr: in std_logic;
|
|
readccr: in std_logic;
|
|
readcount: in std_logic;
|
|
countclear: in std_logic;
|
|
timestamp: in std_logic_vector (15 downto 0);
|
|
indexmask: in std_logic;
|
|
filterrate: in std_logic;
|
|
clk: in std_logic
|
|
);
|
|
end qcounter;
|
|
|
|
architecture behavioral of qcounter is
|
|
|
|
signal count: std_logic_vector (15 downto 0);
|
|
signal up: std_logic;
|
|
signal down: std_logic;
|
|
signal countlatch: std_logic_vector (15 downto 0);
|
|
signal timestamplatch: std_logic_vector (15 downto 0);
|
|
signal quadadel: std_logic;
|
|
signal quada1: std_logic;
|
|
signal quada2: std_logic;
|
|
signal quadacnt: std_logic_vector (3 downto 0);
|
|
signal quadafilt: std_logic;
|
|
signal quadbdel: std_logic;
|
|
signal quadb1: std_logic;
|
|
signal quadb2: std_logic;
|
|
signal quadbcnt: std_logic_vector (3 downto 0);
|
|
signal quadbfilt: std_logic;
|
|
signal indexdel: std_logic;
|
|
signal index1: std_logic;
|
|
signal index2: std_logic;
|
|
signal indexdet: std_logic;
|
|
signal indexcnt: std_logic_vector (3 downto 0);
|
|
signal indexfilt: std_logic;
|
|
signal countup: std_logic;
|
|
signal countdown: std_logic;
|
|
signal doclear: std_logic;
|
|
signal clearonindex: std_logic; -- ccr register bits...
|
|
signal latchonindex:std_logic;
|
|
signal justonce: std_logic;
|
|
signal abgateindex: std_logic;
|
|
signal indexsrc: std_logic;
|
|
signal quadfilter: std_logic;
|
|
signal countermode: std_logic_vector(1 downto 0);
|
|
signal quaderror: std_logic;
|
|
signal indexpol: std_logic;
|
|
signal fixedindexmask: std_logic;
|
|
signal indexmaskpol: std_logic;
|
|
signal useindexmask: std_logic;
|
|
signal abmaskpol: std_logic;
|
|
signal flimit: std_logic_vector(3 downto 0);
|
|
-- OWT missing pulse signals
|
|
signal interpulsetimer: std_logic_vector (31 downto 0);
|
|
signal interpulsethreshold: std_logic_vector (31 downto 0);
|
|
signal alternatemask: std_logic;
|
|
signal preowtindex: std_logic;
|
|
signal owtindex: std_logic;
|
|
signal owtedgedet: std_logic;
|
|
signal indexrb: std_logic;
|
|
|
|
|
|
|
|
begin
|
|
aqcounter: process (clk,abgateindex, indexpol, indexdel, abmaskpol,
|
|
quadadel, quadbdel, indexmaskpol, indexmask,
|
|
quadfilter, countermode, doclear, quada2, owtindex,
|
|
quada1, quadb2, quadb1, index1, index2, alternatemask,
|
|
useindexmask, readcount, timestamplatch, count,
|
|
readccr, countlatch, quaderror, justonce, countdown,
|
|
clearonindex, latchonindex, fixedindexmask, countup)
|
|
|
|
begin
|
|
-- new index logic 02/09/2006 PCW
|
|
-- combinatorial part
|
|
if abgateindex = '0' then -- not gated by A,B
|
|
if indexpol = '1' then
|
|
indexsrc <= indexdel;
|
|
else
|
|
indexsrc <= not indexdel;
|
|
end if;
|
|
else -- gated by A,B
|
|
if indexpol = '1' then -- normal index
|
|
if abmaskpol = '1' then
|
|
indexsrc <= quadadel and quadbdel and indexdel; -- enable by A,B high
|
|
else
|
|
indexsrc <= (not (quadadel or quadbdel)) and indexdel; -- enable by A,B low
|
|
end if;
|
|
else -- inverted index
|
|
if abmaskpol = '1' then
|
|
indexsrc <= quadadel and quadbdel and (not indexdel); -- enable by A,B high
|
|
else
|
|
indexsrc <= (not (quadadel or quadbdel)) and (not indexdel); -- enable by A,B low
|
|
end if;
|
|
end if;
|
|
end if;
|
|
|
|
if indexmaskpol = '1' then
|
|
fixedindexmask <= indexmask;
|
|
else
|
|
fixedindexmask <= not indexmask;
|
|
end if;
|
|
|
|
if quadfilter = '1' then
|
|
flimit <= "1111";
|
|
else
|
|
flimit <= "0011";
|
|
end if;
|
|
|
|
countup <= '0';
|
|
countdown <= '0';
|
|
owtedgedet <='0';
|
|
indexrb <= '0';
|
|
case countermode is
|
|
|
|
when"00" => -- -- -- -- quadrature 4x mode
|
|
if (doclear = '0') and (
|
|
(quada2 = '0' and quada1 = '1' and quadb2 = '0' and quadb1 = '0') or
|
|
(quada2 = '0' and quada1 = '0' and quadb2 = '1' and quadb1 = '0') or
|
|
(quada2 = '1' and quada1 = '1' and quadb2 = '0' and quadb1 = '1') or
|
|
(quada2 = '1' and quada1 = '0' and quadb2 = '1' and quadb1 = '1')) then
|
|
countup <= '1';
|
|
end if;
|
|
if (doclear = '0') and (
|
|
(quada2 = '0' and quada1 = '0' and quadb2 = '0' and quadb1 = '1') or
|
|
(quada2 = '0' and quada1 = '1' and quadb2 = '1' and quadb1 = '1') or
|
|
(quada2 = '1' and quada1 = '0' and quadb2 = '0' and quadb1 = '0') or
|
|
(quada2 = '1' and quada1 = '1' and quadb2 = '1' and quadb1 = '0')) then
|
|
countdown <= '1';
|
|
end if;
|
|
indexrb <= index1;
|
|
|
|
when "01" => -- -- -- -- up/down mode
|
|
if (doclear = '0') and
|
|
quadb2 = '1' and quada2 = '0' and quada1 = '1' then -- up down mode: count up on rising edge of A when B is high
|
|
countup <= '1';
|
|
end if;
|
|
if (doclear = '0') and
|
|
quadb2 = '0' and quada2 = '0' and quada1 = '1' then
|
|
countdown <= '1';
|
|
end if;
|
|
indexrb <= index1;
|
|
|
|
when "10" => -- -- -- -- OWT mode
|
|
if (doclear = '0') and
|
|
quada2 = '0' and quada1 = '1' then -- OWT mode: count up on rising edge of A
|
|
owtedgedet <= '1'; -- detect rising A for interpulse timing index det
|
|
if alternatemask = '1' then
|
|
countup <= '1';
|
|
end if;
|
|
end if;
|
|
countdown <= '0';
|
|
indexrb <= preowtindex;
|
|
|
|
when"11" => -- -- -- -- quadrature 1x mode
|
|
if (doclear = '0') and
|
|
(quada2 = '1' and quada1 = '0' and quadb2 = '1' and quadb1 = '1') then
|
|
countup <= '1';
|
|
end if;
|
|
if (doclear = '0') and
|
|
(quada2 = '0' and quada1 = '1' and quadb2 = '1' and quadb1 = '1') then
|
|
countdown <= '1';
|
|
end if;
|
|
indexrb <= index1;
|
|
|
|
when others => null;
|
|
end case;
|
|
|
|
if rising_edge(clk) then
|
|
|
|
|
|
quadadel <= quada;
|
|
quada1 <= quadafilt;
|
|
quada2 <= quada1;
|
|
|
|
quadbdel <= quadb;
|
|
quadb1 <= quadbfilt;
|
|
quadb2 <= quadb1;
|
|
|
|
indexdel <= index;
|
|
index1 <= indexfilt;
|
|
index2 <= index1;
|
|
|
|
|
|
if filterrate = '1' then
|
|
|
|
-- deadended counter for A input filter --
|
|
if (quadadel = '1') and (quadacnt < flimit) then
|
|
quadacnt <= quadacnt + 1;
|
|
end if;
|
|
if (quadadel = '0') and (quadacnt /= 0) then
|
|
quadacnt <= quadacnt -1;
|
|
end if;
|
|
if quadacnt >= flimit then
|
|
quadafilt<= '1';
|
|
end if;
|
|
if quadacnt = 0 then
|
|
quadafilt<= '0';
|
|
end if;
|
|
|
|
-- deadended counter for B input filter --
|
|
if (quadbdel = '1') and (quadbcnt < flimit ) then
|
|
quadbcnt <= quadbcnt + 1;
|
|
end if;
|
|
if (quadbdel = '0') and (quadbcnt /= 0) then
|
|
quadbcnt <= quadbcnt -1;
|
|
end if;
|
|
if quadbcnt >= flimit then
|
|
quadbfilt<= '1';
|
|
end if;
|
|
if quadbcnt = 0 then
|
|
quadbfilt <= '0';
|
|
end if;
|
|
|
|
-- deadended counter for index input filter --
|
|
if (indexsrc = '1') and (indexcnt < flimit ) then
|
|
indexcnt <= indexcnt + 1;
|
|
end if;
|
|
if (indexsrc = '0') and (indexcnt /= 0) then
|
|
indexcnt <= indexcnt -1;
|
|
end if;
|
|
if indexcnt >= flimit then
|
|
indexfilt<= '1';
|
|
end if;
|
|
if indexcnt = 0 then
|
|
indexfilt<= '0';
|
|
end if;
|
|
|
|
end if; -- filterrate
|
|
|
|
interpulsetimer <= interpulsetimer + 1; -- count up between pulses for OWT mode
|
|
|
|
if (countclear = '1') or
|
|
((clearonindex = '1') and (indexdet = '1')) then -- rising edge of conditioned index
|
|
doclear <= '1';
|
|
if justonce = '1' then
|
|
clearonindex <= '0';
|
|
end if;
|
|
else
|
|
doclear <= '0';
|
|
end if;
|
|
|
|
if ((latchonindex = '1') and (indexdet = '1') ) then -- rising edge of conditioned index
|
|
countlatch <= count;
|
|
if justonce = '1' then
|
|
latchonindex <= '0';
|
|
end if;
|
|
end if;
|
|
|
|
if (countermode = "00") or (countermode = "11") and (
|
|
(quada2 = '0' and quada1 = '1' and quadb2 = '0' and quadb1 = '1') or -- any time both a,b change at same time
|
|
(quada2 = '1' and quada1 = '0' and quadb2 = '1' and quadb1 = '0') or -- indicates a quadrature count error
|
|
(quada2 = '0' and quada1 = '1' and quadb2 = '1' and quadb1 = '0') or
|
|
(quada2 = '1' and quada1 = '0' and quadb2 = '0' and quadb1 = '1')) then
|
|
quaderror <= '1';
|
|
end if;
|
|
|
|
if (countermode = "10") then -- OWT mode
|
|
if interpulsetimer > interpulsethreshold then -- we waited > 1.5 times the previous interpulse time
|
|
alternatemask <= '1'; -- count on next pulse after missing pulse detected
|
|
preowtindex <= '1';
|
|
else
|
|
preowtindex <= '0';
|
|
end if;
|
|
if countup = '1' then
|
|
owtindex <= preowtindex;
|
|
end if;
|
|
if owtindex = '1' then -- just one clock wide
|
|
owtindex <= '0';
|
|
end if;
|
|
if owtedgedet = '1' then -- every rising A in OWT mode
|
|
interpulsethreshold <= interpulsetimer + ('0'&interpulsetimer(31 downto 1)); -- 1.5 nominal interpulse times
|
|
interpulsetimer <= x"00000000";
|
|
alternatemask <= not alternatemask; --toggle mask so count every other pulse
|
|
end if;
|
|
end if;
|
|
|
|
if up /= down then
|
|
timestamplatch <= timestamp; -- time stamp whenever we count
|
|
if up = '1' then
|
|
count <= count + 1;
|
|
else
|
|
count <= count - 1;
|
|
end if;
|
|
end if;
|
|
|
|
if doclear = '1' then
|
|
count <= x"0000";
|
|
end if;
|
|
|
|
if loadccr = '1' then
|
|
countermode(1) <= ibus(16);
|
|
quaderror <= ibus(15);
|
|
abmaskpol <= ibus(14);
|
|
-- latchonprobe (bit 13);
|
|
-- probepol (bit 12);
|
|
quadfilter <= ibus(11);
|
|
countermode(0) <= ibus(10);
|
|
useindexmask <= ibus(9);
|
|
indexmaskpol <= ibus(8);
|
|
abgateindex <= ibus(7);
|
|
justonce <= ibus(6);
|
|
clearonindex <= ibus(5);
|
|
latchonindex <= ibus(4);
|
|
indexpol <= ibus(3);
|
|
end if;
|
|
end if; --(clock edge)
|
|
|
|
if countermode = "10" then -- OWT mode
|
|
indexdet <= owtindex;
|
|
else
|
|
if (index1 = '1') and (index2 = '0') and ((fixedindexmask = '1') or (useindexmask = '0')) then
|
|
indexdet <= '1';
|
|
else
|
|
indexdet <= '0';
|
|
end if;
|
|
end if;
|
|
|
|
if (countup = '1' ) and (doclear = '0') then
|
|
up <= '1';
|
|
else
|
|
up <= '0';
|
|
end if;
|
|
|
|
if (countdown = '1') and (doclear = '0') then
|
|
down <= '1';
|
|
else
|
|
down <= '0';
|
|
end if;
|
|
|
|
obus <= (others => 'Z');
|
|
|
|
if (readcount = '1') then
|
|
obus(31 downto 16) <= timestamplatch;
|
|
obus(15 downto 0) <= count;
|
|
end if;
|
|
|
|
if (readccr = '1') then
|
|
obus(31 downto 16) <= countlatch;
|
|
obus(15) <= quaderror;
|
|
obus(14) <= abmaskpol;
|
|
obus(11) <= quadfilter;
|
|
obus(10) <= countermode(0);
|
|
obus(9) <= useindexmask;
|
|
obus(8) <= indexmaskpol;
|
|
obus(7) <= abgateindex;
|
|
obus(6) <= justonce;
|
|
obus(5) <= clearonindex;
|
|
obus(4) <= latchonindex;
|
|
obus(3) <= indexpol;
|
|
obus(2) <= indexrb;
|
|
obus(1) <= quadb1;
|
|
obus(0) <= quada1;
|
|
end if;
|
|
|
|
end process;
|
|
end behavioral;
|