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

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

问题描述

的算法是众所周知的,这样做8左移和每个移位后检查单元,几十或几百位(4个)。如果他们是上述4添加3到组,等等...

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

 库IEEE;
使用ieee.std_logic_1164.all;
使用ieee.std_logic_unsigned.all;实体hex2bcd是
    口(hex_in:在std_logic_vector(7 DOWNTO 0);
           bcd_hun:出std_logic_vector(3 DOWNTO 0);
           bcd_ten:出std_logic_vector(3 DOWNTO 0);
           bcd_uni:出std_logic_vector(3 DOWNTO 0));
结束hex2bcd;hex2bcd架构arc_hex2bcd是
开始
    流程(hex_in)
        可变hex_src:std_logic_vector(7 DOWNTO 0);
        可变BCD:std_logic_vector(11 DOWNTO 0);
    开始
        hex_src:= hex_in;
        BCD:=(其他=>'0');        因为我在0〜7循环
            BCD:= BCD(11 DOWNTO 1)及hex_src(7); - 转变BCD + 1新条目
            hex_src:= hex_src(7 DOWNTO 1)及0; - 转变SRC +垫0            如果BCD(3 DOWNTO 0)> 0100则
                BCD(3 DOWNTO 0):= BCD(3 DOWNTO 0)+0011;
            万一 ;
            如果BCD(7 DOWNTO 4)> 0100则
                BCD(7 DOWNTO 4):= BCD(7 DOWNTO 4)+0011;
            万一 ;
            如果BCD(11 DOWNTO 8)GT; 0100则
                BCD(11 DOWNTO 8):= BCD(11 DOWNTO 8)+0011;
            万一 ;
        结束循环;        bcd_hun&所述; = BCD(11 DOWNTO 8);
        bcd_ten&所述; = BCD(7 DOWNTO 4);
        bcd_uni&所述; = BCD(3 DOWNTO 0);    结束进程;
结束arc_hex2bcd;


解决方案

的意见都拿到太长。

考虑下面的框图:

这再presents展开循环(0 对我7环),并表明,没有附加+3发生之前,我= 2的LS BCD I = 5的中间BCD数字,并没有调整对MS BCD数字,这是包括在静态部分发生之前的数字,并没有附加+3出现0值。

这给了我们一共有7 A​​DD3模块(重$ P $由封闭if语句和条件增加+3 psented)。

这是表现在VHDL:

 库IEEE;
使用ieee.std_logic_1164.all;
使用ieee.numeric_std.all;实体bin8bcd是
    港口 (
        斌:在std_logic_vector(7 DOWNTO 0);
        BCD:出std_logic_vector(11 DOWNTO 0)
    );
终端实体;bin8bcd的建筑结构是
    程序ADD3(信号斌:在std_logic_vector(3 DOWNTO 0);
                    信号BCD:出std_logic_vector(3 DOWNTO 0))是
    可变is_gt_4:STD_LOGIC;
    开始
        is_gt_4:=斌(3)或(纸槽(2)和(纸槽(1)或箱(0)));        如果is_gt_4 ='1',那么
         - 如果to_integer(无符号(箱))> 4则
            BCD< = std_logic_vector(无符号(斌)+0011);
        其他
            BCD< =斌;
        万一;
    端程序;    信号U0bin,U1bin,U2bin,U3bin,U4bin,U5bin,U6bin:
                std_logic_vector(3 DOWNTO 0);    信号U0bcd,U1bcd,U2bcd,U3bcd,U4bcd,U5bcd,U6bcd:
                std_logic_vector(3 DOWNTO 0);
