)
避开初学Verilog的坑我在HDLBits组合逻辑部分犯过的3个典型错误附正确解法第一次接触Verilog时我以为它和C语言差不多——直到在HDLBits上被组合逻辑题目反复教育。那些看似简单的与或非门在硬件描述语言里藏着无数新手陷阱。编译器不会报错仿真结果却莫名其妙。今天分享三个让我抓狂的典型错误希望能帮你少走弯路。1. 向量位宽匹配当11不等于2我最先栽在了一个看似简单的加法器题目上。题目要求实现两个4位输入相加我自信满满写下module top_module( input [3:0] a, b, output [3:0] sum, output carry ); assign {carry, sum} a b; endmodule仿真结果却显示当a154b1111和b14b0001相加时sum竟然输出0原来问题出在隐式位宽扩展上Verilog默认将ab的结果计算为4位当和超过15时高位直接被截断正确的做法是显式扩展操作数位宽assign {carry, sum} {1b0, a} {1b0, b};关键教训任何算术运算前先确认操作数的位宽是否足够推荐使用$bits()函数检查变量位宽重要计算建议采用SystemVerilog的logic signed [N:0]明确符号和位宽2. 运算符优先级和|的迷惑行为在实现一个多条件组合逻辑时我写了这样的判断if (A B 1b1 || C) // do something仿真时发现逻辑完全错乱。原来Verilog的运算符优先级与C语言不同运算符优先级备注, !最低关系运算,, ^中等,正确的写法应该是if ((A B) 1b1 || C)提示当不确定优先级时多用括号明确意图这不会影响综合结果。3. always块与assign的混用陷阱最隐蔽的错误发生在尝试用always块描述组合逻辑时。我写了always (*) begin out in1 in2; end然后在另一个模块里这样调用wire out; my_module inst(out, a, b); assign out out | c; // 这里出问题了问题本质always块内对out的赋值使其成为wire类型外部又用assign对同一net重复驱动正确的做法应该是// 方案1全部用assign assign out (a b) | c; // 方案2使用中间变量 wire temp; my_module inst(temp, a, b); assign out temp | c;4. 测试平台验证技巧发现代码有问题但不确定原因时可以构造最小测试案例initial begin $monitor(time%0t a%b b%b sum%b carry%b, $time, a, b, sum, carry); a 4b1111; b 4b0001; #10; a 4b0111; b 4b0111; #10; $finish; end调试checklist[ ] 所有输入组合是否覆盖边界条件[ ] 输出位宽是否足够[ ] 是否有未初始化的变量[ ] 是否存在多个驱动源记得在HDLBits上提交前先用EDA Playground本地验证。有次我卡了2小时的题目原来只是把3b101错写成3d101——这种低级错误本可以避免。