【问题标题】:bubble sort in vhdlvhdl中的冒泡排序
【发布时间】:2017-02-26 05:50:41
【问题描述】:

在给定一组数据作为输入的情况下,谁能帮我编写用于冒泡排序的 VHDL 代码?

我已将 in_array 声明为包含 15 个数组元素的输入。我想按降序对它们进行冒泡排序。

in_array 是输入数组。 sorted_array 是输出数组。 in_array_sig 是 in_array 类型的信号

我遇到了进程内部语句的问题

下面是我的代码:

architecture behav of Bubblesort is
  signal in_array_sig : bubble;
  signal temp : std_logic_vector(3 downto 0);
  signal i : integer := 0;
begin

  in_array_sig <= in_array;

  proc1 : process(clk, reset)
  begin
    if reset = '0' then
      if (clk'event and clk = '1') then
        while (i <= 15) loop
          if (in_array_sig(i) < in_array_sig(i + 1)) then
            temp <= in_array_sig(i);
            in_array_sig(i) <= in_array_sig(i + 1);
            in_array_sig(i + 1) <= temp;
          end if;
          i <= i + 1;
        end loop;
      end if;
    end if;
  end process;

  sorted_array <= in_array_sig;

end behav;

我是 VHDL 编码的初学者。请帮我解决这个问题。

【问题讨论】:

  • “我遇到问题”:请描述问题。
  • 您需要描述问题所在,正如@scary_jeff 所说。但是,我确实立即看到了一个:您在此行中分配给temp temp &lt;= in_array_sig(i);,然后在此行后面的两行中使用temp 的值in_array_sig(i + 1) &lt;= temp;。这不会像你想象的那样做。 tempsignal;因此,在进程暂停(到达底部)之前不会更新它。因此,您可以只写:in_array_sig(i) &lt;= in_array_sig(i + 1); 紧跟 in_array_sig(i + 1) &lt;= in_array_sig(i); i 将不会像您预期的那样运行。
  • 您还需要考虑您期望的硬件,特别是您期望排序需要多少时钟周期。
  • How to create a Minimal, Complete, and Verifiable example。一个 MCVE 可以从你的架构中重建,除了问题的描述:“它不起作用”不是问题陈述。告诉我们预期的行为应该是什么。 Matthew 描述了模拟周期中信号更新的影响,请参阅process statement in vhdl。除了将 temp 设为在 process 语句中声明的变量之外,还有其他一些事情需要改变。
  • 嗨,马修,感谢您提供上述信息。

标签: process vhdl


【解决方案1】:

缺少Minimal Complete and Verifiable example 使得很难就阻止代码准确冒泡排序的所有问题提供答案。这些可以按照您在故障排除时遇到的顺序进行描述。

  proc1 : process(clk, reset)
  begin
    if reset = '0' then
      if (clk'event and clk = '1') then
        while (i <= 15) loop
          if (in_array_sig(i) < in_array_sig(i + 1)) then
            temp <= in_array_sig(i);
            in_array_sig(i) <= in_array_sig(i + 1);
            in_array_sig(i + 1) <= temp;
          end if;
          i <= i + 1;
        end loop;
      end if;
    end if;
  end process;

在开始之前,请注意时钟是通过复位门控的。您可以使用重置来限定分配,使其成为启用。

问题

我们会发现生成 MCVe 和测试台的第一件事是进程永远不会暂停。这是由 while 循环中的条件引起的,具体取决于 i 和 i 在进程中更新的信号。我在这里不应该是一个信号(或者你可以在这里使用一个 for 循环)。

这也指出 temp 是一个信号并且遇到同样的问题,在进程暂停和恢复之前,您不能使用 temp 的“新”值。信号被安排更新,没有包含 after 子句的波形元素的信号分配具有零延迟的隐式 after 子句。当任何计划恢复的进程尚未恢复并随后暂停时,不会发生信号更新。这允许在顺序语句中找到分配的信号的并发性(并发语句具有包含等效顺序语句的等效过程)。所以 i 和 temp 在执行一系列语句的过程中都不能更新,并且都想成为变量。

使用 in_array_sig 的信号我们也会被咬。当您增加 i 时,先前索引的 in_array_sig(i + 1) 将成为下一个循环迭代的 in_array_sig(i)。如果没有中间进程挂起和恢复,原始值是可用的。 in_array_sig 也想成为一个变量。

如果我们要修复所有这些问题,我们可能还会注意到 i 未初始化(这将在 for 循环迭代方案中处理)并且我们还可能会发现在一行中使用in_array_sig 的 (i + 1) 索引。如果问题的作者没有提供 MCVe,则不清楚数组大小是 16(编号为 0 到 15)还是 17。如果前者 i = 15 + 1 将超出 in_array 的未公开数组类型的索引范围, in_array_sig 和 sorted_array。

如果我们要确保满足索引范围,并注意到我们只需要比数组中的元素数量少 1 次测试和交换,我们会发现该过程不是完整的冒泡排序。我们会看到 in_array_sig 的最大二进制值最终成为 sorted_array 最右边的元素。但是不能保证剩余元素的顺序。

要执行完整的冒泡排序,我们需要另一个循环嵌套第一个循环。此外,现在的“内部” for 循环可以减少要遍历的元素数量,因为每次迭代都会在最右边留下一个最大的剩余元素,直到确保订单完成为止。

修复

修复上述问题会给我们带来如下所示的内容:

architecture foo of bubblesort is
    use ieee.numeric_std.all;
begin

BSORT:
    process (clk)
        variable temp:      std_logic_vector (3 downto 0);
        variable var_array:     bubble;        
    begin
        var_array := in_array;
        if rising_edge(clk) then
            for j in bubble'LEFT to bubble'RIGHT - 1 loop 
                for i in bubble'LEFT to bubble'RIGHT - 1 - j loop 
                    if unsigned(var_array(i)) > unsigned(var_array(i + 1)) then
                        temp := var_array(i);
                        var_array(i) := var_array(i + 1);
                        var_array(i + 1) := temp;
                    end if;
                end loop;
            end loop;
            sorted_array <= var_array;
        end if;
    end process;
end architecture foo;

注意循环迭代方案是根据气泡边界类型来描述的,对于每次迭代,外部比长度短一个,内部比长度短一个。另请注意, sorted_array 分配已移至 in_array_sig 变量替换 var_array 可见的过程中。

另外值得注意的是无符号大于运算符的使用。 std_logic_vector 的“>”允许元值和“H”和“L”值扭曲关系比较,而无符号运算符是算术。

结果

引入包和实体声明:

library ieee;
use ieee.std_logic_1164.all;

package array_type is
    type bubble is array (0 to 15) of std_logic_vector(3 downto 0);
end package;

library ieee;
use ieee.std_logic_1164.all;
use work.array_type.all;

entity bubblesort is
    port (
        signal clk:             in  std_logic;
        signal reset:           in  std_logic;
        signal in_array:        in  bubble;
        signal sorted_array:    out bubble 
    );
end entity;

连同一个测试台:

library ieee;
use ieee.std_logic_1164.all;
use work.array_type.all;

entity bubblesort_tb is
end entity;

architecture fum of bubblesort_tb is
    signal clk:             std_logic := '0';
    signal reset:           std_logic := '0';
    signal in_array:        bubble :=
                   (x"F", x"E", x"D", x"C", x"B", x"A", x"9", x"8",
                    x"7", x"6", x"5", x"4", x"3", x"2", x"1", x"0");
    signal sorted_array:    bubble;
begin

DUT:
    entity work.bubblesort(foo)
        port map (
            clk => clk,
            reset => reset,
            in_array => in_array,
            sorted_array => sorted_array
        );
CLOCK:
    process
    begin
        wait for 10 ns;
        clk <= not clk;
        if now > 30 ns then
            wait;
        end if;
    end process;

end architecture;

我们得到:

有效的东西。

reset as enable 未包含在架构中的进程 BSORT 中,可以添加到带有时钟沿条件的 if 语句中。

关于这里,我们在关于描述硬件的评论中谈到了 Matthew Taylor 的观点。

根据合成工具的不同,该过程可能会或可能不会作为硬件实现。如果不是,则需要中间变量来保存内部循环的每次连续迭代中使用的数组部分。

还有一个时钟周期可以做多少的问题。最坏的情况是延迟深度由 15 个元素比较和 15 个 2:2 选择器有条件地交换元素对组成。

如果您要选择与合成延迟不兼容的时钟速度,您需要将实现从软件循环仿真重新架构为跨连续时钟运行的东西。

这可能就像允许更多时钟周期一样简单,通过使用该启用来确定冒泡排序何时有效加载到 sorted_array 寄存器。它可能更复杂,还允许使用不同且性能更好的排序方法,或者对冒泡排序进行修改以表示不再需要检测交换。

【讨论】:

  • 您好 user1155120。非常感谢您的宝贵时间。我会听从你的指示。我从你的回答中学到了一些重要的概念。我真的很感谢你的帮助。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2013-10-09
  • 2017-03-11
  • 2015-09-12
  • 2014-02-25
  • 2012-02-09
  • 2013-10-16
  • 1970-01-01
相关资源
最近更新 更多