生成语句去抖动器示例
VHDL 中的 generate 语句可以自动将代码块复制到具有相同信号、进程和实例的闭包中。它是架构区域的 for 循环,可以创建链式进程或模块实例。
与只能存在于进程或子程序中的常规 for 循环不同,generate 语句直接放置在 VHDL 文件的体系结构区域中。当与泛型一起使用时,它成为设计可定制 VHDL 模块的强大工具,允许跨设计重用。
生成语句语法
generate语句的语法如下:
[label :] for <constant_name> in <range> generate
[declarations_local_to_each_loop_iteration]
[begin]
<processes_and_instantiations>
end generate [label];
方括号中的部分是可选的。因此,您可以省略声明区域和 begin
如果您不想声明任何本地对象,请使用关键字。 <范围> 占位符使用 to
表示标准整数范围 或 downto
.
一位开关去抖动器
在开始生成语句之前,我将介绍一个简单的模块,我们将在本文中用作示例。它是一款能够对单个开关输入进行去抖动的去抖动器。
为了使其适用于任何时钟速度,我添加了一个名为 timeout_cycles 的通用输入 .此常数指定开关输入更改后超时的时钟周期数。去抖动器将忽略超时期间开关值的任何额外变化。
下面的清单显示了 debouncer 的实体 模块。有一个弹性开关 输入,然后是干净的 switch_debounced 输出。
entity debouncer is generic ( timeout_cycles : positive ); port ( clk : in std_logic; rst : in std_logic; switch : in std_logic; switch_debounced : out std_logic ); end debouncer;
debouncer 模块依靠一个整数计数器来实现超时时间。 计数器的长度 信号遵循通用常数。这就是实例化期间指定的超时持续时间的作用。
因为我们需要读取switch_debounced的值 在内部输出,我声明了一个名为 debounced 的影子信号 ,我们将使用它来代替它。这是一个比其他选项更简洁的解决方案,即设置 inout
switch_debounce 上的模式 在实体中。
最后,我们在单个进程中实现去抖行为,如下代码所示。
architecture rtl of debouncer is signal debounced : std_logic; signal counter : integer range 0 to timeout_cycles - 1; begin -- Copy internal signal to output switch_debounced <= debounced; DEBOUNCE_PROC : process(clk) begin if rising_edge(clk) then if rst = '1' then counter <= 0; debounced <= switch; else if counter < timeout_cycles - 1 then counter <= counter + 1; elsif switch /= debounced then counter <= 0; debounced <= switch; end if; end if; end if; end process; end architecture;
下面的波形显示了 去抖 的模拟 ModelSim 中的模块。我们可以看到 switch_debounced 输出跟随开关 输入,但它忽略了第一次更改后的立即弹跳行为——它消除了信号的抖动。
使用下面的表格从本文下载 VHDL 代码。当您输入您的电子邮件地址时,您将收到一个 Zip 文件,其中包含整个 ModelSim 项目以及测试台和一个快速运行脚本。您将收到来自 VHDLwhiz 的未来更新,您可以随时退订。
使用实例化生成 for 循环
要为一组开关制作去抖器,我们将使用 generate 语句来创建我们的一位去抖器模块的多个实例。
下面的清单显示了我们新的数组或矢量去抖动模块的实体。它类似于一位去抖动器,但还有一个额外的通用输入:switch_count .它指定要创建多少个去抖动模块的实例。每个开关都应该有一个。
此外,我将开关输入和输出重命名为单词的复数形式,它们现在是向量而不是单个位。
entity debouncer_gen_inst is generic ( switch_count : positive; timeout_cycles : positive ); port ( clk : in std_logic; rst : in std_logic; switches : in std_logic_vector(switch_count - 1 downto 0); switches_debounced : out std_logic_vector(switch_count - 1 downto 0) ); end debouncer_gen_inst;
在架构中,是时候使用 generate 语句了。它就像一个常规的 for 循环,只是用“generate”这个词代替了“loop”这个词。但与常规的 for 循环不同,它可以包含模块实例化。
for 循环在编译时运行,并为每次迭代生成一个 debouncer 模块实例。但是因为每次迭代的“i”常数都会不同,我们可以使用它来将去抖动器的输入和输出映射到开关向量上的各个位,如下所示。
architecture rtl of debouncer_gen_inst is begin MY_GEN : for i in 0 to switch_count - 1 generate DEBOUNCER : entity work.debouncer(rtl) generic map ( timeout_cycles => timeout_cycles ) port map ( clk => clk, rst => rst, switch => switches(i), switch_debounced => switches_debounced(i) ); end generate; end architecture;
请注意,标记生成语句是可选的,但这样做可能是明智的。标签出现在模拟器层次结构和综合日志中,便于在调试时识别具体实例。
下面的波形显示了矢量去抖动器的仿真。我们可以看到“MY_GEN”标签再次出现在这里,并为八个去抖动器实例中的每一个添加了索引。
这个测试台只改变了开关号 3 的输入,这就是你在波形中看到的,也是我只扩展 MY_GEN(3) 组的原因。
如果您安装了 ModelSim,您可以在您的计算机上快速运行此示例。使用下表下载源代码和ModelSim工程!
生成包含进程的 for 循环
在本文的最后一个示例中,我们将使用生成语句来执行一系列相同的过程。我没有创建一位去抖动模块的实例,而是从中提取了 VHDL 代码。实体和前面的例子一样,行为也一样,但实现不同。
我们可以看到我已经在 generate 语句中移动了 DEBOUNCE_PROC 进程,并在下面的代码中对其进行了轻微更改。这次我在 generate 语句中声明了两个本地信号:debounced 和反 .
for 循环的每次迭代都将创建信号和过程的附加副本。在流程中使用这些信号名称将引用范围为该特定循环迭代的外壳的信号名称。
最后,我分配了 debounced std_logic
信号到 switches_debounced 的正确位 模块输出使用进程之上的并发语句。
architecture rtl of debouncer_gen_proc is begin MY_GEN : for i in 0 to switch_count - 1 generate signal debounced : std_logic; signal counter : integer range 0 to timeout_cycles - 1; begin switches_debounced(i) <= debounced; DEBOUNCE_PROC : process(clk) begin if rising_edge(clk) then if rst = '1' then counter <= 0; debounced <= switches(i); else if counter < timeout_cycles - 1 then counter <= counter + 1; elsif switches(i) /= debounced then counter <= 0; debounced <= switches(i); end if; end if; end if; end process; end generate; end architecture;
我省略了仿真波形,因为它看起来与前面使用模块实例化的示例完全相同。行为是相同的。
您可以使用下面的表格下载所有代码。当您输入您的电子邮件地址时,您订阅了来自 VHDLwhiz 的更新。不过不用担心,我发送的每封电子邮件中都有一个退订链接。
如果您有另一个有用的应用程序来分享生成语句,请在下面发表评论! ?
VHDL