我正在开发一个 VHDL 项目,需要设计一个算术单元,该单元执行 6 个 MMX x86 指令,能够处理 64 到 8 位的操作数大小。我从 PADD 指令开始,实现了一个 8 位纹波进位加法器,并将它们级联以获得所需的数据宽度。我面临的挑战是使设计适应各种操作数大小,而无需手动修改实例化语句。
我尝试使用生成语句来实例化基于 DATA_WIDTH 泛型的纹波进位加法器,但我在索引和相应地调整多路复用器逻辑方面遇到了问题。
这是我的 PADD 组件的代码:
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.STD_LOGIC_ARITH.ALL;
use IEEE.STD_LOGIC_UNSIGNED.ALL;
entity PADD is
generic (
DATA_WIDTH : integer := 64
);
Port (
Cin, clk, reset, enable : in std_logic;
op1, op2 : in std_logic_vector(DATA_WIDTH - 1 downto 0);
result : out std_logic_vector(DATA_WIDTH - 1 downto 0);
Cout : out std_logic
);
end PADD;
architecture Behavioral of PADD is
signal carry : std_logic_vector(7 downto 0);
signal S : std_logic_vector(DATA_WIDTH - 1 downto 0);
component full_adder
Port (A, B, Cin : in std_logic;
S, Cout : out std_logic);
end component;
component ripple_carry_adder_padd
Port (
A, B : in std_logic_vector(7 downto 0);
Cin : in std_logic;
S : out std_logic_vector(7 downto 0);
Cout : out std_logic
);
end component;
signal mux_res : std_logic_vector(DATA_WIDTH - 1 downto 0);
begin
carry(0) <= '0';
RCA_1 : ripple_carry_adder_padd port map(A => op1(7 downto 0), B => op2(7 downto 0), Cin => carry(0), S => S(7 downto 0), Cout => carry(1));
RCA_2 : ripple_carry_adder_padd port map(A => op1(15 downto 8), B => op2(15 downto 8), Cin => carry(1), S => S(15 downto 8), Cout => carry(2));
RCA_3 : ripple_carry_adder_padd port map(A => op1(23 downto 16), B => op2(23 downto 16), Cin => carry(2), S => S(23 downto 16), Cout => carry(3));
RCA_4 : ripple_carry_adder_padd port map(A => op1(31 downto 24), B => op2(31 downto 24), Cin => carry(3), S => S(31 downto 24), Cout => carry(4));
RCA_5 : ripple_carry_adder_padd port map(A => op1(39 downto 32), B => op2(39 downto 32), Cin => carry(4), S => S(39 downto 32), Cout => carry(5));
RCA_6 : ripple_carry_adder_padd port map(A => op1(47 downto 40), B => op2(47 downto 40), Cin => carry(5), S => S(47 downto 40), Cout => carry(6));
RCA_7 : ripple_carry_adder_padd port map(A => op1(55 downto 48), B => op2(55 downto 48), Cin => carry(6), S => S(55 downto 48), Cout => carry(7));
RCA_8 : ripple_carry_adder_padd port map(A => op1(63 downto 56), B => op2(63 downto 56), Cin => carry(7), S => S(63 downto 56), Cout => Cout);
MUX_process: process(carry, S)
begin
if carry(1) = '1' then
mux_res <= "00000000000000000000000000000000000000000000000000000000" & S(DATA_WIDTH - 1 downto DATA_WIDTH - 8); --7 downto 0
elsif carry(2) = '1' then
mux_res <= "000000000000000000000000000000000000000000000000" & S(DATA_WIDTH - 1 downto DATA_WIDTH - 16); -- 15 downto 0
elsif carry(3) = '1' then
mux_res <= "0000000000000000000000000000000000000000" & S(DATA_WIDTH - 1 downto DATA_WIDTH - 24); --23 downto 0
elsif carry(4) = '1' then
mux_res <= "00000000000000000000000000000000" & S(DATA_WIDTH - 1 downto DATA_WIDTH - 32); --31 dowto 0
elsif carry(5) = '1' then
mux_res <= "000000000000000000000000" & S(DATA_WIDTH - 1 downto DATA_WIDTH - 40); --39 downto 0
elsif carry(6) = '1' then
mux_res <= "0000000000000000" & S(DATA_WIDTH - 1 downto DATA_WIDTH - 48); --47 downto 0
elsif carry(7) = '1' then
mux_res <= "00000000" & S(DATA_WIDTH - 1 downto DATA_WIDTH - 56); -- 55 downto 0
else
mux_res <= S(DATA_WIDTH - 1 downto DATA_WIDTH - 64);
end if;
end process;
result <= mux_res;
end Behavioral;
我的问题是:
1.如何修改实例化逻辑以确保它能够无缝地处理从 64 位到 4 位的操作数大小? 2.是否有更好的方法来处理不同的操作数大小而不重复实例化语句? 3.我应该如何调整多路复用器逻辑以适应不同的操作数大小?
从字面上翻译你的代码以合并循环和更通用的编程会产生类似这样的结果(请注意,这是未经测试的):
architecture Behavioral of PADD is
constant NUM_BYTES : natural := DATA_WIDTH / 8;
signal carry : std_logic_vector(NUM_BYTES downto 0);
signal S : std_logic_vector(DATA_WIDTH - 1 downto 0);
component ripple_carry_adder_padd
Port (
A, B : in std_logic_vector(7 downto 0);
Cin : in std_logic;
S : out std_logic_vector(7 downto 0);
Cout : out std_logic
);
end component;
signal mux_res : std_logic_vector(DATA_WIDTH - 1 downto 0);
begin
carry(0) <= '0';
rc_chain : for i in 0 to NUM_BYTES - 1 generate
RC_int : ripple_carry_adder_padd
port map(
A => op1(i * 8 - 1 downto (i - 1) * 8),
B => op2(i * 8 - 1 downto (i - 1) * 8),
Cin => carry(i),
S => S(i * 8 - 1 downto (i - 1) * 8),
Cout => carry(i + 1)
);
end generate;
Cout <= carry(NUM_BYTES);
MUX_process: process(carry, S)
begin
if unsigned(carry) = 0 then
mux_res <= S(DATA_WIDTH - 1 downto DATA_WIDTH - 64);
else
for i in 1 to NUM_BYTES loop
if carry(i) = '1' then
mux_res(mux_res'high downto i * 8) <= (others => '0');
mux_res(i * 8 - 1 downto 0) <= S(DATA_WIDTH - 1 downto DATA_WIDTH - i * 8);
exit;
end if;
end loop;
end if;
end process;
result <= mux_res;
end Behavioral;
不过我不太清楚混合过程。请注意,为了真正获得您在其他代码中编写的内容,您必须执行奇怪的 if 检查。这是必需的,因为两种情况(
cary == 0
和 carry(8) == 1
)都会导致 else 情况。不确定这是否适合您的设计。用代码回答你的问题:
请参阅顶部的常数
NUM_BYTES
。我假设你的意思是从 64 位到 8 位,以 8 位为步长,因为这是你在上面写的,而你的加法器只接受 8 位输入。该代码将仅生成 DATA_WIDTH / 8
实例,因为生成循环从 0 到 NUM_BYTES - 1
是的,请参阅
generate for
语句和 for
循环。
相同的答案,请参阅
for
循环。
请注意,此代码可能无法开箱即用,因为它未经测试。然而,在流程中使用循环并在外部生成语句的想法正是您问题的一般方面所需要的。