在分频器代码 VHDL 中输出始终为零(商和余数)

Output is always zeros (quotient and remainder) in divider code VHDL

在下面显示的代码中,输出始终为零(商和余数)。 即使我将 b 的值分配给余数,它也会给出 0。我已经检查了很多次,但我无法理解问题所在。编译时,它显示 2 个警告:

- Initial value of "b" depends on value of signal "divisor".

有什么问题?

-- 分频器

library ieee;  
use ieee.numeric_bit.all;  

entity unsigned_divider is  
port(
-- the two inputs  
dividend: in bit_vector(15 downto 0);  
divisor : in bit_vector(15 downto 0);  
-- the two outputs  
quotient : out bit_vector(15 downto 0);  
remainder : out bit_vector(15 downto 0)  
);  
end entity unsigned_divider;  

architecture behave of unsigned_divider is  

begin  
process  

variable a : bit_vector(15 downto 0):=dividend;  
variable b : bit_vector(15 downto 0):=divisor;  

variable p : bit_vector(15 downto 0):= (others => '0');  
variable i : integer:=0;  
begin  

for i in 0 to 15 loop  
p(15 downto 1) := p(14 downto 0);  
p(0) := a(15);  
a(15 downto 1) := a(14 downto 0);  
p := bit_vector(unsigned(p) -  unsigned(b));  

if(p(15) ='1') then  
a(0) :='0';  
p := bit_vector(unsigned(p) +  unsigned(b));  
else  
a(0) :='1';  
end if;  
wait for 1 ns;  

end loop;

quotient <= a after 1 ns;  
remainder <= p  after 1 ns;  

end process;
end behave;

变量赋值立即生效;但是信号在创建该变量时没有任何价值,因此您不能指望赋值

variable a : bit_vector(15 downto 0):=dividend;  
variable b : bit_vector(15 downto 0):=divisor;

才能正常工作。不过令我感到惊讶的是,没有人抱怨对变量 a 的赋值。也许这是你的第二次警告。您应该按照自己的方式定义变量,但稍后在流程的 begin 部分中保留分配。

P.S。此外,您可能希望将 remainder <= p after 1ns; 更改为 remainder <= p after 1 ns;

您应该对过程语句部分内的变量 a 和 b 进行显式赋值(作为顺序信号赋值)。声明:

        variable a : bit_vector(15 downto 0):=dividend;  
        variable b : bit_vector(15 downto 0):=divisor;  

应该是:

        variable a : bit_vector(15 downto 0);  
        variable b : bit_vector(15 downto 0);  

并且在流程语句部分(在流程开始之后):

        a := dividend;
        b := divisor;

这些解决了 natipar 提到的问题,即值仅在初始化期间分配给 a 和 b。

如果您还希望有 1 ns 的延迟,您应该有一个显式等待语句作为过程语句过程语句部分的最后一个顺序语句:

wait on dividend, divisor;

这些使您的过程语句看起来像这样(添加了缩进):

    process  

        variable a : bit_vector(15 downto 0); -- := dividend;  
        variable b : bit_vector(15 downto 0); -- := divisor;  

        variable p : bit_vector(15 downto 0) :=  (others => '0');  
        variable i : integer := 0;  
    begin  

        a := dividend;
        b := divisor;

        for i in 0 to 15 loop  
            p(15 downto 1) := p(14 downto 0);  
            p(0) := a(15);  
            a(15 downto 1) := a(14 downto 0);  
            p := bit_vector(unsigned(p) -  unsigned(b));  

            if  p(15)  = '1'  then  
                a(0) :='0';  
                p := bit_vector(unsigned(p) +  unsigned(b));  
            else  
                a(0) := '1';
            end if;  
            wait for 1 ns;  

        end loop;

        quotient <= a after 1 ns;  
        remainder <= p  after 1 ns;  

        wait on dividend, divisor;

    end process;

(注意数字文字和单位之间的space,IEEE Std 1076-2008, 15.3 Lexical elements, separators and delimiters paragraph 4, the last sentence "At least one separator is required between an identifier or an abstract literal and an adjacent identifier or abstract literal.", required by Modelsim不需要它)。

编写一个简单的测试平台,我们发现您的恢复除法算法中至少有一个错误:

entity unsigned_divider_tb is
end entity;

architecture foo of unsigned_divider_tb is
    signal dividend, divisor: bit_vector (15 downto 0) := (others => '0');
    signal quotient, remainder: bit_vector (15 downto 0);

    function to_string(inp: bit_vector) return string is
        variable image_str: string (1 to inp'length);
        alias input_str:  bit_vector (1 to inp'length) is inp;
    begin
        for i in input_str'range loop
            image_str(i) := character'VALUE(BIT'IMAGE(input_str(i)));
        end loop;
        return image_str;
    end;

begin
DUT:
    entity work.unsigned_divider
        port map (
            dividend,
            divisor,
            quotient,
            remainder
        );
MONITOR:
    process (quotient, remainder)
    begin
        report "quotient = " & to_string (quotient) severity NOTE;
        report "remainder = " & to_string (remainder) severity NOTE;
    end process;

end architecture;

ghdl -a unsigned_divider.vhdl
ghdl -e unsigned_divider_tb
ghdl -r unsigned_divider_tb
unsigned_divider.vhdl:83:9:@0ms:(report note): quotient = 0000000000000000
unsigned_divider.vhdl:84:9:@0ms:(report note): remainder = 0000000000000000
unsigned_divider.vhdl:83:9:@17ns:(report note): quotient = 1111111111111111
unsigned_divider.vhdl:84:9:@17ns:(report note): remainder = 0000000000000000

(以及关于解释的注释,在时间 0 ms 报告的事务是作为详细说明的结果执行的默认分配)。

你的算法给出了除以 0 的错误答案。

向测试平台添加刺激过程:

STIMULUS:
    process
    begin
        wait for 20 ns;
        dividend <= x"ffff";
        divisor <= x"000f";
    end process;

说明它也能得到正确答案:

unsigned_divider.vhdl:83:9:@37ns:(report note): quotient = 0001000100010001
unsigned_divider.vhdl:84:9:@37ns:(report note): remainder = 0000000000000000

通过测试平台以及在刺激过程中添加的等待语句和赋值,您可以进一步探索。

我自己一直是非恢复除法的粉丝,因为加法或减法需要时钟分频器中的时钟。