【HDLBits刷题笔记】04 Procedures
Alwaysblock1
组合逻辑always块的使用,注意这里的wire和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@(*) begin out_alwaysblock=a&b; end endmodule
Alwaysblock2
组合逻辑用阻塞赋值,时序逻辑用非阻塞赋值,这里与verilog仿真器追踪事件的原理有关,不遵循这一规则将导致很难发现模拟和综合出的硬件之间的非确定性和错误。
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
使用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@(*) begin if(sel_b1&sel_b2) out_always=b; else out_always=a; end endmodule
Always if2
这一节告诉了怎么避免if语句综合出不期望的Latch,即把else的情况补全。
// 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
Always case
case语句的用法,注意case也要把所有条件覆盖,如写一个default,避免综合出不期望的latch。
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=0; endcase end endmodule
Always case2
这一题是一个优先编码器,标准答案直接把所有情况都列出来了,我这里直接用了一个casex,即如果比较双方有一方的某些位的值是z或x,那么这些位的比较就不予考虑。
// 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
Always casez8
这题是一个八位的有限编码器,这里教了casez的使用,和casex的使用是基本一致的,区别是case是全等比较,casez高阻态和0、1比较结果为1,与x比较结果为零,而casex中不定态与0、1、z比较结果均为1。
module top_module ( input [7:0] in, output reg [2:0] pos ); always@(*) begin casez(in) 8'bzzzz_zzz1:pos=0; 8'bzzzz_zz10:pos=1; 8'bzzzz_z100:pos=2; 8'bzzzz_1000:pos=3; 8'bzzz1_0000:pos=4; 8'bzz10_0000:pos=5; 8'bz100_0000:pos=6; 8'b1000_0000:pos=7; default:pos=0; endcase end endmodule
Always nolatches
这里又使用了另外一种方法避免latch:即在组合逻辑块中赋初值。
// 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