我正在尝试用VHDL编写寄存器文件。该文件包含16个64位寄存器。每个周期读取两个寄存器并写入一个寄存器(假设写入已启用)。应该有一个数据旁路(转发),这样如果我们在一个周期内读取和写入同一个寄存器,那么刚写入的值就会直接转发到输出。
我的想法是在上升沿写入并在时钟的下降沿读取,以便在一个周期内完成此操作。但是,我的设计不起作用(不是我预期的,因为我不相信检查 if 块中的下降沿检查上升沿将按预期工作)。
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.NUMERIC_STD.ALL;
entity register_file is
port
(
outA : out std_logic_vector(63 downto 0);
outB : out std_logic_vector(63 downto 0);
input : in std_logic_vector(63 downto 0);
writeEnable : in std_logic;
regASel : in std_logic_vector(5 downto 0);
regBSel : in std_logic_vector(5 downto 0);
writeRegSel : in std_logic_vector(5 downto 0);
clk : in std_logic
);
end register_file;
architecture behavioral of register_file is
type registerFile is array(0 to 15) of std_logic_vector(63 downto 0);
signal registers : registerFile;
begin
regFile: process(clk)
begin
if rising_edge(clk) then
if(writeEnable = '1') then
registers(to_integer(unsigned(writeRegSel))) <= input;
end if;
if falling_edge(clk) then
outA <= registers(to_integer(unsigned(regASel)));
outB <= registers(to_integer(unsigned(regBSel)));
end if;
end if;
if falling_edge(clk) then
outA <= registers(to_integer(unsigned(regASel)));
outB <= registers(to_integer(unsigned(regBSel)));
end if;
end process;
end behavioral;
任何帮助都将不胜感激。
答案 0 :(得分:7)
提交的VHDL代码具有以下结构:
...
if rising_edge(clk) then
...
if falling_edge(clk) then
...
这将留下死代码,因为rising_edge
和falling_edge
都不能
同时是真的。此外,使用上升和下降边缘的想法
经常会导致设计和合成问题。
为了获得最佳时机,易于设计和合成限制,我建议 仅使用上升沿,除非必须同时使用上升沿和下降沿 边缘。
在同一周期中绕过读A和B的写数据,寄存器 文件可能如下所示:
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
entity register_file is
port(
outA : out std_logic_vector(63 downto 0);
outB : out std_logic_vector(63 downto 0);
input : in std_logic_vector(63 downto 0);
writeEnable : in std_logic;
regASel : in std_logic_vector(3 downto 0);
regBSel : in std_logic_vector(3 downto 0);
writeRegSel : in std_logic_vector(3 downto 0);
clk : in std_logic
);
end register_file;
architecture behavioral of register_file is
type registerFile is array(0 to 15) of std_logic_vector(63 downto 0);
signal registers : registerFile;
begin
regFile : process (clk) is
begin
if rising_edge(clk) then
-- Read A and B before bypass
outA <= registers(to_integer(unsigned(regASel)));
outB <= registers(to_integer(unsigned(regBSel)));
-- Write and bypass
if writeEnable = '1' then
registers(to_integer(unsigned(writeRegSel))) <= input; -- Write
if regASel = writeRegSel then -- Bypass for read A
outA <= input;
end if;
if regBSel = writeRegSel then -- Bypass for read B
outB <= input;
end if;
end if;
end if;
end process;
end behavioral;
请注意,* Sel中的“地址”仅减少到4位,以匹配16 正如Daniel Kamil Kozar所指出的那样,在登记档案中必填的条目。
模拟中没有检查X值,但可以添加
Is_X
功能,如果需要。
答案 1 :(得分:1)
在绝大多数情况下,您不能在进程中具有上升沿和下降沿,因为您将定位的(大多数)设备中没有可以在两个边缘上响应的项目。 (一个例外是支持双倍数据速率IO的设备中的IO触发器。)
如果您想要绕过,请在正常的上升沿过程中明确编码:
outa <= registers(to_integer(...etc));
if write_enable = '1' and regAsel = writeregsel then
outa <= input;
end if;
-- similar for regb
另外,为什么不将integer
类型或至少unsigned
的注册表输入 - 因为它们肯定代表一个数字(不仅仅是一个任意的数据包,这是你的情况)数据IO矢量)?