Статьи


 
Обновление сайта

Уважаемые посетители сайта!

18.12.2014


Примеры VHDL'2008

1. Добавление конструкций языка PSL для проверки свойств модели

--------------------------------------------------------------------
-- 1. Добавление конструкций языка PSL  для проверки свойств модели
--------------------------------------------------------------------

library ieee;
use ieee.std_logic_1164.all;
use std.textio.all;
use ieee.std_logic_textio.all;
use ieee.numeric_std.all;

entity Mealy is
  port(x1, x2, x3, x4         : in  std_logic;
       clk, rst               : in  std_logic;
       y1, y2, y3, y4, y5, y6 : out std_logic);
end Mealy;

architecture rtl of Mealy is
  type T_state is (a1, a2, a3, a4, a5, a6);
  signal NEXT_state, state : T_state;
  signal w                 : std_logic_vector (1 to 6);
-- psl  default clock is rising_edge(clk);      -- VHDL'2008
-- psl  property prop1 is
--        always {state = a2; NEXT_state = a3};
-- psl  as1 : assert prop1;
-- psl  as2 : assert always {state = a2; state = a4} |=> {state = a6};
-- psl  as3 : cover {state = a1; state = a4};
-- psl  as4 : assert always {state=a4} |=> {state=a5};
-- psl  as5 : cover {state = a4; state = a5};
begin
  y1 <= w(1);
  y2 <= w(2);
  y3 <= w(3);
  y4 <= w(4);
  y5 <= w(5);
  y6 <= w(6); ns : process (state, x1, x2, x3, x4) begin case state is when a1 =>
        NEXT_state <= a2; w <= "000101"; when a2 =>
        if ((x1 and not x2 and not x3) or (x1 and x2)) = '1'
        then NEXT_state <= a3; w <= "000000";
        elsif ((x1 and not x2 and x3) = '1')
        then NEXT_state <= a4; w <= "001000";
        elsif (not x1 = '1')
        then NEXT_state <= a5; w <= "000010"; end if; when a3 => NEXT_state <= a4; w <= "001001"; when a4 =>
        if (not x2 = '1')
        then NEXT_state <= a1; w <= "000000";
        elsif (x2 = '1')
        then NEXT_state <= a6; w <= "010000"; end if; when a5 =>
        if ((not x1 and x4) = '1')
        then NEXT_state <= a1; w <= "100000";
        elsif ((not x4) or (x1 and x4)) = '1'
        then NEXT_state <= a4; w <= "001001"; end if; when a6 => NEXT_state <= a1; w <= "100000";
    end case;
  end process ns;

  p2 : process (clk, rst) is
  begin  -- process p2
    if rst = '1' then                   -- asynchronous reset (active low)
      state <= a1;
    elsif clk'event and clk = '1' then  -- rising clock edge
      state <= NEXT_state;
    end if;
  end process p2;
end rtl;

2. Параметризация типов и список параметров для пакетов

-------------------------------------------------------------------
-- 2. Параметризация  типов и список параметров для пакетов
--------------------------------------------------------------------

package func_pkg is
  generic (type element_type;
           function "+" (
             a : element_type;
             b : element_type)
           return element_type;
           function "-" (
             a : element_type;
             b : element_type)
           return element_type);

  function add (a : element_type; b : element_type) return element_type;

  function sub (a : element_type; b : element_type) return element_type;
end package func_pkg;

package body func_pkg is
  function add (
    a : element_type;
    b : element_type)
    return element_type is
  begin  -- function add
    return a + b;
  end function add;

  function sub (
    a : element_type;
    b : element_type)
    return element_type is
  begin  -- function add
    return a - b;
  end function sub;
end package body func_pkg;

---------------------------------

package func_int_pkg is new work.func_pkg
  generic map (element_type => integer,
               "+"          => "+",
               "-"          => "-");
package func_real_pkg is new work.func_pkg
  generic map (element_type => real,
               "+"          => "+",
               "-"          => "-");

---------------------------------

library ieee;

entity adder is

  generic (type element_type;
           function add (
             a : element_type;
             b : element_type)
           return element_type);
  port (
    a, b : in  element_type;
    y    : out element_type);

end entity adder;

architecture beh of adder is

begin  -- architecture beh

  y <= add(a, b); end architecture beh; --------------------------------- use work.func_int_pkg.all; use work.func_real_pkg.all; use std.env.all; entity test_tb is end entity test_tb; architecture beh of test_tb is component adder is generic ( type element_type; function add ( a : element_type; b : element_type) return element_type); port ( a, b : in element_type; y : out element_type); end component adder; signal a_int, b_int : integer := 1; signal y_int : integer; signal a_real, b_real : real := 1.0; signal y_real : real; begin -- architecture beh adder_int : adder generic map ( element_type => integer,
      add          => sub)
    port map (
      a => a_int,
      b => b_int,
      y => y_int);

  adder_real : adder
    generic map (
      element_type => real,
      add          => add)
    port map (
      a => a_real,
      b => b_real,
      y => y_real);

  a_int <=
    a_int + 1 after 5 ns;
  b_int <=
    b_int + 1 after 50 ns;

  a_real <=
    a_real + 1.0 after 5 ns;
  b_real <=
    b_real + 1.0 after 50 ns;

  process is
  begin
    wait for 1 us;
    stop(1);
  end process;

end architecture beh;

3. Массивы с неограниченными диапазонами

-------------------------------------------------------------------
-- 3. Массивы с неограниченными диапазонами
--------------------------------------------------------------------

library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;

entity prov_uncon_array is
end;

architecture beh of prov_uncon_array is
  type std_logic_matrix is array (natural range <>) of std_logic_vector;  -- VHDL'2008
  signal A  : std_logic_matrix(4 downto 0)(5 downto 0);
  signal c1 : std_logic_matrix(0 to 6)(7 downto 0);
  signal c2 : std_logic_matrix(5 downto 0)(2 to 4);

  type std_logic_matrix_old is array (4 downto 0) of std_logic_vector (5 downto 0);
  signal B : std_logic_matrix_old;
begin
  process
  begin
    wait for 100 ns;
    a <= ("111111",
          "100000",
          "010000",
          "001000",
          "000010");
    wait for 100 ns;
    b <= ("111111",
          "100000",
          "010000",
          "001000",
          "000111");
    wait for 100 ns;
    wait;
  end process;

end beh;

4. Записи с неограниченными массивами

-------------------------------------------------------------------
--  4. Записи с неограниченными массивами  
--------------------------------------------------------------------

library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;

entity prov_record is
end;

architecture beh of prov_record is
  type complex is record                -- VHDL'2008
    a : std_logic_vector;
    b : signed;
    d : natural range 0 to 10;
    c : unsigned;
  end record;

  signal a1 : std_logic_vector (3 downto 0);
  signal b1 : signed (1 to 5);
  signal c1 : unsigned (6 downto 3);


  signal X1 : complex (a (3 downto 0), b (1 to 5), c (6 downto 3));
-- пропускаем те поля, которые ограничены
begin
  process
  begin
    wait for 100 ns;

-- X1<= ("1111", "10000", "0100");

    X1.a <= "1111";
    X1.b <= "10000";
    X1.c <= "1010";

    wait for 100 ns;
    a1 <= x1.a;
    b1 <= x1.b;
    c1 <= x1.c;
    wait for 100 ns;

    wait;
  end process;
end beh;

5. Использование чисел с фиксированной точкой

-------------------------------------------------------------------
-- 5. Использование чисел с фиксированной точкой
-------------------------------------------------------------------- 

library ieee;
use ieee.std_logic_1164.all;
use ieee.fixed_pkg.all;                          -- VHDL'2008

entity prov_fix_type is
end;

architecture beh of prov_fix_type is
  signal a : ufixed (3 downto -3) := "0110100";  -- 6.5
  signal b : ufixed (4 downto -2) := "0110001";  -- 12,25
  signal c : ufixed (5 downto -3);
  signal d : ufixed (5 downto -3);
  signal e : ufixed (8 downto -5);
  signal k : ufixed (5 downto -8);
begin
  process(all)
  begin
    c <= a + b;
    d <= b - a;
    e <= a * b;
    k <= a / b;
  end process;
end beh;

6. Использование чисел с плавающей точкой

-------------------------------------------------------------------
-- 6. Использование чисел с плавающей точкой 
--------------------------------------------------------------------

library ieee;
use ieee.std_logic_1164.all;
use ieee.float_pkg.all;                 -- VHDL'2008

entity prov_float_type is
end;

architecture beh of prov_float_type is
  signal a             : float (8 downto -23) := "01000001101000000000000000000000";  --+6.5
  signal b             : float (8 downto -23) := "01000000000000000000000000000000";  --+2.0
  signal c, d, e, k, r : float (8 downto -23);
  signal a_real        : real;
  signal b_real        : real;
  signal c_real        : real;
  signal d_real        : real;
  signal e_real        : real;
  signal k_real        : real;
  signal r_real        : real;
begin
  c <= a + b;
  d      <= b - a;
  e      <= a * b;
  k      <= a/b;
  r      <= b/a;
  a_real <= to_real(a);
  b_real <= to_real(b);
  c_real <= to_real(c);
  d_real <= to_real(d);
  e_real <= to_real(e);
  k_real <= to_real(k);
  r_real <= to_real(r);
end beh;
-------------------------------------
library ieee;
use ieee.std_logic_1164.all;
use ieee.float_pkg.all;

entity prov_float is
end;

architecture beh of prov_float is
  signal a, b          : float (5 downto -6) := b"1_01111_010000";  --  число (-1.25)
  signal c, d, e, k, r : float (5 downto -6);
  signal a_real        : real;
  signal b_real        : real;
  signal c_real        : real;
  signal d_real        : real;
  signal e_real        : real;
  signal k_real        : real;
  signal r_real        : real;
begin
  c      <= a + b;
  d      <= b - a;
  e      <= a * b;
  k      <= a/b;
  r      <= b/a;
  a_real <= to_real(a);                 --  число (-1.25)
  b_real <= to_real(b);                 --  число (-1.25)
  c_real <= to_real(c);                 --  число (-2.5)
  d_real <= to_real(d);                 --  число (0)
  e_real <= to_real(e);                 --  число (1.5625)
  k_real <= to_real(k);                 --  число (1)
  r_real <= to_real(r);                 --  число (1)
end beh;

--------------------------------
library ieee;
use ieee.std_logic_1164.all;
use ieee.float_pkg.all;                 -- VHDL'2008

entity prov_float_type is
end;

architecture beh of prov_float_type is
  constant exp_width   : natural := 8;
  constant fract_width : natural := 13;

  signal a      : float (exp_width downto -fract_width);  -- := "01000001101000000000000000000000";   -- +6.5
  signal b      : float (exp_width downto -fract_width);  -- := "01000000000000000000000000000000";   -- +2.0
  signal c      : float (exp_width downto -fract_width);
  signal d      : float (exp_width downto -fract_width);
  signal e      : float (exp_width downto -fract_width);
  signal k      : float (exp_width downto -fract_width);
  signal r      : float (exp_width downto -fract_width);
  signal a_real : real;
  signal b_real : real;
  signal c_real : real;
  signal d_real : real;
  signal e_real : real;
  signal k_real : real;
  signal r_real : real;
begin
  process
  begin
    a <= to_float(6.5, exp_width, fract_width);
    b <= to_float(2.0, exp_width, fract_width);

    wait for 100 ns;
    a <= to_float(10.0, exp_width, fract_width);
    b <= to_float(5.0, exp_width, fract_width);
    wait for 100 ns;
    a <= to_float(10.0, exp_width, fract_width);
    b <= to_float(3.0, exp_width, fract_width);
    wait for 100 ns;
    wait;
  end process;

  c      <= a + b;
  d      <= b - a;
  e      <= a * b;
  k      <= a/b;
  r      <= b/a;
  a_real <= to_real(a);
  b_real <= to_real(b);
  c_real <= to_real(c);
  d_real <= to_real(d);
  e_real <= to_real(e);
  k_real <= to_real(k);
  r_real <= to_real(r);

end beh;

7. Иерархические ссылки на сигналы

-------------------------------------------------------------------
-- 7. Иерархические ссылки на сигналы
--------------------------------------------------------------------

library ieee;
use ieee.std_logic_1164.all;
use std.textio.all;
use ieee.std_logic_textio.all;
use ieee.numeric_std.all;

entity tstb is
end;

architecture BEHAVIOR of tstb is
  component vlsi_1
    port (a, b : in  std_logic_vector (2 downto 1);
          x    : in  std_logic;
          D    : out std_logic_vector (4 downto 1));
  end component;
  signal DATA         : std_logic_vector (4 downto 0);
  signal a, b         : std_logic_vector (2 downto 1);
  signal x            : std_logic;
  signal D            : std_logic_vector (4 downto 1);
  signal inter_sig_c1 : std_logic;

begin
  p1 : vlsi_1 port map (a, b, x, D);
  a <= (DATA(4), DATA(3));
  b <= (DATA(2), DATA(1));
  x <= DATA(0);

  inter_sig_c1 <= << signal .tstb.p1.circ3.c1 : std_logic >>;  -- VHDL'2008

  process
    file INFILE, OUTFILE     : text;
    variable PTR, POKE, PREA : line;
    variable DATA_IN         : std_logic_vector (4 downto 0);
    variable DATA_OUT        : std_logic_vector (4 downto 1);
  begin
    file_open(INFILE, "IN.TST", read_mode);
    file_open(OUTFILE, "OUT.TST", write_mode);
    while not (endfile(INFILE)) loop
      wait for 20 ns;
      readline(INFILE, PTR);
      read(PTR, DATA_IN);
      DATA     <= DATA_IN;
      wait for 20 ns;
      DATA_OUT := D;
      write(POKE, DATA_OUT);
      writeline(OUTFILE, POKE);
    end loop;
    file_close(OUTFILE);
    file_close(INFILE);
    assert(false) report "Done!" severity warning;
    wait;
  end process;
end;
----------------------------
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;

entity vlsi_1 is
  port (a, b : in  std_logic_vector (2 downto 1);
        x    : in  std_logic;
        D    : out std_logic_vector (4 downto 1));
end vlsi_1;

architecture str of vlsi_1 is

  component
    adder_2
    port (a1, b1, a2, b2 : in  std_logic;
          c2, s2, s1     : out std_logic);
  end component;
  component mult_2
    port(s1, s0, r1, r0 : in  std_logic;
         t3, t2, t1, t0 : out std_logic);
  end component;
  component YY_MUX
    port (t4, t3, t2, t1, c2, s2, s1, x : in  std_logic;
          d4, d3, d2, d1                : out std_logic);
  end component;

  signal t4, t3, t2, t1, c2, s2, s1 : std_logic;

begin
  circ1 : YY_MUX port map (t4, t3, t2, t1, c2, s2, s1, x,
                           d(4), d(3), d(2), d(1));
  circ2 : mult_2
    port map (a(2), a(1), b(2), b(1), t4, t3, t2, t1);
  circ3 : adder_2
    port map (a(2), a(1), b(2), b(1), c2, s2, s1);

end str;
--------------------------        
library ieee;
use ieee.std_logic_1164.all;

entity adder_2 is
  port (a1, b1, a2, b2 : in  std_logic;
        c2, s2, s1     : out std_logic);
end adder_2;

architecture struct_1 of adder_2 is
  component
    add1
    port (b1, b2 : in  std_logic;
          c1, s1 : out std_logic);
  end component;
  component add2
    port(c1, a1, a2 : in  std_logic;
         c2, s2     : out std_logic);
  end component;
  signal c1 : std_logic;
begin
  circ1 : add1
    port map (b1, b2, c1, s1);
  circ2 : add2
    port map (c1, a1, a2, c2, s2);
end struct_1;

8. Фраза «all» для списка чувствительности процесса

-------------------------------------------------------------------
--  8.  Фраза «all»  для списка чувствительности процесса
--------------------------------------------------------------------

entity example_selection is
  port (x1, x2, x3, x4 : in  bit;
        selection      : in  bit_vector(1 downto 0);
        F              : out bit);
end example_selection;
architecture first_1993 of example_selection is
begin
  process (x1, x2, x3, x4, selection)   -- VHDL'1993
  begin
    case selection is
      when "00"   => F <= x1; when "01" => F <= x2; when "10" => F <= x3; when others => F <= x4; end case; end process; end first_1993; architecture second_2008 of example_selection is begin process (all) -- VHDL'2008 begin case selection is when "00" => F <= x1; when "01" => F <= x2; when "10" => F <= x3; when others => F <= x4;
    end case;
  end process;
