具有行为架构的桶形移位器的VHDL代码结构

时间:2014-05-27 14:11:54

标签: vhdl digital-logic

我正在尝试构建一个具有左右移位功能的16位桶形移位器。我在如何构造代码方面遇到了一些问题,以便它能够执行我认为我想要做的事情。

我有一个决定方向的操作码输入,一个要移位的输入矢量,一个输出矢量和一个4位的位置矢量。

我正在使用位置向量设置一个班级'在某种方式。我想检查位置(0),如果设置为1,则移动一个位置。然后检查位置(1)和换档位置,位置(3)4位置和位置(3)8位置。

我认为如果我遍历位置向量中的每个位置并按顺序移位,它应该最终获得所有选项。当这个方向正常工作时,我会添加其他操作码。

我被困在为架构分配中间向量。我不确定应该采用什么样的方法,而且我在google中找不到任何东西。也许Case系统会更好。

entity eds_shifter is
port ( a : in bit_vector(15 downto 0) ; --input
    pos : in bit_vector(3 downto 0); -- position
    opc : in bit_vector(3 downto 0); -- opcode
    y : out bit_vector(15 downto 0) --output
    );
end entity eds_shifter ;

architecture behavior of eds_shifter is
begin
process(a,pos,opc) -- input vectors 
signal s1,s2,s3,s4 : bit_vector(15 downto 0); -- intermediate steps
begin
   s1 <= a(14 downto 0) & '0' when pos(0) = '1' and opc = "0000" else -- shifting left by one
   s1 <= a when pos(0) = '0' and opc = "0000" else -- carryover vector to next shift position
   s2 <= s1(13 downto 0) & '0' when pos(1) = '1' and opc = "0000" else -- shift previous vector by 2
   s2 <= s1 when pos(1) = '0' and opc = "0000" else 
   s3 <= s2(12 downto 0) & '0' when pos(2) = '1' and opc = "0000" else -- shift another 4 places
   s3 <= s2 when pos(2) = '0' and opc = "0000" else 
   s4 <= s3(7 downto 0) & '0' when pos(3) = '1' and opc = "0000" else -- shift another 8 places
   s4 <= s3 when pos(3) = '0' and opc = "0000" else 
   y <= s4 when opc = "0000";
end process;
end architecture behavior;

错误消息

** Error: */02/eds_shifter.vhd(14): Illegal sequential statement.
** Error: */02/eds_shifter.vhd(15): Type error resolving infix expression "<=" as type std.standard.bit_vector.

修改

感谢您的详细回复。我知道内置了泛型移位功能,但我想弄清楚如何自己实现它。

感谢有关bit_vector的提示。根据我的理解,当您确定输入不是多源时,只能使用位类型。在这种情况下它可能应该没问题,但我将继续并将其牢记在未来。

我认为我想尝试的概念是合理的。如果检查位置中的每个位为1并在末尾移位适当的量,则移位的位数将等于位置矢量的值。

a =&#34; 1111 1111 1111 1111&#34;和pos =&#34; 1010&#34;所以我们需要将十位移位。所以我们进行第一次迭代并且它没有变化,第二次移位2位,第三次迭代移位0位,第四次移位8位,总共10位移位得到a =&#34; 1111 1100 0000 0000&#34;。

我的问题不在于具体的转换操作(也许它是错误的,如果是这样会使用不同的方法,现在我只是好奇如何实现我的想法),我的问题是编写将更新向量的代码然后检查位置向量中的下一个位置。我正在查看有关增量周期和灵敏度列表的内容。 VHDL可能令人困惑,因为您必须通过处理器的操作来描述现实世界。它需要与标准编程不同的思考。

我尝试了下面的代码,但它只在我的测试台上改变和移动一次。我设置了一个测试平台,它贯穿所有位置组合,但是使用下面的代码,它只在pos = 1000处移动,然后它移动了8位。有没有强制代码检查每个if语句,而不仅仅是最后一个?

entity eds_shifter is
port ( a : in bit_vector(15 downto 0) ; --input
    pos : in bit_vector(3 downto 0); -- position
    opc : in bit_vector(3 downto 0); -- opcode
    y : out bit_vector(15 downto 0) --output
    );
