乘法单元在加法期间跳过溢出位

问题描述

我基于“左移加法”原理制作了一个简单的乘法单元(16位操作数,32位结果),当需要考虑溢出位时,它在加法器部分中无法正常工作

我知道应该怎么做(制作一个17位的求和向量并向产品中添加一个溢出位),但是我不知道如何实现它。您可以在下面找到显示错误位置的波形文件mpu.vhd文件。屏幕截图没有显示最终结果,但是很明显这是错误的。如何使用16位大数字?

Place where the overflow bit is skipped

mpu.vhd

library IEEE;
use IEEE.std_logic_1164.all;
use IEEE.numeric_std.all; 

entity mpu_OP is
    port (C: in std_logic;    -- Clock
    RST : in std_logic;       -- Reset
    LAB : in std_logic;       -- Load A and B,P <= 0
    SHIFT : in std_logic;     -- Shift B and P
    OUTHL : in std_logic;     -- Output most(0) or least(1) significant word P
    DA : in std_logic_vector(15 downto 0);   -- Data A
    DB : in std_logic_vector(15 downto 0);   -- Data B
    DP : out std_logic_vector(15 downto 0)); -- Word result P
end entity;

architecture BEH of mpu_OP is
signal A,B : std_logic_vector(15 downto 0); -- A,B
signal Pi,Ai,Si : integer;
signal S : signed(15 downto 0); -- Sum 
signal S2 : signed(16 downto 0);
signal P : signed(31 downto 0); -- Product

