在 VHDL 中迭代二维信号

问题描述 投票:0回答:1

我正在尝试使用生成函数创建一个n位逻辑移位。

entity logical_shift_n is
    generic(WIDTH : positive :=8);
    port (A: in std_logic_vector(WIDTH-1 downto 0);
          S: in std_logic_vector(log2(WIDTH)-1 downto 0);
          D: out std_logic_vector(WIDTH-1 downto 0));
          type two_dim is array (0 to log2(WIDTH)-1) of std_logic_vector(WIDTH-1 downto 0);
end logical_shift_n;

architecture behavioral of logical_shift_n is

component mux is
  port(A,B : in std_logic_vector(WIDTH-1 downto 0);
         S   : in std_logic;
         O   : out std_logic_vector(WIDTH-1 downto 0));
end component;

signal D1 : two_dim :=(others=>(others=>'0'));
signal D0 : two_dim :=(others=>(others=>'0'));
signal Y : two_dim :=(others=>(others=>'0'));
begin
D0 <= A;
D1 <= A & '0';

reg: for i in 0 to log2(WIDTH)-1 generate
    DC : mux
    port map(
        A => D0,
        B => D1,
        S => S(i),
        O  => Y
        );
end generate;

D <= Y; 

end behavioral;

我面临的问题是

  1. 我需要将“D0”的第一行分配给“A”,将“D1”的第一行分配给“A&'0'”,以便D0的第一行包含正常输入A,D1的第一行包含A 左移 1。

  2. 然后我想迭代行(使用生成函数),以便来自第一个多路复用器的输出充当下一个多路复用器的输入,第二个多路复用器应该有一个正常输入(等于之前的输出)与之前的输入一样,然后是另一个输入,该输入应该是前一个输出移位 2。类似地,对于第三个多路复用器,其输入之一应该是前一个输出移位 4 (2^(n-1))。等等。

Logical shift

为了提供更好的想法,我还创建了一个图表。尽管该图仅适用于 8 位(三个多路复用器),但我想使用生成函数将其概括为 n 位。

我创建了一个二维信号。但我不确定如何初始化它的第一行。此外,我不确定如何迭代行,以便发生多路复用器的级联,并且在 n=0,1,2......n

的情况下也会发生左移(2^n)
vhdl hdl
1个回答
0
投票

有多种方法可以创建通用或参数控制的逻辑(左)移位器。

这是基于您的问题代码的一个:

library ieee;                -- CHANGED, added missing mux
use ieee.std_logic_1164.all;

entity mux is
    generic (WIDTH: natural);
    port (
        A,B: in  std_logic_vector(WIDTH - 1 downto 0);
        S:   in  std_logic;
        O:   out std_logic_vector(WIDTH - 1 downto 0)
    );
end entity;

architecture foo of mux is
begin
    O <= A when S = '0' else B;
end architecture;

library ieee;                -- CHANGED Context clause added
use ieee.std_logic_1164.all;
use ieee.math_real.all;      -- ADDED for log2

