16位到bcd的转换

时间:2016-09-17 15:59:21

标签: vhdl data-conversion bcd

我正在尝试进行16位BCD转换。 我发现这个链接为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 ;

2 个答案:

答案 0 :(得分:1)

注意四个BCD数字可以完全包含在14位输入(您的Hex_Display_Data)和未使用的bcd&#39;位&#39; (19 downto 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的更新敏感)。这些导致了你的其他无法验证的错误。

外部括号已删除。

您没有提供上下文条款。显示的代码使用package 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次以显示所有四位数转换:

bin2bcd_tb.png

我可以轻松修改以证明每个BCD数字的每次转换。

总之,您遇到的错误似乎来自于子程序中变量的详细说明,其中bcdbint将动态详细说明并初始化每个函数调用,并且过程,它们只会被初始化一次。

从查看Xilinx用户指南901 Vivado Design Suite用户指南,综合(2015.3),第4章:VHDL支持,组合流程,案例陈述,for-loop语句,for循环似乎得到了综合的支持,并且据报道在stackoverflow的其他双重问题中合成是合格的。问题是支持在重复的顺序语句序列中重复分配变量,这应该得到支持。 stackoverflow上至少还有一个双重涉及问题,其中使用这样的for循环报告了成功的合成。

请注意,将您处理的输入值限制为14位并不能检测到较大二进制数(> 9999)的影响,否则您的进程无法提供4个BCD输出数字。您可以通过检查输入值是否大于9999(x&#34; 270F&#34;)来解决这个问题。

+ 3表示FPGA中的1 LUT深度(4位输入,4位输出),根据转换后的数字的大小(i的范围),有一些数字深度分层。允许通过ADD3进行转换传播的时间被可视地解释显示的速率所抵消。如果您在毫秒范围内更新Hex_Display_Data,则可能无法直观地区分。

答案 1 :(得分:0)

运行循环16次将使BCD寄存器中的值乘以65536(mod 100000)并添加到二进制寄存器中的值。假设值为4000.然后4000x65536收益率44000. 44000x65536收益率84000. 84000x65536收益率24000. 24000x65536收益率64000.而64000x65536收益率为4000.

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

顺便提一下,二进制到BCD转换器的实际应用通常应接受时钟输入,并为每个有效时钟边沿执行一步。如果您的VHDL完全在仿真中运行,那么生成的逻辑的复杂性并不重要,但尝试在真实硬件中同时执行所有操作将相当昂贵。相比之下,用于简单地移动二进制数和BCD数乘以2的硬件将更加简单。请注意,如果您“一次性”执行操作,则输出的最高有效位将取决于输入的第二个最低有效位,这意味着输入信号必须在一个步骤中传播通过所有逻辑。相比之下,如果每个时钟周期移位一位,输出的每个位仅取决于输入的最多四位(因为在调整阶段之前每个数字将在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的值,加上3(如果大于)等等。一个公式可以将每个位的值设置在一个位置,这样可以更容易地看到它应该如何被渲染到硬件中。