如何在 VHDL 中使用 "function" 来 return 来自同一计算的多个变量?
How to use "function" in VHDL to return multiple variables from the same calculation?
我正在尝试在 return 多个变量的函数中实现解码代码,因为我必须解码两个定点变量,并且由于 fpga 中的逻辑不足而出现错误。所以我需要像在 C 语言中那样执行解码代码--> 用两个变量调用该函数两次,并在单个数字中得到 return。这可能执行吗?如果可能的话该怎么做?还是有其他方法可以做到这一点?
我正在为两个定点数执行下面的代码两次
并对小数部分进行解码,因为 well.decoding 适用于整数部分和小数部分。
解码后我将它们转换为 std_logic_vector 并发送到我的液晶显示器。这就是我解码价值的原因。代码很大,大约 1000 行。
所以我不能把它放在这里。
在当前代码中,我执行了两次相同的解码,因此它产生了 fpga 不支持的大逻辑。他们单独工作。所以我需要将它放入一个函数中并调用该函数两次。
如 link 代码所示,我得到 6 个整数部分变量和 6 个小数部分变量。我需要将这段代码放在一个函数中,其中包含 returns 12 个变量。
在引用的问题 Renaud Pacalet commented in his answer 中,没有特别的理由在实际转换过程中使用带符号的定点数,也没有为此使用整数。
有一种算法 (Double dabble) 使用可以在循环语句中实现的移位和 4 位条件加法。这里的一个是20位整数部分算法的扩展。
还有一种实现小数部分等效的方法:
[多位二进制到十进制转换器(小数也是!)](http://www.minecraftforum.net/forums/minecraft-discussion/redstone-discussion-and/redstone-creations/352668-multi-digit-binary-to-decimal-converter-decimal"Multi-Digit Binary to Decimal Converter (decimal fractions too!)")
An explanation of how the Algorithm works can be found on this website: http://www.johnloomis.org/ece314/notes/devices/binary_to_BCD/bin_to_bcd.html
I went one step further though, and figured out how to apply the same principle to convert Binary Fractions to Decimal Fractions. For example, 0.11(bin) can be converted to 0.75(dec). by using conversion tables with that perform the inverse function (-3 if 8 or more) and shifting in the opposite direction.
Last edited by Hans_Lemurson: Jun 9, 2012
虽然未在 Minecraft 游戏中实现,但分数涉猎涉及每次比较和减法的逻辑单元,就像双涉猎对加法一样。
位顺序移位,double dabble是乘法器,fraction dabble是除法器。 double dabble 具有最大数量的 add3 逻辑单元,为 20 位 x 7 BCD 数字(28 位)或 140 个逻辑单元。它减少了无法更改结果的单元格数量,无论是基于不满足阈值 (> 4) 还是保证所有“0”输入。最终有 57 个逻辑单元(每四个 4x1 LUT)。
分数 dabble 使用更多单元格,因为从左侧移动会立即抛出 sub3 操作的阈值。从 18 位 x 6 BCD 数字或 108 个 sub3 单元进行综合映射后的缩减
只损失 6 个,给出 102 个逻辑单元。 add3 和 sub3 之间的差异是模四加法与减法以及 (> 4) 与 (>7) 的阈值。
通过使 BCD 值成为时钟寄存器并一次迭代 20 或 18 个操作时钟,可以进一步减少逻辑单元的数量(对于小数部分可以减少很多)。状态机需要与输入和输出握手,并迭代表示二进制输入值长度的时钟数。
绝对值转换少于40个逻辑单元。
这里的想法是,一次使用顺序操作位表示性能与大小的权衡(请注意,您尚未使用固定除法和模数缩减指定当前实现的大小)。
以下代码将这两个 dabbles 实现为不同的函数,可以针对更大或更小的 sfixed 值和 BCD 位数进行缩放,并且可能前面有多路复用器,如 Brian Drummond 所指出的,尽管根据它们的大小似乎不太可能保证。 (多路复用器有多大?)。
'slower' 性能的含义是您更新输入值(此处显示为 cp
)的速度不会快于与最长时间连接的绝对值转换的下降时间两次涉猎(较大的一次)。
此代码:
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
use ieee.fixed_pkg.all; -- included in -2008
entity iopertyki is
end entity;
architecture fum of iopertyki is
function doubledabble_20bit (inp: std_logic_vector(19 downto 0))
return unsigned is
variable bin: std_logic_vector(inp'range);
variable bcd: unsigned(27 downto 0);
begin
bin := inp;
bcd := (others => '0');
for i in 0 to 19 loop
if bcd(3 downto 0) > 4 then
bcd(3 downto 0) := bcd(3 downto 0) + 3;
end if;
if bcd(7 downto 4) > 4 then
bcd(7 downto 4) := bcd(7 downto 4) + 3;
end if;
if bcd(11 downto 8) > 4 then
bcd(11 downto 8) := bcd(11 downto 8) + 3;
end if;
if bcd(15 downto 12) > 4 then
bcd(15 downto 12) := bcd(15 downto 12) + 3;
end if;
if bcd(19 downto 16) > 4 then
bcd(19 downto 16) := bcd(19 downto 16) + 3;
end if;
if bcd(23 downto 20) > 4 then
bcd(23 downto 20) := bcd(23 downto 20) + 3;
end if;
bcd := bcd(26 downto 0) & bin(19);
bin := bin(18 downto 0) & '0';
end loop;
return bcd;
end function;
function fracdabble_19bit (inp: std_logic_vector(18 downto 0))
return unsigned is
variable bin: std_logic_vector(inp'range);
variable bcd: unsigned(23 downto 0);
-- variable tbcd: unsigned(23 downto 0); -- DEBUG
begin
bin := inp;
bcd := (others => '0'); -- DEBUG
for i in 0 to 18 loop
bcd := bin(0) & bcd(23 downto 1);
bin := '0' & bin(18 downto 1);
-- tbcd := bcd; -- DEBUG
if bcd(3 downto 0) > 7 then
bcd(3 downto 0) := bcd(3 downto 0) - 3;
end if;
if bcd(7 downto 4) > 7 then
bcd(7 downto 4) := bcd(7 downto 4) - 3;
end if;
if bcd(11 downto 8) > 7 then
bcd(11 downto 8) := bcd(11 downto 8) - 3;
end if;
if bcd(15 downto 12) > 7 then
bcd(15 downto 12) := bcd(15 downto 12) - 3;
end if;
if bcd(19 downto 16) > 7 then
bcd(19 downto 16) := bcd(19 downto 16) - 3;
end if;
if bcd(23 downto 20) > 7 then
bcd(23 downto 20) := bcd(23 downto 20) - 3;
end if;
-- report "i = " & integer'image(i) & LF & HT & -- DEBUG
-- "prior sub3 bcd = " & to_string (tbcd) & LF & HT & -- DEBUG
-- "after sub3 bcd = " & to_string (bcd); -- DEBUG
end loop;
bcd(0) := inp(0); -- An odd binary produces an odd decimal value
return bcd; -- the algorithm loses the LSB
end function;
signal cp: sfixed(20 downto -19) := to_sfixed(174334.738295,20,-19);
begin
BCD_CONVERT:
process (cp)
variable int_digits: unsigned(27 downto 0);
variable frac_digits: unsigned(23 downto 0);
alias L6: unsigned(3 downto 0) is int_digits(27 downto 24);
alias L5: unsigned(3 downto 0) is int_digits(23 downto 20);
alias L4: unsigned(3 downto 0) is int_digits(19 downto 16);
alias L3: unsigned(3 downto 0) is int_digits(15 downto 12);
alias L2: unsigned(3 downto 0) is int_digits(11 downto 8);
alias L1: unsigned(3 downto 0) is int_digits(7 downto 4);
alias L0: unsigned(3 downto 0) is int_digits(3 downto 0);
alias R5: unsigned(3 downto 0) is frac_digits(23 downto 20);
alias R4: unsigned(3 downto 0) is frac_digits(19 downto 16);
alias R3: unsigned(3 downto 0) is frac_digits(15 downto 12);
alias R2: unsigned(3 downto 0) is frac_digits(11 downto 8);
alias R1: unsigned(3 downto 0) is frac_digits(7 downto 4);
alias R0: unsigned(3 downto 0) is frac_digits(3 downto 0);
variable scp: sfixed(20 downto -19);
variable sign: character;
begin
if cp < 0.0 then
scp := "-"(0.0, cp)(20 downto -19); -- change sign, slice length
sign := '-';
else
scp := cp;
sign := ' '; -- no sign instead of '+'
end if;
report LF & HT & " cp = " & to_string(cp) &
LF & HT & "absolute val cp = " & to_string(scp);
report LF & HT & "slv int = " & to_string(to_slv(scp)(38 downto 19))
& " slv frac = " & to_string(to_slv(scp)(18 downto 0));
-- leave off sign bit:
int_digits := doubledabble_20bit(to_slv(scp)(38 downto 19));
report "int_digits = " & to_string (int_digits);
-- 55 logic cells following mspping and reduction:
frac_digits := fracdabble_19bit(to_slv(scp)(18 downto 0));
report "frac_digits = " & to_string (frac_digits);
-- R6 = "0000"
report "result = " & sign &
integer'image(to_integer(L6)) &
integer'image(to_integer(L5)) &
integer'image(to_integer(L4)) &
integer'image(to_integer(L3)) &
integer'image(to_integer(L2)) &
integer'image(to_integer(L1)) &
integer'image(to_integer(L0)) &
'.' &
integer'image(to_integer(R5)) &
integer'image(to_integer(R4)) &
integer'image(to_integer(R3)) &
integer'image(to_integer(R2)) &
integer'image(to_integer(R1)) &
integer'image(to_integer(R0));
end process;
MORE:
process
begin
wait for 20 ns;
cp <= "-"(cp)(20 downto -19); -- change sign, slice length
wait for 20 ns;
cp <= to_sfixed(-307.83929,20,-19);
wait;
end process;
end architecture;
经过分析、阐述和模拟后产生:
ghdl -a --std=08 iopertyki.vhdl
ghdl -e --std=08 iopertyki
ghdl -r --std=08 iopertyki
iopertyki.vhdl:112:9:@0ms:(report note):
cp = 000101010100011111110.1011110100000000111
absolute val cp = 000101010100011111110.1011110100000000111
iopertyki.vhdl:114:9:@0ms:(report note):
slv int = 00101010100011111110 slv frac = 1011110100000000111
iopertyki.vhdl:118:9:@0ms:(report note): int_digits = 0000000101110100001100110100
iopertyki.vhdl:121:9:@0ms:(report note): frac_digits = 011100111000001010010101
iopertyki.vhdl:124:9:@0ms:(report note): result = 0174334.738295
iopertyki.vhdl:112:9:@20ns:(report note):
cp = 111010101011100000001.0100001011111111001
absolute val cp = 000101010100011111110.1011110100000000111
iopertyki.vhdl:114:9:@20ns:(report note):
slv int = 00101010100011111110 slv frac = 1011110100000000111
iopertyki.vhdl:118:9:@20ns:(report note): int_digits = 0000000101110100001100110100
iopertyki.vhdl:121:9:@20ns:(report note): frac_digits = 011100111000001010010101
iopertyki.vhdl:124:9:@20ns:(report note): result = -0174334.738295
iopertyki.vhdl:112:9:@40ns:(report note):
cp = 111111111111011001100.0010100100100100010
absolute val cp = 000000000000100110011.1101011011011011110
iopertyki.vhdl:114:9:@40ns:(report note):
slv int = 00000000000100110011 slv frac = 1101011011011011110
iopertyki.vhdl:118:9:@40ns:(report note): int_digits = 0000000000000000001100000111
iopertyki.vhdl:121:9:@40ns:(report note): frac_digits = 100000111001001010010000
iopertyki.vhdl:124:9:@40ns:(report note): result = -0000307.839290
展示正确的转换。
在对您的 LCD 显示器一无所知的情况下,尝试将 BCD 数字映射到它似乎不切实际。
这些从固定值到 BCD 数字的转换代表了硬件思维与机器指令思维的对比。如果减少 space 的需要不被涉猎所满足,使用时钟移位寄存器可以进一步减小大小,减少 add3 或 sub3 单元与小型状态机权衡的要求。这之所以可行,是因为眼睛和 LCD 显示器的工作方式都存在光学持久性。您根本看不到不会持续几毫秒的事情。
我正在尝试在 return 多个变量的函数中实现解码代码,因为我必须解码两个定点变量,并且由于 fpga 中的逻辑不足而出现错误。所以我需要像在 C 语言中那样执行解码代码--> 用两个变量调用该函数两次,并在单个数字中得到 return。这可能执行吗?如果可能的话该怎么做?还是有其他方法可以做到这一点?
我正在为两个定点数执行下面的代码两次 并对小数部分进行解码,因为 well.decoding 适用于整数部分和小数部分。 解码后我将它们转换为 std_logic_vector 并发送到我的液晶显示器。这就是我解码价值的原因。代码很大,大约 1000 行。 所以我不能把它放在这里。
在当前代码中,我执行了两次相同的解码,因此它产生了 fpga 不支持的大逻辑。他们单独工作。所以我需要将它放入一个函数中并调用该函数两次。
如 link 代码所示,我得到 6 个整数部分变量和 6 个小数部分变量。我需要将这段代码放在一个函数中,其中包含 returns 12 个变量。
在引用的问题
有一种算法 (Double dabble) 使用可以在循环语句中实现的移位和 4 位条件加法。这里的一个是20位整数部分算法的扩展。
还有一种实现小数部分等效的方法:
[多位二进制到十进制转换器(小数也是!)](http://www.minecraftforum.net/forums/minecraft-discussion/redstone-discussion-and/redstone-creations/352668-multi-digit-binary-to-decimal-converter-decimal"Multi-Digit Binary to Decimal Converter (decimal fractions too!)")
An explanation of how the Algorithm works can be found on this website: http://www.johnloomis.org/ece314/notes/devices/binary_to_BCD/bin_to_bcd.html
I went one step further though, and figured out how to apply the same principle to convert Binary Fractions to Decimal Fractions. For example, 0.11(bin) can be converted to 0.75(dec). by using conversion tables with that perform the inverse function (-3 if 8 or more) and shifting in the opposite direction.
Last edited by Hans_Lemurson: Jun 9, 2012
虽然未在 Minecraft 游戏中实现,但分数涉猎涉及每次比较和减法的逻辑单元,就像双涉猎对加法一样。
位顺序移位,double dabble是乘法器,fraction dabble是除法器。 double dabble 具有最大数量的 add3 逻辑单元,为 20 位 x 7 BCD 数字(28 位)或 140 个逻辑单元。它减少了无法更改结果的单元格数量,无论是基于不满足阈值 (> 4) 还是保证所有“0”输入。最终有 57 个逻辑单元(每四个 4x1 LUT)。
分数 dabble 使用更多单元格,因为从左侧移动会立即抛出 sub3 操作的阈值。从 18 位 x 6 BCD 数字或 108 个 sub3 单元进行综合映射后的缩减 只损失 6 个,给出 102 个逻辑单元。 add3 和 sub3 之间的差异是模四加法与减法以及 (> 4) 与 (>7) 的阈值。
通过使 BCD 值成为时钟寄存器并一次迭代 20 或 18 个操作时钟,可以进一步减少逻辑单元的数量(对于小数部分可以减少很多)。状态机需要与输入和输出握手,并迭代表示二进制输入值长度的时钟数。
绝对值转换少于40个逻辑单元。
这里的想法是,一次使用顺序操作位表示性能与大小的权衡(请注意,您尚未使用固定除法和模数缩减指定当前实现的大小)。
以下代码将这两个 dabbles 实现为不同的函数,可以针对更大或更小的 sfixed 值和 BCD 位数进行缩放,并且可能前面有多路复用器,如 Brian Drummond 所指出的,尽管根据它们的大小似乎不太可能保证。 (多路复用器有多大?)。
'slower' 性能的含义是您更新输入值(此处显示为 cp
)的速度不会快于与最长时间连接的绝对值转换的下降时间两次涉猎(较大的一次)。
此代码:
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
use ieee.fixed_pkg.all; -- included in -2008
entity iopertyki is
end entity;
architecture fum of iopertyki is
function doubledabble_20bit (inp: std_logic_vector(19 downto 0))
return unsigned is
variable bin: std_logic_vector(inp'range);
variable bcd: unsigned(27 downto 0);
begin
bin := inp;
bcd := (others => '0');
for i in 0 to 19 loop
if bcd(3 downto 0) > 4 then
bcd(3 downto 0) := bcd(3 downto 0) + 3;
end if;
if bcd(7 downto 4) > 4 then
bcd(7 downto 4) := bcd(7 downto 4) + 3;
end if;
if bcd(11 downto 8) > 4 then
bcd(11 downto 8) := bcd(11 downto 8) + 3;
end if;
if bcd(15 downto 12) > 4 then
bcd(15 downto 12) := bcd(15 downto 12) + 3;
end if;
if bcd(19 downto 16) > 4 then
bcd(19 downto 16) := bcd(19 downto 16) + 3;
end if;
if bcd(23 downto 20) > 4 then
bcd(23 downto 20) := bcd(23 downto 20) + 3;
end if;
bcd := bcd(26 downto 0) & bin(19);
bin := bin(18 downto 0) & '0';
end loop;
return bcd;
end function;
function fracdabble_19bit (inp: std_logic_vector(18 downto 0))
return unsigned is
variable bin: std_logic_vector(inp'range);
variable bcd: unsigned(23 downto 0);
-- variable tbcd: unsigned(23 downto 0); -- DEBUG
begin
bin := inp;
bcd := (others => '0'); -- DEBUG
for i in 0 to 18 loop
bcd := bin(0) & bcd(23 downto 1);
bin := '0' & bin(18 downto 1);
-- tbcd := bcd; -- DEBUG
if bcd(3 downto 0) > 7 then
bcd(3 downto 0) := bcd(3 downto 0) - 3;
end if;
if bcd(7 downto 4) > 7 then
bcd(7 downto 4) := bcd(7 downto 4) - 3;
end if;
if bcd(11 downto 8) > 7 then
bcd(11 downto 8) := bcd(11 downto 8) - 3;
end if;
if bcd(15 downto 12) > 7 then
bcd(15 downto 12) := bcd(15 downto 12) - 3;
end if;
if bcd(19 downto 16) > 7 then
bcd(19 downto 16) := bcd(19 downto 16) - 3;
end if;
if bcd(23 downto 20) > 7 then
bcd(23 downto 20) := bcd(23 downto 20) - 3;
end if;
-- report "i = " & integer'image(i) & LF & HT & -- DEBUG
-- "prior sub3 bcd = " & to_string (tbcd) & LF & HT & -- DEBUG
-- "after sub3 bcd = " & to_string (bcd); -- DEBUG
end loop;
bcd(0) := inp(0); -- An odd binary produces an odd decimal value
return bcd; -- the algorithm loses the LSB
end function;
signal cp: sfixed(20 downto -19) := to_sfixed(174334.738295,20,-19);
begin
BCD_CONVERT:
process (cp)
variable int_digits: unsigned(27 downto 0);
variable frac_digits: unsigned(23 downto 0);
alias L6: unsigned(3 downto 0) is int_digits(27 downto 24);
alias L5: unsigned(3 downto 0) is int_digits(23 downto 20);
alias L4: unsigned(3 downto 0) is int_digits(19 downto 16);
alias L3: unsigned(3 downto 0) is int_digits(15 downto 12);
alias L2: unsigned(3 downto 0) is int_digits(11 downto 8);
alias L1: unsigned(3 downto 0) is int_digits(7 downto 4);
alias L0: unsigned(3 downto 0) is int_digits(3 downto 0);
alias R5: unsigned(3 downto 0) is frac_digits(23 downto 20);
alias R4: unsigned(3 downto 0) is frac_digits(19 downto 16);
alias R3: unsigned(3 downto 0) is frac_digits(15 downto 12);
alias R2: unsigned(3 downto 0) is frac_digits(11 downto 8);
alias R1: unsigned(3 downto 0) is frac_digits(7 downto 4);
alias R0: unsigned(3 downto 0) is frac_digits(3 downto 0);
variable scp: sfixed(20 downto -19);
variable sign: character;
begin
if cp < 0.0 then
scp := "-"(0.0, cp)(20 downto -19); -- change sign, slice length
sign := '-';
else
scp := cp;
sign := ' '; -- no sign instead of '+'
end if;
report LF & HT & " cp = " & to_string(cp) &
LF & HT & "absolute val cp = " & to_string(scp);
report LF & HT & "slv int = " & to_string(to_slv(scp)(38 downto 19))
& " slv frac = " & to_string(to_slv(scp)(18 downto 0));
-- leave off sign bit:
int_digits := doubledabble_20bit(to_slv(scp)(38 downto 19));
report "int_digits = " & to_string (int_digits);
-- 55 logic cells following mspping and reduction:
frac_digits := fracdabble_19bit(to_slv(scp)(18 downto 0));
report "frac_digits = " & to_string (frac_digits);
-- R6 = "0000"
report "result = " & sign &
integer'image(to_integer(L6)) &
integer'image(to_integer(L5)) &
integer'image(to_integer(L4)) &
integer'image(to_integer(L3)) &
integer'image(to_integer(L2)) &
integer'image(to_integer(L1)) &
integer'image(to_integer(L0)) &
'.' &
integer'image(to_integer(R5)) &
integer'image(to_integer(R4)) &
integer'image(to_integer(R3)) &
integer'image(to_integer(R2)) &
integer'image(to_integer(R1)) &
integer'image(to_integer(R0));
end process;
MORE:
process
begin
wait for 20 ns;
cp <= "-"(cp)(20 downto -19); -- change sign, slice length
wait for 20 ns;
cp <= to_sfixed(-307.83929,20,-19);
wait;
end process;
end architecture;
经过分析、阐述和模拟后产生:
ghdl -a --std=08 iopertyki.vhdl ghdl -e --std=08 iopertyki ghdl -r --std=08 iopertyki iopertyki.vhdl:112:9:@0ms:(report note): cp = 000101010100011111110.1011110100000000111 absolute val cp = 000101010100011111110.1011110100000000111 iopertyki.vhdl:114:9:@0ms:(report note): slv int = 00101010100011111110 slv frac = 1011110100000000111 iopertyki.vhdl:118:9:@0ms:(report note): int_digits = 0000000101110100001100110100 iopertyki.vhdl:121:9:@0ms:(report note): frac_digits = 011100111000001010010101 iopertyki.vhdl:124:9:@0ms:(report note): result = 0174334.738295 iopertyki.vhdl:112:9:@20ns:(report note): cp = 111010101011100000001.0100001011111111001 absolute val cp = 000101010100011111110.1011110100000000111 iopertyki.vhdl:114:9:@20ns:(report note): slv int = 00101010100011111110 slv frac = 1011110100000000111 iopertyki.vhdl:118:9:@20ns:(report note): int_digits = 0000000101110100001100110100 iopertyki.vhdl:121:9:@20ns:(report note): frac_digits = 011100111000001010010101 iopertyki.vhdl:124:9:@20ns:(report note): result = -0174334.738295 iopertyki.vhdl:112:9:@40ns:(report note): cp = 111111111111011001100.0010100100100100010 absolute val cp = 000000000000100110011.1101011011011011110 iopertyki.vhdl:114:9:@40ns:(report note): slv int = 00000000000100110011 slv frac = 1101011011011011110 iopertyki.vhdl:118:9:@40ns:(report note): int_digits = 0000000000000000001100000111 iopertyki.vhdl:121:9:@40ns:(report note): frac_digits = 100000111001001010010000 iopertyki.vhdl:124:9:@40ns:(report note): result = -0000307.839290
展示正确的转换。
在对您的 LCD 显示器一无所知的情况下,尝试将 BCD 数字映射到它似乎不切实际。
这些从固定值到 BCD 数字的转换代表了硬件思维与机器指令思维的对比。如果减少 space 的需要不被涉猎所满足,使用时钟移位寄存器可以进一步减小大小,减少 add3 或 sub3 单元与小型状态机权衡的要求。这之所以可行,是因为眼睛和 LCD 显示器的工作方式都存在光学持久性。您根本看不到不会持续几毫秒的事情。