Есть ли способ распечатать значения сигнала в файле из симуляции модели?

Мне нужно получить значения нескольких сигналов, чтобы сравнить их с симуляцией (симуляция в Matlab). Есть много значений, и я хочу получить их в файле, чтобы я мог запустить его в скрипте и не копировать значения вручную.

Есть ли способ автоматически печатать значения нескольких сигналов в текстовый файл?

(Дизайн реализован на VHDL)


person SIMEL    schedule 20.06.2014    source источник


Ответы (3)


Сначала создайте функции, которые преобразуют std_logic и std_logic_vector в string, например:

function to_bstring(sl : std_logic) return string is
  variable sl_str_v : string(1 to 3);  -- std_logic image with quotes around
begin
  sl_str_v := std_logic'image(sl);
  return "" & sl_str_v(2);  -- "" & character to get string
end function;

function to_bstring(slv : std_logic_vector) return string is
  alias    slv_norm : std_logic_vector(1 to slv'length) is slv;
  variable sl_str_v : string(1 to 1);  -- String of std_logic
  variable res_v    : string(1 to slv'length);
begin
  for idx in slv_norm'range loop
    sl_str_v := to_bstring(slv_norm(idx));
    res_v(idx) := sl_str_v(1);
  end loop;
  return res_v;
end function;

Использование побитового формата имеет то преимущество, что любые значения, отличные от 01, будут отображаться с точным значением std_logic, чего нельзя сказать, например, о шестнадцатеричное представление.

Затем создайте процесс, который записывает строки из std_logic и std_logic_vector в файл, например, в rising_edge(clk), например:

library std;
use std.textio.all;
...
process (clk) is
  variable line_v   : line;
  file     out_file : text open write_mode is "out.txt";
begin
  if rising_edge(clk) then
    write(line_v, to_bstring(rst) & " " & to_bstring(cnt_1) & " " & to_bstring(cnt_3));
    writeline(out_file, line_v);
  end if;
end process;

В приведенном выше примере rst используется как std_logic, а cnt_1 и cnt_3 — как std_logic_vector(7 downto 0). Результирующий вывод в «out.txt» будет таким:

1 00000000 00000000
1 00000000 00000000
1 00000000 00000000
0 00000000 00000000
0 00000001 00000011
0 00000010 00000110
0 00000011 00001001
0 00000100 00001100
0 00000101 00001111
0 00000110 00010010
person Morten Zilmer    schedule 20.06.2014

Потому что есть несколько способов содрать шкуру с кошки:

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

entity changed_morten is
end entity;

architecture foo of changed_morten is

    signal clk: std_logic := '0';
    signal rst: std_logic := '1';
    signal cnt_1: unsigned (7 downto 0);
    signal cnt_3: unsigned (7 downto 0);

    function string_it (arg:unsigned) return string is
        variable ret:    string (1 to arg'LENGTH);
        variable str:  string (1 to 3);  -- enumerated type "'X'"
        alias varg: unsigned (1 to arg'LENGTH) is arg;
    begin
        if arg'LENGTH = 0 then
            ret := "";
        else 
            for i in varg'range loop
                str := std_logic'IMAGE(varg(i));
                ret(i) := str(2);  -- the actual character 
            end loop;
        end if;
        return ret;
    end function;

begin


PRINT:        
    process (clk) is
        variable line_v   : line;
        variable str: string (1 to 3); -- size matches charcter enumeration
        file     out_file : text open write_mode is "out.txt";
    begin
        if rising_edge(clk) then
            str := std_logic'IMAGE(rst);
            write ( line_v,
                    str(2) & " " &
                    string_it(cnt_1) & " " &
                    string_it(cnt_3) & " "
                  );
            writeline(out_file, line_v);
      end if;
    end process;

COUNTER1:
    process (clk,rst)
    begin
        if rst = '1' then
            cnt_1 <= (others => '0');
        elsif rising_edge(clk) then
            cnt_1 <= cnt_1 + 1;
        end if;
    end process;

COUNTER3: 
    process (clk,rst)
    begin
        if rst = '1' then
            cnt_3 <= (others => '0');
        elsif rising_edge(clk) then
            cnt_3 <= cnt_3 + 3;
        end if;
    end process;

RESET:
    process
    begin
        wait until rising_edge(clk);
        wait until rising_edge(clk);
        wait until rising_edge(clk);
        rst <= '0';
        wait;
    end process;

CLOCK:
    process 
    begin
        wait for 10 ns;
        clk <= not clk;
        if Now > 210 ns then
            wait;
        end if;
    end process;

end architecture;

И в основном потому, что выражение лица Мортена

"" & std_logic'image(sl)(2);  -- "" & character to get string

не принимается ghdl, это не проиндексированное имя, строка безымянная.

Проблема, по-видимому, вызвана тем, что вызов функции ('IMAGE) не распознается как префикс для проиндексированного имени. Для любых пользователей ghdl вы захотите использовать промежуточную целевую строку с именем для вывода вызова функции атрибута (показанной в функции string_it и в строке в процессе PRINT). Я отправил отчет об ошибке.

Дополнение

Другой способ выразить функцию возврата строки to_bstring(sl : std_logic) Мортена:

function to_bstring(sl : std_logic) return string is
  variable sl_str_v : string(1 to 3) := std_logic'image(sl);  -- character literal length 3
begin
  return "" & sl_str_v(2);  -- "" & character to get string
end function;

И причина, по которой это работает, заключается в том, что вызовы функций динамически обрабатываются, что означает, что строка sl_str_v создается каждый раз при вызове функции.

См. IEEE Std 1076-1993 12.5 Dynamic Elaboration, b.:

Выполнение вызова подпрограммы включает в себя разработку списка параметров интерфейса соответствующего объявления подпрограммы; это включает разработку каждого объявления интерфейса для создания соответствующих формальных параметров. Затем фактические параметры связываются с формальными параметрами. Наконец, если указатель подпрограммы не украшен атрибутом FOREIGN, определенным в пакете STANDARD, декларативная часть тела соответствующей подпрограммы разрабатывается и выполняется последовательность операторов в теле подпрограммы.

Описание динамической обработки вызова подпрограммы немного расширено в IEEE Std 1076-2008, 14.6.

person Community    schedule 21.06.2014
comment
Спасибо за комментарии. Я обновил свой ответ, чтобы поддерживать GHDL и использовать итерацию (в этом случае нет необходимости в рекурсии, и некоторым может быть труднее читать). - person Morten Zilmer; 21.06.2014
comment
@MortenZilmer В вашем ответе не было ничего плохого. Работал нормально по крайней мере в двух анализаторах/симуляторах. Только не так много в ghdl, где я хотел бы исправить это, очевидное сокращение синтаксического анализатора или неполное семантическое правило. Должен был работать в IEEE Std 1076-1987 до -2008. (И я готов поклясться, что видел эту ошибку раньше, не могу ничего найти в своих местных архивах). Анализируя это, я получаю от stackoverflow. - person ; 21.06.2014
comment
Видимо теперь исправили на ghdl транке. Дата выпуска ghdl-0.32 еще не определена, но сборка ghdl из последнего исходного кода должна работать. - person user_1818839; 21.06.2014
comment
@David: Хорошо, но обновление по-прежнему улучшает читаемость. - person Morten Zilmer; 21.06.2014
comment
@BrianDrummond Tristan удивил меня скоростью этого. Отсутствуют атрибуты в процедуре Check_Kind_For_Base_Name. Вы собираетесь заставить меня предоставить компоновщик для следующего выпуска OS X, не так ли? - person ; 21.06.2014

Я хотел бы представить гибкий способ преобразования std_logic(_vector) в строку:

Сначала вы можете определить две функции для преобразования std_logic-битов и цифр в символ:

FUNCTION to_char(value : STD_LOGIC) RETURN CHARACTER IS
BEGIN
    CASE value IS
        WHEN 'U' =>     RETURN 'U';
        WHEN 'X' =>     RETURN 'X';
        WHEN '0' =>     RETURN '0';
        WHEN '1' =>     RETURN '1';
        WHEN 'Z' =>     RETURN 'Z';
        WHEN 'W' =>     RETURN 'W';
        WHEN 'L' =>     RETURN 'L';
        WHEN 'H' =>     RETURN 'H';
        WHEN '-' =>     RETURN '-';
        WHEN OTHERS =>  RETURN 'X';
    END CASE;
END FUNCTION;

function to_char(value : natural) return character is
begin
    if (value < 10) then
        return character'val(character'pos('0') + value);
    elsif (value < 16) then
        return character'val(character'pos('A') + value - 10);
    else
        return 'X';
    end if;
end function;

И теперь можно определить две функции to_string, которые преобразуют логическое значение и std_logic_vector в строку:

function to_string(value : boolean) return string is
begin
    return str_to_upper(boolean'image(value));  -- ite(value, "TRUE", "FALSE");
end function;

FUNCTION to_string(slv : STD_LOGIC_VECTOR; format : CHARACTER; length : NATURAL := 0; fill : CHARACTER := '0') RETURN STRING IS
    CONSTANT int                    : INTEGER               := ite((slv'length <= 31), to_integer(unsigned(resize(slv, 31))), 0);
    CONSTANT str        : STRING    := INTEGER'image(int);
    CONSTANT bin_len    : POSITIVE  := slv'length;
    CONSTANT dec_len    : POSITIVE  := str'length;--log10ceilnz(int);
    CONSTANT hex_len    : POSITIVE  := ite(((bin_len MOD 4) = 0), (bin_len / 4), (bin_len / 4) + 1);
    CONSTANT len        : NATURAL   := ite((format = 'b'), bin_len,
                                       ite((format = 'd'), dec_len,
                                       ite((format = 'h'), hex_len, 0)));

    VARIABLE j          : NATURAL   := 0;
    VARIABLE Result     : STRING(1 TO ite((length = 0), len, imax(len, length)))    := (OTHERS => fill);

BEGIN
    IF (format = 'b') THEN
        FOR i IN Result'reverse_range LOOP
            Result(i)    := to_char(slv(j));
            j            := j + 1;
        END LOOP;
    ELSIF (format = 'd') THEN
        Result(Result'length - str'length + 1 TO Result'high) := str;
    ELSIF (format = 'h') THEN
        FOR i IN Result'reverse_range LOOP
            Result(i)    := to_char(to_integer(unsigned(slv((j * 4) + 3 DOWNTO (j * 4)))));
            j            := j + 1;
        END LOOP;
    ELSE
        REPORT "unknown format" SEVERITY FAILURE;
    END IF;

    RETURN Result;
END FUNCTION;

Эта функция to_string может преобразовывать std_logic_vectors в двоичные (format='b'), десятичные (format='d') и шестнадцатеричные (format='h'). При желании вы можете определить минимальную длину строки, если длина больше 0, и символ заполнения, если требуемая длина std_logic_vector короче длины.

И вот необходимая вспомогательная функция:

-- calculate the minimum of two inputs
function imin(arg1 : integer; arg2 : integer) return integer is
begin
    if arg1 < arg2 then return arg1; end if;
    return arg2;
end function;

-- if-then-else for strings
FUNCTION ite(cond : BOOLEAN; value1 : STRING; value2 : STRING) RETURN STRING IS
BEGIN
    IF cond THEN
        RETURN value1;
    ELSE
        RETURN value2;
    END IF;
END FUNCTION;

-- a resize function for std_logic_vector
function resize(vec : std_logic_vector; length : natural; fill : std_logic := '0') return std_logic_vector is
    constant  high2b : natural := vec'low+length-1;
    constant  highcp : natural := imin(vec'high, high2b);
    variable  res_up : std_logic_vector(vec'low to high2b);
    variable  res_dn : std_logic_vector(high2b downto vec'low);
begin
    if vec'ascending then
        res_up := (others => fill);
        res_up(vec'low to highcp) := vec(vec'low to highcp);
        return  res_up;
    else
        res_dn := (others => fill);
        res_dn(highcp downto vec'low) := vec(highcp downto vec'low);
        return  res_dn;
end if;
end function;

Ok, this solution looks a bit long, but if you gather some of this functions -- and maybe overload them for several types -- you get an extended type converting system and in which you can convert nearly every type to every other type or representation.
person Paebbels    schedule 23.06.2014