VHDL sfixed解码代码不能正常工作

VDHL sfixed decoding code does not work properly

我正在使用 David Bishop 的定点库 在 vhdl 中做一些数学运算。我需要将最终值解码为整数。我遵循的方法如下,我确实得到了小数部分的精细值,但小数值不正确。我还找不到问题。小数部分第一个两位数字是错误的。 xx8374.839923 xx 数字总是错的。

当我执行此操作时,我得到 274334.738295 for 174334.738295

建筑内部, 在过程中我确实声明了这些变量,

variable  cp : sfixed(20 downto -19);
variable mod10 : sfixed(4 downto 0);
variable div10 : sfixed(4 downto 0);

variable L0 : sfixed(4 downto 0);
variable L1 : sfixed(4 downto -4);
variable L2 : sfixed(4 downto -8);
variable L3 : sfixed(4 downto -12);
variable L4 : sfixed(4 downto -16);
variable L5 : sfixed(4 downto -20);
variable L6 : sfixed(4 downto -24); 

variable    temp_L  : sfixed(19 downto 0);
variable    temp_L1 : sfixed(20 downto -4);
variable    temp_L2 : sfixed(21 downto -8);
variable    temp_L3 : sfixed(22 downto -12);
variable    temp_L4 : sfixed(23 downto -16);
variable    temp_L5 : sfixed(24 downto -20);
variable    temp_L6 : sfixed(25 downto -24);

开始后,我需要在 sfixed 中解码 174334.738295,因为有时我会得到负数。这个数字将被另一个计算所取代,这里没有提供,如果那个数字是 174334.738295 (sfixed) 那么我需要解码这个数字,

cp      :=  to_sfixed(174334.738295,20,-19);
temp_L  := cp(19 downto 0); -- remove sign bit

mod10   :=to_sfixed(10,4,0) ;                 
div10   :=to_sfixed(10,4,0) ;

L0      := temp_L mod mod10;
temp_L1 := temp_L/div10;
L1      := temp_L1 mod mod10;
temp_L2 := temp_L1/div10;
L2      := temp_L2 mod mod10;
temp_L3 := temp_L2/div10;
L3      := temp_L3 mod mod10;  
temp_L4 := temp_L3/div10;
L4      := temp_L4 mod mod10;               
temp_L5 := temp_L4/div10;
L5      := temp_L5 mod mod10;
temp_L6 := temp_L5/div10;
L6      := temp_L6 mod mod10;   

L6 是第一位,L5 是第二位

你的除法应该是整数除法;他们不是(定点划分)。而且我什至无法想象模数运算符在应用于非整数(定点)参数时应该 return 是什么。不管怎样,这个定点表示很简单,所以,如果你只想要正定点数的整数部分的数字,你可以先将其转换为自然数,然后计算数字:

library ieee;
use ieee.numeric_std.all;
use ieee.std_logic_1164.all;
...
variable n: natural;
subtype digit is natural range 0 to 9;
type digit_vector is array(natural range <>) of digits;
variable digits: digit_vector(5 downto 0);
...
n := to_integer(u_unsigned(cp(20 downto 0)));
for i in 0 to 5 loop
  digits(i) := n mod 10;
  n := n / 10;
end loop;

或者,如果您只想打印 cp 的十进制表示:

