HBLbits_Verilog Procedures
Procedures
Procedures
include always, initial, task, and function blocks. Procedures
allow sequential statements (which cannot be used outside of a procedure) to be
used to describe the behaviour of a circuit.
·
Always blocks (combinational)
Alwaysblock1
For
synthesizing hardware, two types of always blocks are relevant:
·
Combinational: always @(*)
·
Clocked: always @(posedge
clk)
·
assign out1 = a &
b | c ^ d;
·
always
@(*) out2 = a & b | c ^ d;
· For combinational always blocks, always use a sensitivity list of (*).
Build an AND gate using both an assign
statement and a combinational always block
// 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@(*)begin
out_alwaysblock=a&b; end endmodule |
Alwaysblock2
For hardware
synthesis, there are two types of always blocks that
are relevant:
·
Combinational: always @(*)
·
Clocked: always @(posedge clk)
Blocking
vs. Non-Blocking Assignment
There are three types of assignments in Verilog:
Continuous assignments (assign x = y;)
Procedural blocking assignment: (x = y;).
In a combinational always block, use blocking assignments.
Procedural non-blocking assignment: (x <= y;).
In a clocked always block, use non-blocking assignments.
Build an XOR gate three ways, using an assign statement, a
combinational always block, and a clocked always block.
// 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@(*) begin out_always_comb = a^b; end
always@(posedge clk) begin out_always_ff <= a^b; end endmodule |
Always
if
always @(*)
begin if (condition) begin out = x; end else begin out = y; end end |
This is equivalent to using a continuous assignment with a conditional operator:
assign out = (condition) ? x : y; |
Build a 2-to-1 mux that chooses between a and b.
sel_b1 |
sel_b2 |
out_assign |
0 |
0 |
a |
0 |
1 |
a |
0 |
0 |
a |
1 |
1 |
b |
// 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==0 && sel_b2==0)?a:(sel_b1==0 &&
sel_b2==1)?a: (sel_b1==1 && sel_b2==0)? a: b;
always@(*) begin if (sel_b1==0 && sel_b2==0) begin out_always=a; end else if (sel_b1==0 && sel_b2==1) begin out_always=a; end else if (sel_b1==1 && sel_b2==0) begin out_always=a; end else out_always=b; end
endmodule |
Always
if2
A
common source of errors: How to avoid making 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
always @(*) begin if (cpu_overheated) shut_off_computer = 1; end
always @(*) begin if (~arrived) keep_driving = ~gas_tank_empty; end
|
修改前 // 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; end always @(*) begin if (~arrived) keep_driving = ~gas_tank_empty; end endmodule |
修改後 // 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) begin shut_off_computer = 1; end
else begin
shut_off_computer =
0; end
end always @(*) begin if (~arrived) begin keep_driving = ~gas_tank_empty; end else keep_driving = ~arrived; end endmodule |
Always
case
Case statements in Verilog are nearly
equivalent to a sequence of if-elseif-else that compares one expression to a
list of others.
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
|
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.
// 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 |
Always
case2
Build a 4-bit priority encoder.
// synthesis verilog_input_version verilog_2001 module top_module ( input [3:0] in, output reg [1:0] pos ); always @(*) begin // Combinational always block case (in) 4'h0: pos = 2'h0; // hexadecimal 4'h1: pos = 2'h0; 4'h2: pos = 2'h1; 4'h3: pos = 2'h0; 4'h4: pos = 2'h2; 4'h5: pos = 2'h0; 4'h6: pos = 2'h1; 4'h7: pos = 2'h0; 4'h8: pos = 2'h3; 4'h9: pos = 2'h0; 4'ha: pos = 2'h1; 4'hb: pos = 2'h0; 4'hc: pos = 2'h2; 4'hd: pos = 2'h0; 4'he: pos = 2'h1; 4'hf: pos = 2'h0; default: pos = 2'b0; // Default case. endcase end endmodule |
Always
casez
This is what casez is for: It treats bits that have the value z as don't-care in the comparison.
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 |
Build a priority encoder for 8-bit inputs.
// synthesis verilog_input_version
verilog_2001 module top_module (
input [7:0] in,
output reg [2:0] pos ); always
@(*) begin
casez (in)
8'bzzzz_zzz1: pos = 3'd0; // in[3:1] can be anything
8'bzzzz_zz1z: pos = 3'd1;
8'bzzzz_z1zz: pos = 3'd2;
8'bzzzz_1zzz: pos = 3'd3;
8'bzzz1_zzzz: pos = 3'd4;
8'bzz1z_zzzz: pos = 3'd5;
8'bz1zz_zzzz: pos = 3'd6;
8'b1zzz_zzzz: pos = 3'd7;
default: pos = 3'd0; endcase end endmodule |
Always
nolatches
Suppose
you're building a circuit to process scancodes from a PS/2 keyboard for a game.
Given the last two bytes of scancodes received, you need to indicate whether
one of the arrow keys on the keyboard have been pressed. This involves a fairly
simple mapping, which can be implemented as a case statement (or if-elseif)
with four cases.
Scancode
[15:0] |
Arrow key |
16'he06b |
left arrow |
16'he072 |
down arrow |
16'he074 |
right arrow |
16'he075 |
up arrow |
Anything else |
none |
Your circuit has one 16-bit input, and four
outputs. Build this circuit that recognizes these four scancodes and asserts
the correct output.
always @(*) begin up = 1'b0; down = 1'b0; left = 1'b0; right = 1'b0; case (scancode) ... // Set to 1 as necessary. endcase end
|
// 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
case (scancode)
16'he06b:
begin
left=1;
down=0;
right=0;
up=0;
end
16'he072:begin
left=0;
down=1;
right=0;
up=0;
end
16'he074:begin
left=0;
down=0;
right=1;
up=0;
end
16'he075:begin
left=0;
down=0;
right=0;
up=1;
end
default: begin left=0; down=0; right=0; up=0; end
endcase end endmodule |
沒有留言:
張貼留言