我最近购买了Altera DE0 nano板,并成功实现了计数器和状态机等基本功能。我现在正试图在电路板的内置LED上实现一维生命游戏,它可以正常工作,但有问题。
我希望游戏状态以1Hz(或任意快速)更新,这个程序可以做到,除了它还以相同的频率闪烁LED,因此LED在显示下一个状态之前会空白半秒。我没有看到代码有什么问题,但我怀疑我是如何处理造成这个问题的1Hz时钟边缘。
以下是当前版本的代码:
----------------------------------
-- Library Declaration --
----------------------------------
-- Like any other programming language, we should declare libraries
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
----------------------------------
-- Entity Declaration --
----------------------------------
-- Here we specify all input/output ports
entity blinking_led is
port(
clk_50mhz : in std_logic ;
reset_btn : in std_logic;
green_leds : out unsigned(7 downto 0) := "11111111"
);
end entity;
----------------------------------
-- Architecture Declaration --
----------------------------------
-- here we put the description code of the design
architecture behave of blinking_led is
-- signal declaration
constant CLK_SPD : integer := 50000000;
constant N : integer := 8;
signal LED_init : unsigned(7 downto 0) := "00100100";
signal clk_1hz : std_logic ;
signal scaler : integer range 0 to 25000000 ;
signal out_register : unsigned(7 downto 0) := LED_init;
signal out_register_old : unsigned(7 downto 0) := "00000000";
begin
-- this process is used to scale down the 50mhz frequency
-- In reality, clk_1hz is not periodic but i used it to get 2 clock cycle by second ( 2 rising edge ).
-- 50 mhz means 50 000 000 cycle in one second :
-- by using the scaler , i will have 2 cycle by second so that led will be on 1/2 s and off 1/2 s
clk_1hz_process : process( clk_50mhz , reset_btn )
begin
if (reset_btn = '0') then
clk_1hz <= '0';
scaler <= 0;
elsif(rising_edge(clk_50mhz)) then
if (scaler < CLK_SPD/2) then
scaler <= scaler + 1 ;
clk_1hz <= '0';
else
scaler <= 0;
clk_1hz <= '1';
end if;
end if;
end process clk_1hz_process;
next_gen : process (clk_1hz,reset_btn, out_register, out_register_old)
variable neighbours : std_logic_vector(1 downto 0);
variable rand_temp : std_logic_vector(N-1 downto 0) := (N-1 => '1',others => '0');
variable temp : std_logic := '0'; --(others => '0');
begin
--green_leds <= LED_init;
if (reset_btn = '0') then
--green_leds <= LED_init;
elsif clk_1hz'event and clk_1hz = '1' then
out_register_old <= out_register;
--Game rules:
--Cells are connected on a N-entry long ring, so the first entry has its last as a neighbor and v/v
--0 neighbors: no action
--1 neighbor: cell is born/stays alive
--2 neighbors: cell dies
for I in 0 to (N-1) loop
if(I = 0) then
neighbours := out_register_old(N-1) & out_register_old(I+1);
elsif(I > 0 and I < (N-1)) then
neighbours := out_register_old(I-1) & out_register_old(I+1);
elsif(I = N-1) then
neighbours := out_register_old(I-1) & out_register_old(0);
end if;
case neighbours is
when "00" => out_register(I) <= out_register_old(I);
when "01" => out_register(I) <= '1';
when "10" => out_register(I) <= '1';
when "11" => out_register(I) <= '0';
when others => report "unreachable" severity failure;
end case;
end loop;
--PRNG for game reset logic
temp := rand_temp(N-1) xor rand_temp(N-2);
rand_temp(N-1 downto 1) := rand_temp(N-2 downto 0);
rand_temp(0) := temp;
--
-- if(out_register = 0) then
-- --reset to random vector
-- --out_register <= unsigned(rand_temp);
-- out_register <= LED_init;
-- end if;
--
-- if(out_register = out_register_old) then
-- --stalemate, prepare to reset
-- out_register <= "00000000";
-- end if;
--
end if;
green_leds <= out_register;
end process next_gen;
end behave;
我的VHDL生锈了所以任何帮助都表示赞赏。
答案 0 :(得分:0)
据我了解代码,clk_1hz实际上在一秒内有两个高脉冲(缩放器 似乎是在一个错误的地方。 green_leds <= out_register;
答案 1 :(得分:0)
虽然它可能有用,但你不应该使用派生信号作为时钟,而是使用clk_50mhz
直到使用clk_1hz
作为门控信号。您也可以异步使用reset_btn
(在clk_1hz_process
中)和同步(在next_gen
中),这也可能会产生一些有趣的效果。
next_gen : process
-- ...
begin
if(rising_edge(clk_50mhz)) then
if (reset_btn = '0') or (out_register = 0) then
-- synchronous reset and check for empty state in one
out_register <= ...;
elsif (clk_1hz = '1') then
-- the main logic here
out_register <= ...;
else
-- nothing happens here
end if;
end if;
end process;
-- output assignment
green_leds <= out_register;
但最重要的是,您尝试在同一个周期中使用out_register_old
,同时也指定它(out_register_old <= out_register
),因此它应该是一个变量(out_register_old := out_register
);或者它可以只用out_register
本身替换,因为这将保持其旧值直到过程结束。