end entity eds_shifter ;

architecture behavior of eds_shifter is
begin
process(a,pos,opc) -- input vectors 
begin
   if  pos(0) = '1' and opc = "0000" then  -- shifting left by one
      y <= a(14 downto 0) & "0";
   else
      y <= a;
   end if;
   if  pos(1) = '1' and opc = "0000" then  -- shifting left by two
      y <= a(13 downto 0) & "00";
   else
      y <= a;
   end if; 
   if  pos(2) = '1' and opc = "0000" then  -- shifting left by four
      y <= a(11 downto 0) & "0000";
   else
      y <= a;
   end if;
   if  pos(3) = '1' and opc = "0000" then  -- shifting left by eight
      y <= a(7 downto 0) & "00000000";
   else
      y <= a;
   end if;
end process;

结束架构行为;

试验台

entity eds_shifter_tb is 
end eds_shifter_tb;

architecture behavior of eds_shifter_tb is
    signal opc: bit_vector(3 downto 0);
    signal pos: bit_vector(3 downto 0);
    signal Y : bit_vector (15 downto 0);
    signal a: bit_vector (15 downto 0);

begin 
    dut: entity work.eds_shifter(behavior)
    port map(opc => opc,
            pos => pos,
            Y => Y,
            a => a); -- assigns all ports to entity spec

   a <= (others => '1'),
         (others => '1') after 30 ns;                   
   opc <= "0000",
          "0001" after 30 ns;
   pos <= "0000",
        "0001" after 2 ns,
        "0010" after 4 ns,
        "0011" after 6 ns,
        "0100" after 8 ns,
        "0101" after 10 ns,
        "0110" after 12 ns,
        "0111" after 14 ns,
        "1000" after 16 ns,
        "1001" after 18 ns,
        "1010" after 20 ns,
        "1011" after 22 ns,
        "1100" after 24 ns,
        "1101" after 26 ns,
        "1110" after 28 ns,
        "1111" after 30 ns,
        "0000" after 32 ns,
         "0001" after 34 ns,
         "0010" after 36 ns,
         "0011" after 38 ns,
         "0100" after 40 ns,
         "0101" after 42 ns,
         "0110" after 44 ns,
      "0111" after 46 ns,
      "1000" after 48 ns,
      "1001" after 50 ns,
      "1010" after 52 ns,
      "1011" after 54 ns,
      "1100" after 56 ns,
      "1101" after 58 ns,
      "1110" after 60 ns,
      "1111" after 62 ns;
end behavior;

3 个答案:

答案 0 :(得分:1)

代码中有几个问题:

  • when无法用作顺序语句(正在进行中;在VHDL-2008之前),以及 else部分看起来也像一个语句,语法不正确

  • signal无法在流程中声明

  • signal的新值在可用之前采用增量循环,因此 s*必须位于灵敏度列表中,以便通过

  • 来涟漪
  • VHDL提供了应该使用的标准移位功能,而不是 家庭建设(甚至看起来不对)。请注意,VHDL转移in-fix运算符 (在VHDL-2008之前)已知会产生意外结果,因此请使用这些函数 代替;阅读更多 here

因此,基于此,带有进程的代码可以更新为:

library ieee;
use ieee.numeric_bit.all;

architecture behavior of eds_shifter is
begin
  process(a, pos, opc)                                                   -- input vectors
  begin
    if opc = "0000" then  -- Shift left
      y <= bit_vector(shift_left(unsigned(a), to_integer(unsigned(pos))));
    else  -- Assuming shift right
      y <= bit_vector(shift_right(unsigned(a), to_integer(unsigned(pos))));
    end if;
  end process;
end architecture behavior;

或者使用并发when,可以将过程替换为:

y <= bit_vector(shift_left(unsigned(a), to_integer(unsigned(pos)))) when opc = "0000" else
     bit_vector(shift_right(unsigned(a), to_integer(unsigned(pos))));

注意bit_vector未广泛使用,因此请考虑更新以使用 相反,std_logic_vector代码可以是:

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

