HDLBits答案5-Procedures

1.Always block(combinational)

有两种类型的always块:
组合:always@(*)
时序:always@(posedge clk)
组合always块等效于assign语句
例如下面描述了相同的电路

assign out1 = a & b | c ^ d;
always@(*) out2 = a & b | c ^ d;
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 block(clocked)

verilog中有三种赋值方式:
1.连续赋值:assign x = y;只能在always块外使用
2.阻塞赋值:x = y;只能在always块内使用
3.非阻塞赋值:x <= y;只能在always块内使用
在组合逻辑always块中(always @(*))使用阻塞赋值语句;
在时序逻辑always块中(always@(posedge clk)) 使用非阻塞赋值语句;
使用赋值语句,组合always块和时序always块三种方式构建一个异或门。

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

一个if语句会产生一个2选1的数据选择器,相当于三元运算符
在这里插入图片描述

always@(*)begin
	if(condition)begin
		out = x;
	end
	else begin
		out = y;
	end
end
assign out = (condition)?x : y;

建立一个2比1的mux,在a和b之间进行选择。如果sel_b1和sel_b2都为真,选择b。重复两次,一次使用assign语句,另一次使用过程性if语句
在这里插入图片描述

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)begin
			out_always = b;
		end
		else begin
			out_always = a;
		end
			
	end
endmodule

4.If statement latches

锁存器与触发器的区别?
锁存器是一种对脉冲电平(也就是0或1)敏感的存储单元电路,而触发器是一种对脉冲(即上升沿或者下降沿)敏感的存储电路。
当我们在使用if语句或者case语句时,我们必须考虑到所有情况并给对应情况的输出进行赋值,意味着我们要为else或者default中的输出赋值。

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 begin
			keep_driving = 0;
		end
	end
endmodule

5.Case statement

Verilog中的case语句几乎等同于if-else-if-else序列,它的语法和功能不同于C语言中的switch语句

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

1.case语句以case开始,每个case的选项以分号结束。
2.每个case的选项中只能执行一个statement,所以就无需break语句。但如果我们想在一个case选项中执行多个statement,就需要使用begin…end
3.case中可以有重复的case item,首次匹配的将会被执行

Case语句在Case数量较多的情况下比if语句更方便。所以,在这个练习中,创建一个6比1的多路复用器。当sel在0 ~ 5之间时,选择相应的数据输入。否则,输出0。数据输入和输出都是4位宽。

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  
        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 = 3'b0;
        endcase
    end

endmodule

6.Priority encoder

优先编码器是一种组合电路,当给定输入位向量时,输出向量中前1位的位置。例如,给定输入8’b10010000的8位优先编码器将输出3’d4,因为位[4]是第一个高的位。

module top_module (
    input [3:0] in,
    output reg [1:0] pos  );
    always@(*) begin
        case(in)
            4'b0000:pos = 2'b00;
            4'b0001:pos = 2'b00;
            4'b0010:pos = 2'b01;
            4'b0011:pos = 2'b00;
            4'b0100:pos = 2'b10;
            4'b0101:pos = 2'b00;
            4'b0110:pos = 2'b01;
            4'b0111:pos = 2'b00;
            4'b1000:pos = 2'b11;
            4'b1001:pos = 2'b00;
            4'b1010:pos = 2'b01;
            4'b1011:pos = 2'b00;
            4'b1100:pos = 2'b10;
            4'b1101:pos = 2'b00;
            4'b1110:pos = 2'b01;
            4'b1111:pos = 2'b00;
            default:pos = 2'b00;
        endcase
    end
endmodule

7.Priority encoder with casez

casez的作用,在比较中,它将值z的位视为不关心

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)
			8'bzzzzzzz1:pos = 0;
            8'bzzzzzz10:pos = 1;
            8'bzzzzz100:pos = 2;
            8'bzzzz1000:pos = 3;
            8'bzzz10000:pos = 4;
            8'bzz100000:pos = 5;
            8'bz1000000:pos = 6;
            8'b10000000:pos = 7;
            default: pos = 0;
        endcase	
	end
endmodule

8.Avoiding latches

在这里插入图片描述
为避免生成锁存器,所有的输入情况必须要被考虑到。但仅有一个简单的default是不够的,我们必须在case item和default中为4个输出进行赋值,这会导致很多不必要的代码编写。
一种简单的方式就是对输出先进行赋初值的操作,这种类型的代码确保在所有可能的情况下输出都被赋值,除非case语句覆盖了赋值。

module top_module (
    input [15:0] scancode,
    output reg left,
    output reg down,
    output reg right,
    output reg up  ); 
    always @(*) begin
        left=0;down=0;right=0;up=0;
        case(scancode)
            16'he06b:left=1;
            16'he072:down=1;
            16'he074:right=1;
            16'he075:up=1;
        endcase
    end

endmodule
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值