跳轉到

Procedures

Always blocks (combinational)

原題:Always blocks (combinational)

講說combinational logic可以有assign和always @(*)兩種寫法。然後有個細節要注意,assign的左值要用wire,always的左值要用reg,雖然這兩者在合成電路後沒差。

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

原題:Always blocks (clocked)

重點是在講combinational logic和sequential logic的差別。如果是clock always的話,最好賦值使用non-blocking。

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

原題:If statement

分別要求要寫三元運算和在combinational block中寫if/else,可能要注意的是cond可以共用。

Verilog
// 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   ); 
    wire cond;
    assign cond = sel_b1 & sel_b2;
    assign out_assign = cond ? b : a;
    always@(*)begin
        if(cond)begin
            out_always = b;
        end
        else begin
            out_always = a;
        end
    end 
endmodule

If statement latches

原題:If statement latches

講說要寫清楚elsedefault,不然Verilog 會合成出latch。

Verilog
// 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 = 1'b0;
    end

endmodule

Case statement

原題:Case statement

說明case 如何使用,然後要記得寫default 防止latch。

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

endmodule

Priority encoder

原題:Priority encoder

需要寫一個 priority encoder。這裡用 if/else 表達優先順序,比直接化成 gate-level 邏輯更容易閱讀。

Verilog
// synthesis verilog_input_version verilog_2001
module top_module (
    input [3:0] in,
    output reg [1:0] pos  );
    always@(*)begin
        if(in[0]) pos = 2'b00;
        else if(in[1]) pos = 2'b01;
        else if(in[2]) pos = 2'b10;
        else if(in[3]) pos = 2'b11;
        else pos= 2'b00;
    end
endmodule

Priority encoder with casez

原題:Priority encoder with casez

和前一題類似,只是嘗試用casez實作encoder。

Verilog
// 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'b000;
            8'bzzzzzz10: pos = 3'b001;
            8'bzzzzz100: pos = 3'b010;
            8'bzzzz1000: pos = 3'b011;
            8'bzzz10000: pos = 3'b100;
            8'bzz100000: pos = 3'b101;
            8'bz1000000: pos = 3'b110;
            8'b10000000: pos = 3'b111;
            default:     pos = 3'b000;
        endcase
    end
endmodule

Avoiding latches

原題:Avoiding latches

當 output 很多時,可以先給預設值,再覆寫需要變動的訊號。這種寫法能減少重複分支,也能避免不小心推導出 latch。

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