1. 程式人生 > >Verilog - ABS程式碼重構

Verilog - ABS程式碼重構

 https://mp.weixin.qq.com/s/-KUviTzO3Hdir_mI57L24g

 

從形式和語義兩個層面,來扣一下ABS這段程式碼。 目的在於:在不降低通用性、不增加複雜度的情況下,提升可讀性。  
module ABS
#(
    parameter    DATA_WIDTH = 8
)
(
    input        [DATA_WIDTH-1:0]            din,
    output reg   [DATA_WIDTH-1:0]            dout
);

always
@(*) begin if (din[DATA_WIDTH-1] == 1'b1) begin // negative data if (din[DATA_WIDTH-2:0] == {(DATA_WIDTH-1){1'b0}}) begin // Max dout = {1'b0,{(DATA_WIDTH-1){1'b1}}}; end else begin dout = {1'b0,((~din[DATA_WIDTH-2:0])+1'b1)}; end end
else begin dout = din; end end endmodule

 

    1. 從形式上,DATA_WIDTH這個命名太長,作為module parameter提供詳細語義無可厚非。但在module實現中使用這麼長的名字,並且多次出現,則程式碼稍顯冗長。可以使用localparam來縮短長度。  
module ABS
#( 
    parameter    DATA_WIDTH = 8
)
(
    input        [DATA_WIDTH-1
:0] din, output reg [DATA_WIDTH-1:0] dout ); localparam W = DATA_WIDTH; localparam MSB = DATA_WIDTH - 1; always @(*) begin if (din[MSB] == 1'b1) begin // negative data if (din[W-2:0] == { (W-1){1'b0} }) begin // Max dout = {1'b0,{(W-1){1'b1}}}; end else begin dout = {1'b0,((~din[W-2:0])+1'b1)}; end end else begin dout = din; end end endmodule

 

  2. 形式上,實現中2次用到了W-1做bit-replicate與din對比,2次用到了W-2對din做part-select,1次使用W-1對din做bit-select(已經替換為MSB)。能否對這些重複出現的程式碼,增加一個別名?  
module ABS
#( 
    parameter    DATA_WIDTH = 8
)
(
    input        [DATA_WIDTH-1:0]            din,
    output reg   [DATA_WIDTH-1:0]            dout
);

localparam W   = DATA_WIDTH; 
localparam MSB = DATA_WIDTH - 1;

wire         din_sign  = din[MSB];
wire [W-2:0] din_data  = din[W-2:0];
wire [W-2:0] pad0      = { (W-1){1'b0} };
wire [W-2:0] pad1      = { (W-1){1'b1} };

always @(*) begin
    if (din_sign == 1'b1) begin // negative data
            if (din_data == pad0) begin // Max 
                dout = {1'b0, pad1};
            end
            else begin
                dout  = {1'b0,((~din_data)+1'b1)};
            end
    end
    else begin
            dout = din;
    end
end

endmodule

 

  3. 從語義上,把din_data與pad0比較,等價於直接與0比較,則可以簡化:  
module ABS
#( 
    parameter    DATA_WIDTH = 8
)
(
    input        [DATA_WIDTH-1:0]            din,
    output reg   [DATA_WIDTH-1:0]            dout
);

localparam W   = DATA_WIDTH; 
localparam MSB = DATA_WIDTH - 1;

wire         din_sign  = din[MSB];
wire [W-2:0] din_data  = din[W-2:0];
wire [W-2:0] pad1      = { (W-1){1'b1} };

always @(*) begin
    if (din_sign == 1'b1) begin // negative data
            if (din_data == 0) begin // Max 
                dout = {1'b0, pad1};
            end
            else begin
                dout  = {1'b0,((~din_data)+1'b1)};
            end
    end
    else begin
            dout = din;
    end
end

endmodule

 

    4. 語義上,如果-128的絕對值取127,則直接對din取反即可。  
module ABS
#( 
    parameter    DATA_WIDTH = 8
)
(
    input        [DATA_WIDTH-1:0]            din,
    output reg   [DATA_WIDTH-1:0]            dout
);

localparam W   = DATA_WIDTH; 
localparam MSB = DATA_WIDTH - 1;

wire         din_sign  = din[MSB];
wire [W-2:0] din_data  = din[W-2:0];
wire [W-2:0] pad1      = { (W-1){1'b1} };

always @(*) begin
    if (din_sign == 1'b1) begin // negative data
            if (din_data == 0) begin // Max 
                dout = ~din;
            end
            else begin
                dout  = {1'b0,((~din_data)+1'b1)};
            end
    end
    else begin
            dout = din;
    end
end

endmodule

 

    5. 語義上,對非-128的負數取反,直接把din全部參與運算即可,無需使用concat操作。同時可以省略pad1。  
module ABS
#( 
    parameter    DATA_WIDTH = 8
)
(
    input        [DATA_WIDTH-1:0]            din,
    output reg   [DATA_WIDTH-1:0]            dout
);

localparam W   = DATA_WIDTH; 
localparam MSB = DATA_WIDTH - 1;

wire         din_sign  = din[MSB];
wire [W-2:0] din_data  = din[W-2:0];

always @(*) begin
    if (din_sign == 1'b1) begin // negative data
            if (din_data == 0) begin // Max 
                dout = ~din;
            end
            else begin
                dout  = ~din + 1;
            end
    end
    else begin
            dout = din;
    end
end

endmodule

 

    6. 形式上,module的實現中已經沒有對parameter的使用。localparam MSB只被使用了一次。可以取消,直接使用W即可。甚至W也可以去掉,但保留也沒有大礙,畢竟多次使用。  
module ABS
#( 
    parameter    DATA_WIDTH = 8
)
(
    input        [DATA_WIDTH-1:0]            din,
    output reg   [DATA_WIDTH-1:0]            dout
);

localparam W   = DATA_WIDTH; 

wire         din_sign  = din[W-1];
wire [W-2:0] din_data  = din[W-2:0];

always @(*) begin
    if (din_sign == 1'b1) begin // negative data
            if (din_data == 0) begin // Max 
                dout = ~din;
            end
            else begin
                dout  = ~din + 1;
            end
    end
    else begin
            dout = din;
    end
end

endmodule

 

    7. ABS模組實現上,這裡對-128的處理,只是一種方式。可以看到這種方式增加複雜度的同時,降低了模組的通用性。   這個策略需要在具體專案中做選擇。這裡不做過多討論。