我正在编写VHDL作业,这会产生一种奇怪的行为,我不明白。
概念如下。应该有一个LFSR用于生成随机数。 LFSR可以由I_CLK或I_NEXT输入驱动。如果LFSR由I_CLK驱动,它应该在其输出上自动生成随机数,但如果它由I_NEXT输入驱动,它应该通过手动将I_NEXT值从0更改为1来生成数字。我有以下问题码。如果我注释掉其中一个进程,LFSR工作正常,但如果启用了所有进程,它根本就不起作用。你能帮我解决一下这个问题吗?我认为这应该是一个设计错误,但我不知道我的设计有什么问题。
entity LFSR_v2 is
Generic (
width : positive := 31;
tap_1 : positive := 30;
tap_2 : positive := 27
);
Port (
i_enable : in std_logic;
i_reset : in std_logic;
i_clk : in std_logic;
i_next : in std_logic;
i_free_run : in std_logic;
i_load : in std_logic;
i_direction : in std_logic;
o_number : out std_logic_vector (width -1 downto 0);
i_seed : in std_logic_vector (width -1 downto 0)
);
end LFSR_v2;
architecture Behavioral of LFSR_v2 is
signal internal_number : std_logic_vector(width -1 downto 0);
begin
-------------------------------------------------------------------------------------------
-- FREE RUNNING PROCESS
--
-- In Free Running mode the LFSR switches its state on every rising edge of the i_clk input.
-------------------------------------------------------------------------------------------
next_number_free_run : process(i_clk, i_reset)
--variable fileline : line;
--variable gen_num : integer;
begin
if rising_edge(i_clk) then
--------------------------------------
-- NORMAL MODE
-- enable = 1
-- reset = 0
--------------------------------------
if (i_enable = '1' and i_free_run = '1') then
-- Internal number to the output
o_number <= internal_number;
-----------------------------
-- RESET
-----------------------------
if(i_reset = '1') then
if(i_direction = '1') then
internal_number <= (OTHERS => '1');
else
internal_number <= (OTHERS => '0');
end if;
else
------------------------------
-- LOAD SEED
-- load = 1
------------------------------
if(i_load = '1') then
internal_number <= i_seed;
else
--------------------------------------
-- GENERATE NEXT NUMBER - FREE RUNNING
-- load = 0
-- free_run = 1
-------------------------------------
if(i_direction = '1') then
internal_number <= internal_number(width - 2 downto 0) & (internal_number(tap_1) xnor internal_number(tap_2));
else
internal_number <= internal_number(width - 2 downto 0) & (internal_number(tap_1) xor internal_number(tap_2));
end if;
----------------------------------------
-- FILE LOGGING
----------------------------------------
--gen_num := to_integer(internal_number);
--write(fileline, gen_num);
--writeline(MyFile, fileline);
end if;
end if;
end if;
end if;
end process next_number_free_run;
---------------------------------------------------------------------------------
-- MANUAL RUNNING PROCESS
--
-- In this mode the LFSR does not use the input clock to generate the next number.
-- Number can be generated by creating a 0 -> 1 signal change on the i_next input.
---------------------------------------------------------------------------------
next_number_man_run : process(i_next, i_reset)
--variable fileline : line;
--variable gen_num : integer;
begin
if rising_edge(i_next) then
--------------------------------------
-- NORMAL MODE
-- enable = 1
-- reset = 0
--------------------------------------
if (i_enable = '1' and i_free_run = '0') then
-- Internal number to the output
o_number <= internal_number;
-----------------------------
-- RESET
-----------------------------
if(i_reset = '1') then
if(i_direction = '1') then
internal_number <= (OTHERS => '1');
else
internal_number <= (OTHERS => '0');
end if;
else
------------------------------
-- LOAD SEED
-- load = 1
------------------------------
if(i_load = '1') then
internal_number <= i_seed;
else
--------------------------------------
-- GENERATE NEXT NUMBER - FREE RUNNING
-- load = 0
-- free_run = 1
-------------------------------------
if(i_direction = '1') then
internal_number <= internal_number(width - 2 downto 0) & (internal_number(tap_1) xnor internal_number(tap_2));
else
internal_number <= internal_number(width - 2 downto 0) & (internal_number(tap_1) xor internal_number(tap_2));
end if;
----------------------------------------
-- FILE LOGGING
----------------------------------------
--gen_num := to_integer(internal_number);
--write(fileline, gen_num);
--writeline(MyFile, fileline);
end if;
end if;
end if;
end if;
end process next_number_man_run;
end Behavioral;
代码的测试平台:
----------------------------
-- TEST SEED INIT
----------------------------
-- ENABLE OFF -> SEED SHOULD NOT BE INITIALIZED
s_enable <= '0';
s_reset <= '0';
s_free_run <= '0';
s_load <= '1';
s_next <= '0';
s_direction <= '0';
s_seed <= (OTHERS => '1');
wait for 20 ns;
-- ENABLE ON -> SEED SHOULD BE INITIALIZED
s_enable <= '1';
s_reset <= '0';
s_next <= '0';
s_free_run <= '0';
s_load <= '1';
s_direction <= '0';
s_seed <= (OTHERS => '1');
wait for 20 ns;
-- DRIVE MANUAL
s_next <= '1';
wait for clk_period /2;
s_next <= '0';
wait for clk_period /2;
s_next <= '1';
wait for clk_period /2;
s_next <= '0';
wait for clk_period /2;
答案 0 :(得分:2)
不应使用时钟源多路复用器,而应使用Brian建议的同步时钟使能。
当时钟使能为高电平时,LFSR在自由运行时钟i_clk
的上升沿向上/向下计数一步。定义是:
i_free_run
为高,则时钟启用也很高,即始终计数。i_free_run
为低电平,则每当i_clk
从低电平变为高电平时,时钟使能仅在i_next
的一个时钟周期内为高电平,即i_next
单步执行i_next
1}}。由于i_clk
由按钮驱动,您必须:
i_next
对按钮值进行采样,即使其与时钟同步,library ieee;
use ieee.std_logic_1164.all;
entity LFSR_v2 is
Generic (
width : positive := 31;
tap_1 : positive := 30;
tap_2 : positive := 27
);
Port (
i_enable : in std_logic;
i_reset : in std_logic;
i_clk : in std_logic;
i_next : in std_logic;
i_free_run : in std_logic;
-- i_load : in std_logic;
-- i_direction : in std_logic;
-- i_seed : in std_logic_vector (width -1 downto 0)
o_number : out std_logic_vector (width -1 downto 0)
);
end LFSR_v2;
architecture Behavioral of LFSR_v2 is
signal internal_number : std_logic_vector(width -1 downto 0);
signal clock_enable : std_logic;
signal next_old : std_logic := '0'; -- old value of "i_next"
begin
-- calculate clock enable
clock_enable <= '1' when i_free_run = '1' else
i_next and not next_old;
process(i_clk) -- no i_reset here!
begin
if rising_edge(i_clk) then
next_old <= i_next; -- save old value for edge detection
-- This should be outside of the clock-enable block or even a concurrent statement
o_number <= internal_number;
if (clock_enable = '1' and i_enable = '1') then -- "i_enable" as in original code
---------------------------------------------------------------
-- Replace the following short implementation with your full
-- implementation
---------------------------------------------------------------
if(i_reset = '1') then
internal_number <= (OTHERS => '0'); -- must be all zero for XNOR below!
else
internal_number <= internal_number(width - 2 downto 0) &
(internal_number(tap_1) xnor internal_number(tap_2));
end if;
end if;
end if;
end process;
end Behavioral;
是辩护人的输出。我已将此方法应用于您的代码。为了限制代码大小,我将实现简化为一个方向,并且没有使用种子进行初始化。您必须按照指示进行全面实施。请注意,在使用XNOR进行计数时,必须使用全零来初始化LFSR。
library ieee;
use ieee.std_logic_1164.all;
entity LFSR_v2_tb is
end LFSR_v2_tb;
architecture sim of LFSR_v2_tb is
component LFSR_v2
generic (
width : positive;
tap_1 : positive;
tap_2 : positive);
port (
i_enable : in std_logic;
i_reset : in std_logic;
i_clk : in std_logic;
i_next : in std_logic;
i_free_run : in std_logic;
o_number : out std_logic_vector (width -1 downto 0));
end component;
-- component generics
constant width : positive := 31;
constant tap_1 : positive := 30;
constant tap_2 : positive := 27;
-- component ports
signal i_enable : std_logic;
signal i_reset : std_logic;
signal i_clk : std_logic := '1';
signal i_next : std_logic;
signal i_free_run : std_logic;
signal o_number : std_logic_vector (width -1 downto 0);
begin -- sim
DUT: LFSR_v2
generic map (
width => width,
tap_1 => tap_1,
tap_2 => tap_2)
port map (
i_enable => i_enable,
i_reset => i_reset,
i_clk => i_clk,
i_next => i_next,
i_free_run => i_free_run,
o_number => o_number);
-- clock generation
i_clk <= not i_clk after 10 ns;
-- waveform generation
WaveGen_Proc : process
begin
i_free_run <= '1'; -- start with a free-running clock
i_reset <= '1';
i_enable <= '1'; -- must be high even for reset
i_next <= '0';
wait until rising_edge(i_clk);
i_reset <= '0'; -- now let the LFSR toogle on i_clk
wait until rising_edge(i_clk);
wait until rising_edge(i_clk);
wait until rising_edge(i_clk);
i_free_run <= '0'; -- change to single step mode
wait until rising_edge(i_clk);
wait until rising_edge(i_clk);
wait until rising_edge(i_clk);
for i in 1 to 3 loop -- 3 single steps
i_next <= '1'; -- do single step
wait until rising_edge(i_clk);
wait until rising_edge(i_clk);
wait until rising_edge(i_clk);
i_next <= '0';
wait until rising_edge(i_clk);
wait until rising_edge(i_clk);
wait until rising_edge(i_clk);
end loop; -- i
i_free_run <= '1'; -- change back to free-running clock
wait until rising_edge(i_clk);
wait;
end process WaveGen_Proc;
end sim;
这是我的测试平台:
scp user1@123.123:/var/www/file.sql user2@456.456:/var/www/
这是模拟结果。请注意,输出信号在&#34; ...&#34;框。
答案 1 :(得分:1)
您无法在一个实体中实现两种不同的设计。
使用:
if..generate
语句和一个用于切换实现的通用参数。在您的情况下,解决方案2和3并不是那么好,因为一个使用时钟而另一个使用下一个信号。一个信号总是未使用 - &gt;实体的端口列表中填充了虚拟信号。