end second_2008;

9. Упрощенный оператор case (выбора)

--------------------------------------------------------------------
-- 9. Упрощенный оператор case (выбора)
--------------------------------------------------------------------

library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;

entity Encoder is
  port (x, y : in  std_logic_vector (1 downto 0);
        F    : out unsigned (3 downto 0));
end Encoder;

architecture beh of Encoder is
begin
  process (x, y)
    constant z  : std_logic_vector (1 downto 0) := "10";
    constant w1 : std_logic_vector (1 downto 0) := "10";
    constant w2 : std_logic_vector (1 downto 0) := "11";

  begin
    case ((x xor y) & z) is
      when "1010"  => F <= "1000"; when w1 & w2 => F <= "0100"; when "001-" => F <= "0010"; when "1101" => F <= "0001"; when "01--" => F <= "1111"; when others => F <= "0110";
    end case;
  end process;
end beh;

10. Безразличные условия в операторах case

--------------------------------------------------------------------
-- 10. Безразличные условия в операторах case
--------------------------------------------------------------------

library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;

entity Encoder is
  port (x : in  std_logic_vector (3 downto 0);
        F : out unsigned (3 downto 0));
end Encoder;

architecture beh of Encoder is
begin
  process (x)
  begin
    case? x is
      when "10--" => F <= "1000"; when "01--" => F <= "0100"; when "001-" => F <= "0010"; when "0001" => F <= "0001"; when "11--" => F <= "1111"; when others => F <= "0000";
    end case?;
  end process;
end beh;

11. Упрощенные условные выражения

-------------------------------------------------------------------
-- 11. Упрощенные условные выражения 
--------------------------------------------------------------------

library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;

entity prov_new_if is
end;

architecture beh of prov_new_if is
  signal a          : std_logic := '1';
  signal b          : std_logic := 'H';
  signal c          : std_logic := '1';
  signal x1, x2, x3 : std_logic;

  signal d : bit := '1';
  signal e : bit := '0';
  signal k : bit;
begin
  process
  begin
    wait for 100 ns;

    if (a or b) then
      x1 <= '1';
    else
      x1 <= '0';
    end if;

    wait for 100 ns;

    if (d and e) then
      k  <= '1';
    else
      k  <= '0';
      x2 <= '1';
    end if;
    
    wait for 100 ns;
    
    if ((a or b) and (a or b ?= '1')) then
      x3 <= (a or b ?= '1');
    end if;

    wait for 100 ns;

    wait;
  end process;

end beh;

12. Чтение выходных портов

-------------------------------------------------------------------
-- 12. Чтение выходных портов 
--------------------------------------------------------------------

entity out_port is
  port(
    x1, x2, x3 : in  bit;
    y1, y2     : out bit);
end out_port;

architecture beh of out_port is
begin
  y1 <= (x1 and x2);
  y2 <= (x1 xor x3) or y1;              --  y1 выходной порт
end beh;

13. Унарная редукция логических операторов

-------------------------------------------------------------------
--  13. Унарная редукция логических операторов 
--------------------------------------------------------------------

library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;

entity prov_unary_reduction is
end;

architecture beh of prov_unary_reduction is
  constant a : signed (1 to 4) := "0111";

  signal b, c, d, e, f, g : std_logic;
begin
  process
  begin
    wait for 100 ns;

    b <= and (a);   -- b <= a(1) and a(2) and a(3) and a(4);
    c <= nand (a);  -- c <= not ( a(1) and a(2) and a(3) and a(4) );
    d <= or (a);    -- d <= a(1) or a(2) or a(3) or a(4);
    e <= nor (a);   -- e <= not ( a(1) or a(2) or a(3) or a(4) );
    f <= xor (a);   -- f <= a(1) xor a(2) xor a(3) xor a(4);
    g <= xnor (a);  -- g <= a(1) xnor a(2) xnor a(3) xnor a(4);
    wait;
  end process;

end beh;

14. Изменения в пакете STANDARD библиотеки STD

-------------------------------------------------------------------- 
-- 14. Изменения в пакете STANDARD библиотеки STD
--------------------------------------------------------------------

entity std_tb is

end entity std_tb;

architecture beh of std_tb is

  signal bv   : bit_vector(3 downto 0) := 4d"12";
  signal r    : real                   := 1.0045;
  signal int  : integer                := 10045;
  signal bool : boolean                := true;
begin  -- architecture beh

  p1 : process is
  begin  -- process p1
    report "Bit_vector = " & to_string(bv) & " O = " & to_ostring(bv) & " HEX = " & to_hstring(bv) & LF severity note;
    report "Real = " & to_string(r) & " ""%6.3f"" = " & to_string(r, "%6.3f") & LF severity note;
    report "Integer = " & to_string(int) & LF severity note;
    report "Boolean = " & to_string(bool) & LF severity note;

    wait;
  end process p1;

end architecture beh;

15. Изменения в пакете TEXTIO библиотеки STD

------------------------------------------------------------------- 
-- 15. Изменения в пакете TEXTIO библиотеки STD
--------------------------------------------------------------------

use std.textio.all;

entity textio_tb is
  generic (
    filename : string := "./file.log");

end entity textio_tb;

architecture beh of textio_tb is

  signal bv    : bit_vector(3 downto 0) := 4d"12";
  signal r     : real                   := 1.0045;
  signal int   : integer                := 10045;
  signal bool  : boolean                := true;
  file outfile : text open write_mode is filename;
  file infile  : text open read_mode  is filename;
begin  -- architecture beh

  p1 : process is
    variable l : line;
  begin  -- process p1
    write (l, "Bit_vector = " & to_string(bv) & " O = " & to_ostring(bv) & " HEX = " & to_hstring(bv) & LF);
    write (l, "Real = " & to_string(r) & " ""%6.3f"" = " & to_string(r, "%6.3f") & LF);
    STRING_WRITE(l, "Real = ");
    write (l, r);
    swrite (l, " ""%6.3f"" = ");
    write (l, r, "%6.3f");
    write (l, LF);
    write (l, "Integer = " & to_string(int) & LF);
    write (l, "Boolean = " & to_string(bool) & LF);
    tee(outfile, l);
    flush(outfile);
    wait;
  end process p1;

end architecture beh;

16. Упрощенная запись символьных строк

--------------------------------------------------------------------
-- 16. Упрощенная запись символьных строк
--------------------------------------------------------------------

library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;

entity bit_str_tb is
end;

architecture beh of bit_str_tb is

-- vhdl'2008
  signal s1  : std_logic_vector (1 to 12) := O"3XZ4";
  signal ps1 : std_logic_vector (1 to 12) := "011XXXZZZ100";

  signal s2  : std_logic_vector (1 to 16) := X"A3--";
  signal ps2 : std_logic_vector (1 to 16) := "10100011--------";

  signal s3  : std_logic_vector (1 to 5) := 5B"10UU";
  signal ps3 : std_logic_vector (1 to 5) := "010UU";

  signal s4  : std_logic_vector (1 to 6) := O"3_X";
  signal ps4 : std_logic_vector (1 to 6) := "011XXX";

  signal s5  : string(1 to 20) := 20SX"F#?F";
  signal ps5 : string(1 to 20) := "11111111####????1111";

  signal s6  : std_logic_vector(1 to 7) := 7X"3C";
  signal ps6 : std_logic_vector(1 to 7) := "0111100";

  signal s7  : std_logic_vector (1 to 8) := 8O"5";
  signal ps7 : std_logic_vector (1 to 8) := "00000101";

  signal s8  : std_logic_vector(1 to 10) := 10B"X";
  signal ps8 : std_logic_vector(1 to 10) := "000000000X";

-- signal s9 : std_logic_vector(1 to 6):= 6X"FC";    -- Error
  signal ps9 : std_logic_vector(1 to 6) := "111100";

begin

end architecture beh;

18.12.2014


Введение в OS-VVM (Open Source VHDL Verification Methodology)

I. Введение

Функциональное покрытие является одной из метрик, показывающей какая часть спецификации проверена. Качество результатов покрытия зависит от плана тестирования, т. к. 100% функциональное покрытие означает, что все функции, заданные в плане тестирования, выполнены во время моделирования. В отличии от покрытия кода, которое является функцией системы моделирования и может быть полностью автоматизировано, функциональное покрытие требует тщательной разработки тестового окружения и тестов в соответствии со спецификацией, а также анализа результатов моделирования, что не может быть полностью автоматизировано. Для осуществления функционального покрытия разработаны специальные функции в различных специализированных языках верификации, таких как SystemVerilog, ‘е’ и др.

Структура пакетов в ОS-VVM

Рис. 1. Тип protected используется в OS-VVM

Проблема верификации цифровых устройств привела к появлению методологии OS-VVM (Open Source VHDL Verification Methodology) [1, 2]. OS-VVM – это методология написания «интеллектуальных» тестирующих программ с использованием языка VHDL. Данная методология позволяет реализовать функциональное покрытие и управляемую генерацию псевдослучайных тестов, что используется при верификации цифровых функциональных блоков.

Методология OS-VVM основывается на использовании специализированных VHDL пакетов RandomPkg и CoveragePkg [2] при разработке тестирующих программ. Функции пакетов базируются на использовании защищенного типа protected (рис. 1), который появился в стандарте VHDL’2002.

II.Защищенный тип protected

Защищенный тип (protected) [3] базируется на концепции, похожей на классы в объектно-ориентированном подходе, известном из других языков программирования. Тип protected позволяет объединить данные и операции, выполняемые над ними, в один объект (инкапсуляция), таким образом, скрываются детали реализации типов данных от пользователей.

Полное определение типа protected состоит из двух частей: декларации и тела (body) типа. Объявления в декларативной части типа могут включать декларации подпрограмм (процедур и функций), спецификации атрибутов и конструкции подключения, использующие ключевое слово use. Тела подпрограмм объявляются в теле типа protected. Подпрограммы, описанные при декларации типа protected, называются методами. Ниже приведён пример декларации защищенного типа COUNTER_TYPE:

type COUNTER_TYPE is protected
  procedure Set (num : integer);
  procedure Inc;
  impure function get return integer;
end protected COUNTER_TYPE;

Элементы, объявленные внутри тела типа protected, не доступны для использования вне этого типа. Таким образом, единственный способ доступа к этим элементам, это использование методов, объявленных при декларации типа. Единственным ограничением для методов является то, что формальные параметры методов не могут быть типа access или file.

Тело типа protected задаёт детали реализации данного типа, в теле типа могут быть описаны: декларации и тела подпрограмм, пакетов; декларации типов, подтипов, констант, переменных, файлов и alias (переименований); декларации атрибутов, спецификации и др. Пример тела защищенного типа COUNTER_TYPE:

type COUNTER_TYPE is protected body 
  variable count : integer := 0;
  procedure Set ( num : integer) is
  begin
     count := num ;
  end procedure Set;
  procedure Inc is
  begin
    count := count + 1 ;
  end procedure Inc;
  impure function Get return integer is
  begin
    return count;
  end function Get;
end protected body COUNTER_TYPE;

Только локальные либо общие (shared) переменные могут быть типа protected. Передача значения одной переменной типа protected другой переменной не допускается. Как следствие, переменная защищенного типа не должна иметь присвоения начального значения при декларации. Аналогичным образом, операторы отношений (например, равенства ("=") и неравенства ("/=")) не могут использоваться для переменных защищенного типа.

Для того чтобы вызвать методы (функции, процедуры) защищенного типа, нужно указать имя переменной и имя метода, разделенные точкой, например, если переменная объявлена как:

shared variable Cnt : COUNTER_TYPE;

тогда она может использоваться так:

if (Cnt.Get = 6) then . .

В выражении выше вызывается метод Get переменной Cnt, который возвращает значение внутренней переменной count.

Использование защищённых типов в OS-VVM защищает пользователя от довольно сложных структур и подпрограмм, поддерживающих генерацию псевдослучайных тестов и функциональное покрытие.

III. Пакет RandomPkg

В пакете RandomPkg декларируется защищенный тип RandomPType, который включает в себя начальное значение (seed) псевдослучайного генератора и набор функций для генерации случайных чисел в различных форматах и диапазонах. Генерация псевдослучайных чисел с использованием типа RandomPType проходит в три этапа: декларация переменной данного типа, настройка генератора (в простейшем случае задание начального значения seed) и получение псевдослучайного числа, как показано в следующем примере.

-- декларация переменной RV
variable RV : RandomPType;
...
-- задание начального значения seed
RV.InitSeed(RV’instance_name);
X <= RV.RandInt(1, 10); -- получение
-- псевдослучайного числа в диапазоне [1, 10]

Метод RandInt является перегруженным, т.е. для него описано несколько реализаций с различным набором входных аргументов, как показано в примере.

RndGenProc : process
-- защищённый тип из RandomPkg
 variable RV : RandomPType ;
 variable D  : integer ;
begin
-- Задание значения seeds
RV.InitSeed(RV'instance_name);
-- Получение значения 
-- из диапазона [0, 255]
D := RV.RandInt(0, 255);
 . . .
-- Получение значения в
-- диапазоне [1, 9], исключая
-- значения 2, 4, 6, 8
D := RV.RandInt(1, 9, (2, 4, 6, 8));
 . . .
-- Получение значения из
-- набора чисел 1, 3, 7, 9.
D := RV.RandInt( (1, 3, 7, 9) );
 . . .
-- Получение значения из
-- набора 1, 3, 7, 9, исключая
-- значения 3, 7
D:=RV.RandInt((1, 3, 7, 9), (3, 7));

В приведенном примере дополнительные круглые скобки используются для задания аргумента, имеющего тип integer_vector и представляющего собой массив чисел.

В пакете RandomPkg описан также ряд функций генерации псевдослучайных чисел, имеющих упрощенный вызов (сокращенный набор указываемых при вызове входных аргументов) [4].

Функции генерации псевдослучайных чисел доступны не только для целых чисел, но и для векторных типов std_logic_vector (метод RandSlv), unsigned (RandUnsigned) и signed (RandSigned). При этом значения параметров по-прежнему задаются как целые числа (integer), но при вызове этих функций нужно указать еще дополнительный параметр – разрядность генерируемого вектора.

. . .
variable DataSlv :
  std_logic_vector(7 downto 0);
begin
. . .
-- Получение значения
-- из диапазона [0, 255]
DataSlv := RV.RandSlv(0, 255, 8);

По умолчанию, функции генерации возвращают псевдослучайные числа, подчиняющиеся равномерному закону распределения (реализованному с помощью процедуры uniform пакета math_real из библиотеки IEEE). В пакете реализованы другие законы распределения: FAVOR_SMALL (распределение с преобладанием малых значений), FAVOR_BIG (распределение с преобладанием больших значений), NORMAL (нормальный закон распределения, закон Гаусса), POISSON (распределение Пуассона). Получить другой закон распределения можно двумя способами. Первый – это использовать метод SetRandomParm для задания закона распределения по умолчанию, например:

RV.SetRandomParm(NORMAL, 5.0, 2.0);

В этом случае все функции генерации псевдослучайных чисел (Rand*) будут возвращать числа, подчиняющиеся нормальному распределению. В случае, если нужно генерировать только целые псевдослучайные числа, можно использовать перегруженные функции Uniform, FavorSmall, FavorBig, Normal, Poisson, которые возвращают псевдослучайные значения, подчиняющихся соответствующим законам распределения, независимо от закона распределения, заданного по умолчанию.

Кроме стандартных законов распределения случайной величины в пакете существует возможность взвешенной генерации – так называют [5] генерацию по произвольному закону распределения с помощью указания списка требуемых значений целых чисел и их вероятностей появления (весов). Для взвешенной генерации псевдослучайных чисел в типе RandomPType есть две группы перегруженных функций DistVal* и Dist*. При вызове функций группы DistVal* в качестве аргумента задаётся массив пар чисел (число, вес). При вызове функций из другой группы Dist* задаётся массив (integer_vector) весов. Например, функция DistValInt вызывается с массивом пар значений.

Data := RV.DistValInt( ((1, 7), (3, 2), (5, 1)) );

Первый элемент в паре это значение, а второй – его вес. Частота, с которой каждое значение будет возникать, зависит от вероятности, которая определяется по формуле [вес/(сумма всех весов)]. В приведённом примере в результате многократного вызова метода DistValInt появление числа 1 будет с вероятностью 7/10 или 70%, числа 3 – 20%, а числа 5 – 10%.

Функция DistInt является упрощённой версией DistValInt, в которой задаются только веса. Числа генерируются в диапазоне от 0 до N – 1, где N –количество заданных весов. Например, результат многократного вызова

Data := RV.DistValInt( ((1, 7), (3, 2), (5, 1)) );

функции DistInt будет следующим: вероятность выпадения числа 0 будет 70%, числа 1 – 20%, а числа 2 – 10%.

IV. Пакет CoveragePkg

Пакет CoveragePkg включает описание новых типов данных и функций, которые позволяют создавать корзины для точек покрытия и перекрестного покрытия, собирать контролируемые значения переменных (сигналов), проверять полноту покрытия, выводить отчет о результатах покрытия. Но наиболее важной функцией пакета CoveragePkg является возможность организации интеллектуального покрытия (intelligent coverage), под которым понимается выбор псевдослучайного значения (или набора значений для перекрестного покрытия) из диапазона непокрытых значений [1, 2].

В методологии OS-VVM функциональное покрытие осуществляется сбором значений переменных и сигналов VHDL проекта при выполнении моделирования.

В табл. 1 приведены основные этапы работы с функциями пакета CoveragePkg. Для организации покрытия в VHDL-программе необходимо создать переменную защищенного типа CovPType и описать модель покрытия путем задания необходимых корзин. Далее в соответствии с планом тестирования с помощью метода ICover осуществляется сбор значений переменных или сигналов в заданные моменты времени (или по определенным событиям). Полученные данные о покрытии можно использовать для управления псевдослучайной генерацией тестов при использовании метода RandCovPoint. Метод IsCovered позволяет проверить достигнуто ли полное покрытие всех корзин. С помощью методов WriteCovDb и ReadCovDb можно сохранить и загрузить базу данных о покрытии, что позволяет осуществить объединение данных о покрытии по нескольким запускам моделирования, которые могут выполняться параллельно. Далее рассмотрим этап создания корзин более подробно.

Таблица 1 - Основные этапы работы с функциями пакета CoveragePkg

Подключение пакета

use work.CoveragePkg.all;

Декларация объекта покрытия

shared variable CovX, CovXY : CovPType;

Генерация корзин

GenBin(0, 7); -- 8 корзин, 1 значение в каждой

 

GenBin(0, 255, 16); -- 16 корзин одинакового размера}

