二、Verilog Language
Procedures
1、Always blocks(Combinational)
Problem Statement:
Build an AND gate using both an assign statement and a combinational always block.
module top_module(
input a,
input b,
output wire out_assign,
output reg out_alwaysblock
);
assign out_assign = a & b;
always@(*)begin
out_alwaysblock = a & b;
end
endmodule
2、Always blocks(clocked)
Problem Statement:
Build an XOR gate three ways, using an assign statement, a combinational always block, and a clocked always block. Note that the clocked always block produces a different circuit from the other two: There is a flip-flop so the output is delayed.
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@(*) begin
out_always_comb = a ^ b;
end
always@(posedge clk) begin
out_always_ff = a ^ b;
end
endmodule
3、If statement
Problem Statement:
Build a 2-to-1 mux that chooses between a and b. Choose b if both sel_b1 and sel_b2 are true. Otherwise, choose a. Do the same twice, once using assign statements and once using a procedural if statement.
sel_b1 sel_b2 out_assign
out_always0 0 a 0 1 a 1 0 a 1 1 b
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 == 1'b1) ? b : a;
always@(*) begin
if(sel_b1 & sel_b2 == 1'b1)begin
out_always = b;
end
else begin
out_always = a;
end
end
endmodule
4、If statement latches
Problem Statement:
The following code contains incorrect behaviour that creates a latch. Fix the bugs so that you will shut off the computer only if it's really overheated, and stop driving if you've arrived at your destination or you need to refuel.
always @(*) begin if (cpu_overheated) shut_off_computer = 1; end always @(*) begin if (~arrived) keep_driving = ~gas_tank_empty; end
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 == 1'b1)
shut_off_computer = 1;
else
shut_off_computer = 0;
end
always @(*) begin
if (~arrived == 1'b1)
keep_driving = ~gas_tank_empty;
else
keep_driving = 1'b0;
end
endmodule
5、Case statement
Problem Statement:
Case statements are more convenient than if statements if there are a large number of cases. So, in this exercise, create a 6-to-1 multiplexer. When sel is between 0 and 5, choose the corresponding data input. Otherwise, output 0. The data inputs and outputs are all 4 bits wide.
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'd0 : out = data0;
3'd1 : out = data1;
3'd2 : out = data2;
3'd3 : out = data3;
3'd4 : out = data4;
3'd5 : out = data5;
default : out = 4'b0;
endcase
end
endmodule
6、Priority encoder
Problem Statement:
Build a 4-bit priority encoder. For this problem, if none of the input bits are high (i.e., input is zero), output zero. Note that a 4-bit number has 16 possible combinations.
module top_module (
input [3:0] in,
output reg [1:0] pos );
always@(*)begin
case(1)
in[0] : pos = 2'd0;
in[1] : pos = 2'd1;
in[2] : pos = 2'd2;
in[3] : pos = 2'd3;
default : pos = 2'd0;
endcase
end
endmodule
7、Priority encoder with casez
Problem Statement:
Build a priority encoder for 8-bit inputs. Given an 8-bit vector, the output should report the first bit in the vector that is 1. Report zero if the input vector has no bits that are high. For example, the input 8'b10010000 should output 3'd4, because bit[4] is first bit that is high.
For example, this would implement the 4-input priority encoder from the previous exercise:
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
module top_module (
input [7:0] in,
output reg [2:0] pos
);
always@(*)begin
casez(in[7:0])
8'bzzzzzzz1 : pos = 3'd0;
8'bzzzzzz1z : pos = 3'd1;
8'bzzzzz1zz : pos = 3'd2;
8'bzzzz1zzz : pos = 3'd3;
8'bzzz1zzzz : pos = 3'd4;
8'bzz1zzzzz : pos = 3'd5;
8'bz1zzzzzz : pos = 3'd6;
8'b1zzzzzzz : pos = 3'd7;
default : pos = 3'd0;
endcase
end
endmodule
8、Avoiding latches
Problem Statement:
Your circuit has one 16-bit input, and four outputs. Build this circuit that recognizes these four scancodes and asserts the correct output.
To avoid creating latches, all outputs must be assigned a value in all possible conditions. Simply having a default case is not enough. You must assign a value to all four outputs in all four cases and the default case. This can involve a lot of unnecessary typing. One easy way around this is to assign a "default value" to the outputs before the case statement:
always @(*) begin up = 1'b0; down = 1'b0; left = 1'b0; right = 1'b0; case (scancode) ... // Set to 1 as necessary. endcase endThis style of code ensures the outputs are assigned a value (of 0) in all possible cases unless the case statement overrides the assignment. This also means that a default: case item becomes unnecessary.
Scancode [15:0] Arrow key 16'he06b left arrow 16'he072 down arrow 16'he074 right arrow 16'he075 up arrow Anything else none
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