Вот что написано в Википедии: "Mультиплексор — устройство, имеющее несколько сигнальных входов, один или более управляющих входов и один выход. Мультиплексор позволяет передать сигнал с одного из входов на выход; при этом выбор желаемого входа осуществляется подачей соответствующей комбинации управляющих сигналов".
На языке Verilog мультиплексор можно описать разными способами.
Самый простой способ - это с использованием конструкции if-else.
reg q;
always @*
if(sel)
q = a;
else
q = b;
Такой фрагмент кода Verilog можно представить в схемотехническом виде:
Таким образом, на выходе q появится сигнал идентичный сигналу a, если sel=1. Если же сигнал sel=0, то на выходе q будет сигнал равный сигналу b. Вот временная диаграмма:
Альтернативой if-else в коде Verilog для простого мультиплексора 2:1 может быть использование оператора "?".
reg q;
always @*
q = sel ? a : b;
Программа RTLViewer среды Altera Quartus отображает такую конструкцию точно так же, как и в случае с if-else.
Еще один способ представления мультиплексора с использованием оператора case:
always @*
case(sel)
0: q=b;
1: q=a;
endcase
Вообще-то конструкция с использованием case в Altera RTLViewer выглядит несколько иначе:
Тем не менее, логика работы остается абсолютно такой же. На самом деле на этой картинке изображен декодер один-к-двум и только один из его выходов (старший) используется для управления мультиплексором. Но ведь у конкретно этого декодера старший выход OUT[1]=sel. Так что, эта схема абсолютно такая же, как и представленная выше.
Рассмотрим мультиплексоры три-к-одному.
Вот, например, вот такой код на Verilog:
reg q;
always @*
if(sel==2'b00)
q=a;
else
if(sel==2'b01)
q=b;
else
q=c;
Схемотехническое представление этой конструкции вот такое:
Вот его временная диаграмма:
То же самое можно сделать и с помощью конструкции языка Verilog case:
reg q;
always @*
begin
case(sel)
2'b00: q = a;
2'b01: q = b;
default:
q = c;
endcase
end
Эта конструкция мультиплексора будет работать точно так же, как и с if-else-if-else.
Хотелось бы обратить внимание на один тонкий момент.
При написании кода на Verilog нужно учитывать все возможные варианты событий.
Вот, например, мультиплексор 3:1. Выходных сигналов три a, b и c, а управляющих сигналов два sel[1:0].
Раз сигналов селектора два, то значит всего они описывают четыре случая, а не три, как у нас.
В описанных выше примерах все сделано правильно: там вариант q=c выполняется в случае sel==2'b10 и sel=2'b11 (значения селектора 2 или 3).
Проблема состоит в том, что иногда, по невнимательности, можно написать "нехороший" код.
Вот пример такого "нехорошего" кода:
reg q;
always @*
if(sel==2'b00)
q=a;
else
if(sel==2'b01)
q=b;
else
if(sel==2'b10) // <---- вот это явно лишняя строка!
q=c;
Да, у нас вроде бы описан мультиплексор, но что произойдет когда селектор станет равным трем?
Этот случай мы не описали в коде. Синтезатор считает, что в случае с sel==2'b11 значение на выходе не должно меняться, должно оставаться предыдущим. Значит в логике появится latch (защелка) - это своего рода элемент памяти.
Вот что показывает Altera Quartus RTLViewer:
Вот допускать появление в проекте элементов latch очень не желательно. Их состояние в начальный момент времени не определено, их трудно тестировать и следовательно поведение проекта в конечном счете может стать не предсказуемым. Кстати и Quartus выдает предупреждение: "Verilog HDL Always Construct warning at <location>: inferring latch(es) for variable "<name>", which holds its previous value in one or more paths through the always construct". И далее следующее предупреждение: "Latch <name> has unsafe behavior".
Таким образом, при описании схем на языке Verilog желательно представлять себе эквивалентную схему устройства и учитывать все возможные варианты сигналов.
Подробнее...