16bit转bcd

16bit to bcd conversion

我正在尝试进行 16 位到 BCD 的转换。 我发现这个 link 是 8 位的,我正在尝试将其转换为 16 位。 http://vhdlguru.blogspot.nl/2010/04/8-bit-binary-to-bcd-converter-double.html

我不知道我做错了什么 rpm_1000 不断变化,rpm_100 保持在 4。有人知道我做错了什么吗?

process (Hex_Display_Data)
        variable i : integer:=0;
        variable bcd : std_logic_vector(19 downto 0) := (others => '0');
        variable bint : std_logic_vector(15 downto 0) := Hex_Display_Data;

    begin
        for i in 0 to 15 loop  -- repeating 16 times.
        bcd(19 downto 1) := bcd(18 downto 0);  --shifting the bits.
        bcd(0) := bint(15); -- shift bit in
        bint(15 downto 1) := bint(14 downto 0); --removing msb
        bint(0) :='0'; -- adding a '0'


        if(i < 15 and bcd(3 downto 0) > "0100") then --add 3 if BCD digit is greater than 4.
        bcd(3 downto 0) := bcd(3 downto 0) + "0011";
        end if;

        if(i < 15 and bcd(7 downto 4) > "0100") then --add 3 if BCD digit is greater than 4.
        bcd(7 downto 4) := bcd(7 downto 4) + "0011";
        end if;

        if(i < 15 and bcd(11 downto 8) > "0100") then  --add 3 if BCD digit is greater than 4.
        bcd(11 downto 8) := bcd(11 downto 8) + "0011";
        end if;

        if(i < 15 and bcd(15 downto 12) > "0100") then  --add 3 if BCD digit is greater than 4.
        bcd(15 downto 12) := bcd(15 downto 12) + "0011";
        end if;

    end loop;

    rpm_1000    <= bcd(15 downto 12);
    rpm_100     <= bcd(11 downto 8);
    rpm_10      <= bcd(7 downto 4);
    rpm_1       <= bcd(3 downto 0);


end process ;

运行 循环 16 次将使 BCD 寄存器中的值乘以 65536(mod 100000)并与二进制寄存器中的值相加。假设值为 4000。那么 4000x65536 产生 44000。44000x65536 产生 84000。84000x65536 产生 24000。24000x65536 产生 64000。而 64000x65536 产生 4000。

要使算法起作用,您必须先清除 BCD 寄存器。修复关于循环运行次数的评论也没有什么坏处。

顺便说一句,二进制到 BCD 转换器的实际实现通常应该接受时钟输入,并为每个有效时钟边沿执行一个步骤。如果您的 VHDL 运行 完全在仿真中,那么所产生的逻辑的复杂性将无关紧要,但尝试在真实硬件中同时执行所有操作将相当昂贵。相比之下,执行二进制数简单移位和 BCD 数乘以 2 的硬件要简单得多。请注意,如果您执行操作 "all at once",则输出的最高有效位将取决于输入的次低有效位,这意味着输入信号必须在一个步骤中传播通过所有逻辑。相比之下,如果每个时钟周期移动一位,输出的每一位将仅取决于输入的最多四位(因为在调整阶段之前每个数字都在 0-9 范围内,加 3 永远不会引起执行)。

此外,"double dabble" 算法要求在 BCD 移位之前执行调整,但看起来好像代码是在之后执行调整。稍微看一下之后再做调整就好了 范围为 16..13、12..9、8..5 和 4..1 而不是 15..12 等。或者,可以指定位 19..17 的值应该是位的值18..16,第 16..13 位的值应该是第 15..12 位的值(如果小于 5)或第 15..12 位的值加上三(如果更大)等。这样一个公式会将每个位的值设置在一个位置,这样可以更容易地看到它应该如何呈现到硬件中。

请注意,四个 BCD 数字可以完全包含在 14 位输入(您的 Hex_Display_Data)中,未使用的 bcd 'bits'(19 到 16)将在合成过程中与所有不能出现的加法 3,因为它们的高两位是“0”(不是 > 4)。

如果您将 bcd 值限制为 4 个十六进制数字,并将循环迭代限制为 14 位:

library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;

entity bin2bcd is
    port ( 
        input:      in   std_logic_vector (15 downto 0);
        ones:       out  std_logic_vector (3 downto 0);
        tens:       out  std_logic_vector (3 downto 0);
        hundreds:   out  std_logic_vector (3 downto 0);
        thousands:  out  std_logic_vector (3 downto 0)
    );
end entity;

architecture fum of bin2bcd is
    alias Hex_Display_Data: std_logic_vector (15 downto 0) is input;
    alias rpm_1:    std_logic_vector (3 downto 0) is ones;
    alias rpm_10:   std_logic_vector (3 downto 0) is tens;
    alias rpm_100:  std_logic_vector (3 downto 0) is hundreds;
    alias rpm_1000: std_logic_vector (3 downto 0) is thousands;
