VHDL 中的不相交范围

Disjoint ranges in VHDL

我有这样的位向量

subtype alarms_type : std_logic_vector(1 to 8)
signal alarms : alarms_type := (others => '0');

每个位的用途是这样定义的

constant sys1_temp_hi_al : integer := 1;
constant sys1_temp_lo_al : integer := 2;
constant sys1_crnt_hi_al : integer := 3;
constant sys1_cnrt_lo_al : integer := 4;
constant sys2_temp_hi_al : integer := 5;
constant sys2_temp_lo_al : integer := 6;
constant sys2_crnt_hi_al : integer := 7;
constant sys2_cnrt_lo_al : integer := 8;

我希望能够使用简短易读的符号访问 alarms_type 的子集。例如

alarms(SYS2_ALS) <= (others => '0');  -- set multiple values
temp_alarm <= or(alarms(TEMP_ALS));   -- or together multiple values to a std_logic
temp_alarms <= alarms(TEMP_ALS));     -- extract a subset to a suitably sized vector
alarms(TEMP_ALS) := (others => '1');  -- set (or clear) multiple disjoint values

我想知道 alias 关键字是否对我有帮助,例如:

alias HI_ALARMS is sys1_temp_hi_al|sys1_crnt_hi_al|sys2_temp_hi_al|sys2_crnt_hi_al;
alias LO_ALARMS is sys1_temp_lo_al|sys1_crnt_lo_al|sys2_temp_lo_al|sys2_crnt_lo_al;
alias TEMP_ALS  is sys1_temp_hi_al|sys1_temp_lo_al|sys2_temp_hi_al|sys2_temp_lo_al;
alias CRNT_ALS  is sys1_crnt_hi_al|sys1_crnt_lo_al|sys2_crnt_hi_al|sys2_crnt_lo_al;
alias SYS1_ALS  is sys1_temp_hi_al|sys1_crnt_hi_al|sys2_temp_hi_al|sys2_crnt_hi_al;
alias SYS2_ALS  is sys1_temp_hi_al|sys1_crnt_hi_al|sys2_temp_hi_al|sys2_crnt_hi_al;

从 Ashenden 书的 Alias 章节看来,这不是应该使用别名的方式,但希望我遗漏了什么。

如果有正确的方法使用alias达到我的目的,请举例说明。

或者,如果有使用 constant 或 VHDL 其他方面的不同或更好的方法,请告诉我如何使用。

或者直接告诉我做不到,如果合适,请确认我可以写函数获取和设置不同的子集。

如果我使用函数和过程,有没有比这更简洁的表示法? (我可能需要很多这样的函数和程序)。

function get_temp_als(alarms : alarms_type)
  return alarms(sys1_temp_hi_al) & alarms(sys1_temp_lo_al) & alarms(sys2_temp_hi_al) & alarms(sys2_temp_lo_al);

function get_combined_temp_als(alarms : alarms_type)
  return alarms(sys1_temp_hi_al) or alarms(sys1_temp_lo_al) or alarms(sys2_temp_hi_al) or alarms(sys2_temp_lo_al);

procedure set_temp_als(alarms: alarm_type, value:std_logic)
begin
  alarms(sys1_temp_hi_al) <= value;
  alarms(sys1_temp_lo_al) <= value;
  alarms(sys2_temp_hi_al) <= value;
  alarms(sys2_temp_lo_al) <= value;;
end;

我希望它能与 VHDL 2002 一起使用,它是为综合而设计的。

你是对的,别名不是那样工作的。它们是单个对象(或其切片)的别名,不能用于创建新的复合对象,就像您在另一种语言中使用指针所做的那样。

程序可能是您实现此目标的唯一方法。警报参数应该是信号和模式:

procedure set_temp_als(signal alarms: out alarm_type; value:std_logic)
begin
  alarms(sys1_temp_hi_al) <= value;
  alarms(sys1_temp_lo_al) <= value;
  alarms(sys2_temp_hi_al) <= value;
  alarms(sys2_temp_lo_al) <= value;
end;

因此您可以使用以下方式分配警报: set_temp_als(alarms, '1');

你的函数是正确的想法,但在语法上是错误的:

function get_temp_als(alarms : alarms_type) return std_logic_vector is
begin
  return alarms(sys1_temp_hi_al) & alarms(sys1_temp_lo_al) & alarms(sys2_temp_hi_al) & alarms(sys2_temp_lo_al);
end function;
signal some_other_slv : std_logic_vector(3 downto 0);

some_other_slv <= get_temp_als(alarms);

别名是现有命名实体的新名称,而不是新实体。

Alternatively, if there is a different or better way using constant or some other aspect of VHDL, please show me how.

存在一个基本问题,即不清楚您将如何处理信息,缺少 minimal, complete, and verifiable example 您正试图获得更多 'elegant'。

可以使用常量指定alarms_type个索引:

