Демультиплексор

Демультиплексор на verilog

Демультиплексор выполняет функцию обратную мультиплексору - "подключает" входной сигнал к нужному выходному, номер которого задается селектором. Если входной сигнал - логическая единица, то он ведет себя точно, как декодер. Если же входной сигнал - это ноль, то не зависимо от значения селекторов, на всех выходах будет ноль.

Демультиплексор можно рассматривать как частный случай дешифратора, если считать, что входной полезный переключаемый сигнал и сигналы селекторов - это все просто "входные сигналы".

Посмотрим, как демультиплексор можно описать на языке Verilog.

Я могу предложить несколько способов описания демультиплексора. Некоторые способы будут громоздкими, другие - нет. Выбирайте сами, что вам понятней и удобней.

 

При описании я иногда буду пользоваться специальной конструкцией языка Verilog для объединения нескольких сигналов в группу (шину сигналов): { sigN, ..., sig2 ,sig1, sig0 } - здесь используются фигурные скобки. В такой записи слева расположены сигналы старших разрядов, а справа - сигналы младших разрядов.

Вот первый вариант демультиплексора: однобитный сигнал signal должен появиться на одном из выходов out в "нужном" месте. 2х битный addr определяет позицию signal в выходном сигнале out:


module my_dmux0(
  input wire signal,
  input wire [1:0]addr,
  output reg [3:0]out
);

always @*
begin
  case
( addr )
   2'd0: out = { 3'b000, signal      };
   2'd1: out = { 2'b00, signal, 1'b0 };
   2'd2: out = { 1'b0, signal, 2'b00 };
   2'd3: out = {      signal, 3'b000 };
  endcase
end

Могу напомнить, что запись типа 3'b000 обозначает трехбитный сигнал. В данном случае все биты сброшены в ноль. Запись вида 2'd3 обозначает 2х битный сигнал, но значения битов записаны в десятичном виде. В данном случае - это три. Любое число можно записывать в десятичном, шестнадцатеричном или двоичном формате. Например число 10 - это:

4'd10 или 4'hA или 4'b1010.

Откомпилируем этот модуль в системе Altera Quartus II и посмотрим, что получилось в RTLViewer:

реализация демультиплексора на Verilog

Видно декодер и 4 мультиплексора.

Теперь рассмотрим второй способ описания демультиплексора - входной сигнал signal сдвигаем влево в нужную позицию (на столько бит, какое значение на входах addr) и получаем выходной out:


module my_dmux1(
  input wire signal,
  input wire [1:0]addr,
  output reg [3:0]out
);

always @*
  out = signal << addr;

endmodule


Опять компилируем и смотрим в RTLViewer:

реализация демультиплексора на Verilog

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

Третий способ - описываем демультиплексор, как декодер, при входном сигнале signal равном единице. Иначе - на выходах - ноль:


module my_dmux2(
  input wire signal,
  input wire [1:0]addr,
  output reg [3:0]out
);

always @*
begin
  if
(signal)
   case(addr)
    2'd0: out = 4'b0001;
    2'd1: out = 4'b0010;
    2'd2: out = 4'b0100;
    2'd3: out = 4'b1000;
   endcase
  else

   out = 4'b0000;
end

endmodule


Вот картинка в RTLViewer:

реализация демультиплексора на Verilog

Ну и вот последний способ: объединяем однобитный инвертированный signal и 2х битный addr и получаем 3х битный входной код для дешифратора:


module my_dmux3(
  input wire signal,
  input wire [1:0]addr,
  output reg [3:0]out
);

always @*
begin
  case
( {~signal,addr} )
   3'd0: out = 4'b0001;
   3'd1: out = 4'b0010;
   3'd2: out = 4'b0100;
   3'd3: out = 4'b1000;
  default:
   out = 4'b0000;
  endcase
end
endmodule

Последняя картинка:

реализация демультиплексора на Verilog

Несмотря на то, что одна и та же функция демультиплексора была написана на Verilog четырьмя разными способами и даже в RTLViewer результат выглядит по разному, тем не менее, работать все эти наши модули будут абсолютно одинаково.

В этом легко убедиться с помощью тестбенча. Напишем тестовый модуль на Verilog:


`timescale 1ns / 1ns

module test();

//моделируем тактовую частоту
reg clk;
initial clk=0;
always
 #5 clk=~clk;

//сделаем 2х битный счетчик

reg [1:0]cnt;
initial cnt=0;
always @(posedge clk)
 cnt = cnt+1;

reg my_signal;

//моделируем провода подключенные к выходу демультиплексоров
wire out_a0,out_a1,out_a2,out_a3;
wire out_b0,out_b1,out_b2,out_b3;
wire out_c0,out_c1,out_c2,out_c3;
wire out_d0,out_d1,out_d2,out_d3;

//вставляем в тестбенч экземпляры демультиплексоров:
my_dmux0 dmx0(
  .signal(my_signal),
  .addr(cnt),
  .out( {out_a3,out_a2,out_a1,out_a0} )
);

my_dmux1 dmx1(
  .signal(my_signal),
  .addr(cnt),
  .out( {out_b3,out_b2,out_b1,out_b0} )
);

my_dmux2 dmx2(
  .signal(my_signal),
  .addr(cnt),
  .out( {out_c3,out_c2,out_c1,out_c0} )
);

my_dmux3 dmx3(
  .signal(my_signal),
  .addr(cnt),
  .out( {out_d3,out_d2,out_d1,out_d0} )
);

initial
begin

  //объявляем генерируемый Waveform файл
  $dumpfile("out.vcd");
  $dumpvars(0,test);

  my_signal = 1'b0;
  #75;
  my_signal = 1'b1;
  #80;
  my_signal = 1'b0;

  #200 $finish;
end

endmodule

 

Тестбенч - это виртуальная среда тестирования модулей. Мы симулируем входные сигналы и наблюдаем за выходными сигналами. В среде тестбенча устанавливаем четыре разных модуля демультиплексора и подаем на их входы одинаковые сигналы. Посмотрим какие у них сигналы на выходах.

Я использую icarus verilog для симуляции проектов.

Вот такую временную диаграммы нам покажет программа GtkWave после симуляции тестбенча:

Симуляция демультиплексора в среде icarus verilog

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

Я скажу даже более того, несмотря на различия в описании на языке Verilog, внутри ПЛИС скорее всего получится один и тот же образ. В конечном счете, функция демультиплексора (как и декодера, дешифратора) - это табличное преобразование, которое кодируется в Look-Up Table (LUT) внутри ПЛИС.

 


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