Verilog - ABS代码重构

Posted wjcdx

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了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] == 1b1) begin // negative data
          if (din[DATA_WIDTH-2:0] == {(DATA_WIDTH-1){1b0}}) begin // Max
                dout = {1b0,{(DATA_WIDTH-1){1b1}}};
          end
          else begin
               dout  = {1b0,((~din[DATA_WIDTH-2:0])+1b1)};
          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] == 1b1) begin // negative data
            if (din[W-2:0] == { (W-1){1b0} }) begin // Max 
                dout = {1b0,{(W-1){1b1}}};
            end
            else begin
                dout  = {1b0,((~din[W-2:0])+1b1)};
            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){1b0} };
wire [W-2:0] pad1      = { (W-1){1b1} };

always @(*) begin
    if (din_sign == 1b1) begin // negative data
            if (din_data == pad0) begin // Max 
                dout = {1b0, pad1};
            end
            else begin
                dout  = {1b0,((~din_data)+1b1)};
            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){1b1} };

always @(*) begin
    if (din_sign == 1b1) begin // negative data
            if (din_data == 0) begin // Max 
                dout = {1b0, pad1};
            end
            else begin
                dout  = {1b0,((~din_data)+1b1)};
            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){1b1} };

always @(*) begin
    if (din_sign == 1b1) begin // negative data
            if (din_data == 0) begin // Max 
                dout = ~din;
            end
            else begin
                dout  = {1b0,((~din_data)+1b1)};
            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 == 1b1) 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 == 1b1) 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的处理,只是一种方式。可以看到这种方式增加复杂度的同时,降低了模块的通用性。
 
这个策略需要在具体项目中做选择。这里不做过多讨论。

以上是关于Verilog - ABS代码重构的主要内容,如果未能解决你的问题,请参考以下文章

如何重构这个 Java 代码片段

10 个你可能还不知道 VS Code 使用技巧

我应该如何重构复杂的 If else block in view?

我的重构第一步

如何使用 Icarus Verilog 在 Verilog 中转换 VHDL 代码?

求一个用verilog实现二分之一分频(是提高频率,不是降低频率)的代码