在VHDL中将8位二进制数转换为BCD

use*_*920 1 binary vhdl bcd

该算法众所周知,您进行 8 次左移,并在每次移位后检查个位、数十位或数百位(每个 4 位)。如果它们超过 4 个,则将 3 个添加到该组中,依此类推...

这是一个基于流程的解决方案,但不起作用。它会编译,但输出不是我想要的。有什么想法可能是什么问题吗?

library ieee ;
use ieee.std_logic_1164.all ;
use ieee.std_logic_unsigned.all ;

entity hex2bcd is
    port ( hex_in  : in  std_logic_vector (7 downto 0) ;
           bcd_hun : out std_logic_vector (3 downto 0) ;
           bcd_ten : out std_logic_vector (3 downto 0) ;
           bcd_uni : out std_logic_vector (3 downto 0) ) ;
end hex2bcd ;

architecture arc_hex2bcd of hex2bcd is
begin
    process ( hex_in )
        variable hex_src : std_logic_vector (7 downto 0) ;
        variable bcd     : std_logic_vector (11 downto 0) ;
    begin
        hex_src := hex_in ;
        bcd     := (others => '0') ;

        for i in 0 to 7 loop
            bcd := bcd(11 downto 1) & hex_src(7) ; -- shift bcd + 1 new entry
            hex_src := hex_src(7 downto 1) & '0' ; -- shift src + pad with 0

            if bcd(3 downto 0) > "0100" then
                bcd(3 downto 0) := bcd(3 downto 0) + "0011" ;
            end if ;
            if bcd(7 downto 4) > "0100" then
                bcd(7 downto 4) := bcd(7 downto 4) + "0011" ;
            end if ;
            if bcd(11 downto 8) > "0100" then
                bcd(11 downto 8) := bcd(11 downto 8) + "0011" ;
            end if ;
        end loop ;

        bcd_hun <= bcd(11 downto 8) ;
        bcd_ten <= bcd(7  downto 4) ;
        bcd_uni <= bcd(3  downto 0) ;

    end process ;
end arc_hex2bcd ;
Run Code Online (Sandbox Code Playgroud)

小智 5

评论变得太长了。

考虑以下框图:

bin8bcd 框图

这表示一个展开的循环 ( for i in 0 to 7 loop),并表明对于 LS BCD 数字,在 i = 2 之前不发生添加 +3,对于中间 BCD 数字,在 i = 5 之前不发生添加 +3,并且在 MS BCD 数字上不发生调整,它部分由静态“0”值组成。

这给了我们总共 7 个 add3 模块(由封闭的 if 语句和条件 add +3 表示)。

这在 VHDL 中得到了演示:

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

entity bin8bcd is
    port (
        bin:    in  std_logic_vector (7 downto 0);
        bcd:    out std_logic_vector (11 downto 0)
    );
end entity;

architecture struct of bin8bcd is
    procedure add3 (signal bin: in  std_logic_vector (3 downto 0); 
                    signal bcd: out std_logic_vector (3 downto 0)) is
    variable is_gt_4:  std_logic;
    begin
        is_gt_4 := bin(3) or (bin(2) and (bin(1) or bin(0)));

        if is_gt_4 = '1' then
        -- if to_integer(unsigned (bin)) > 4 then
            bcd <= std_logic_vector(unsigned(bin) + "0011");
        else
            bcd <= bin;
        end if;
    end procedure;

    signal U0bin,U1bin,U2bin,U3bin,U4bin,U5bin,U6bin:
                std_logic_vector (3 downto 0);

    signal U0bcd,U1bcd,U2bcd,U3bcd,U4bcd,U5bcd,U6bcd:
                std_logic_vector (3 downto 0);       
