HDLBits自学笔记4:Verilog language.Procedures + More Verilog Features

Procedures

Always blocks(combinational)

建立一个与门,用assign语句和always语句

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)

建立一个异或门,使用assign语句、组合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
endmodul

Always if

if语句通常用于创建2选1选择器,等同于三目运算符:assign out = (condition) ? x : y;

建立一个2选1选择器,如果sel_b1sel_b2为真,选择b,其他情况选择a,使用assignalways

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

If statement latches

如下代码产生了锁存器,修复代码:

always @(*) begin
    if (cpu_overheated)
       shut_off_computer = 1;
end

always @(*) begin
    if (~arrived)
       keep_driving = ~gas_tank_empty;
end

修复后:

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

endmodule

Case statement

case语句创建一个6选1多路选择器

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 = 4'h0;
        endcase
    end
endmodule

Priority encoder

优先编码器输出一个向量中第一个1的位置,建立一个4bit优先编码器,如果输入中没有1,则输出0,

module top_module (
    input [3:0] in,
    output reg [1:0] pos  );
    always @(*) begin
        case(in)
            4'h0   : pos = 2'h0;
            4'h1   : pos = 2'h0;
            4'h2   : pos = 2'h1;
            4'h3   : pos = 2'h0;
            4'h4   : pos = 2'h2;
            4'h5   : pos = 2'h0;
            4'h6   : pos = 2'h1;
            4'h7   : pos = 2'h0;
            4'h8   : pos = 2'h3;
            4'h9   : pos = 2'h0;
            4'ha   : pos = 2'h1;
            4'hb   : pos = 2'h0;
            4'hc   : pos = 2'h2;
            4'hd   : pos = 2'h0;
            4'he   : pos = 2'h1;
            4'hf   : pos = 2'h0;
            default: pos = 2'h0;
        endcase
    end
endmodule

Priority encoder with casez

建立一个8bit优先编码器,从低位开始,输出第一个1的位置,如果输入全0,则输出0,使用casez语句

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

Avoiding latches

假设你在建立一个电路处理PS/2键盘的信号,给定2字节信号,你需要判断被按下的按键是哪个

Scancode[15:0] Arrow key
16’he06b left arrow
16’he072 down arrow
16’he074 right arrow
16’he075 up arrow
Anything else none

你的电路有1个16bit输入,和4个输出,避免产生锁存器

module top_module (
    input [15:0] scancode,
    output reg left,
    output reg down,
    output reg right,
    output reg up  );
    // 方法一:case
    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;
        endcase
    end
    // 方法二:assign
    // assign left  = scancode == 16'he06b;
    // assign down  = scancode == 16'he072;
    // assign right = scancode == 16'he074;
    // assign up    = scancode == 16'he075;
endmodule

More Verilog Features

conditional ternary operator

输入4个无符号数,输出最小值,使用条件三元运算符

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

Reduction operator

奇偶校验常用于传输数据时检测错误,建立一个电路输出8bit数据的奇偶校验位,使用偶校验

奇校验:若8bit数据中1的个数为偶数,则校验位为1,添加校验位后的9bit数据中1的个数为奇数

偶校验:若8bit数据中1的个数为奇数,则校验位为1,添加校验位后的9bit数据中1的个数为偶数

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

Reduction: Even wider gates

建立一个电路,有100bit输入,输出其与、或、异或

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 reversal 2

输入100bit信号,反转其bit顺序输出

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

Combinational for-loop: 255-bit population count

人口计数器,计算一个向量中1的个数,建立一个255位宽的人口计数器

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

Generate for-loop: 100bit binary adder

实例化100个全加器实现一个100bit的行波进位加法器

module top_module( 
    input [99:0] a, b,
    input cin,
    output [99:0] cout,
    output [99:0] sum );
    // 方法一:genearte-for
    generate
        genvar i;
        for(i = 0; i < 100; i = i + 1) begin:gen
            fadd ins(a[i], b[i], (i == 0) ? cin : cout[i - 1], cout[i], sum[i]); 
        end
    endgenerate
    /* 方法二:实例化数组
    fadd ins[99:0](a, b, {cout[98:0], cin}, cout, sum);
    */
endmodule

module fadd(
    input a, b, cin,
    output cout, sum);
    assign sum = a ^ b ^ cin;
    assign cout = (a & b) | (b & cin) | (a & cin);
endmodule

Generate for-loop: 100-digit BCD adder

提供bcd_add模块:

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

实例化100个该模块,实现100位数BCD行波进位加法器

module top_module( 
    input [399:0] a, b,
    input cin,
    output cout,
    output [399:0] sum );
    // 方法一:generate-for
    wire [99:0] cout_vec;
    generate
        genvar i;
        for(i = 0; i < 100; i = i + 1) begin:gen
            bcd_fadd ins(a[i*4+3 -: 4], b[i*4+3 -: 4], (i == 0) ? cin : cout_vec[i-1], cout_vec[i], sum[i*4+3 -: 4]); 
        end
    endgenerate
    assign cout = cout_vec[99];
    /*
	// 方法二:实例化数组
    wire [99:0] cout_vec;
    bcd_fadd ins[99:0](a, b, {cout_vec[98:0], cin}, cout_vec, sum);
    assign cout = cout_vec[99];
    */
endmodule

你可能感兴趣的:(HDLBits,fpga开发)