【6.19】Verilog 新手必看:assign 书写位置 代码顺序详解!
一、前言很多刚从 C、C 软件转 Verilog 硬件开发的同学都会踩两个经典大坑assign能不能写在module关键字上方模块内部多条assign交换上下书写顺序生成的硬件会不会改变 本文结合二输入与门电路案例逐行超细注释讲清代码实现功能、区分「模块外写 assign」「模块内调换 assign 顺序」两种场景彻底分清并行硬件语言和串行软件语言的区别。二、标准合规完整代码// // 模块整体功能实现二输入数字逻辑【与门】电路 // 逻辑功能说明 // 输入两个电平信号 a、b只有当 a1 并且 b1 同时成立时输出 y1 // 其余任意组合a0,b0 / a0,b1 / a1,b0输出 y 全部为 0 // 真值表直观展示电路行为 // a | b | y // 0 | 0 | 0 // 0 | 1 | 0 // 1 | 0 | 0 // 1 | 1 | 1 // 模块名称and_gate // 硬性语法规则所有硬件描述代码必须包裹在 module ~ endmodule 内部 // // module硬件模块起始标记等同于一块独立数字芯片的外壳开口 // 括号内是芯片对外引出的金属引脚分为输入引脚input、输出引脚output module and_gate ( // input wire a芯片第1路输入引脚 // input信号流向外部电平输入进芯片内部 // wire信号类型单纯导线只传递高低电平0/1不存储数据 // a引脚自定义名称外部可以输入0低电平、1高电平两种电平信号 input wire a, // input wire b芯片第2路输入引脚第二路外部输入电平信号作用和a完全一致 input wire b, // output wire y芯片输出引脚 // output信号流向芯片内部运算完成后把结果向外输出 // wire输出类型为导线实时输出组合逻辑运算结果无存储功能 // y输出引脚名称专门输出 a、b 做与运算后的最终电平 output wire y ); // 分割线以下区域全部属于芯片外壳内部电路所有assign、wire、逻辑门都必须写在此区间 //------------------------------------------------------------------------- // assign连续赋值语句专门用来描述硬件中永久焊死、实时连通的铜导线连接关系 // 硬件实物对应在芯片内部实例化一个标准2输入与门元器件 // 硬件连接关系两根输入导线a、b分别接入与门的两个输入端口与门输出端口永久连通输出导线y // 硬件运行特性FPGA/芯片只要上电这条连线24小时不间断实时运算不存在代码先后执行顺序 // 运算符号 数字逻辑按位与对应本模块核心功能实现与门逻辑运算 assign y a b; //------------------------------------------------------------------------- // endmodule硬件模块结束标记代表芯片外壳封口模块内部电路区域到此截止 endmodule实物通俗对应讲解上面这段代码编译综合后会生成一块实体数字芯片芯片外壳左侧两根金属针脚a、b用来外接外部高低电平芯片外壳右侧一根金属针脚y用来输出运算结果芯片外壳内部固定焊接一个标准与门元器件a、b 两根铜线接入与门输入与门输出铜线直接连到 y 引脚电路工作逻辑通电后持续实时判断两个输入电平严格遵循与门真值表输出对应电平只要 a 或 b 电平发生变化y 会立刻同步更新不存在等待、分步执行的概念。三、错误示范assign 写在 module 上方// // 错误示范assign写在module模块外壳外部语法非法编译直接报错 // 模块原本功能依旧是二输入与门但书写位置违规导致代码完全无法运行 // 报错核心原因a、b、y三个引脚、导线全部定义在module内部 // 外壳外部没有任何信号定义编译器无法识别a/b/y是什么信号 // 类比理解芯片盒子都没拆开凭空在空气里焊接导线无引脚、无内部空间逻辑无法实现 // // 致命错误assign位于module关键字上方模块外壳外部 assign y a b; // 芯片外壳才开始定义引脚但前面的assign已经提前引用了未定义信号 module and_gate ( input wire a, input wire b, output wire y ); // 模块内部无任何逻辑 endmodule四、重点解惑模块内部调换 assign 顺序硬件完全不变与门功能不受影响核心原理Verilog 是并行硬件描述语言所有assign等价于电路板上同步焊好的铜线不分书写先后 而 C/C 是串行软件语言代码从上到下依次执行调换顺序会直接改变运行结果两者思维不能混用。合法示例 1先定义中间导线再写两条 assign功能依旧是二输入与门module and_gate ( input wire a, input wire b, output wire y ); // wire temp定义芯片内部一根中间过渡导线用来承接ab与运算结果 wire temp; // 第一条assign把a、b与运算结果连接到中间导线temp assign temp a b; // 第二条assign把中间导线temp连接到输出引脚y // 整体电路功能不变依旧实现二输入与门逻辑 assign y temp; endmodule合法示例 2两条 assign 书写顺序互换生成硬件、与门功能和上面完全一致module and_gate ( input wire a, input wire b, output wire y ); wire temp; // 调换顺序先把temp连到y再把ab连到temp // 硬件电路、与门逻辑、输出真值表没有任何变化 assign y temp; assign temp a b; endmodule通俗解释两条 assign 代表两根独立铜线先焊接哪一根、代码先写哪一行不会改变电路板最终结构芯片上电后两根导线同步工作与门逻辑行为完全不变不存在 “先执行第一行再执行第二行” 的先后流程。五、全文核心规则总结模块功能定位本代码是标准 2 输入与门组合逻辑电路仅当 a、b 同时为高电平时输出高电平语法硬性红线所有assign、wire、时序逻辑代码必须全部包裹在一对 module ~ endmodule 中间不能写在 module 上方、模块外壳外部内部书写自由同一个模块内多条assign上下调换书写顺序不会改变最终硬件电路、不会改变电路功能语言思维区分软件代码看书写先后顺序Verilog assign 描述硬件并行连线禁止用 C 语言串行思维理解硬件逻辑代码规范建议统一排版顺序 —— 定义模块端口 → 定义内部中间 wire 导线 → 书写 assign 连续赋值可读性更强。