begin 
    RG_A : process(C,RST) -- Register for A
    begin
        if (RST = '1') then
            A <= X"0000";
        elsif rising_edge(C) then                                        `-- Reg_A`
            if LAB = '1' then
                A <= DA;
            end if;
        end if;
    end process;
    
    RG_B : process(C,RST) -- Register for B
    begin
        if (RST = '1') then
            B <= X"0000";
        elsif rising_edge(C) then
            if LAB = '1' then
                B <= DB;
            elsif (SHIFT = '1') then
                B <= std_logic_vector(shift_left(unsigned(B),1));       `-- Reg_B`
            end if;
        end if;
    end process;    
    
    Adder : process (C)
    begin
        Pi <= to_integer(unsigned(std_logic_vector(P(15 downto 0))));
        Ai <= to_integer(unsigned(A));

        if B(15) = '1' then
            S <= P(15 downto 0) + signed(A);                             -- Adder
            Si <= Pi + Ai;
        else
            S <= P(15 downto 0);    
            Si <= Pi;
        S2 <= to_signed(Si,S2'length); 
        end if;
    end process;

    
    RG_P : process (C,RST,P) -- Register for P   
    begin
        if RST = '1' then 
            P <= X"00000000";
        elsif rising_edge(C) then
            if LAB = '1' then
                P <= X"00000000";
            elsif SHIFT = '1' then
                if B /= "1000000000000000" then
                    P <= P(30 downto 16) & S & '0'; -- Shift LEFT        `-- Reg_Product`
                else
                    P <= P(31 downto 16) & S;
                end if;
            end if;
        end if;
    end process;
    
    MUX_P : DP <= std_logic_vector(P(15 downto 0)) when OUTHL = '1' else
        std_logic_vector(P(31 downto 16));
    
end architecture;
        

下面是重现上述问题和测试平台的最小代码

mpu.vhd

library IEEE;
use IEEE.std_logic_1164.all;
use IEEE.numeric_std.all; 

entity mpu_TEST is
    port (C: in std_logic;
    LAB : in std_logic;
    SHIFT : in std_logic;
    DA : in std_logic_vector(15 downto 0);
    DB : in std_logic_vector(15 downto 0);
    DP : out std_logic_vector(31 downto 0));
end entity;

architecture BEH of mpu_TEST is
signal A,B : std_logic_vector(15 downto 0);
signal S : signed(15 downto 0);
signal P : signed(31 downto 0); 

begin 
    RG_A : process(C)
    begin
        if rising_edge(C) then
            if LAB = '1' then
                A <= DA;
            end if;
        end if;
    end process;
    
    RG_B : process(C) 
    begin 
        if rising_edge(C) then
            if LAB = '1' then
                B <= DB;
            elsif (SHIFT = '1') then
                B <= std_logic_vector(shift_left(unsigned(B),1));
            end if;
        end if;
    end process;    
    
    Adder : process (C)
    begin
        if B(15) = '1' then
            S <= P(15 downto 0) + signed(A);
        else
            S <= P(15 downto 0);    
        end if;
    end process;

    
    RG_P : process (C,P) 
    begin 
        if rising_edge(C) then
            if LAB = '1' then
                P <= X"00000000";
            elsif SHIFT = '1' then
                if B /= "1000000000000000" then
                    P <= P(30 downto 16) & S & '0';
                else
                    P <= P(31 downto 16) & S;
                end if;
            end if;
        end if;
    end process;
    
    DP <= std_logic_vector(P);
end architecture;
            

mpu_TB.vhd

library ieee;
use ieee.NUMERIC_STD.all;
use ieee.std_logic_1164.all;

entity mpu_test_tb is
end mpu_test_tb;

architecture TB_ARCHITECTURE of mpu_test_tb is
    component mpu_test
    port(
        C : in STD_LOGIC;
        LAB : in STD_LOGIC;
        SHIFT : in STD_LOGIC;
        DA : in STD_LOGIC_VECTOR(15 downto 0);
        DB : in STD_LOGIC_VECTOR(15 downto 0);
        DP : out STD_LOGIC_VECTOR(31 downto 0) );
    end component;


    signal C : STD_LOGIC;
    signal LAB : STD_LOGIC;
    signal SHIFT : STD_LOGIC;
    signal DA : STD_LOGIC_VECTOR(15 downto 0);
    signal DB : STD_LOGIC_VECTOR(15 downto 0);

    signal DP : STD_LOGIC_VECTOR(31 downto 0);


begin


    UUT : mpu_test
        port map (
            C => C,LAB => LAB,SHIFT => SHIFT,DA => DA,DB => DB,DP => DP
        );

    process
    begin 
        C <= '0';
        wait for 5 ns;
        C <= '1';
        wait for 5 ns;
    end process;
    
    LAB <= '1','0' after 10 ns;
    SHIFT <= '0','1' after 10 ns,'0' after 170 ns;
    DA <= X"1234";
    DB <= X"F234";
    
end TB_ARCHITECTURE;

一个新的信号,乘法结果不正确。错误发生在加法器中。

enter image description here

解决方法

我设法使其正常工作。移位产品时,我明确添加了“ 0”,并在 S 中添加了第17位以保持溢出位。同样,信号范围已更改,应将其存储在乘积和总和中。最终得到下面的代码。

MPU.vhd

library IEEE;
use IEEE.std_logic_1164.all;
use IEEE.numeric_std.all; 

entity MPU_TEST is
    port (C: in std_logic;
    LAB : in std_logic;
    SHIFT : in std_logic;
    DA : in std_logic_vector(15 downto 0);
    DB : in std_logic_vector(15 downto 0);
    DP : out std_logic_vector(31 downto 0));
end entity;

architecture BEH of MPU_TEST is
signal A,B : std_logic_vector(15 downto 0);
signal S : signed(16 downto 0);
signal P : signed(31 downto 0); 

begin 
    RG_A : process(C)
    begin
        if rising_edge(C) then
            if LAB = '1' then
                A <= DA;
            end if;
        end if;
    end process;
    
    RG_B : process(C) 
    begin 
        if rising_edge(C) then
            if LAB = '1' then
                B <= DB;
            elsif (SHIFT = '1') then
                B <= std_logic_vector(shift_left(unsigned(B),1));
            end if;
        end if;
    end process;    
    
    Adder : process (C)
    begin
        if B(15) = '1' then
            S <= P(16 downto 0) + signed(A);
        else
            S <= P(16 downto 0);    
        end if;
    end process;

    
    RG_P : process (C,P) 
    begin 
        if rising_edge(C) then
            if LAB = '1' then
                P <= X"00000000";
            elsif SHIFT = '1' then
                if B /= "1000000000000000" then
                    P <= P(30 downto 17) & S & '0';
                else
                    P <= P(31 downto 17) & S;
                end if;
            end if;
        end if;
    end process;
    
    DP <= std_logic_vector(P);
end architecture;
    

正确波形的模拟屏幕截图 First example Second example