编码

此示例是一系列 3 中的第二个。如果你还没有,请首先阅读方框图示例。

使用符合 10 条规则的框图 (参见框图示例),VHDL 编码变得简单明了:

  • 大的周围矩形成为 VHDL 实体,
  • 内部箭头成为 VHDL 信号并在架构中声明,
  • 每个方块都成为架构体中的同步过程,
  • 每个圆形块都成为体系结构体中的组合过程。

让我们在时序电路的框图中说明这一点:

StackOverflow 文档

电路的 VHDL 模型包括两个编译单元:

  • 描述电路名称及其接口的实体(端口名称,方向和类型)。它是程序框图的大周围矩形的直接平移。假设数据是整数,并且 clock 使用 VHDL 类型 bit(仅两个值:'0''1'),我们的时序电路的实体可以是:
entity sequential_circuit is
  port(
    Data_in:  in  integer;
    Clock:    in  bit;
    Data_out: out integer
  );
end entity sequential_circuit;
  • 描述电路内部的架构(它的作用)。这是声明内部信号的位置以及实例化所有进程的位置。我们的时序电路架构的骨架可以是:
architecture ten_rules of sequential_circuit is
  signal Sum, Next_sum: integer;
begin
  <...processes...>
end architecture ten_rules;

我们有三个过程添加到架构主体,一个同步(方块)和两个组合(圆块)。

同步过程如下所示:

process(clock)
begin
  if rising_edge(clock) then
    o1 <= i1;
    ...
    ox <= ix;
  end if;
end process;

其中 i1, i2,..., ix所有即进入图的相应的正方形块和 o1, ..., ox 是箭头所有的箭输出图表的对应的正方形块。当然,除了信号的名称外,绝对不会改变任何东西。没有。甚至不是一个角色。

因此,我们的例子的同步过程是:

  process(clock)
  begin
    if rising_edge(clock) then
      Sum <= Next_sum;
    end if;
  end process;

这可以非正式地翻译成:如果 clock 发生变化,只有这样,如果变化是上升沿('0''1'),则将信号 Next_sum 的值赋给信号 Sum

组合过程如下所示:

process(i1, i2,... , ix)
  variable v1: <type_of_v1>;
  ...
  variable vy: <type_of_vy>;
begin
  v1 := <default_value_for_v1>;
  ...
  vy := <default_value_for_vy>;
  o1 <= <default_value_for_o1>;
  ...
  oz <= <default_value_for_oz>;
  <statements>
end process;

其中 i1, i2,..., in 是进入图表相应圆块的所有箭头。一切都没有了。我们不会忘记任何箭头,我们不会在列表中添加任何其他内容。

v1, ..., vy 是我们可能需要简化过程代码的变量。它们与任何其他命令式编程语言具有完全相同的角色:保留临时值。在阅读之前必须完全分配它们。如果我们不能保证这一点,那么该过程将不再是组合的,因为它将对存储器元素的类型进行建模,以保留从一个流程执行到下一个流程执行的某些变量的值。这就是该过程开始时 vi := <default_value_for_vi> 语句的原因。请注意,<default_value_for_vi> 必须是常量。如果不是,如果它们是表达式,我们可能会意外地在表达式中使用变量并在分配变量之前读取变量。

o1, ..., om所有的箭输出的图表的相应的圆形块。一切都没有了。在流程执行期间,它们必须至少分配一次。由于 VHDL 控制结构(ifcase ……)可以非常容易地防止输出信号被分配,我们强烈建议在过程开始时无条件地为它们分配恒定值 <default_value_for_oi>。这样,即使 if 语句屏蔽了信号分配,它也会收到一个值。

除了变量的名称(如果有的话),输入的名称,输出的名称,<default_value_for_..> 常量和 <statements> 的值之外,绝对不能将任何内容更改为此 VHDL 框架。千万不能忘了一个默认值分配,如果你做的合成将推断不必要的存储元件(最有可能的锁存器),结果不会是你最初想什么。

在我们的示例时序电路中,组合加法器过程是:

  process(Sum, Data_in)
  begin
    Next_sum <= 0;
    Next_sum <= Sum + Data_in;
  end process;

这可以非正式地翻译成:如果 SumData_in(或两者)改变将值 0 分配给信号 Next_sum 然后再分配值 Sum + Data_in

由于第一个赋值(具有常量默认值 0)紧接着是另一个覆盖它的赋值,我们可以简化:

  process(Sum, Data_in)
  begin
    Next_sum <= Sum + Data_in;
  end process;

第二个组合过程对应于我们在具有多个目标的输出箭头上添加的圆形块,以符合 2008 之前的 VHDL 版本。其代码很简单:

  process(Sum)
  begin
    Data_out <= 0;
    Data_out <= Sum;
  end process;

出于与其他组合过程相同的原因,我们可以将其简化为:

  process(Sum)
  begin
    Data_out <= Sum;
  end process;

时序电路的完整代码是:

-- File sequential_circuit.vhd
entity sequential_circuit is
  port(
    Data_in:  in  integer;
    Clock:    in  bit;
    Data_out: out integer
  );
end entity sequential_circuit;

architecture ten_rules of sequential_circuit is
  signal Sum, Next_sum: integer;
begin
  process(clock)
  begin
    if rising_edge(clock) then
      Sum <= Next_sum;
    end if;
  end process;

  process(Sum, Data_in)
  begin
    Next_sum <= Sum + Data_in;
  end process;

  process(Sum)
  begin
    Data_out <= Sum;
  end process;
end architecture ten_rules;

注意:我们可以按任何顺序编写这三个过程,它不会改变模拟或综合中的最终结果。这是因为三个进程是并发语句,VHDL 将它们视为真正并行。