Сумматор с переносом на Verilog HDL

Как на языке Verilog HDL реализовать сумматор или вычитатель с переносом ? Вопрос кажется очень простым для тех, кто давно использует язык Verilog, но почему-то оказывается абсолютно непонятным для новичков – это видно из писем, которые к нам приходят.

Все очень просто.
Вот такой код Verilog описывает модуль сумматора с переносом:


module adder(
  input wire [7:0]a,
  input wire [7:0]b,
  output wire [7:0]out,
  output wire carry
);

assign {carry, out} = a + b;

endmodule


Ключевая фраза здесь: assign {carry, out} = a + b;

Фигурные скобки описывают группу сигналов подключенных к выходу сумматора. В данном примере входные сигналы a и b восьмибитные. При суммировании восьмибитных чисел результат должен быть девятибитный. Так и в этом примере: выходной сигнал уже девятибитный и состоит из старшего бита carry, он слева внутри фигурных скобок, и восьмибитного результата out.


В этом легко убедиться если откомпилировать такой модуль в среде Altera Quartus II и посмотреть результат в RTLViewer:
Сумматор с переносом на Verilog
Проверить правильность работы сумматора можно написав простой тестбенч. Подаем на входы сумматора разные числа и смотрим результат:

`timescale 1ns / 1ns

module testbench;

reg [7:0]var_a;
reg [7:0]var_b;
wire [7:0]r_out;
wire r_carry;

//instance of module being studied
adder adder_inst(
  .a(var_a),
  .b(var_b),
  .out(r_out),
  .carry(r_carry)
);

initial
begin

  $dumpfile("out.vcd");
  $dumpvars(0,testbench);
  var_a = 8'h55;
  var_b = 8'h01;
   #10;
  var_a = 8'h55;
  var_b = 8'hAA;
   #10;
  var_a = 8'h55;
  var_b = 8'hAB;
   #10;
  var_a = 8'h99;
  var_b = 8'h05;
   #10;
  var_a = 8'h99;
  var_b = 8'h67;
   #10;
  var_a = 8'h99;
  var_b = 8'h66;
   #10;
  $finish;
end

endmodule


Откомпилировать оба модуля, сумматор и тестбенч, легко с помощью IcarusVerilog, в командной строке:

> iverilog –o qqq adder.v tb.v

Потом симулируем икарусом:

> vvp qqq

Получается выходной файл содержащий все сигналы проекта out.vcd. Эти сигналы можно детально рассмотреть в программе GtkWave:

Суммирование с переносом

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

Аналогично, легко описать вычитатель с переносом:


assign
{carry, out} = a - b;


Если carry и out описаны как регистры, а не wire, то используется такая конструкция:


reg carry;
reg [7:0]out;

always @*
begin
  { carry, out } = a + b ;
end



Здесь always @* обозначает «всегда», при любых изменениях любых сигналов.

Читайте другие статьи из раздела "Язык описания аппаратуры Verilog HDL".


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