在VHDL中将8位二进制数转换为BCD [英] Convert 8bit binary number to BCD in VHDL

查看:11
本文介绍了在VHDL中将8位二进制数转换为BCD的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

The algorithm is well known, you do 8 left shifts and check the units, tens or hundreds bits (4 each) after each shift. If they are above 4 you add 3 to the group and so on...

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

Here is a process based solution that does not work. It will compile but the output is not what I wanted. Any thoughts what could be the problem?

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 ;

推荐答案

评论太长了.

考虑以下框图:

这表示展开的循环(for i in 0 to 7 loop)并表明对于 LS BCD 数字,在 i = 2 之前没有加 +3,并且在 i = 之前没有加 +35 用于中间 BCD 数字,MS BCD 数字不发生调整,它包含部分静态0"值.

This represents an unrolled loop (for i in 0 to 7 loop) and shows that no add +3 occurs before i = 2 for the LS BCD digit and no add +3 occurs before i = 5 for the middle BCD digit, and no adjustment occurs on the MS BCD digit, which is comprise in part of static '0' values.

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

This gives us a total of 7 add3 modules (represented by the enclosing if statement, and conditional add +3).

这在 VHDL 中得到了演示:

This is demonstrated in 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;

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

That when the accompanying test bench is run yields:

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

And if you were to scroll through the entire waveform you'd find that all bcd outputs from 001 to 255 are present and accounted for (no holes), no 'X's or 'U's anywhere.

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

From the representation in the block diagram showing i = 7 we see that no add +3 occurs after the final shift.

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

Also note that the LSB of bcd is always the LSB of bin, and that bcd(11) and bcd(10) are always '0'.

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

The add3 can be hand optimized to create an increment by 3 using logic operators to get rid of any possibility of reporting meta values derived from bin (and there'd be a lot of them).

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

As far as I can tell this represents the most optimized representation of 8 bit binary to 12 bit BCD conversion.

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

Sometime previously I wrote a C program to provide input to espresso (a term minimizer):

/*
 * 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
");
    printf(".o 12
");

    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
",
                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("
");
    }

    printf (".e
");
    exit (0);

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

Then started poking around with intermediary terms, which leads you directly to what is represented in the block diagram above.

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

And of course you could use an actual component add3 as well as use nested generate statements to hook everything up.

如果不限制 if 语句,您将无法从循环语句表示中获得相同的最小化硬件(LS BCD 数字为 2

You won't get the same minimized hardware from a loop statement representation without constraining the if statements (2 < i < 7 for the LS BCD digit, 5 < i < 7 for the middle BCD digit).

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

You'd want the subsidiary nested generate statement to provide the same constraints for a shortened structural representation.

add3 的逻辑运算符版本显示在 大学讲座幻灯片 用于二进制到 BCD 转换使用双 dabble,其中正向刻度用于否定符号,"+" 表示 OR,Adjacency 表示 AND.

A logic operator version of add3 is shown on PDF page 5 on the university lecture slides for Binary to BCD Conversion using double dabble, where the forward tick is used for negation notation, "+" signifies OR, and Adjacency signifies AND.

add3 然后看起来像:

The add3 then looks like:

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(或等效项).

Note this would allow package numeric_std (or equivalent) to be dropped from the context clause.

如果您以相同的顺序(在本例中从左到右)在 AND 项中编写信号,则重复的 AND 项会显示得很好,就像使用 espresso 一样.在 FPGA 实现中使用中间 AND 术语没有任何价值,这些都适合它的 LUT,就像它们一样.

If you write signals in AND terms in the same order (in this case left to right) the duplicated AND terms show up well, as the also do using espresso. There is no value in using intermediary AND terms in an FPGA implementation, these all fit it LUTs just the way they are.

add3 的浓缩咖啡输入:<代码>.i 4.o 40000 00000001 00010010 00100011 00110100 01000101 10000110 10010111 10101000 10111001 11001010----1011----1100 ----1101----1110----1111----.e

espresso input for 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 010000-1 0001--11 0010-01- 0010-110 1001-1-1 10001--1 11001--0 1011.e

And espresso's output (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 以内.

When you consider the combinatorial 'depth' of the binary to BCD conversion, for an FPGA it's 6 LUTs (the 6th an input to something following). That likely limits the clock speed to something shy of 100 MHz if the conversion occurs in one clock.

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

By pipelining or using sequential logic (clocked loop) you'd be able to run an FPGA at it's fastest speed while executing in 6 clocks.

这篇关于在VHDL中将8位二进制数转换为BCD的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