Verilog案例

1、用verilog HDL设计一个4位加法器树乘法器

`timescale 1ns/10ps
module mul_addtree(mul_a,mul_b,mul_out);
    input [3:0] mul_a,mul_b;          //IO端口声明
    output [7:0] mul_out;
    
    wire [7:0] mul_out;               //连线类型声明
    wire [7:0] store0,store1,store2,store3;
    wire [7:0] add01,add23;
    
    assign store0 = mul_b[0]?{4'b0000,mul_a}:8'b0000_0000;
    assign store1 = mul_b[1]?{3'b000,mul_a,1'b0}:8'b0000_0000;
    assign store2 = mul_b[2]?{2'b00,mul_a,2'b00}:8'b0000_0000;
    assign store3 = mul_b[3]?{1'b0,mul_a,3'b000}:8'b0000_0000;
    assign add01 = store0+store1;
    assign add23 = store2+store3;
    assign mul_out = add01+add23;
endmodule

//*****************testbench of mul_addtree******************
module mul_addtree_tb;
    wire [7:0] mul_out;               //输出是wire
    reg [3:0] mul_a;                  //输入是reg 
    reg [3:0] mul_b;
    
    //模块例化
    mul_addtree U(.mul_a(mul_a),.mul_b(mul_b),.mul_out(mul_out));
    
    //测试信号
    initial
        begin
            mul_a=4'b0;mul_b=4'b0;
            repeat(9)
                begin
                    #20 mul_a = mul_a+1'b1;mul_b = mul_b+1'b1;
                end
        end
endmodule

 

 

2、用verilog HDL设计一个两级流水线4位加法器树乘法器

`timescale 1ns/10ps
module mul_addtree2(clk,clr,mul_a,mul_b,mul_out);

    input clk,clr;
    input [3:0] mul_a,mul_b;                    //IO端口声明
    output [7:0] mul_out;
    
    reg [7:0] add_tmp1,add_tmp2,mul_out;        //连线类型声明
    wire [7:0] store0,store1,store2,store3;
    
    assign store0 = mul_b[0]?{4'b0000,mul_a}:8'b0000_0000;   //逻辑设计
    assign store1 = mul_b[1]?{3'b000,mul_a,1'b0}:8'b0000_0000;
    assign store2 = mul_b[2]?{2'b00,mul_a,2'b00}:8'b0000_0000;
    assign store3 = mul_b[3]?{1'b0,mul_a,3'b000}:8'b0000_0000;
    
    always@(posedge clk or negedge clr)
    begin
        if(!clr) begin             //注意使用非阻塞语句
            add_tmp1 <= 8'b0;
            add_tmp2 <= 8'b0;
            mul_out <= 8'b0;
        end
        else begin
           add_tmp1 <= store2+store3;
            add_tmp2 <= store1+store0;
            mul_out <= add_tmp1+add_tmp2;
        end
    end
endmodule

//*****************testbench of mul_addtree******************
module mul_addtree2_tb;
    wire [7:0] mul_out;               //输出是wire
    reg [3:0] mul_a;                  //输入是reg 
    reg [3:0] mul_b;
    reg clk,clr;
    
    //模块例化
    mul_addtree2 U(.mul_a(mul_a),.mul_b(mul_b),.mul_out(mul_out),.clk(clk),.clr(clr));
    
    //测试信号
    initial
        begin
            clk=0;clr=0;mul_a=1;mul_b=1;
            #5 clr=1;
        end
        
    always #10 clk=~clk;
    
    initial
        begin
            repeat(5)
            begin
                #20 mul_a = mul_a+1;mul_b = mul_b+1;
            end 
        end
endmodule

 

3、用verilog HDL 设计4位wallace树乘法器

1)从数据最多的那一列开始,用半加器将数据最多的那一列中的两个数相加,得到和a0以及向高列的进位b0;

这时得到进位的那一列也有四个数据,我们也用半加器相加得到积a1和进位b0

2)用半加器和全加器反复压缩覆盖所有数据超过三个的列,得到下表所示的数据

3)最后采用简单的2输入加法器,就可以得到相乘结果了

 

 

