Учебный курс. Моделируем счетчик в ModelSim.

Настало время промоделировать работу счетчика, рассмотренного в предыдущей статье учебного курса. Инструментов для моделирования существует великое множество, мы же рассмотрим среду ModelSim. Это довольно мощная среда, детище компании Mentor Graphics, одного из лидеров в разработке САПР для проектирования электроники. ModelSim является стандартом де-факто для разработки и верификации цифровых схем на языках Verilog, SystemVerilog и VHDL.

На сайте www.mentor.com можно скачать 21-дневную триальную версию пакета. Если же нет строгих моральных предубеждений, то не составит труда найти и скачать полную версию вместе с лекарством.

Итак, устанавливаем и запускаем программу. Сразу идем в File->New->Project для создания нового проекта. Вводим имя для проекта и путь, где он будет храниться, затем жмем Ок.

2

В выскочившем окошке жмем Add Existing File и находим наш файл счетчика counter.v, написанный в предыдущей статье данного курса. В поле Add file as type выбираем Verilog и жмем Ок.

3

Выделяем наш файл в списке файлов проекта и компилируем его (Compile->Compile Selected):

6

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

pic6_7

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

8

Содержимое этого файла должно быть следующим.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
`timescale 1ns/100ps
 
module tb_counter;
 
reg        clk   = 1'b0;
reg        rst_n = 1'b0;
reg        down  = 1'b0;
wire [3:0] out;
 
initial begin
    #10 rst_n = 1'b1;
    #32 down  = 1'b1;
    #40 rst_n = 1'b0;
    #10 $finish;     
end
 
always
    #1 clk = ~clk;
 
counter cnt0(.clk(clk), .rst_n(rst_n), .down(down), .out(out));
 
endmodule

 Первой строкой указывается временной шаг для моделирования и точность его определения. Временные задержки задаются при помощи символа решетки (#), после которого следует число, указывающее какое количество шагов необходимо выждать, прежде чем выполнить следующую операцию. Таким образом, указав шаг равным 1 нс в директиве `timescale, выполнение выражения #10 даст нам задержку 10 нс перед тем, как выполнить следующее выражение. Число, указанное через слэш (100 пс) — точность,  означает, что мы можем указать величину шага до десятых долей, т. е. #5.7 даст задержку 5.7 нс. Однако, если указать большее количество знаков после запятой, то число будет округляться до десятых. Например, если мы хотим задавать величину задержки с точностью до сотых долей, необходимо указать в директиве `timescale значение 1ns/10ps, в этом случае время можно будет устанавливать с точностью 10 пс.

В тестбенче определены блоки initial и always. Про always мы уже говорили, когда писали модуль счетчика. Initial так же, как и always, определяет некий процесс, однако, в отличии от always, выполняется не постоянно во время моделирования, а лишь один единственный раз. Это значит, что как только тело блока initial выполнено, то оно больше никогда не будет выполняться в процессе моделирования. Сигналы счетчика определяем с типом reg, поскольку будем записывать в них то или иное значение. С шины out мы просто будем снимать сигнал, смотреть, что на выходе счетчика, поэтому можно определить его как wire. При определении входных сигналов счетчика инициализируем их нулями, это значит, что в начальный момент времени (t=0) эти сигналы будут иметь низкий логический уровень. В блоке initial, выждав некоторое время (10 нс), установим сигнал rst_n равный единице, тем самым разрешая счетчику начать счет. Он должен увеличивать свое значение каждый такт clk (поскольку down=0) в течение следующих 32 нс. Далее устанавливается сигнал down=1, и в течение следующих 40 нс значение сигнала out должно уменьшаться по фронту clk. Далее мы сбрасываем счетчик, и out сразу же должен установиться в 0. Потом выжидаем еще 10 нс и завершаем моделирование (после значка доллара $ идет имя встроенной функции, завершающее выполнение тестбенча). Тактовый сигнал clk генерируется в блоке always, он меняет свое состояние (символ «~» обозначает инверсию) каждую 1 нс. В конце описания модуля стоит определение блока счетчика и его подключение к сигналам тестбенча. Сначала идет название модуля счетчика, далее имя этого блока (можем выбрать любое имя, согласно правилам именования). В скобочках идут описания соединений портов счетчика с сигналами тестбенча. Обращение к порту осуществляется через точку, после которой следует имя порта, а в скобках сигнал, к которому необходимо подключить этот порт. Для простоты, я назвал сигналы тестбенча также, как и порты счетчика.

Теперь добавим модуль тестбенча в проект, кликнув правой кнопкой мыши во вкладке Project и выбрав в контекстном меню Add to project->Existing file или через главное меню программы. После чего скомпилируйте файл, как мы уже проделывали ранее.

Чтобы запустить моделирование нужно выбрать в меню пункт Simulate->Start Simulation… В появившемся окне выбираем наш модуль с тестбенчем и снимаем галочку с опции Enable Optimization. Дело в том, что если включить оптимизацию, то сигналы перестанут быть доступны после моделирования, и мы не сможем их вывести на график.

pic6_8

После завершения процесса симуляции появятся несколько вкладок в главном окне программы. Необходимо выбрать вкладку Objects, где будут отображены все сигналы, определенные в тестбенче. Выделяем их все с нажатым шифтом, вызываем контекстное меню правой кнопкой мыши и выбираем Add to->Wave->Selected Signals.  Тем самым, мы добавили эти сигналы для вывода на график.

15

 Итак, все приготовления сделаны, теперь можно запустить тестбенч на выполнение. Для этого выбираем в меню Simulate->Run->Run -All. Появится окно вывода результатов и сообщение с вопросом завершить ли выполнение? Если мы ответим «Yes», то среда ModelSim закроется, поэтому отвечаем «No».

pic6_5

На этом выполнение тестбенча завершается, и появляется временная диаграмма всех сигналов, которые мы добавили для вывода.

21

Проанализировав результат, убедимся в том, что счетчик работает так, как и было задумано.

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

Добавить комментарий

Ваш e-mail не будет опубликован. Обязательные поля помечены *