23.03.2016 Применение verilator и vmodel

Материал из SRNS
Перейти к: навигация, поиск
(Передача параметров в Verilog)
(Всё просто! (Пример использования))
 
(не показаны 14 промежуточных версий 3 участников)
Строка 1: Строка 1:
 
<summary [ hidden ] >
 
<summary [ hidden ] >
[[File:20160323_KDPV.jpg|400px|center]]
+
[[File:20160323_KDPV.jpg|400px|center|link=Blog:Boldenkov/23.03.2016 Применение verilator и vmodel]]
  
 
Совместное моделирование Matlab и Verilog
 
Совместное моделирование Matlab и Verilog
Строка 20: Строка 20:
 
Зачем пытаться использовать эти языки совместно? Первоначально алгоритмы удобно отлаживать в Matlab, где есть безграничные возможности. Но когда дело идёт к реализации алгоритмов, их нужно описать на одном из языков описания аппаратуры. Тут мы используем Verilog.
 
Зачем пытаться использовать эти языки совместно? Первоначально алгоритмы удобно отлаживать в Matlab, где есть безграничные возможности. Но когда дело идёт к реализации алгоритмов, их нужно описать на одном из языков описания аппаратуры. Тут мы используем Verilog.
  
Для отладки алгоритмов Verilog желательно иметь возможность сравнения результатов с исходной моделью Matlab. Конечно, можно сделать это путём записи в результатов в файл, но это не слишком удобно. Особенно сложно это становится, если нужно реализовать обратную связь из Verilog в Matlab.
+
Для отладки алгоритмов Verilog желательно иметь возможность сравнения результатов с исходной моделью Matlab. Конечно, можно сделать это путём записи результатов в файл, но это не слишком удобно. Особенно сложно это становится, если нужно реализовать обратную связь из Verilog в Matlab.
  
 
== Применяемые средства ==
 
== Применяемые средства ==
Строка 30: Строка 30:
 
В отличии от большинства подобных программ, Verilator не является интерпретатором языка Verilog. Это конвертор из Verilog в C++. Полученный файл затем компилируется компирятором gcc и исполняется, как обычная компьютерная программа.
 
В отличии от большинства подобных программ, Verilator не является интерпретатором языка Verilog. Это конвертор из Verilog в C++. Полученный файл затем компилируется компирятором gcc и исполняется, как обычная компьютерная программа.
  
В результате Verilator поддерживает не все возможности Verilog. Поддерживаются синтезируемые конструкции, а также некоторые системые функции вроде $display(). Впрочем, поддержка Verilog (и SystemVerilog) достаточно хорошая.
+
В результате Verilator поддерживает не все возможности Verilog. Поддерживаются синтезируемые конструкции, а также некоторые системые функции вроде $display(). Впрочем, поддержка Verilog (а также SystemVerilog и SystemC) достаточно хорошая.
  
 
Преимуществом является высокая скорость исполнения получаемого кода.
 
Преимуществом является высокая скорость исполнения получаемого кода.
Строка 81: Строка 81:
  
 
   always @(posedge clk or negedge Rst)
 
   always @(posedge clk or negedge Rst)
     if (Rst == 1'b1)
+
     if (Rst == 1'b0)
 
       cnt <= 0;
 
       cnt <= 0;
 
     else
 
     else
Строка 111: Строка 111:
  
 
% Устанавливаем Rst в единицу, чтобы сделать сброс
 
% Устанавливаем Rst в единицу, чтобы сделать сброс
mult.Rst = 1;
+
mult.Rst = 0;
  
 
% Делаем такт clk, не считывая результат
 
% Делаем такт clk, не считывая результат
Строка 117: Строка 117:
  
 
% Устанавливаем Rst в ноль, чтобы прекратить сброс
 
% Устанавливаем Rst в ноль, чтобы прекратить сброс
mult.Rst = 0;
+
mult.Rst = 1;
  
 
% Делаем такт clk, не считывая результат
 
% Делаем такт clk, не считывая результат
Строка 150: Строка 150:
 
Поддержка параметров реализована с помощью дополнительного скрипта insert_with_param.m. Он делает дополнительный файл, вызываемый в качестве верхнеуровневого модуля, прописывая значения параметров в этом файле.
 
Поддержка параметров реализована с помощью дополнительного скрипта insert_with_param.m. Он делает дополнительный файл, вызываемый в качестве верхнеуровневого модуля, прописывая значения параметров в этом файле.
  
Вот тут выяснилось, что есть проблема. Verilog поддерживает два разных варианта синтаксиса описания портов. Первый вариант - когда всё описано в заголовке модуля:
+
Вот тут выяснилось, что есть проблема. Verilog поддерживает два разных варианта синтаксиса описания портов. Первый вариант - когда всё описано в заголовке модуля (Verilog-2001):
  
 
<source lang="Verilog">
 
<source lang="Verilog">
Строка 164: Строка 164:
 
</source>
 
</source>
  
Второй вариант - когда всё описано уже после заголовка модуля:
+
Второй вариант - когда всё описано уже после заголовка модуля (Verilog-95):
  
 
<source lang="Verilog">
 
<source lang="Verilog">
Строка 174: Строка 174:
 
   );
 
   );
  
   parameter R=4;