Создание точек покрытия, либо перекрестного покрытия

CovX.AddBins(GenBin(0, 31, 8));

CovX.AddBins(GenBin(32, 47, 1));

CovXY.AddCross(GenBin(0, 7), GenBin(0, 7));

Выборка (сбор) значений

CovX.ICover(X);

Проверка полноты покрытия

if CovX.IsCovered then

Оценка непокрытой области

NotCov := CovX.CountCovHoles;

Генерация псевдослучайных тестов

X := CovX.RandCovPoint; -- выбор непокрытых значений

Вывод отчета

CovX.WriteBin; -- отчет может быть достаточно большим

Сохранение базы данных

CovX.WriteCovDb("covdb.txt", OpenKind => WRITE_MODE);

 

Создание корзин (модели покрытия)

Функциональное покрытие осуществляется распределением значений переменных проекта по заранее определённым корзинам (bins) – диапазонам значений, которые имеют специальное назначение в проекте. Для корзин, использующих только одну переменную, создается структура данных, которую называют элементом покрытия (coverage item) или точкой покрытия (coverage point). По корзинам перекрёстного покрытия (cross coverage bins) распределяются пары (тройки и т.д.) значений двух либо нескольких переменных. Для корзин, использующих две и более переменные, создается структура данных, называемая элементом перекрёстного покрытия (cross coverage item).

В пакете CoveragePkg для корзины определена запись CovBinBaseType со следующими полями: BinVal – массив, включающий минимальное и максимальное значения интервала собираемых корзиной значений; Count – текущее (при моделировании) число попаданий в корзину значений из диапазона BinVal; AtLeast – цель покрытия задаёт число попаданий, при котором корзина будет считаться покрытой; Weight – вес – это целое (не равное нулю) положительное число, по которому вычисляется вероятность выбора корзины при использовании метода RandCovPoint; Action – действие (корзина может быть запрещенной, игнорируемой или рабочей), для рабочей корзины считается число попаданий. Тип CovBinType представляет собой массив записей CovBinBaseType. Создание корзин (тип CovBinType) осуществляется вызовом функции GenBin. Метод AddBins используется для последовательного добавления созданных корзин в структуру данных покрытия – переменную, заданную в защищенном типе CovPType.

Функция GenBin является перегруженной и может вызываться с числом целочисленных аргументов от одного до пяти: AtLeast – цель покрытия, Weight – вес, Min – нижняя граница диапазона, Max – верхняя граница диапазона, NumBin – число корзин, на которое нужно разделить диапазон [Min, Max]. Функция GenBin возвращает тип CovBinType. Например, следующая команда создает три корзины с диапазонами собираемых значений [1, 2], [3, 4], [5, 6], устанавливает для каждой корзины цель покрытия равную 3, а метод AddBins добавляет корзины в структуру данных покрытия.

--                AtLeast  Min  Max  NumBin
CovX.AddBins( GenBin(  3,   1,   6,   3) );

При вызове функции GenBin с двумя аргументами (Min, Max) будет создано N корзин, где N = MaxMin + 1. Следующие три вызова функции GenBin являются эквивалентными и создают одну корзину с диапазоном собираемых значений [7, 7], значение цели покрытия и веса для данной корзины устанавливаются равными 1.

CovX.AddBins( GenBin(5) );
CovX.AddBins( GenBin(5, 5) );
CovX.AddBins( GenBin(5, 5, 1) );

Каждый раз, когда вызывается метод AddBins, новые корзины добавляются после уже созданных корзин. Метод AddBins является перегруженным и позволяет задавать цель покрытия и вес для добавляемых корзин. Используя раздельные вызовы AddBins, каждая корзина может иметь различные цель покрытия и/или вес псевдослучайного тестирования.

При создании корзин, иногда необходимо обозначить их так, чтобы при попадании значений в них реагировать как на ошибки или игнорировать и не считать их. Перегруженные функции IllegalBin и IgnoreBin используются для создания запрещённых и игнорируемых корзин и могут вызываться с одним, двумя либо тремя аргументами. При вызове функций IllegalBin и IgnoreBin с тремя аргументами задаются: минимальное (Min) и максимальное (Max) значения диапазона, и число корзин (NumBin) на которое разбивается заданный диапазон.

-- 3 запрещённые корзины: [1,3], [4,6], [7,9]
CovX.AddBins( IllegalBin(1, 9, 3) );
-- 1 запрещенная корзина [1,9]
CovX.AddBins( IllegalBin(1, 9, 1) );
-- 3 игнорируемые корзины: [1,1], [2,2], [3,3]
CovX.AddBins( IgnoreBin ( 1, 3, 3) );

Вызов функций IgnoreBin и IllegalBin с двумя параметрами (Min, Max) приведёт к созданию одной корзины с диапазоном [Min, Max]. При вызове данных функций с одним параметром создаётся одна корзина с единичным диапазоном собираемых значений.

Так как все функции GenBin, IllegalBin и IgnoreBin возвращают значение типа CovBinType, их результаты могут быть объединены с помощью оператора конкатенации. В приведенном ниже примере будут добавлены шесть допустимых корзин [0, 0], [1, 1], [2, 5], [6, 9], [14, 14], [15, 15], одна игнорируемая корзина [10, 13], а все остальные корзины попадают в запрещённую корзину.

CovX.AddBins(
 GenBin(0,1) & GenBin(2,9,2) & GenBin(14,15)
 & IgnoreBin(10, 13)
 & ALL_ILLEGAL);

Кроме приведенной константы ALL_ILLEGAL, означающей запрещенную корзину с диапазоном значений [integer'left, integer'right], в пакете CoveragePkg декларируются следующие константы: ALL_BIN и ALL_COUNT – являются синонимами и обозначают рабочую корзину [integer'left, integer'right], ALL_IGNORE – игнорируемая корзина [integer'left, integer'right], ZERO_BIN – рабочая корзина [0, 0], ONE_BIN – рабочая корзина [1, 1]. Порядок добавления корзин в структуру данных покрытия имеет значение, т.к. по умолчанию установлен режим COUNT_FIRST, при котором собираемое значение распределяется в первую подходящую корзину. Чтобы задать режим, при котором собираемое значение распределяется по всем подходящим корзинам, необходимо вызвать метод SetCountMode с параметром COUNT_ALL.

Метод AddCross используется для добавления перекрестных корзин в структуру данных покрытия. При вызове метода AddCross, также как AddBins, можно передавать дополнительные параметры, задающие цель покрытия и вес псевдослучайного тестирования.

CovXY.AddCross( GenBin(0,3), GenBin(0,3) );

Метод AddCross создаёт векторное произведение корзин, заданных в качестве входных аргументов. Каждый вызов GenBin(0,3) создаёт четыре корзины: 0, 1, 2, 3. В результате чего AddCross создаёт 16 корзин со следующими парами: (0,0), (0,1), (0,2), (0,3), (1,0), (1,1), (1,2), (1,3), … , (3,0), (3,1), (3,2), (3,3). В приведённом примере используется перекрестное покрытие между двумя элементами, но метод AddCross поддерживает пересечение до 20 элементов.

Метод ICover используется для сбора покрытия. Для точек покрытия, метод ICover принимает значение integer. Для перекрёстного покрытия, метод ICover принимает значение integer_vector. Примеры вызова метода приведены ниже. Для обозначения типа integer_vector требуется вторая пара круглых скобок.

CovX.ICover( X );
CovXY.ICover( (X, Y) );

Процедуры WriteBin и WriteCovHoles используются для вывода отчета о покрытии.

procedure WriteBin ;
procedure WriteBin (FileName : string; OpenKind : File_Open_Kind := APPEND_MODE) ;
procedure WriteCovHoles ( PercentCov : real := 100.0 ) ;
procedure WriteCovHoles ( FileName : string;
   PercentCov : real := 100.0 ;
   OpenKind : File_Open_Kind := APPEND_MODE );

Метод WriteBin печатает (выводит) результаты покрытия с выводом одной корзины на строку. Есть две версии. Первая не имеет аргументов и выводит в стандартный поток OUTPUT. Это показано ниже. Следует обратить внимание, что корзины, отмеченные как игнорируемые не выводятся WriteBin, а корзины отмеченные как запрещённые выводятся только если они имеют не нулевые значения счетчика (счёта).

ReportCov : process
begin
 wait 
  until rising_edge(Clk) and CovX.IsCovered ;
 CovX.WriteBin ;
 wait ;
end process ;

Другая версия метода принимает два аргумента. Первый аргумент FileName задаёт имя файла (тип string). Второй аргумент задаёт значение OpenKind (to file_open) и принимает одно из значений WRITE_MODE или APPEND_MODE. Аргумент OpenKind инициализируется в значение APPEND_MODE.

--                FileName,    OpenKind
CovBin1.WriteBin ("Test1.txt", WRITE_MODE);

Метод WriteCovHoles выводит результаты покрытия, которые ниже параметра PercentCov. Следует обратить внимание, что корзины, помеченные как запрещённые или игнорируемые, не выводятся методом WriteCovHoles. Параметр ProcentCov инициализируется в 100% и обычно таким и остается.

CovX.WriteCovHoles ;

Другая версия WriteCovHoles задаёт FileName, PercentCov, и OpenKind в похожем стиле метода WriteBin. Аргумент инициализируется в APPEND_MODE. Это показано ниже.

--                 FileName,    PercentCov, OpenKind
CovX.WriteCovHoles("Test1.txt", 100.0,      APPEND_MODE);

Методы SetName и SetItemName используютя для печати первой и второй строки заголовка для методов WriteBin и WriteCovHoles. SetName предназначается для ссылки на имя или цель корзины покрытия. SetItemName предназначена для вывода столбцов заголовка для корзин покрытия. Каждая из них также использует их строковые параметры для инициализации внутреннего начального значения(seed) для псевдослучайного генератора чисел.

 

V. Использование пакетов

В примере демонстрируется использование пакетов RandomPkg и CoveragePkg. Заданы два сигнала целочисленного типа, принимающие значения из диапазонов [0, 3] и [0, 4] соответственно, необходимо сгенерировать все возможные пары значений не менее двух раз. В программе декларируются две пары сигналов X, Y и A, B. Для генерации значений X, Y используется метод RandInt из пакета RandomPkg, а для A, B – метод RandCovPoint из пакета CoveragePkg для проведения интеллектуального покрытия.

library ieee;
use work.RandomPkg.all;
use work.CoveragePkg.all;
entity example is
end entity example;
architecture beh of example is
 signal X, Y, A, B : natural;
 shared variable CrossXY, CrossAB : CovPType;
