После некоторых раздумий я решил написать статью о симуляции Verilog проектов с помощью пакета программ icarus-verilog. Мне кажется, что это лучший способ «быстро попробовать» возможности симуляции. Конечно, среда симуляции ModelSim компании Mentor Graphics (или ModelSim-Altera Edition) - это мощное средство, но освоить ее несколько труднее.
Сейчас мы быстренько скачаем из интернета icarus-verilog, установим его и попробуем что нибудь просимулировать...
Первое, что нужно сделать – это посетить сайт http://www.icarus.com/eda/verilog/ - отправная точка для изучения Icarus Verilog. Это свободный проект, то есть при желании можно даже посмотреть исходные тексты всех программ, и компилятора и симулятора Verilog. Здесь есть ссылки на документацию и откуда скачивать файлы для установки. Конечно, есть пакеты программ и для Linux и для Windows.
Оттуда я перехожу по ссылке Pablo Bleyer Kocik's Icarus Verilog Windows packages (off-site), которая ведет меня на станицу скачивания программы для операционной системы Windows. Вы будете приятно удивлены – размер файла для скачивания составляет около 17 мегабайт! Для ModelSim, например, размер будет более 500Мб!
Cкачиваем и устанавливаем, по умолчанию программа устанавливается в папку c:\iverilog и установщик сам прописывает пути к исполняемым файлам. Но можно использовать любую удобную директорию, у нас это d:\dev\iverilog.
В этой же папке есть несколько коротких но понятных инструкций, как пользоваться компилятором и симулятором (правда на английском языке). Перед началом симуляции, изменим код нашего проекта Логический анализатор SignalTap на примере счетчика Грея, а именно добавим вход wr для установки начального состояния счетчика со входа d:
Verilog Code:
`timescale 1ns /100ps module gray_cnt( input wire clk, input wire nreset, input wire wr, input wire [SIZE-1:0]d, output wire [SIZE-1:0]q ); parameter SIZE = 4; integer i; reg [SIZE-1:0]gray_cnt; reg [SIZE-1:0]bin; reg [SIZE-1:0]next_gray_cnt; always @* begin //convert gray-to-bin for (i=0; i<SIZE; i=i+1) bin[i] = ^(gray_cnt>>i); //increment binary bin=bin+1; //convert bin-to-gray next_gray_cnt = (bin>>1)^bin; end always @(posedge clk or negedge nreset) if(~nreset) gray_cnt <= 0; else if(~wr) begin gray_cnt <= d; $display("written %h",d); end else gray_cnt <= next_gray_cnt; assign q=gray_cnt; endmodule
С помощью SignalTap посмотрим, как наш счетчик работает в реальном железе:
Теперь напишем специальный модуля на языке Verilog, который называется testbench:
Verilog Code:
`timescale 1ns /100ps module gray_tb; reg clk, nreset, wr; reg [SIZE-1:0]d; wire [SIZE-1:0]q; parameter SIZE = 4; //устанавливаем экземпляр тестируемого модуля gray_cnt gray_cnt_inst(clk, nreset, wr, d, q); //моделируем сигнал тактовой частоты always #10 clk = ~clk; //от начала времени... initial begin clk = 0; nreset = 0; d = 4'h0; wr = 1'b1; //через временной интервал "50" подаем сигнал сброса #50 nreset = 0; //еще через время "4" снимаем сигнал сброса #4 nreset = 1; //пауза длительностью "50" #50; //ждем фронта тактовой частоты и сразу после нее подаем сигнал записи @(posedge clk) #0 begin d = 4'h5; wr = 1'b0; end //по следующему фронту снимаем сигнал записи @(posedge clk) #0 begin d = 4'h0; wr = 1'b1; end end //заканчиваем симуляцию в момент времени "400" initial begin #400 $finish; end //создаем файл VCD для последующего анализа сигналов initial begin $dumpfile("out.vcd"); $dumpvars(0,gray_tb); end //наблюдаем на некоторыми сигналами системы initial $monitor($stime,, clk,, nreset,, d,, wr,, q); endmodule
Чтобы он был более понятным пожалуйста прочитайте предыдущую статью про System Tasks.
Для чего применяется такая методика из раздельных модулей – тестируемого и тестирующего? Первый модуль – это тот, который мы в будущем хотим компилировать для чипа. Для него важно быть простым и компактным. А второй модуль, тестирующий (их называют testbench) моделирует внешние сигналы, которые подаются на тестируемый модуль и проверяет выходные сигналы из него.
Тут надо заметить, что написание тестбенчей – это в каком-то смысле искусство. Получается мы пишем программу, модуль. Для тестирования этой программы мы пишем вторую программу – модуль тестбенч. Мы можем ошибиться как в первой программе, так и во второй или в обеих сразу! Ведь в любой программе возможны баги. Разработчик может думать, что он все сделал правильно и просимулировал и увидел результат какой хотел, но на самом деле проект может остаться неработоспособным. Но не нужно пугаться.
Icarus-verilog может скомпилировать их в свой «исполняемый» формат. Для этого в командной строке набираем команду:
>iverilog -o qqq gray_cnt.v gray_tb.v
Iverilog – это компилятор, который транслирует исходный код Verilog в файл специального формата для симуляции проекта, или в файлы других форматов netlist для последующей обработки другими программами.
После выполнения этой команды у нас появился новый файл «qqq». Мы будем использовать его для симуляции. Запускаем в командной строке симулятор из комплекта icarus-verilog:
>vvp qqq
Вот мы и видим весь вывод симулятора на консоль:
Здесь видно, как значение счетчика увеличивается с каждым фронтом сигнала clk.
Видно, что в момент времени "110" устанавливается сигнал wr, а в момент времени "130" происходить запись нового значения в счетчик.
Если вы теперь захотите увидеть сигналы в графическом виде, то это тоже возможно. В результате симуляции у нас появился новый файл "out.vcd" - это Value Change Dump File. Для его просмотра есть инструмент gtkwave. Он есть здесь же в комплекте установленного нами icarus-verilog.
Набираем в командной строке:
>gtkwave out.vcd
И появляется вот такое окно (кликните на картинку, чтобы увеличить ее):
Слева есть окошко со списком сигналов проекта. Нужно выбрать необходимые сигналы и добавить их к просмотру кнопкой "Append".
Справа – окно графического представления сигналов. Можно менять масштаб просмотра и скроллировать вдоль шкалы времени.
Вот так можно проводить функциональную симуляцию проектов написаных на языке Verilog.
Проект Icarus-Verilog для платы VE-EP4CE10E: signaltap_grey_icarus.zip