开始
    U0bin&所述; ='0'和;槽(7 DOWNTO 5);
    U1bin&所述; = U0bcd(2 DOWNTO 0)及仓(4);
    U2bin&所述; = U1bcd(2 DOWNTO 0)及仓(3);
    U3bin&所述; = U2bcd(2 DOWNTO 0)及仓(2);
    U4bin&所述; = U3bcd(2 DOWNTO 0)及槽(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&安培;斌(0);最终结构;图书馆的IEEE;
使用ieee.std_logic_1164.all;
使用ieee.numeric_std.all;实体bin8bcd_tb是
终端实体;bin8bcd_tb架构foo是
    信号斌:std_logic_vector(7 DOWNTO 0):=(其他=>'0');
     - (初始化为prevent那些烦人的metavalue报道)    信号BCD:std_logic_vector(11 DOWNTO 0);开始DUT:
    实体work.bin8bcd
        端口映射(
            斌= GT;斌
            BCD => BCD
        );STIMULUS:
    处理    开始
        因为我在0到255之间循环
            斌< = std_logic_vector(to_unsigned(I,8));
            等待1纳秒;
        结束循环;
        等待1纳秒;
        等待;
    结束进程;
最终结构;

当随行试验台运行率:

如果你是在整个波形上滚动,你会发现,从001到255的所有BCD输出为present,占(无孔),无X的或U的任何地方。

从框图重新presentation显示I = 7,我们看到无添加+3最终转变后发生。

还要注意的是LSB的BCD的是LSB的仓总是,并且BCD(11)和BCD(10)总是0。

该ADD3可以手工优化使用逻辑运算符3来创建一个增量摆脱报告来自仓衍生元值(有会是他们中的很多)的可能性。

据我可以告诉这个重新presents 8位的最优化的再presentation二进制12位BCD转换。

有时previously我写了一个C程序提供输入的ES preSSO(任期最小化):

/ *
 * binbcd.c - 产生输入到ES preSSO 8位二进制
 *到12位BCD。
 *
 * /
#包括LT&;&stdlib.h中GT;
#包括LT&;&stdio.h中GT;
INT主(ARGC,ARGV)
INT ARGC;
焦炭** argv的;
{
INT二进制;
int位;
炭bcd_buff [4];
INT数字;
INT BCD;    的printf(我8 \\ n);
    的printf(O 12 \\ n);    为(二进制= 0;二进制所述; 256;二进制++){
        对(位= 7;位> = 0; bit--){
            如果((1 <<;&下;位)及二进制)
                输出(1);
            其他
                输出(0);
        }        数字=的snprintf(bcd_buff; 4,%03D,​​二进制); / *前导零* /        如果(数字!= 3){
            fprintf中(标准错误,%S:二进制字符串转换失败,数字=%d个\\ N,
                的argv [0],数字);
            出口(-1);
        }        的printf(); / *输入到输出的空间* /        对(位= 0;&两位数LT; = 2;位数++){
            BCD = bcd_buff [数字] - 的0x30;
            对(位= 3;位&GT; = 0; bit--){
                如果((1 <<;&下;位)及BCD)
                    输出(1);
                其他
                    输出(0);
            }
        }
        / *的printf(%03D,​​二进制); * /
        的printf(\\ n);
    }    的printf(.E \\ n);
    出口(0);

然后开始与中介方面打交道了,这直接导致你什么是重新在上面的框图psented $ P $。

当然,你可以使用一个实际的组件ADD3以及使用嵌套生成报表挂钩一切。

您将无法获得循环语句重新presentation相同最小化硬件没有制约的if语句(2',我7;对于LS BCD位,第5版,我7;为中等BCD数字)。

您会希望子公司嵌套生成报表,为缩短结构重新presentation提供同样的限制。

ADD3的一种逻辑运算符版本显示PDF第5页上的<一个href=\"https://web.archive.org/web/20120131075956/http://edda.csie.dyu.edu.tw/course/fpga/Binary2BCD.pdf\"相对=nofollow称号=大学的演讲稿>大学的演讲稿的二进制采用双涉猎,其中前打勾用于否定符号,以BCD转换+表示OR和邻接表示AND。

该ADD3则是这样的:

 程序ADD3(信号斌:在std_logic_vector(3 DOWNTO 0);
                信号BCD:出std_logic_vector(3 DOWNTO 0))是开始    BCD(3)&下; =仓(3)或
              (纸槽(2)和bin(0))或
              (纸槽(2)和bin(1));    BCD(2)&LT; =(彬(3)和bin(0))或
              (仓(2)和不仓(1),而不是槽(0));    BCD(1) - ; =(容器(3),而不是槽(0))或
              (不斌(2)和bin(1))或
              (纸槽(1)和bin(0));    BCD(0)&所述; =(容器(3),而不是槽(0))或
              (未仓(3)和不仓(2)和bin(0))或
              (纸槽(2)和bin(1),而不是纸槽(0));端程序;

请注意,这将允许包numeric_std(或同等学历)从上下文条款被删除。

如果你写的信号和术语以相同的顺序(在这种情况下,从左至右)的复制和条款显示良好,因为也别用ES preSSO。有在FPGA实现利用中介而言没有价值,这些都适合它的LUT只是他们的方式。

ES preSSO为ADD3输入:

4。我
4的.o
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

和ES preSSO的输出(ES preSSO -eonset):

4。我
4的.o
.P 8
-100 0100
00-1 0001
--11 0010
-01- 0010
-110 1001
1000 -1-1
1--1 1100
1--0 1011
.E

当你考虑二进制的组合深度为BCD转换,对于FPGA是6个LUT(6日以下的输入的东西)。如果在一个时钟发生转换这可能限制了时钟速度的东西害羞100MHz的。

通过管道或使用时序逻辑(主频循环),你可以在它运行一个FPGA的速度最快,而在6个时钟执行。

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 ;

解决方案

The comments were getting too long.

Consider the following block diagram:

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.

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

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:

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.

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

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

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).

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

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\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);

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

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

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.

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.

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;

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

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.

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

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

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.

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.

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

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