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

从形式和语义两个层面,来扣一下ABS这段代码。
目的在于:在不降低通用性、不增加复杂度的情况下,提升可读性。
 
module ABS
#(
parameter DATA_WIDTH =
)
(
input [DATA_WIDTH-:] din,
output reg [DATA_WIDTH-:] dout
); always @(*) begin
if (din[DATA_WIDTH-] == 'b1) begin // negative data
if (din[DATA_WIDTH-:] == {(DATA_WIDTH-){'b0}}) begin // Max
dout = {'b0,{(DATA_WIDTH-1){1'b1}}};
end
else begin
dout = {'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 =
)
(
input [DATA_WIDTH-:] din,
output reg [DATA_WIDTH-:] dout
); localparam W = DATA_WIDTH;
localparam MSB = DATA_WIDTH - ; always @(*) begin
if (din[MSB] == 'b1) begin // negative data
if (din[W-:] == { (W-){'b0} }) begin // Max
dout = {'b0,{(W-1){1'b1}}};
end
else begin
dout = {'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 =
)
(
input [DATA_WIDTH-:] din,
output reg [DATA_WIDTH-:] dout
); localparam W = DATA_WIDTH;
localparam MSB = DATA_WIDTH - ; wire din_sign = din[MSB];
wire [W-:] din_data = din[W-:];
wire [W-:] pad0 = { (W-){'b0} };
wire [W-:] pad1 = { (W-){'b1} }; always @(*) begin
if (din_sign == 'b1) begin // negative data
if (din_data == pad0) begin // Max
dout = {'b0, pad1};
end
else begin
dout = {'b0,((~din_data)+1'b1)};
end
end
else begin
dout = din;
end
end endmodule
 
3. 从语义上,把din_data与pad0比较,等价于直接与0比较,则可以简化:

module ABS
#(
parameter DATA_WIDTH =
)
(
input [DATA_WIDTH-:] din,
output reg [DATA_WIDTH-:] dout
); localparam W = DATA_WIDTH;
localparam MSB = DATA_WIDTH - ; wire din_sign = din[MSB];
wire [W-:] din_data = din[W-:];
wire [W-:] pad1 = { (W-){'b1} }; always @(*) begin
if (din_sign == 'b1) begin // negative data
if (din_data == ) begin // Max
dout = {'b0, pad1};
end
else begin
dout = {'b0,((~din_data)+1'b1)};
end
end
else begin
dout = din;
end
end endmodule
 
 
4. 语义上,如果-128的绝对值取127,则直接对din取反即可。

module ABS
#(
parameter DATA_WIDTH =
)
(
input [DATA_WIDTH-:] din,
output reg [DATA_WIDTH-:] dout
); localparam W = DATA_WIDTH;
localparam MSB = DATA_WIDTH - ; wire din_sign = din[MSB];
wire [W-:] din_data = din[W-:];
wire [W-:] pad1 = { (W-){'b1} }; always @(*) begin
if (din_sign == 'b1) begin // negative data
if (din_data == ) begin // Max
dout = ~din;
end
else begin
dout = {'b0,((~din_data)+1'b1)};
end
end
else begin
dout = din;
end
end endmodule
 
 
5. 语义上,对非-128的负数取反,直接把din全部参与运算即可,无需使用concat操作。同时可以省略pad1。

module ABS
#(
parameter DATA_WIDTH =
)
(
input [DATA_WIDTH-:] din,
output reg [DATA_WIDTH-:] dout
); localparam W = DATA_WIDTH;
localparam MSB = DATA_WIDTH - ; wire din_sign = din[MSB];
wire [W-:] din_data = din[W-:]; always @(*) begin
if (din_sign == 'b1) begin // negative data
if (din_data == ) begin // Max
dout = ~din;
end
else begin
dout = ~din + ;
end
end
else begin
dout = din;
end
end endmodule
 
 
6. 形式上,module的实现中已经没有对parameter的使用。localparam MSB只被使用了一次。可以取消,直接使用W即可。甚至W也可以去掉,但保留也没有大碍,毕竟多次使用。

module ABS
#(
parameter DATA_WIDTH =
)
(
input [DATA_WIDTH-:] din,
output reg [DATA_WIDTH-:] dout
); localparam W = DATA_WIDTH; wire din_sign = din[W-];
wire [W-:] din_data = din[W-:]; always @(*) begin
if (din_sign == 'b1) begin // negative data
if (din_data == ) begin // Max
dout = ~din;
end
else begin
dout = ~din + ;
end
end
else begin
dout = din;
end
end endmodule
 
 
7. ABS模块实现上,这里对-128的处理,只是一种方式。可以看到这种方式增加复杂度的同时,降低了模块的通用性。
 
这个策略需要在具体项目中做选择。这里不做过多讨论。

Verilog - ABS代码重构的更多相关文章

  1. Android Studio在代码重构中的妙用

    代码重构几乎是每个程序员在软件开发中必须要不断去做的事情,以此来不断提高代码的质量.Android Stido(以下简称AS)以其强大的功能,成为当下Android开发工程师最受欢迎的开发工具,也是A ...

  2. 让代码重构渐行渐远系列(3)——string.Equals取代直接比较与非比较

    重构背景及原因 最近由于项目组的人员在不断扩充,导致项目中代码风格各异,大有百花齐放甚至怒放之势.考虑到团队的生存与发展,经过众人多次舌战之后,最终决定项目组根据业务分成几个小分队,以加强团队管理与提 ...

  3. C++代码重构——从C global到C++ template

    在学数据结构的时候,我常有这样目标--写出能够最大程度复用的代码(算法正确,封装优秀).我常想--如何能在短时间内达成"算法正确,封装优秀"这样的目标.经过一段时间的摸索,我的结论 ...

  4. ASP.NET SignalR 与 LayIM2.0 配合轻松实现Web聊天室(十二) 代码重构使用反射工厂解耦(一)缓存切换

    前言 上一篇中,我们用了反射工厂来解除BLL和UI层耦合的问题.当然那是最简单的解决方法,再复杂一点的程序可能思路相同,但是在编程细节中需要考虑的就更多了,比如今天我在重构过程中遇到的问题.也是接下来 ...

  5. CSS代码重构与优化之路

    作者:@狼狼的蓝胖子 网址:http://www.cnblogs.com/lrzw32/p/5100745.html 写CSS的同学们往往会体会到,随着项目规模的增加,项目中的CSS代码也会越来越多, ...

  6. NET代码重构

    记一次.NET代码重构   好久没写代码了,终于好不容易接到了开发任务,一看时间还挺充足的,我就慢慢整吧,若是遇上赶进度,基本上直接是功能优先,完全不考虑设计.你可以认为我完全没有追求,当身后有鞭子使 ...

  7. 代码重构 & 常用设计模式

    代码重构 重构目的 相同的代码最好只出现一次 主次方法 主方法 只包含实现完整逻辑的子方法 思维清楚,便于阅读 次方法 实现具体逻辑功能 测试通过后,后续几乎不用维护 重构的步骤 1  新建一个方法 ...

  8. ASP.NET SignalR 与 LayIM2.0 配合轻松实现Web聊天室(十一) 代码重构使用反射工厂解耦

    前言 自从此博客发表以及代码开源以来,得到了许多人的关注.也没许多吧,反正在我意料之外的.包括几位大牛帮我做订阅号推广,真的很感谢他们.另外,还有几个高手给我提了一些架构上的问题.其实本身这个项目是没 ...

  9. CSS代码重构

    CSS代码重构的目的 我们写CSS代码时,不仅仅只是完成页面设计的效果,还应该让CSS代码易于管理,维护.我们对CSS代码重构主要有两个目的:1.提高代码性能2.提高代码的可维护性 提高代码性能 提高 ...

随机推荐

  1. Spring官网阅读(十五)Spring中的格式化(Formatter)

    文章目录 Formatter 接口定义 继承树 注解驱动的格式化 AnnotationFormatterFactory FormatterRegistry 接口定义 UML类图 FormattingC ...

  2. 机器学习的hello world——MNIST

    MNIST:一个由60000行训练数据集和10000行的测试数据集(机器学习模型设计时必须有一个单独的数据集用于评估模型的性能)组成的数据集. 下载mnist的数据集后,将文件放入C:\Users\m ...

  3. springboot启动报错:Handler dispatch failed; nested exception is java.lang.AbstractMethodError

    最近在用springboot构建项目,控制台报错:Handler dispatch failed; nested exception is java.lang.AbstractMethodError, ...

  4. [hdu5392 Infoplane in Tina Town]置换的最小循环长度,最小公倍数取模,输入挂

    题意:给一个置换,求最小循环长度对p取模的结果 思路:一个置换可以写成若干循环的乘积,最小循环长度为每个循环长度的最小公倍数.求最小公倍数对p取模的结果可以对每个数因式分解,将最小公倍数表示成质数幂的 ...

  5. 【系列】Python编程思想(1):Python简介与开发环境搭建

    李宁老师的 开始学习.   本系列文章深入介绍了Python的各种技术,堪称是目前最全的Python教程.主要目的是让读者可以了解Python的各种核心技术,包括各种Python函数库.本教程使用Py ...

  6. 漫谈Huawei LiteOS五大内核模块

    [摘要]Huawei LiteOS是华为面向IoT领域,构建的“统一物联网操作系统和中间件软件平台”,以轻量级(内核小于10k).低功耗(1节5号电池最多可以工作5年),快速启动,互联互通,安全等关键 ...

  7. [Abp vNext 入坑分享] - 6.完整接入swagger

    前言 由于最近一直在修改一下排版,同时找了非技术的朋友帮忙看一下排版的问题,现在已经基本上确定了排版和样式了.更新可以恢复正常了. 作为一个写前端代码基本只写js不写css的开发,搞排版真的头疼..各 ...

  8. docer run 、docker attach 与 docker exec的区别

    进入容器的方式有以下三种: 使用ssh登陆进容器 使用nsenter.nsinit等第三方工具 使用Docker本身提供的工具 最佳方案为使用Docker本身提供的工具 docker run:创建和启 ...

  9. 「雕爷学编程」Arduino动手做(13)——触摸开关模块

    37款传感器和模块的提法,在网络上广泛流传,其实Arduino能够兼容的传感器模块肯定是不止37种的.鉴于本人手头积累了一些传感器与模块,依照实践出真知(动手试试)的理念,以学习和交流为目的,这里准备 ...

  10. java触发器的学习

         public class OpenVirtualService {             public void open(){ //虚机开通                //业务逻辑 ...