【问题标题】:Is there a way to define a range type based on the range of an unconstrained vector declared in the entity's port?有没有办法根据实体端口中声明的无约束向量的范围来定义范围类型?
【发布时间】:2018-12-04 20:30:12
【问题描述】:

我正在尝试在 VHDL-2008 中实现通用解串器。 (具体来说,我的目标是可以通过 Vivado 在 VHDL-2008 模式下合成)。

我在下面包含了我当前的代码。实体端口声明为反序列化的输出字指定了一个不受约束的 std_logic_vector DATA_OUT。

问题是,在这个实现中,如果我希望能够处理 32 位字,我需要指定一个 CounterType 如下:

type CounterType is range 0 to 31;

我一直无法找到一种方法,以一种有效的 VHDL 方式从 DATA_OUT 端口的大小编写 CounterType 的定义,更不用说 Vivado 的编译器可以接受的方式了。

有没有办法做到这一点? (即定义一个范围类型,其中范围对应于无约束实参的范围?)

如果不是,我有哪些选择可以使这个反序列化器实现尽可能通用,即能够针对不同的输出字长对其进行实例化?

(注意:我更喜欢一种不向实体接口添加泛型的方法,因为这对于实例化时 DATA_OUT 范围的规范来说似乎是多余的。但如果不能这样做,我会也对这类解决方案感兴趣。)

library ieee;
use ieee.std_logic_1164.all;

entity deserializer is

    -- The deserializer accepts its single input bit DATA_IN whenever (DATA_IN_VALID and DATA_IN_READY) = '1'.
    -- The deserializer drops its output word DATA_OUT and proceeds whenever (DATA_OUT_VALID and DATA_OUT_READY) = '1'.

    port (
        CLK            : in  std_logic;
        RESET          : in  std_logic;
        DATA_IN        : in  std_logic;
        DATA_IN_VALID  : in  std_logic;
        DATA_IN_READY  : out std_logic;
        DATA_OUT       : out std_logic_vector;
        DATA_OUT_VALID : out std_logic;
        DATA_OUT_READY : in  std_logic
    );

end entity deserializer;


architecture arch of deserializer is

-- This implementation is designed to have no wait states: if a continuous stream of input bits is offered,
-- and the deserializer can offload its output words unimpeded, DATA_IN_READY will always be true, i.e.,
-- we'll never throttle our input; we'll process 1 bit per clock cycle.

type CounterType is range 0 to 31; -- should correspond to the index range of DATA_OUT.

type StateType is record
    -- Internal state.
    counter     : CounterType;
    data_in_bit : std_logic; -- Used to store an input bit while waiting to offload the output word in state (counter == 0).
    -- Output registers.
    data_in_ready  : std_logic;
    data_out       : std_logic_vector(DATA_OUT'range);
    data_out_valid : std_logic;
end record StateType;

constant reset_state : StateType := (
    counter        => 0,
    data_in_bit    => '-',
    data_in_ready  => '1',
    data_out       => (others => '-'),
    data_out_valid => '0'
  );

signal current_state : StateType := reset_state;
signal next_state    : StateType;

begin

    combinatorial: process (all) is
    variable state: StateType;
    begin
        -- Calculate next state based on current state and inputs.
        if RESET = '1' then
            -- Handle synchronous reset.
            state := reset_state;
        else
            -- Start from current state.
            state := current_state;

            if state.counter = 0 then
                -- Note: we may have a pending output, waiting to be accepted.
                if state.data_out_valid = '1' and DATA_OUT_READY = '1' then
                    state.data_out := (others => '-');
                    state.data_out_valid := '0';
                end if;

                if state.data_in_ready = '1' and DATA_IN_VALID = '1' then
                    state.data_in_bit := DATA_IN;
                    state.data_in_ready := '0';
                end if;

                if state.data_out_valid = '0' and state.data_in_ready = '0' then
                    state.data_out(state.data_out'right) := state.data_in_bit;
                    state.data_in_bit := '-';
                    state.counter := state.counter + 1;
                    state.data_in_ready := '1';
                end if;
            else
                if state.data_in_ready = '1'and DATA_IN_VALID = '1' then
                    state.data_out := state.data_out sll 1;
                    state.data_out(state.data_out'right) := DATA_IN;
                    if state.counter = CounterType'high then
                        state.data_out_valid := '1';
                        state.counter := 0;
                    else
                        state.counter := state.counter + 1;
                    end if;
                end if; 
            end if;

        end if;

        -- Schedule next state for update at next rising clock edge.
        next_state <= state;

        -- Drive entity outputs from current state.
        DATA_IN_READY  <= current_state.data_in_ready;
        DATA_OUT       <= current_state.data_out;
        DATA_OUT_VALID <= current_state.data_out_valid;

    end process combinatorial;

    sequential: process (CLK) is
    begin
        if rising_edge(CLK) then
            current_state <= next_state;
        end if;
    end process sequential;

end architecture arch;

【问题讨论】:

  • 为什么要为CounterType 声明一个新的整数类型。通常,您应该声明一个子类型,并从类型integer 中约束这样的子类型。据我所知,目前综合工具中不支持不受约束和部分约束的端口。 Vivado 真的接受这一点吗?
  • 您可能对子类型是正确的。我仍然觉得 VHDL 的打字系统相当混乱。是的,Vivado 接受此代码(在 VHDL-2008 模式下)。
  • 您的设计规范有一个不受约束的端口,不能是设计层次结构的顶层。您没有提供minimal reproducible example。 (未来的读者无法验证需要详细说明的答案。)
  • minimal, complete and verifiable 示例。 (如果不会产生语法错误,也可用于确定 Vivado 中发生的情况与您之前的尝试subtype CounterType is DATA_OUT'range;)。

标签: vhdl


【解决方案1】:

CounterType 可以通过DATA_OUT'low to DATA_OUT'high 调整大小。您应该声明一个子类型,而不是声明一个与称为“整数”的预定义整数类型不兼容的全新整数类型:

subtype CounterType is integer range DATA_OUT'low to DATA_OUT'high;

如果工具完全符合 VHDL-2008,它也应该接受这一点:

subtype CounterType is integer range DATA_OUT'range;

【讨论】:

  • 太好了,您提出的两个子类型声明都可以在 Vivado 中使用。我之前尝试过类似于您的第二个建议的方法:子类型 CounterType 是 DATA_OUT'range。这确实可以编译,但不知何故会导致不同的(和错误的)行为,我希望声明与您的第二个解决方案具有相同的含义。你知道为什么会这样吗?
  • 回复:subtype CounterType is DATA_OUT'range; 未提供子类型指示中所需的类型标记(IEEE 标准 1076-2008 6.3 子类型声明。接受它表示 Vivado 模拟器/HDL 解析器错误。
  • @user1155120 这就是我在is 之后使用integer range 的原因。在range之后,只需要一个范围,对吧?
  • 没有。 subtype identifier is subtype_indication ;subtype_indication ::= [ resolution_indication ] type_mark [ constraint ]。标量子类型范围约束需要 range 保留字(5.2 标量类型)。 A'RANGE 属性返回一个范围。你的两个例子都有效。您已将类型标记提供为整数。
猜你喜欢
  • 1970-01-01
  • 2013-01-18
  • 2021-10-10
  • 1970-01-01
  • 1970-01-01
  • 2016-01-10
  • 2017-07-14
  • 1970-01-01
  • 2023-02-10
相关资源
最近更新 更多