entity logical_shift_n is
    generic (WIDTH:     positive := 8);
    port (
        A: in  std_logic_vector(WIDTH - 1 downto 0);
    -- CHANGED, added useage for log2 from package math_real, ceil for non powers of two
        S: in  std_logic_vector(integer(ceil(log2(real(WIDTH)))) - 1 downto 0);
        D: out std_logic_vector(WIDTH - 1 downto 0));
          
          -- CHANGED don't calculate length again and again:
          type two_dim is array (0 to S'LEFT) of 
                           std_logic_vector(WIDTH - 1 downto 0);
end entity logical_shift_n;

architecture behavioral of logical_shift_n is

    component mux is
        generic (WIDTH: natural);
        port (
            A,B: in  std_logic_vector(WIDTH - 1 downto 0);
            S:   in  std_logic;
            O:   out std_logic_vector(WIDTH - 1 downto 0)
        );
    end component;

    signal D1: two_dim; -- CHANGED -- :=(others=>(others=>'0'));
    -- signal D0: two_dim; -- CHANGED -- :=(others=>(others=>'0'));
    signal Y : two_dim; -- CHANGED -- :=(others=>(others=>'0'));
    
    -- CHANGED, BORROWED from -1997 numeric_std-body.vhdl
    function XSLL (ARG: STD_LOGIC_VECTOR; COUNT: NATURAL) return STD_LOGIC_VECTOR
        is
      constant ARG_L: INTEGER := ARG'LENGTH-1;
      alias XARG: STD_LOGIC_VECTOR(ARG_L downto 0) is ARG;
      variable RESULT: STD_LOGIC_VECTOR(ARG_L downto 0) := (others => '0');
    begin
      if COUNT <= ARG_L then
        RESULT(ARG_L downto COUNT) := XARG(ARG_L-COUNT downto 0);
      end if;
      return RESULT;
    end XSLL;
begin
-- D0 <= A;  CHANGED Either A for i = 0 or Y (i - 1) for i /= 0
-- D1 <= A & '0';

reg:
    for i in S'range generate  -- CHANGED, breakout i = 0 from rest -1993 syntax
I_EQ_0:
        if i = 0 generate
            D1(i) <= XSLL(A, 2 ** i);
DC:     
            mux
                generic map (WIDTH => WIDTH)
                port map (
                    A => A,      -- CHANGED   Y(0) not used
                    B => D1(i),  -- CHANGED, indexed name
                    S => S(i),
                    O  => Y(i)   -- CHANGED, indexed name
                );
  
        end generate;
I_NEQ_0:
        if i /= 0 generate 
            D1(i) <= XSLL(Y(i - 1), 2 ** i);
DC:
            mux
                generic map (WIDTH => WIDTH)
                port map (
                    A => Y(i - 1),  -- CHANGED
                    B => D1(i),     -- CHANGED, indexed name
                    S => S(i),
                    O  => Y(i)       -- CHANGED, indexed name
                );
        end generate;
    end generate;

    D <= Y(S'LEFT); 
    
end architecture behavioral;


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

entity logical_shift_n_tb is
end entity;

architecture foo of logical_shift_n_tb is
    
    constant WIDTH:     natural := 8;
    
    component logical_shift_n is
        generic (WIDTH:     positive := 8);
        port (
            A: in  std_logic_vector(WIDTH - 1 downto 0);
            S: in  std_logic_vector(integer(ceil(log2(real(WIDTH)))) - 1 downto 0);
            D: out std_logic_vector(WIDTH - 1 downto 0)
        );
    end component logical_shift_n;
    
    signal A:   std_logic_vector(WIDTH - 1 downto 0) := "01001100";
    signal S:   std_logic_vector(integer(ceil(log2(real(WIDTH)))) - 1 downto 0);
    signal D:   std_logic_vector(WIDTH - 1 downto 0);
    -- for IEEE Std 1076 revision less than 2008:
    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 function;
    
begin
UUT:
    logical_shift_n
        generic map ( WIDTH => WIDTH)
        port map (
            A => A,
            S => S,
            D => D
        );
STIMULI:
    process
    begin
        for i in 0 to 2 ** S'length - 1 loop
            S <= std_logic_vector(to_unsigned(i, S'length));
            wait for 5 ns;
            report LF & HT &
                   "A = " & to_string(A) & LF & HT &
                   "S = " & to_string(S) & LF & HT &
                   "D = " & to_string(D);
            wait for 5 ns;
        end loop;
        wait for 10 ns;
        wait;
    end process;
end architecture;

这会产生:

%: ghdl -r logical_shift_n_tb
logical_shift_n.vhdl:152:13:@5ns:(report note):
    A = 01001100
    S = 000
    D = 01001100
logical_shift_n.vhdl:152:13:@15ns:(report note):
    A = 01001100
    S = 001
    D = 10011000
logical_shift_n.vhdl:152:13:@25ns:(report note):
    A = 01001100
    S = 010
    D = 00110000
logical_shift_n.vhdl:152:13:@35ns:(report note):
    A = 01001100
    S = 011
    D = 01100000
logical_shift_n.vhdl:152:13:@45ns:(report note):
    A = 01001100
    S = 100
    D = 11000000
logical_shift_n.vhdl:152:13:@55ns:(report note):
    A = 01001100
    S = 101
    D = 10000000
logical_shift_n.vhdl:152:13:@65ns:(report note):
    A = 01001100
    S = 110
    D = 00000000
logical_shift_n.vhdl:152:13:@75ns:(report note):
    A = 01001100
    S = 111
    D = 00000000
%: 

注意报告语句的格式取决于 VHDL 工具的实现。

更改代码的操作思路包括使用前一个“阶段”Y 作为多路复用器的未更改输入,第一个除外,它使用未更改的 A 输入。对于移位输入,函数 XSLL 是从 IEEE 包 numeric_std 的最早版本中窃取的,该包主体中的声明通过 use 子句不可见,该子句根据移位距离分配一个输出切片,覆盖输出值的一部分,该输出值具有初始值全部为“0”。对于每一级,D1(i) 的移位距离是 2 的 S 元素次方,除了从 A 派生的第一级之外。之后前一级的 Y 输出用于未移位的多路复用器输入,并且 D1(i) 值是通过移位 2 次方到距离而从前一级 Y 导出的。

测试平台只是一些拼凑在一起的东西,用于演示代码(具有多路复用器的独立实现)分析、详细说明和模拟,没有错误。

一般还有两种方法,递归实例化或递归子程序调用,其中泛型或参数可以定义“阶段”的数量,并在后续实例或调用中进行修改,直到不需要更多的转换。这些可以消除定义您自己的数组类型的需要。

这里,two_dim 类型是一种一维数组类型(它有一个索引),其元素类型是数组类型 (std_logic_vector)。

随便搜索一下,就发现没有返回整数值的标准包 log2 函数的来源。如果 A 的长度不是 2 的幂,则 A 会放入封装 ceil 函数调用中。如果移位距离超过 WIDTH - 1,则函数 XSLL 将返回全“0”,此处使用该函数来鼓励探索预先存在的包。

© www.soinside.com 2019 - 2024. All rights reserved.