【FPGA学习】HDLbits练习(持续更新中。。。。)

该文档详细介绍了Verilog HDL的基础知识,包括基本逻辑门、组合逻辑电路、时序逻辑电路的设计,以及使用Verilog进行多模块连接和向量操作的方法。通过实例展示了如何创建反相器、与门、异或门等,并探讨了如何避免在设计中引入锁存器错误。此外,还涵盖了条件运算符、减少运算符在更广泛逻辑电路中的应用。
摘要由CSDN通过智能技术生成

目录

verilog language

base

simple wire

four wires

inverter

 and gate

nor gate

 xnor gate

declaring wire

 7845 chip

vectors

vectors

Vector1

Vector2

Vectorgates 

 Gates4

 Vector3

Vectorr 

 Vector4\

Vector5

Modules:Hierarchy

Module

Connecting ports by position

Connecting ports by name

 Three modules

Modules and vectors

adder1

 Carry-select adder

Adder-subtractor

procedures

Always blocks(combinational)

 Always blocks(clocked)

 If statement

 If statement latches

Case statement

Pority encoder

 Priority encoder with casez

 Avoiding latches

More Verilog Features

 Conditional ternary operator

 Reduction operators

 Reduction even wider gates

 Combinational for-loop;Vector reversal2

Combinational for-loop : 255-bit population count

Generatefor-loop:100-bit binary adder 2


verilog language

base

simple wire

module top_module( input in, output out );

endmodule

four wires

module top_module( 
    input a,b,c,
    output w,x,y,z );
	assign w = a;
    assign x = b;
    assign y = b;
    assign z = c;
endmodule

inverter

module top_module( input in, output out );
	assign out = ~in;
endmodule

 and gate

module top_module( 
    input a, 
    input b, 
    output out );
	assign out = a & b;
endmodule

nor gate

module top_module( 
    input a, 
    input b, 
    output out );
    assign out = ~(a | b);
endmodule

 xnor gate

module top_module( 
    input a, 
    input b, 
    output out );
    assign out = ~(a^b);
endmodule

declaring wire

`default_nettype none
module top_module(
    input a,
    input b,
    input c,
    input d,
    output out,
    output out_n   ); 
	wire wire_1,wire_2;
    assign wire_1 = a & b;
    assign wire_2 = c & d;
    assign out = wire_1 | wire_2;
    assign out_n = ~out;
endmodule

 7845 chip

module top_module ( 
    input p1a, p1b, p1c, p1d, p1e, p1f,
    output p1y,
    input p2a, p2b, p2c, p2d,
    output p2y );
    assign p2y =( p2a & p2b) | (p2c & p2d);
    assign p1y = (p1a & p1c & p1b) | (p1d & p1e & p1f);
endmodule

vectors

vectors

module top_module ( 
    input wire [2:0] vec,
    output wire [2:0] outv,
    output wire o2,
    output wire o1,
    output wire o0  ); // Module body starts after module declaration
	
    assign outv = vec;
    assign o2 = vec[2];
    assign o1 = vec[1];
    assign o0 = vec[0];
    
endmodule

Vector1

        Build a combinational circuit that splits an input half-word (16 bits, [15:0] ) into lower [7:0] and upper[15:8] bytes.

`default_nettype none     // Disable implicit nets. Reduces some types of bugs.
module top_module( 
    input wire [15:0] in,
    output wire [7:0] out_hi,
    output wire [7:0] out_lo );
    assign out_hi = in[15:8];
    assign out_lo = in[7:0];
endmodule

Vector2

        A 32-bit vector can be viewed as containing 4 bytes (bits [31:24], [23:16], etc.). Build a circuit that will reverse the byte ordering of the 4-byte word.

AaaaaaaaBbbbbbbbCcccccccDddddddd => DdddddddCcccccccBbbbbbbbAaaaaaaa

This operation is often used when the endianness of a piece of data needs to be swapped, for example between little-endian x86 systems and the big-endian formats used in many Internet protocols

module top_module( 
    input [31:0] in,
    output [31:0] out );//

    assign out = {in[7:0],in[15:8],in[23:16],in[31:24]};

