[英]Convert 8bit binary number to BCD in VHDL
该算法是众所周知的,您需要进行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 ;
评论太长了。
考虑以下框图:
这表示展开的循环( 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以及使用嵌套的generate语句来连接所有内容。
如果不限制if语句(对于LS BCD数字为2 <i <7,对于中间BCD数字为5 <i <7),您将无法从循环语句表示中获得相同的最小化硬件。
您希望辅助嵌套的generate语句为缩短的结构表示提供相同的约束。
大学讲座幻灯片的 PDF第5页上显示了add3的逻辑运算符版本,用于使用双涉水进行二进制到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;
请注意,这将允许从上下文子句中删除软件包numeric_std(或等效项)。
如果您以相同的顺序(在这种情况下,从左到右)在AND项中写入信号,则重复的AND项会很好地显示,就像使用espresso一样。 在FPGA实现中使用中间AND术语没有任何价值,所有这些都完全适合LUT。
用于add3的espresso输入: .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 .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以下。
通过流水线或使用顺序逻辑(时钟循环),您将能够以最快的速度运行FPGA,同时执行6个时钟。
至少出现两个问题:
加法是在移位之后完成的,而不是在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 ;
但是,实施可能需要慢一点的时钟...
根据评论中Davids的观察,将代码优化为:
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 ;
1.您需要将BCD的位10设置为0,并将hex_src的位设置为6至0才能正确移位。
2.在第8个移位之后,您不应该进一步添加hex_src值,尝试在第7个移位上限制加法,可以使用if语句来避免。
上述更正代码后应该工作
这适用于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;
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.