/ kubstepgenzi.vhd
kubstepgenzi.vhd
1 library IEEE; 2 use IEEE.STD_LOGIC_1164.ALL; 3 use IEEE.STD_LOGIC_ARITH.ALL; 4 use IEEE.STD_LOGIC_UNSIGNED.ALL; 5 6 7 -- 8 -- Copyright (C) 2007, Peter C. Wallace, Mesa Electronics 9 -- http://www.mesanet.com 10 -- 11 -- This program is is licensed under a disjunctive dual license giving you 12 -- the choice of one of the two following sets of free software/open source 13 -- licensing terms: 14 -- 15 -- * GNU General Public License (GPL), version 2.0 or later 16 -- * 3-clause BSD License 17 -- 18 -- 19 -- The GNU GPL License: 20 -- 21 -- This program is free software; you can redistribute it and/or modify 22 -- it under the terms of the GNU General Public License as published by 23 -- the Free Software Foundation; either version 2 of the License, or 24 -- (at your option) any later version. 25 -- 26 -- This program is distributed in the hope that it will be useful, 27 -- but WITHOUT ANY WARRANTY; without even the implied warranty of 28 -- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 29 -- GNU General Public License for more details. 30 -- 31 -- You should have received a copy of the GNU General Public License 32 -- along with this program; if not, write to the Free Software 33 -- Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA 34 -- 35 -- 36 -- The 3-clause BSD License: 37 -- 38 -- Redistribution and use in source and binary forms, with or without 39 -- modification, are permitted provided that the following conditions 40 -- are met: 41 -- 42 -- * Redistributions of source code must retain the above copyright 43 -- notice, this list of conditions and the following disclaimer. 44 -- 45 -- * Redistributions in binary form must reproduce the above 46 -- copyright notice, this list of conditions and the following 47 -- disclaimer in the documentation and/or other materials 48 -- provided with the distribution. 49 -- 50 -- * Neither the name of Mesa Electronics nor the names of its 51 -- contributors may be used to endorse or promote products 52 -- derived from this software without specific prior written 53 -- permission. 54 -- 55 -- 56 -- Disclaimer: 57 -- 58 -- THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 59 -- "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 60 -- LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 61 -- FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 62 -- COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 63 -- INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 64 -- BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 65 -- LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 66 -- CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 67 -- LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN 68 -- ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 69 -- POSSIBILITY OF SUCH DAMAGE. 70 -- 71 72 73 entity stepgeni is 74 generic ( 75 buswidth : integer; 76 timersize : integer; 77 tablewidth : integer; 78 asize : integer; 79 rsize : integer; 80 lsize : integer 81 ); 82 Port ( clk : in std_logic; 83 ibus : in std_logic_vector(buswidth-1 downto 0); 84 obus : out std_logic_vector(buswidth-1 downto 0); 85 loadsteprate : in std_logic; 86 loadaccum : in std_logic; 87 loadstepmode : in std_logic; 88 loaddirsetuptime : in std_logic; 89 loaddirholdtime : in std_logic; 90 loadpulseactivetime : in std_logic; 91 loadpulseidletime : in std_logic; 92 loadtable : in std_logic; 93 loadtablemax : in std_logic; 94 readsteprate : in std_logic; 95 readaccum : in std_logic; 96 readstepmode : in std_logic; 97 readdirsetuptime : in std_logic; 98 readdirholdtime : in std_logic; 99 readpulseactivetime : in std_logic; 100 readpulseidletime : in std_logic; 101 readtable : in std_logic; 102 readtablemax : in std_logic; 103 basicrate : in std_logic; 104 hold : in std_logic; 105 index : in std_logic; 106 probe : in std_logic; 107 stout : out std_logic_vector(tablewidth-1 downto 0) 108 ); 109 end stepgeni; 110 111 architecture Behavioral of stepgeni is 112 113 114 -- Step Generator related signals 115 116 signal stepaccum: std_logic_vector(asize-1 downto 0); 117 signal nextaccum: std_logic_vector(asize-1 downto 0); 118 alias stepmsbs: std_logic_vector(1 downto 0) is stepaccum(rsize-1 downto rsize -2); 119 alias stepmsb: std_logic is stepaccum(rsize -1); 120 alias nextmsb: std_logic is nextaccum(rsize -1); 121 signal dstepmsb : std_logic; 122 signal ddshold : std_logic; 123 signal steprate: std_logic_vector(rsize -1 downto 0); 124 alias stepdir: std_logic is steprate(rsize -1); 125 signal dstepdir : std_logic; 126 signal stepdirout : std_logic; 127 signal pulsewait : std_logic; 128 signal steppulse : std_logic := '0'; 129 signal dpulsewait : std_logic := '0'; 130 signal dirsetupwait : std_logic; 131 signal dirholdwait : std_logic; 132 signal dirshwait : std_logic; 133 signal dirhold : std_logic; 134 signal dirshcount: std_logic_vector(timersize-1 downto 0); 135 signal pulsewidthcount: std_logic_vector(timersize-1 downto 0); 136 signal dirsetuptime: std_logic_vector(timersize -1 downto 0); 137 signal dirholdtime: std_logic_vector(timersize -1 downto 0); 138 signal pulseactivetime: std_logic_vector(timersize -1 downto 0); 139 signal pulseidletime: std_logic_vector(timersize -1 downto 0); 140 signal stepmode: std_logic_vector(6 downto 0); 141 signal localout: std_logic_vector(tablewidth-1 downto 0); 142 signal wewouldcount : std_logic; 143 signal dirchange : std_logic; 144 signal waitforhold : std_logic; 145 signal waitforpulse : std_logic; 146 signal tableptr: std_logic_vector(3 downto 0); 147 signal tablemax: std_logic_vector(3 downto 0); 148 signal tabledata: std_logic_vector(tablewidth-1 downto 0); 149 -- index and probe stuff; 150 alias latchonindex : std_logic is stepmode(2); 151 alias indexpol : std_logic is stepmode(3); 152 alias latchonprobe : std_logic is stepmode(4); 153 alias probepol : std_logic is stepmode(5); 154 alias justonce : std_logic is stepmode(6); 155 signal indexflt: std_logic_vector(3 downto 0); 156 signal probeflt: std_logic_vector(3 downto 0); 157 signal indexd: std_logic_vector(1 downto 0); 158 signal probed: std_logic_vector(1 downto 0); 159 signal countlatch : std_logic_vector(lsize-1 downto 0); 160 component SRL16E 161 -- 162 generic (INIT : bit_vector); 163 164 165 -- 166 port (D : in std_logic; 167 CE : in std_logic; 168 CLK : in std_logic; 169 A0 : in std_logic; 170 A1 : in std_logic; 171 A2 : in std_logic; 172 A3 : in std_logic; 173 Q : out std_logic); 174 end component; 175 176 177 begin 178 179 steptable: for i in 0 to tablewidth -1 generate 180 asr16e: SRL16E generic map (x"0000") port map( 181 D => ibus(i), 182 CE => loadtable, 183 CLK => clk, 184 A0 => tableptr(0), 185 A1 => tableptr(1), 186 A2 => tableptr(2), 187 A3 => tableptr(3), 188 Q => tabledata(i) 189 ); 190 end generate; 191 192 astepgen: process (clk,stepdirout, steprate, nextaccum, stepaccum,dirshwait, 193 dirholdwait, pulsewait, dpulsewait,dirchange,wewouldcount,waitforpulse, 194 dirsetupwait, pulsewidthcount, dirshcount, dirhold, waitforhold, 195 readaccum, tabledata, stepmode, steppulse, stepmsbs,localout) 196 begin 197 if rising_edge(clk) then 198 199 if basicrate = '1' and hold = '0' and ddshold = '0' then -- our basic step rate DDS 200 stepaccum <= nextaccum; 201 dstepdir <= stepdir; -- only updated when we add 202 end if; 203 204 if pulsewait = '1' then -- our two timers 205 pulsewidthcount <= pulsewidthcount -1; -- we share dirshcount between setup and hold functions 206 end if; 207 208 if (pulsewait = '0') and (dpulsewait = '1') and (steppulse = '1') then 209 pulsewidthcount <= pulseidletime; -- output pulse idle time 210 steppulse <= '0'; -- clear our output pulse 211 end if; 212 213 if dirshwait = '1' then 214 dirshcount <= dirshcount -1; 215 end if; 216 217 if (stepmsb = '0' and dstepmsb = '1' and dstepdir = '0') -- overflow = we counted up 218 or (stepmsb = '1' and dstepmsb = '0' and dstepdir = '1') then -- underflow = we counted down -- the output of the DDS 219 pulsewidthcount <= pulseactivetime; -- output pulse active time 220 steppulse <= '1'; 221 dirshcount <= dirholdtime; -- set pulse to dir change hold timer 222 dirhold <= '1'; -- set our flag to indicate 223 else 224 if dirholdwait = '0' then -- no change during hold time 225 if dirchange = '1' then -- we need to change the external direction signal 226 dirshcount <= dirsetuptime; -- set dir change to next pulse setup time 227 dirhold <= '0'; -- set our flag to indicate 228 stepdirout <= stepdir; -- update the output direction 229 end if; -- our timer is for setup time 230 end if; 231 end if; -- our timer is for hold time 232 233 234 if (stepmsb = '0' and dstepmsb = '1' and dstepdir = '0') then -- we counted up 235 if (tableptr = tablemax) then 236 tableptr <= x"0"; 237 else 238 tableptr <= tableptr +1; 239 end if; 240 end if; 241 if (stepmsb = '1' and dstepmsb = '0' and dstepdir = '1') then -- we counted down 242 if (tableptr = x"0") then 243 tableptr <= tablemax; 244 else 245 tableptr <= tableptr -1; 246 end if; 247 end if; 248 249 if loadstepmode = '1' then -- our register writes 250 stepmode <= ibus(6 downto 0); 251 end if; 252 if loadsteprate = '1' then 253 steprate <= ibus(rsize -1 downto 0); 254 end if; 255 if loadaccum = '1' then 256 stepaccum(asize -1 downto asize-buswidth) <= ibus; 257 dstepmsb <= ibus(buswidth-1); -- avoid generating a step when loading accumulator 258 end if; 259 if loaddirsetuptime = '1' then 260 dirsetuptime <= ibus(timersize -1 downto 0); 261 end if; 262 if loaddirholdtime = '1' then 263 dirholdtime <= ibus(timersize -1 downto 0); 264 end if; 265 if loadpulseactivetime = '1' then 266 pulseactivetime <= ibus(timersize -1 downto 0); 267 end if; 268 if loadpulseidletime = '1' then 269 pulseidletime <= ibus(timersize -1 downto 0); 270 end if; 271 272 if loadtablemax = '1' then 273 tablemax <= ibus(3 downto 0); 274 tableptr <= x"0"; 275 end if; 276 277 dpulsewait <= pulsewait; 278 dstepmsb <= stepmsb; 279 280 -- index/probe logic 281 282 if index = '1' then 283 if indexflt /= x"F" then 284 indexflt <= indexflt + 1; 285 end if; 286 else 287 if indexflt /= x"0" then 288 indexflt <= indexflt - 1; 289 end if; 290 end if; 291 if indexflt = x"0" then 292 indexd(0) <= '0'; 293 end if; 294 if indexflt = x"F" then 295 indexd(0) <= '1'; 296 end if; 297 indexd(1) <= indexd(0); 298 299 if probe = '1' then 300 if probeflt /= x"F" then 301 probeflt <= probeflt + 1; 302 end if; 303 else 304 if probeflt /= x"0" then 305 probeflt <= probeflt - 1; 306 end if; 307 end if; 308 if probeflt = x"0" then 309 probed(0) <= '0'; 310 end if; 311 if probeflt = x"F" then 312 probed(0) <= '1'; 313 end if; 314 probed(1) <= probed(0); 315 316 if (indexd = "01" and latchonindex = '1' and indexpol = '1') or 317 (indexd = "10" and latchonindex = '1' and indexpol = '0') then 318 countlatch <= stepaccum(asize-1 downto asize-lsize); 319 if justonce = '1' then 320 latchonindex <= '0'; 321 end if; 322 end if; 323 324 if (probed = "01" and latchonprobe = '1' and probepol = '1') or 325 (probed = "10" and latchonprobe = '1' and probepol = '0') then 326 countlatch <= stepaccum(asize-1 downto asize-lsize); 327 if justonce = '1' then 328 latchonprobe <= '0'; 329 end if; 330 end if; 331 332 333 end if; -- clk 334 335 dirchange <= stepdirout xor stepdir; 336 337 if (stepmsb = '1' and nextmsb = '0' and stepdir = '0') -- overflow = we would count up 338 or (stepmsb = '0' and nextmsb = '1' and stepdir = '1') then -- underflow = we would count down 339 wewouldcount <= '1'; 340 else 341 wewouldcount <= '0'; 342 end if; 343 344 waitforhold <= dirholdwait and dirchange; 345 waitforpulse <= pulsewait or dpulsewait; 346 347 nextaccum <= signed(stepaccum)+ signed(steprate); -- to lookahead 348 349 if (wewouldcount = '1') and 350 -- (((waitforhold = '1') or (dirsetupwait = '1') or (waitforpulse = '1'))) -- misses the case where Dirhold has timed out! 351 (((waitforhold = '1') or (dirsetupwait = '1') or (waitforpulse = '1') or (dirchange = '1'))) 352 then -- need to pause 353 ddshold <= '1'; 354 else 355 ddshold <= '0'; 356 end if; 357 358 if pulsewidthcount = 0 then 359 pulsewait <= '0'; 360 else 361 pulsewait <= '1'; 362 end if; 363 364 if dirshcount = 0 then 365 dirshwait <= '0'; 366 else 367 dirshwait <= '1'; 368 end if; 369 370 dirholdwait <= (dirhold and dirshwait); 371 dirsetupwait <= (not dirhold) and dirshwait; 372 373 obus <= (others => 'Z'); 374 375 -- if readsteprate = '1' then 376 -- obus(rsize -1 downto 0) <= steprate; 377 -- end if; 378 379 if readaccum = '1' then 380 obus <= stepaccum(asize -1 downto asize-buswidth); 381 end if; 382 383 if readstepmode = '1' then 384 obus(6 downto 0) <= stepmode; 385 obus(buswidth-1 downto buswidth-lsize) <= countlatch; 386 end if; 387 388 -- if readdirsetuptime = '1' then 389 -- obus(timersize -1 downto 0) <= dirsetuptime; -- most register readbacks commented out for size 390 -- obus(31 downto timersize) <= (others => '0'); 391 -- end if; 392 -- if readdirholdtime = '1' then 393 -- obus(timersize -1 downto 0) <= dirholdtime; 394 -- obus(31 downto timersize) <= (others => '0'); 395 -- end if; 396 -- if readpulseactivetime = '1' then 397 -- obus(timersize -1 downto 0) <= pulsewidth; 398 -- obus(31 downto timersize) <= (others => '0'); 399 -- end if; 400 -- if readpulseidletime = '1' then 401 -- obus(timersize -1 downto 0) <= pulseidle; 402 -- obus(31 downto timersize) <= (others => '0'); 403 -- end if; 404 405 406 localout <= tabledata; -- this is the default unless: 407 case stepmode(1 downto 0) is 408 when "00" => 409 localout(0) <= steppulse; -- step 410 localOut(1) <= stepdirout; -- dir 411 when "01" => 412 localout(0) <= steppulse and (not stepdirout); -- count up 413 localOut(1) <= steppulse and stepdirout; -- count down 414 when "10" => 415 case stepmsbs is 416 when "00" => localout(1 downto 0) <= "00"; -- quadrature 417 when "01" => localout(1 downto 0) <= "01"; 418 when "10" => localout (1 downto 0)<= "11"; 419 when "11" => localout(1 downto 0) <= "10"; 420 when others => null; 421 end case; 422 when others => null; 423 end case; 424 stout <= localout; 425 426 end process astepgen; 427 428 end Behavioral;