加法和移位乘法器的 VHDL 逻辑仿真错误
VHDL Logical Simulation Error on add and shift Multiplier
我正在尝试做一个 "add and shift multiplier (sequential)",但我在最终模拟中遇到问题,输出值总是错误的。我使用状态机逻辑来制作部分和的控制块。
当我制作 1 x 1 时,输出出错(所有产品都出错):
所有被乘数和乘数输入都会出现此错误。
我正在使用以下代码求和:
library IEEE;
use IEEE.std_logic_1164.all;
entity adder_8bits is
port (
cin: in STD_LOGIC;
a,b: in STD_LOGIC_VECTOR(7 DOWNTO 0);
s: out STD_LOGIC_VECTOR(8 DOWNTO 0)
);
end adder_8bits;
architecture arch_1 of adder_8bits is
begin
process(a,b,cin)
variable soma:std_logic_vector(8 downto 0);
variable c:std_logic;
begin
c := cin;
for i in 0 to 7 loop
soma(i) := a(i) xor b(i) xor c;
c := (a(i) and b(i)) or ((a(i) xor b(i)) and c);
end loop;
s(7 downto 0) <= soma(7 downto 0);
s(8) <= c;
end process;
end arch_1;
一个 8 位加法器,用于对部分结果求和。
library IEEE;
use IEEE.std_logic_1164.all;
use IEEE.numeric_std.all;
entity sum_register is
port (
i_DIN : in UNSIGNED(8 DOWNTO 0);
i_LOAD : in STD_LOGIC;
i_CLEAR : in STD_LOGIC;
i_SHIFT : in STD_LOGIC;
i_CLK : in STD_ULOGIC;
o_DOUT : buffer UNSIGNED(15 downto 0)
);
end sum_register;
architecture arch_1 of sum_register is
begin
process(i_CLK)
begin
IF rising_edge(i_CLK) THEN
IF (i_CLEAR = '1') THEN
o_DOUT <= "0000000000000000";
ELSIF (i_LOAD = '1') THEN
o_DOUT(15 downto 7) <= i_DIN;
ELSIF (i_SHIFT = '1') THEN
IF (i_DIN(8) = '1') THEN
o_DOUT <= o_DOUT SRL 1;
END IF;
END IF;
END IF;
end process;
end arch_1;
求和寄存器,用于获取实际求和值并在其他求和之前移位。
LIBRARY IEEE;
USE IEEE.std_logic_1164.ALL;
USE IEEE.std_logic_unsigned.ALL;
use IEEE.std_logic_arith.ALL;
ENTITY controller IS
PORT (
i_CLK : IN STD_ULOGIC;
i_START : IN STD_LOGIC;
i_MLTPLR : IN STD_LOGIC_VECTOR(7 downto 0);
o_MDLD : OUT STD_LOGIC;
o_MRLD : OUT STD_LOGIC;
o_RSLD : OUT STD_LOGIC;
o_RSCLR : OUT STD_LOGIC;
o_RSSHR : OUT STD_LOGIC
);
END controller;
ARCHITECTURE arch_1 OF controller IS
TYPE state_type IS (s0, s1, s2, s3, s4, s5, s6, s7, s8, s9, s10, s11, s12, s13, s14, s15, s16, s17, s18);
SIGNAL stateT : state_type;
BEGIN
PROCESS(i_CLK)
BEGIN
IF rising_edge(i_CLK) THEN
IF (i_START = '0') THEN
stateT <= s0;
ELSE
CASE stateT IS
when s0 => if (i_START = '1') then
stateT <= s1;
end if;
when s1 => stateT <= s2;
when s2 => if (i_MLTPLR(0) = '1') then
stateT <= s3;
else
stateT <= s4;
end if;
when s3 => stateT <= s4;
when s4 => if (i_MLTPLR(1) = '1') then
stateT <= s5;
else
stateT <= s6;
end if;
when s5 => stateT <= s6;
when s6 => if (i_MLTPLR(2) = '1') then
stateT <= s7;
else
stateT <= s8;
end if;
when s7 => stateT <= s8;
when s8 => if (i_MLTPLR(3) = '1') then
stateT <= s9;
else
stateT <= s10;
end if;
when s9 => stateT <= s10;
when s10 => if (i_MLTPLR(4) = '1') then
stateT <= s11;
else
stateT <= s12;
end if;
when s11 => stateT <= s12;
when s12 => if (i_MLTPLR(5) = '1') then
stateT <= s13;
else
stateT <= s14;
end if;
when s13 => stateT <= s14;
when s14 => if (i_MLTPLR(6) = '1') then
stateT <= s15;
else
stateT <= s16;
end if;
when s15 => stateT <= s16;
when s16 => if (i_MLTPLR(7) = '1') then
stateT <= s17;
else
stateT <= s18;
end if;
when s17 => stateT <= s18;
when s18 => stateT <= s0;
END CASE;
END IF;
END IF;
END PROCESS;
o_MDLD <= '1' when (stateT = s1) else '0';
o_MRLD <= '1' when (stateT = s1) else '0';
o_RSCLR <= '1' when (stateT = s1) else '0';
o_RSLD <= '1' when (stateT = s3 or stateT = s5 or
stateT = s7 or stateT = s9 or
stateT = s11 or stateT = s13 or
stateT = s15 or stateT = s17) else '0';
o_RSSHR <= '1' when (stateT = s4 or stateT = s6 or
stateT = s8 or stateT = s10 or
stateT = s12 or stateT = s14 or
stateT = s16 or stateT = s18) else '0';
END arch_1;
一个状态机控制器,用于控制来自 desum 寄存器的输入信号。
我正在使用 BDF 文件连接所有块,与下面示意图的唯一区别是加法器块中有一个进位输入。
所有块的时钟都在同一个引脚上。
有人知道导致此错误的原因吗?
问题出在sum_register,我将加法器的进位位发送到和寄存器,所以这使得输出出错,我只是从发送的字节中取出进位位到总和寄存器。
s <= soma;
来自加法器的变量 soma 已更改为 8 位:
variable soma:std_logic_vector(7 downto 0);
求和寄存器已更改为仅从加法器接收 8 位:
architecture arch_1 of sum_register is
begin
process(i_CLK)
begin
IF rising_edge(i_CLK) THEN
IF (i_CLEAR = '1') THEN
o_DOUT <= "0000000000000000";
ELSIF (i_LOAD = '1') THEN
o_DOUT(15 downto 8) <= i_DIN;
ELSIF (i_SHIFT = '1') THEN
o_DOUT <= o_DOUT SRL 1;
END IF;
END IF;
end process;
end arch_1;
有了这个改变,模拟就可以了!
实施你的答案时:
architecture arch_1 of sum_register is
begin
process(i_CLK)
begin
IF rising_edge(i_CLK) THEN
IF (i_CLEAR = '1') THEN
o_DOUT <= "0000000000000000";
ELSIF (i_LOAD = '1') THEN
o_DOUT(15 downto 8) <= i_DIN;
ELSIF (i_SHIFT = '1') THEN
o_DOUT <= o_DOUT SRL 1;
END IF;
END IF;
end process;
end arch_1;
乘以 255 x 255 会发生什么?
你的乘积是 1(如果这是一个带符号的乘法,这将是正确的,你指定了无符号的乘数和被乘数,正确的答案是 65025(“1111111000000001”)。因为你有单独的加载和移位操作你需要保存丢弃的进位并在移入时使用它。并且因为您可以有连续的乘数位为“0”,所以您需要在移位指令中使用该进位后清除该进位(默认为预期的符号,即' 0' 表示无符号乘法)。
您可以使用 adder_8bits 总和的原始 9 位路径并保存进位:
architecture foo of sum_register is
signal carry: std_logic;
begin
process (i_clk)
begin
if rising_edge(i_clk) then
if i_clear = '1' then
o_dout <= (others => '0');
carry <= '0';
elsif i_load = '1' then
o_dout(15 downto 8) <= i_din (7 downto 0);
carry <= i_din(8);
elsif i_shift = '1' then
o_dout <= carry & o_dout(15 downto 1);
carry <= '0'; -- expected sign for multiply result
end if;
end if;
end process;
end architecture;
请注意,它在消耗时被清除,需要前面的加载插入 carry = '1'。
如果您有两个加载和移位加载指令和加载指令而不是加载指令和移位指令,那么这种设计可能会消失。这将需要从 Moore 状态机切换到 Mealy 状态机并减少状态数。
你是控制器,Moore 状态机可以遍历 16 个状态,同时为乘数“11111111”进行移位和加载,Mealy 状态机可以在 8 个状态下进行移位和加载以及移位操作sum_register.
sum_register 看起来像:
architecture fum of sum_register is
begin
process (i_clk)
begin
if rising_edge(i_clk) then
if i_clear = '1' then
o_dout <= (others => '0');
elsif i_load_shift = '1' then
o_dout(15 downto 7) <= i_din & o_dout (6 downto 1);
elsif i_shift = '1' then
o_dout <= '0' & o_dout(15 downto 1); -- '0' expected result sign
end if;
end if;
end process;
end architecture;
来自 adder_8bits 的 9 位总和。请注意,i_load 信号已重命名为 i_load_shift,控制器状态机需要重写为发出 i_load_shift = '1' 或 i_shift 的 Mealy 机器= '1' 和另一个 '0' 取决于评估的乘数位是 '1' 还是 '0'。
请注意,即使您将乘数、被乘数和乘积声明为无符号,这里也有很多关于如何对乘法进行签名的提示。
我正在尝试做一个 "add and shift multiplier (sequential)",但我在最终模拟中遇到问题,输出值总是错误的。我使用状态机逻辑来制作部分和的控制块。
当我制作 1 x 1 时,输出出错(所有产品都出错):
所有被乘数和乘数输入都会出现此错误。
我正在使用以下代码求和:
library IEEE;
use IEEE.std_logic_1164.all;
entity adder_8bits is
port (
cin: in STD_LOGIC;
a,b: in STD_LOGIC_VECTOR(7 DOWNTO 0);
s: out STD_LOGIC_VECTOR(8 DOWNTO 0)
);
end adder_8bits;
architecture arch_1 of adder_8bits is
begin
process(a,b,cin)
variable soma:std_logic_vector(8 downto 0);
variable c:std_logic;
begin
c := cin;
for i in 0 to 7 loop
soma(i) := a(i) xor b(i) xor c;
c := (a(i) and b(i)) or ((a(i) xor b(i)) and c);
end loop;
s(7 downto 0) <= soma(7 downto 0);
s(8) <= c;
end process;
end arch_1;
一个 8 位加法器,用于对部分结果求和。
library IEEE;
use IEEE.std_logic_1164.all;
use IEEE.numeric_std.all;
entity sum_register is
port (
i_DIN : in UNSIGNED(8 DOWNTO 0);
i_LOAD : in STD_LOGIC;
i_CLEAR : in STD_LOGIC;
i_SHIFT : in STD_LOGIC;
i_CLK : in STD_ULOGIC;
o_DOUT : buffer UNSIGNED(15 downto 0)
);
end sum_register;
architecture arch_1 of sum_register is
begin
process(i_CLK)
begin
IF rising_edge(i_CLK) THEN
IF (i_CLEAR = '1') THEN
o_DOUT <= "0000000000000000";
ELSIF (i_LOAD = '1') THEN
o_DOUT(15 downto 7) <= i_DIN;
ELSIF (i_SHIFT = '1') THEN
IF (i_DIN(8) = '1') THEN
o_DOUT <= o_DOUT SRL 1;
END IF;
END IF;
END IF;
end process;
end arch_1;
求和寄存器,用于获取实际求和值并在其他求和之前移位。
LIBRARY IEEE;
USE IEEE.std_logic_1164.ALL;
USE IEEE.std_logic_unsigned.ALL;
use IEEE.std_logic_arith.ALL;
ENTITY controller IS
PORT (
i_CLK : IN STD_ULOGIC;
i_START : IN STD_LOGIC;
i_MLTPLR : IN STD_LOGIC_VECTOR(7 downto 0);
o_MDLD : OUT STD_LOGIC;
o_MRLD : OUT STD_LOGIC;
o_RSLD : OUT STD_LOGIC;
o_RSCLR : OUT STD_LOGIC;
o_RSSHR : OUT STD_LOGIC
);
END controller;
ARCHITECTURE arch_1 OF controller IS
TYPE state_type IS (s0, s1, s2, s3, s4, s5, s6, s7, s8, s9, s10, s11, s12, s13, s14, s15, s16, s17, s18);
SIGNAL stateT : state_type;
BEGIN
PROCESS(i_CLK)
BEGIN
IF rising_edge(i_CLK) THEN
IF (i_START = '0') THEN
stateT <= s0;
ELSE
CASE stateT IS
when s0 => if (i_START = '1') then
stateT <= s1;
end if;
when s1 => stateT <= s2;
when s2 => if (i_MLTPLR(0) = '1') then
stateT <= s3;
else
stateT <= s4;
end if;
when s3 => stateT <= s4;
when s4 => if (i_MLTPLR(1) = '1') then
stateT <= s5;
else
stateT <= s6;
end if;
when s5 => stateT <= s6;
when s6 => if (i_MLTPLR(2) = '1') then
stateT <= s7;
else
stateT <= s8;
end if;
when s7 => stateT <= s8;
when s8 => if (i_MLTPLR(3) = '1') then
stateT <= s9;
else
stateT <= s10;
end if;
when s9 => stateT <= s10;
when s10 => if (i_MLTPLR(4) = '1') then
stateT <= s11;
else
stateT <= s12;
end if;
when s11 => stateT <= s12;
when s12 => if (i_MLTPLR(5) = '1') then
stateT <= s13;
else
stateT <= s14;
end if;
when s13 => stateT <= s14;
when s14 => if (i_MLTPLR(6) = '1') then
stateT <= s15;
else
stateT <= s16;
end if;
when s15 => stateT <= s16;
when s16 => if (i_MLTPLR(7) = '1') then
stateT <= s17;
else
stateT <= s18;
end if;
when s17 => stateT <= s18;
when s18 => stateT <= s0;
END CASE;
END IF;
END IF;
END PROCESS;
o_MDLD <= '1' when (stateT = s1) else '0';
o_MRLD <= '1' when (stateT = s1) else '0';
o_RSCLR <= '1' when (stateT = s1) else '0';
o_RSLD <= '1' when (stateT = s3 or stateT = s5 or
stateT = s7 or stateT = s9 or
stateT = s11 or stateT = s13 or
stateT = s15 or stateT = s17) else '0';
o_RSSHR <= '1' when (stateT = s4 or stateT = s6 or
stateT = s8 or stateT = s10 or
stateT = s12 or stateT = s14 or
stateT = s16 or stateT = s18) else '0';
END arch_1;
一个状态机控制器,用于控制来自 desum 寄存器的输入信号。
我正在使用 BDF 文件连接所有块,与下面示意图的唯一区别是加法器块中有一个进位输入。 所有块的时钟都在同一个引脚上。
有人知道导致此错误的原因吗?
问题出在sum_register,我将加法器的进位位发送到和寄存器,所以这使得输出出错,我只是从发送的字节中取出进位位到总和寄存器。
s <= soma;
来自加法器的变量 soma 已更改为 8 位:
variable soma:std_logic_vector(7 downto 0);
求和寄存器已更改为仅从加法器接收 8 位:
architecture arch_1 of sum_register is
begin
process(i_CLK)
begin
IF rising_edge(i_CLK) THEN
IF (i_CLEAR = '1') THEN
o_DOUT <= "0000000000000000";
ELSIF (i_LOAD = '1') THEN
o_DOUT(15 downto 8) <= i_DIN;
ELSIF (i_SHIFT = '1') THEN
o_DOUT <= o_DOUT SRL 1;
END IF;
END IF;
end process;
end arch_1;
有了这个改变,模拟就可以了!
实施你的答案时:
architecture arch_1 of sum_register is
begin
process(i_CLK)
begin
IF rising_edge(i_CLK) THEN
IF (i_CLEAR = '1') THEN
o_DOUT <= "0000000000000000";
ELSIF (i_LOAD = '1') THEN
o_DOUT(15 downto 8) <= i_DIN;
ELSIF (i_SHIFT = '1') THEN
o_DOUT <= o_DOUT SRL 1;
END IF;
END IF;
end process;
end arch_1;
乘以 255 x 255 会发生什么?
你的乘积是 1(如果这是一个带符号的乘法,这将是正确的,你指定了无符号的乘数和被乘数,正确的答案是 65025(“1111111000000001”)。因为你有单独的加载和移位操作你需要保存丢弃的进位并在移入时使用它。并且因为您可以有连续的乘数位为“0”,所以您需要在移位指令中使用该进位后清除该进位(默认为预期的符号,即' 0' 表示无符号乘法)。
您可以使用 adder_8bits 总和的原始 9 位路径并保存进位:
architecture foo of sum_register is
signal carry: std_logic;
begin
process (i_clk)
begin
if rising_edge(i_clk) then
if i_clear = '1' then
o_dout <= (others => '0');
carry <= '0';
elsif i_load = '1' then
o_dout(15 downto 8) <= i_din (7 downto 0);
carry <= i_din(8);
elsif i_shift = '1' then
o_dout <= carry & o_dout(15 downto 1);
carry <= '0'; -- expected sign for multiply result
end if;
end if;
end process;
end architecture;
请注意,它在消耗时被清除,需要前面的加载插入 carry = '1'。
如果您有两个加载和移位加载指令和加载指令而不是加载指令和移位指令,那么这种设计可能会消失。这将需要从 Moore 状态机切换到 Mealy 状态机并减少状态数。
你是控制器,Moore 状态机可以遍历 16 个状态,同时为乘数“11111111”进行移位和加载,Mealy 状态机可以在 8 个状态下进行移位和加载以及移位操作sum_register.
sum_register 看起来像:
architecture fum of sum_register is
begin
process (i_clk)
begin
if rising_edge(i_clk) then
if i_clear = '1' then
o_dout <= (others => '0');
elsif i_load_shift = '1' then
o_dout(15 downto 7) <= i_din & o_dout (6 downto 1);
elsif i_shift = '1' then
o_dout <= '0' & o_dout(15 downto 1); -- '0' expected result sign
end if;
end if;
end process;
end architecture;
来自 adder_8bits 的 9 位总和。请注意,i_load 信号已重命名为 i_load_shift,控制器状态机需要重写为发出 i_load_shift = '1' 或 i_shift 的 Mealy 机器= '1' 和另一个 '0' 取决于评估的乘数位是 '1' 还是 '0'。
请注意,即使您将乘数、被乘数和乘积声明为无符号,这里也有很多关于如何对乘法进行签名的提示。