VHDL - 使用泛型添加/删除管道寄存器

发布于 2025-01-19 07:39:13 字数 2716 浏览 0 评论 0原文

假设我有两个进程 PROC_APROC_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 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

帅冕 2025-01-26 07:39:13

您的示例已被修改以从进程 A 中删除寄存器并显示控制寄存器存在的通用方法。一般也可以添加额外的流水线寄存器。

library ieee;
use ieee.std_logic_1164.all;

entity example is

    generic ( PIPELINED:    BOOLEAN := TRUE);
    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 genericly_pipelined of example is
    signal a_and_b:   std_logic;
    signal ab_xor_c:  std_logic;
begin
NO_PIPELINE:
    if not PIPELINED generate
PROC_A:
        process (a, b) is
        begin
            a_and_b <= a and b;  -- could be a concurrent statement instead
        end process;
    end generate;

GEN_PIPELINED:
    if PIPELINED generate
PIPELINED_PROC_A: 
    process (clk, rst_n) is
        begin
            if rst_n = '0' then
                a_and_b <= '0';
            elsif rising_edge(clk) then
                a_and_b <= a and b;
            end if;
        end process;
    end generate;

PROC_B:
    process (clk, rst_n) is
    begin
        if rst_n = '0' then
            ab_xor_c <= '0';
        elsif rising_edge(clk) then
            ab_xor_c <= a_and_b xor c;
        end if;
    end process;

end architecture genericly_pipelined;

使用生成语句的粒度是并发语句。为了更改信号名称,您可以在由生成语句的块声明区域详细说明的块语句中声明中间信号。生成语句可以嵌套(它是并发语句),可用于添加更多管道寄存器。

生成语句主体可以在块语句主体中的任何并发语句之前具有块声明部分。当块声明部分中存在任何声明时,并发语句由保留字 beginend 描述,后跟分号。例如 IEEE Std 10786-2008:

11.8 生成语句

if_generate_statement ::=
    generate_label :
       if [ alternative_label : ] 条件生成
         generate_statement_body
        { elsif [ alternative_label : ] 条件生成
         generate_statement_body }
       [ 其他 [ 替代_label : ] 生成
         generate_statement_body]
    结束生成 [ 生成_label ] ;

generate_statement_body ::=
       [ block_declarative_part
    开始]
       {并发语句}
    [ 结束 [ 替代_label ] ; ]

上述VHDL代码中的generate语句没有声明。括起项目 concurrent_statement 的大括号 { } 表示您可以使用带有 beginend 保留字的“长格式”以及零个或多个并发语句。您将声明用于在同一设计层次结构中的不同生成语句中找到的语句之间进行通信的任何中间信号。 (由生成语句详细说明的块语句是一个单独的声明区域。)

在标准的编号部分中找到的 BNF 是规范性的。

请注意,您没有分配 z_out

这是一个与OP代码兼容的示例:

library ieee;
use ieee.std_logic_1164.all;