begin
    U0bin <= '0' & bin (7 downto 5);
    U1bin <= U0bcd(2 downto 0) & bin(4);
    U2bin <= U1bcd(2 downto 0) & bin(3);
    U3bin <= U2bcd(2 downto 0) & bin(2);
    U4bin <= U3bcd(2 downto 0) & bin(1);

    U5bin <= '0' & U0bcd(3) & U1bcd(3) & U2bcd(3);
    U6bin <= U5bcd(2 downto 0) & U3bcd(3);

U0: add3(U0bin,U0bcd);

U1: add3(U1bin,U1bcd);

U2: add3(U2bin,U2bcd);

U3: add3(U3bin,U3bcd);

U4: add3(U4bin,U4bcd);

U5: add3(U5bin,U5bcd);

U6: add3(U6bin,U6bcd);

OUTP:
    bcd <= '0' & '0' & U5bcd(3) & U6bcd & U4bcd & bin(0);

end architecture;

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

entity bin8bcd_tb is
end entity;

architecture foo of bin8bcd_tb is
    signal bin: std_logic_vector (7 downto 0) := (others => '0');
    -- (initialized to prevent those annoying metavalue reports)

    signal bcd: std_logic_vector (11 downto 0);

begin

DUT:
    entity work.bin8bcd
        port map (
            bin => bin,
            bcd => bcd
        );

STIMULUS:
    process

    begin
        for i in 0 to 255 loop
            bin <= std_logic_vector(to_unsigned(i,8));
            wait for 1 ns;
        end loop;
        wait for 1 ns;
        wait;
    end process;
end architecture;
Run Code Online (Sandbox Code Playgroud)

当运行附带的测试台时,会产生:

bin8bcd_tb PNG

如果您滚动浏览整个波形,您会发现从 001 到 255 的所有 bcd 输出都存在并被考虑(没有孔),任何地方都没有“X”或“U”。

从显示 i = 7 的框图中我们可以看出,在最后一次移位之后没有发生 add +3。

另请注意,bcd 的 LSB 始终是 bin 的 LSB,并且 bcd(11) 和 bcd(10) 始终为“0”。

add3 可以手动优化,使用逻辑运算符创建 3 的增量,以消除报告从 bin 派生的元值的任何可能性(并且会有很多元值)。

据我所知,这代表了 8 位二进制到 12 位 BCD 转换的最优化表示。

之前我编写了一个 C 程序来为 espresso(术语最小化器)提供输入:

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

entity bin8bcd is
    port (
        bin:    in  std_logic_vector (7 downto 0);
        bcd:    out std_logic_vector (11 downto 0)
    );
end entity;

architecture struct of bin8bcd is
    procedure add3 (signal bin: in  std_logic_vector (3 downto 0); 
                    signal bcd: out std_logic_vector (3 downto 0)) is
    variable is_gt_4:  std_logic;
    begin
        is_gt_4 := bin(3) or (bin(2) and (bin(1) or bin(0)));

        if is_gt_4 = '1' then
        -- if to_integer(unsigned (bin)) > 4 then
            bcd <= std_logic_vector(unsigned(bin) + "0011");
        else
            bcd <= bin;
        end if;
    end procedure;

    signal U0bin,U1bin,U2bin,U3bin,U4bin,U5bin,U6bin:
                std_logic_vector (3 downto 0);

    signal U0bcd,U1bcd,U2bcd,U3bcd,U4bcd,U5bcd,U6bcd:
                std_logic_vector (3 downto 0);       
begin
    U0bin <= '0' & bin (7 downto 5);
    U1bin <= U0bcd(2 downto 0) & bin(4);
    U2bin <= U1bcd(2 downto 0) & bin(3);
    U3bin <= U2bcd(2 downto 0) & bin(2);
    U4bin <= U3bcd(2 downto 0) & bin(1);

    U5bin <= '0' & U0bcd(3) & U1bcd(3) & U2bcd(3);
    U6bin <= U5bcd(2 downto 0) & U3bcd(3);

U0: add3(U0bin,U0bcd);