+
   parameter R = 4;
 
      
 
      
 
   input clk;
 
   input clk;
Строка 189: Строка 189:
 
Так вот, скрипт insert_with_param.m, входящий в в исходный вариант vmodel, поддерживает только первый вариант синтаксиса.  
 
Так вот, скрипт insert_with_param.m, входящий в в исходный вариант vmodel, поддерживает только первый вариант синтаксиса.  
  
Я доработал скрипт insert_with_param для поддержки любого вида синтаксиса. Планирую выложить на github, чтобы его включили в официальный вариант vmodel.
+
Я доработал скрипт insert_with_param для поддержки любого вида синтаксиса и выложил на GitHub доработанный вариант: https://github.com/amromanov/vmodel/pull/1.
  
Итак, что получается в результате:
+
Изменяем заголовок counter.m следующим образом:
  
 
<source lang="bash">
 
<source lang="bash">
 +
clear;
 +
 +
% Параметры vmodel
 +
src_orig_filename = 'counter.v';
 +
src_filename = 'counter_param.v';
 +
 +
params.R = 3;
 +
insert_with_param(src_orig_filename, src_filename, params);
 +
 +
data.src_filename = src_filename;
 +
 +
data.output = '.';          % Output directory
 +
data.clk_name='clk';        % Clock signal name (by default 'clk')
 +
data.save_cpp=0;            % Is it necessary to save mex source c++ file
 +
data.constr_name = 'mult';  % Simulation object constructor name
 +
data.sim_name = 'sim_step'; % Simulation function name
 +
data.no_simulink_model = 1;
 +
 +
addpath(data.output);
 +
 +
vmodel(data)
  
 
</source>
 
</source>
 +
 +
Скрипт insert_with_param берёт исходный файл counter.v, парсит его, выделяет все параметры. Потом берёт структуру params, находит все поля, совпадающие по названию с параметрами. Значения этих параметров изменяет, создавая дополнительный файл counter_param.v следующего содержания:
 +
 +
<source lang="Verilog">
 +
module counter_param #(parameter R=3)
 +
(
 +
input clk,
 +
input Rst,
 +
output [R-1:0]cnt
 +
);
 +
 +
counter #(.R(R))
 +
counter(
 +
.clk(clk),
 +
.Rst(Rst),
 +
.cnt(cnt)
 +
);
 +
endmodule
 +
</source>
 +
 +
В этом файле просто осуществляется встраивание модуля counter с требумыми значениями параметров.
 +
 +
Результат при R=3.
 +
 +
[[File:20160323_Counter_result_R3.png|400px]]
 +
 +
Результат при R=5:
 +
 +
[[File:20160323_Counter_result_R5.png|400px]]
 +
 +
It works!
 +
 +
=== Разбор длинных слов ===
 +
 +
В Verilog поддерживаются одномерные массивы данных. Объявляются они примерно так:
 +
 +
<source lang="Verilog">
 +
reg [5:0] R [9:0];
 +
</source>
 +
 +
Здесь объявлен массив из 10 6-разрядных чисел. Казалось бы, всё хорошо, но Verilog не позволяет передавать такие массивы через порты модулей.
 +
 +
Чтобы обойти это ограничение, распространённой практикой является объявление одного длинного слова, содержащего все необходимые данные. Обращение к отдельным элементам массива при этом осуществляется по диапазону бит:
 +
 +
<source lang="Verilog">
 +
reg [6*10-1:0] R;
 +
 +
always @(posedge clk)
 +
  R[ 11:6 ] <= R[ 11:6 ] + 1;
 +
</source>
 +
 +
Но это легко работает в Verilog, но что делать с такими данными в Matlab?
 +
 +
С точки зрения Verilator и языка C++ подобные данные упаковываются в массивы целых чисел. Это могут быть  8, 16, 32, 64-разрядные числа или массивы из 32-разрядных чисел.
 +
 +
Из vmodel Matlab получает массивы данных в виде uint32.
 +
 +