entity example1 is

    generic ( PIPELINES:    natural := 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 example1;

architecture generic_pipeline_stages of example1 is
    signal a_and_b:   std_logic;
    signal ab_xor_c:  std_logic;
begin
NO_PIPELINE:
    if PIPELINES = 0 generate
PROC_A:
        process (a, b) is
        begin
            a_and_b <= a and b;  -- could be a concurrent statement instead
        end process;
    end generate;

GEN_PIPELINED:
    if PIPELINES > 0 generate
        type pipeline is array (0 to PIPELINES - 1) of std_logic;
        signal pipeline_reg:  pipeline;
    begin
PIPELINED_PROC_A: 
        process (clk, rst_n) is
            begin
                if rst_n = '0' then
                    pipeline_reg <= (others => '0');
                elsif rising_edge(clk) then
                    for i in pipeline'range loop
                        if i = 0 then
                            pipeline_reg(i) <= a and b;
                        else
                            pipeline_reg(i) <= pipeline_reg(i - 1);
                        end if;
                    end loop;
                end if;
            end process;
            a_and_b <= pipeline_reg(PIPELINES - 1); -- a separate process
    end generate;

PROC_B:
    process (clk, rst_n) is
    begin
        if rst_n = '0' then
            ab_xor_c <= '0';
        elsif rising_edge(clk) then
            ab_xor_c <= a_and_b xor c;
        end if;
    end process;

end architecture generic_pipeline_stages;

它产生:

example1_pipelines_equal2.jpg

并使用自然通用管道显示两个时钟延迟。

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.

library ieee;
use ieee.std_logic_1164.all;

entity example is

    generic ( PIPELINED:    BOOLEAN := TRUE);
    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 genericly_pipelined of example is
    signal a_and_b:   std_logic;
    signal ab_xor_c:  std_logic;
begin
NO_PIPELINE:
    if not PIPELINED generate
PROC_A:
        process (a, b) is
        begin
            a_and_b <= a and b;  -- could be a concurrent statement instead
        end process;
    end generate;

GEN_PIPELINED:
    if PIPELINED generate
PIPELINED_PROC_A: 
    process (clk, rst_n) is
        begin
            if rst_n = '0' then
                a_and_b <= '0';
            elsif rising_edge(clk) then
                a_and_b <= a and b;
            end if;
        end process;
    end generate;

PROC_B:
    process (clk, rst_n) is
    begin
        if rst_n = '0' then
            ab_xor_c <= '0';
        elsif rising_edge(clk) then
            ab_xor_c <= a_and_b xor c;
        end if;
    end process;

end architecture genericly_pipelined;

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

if_generate_statement ::=
    generate_label :
        if [ alternative_label : ] condition generate
            generate_statement_body
        { elsif [ alternative_label : ] condition generate
            generate_statement_body }
        [ else [ alternative_label : ] generate
            generate_statement_body ]
    end generate [ generate_label ] ;

generate_statement_body ::=
        [ block_declarative_part
    begin ]
        { concurrent_statement }
    [ end [ alternative_label ] ; ]

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:

library ieee;
use ieee.std_logic_1164.all;

entity example1 is

    generic ( PIPELINES:    natural := 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 example1;

architecture generic_pipeline_stages of example1 is
    signal a_and_b:   std_logic;
    signal ab_xor_c:  std_logic;
begin
NO_PIPELINE:
    if PIPELINES = 0 generate
PROC_A:
        process (a, b) is
        begin
            a_and_b <= a and b;  -- could be a concurrent statement instead
        end process;
    end generate;

GEN_PIPELINED:
    if PIPELINES > 0 generate
        type pipeline is array (0 to PIPELINES - 1) of std_logic;
        signal pipeline_reg:  pipeline;
    begin
PIPELINED_PROC_A: 
        process (clk, rst_n) is
            begin
                if rst_n = '0' then
                    pipeline_reg <= (others => '0');
                elsif rising_edge(clk) then
                    for i in pipeline'range loop
                        if i = 0 then
                            pipeline_reg(i) <= a and b;
                        else
                            pipeline_reg(i) <= pipeline_reg(i - 1);
                        end if;
                    end loop;
                end if;
            end process;
            a_and_b <= pipeline_reg(PIPELINES - 1); -- a separate process
    end generate;

PROC_B:
    process (clk, rst_n) is
    begin
        if rst_n = '0' then
            ab_xor_c <= '0';
        elsif rising_edge(clk) then
            ab_xor_c <= a_and_b xor c;
        end if;
    end process;

end architecture generic_pipeline_stages;

which produces:

example1_pipelines_equal2.jpg

And shows the two clock delays using natural generic PIPELINES.

With PIPELINES = 1:

enter image description here

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.

调妓 2025-01-26 07:39:13

您编写的设计中的原理很好,除了如果pipeline_en ='1',则 在声明pipeline_reg中应跳过,因为合成将然后只需删除未使用的pipeline_reg。另外,我建议将pipeline_en声明为boolean,因为这是一个更明显的选择,='1'可以然后可以在条件下跳过。

如果由于某种原因您想避免在实际设计中声明管道信号'pipeline_reg',则可以在过程中声明一个变量,如以下代码。在代码中使用后,需要分配变量,以获取触发器,因为否则它只是成为组合逻辑。但是,建议通过使用变量来创建触发器,因为很难读取和正确地读取和正确,因此容易出错,并且应该避免使用。虽然来了:

PROC_B : process (clk, rst_n) is
  variable pipeline_reg_v : std_logic;  -- Results in pipeline register if PIPELINE_EN, otherwise removed by synthesis
begin  -- process PROC_B
  if rst_n = '0' then                 -- asynchronous reset (active low)
    ab_xor_c <= '0';
    if PIPELINE_EN then
      pipeline_reg_v := '0';
    end if;
  elsif rising_edge(clk) then         -- rising clock edge
    if PIPELINE_EN then
      ab_xor_c       <= pipeline_reg_v xor c;
      pipeline_reg_v := a_and_b;
    else
      ab_xor_c <= a_and_b xor c;
    end if;
  end if;
end process PROC_B;

一种替代方法是使用VHDL block构造,以及Generate ,您可以拥有Signal> Signal> Signal声明,这些声明是本地的块,如下所示。尽管请注意,Block构造很少在VHDL中使用,因此在工具中遇到错误的风险更高。

PIPELINE_EN_TRUE_GENERATE : if PIPELINE_EN generate
  PIPELINE_EN_TRUE_BLOCK : block
    signal pipeline_reg : std_logic;
  begin
    PROC_B : process (clk, rst_n) is
    begin  -- process PROC_B
      if rst_n = '0' then                   -- asynchronous reset (active low)
        ab_xor_c     <= '0';
        pipeline_reg <= '0';
      elsif rising_edge(clk) then           -- rising clock edge
        pipeline_reg <= a_and_b;
        ab_xor_c     <= pipeline_reg xor c;
      end if;
    end process PROC_B;
  end block PIPELINE_EN_TRUE_BLOCK;
end generate PIPELINE_EN_TRUE_GENERATE;

PIPELINE_EN_FALSE_GENERATE : if not PIPELINE_EN generate
  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 generate PIPELINE_EN_FALSE_GENERATE;

Principles in the design you wrote are fine, except for the if PIPELINE_EN = '1' then part in the declaration of pipeline_reg, which should be skipped, since the synthesis will then just remove the unused pipeline_reg. Also I would suggest that PIPELINE_EN is declared as type boolean 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:

PROC_B : process (clk, rst_n) is
  variable pipeline_reg_v : std_logic;  -- Results in pipeline register if PIPELINE_EN, otherwise removed by synthesis
begin  -- process PROC_B
  if rst_n = '0' then                 -- asynchronous reset (active low)
    ab_xor_c <= '0';
    if PIPELINE_EN then
      pipeline_reg_v := '0';
    end if;
  elsif rising_edge(clk) then         -- rising clock edge
    if PIPELINE_EN then
      ab_xor_c       <= pipeline_reg_v xor c;
      pipeline_reg_v := a_and_b;
    else
      ab_xor_c <= a_and_b xor c;
    end if;
  end if;
end process PROC_B;

An alternative is to use the VHDL block construction, together with generate, whereby you can have signal declarations that are local to the block, as shown below. Though note that the block construction is rarely used in VHDL, thus there is a higher risk of encountering bugs in tools.

PIPELINE_EN_TRUE_GENERATE : if PIPELINE_EN generate
  PIPELINE_EN_TRUE_BLOCK : block
    signal pipeline_reg : std_logic;
  begin
    PROC_B : process (clk, rst_n) is
    begin  -- process PROC_B
      if rst_n = '0' then                   -- asynchronous reset (active low)
        ab_xor_c     <= '0';
        pipeline_reg <= '0';
      elsif rising_edge(clk) then           -- rising clock edge
        pipeline_reg <= a_and_b;
        ab_xor_c     <= pipeline_reg xor c;
      end if;
    end process PROC_B;
  end block PIPELINE_EN_TRUE_BLOCK;
end generate PIPELINE_EN_TRUE_GENERATE;

PIPELINE_EN_FALSE_GENERATE : if not PIPELINE_EN generate
  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 generate PIPELINE_EN_FALSE_GENERATE;
夏雨凉 2025-01-26 07:39:13

使用管道深度的通用参数:

library ieee;
use ieee.std_logic_1164.all;

entity example is
  generic(
    depth: natural := 0
  );
  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_vector(0 to depth);

begin

  z_out <= ab_xor_c(depth);

  process(clk, rst_n) is
  begin
    if rst_n = '0' then
      a_and_b  <= '0';
      ab_xor_c <= (others => '0');
    elsif rising_edge(clk) then
      a_and_b     <= a and b;
      ab_xor_c    <= ab_xor_c srl 1;
      ab_xor_c(0) <= a_and_b xor c;
    end if;
  end process;

end architecture rtl;

然后使用 深度=2

use std.env.all;

library ieee;
use ieee.std_logic_1164.all;

entity example_sim is
end entity example_sim;

architecture sim of example_sim is

  signal clk:   std_logic;
  signal rst_n: std_logic;
  signal a:     std_logic;
  signal b:     std_logic;
  signal c:     std_logic;
  signal z_out: std_logic;

begin

  u0: entity work.example(rtl)
    generic map(
      depth => 2
    )
    port map(
      clk   => clk,
      rst_n => rst_n,
      a     => a,
      b     => b,
      c     => c,
      z_out => z_out
    );

  process
  begin
    clk <= '0';
    wait for 1 ns;
    clk <= '1';
    wait for 1 ns;
  end process;

  process
  begin
    rst_n <= '0';
    a     <= '1';
    b     <= '1';
    c     <= '1';
    wait until rising_edge(clk);
    rst_n <= '1';
    for i in 1 to 15 loop
      wait until rising_edge(clk);
      c <= not c;
    end loop;
    finish;
  end process;

end architecture sim;

演示:

$ ghdl -a --std=08 example_sim.vhd
$ ghdl -r --std=08 example_sim --vcd=example_sim.vcd
simulation finished @21ns
$ open example_sim.vcd

waveform

当然,如果你的数据类型(T)更多比单一复杂std_logic 您将需要一些额外的工作。

  1. 定义您的数据类型的向量类型 (T_vector)。
  2. 为您的基本类型定义一个“”常量值 (T_zero),这将是向右移动时在左侧输入的值。
  3. 重载 T_vector 向量类型的 srl 运算符。

T 类型的示例(未测试):

type T_vector is array(natural range <>) of T;
constant T_zero: T := <some zero value for your type>;
...
function "srl"(l: T_vector; r: natural) return T_vector is
  constant size: positive := l'length;
  constant tmp: T_vector(0 to size - 1) := l;
  variable res: T_vector(0 to size - 1);
begin
  if r = 0 then
    res := tmp;
  elsif r = 1 then
    res := T_zero & tmp(0 to size - 2);
  else
    res := (l srl 1) srl (r - 1);
  end if;
  return res;
end function "srl";

With a generic parameter for the pipeline depth:

library ieee;
use ieee.std_logic_1164.all;

entity example is
  generic(
    depth: natural := 0
  );
  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_vector(0 to depth);

begin

  z_out <= ab_xor_c(depth);

  process(clk, rst_n) is
  begin
    if rst_n = '0' then
      a_and_b  <= '0';
      ab_xor_c <= (others => '0');
    elsif rising_edge(clk) then
      a_and_b     <= a and b;
      ab_xor_c    <= ab_xor_c srl 1;
      ab_xor_c(0) <= a_and_b xor c;
    end if;
  end process;

end architecture rtl;

And then, with depth=2:

use std.env.all;

library ieee;
use ieee.std_logic_1164.all;

entity example_sim is
end entity example_sim;

architecture sim of example_sim is

  signal clk:   std_logic;
  signal rst_n: std_logic;
  signal a:     std_logic;
  signal b:     std_logic;
  signal c:     std_logic;
  signal z_out: std_logic;

begin

  u0: entity work.example(rtl)
    generic map(
      depth => 2
    )
    port map(
      clk   => clk,
      rst_n => rst_n,
      a     => a,
      b     => b,
      c     => c,
      z_out => z_out
    );

  process
  begin
    clk <= '0';
    wait for 1 ns;
    clk <= '1';
    wait for 1 ns;
  end process;

  process
  begin
    rst_n <= '0';
    a     <= '1';
    b     <= '1';
    c     <= '1';
    wait until rising_edge(clk);
    rst_n <= '1';
    for i in 1 to 15 loop
      wait until rising_edge(clk);
      c <= not c;
    end loop;
    finish;
  end process;

end architecture sim;

Demo:

$ ghdl -a --std=08 example_sim.vhd
$ ghdl -r --std=08 example_sim --vcd=example_sim.vcd
simulation finished @21ns
$ open example_sim.vcd

waveform

Of course, if your data type (T) is more complex than a single std_logic you will need some extra work.

  1. Define a vector type of your data type (T_vector).
  2. Define a "zero" constant value for your base type (T_zero), this will be the value that enters on the left when shifting to the right.
  3. Overload the srl operator for the T_vector vector type.

Example with a T type (not tested):

type T_vector is array(natural range <>) of T;
constant T_zero: T := <some zero value for your type>;
...
function "srl"(l: T_vector; r: natural) return T_vector is
  constant size: positive := l'length;
  constant tmp: T_vector(0 to size - 1) := l;
  variable res: T_vector(0 to size - 1);
begin
  if r = 0 then
    res := tmp;
  elsif r = 1 then
    res := T_zero & tmp(0 to size - 2);
  else
    res := (l srl 1) srl (r - 1);
  end if;
  return res;
end function "srl";
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文