2

论文:
Xilinx XST 在连接这些向量后反转向量的方向。

我有一个 SATAController 和一个 PicoBlaze 软核 CPU。该 CPU 使用寄存器接口 + 交叉时钟来读取/写入测试数据。CPU 写入 6 个 8 位寄存器,这些寄存器存储 24 位偏移量和 24 位长度字段以用于读取请求。这些地址和长度字段扩展为 48 位(关键字:LBA-48 寻址模式)。

它看起来怎样?

  -- register values after cross clocking with double FFs
  signal sync_Offset     : T_SLV_24;   -- std_logic_vector(23 downto 0)
  signal sync_Length     : T_SLV_24;
  -- output signals for LBA-48 addressing
  signal Address_LB      : T_SLV_48;   -- std_logic_vector(47 downto 0)
  signal BlockCount_LB   : T_SLV_48;
  -- [...]  
begin
  -- [...]
  -- SLL 7 -> granularity for logical blocks is 1 MiB
  Address_LB    <= resize(sync_Offset & "0000000", Address_LB'length);
  BlockCount_LB <= resize(sync_Length & "0000000", BlockCount_LB'length);

通常人们会猜测调整大小会导致
Address_LB == "0000_0000_0000_0000_0" & sync_Offset & "000_0000"
BlockCount_LB == "0000_0000_0000_0000_0" & sync_Length & "000_0000"

但是,事实并非如此。经过三个小时的调试,我发现综合结果如下:
Address_LB = "0000_000" & sync_Offset & "0_0000_0000_0000_0000"
BlockCount_LB = "0000_000" & sync_Length & "0_0000_0000_0000_0000"

那么会发生什么?
信号sync_*是下降向量。与运算符连接后&,向量呈上升方向,这会导致调整大小以在向量的另一个边界对齐 sync_*。

所以我在网上搜索了这个现象,我找不到任何东西。我还搜索了 std_logic_1164,但没有为 std_logic(_vector) 明确定义连接运算符。

所以这是我的问题:

  • 这是特定于语言的功能或工具吗?
    (我使用 Xilinx XST 进行这些测试。)
  • 在哪里&定义?
  • 连接两个后得到的向量方向是什么:
    • 相等的有向向量或两个
    • 反向向量?

解决方案:

  1. 可以使用已知方向的中间信号。
  2. 可以编写一个函数来强制某个方向。见功能descend(..)

上面的固定示例:

Address_LB    <= resize(descend(sync_Offset & "0000000"), Address_LB'length);
BlockCount_LB <= resize(descend(sync_Length & "0000000"), BlockCount_LB'length);

附录 - 函数声明:

subtype T_SLV_24  is STD_LOGIC_VECTOR(23 downto 0);
subtype T_SLV_48  is STD_LOGIC_VECTOR(47 downto 0);

调整大小功能:

-- Resizes the vector to the specified length. The adjustment is make on
-- on the 'high end of the vector. The 'low index remains as in the argument.
-- If the result vector is larger, the extension uses the provided fill value
-- (default: '0').
-- Use the resize functions of the numeric_std package for value-preserving
-- resizes of the signed and unsigned data types.
function resize(vec : std_logic_vector; length : natural; fill : std_logic := '0') return std_logic_vector is
  constant  high2b : natural := vec'low+length-1;
  constant  highcp : natural := imin(vec'high, high2b);
  variable  res_up : std_logic_vector(vec'low to high2b);
  variable  res_dn : std_logic_vector(high2b downto vec'low);
begin
  if vec'ascending then
    res_up := (others => fill);
    res_up(vec'low to highcp) := vec(vec'low to highcp);
    return  res_up;
  else
    res_dn := (others => fill);
    res_dn(highcp downto vec'low) := vec(highcp downto vec'low);
    return  res_dn;
  end if;
end function;

function imin(arg1 : integer; arg2 : integer) return integer is
begin
  if arg1 < arg2 then return arg1; end if;
  return arg2;
end function;

function descend(vec : std_logic_vector) return std_logic_vector is
  variable res : std_logic_vector(vec'high downto vec'low);
begin
  res := vec;
  return  res;
end function;

编辑1:

涉及的包:

library ieee;
use     ieee.std_logic_1164.all;
use     ieee.numeric_std.all;

library PoC;
use     PoC.utils.all;    -- here are resize, imin and descend declared

T_SLV_<n>代表“类型;std_logic_vector;n 位 -> (n-1 downto 0)”

4

2 回答 2

2

以此作为 MCVe:

library ieee;
use ieee.std_logic_1164.all;

entity sync is
end entity;
architecture mcve of sync is

    subtype T_SLV_24 is std_logic_vector(23 downto 0);
    subtype T_SLV_48 is std_logic_vector(47 downto 0);
    -- register values after cross clocking with double FFs
    signal sync_Offset     : T_SLV_24 := x"deadbe";
    signal sync_Length     : T_SLV_24 := x"feedfa";
    -- output signals for LBA-48 addressing
    signal Address_LB      : T_SLV_48;   -- std_logic_vector(47 downto 0)
    signal BlockCount_LB   : T_SLV_48;

    function MINIMUM (l,r: integer) return integer is
        begin
            if l > r then
                return r;
            else
                return l;
            end if;
        end function;
  -- [...]  
  -- Resizes the vector to the specified length. The adjustment is make on
  -- on the 'high end of the vector. The 'low index remains as in the argument.
  -- If the result vector is larger, the extension uses the provided fill value
  -- (default: '0').
  -- Use the resize functions of the numeric_std package for value-preserving
  -- resizes of the signed and unsigned data types.
  function resize(vec : std_logic_vector; length : natural; fill : std_logic := '0') return std_logic_vector is
    constant  high2b : natural := vec'low+length-1;
    constant  highcp : natural := MINIMUM(vec'high, high2b);  -- imin
    variable  res_up : std_logic_vector(vec'low to high2b);
    variable  res_dn : std_logic_vector(high2b downto vec'low);
  begin
    if vec'ascending then
      res_up := (others => fill);
      res_up(vec'low to highcp) := vec(vec'low to highcp);
      return  res_up;
    else
      res_dn := (others => fill);
      res_dn(highcp downto vec'low) := vec(highcp downto vec'low);
      return  res_dn;
    end if;
  end function;
  function descend(vec : std_logic_vector) return std_logic_vector is
    variable res : std_logic_vector(vec'high downto vec'low);
  begin
    res := vec;
    return  res;
  end function;

  function to_string(inp: std_logic_vector) return string is
      variable image_str: string (1 to inp'length);
      alias input_str:  std_logic_vector (1 to inp'length) is inp;
  begin
      for i in input_str'range loop
          image_str(i) := character'VALUE(std_ulogic'IMAGE(input_str(i)));
      end loop;
      return image_str;
  end;

begin
  -- [...]
  -- SLL 7 -> granularity for logical blocks is 1 MiB
    -- Address_LB    <= resize(sync_Offset & "0000000", Address_LB'length);
    -- BlockCount_LB <= resize(sync_Length & "0000000", BlockCount_LB'length);
    Address_LB    <= resize(descend(sync_Offset & "0000000"), Address_LB'length);
    BlockCount_LB <= resize(descend(sync_Length & "0000000"), BlockCount_LB'length);

    Process (Address_LB, BlockCount_LB)
    begin
        report "Address_LB = " & to_string(Address_LB) Severity NOTE;
        report "BlockCount_LB = " & to_string(BlockCount_LB) Severity NOTE;
    end process;
end architecture;

有两个初始值:

    signal sync_Offset     : T_SLV_24 := x"deadbe";
    signal sync_Length     : T_SLV_24 := x"feedfa";

请注意本地函数 MINIMUM 而不是 imin(未提供)和 to_string 的本地副本(此 ghdl 符合 -1993 标准)。还要注意带有本地 MINIMUM 的最小上下文子句

那给了:

ghdl -a sync.vhdl
ghdl -e sync
ghdl -r sync
sync.vhdl:75:9:@0ms:(report note): Address_LB = uuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuu
sync.vhdl:76:9:@0ms:(report note): BlockCount_LB = uuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuu
sync.vhdl:75:9:@0ms:(report note): Address_LB = 000000000000000001101111010101101101111100000000
sync.vhdl:76:9:@0ms:(report note): BlockCount_LB = 000000000000000001111111011101101111110100000000

0000 0000 0000 0000 0 1101 1110 1010 1101 1011 1110 000 0000
                        D    E    A    D    B    E

Address_LB 看起来不错。

0000 0000 0000 0000 0 1111 1110 1110 1101 1111 1010 000 0000
                        F    E    E    D    F    A

BlockCount_LB 也是如此。

没有下降调用(原始分配):

  Address_LB    <= resize(sync_Offset & "0000000", Address_LB'length);
  BlockCount_LB <= resize(sync_Length & "0000000", BlockCount_LB'length);

Sync.vhdl:75:9:@0ms :(报告注释):地址_lb = 11011110101101101111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111ME000000000000000
SYNC.VHDL:76:9:9:@0MS:(报告注释):

哪个是

D  E   A   D   B   E  0000 0000 0000 0000 0000 0000

F  E   E   D   F   A  0000 0000 0000 0000 0000 0000

而且看起来不像问题,它真的说你应该提供一个 MCVe。(这些看起来确实像您阅读 resize 函数时所期望的那样)。

  • 这是特定于语言的功能或工具吗?(我使用 Xilinx XST 进行这些测试。)

在ghdl工作。工具特定。我还会仔细查看 XST 支持的 VHDL 构造。

  • 在哪里&定义?

定义类型后立即定义它,以及用于一维数组类型和基本操作的其他预定义运算符。注意我使用了一个子类型,所以在这种情况下,这些隐式声明出现在 std_logic_1164 包中,紧随 std_logic_vector (std_ulogic_vector, -2008) 的声明之后。

  • 等向向量和反向向量的结果向量方向是什么?

嗯?再试一次paebbels。赋值是从左到右关联的,左元素到左元素,... 右元素到 right_element)。没有保留数据,这将需要一个循环下降(或接口列表正式中的子类型指示,但它不会以任何长度工作)。

就我个人而言,我没有看到编写函数来做到这一点的意义。简单地使用连接应该是合成安全的。

于 2015-02-11T07:33:26.630 回答
2

&VHDL标准中定义了连接运算符(

a) ... 令 S 为结果基类型的索引子类型。拼接结果的方向是S的方向,结果的左边界是S'LEFT。

对于TYPE std_logic_vector IS ARRAY (NATURAL RANGE <>) OF std_logic;(或类似的),索引子类型 SNATURAL具有上升方向 ( NATURAL'ASCENDING = TRUE) 和左边界 0 ( NATURAL'LEFT = 0)。

因此, 的连接结果在std_logic_vector左边界为 0 的情况下递增,对于 也是如此sync_Offset & "0000000"。(唯一的例外是连接两个零长度数组,它返回正确的参数。)

您编写的resize函数会将vec参数放在结果的左侧,并用 填充fill,所以我希望结果来自:

resize(sync_Offset & "0000000", Address_LB'length);

成为:

sync_Offset & "000...000"

如果结果中的值左侧有任何 0 sync_Offset,那么这听起来像是您的结果解释或 XST 中的问题(不太可能)。

顺便提一句。将函数的名称与anresize以外的其他操作 重用可能会导致混淆。resizeunsigned

于 2015-02-11T15:14:40.617 回答