begin
    process (Hex_Display_Data)
        type fourbits is array (3 downto 0) of std_logic_vector(3 downto 0);
        -- variable i : integer := 0;  -- NOT USED
        -- variable bcd : std_logic_vector(15 downto 0) := (others => '0');
        variable bcd:   std_logic_vector (15 downto 0);
        -- variable bint : std_logic_vector(15 downto 0) := Hex_Display_Data;
        variable bint:  std_logic_vector (13 downto 0); -- SEE process body
    begin
        bcd := (others => '0');      -- ADDED for EVERY CONVERSION
        bint := Hex_Display_Data (13 downto 0); -- ADDED for EVERY CONVERSION

        for i in 0 to 13 loop
            bcd(15 downto 1) := bcd(14 downto 0);
            bcd(0) := bint(13);
            bint(13 downto 1) := bint(12 downto 0);
            bint(0) := '0';

            if i < 13 and bcd(3 downto 0) > "0100" then
                bcd(3 downto 0) := 
                    std_logic_vector (unsigned(bcd(3 downto 0)) + 3);
            end if;
            if i < 13 and bcd(7 downto 4) > "0100" then
                bcd(7 downto 4) := 
                    std_logic_vector(unsigned(bcd(7 downto 4)) + 3);
            end if;
            if i < 13 and bcd(11 downto 8) > "0100" then
                bcd(11 downto 8) := 
                    std_logic_vector(unsigned(bcd(11 downto 8)) + 3);
            end if;
            if i < 13 and bcd(15 downto 12) > "0100" then
                bcd(11 downto 8) := 
                    std_logic_vector(unsigned(bcd(15 downto 12)) + 3);
            end if;
        end loop;

        (rpm_1000, rpm_100, rpm_10, rpm_1)  <= 
                  fourbits'( bcd (15 downto 12), bcd (11 downto 8), 
                               bcd ( 7 downto  4), bcd ( 3 downto 0) );
    end process ;
end architecture;

请注意别名的使用,使您的名字能够在现有的兼容 Minimal, Complete and Verifiable Example 中使用,您的问题没有提供。

聚合信号分配也取自原来的,您对单个数字的分配应该可以正常工作。

除了将转换限制为 14 位和 BCD 位数以匹配输出的位数之外,还有两个更改。

bcdbint 变量现在在每次进程恢复时被清除(对 Hex_Display_Data 的更新敏感)。这些很可能导致您无法验证的错误。

多余的括号已被删除。

您没有提供上下文子句。显示的代码使用包 numeric_std 而不是 -2008 numeric_std_unsigned 在使用 IEEE 编写的包时提供与标准早期修订版的兼容性。

你会得到一些有用的东西,可以用测试平台证明:

library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;

entity bin2bcd_tb is
end entity;

architecture foo of bin2bcd_tb is
    signal input:      std_logic_vector (15 downto 0) := (others => '0');
    signal ones:       std_logic_vector (3 downto 0);
    signal tens:       std_logic_vector (3 downto 0);
    signal hundreds:   std_logic_vector (3 downto 0);
    signal thousands:  std_logic_vector (3 downto 0);
begin
DUT:
    entity work.bin2bcd
        port map (
            input => input,
            ones => ones,
            tens => tens,
            hundreds => hundreds,
            thousands => thousands
        );
STIMULUS:
    process
    begin
        for i in 0 to 1001 loop
            wait for 20 ns;
            input <= std_logic_vector(to_unsigned(9999 - i, 16));
        end loop;
        wait for 20 ns;
        wait;
    end process;
end architecture;

其他一些刺激方案可用于切换所有四个数字的 BCD 数字翻转。

此测试平台提供从 9999 开始并递减 1001 次的输入值以显示所有四个数字的转换:

我可以很容易地修改以证明每个 BCD 数字的每个转换。

总而言之,您遇到的错误似乎是由于子程序中变量的详细说明差异所致,其中 bcdbint 将在每次函数调用时动态详细说明和初始化,并且在他们只会被初始化一次的过程中。

来自 Xilinx 用户指南 901 Vivado Design Suite 用户指南综合 (2015.3),第 4 章:VHDL 支持、组合过程、case 语句、for 循环语句、the for 循环似乎支持合成,并且据报道在 Whosebug 上的其他双重涉猎问题中符合合成条件。问题是支持在重复的顺序语句序列中对变量进行重复赋值,这应该得到支持。在 Whosebug 上至少还有一个双重涉猎问题,其中已报告使用这样的 for 循环成功合成。

请注意,将您处理的输入值限制为 14 位不会检测到较大二进制数 (> 9999) 的影响,否则您的进程不会这样做,或者仅提供 4 个 BCD 输出数字。您可以通过检查输入值是否大于 9999 (x"270F") 来处理这个问题。

FPGA中的+3表示1个LUT深度(4位输入,4位输出),根据转换数的大小(范围i).通过 ADD3 允许转换传播的时间被显示可以被视觉解释的速率所抵消。如果您在毫秒范围内更新 Hex_Display_Data,您可能无法从视觉上分辨出差异。