entity eds_shifter is
  port (a   : in  std_logic_vector(15 downto 0);  --input
        pos : in  std_logic_vector(3 downto 0);   -- position
        opc : in  std_logic_vector(3 downto 0);   -- opcode
        y   : out std_logic_vector(15 downto 0)   --output
        );
end entity eds_shifter;

architecture behavior of eds_shifter is
begin

  y <= std_logic_vector(shift_left(unsigned(a), to_integer(unsigned(pos)))) when (opc = "0000") else
       std_logic_vector(shift_right(unsigned(a), to_integer(unsigned(pos))));

end architecture behavior;

答案 1 :(得分:1)

我认为您完全没有完全理解硬件描述与编写软件以及流程如何在VHDL中工作的区别。也就是说,您可以使用多个并发分配来执行您想要的操作(级联式桶形移位器)。请参阅以下模型:

-- note, entirely untested!
library ieee;
use ieee.std_logic_1164.all;

entity eds_shifter is
port ( a   : in  std_logic_vector(15 downto 0) ; --input
       pos : in  std_logic_vector(3 downto 0); -- position
       opc : in  std_logic_vector(3 downto 0); -- opcode
       y   : out std_logic_vector(15 downto 0) --output
    );
end entity eds_shifter ;

architecture behavior of eds_shifter is
    signal s1,s2,s3,s4 : std_logic_vector(15 downto 0); -- intermediate steps
begin
    --opcode 0000 is shift left, else is shift right
    s1 <= a(14 downto 0) & '0' when pos(0) = '1' and opc = "0000" else --maybe shift by 1 place
        '0' & a(15 downto 1) when pos(0) = '1' and opc /= "0000" else
        a;

    s2 <= s1(13 downto 0) & "00" when pos(1) = '1' and opc = "0000" else --maybe shift 2 places 
        "00" & s1(15 downto 2) when pos(1) = '1' and opc /= "0000" else
        s1;

    s3 <= s2(11 downto 0) & x"0" when pos(2) = '1' and opc = "0000" else --maybe shift 4 places
        x"0" & s2(15 downto 4) when pos(2) = '1' and opc /= "0000" else
        s2;

    s4 <= s3(7 downto 0) & x"00" when pos(3) = '1' and opc = "0000" else --maybe shift 8 places
        x"00" & s3(15 downto 8) when pos(3) = '1' and opc /= "0000" else
        s3;

    y <= s4;
end architecture behavior;

一般来说,推荐的实现移位的方法仍然使用内置函数,如果优化器正在执行其工作,它们很可能会在合成后变成相同的硬件。虽然这样的练习有助于理解硬件的工作原理,但要意识到这不再有效,而且它作为大型项目的一个小组件是无用的,因为它会增加代码大小并降低可读性而无益。

答案 2 :(得分:0)

在修改过的代码中:

process(a,pos,opc) -- input vectors 
begin
   if  pos(0) = '1' and opc = "0000" then  -- shifting left by one
      y <= a(14 downto 0) & "0";
   else
      y <= a;
   end if;
   if  pos(1) = '1' and opc = "0000" then  -- shifting left by two
      y <= a(13 downto 0) & "00";
   else
      y <= a;
   end if;
...

您正在使用每个新的if块覆盖y的作业。进程中的信号分配已调度,用于进程结束,而不是立即执行。如果您修改了语法并将中间信号添加到敏感列表中,您的原始代码(包含中间信号)将起作用,如Morten建议的那样。或者,您可以使用变量,如下所示(请注意,在此版本中,每个块中的else将是多余的):

process (a, pos, opc)
  variable result : std_logic_vector(15 downto 0);
begin
  result := a;
  if pos(0) = '1' and opc = "0000" then
    result := result(14 downto 0) & '0';
  end if;
  if pos(1) = '1' and opc = "0000" then
    result := result(13 downto 0) & "00";
  end if;
  ...
  y <= result;
end process;

除非你最终想要移植你的移位器,在这种情况下你应该回到中间信号,你还需要管道你的其他输入以匹配。但是,也许我们已经领先于自己......