TestBench на Verilog для новичков

Данная статья освещает базовые вопросы написания TestBench на языке Verilog. Предполагается, что вы уже знакомы с синтаксисом языка Verilog и прочли пост про интеграцию Quartus и ModelSim.
Рекомендуется к изучения новичкам, всем интересующимся и незнающим как подступиться к написанию TestBench.

Данный пост является вольным переводом Art of Writing TestBenches by Deepak Kumar Tala.

Приступим.


Возьмем в качестве подопытного 4х битный счетчик с синхронным сбросом и входом разрешения. Его код

module counter (clk, reset, enable, count);
input clk, reset, enable;
output [3:0] count;
reg [3:0] count;                                   
 
always @ (posedge clk)
if (reset == 1'b1) begin
   count <= 0;
end else if ( enable == 1'b1) begin
   count <= count + 1;
end
 
endmodule  


План тестирования.


Необходимо исследовать поведения счетчика во всех мыслимых и немыслемых ситуациях. Все ситуации есть не что иное как комбинации входных воздействий, коих у нас три: clk, reset, enable.

Тактовый вход clk трогать не будет, на нем все время будет постоянная рабочая частота. Тестирования остальных входов разделим на три варианта:
1. Тестирования сбороса Reset
2. Тестирования входа разрешения Enable
3. Тестирование Reset и Enable в боевых условиях

Создание TestBench
Как вы знаете из статьи Quartus автоматически создает шаблон TestBench.

Модифицируем TestBench. Cоздадим входную частоту счетчика и зададим начальные значения всех входным сигналов.

`timescale 1 ps/ 1 ps
module counter_vlg_tst();

// test vector input registers
reg clk;
reg enable;
reg reset;
// wires                                               
wire [3:0]  count;

// assign statements (if any)                          
counter i1 (
// port map - connection between master ports and signals/registers   
	.clk(clk),
	.count(count),
	.enable(enable),
	.reset(reset)
);

initial                                                
begin                                                  
  clk = 0;
  enable = 0;
  reset = 0;                                           
  $display("Running testbench");                       
end                                                    

always 
  #5  clk =  ! clk;    //создание clk                                                
 
endmodule


Блок initial исполняется один раз в нулевой момент времени, задавая все необходимые начальные воздействия.
Тактовую частоту с периодом 10 шагов симуляции (а шаг симуляции пикосекуда!) задает блок always.

Запускаем и смотрим


Как видим всех входные сигналы приняли нужные начальные воздействия, частота есть, но счетчик по понятным причинам не считает )

Добавление логики сброса.


Давайте добавим логику сброса, заодно изучив (или закрепив) пару конструкций языка Verilog.

Создадим два события reset_trigger и reset_done_trigger. Первое будет вызываться, когда нам необходимо сделать reset. Второе — будет сообщать что reset выполнен.

`timescale 1 ps/ 1 ps
module counter_vlg_tst();

// test vector input registers
reg clk;
reg enable;
reg reset;
// wires                                               
wire [3:0]  count;

// assign statements (if any)                          
counter i1 (
// port map - connection between master ports and signals/registers   
	.clk(clk),
	.count(count),
	.enable(enable),
	.reset(reset)
);

initial                                                
begin                                                  
  clk = 0;
  enable = 0;
  reset = 0;                                           
  $display("Running testbench");                       
end                                                    

always 
  #5  clk =  ! clk;                                                    
 
endmodule

event reset_trigger; //объявление событий
event reset_done_trigger; //

//блок формирования Reset
initial begin 
 forever begin //бесконечный цикл 
  @ (reset_trigger); //ждем события reset_trigger
  @ (negedge clk); //ждем negedge clk
  reset = 1; 	//сброс
  @ (negedge clk); 
  reset = 0; 
  -> reset_done_trigger; //сигналим что reset выполнен
  end 
end

//Ход симуляции
initial  
 begin: TEST_CASE 
    #10  -> reset_trigger;  //сделать ресет
end


Запускаем и видим что reset прошел) Так же кружочками обозначены времена появления событий


Симуляция Enable


Модифицируем ход симуляции

//Ход симуляции
initial  
  begin: TEST_CASE 
  #10  -> reset_trigger;  //делаем ресет с задержкой 10
  @ (reset_done_trigger); //ждем сигнал reset_done_trigger
  @ (negedge clk); 	
  	enable = 1; //разрешаем счет 
  repeat (10) begin  //цикл на 10 повторений
    @ (negedge clk); //ждем negedge clk
  end 
  enable = 0; //запрещаем счет
end


Результаты на картинке


Тестирование Reset и Enable в боевых условиях.


Попробуем обыграть реальную картину работы, доверив управления reset и enable генератору случайных чисел)