begin
 p1: process is
  variable RndX : RandomPtype;
  variable RndY : RandomPtype;
 begin
  CrossXY.AddCross(2,GenBin(0,3),GenBin(0,4));
  RndX.InitSeed(RndX'instance_name);
  RndY.InitSeed(RndY'instance_name);
  l1: while not CrossXY.IsCovered loop
   X <= RndX.RandInt(0,3);
   Y <= RndY.RandInt(4);
   wait for 10 ns;
   CrossXY.ICover((X, Y));
  end loop;
  CrossXY.WriteBin; 
  wait;
 end process p1;
 p2: process is
 begin
  CrossAB.AddCross(2,GenBin(0,3),GenBin(0,4));
  l1: while not CrossAB.IsCovered loop
    (A, B) <= CrossAB.RandCovPoint;
    wait for 10 ns;
    CrossAB.ICover((A, B));
  end loop;
  CrossAB.WriteBin; 
  wait;
 end process p2;
end architecture beh;

Для каждой из пар сигналов (X, Y и A, B) собирается перекрестное покрытие с помощью общих переменных CrossXY и CrossAB. В результате моделирования для покрытия всех пар значений X, Y дважды потребовалось 105 циклов, а для покрытия A, B – 40 циклов. В табл. 2 приведены результаты покрытия пары X, Y, в табл. 3 – пары A, B. Из табл. 2 видно, что при использовании псевдослучайного генератора с линейным законом распределения (uniform) распределение пар значений X, Y не равномерно. Пара чисел (2, 3) генерировалась 10 раз, а пара (0, 1) – 2 раза.

Таблица 2 - Распределение пар значений X, Y

Значения

X

Значения Y

0

1

2

3

4

0

6

2

6

4

3

1

4

6

3

6

7

2

6

5

3

10

6

3

9

6

4

3

6

 

Таблица 3 - Распределение пар значений A, B

Значения A

Значения B

0

1

2

3

4

0

2

2

2

2

2

1

2

2

2

2

2

2

2

2

2

2

2

3

2

2

2

2

2

 

Таким образом, использование интеллектуального покрытия в тестирующей программе позволяет значительно сократить необходимое число генерируемых псевдослучайных тестов для полного покрытия, что приводит к уменьшению времени моделирования.

Заключение

Пакеты RandomPkg и CoveragePkg, входящие в методологию OS-VVM, существенно расширяют возможности функциональной верификации с помощью языка VHDL, упрощая процесс разработки тестирующих программ, использующих управляемую генерацию псевдослучайных тестов и функциональное покрытие. Исходные тексты пакетов доступны в сети Internet, продолжают обновляться и хорошо документированы. В последних версиях системы моделирования Questasim фирмы Mentor Graphics появилась библиотека OS-VVM, в которой скомпилированы пакеты RandomPkg и CoveragePkg.

Литература

[1] Open source VHDL verification methodology. User’s Guide Rev. 1.2 [Electronic resource] / Ed. J. Lewis. – Mode of access: http://osvvm.org/downloads. – Date of access: 02.09.2013.

[2] Авдеев, Н. А. Средства VHDL для функциональной верификации цифровых систем. Методология OS-VVM. / Н. А. Авдеев, П. Н. Бибило // Современная электроника. – 2013. – № 5. – С. 66-70.

[3] Авдеев, Н. А. Средства VHDL для функциональной верификации цифровых систем / Н. А. Авдеев, П. Н. Бибило // Современная электроника. – 2013. – № 3. – С. 74-76.

[4] Авдеев, Н. А. Средства VHDL для функциональной верификации цифровых систем: пакет RandomPkg / Н. А. Авдеев, П. Н. Бибило // Современная электроника. – 2014. – № 1. – С. 60-65.

[5] Проектирование и верификация цифровых систем на кристаллах. Verilog & SystemVerilog / В. И. Хаханов [и др.]. – Харьков : ХНУРЭ, 2010. – 528 с.

20.10.2014


Пакет NUMERIC_STD языка VHDL

УДК 681.5:004.414.2

ПАКЕТ NUMERIC_STD ЯЗЫКА VHDL

Н.А. Авдеев, П.Н. Бибило

Объединенный институт проблем информатики Национальной академии наук Беларуси, г. Минск

  Изучается пакет NUMERIC_STD, предназначенный для согласования арифметических типов данных языка VHDL с логическими типами, построенными на базе девятизначного алфавита моделирования логических схем. Проблема согласования таких типов данных возникает при совместном использовании алгоритмических описаний и структурных описаний логических схем.

Введение

Язык VHDL (Very high speed integrated circuits Hardware Description Language) широко используется во всем мире для разработки цифровых систем. Первый стандарт VHDL’87 языка появился в 1987 году [1], второй стандарт VHDL’93 – в 1993 году [2]. В 1999 году был принят стандарт VHDL-AMS аналогового надмножества языка VHDL [3], что позволило проводить описание смешанных (цифро-аналоговых) схем. Желательно, чтобы читатель был знаком с основными элементами языка VHDL. С языком VHDL можно познакомиться по книгам [4 - 10]. Для VHDL разработаны и стандартизированы ряд пакетов [6, 7], в которых описаны различные арифметические и логические функции для работы с различными типами данных. Одним из самых важных является пакет STD_LOGIC_1164, в котором декларируется девятизначный тип std_ulogic для описания различных состояний сигналов в проводниках (межсоединениях) между элементами и устройствами и важный подтип std _logic этого типа. Для типа std_logic разрешается назначать значение сигнала из различных источников, что является удобным для описания монтажных соединений в логических схемах и описания шин. Соответствующая “разрешающая” функция имеется в пакете STD_LOGIC_1164. Заметим, что в общем случае ее необходимо написать самому разработчику VHDL-кода. Кроме того, имеющиеся в практике проектирования синтезаторы логических схем (LeonardoSpestrum, XST, Synplify и др.), позволяющие по исходным алгоритмическим VHDL-описаниям синтезировать логические схемы, используют для описания синтезированных схем типы std_logic, std_logic_vector. Последний тип является обобщением типа std_logic на случай векторов – одноразмерных массивов значений типа std_logic. Таким образом, если часть VHDL-проекта синтезирована и описывается в терминах девятизначного логического алфавита, а часть проекта остается на алгоритмическом уровне описания и использует типы INTEGER и NATURAL, то возникает проблема совместимости типов std_logic, std_logic_vector с типами INTEGER и NATURAL. Логические функции, описанные в пакете STD_ LOGIC_1164, не позволяют напрямую использовать тип std_logic совместно с целыми типами INTEGER и NATURAL. Для того чтобы упростить согласование алгоритмических и схемных описаний, разработан VHDL-пакет NUMERIC_STD. Пакет NUMERIC_STD ориентирован на стандарт языка VHDL’93 [2]. Если необходима совместимость с VHDL’87, то требуется из пакета NUMERIC_STD удалить (например, закомментировать двумя знаками дефис) декларации и тела функций xnor (логическая функция “эквивалентость”), sll, srl, rol, ror (функции сдвига). Данная работа посвящена описанию пакета NUMERIC_STD, его возможностям, особенностям и ограничениям, возникающим при моделировании VHDL-программ. Использование данного пакета при синтезе логических схем требует отдельного изучения и в данной работе не рассматривается. Приведенные в статье примеры работы функций пакета были проверены в системе моделирования ModelSim PE 5.7f, в которой содержится рассматриваемая в статье версия пакета NUMERIC_STD.

Основные типы данных

В пакете NUMERIC_STD определены два новых UNSIGNED, SIGNED числовых типа данных и различные арифметические функции над ними, которые поддерживаются системами синтеза. Тип UNSIGNED представляет собой числа без знака в векторном двоичном (булевом) представлении, а тип SIGNEDзнаковые числа (числа со знаком). Для векторов SIGNED старший (левый) бит определяет знак числа. Отрицательные числа представляются в дополнительном коде. Например, двоичный вектор 1001 представляет число –7. Вектор “1000” типа UNSIGNED понимается как 8, вектор “1000” типа SIGNED понимается как –8. Базовым элементом типов UNSIGNED и SIGNED является стандартный тип std_logic, описанный в пакете STD_LOGIC_1164. Тип std_logic является многозначным (перечислимым) подтипом типа std_ulogic (табл. 1). Типы UNSIGNED и SIGNED в пакете NUMERIC_STD (далее просто в пакете) определены следующим образом:
  type UNSIGNED is array (NATURAL range <>) of STD_LOGIC;
  type SIGNED is array (NATURAL range <>) of STD_LOGIC;
Размерности векторов UNSIGNED и SIGNED ограничены типом NATURAL, который определен в пакете STANDARD [7] как подтип типа INTEGER:
  type INTEGER is range -2147483648 to 2147483647;
  subtype NATURAL is integer range 0 to INTEGER‘high;
В VHDL через S'high обозначается атрибут “верхняя граница” объекта S. Следовательно, запись INTEGER'high означает верхнюю границу типа INTEGER. Далее в статье будут использоваться атрибуты 'left (левая граница), 'range (диапазон), 'length (длина диапазона). Заметим также, что в VHDL (и в текстах VHDL-кодов данной статьи) не различаются прописные и строчные буквы.  

Таблица 1 – Элементы базового типа std_ulogic

Элемент типа std_ulogic Описание
'U' не инициализировано (Uninitialized)
'X' сильное неизвестное (Forcing Unknown)
'0' сильный нуль (Forcing 0)
'1' сильная единица (Forcing 1)
'Z' высокий импеданс (High Impedance)
'W' слабое неизвестное (Weak Unknown)
'L' слабый нуль (Weak 0)
'H' слабая единица (Weak 1)
'–' безразлично (Don't care)
  Тип NATURAL включает в себя все положительные целые числа от 0 до 2147483647, а тип INTEGER – положительные и отрицательные числа от -2147483648 до 2147483647. Если перейти к двоичной системе счисления, то тип INTEGER ограничен 32-разрядным вектором, старший (левый) разряд которого означает знак числа ('0' – число положительное, '1' – число отрицательное). Тип NATURAL ограничен 31-разрядным двоичным вектором.

Функции пакета NUMERIC_STD

Пакет NUMERIC_STD содержит описания следующих функций над типами UNSIGNED и SIGNED:
  • функции, реализующие арифметические операции;
  • функции, реализующие операции сравнения;
  • функции сдвига (и вращения);
  • функции изменения размерности;
  • функции преобразования типов;
  • функции, реализующие логические операции.
В основе описания всех функций пакета лежат вспомогательные функции изменения типов (табл. 2), функция преобразования вектора (табл. 3), функции изменения размерности (табл. 4).

Функции изменения типов

Язык VHDL позволяет создавать несколько функций с одинаковым именем. Это называется перегрузкой функций. Функция TO_INTEGER (табл. 2) является перегруженной функцией, которая в пакете описана для двух типов аргументов: UNSIGNED и SIGNED. С помощью этой функции можно преобразовать любой вектор SIGNED размерности 1…32 бита или вектор UNSIGNED размерности 1…31 бит в целое число INTEGER или в целое положительное (натуральное) число NATURAL соответственно.  

Таблица 2 – Функции изменения типов (Conversion Functions)

Номер Функция Аргумент Новый размер (SIZE) Результат
D.1 TO_INTEGER UNSIGNED - NATURAL
D.2 TO_INTEGER SIGNED - INTEGER
D.3 TO_UNSIGNED NATURAL NATURAL UNSIGNED(SIZE-1 downto 0)
D.4 TO_SIGNED INTEGER NATURAL SIGNED(SIZE-1 downto 0)
Примечание. В табл. 2 (и других таблицах) номер – это номер, который функция имеет (в виде комментария) в пакете NUMERIC_STD. Номер облегчает поиск текста функции в пакете.

 

Пример применения функции TO_INTEGER.
  signal a_s : signed(3 downto 0) := "1011";
  signal a_u : unsigned(3 downto 0) := "1011";
  signal y_i : integer range -8 to 7 ;
  signal y_n : natural range  0 to 15 ;
    ...
  y_i <= to_integer(a_s);  -- результат y_i = -5
  y_n <= to_integer(a_u);  -- результат y_n = 11
Не следует использовать векторы, размерность которых превышает размерность типов INTEGER (32 бита) и NATURAL (31 бит), так как в некоторых ситуациях это может привести к неправильному результату функции, который не всегда просто отследить. Функция TO_UNSIGNED позволяет преобразовать положительное целое число NATURAL (из диапазона от 0 до 2147483647) в “беззнаковый” вектор UNSIGNED заданной размерности. Пример применения функции TO_UNSIGNED.
  signal a_n : natural := 8 ;
  signal y_u : unsigned(3 downto 0);
    . . .
  y_u <= to_unsigned(a_n, 4);  -- результат y_u = “1000”
С помощью функции TO_SIGNED можно преобразовать целое число INTEGER (из диапазона от -2147483648 до 2147483647) в знаковый вектор SIGNED заданной размерности. Пример применения функции TO_SIGNED.  
signal a_i : integer := -8 ;
signal y_s : signed(3 downto 0);
. . . 
y_s <= to_signed(a_i, 4);  -- результат y_s = “1000”

Если в функции TO_SIGNED или TO_UNSIGNED задать размерность для результирующего вектора меньше, чем необходимо для представления числа в двоичной форме, то старшие биты вектора-результата отбрасываются (теряются). Например,

 
y_u <= to_unsigned(16,4);   -- y_u = “0000”, старший бит 
                            -- отсутствует, т.к. 16 = “10000”
y_s <= to_signed(-9, 4);    -- y_s = “0111”, старший бит 
                            -- отсутствует, т.к. -9 = “10111”

Если в результате выполнения операции TO_SIGNED или TO_UNSIGNED потеряны старшие биты, то выдается одно из предупреждений:

# ** Warning: NUMERIC_STD.TO_SIGNED: vector truncated
# ** Warning: NUMERIC_STD.TO_UNSIGNED: vector truncated

при этом работа VHDL-программы не прекращается.

Функция TO_01 (табл. 3) побитно преобразует элементы 'H', 'L' входного вектора (тип SIGNED или UNSIGNED) в '1', '0' соответственно. Если хотя бы один из элементов входного вектора не равен одному из элементов подмножества {' H', '1', 'L', '0'}, то всем элементам результирующего вектора по умолчанию присваивается '0', или одно из возможных значений типа std_logic, которое можно указать при обращении к этой функции.  

Таблица 3 – Функция TO_01 преобразования вектора (Translation Function)

Номер Функция Аргумент (S) XMAP Результат
T.1, 2 TO_01 UNSIGNED SIGNED STD_LOGIC:='0 UNSIGNED(S'RANGE) SIGNED(S'RANGE)
  Пример применения функции TO_01.
  y_s <= to_01(a_s, 'U');	-- аргумент “H1L0” => результат “1100”
                                -- аргумент “HU10” => результат “UUUU”
  y_s <= to_01(a_s);	        -- аргумент “HLHL” => результат “1010”
                                -- аргумент “-101” => результат “0000”
  y_u <= to_01(a_u, '1');	-- аргумент “W101” => результат “1111”

Функции изменения размерности

Функция RESIZE (табл. 4) изменяет размерность вектора типа SIGNED или UNSIGNED. При увеличении размерности вектора UNSIGNED дополнительные старшие биты результирующего вектора заполняются нулями. При усечении вектора UNSIGNED лишние старшие биты результирующего вектора отбрасываются (теряются). При увеличении вектора SIGNED старший знаковый разряд копируется в дополнительные старшие биты, а при усечении вектора SIGNED старший знаковый разряд копируется в старший бит результирующего вектора.  

Таблица 4 – Функции изменения размерности (Resize Functions)

Номер Функция Аргумент Новый размер (NEW_SIZE) Результат
R.1 RESIZE SIGNED NATURAL SIGNED(NEW_SIZE-1 downto 0)
R.2 RESIZE UNSIGNED NATURAL UNSIGNED(NEW_SIZE-1 downto 0)
  Функция RESIZE написана таким образом, что работает со всеми значениями 'L', '0', 'H', '1', 'U', 'X', 'Z', 'W', '-' старшего (знакового) бита. Примеры, поясняющие работу функции RESIZE, приведены в табл. 5.  

Таблица 5 – Примеры работы функции RESIZE

Аргумент
ARG
Усечение вектора resize(ARG,3); Увеличение вектора resize(ARG,7);
unsigned(signed) unsigned signed unsigned signed
10010” 010” 110” 0010010” 1110010”
WHL01” L01” W01” 00WHL01” WWWHL01”
-W10L” 10L” -0L” 00-W10L” ---W10L”
X0101” 101” X01” 00X0101” XXX0101”
  Функцию RESIZE можно реализовать с помощью стандартной операции конкатенации (&). Если необходимо выполнить усечение вектора SIGNED, то выражение
min_s <= resize(a_s,NEW_SIZE_MIN);
и
min_s <= a_s(a_s'left) & a_s(NEW_SIZE_MIN-2 downto 0);
эквивалентны. Если необходимо увеличить размерность вектора SIGNED, то выражение
  max_s <= resize(a_s,NEW_SIZE_MAX);
и
  max_s <= ( NEW_SIZE_MAX-1 downto (a_s'left+1) => a_s(a_s'left) ) & a_s(a_s'left downto 0);
эквивалентны. Если необходимо выполнить усечение вектора UNSIGNED, то выражение
min_u <= resize(a_u,NEW_SIZE_MIN);
и
min_u <= a_u(NEW_SIZE_MIN-1 downto 0);
эквивалентны. Если необходимо увеличить размерность вектора UNSIGNED, то выражение
  max_u <= resize(a_u,NEW_SIZE_MAX);
и
  max_u <= (NEW_SIZE_MAX-1 downto (a_u'left+1) => '0') & a_u(a_u'left downto 0);
также эквивалентны. Функции RESIZE и TO_01, в отличие от функций TO_INTEGER, TO_UNSIGNED, TO_SIGNED, работают корректно для векторов любой размерности не более 2147483647 бит (размерность типа NATURAL). Экспериментальная проверка была проведена для векторов размерностью 300 бит. Следует обратить внимание на следующее выражение:
  d_i <= TO_INTEGER(a_u);
В этом выражении аргументом функции TO_INTEGER является переменная (сигнал) a_u типа UNSIGNED, следовательно, в соответствии с табл. 2, функция TO_INTEGER вернет тип NATURAL. Таким образом, переменной d_i типа INTEGER присваивается значение типа NATURAL. Выражение d_i <= TO_INTEGER(a_u); система моделирования ModelSim не считает ошибкой, так как тип NATURAL является подтипом типа INTEGER. Использование такого вызова функции при выполнении VHDL-программы не повлечет ошибки, потому что все значения типа NATURAL входят в множество значений типа INTEGER. Проблемы в работе VHDL-программы могут возникнуть при использовании следующего оператора:
  c_n <= TO_INTEGER(a_s);
В этом случае переменной c_n типа NATURAL присваивается значение переменной a_s, которая имеет тип SIGNED. Система моделирования также не считает это ошибкой при компиляции VHDL-кода, но при выполнении VHDL-программы не исключен случай, когда переменная a_s примет отрицательное значение, и тогда работа VHDL-программы прекратится, так как отрицательное число нельзя присвоить переменной c_n, которая имеет тип NATURAL. Принимая во внимание вышесказанное, не рекомендуется совместное использование знаковых и “беззнаковых” типов в функциях.

Логические операции

В табл. 6 приведен список логических операций, описанных в пакете NUMERIC_STD.  

Таблица 6 – Логические операции (Logical Operators)

Номер Аргумент (L) Функция Аргумент (R) Результат
L.1, 8   not UNSIGNED UNSIGNED(L'LENGTH-1 downto 0)
SIGNED SIGNED(L'LENGTH-1 downto 0)
L.2-6 UNSIGNED and or nand nor xor UNSIGNED UNSIGNED(L'LENGTH-1 downto 0)
L.9-13 SIGNED SIGNED SIGNED(L'LENGTH-1 downto 0)
L.7, 14 UNSIGNED xnor UNSIGNED UNSIGNED(L'LENGTH-1 downto 0)
SIGNED SIGNED SIGNED(L'LENGTH-1 downto 0)
  Размерности левого (L) и правого (R) аргументов логических функций (табл. 6) обязательно должны совпадать. Размерность результата равна размерности аргументов. Все логические функции выполняются с помощью логических функций, оперирующих с векторами типа std_logic_vector. Данные функции описаны в пакете STD_LOGIC_1164. Пример описания логической функции and в пакете NUMERIC_STD.
-- Id: L.2
function "and" (L, R: UNSIGNED) return UNSIGNED is
  variable RESULT: UNSIGNED(L'LENGTH-1 downto 0);
begin
  RESULT := UNSIGNED(STD_LOGIC_VECTOR(L) and STD_LOGIC_VECTOR(R));
  return RESULT;
end "and";
При выполнении логических операций значение 'H' эквивалентно '1', а 'L' эквивалентно '0': Пример логической операции and (И).
  "HLHL" and "1111" = "1010"
Если значение компонента вектора равно 'U', то и результат любой логической операции над этим компонентом равен 'U'. Значение 'X' получается, если компонент вектора равен одному из следующих значений {'X', 'Z', 'W', '–'}. Пример логической операции or (ИЛИ).
  "UX01ZWLH–" or "–01HLUXWZ" = "UX11XUXXX"
 

Операции сдвига

В пакете описаны две группы операций (операторов) сдвига и вращения (табл. 7). Первая группа состоит из операторов SHIFT_RIGHT (сдвиг вправо), SHIFT_LEFT (сдвиг влево), ROTATE_LEFT (вращение влево), ROTATE_RIGHT (вращение вправо), описанных для векторов типа UNSIGNED и SIGNED: Пример применения операторов сдвига SHIFT_RIGHT, SHIFT_LEFT, ROTATE_RIGHT, ROTATE_LEFT.
signal sr_u, sl_u : UNSIGNED(7 downto 0);
signal sr_s, sl_s : SIGNED(7 downto 0);
signal rr_u, rl_u : UNSIGNED(7 downto 0);
signal rr_s, rl_s : SIGNED(7 downto 0);
..
sr_u <= SHIFT_RIGHT("11001001",2);    -- sr_u = "00110010"
sr_s <= SHIFT_RIGHT("11011010",3);    -- sr_s = "11111011"

sl_u <= SHIFT_LEFT("11001100",2);     -- sl_u = "00110000"
sl_s <= SHIFT_LEFT("00110011",4);     -- sl_s = "00110000"

rr_u <= ROTATE_RIGHT("00110011",2);   -- rr_u = "11001100"
rr_s <= ROTATE_RIGHT("11100011",2);   -- rr_s = "11111000"

rl_u <= ROTATE_LEFT("11000011",3);    -- rl_u = "00011110"
rl_s <= ROTATE_LEFT("10110111",5);    -- rl_s = "11110110"
Следует обратить внимание на работу оператора SHIFT_RIGHT. Если аргументом этой функции является вектор SIGNED, то в освободившиеся при сдвиге старшие разряды (левые) записывается значение старшего разряда вектора–аргумента.  

Таблица 7 – Функции сдвига и вращения (Shift and Rotate Functions)

Номер Функция Аргумент Шаг сдвига
(COUNT)
S.1 SHIFT_LEFT UNSIGNED NATURAL
S.3 SIGNED
S.2 SHIFT_RIGHT UNSIGNED NATURAL
S.4 SIGNED
S.5 ROTATE_LEFT UNSIGNED NATURAL
S.7 SIGNED
S.6 ROTATE_RIGHT UNSIGNED NATURAL
S.8 SIGNED
S.9 sll UNSIGNED INTEGER
S.10 SIGNED
S.11 srl UNSIGNED INTEGER
S.12 SIGNED
S.13 rol UNSIGNED INTEGER
S.14 SIGNED
S.15 ror UNSIGNED INTEGER
S.16 SIGNED
  Пример применения операторов сдвига SHIFT_RIGHT.
  signal sr_s, sr_s1 : SIGNED(7 downto 0);
    ..
  sr_s  <= SHIFT_RIGHT("11011010",3);   -- sr_s  = "11111011"
  sr_s1 <= SHIFT_RIGHT("01011010",3);   -- sr_s1 = "00001011"
Операторы sll (сдвиг влево), srl (сдвиг вправо), rol (вращение влево), ror (вращение вправо) второй группы выполняют те же функции, что и соответствующие операторы из первой группы, но имеют следующие отличия:
  • функции sll, srl, rol, ror не совместимы с VHDL’87;
  • обращение к этим функциям как к операторам, например, чтобы сдвинуть вектор a на два бита вправо, надо записать a srl 2;
  • позволяют задавать сдвиг не только положительным, но и отрицательным числом. Последнее означает изменение направления сдвига на противоположное.
Пример применения операторов сдвига sll, srl.
signal sll_u, srl_u : UNSIGNED(7 downto 0);
signal sll_s, srl_s : SIGNED(7 downto 0);

signal sll_u1, srl_u1 : UNSIGNED(7 downto 0);
signal sll_s1, srl_s1 : SIGNED(7 downto 0);
..
srl_u  <= "10100111" srl 3;           -- srl_u  = "00010100"
srl_s  <= "11100110" srl 1;           -- srl_s  = "01110011"

srl_u1 <= "10100111" srl -3;          -- srl_u1 = "00111000"
srl_s1 <= "01100110" srl -1;          -- srl_s1 = "11001100"

sll_u  <= "11010111" sll 2;           -- sll_u  = "01011100"
sll_s  <= "11100110" sll 1;           -- sll_s  = "11001100"

sll_u1 <= "11010111" sll -2;          -- sll_u1 = "00110101"
sll_s1 <= "11100110" sll -1;          -- sll_s1 = "01110011"
При сдвиге вправо с помощью операторов sll, srl вектора SIGNED не происходит “размножения” знака вектора в освободившиеся старшие разряды результирующего вектора, как в операторе SHIFT_RIGHT Пример применения операторов sll, srl для сдвига вправо вектора SIGNED.
signal srl2_s, srl3_s : SIGNED(7 downto 0);
signal sll2_s, sll3_s : SIGNED(7 downto 0);
..
srl2_s <= "01101110" srl 3;           -- srl2_s = "00001101"
srl3_s <= "11101110" srl 3;           -- srl3_s = "00011101"

sll2_s <= "00111001" sll -2;          -- sll2_s = "00001110"
sll3_s <= "10111001" sll -2;          -- sll3_s = "00101110"
Это связано с особенностью описания тела функций sll, srl в пакете. Пример описания функций сдвига sll, srl в пакете NUMERIC_STD.
-- Id: S.12
  function "srl" (ARG: SIGNED; COUNT: INTEGER) return SIGNED is
  begin
    if (COUNT >= 0) then
      return SIGNED(SHIFT_RIGHT(UNSIGNED(ARG), COUNT));
    else
      return SHIFT_LEFT(ARG, -COUNT);
    end if;
  end "srl";

-- Id: S.10
  function "sll" (ARG: SIGNED; COUNT: INTEGER) return SIGNED is
  begin
    if (COUNT >= 0) then
      return SHIFT_LEFT(ARG, COUNT);
    else
      return SIGNED(SHIFT_RIGHT(UNSIGNED(ARG), -COUNT));
    end if;
  end "sll";
Как видно из описания для сдвига вектора вправо, вектор SIGNED преобразуется в вектор UNSIGNED и передается функции SHIFT_RIGHT, которая не размножает старший (знаковый) разряд вектора. Пример применения операторов вращения rol, ror.
signal rol_u, ror_u : UNSIGNED(7 downto 0);
signal rol_s, ror_s : SIGNED(7 downto 0);
signal rol_u1, ror_u1 : UNSIGNED(7 downto 0);
signal rol_s1, ror_s1 : SIGNED(7 downto 0);
..
rol_u  <= "01101110" rol 2;           -- rol_u  = "10111001"
rol_s  <= "10110111" rol 3;           -- rol_s  = "10111101"

rol_u1 <= "01101110" rol -2;          -- rol_u1 = "10011011"
rol_s1 <= "10110111" rol -3;          -- rol_s1 = "11110110"

ror_u  <= "10110111" ror 3;           -- ror_u  = "11110110"
ror_s  <= "01101111" ror 3;           -- ror_s  = "11101101"

ror_u1 <= "10110111" ror -3;          -- ror_u1 = "10111101"
ror_s1 <= "01101111" ror -3;          -- ror_s1 = "01111011"
Функции сдвига работают с векторами любой длины, которая ограничена размерностью типа NATURAL. Операции сдвига можно заменить стандартным оператором & конкатенации. Пример замены оператора сдвига SHIFT_RIGHT оператором конкатенации.
signal c_sr_s, sr_s, byte : SIGNED(7 downto 0);
..
byte <= "11101110";

sr_s <= SHIFT_RIGHT(byte,3);   -- результат sr_s = “11111101”

c_sr_s <= (7 downto 5 => byte(byte'length-1))&byte(7 downto 3);
                                -- результат c_sr_s = “11111101”
Пример замены оператора сдвига rol оператором конкатенации
signal c_rol_u, rol_u, byte_u : UNSIGNED(7 downto 0);
..
byte_u <= "11011100";
rol_u <= byte_u rol 3;    -- результат rol_u = “11100110”
c_rol_u <= byte_u(4 downto 0)&byte_u(7 downto 5);
                           -- результат c_rol_u = “11100110”
 

Операции сравнения

Описанные в пакете функции сравнения приведены в табл. 8. Если хотя бы один из аргументов L, R (табл. 8) содержит один или несколько символов, не входящих в подмножество {'H','L','0','1'}, то результат сравнения равен false и выдается предупреждение
  "NUMERIC_STD.""*"": metavalue detected, returning FALSE",
где * – выполняемая операция сравнения (>, <, <=, >=, =, /=). Сравниваемые с помощью операций табл. 8 векторы могут быть разной длины. Все функции сравнения основаны на функциях сравнения векторов STD_LOGIC_VECTOR из пакета STD_LOGIC_1164.  

Таблица 8 – Операции сравнения (Comparison Operators, Match Functions)

Номер Аргумент (L) Функция Аргумент (R) Результат
C.1, 7, 13, 19, 25, 31 UNSIGNED >, <,>=, <=, =, /= UNSIGNED BOOLEAN
C.2, 8, 14, 20, 26, 32 SIGNED SIGNED
C.3, 9, 15, 21, 27, 33 NATURAL UNSIGNED
C.4, 10, 16, 22, 28, 34 INTEGER SIGNED
C.5, 11, 17, 23, 29, 35 UNSIGNED NATURAL
C.6, 12, 18, 24, 30, 36 SIGNED INTEGER
M.1 STD_ULOGIC STD_MATCH STD_ULOGIC BOOLEAN
M.2 UNSIGNED UNSIGNED
M.3 SIGNED SIGNED
M.4 STD_LOGIC_VECTOR STD_LOGIC_VECTOR
M.5 STD_ULOGIC_VECTOR STD_ULOGIC_VECTOR
  Операция STD_MATCH сравнивает два аргумента одинаковых типов на равенство. Аргументы могут быть следующих типов: std_ulogic, unsigned, signed, std_logic_vector, std_ulogic_vector. Типы аргументов обязательно должны совпадать. Операция STD_MATCH сравнивает аргументы по следующим правилам.
  1. При сравнении любого компонента вектора с значением '–' результат равен true.
  2. Значение 'H' при сравнении эквивалентно '1', а значение 'L эквивалентно '0'.
  3. Если значение компонента равно 'U','X','Z','W', то результат сравнения с любым (кроме '–') значением соответствующего компонента второго аргумента, будет равен false.
Ниже приведена компактная условная запись правил сравнения:     Длины аргументов в функции STD_MATCH должны совпадать, в противном случае на экран при моделировании выдается сообщение
  "NUMERIC_STD.STD_MATCH: L'LENGTH /= R'LENGTH, returning FALSE" 
и результату присваивается значение false. Возникает ошибка при использовании следующих операторов:
c_boolean <= “101” = “101”; -- ошибка
Возможно, система моделирования не может определить, какую функцию использовать, так как не может однозначно идентифицировать тип вектора “101”. Вектор “101” может иметь тип BIT_VECTOR, STD_LOGIC_VECTOR, SIGNED и т.д. Если же тип аргументов задан строго, то ошибки не возникает. Например,
c_boolean <= 10 = 10;     -- нет ошибки
не считается ошибкой. Здесь 10 – число INTEGER. В результате выполнения таких операторов (назначить сигналу c_boolean значение, равное результату проверки отношения равенства двух целых чисел 10) сигнал c_boolean примет значение true.  

Арифметические операции (Arithmetic Operators)

К арифметическим операциям относятся: abs (абсолютное значение),+ (сложение), (вычитание), * (умножение), / (деление, т.е. получение целой части частного), rem (получение остатка от деления), mod. Преимуществом типов UNSIGNED и SIGNED над типом STD_LOGIC_VECTOR является то, что для этих типов описаны арифметические операции (1), (2)
  UNSIGNED {+, –, *, /, rem, mod} UNSIGNED,                       (1)
  SIGNED {+, –, *, /, rem, mod} SIGNED,                           (2)
не только над векторами типов UNSIGNED, SIGNED, но и операции (3), (4)
  UNSIGNED{+,–,*,/,rem,mod} NATURAL,                              (3)
  SIGNED {+,–,*,/,rem,mod} INTEGER.                               (4)
над вектором и целым числом. Особенности работы, характерные для всех арифметических функций abs, , +, *, /, rem, mod, заключаются в следующем:
  • если один из аргументов, какой либо арифметической функции является вектором, в котором хотя бы один из компонентов вектора не равен '0','1','L','H', то результат функции будет вектор “XX…XX”;
  • если аргументами арифметической функции являются векторы, то их размерность ограничена размерностью типа NATURAL;
  • если одним из аргументов арифметической функции является целое число (NATURAL, INTEGER), то перед выполнением функции это число преобразуется в вектор с помощью соответствующей функции (TO_UNSIGNED, TO_SIGNED) изменения типа. Размерность этого вектора равна размерности второго аргумента, который является вектором. Таким образом, если целое число будет больше чем можно задать вектором такой размерности, то при преобразовании числа в вектор старшие (значащие) биты будут потеряны и результат операции будет неверный.
Функции “–” и “abs” описаны только для типа SIGNED (табл. 9). Данные функции возвращают вектор, размерность которого совпадает с размерностью аргумента. Функция “–” (изменение знака числа) возвращает число, взятое с противоположным знаком, а функция “abs” возвращает абсолютное значение числа (аргумента). Размерность аргументов этих функций ограничена типом NATURAL.  

Таблица 9 – Арифметические функции abs, –

Номер Функция Аргумент (ARG) Результат
A.1 abs SIGNED SIGNED(ARG'LENGTH-1 downto 0)
A.2 SIGNED SIGNED(ARG'LENGTH-1 downto 0)
  Пример применения функций abs, –.
  signal a_s, b_s, c_s : SIGNED(5 downto 0);
    ...
  a_s <= TO_SIGNED(-27,6);              -- a_s = "100101" (-27)
  b_s <= -(a_s);                        -- b_s = "011011" (27)
  c_s <= abs(a_s);                      -- c_s = "011011" (27)
При использовании данных функций необходимо учитывать следующую особенность их выполнения. Например, если взять четырехразрядный вектор SIGNED, присвоить ему значение –8 (“1000”) и применить к нему одну из функций abs, –, то результатом будет являться число –8 (“1000”), а не 8 (“1000”): Пример применения функций abs, –.
  signal a_s : SIGNED(3 downto 0) := “1000”; -- a_s = “1000” (-8)
  signal b_s, c_s : SIGNED(3 downto 0);
     ...
  b_s <= - (a_s);    -- результат b_s = -8 (“1000”)
  c_s <= abs(a_s);  -- результат c_s = -8 (“1000”)
Функции сложения, вычитания (табл. 10), умножения (табл. 11), деления (табл. 12) допускают выполнение операции (1), (2) не только над одноименными типами, но и операции (3), (4) для комбинаций типов. Следует придерживаться таких комбинаций и не использовать других, так как в пакете не описаны функции для типов аргументов, отличных от приведенных выше комбинаций. Следующие комбинации типов аргументов арифметических функций “официально” не поддерживаются:
UNSIGNED {арифметическая операция} SIGNED;
UNSIGNED {арифметическая операция} INTEGER;
SIGNED {арифметическая операция} NATURAL.
Функция “+” (“–”) осуществляет функцию сложения (разности) двух векторов (которые могут быть разной размерности) или вектора и целого числа. При сложении двух векторов (SIGNED, UNSIGNED) разной размерности результирующий вектор принимает размерность того из аргументов, который имеет большую разрядность.  

Таблица 10 – Функции арифметических операций сложения и вычитания

Номер Аргумент (L) Функ-ция Аргумент (R) Результат
A.3, A.9 UNSIGNED + UNSIGNED UNSIGNED(MAX(L'LENGTH, R'LENGTH)-1 downto 0)
A.4,10 SIGNED SIGNED SIGNED(MAX(L'LENGTH, R'LENGTH)-1 downto 0)
A.5, 11 UNSIGNED NATURAL UNSIGNED(L'LENGTH-1 downto 0)
A.6,12 NATURAL UNSIGNED UNSIGNED(R'LENGTH-1 downto 0)
A.7,13 INTEGER SIGNED SIGNED(R'LENGTH-1 downto 0)
A.8,14 SIGNED INTEGER SIGNED(L'LENGTH-1 downto 0)
  Пример применения функции сложения для векторов различной размерности.
-- Для unsigned
signal l_u : unsigned(3 downto 0) := “1100”;   -- “1100” = (12)
signal r_u : unsigned(5 downto 0) := “000100”; -- “000100” = (4)
signal c_u : unsigned(5 downto 0);
..
c_u <= l_u + r_u; 		-- результат c_u = “010000” (16)

-- Для signed
signal l_s : signed(3 downto 0) := “1010”;     -- (-6)
signal r_s : signed(5 downto 0) := “010010”;   -- (18)
signal c_s : signed(5 downto 0);
..
c_s <= l_s + r_s; -- c_s = “001100” (12)
При сложении (вычитании) вектора (SIGNED, UNSIGNED) и целого числа (NATURAL, INTEGER) результирующий вектор (независимо от значения целого числа) имеет размерность вектора. Пример применения функции сложения.
-- Для unsigned + natural
signal l_u  : unsigned(5 downto 0) := "000100"; -- "000100"=(4)
signal r_n  : natural := 5;
signal y_nu : unsigned(5 downto 0);
...
y_nu <= l_u + r_n;        -- результат y_nu = “001001” (9)

-- Для signed + integer
signal l_s  : signed(0 to 5) := "010010";  -- "010010" = (18)
signal r_i  : integer := -2; 
signal y_is : signed(5 downto 0);
...
y_is <= l_s + r_i;   -- результат y_is = “010000” (16)
  Рассмотрим пример сложения трехразрядного вектора (UNSIGNED) и целого числа 9 (NATURAL):
signal l_u : unsigned(2 downto 0) := "110"; -- "110" = (6)
signal r_n : natural range 0 to 15 := 9;    -- (9) = “1001”
Очевидно, что для представления r_n в двоичной форме необходимо четыре разряда. Если выполнить операцию сложения:
  signal y_nu : unsigned(2 downto 0);
     ...
  y_nu <= l_u + r_n; -- “110”(6) + 9(“1001”) = “111” (7) !Ошибка
то результат получается неверным, т.к. целое число 9 (“1001”) преобразуется к вектору размерности 3 и, следовательно, складываются векторы “110” + “001” = “111”. Чтобы избежать такой ошибки, необходимо предварительно перевести целое число в вектор необходимой размерности. Для этого можно использовать функцию to_unsigned:
signal l_u : unsigned(2 downto 0) := "110"; -- "110" = (6)
signal r_n : natural range 0 to 15 := 9;    -- (9) = “1001”
signal y_nu : unsigned(3 downto 0);
...
y_nu <= l_u + to_unsigned(r_n,4); 
                       -- “110”(6) + 9(“1001”) = “1111” (15)
В данном случае получается правильный результат (15), но если сложить целое число 9 с вектором “111” (7), то заданной выше разрядности недостаточно. Для получения правильного результата необходимо добавить еще один разряд, чтобы не потерять перенос (значение старшего разряда):
signal r_n : natural range 0 to 15 := 9;    -- (9) = “1001”
signal l_u  : unsigned(2 downto 0) := "111"; -- "111" = (7)
signal y_nu : unsigned(4 downto 0);
. . .
y_nu <= l_u + to_unsigned(r_n,5); 
                      -- “111”(7) + 9(“01001”) = “10000” (16)
или
y_nu <= l_u + ‘0’ & to_unsigned(r_n,4); 
                       -- “111”(7) + 9(“01001”) = “10000” (16)
При умножении двух векторов (табл. 11), размерность результирующего вектора равна сумме размеров векторов-аргументов. Пример применения функции умножения.
signal l_u : unsigned(3 downto 0) := "1101";  -- "1101" = (13)
signal r_u : unsigned(2 downto 0) := "100";   -- "100" = (4)
signal y_u : unsigned(6 downto 0); 
...    
y_u <= l_u * r_u;	-- результат y_u = “0110100” (52)
 

Таблица 11 – Функции арифметической операции умножения

Номер Аргумент (L) Функция Аргумент (R) Результат
A.15 UNSIGNED * UNSIGNED UNSIGNED((L'LENGTH+R'LENGTH-1) downto 0)
A.16 SIGNED SIGNED SIGNED((L'LENGTH+R'LENGTH-1) downto 0)
A.17 UNSIGNED NATURAL UNSIGNED((L'LENGTH+L'LENGTH-1) downto 0)
A.18 NATURAL UNSIGNED UNSIGNED((R'LENGTH+R'LENGTH-1) downto 0)
A.19 SIGNED INTEGER SIGNED((L'LENGTH+L'LENGTH-1) downto 0)
A.20 INTEGER SIGNED SIGNED((R'LENGTH+R'LENGTH-1) downto 0)
  При умножении вектора и целого числа, результирующий вектор имеет удвоенную размерность вектора-аргумента: Пример применения функции умножения.
signal l_s : signed(4 downto 0) := "11101"; -- "11101" = (-3)
signal r_i : integer := 13;
signal y_s : signed(9 downto 0);
..
y_s <= l_s * r_i;       -- результат y_s = "1111011001" (-39)
При делении (табл. 12) одного вектора на другой, результатом является вектор, размерность которого равна размерности вектора-делимого.  

Таблица 12 – Функции деления

Номер Аргумент (L) Функция Аргумент (R) Результат
A.21 UNSIGNED / UNSIGNED UNSIGNED(L'LENGTH-1 downto 0)
A.22 SIGNED SIGNED SIGNED(L'LENGTH-1 downto 0)
A.23 UNSIGNED NATURAL UNSIGNED(L'LENGTH-1 downto 0)
A.24 NATURAL UNSIGNED UNSIGNED(R'LENGTH-1 downto 0)
A.25 SIGNED INTEGER SIGNED(L'LENGTH-1 downto 0)
A.26 INTEGER SIGNED SIGNED(R'LENGTH-1 downto 0)
  При делении, когда делитель является вектором (UNSIGNED, SIGNED), а делимое целым числом (NATURAL, INTEGER), следует вести контроль того, чтобы значение целого числа-результата не превышало максимально возможного значения вектора-аргумента (делителя) заданной размерности
signal l_n : NATURAL := 20;
signal r_u : UNSIGNED(2 downto 0) := "010";
signal y_u : UNSIGNED(2 downto 0);
...
y_u <= l_n / r_u;  -- y_u = 20 / “010” = “010” – Ошибка
                   -- Для результата “1010” (10) нужно 4 бита
При возникновении такой ситуации выдается следующее предупреждение об ошибке:
# ** Warning: NUMERIC_STD."/": Quotient Truncated
При делении на нуль выдается сообщение об ошибке
# ** Error: DIV, MOD, or REM by zero,
но работа VHDL-программы продолжается. При этом результат деления не является определенным. Если значение делителя больше значения делимого, то результат деления 0. Нуль (вектор “00…00” или целое число 0) можно делить на любое число. Результат такой операции всегда 0. Если поделить на –1 наименьшее отрицательное число, представимое вектором заданной разрядности (это число представляется вектором, в котором имеется единица в левом разряде, а остальные разряды содержат нуль), то результатом будет являться само это число:
signal l_s : SIGNED(2 downto 0) := "100";     -- (-4)
signal y_s : SIGNED(2 downto 0);
...
y_s <= l_s /(-1); -- y_s = “100”(-4) / (-1) = “100”(-4) - Ошибка
Эта ошибка подобна ошибке в операции abc. Операторы rem и mod вычисляют остаток от деления. Результирующий вектор для операций rem и mod имеет размерность делителя, если аргументы векторы, а если один из аргументов является целым числом, то размерность результата равна размерности второго аргумента-вектора (табл. 13). В языке VHDL [1] операции rem и mod определяются следующим образом. Для операции L rem R должно выполняться соотношение
  L = (L/R)*R + (L rem R), 
где L/R целая часть частного, (L rem R) - результат выполнения операции rem (остаток). Остаток имеет знак операнда L. Для операции L mod R должно выполняться соотношение
  L = N*R + (L mod R), 
где N – некоторое целое число, (L mod R) – результат выполнения операции mod. Результат имеет знак операнда R. Пример выполнения операций rem, mod языка VHDL.
13 rem 5 = 3,                   13 mod 5 = 3;
13 rem (-5) = 3,                13 mod (-5) = -2;
(-13) rem 5 = -3,               (-13) mod 5 = 2;
(-13) rem (–5) = -3,            (-13) mod (–5) = -3.
 

Таблица 13 – Функции rem, mod

Номер Аргумент (L) Функция Аргумент (R) Результат
A.27, 33 UNSIGNED rem mod UNSIGNED UNSIGNED(R'LENGTH-1 downto 0)
A.28, 34 SIGNED SIGNED SIGNED(R'LENGTH-1 downto 0)
A.29, 35 UNSIGNED NATURAL UNSIGNED(L'LENGTH-1 downto 0)
A.30, 36 NATURAL UNSIGNED UNSIGNED(R'LENGTH-1 downto 0)
A.31, 37 SIGNED INTEGER SIGNED(L'LENGTH-1 downto 0)
A.32, 38 INTEGER SIGNED SIGNED(R'LENGTH-1 downto 0)
  Пример применения функций rem, mod (пакета NUMERIC_STD) для типа SIGNED.
"0011" rem "0101" = "0011"   -- 3 rem 5 = 3        
"0011" mod "0101" = "0011"   -- 3 mod 5 = 3

"1101" rem "0101" = "1101"   -- (-3) rem 5 = -3
"1101" mod "0101" = "0010"   -- (-3) mod 5 = 2

"0011" rem "1011" = "0011"   -- 3 rem (-5) = 3
"0011" mod "1011" = "1110"   -- 3 mod (-5) = -2

"1101" rem "1011" = "1101"   -- (-3) rem (-5) = -3
"1101" mod "1011" = "1101"   -- (-3) mod (-5) = -3
Как показано в примерах, для типа SIGNED функции rem, mod пакета NUMERIC_STD корректно реализуют соответствующие операции языка VHDL. Заметим, что результаты операций rem, mod над типом UNSIGNED одинаковы.

Заключение

Пакет NUMERIC_STD является удобным и достаточно надежным средством для согласования типов данных при моделировании смешанных VHDL-описаний – алгоритмических описаний и описаний логических схем. Рекомендуем пользователям, которые начинают использовать данный пакет в своей работе, провести лично проверку найденных (и представленных в данной статье) неточностей в работе функций этого пакета и предусмотреть возможные ошибки. Особенно внимательно нужно следить за размерностями векторов, представляющих результирующие значения операций, так как размерность результата операции числа и вектора определяется именно размерностью вектора.

ЛИТЕРАТУРА

  1. IEEE Standard VHDL Language Reference Manual, IEEE Std 1076-1987.
  2. IEEE Standard VHDL Language Reference Manual, IEEE Std 1076-1993.
  3. IEEE Standard VHDL Analog and Mixed-Signal Extensions, IEEE Std 1076.1-1999.
  4. Бибило П.Н. Синтез логических схем с использованием языка VHDL. – М.: СОЛОН-Р, 2002. – 384 с.
  5. Бибило П.Н. Основы языка VHDL. – М.: СОЛОН-Р, 2002. – 224 с.
  6. Сергиенко А.М. VHDL для проектирования вычислительных устройств. К.: ЧП “Корнейчук”, ООО “ТИД “ДС”, 2003. – 208 с.
  7. Перельройзен Е.З. Проектируем на VHDL – М.: СОЛОН - Пресс, 2004. – 448 с.
  8. Поляков А.К. Языки VHDL и VERILOG в проектировании цифровой аппаратуры. – М.: СОЛОН-Пресс, 2003. – 320 с.
  9. Стешенко В.Б. EDA. Практика автоматизированного проектирования радиоэлектронных устройств. – М.: “Нолидж”, 2002. – 768 с.
  10. Суворова Е.А., Шейнин Ю.Е. Проектирование цифровых систем на VHDL. – СПб.: БХВ-Петербург, 2003. – 576 с.

25.10.2012


Пакет STANDARD (VHDL-2008) — Листинг

package STANDARD is
-- Predefined enumeration types:
  type BOOLEAN is (FALSE, TRUE);
-- The predefined operations for this type are as follows:
-- function "and" (anonymous, anonymous: BOOLEAN) return BOOLEAN;
-- function "or" (anonymous, anonymous: BOOLEAN) return BOOLEAN;
-- function "nand" (anonymous, anonymous: BOOLEAN) return BOOLEAN;
-- function "nor" (anonymous, anonymous: BOOLEAN) return BOOLEAN;
-- function "xor" (anonymous, anonymous: BOOLEAN) return BOOLEAN;
-- function "xnor" (anonymous, anonymous: BOOLEAN) return BOOLEAN;
 
-- function "not" (anonymous: BOOLEAN) return BOOLEAN;
 
-- function "=" (anonymous, anonymous: BOOLEAN) return BOOLEAN;
-- function "/=" (anonymous, anonymous: BOOLEAN) return BOOLEAN;
-- function "<" (anonymous, anonymous: BOOLEAN) return BOOLEAN;
-- function "<=" (anonymous, anonymous: BOOLEAN) return BOOLEAN;
-- function ">" (anonymous, anonymous: BOOLEAN) return BOOLEAN;
-- function ">=" (anonymous, anonymous: BOOLEAN) return BOOLEAN;
 
-- function MINIMUM (L, R: BOOLEAN) return BOOLEAN;
-- function MAXIMUM (L, R: BOOLEAN) return BOOLEAN;
 
-- function RISING_EDGE (signal S: BOOLEAN) return BOOLEAN;
-- function FALLING_EDGE (signal S: BOOLEAN) return BOOLEAN;
 
  type BIT is ('0', '1');
-- The predefined operations for this type are as follows:
-- function "and" (anonymous, anonymous: BIT) return BIT;
-- function "or" (anonymous, anonymous: BIT) return BIT;
-- function "nand" (anonymous, anonymous: BIT) return BIT;
-- function "nor" (anonymous, anonymous: BIT) return BIT;
-- function "xor" (anonymous, anonymous: BIT) return BIT;
-- function "xnor" (anonymous, anonymous: BIT) return BIT;
-- function "not" (anonymous: BIT) return BIT;
-- function "=" (anonymous, anonymous: BIT) return BOOLEAN;
-- function "/=" (anonymous, anonymous: BIT) return BOOLEAN;
-- function "<" (anonymous, anonymous: BIT) return BOOLEAN;
-- function "<=" (anonymous, anonymous: BIT) return BOOLEAN;
-- function ">" (anonymous, anonymous: BIT) return BOOLEAN;
-- function ">=" (anonymous, anonymous: BIT) return BOOLEAN;
 
-- function "?=" (anonymous, anonymous: BIT) return BIT;
-- function "?/=" (anonymous, anonymous: BIT) return BIT;
-- function "?<" (anonymous, anonymous: BIT) return BIT;
-- function "?<=" (anonymous, anonymous: BIT) return BIT;
-- function "?>" (anonymous, anonymous: BIT) return BIT;
-- function "?>=" (anonymous, anonymous: BIT) return BIT;
-- function MINIMUM (L, R: BIT) return BIT;
-- function MAXIMUM (L, R: BIT) return BIT;
-- function "??" (anonymous: BIT) return BOOLEAN;
-- function RISING_EDGE (signal S: BIT) return BOOLEAN;
-- function FALLING_EDGE (signal S: BIT) return BOOLEAN;
  type CHARACTER is (
    NUL, SOH, STX, ETX, EOT, ENQ, ACK, BEL,
    BS, HT, LF, VT, FF, CR, SO, SI,
    DLE, DC1, DC2, DC3, DC4, NAK, SYN, ETB,
    CAN, EM, SUB, ESC, FSP, GSP, RSP, USP,
    ' ', '!', '"', '#', '$', '%', '&', ''',
    '(', ')', '*', '+', ',', '-', '.', '/',
    '0', '1', '2', '3', '4', '5', '6', '7',
    '8', '9', ':', ';', '<', '=', '>', '?',
    '@', 'A', 'B', 'C', 'D', 'E', 'F', 'G',
    'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O',
    'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W',
    'X', 'Y', 'Z', '[', '', ']', '^', '_',
    '`', 'a', 'b', 'c', 'd', 'e', 'f', 'g',
    'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o',
    'p', 'q', 'r', 's', 't', 'u', 'v', 'w',
    'x', 'y', 'z', '{', '|', '}', '~', DEL,
    C128, C129, C130, C131, C132, C133, C134, C135,
    C136, C137, C138, C139, C140, C141, C142, C143,
    C144, C145, C146, C147, C148, C149, C150, C151,
    C152, C153, C154, C155, C156, C157, C158, C159,
    ' ', '¡', '¢', '£', '¤', '¥', '¦', '§',
    ' ̈', '©', 'a', '«', '¬', '-', '®', ' ̄',
    '°', '±', '2', '3', ' ́', 'μ', '¶', '·',
    ' ̧', '1', 'o', '»', '14', '12', '34', '¿',
    'À', 'Á', 'Â', 'Ã', 'Ä', 'Å', 'Æ', 'Ç',
    'È', 'É', 'Ê', 'Ë', 'Ì', 'Í', 'Î', 'Ï',
    'Ð', 'Ñ', 'Ò', 'Ó', 'Ô', 'Õ', 'Ö', '×',
    'Ø', 'Ù', 'Ú', 'Û', 'Ü', 'Ý', 'Þ', 'ß',
    'à', 'á', 'â', 'ã', 'ä', 'å', 'æ', 'ç',
    'è', 'é', 'ê', 'ë', 'ì', 'í', 'î', 'ï',
    'ð', 'ñ', 'ò', 'ó', 'ô', 'õ', 'ö', '÷',
    'ø', 'ù', 'ú', 'û', 'ü', 'ý', 'þ', 'ÿ');
 
-- The predefined operations for this type are as follows:
-- function "=" (anonymous, anonymous: CHARACTER)
-- return BOOLEAN;
-- function "/=" (anonymous, anonymous: CHARACTER)
-- return BOOLEAN;
-- function "<" (anonymous, anonymous: CHARACTER)
-- return BOOLEAN;
-- function "<=" (anonymous, anonymous: CHARACTER)
-- return BOOLEAN;
-- function ">" (anonymous, anonymous: CHARACTER)
-- return BOOLEAN;
-- function ">=" (anonymous, anonymous: CHARACTER)
-- return BOOLEAN;
 
-- function MINIMUM (L, R: CHARACTER) return CHARACTER;
-- function MAXIMUM (L, R: CHARACTER) return CHARACTER;
 
  type SEVERITY_LEVEL is (NOTE, WARNING, ERROR, FAILURE);
 
-- The predefined operations for this type are as follows:
-- function "="  (anonymous, anonymous: SEVERITY_LEVEL)
-- return BOOLEAN;
-- function "/=" (anonymous, anonymous: SEVERITY_LEVEL)
-- return BOOLEAN;
-- function "<" (anonymous, anonymous: SEVERITY_LEVEL)
-- return BOOLEAN;
-- function "<=" (anonymous, anonymous: SEVERITY_LEVEL)
-- return BOOLEAN;
-- function ">" (anonymous, anonymous: SEVERITY_LEVEL)
-- return BOOLEAN;
-- function ">=" (anonymous, anonymous: SEVERITY_LEVEL)
-- return BOOLEAN;
 
-- function MINIMUM (L, R: SEVERITY_LEVEL) return SEVERITY_LEVEL;
-- function MAXIMUM (L, R: SEVERITY_LEVEL) return SEVERITY_LEVEL;
 
 
-- type universal_integer is range implementation_defined;
 
-- The predefined operations for this type are as follows:
-- function "=" (anonymous, anonymous: universal_integer)
-- return BOOLEAN;
-- function "/=" (anonymous, anonymous: universal_integer)
-- return BOOLEAN;
-- function "<" (anonymous, anonymous: universal_integer)
-- return BOOLEAN;
-- function "<=" (anonymous, anonymous: universal_integer)
-- return BOOLEAN;
-- function ">" (anonymous, anonymous: universal_integer)
-- return BOOLEAN;
-- function ">=" (anonymous, anonymous: universal_integer)
-- return BOOLEAN;
-- function "+" (anonymous: universal_integer)
-- return universal_integer;
-- function "-" (anonymous: universal_integer)
-- return universal_integer;
-- function "abs" (anonymous: universal_integer)
-- return universal_integer;
-- function "+" (anonymous, anonymous: universal_integer)
-- return universal_integer;
-- function "-" (anonymous, anonymous: universal_integer)
-- return universal_integer;
-- function "*" (anonymous, anonymous: universal_integer)
-- return universal_integer;
-- function "/" (anonymous, anonymous: universal_integer)
-- return universal_integer;
-- function "mod" (anonymous, anonymous: universal_integer)
-- return universal_integer;
-- function "rem" (anonymous, anonymous: universal_integer)
-- return universal_integer;
-- function MINIMUM (L, R: universal_integer)
-- return universal_integer;
-- function MAXIMUM (L, R: universal_integer)
-- return universal_integer;
 
 
-- type universal_real is range implementation_defined;
 
-- The predefined operations for this type are as follows:
-- function "=" (anonymous, anonymous: universal_real)
-- return BOOLEAN;
-- function "/=" (anonymous, anonymous: universal_real)
-- return BOOLEAN;
-- function "<" (anonymous, anonymous: universal_real)
-- return BOOLEAN;
-- function "<=" (anonymous, anonymous: universal_real)
-- return BOOLEAN;
-- function ">" (anonymous, anonymous: universal_real)
-- return BOOLEAN;
-- function ">=" (anonymous, anonymous: universal_real)
-- return BOOLEAN;
 
-- function "+" (anonymous: universal_real)
-- return universal_real;
-- function "-" (anonymous: universal_real)
-- return universal_real;
-- function "abs" (anonymous: universal_real)
-- return universal_real;
-- function "+" (anonymous, anonymous: universal_real) return universal_real;
-- function "-" (anonymous, anonymous: universal_real) return universal_real;
-- function "*" (anonymous, anonymous: universal_real) return universal_real;
-- function "/" (anonymous, anonymous: universal_real) return universal_real;
-- function "*" (anonymous: universal_real; anonymous: universal_integer) return universal_real;
-- function "*" (anonymous: universal_integer; anonymous: universal_real) return universal_real;
-- function "/" (anonymous: universal_real; anonymous: universal_integer) return universal_real;
 
-- function MINIMUM (L, R: universal_real) return universal_real;
-- function MAXIMUM (L, R: universal_real) return universal_real;
 
 
-- Predefined numeric types:
  type INTEGER is range implementation_defined;
 
-- The predefined operations for this type are as follows:
-- function "**" (anonymous: universal_integer;
-- anonymous: INTEGER) return universal_integer;
-- function "**" (anonymous: universal_real;
-- anonymous: INTEGER) return universal_real;
-- function "=" (anonymous, anonymous: INTEGER) return BOOLEAN;
-- function "/=" (anonymous, anonymous: INTEGER) return BOOLEAN;
-- function "<" (anonymous, anonymous: INTEGER) return BOOLEAN;
-- function "<=" (anonymous, anonymous: INTEGER) return BOOLEAN;
-- function ">" (anonymous, anonymous: INTEGER) return BOOLEAN;
-- function ">=" (anonymous, anonymous: INTEGER) return BOOLEAN;
-- function "+" (anonymous: INTEGER) return INTEGER;
-- function "-" (anonymous: INTEGER) return INTEGER;
-- function "abs" (anonymous: INTEGER) return INTEGER;
-- function "+" (anonymous, anonymous: INTEGER) return INTEGER;
-- function "-" (anonymous, anonymous: INTEGER) return INTEGER;
-- function "*" (anonymous, anonymous: INTEGER) return INTEGER;
-- function "/" (anonymous, anonymous: INTEGER) return INTEGER;
-- function "mod" (anonymous, anonymous: INTEGER) return INTEGER;
-- function "rem" (anonymous, anonymous: INTEGER) return INTEGER;
-- function "**" (anonymous: INTEGER; anonymous: INTEGER)
-- return INTEGER;
-- function MINIMUM (L, R: INTEGER) return INTEGER;
-- function MAXIMUM (L, R: INTEGER) return INTEGER;
 
  type REAL is range implementation_defined;
-- The predefined operations for this type are as follows:
-- function "=" (anonymous, anonymous: REAL) return BOOLEAN;
-- function "/=" (anonymous, anonymous: REAL) return BOOLEAN;
-- function "<" (anonymous, anonymous: REAL) return BOOLEAN;
-- function "<=" (anonymous, anonymous: REAL) return BOOLEAN;
-- function ">" (anonymous, anonymous: REAL) return BOOLEAN;
-- function ">=" (anonymous, anonymous: REAL) return BOOLEAN;
-- function "+" (anonymous: REAL) return REAL;
-- function "-" (anonymous: REAL) return REAL;
-- function "abs" (anonymous: REAL) return REAL;
-- function "+" (anonymous, anonymous: REAL) return REAL;
-- function "-" (anonymous, anonymous: REAL) return REAL;
-- function "*" (anonymous, anonymous: REAL) return REAL;
-- function "/" (anonymous, anonymous: REAL) return REAL;
-- function "**" (anonymous: REAL; anonymous: INTEGER) return REAL;
-- function MINIMUM (L, R: REAL) return REAL;
-- function MAXIMUM (L, R: REAL) return REAL;
 
-- Predefined type TIME:
  type TIME is range implementation_defined
    units
      fs; -- femtosecond
      ps = 1000 fs; -- picosecond
      ns = 1000 ps; -- nanosecond
      us = 1000 ns; -- microsecond
      ms = 1000 us; -- millisecond
      sec = 1000 ms; -- second
      min = 60 sec; -- minute
      hr = 60 min; -- hour
    end units;
 
-- The predefined operations for this type are as follows:
-- function "=" (anonymous, anonymous: TIME) return BOOLEAN;
-- function "/=" (anonymous, anonymous: TIME) return BOOLEAN;
-- function "<" (anonymous, anonymous: TIME) return BOOLEAN;
-- function "<=" (anonymous, anonymous: TIME) return BOOLEAN;
-- function ">" (anonymous, anonymous: TIME) return BOOLEAN;
-- function ">=" (anonymous, anonymous: TIME) return BOOLEAN;
-- function "+" (anonymous: TIME) return TIME;
-- function "-" (anonymous: TIME) return TIME;
-- function "abs" (anonymous: TIME) return TIME;
-- function "+" (anonymous, anonymous: TIME) return TIME;
-- function "-" (anonymous, anonymous: TIME) return TIME;
-- function "*" (anonymous: TIME; anonymous: INTEGER) return TIME;
-- function "*" (anonymous: TIME; anonymous: REAL) return TIME;
-- function "*" (anonymous: INTEGER; anonymous: TIME) return TIME;
-- function "*" (anonymous: REAL; anonymous: TIME) return TIME;
-- function "/" (anonymous: TIME; anonymous: INTEGER) return TIME;
-- function "/" (anonymous: TIME; anonymous: REAL) return TIME;
-- function "/" (anonymous, anonymous: TIME) return universal_integer;
-- function "mod" (anonymous, anonymous: TIME) return TIME;
-- function "rem" (anonymous, anonymous: TIME) return TIME;
-- function MINIMUM (L, R: TIME) return TIME;
-- function MAXIMUM (L, R: TIME) return TIME;
 
  subtype DELAY_LENGTH is TIME range 0 fs to TIME'HIGH;
 
-- A function that returns the current simulation time, Tc,
-- (see 14.7.5.1): 
  impure function NOW return DELAY_LENGTH;
 
-- Predefined numeric subtypes:
  subtype NATURAL is INTEGER range 0 to INTEGER'HIGH;
  subtype POSITIVE is INTEGER range 1 to INTEGER'HIGH;
 
-- Predefined array types:
  type STRING is array (POSITIVE range <>) of CHARACTER;
 
-- The predefined operations for these types are as follows:
-- function "=" (anonymous, anonymous: STRING) return BOOLEAN;
-- function "/=" (anonymous, anonymous: STRING) return BOOLEAN;
-- function "<" (anonymous, anonymous: STRING) return BOOLEAN;
-- function "<=" (anonymous, anonymous: STRING) return BOOLEAN;
-- function ">" (anonymous, anonymous: STRING) return BOOLEAN;
-- function ">=" (anonymous, anonymous: STRING) return BOOLEAN;
 
-- function "&" (anonymous: STRING; anonymous: STRING) return STRING;
-- function "&" (anonymous: STRING; anonymous: CHARACTER) return STRING;
-- function "&" (anonymous: CHARACTER; anonymous: STRING) return STRING;
-- function "&" (anonymous: CHARACTER; anonymous: CHARACTER) return STRING;
 
-- function MINIMUM (L, R: STRING) return STRING;
-- function MAXIMUM (L, R: STRING) return STRING;
-- function MINIMUM (L: STRING) return CHARACTER;
-- function MAXIMUM (L: STRING) return CHARACTER;
 
  type BOOLEAN_VECTOR is array (NATURAL range <>) of BOOLEAN;
-- The predefined operations for this type are as follows:
-- function "and" (anonymous, anonymous: BOOLEAN_VECTOR) return BOOLEAN_VECTOR;
-- function "or" (anonymous, anonymous: BOOLEAN_VECTOR) return BOOLEAN_VECTOR;
-- function "nand" (anonymous, anonymous: BOOLEAN_VECTOR) return BOOLEAN_VECTOR;
-- function "nor" (anonymous, anonymous: BOOLEAN_VECTOR) return BOOLEAN_VECTOR;
-- function "xor" (anonymous, anonymous: BOOLEAN_VECTOR) return BOOLEAN_VECTOR;
-- function "xnor" (anonymous, anonymous: BOOLEAN_VECTOR) return BOOLEAN_VECTOR;
 
-- function "not" (anonymous: BOOLEAN_VECTOR) return BOOLEAN_VECTOR;
 
-- function "and" (anonymous: BOOLEAN_VECTOR; anonymous: BOOLEAN) return BOOLEAN_VECTOR;
-- function "and" (anonymous: BOOLEAN; anonymous: BOOLEAN_VECTOR) return BOOLEAN_VECTOR;
-- function "or" (anonymous: BOOLEAN_VECTOR; anonymous: BOOLEAN) return BOOLEAN_VECTOR;
-- function "or" (anonymous: BOOLEAN; anonymous : BOOLEAN_VECTOR) return BOOLEAN_VECTOR;
-- function "nand" (anonymous: BOOLEAN_VECTOR; anonymous: BOOLEAN) return BOOLEAN_VECTOR;
-- function "nand" (anonymous: BOOLEAN; anonymous: BOOLEAN_VECTOR) return BOOLEAN_VECTOR;
-- function "nor" (anonymous: BOOLEAN_VECTOR; anonymous: BOOLEAN) return BOOLEAN_VECTOR;
-- function "nor" (anonymous: BOOLEAN; anonymous: BOOLEAN_VECTOR) return BOOLEAN_VECTOR;
-- function "xor" (anonymous: BOOLEAN_VECTOR; anonymous: BOOLEAN) return BOOLEAN_VECTOR;
-- function "xor" (anonymous: BOOLEAN; anonymous: BOOLEAN_VECTOR) return BOOLEAN_VECTOR;
-- function "xnor" (anonymous: BOOLEAN_VECTOR; anonymous: BOOLEAN) return BOOLEAN_VECTOR;
-- function "xnor" (anonymous: BOOLEAN; anonymous: BOOLEAN_VECTOR) return BOOLEAN_VECTOR;
 
-- function "and" (anonymous: BOOLEAN_VECTOR) return BOOLEAN;
-- function "or" (anonymous: BOOLEAN_VECTOR) return BOOLEAN;
-- function "nand" (anonymous: BOOLEAN_VECTOR) return BOOLEAN;
-- function "nor" (anonymous: BOOLEAN_VECTOR) return BOOLEAN;
-- function "xor" (anonymous: BOOLEAN_VECTOR) return BOOLEAN;
-- function "xnor" (anonymous: BOOLEAN_VECTOR) return BOOLEAN;
 
-- function "sll" (anonymous: BOOLEAN_VECTOR; anonymous: INTEGER) return BOOLEAN_VECTOR;
-- function "srl" (anonymous: BOOLEAN_VECTOR; anonymous: INTEGER) return BOOLEAN_VECTOR;
-- function "sla" (anonymous: BOOLEAN_VECTOR; anonymous: INTEGER) return BOOLEAN_VECTOR;
-- function "sra" (anonymous: BOOLEAN_VECTOR; anonymous: INTEGER) return BOOLEAN_VECTOR;
-- function "rol" (anonymous: BOOLEAN_VECTOR; anonymous: INTEGER) return BOOLEAN_VECTOR;
-- function "ror" (anonymous: BOOLEAN_VECTOR; anonymous: INTEGER) return BOOLEAN_VECTOR;
 
-- function "=" (anonymous, anonymous: BOOLEAN_VECTOR) return BOOLEAN;
-- function "/=" (anonymous, anonymous: BOOLEAN_VECTOR) return BOOLEAN;
-- function "<" (anonymous, anonymous: BOOLEAN_VECTOR) return BOOLEAN;
-- function "<=" (anonymous, anonymous: BOOLEAN_VECTOR) return BOOLEAN;
-- function ">" (anonymous, anonymous: BOOLEAN_VECTOR) return BOOLEAN;
-- function ">=" (anonymous, anonymous: BOOLEAN_VECTOR) return BOOLEAN;
-- function "?=" (anonymous, anonymous: BOOLEAN_VECTOR) return BOOLEAN;
-- function "?/=" (anonymous, anonymous: BOOLEAN_VECTOR) return BOOLEAN;
 
-- function "&" (anonymous: BOOLEAN_VECTOR; anonymous: BOOLEAN_VECTOR) return BOOLEAN_VECTOR;
-- function "&" (anonymous: BOOLEAN_VECTOR; anonymous: BOOLEAN) return BOOLEAN_VECTOR;
-- function "&" (anonymous: BOOLEAN; anonymous: BOOLEAN_VECTOR) return BOOLEAN_VECTOR;
-- function "&" (anonymous: BOOLEAN; anonymous: BOOLEAN) return BOOLEAN_VECTOR;
 
-- function MINIMUM (L, R: BOOLEAN_VECTOR) return BOOLEAN_VECTOR;
-- function MAXIMUM (L, R: BOOLEAN_VECTOR) return BOOLEAN_VECTOR;
-- function MINIMUM (L: BOOLEAN_VECTOR) return BOOLEAN;
-- function MAXIMUM (L: BOOLEAN_VECTOR) return BOOLEAN;
 
  type BIT_VECTOR is array (NATURAL range <>) of BIT;
 
-- The predefined operations for this type are as follows:
-- function "and" (anonymous, anonymous: BIT_VECTOR) return BIT_VECTOR;
-- function "or" (anonymous, anonymous: BIT_VECTOR) return BIT_VECTOR;
-- function "nand" (anonymous, anonymous: BIT_VECTOR) return BIT_VECTOR;
-- function "nor" (anonymous, anonymous: BIT_VECTOR) return BIT_VECTOR;
-- function "xor" (anonymous, anonymous: BIT_VECTOR) return BIT_VECTOR;
-- function "xnor" (anonymous, anonymous: BIT_VECTOR) return BIT_VECTOR;
 
-- function "not" (anonymous: BIT_VECTOR) return BIT_VECTOR;
 
-- function "and" (anonymous: BIT_VECTOR; anonymous : BIT) return BIT_VECTOR;
-- function "and" (anonymous: BIT; anonymous : BIT_VECTOR) return BIT_VECTOR;
-- function "or" (anonymous: BIT_VECTOR; anonymous : BIT) return BIT_VECTOR;
-- function "or" (anonymous: BIT; anonymous : BIT_VECTOR) return BIT_VECTOR;
-- function "nand" (anonymous: BIT_VECTOR; anonymous : BIT) return BIT_VECTOR;
-- function "nand" (anonymous: BIT; anonymous : BIT_VECTOR) return BIT_VECTOR;
-- function "nor" (anonymous: BIT_VECTOR; anonymous : BIT) return BIT_VECTOR;
-- function "nor" (anonymous: BIT; anonymous : BIT_VECTOR) return BIT_VECTOR;
-- function "xor" (anonymous: BIT_VECTOR; anonymous : BIT) return BIT_VECTOR;
-- function "xor" (anonymous: BIT; anonymous : BIT_VECTOR) return BIT_VECTOR;
-- function "xnor" (anonymous: BIT_VECTOR; anonymous : BIT) return BIT_VECTOR;
-- function "xnor" (anonymous: BIT; anonymous : BIT_VECTOR) return BIT_VECTOR;
 
-- function "and" (anonymous: BIT_VECTOR) return BIT;
-- function "or" (anonymous: BIT_VECTOR) return BIT;
-- function "nand" (anonymous: BIT_VECTOR) return BIT;
-- function "nor" (anonymous: BIT_VECTOR) return BIT;
-- function "xor" (anonymous: BIT_VECTOR) return BIT;
-- function "xnor" (anonymous: BIT_VECTOR) return BIT;
 
-- function "sll" (anonymous: BIT_VECTOR; anonymous: INTEGER) return BIT_VECTOR;
-- function "srl" (anonymous: BIT_VECTOR; anonymous: INTEGER) return BIT_VECTOR;
-- function "sla" (anonymous: BIT_VECTOR; anonymous: INTEGER) return BIT_VECTOR;
-- function "sra" (anonymous: BIT_VECTOR; anonymous: INTEGER) return BIT_VECTOR;
-- function "rol" (anonymous: BIT_VECTOR; anonymous: INTEGER) return BIT_VECTOR;
-- function "ror" (anonymous: BIT_VECTOR; anonymous: INTEGER) return BIT_VECTOR;
 
-- function "="  (anonymous, anonymous: BIT_VECTOR) return BOOLEAN;
-- function "/=" (anonymous, anonymous: BIT_VECTOR) return BOOLEAN;
-- function "<"  (anonymous, anonymous: BIT_VECTOR) return BOOLEAN;
-- function "<=" (anonymous, anonymous: BIT_VECTOR) return BOOLEAN;
-- function ">"  (anonymous, anonymous: BIT_VECTOR) return BOOLEAN;
-- function ">=" (anonymous, anonymous: BIT_VECTOR) return BOOLEAN;
-- function "?=" (anonymous, anonymous: BIT_VECTOR) return BIT;
-- function "?/=" (anonymous, anonymous: BIT_VECTOR) return BIT;
 
-- function "&" (anonymous: BIT_VECTOR; anonymous: BIT_VECTOR) return BIT_VECTOR;
-- function "&" (anonymous: BIT_VECTOR; anonymous: BIT) return BIT_VECTOR;
-- function "&" (anonymous: BIT; anonymous: BIT_VECTOR) return BIT_VECTOR;
-- function "&" (anonymous: BIT; anonymous: BIT) return BIT_VECTOR;
 
-- function MINIMUM (L, R: BIT_VECTOR) return BIT_VECTOR;
-- function MAXIMUM (L, R: BIT_VECTOR) return BIT_VECTOR;
-- function MINIMUM (L: BIT_VECTOR) return BIT;
-- function MAXIMUM (L: BIT_VECTOR) return BIT;
 
-- function TO_STRING (VALUE: BIT_VECTOR) return STRING;
-- alias TO_BSTRING is TO_STRING
--                     [BIT_VECTOR return STRING];
-- alias TO_BINARY_STRING is TO_STRING
--                     [BIT_VECTOR return STRING];
-- function TO_OSTRING (VALUE: BIT_VECTOR) return STRING;
-- alias TO_OCTAL_STRING is TO_OSTRING
--                     [BIT_VECTOR return STRING];
-- function TO_HSTRING (VALUE: BIT_VECTOR) return STRING;
-- alias TO_HEX_STRING is TO_HSTRING
--                     [BIT_VECTOR return STRING];
 
  type INTEGER_VECTOR is array (NATURAL range <>) of INTEGER;
 
-- The predefined operations for this type are as follows:
-- function "=" (anonymous, anonymous: INTEGER_VECTOR) return BOOLEAN;
-- function "/=" (anonymous, anonymous: INTEGER_VECTOR) return BOOLEAN;
-- function "<" (anonymous, anonymous: INTEGER_VECTOR) return BOOLEAN;
-- function "<=" (anonymous, anonymous: INTEGER_VECTOR) return BOOLEAN;
-- function ">" (anonymous, anonymous: INTEGER_VECTOR) return BOOLEAN;
-- function ">=" (anonymous, anonymous: INTEGER_VECTOR) return BOOLEAN;
-- function "&" (anonymous: INTEGER_VECTOR;
--               anonymous: INTEGER_VECTOR) return INTEGER_VECTOR;
-- function "&" (anonymous: INTEGER_VECTOR;
--               anonymous: INTEGER) return INTEGER_VECTOR;
-- function "&" (anonymous: INTEGER;
--               anonymous: INTEGER_VECTOR) return INTEGER_VECTOR;
-- function "&" (anonymous: INTEGER;
--               anonymous: INTEGER) return INTEGER_VECTOR;
-- function MINIMUM (L, R: INTEGER_VECTOR) return INTEGER_VECTOR;
-- function MAXIMUM (L, R: INTEGER_VECTOR) return INTEGER_VECTOR;
-- function MINIMUM (L: INTEGER_VECTOR) return INTEGER;
-- function MAXIMUM (L: INTEGER_VECTOR) return INTEGER;
 
  type REAL_VECTOR is array (NATURAL range <>) of REAL;
 
-- The predefined operations for this type are as follows:
-- function "=" (anonymous, anonymous: REAL_VECTOR) return BOOLEAN;
-- function "/=" (anonymous, anonymous: REAL_VECTOR) return BOOLEAN;
-- function "&" (anonymous: REAL_VECTOR; anonymous: REAL_VECTOR) return REAL_VECTOR;
-- function "&" (anonymous: REAL_VECTOR; anonymous: REAL) return REAL_VECTOR;
-- function "&" (anonymous: REAL; anonymous: REAL_VECTOR) return REAL_VECTOR;
-- function "&" (anonymous: REAL; anonymous: REAL) return REAL_VECTOR;
-- function MINIMUM (L: REAL_VECTOR) return REAL;
-- function MAXIMUM (L: REAL_VECTOR) return REAL;
 
  type TIME_VECTOR is array (NATURAL range <>) of TIME;
 
-- The predefined operations for this type are as follows:
-- function "=" (anonymous, anonymous: TIME_VECTOR) return BOOLEAN;
-- function "/=" (anonymous, anonymous: TIME_VECTOR) return BOOLEAN;
-- function "&" (anonymous: TIME_VECTOR; anonymous: TIME_VECTOR) return TIME_VECTOR; 
-- function "&" (anonymous: TIME_VECTOR; anonymous: TIME) return TIME_VECTOR;
-- function "&" (anonymous: TIME; anonymous: TIME_VECTOR) return TIME_VECTOR;
-- function "&" (anonymous: TIME; anonymous: TIME) return TIME_VECTOR;
-- function MINIMUM (L: TIME_VECTOR) return TIME;
-- function MAXIMUM (L: TIME_VECTOR) return TIME;
-- The predefined types for opening files:
 
  type FILE_OPEN_KIND is (
    READ_MODE,
    WRITE_MODE,
    APPEND_MODE);
-- Resulting access mode is read-only.
-- Resulting access mode is write-only.
-- Resulting access mode is write-only;
-- information is appended to the end
-- of the existing file.
-- The predefined operations for this type are as follows:
-- function "=" (anonymous, anonymous: FILE_OPEN_KIND) return BOOLEAN;
-- function "/=" (anonymous, anonymous: FILE_OPEN_KIND) return BOOLEAN;
-- function "<" (anonymous, anonymous: FILE_OPEN_KIND) return BOOLEAN;
-- function "<=" (anonymous, anonymous: FILE_OPEN_KIND) return BOOLEAN;
-- function ">" (anonymous, anonymous: FILE_OPEN_KIND) return BOOLEAN;
-- function ">=" (anonymous, anonymous: FILE_OPEN_KIND) return BOOLEAN;
-- function MINIMUM (L, R: FILE_OPEN_KIND) return FILE_OPEN_KIND;
-- function MAXIMUM (L, R: FILE_OPEN_KIND) return FILE_OPEN_KIND;
 
  type FILE_OPEN_STATUS is (
    OPEN_OK, -- File open was successful.
    STATUS_ERROR, -- File object was already open.
    NAME_ERROR,  -- External file not found
    -- or inaccessible.
    MODE_ERROR); -- Could not open file with requested
  -- access mode.
 
-- The predefined operations for this type are as follows:
-- function "=" (anonymous, anonymous: FILE_OPEN_STATUS) return BOOLEAN;
-- function "/=" (anonymous, anonymous: FILE_OPEN_STATUS) return BOOLEAN;
-- function "<" (anonymous, anonymous: FILE_OPEN_STATUS) return BOOLEAN;
-- function "<=" (anonymous, anonymous: FILE_OPEN_STATUS) return BOOLEAN;
-- function ">" (anonymous, anonymous: FILE_OPEN_STATUS) return BOOLEAN;
-- function ">=" (anonymous, anonymous: FILE_OPEN_STATUS) return BOOLEAN;
-- function MINIMUM (L, R: FILE_OPEN_STATUS) return FILE_OPEN_STATUS;
-- function MAXIMUM (L, R: FILE_OPEN_STATUS) return FILE_OPEN_STATUS;
 
-- The 'FOREIGN attribute:
  attribute FOREIGN: STRING;
 
-- Predefined TO_STRING operations on scalar types
-- function TO_STRING (VALUE: BOOLEAN) return STRING;
-- function TO_STRING (VALUE: BIT) return STRING;
-- function TO_STRING (VALUE: CHARACTER) return STRING;
-- function TO_STRING (VALUE: SEVERITY_LEVEL) return STRING;
-- function TO_STRING (VALUE: universal_integer) return STRING;
-- function TO_STRING (VALUE: universal_real) return STRING;
-- function TO_STRING (VALUE: INTEGER) return STRING;
-- function TO_STRING (VALUE: REAL) return STRING;
-- function TO_STRING (VALUE: TIME) return STRING;
-- function TO_STRING (VALUE: FILE_OPEN_KIND) return STRING;
-- function TO_STRING (VALUE: FILE_OPEN_STATUS) return STRING;
-- Predefined overloaded TO_STRING operations
-- function TO_STRING (VALUE: REAL; DIGITS: NATURAL) return STRING;
-- function TO_STRING (VALUE: REAL; FORMAT: STRING) return STRING;
-- function TO_STRING (VALUE: TIME; UNIT: TIME) return STRING;
end STANDARD;
 

30.09.2012


Контактная информация:

Автор идеи и контента: Бибило П.Н.
Разработчики: Голанов В.А., Зарембо Д.В.
На основе Wordpress CMS

Статистика за сегодня:

Сайт размещен на сервере ОИПИ НАН Беларуси