445 lines
15 KiB
VHDL
Executable File
445 lines
15 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 stepgenid is
|
|
generic (
|
|
buswidth : integer;
|
|
timersize : integer;
|
|
tablewidth : integer;
|
|
asize : integer;
|
|
rsize : integer;
|
|
lsize : integer
|
|
);
|
|
Port ( clk : in std_logic;
|
|
ibus : in std_logic_vector(buswidth-1 downto 0);
|
|
obus : out std_logic_vector(buswidth-1 downto 0);
|
|
loadsteprate : in std_logic;
|
|
loadaccum : in std_logic;
|
|
loadstepmode : in std_logic;
|
|
loaddirsetuptime : in std_logic;
|
|
loaddirholdtime : in std_logic;
|
|
loadpulseactivetime : in std_logic;
|
|
loadpulseidletime : in std_logic;
|
|
loadtable : in std_logic;
|
|
loadtablemax : in std_logic;
|
|
readsteprate : in std_logic;
|
|
readaccum : in std_logic;
|
|
readstepmode : in std_logic;
|
|
readdirsetuptime : in std_logic;
|
|
readdirholdtime : in std_logic;
|
|
readpulseactivetime : in std_logic;
|
|
readpulseidletime : in std_logic;
|
|
readtable : in std_logic;
|
|
readtablemax : in std_logic;
|
|
basicrate : in std_logic;
|
|
hold : in std_logic;
|
|
index : in std_logic;
|
|
probe : in std_logic;
|
|
timer : in std_logic;
|
|
timerenable : in std_logic;
|
|
stout : out std_logic_vector(tablewidth-1 downto 0)
|
|
);
|
|
end stepgenid;
|
|
|
|
architecture Behavioral of stepgenid is
|
|
|
|
|
|
-- Step Generator related signals
|
|
|
|
signal stepaccum: std_logic_vector(asize-1 downto 0);
|
|
signal steplatch: std_logic_vector(buswidth-1 downto 0);
|
|
signal nextaccum: std_logic_vector(asize-1 downto 0);
|
|
alias stepmsbs: std_logic_vector(1 downto 0) is stepaccum(rsize-1 downto rsize -2);
|
|
alias stepmsb: std_logic is stepaccum(rsize -1);
|
|
alias nextmsb: std_logic is nextaccum(rsize -1);
|
|
signal dstepmsb : std_logic;
|
|
signal ddshold : std_logic;
|
|
signal steprate: std_logic_vector(rsize -1 downto 0);
|
|
alias stepdir: std_logic is steprate(rsize -1);
|
|
signal dstepdir : std_logic;
|
|
signal stepdirout : std_logic;
|
|
signal pulsewait : std_logic;
|
|
signal steppulse : std_logic := '0';
|
|
signal dpulsewait : std_logic := '0';
|
|
signal dirsetupwait : std_logic;
|
|
signal dirholdwait : std_logic;
|
|
signal dirshwait : std_logic;
|
|
signal dirhold : std_logic;
|
|
signal dirshcount: std_logic_vector(timersize-1 downto 0);
|
|
signal pulsewidthcount: std_logic_vector(timersize-1 downto 0);
|
|
signal dirsetuptime: std_logic_vector(timersize -1 downto 0);
|
|
signal dirholdtime: std_logic_vector(timersize -1 downto 0);
|
|
signal pulseactivetime: std_logic_vector(timersize -1 downto 0);
|
|
signal pulseidletime: std_logic_vector(timersize -1 downto 0);
|
|
signal stepmode: std_logic_vector(7 downto 0);
|
|
signal localout: std_logic_vector(tablewidth-1 downto 0);
|
|
signal wewouldcount : std_logic;
|
|
signal dirchange : std_logic;
|
|
signal waitforhold : std_logic;
|
|
signal waitforpulse : std_logic;
|
|
signal tableptr: std_logic_vector(3 downto 0);
|
|
signal tablemax: std_logic_vector(3 downto 0);
|
|
signal tabledata: std_logic_vector(tablewidth-1 downto 0);
|
|
-- index and probe stuff;
|
|
alias swapoutputs : std_logic is stepmode(2);
|
|
alias latchonindex : std_logic is stepmode(4);
|
|
alias indexpol : std_logic is stepmode(5);
|
|
alias latchonprobe : std_logic is stepmode(6);
|
|
alias probepol : std_logic is stepmode(7);
|
|
signal indexflt: std_logic_vector(7 downto 0);
|
|
signal probeflt: std_logic_vector(7 downto 0);
|
|
signal indexd: std_logic_vector(1 downto 0);
|
|
signal probed: std_logic_vector(1 downto 0);
|
|
signal countlatch : std_logic_vector(lsize-1 downto 0);
|
|
|
|
signal dtimer : std_logic;
|
|
signal sample : std_logic;
|
|
|
|
component SRL16E
|
|
--
|
|
generic (INIT : bit_vector);
|
|
|
|
|
|
--
|
|
port (D : in std_logic;
|
|
CE : in std_logic;
|
|
CLK : in std_logic;
|
|
A0 : in std_logic;
|
|
A1 : in std_logic;
|
|
A2 : in std_logic;
|
|
A3 : in std_logic;
|
|
Q : out std_logic);
|
|
end component;
|
|
|
|
|
|
begin
|
|
|
|
steptable: for i in 0 to tablewidth -1 generate
|
|
asr16e: SRL16E generic map (x"0000") port map(
|
|
D => ibus(i),
|
|
CE => loadtable,
|
|
CLK => clk,
|
|
A0 => tableptr(0),
|
|
A1 => tableptr(1),
|
|
A2 => tableptr(2),
|
|
A3 => tableptr(3),
|
|
Q => tabledata(i)
|
|
);
|
|
end generate;
|
|
|
|
astepgen: process (clk,stepdirout, steprate, nextaccum, stepaccum,dirshwait,
|
|
dirholdwait, pulsewait, dpulsewait,dirchange,wewouldcount,waitforpulse,
|
|
dirsetupwait, pulsewidthcount, dirshcount, dirhold, waitforhold,
|
|
readaccum, tabledata, stepmode, steppulse, stepmsbs,localout)
|
|
begin
|
|
if rising_edge(clk) then
|
|
|
|
if basicrate = '1' and hold = '0' and ddshold = '0' then -- our basic step rate DDS
|
|
stepaccum <= nextaccum;
|
|
dstepdir <= stepdir; -- only updated when we add
|
|
end if;
|
|
|
|
if pulsewait = '1' then -- our two timers
|
|
pulsewidthcount <= pulsewidthcount -1; -- we share dirshcount between setup and hold functions
|
|
end if;
|
|
|
|
if (pulsewait = '0') and (dpulsewait = '1') and (steppulse = '1') then
|
|
pulsewidthcount <= pulseidletime; -- output pulse idle time
|
|
steppulse <= '0'; -- clear our output pulse
|
|
end if;
|
|
|
|
if dirshwait = '1' then
|
|
dirshcount <= dirshcount -1;
|
|
end if;
|
|
|
|
if (stepmsb = '0' and dstepmsb = '1' and dstepdir = '0') -- overflow = we counted up
|
|
or (stepmsb = '1' and dstepmsb = '0' and dstepdir = '1') then -- underflow = we counted down -- the output of the DDS
|
|
pulsewidthcount <= pulseactivetime; -- output pulse active time
|
|
steppulse <= '1';
|
|
dirshcount <= dirholdtime; -- set pulse to dir change hold timer
|
|
dirhold <= '1'; -- set our flag to indicate
|
|
else
|
|
if dirholdwait = '0' then -- no change during hold time
|
|
if dirchange = '1' then -- we need to change the external direction signal
|
|
dirshcount <= dirsetuptime; -- set dir change to next pulse setup time
|
|
dirhold <= '0'; -- set our flag to indicate
|
|
stepdirout <= stepdir; -- update the output direction
|
|
end if; -- our timer is for setup time
|
|
end if;
|
|
end if; -- our timer is for hold time
|
|
|
|
|
|
if (stepmsb = '0' and dstepmsb = '1' and dstepdir = '0') then -- we counted up
|
|
if (tableptr = tablemax) then
|
|
tableptr <= x"0";
|
|
else
|
|
tableptr <= tableptr +1;
|
|
end if;
|
|
end if;
|
|
if (stepmsb = '1' and dstepmsb = '0' and dstepdir = '1') then -- we counted down
|
|
if (tableptr = x"0") then
|
|
tableptr <= tablemax;
|
|
else
|
|
tableptr <= tableptr -1;
|
|
end if;
|
|
end if;
|
|
|
|
if loadstepmode = '1' then -- our register writes
|
|
stepmode <= ibus(7 downto 0);
|
|
end if;
|
|
if loadsteprate = '1' then
|
|
steprate <= ibus(rsize -1 downto 0);
|
|
end if;
|
|
if loadaccum = '1' then
|
|
stepaccum(asize -1 downto asize-buswidth) <= ibus;
|
|
dstepmsb <= ibus(buswidth-1); -- avoid generating a step when loading accumulator
|
|
end if;
|
|
if loaddirsetuptime = '1' then
|
|
dirsetuptime <= ibus(timersize -1 downto 0);
|
|
end if;
|
|
if loaddirholdtime = '1' then
|
|
dirholdtime <= ibus(timersize -1 downto 0);
|
|
end if;
|
|
if loadpulseactivetime = '1' then
|
|
pulseactivetime <= ibus(timersize -1 downto 0);
|
|
end if;
|
|
if loadpulseidletime = '1' then
|
|
pulseidletime <= ibus(timersize -1 downto 0);
|
|
end if;
|
|
|
|
if loadtablemax = '1' then
|
|
tablemax <= ibus(3 downto 0);
|
|
tableptr <= x"0";
|
|
end if;
|
|
if sample = '1' then
|
|
steplatch <= stepaccum(asize -1 downto asize-buswidth);
|
|
end if;
|
|
dpulsewait <= pulsewait;
|
|
dstepmsb <= stepmsb;
|
|
dtimer <= timer;
|
|
-- index/probe logic
|
|
|
|
if index = '1' then
|
|
if indexflt /= x"FF" then
|
|
indexflt <= indexflt + 1;
|
|
end if;
|
|
else
|
|
if indexflt /= x"0" then
|
|
indexflt <= indexflt - 1;
|
|
end if;
|
|
end if;
|
|
if indexflt = x"0" then
|
|
indexd(0) <= '0';
|
|
end if;
|
|
if indexflt = x"FF" then
|
|
indexd(0) <= '1';
|
|
end if;
|
|
indexd(1) <= indexd(0);
|
|
|
|
if probe = '1' then
|
|
if probeflt /= x"FF" then
|
|
probeflt <= probeflt + 1;
|
|
end if;
|
|
else
|
|
if probeflt /= x"0" then
|
|
probeflt <= probeflt - 1;
|
|
end if;
|
|
end if;
|
|
if probeflt = x"0" then
|
|
probed(0) <= '0';
|
|
end if;
|
|
if probeflt = x"FF" then
|
|
probed(0) <= '1';
|
|
end if;
|
|
probed(1) <= probed(0);
|
|
|
|
if (indexd = "01" and latchonindex = '1' and indexpol = '1') or
|
|
(indexd = "10" and latchonindex = '1' and indexpol = '0') then
|
|
countlatch <= stepaccum(asize-1 downto asize-lsize);
|
|
latchonindex <= '0';
|
|
end if;
|
|
|
|
if (probed = "01" and latchonprobe = '1' and probepol = '1') or
|
|
(probed = "10" and latchonprobe = '1' and probepol = '0') then
|
|
countlatch <= stepaccum(asize-1 downto asize-lsize);
|
|
latchonprobe <= '0';
|
|
end if;
|
|
|
|
end if; -- clk
|
|
|
|
dirchange <= stepdirout xor stepdir;
|
|
|
|
if (stepmsb = '1' and nextmsb = '0' and stepdir = '0') -- overflow = we would count up
|
|
or (stepmsb = '0' and nextmsb = '1' and stepdir = '1') then -- underflow = we would count down
|
|
wewouldcount <= '1';
|
|
else
|
|
wewouldcount <= '0';
|
|
end if;
|
|
|
|
waitforhold <= dirholdwait and dirchange;
|
|
waitforpulse <= pulsewait or dpulsewait;
|
|
|
|
nextaccum <= signed(stepaccum)+ signed(steprate); -- to lookahead
|
|
|
|
if (wewouldcount = '1') and
|
|
-- (((waitforhold = '1') or (dirsetupwait = '1') or (waitforpulse = '1'))) -- misses the case where Dirhold has timed out!
|
|
(((waitforhold = '1') or (dirsetupwait = '1') or (waitforpulse = '1') or (dirchange = '1')))
|
|
then -- need to pause
|
|
ddshold <= '1';
|
|
else
|
|
ddshold <= '0';
|
|
end if;
|
|
|
|
if pulsewidthcount = 0 then
|
|
pulsewait <= '0';
|
|
else
|
|
pulsewait <= '1';
|
|
end if;
|
|
|
|
if dirshcount = 0 then
|
|
dirshwait <= '0';
|
|
else
|
|
dirshwait <= '1';
|
|
end if;
|
|
|
|
dirholdwait <= (dirhold and dirshwait);
|
|
dirsetupwait <= (not dirhold) and dirshwait;
|
|
|
|
if (timer = '1' and dtimer = '0') or (timerenable = '0') then -- rising edge of selected timer
|
|
sample <= '1';
|
|
else
|
|
sample <= '0';
|
|
end if;
|
|
|
|
obus <= (others => 'Z');
|
|
|
|
-- if readsteprate = '1' then
|
|
-- obus(rsize -1 downto 0) <= steprate;
|
|
-- end if;
|
|
|
|
if readaccum = '1' then
|
|
obus <= steplatch;
|
|
end if;
|
|
|
|
if readstepmode = '1' then
|
|
obus(7 downto 0) <= stepmode;
|
|
obus(buswidth-1 downto buswidth-lsize) <= countlatch;
|
|
end if;
|
|
|
|
-- if readdirsetuptime = '1' then
|
|
-- obus(timersize -1 downto 0) <= dirsetuptime; -- most register readbacks commented out for size
|
|
-- obus(31 downto timersize) <= (others => '0');
|
|
-- end if;
|
|
-- if readdirholdtime = '1' then
|
|
-- obus(timersize -1 downto 0) <= dirholdtime;
|
|
-- obus(31 downto timersize) <= (others => '0');
|
|
-- end if;
|
|
-- if readpulseactivetime = '1' then
|
|
-- obus(timersize -1 downto 0) <= pulsewidth;
|
|
-- obus(31 downto timersize) <= (others => '0');
|
|
-- end if;
|
|
-- if readpulseidletime = '1' then
|
|
-- obus(timersize -1 downto 0) <= pulseidle;
|
|
-- obus(31 downto timersize) <= (others => '0');
|
|
-- end if;
|
|
|
|
|
|
localout <= tabledata; -- this is the default unless:
|
|
case stepmode(1 downto 0) is
|
|
when "00" =>
|
|
localout(0) <= steppulse; -- step
|
|
localOut(1) <= stepdirout; -- dir
|
|
when "01" =>
|
|
localout(0) <= steppulse and (not stepdirout); -- count up
|
|
localOut(1) <= steppulse and stepdirout; -- count down
|
|
when "10" =>
|
|
case stepmsbs is
|
|
when "00" => localout(1 downto 0) <= "00"; -- quadrature
|
|
when "01" => localout(1 downto 0) <= "01";
|
|
when "10" => localout (1 downto 0)<= "11";
|
|
when "11" => localout(1 downto 0) <= "10";
|
|
when others => null;
|
|
end case;
|
|
when others => null;
|
|
end case;
|
|
|
|
if swapoutputs = '0' then
|
|
stout <= localout;
|
|
else
|
|
stout(0) <= localout(1);
|
|
stout(1) <= localout(0);
|
|
end if;
|
|
|
|
end process astepgen;
|
|
|
|
end Behavioral;
|