【HDLBits】Procedures
I. Always blocks(combinational)
1.代码编写
// 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
2.提交结果
3.题目分析
Combinational always blocks are equivalent to assign statements.
组合逻辑always块等同于assign。
A note on wire vs. reg: The left-hand-side of an assign statement must be a net type (e.g., wire), while the left-hand-side of a procedural assignment (in an always block) must be a variable type (e.g., reg). These types (wire vs. reg) have nothing to do with what hardware is synthesized, and is just syntax left over from Verilog’s use as a hardware simulation language.
关于连线与reg的注释:赋值语句assign的左侧必须是网络类型(例如,wire),而过程赋值的左侧(在过程块中)必须是变量类型(例如reg)。 这些类型(wire vs. reg)与硬件合成无关,只是Verilog用作硬件模拟语言时遗留下来的语法。
II. Always blocks(clocked)
1.代码编写
// 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
2.提交结果
3.题目分析
分别用assign、always(combinational)、always(clocked)来实现赋值。
III. Always if (if statement)
1.代码编写
// 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@(*) begin
if(sel_b1&sel_b2) out_always=b;
else out_always=a;
end
endmodule
2.提交结果
3.题目分析
两种方法(assign_if,always_if)分别实现if语句。
IV. Always if2 (if statement latches)
1.代码编写
// 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
2.提交结果
3.题目分析
Syntactically-correct code does not necessarily result in a reasonable circuit (combinational logic + flip-flops). The usual reason is: “What happens in the cases other than those you specified?”. Verilog’s answer is: Keep the outputs unchanged.
This behaviour of “keep outputs unchanged” means the current state needs to be remembered, and thus produces a latch. Combinational logic (e.g., logic gates) cannot remember any state. Watch out for Warning (10240): … inferring latch(es)" messages. Unless the latch was intentional, it almost always indicates a bug. Combinational circuits must have a value assigned to all outputs under all conditions. This usually means you always need else clauses or a default value assigned to the outputs.
应确保if(case)分支中包含了所有情况,否则会生成锁存器。
题目要求: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.
V. Always case(Case statement)
1.代码编写
// 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
2.提交结果
3.题目分析
- The case statement begins with case and each “case item” ends with a colon. There is no “switch”.
分支语句后为冒号,不用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.
允许分支表达式重复(或部分重叠),会采用首个匹配的分支。(在C中不允许重复)
VI.Always case2 (Priority encoder)
1.代码编写
// synthesis verilog_input_version verilog_2001
module top_module (
input [3:0] in,
output reg [1:0] pos );
always@(*) begin
case(in)
4'h0: pos=2'd0;
4'h1: pos=2'd0;
4'h2: pos=2'd1;
4'h3: pos=2'd0;
4'h4: pos=2'd2;
4'h5: pos=2'd0;
4'h6: pos=2'd1;
4'h7: pos=2'd0;
4'h8: pos=2'd3;
4'h9: pos=2'd0;
4'hA: pos=2'd1;
4'hB: pos=2'd0;
4'hC: pos=2'd2;
4'hD: pos=2'd0;
4'hE: pos=2'd1;
4'hF: pos=2'd0;
endcase
end
endmodule
2.提交结果
3.题目分析
A priority encoder is a combinational circuit that, when given an input bit vector, outputs the position of the first 1 bit in the vector. For example, a 8-bit priority encoder given the input 8’b10010000 would output 3’d4, because bit[4] is first bit that is high.
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.
输出首个“高位”。
Hint: Using hexadecimal (4’hb) or decimal (4’d11) number literals would save typing vs. binary (4’b1011) literals.
同样是4bit长的数值,用16进制/10进制表示,就比用2进制表示更节省空间。
4'hC: pos=2'd2;
4'hC表示4bit宽的十进制12(二进制1100),右侧表示2bit宽的十进制2(二进制10)。
VII. Always casez (Priority encoder with casez)
1.代码编写
// 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'd0;
8'bzzzzzz10: pos=3'd1;
8'bzzzzz100: pos=3'd2;
8'bzzzz1000: pos=3'd3;
8'bzzz10000: pos=3'd4;
8'bzz100000: pos=3'd5;
8'bz1000000: pos=3'd6;
8'b10000000: pos=3'd7;
default: pos=3'd0;
endcase
end
endmodule
2.提交结果
3.题目分析
case、casez、casex的真值表:
可见:
- 使用case时,需区分x,z。
- 使用casez时,z可实现全匹配,需区分x。
- 使用casex时,x,z均可实现全匹配。
- 但一般使用casez而不用casex,前者还可以表示don‘t care的值。
- 电路中可以用?代替 z。
- e.g. 对于分支表达式2’b1?
在case中,可匹配2’b1z;在casez中,可匹配2’b11、2’b10、2’b1x、2’b1z;在casex中,可匹配2’b11、2’b10、2’b1x、2’b1z。
VIII. Always nolatches(Avoiding latches)
1.代码编写
// 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;down=1'b0;right=1'b0;up=1'b0; //别写在case里第一句了!!!
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
2.提交结果
3.题目分析
To avoid creating latches, all outputs must be assigned a value in all possible conditions (See also always_if2).
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
end
This 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.
用default value 代替default case,节省unecessary typing(从前每个分支即default分支都需要规定四个信号的装填,现在只需要规定一个)。