我知道错误的含义以及错误的原因,但无法弄清楚如何以其他方式执行此操作。
无法在snake_driver中解析net“snake [17]”的多个常量驱动程序。
(和其他人一样)
分配是我们在std_logic_vector中有一个“动蛇”,它是端到端的,当你按下一个按钮(切换信号)时,蛇会改变它的长度(2,3,4,5) ,6,2,...)
显然,蛇矢量必须通过监听切换的过程和监听时钟的过程来改变。当我把两者放在同一个过程中时,我得到一个错误,两个边缘检测到的不能在同一个过程中。
/\____ +--------------------+
toggle ----> change length |
| v |
| [snake register] =====> snake 17 downto 0
\/\/\/ | ^ |
clock ----> move one step |
+--------------------+
欢迎任何想法。
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
entity snake_driver is
generic
(
LEN : integer := 18;
MAX_SNAKE_LEN : integer := 6
);
port
(
clk : in std_logic;
change : in std_logic;
output : out std_logic_vector(LEN-1 downto 0)
);
end snake_driver;
architecture Anaconda of snake_driver is
signal snake : std_logic_vector(LEN-1 downto 0) := (0 => '1', 1 => '1', others => '0'); -- two snake pieces
signal dir_right : boolean := FALSE; -- start left
begin
process(change)
variable data : std_logic_vector(LEN-1 downto 0); -- two snake pieces
variable snake_len : integer := 2; -- snake 2 long
begin
if rising_edge(change) then -- change snake length
-- add snake piece based on direction
data := snake; -- <-- here I tried to avoid the problem
-- by caching snake data. To no avail.
if snake_len = MAX_SNAKE_LEN then
snake_len := 2;
-- shorten to 2 len
if dir_right then
-- moving right, remove from left
data := std_logic_vector(unsigned(data) and shift_right(unsigned(data), MAX_SNAKE_LEN-2));
else
-- moving left, remove from right
data := std_logic_vector(unsigned(data) and shift_left(unsigned(data), MAX_SNAKE_LEN-2));
end if;
else
-- add one at the end
if dir_right then
-- moving right, add on left
data := std_logic_vector(unsigned(data) or shift_left(unsigned(data), 1));
else
-- moving left, add on right
data := std_logic_vector(unsigned(data) or shift_right(unsigned(data), 1));
end if;
end if;
snake <= data;
end if;
end process;
-- move snake on clock
process(clk)
-- variables in the process
variable data : std_logic_vector(LEN-1 downto 0);
begin
-- shift the snake
if rising_edge(clk) then
data := snake;
if dir_right then
-- right move
data(LEN-2 downto 0) := data(LEN-1 downto 1);
if data(0) = '1' then
dir_right <= FALSE; -- change direction
end if;
else
-- left move
data(LEN-1 downto 1) := data(LEN-2 downto 0);
if data(LEN-1) = '1' then
dir_right <= TRUE; -- change direction
end if;
end if;
snake <= data;
end if;
end process;
-- send changed data to output
output <= snake;
end Anaconda;
答案 0 :(得分:2)
你的时钟有多快?通常,FPGA中的时钟非常快(50MHz或更高)。如果速度很快,您通常会在每个时钟边沿采样“切换”信号,并使用延迟元件来检测边沿。您可以使用此边缘检测来增加蛇的长度。如果您需要将蛇慢慢地移动以供人检测,则通常每x个时钟边沿移动一步(使用计数器生成时钟使能)。这一切都可以在一个只依赖于高速时钟边缘的过程中完成。
但是,如果您的切换信号来自物理开关,您可能需要注意开关弹跳的物理现象。在检测到负边缘后,通过忽略一定数量的计数的正边缘,可以避免大多数弹跳问题。这样,当您按下开关时,只有第一个正边沿计数,并且在释放开关时没有使用(弹跳)正边缘。
如果我上面提到的任何内容没有意义,我可以详细介绍。
以上是我上面所说的蛇的示例,它总是向右旋转,开始2位宽,并且对最大尺寸没有限制(警告:未经测试):
architecture behav of snake is
signal clk : std_logic; --actually an input. 50MHz
signal toggle : std_logic := '0'; --actually an input, not an internal signal
signal toggle_d : std_logic := '0';
signal snake_vec : std_logic_vector(17 downto 0) := "000000000000000011";
signal disable_count : unsigned(20 downto 0):=(others => '0'); --about 50ms to cycle through full range
signal step_count : unsigned(24 downto 0):=(others => '0'); --about 0.7s to cycle through full range
begin
process(clk)
if (clk = '1' and clk'event) then
toggle_d <= toggle; --store previous value of toggle
if (toggle_d = '1' and toggle = '0') then --trigger blocking counter on negative edges of toggle
disable_count <= (others => '1');
elsif (disable_count /= 0) then --count down if blocking counter is enabled
disable_count <= disable_count-1;
end if;
if (toggle_d = '0' and toggle = '1' and disable_count = 0) then --extend on allowed rising edges of toggle
snake_vec <= snake_vec or (snake_vec(0) & snake_vec(17 downto 1); --extend the snake by 1
else
step_count <= step_count-1; --this could be + or -
if (step_count = 0) then --functions as a clock enable every 1 in 33.5 million cycles
snake_vec <= snake_vec(0) & snake_vec(17 downto 0); --rotate snake
end if;
end if;
end if;
end process;
end behav;
编辑:根据你在评论中描述的情况,最好的方法可能是将事件锁存在高速时钟上并用低速时钟读取。以下是如何做到这一点的示例。请注意,时钟分频器需要在分频时钟的每个上升沿为高速时钟提供输出(假设基于计数器的时钟分频器)。对于您的项目,您可能希望在使用慢速时钟的块外部进行高速锁存 - 它可以将事件作为输入传递。
architecture behav of snake is
signal clk : std_logic; --50MHz
signal divide_event : std_logic; --on the 50MHz domain, single clock wide pulse every rising edge of 4Hz clock, sourced from clock divider
signal clk_slow : std_logic; --4Hz
signal toggle : std_logic := '0'; --actually an input, not an internal signal
signal toggle_d : std_logic := '0';
signal snake_vec : std_logic_vector(17 downto 0) := "000000000000000011";
begin
process(clk)
if (clk = '1' and clk'event) then
toggle_d <= toggle; --store previous value of toggle
if (toggle_d = '0' and toggle = '1') then
extend_event <= '1';
elsif divide_event = '1' then
extend_event <= '0';
end if;
end process;
process(clk_slow)
if (clk_slow = '1' and clk_slow'event) then
if (extend_event = '1') then
snake_vec <= snake_vec or (snake_vec(0) & snake_vec(17 downto 1); --extend the snake by 1
else
snake_vec <= snake_vec(0) & snake_vec(17 downto 0); --rotate snake
end if;
end if;
end process
end behav;