module wallace(x,y,out);
    input [3:0] x,y;        //IO端口声明
    output [7:0] out;
    
    wire [7:0] out;       //连线类型声明
    wire [15:0] a;        
    wire [1:0] out1,out2,out3,out4,out5,out6;
    wire [6:0] add1,add2;
    
    assign a = {x[0],x[1],x[2],x[3],x[0],x[1],x[2],x[3],x[0],x[1],x[2],x[3],x[0],x[1],x[2],x[3]}
              &{y[0],y[0],y[0],y[0],y[1],y[1],y[1],y[1],y[2],y[2],y[2],y[2],y[3],y[3],y[3],y[3]};
                 
    //第一级 2个半加器
    Hadd U1(.x(a[3]),.y(a[6]),.out(out1));
    Hadd U2(.x(a[2]),.y(a[5]),.out(out2));
    
    //第二级 3个全加器+1个半加器
    Hadd U3(.x(a[7]),.y(a[10]),.out(out3));
    Fadd U4(.x(a[12]),.y(a[9]),.c(out1[0]),.out(out4));
    Fadd U5(.x(a[8]),.y(out2[0]),.c(out1[1]),.out(out5));
    Fadd U6(.x(a[4]),.y(a[1]),.c(out2[1]),.out(out6));
    
    assign add1 = {a[0],out6[0],out5[0],out4[0],a[13],a[14],a[15]};
    assign add2 = {out6[1],out5[1],out4[1],out3[1],out3[0],a[11],1'b0};
    assign out = add1+add2;
endmodule

module Hadd(x,y,out);
    input x,y;
    output [1:0] out;
    assign out = x+y;
endmodule

module Fadd(x,y,c,out);
    input x,y,c;
    output [1:0] out;
    assign out = x+y+c;
endmodule

//*************测试代码***************
module wallace_tb;
    reg [3:0] x,y;
    wire [7:0] out;
    
    wallace U(.x(x),.y(y),.out(out));
    
    initial
    begin
        x=3;y=4;
        #20 x=2;y=3;
        #20 x=6;y=8;
    end
endmodule

 

 

 4、用verilog HDL设计一个十六进制键盘电路的键盘扫描和编码器

1)键盘的每一行都会通过一个下拉电阻连接到地,而行和列之间有一个以按键为开关的连接,当按下按键时行和列之间就建立了连续。

2)如果列线的值为1,则由按键连接到的那个列的行值也会被拉升为1,反之行线将会被下拉至0。

3)设计一个时序状态机,通过不同状态之间的转换来实现信号的检测识别以及对应扫描的输出。

每一步对应一个时钟周期
第一步,S_0状态,将Col[3:0] 都置为1,检测row[3:0]的信号值;若row为1,跳到S_1; 若为0,保持在当前状态;
第二步,S_1状态,将Col[0] 置为1,检测row[3:0]的信号值;若row为1,跳到S_5; 若为0,跳到S_2;
第三步,S_2状态,将Col[1] 置为1,检测row[3:0]的信号值;若row为1,跳到S_5; 若为0,跳到S_3;
第四步,S_3状态,将Col[2] 置为1,检测row[3:0]的信号值;若row为1,跳到S_5; 若为0,跳到S_4;
第五步,S_4状态,将Col[3] 置为1,检测row[3:0]的信号值;若row为1,跳到S_5; 若为0,跳到S_0;
第六步,S_5状态,将Col[3:0] 置为1(意味着code的输出值只需要维持一个clk,Valid 的值也一样),检测row[3:0] 的信号值,若row为1,保持为S_5,若为0,跳到S_0

 

4)十六进制键盘电路的编码器码表

 

 5)keypad.v

//顶层模块
module keypad(clock,reset,row,code,valid,col);
    input clock,reset;
    input[3:0] row;
    output[3:0] code;
    output valid;
    output[3:0] col;
    wire s_row;
    
    hex_keypad_grayhill U1(.code(code),.col(col),.valid(valid),.row(row),.s_row(s_row),.clock(clock),.reset(reset));
    synchronizer U2(.s_row(s_row),.row(row),.clock(clock),.reset(reset));
endmodule

