HDLbits 代码练习记录

前言

最近在HDLbits 网站(https://hdlbits.01xz.net/wiki/)上练习Verilog代码,将仿真通过的部分代码做一个记录,希望大家多多批评指正,共同进步。

代码部分

Module_add

//Module_add
module top_module(
    input [31:0] a,
    input [31:0] b,
    output [31:0] sum
);
    
    wire [15:0] sum1,sum2;
    wire cin,cout1,cout2;
    
    assign cin = 1'b0;
    
    add16 inst1(a[15:0], b[15:0], cin, sum1, cout1);
    add16 inst2(a[31:16], b[31:16], cout1, sum2, cout2);
    
    assign sum = {sum2, sum1};
endmodule
//

注意:
1、要声明变量cin,再赋值,(考虑代码复用);
2、今后多尝试按名称实例化,按位置容易错。

Module_fadd

//Module_fadd
module top_module (
    input [31:0] a,
    input [31:0] b,
    output [31:0] sum
);
    wire cin1, cout1, cout2;
    wire [15:0] sum1, sum2;
    
    assign cin1 = 1'b0;
    
    add16 instance1(a[15:0], b[15:0], cin1, sum1, cout1);
    add16 instance2(a[31:16], b[31:16], cout1, sum2, cout2);
    
    assign sum = {sum2, sum1};
endmodule

module add1 ( input a, input b, input cin,   output sum, output cout );
    
    always @(a or b or cin)
    	{cout, sum} = a + b + cin;

endmodule

Module_cseladd

//Module_cseladd
module top_module(
    input [31:0] a,
    input [31:0] b,
    output [31:0] sum
);
    wire cin1,cin2_0,cin2_1, cout1, cout2;
    // sum2_0 means carry_in from the first add16 is 0;
    // sum2_1 means carry_in from the first add16 is 1;
    wire [15:0] sum1, sum2_0, sum2_1;
    wire [31:0] sum_0, sum_1;
    
    assign cin1 = 1'b0;
    assign cin2_0 = 1'b0;
    assign cin2_1 = 1'b1;
    
    add16 instance1(.a(a[15:0]), .b(b[15:0]), .cin(cin1), .cout(cout1), .sum(sum1));
    add16 instance2_0(.a(a[31:16]), .b(b[31:16]), .cin(cin2_0), .cout(cout2), .sum(sum2_0));
    add16 instance2_1(.a(a[31:16]), .b(b[31:16]), .cin(cin2_1), .cout(cout2), .sum(sum2_1));
    
    assign sum_0 = {sum2_0, sum1};
    assign sum_1 = {sum2_1, sum1};
    
    always@(*)
    begin
    	case (cout1)
        1'b0 : sum = sum_0;
        1'b1 : sum = sum_1;
    	endcase
    end
endmodule

Module_addsub

在这里插入图片描述

module top_module(
    input [31:0] a,
    input [31:0] b,
    input sub,
    output [31:0] sum
);
    wire [15:0] sum1,sum2;
    wire cout1,cout2;
    wire [31:0] b_xor;

    assign b_xor = b ^ {32{sub}};
    
    add16 instance1(a[15:0], b_xor[15:0], sub, sum1, cout1);
    add16 instance2(a[31:16], b_xor[31:16], cout1, sum2, cout2);
    
    assign sum = {sum2, sum1};

endmodule

注:
1、A^B=AB’+A’B,所以A和0异或等于A,A和1异或等于~A,A和自己异或等于0。
2、若写成assign b_xor = b ^ sub,则会报错,此处的异或是按位异或,所以得把b弄成32位。而且题目也有提示;这一句很多人写复杂了,有人用If…else去判断sub。

Always case2

在这里插入图片描述

module top_module (
    input [3:0] in,
    output reg [1:0] pos  );
	
    always @(*)
        begin
            casez(in)
                4'bzzz1: pos = 2'b00; 
                4'bzz1z: pos = 2'b01; 
                4'bz1zz: pos = 2'b10; 
                4'b1zzz: pos = 2'b11; 
                default: pos = 2'b00;
            endcase
        end
endmodule

注:z代表不关心,平时用的2’bz0也可写成2’b?0

Always nolatches

在这里插入图片描述
代码:

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;
        16'he072 : down = 1;
        16'he074 : right = 1;
        16'he075 : up = 1;    
    	endcase
	end
endmodule

注:
1、所有的输出都必须有赋值——在一个module里,如果有多个输出,而某条件成立时只对一个输出进行赋值(比如0),那么就会产生latch;可以在写case语句前就对所有的输出进行赋值,这样就可以避免latch产生。

Conditional

在这里插入图片描述

module top_module (
    input [7:0] a, b, c, d,
    output [7:0] min);//
	
    wire [7:0] min_1,min_2,min_3;
	assign min_1 = a < b ? a : b;
    assign min_2 = min_1 < c ? min_1 : c;
    assign min_3 = min_2 < d ? min_2 : d;
    assign min = min_3;
    
endmodule

注:操作符优先级中,?:排在最后,所以此处不必写成 (a<b) ? a : b

Reduction

在这里插入图片描述

module top_module (
    input [7:0] in,
    output parity); 
	assign parity = ^ in;
endmodule

注:同理,要想对一个向量的所有位进行与/或操作也一样:
assign parity = & in;
assign parity = | in;

Vector100r

先来一个错误的答案。。。
代码打多了还以为变量类型不是reg就是wire了,都忘记还有integer…
在这里插入图片描述
改了变量就对了。

module top_module( 
    input [99:0] in,
    output [99:0] out
);
    parameter number = 100;
    integer i;
    always @(*)
        begin
            for(i=0; i<number; i=i+1)
                begin
                    out[i] = in[number-i-1];
                end
        end
endmodule

Popcount255

在这里插入图片描述
常规操作,贴上错误的代码。
在这里插入图片描述
这个错误倒挺有价值的,让我知道我还是用软件思维在描述硬件。
assign和always语句块是并行的,而且assign的赋值是一直执行的。也就是说,如果我在always语句块外面用assign给out赋值,那么always块里的for循环完全失效了,因为out一直等于0,把赋值移到always里就好了;
同理,今后也不能在两个always块里对同一个变量进行赋值。

module top_module( 
    input [254:0] in,
    output [7:0] out );

    parameter Bits = 255;
    //assign out = 0;
    integer i;
    
    always @(*)
        begin
        out = 0;
   		for(i=0; i<Bits; i=i+1)
    		begin
    			if (in[i])
        			out = out + 1;
    			else
        			out = out;
    		end
        end
endmodule

Adder100i

在这里插入图片描述

module top_module( 
    input [99:0] a, b,
    input cin,
    output [99:0] cout,
    output [99:0] sum );

    integer i;
    parameter Bits = 100;
    
    always @(*)
        begin
            { cout[0], sum[0] } = a[0] + b[0] + cin;
            for(i=1;i<Bits;i=i+1)
        		begin
                    {cout[i], sum[i]} = a[i] + b[i] + cout[i-1];
        		end
        end
endmodule

注:这一题得多想下,看到实例化我还以为需要和Module_fadd一样再写一个一位加法器然后再实例化,所以觉得很复杂。
其实好像只要加法器的cout和下一个加法器的cin用同一个变量表示,不就相当于连接上了嘛。不一定需要通过实例化来连线。(不知道这样理解是否有问题)

Popcount3

A “population count” circuit counts the number of '1’s in an input vector. Build a population count circuit for a 3-bit input vector.

module top_module( 
    input [2:0] in,
    output [1:0] out );

	integer i;
    
    always@(*)
        	begin
                out = 0;
                for(i=0;i<3;i=i+1)
                    out =  in[i]+ out;
            end
    // 答案提供的其他方法
    // This is a function of 3 inputs. One method is to use a 8-entry truth table:
	// in[2:0] out[1:0]
	// 000      00
	// 001      01
	// 010      01
	// 011      10
	// 100      01
	// 101      10
	// 110      10
	// 111      11
	// assign out[0] = (~in[2] & ~in[1] & in[0]) | (~in[2] & in[1] & ~in[0]) | (in[2] & ~in[1] & ~in[0]) | (in[2] & in[1] & in[0]);
	// assign out[1] = (in[1] & in[0]) | (in[2] & in[0]) | (in[2] & in[1]);
	
	// Using the addition operator works too:
	// assign out = in[0]+in[1]+in[2];
	
	// Yet another method uses behavioural code inside a procedure (combinational always block)
	// to directly implement the truth table:
	/*
	always @(*) begin
		case (in)
			3'd0: out = 2'd0;
			3'd1: out = 2'd1;
			3'd2: out = 2'd1;
			3'd3: out = 2'd2;
			3'd4: out = 2'd1;
			3'd5: out = 2'd2;
			3'd6: out = 2'd2;
			3'd7: out = 2'd3;
		endcase
	end
	*/
endmodule

注:这道题隐含了in是用二进制表示的(毕竟问1的个数,显然就是01代码了),所以不用这么复杂,直接 assign out = in[0]+in[1]+in[2];

Gatesv

在这里插入图片描述

module top_module( 
    input [3:0] in,
    output [2:0] out_both,
    output [3:1] out_any,
    output [3:0] out_different );
	
    assign out_any = in[3:1] | in[2:0];
	assign out_both = in[2:0] & in[3:1];
	assign out_different = in ^ {in[0], in[3:1]};
   	/*	不懂可以看下面详细解释
    assign out_both = { in[3] & in[2], in[2] & in[1], in[1] & in[0] };
    assign out_any = { in[3] | in[2], in[2] | in[1], in[1] | in[0] };
    assign out_different  = { in[3] ^ in[0], in[2] ^ in[3], in[1] ^ in[2], in[0] ^ in[1]};    
    */
endmodule

之后尝试以专题形式总结

Circuits_Combinational Logic_Arithmetic Circuits 总结

3-bit binary adder & 4-digit BCD adder

在这里插入图片描述

在这里插入图片描述
这两题有以下共同点:
1.a和b的位数均大于1,因此在实例化的时候要注意输入和输出的位宽,比如

bcd_fadd u1_fadd(
       .a(a[3:0]),
       .b(b[3:0]),
       .cin(cin),
       .cout(cout_temp[0]),
       .sum(sum[3:0])
   );

2.要进行循环例化。注意不能直接用for,而要用generate语句搭配for循环。注意写的时候注意别漏了begin-end块的名字

generate
        genvar i;
        for(i=4;i<16;i=i+4)
            begin:fadder
                bcd_fadd u1_fadd(
                    .a(a[i+3:i]),
        			.b(b[i+3:i]),
                    .cin(cout_temp[i-4]),
        			.cout(cout_temp[i+3:i]),
                    .sum(sum[i+3:i]));
            end
    endgenerate

最后附上代码

//3-bit binary adder
module top_module( 
    input [2:0] a, b,
    input cin,
    output [2:0] cout,
    output [2:0] sum );

    fadd u1_fadd(
        .a(a[0]),
        .b(b[0]),
        .cin(cin),
        .cout(cout[0]),
        .sum(sum[0])
    				);
    generate				//多个例化不可只用for,要用generate
        genvar i;
            for(i=1;i<3;i=i+1)
                begin:adder	//注意别漏了模块名
                fadd u2_fadd(
                    .a(a[i]),
                    .b(b[i]),
                    .cin(cout[i-1]),
                    .cout(cout[i]),
                    .sum(sum[i])
    				);
                end
    endgenerate
endmodule

module fadd(input a,b,cin,
           output cout,sum);
    assign {cout,sum}=a+b+cin;
endmodule
    
//4-digit BCD adder
module top_module( 
    input [15:0] a, b,
    input cin,
    output cout,
    output [15:0] sum );

    wire [15:0] cout_temp;
    
    bcd_fadd u1_fadd(
        .a(a[3:0]),
        .b(b[3:0]),
        .cin(cin),
        .cout(cout_temp[0]),
        .sum(sum[3:0])
    );
    
    generate
        genvar i;
        for(i=4;i<16;i=i+4)
            begin:fadder
                bcd_fadd u1_fadd(
                    .a(a[i+3:i]),
        			.b(b[i+3:i]),
                    .cin(cout_temp[i-4]),
        			.cout(cout_temp[i+3:i]),
                    .sum(sum[i+3:i]));
            end
    endgenerate
                    
                    assign cout = cout_temp[12];
endmodule


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Hardworking_IC_boy

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值