VHDL:连接2个向量 - 结果向量方向是什么?

时间:2015-02-11 00:59:28

标签: vhdl xilinx-ise

论文:
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(..)
  3. 上面的固定示例:

    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>代表&#34;类型; std_logic_vector; n位 - &gt; (n-1 downto 0)&#34;

2 个答案:

答案 0 :(得分: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 :(报告说明):Address_LB = uuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuu   sync.vhdl:76:9:@ 0ms :(报告说明):BlockCount_LB = uuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuu   sync.vhdl:75:9:@ 0ms :(报告单):Address_LB = 000000000000000001101111010101101101111100000000
  sync.vhdl:76:9:@ 0ms :(报告单):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 :(报告单):Address_LB = 110111101010110110111110000000000000000000000000
  sync.vhdl:76:9:@ 0ms :(报告单):BlockCount_LB = 111111101110110111111010000000000000000000000000

哪个是

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。 (这些看起来就像你阅读调整大小函数所期望的那样)。

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

在ghdl工作。特定工具。我还仔细研究了XST支持的VHDL结构。

  • &定义在哪里?

定义类型后定义,以及单维数组类型和基本操作的其他预定义运算符。注意我使用了一个子类型,所以在这种情况下,这些隐式声明发生在包std_logic_1164中,遵循std_logic_vector(std_ulogic_vector,-2008)的声明。

  • 得到的矢量方向是什么?           等向导向和           反向矢量?

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

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

答案 1 :(得分:2)

串联运算符(&)在VHDL标准中定义,例如 VHDL-2008部分&#34; 9.2.5添加运算符&#34;,其中的相关信息 关于方向和范围是:

  

a)...设S为结果基类型的索引子类型。   连接结果的方向是方向   S的结果左边界是S&#39; LEFT。

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

std_logic_vector的连接结果因此以0的左边界升序,sync_Offset & "0000000"的情况也是如此。 (只有例外是两个零长度数组的连接,它返回正确的参数。)

您编写的resize函数会将vec参数放入。{1}} 留在结果中,并填入fill,所以我希望结果来自:

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

是:

sync_Offset & "000...000"

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

顺便说一下。重复使用resize名称作为其他操作的函数 resize的{​​{1}}可能会导致混淆。