1. 从“与”开始:Verilog里两种容易被混淆的操作
刚开始学Verilog那会儿,我也被 & 和 && 这两个符号搞得有点晕。它们都叫“与”,长得也像,但在硬件描述语言里,它们干的活、用的地方,差别可大了去了。简单来说,&(按位与)更像一个“微观”的工匠,它会把你给的两个数的每一位都拿出来,一对一地做“与”运算;而 &&(逻辑与)则是个“宏观”的裁判,它只看你给的两个数整体是不是“非零”,然后给出一个“是”或“否”的判决。如果你把它们用错了地方,代码仿真可能看着没问题,但一综合成实际电路,要么面积爆炸,要么功能完全不对,那坑可就踩大了。这篇文章,我就结合自己这些年做FPGA和ASIC设计时踩过的坑和总结的经验,带你彻底搞懂这两种“与”,并且知道在什么场景下该用哪一个。
2. 庖丁解牛:按位与(&)的两种面孔
按位与运算符 &,是Verilog里非常基础也极其重要的位操作符。它的核心思想是“位对位”操作。我习惯把它想象成两排并列的开关,每一对上下对齐的开关同时按下(都为1),输出才亮(1),否则就灭(0)。这个操作符有两种用法,一种是常见的双目运算,另一种是很多人会忽略但很有用的单目规约运算。
2.1 双目按位与:数据的精确掩码
双目按位与,就是 A & B 这种形式。这里有个关键点:参与运算的两个操作数,它们的位宽必须对齐。如果位宽不同,Verilog会按照规则进行位宽扩展(通常是补零),然后再进行按位操作。这个特性让我们可以非常方便地实现“掩码”功能。
举个例子,我在处理传感器数据流时经常用到。假设我有一个8位的数据总线 data_in = 8‘b1011_0110,但我只关心其中高4位的数据,低4位可能是噪声或者不需要的信息。这时候,我就可以定义一个8位的掩码 mask = 8‘b1111_0000,然后进行按位与操作:
wire [7:0] data_in = 8'b10110110;
wire [7:0] mask = 8'b11110000;
wire [7:0] filtered_data = data_in & mask; // 结果是 8'b10110000
你看,filtered_data 的低4位被清晰地清零了,高4位则原封不动地保留下来。这种操作在通信协议解析、特定数据位提取、寄存器位操作等场景中无处不在。它生成的是一个与输入位宽相同的向量,每一位都是独立运算的结果,这完全对应了硬件上并行的与门阵列。
2.2 单目规约与:快速的全位检测
单目按位与,写成 &A,这是一个规约操作符。它做的事是把一个向量的所有位进行“与”操作,最终缩并成一个1位的标量结果。这个功能非常强大,可以高效地检查一个向量的所有位是否同时为1。
我印象很深的一个案例是在设计一个多通道使能信号校验模块时。系统有8个通道,每个通道有一个“就绪”信号(1位),所有通道都就绪时,总使能才能拉高。最笨的办法是用 && 把8个信号连起来,但用单目按位与就优雅多了:
wire [7:0] channel_ready;
wire all_ready = &channel_ready; // 当且仅当 channel_ready == 8‘b1111_1111 时,all_ready为1
如果 channel_ready 是 8‘b1111_0111,那么 &channel_ready 的计算过程就是 1 & 1 & 1 & 1 &a


414

被折叠的 条评论
为什么被折叠?



