Always blocks(combinational)
分别用 assign 语句和 always @(*) 块语句实现与门操作。
// 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)
使用 assign 语句、组合始终块和时钟始终块以三种方式构建异或门。请注意,时钟始终模块产生的电路与其他两个不同:有一个触发器,因此输出延迟。
// 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
If statement
构建一个在 a 和 b 之间进行选择的 2 对 1 复用器。如果 sel\_b1 和 sel\_b2 都为真,则选择 b。否则,请选择 a。执行相同的操作两次,一次使用 assign 语句,一次使用过程 if 语句。
// 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 );
assign out_assign = (sel_b1 && sel_b2)? b : a;
always@(*)
if (sel_b1 && sel_b2)
out_always <= b;
else
out_always <= a;
endmodule
If statement latches
学习如何避免产生 latch。
// 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
shut_off_computer = 0;
end
always @(*) begin
if (~arrived)
keep_driving = ~gas_tank_empty;
else
keep_driving = 0;
end
endmodule
Case statement
如果有大量案例,则案例陈述比 if 语句更方便。因此,在本练习中,创建一个 6 对 1 多路复用器。当 sel 介于 0 和 5 之间时,选择相应的数据输入。否则,输出 0。数据输入和输出均为 4 位宽。
// 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)
3'b000: out = data0;
3'b001: out = data1;
3'b010: out = data2;
3'b011: out = data3;
3'b100: out = data4;
3'b101: out = data5;
default: out = 3'b0000;
endcase
end
endmodule
Priority encoder
构建 4 位优先级编码器。对于此问题,如果输入位都不高(即输入为零),则输出为零。请注意,一个 4 位数字有 16 种可能的组合。
// synthesis verilog_input_version verilog_2001
module top_module (
input [3:0] in,
output reg [1:0] pos );
always @ (*)begin
casex (in)
4'bxxx1: pos = 2'd0;
4'bxx10: pos = 2'd1;
4'bx100: pos = 2'd2;
4'b1000: pos = 2'd3;
default: pos = 2'd0;
endcase
end
endmodule
Priority encoder with casez
case 语句就像是按顺序检查每个情况,这是一个很大的组合逻辑函数。请注意,某些输入(例如,4'b1111)将如何匹配多个事例项。选择第一个匹配项(因此 4'b1111 匹配第一个项目,out = 0,但后面的任何一个都不匹配)。还有一个类似的案例,它将x和z视为不在乎。我看不出在casez上使用它有多大意义。数字 ? 是 z 的同义词。所以 2'bz0 与 2'b?0 相同。
// synthesis verilog_input_version verilog_2001
module top_module (
input [7:0] in,
output reg [2:0] pos );
always @(*)begin
casez(in)
8'b???????1: pos = 3'd0;
8'b??????10: pos = 3'd1;
8'b?????100: pos = 3'd2;
8'b????1000: pos = 3'd3;
8'b???10000: pos = 3'd4;
8'b??100000: pos = 3'd5;
8'b?1000000: pos = 3'd6;
8'b10000000: pos = 3'd7;
default: pos = 3'd0;
endcase
end
endmodule
Avoiding latches
假设您正在构建一个电路来处理来自游戏的 PS/2 键盘的扫描码。鉴于收到的扫描码的最后两个字节,您需要指示是否已按下键盘上的箭头键之一。这涉及一个相当简单的映射,它可以实现为具有四个案例的案例语句(或 if-elseif)。
扫描码 [15:0] | 箭头 |
---|---|
16'HE06B | left arrow |
16'he072 | down arrow |
16'he074 | right arrow |
16'he075 | up arrow |
Anything else | none |
// 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
left = 1'b0;right = 1'b0;down = 1'b0;up = 1'b0;
case(scancode)
16'he06b: left = 1'b1;
16'he072: down = 1'b1;
16'he074: right = 1'b1;
16'he075: up = 1'b1;
endcase
end
endmodule