带加法器的 ALU 实现
ALU implementation w/ ADDER
你好,我正在尝试创建一个带有一些操作码的 32 位加法器,我已经让它工作得很好,除了两种情况,我似乎找不到导致它们的原因。也许你可以帮帮我?
减法案例总是由于某种原因失败,ADDC 案例无法计算正确的输出,而它应该使用 c_reg 中由 ADDS 操作创建的进位位。
LIBRARY ieee;
USE ieee.std_logic_1164.ALL;
USE ieee.numeric_std.ALL;
ENTITY ALU IS
GENERIC(WIDTH : NATURAL := 32);
PORT(Clk : IN STD_LOGIC := '0';
Reset : IN STD_LOGIC := '0';
A : IN STD_LOGIC_VECTOR(WIDTH-1 DOWNTO 0) := (OTHERS => '0');
B : IN STD_LOGIC_VECTOR(WIDTH-1 DOWNTO 0) := (OTHERS => '0');
Op : IN STD_LOGIC_VECTOR(3 DOWNTO 0) := (OTHERS => '0');
Outs : OUT STD_LOGIC_VECTOR(WIDTH-1 DOWNTO 0));
END ALU;
ARCHITECTURE arch_ALU OF ALU IS
COMPONENT adder
PORT(OpA : IN STD_LOGIC_VECTOR(WIDTH-1 DOWNTO 0);
OpB : IN STD_LOGIC_VECTOR(WIDTH-1 DOWNTO 0);
Cin : IN STD_LOGIC;
Cout : OUT STD_LOGIC;
Result : OUT STD_LOGIC_VECTOR(WIDTH-1 DOWNTO 0));
END COMPONENT;
SIGNAL adder_output : STD_LOGIC_VECTOR(WIDTH-1 DOWNTO 0) := (OTHERS => '0');
SIGNAL B_neg : STD_LOGIC_VECTOR(WIDTH-1 DOWNTO 0) := (OTHERS => '0');
SIGNAL c_flag : STD_LOGIC := '0';
SIGNAL c_reg : STD_LOGIC := '0';
SIGNAL cin : STD_LOGIC := '0';
BEGIN
adder_comp : adder
PORT MAP(OpA => A,
OpB => B_neg,
Cin => cin,
Result => adder_output,
Cout => c_flag);
WITH Op SELECT
B_neg <= NOT(B) WHEN "1000",
B WHEN OTHERS;
WITH Op SELECT
cin <= '1' WHEN "1000", -- SUB
c_reg WHEN "0111", -- ADDC
'0' WHEN OTHERS; -- ADD/ADDS
ALU_Process:
PROCESS(Clk)
BEGIN
IF Reset = '0' THEN
Outs <= (OTHERS => '0');
ELSIF rising_edge(Clk) THEN
CASE Op IS
WHEN "0001" => Outs <= A AND B;
WHEN "0010" => Outs <= A OR B;
WHEN "0011" => Outs <= A NOR B;
WHEN "0100" => Outs <= A XOR B;
WHEN "0101" => Outs <= adder_output; -- ADD
WHEN "0110" => Outs <= adder_output; -- ADDS
c_reg <= c_flag;
WHEN "0111" => Outs <= adder_output; -- ADDC
WHEN "1000" => Outs <= adder_output; -- SUB
WHEN "1001" => Outs <= STD_LOGIC_VECTOR(UNSIGNED(A) SLL to_integer(UNSIGNED(B(4 DOWNTO 0))));
WHEN "1010" => Outs <= STD_LOGIC_VECTOR(unsigned(A) SRL to_integer(UNSIGNED(B(4 DOWNTO 0))));
WHEN "1011" => Outs <= STD_LOGIC_VECTOR(shift_right(SIGNED(A),to_integer(UNSIGNED(B(4 DOWNTO 0)))));
WHEN OTHERS => Outs <= (OTHERS => '0');
END CASE;
END IF;
END PROCESS;
END arch_ALU;
只有 ADDS 操作应该将其进位输出写入 c_reg 并且 ADDC 操作在计算其输出时应考虑 c_reg
加法器已经过测试并且工作正常,因此问题不在加法器设计中。
首先我想知道减法的问题,因为它正在做减法,但结果有点偏差。例如:
A : h'E6A4960F
B : h'7B494E34
作品:d'1000
出局:h'6B5B47DA 而它应该是 h'6B5B47DB
A : h'EFDE31A3
B : h'0BCAB8FA
作品:d'1000
输出:h'E41378BB 而应该是 h'E41378A9
你能发现我的错误吗?因为我当然不能..
虽然您没有提供 Minimal, Complete, and Verifiable example,但 reader 至少可以测试存在的设计减法部分:
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
entity alu is
generic (width: natural := 32);
port (
clk: in std_logic := '0';
reset: in std_logic := '0';
a: in std_logic_vector(width - 1 downto 0) := (others => '0');
b: in std_logic_vector(width - 1 downto 0) := (others => '0');
op: in std_logic_vector(3 downto 0) := (others => '0');
outs: out std_logic_vector(width - 1 downto 0)
);
end alu;
architecture arch_alu of alu is
-- component adder
-- port (
-- opa: in std_logic_vector(width - 1 downto 0);
-- opb: in std_logic_vector(width - 1 downto 0);
-- cin: in std_logic;
-- cout: out std_logic;
-- result: out std_logic_vector(width - 1 downto 0)
-- );
-- end component;
procedure adder (
signal opa: in std_logic_vector(width - 1 downto 0);
signal opb: in std_logic_vector(width - 1 downto 0);
signal cin: in std_logic;
signal cout: out std_logic;
signal result: out std_logic_vector(width - 1 downto 0)
) is
variable sum: unsigned (width downto 0);
begin
sum := unsigned('0' & opa) + unsigned(opb) + unsigned'(""& cin);
result <= std_logic_vector(sum (width - 1 downto 0));
cout <= sum(width);
end procedure;
signal adder_output: std_logic_vector(width - 1 downto 0) := (others => '0');
signal b_neg: std_logic_vector(width - 1 downto 0) := (others => '0');
signal c_flag: std_logic := '0';
signal c_reg: std_logic := '0';
signal cin: std_logic := '0';
begin
adder_comp:
adder
-- port map (
(
opa => a,
opb => b_neg,
cin => cin,
result => adder_output,
cout => c_flag
);
with op select
b_neg <= not b when "1000",
b when others;
with op select
cin <= '1' when "1000", -- sub
c_reg when "0111", -- addc
'0' when others; -- add/adds
alu_process:
process(clk)
begin
if reset = '0' then
outs <= (others => '0');
elsif rising_edge(clk) then
case op is
when "0001" => outs <= a and b;
when "0010" => outs <= a or b;
when "0011" => outs <= a nor b;
when "0100" => outs <= a xor b;
when "0101" => outs <= adder_output; -- add
when "0110" => outs <= adder_output; -- adds
c_reg <= c_flag;
when "0111" => outs <= adder_output; -- addc
when "1000" => outs <= adder_output; -- sub
when "1001" => outs <= std_logic_vector (
unsigned(a) sll to_integer(unsigned(b(4 downto 0)))
);
when "1010" => outs <= std_logic_vector (
unsigned(a) srl to_integer(unsigned(b(4 downto 0)))
);
when "1011" => outs <= std_logic_vector (
shift_right(signed(a),to_integer(unsigned(b(4 downto 0))))
);
when others => outs <= (others => '0');
end case;
end if;
end process;
end arch_alu;
library ieee;
use ieee.std_logic_1164.all;
entity alu_tb is
end entity;
architecture foo of alu_tb is
constant width: integer := 32;
signal clk: std_logic := '0';
signal reset: std_logic := '0';
signal a: std_logic_vector(width - 1 downto 0) := (others => '0');
signal b: std_logic_vector(width - 1 downto 0) := (others => '0');
signal op: std_logic_vector(3 downto 0) := (others => '0');
signal outs: std_logic_vector(width - 1 downto 0);
begin
CLOCK:
process
begin
wait for 10 ns;
clk <= not clk;
if Now > 90 ns then
wait;
end if;
end process;
DUT:
entity work.alu
port map (
clk => clk,
reset => reset,
a => a,
b => b,
op => op,
outs => outs
);
STIMULUS:
process
begin
wait for 20 ns;
reset <= '1';
a <= x"E6A4960F";
b <= x"7B494E34";
op <= "1000";
wait for 20 ns;
a <= x"EFDE31A3";
b <= x"0BCAB8FA";
wait for 20 ns;
wait;
end process;
end architecture;
我写了一个快速而肮脏的过程加法器。这消除了您的加法器 entity/architecture 和组件声明。
我为两个减法添加了一个简单的测试台,这消除了您的测试台或测试程序。
这给出了:
如您所见,结果就是您声称的正确结果。
那么剩下的就是您的加法器或您的测试平台(将责任归咎于您的组件声明是一种延伸)。
因此我们从中得到的是您没有提供足够的信息来确定错误所在。
我做了这个小演示,因为这两个错误的错误位并不相同。如果你测试过你的加法器并确定它,它可能是减法时的刺激输入。
你好,我正在尝试创建一个带有一些操作码的 32 位加法器,我已经让它工作得很好,除了两种情况,我似乎找不到导致它们的原因。也许你可以帮帮我?
减法案例总是由于某种原因失败,ADDC 案例无法计算正确的输出,而它应该使用 c_reg 中由 ADDS 操作创建的进位位。
LIBRARY ieee;
USE ieee.std_logic_1164.ALL;
USE ieee.numeric_std.ALL;
ENTITY ALU IS
GENERIC(WIDTH : NATURAL := 32);
PORT(Clk : IN STD_LOGIC := '0';
Reset : IN STD_LOGIC := '0';
A : IN STD_LOGIC_VECTOR(WIDTH-1 DOWNTO 0) := (OTHERS => '0');
B : IN STD_LOGIC_VECTOR(WIDTH-1 DOWNTO 0) := (OTHERS => '0');
Op : IN STD_LOGIC_VECTOR(3 DOWNTO 0) := (OTHERS => '0');
Outs : OUT STD_LOGIC_VECTOR(WIDTH-1 DOWNTO 0));
END ALU;
ARCHITECTURE arch_ALU OF ALU IS
COMPONENT adder
PORT(OpA : IN STD_LOGIC_VECTOR(WIDTH-1 DOWNTO 0);
OpB : IN STD_LOGIC_VECTOR(WIDTH-1 DOWNTO 0);
Cin : IN STD_LOGIC;
Cout : OUT STD_LOGIC;
Result : OUT STD_LOGIC_VECTOR(WIDTH-1 DOWNTO 0));
END COMPONENT;
SIGNAL adder_output : STD_LOGIC_VECTOR(WIDTH-1 DOWNTO 0) := (OTHERS => '0');
SIGNAL B_neg : STD_LOGIC_VECTOR(WIDTH-1 DOWNTO 0) := (OTHERS => '0');
SIGNAL c_flag : STD_LOGIC := '0';
SIGNAL c_reg : STD_LOGIC := '0';
SIGNAL cin : STD_LOGIC := '0';
BEGIN
adder_comp : adder
PORT MAP(OpA => A,
OpB => B_neg,
Cin => cin,
Result => adder_output,
Cout => c_flag);
WITH Op SELECT
B_neg <= NOT(B) WHEN "1000",
B WHEN OTHERS;
WITH Op SELECT
cin <= '1' WHEN "1000", -- SUB
c_reg WHEN "0111", -- ADDC
'0' WHEN OTHERS; -- ADD/ADDS
ALU_Process:
PROCESS(Clk)
BEGIN
IF Reset = '0' THEN
Outs <= (OTHERS => '0');
ELSIF rising_edge(Clk) THEN
CASE Op IS
WHEN "0001" => Outs <= A AND B;
WHEN "0010" => Outs <= A OR B;
WHEN "0011" => Outs <= A NOR B;
WHEN "0100" => Outs <= A XOR B;
WHEN "0101" => Outs <= adder_output; -- ADD
WHEN "0110" => Outs <= adder_output; -- ADDS
c_reg <= c_flag;
WHEN "0111" => Outs <= adder_output; -- ADDC
WHEN "1000" => Outs <= adder_output; -- SUB
WHEN "1001" => Outs <= STD_LOGIC_VECTOR(UNSIGNED(A) SLL to_integer(UNSIGNED(B(4 DOWNTO 0))));
WHEN "1010" => Outs <= STD_LOGIC_VECTOR(unsigned(A) SRL to_integer(UNSIGNED(B(4 DOWNTO 0))));
WHEN "1011" => Outs <= STD_LOGIC_VECTOR(shift_right(SIGNED(A),to_integer(UNSIGNED(B(4 DOWNTO 0)))));
WHEN OTHERS => Outs <= (OTHERS => '0');
END CASE;
END IF;
END PROCESS;
END arch_ALU;
只有 ADDS 操作应该将其进位输出写入 c_reg 并且 ADDC 操作在计算其输出时应考虑 c_reg 加法器已经过测试并且工作正常,因此问题不在加法器设计中。
首先我想知道减法的问题,因为它正在做减法,但结果有点偏差。例如:
A : h'E6A4960F B : h'7B494E34 作品:d'1000 出局:h'6B5B47DA 而它应该是 h'6B5B47DB
A : h'EFDE31A3 B : h'0BCAB8FA 作品:d'1000 输出:h'E41378BB 而应该是 h'E41378A9
你能发现我的错误吗?因为我当然不能..
虽然您没有提供 Minimal, Complete, and Verifiable example,但 reader 至少可以测试存在的设计减法部分:
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
entity alu is
generic (width: natural := 32);
port (
clk: in std_logic := '0';
reset: in std_logic := '0';
a: in std_logic_vector(width - 1 downto 0) := (others => '0');
b: in std_logic_vector(width - 1 downto 0) := (others => '0');
op: in std_logic_vector(3 downto 0) := (others => '0');
outs: out std_logic_vector(width - 1 downto 0)
);
end alu;
architecture arch_alu of alu is
-- component adder
-- port (
-- opa: in std_logic_vector(width - 1 downto 0);
-- opb: in std_logic_vector(width - 1 downto 0);
-- cin: in std_logic;
-- cout: out std_logic;
-- result: out std_logic_vector(width - 1 downto 0)
-- );
-- end component;
procedure adder (
signal opa: in std_logic_vector(width - 1 downto 0);
signal opb: in std_logic_vector(width - 1 downto 0);
signal cin: in std_logic;
signal cout: out std_logic;
signal result: out std_logic_vector(width - 1 downto 0)
) is
variable sum: unsigned (width downto 0);
begin
sum := unsigned('0' & opa) + unsigned(opb) + unsigned'(""& cin);
result <= std_logic_vector(sum (width - 1 downto 0));
cout <= sum(width);
end procedure;
signal adder_output: std_logic_vector(width - 1 downto 0) := (others => '0');
signal b_neg: std_logic_vector(width - 1 downto 0) := (others => '0');
signal c_flag: std_logic := '0';
signal c_reg: std_logic := '0';
signal cin: std_logic := '0';
begin
adder_comp:
adder
-- port map (
(
opa => a,
opb => b_neg,
cin => cin,
result => adder_output,
cout => c_flag
);
with op select
b_neg <= not b when "1000",
b when others;
with op select
cin <= '1' when "1000", -- sub
c_reg when "0111", -- addc
'0' when others; -- add/adds
alu_process:
process(clk)
begin
if reset = '0' then
outs <= (others => '0');
elsif rising_edge(clk) then
case op is
when "0001" => outs <= a and b;
when "0010" => outs <= a or b;
when "0011" => outs <= a nor b;
when "0100" => outs <= a xor b;
when "0101" => outs <= adder_output; -- add
when "0110" => outs <= adder_output; -- adds
c_reg <= c_flag;
when "0111" => outs <= adder_output; -- addc
when "1000" => outs <= adder_output; -- sub
when "1001" => outs <= std_logic_vector (
unsigned(a) sll to_integer(unsigned(b(4 downto 0)))
);
when "1010" => outs <= std_logic_vector (
unsigned(a) srl to_integer(unsigned(b(4 downto 0)))
);
when "1011" => outs <= std_logic_vector (
shift_right(signed(a),to_integer(unsigned(b(4 downto 0))))
);
when others => outs <= (others => '0');
end case;
end if;
end process;
end arch_alu;
library ieee;
use ieee.std_logic_1164.all;
entity alu_tb is
end entity;
architecture foo of alu_tb is
constant width: integer := 32;
signal clk: std_logic := '0';
signal reset: std_logic := '0';
signal a: std_logic_vector(width - 1 downto 0) := (others => '0');
signal b: std_logic_vector(width - 1 downto 0) := (others => '0');
signal op: std_logic_vector(3 downto 0) := (others => '0');
signal outs: std_logic_vector(width - 1 downto 0);
begin
CLOCK:
process
begin
wait for 10 ns;
clk <= not clk;
if Now > 90 ns then
wait;
end if;
end process;
DUT:
entity work.alu
port map (
clk => clk,
reset => reset,
a => a,
b => b,
op => op,
outs => outs
);
STIMULUS:
process
begin
wait for 20 ns;
reset <= '1';
a <= x"E6A4960F";
b <= x"7B494E34";
op <= "1000";
wait for 20 ns;
a <= x"EFDE31A3";
b <= x"0BCAB8FA";
wait for 20 ns;
wait;
end process;
end architecture;
我写了一个快速而肮脏的过程加法器。这消除了您的加法器 entity/architecture 和组件声明。
我为两个减法添加了一个简单的测试台,这消除了您的测试台或测试程序。
这给出了:
如您所见,结果就是您声称的正确结果。
那么剩下的就是您的加法器或您的测试平台(将责任归咎于您的组件声明是一种延伸)。
因此我们从中得到的是您没有提供足够的信息来确定错误所在。
我做了这个小演示,因为这两个错误的错误位并不相同。如果你测试过你的加法器并确定它,它可能是减法时的刺激输入。