我正在学习VHDL,有什么比学习项目更好的学习方法。所以,我现在的项目部分是创建一个小内存组件。
这是我的完整代码:
entity memory is
port(
Address: in std_logic_vector(15 downto 0); --memory address
Write: in std_logic; --write or read
UseTopBits: in std_logic; --if 1, top 8 bits of data is ignored and not written to memory
Clock: in std_logic;
DataIn: in std_logic_vector(15 downto 0);
DataOut: out std_logic_vector(15 downto 0);
Reset: in std_logic
);
end memory;
architecture Behavioral of memory is
constant SIZE : integer := 4096;
type memorytype is array(0 to (size-1)) of std_logic_vector(7 downto 0);
signal mem: memorytype;
begin
resetmem: process(Clock, Reset) --this process is the troublemaker
begin
if(Reset ='1' and rising_edge(Clock)) then
mem <= (others => "00000000");
end if;
end process;
writemem: process(Reset,Write, Address, UseTopBits, Clock)
variable addr: integer;
begin
addr := conv_integer(Address);
if(addr>size-1) then
addr:=0;
end if;
if(Write='1' and Reset='0') then
if(rising_edge(clock)) then
mem(conv_integer(addr)) <= DataIn(7 downto 0);
if(UseTopBits='1') then
mem(conv_integer(addr)+1) <= DataIn(15 downto 8);
end if;
end if;
end if;
end process;
readmem: process(Reset,Address,Write,Clock)
variable addr: integer;
begin
addr := conv_integer(Address);
if(addr>size-1) then
addr:=0;
end if;
if(Reset='1') then
DataOut <= (others => '0');
elsif(Write='0') then
DataOut <= mem(conv_integer(addr)+1) & mem(conv_integer(addr));
else
DataOut <= (others => '0');
end if;
end process;
end Behavioral;
在添加重置过程之前,根据我的测试平台,我的代码工作正常。在添加它之后,我在DataOut
上得到了各种各样的怪异。看似随机的位将具有X
而不是0
或1
的逻辑状态,这会导致我的所有测试平台失败(应该如此)
我通过将代码放入writemem
进程来修复它:
begin
--where resetmem process was
writemem: process(Reset,Write, Address, UseTopBits, Clock)
variable addr: integer;
begin
addr := conv_integer(Address);
if(addr>size-1) then
addr:=0;
end if;
if(Reset ='1' and rising_edge(Clock)) then --code is now here
mem <= (others => "00000000");
elsif(Write='1' and Reset='0') then
if(rising_edge(clock)) then
mem(conv_integer(addr)) <= DataIn(7 downto 0);
if(UseTopBits='1') then
mem(conv_integer(addr)+1) <= DataIn(15 downto 8);
end if;
end if;
end if;
end process;
所以问题现在已解决,但我不明白为什么将resetmem作为一个单独的进程导致所有这些奇怪的问题。任何人都能说明这是怎么发生的吗?
答案 0 :(得分:2)
您有两个同时驱动mem
并具有不同(非Z
)值的流程 - 这就是导致'X'值的原因。
另外,如果您计划合成代码,可能需要查看推荐的用于推断触发器的流程模板(如果您使用的是Xilinx ISE,可以在编辑&gt;语言模板&gt中找到这些模板; VHDL&gt;合成构建体&gt;编码实施例&gt;触发器)。这将有助于您优先考虑复位/时钟使能引脚,以获得有效映射到FPGA硬件的设计。
例如:
if(Write='1' and Reset='0') then
if(rising_edge(clock)) then
mem(conv_integer(addr)) <= DataIn(7 downto 0);
if(UseTopBits='1') then
mem(conv_integer(addr)+1) <= DataIn(15 downto 8);
end if;
end if;
end if;
根据您的合成器的智能,这可能会使您的时钟使能(Write
)处于比FPGA实际存在的“更高”的优先级 - 并且您在以后添加代码的风险很高这一点肯定会导致这种情况发生。
如果你把它写成:
if(Reset='1') then
--Do nothing, for now
elsif(rising_edge(clock)) then
if(Write='1') then
mem(conv_integer(addr)) <= DataIn(7 downto 0);
if(UseTopBits='1') then
mem(conv_integer(addr)+1) <= DataIn(15 downto 8);
end if;
end if;
end if;
您的代码将更加清晰,并且它还应该更好地合成底层硬件(至少在Xilinx FPGA的情况下)。
另外,请查看Ken Chapmans Get your priorities right白皮书。
答案 1 :(得分:2)
VHDL在信号上有“驱动程序”的概念。
写入信号的每个进程(或总线的一部分)都会创建一个驱动程序。当多个驱动器连接到信号时,调用“分辨率函数”,其决定结果值应该是什么。碰巧(对于第一次近似)std_logic
(因此对于std_logic_vector
位)的分辨率函数在具有相反值(1
和0
的驱动程序时产生Xs被驱使信号。还有一个名为Z
的值,它被视为非驱动值,可以被其他值覆盖。 (并且有W
,L
和H
,但我们暂时将这些留空,U
未初始化
这个过程:
resetmem: process(Clock, Reset) --this process is the troublemaker
begin
if(Reset ='1' and rising_edge(Clock)) then
mem <= (others => "00000000");
end if;
end process;
说(转述)
if(reset和clock)然后将零驱动到mem
如果条件为false,它不会说出该怎么做,因此它会继续驱动零(剩下的时间)。当您的其他流程驱动值时,它们会发生冲突并生成X
s
出于模拟目的,您可以做
else
mem <= (others => 'Z');
这将使其“驱动”高阻抗,而另一个过程可以覆盖它。
但是我认为你要做的是将RAM初始化全部为零。 FPGA RAM不能通过信号复位到特定值,但可以在配置时使用值加载。模拟器对配置过程一无所知,在配置完成后,您认为模拟正在发生。
因此,模拟此行为的一种方法是在声明信号时初始化信号:
signal mem: memorytype := (others => (others => '0'));