Procedures
Always blocks (combinational)
講說combinational logic可以有assign和always @(*)兩種寫法。然後有個細節要注意,assign的左值要用wire,always的左值要用reg,雖然這兩者在合成電路後沒差。
Verilog
// 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)
重點是在講combinational logic和sequential logic的差別。如果是clock always的話,最好賦值使用non-blocking。
Verilog
// 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
原題:If statement
分別要求要寫三元運算和在combinational block中寫if/else,可能要注意的是cond可以共用。
Verilog
// 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 );
wire cond;
assign cond = sel_b1 & sel_b2;
assign out_assign = cond ? b : a;
always@(*)begin
if(cond)begin
out_always = b;
end
else begin
out_always = a;
end
end
endmodule
If statement latches
講說要寫清楚else 和 default,不然Verilog 會合成出latch。
Verilog
// 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 = 1'b0;
end
endmodule
Case statement
說明case 如何使用,然後要記得寫default 防止latch。
Verilog
// 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 = 4'b0000;
endcase
end
endmodule
Priority encoder
需要寫一個 priority encoder。這裡用 if/else 表達優先順序,比直接化成 gate-level 邏輯更容易閱讀。
Verilog
// synthesis verilog_input_version verilog_2001
module top_module (
input [3:0] in,
output reg [1:0] pos );
always@(*)begin
if(in[0]) pos = 2'b00;
else if(in[1]) pos = 2'b01;
else if(in[2]) pos = 2'b10;
else if(in[3]) pos = 2'b11;
else pos= 2'b00;
end
endmodule
Priority encoder with casez
和前一題類似,只是嘗試用casez實作encoder。
Verilog
// synthesis verilog_input_version verilog_2001
module top_module (
input [7:0] in,
output reg [2:0] pos );
always@(*)begin
casez(in)
8'bzzzzzzz1: pos = 3'b000;
8'bzzzzzz10: pos = 3'b001;
8'bzzzzz100: pos = 3'b010;
8'bzzzz1000: pos = 3'b011;
8'bzzz10000: pos = 3'b100;
8'bzz100000: pos = 3'b101;
8'bz1000000: pos = 3'b110;
8'b10000000: pos = 3'b111;
default: pos = 3'b000;
endcase
end
endmodule
Avoiding latches
當 output 很多時,可以先給預設值,再覆寫需要變動的訊號。這種寫法能減少重複分支,也能避免不小心推導出 latch。
Verilog
// 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'b1;
16'he072: down= 1'b1;
16'he074: right= 1'b1;
16'he075: up= 1'b1;
endcase
end
endmodule