ALU на Verilog

logo-verilog

Простое арифметико-логическое устройство (ALU) на Verilog

Пример написания reusable-кода к данной статье.  

Задание. Спроектировать арифметико-логическое устройство с восьмиразрядным входом данных, выполняющее следующие операции: not(А+В), not(А*В), А+В+1, (А + notВ)+1.

Начнем с обдумывания задачи.

Одну из выполняемых устройством операций можно упростить. (А + notВ)+1 это то же самое, что вычитание, поскольку –B=(notB+1). Таким образом четвертой операцией будет: A-B.

Пусть у устройства будет два информационных входа (А и В) и один выход(результат). Тогда для выбора конкретной выполняемой операции из четырех возможных потребуется еще один «вход выбора». Пусть кодирование будет двоичным, тогда разрядность этого входа – 2 бита.

Осталось определить разрядность выхода. Конечно, можно было сделать ее параметрической, однако в таком случае при некоторых операциях и маленькой разрядности выхода будет возникать переполнение, а значит потребуется еще один выход, что очевидно повлечет за собой усложнение модуля. Но модуль может использоваться по-разному и заведомо усложнять его не стоит. С другой стороны, если результат появляется на N-разрядном выходе, то всегда можно обрезать разрядность и вывести переполнение отдельно. Такой подход предпочтительнее, поскольку он является более гибким и более параметрическим.

Тогда нужно определиться с максимальной разрядностью выхода. Очевидно, что среди всех 4х операций, наибольшую разрядность будет иметь умножение not(А*В), а как известно результат умножения числа в [A] бит на число в [B] бит будет числом размером в [A]+[B] бит, это следствие из теории чисел.

Следовательно, выход будет иметь размерность [A]+[B] бит.

Далее представлен листинг Verilog-описания

Листинг программы ALU.v

 

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

Также можно заметить, что основная часть модуля комбинационная, с регистром на выходе(registered output), срабатывающим по заднему фронту сигнала тактирования clk. Для упрощения понимания кода, соответствующие режимы работы ALU были вынесены в localparam.

 

Теперь разработаем testbench для данного модуля. Сам TB будет состоять из двух файлов: в одном описана вся внутренняя логика тестирования. Другой же файл используется для вызова task’ов, управляющих входами ALU. Такой подход позволяет тестировать модуль, не будучи знакомым с его внутренней структурой.

 

Листинг ALU_tb_core.v

Как видим, здесь частота тактирования задается параметром внутри testbench’a. Весь процесс тестирования производится с помощью вызовов тасков из файла ALU_tb_list.inc.v

 

Листинг ALU_tb_list.inc.v

 

 

Ключевым моментом в этом файле является конструкция:

 

__ALU_TB_CORE_V__ задан define‘ом в основном файле testbench’a из которого производится подключение. Использование такой конструкции необходимо для того, что бы избавиться от ошибок компиляции: если в списке компиляции какого-то симулятора файл ALU_tb_list.inc.v будет находиться раньше, чем файл ALU_tb_core.v, то ошибка уже не возникнет. То есть происходит проверка, действительно ли компиляция дочернего файла вызвана необходимостью компиляции родительского.

 

Автор: Ходнев Т.А., ДК-11.