HDLBits练习答案(持续更新)

1.Getting Started

2. Verilog Language

2.3 Modules:Hierarchy

2.3.5 Modules and vertors

module top_module ( 
    input clk, 
    input [7:0] d, 
    input [1:0] sel, 
    output [7:0] q 
);
    wire [7:0]	q1,q2,q3,qout;
    
    my_dff8 U1(clk, d, q1);
    my_dff8 U2(clk, q1, q2);
    my_dff8 U3(clk, q2, q3);
    
    always	@(*)
        begin
            case(sel)
                2'b00:	qout<=d;
                2'b01:	qout<=q1;
                2'b10:	qout<=q2;
                2'b11:	qout<=q3;   
            endcase
        end
    assign q=qout;
endmodule

2.3.6 Adder 1

方法1:直接使用变量进行访问,处理方法是将相应的数据按照Module定义的顺序进行调用,参数位置不可以错

module top_module(
    input [31:0] a,
    input [31:0] b,
    output [31:0] sum
);
    wire [15:0]	suml,sumh;
    wire cinl,coutl,couth;
    
    assign cinl=0;
    add16 U1(a[15:0], b[15:0], cinl, suml, coutl);
    add16 U2(a[31:16], b[31:16], coutl, sumh, couth);
    assign sum={sumh, suml};    
endmodule

方法2:使用点变量的方式,好处就是参数位置可以随意调整。

module top_module(
    input [31:0] a,
    input [31:0] b,
    output [31:0] sum
);
    wire [15:0]	suml,sumh;
    wire cinl,coutl,couth;
    
    assign cinl=0;
    add16 U1(.b(b[15:0]), .cin(cinl), .sum(suml), .cout(coutl),.a(a[15:0]) );
    add16 U2(.a(a[31:16]),.cin(coutl), .sum(sumh), .cout(couth), .b(b[31:16]) );
    assign sum={sumh, suml};    
endmodule

2.3.7 Adder 2

此任务是先完成一个小模块add1的设计,两个1bit的数据相加运算,然后再调试add16实现顶层模块的功能

module top_module (
    input [31:0] a,
    input [31:0] b,
    output [31:0] sum
);//
    wire [15:0] suml,sumh;
    wire cinl,cinh,coutl,couth;
    assign cinl=0;
    add16 U1(a[15:0],b[15:0],cinl,suml,coutl);
    add16 U2(a[31:16],b[31:16],coutl,sumh,couth);
    assign sum={sumh,suml};
endmodule

module add1 ( input a, input b, input cin,   output sum, output cout );
// Full adder module here
	assign sum=a^b^cin;
    assign cout= (a&b)|(b&cin)|(a&cin);
endmodule

2.3.8 Carry-select adder

通过低16位的计算得到的进位结果进行选择,这里代码编写的时候要注意改掉以前使用C语言的习惯,比如:

if()
{}
else
{}

在不知不觉中就喜欢添加“{}”,经常导致出错。

module top_module(
    input [31:0] a,
    input [31:0] b,
    output [31:0] sum
);
    wire [15:0]	suml,sumh0,sumh1;
    wire [31:0]	sumh;
    wire cinl,cinh0,cinh1,coutl;
    
    assign cinl=0;
    assign cinh0=0;
    assign cinh1=1;
    add16 U1(a[15:0], b[15:0], cinl, suml,coutl);
    add16 U2(a[31:16], b[31:16], cinh0, sumh0);
    add16 U3(a[31:16], b[31:16], cinh1, sumh1);
    
    always @(*) begin
        if(coutl==0)
            sumh <= {sumh0, suml};
        else
            sumh <= {sumh1, suml};
    end
    assign sum = sumh;
endmodule

2.3.9 Adder-subrtactor

module top_module(
    input [31:0] a,
    input [31:0] b,
    input sub,
    output [31:0] sum
);
    wire [31:0] bxor;
    wire [15:0]	suml,sumh;
    wire cinh;
    always @(*)begin
        if(sub)
            bxor <= b^32'hffff_ffff;
        else
            bxor <= b^32'h0000_0000;            
    end
    add16 U1(a[15:0], bxor[15:0], sub, suml, cinh);
    add16 U2(a[31:16], bxor[31:16], cinh, sumh);
    assign sum = {sumh, suml};
endmodule

2.4 Procedures

2.4.1 Always block1

使用一个与门设计,输出wire和reg

module top_module(
    input a, 
    input b,
    output wire out_assign,
    output reg out_alwaysblock
);
	reg out2;
    assign out_assign = a & b;
    always @(*) begin
    	out_alwaysblock <= a & b;
    end
