VHDL - 使用泛型添加/删除管道寄存器
假设我有两个进程 PROC_A
和 PROC_B
,它们之间共享一个信号。让我写一个虚拟示例:
library ieee;
use ieee.std_logic_1164.all;
entity example is
port (
clk : in std_logic;
rst_n : in std_logic;
a : in std_logic;
b : in std_logic;
c : in std_logic;
z_out : out std_logic);
end entity example;
architecture rtl of example is
signal a_and_b : std_logic;
signal ab_xor_c : std_logic;
begin -- architecture rtl
z_out <= ab_xor_c;
PROC_A : process (clk, rst_n) is
begin -- process PROC_A
if rst_n = '0' then -- asynchronous reset (active low)
a_and_b <= '0';
elsif rising_edge(clk) then -- rising clock edge
a_and_b <= a and b;
end if;
end process PROC_A;
PROC_B : process (clk, rst_n) is
begin -- process PROC_B
if rst_n = '0' then -- asynchronous reset (active low)
ab_xor_c <= '0';
elsif rising_edge(clk) then -- rising clock edge
ab_xor_c <= a_and_b xor c;
end if;
end process PROC_B;
end architecture rtl;
现在,我想在 a_and_b 和 ab_xor_c 信号之间有一个管道寄存器,我想对其进行硬编码,但也可以轻松启用/禁用它。我真的想要一些类似 C/C++
中的 ifdef
的东西。我可以想到一个通用的方法来做到这一点,但我也对任何其他方法持开放态度(也许使用编译指示?)。我在下面写了一个例子,我知道它在 VHDL 方面是错误的,但只是将其视为一个想法:
library ieee;
use ieee.std_logic_1164.all;
entity example is
generic (
PIPELINE_EN : std_logic := '1');
port (
clk : in std_logic;
rst_n : in std_logic;
a : in std_logic;
b : in std_logic;
c : in std_logic;
z_out : out std_logic);
end entity example;
architecture rtl of example is
signal a_and_b : std_logic;
signal ab_xor_c : std_logic;
if PIPELINE_EN = '1' then
signal pipeline_reg : std_logic;
end if;
begin -- architecture rtl
z_out <= ab_xor_c;
PROC_A : process (clk, rst_n) is
begin -- process PROC_A
if rst_n = '0' then -- asynchronous reset (active low)
a_and_b <= '0';
elsif rising_edge(clk) then -- rising clock edge
a_and_b <= a and b;
end if;
end process PROC_A;
PROC_B : process (clk, rst_n) is
begin -- process PROC_B
if rst_n = '0' then -- asynchronous reset (active low)
ab_xor_c <= '0';
if PIPELINE_EN = '1' then
pipeline_reg <= '0'
end if;
elsif rising_edge(clk) then -- rising clock edge
if PIPELINE_EN = '1' then
pipeline_reg <= a_and_b;
ab_xor_c <= pipeline_reg xor c;
else
ab_xor_c <= a_and_b xor c;
end if;
end if;
end process PROC_B;
end architecture rtl;
Let's assume I have two processes PROC_A
and PROC_B
, and they share a signal between them. Let me write a dummy example:
library ieee;
use ieee.std_logic_1164.all;
entity example is
port (
clk : in std_logic;
rst_n : in std_logic;
a : in std_logic;
b : in std_logic;
c : in std_logic;
z_out : out std_logic);
end entity example;
architecture rtl of example is
signal a_and_b : std_logic;
signal ab_xor_c : std_logic;
begin -- architecture rtl
z_out <= ab_xor_c;
PROC_A : process (clk, rst_n) is
begin -- process PROC_A
if rst_n = '0' then -- asynchronous reset (active low)
a_and_b <= '0';
elsif rising_edge(clk) then -- rising clock edge
a_and_b <= a and b;
end if;
end process PROC_A;
PROC_B : process (clk, rst_n) is
begin -- process PROC_B
if rst_n = '0' then -- asynchronous reset (active low)
ab_xor_c <= '0';
elsif rising_edge(clk) then -- rising clock edge
ab_xor_c <= a_and_b xor c;
end if;
end process PROC_B;
end architecture rtl;
Now, I want to have a pipeline register between a_and_b
and ab_xor_c
signals, and I want to hardcode it but also enable/disable it with ease. I really want something like a ifdef
in C/C++
. I could think of a generic to do that but I am also open to any other method (maybe with pragmas?). I am writing an example below, I know that it is so wrong in terms of VHDL but just see it as an idea:
library ieee;
use ieee.std_logic_1164.all;
entity example is
generic (
PIPELINE_EN : std_logic := '1');
port (
clk : in std_logic;
rst_n : in std_logic;
a : in std_logic;
b : in std_logic;
c : in std_logic;
z_out : out std_logic);
end entity example;
architecture rtl of example is
signal a_and_b : std_logic;
signal ab_xor_c : std_logic;
if PIPELINE_EN = '1' then
signal pipeline_reg : std_logic;
end if;
begin -- architecture rtl
z_out <= ab_xor_c;
PROC_A : process (clk, rst_n) is
begin -- process PROC_A
if rst_n = '0' then -- asynchronous reset (active low)
a_and_b <= '0';
elsif rising_edge(clk) then -- rising clock edge
a_and_b <= a and b;
end if;
end process PROC_A;
PROC_B : process (clk, rst_n) is
begin -- process PROC_B
if rst_n = '0' then -- asynchronous reset (active low)
ab_xor_c <= '0';
if PIPELINE_EN = '1' then
pipeline_reg <= '0'
end if;
elsif rising_edge(clk) then -- rising clock edge
if PIPELINE_EN = '1' then
pipeline_reg <= a_and_b;
ab_xor_c <= pipeline_reg xor c;
else
ab_xor_c <= a_and_b xor c;
end if;
end if;
end process PROC_B;
end architecture rtl;
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
您的示例已被修改以从进程 A 中删除寄存器并显示控制寄存器存在的通用方法。一般也可以添加额外的流水线寄存器。
使用生成语句的粒度是并发语句。为了更改信号名称,您可以在由生成语句的块声明区域详细说明的块语句中声明中间信号。生成语句可以嵌套(它是并发语句),可用于添加更多管道寄存器。
生成语句主体可以在块语句主体中的任何并发语句之前具有块声明部分。当块声明部分中存在任何声明时,并发语句由保留字 begin 和 end 描述,后跟分号。例如 IEEE Std 10786-2008:
11.8 生成语句
上述VHDL代码中的generate语句没有声明。括起项目
concurrent_statement
的大括号 { } 表示您可以使用带有 begin 和 end 保留字的“长格式”以及零个或多个并发语句。您将声明用于在同一设计层次结构中的不同生成语句中找到的语句之间进行通信的任何中间信号。 (由生成语句详细说明的块语句是一个单独的声明区域。)在标准的编号部分中找到的 BNF 是规范性的。
请注意,您没有分配
z_out
。这是一个与OP代码兼容的示例:
它产生:
并使用自然通用管道显示两个时钟延迟。
PIPELINES = 1:
信号 a_and_b 和 a_xor_b 提前一个时钟出现。它与本答案中的第一个 VHDL 示例兼容,其中 PIPELINED = TRUE。
请注意,块声明部分包含管道阶段的复合信号声明。生成语句是它自己的声明区域,这意味着 pipeline_reg 在详细块之外不可见。要访问中间管道阶段,您可以将 pipeline_reg 声明移动到顶层(此处为 example1),或者分配在生成语句中分配的顶层中声明的信号。
Your example has been modified to removed the register from process A and show a generic controlling the presence of the register. Additional pipeline registers could be added generically as well.
The granularity using a generate statement is to a concurrent statement. For purposes of changing signal names you can declare intermediary signals in the block statement elaborated by the generate statement's block declarative region. Generate statements can be nested (it's a concurrent statement) which can be used to add more pipeline registers.
A generate statement body can have a block declarative part prior to any concurrent statements in the block statement body. Concurrent statements are delineated by the reserved words begin and end followed by a semicolon when any declarations are present in the block declarative part. E.g. IEEE Std 10786-2008:
11.8 Generate statements
The generate statements in the above VHDL code have no declarations. Braces { } enclosing the item
concurrent_statement
indicate you can use the 'long form' with the begin and end reserved words with zero or more concurrent statements. You'd declare any intermediary signals used to communicate between statements found in different generate statements in the same design hierarchy. (The block statement elaborated by a generate statement is a separate declarative region.)The BNF found in the standard's numbered sections is normative.
Note you didn't assign
z_out
.Here's an example compatible with the OP's code:
which produces:
And shows the two clock delays using natural generic PIPELINES.
With PIPELINES = 1:
The signals a_and_b and a_xor_b show up one clock earlier. It's compatible with the first VHDL example in this answer with PIPELINED = TRUE.
Note the block declarative part contains a composite signal declaration for the pipeline stages. A generate statement is it's own declarative region which means pipeline_reg wouldn't be visible outside the elaborated block. To access intermediary pipeline stages you'd either move the pipeline_reg declaration to the top level (example1, here) or assign signals declared in the top level assigned in the generate statement.
您编写的设计中的原理很好,除了
如果pipeline_en ='1',则
在声明pipeline_reg
中应跳过,因为合成将然后只需删除未使用的pipeline_reg
。另外,我建议将pipeline_en
声明为boolean
,因为这是一个更明显的选择,='1'
可以然后可以在条件下跳过。如果由于某种原因您想避免在实际设计中声明管道信号'pipeline_reg',则可以在过程中声明一个变量,如以下代码。在代码中使用后,需要分配变量,以获取触发器,因为否则它只是成为组合逻辑。但是,建议通过使用变量来创建触发器,因为很难读取和正确地读取和正确,因此容易出错,并且应该避免使用。虽然来了:
一种替代方法是使用VHDL
block
构造,以及Generate
,您可以拥有Signal> Signal> Signal
声明,这些声明是本地的块,如下所示。尽管请注意,Block
构造很少在VHDL中使用,因此在工具中遇到错误的风险更高。Principles in the design you wrote are fine, except for the
if PIPELINE_EN = '1' then
part in the declaration ofpipeline_reg
, which should be skipped, since the synthesis will then just remove the unusedpipeline_reg
. Also I would suggest thatPIPELINE_EN
is declared as typeboolean
instead, since that is a more obvious choice, and the= '1'
can then be skipped in the conditions.If for some reason you want to avoid declaration of the pipeline signal 'pipeline_reg' in the actual design, then you can declare a variable in the process, with code like below. It is required to assign the variable after use in the code, to get a flip-flop, since it otherwise just becomes combinatorial logic. However, such creation of flip-flops through use of variables is advised against, since it is hard to read and get right, thus error prone, and should be avoided in general. Though here it comes:
An alternative is to use the VHDL
block
construction, together withgenerate
, whereby you can havesignal
declarations that are local to the block, as shown below. Though note that theblock
construction is rarely used in VHDL, thus there is a higher risk of encountering bugs in tools.使用管道深度的通用参数:
然后使用
深度=2
:演示:
当然,如果你的数据类型(
T
)更多比单一复杂std_logic
您将需要一些额外的工作。T_vector
)。T_zero
),这将是向右移动时在左侧输入的值。T_vector
向量类型的srl
运算符。T
类型的示例(未测试):With a generic parameter for the pipeline depth:
And then, with
depth=2
:Demo:
Of course, if your data type (
T
) is more complex than a singlestd_logic
you will need some extra work.T_vector
).T_zero
), this will be the value that enters on the left when shifting to the right.srl
operator for theT_vector
vector type.Example with a
T
type (not tested):