use std.textio.all;
...
variable l: line;
...
write(l, to_integer(u_unsigned(cp(20 downto 0)));
writeline(output, n);

或者,甚至更简单,使用库本身的 write 过程:

variable tmp: sfixed(20 downto 0);
...
tmp := cp(20 downto 0);
write(l, tmp);
writeline(output, l);

修改您的原始代码,修复 div10、mod10(下划线单独保留声明)并生成 MCVE:

library ieee;
use ieee.fixed_pkg.all;

entity iopertyki is
end entity;

architecture fum of iopertyki is
begin
    process
        variable  cp:       sfixed(20 downto -19);
        variable mod_10:    sfixed(4 downto 0);
        variable div_10:    sfixed(4 downto 0);
        variable mul_10:    sfixed(4 downto 0); 

        variable L0:        sfixed(4 downto 0);
        variable L1:        sfixed(4 downto -4);
        variable L2:        sfixed(4 downto -8);
        variable L3:        sfixed(4 downto -12);
        variable L4:        sfixed(4 downto -16);
        variable L5:        sfixed(4 downto -20);
        variable L6:        sfixed(4 downto -24); 

        variable temp_L:    sfixed(19 downto 0);
        variable temp_L1:   sfixed(20 downto -4);
        variable temp_L2:   sfixed(21 downto -8);
        variable temp_L3:   sfixed(22 downto -12);
        variable temp_L4:   sfixed(23 downto -16);
        variable temp_L5:   sfixed(24 downto -20);
        variable temp_L6:   sfixed(25 downto -24);
    begin
        cp    :=  to_sfixed(174334.738295,20,-19);
        report "cp = " & to_string(cp);
        temp_L      := cp(19 downto 0); -- remove sign bit
        report "temp_L = " & to_string(temp_L);
        report "integer'image temp_L = " & integer'image(to_integer(temp_L));
        mod_10 := to_sfixed(10,4,0);                 
        div_10 := to_sfixed(10,4,0);
        mul_10 := to_sfixed(10,4,0);

        L0          := temp_L mod mod_10;
        temp_L1     := temp_L/div_10;
        L1          := temp_L1 mod mod_10;
        temp_L2     := temp_L1/div_10;
        L2          := temp_L2 mod mod_10;
        temp_L3     := temp_L2/div_10;
        L3          := temp_L3 mod mod_10; 
        temp_L4     := temp_L3/div_10;
        L4          := temp_L4 mod mod_10;              
        temp_L5     := temp_L4/div_10;
        L5          := temp_L5 mod mod_10;
        temp_L6     := temp_L5/div_10;
        L6          := temp_L6 mod mod_10; 
        -- xx8374.839923 ? 
        report " result   = " & 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));

        report " no round = " & integer'image(to_integer(L6(4 downto 0))) &
                              integer'image(to_integer(L5(4 downto 0))) &
                              integer'image(to_integer(L4(4 downto 0))) &
                              integer'image(to_integer(L3(4 downto 0))) &
                              integer'image(to_integer(L2(4 downto 0))) &
                              integer'image(to_integer(L1(4 downto 0))) &
                              integer'image(to_integer(L0(4 downto 0)));
        wait;
    end process;
end architecture;

这会产生整数部分结果(你没有在你的问题中展示你是如何做到的,新的结果:

...get 274334.738295 for 174334.738295

您可以证明 to_integer 四舍五入是 L5 为 2 而不是 1 的原因:

ghdl -a --std=08 iopertyki.vhdl
ghdl -e --std=08 iopertyki
ghdl -r iopertyki

iopertyki.vhdl:91:9:@0ms:(report note): cp = 000101010100011111110.1011110100000000111
iopertyki.vhdl:93:9:@0ms:(report note): temp_L = 00101010100011111110.0
iopertyki.vhdl:94:9:@0ms:(report note): integer'image temp_L = 174334
iopertyki.vhdl:113:9:@0ms:(report note):  result   = 0274334
iopertyki.vhdl:121:9:@0ms:(report note):  no round = 0174334

所以所有这些告诉你只使用 L6 - L1 的整数部分,所以没有四舍五入。 (在您评论过的 David Bishop 的用户指南中,有关于如何裁剪 sfixed 或 ufixed 值的提示)。

您可能会注意到,剪裁 sfixed 值会受到符号偏差的影响,并且您需要更改所有恢复的十进制数字的符号或使用带符号的幅度(您的数字计算可能不固定)符号转发到负数的结果。几十年后的数学会很麻烦。

使用ghdl时的细化和模拟注意事项

ghdl 的代码生成有三种架构,分别使用 GCC 后端、LLVM 后端和 mcode 即时代码生成器。

来自 运行 命令的最新 GHDL Documentation section on Invoking GHDL

run -r

Runs/simulates a design. The options and arguments are the same as for the elaboration command.

  • GGC/LLVM: simply, the filename of the executable is determined and it is executed. Options are ignored. You may also directly execute the program. The executable must be in the current directory.
  • mcode: the design is elaborated and the simulation is launched. As a consequence, you must use the same options used during analysis.

在诸如为 Win32 分发的 mcode 版本中,-e 详细命令是多余的,运行 命令 (-r) 必须包含与分析命令 (-a) 相同的选项。

对于 GCC/LLVM 后端代码生成器版本的 ghdl,细化 (-e) 命令必须具有与分析命令 (-a) 相同的选项。对于 --std=08,使用了不同的工作库,如果没有单独指定库目录,则不使用 std 选项或使用不同的 STD 值生成的任何目标文件都将被覆盖。

mcode 版本没有目标文件。分析的对象仅存在于 ghdl 程序的内存中,随后使用 运行 (-r) 命令将其详细化为模拟设计模型。

不指定版本或发布 用户只能依赖 ghdl 文档。

您还可以注意到,ghdl-0.34 已在最后一天发布,并且提供了 Win32 二进制映像 (mcode) 和 64 位二进制映像 (llvm)(它们的名称包括 "mingw") .