我来自软件领域,并试图找出如何在VHDL中编码顺序算法。从教科书中可以看出,进程内的语句是按顺序执行的。但我意识到只有变量而不是信号才是真的。在进程内重新发出信号,它们在进程结束时得到更新,并且评估使用右操作数的先前值。所以对于我的理解,它仍然是并发的。出于性能目的,我不能总是使用变量进行复杂计算。
答案 0 :(得分:3)
当您尝试在不同的周期中执行算法的步骤时,您已经意识到过程中的“顺序”构造本身不会这样做 - 事实上,变量没有帮助。顺序程序 - 除非它使用显式的“等待some_event”,例如等待rising_edge(clk) - 将展开并在一个时钟周期内执行。
正如您可能已经发现使用变量,这可能是一个很长的时钟周期。
在VHDL中有三种主要的顺序执行方式,目的不同。
让我们尝试在a和b之间实现线性插值,
a, b, c, x : unsigned(15 downto 0);
x <= ((a * (65536 - c)) + (b * c)) / 65536;
(1)是经典状态机;最好的形式是单一过程SM。 在这里,计算被分解为几个周期,这些周期确保一次最多只有一个乘法正在进行(乘法器很昂贵!)但是C1是并行计算的(加法/减法很便宜!)。它可以安全地用变量而不是中间结果的信号重写。
type state_type is (idle, step_1, step_2, done);
signal state : state_type := idle;
signal start : boolean := false;
signal c1 : unsigned(16 downto 0); -- range includes 65536!
signal p0, p1, s : unsigned(31 downto 0);
process(clk) is
begin
if rising_edge(clk) then
case state is
when idle => if start then
p1 <= b * c;
c1 <= 65536 - c;
state <= step_1;
end if;
when step_1 => P0 <= a * c1;
state <= step_2;
when step_2 => s <= p0 + p1;
state <= done;
when done => x <= s(31 downto 16);
if not start then -- avoid retriggering
state <= idle;
end if;
end case;
end if;
end process;
(2)是Martin Thompson联系的“隐式状态机”(优秀文章!) 与显式状态机相同的备注适用于它。
process(clk) is
begin
if start then
p1 <= b * c;
c1 <= 65536 - c;
wait for rising_edge(clk);
p0 <= a * c1;
wait for rising_edge(clk);
s <= p0 + p1;
wait for rising_edge(clk);
x <= s(31 downto 16);
while start loop
wait for rising_edge(clk);
end loop;
end if;
end process;
(3)是流水线处理器。在这里,执行需要几个周期,但一切都是并行的!管道的深度(循环)允许每个逻辑顺序步骤以顺序方式发生。这允许高性能,因为长链计算被分解为循环大小的步骤......
signal start : boolean := false;
signal c1 : unsigned(16 downto 0); -- range includes 65536!
signal pa, pb, pb2, s : unsigned(31 downto 0);
signal a1 : unsigned(15 downto 0);
process(clk) is
begin
if rising_edge(clk) then
-- first cycle
pb <= b * c;
c1 <= 65536 - c;
a1 <= a; -- save copy of a for next cycle
-- second cycle
pa <= a1 * c1; -- NB this is the LAST cycle copy of c1 not the new one!
pb2 <= pb; -- save copy of product b
-- third cycle
s <= pa + pb2;
-- fourth cycle
x <= s(31 downto 16);
end if;
end process;
在这里,不共享资源;它会使用2个乘数 每个时钟周期有2个乘法。它还将使用更多的寄存器 中间结果和副本。但是,给定每个周期中a,b,c的新值,它将在每个周期吐出一个新结果 - 从输入延迟四个周期。
答案 1 :(得分:1)
大多数多周期算法可以按照您的建议使用FSM,也可以使用流水线逻辑实现。如果算法由严格的顺序步骤(即无循环)组成,则流水线逻辑可能是更好的选择,FSM通常仅用于需要根据输入的不同控制流的更复杂的算法。
流水线逻辑实际上是一个很长的组合逻辑链,它使用寄存器分成多个“阶段”,数据从一个阶段流向另一个阶段。添加寄存器是为了减少每个级(两个寄存器之间)的延迟,允许更高的时钟频率,但代价是延迟增加。但请注意,较高的延迟并不意味着较低的吞吐量,因为新数据可以在前一个数据项完成之前开始处理!对于FSM,这通常是不可能的。
过程中信号分配与架构相反的最大区别在于,您可以在过程中的多个位置为信号分配值,最后一个分配“获胜”。在架构级别,只有一个信号的赋值语句是可能的。许多控制流语句(if,case / when等)也只能在流程中使用,而不能在架构级别使用。