Always blocks(combinational)

分别用 assign 语句和 always @(*) 块语句实现与门操作。

// 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 @(*) out_alwaysblock = a & b;

endmodule

Always blocks(clocked)

使用 assign 语句、组合始终块和时钟始终块以三种方式构建异或门。请注意,时钟始终模块产生的电路与其他两个不同:有一个触发器,因此输出延迟。

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

If statement

构建一个在 a 和 b 之间进行选择的 2 对 1 复用器。如果 sel\_b1 和 sel\_b2 为真,则选择 b。否则,请选择 a。执行相同的操作两次,一次使用 assign 语句,一次使用过程 if 语句。

// 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@(*)
        if (sel_b1 && sel_b2)
            out_always <= b;
        else
            out_always <= a;
  
endmodule

If statement latches

学习如何避免产生 latch。

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

如果有大量案例,则案例陈述比 if 语句更方便。因此,在本练习中,创建一个 6 对 1 多路复用器。当 sel 介于 0 和 5 之间时,选择相应的数据输入。否则,输出 0。数据输入和输出均为 4 位宽。

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

endmodule

Priority encoder

构建 4 位优先级编码器。对于此问题,如果输入位都不高(即输入为零),则输出为零。请注意,一个 4 位数字有 16 种可能的组合。

// synthesis verilog_input_version verilog_2001

module top_module (
    input [3:0] in,
    output reg [1:0] pos  );

    always @ (*)begin
        casex (in)
            4'bxxx1: pos = 2'd0;
            4'bxx10: pos = 2'd1;
            4'bx100: pos = 2'd2;
            4'b1000: pos = 2'd3;
            default: pos = 2'd0;
        endcase
    end

endmodule

Priority encoder with casez

case 语句就像是按顺序检查每个情况,这是一个很大的组合逻辑函数。请注意,某些输入(例如,4'b1111)将如何匹配多个事例项。选择第一个匹配项(因此 4'b1111 匹配第一个项目,out = 0,但后面的任何一个都不匹配)。还有一个类似的案例,它将x和z视为不在乎。我看不出在casez上使用它有多大意义。数字 ? 是 z 的同义词。所以 2'bz0 与 2'b?0 相同。

// synthesis verilog_input_version verilog_2001
module top_module (
    input [7:0] in,
    output reg [2:0] pos  );

    always @(*)begin
        casez(in)
            8'b???????1: pos = 3'd0;
            8'b??????10: pos = 3'd1;
            8'b?????100: pos = 3'd2;
            8'b????1000: pos = 3'd3;
            8'b???10000: pos = 3'd4;
            8'b??100000: pos = 3'd5;
            8'b?1000000: pos = 3'd6;
            8'b10000000: pos = 3'd7;
            default: pos = 3'd0;
        endcase
    end
endmodule

Avoiding latches

假设您正在构建一个电路来处理来自游戏的 PS/2 键盘的扫描码。鉴于收到的扫描码的最后两个字节,您需要指示是否已按下键盘上的箭头键之一。这涉及一个相当简单的映射,它可以实现为具有四个案例的案例语句(或 if-elseif)。

扫描码 [15:0]箭头
16'HE06Bleft arrow
16'he072down arrow
16'he074right arrow
16'he075up arrow
Anything elsenone
// 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;right = 1'b0;down = 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
endmodule

最后修改:2023 年 10 月 18 日
如果觉得我的文章对你有用,请随意赞赏