endmodule

Vectorgates 

module top_module( 
    input [2:0] a,
    input [2:0] b,
    output [2:0] out_or_bitwise,
    output out_or_logical,
    output [5:0] out_not
);
	assign out_or_bitwise = a | b;
    assign out_or_logical = a||b;
    assign out_not = {~b,~a};
endmodule

 Gates4

 

module top_module( 
    input [3:0] in,
    output out_and,
    output out_or,
    output out_xor
);
    assign out_and = ∈
    assign out_or = |in;
    assign out_xor = ^in;

endmodule

 Vector3

module top_module (
    input [4:0] a, b, c, d, e, f,
    output [7:0] w, x, y, z );//

    assign { w,x,y,z} = {a,b,c,d,e,f,2'b11};

endmodule

Vectorr 

 

module top_module( 
    input [7:0] in,
    output [7:0] out
);
    assign out = {in[0],in[1],in[2],in[3],in[4],in[5],in[6],in[7]};
endmodule

 Vector4\

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

    assign out = { {24{in[7]}} , in };

endmodule

Vector5

module top_module (
    input a, b, c, d, e,
    output [24:0] out );//

    // The output is XNOR of two vectors created by 
    // concatenating and replicating the five inputs.
    assign out = ~{ {5{a}},{5{b}},{5{c}},{5{d}},{5{e}} } ^ { 5{a,b,c,d,e} };

endmodule

//second way

    wire [24:0] way1;
    wire [24:0] way2;
    
    assign way1 = ~{{5{a}}, {5{b}}, {5{c}}, {5{d}}, {5{e}}};
    assign way2 = {5{a, b, c, d, e}};
    assign out = way1 ^ way2;

Modules:Hierarchy

Module

        这里主要考察模块例化,介绍中介绍了两种例化方式基于位置(by position)和基于名称(by name)

By position :mod_a instance1(wa,wb,wc);从左到右依次对应相应端口,这种写法简洁,如果模块的端口列表发生更改,则需要找到并更改模块的所有实例以匹配新模块。

By name :mod_a instance2 ( .out(wc), .in1(wa), .in2(wb) ); 他是将模块外部的信号与模块的端口相连接,与顺序无关,故不论子模块的端口列表位置如何,都将对应名称一一连接。

module top_module ( input a, input b, output out );
   // mod_a instance1(a,b,out);
        mod_a	mod_a_inst(
        .in1	(a),
        .in2	(b),
        .out	(out)
    );
endmodule

/*module mod_a ( input in1, input in2, output out );
    // Module body
endmodule*/

Connecting ports by position

module top_module ( 
    input a, 
    input b, 
    input c,
    input d,
    output out1,
    output out2
);
    mod_a mod_a_inst(out1,out2,a,b,c,d);
endmodule

Connecting ports by name

module top_module ( 
    input a, 
    input b, 
    input c,
    input d,
    output out1,
    output out2
);
    mod_a mod_a_inst(
        .in1 (a),
        .in2 (b),
        .in3 (c),
        .in4 (d),
        .out1 (out1),
        .out2 (out2)
    
    
    );

        
endmodule

 Three modules

module top_module ( input clk, input d, output q );
	  wire	wire_1;
      wire wire_2;
    
    my_dff my_dff_inst1(
        .clk (clk),
        .d  (d),
        .q  (wire_1)
    );
    
    my_dff my_dff_inst2(
        .clk (clk),
        .d  (wire_1),
        .q  (wire_2)
    );
    
    my_dff my_dff_inst3(
        .clk (clk),
        .d  (wire_2),
        .q  (q)
    );

endmodule

Modules and vectors

 

module top_module ( 
    input clk, 
    input [7:0] d, 
    input [1:0] sel, 
    output [7:0] q 
);
    wire  [7:0]  wire_1;
    wire  [7:0]  wire_2;
    wire  [7:0]  wire_3;
    
    my_dff8 my_dff8_inst1(
        .clk (clk),
        .d  (d),
        .q  (wire_1)
    );
    
    my_dff8 my_dff8_inst2(
        .clk (clk),
        .d  (wire_1),
        .q  (wire_2)
    );
    
    my_dff8 my_dff8_inst3(
        .clk (clk),
        .d  (wire_2),
        .q  (wire_3)
    );
    always @(*)begin
        case (sel)
            2'd3: q = wire_3;
            2'd2: q = wire_2;
            2'd1: q = wire_1;
            2'd0: q = d;
        
        endcase   
    end
endmodule

adder1

module top_module(
    input [31:0] a,
    input [31:0] b,
    output [31:0] sum
);
    wire wire_1;
 add16 add16_inst1(
     .a (a[15:0]),
     .b (b[15:0]),
        .cin (0),
        .cout (wire_1),
     .sum(sum[15:0])
    );
    
    add16 add16_inst2(
        
        .a (a[31:16]),
        .b (b[31:16]),
        .cin (wire_1) ,
        .sum (sum[31:16]),
        .cout ()
                     
     );
		
endmodule

 adder2

add16是已提供的 将两个add16例化,并且写出add1全加器

例图的画法容易混淆 a[15:0] b[15:0] sum[15:0]就已经代表了16个1bit的add1连在一块。不需要重复16次1bit的例化。

module top_module (
    input [31:0] a,
    input [31:0] b,
    output [31:0] sum
);
    wire wire_1;
 add16 add16_inst1(
     .a (a[15:0]),
     .b (b[15:0]),
        .cin (0),
        .cout (wire_1),
     .sum(sum[15:0])
    );
    
    add16 add16_inst2(
        
        .a (a[31:16]),
        .b (b[31:16]),
        .cin (wire_1) ,
        .sum (sum[31:16]),
        .cout ()
                     
     );

endmodule

module add1 ( input a, input b, input cin,   output sum, output cout );

    assign sum = a^b^cin;
    assign cout = (a|b)&cin |(a&b);
// assign {count,sum} = a+b+cin;

endmodule

 Carry-select adder

module top_module(
    input [31:0] a,
    input [31:0] b,
    output [31:0] sum
);
    wire wire_1;
    wire [15:0]sum1;
    wire [15:0]sum2;
   	   
 add16 add16_inst1(
     .a (a[15:0]),
     .b (b[15:0]),
     .cin (0),
     .cout (wire_1),
     .sum(sum[15:0])
    );
    
    add16 add16_inst2(
        
        .a (a[31:16]),
        .b (b[31:16]),
        .cin (0) ,
        .sum (sum1),
        .cout ()
    );
       add16 add16_inst3(
        
        .a (a[31:16]),
        .b (b[31:16]),
        .cin (1),
        .sum (sum2),
           .cout ()     
       );
        always @(*)begin
            case(wire_1)
                1'b0 : sum[31:16] = sum1;
                1'b1 : sum[31:16] = sum2;
                default :;
            endcase
            
        end
//assign sum[31:16] = (wire_1)?sum2:sum1;
endmodule

Adder-subtractor

        此题要求做一个具有可切换的(sub)加法—减法器,这个电路由两个可执行操作的电路组成:(a+b+0),(a+~b+1)这里0,1既作为计算的一个数值,同时也作为判断做加法还是减法的控制信号,这个操作由一个异或门形成。

module top_module(
    input [31:0] a,
    input [31:0] b,
    input sub,
    output [31:0] sum
);
    wire [31:0]yihuo;
    wire wire_cout;
    assign yihuo = b^{32{sub}};
    
    add16 add16_inst1(
        .a(a[15:0]),
        .b(yihuo[15:0]),
        .cin(sub),
        .cout(wire_cout),
        .sum (sum[15:0])
    );
    
    add16 add16_inst2(
        .a(a[31:16]),
        .b(yihuo[31:16]),
        .cin(wire_cout),
        .cout(),
        .sum (sum[31:16])
    );

endmodule

procedures

Always blocks(combinational)

always块中被赋值的要为寄存器型的(reg)变量,而在assign块中被赋值的为线网型(wire)变量。

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

 Always blocks(clocked)

用三种描述方式 描述XOR电路

// 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@(*)begin
        out_always_comb = a^b;
    end
    always @(posedge clk)
        out_always_ff <= a^b;
endmodule

 If statement

 分别用assign语句和always语句 描述一个二选一多路器,如果sel_b1、sel_b2为1则输出b,否则输出a。

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

 If statement latches

       此题主要讲的是; 为什么if语句会引入新的错误,怎么去避免自锁,但我们在在设计电路时我们首先会想:需要一个怎样的逻辑门、需要一个什么样的逻辑块他们以规定的输入产生想要的输出、设置一个触发使电路动作

在设计电路时不要指望自己写的代码会生成一个正确的电路,例如:

If (cpu_overheated) then shut_off_computer = 1;
If (~arrived) then keep_driving = ~gas_tank_empty;

一个正确的语法不一定会获得一个正确的结果,它主要的原因就是当出现你预想其他情况出现的时候,在verilog中会使输出保持不变。那么就意味着这个输出被“记录了”,在组合逻辑电路中是没有“记忆功能的”,所以但我们没有考虑全部的情况,在预想情况的其他情况出现时,他就会输出上一状态的值(latches),这就不符合我们逻辑组合电路设计的本质。

如何避免:对于if语句我们就需要一个else,或一个默认值申明,保证电路在任何时候都能有一个确切的output。

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

Case statement

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

endmodule

Pority encoder

// synthesis verilog_input_version verilog_2001
module top_module (
    input [3:0] in,
    output reg [1:0] pos  );
    always @(*)begin
        pos = 'd0;//这里如果没赋初值 那么default : pos = 'd0;
        casex (in)
            4'bxxx1: pos = 2'd0;
            4'bxx10: pos = 2'd1;
            4'bx100: pos = 2'd2;
            4'b1000: pos = 2'd3;
            default :;
        endcase 
        
    end

endmodule

 Priority encoder with 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 = 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='d0;
        endcase
            
    end

endmodule

 Avoiding latches

 在case语句中为了避免自锁,要在case赋初值

// 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 (scancode)
            16'he06b : left  =  1'b1;
            16'he072 : down  =  1'b1;
            16'he074 : right =  1'b1;
            16'he075 : up    =  1'b1;
           /* default : begin//为什么这个方法结果不对?
               left   = 1'b0;
                down  = 1'b0;
                right = 1'b0;
                up    = 1'b0;
            end*/
        endcase
    end

endmodule

More Verilog Features

 Conditional ternary operator

 构造一个8bit的最小比较器

module top_module (
    input [7:0] a, b, c, d,
    output [7:0] min);//
	
    wire [7:0] compar_1;
    wire[7:0] compar_2;
  
    assign compar_1 = (a<b)?a:b;
    assign compar_2 = (compar_1 < c)? compar_1 : c;
    assign min= (compar_2 <d )? compar_2:d;// assign intermediate_result1 = compare? true: false;
	
endmodule

 Reduction operators

构建一个8bit奇偶校验电路  偶数为parity= 1 奇数 parity= 0.

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

 Reduction even wider gates

 

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

 Combinational for-loop;Vector reversal2

方法一

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

 方法二(generate)

module top_module( 
    input [99:0] in,
    output [99:0] out
);
  genvar i;
    generate 
         
        for (i = 0 ; i<= 99; i++)begin:reversal
         assign  out[99-i] = in[i]; 
        end
    endgenerate
endmodule

Combinational for-loop : 255-bit population count

 构造一个255的记数器,具有能计255位二进制数中1的个数的功能

module top_module( 
    input [254:0] in,
    output [7:0] out );
    integer i;
    always @(*)begin
        out = 'd0;
        for (i = 0 ; i<= 254 ; i++)begin
            if(in[i])begin
                out = out + 1'b1;
            end
            else begin
                out = out + 1'b0;
            end
        end
            
    end

endmodule

module top_module( 
    input [254:0] in,
    output [7:0] out );
    integer i;
    always @(*)begin
        out = 'd0;
        for (i = 0 ; i<= 254 ; i++)begin
            out = out +in[i];
            end
 
            
    end

endmodule

Generatefor-loop:100-bit binary adder 2

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值