Комбинационная логика
Введение в проектирование на языке Verilog
Прутьянов В. В.
Цифровые схемы
Комбинационные
Последовательностные
Синхронные
Цифровые схемы
Комбинационные
Последовательностные
Синхронные
Побитовые операции в языке Verilog
Разрядность результата &, |, ^ определяется по наибольшей из разрядностей операндов
Источник: IEEE Std 1364-2001 Verilog Hardware Description Language
Full adder
module full_adder(
input a,
input b,
input carry_in,
output sum,
output carry_out
);
assign sum = (a ^ b) ^ carry_in;
assign carry_out = (a & b) | ((a ^ b) & carry_in);
endmodule
Ripple-carry adder (RCA)
module rca #(parameter N = 4)(
input [N-1:0] a,
input [N-1:0] b,
output [N-1:0] sum
);
wire [N:0] c;
assign c[0] = 1'b0;
genvar i;
generate
for (i = 0; i < N; i = i + 1)
begin : gen_adders
full_adder fa(
.a(a[i]), .b(b[i]), .carry_in(c[i]), .sum(sum[i]), .carry_out(c[i+1]));
end
endgenerate
endmodule
Carry look-ahead adder (CLA)
module cla #(parameter N = 4)(
input [N-1:0] a,
input [N-1:0] b,
output [N-1:0] sum
);
wire [N:0] c;
wire [N-1:0] P = a | b;
wire [N-1:0] G = a & b;
assign c[0] = 1'b0;
assign c[N:1] = G | (P & c);
genvar i;
generate
for (i = 0; i < N; i = i + 1)
begin : gen_adders
full_adder fa(.a(a[i]), .b(b[i]), .carry_in(c[i]), .sum(sum[i]), .carry_out(c[i+1]));
end
endgenerate
endmodule
Сумматор в Verilog
module adder #(
parameter N = 8
)(
input [N-1:0] a,
input [N-1:0] b,
output [N-1:0] sum
);
assign sum = a + b;
endmodule
Сумматор в Verilog
module adder #(
parameter N = 8
)(
input [N-1:0] a,
input [N-1:0] b,
output [N-1:0] sum
);
assign sum = a + b;
endmodule
Операторы в языке Verilog
Знаковые и беззнаковые типы в Verilog
Мультиплексор
Мультиплексор 2-в-1
module mux #(
parameter WIDTH = 32
)(
input wire [WIDTH-1:0] i0, i1,
input wire sel,
output wire [WIDTH-1:0] out
);
assign out = sel ? i1 : i0;
endmodule
Конструкция always @(*) и блокирующее присваивание
module mux #(
parameter WIDTH = 32
)(
input wire [WIDTH-1:0] i0, i1,
input wire sel,
output reg [WIDTH-1:0] out
);
always @(*) begin
if (sel)
out = i1;
else
out = i0;
end
endmodule
Конструкция always @(*) и блокирующее присваивание
module mux #(
parameter WIDTH = 32
)(
input wire [WIDTH-1:0] i0, i1,
input wire sel,
output reg [WIDTH-1:0] out
);
always @(*) begin
if (sel)
out = i1;
else
out = i0;
end
endmodule
always @(*) begin
case (sel)
1'b0: out = i0;
1'b1: out = i1;
endcase
end
Конструкция always @(*) и блокирующее присваивание
module mux3(
input wire i0, i1, i2,
input wire sel0, sel1,
output wire out
);
reg x, y;
assign out = y;
always @(*) begin
if (sel0)
x = i1;
else
x = i0;
end
always @(*) begin
if (sel1)
y = i2;
else
y = x;
end
endmodule
Конструкция always @(*) и блокирующее присваивание
module bad_mux3(
input wire i0, i1,
input wire sel0, sel1,
output wire out
);
reg x, y;
assign out = y;
always @(*) begin
if (sel0)
x = i1;
else
x = i0;
end
always @(*) begin
if (sel1)
y = x;
end
endmodule
Конструкция always @(*) и блокирующее присваивание
module bad_mux3(
input wire i0, i1,
input wire sel0, sel1,
output wire out
);
reg x, y;
assign out = y;
always @(*) begin
if (sel0)
x = i1;
else
x = i0;
end
always @(*) begin
if (sel1)
y = x;
end
endmodule
Warning (10240): Verilog HDL Always Construct warning at bad_mux3.v(19): inferring latch(es) for variable "y", which holds its previous value in one or more paths through the always construct
Verilator: линтинг
$ verilator --lint-only bad_mux3.v
%Warning-LATCH: bad_mux3.v:18:1: Latch inferred for signal 'mux3.y' (not all control paths of combinational always assign a value)
: ... Suggest use of always_latch for intentional latches
18 | always @(*) begin
| ^~~~~~
... For warning description see https://verilator.org/warn/LATCH?v=5.040
... Use "/* verilator lint_off LATCH */" and lint_on around source to disable this message.
%Error: Exiting due to 1 warning(s)
Блоки case/casez-endcase
always @(*) begin
case ({sel1, sel0})
2'b00: y = i0;
2'b01: y = i1;
2'b10: y = i2;
2'b11: y = i2;
endcase
end
always @(*) begin
case ({sel1, sel0})
2'b00: y = i0;
2'b01: y = i1;
default: y = i2;
endcase
end
always @(*) begin
casez ({sel1, sel0})
2'b00: y = i0;
2'b01: y = i1;
2'b1?: y = i2;
endcase
end
Энкодер
// 4-to-2 MSB priority encoder
module enc4(
input wire [3:0] i_data,
output reg [1:0] o_enc,
output wire o_vld
);
always @(*) begin
casez (i_data)
4'b1???: o_enc = 2'd3;
4'b01??: o_enc = 2'd2;
4'b001?: o_enc = 2'd1;
4'b0001: o_enc = 2'd0;
default: o_enc = 2'dX;
endcase
end
assign o_vld = |i_data; // Reduction OR
endmodule
Декодер
// 2-to-4 one-hot decoder
module dec4(
input wire [1:0] i_data,
output wire [3:0] o_dec
);
assign o_dec = 4'b1 << i_data;
endmodule
module dec4(
input wire [1:0] i_data,
output reg [3:0] o_dec
);
always @(*) begin
case (i_data)
2'd0: o_dec = 4'b0001;
2'd1: o_dec = 4'b0010;
2'd2: o_dec = 4'b0100;
2'd3: o_dec = 4'b1000;
endcase
end
endmodule
Функции
function slt; // Signed less-than
input [WIDTH-1:0] a, b;
begin
slt = $signed(a) < $signed(b);
end
endfunction
wire a_lt_b;
assign a_lt_b = slt(a, b);
АЛУ
Арифметико-логическое устройство – блок в вычислительном устройстве (CPU, GPU и др.), производящий арифметические, логические и побитовые операции над целыми числами
ADD | Сложение | rd = rs1 + rs2 |
SUB | Вычитание | rd = rs1 - rs2 |
SLL | Логический* сдвиг влево | rd = rs1 << rs24:0 |
SLT | Rd в 1, если rs1 знаково* меньше, чем rs2 | rd = (rs1 <s rs2) |
SLTU | Rd в 1, если rs1 беззнаково* меньше, чем rs2 | rd = (rs1 <u rs2) |
XOR | Побитовое ИСКЛЮЧАЮЩЕЕ ИЛИ | rs = rs1 ^ rs2 |
SRL | Логический* сдвиг вправо | rd = rs1 >> rs24:0 |
SRA | Арифметический* сдвиг вправо | rd = rs1 >>> rs24:0 |
OR | Побитовая операция ИЛИ | rd = rs1 | rs2 |
AND | Побитовая операция И | rd = rs1 & rs2 |
* См. детали по R операциям RV32I в The RISC-V Instruction Set Manual Volume I: Unprivileged ISA
Блок сравнения
Блок сравнения – опциональный (его роль может выполнять ALU) блок для проверки выполнения условия в инструкциях условного перехода (branch)
BEQ | Переход, если равно | out = (rs1 == rs2) |
BNE | Переход, если не равно | out = (rs1 ≠ rs2) |
BLT | Переход, если знаково* меньше | out = (rs1 < rs2) |
BGE | Переход, если знаково* больше или равно | out = (rs1 ≥ rs2) |
BLTU | Переход, если беззнаково* меньше | out = (rs1 < rs2) |
BGEU | Переход, если беззнаково* больше | out = (rs1 ≥ rs2) |
* См. детали по B операциям RV32I в The RISC-V Instruction Set Manual Volume I: Unprivileged ISA
Задание