library ieee;
use ieee.std_logic_1164.all;

entity alarming is
end entity;

architecture fum of alarming is
    -- subprograms, constants and type declarations could be in a package
    subtype alarm_range is integer range 1 to 8;
    subtype alarms_type is std_logic_vector(alarm_range);
    signal alarms: alarms_type := (others => '0');

    constant sys1_temp_hi_al : integer := 1;
    constant sys1_temp_lo_al : integer := 2;
    constant sys1_crnt_hi_al : integer := 3;
    constant sys1_crnt_lo_al : integer := 4;
    constant sys2_temp_hi_al : integer := 5;
    constant sys2_temp_lo_al : integer := 6;
    constant sys2_crnt_hi_al : integer := 7;
    constant sys2_crnt_lo_al : integer := 8;

    type index is array (natural range <>) of alarm_range;

    constant  HI_ALARMS:  index := (sys1_temp_hi_al, sys1_crnt_hi_al,
                                    sys2_temp_hi_al, sys2_crnt_hi_al);

    constant  LO_ALARMS:  index := (sys1_temp_lo_al, sys1_crnt_lo_al,
                                    sys2_temp_lo_al, sys2_crnt_lo_al);

    constant TEMP_ALS:    index := (sys1_temp_hi_al, sys1_temp_lo_al, 
                                    sys2_temp_hi_al, sys2_temp_lo_al);

    constant CRNT_ALS:    index := (sys1_crnt_hi_al, sys1_crnt_lo_al, 
                                    sys2_crnt_hi_al, sys2_crnt_lo_al);

    constant SYS1_ALS:    index := (sys1_temp_hi_al, sys1_temp_lo_al,
                                    sys1_crnt_hi_al, sys1_crnt_lo_al);

    constant SYS2_ALS:    index := (sys2_temp_hi_al, sys2_temp_lo_al,
                                    sys2_crnt_hi_al, sys2_crnt_lo_al);

    function get_alarm (alarm: alarms_type; indx: alarm_range)
    return std_logic is
    begin
        return alarm(indx);
    end function;

    function set_alarm (alarm: alarms_type; indx: alarm_range)
    return alarms_type is
        variable ret_val:   alarms_type := alarm;
    begin
        ret_val(indx) := '1';
        return ret_val;
    end function;

    function get_alarms (alarm: alarms_type; alarm_indx: index) 
    return std_logic_vector is  -- doesn't look real useful.
        variable ret_val: std_logic_vector(alarm_indx'range);
    begin
        for i in alarm_indx'range loop
            ret_val(i) := alarm(alarm_indx(i));
        end loop;
        return ret_val;
    end function;

    -- instead:
    function select_alarms (alarm: alarms_type; alarm_indx: index)
    return alarms_type is
        variable ret_val: alarms_type := (others => '0');
    begin
        for i in alarm_indx'range loop
            ret_val(alarm_indx(i)) := alarm(alarm_indx(i));
        end loop;
        return  ret_val;
    end function;

    -- which returns a mask selected alarms_type value that allows the use of a
    -- single alarm service routine.


    function set_alarms (alarm: alarms_type; alarm_indx: index) 
    return alarms_type is
        variable ret_val: alarms_type := (others => '0');
    begin
        for i in alarm_indx'range loop
            ret_val(i) := alarm(alarm_indx(i));
        end loop;
        return ret_val;
    end function;

    procedure report_alarms (alarm: in alarms_type) is
        type name_array is array (alarm_range) of string (1 to 15);
        constant alarm_name:  name_array := ( 
              "sys1_temp_hi_al", "sys1_temp_lo_al",
              "sys1_crnt_hi_al", "sys1_crnt_lo_al",
              "sys2_temp_hi_al", "sys2_temp_lo_al",
              "sys2_crnt_hi_al", "sys2_crnt_lo_al"
        );
    begin
        for i in alarm_range loop
            if alarm(i) = '1' then
                report "alarm " & alarm_name(i) & " is set";
            end if;
        end loop;
    end procedure;

begin
    alarms <= select_alarms("11111111", TEMP_ALS) after 5 ns;
LABELED:
    process (alarms)
    begin
        report_alarms(alarms);
    end process;
end architecture;

ghdl -r alarming
alarming.vhdl:102:17:@5ns:(report note): alarm sys1_temp_hi_al is set
alarming.vhdl:102:17:@5ns:(report note): alarm sys1_temp_lo_al is set
alarming.vhdl:102:17:@5ns:(report note): alarm sys2_temp_hi_al is set
alarming.vhdl:102:17:@5ns:(report note): alarm sys2_temp_lo_al is set

告诉我们我可以使用温度警报索引集选择的警报来设置所有温度警报。

通过提供第二个参数来按名称选择一组警报,子程序的数量会减少(另一种方法是为所有不同的警报集声明一个类型并为它们提供子程序)。