ARTICLE DETAIL

建站实战干货

来自一线的建站与推广经验沉淀,每一条都经过真实交付验证。

2.5 HDLBits —— verilog 语言之更多Verilog特性

2026/8/12 17:42:56 拓冰建站 浏览量
2.5 HDLBits —— verilog 语言之更多Verilog特性 三元运算符语法条件表达式) ? 条件成立执行的表达式1 : 条件不成立时执行的表达式2它可以在一行代码里根据条件二选一本质就是二选一多路选择器 mux不用在组合逻辑 always 块里写 if-else括号加上提升可读性示例(0?3:5)// 条件为假结果等于 5。.(sel?b:a)// 由 sel 控制的二选一多路器sel1 输出 bsel0 输出 a。always (posedge clk)// T 触发器qtoggle?~q:q;// toggle1 则 q 翻转toggle0 则 q 保持原值。always (*)// 有限状态机状态跳转逻辑case(state)A:nextw?B:A;B:nextw?A:B;endcase assign outena?q:1bz;// 三态缓冲器ena 有效输出 q否则输出高阻 z。((sel[1:0]2h0)?a:// 嵌套三元运算符实现三选一多路器(sel[1:0]2h1)?b:c)练习给定 4 个无符号数找出其中最小值。无符号数可直接用比较运算符 a b 对比。 要求使用三元条件运算符先搭建二输入取最小值电路再通过多层嵌套 / 中间连线组合实现四输入最小值电路建议用 wire 线网存储中间比较结果。参考答案// synthesis verilog_input_version verilog_2001// 功能四路8位无符号数两两分组比较、逐级筛选计算输出四个输入里的最小值// 电路架构两级流水线式二元比较器先分组求局部最小、再跨组求全局最小moduletop_module(input wire[7:0]a,b,c,d,// 四路独立8位无符号整型输入数据output wire[7:0]min// 最终输出a/b/c/d四个数中的最小值位宽与输入保持一致);// 定义中间网线变量存储第一轮分组比较得到的局部最小值wire[7:0]w1;// 保存a、b二者的较小值wire[7:0]w2;// 保存c、d二者的较小值// 第一级比较分组两两对比assign w1(ab)?a:b;// 三元运算符实现2选1a小于b选a否则选bassign w2(cd)?c:d;// 同理计算c、d分组的最小值// 第二级比较两个分组最小值再次对比得到全局最小值assign min(w1w2)?w1:w2;endmodule输出结果归约缩位运算符6 种基础归约运算符x 归约与所有比特全部为 1 才输出 1|x 归约或任意一个比特为 1 就输出 1^x 归约异或1 的个数为奇数输出 1奇偶校验1 的个数为偶数输出 0~x 归约与非只要有一个 0 就输出 1~|x 归约或非全部比特为 0 才输出 1~^x 归约同或1 的个数为偶数输出 1你已经熟悉两个变量之间的位运算例如 a b、a ^ b。 有时候你需要对一个向量的所有比特做串联运算比如 a[0] a[1] a[2] a[3]…如果向量位宽很长这样写会非常繁琐。归约缩位运算符 可以对一个向量内部所有比特连续做与、或、异或运算最终只输出 1bita[3:0]// 归约与a[3] a[2] a[1] a[0]// 等价判断(a[3:0] 4hf)|b[3:0]// 归约或b[3] | b[2] | b[1] | b[0]// 等价判断(b[3:0] ! 4h0)^c[2:0]// 归约异或c[2] ^ c[1] ^ c[0]归约运算符是单目运算符只有一个操作数类似取反 !、~。 也可以对归约结果取反实现归约与非、归约或非、归约同或示例(~ d[7:0])。有了归约运算符不管是 4 输入门、100 输入门都能一行写完。练习奇偶校验常用于信道传输检错。设计电路对 8 位字节生成偶校验位作为第 9 位。偶校验规则校验位等于 8 个数据位全部异或的结果。参考答案// synthesis verilog_input_version verilog_2001// 功能对8位输入做按位归约异或生成偶校验位// 校验规则输出parity1代表输入有奇数个1parity0代表输入有偶数个1适配偶校验场景moduletop_module(input wire[7:0]in,// 8位并行输入数据总线output wire parity// 1位偶校验结果输出);// Verilog归约异或运算符 ^单目运算符// 运算逻辑依次完成 in[0]^in[1]^in[2]^...^in[7]把多bit输入压缩成1bit校验结果assign parity^in;endmodule输出结果偶校验8bit 中 1 的总数为奇数 → parity11 总数偶数 → parity0归约运算位宽扩展型逻辑门使用归约运算符一键实现百输入与 / 或 / 异或门不用手动拼接 100 个信号。in归约与全部 bit 为 1 才输出 1|in归约或任意 bit 为 1 输出 1^in归约异或1 的个数为奇数输出 1奇偶校验1 的个数为偶数输出 0参考答案// synthesis verilog_input_version verilog_2001// 功能对100位宽输入向量执行三种单目归约运算分别输出全员与、全员或、全员异或结果moduletop_module(input wire[99:0]in,// 100位并行输入向量下标范围最高位in[99]~最低位in[0]output wire out_and,// 归约与运算输出所有位全为1时输出1否则输出0output wire out_or,// 归约或运算输出任意一位为1时输出1全0才输出0output wire out_xor// 归约异或运算输出向量内1的个数为奇数输出1偶数输出0);// 单目归约与 依次完成 in[99]in[98]...in[0]多比特压缩为1比特结果assign out_andin;// 单目归约或 |依次完成 in[99]|in[98]|...|in[0]assign out_or|in;// 单目归约异或 ^依次完成 in[99]^in[98]^...^in[0]常用于奇偶校验生成assign out_xor^in;endmodule输出结果过程 for循环语句integer i;// 循环变量只能integerfor(初始赋值;判断条件;自增/自减)begin 多条语句;end示例moduletest;reg[7:0]a;always (*)begin integer i;a8d0;// 先全部清零for(i0;i8;ii1)begin a[i]1b1;end end endmodulegenerate for 循环genvar 循环变量名;// 必须genvar不能integergeneratefor(初始化;条件;更新)begin:循环块标签// 标签不可省略assign/模块例化/寄存器定义 end endgenerate示例//多模块例化经典示例生成 8 个相同子模块genvar k;generatefor(k0;k8;kk1)begin:mod_loop sub_moduleu_sub(.din(din[k]),.dout(dout[k]));end endgenerate练习给定 100 位输入向量in[99:0]反转它的比特顺序原最高位in[99]映射到out[0]原最低位in[0]映射到out[99]。允许用 reg 输出、写 always 块 → 可以用 integer for想要纯 wire、只用 assign、不使用 reg → 必须用 generate for参考答案一// synthesis verilog_input_version verilog_2001// 题目需求100位输入向量in[99:0]整体反转比特顺序输出// 映射规则out[i] in[99-i]原高位换到低位、原低位换到高位moduletop_module(input wire[99:0]in,// 100位原始输入位序in[99]最高位、in[0]最低位output reg[99:0]out// 反转后输出always块内赋值需声明reg类型);integer i;// 循环计数变量顶层声明兼容Quartus旧版语法禁止放入always块内引发报错// 纯组合逻辑敏感列表输入in任意位变化立刻重新计算反转结果无时钟延迟always (*)begin// 循环遍历0~99全部下标逐位完成位序反转映射for(i0;i100;ii1)begin out[i]in[99-i];// 核心反转逻辑输出第i位 输入倒数第i位// 例i0 → out[0]in[99]i99 → out[99]in[0]end end endmodule参考答案二// synthesis verilog_input_version verilog_2001// 题目需求100位输入向量in[99:0]整体反转比特顺序输出// 适用场景纯连线映射无需时序逻辑综合结构更轻量化moduletop_module(input wire[99:0]in,// 100位原始输入位序in[99]最高位、in[0]最低位output wire[99:0]out// 反转后输出连续赋值默认wire类型);genvar i;// generate专用循环变量类型genvar仅用于编译期展开硬件结构// generate编译期生成循环预先展开100条独立assign连线运行时无循环开销generatefor(i0;i100;ii1)begin:rev_bit_loop// rev_bit_loop为循环实例命名语法强制要求assign out[i]in[99-i];// 逐位绑定反转映射关系end endgenerate endmodule输出结果位统计电路“位统计电路popcount” 用于统计输入向量中逻辑 1 的总比特数量。请为一个 255 位输入向量搭建该计数电路。参考答案// synthesis verilog_input_version verilog_2001// 模块功能统计255位输入向量内逻辑高电平1的总数量// 设计类型纯组合逻辑输入变化实时重算、无时钟节拍与寄存器延迟// 输出位宽依据最多255个18位无符号数取值0~255可完整容纳计数结果moduletop_module(input wire[254:0]in,// 255位并行输入总线下标规则in[254]为最高位、in[0]为最低位output reg[7:0]out// 8位计数结果输出在always过程块内赋值因此声明为reg类型);// 组合逻辑敏感列表(*)自动监听所有内部依赖信号即输入in任意比特变化立刻触发整块逻辑重执行always (*)begin integer i;// 循环遍历下标变量Verilog2001标准支持过程块内声明老版本Quartus建议移至模块顶层规避语法报错out8d0;// 前置计数器清零给输出设置全局默认值覆盖全部场景杜绝隐式锁存器推断// for循环逐位扫描遍历下标0~254共255个比特位for(i0;i255;ii1)begin// 累加计数原理单比特in[i]参与算术运算时自动高位补0扩展至8位// in[i]1时计数1、in[i]0时数值不变最终累加和即为向量中1的总个数outoutin[i];end end endmodule输出结果100 位行波进位加法器实例化 100 个全加器搭建 100 位行波进位加法器。你需要先写出全加器模块可以复用之前的全加器代码。 加法器功能输入两个 100 位操作数 1 位进位输入输出 100 位和 总进位输出。 题目要求额外输出每一级全加器的进位信号cout[99] 是最后一级的进位也就是常规加法器的最终进位输出。参考答案// synthesis verilog_input_version verilog_2001//// 子模块名称add_full// 模块类型组合逻辑1位全加器RCA基础运算单元// 功能说明对单比特两个加数低位进位做加法输出本位和、向高位进位// 数学公式// 本位和 sum a ^ b ^ cin// 进位输出 co (ab)|(acin)|(bcin)// 适用场景可堆叠搭建任意位宽行波进位加法器//moduleadd_full(input a,// 本位第一路单比特加数input b,// 本位第二路单比特加数input cin,// 低位相邻位传递过来的进位输入output sum,// 当前位相加产生的本位结果output co// 当前位向更高相邻位输出的进位信号);// 本位和逻辑三路输入连续异或是全加器标准求和表达式assign suma^b^cin;// 进位逻辑任意两个输入同时为1即向上进位覆盖全部进位触发场景assign co(ab)|(acin)|(bcin);endmodule//// 顶层模块名称top_module// 模块类型100位行波进位加法器Ripple Carry Adder, RCA// 架构特点进位从最低位开始逐位串行向后传递结构简单、资源占用少高位时序延迟随位宽累加// 端口定义// a[99:0]、b[99:0]两路100位待相加操作数下标99最高位、0最低位// cin全局最低位第0位外部初始进位输入支持带进位加法运算// cout[99:0]分级进位总线cout[i]为第i位全加器产生的向上进位// sum[99:0]100位逐位相加最终本位结果// 设计思路第0位单独例化接外部cin1~99位通过generate批量例化、链式承接前级进位//moduletop_module(input[99:0]a,b,input cin,output[99:0]cout,output[99:0]sum);// 单独实例化最低位(第0级)全加器// 特殊点本级没有更低位进位进位源直接绑定顶层全局cinadd_fulladd_add1(.a(a[0]),.b(b[0]),.cin(cin),.co(cout[0]),.sum(sum[0]));// genvargenerate编译期循环专属变量编译时直接展开所有硬件实例不属于运行时仿真变量genvar i;generate// 批量生成第1~99位共99级高位全加器// i起始值1跳过已手动例化的第0位i100覆盖下标上限99和端口位宽严格匹配for(i1;i100;ii1)begin:add_f add_fulladd_add2(.a(a[i]),.b(b[i]),.cin(cout[i-1]),// 行波进位核心链路前一级i-1的进位输出 本级进位输入.co(cout[i]),.sum(sum[i]));end endgenerate endmodule输出结果BCD 加法器现有一位 BCD 加法器子模块 bcd_fadd功能为输入两个 1 位 BCD 数字与进位输入输出本位和以及进位输出。 子模块端口定义modulebcd_fadd(input[3:0]a,input[3:0]b,input cin,output cout,output[3:0]sum);请实例化 100 个该bcd_fadd模块搭建100 位十进制行波进位 BCD 加法器。 该加法器需求 输入两组 100 位 BCD 数字整体打包为 400 位向量1 位 BCD 占 4 比特外加 1 个全局进位输入 输出 100 位 BCD 结果和最终进位输出。参考答案// synthesis verilog_input_version verilog_2001//// 顶层模块100位十进制BCD行波进位加法器// 数据格式1位十进制BCD占用4bit100位十进制共400bit// 架构串行链式进位低位BCD单元进位逐级传给高位BCD单元// 端口说明// a[399:0]/b[399:0]两路待相加BCD数据每4bit对应1个十进制数位// cin最低十进制位第0组4bit外部初始进位输入// cout最高十进制位运算结束后最终进位输出全局进位// sum[399:0]逐位BCD相加得到的400bit结果// 内部信号w1[99:0]保存100组BCD加法单元逐级传递的中间进位//moduletop_module(input[399:0]a,b,input cin,output cout,output[399:0]sum);// 中间进位总线共100个BCD运算单元每个单元输出1bit进位w1[i]为第i组BCD的进位输出wire[99:0]w1;// 单独实例化第0组最低位十进制BCD加法单元// 本级无前级内部进位进位直接接入顶层全局cinbcd_faddbcd_fadd1(.a(a[3:0]),// 截取最低4bit第0位BCD加数.b(b[3:0]),// 截取最低4bit第0位BCD加数.cin(cin),// 外部初始进位输入.cout(w1[0]),// 本级进位存入第0位中间进位线网.sum(sum[3:0])// 输出第0位BCD相加结果);// genvargenerate编译期循环专用变量编译阶段展开全部硬件实例genvar i;generate// 批量实例化第1~99组高位BCD加法单元共99组for(i1;i100;ii1)begin:bcd_add_full bcd_faddbcd_fadd2(// 位宽切片第i个十进制位对应 a/b/sum 的 [4i3 : 4i] 4bit区间.a(a[i*43:i*4]),.b(b[i*43:i*4]),.cin(w1[i-1]),// 行波进位核心前一组BCD的进位输出作为本组进位输入.cout(w1[i]),// 本组运算产生的进位存入中间总线传给下一组高位.sum(sum[i*43:i*4]));end endgenerate// 最高一组(第99位)BCD产生的进位作为整个加法器最终全局进位输出assign coutw1[99];endmodule输出结果