//编码模块
module hex_keypad_grayhill(code,col,valid,row,s_row,clock,reset);
    output[3:0] code;    //对应扫描码
    output valid;        //当前输出有效
    output[3:0] col;     //
    input[3:0] row;     //
    input s_row;         //因为键盘的输入是一个异步信号,因此需要引入一个同步模块,将row 的信号转换成同步的s_row 信号
    input clock,reset;
    
    reg[3:0] col;
    reg[3:0] code;
    reg[5:0] state,next_state;
    
    parameter S_0=6'b000_001,S_1=6'b000_010,S_2=6'b000_100,S_3=6'b001_000,S_4=6'b010_000,S_5=6'b100_000;
    
    assign valid=(state==S_1 || state==S_2 || state==S_3 || state==S_4) && row;

    always@(row or col)
    begin
        case({row,col})
            8'b0001_0001:code=0;
            8'b0001_0010:code=1;
            8'b0001_0100:code=2;
            8'b0001_1000:code=3;
            8'b0010_0001:code=4;
            8'b0010_0010:code=5;
            8'b0010_0100:code=6;
            8'b0010_1000:code=7;
            8'b0100_0001:code=8;
            8'b0100_0010:code=9;
            8'b0100_0100:code=10;
            8'b0100_1000:code=11;
            8'b1000_0001:code=12;
            8'b1000_0010:code=13;
            8'b1000_0100:code=14;
            8'b1000_1000:code=15;
            default code=0;
        endcase
    end
    
    
    always@(state or row or s_row)
    begin
       next_state=state;   //要初始化,使得系统复位以后能进入正确的状态
        col=0;
        case(state)
            S_0:begin
                col=15;
                if(s_row) next_state=S_1;
            end
            S_1:begin
                col=1;
                if(row) next_state=S_5;
                else next_state=S_2;
            end
            S_2:begin
                col=2;
                if(row) next_state=S_5;
                else next_state=S_3;
            end
            S_3:begin
                col=4;
                if(row) next_state=S_5;
                else next_state=S_4;
            end
            S_4:begin
                col=8;
                if(row) next_state=S_5;
                else next_state=S_0;
            end
            S_5:begin
                col=15;
                if(row) next_state=S_5;
                else next_state=S_0;
            end
        endcase
    end
    
    always@(posedge clock or posedge reset)
    begin
        if(reset) state<=S_0;
        else state<=next_state;
    end
endmodule

module synchronizer(s_row,row,clock,reset);
    input clock,reset;
    input[3:0] row;
    output s_row;
    
    reg s_row;
    reg a_row;
    
    always@(negedge clock or posedge reset)  //为了消除潜在的冒险,这里的同步clk 选用下边沿驱动
    begin
        if(reset) begin
            a_row<=0;
            s_row<=0;
        end
        else begin
            a_row<=row[0]||row[1]||row[2]||row[3]; //通过检测各个行线值的或逻辑来确定是否有按键按下
            s_row<=a_row;
        end
    end    
endmodule

6)hex_keypad_grayhill_tb.v

`timescale 1ns/1ns
module hex_keypad_grayhill_tb;
    wire[3:0] code;
    wire valid;
    wire[3:0] col;
    wire[3:0] row;
    reg clock;
    reg reset;
    reg[15:0] key;
    integer j,k;
    reg [39:0] pressed;//在ASCII码中一个英文字符占一个字节,这里有5个英文字符故需5*8=40个bit位
    
    keypad U1(.clock(clock),.reset(reset),.row(row),.code(code),.valid(valid),.col(col));//顶层模块
    
    row_signal U2(.row(row),.key(key),.col(col)); //产生测试信号
    
    always@(key)begin
        case(key)
            16'h0000:pressed="None";
            16'h0001:pressed="key_0";
            16'h0002:pressed="key_1";
            16'h0004:pressed="key_2";
            16'h0008:pressed="key_3";
            16'h0010:pressed="key_4";
            16'h0020:pressed="key_5";
            16'h0040:pressed="key_6";
            16'h0080:pressed="key_7";
            16'h0100:pressed="key_8";
            16'h0200:pressed="key_9";
            16'h0400:pressed="key_A";
            16'h0800:pressed="key_B";
            16'h0100:pressed="key_C";
            16'h0200:pressed="key_D";
            16'h0400:pressed="key_E";
            16'h0800:pressed="key_F";
            default:pressed="None";
        endcase
    end
    
    initial #2000 $stop;
    initial begin
        clock=0;
        forever #5 clock=~clock;
    end
    initial begin
        reset=1;
        #10 reset=0;
    end
    initial begin
        for(k=0;k<=1;k=k+1)
        begin
            key=0;
            #20 for(j=0;j<=16;j=j+1)
            begin
                #20 key[j]=1;
                #60 key=0;
            end 
        end
    end
endmodule

//用于确定按键所在的行
module row_signal(row,key,col);
    output[3:0] row;
    input[15:0] key;
    input[3:0] col;
    reg[3:0] row;
    
    always@(key or col)
    begin
        row[0]=(key[0]&&col[0])||(key[1]&&col[1])||(key[2]&&col[2])||(key[3]&&col[3]);
        row[1]=(key[4]&&col[0])||(key[5]&&col[1])||(key[6]&&col[2])||(key[7]&&col[3]);
        row[2]=(key[8]&&col[0])||(key[9]&&col[1])||(key[10]&&col[2])||(key[11]&&col[3]);
        row[3]=(key[12]&&col[0])||(key[13]&&col[1])||(key[14]&&col[2])||(key[15]&&col[3]);
    end    
endmodule

7)波形图

 

posted @ 2022-05-11 11:26  super_sweet  阅读(744)  评论(0编辑  收藏  举报