U1: add3(U1bin,U1bcd);

U2: add3(U2bin,U2bcd);

U3: add3(U3bin,U3bcd);

U4: add3(U4bin,U4bcd);

U5: add3(U5bin,U5bcd);

U6: add3(U6bin,U6bcd);

OUTP:
    bcd <= '0' & '0' & U5bcd(3) & U6bcd & U4bcd & bin(0);

end architecture;

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

entity bin8bcd_tb is
end entity;

architecture foo of bin8bcd_tb is
    signal bin: std_logic_vector (7 downto 0) := (others => '0');
    -- (initialized to prevent those annoying metavalue reports)

    signal bcd: std_logic_vector (11 downto 0);

begin

DUT:
    entity work.bin8bcd
        port map (
            bin => bin,
            bcd => bcd
        );

STIMULUS:
    process

    begin
        for i in 0 to 255 loop
            bin <= std_logic_vector(to_unsigned(i,8));
            wait for 1 ns;
        end loop;
        wait for 1 ns;
        wait;
    end process;
end architecture;
Run Code Online (Sandbox Code Playgroud)

然后开始研究中间术语,这将直接引导您了解上面框图中所表示的内容。

当然,您可以使用实际的组件 add3 以及使用嵌套的生成语句来连接所有内容。

如果不限制 if 语句(对于 LS BCD 数字,2 < i < 7,对于中间 BCD 数字,5 < i < 7),您将无法从循环语句表示中获得相同的最小化硬件。

您希望辅助嵌套生成语句为缩短的结构表示提供相同的约束。

add3 的逻辑运算符版本显示在大学讲座幻灯片的 PDF 第 5页上,用于使用双重涉足进行二进制到 BCD 转换,其中前勾用于表示否定符号,“+”表示 OR,邻接表示 AND。

add3 看起来像:

procedure add3 (signal bin: in  std_logic_vector (3 downto 0); 
                signal bcd: out std_logic_vector (3 downto 0)) is

begin

    bcd(3) <=  bin(3) or 
              (bin(2) and bin(0)) or 
              (bin(2) and bin(1));

    bcd(2) <= (bin(3) and bin(0)) or
              (bin(2) and not bin(1) and not bin(0));

    bcd(1) <= (bin(3) and not bin(0)) or
              (not bin(2) and bin(1)) or
              (bin(1) and bin(0));

    bcd(0) <= (bin(3) and not bin(0)) or
              (not bin(3) and not bin(2) and bin(0)) or
              (bin(2) and bin(1) and not bin(0));

end procedure;
Run Code Online (Sandbox Code Playgroud)

请注意,这将允许从上下文子句中删除程序包 numeric_std (或等效程序)。

如果您以相同的顺序(在本例中从左到右)在 AND 项中写入信号,则重复的 AND 项会很好地显示,就像使用浓缩咖啡一样。在 FPGA 实现中使用中间 AND 术语没有任何价值,这些术语都按原样适合 LUT。

add3 的浓缩咖啡输入: .i 4 .o 4 0000 0000 0001 0001 0010 0010 0011 0011 0100 0100 0101 1000 0110 1001 0111 1010 1000 1011 1001 1100 1010 ---- 1011 ---- 1100 ---- 1101 ---- 1110 ---- 1111 ---- .e

浓缩咖啡的输出(espresso -eonset): .i 4 .o 4 .p 8 -100 0100 00-1 0001 --11 0010 -01- 0010 -110 1001 -1-1 1000 1--1 1100 1--0 1011 .e

当您考虑二进制到 BCD 转换的组合“深度”时,对于 FPGA 来说,它是 6 个 LUT(第 6 个是后续内容的输入)。如果转换发生在一个时钟内,这可能会将时钟速度限制在 100 MHz 以下。

通过流水线或使用顺序逻辑(时钟循环),您可以在 6 个时钟周期内以最快的速度运行 FPGA。