Always blocks (combinational)
Solution
// synthesis verilog_input_version verilog_2001
module top_module(
input a,
input b,
output wire out_assign,
output reg out_alwaysblock
);
assign out_assign = a & b;
always @(*) out_alwaysblock = a & b;
endmodule
Always blocks (clocked)
Solution
// synthesis verilog_input_version verilog_2001
module top_module(
input clk,
input a,
input b,
output wire out_assign,
output reg out_always_comb,
output reg out_always_ff
);
assign out_assign = a ^ b;
always @(*) out_always_comb = a ^ b;
always @(posedge clk) out_always_ff = a ^ b;
endmodule
There are three types of assignments in Verilog:
- Continuous assignments ( assign x = y; ). Can only be used when not inside a procedure ( "always block" ).
- Procedural blocking assignment: ( x = y; ). Can only be used inside a procedure.
- Procedural non-blocking assignment: ( x <= y; ). Can only be used inside a procedure.
If statement
语法格式:
always @(*) begin
if (condition) begin
out = x;
end
else begin
out = y;
end
end
这等效于条件运算符的连续赋值:
assign out = (condition) ? x : y;
Solution
// synthesis verilog_input_version verilog_2001
module top_module(
input a,
input b,
input sel_b1,
input sel_b2,
output wire out_assign,
output reg out_always );
always @(*) begin
if (sel_b1 == 1 && sel_b2 == 1) begin
// 注意:`=`是用于过程赋值的,而逻辑比较应该使用`==`
out_always = b;
end
else begin
out_always = a;
end
end
assign out_assign = (sel_b1 == 1 && sel_b2 == 1) ? b : a;
endmodule
If statement latches
When designing circuits, you _must_ think first in terms of circuits:
- I want this logic gate
- I want a _combinational_ blob of logic that has these inputs and produces these outputs
- I want a combinational blob of logic followed by a set of flip-flops
What you _must not_ do is write the code first, then hope it generates a proper circuit.
- If (cpu_overheated) then shut_off_computer = 1;
- If (~arrived) then keep_driving = ~gas_tank_empty;
在不提供 else clauses or a default value 的情况下,Verilog 将会 keep the outputs unchanged,这不是我们想要的。(因为本应 Combinational logic (e.g., logic gates) cannot remember any state.) 所以,Combinational circuits must have a value assigned to all outputs under all conditions.
Solution
// synthesis verilog_input_version verilog_2001
module top_module (
input cpu_overheated,
output reg shut_off_computer,
input arrived,
input gas_tank_empty,
output reg keep_driving ); //
always @(*) begin
if (cpu_overheated)
shut_off_computer = 1;
else // 添加else
shut_off_computer = 0;
end
always @(*) begin
if (arrived || gas_tank_empty)
keep_driving = 0;
else //添加else
keep_driving = 1;
end
endmodule
Tips:
error
是 “流程跑不通”(工具拒绝执行,因为代码 / 设计非法);incorrect
是 “流程跑得通,但结果不对”(代码合法,但逻辑错误)。
Case statement
语法格式:
always @(*) begin // This is a combinational circuit
case (in)
1'b1: begin
out = 1'b1; // begin-end if >1 statement
end
1'b0: out = 1'b0;
default: out = 1'bx;
endcase
end
- The case statement begins with case and each "case item" ends with a colon. There is no "switch".
- Each case item can execute _exactly one_ statement. This makes the "break" used in C unnecessary. But this means that if you need more than one statement, you must use begin ... end.
- Duplicate (and partially overlapping) case items are permitted. The first one that matches is used. C does not allow duplicate case items.
Solution
// synthesis verilog_input_version verilog_2001
module top_module (
input [2:0] sel,
input [3:0] data0,
input [3:0] data1,
input [3:0] data2,
input [3:0] data3,
input [3:0] data4,
input [3:0] data5,
output reg [3:0] out );//
always@(*) begin // This is a combinational circuit
case(sel)
4'b0000: out = data0;
4'b0001: out = data1;
4'b0010: out = data2;
4'b0011: out = data3;
4'b0100: out = data4;
4'b0101: out = data5;
default: out = 4'b0000;
endcase // 勿忘 case 语句的结束关键字
end
endmodule
Priority encoder
Tips:
'b
:二进制(Binary)'o
:八进制(Octal)'h
:十六进制(Hexadecimal)'d
:十进制(Decimal)
module top_module (
input [3:0] in,
output reg [1:0] pos );
always @(*) begin
case(in)
4'b0000: pos = 0;
4'b0001: pos = 0;
4'b0010: pos = 1;
4'b0011: pos = 0;
4'b0100: pos = 2;
4'b0101: pos = 0;
4'b0110: pos = 1;
4'b0111: pos = 0;
4'b1000: pos = 3;
4'b1001: pos = 0;
4'b1010: pos = 1;
4'b1011: pos = 0;
4'b1100: pos = 2;
4'b1101: pos = 0;
4'b1110: pos = 1;
4'b1111: pos = 0;
default: pos = 0;
endcase
end
endmodule
记录从右(低位)向左数第一个高位的位置。
Priority encoder with casez
It treats bits that have the value z as don't-care in the comparison.
语法格式:
always @(*) begin
casez (in[3:0])
4'bzzz1: out = 0; // in[3:1] can be anything
4'bzz1z: out = 1;
4'bz1zz: out = 2;
4'b1zzz: out = 3;
default: out = 0;
endcase
end
Solution
// synthesis verilog_input_version verilog_2001
module top_module (
input [7:0] in,
output reg [2:0] pos );
always @(*) begin
casez (in[7:0])
8'bzzzzzzz1: pos = 3'b000;
8'bzzzzzz1z: pos = 3'b001;
8'bzzzzz1zz: pos = 3'b010;
8'bzzzz1zzz: pos = 3'b011;
8'bzzz1zzzz: pos = 3'b100;
8'bzz1zzzzz: pos = 3'b101;
8'bz1zzzzzz: pos = 3'b110;
8'b1zzzzzzz: pos = 3'b111;
default: pos = 3'b000;
endcase
end
endmodule
Avoiding latches
One easy way to assign a "default value":
always @(*) begin
up = 1'b0; down = 1'b0; left = 1'b0; right = 1'b0;
case (scancode)
... // Set to 1 as necessary.
endcase
end
Solution
// synthesis verilog_input_version verilog_2001
module top_module (
input [15:0] scancode,
output reg left,
output reg down,
output reg right,
output reg up );
always @(*) begin
up = 1'b0; down = 1'b0; left = 1'b0; right = 1'b0;
case (scancode)
16'he06b: left = 1;
16'he072: down = 1;
16'he074: right=1;
16'he075: up = 1;
endcase
end
endmodule