Итак, стоит следующая задача: на входе - массив 32-разрядных чисел, в который упаковыны целые числа произвольной разрядости (до 32). На выходе надо получить массив из нормальных чисел, которые можно обрабатывать в Matlab.
 +
 +
Я написал для этого специальные скрипты. Пока они названы arr2wdata.m и wdata2arr.m. Предполагается, что числа, выделяемые из массива, являются целыми числами со знаком. Надо также дописать вариант с беззнаковыми числами.
 +
 +
Как использовать? Примерно так:
 +
 +
<source lang="Matlab">
 +
NR1 = 14;
 +
 +
for i=1:N
 +
    in = arr2wdata(y(i, :), NR1);
 +
    mult.in = uint32(in');
 +
   
 +
    [res t] = sim_step(mult, 1, 0);
 +
   
 +
    rc = wdata2arr(res.out, NR1);
 +
    arr(i, :) = rc(1:NA);
 +
end
 +
</source>
 +
 +
Здесь я указал, что разрядность чисел внутри Verilog - 14. Входные данные упаковываются из простого массива отсчётов y в массив in в формате uint32. Потом результат отправляется в vmodel. На выходе получается массив res.out в формате uint32, из которого с помощью функции wdata2arr() выделяются числа, пригодные для Matlab.
 +
 +
== Решение проблем с установкой ==
 +
 +
=== libstdc++ ===
 +
 +
Возможна проблема, связанная не столько с vmodel, сколько с MEX-файлами в Matlab вообще. Matlab может быть расчитан на более старую версию компилятора gcc, в результате чего будут появляеться ошибки вроде такой:
 +
 +
<source lang="bash">
 +
Warning: You are using gcc version "5.3.0".  The version
 +
        currently supported with MEX is "4.4.6".
 +
        For a list of currently supported compilers see:
 +
        http://www.mathworks.com/support/compilers/current_release/
 +
 +
Invalid MEX-file '/tmp/Verilator/m_counter.mexa64':
 +
/mnt/big_disk/usr/local/opt/MATLAB/R2012a/bin/glnxa64/libstdc++.so.6: version
 +
`GLIBCXX_3.4.21' not found (required by /tmp/Verilator/m_counter.mexa64)
 +
</source>
 +
 +
Лечится это запуском Matlab с указанием на правильную библиотеку libstdc++:
 +
 +
<source lang="bash">
 +
LD_PRELOAD=/usr/lib/gcc/x86_64-pc-linux-gnu/5.4.0/libstdc++.so.6 /usr/local/opt/MATLAB/R2012a/bin/matlab
 +
</source>
 +
 +
Разумеется, путь надо исправить на правильный путь в вашей системе. Взято [http://stackoverflow.com/questions/22564357/usr-libstdc-so-6-version-glibcxx-3-4-11-not-found-required-by отсюда], да и много ещё откуда.
 +
 +
[[Категория:Verilog]]
 +
[[Категория:ММ РУиС (дисциплина)]]

Текущая версия на 12:55, 1 ноября 2016

Содержание

[править] Зачем?

Это классно!

[править] О чём речь?

Моделировать можно по-разному.

Вот Matlab, например, позволяет удобно работать с матрицами. При этом язык программирования Matlab подобен другим императивным языкам программирования - инструкции выполняются друг за другом последовательно

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

Зачем пытаться использовать эти языки совместно? Первоначально алгоритмы удобно отлаживать в Matlab, где есть безграничные возможности. Но когда дело идёт к реализации алгоритмов, их нужно описать на одном из языков описания аппаратуры. Тут мы используем Verilog.

Для отладки алгоритмов Verilog желательно иметь возможность сравнения результатов с исходной моделью Matlab. Конечно, можно сделать это путём записи результатов в файл, но это не слишком удобно. Особенно сложно это становится, если нужно реализовать обратную связь из Verilog в Matlab.

[править] Применяемые средства

[править] Verilator

Есть множество программ, позволяющих моделировать алгоритмы на языке Verilog. Одной из таких программ является Verilator. Более подробную информацию можно найти на сайте http://veripool.org. Программу написал Wilson Snyder, она существует уже более десяти лет и активно поддерживается.

В отличии от большинства подобных программ, Verilator не является интерпретатором языка Verilog. Это конвертор из Verilog в C++. Полученный файл затем компилируется компирятором gcc и исполняется, как обычная компьютерная программа.

В результате Verilator поддерживает не все возможности Verilog. Поддерживаются синтезируемые конструкции, а также некоторые системые функции вроде $display(). Впрочем, поддержка Verilog (а также SystemVerilog и SystemC) достаточно хорошая.

Преимуществом является высокая скорость исполнения получаемого кода.

Verilator не является полноценным симулятором Verilog, тестбенчи требуется писать на C++.

[править] vmodel

Очевидно, что программу C++ можно подключить к Matlab с использованием MEX-интерфейса. Это было сделано в программе vmodel коллегами из МИРЭА:

%%*********************vmodel MATLAB Verilog simulator******************
%%Version 0.9.6
%%Moscow, Control Problems Department MIREA, 2009-2015
%%Authors: Karyakin D, Romanov A, Slaschov B
%%-
%%Distributed under the GNU LGPL
%%**********************************************************************

Программу можно скачать с github:

git clone https://github.com/amromanov/vmodel.git

Программа предполагает написание тестбенчей в Matlab, а отлаживаемый код на Verilog обрабатывается с помощью Verilator.

[править] vppreproc

Ещё одна утилита от Wilson Snyder - препроцессор Verilog vppreproc. Найти его можно на том же сайте http://veripool.org

[править] Всё просто! (Пример использования)

Допустим, мы хотим протестировать вот такой простой модуль Verilog:

module counter
  (
   clk,
   Rst,
   cnt
   );

   parameter R=4;
     
   input clk;
   input Rst;
   output [R-1:0] cnt;

   reg [R-1:0]    cnt;

   always @(posedge clk or negedge Rst)
     if (Rst == 1'b0)
       cnt <= 0;
     else
       cnt <= cnt + 1;
   
endmodule

Тестбенч должен формировать тактовый сигнал clk и сигнал сброса Rst. Эти сигналы будем формировать в Matlab и считывать результат - состояние счётчика cnt.

clear;

% Параметры vmodel
data.src_filename = 'counter.v';

data.output = '.';          % Output directory
data.clk_name='clk';        % Clock signal name (by default 'clk')
data.save_cpp=0;            % Is it necessary to save mex source c++ file
data.constr_name = 'mult';  % Simulation object constructor name
data.sim_name = 'sim_step'; % Simulation function name
data.no_simulink_model = 1;

addpath(data.output);

vmodel(data)

%% Сброс

% Устанавливаем Rst в единицу, чтобы сделать сброс
mult.Rst = 0;

% Делаем такт clk, не считывая результат
sim_step(mult, 1, 1);

% Устанавливаем Rst в ноль, чтобы прекратить сброс
mult.Rst = 1;

% Делаем такт clk, не считывая результат
sim_step(mult, 1, 1);


%% Само моделирование
N = 100;
cnt = zeros(1, N);
for i=1:N
    % Делаем такт clk, считывая результат
    [res t] = sim_step(mult, 1, 0);
   
    % Записываем результат в массив
    cnt(i) = res.cnt;
end

%% Вывод результатов
plot(cnt)

Запускаем и получаем ожидаемый результат:

20160323 Counter result.png

[править] Решение проблем

[править] Передача параметров в Verilog

Параметры в Verilog придуманы для того, чтобы их можно было изменять при встраивании. Аналогичную операцию желательно делать и в vmodel.

Поддержка параметров реализована с помощью дополнительного скрипта insert_with_param.m. Он делает дополнительный файл, вызываемый в качестве верхнеуровневого модуля, прописывая значения параметров в этом файле.

Вот тут выяснилось, что есть проблема. Verilog поддерживает два разных варианта синтаксиса описания портов. Первый вариант - когда всё описано в заголовке модуля (Verilog-2001):

module counter
  #(
    parameter R=4
     )
  (
   input clk,
   input Rst,
   output reg [R-1:0] cnt
   );

Второй вариант - когда всё описано уже после заголовка модуля (Verilog-95):

module counter
  (
   clk,
   Rst,
   cnt
   );

   parameter R = 4;
     
   input clk;
   input Rst;
   output [R-1:0] cnt;

   reg [R-1:0]    cnt;

Лично мне больше нравится первый вариант, т.к. в нём нет трёхкратного дублирования одного и того же - описания входов и выходов. А дублирование - это плохо. Плохо тем, что рано или поздно при редактировании может закрасться ошибка, если три описания будут отличаться. Одна сущность должна описываться один раз.

Но на практике в окружающем мире обычно приходится сталкиваться именно со вторым вариантом синтаксиса.

Так вот, скрипт insert_with_param.m, входящий в в исходный вариант vmodel, поддерживает только первый вариант синтаксиса.

Я доработал скрипт insert_with_param для поддержки любого вида синтаксиса и выложил на GitHub доработанный вариант: https://github.com/amromanov/vmodel/pull/1.

Изменяем заголовок counter.m следующим образом:

clear;

% Параметры vmodel
src_orig_filename = 'counter.v';
src_filename = 'counter_param.v';

params.R = 3;
insert_with_param(src_orig_filename, src_filename, params);

data.src_filename = src_filename;

data.output = '.';          % Output directory
data.clk_name='clk';        % Clock signal name (by default 'clk')
data.save_cpp=0;            % Is it necessary to save mex source c++ file
data.constr_name = 'mult';  % Simulation object constructor name
data.sim_name = 'sim_step'; % Simulation function name
data.no_simulink_model = 1;

addpath(data.output);

vmodel(data)

Скрипт insert_with_param берёт исходный файл counter.v, парсит его, выделяет все параметры. Потом берёт структуру params, находит все поля, совпадающие по названию с параметрами. Значения этих параметров изменяет, создавая дополнительный файл counter_param.v следующего содержания:

module counter_param #(parameter R=3)
(
        input clk,
        input Rst,
        output [R-1:0]cnt
);

counter #(.R(R))
counter(
        .clk(clk),
        .Rst(Rst),
        .cnt(cnt)
);
endmodule

В этом файле просто осуществляется встраивание модуля counter с требумыми значениями параметров.

Результат при R=3.

20160323 Counter result R3.png

Результат при R=5:

20160323 Counter result R5.png

It works!

[править] Разбор длинных слов

В Verilog поддерживаются одномерные массивы данных. Объявляются они примерно так:

reg [5:0] R [9:0];

Здесь объявлен массив из 10 6-разрядных чисел. Казалось бы, всё хорошо, но Verilog не позволяет передавать такие массивы через порты модулей.

Чтобы обойти это ограничение, распространённой практикой является объявление одного длинного слова, содержащего все необходимые данные. Обращение к отдельным элементам массива при этом осуществляется по диапазону бит:

reg [6*10-1:0] R;

always @(posedge clk)
   R[ 11:6 ] <= R[ 11:6 ] + 1;

Но это легко работает в Verilog, но что делать с такими данными в Matlab?

С точки зрения Verilator и языка C++ подобные данные упаковываются в массивы целых чисел. Это могут быть 8, 16, 32, 64-разрядные числа или массивы из 32-разрядных чисел.

Из vmodel Matlab получает массивы данных в виде uint32.

Итак, стоит следующая задача: на входе - массив 32-разрядных чисел, в который упаковыны целые числа произвольной разрядости (до 32). На выходе надо получить массив из нормальных чисел, которые можно обрабатывать в Matlab.

Я написал для этого специальные скрипты. Пока они названы arr2wdata.m и wdata2arr.m. Предполагается, что числа, выделяемые из массива, являются целыми числами со знаком. Надо также дописать вариант с беззнаковыми числами.

Как использовать? Примерно так:

NR1 = 14;

for i=1:N
    in = arr2wdata(y(i, :), NR1);
    mult.in = uint32(in');
   
    [res t] = sim_step(mult, 1, 0);
   
    rc = wdata2arr(res.out, NR1);
    arr(i, :) = rc(1:NA);
end

Здесь я указал, что разрядность чисел внутри Verilog - 14. Входные данные упаковываются из простого массива отсчётов y в массив in в формате uint32. Потом результат отправляется в vmodel. На выходе получается массив res.out в формате uint32, из которого с помощью функции wdata2arr() выделяются числа, пригодные для Matlab.

[править] Решение проблем с установкой

[править] libstdc++

Возможна проблема, связанная не столько с vmodel, сколько с MEX-файлами в Matlab вообще. Matlab может быть расчитан на более старую версию компилятора gcc, в результате чего будут появляеться ошибки вроде такой:

Warning: You are using gcc version "5.3.0".  The version
         currently supported with MEX is "4.4.6".
         For a list of currently supported compilers see:
         http://www.mathworks.com/support/compilers/current_release/

Invalid MEX-file '/tmp/Verilator/m_counter.mexa64':
/mnt/big_disk/usr/local/opt/MATLAB/R2012a/bin/glnxa64/libstdc++.so.6: version
`GLIBCXX_3.4.21' not found (required by /tmp/Verilator/m_counter.mexa64)

Лечится это запуском Matlab с указанием на правильную библиотеку libstdc++:

LD_PRELOAD=/usr/lib/gcc/x86_64-pc-linux-gnu/5.4.0/libstdc++.so.6 /usr/local/opt/MATLAB/R2012a/bin/matlab

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

[ Хронологический вид ]Комментарии

(нет элементов)

Войдите, чтобы комментировать.

Персональные инструменты
Пространства имён

Варианты
Действия
SRNS Wiki
Рабочие журналы
Приватный файлсервер
QNAP Сервер
Инструменты