Модифицируем ход симуляции

//Ход симуляции
initial  
begin : TEST_CASE 
  #10  -> reset_trigger; 
  @ (reset_done_trigger); 
  fork  // внутри fork все выполняется одновременно
   repeat (10) begin // 10 повторений
      @ (negedge clk); //ждем negedge clk
      enable = $random; 
    end	
   repeat (10) begin // 10 повторений
      @ (negedge clk); // negedge clk
      reset = $random; 
   end 
  join //end fork
end


Запускаем, получаем


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

event terminate_sim;  
initial begin  
 @ (terminate_sim); 
 #5  $stop; 
end  


Теперь в нужное место вставляем
-> terminate_sim;


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

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

Спасибо за внимание.
  • +2
  • 24 ноября 2011, 12:48
  • covsh

Комментарии (14)

RSS свернуть / развернуть
А как обстоят дела с автоматизацией процесса тестирования? Можно-ли запустить симуляцию из какого-то скрипта, без UI, без взаимодействия с пользователем и получить результат тест прошел, или не прошел? Было-бы интересно узнать.
0
частичный ответ на Ваш вопрос, кажется, здесь:
www.asic-world.com/verilog/art_testbench_writing4.html#Adding_compare_Logic
это одна из глав первоисточника, на который ссылается автор )
0
конечно возможно. ModelSim поддерживает очень развитый скрипиовый интерфейс. из него делается все что угодно
0
Это радует. Интересно было-бы почитать об этом.
0
как будет желание, напишу об этом.
для начала можете поглядеть на скрипт, которым quartus запускает modelsim в \simulation\modelsim\*_run_msim_rtl_verilog.do
0
Вообще в моделсиме есть набор шаблонов для тестирования, он может создать автоматом структуру тестбенча, т.е. объявить новый проект и подключить ваще устройство, плюс есть несколько шаблонов воздействующих функций, в том числе и счетчик. Было бы интересно посмотреть их использование.
0
не знаком с данной методикой, но чувствуется что для нее нужен не хилый подготовительный этап. если вам известны подробности, напишите об этом)
0
Подскажите где выставить время моделирования в шагах или единицах времени а то при первом же тесте кончилось место на жёстком диске)). В modelsim нужно передать параметр run <время>, только что то не нашёл настроек через квартус. Как вариант прокатит исправление *.do файла в проекте или же всё таки придётся через квартус искать?
0
В тестбенче пишете:
initial
#10000 $finish;
Понятное дело, количество шагов сами задаете
0
как вариант нашёл где настроить из квартуса: Assignments — Settings — Simulation — Test Benches — Edit — «End simulation at ...»
0
появилась проблема при повторении статьи. При использовании кода в котором мы добавляем события в testbench, modelsim начинает ругаться:

# ** Error: C:/altera/Project/counter/simulation/modelsim/counter.vt(33): (vlog-2155) Global declarations are illegal in Verilog 2001 syntax.
# ** Error: C:/altera/Project/counter/simulation/modelsim/counter.vt(37): near «initial»: syntax error, unexpected «initial», expecting «class»
# ** Error: C:/altera/11.0/modelsim_ase/win32aloem/vlog failed.
# Error in macro ./counter_run_msim_rtl_verilog.do line 10
# C:/altera/11.0/modelsim_ase/win32aloem/vlog failed.
# while executing
P.S.: по умолчанию в quartus выбран стандарт Verilog-2001
0
ну Вы б код из тестбенча тут привели. В логе ему не нравятся 33 и 37 строчки
0
уже 2 раз отвечаю на свои вопросы =) я не понял почему но если «endmodule» переместить в конец кода то код начинает работать))
0
всерно выкладывайте, если не жалко. Уже мы будем учиться на Ваших ошибках
0
Только зарегистрированные и авторизованные пользователи могут оставлять комментарии.