2

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

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

我正在使用位置向量以某种方式设置移位“级别”。我想检查位置(0),如果它设置为 1,则移动一个位置。然后检查 position(1) 和 shift 2 个位置, position(3) 4 个位置和 position(3) 8 个位置。

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

我坚持为架构分配中间向量。我不确定正确的方法应该是什么,我在谷歌中找不到任何东西。也许案例系统会更好地工作。

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 = "1111 1111 1111 1111" 和 pos = "1010" 所以我们需要移动小数点后 10 位。所以我们进行第一次迭代,它没有变化,第二次移动 2 位,第三次迭代移动 0 位,第四次移动 8 位,总共移动 10 位得到 a="1111 1100 0000 0000" .

我的问题不在于特定的移位操作(也许它是错误的,如果是这样将使用不同的方法,现在我只是好奇如何实现我的想法),我的问题是编写将更新向量然后检查的代码位置向量中的下一个位置。我正在查看您发布的有关增量周期和敏感度列表的内容。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;
4

3 回答 3

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;

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

于 2014-05-28T15:08:43.060 回答
1

代码中有几个问题:

  • when不能用作顺序语句(在处理中;在 VHDL-2008 之前),并且该else部分也看起来像一个语句,这是不正确的语法

  • signal不能在进程中声明

  • a 的新值signal在可用之前需要一个增量周期,因此s*必须在敏感度列表中才能使值通过

  • VHDL 提供了应该使用的标准移位函数,而不是家庭构建(甚至看起来错误)。请注意,已知 VHDL shift in-fix 运算符(在 VHDL-2008 之前)会产生意想不到的结果,因此请改用这些函数;在这里阅读更多 。

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

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;

或使用 concurrent when,则 process 可以替换为:

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;
于 2014-05-27T14:52:37.880 回答
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;
...

y您正在使用每个新的 if 块覆盖分配。进程中的信号分配被安排在进程结束时,而不是立即执行。如果您按照 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;

除非您最终想要对移位器进行流水线化,在这种情况下,您应该返回中间信号,并且您还需要对其他输入进行流水线化以匹配。但也许我们正在超越自己......

于 2014-05-28T14:05:11.130 回答