Как на языке 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:
Проверить правильность работы сумматора можно написав простой тестбенч. Подаем на входы сумматора разные числа и смотрим результат:
`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".
Подробнее...