16bit转bcd
16bit to bcd conversion
我正在尝试进行 16 位到 BCD 的转换。
我发现这个 link 是 8 位的,我正在尝试将其转换为 16 位。
http://vhdlguru.blogspot.nl/2010/04/8-bit-binary-to-bcd-converter-double.html
我不知道我做错了什么 rpm_1000 不断变化,rpm_100 保持在 4。有人知道我做错了什么吗?
process (Hex_Display_Data)
variable i : integer:=0;
variable bcd : std_logic_vector(19 downto 0) := (others => '0');
variable bint : std_logic_vector(15 downto 0) := Hex_Display_Data;
begin
for i in 0 to 15 loop -- repeating 16 times.
bcd(19 downto 1) := bcd(18 downto 0); --shifting the bits.
bcd(0) := bint(15); -- shift bit in
bint(15 downto 1) := bint(14 downto 0); --removing msb
bint(0) :='0'; -- adding a '0'
if(i < 15 and bcd(3 downto 0) > "0100") then --add 3 if BCD digit is greater than 4.
bcd(3 downto 0) := bcd(3 downto 0) + "0011";
end if;
if(i < 15 and bcd(7 downto 4) > "0100") then --add 3 if BCD digit is greater than 4.
bcd(7 downto 4) := bcd(7 downto 4) + "0011";
end if;
if(i < 15 and bcd(11 downto 8) > "0100") then --add 3 if BCD digit is greater than 4.
bcd(11 downto 8) := bcd(11 downto 8) + "0011";
end if;
if(i < 15 and bcd(15 downto 12) > "0100") then --add 3 if BCD digit is greater than 4.
bcd(15 downto 12) := bcd(15 downto 12) + "0011";
end if;
end loop;
rpm_1000 <= bcd(15 downto 12);
rpm_100 <= bcd(11 downto 8);
rpm_10 <= bcd(7 downto 4);
rpm_1 <= bcd(3 downto 0);
end process ;
运行 循环 16 次将使 BCD 寄存器中的值乘以 65536(mod 100000)并与二进制寄存器中的值相加。假设值为 4000。那么 4000x65536 产生 44000。44000x65536 产生 84000。84000x65536 产生 24000。24000x65536 产生 64000。而 64000x65536 产生 4000。
要使算法起作用,您必须先清除 BCD 寄存器。修复关于循环运行次数的评论也没有什么坏处。
顺便说一句,二进制到 BCD 转换器的实际实现通常应该接受时钟输入,并为每个有效时钟边沿执行一个步骤。如果您的 VHDL 运行 完全在仿真中,那么所产生的逻辑的复杂性将无关紧要,但尝试在真实硬件中同时执行所有操作将相当昂贵。相比之下,执行二进制数简单移位和 BCD 数乘以 2 的硬件要简单得多。请注意,如果您执行操作 "all at once",则输出的最高有效位将取决于输入的次低有效位,这意味着输入信号必须在一个步骤中传播通过所有逻辑。相比之下,如果每个时钟周期移动一位,输出的每一位将仅取决于输入的最多四位(因为在调整阶段之前每个数字都在 0-9 范围内,加 3 永远不会引起执行)。
此外,"double dabble" 算法要求在 BCD 移位之前执行调整,但看起来好像代码是在之后执行调整。稍微看一下之后再做调整就好了
范围为 16..13、12..9、8..5 和 4..1 而不是 15..12 等。或者,可以指定位 19..17 的值应该是位的值18..16,第 16..13 位的值应该是第 15..12 位的值(如果小于 5)或第 15..12 位的值加上三(如果更大)等。这样一个公式会将每个位的值设置在一个位置,这样可以更容易地看到它应该如何呈现到硬件中。
请注意,四个 BCD 数字可以完全包含在 14 位输入(您的 Hex_Display_Data
)中,未使用的 bcd
'bits'(19 到 16)将在合成过程中与所有不能出现的加法 3,因为它们的高两位是“0”(不是 > 4)。
如果您将 bcd
值限制为 4 个十六进制数字,并将循环迭代限制为 14 位:
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
entity bin2bcd is
port (
input: in std_logic_vector (15 downto 0);
ones: out std_logic_vector (3 downto 0);
tens: out std_logic_vector (3 downto 0);
hundreds: out std_logic_vector (3 downto 0);
thousands: out std_logic_vector (3 downto 0)
);
end entity;
architecture fum of bin2bcd is
alias Hex_Display_Data: std_logic_vector (15 downto 0) is input;
alias rpm_1: std_logic_vector (3 downto 0) is ones;
alias rpm_10: std_logic_vector (3 downto 0) is tens;
alias rpm_100: std_logic_vector (3 downto 0) is hundreds;
alias rpm_1000: std_logic_vector (3 downto 0) is thousands;
begin
process (Hex_Display_Data)
type fourbits is array (3 downto 0) of std_logic_vector(3 downto 0);
-- variable i : integer := 0; -- NOT USED
-- variable bcd : std_logic_vector(15 downto 0) := (others => '0');
variable bcd: std_logic_vector (15 downto 0);
-- variable bint : std_logic_vector(15 downto 0) := Hex_Display_Data;
variable bint: std_logic_vector (13 downto 0); -- SEE process body
begin
bcd := (others => '0'); -- ADDED for EVERY CONVERSION
bint := Hex_Display_Data (13 downto 0); -- ADDED for EVERY CONVERSION
for i in 0 to 13 loop
bcd(15 downto 1) := bcd(14 downto 0);
bcd(0) := bint(13);
bint(13 downto 1) := bint(12 downto 0);
bint(0) := '0';
if i < 13 and bcd(3 downto 0) > "0100" then
bcd(3 downto 0) :=
std_logic_vector (unsigned(bcd(3 downto 0)) + 3);
end if;
if i < 13 and bcd(7 downto 4) > "0100" then
bcd(7 downto 4) :=
std_logic_vector(unsigned(bcd(7 downto 4)) + 3);
end if;
if i < 13 and bcd(11 downto 8) > "0100" then
bcd(11 downto 8) :=
std_logic_vector(unsigned(bcd(11 downto 8)) + 3);
end if;
if i < 13 and bcd(15 downto 12) > "0100" then
bcd(11 downto 8) :=
std_logic_vector(unsigned(bcd(15 downto 12)) + 3);
end if;
end loop;
(rpm_1000, rpm_100, rpm_10, rpm_1) <=
fourbits'( bcd (15 downto 12), bcd (11 downto 8),
bcd ( 7 downto 4), bcd ( 3 downto 0) );
end process ;
end architecture;
请注意别名的使用,使您的名字能够在现有的兼容 Minimal, Complete and Verifiable Example 中使用,您的问题没有提供。
聚合信号分配也取自原来的,您对单个数字的分配应该可以正常工作。
除了将转换限制为 14 位和 BCD 位数以匹配输出的位数之外,还有两个更改。
bcd
和 bint
变量现在在每次进程恢复时被清除(对 Hex_Display_Data
的更新敏感)。这些很可能导致您无法验证的错误。
多余的括号已被删除。
您没有提供上下文子句。显示的代码使用包 numeric_std 而不是 -2008 numeric_std_unsigned 在使用 IEEE 编写的包时提供与标准早期修订版的兼容性。
你会得到一些有用的东西,可以用测试平台证明:
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
entity bin2bcd_tb is
end entity;
architecture foo of bin2bcd_tb is
signal input: std_logic_vector (15 downto 0) := (others => '0');
signal ones: std_logic_vector (3 downto 0);
signal tens: std_logic_vector (3 downto 0);
signal hundreds: std_logic_vector (3 downto 0);
signal thousands: std_logic_vector (3 downto 0);
begin
DUT:
entity work.bin2bcd
port map (
input => input,
ones => ones,
tens => tens,
hundreds => hundreds,
thousands => thousands
);
STIMULUS:
process
begin
for i in 0 to 1001 loop
wait for 20 ns;
input <= std_logic_vector(to_unsigned(9999 - i, 16));
end loop;
wait for 20 ns;
wait;
end process;
end architecture;
其他一些刺激方案可用于切换所有四个数字的 BCD 数字翻转。
此测试平台提供从 9999 开始并递减 1001 次的输入值以显示所有四个数字的转换:
我可以很容易地修改以证明每个 BCD 数字的每个转换。
总而言之,您遇到的错误似乎是由于子程序中变量的详细说明差异所致,其中 bcd
和 bint
将在每次函数调用时动态详细说明和初始化,并且在他们只会被初始化一次的过程中。
来自 Xilinx 用户指南 901 Vivado Design Suite 用户指南综合 (2015.3),第 4 章:VHDL 支持、组合过程、case 语句、for 循环语句、the for 循环似乎支持合成,并且据报道在 Whosebug 上的其他双重涉猎问题中符合合成条件。问题是支持在重复的顺序语句序列中对变量进行重复赋值,这应该得到支持。在 Whosebug 上至少还有一个双重涉猎问题,其中已报告使用这样的 for 循环成功合成。
请注意,将您处理的输入值限制为 14 位不会检测到较大二进制数 (> 9999) 的影响,否则您的进程不会这样做,或者仅提供 4 个 BCD 输出数字。您可以通过检查输入值是否大于 9999 (x"270F") 来处理这个问题。
FPGA中的+3表示1个LUT深度(4位输入,4位输出),根据转换数的大小(范围i
).通过 ADD3 允许转换传播的时间被显示可以被视觉解释的速率所抵消。如果您在毫秒范围内更新 Hex_Display_Data
,您可能无法从视觉上分辨出差异。
我正在尝试进行 16 位到 BCD 的转换。 我发现这个 link 是 8 位的,我正在尝试将其转换为 16 位。 http://vhdlguru.blogspot.nl/2010/04/8-bit-binary-to-bcd-converter-double.html
我不知道我做错了什么 rpm_1000 不断变化,rpm_100 保持在 4。有人知道我做错了什么吗?
process (Hex_Display_Data)
variable i : integer:=0;
variable bcd : std_logic_vector(19 downto 0) := (others => '0');
variable bint : std_logic_vector(15 downto 0) := Hex_Display_Data;
begin
for i in 0 to 15 loop -- repeating 16 times.
bcd(19 downto 1) := bcd(18 downto 0); --shifting the bits.
bcd(0) := bint(15); -- shift bit in
bint(15 downto 1) := bint(14 downto 0); --removing msb
bint(0) :='0'; -- adding a '0'
if(i < 15 and bcd(3 downto 0) > "0100") then --add 3 if BCD digit is greater than 4.
bcd(3 downto 0) := bcd(3 downto 0) + "0011";
end if;
if(i < 15 and bcd(7 downto 4) > "0100") then --add 3 if BCD digit is greater than 4.
bcd(7 downto 4) := bcd(7 downto 4) + "0011";
end if;
if(i < 15 and bcd(11 downto 8) > "0100") then --add 3 if BCD digit is greater than 4.
bcd(11 downto 8) := bcd(11 downto 8) + "0011";
end if;
if(i < 15 and bcd(15 downto 12) > "0100") then --add 3 if BCD digit is greater than 4.
bcd(15 downto 12) := bcd(15 downto 12) + "0011";
end if;
end loop;
rpm_1000 <= bcd(15 downto 12);
rpm_100 <= bcd(11 downto 8);
rpm_10 <= bcd(7 downto 4);
rpm_1 <= bcd(3 downto 0);
end process ;
运行 循环 16 次将使 BCD 寄存器中的值乘以 65536(mod 100000)并与二进制寄存器中的值相加。假设值为 4000。那么 4000x65536 产生 44000。44000x65536 产生 84000。84000x65536 产生 24000。24000x65536 产生 64000。而 64000x65536 产生 4000。
要使算法起作用,您必须先清除 BCD 寄存器。修复关于循环运行次数的评论也没有什么坏处。
顺便说一句,二进制到 BCD 转换器的实际实现通常应该接受时钟输入,并为每个有效时钟边沿执行一个步骤。如果您的 VHDL 运行 完全在仿真中,那么所产生的逻辑的复杂性将无关紧要,但尝试在真实硬件中同时执行所有操作将相当昂贵。相比之下,执行二进制数简单移位和 BCD 数乘以 2 的硬件要简单得多。请注意,如果您执行操作 "all at once",则输出的最高有效位将取决于输入的次低有效位,这意味着输入信号必须在一个步骤中传播通过所有逻辑。相比之下,如果每个时钟周期移动一位,输出的每一位将仅取决于输入的最多四位(因为在调整阶段之前每个数字都在 0-9 范围内,加 3 永远不会引起执行)。
此外,"double dabble" 算法要求在 BCD 移位之前执行调整,但看起来好像代码是在之后执行调整。稍微看一下之后再做调整就好了 范围为 16..13、12..9、8..5 和 4..1 而不是 15..12 等。或者,可以指定位 19..17 的值应该是位的值18..16,第 16..13 位的值应该是第 15..12 位的值(如果小于 5)或第 15..12 位的值加上三(如果更大)等。这样一个公式会将每个位的值设置在一个位置,这样可以更容易地看到它应该如何呈现到硬件中。
请注意,四个 BCD 数字可以完全包含在 14 位输入(您的 Hex_Display_Data
)中,未使用的 bcd
'bits'(19 到 16)将在合成过程中与所有不能出现的加法 3,因为它们的高两位是“0”(不是 > 4)。
如果您将 bcd
值限制为 4 个十六进制数字,并将循环迭代限制为 14 位:
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
entity bin2bcd is
port (
input: in std_logic_vector (15 downto 0);
ones: out std_logic_vector (3 downto 0);
tens: out std_logic_vector (3 downto 0);
hundreds: out std_logic_vector (3 downto 0);
thousands: out std_logic_vector (3 downto 0)
);
end entity;
architecture fum of bin2bcd is
alias Hex_Display_Data: std_logic_vector (15 downto 0) is input;
alias rpm_1: std_logic_vector (3 downto 0) is ones;
alias rpm_10: std_logic_vector (3 downto 0) is tens;
alias rpm_100: std_logic_vector (3 downto 0) is hundreds;
alias rpm_1000: std_logic_vector (3 downto 0) is thousands;
begin
process (Hex_Display_Data)
type fourbits is array (3 downto 0) of std_logic_vector(3 downto 0);
-- variable i : integer := 0; -- NOT USED
-- variable bcd : std_logic_vector(15 downto 0) := (others => '0');
variable bcd: std_logic_vector (15 downto 0);
-- variable bint : std_logic_vector(15 downto 0) := Hex_Display_Data;
variable bint: std_logic_vector (13 downto 0); -- SEE process body
begin
bcd := (others => '0'); -- ADDED for EVERY CONVERSION
bint := Hex_Display_Data (13 downto 0); -- ADDED for EVERY CONVERSION
for i in 0 to 13 loop
bcd(15 downto 1) := bcd(14 downto 0);
bcd(0) := bint(13);
bint(13 downto 1) := bint(12 downto 0);
bint(0) := '0';
if i < 13 and bcd(3 downto 0) > "0100" then
bcd(3 downto 0) :=
std_logic_vector (unsigned(bcd(3 downto 0)) + 3);
end if;
if i < 13 and bcd(7 downto 4) > "0100" then
bcd(7 downto 4) :=
std_logic_vector(unsigned(bcd(7 downto 4)) + 3);
end if;
if i < 13 and bcd(11 downto 8) > "0100" then
bcd(11 downto 8) :=
std_logic_vector(unsigned(bcd(11 downto 8)) + 3);
end if;
if i < 13 and bcd(15 downto 12) > "0100" then
bcd(11 downto 8) :=
std_logic_vector(unsigned(bcd(15 downto 12)) + 3);
end if;
end loop;
(rpm_1000, rpm_100, rpm_10, rpm_1) <=
fourbits'( bcd (15 downto 12), bcd (11 downto 8),
bcd ( 7 downto 4), bcd ( 3 downto 0) );
end process ;
end architecture;
请注意别名的使用,使您的名字能够在现有的兼容 Minimal, Complete and Verifiable Example 中使用,您的问题没有提供。
聚合信号分配也取自原来的,您对单个数字的分配应该可以正常工作。
除了将转换限制为 14 位和 BCD 位数以匹配输出的位数之外,还有两个更改。
bcd
和 bint
变量现在在每次进程恢复时被清除(对 Hex_Display_Data
的更新敏感)。这些很可能导致您无法验证的错误。
多余的括号已被删除。
您没有提供上下文子句。显示的代码使用包 numeric_std 而不是 -2008 numeric_std_unsigned 在使用 IEEE 编写的包时提供与标准早期修订版的兼容性。
你会得到一些有用的东西,可以用测试平台证明:
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
entity bin2bcd_tb is
end entity;
architecture foo of bin2bcd_tb is
signal input: std_logic_vector (15 downto 0) := (others => '0');
signal ones: std_logic_vector (3 downto 0);
signal tens: std_logic_vector (3 downto 0);
signal hundreds: std_logic_vector (3 downto 0);
signal thousands: std_logic_vector (3 downto 0);
begin
DUT:
entity work.bin2bcd
port map (
input => input,
ones => ones,
tens => tens,
hundreds => hundreds,
thousands => thousands
);
STIMULUS:
process
begin
for i in 0 to 1001 loop
wait for 20 ns;
input <= std_logic_vector(to_unsigned(9999 - i, 16));
end loop;
wait for 20 ns;
wait;
end process;
end architecture;
其他一些刺激方案可用于切换所有四个数字的 BCD 数字翻转。
此测试平台提供从 9999 开始并递减 1001 次的输入值以显示所有四个数字的转换:
我可以很容易地修改以证明每个 BCD 数字的每个转换。
总而言之,您遇到的错误似乎是由于子程序中变量的详细说明差异所致,其中 bcd
和 bint
将在每次函数调用时动态详细说明和初始化,并且在他们只会被初始化一次的过程中。
来自 Xilinx 用户指南 901 Vivado Design Suite 用户指南综合 (2015.3),第 4 章:VHDL 支持、组合过程、case 语句、for 循环语句、the for 循环似乎支持合成,并且据报道在 Whosebug 上的其他双重涉猎问题中符合合成条件。问题是支持在重复的顺序语句序列中对变量进行重复赋值,这应该得到支持。在 Whosebug 上至少还有一个双重涉猎问题,其中已报告使用这样的 for 循环成功合成。
请注意,将您处理的输入值限制为 14 位不会检测到较大二进制数 (> 9999) 的影响,否则您的进程不会这样做,或者仅提供 4 个 BCD 输出数字。您可以通过检查输入值是否大于 9999 (x"270F") 来处理这个问题。
FPGA中的+3表示1个LUT深度(4位输入,4位输出),根据转换数的大小(范围i
).通过 ADD3 允许转换传播的时间被显示可以被视觉解释的速率所抵消。如果您在毫秒范围内更新 Hex_Display_Data
,您可能无法从视觉上分辨出差异。