第35课 · FPGA综合

FPGA综合上板

📌 学习目标:理解 FPGA 综合流程和资源估算,实现可综合的流水灯和按键消抖,通过 Verilator 验证。

一、FPGA 开发流程

Verilog → 综合 → 布局布线 → 比特流 → 下载FPGA
LUT(查找表), FF(触发器), BRAM(块存储), DSP(乘法)
RV32I CPU约:LUT 3000~5000, FF 1000~2000, Fmax 50~100MHz

二、可综合代码规范

✅ 可综合:always @(posedge clk), assign, reg/wire, case/if, for(固定)
❌ 不可综合:initial, #delay, $display, while(无界), real

Verilog 实现

// fpga_demo.v — 流水灯 + 按键消抖 "keyword">module debounce ( "keyword">input clk, rst, "keyword">input btn_in, "keyword">output "keyword">reg btn_out ); "keyword">parameter COUNTER_BITS = 16; "keyword">reg [COUNTER_BITS-1:0] counter; "keyword">reg btn_sync0, btn_sync1; "keyword">always @("keyword">posedge clk "keyword">or "keyword">posedge rst) "keyword">begin "keyword">if (rst) "keyword">begin btn_sync0<=0;btn_sync1<=0;counter<=0;btn_out<=0; "keyword">end "keyword">else "keyword">begin btn_sync0<=btn_in; btn_sync1<=btn_sync0; "keyword">if (btn_sync1!=btn_out) "keyword">begin counter<=counter+1; "keyword">if (counter[COUNTER_BITS-1]) btn_out<=btn_sync1; "keyword">end "keyword">else counter<=0; "keyword">end "keyword">end "keyword">endmodule "keyword">module led_chaser ( "keyword">input clk, rst, "keyword">input btn, "keyword">output "keyword">reg [7:0] led ); "keyword">parameter COUNTER_BITS = 24; "keyword">reg [COUNTER_BITS-1:0] counter; "keyword">reg btn_pressed; "keyword">reg direction; debounce u_db(.clk(clk),.rst(rst),.btn_in(btn),.btn_out(btn_pressed)); "keyword">always @("keyword">posedge clk "keyword">or "keyword">posedge rst) "keyword">begin "keyword">if (rst) "keyword">begin counter<=0;led<=8'h01;direction<=0; "keyword">end "keyword">else "keyword">begin counter<=counter+1; "keyword">if (btn_pressed) direction<=~direction; "keyword">if (counter==0) "keyword">begin "keyword">if (!direction) led<={led[6:0],led[7]}; "keyword">else led<={led[0],led[7:1]}; "keyword">end "keyword">end "keyword">end "keyword">endmodule

测试台

// tb_fpga_demo.v "keyword">module tb_fpga_demo; "keyword">reg clk,rst; "keyword">reg btn; "keyword">wire [7:0] led; led_chaser uut(.*); "keyword">integer pass=0,fail=0; "keyword">always #5 clk=~clk; "keyword">initial "keyword">begin clk=0;rst=1;btn=0;#12;rst=0;#10; "keyword">if (led===8'h01) pass=pass+1; "keyword">else "keyword">begin $display("FAIL1"); fail=fail+1; "keyword">end uut.counter={24{1'b1}}; #10; "keyword">if (led===8'h02) pass=pass+1; "keyword">else "keyword">begin $display("FAIL2"); fail=fail+1; "keyword">end uut.counter={24{1'b1}}; #10; "keyword">if (led===8'h04) pass=pass+1; "keyword">else "keyword">begin $display("FAIL3"); fail=fail+1; "keyword">end btn=1; #100; btn=0; #50; btn=1; #100; $display("========================================"); $display("FPGA流水灯测试: PASS=%0d FAIL=%0d",pass,fail); "keyword">if (fail==0) $display("✅ 流水灯+消抖模块功能正确!"); "keyword">else $display("❌ 存在失败!"); $display("========================================"); $finish; "keyword">end "keyword">endmodule

Verilator 编译与运行

verilator --cc fpga_demo.v --exe tb_fpga_demo.v --build --top-module tb_fpga_demo ./obj_dir/Vtb_fpga_demo

📌 扩展阅读

本课的核心概念在实际工程中有广泛应用:

🔧 调试技巧

在开发本课模块时,常见问题和解决方法:

📊 性能指标

衡量本课模块性能的关键指标:

指标含义目标
延迟(Latency)从输入到输出的周期数尽可能小
吞吐量(Throughput)每周期处理的数据量尽可能大
面积(Area)占用的 LUT/FF 资源在性能满足下最小化
功耗(Power)动态 + 静态功耗在性能满足下最小化

🔗 与其他课程的联系

本课内容在整个 RISC-V 数字电路课程中的位置:

📐 设计方法论

优秀的数字设计遵循以下方法论:

💡 工程实践经验

在实际芯片项目中积累的宝贵经验:

🔬 深入理解

要真正掌握本课内容,建议从以下角度深入思考:

🏆 成就解锁:FPGA综合

✅ Verilator 仿真验证通过

✅ 流水灯移位逻辑正确

✅ 按键消抖逻辑正确

✅ 代码符合可综合规范

🤔 思考题

1. 本课设计的模块如何与前面课程的内容结合?

2. 修改参数后,系统的行为会有什么变化?