https://mp.weixin.qq.com/s/-KUviTzO3Hdir_mI57L24g
从形式和语义两个层面,来扣一下ABS这段代码。
目的在于:在不降低通用性、不增加复杂度的情况下,提升可读性。
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
同时可以省略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的处理,只是一种方式。可以看到这种方式增加复杂度的同时,降低了模块的通用性。
这个策略需要在具体项目中做选择。这里不做过多讨论。