加法和移位乘法器的 VHDL 逻辑仿真错误

VHDL Logical Simulation Error on add and shift Multiplier

我正在尝试做一个 "add and shift multiplier (sequential)",但我在最终模拟中遇到问题,输出值总是错误的。我使用状态机逻辑来制作部分和的控制块。

当我制作 1 x 1 时,输出出错(所有产品都出错):

Output Error on VWF File

所有被乘数和乘数输入都会出现此错误。

我正在使用以下代码求和:

 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 文件连接所有块,与下面示意图的唯一区别是加法器块中有一个进位输入。 所有块的时钟都在同一个引脚上。

Controller simulation

有人知道导致此错误的原因吗?

问题出在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'。

请注意,即使您将乘数、被乘数和乘积声明为无符号,这里也有很多关于如何对乘法进行签名的提示。