endmodule

2.4.2 Always block2

用异或门实现三种输出,第一种assign实现组合逻辑,第二种用always@(*)实现组合逻辑,第三种用always @(posedge clk)实现时序逻辑

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

2.4.4 If statement

用两种方式实现2选1选择器

module top_module(
    input a,
    input b,
    input sel_b1,
    input sel_b2,
    output wire out_assign,
    output reg out_always   ); 

//    reg out0;
    assign out_assign = ((sel_b1==1)&&(sel_b2==1))? b:a;
    always @(*)begin
        if((sel_b1==1)&&(sel_b2==1))
            out_always <= b;
        else
            out_always <= a;
    end
    
endmodule

2.4.5 If statement latches

在verilog中如果if-else只写一半,则会出现闩锁,输出状态可能与实际设想的不一致

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 | gas_tank_empty)
           keep_driving = 0;
        else
           keep_driving = 1;
    end

endmodule

上半部分很好理解,下面的语句就不太容易理解了,我们从原来的语句来看,代码的本意应该是如下的真值表,但是原来的代码在arrived=1时就会出现异常,所以我们订正后的代码只要符合该真值表即可。

arrivedgas_tank_emptykeep_driving
001
010
100
110

2.4.6 Case statement— Always case

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

endmodule

2.4.6 Priority encoder—Always case2

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

2.4.7 Priority encoder with casez—Always casez

// 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 = 0; 
            8'bzzzzzz1z: pos = 1;
            8'bzzzzz1zz: pos = 2;
            8'bzzzz1zzz: pos = 3;
            8'bzzz1zzzz: pos = 4; 
            8'bzz1zzzzz: pos = 5;
            8'bz1zzzzzz: pos = 6;
            8'b1zzzzzzz: pos = 7;
            default: 	 pos = 0;
        endcase
    end
endmodule

2.4.7 Avoid latches—Always nolatches

此处介绍了一种不使用default的方法避免出现latch的方法,类似于C中的变量初始化

// 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

2.5 More Verilog Features

2.5.1 Conditional ternary operator

三目操作符(x)? (y):(z)

module top_module (
    input [7:0] a, b, c, d,
    output [7:0] min);//

    // assign intermediate_result1 = compare? true: false;
    wire [7:0] min0,min1;
    always @(*)begin
        min0 = (a<b)?a:b;
        min1 = (c<d)?c:d;
        min <= (min0<min1)?min0:min1;
    end

endmodule

2.5.2 Reduction operators—Reduction

归约运算符(缩位运算符)对一个数据的内部所有位进行&、|、^等等操作

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

    assign parity = ^in;
endmodule

2.5.3 Reduction:Event wider gates—Gates100

module top_module( 
    input [99:0] in,
    output out_and,
    output out_or,
    output out_xor 
);

    assign out_and = &in;
    assign out_or  = |in;
    assign out_xor = ^in;
endmodule

2.5.4 Combinational for-loop:Vector reversal 2—Vector100r

100bit的数据倒序输出

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

2.5.5 Combinational for-loop:255-bit population count—Popcount255

计算一串序列中1的个数

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

    integer i;

    always @(*)begin
        out = 0;
        for(i=0; i<255; i=i+1) 
            begin
            if(in[i])
                out= out+1'b1;
            end
    end

endmodule

2.5.6 Generate for-loop:100-bit binary adder 2—Adder100i

相当于例化100个1bit的全加器来实现100bit的带进位的加法器

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

    integer i;
    
    
    always @(*)begin
        sum[0] = (a[0]^b[0])^cin;
        cout[0] = (a[0]&b[0]) | ((a[0]^b[0])&cin);
        for(i=1; i<100; i=i+1)begin
            sum[i] = (a[i]^b[i])^cout[i-1];
            cout[i] = (a[i]&b[i]) | ((a[i]^b[i])&cout[i-1]);
        end

    end
    
    
endmodule

2.5.7 Generate for-loop:100-bit digit BCD adder—Bcdadd100

待更新

3 Circuits

3.1 Combinational Logic

3.1.1 Basic Gates

1.wire

module top_module (
    input in,
    output out);

    assign out = in;
endmodule

  1. GND
module top_module (
    output out);

    assign out = 0;
endmodule

  1. NOR
module top_module (
    input in1,
    input in2,
    output out);

    assign out = !(in1 | in2);
endmodule

  1. Another gate
module top_module (
    input in1,
    input in2,
    output out);

    assign out = in1 & (!in2);
endmodule

版权声明:本文为weixin_43306071原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明。