【问题标题】:Convert 8bit binary number to BCD in VHDL在VHDL中将8位二进制数转换为BCD
【发布时间】:2014-05-26 13:54:36
【问题描述】:

该算法众所周知,您执行 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 ;

【问题讨论】:

    标签: binary vhdl bcd


    【解决方案1】:

    cmets 变得太长了。

    考虑以下框图:

    这表示展开的循环 (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;
    

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

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

    从显示 i = 7 的框图表示中,我们看到在最后一次移位之后没有发生加法 +3。

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

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

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

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

    /*
     * binbcd.c   - generates input to espresso for 8 bit binary
     *         to 12 bit bcd.
     *
     */
    #include <stdlib.h>
    #include <stdio.h>
    
    
    int main (argc, argv)
    int argc;
    char **argv;
    {
    int binary;
    int bit;
    char bcd_buff[4];
    int digit;
    int bcd;
    
        printf(".i 8\n");
        printf(".o 12\n");
    
        for (binary = 0; binary < 256; binary++)  {
            for ( bit = 7; bit >= 0; bit--) {
                if ((1 << bit) & binary)
                    printf("1");
                else
                    printf("0");
            }
    
            digit = snprintf(bcd_buff,4,"%03d",binary); /* leading zeros */
    
            if (digit != 3) {
                fprintf(stderr,"%s: binary to string conversion failure, digit = %d\n",
                    argv[0],digit);
                exit (-1);
            }
    
            printf (" ");  /* input to output space */
    
            for ( digit = 0; digit <= 2; digit++) {
                bcd = bcd_buff[digit] - 0x30;
                for (bit = 3; bit >= 0; bit--) {
                    if ((1 << bit) & bcd) 
                        printf("1");
                    else
                        printf("0"); 
                }
            }
            /* printf(" %03d",binary); */
            printf("\n");
        }
    
        printf (".e\n");
        exit (0);
    

    然后开始研究中间术语,直接将您带到上面的框图中表示的内容。

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

    如果不限制 if 语句(LS BCD 数字为 2

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

    add3 的逻辑运算符版本显示在university lecture slides 上的 PDF 第 5 页上,用于使用双 dabble 进行二进制到 BCD 转换,其中正向刻度用于否定表示法,“+”表示 OR,而 Adjacency 表示 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;
    

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

    如果您以相同的顺序(在这种情况下从左到右)在 AND 项中编写信号,则重复的 AND 项会很好地显示出来,就像使用 espresso 一样。在 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 的输出(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。

    【讨论】:

      【解决方案2】:

      至少出现两个问题:

      • 添加是在 shift 之后完成的,而不是在 Double dabble 算法中描述的之前完成

      • bcd 转移到 bcd(11 downto 1),但应该是 bcd(10 downto 0)

      所以试试代码:

      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
              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 ;
      
              bcd := bcd(10 downto 0) & hex_src(7) ; -- shift bcd + 1 new entry
              hex_src := hex_src(6 downto 0) & '0' ; -- shift src + pad with 0
          end loop ;
      
          bcd_hun <= bcd(11 downto 8) ;
          bcd_ten <= bcd(7  downto 4) ;
          bcd_uni <= bcd(3  downto 0) ;
      
      end process ;
      

      但是,实现可能需要一个慢时钟...

      基于大卫在 cmets 中的观察,代码被优化为:

      process ( hex_in )
          variable hex_src : std_logic_vector (4 downto 0) ;
          variable bcd     : std_logic_vector (11 downto 0) ;
      begin
          bcd             := (others => '0') ;
          bcd(2 downto 0) := hex_in(7 downto 5) ;
          hex_src         := hex_in(4 downto 0) ;
      
          for i in hex_src'range loop
              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 ;
              -- No roll over for hundred digit, since in 0 .. 2
      
              bcd := bcd(10 downto 0) & hex_src(hex_src'left) ; -- shift bcd + 1 new entry
              hex_src := hex_src(hex_src'left - 1 downto hex_src'right) & '0' ; -- shift src + pad with 0
          end loop ;
      
          bcd_hun <= bcd(11 downto 8) ;
          bcd_ten <= bcd(7  downto 4) ;
          bcd_uni <= bcd(3  downto 0) ;
      end process ;
      

      【讨论】:

      • BCD 向量移位确实有一个错误,但是我在检查是否应该添加 3 的 if 语句之前进行移位。我在 Quartus 模拟器中对其进行了测试,它对第一个输入工作正常,第二个输入(当输入更改时)它不会更新输出。
      • hex_src := hex_src(7 downto 1) & '0' ;也是错的,应该是(6 down to 1)。现在它起作用了。我不明白为什么。转换应在添加之前进行。
      • 你们意识到对于 8 位二进制值输入,您不需要涉足 bcd[11 到 8),不是吗?那里的值永远不会超过 2。MS bcd 数字是免费的。请参阅web.archive.org/web/20120131075956/http://edda.csie.dyu.edu.tw/… 的第 2 页您的最后一个 if 语句不需要,bcd(11) 和 bcd(10) 应该始终为 '0',没有&gt; "0100"。您也可以在 8 个时钟内按顺序执行此操作(通常可以根据显示刷新间隔隐藏)。
      • 对于上述循环语句,在 bcd(3 downto 0) 的 i = 2 和 bcd(7 downto 4) 的 i = 5 之前不能出现任何问题,可用于减少生成量硬件通过使用 if 语句限定的涉猎。 (加快时钟)。
      • @DavidKoontz - 所以你说我可以做更少的迭代,因为在 3 个班次之前,无论如何不可能有一个大于“100”的数字,而且最后一个数字不能超过 2,因为2^8-1 是 255,所以它已经很高了,而且因为我没有移动足够的时间来将超过 2 位引入 MSB BCD 数字。我仍然不明白的一件事是它如何在检查后与班次一起工作?
      【解决方案3】:

      1.你需要将BCD的第10位到0,从hex_src的6到0才能正确移位。

      2.第8班后,hex_src值你不应该再添加,尝试限制添加 第 7 次换档时,可以使用 if 语句来避免。

      1. 每次转换后将 BCD 值重置为零。

      上面的修正代码应该可以工作

      【讨论】:

        【解决方案4】:

        这适用于 quartus 18.1 lite

            LIBRARY ieee;                       
        USE ieee.std_logic_1164.ALL; 
        use ieee.numeric_std.all;  
        --converting a 8bit binary number to a 12bit bcd
        entity bin2bcd is
        port (bin :in std_logic_vector (7 downto 0);
                bcd1 : out std_logic_vector (3 downto 0);
                bcd2 : out std_logic_vector (3 downto 0);
                bcd3 : out std_logic_vector (3 downto 0));
        end entity;
        
        architecture rtl of bin2bcd is 
        begin
        process ( bin )
            variable binx : std_logic_vector (7 downto 0) ;
            variable bcd     : std_logic_vector (11 downto 0) ;
        begin
            bcd             := (others => '0') ;
            binx        := bin(7 downto 0) ;
        
            for i in binx'range loop
                if bcd(3 downto 0) > "0100" then
                  bcd(3 downto 0) := std_logic_vector(unsigned( bcd(3 downto 0)) + "0011"); 
        
                end if ;
                if bcd(7 downto 4) > "0100" then
                   bcd(7 downto 4) := std_logic_vector(unsigned( bcd(7 downto 4)) + "0011");    
                end if ;
                bcd := bcd(10 downto 0) & binx(7) ; 
                binx := binx(6 downto 0) & '0' ; 
            end loop ;
        
            bcd3 <= bcd(11 downto 8) ;
            bcd2 <= bcd(7  downto 4) ;
            bcd1 <= bcd(3  downto 0) ;
        end process ;
        end architecture;
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2015-01-21
          • 1970-01-01
          • 2015-05-16
          • 1970-01-01
          • 1970-01-01
          • 2013-06-11
          • 2018-09-15
          • 1970-01-01
          相关资源
          最近更新 更多