从零开始设计riscv cpu九之降低LUT使用量语法技巧 一、首先知道LUT是什么LUTLook-Up Table查找表是 FPGA 中最核心的可编程逻辑资源。你可以把它想象成一个真值表输入信号作为地址输出就是预先存储在表中的结果。输入 A输入 B输出AND000010100111二、LUT的使用方式有两种模式本质用途LUT逻辑模式查找表实现组合逻辑与、或、异或、多路选择器等LUTRAM存储模式同一个物理 LUT配置为小型 RAM存储数据作为分布式 RAM 使用不要看LUTRAM带着RAM其实就是LUT是LUT实现的RAM。关键认知LUTRAM 本质上就是 LUT是 LUT 实现的 RAM。1 LUTRAM 1 LUT物理同一资源通过配置位实现不同的用途。然后可以看下面的这个真实的综合出来的资源使用结果一目了然。看第一行top这一行就足够使用logic LUT 3659个 LUTRAM 212个 总共的3871个至此应该对LUT的使用清楚了。三、现在看ram的实现方式除了 Block RAMBRAM还有LUTRAM / 分布式 RAM。通过ram_style属性控制实现方式(* ram_style “block”)(ram_style “distributed” *)值实现方式适用场景blockBlock RAMBRAM大容量存储1KB需要独立时钟端口distributedLUTRAM / 分布式 RAM小容量存储需要异步读或 BRAM 资源紧张auto工具自动选择默认行为由综合工具决定四、现在来看怎么减少LUT使用。五、先看代码timescale1ns/1ps includedefines.v// Tournament direction predictor with bimodal, gshare, and a PC-indexed chooser.module bht #(parameter ENTRY_NUM256,parameter INDEX_W8,parameter GHR_W4)(input wire clk,input wire rst,input wire[AW-1:0]lookup_pc_i,output wire predict_taken_o,output wire[INDEX_W-1:0]lookup_index_o,output wire bimodal_taken_o,output wire gshare_taken_o,input wire update_valid_i,input wire[AW-1:0]update_pc_i,input wire[INDEX_W-1:0]update_index_i,input wire update_taken_i,input wire update_bimodal_taken_i,input wire update_gshare_taken_i);reg[1:0]bimodal_counter_r[0:ENTRY_NUM-1];reg[1:0]gshare_counter_r[0:ENTRY_NUM-1];reg[1:0]chooser_counter_r[0:ENTRY_NUM-1];reg[GHR_W-1:0]ghr_r;wire[INDEX_W-1:0]lookup_pc_index;wire[INDEX_W-1:0]update_pc_index;wire[INDEX_W-1:0]ghr_extended;wire choose_gshare;assign lookup_pc_indexlookup_pc_i[INDEX_W1:2];assign update_pc_indexupdate_pc_i[INDEX_W1:2];assign ghr_extended{{(INDEX_W-GHR_W){1b0}},ghr_r};assign lookup_index_olookup_pc_index^ghr_extended;//assign lookup_index_o lookup_pc_index ^ ghr_r;assign bimodal_taken_obimodal_counter_r[lookup_pc_index][1];assign gshare_taken_ogshare_counter_r[lookup_index_o][1];assign choose_gsharechooser_counter_r[lookup_pc_index][1];assign predict_taken_ochoose_gshare?gshare_taken_o:bimodal_taken_o;integer i;initial beginif(ENTRY_NUM!(1INDEX_W))begin $error(BHT: ENTRY_NUM must equal 2^INDEX_W);$finish;endif((GHR_W2)||(GHR_WINDEX_W))begin $error(BHT: GHR_W must be in the range 2..INDEX_W);$finish;end end always (posedge clk)beginif(rstRstEnable)begin ghr_r{GHR_W{1b0}};for(i0;iENTRY_NUM;ii1)begin bimodal_counter_r[i]2b01;gshare_counter_r[i]2b01;chooser_counter_r[i]2b01;end endelseif(update_valid_i)beginif(update_taken_i)beginif(bimodal_counter_r[update_pc_index]!2b11)bimodal_counter_r[update_pc_index]bimodal_counter_r[update_pc_index]2b01;if(gshare_counter_r[update_index_i]!2b11)gshare_counter_r[update_index_i]gshare_counter_r[update_index_i]2b01;endelsebeginif(bimodal_counter_r[update_pc_index]!2b00)bimodal_counter_r[update_pc_index]bimodal_counter_r[update_pc_index]-2b01;if(gshare_counter_r[update_index_i]!2b00)gshare_counter_r[update_index_i]gshare_counter_r[update_index_i]-2b01;endif(update_bimodal_taken_i!update_gshare_taken_i)beginif(update_gshare_taken_iupdate_taken_i)beginif(chooser_counter_r[update_pc_index]!2b11)chooser_counter_r[update_pc_index]chooser_counter_r[update_pc_index]2b01;endelsebeginif(chooser_counter_r[update_pc_index]!2b00)chooser_counter_r[update_pc_index]chooser_counter_r[update_pc_index]-2b01;end end ghr_r{ghr_r[GHR_W-2:0],update_taken_i};end end endmodule可以看到采用的是同步复位。此时综合的结果是可以看到bht使用了1794个LUT和1544个FF触发器六、为什么消耗了 1794 个 LUT6.1 致命误解for循环不是循环 256 拍always块里的for循环在编译期elaboration就被完全展开语义等价于if (rst) begin bimodal_counter_r[0] lt; 2b01; bimodal_counter_r[1] lt; 2b01; // ... 共 768 条全部在同一拍生效 end也就是说你要求的是rst 有效的那一拍之后1536 个 bit 同时变成 2’b01。复位分支的隐藏代价为什么 1536 bit 表变成了 1794 个 LUT2. 这个语义只有触发器能实现对比一下硬件原语的能力原语清零能力实现代价LUTRAM / BRAM写端口一拍只能写一个地址没有任何全体清零端口要清空 256 项需要256 拍 一个状态机——综合器不会替你发明这个因为它必须保持逐拍等价的语义触发器 (FDRE/FDSE)每个都带 SR 引脚复位信号扇出到 1536 个 FF一拍全部归位。复位本身走专用引脚不花 LUT所以综合器没有选择权只要这个复位分支存在表就必须是 1536 个 FF。3. LUT 是从 FF 的配套电路里长出来的表变成 FF 之后访问它的电路全部失去原语可以吸收只能摊在逻辑 LUT 上粗估老代码的 1794 个 LUT功能估算 LUT读出 mux3 表 × 2bit × 256:1~400–500写译码 每使能256 项 × 3 表~500–600每项保持/更新的 D 端 mux 和饱和比较~几百chooser 判断、共享加减法、XOR~几十LUTRAM 方案同样的功能不同的归属LUTRAM 之后同样是这些功能但功能LUTRAM 中的归属译码器就是 LUT 的6 根地址线读出 muxLUT 内部结构 Slice 里专用的F7/F8 选择器独立资源不计入 LUT 数所以1536 bit 的表 全部访问电路 48 个 LUTRAM 17 个逻辑 LUT一句话总结复位分支的真正代价不是它自己生成的电路而是它剥夺了综合器把表映射成 RAM 的权利。删掉它、用initial赋初值FPGA 比特流配置时免费写入选择权就回来了。七、改为使用LUTRAMINITIAL赋初值timescale1ns/1ps includedefines.v// Tournament direction predictor with bimodal, gshare, and a PC-indexed chooser.module bht #(parameter ENTRY_NUM256,parameter INDEX_W8,parameter GHR_W4)(input wire clk,input wire rst,input wire[AW-1:0]lookup_pc_i,output wire predict_taken_o,output wire[INDEX_W-1:0]lookup_index_o,output wire bimodal_taken_o,output wire gshare_taken_o,input wire update_valid_i,input wire[AW-1:0]update_pc_i,input wire[INDEX_W-1:0]update_index_i,input wire update_taken_i,input wire update_bimodal_taken_i,input wire update_gshare_taken_i);(*ram_styledistributed*)reg[1:0]bimodal_counter_r[0:ENTRY_NUM-1];(*ram_styledistributed*)reg[1:0]gshare_counter_r[0:ENTRY_NUM-1];(*ram_styledistributed*)reg[1:0]chooser_counter_r[0:ENTRY_NUM-1];reg[GHR_W-1:0]ghr_r;wire[INDEX_W-1:0]lookup_pc_index;wire[INDEX_W-1:0]update_pc_index;wire[INDEX_W-1:0]ghr_extended;wire choose_gshare;assign lookup_pc_indexlookup_pc_i[INDEX_W1:2];assign update_pc_indexupdate_pc_i[INDEX_W1:2];assign ghr_extended{{(INDEX_W-GHR_W){1b0}},ghr_r};assign lookup_index_olookup_pc_index^ghr_extended;//assign lookup_index_o lookup_pc_index ^ ghr_r;assign bimodal_taken_obimodal_counter_r[lookup_pc_index][1];assign gshare_taken_ogshare_counter_r[lookup_index_o][1];assign choose_gsharechooser_counter_r[lookup_pc_index][1];assign predict_taken_ochoose_gshare?gshare_taken_o:bimodal_taken_o;integer i;initial beginif(ENTRY_NUM!(1INDEX_W))begin $error(BHT: ENTRY_NUM must equal 2^INDEX_W);$finish;endif((GHR_W2)||(GHR_WINDEX_W))begin $error(BHT: GHR_W must be in the range 2..INDEX_W);$finish;end end initial beginfor(i0;iENTRY_NUM;ii1)begin bimodal_counter_r[i]2b01;gshare_counter_r[i]2b01;chooser_counter_r[i]2b01;end ghr_r{GHR_W{1b0}};end always (posedge clk)beginif(update_valid_i)beginif(update_taken_i)beginif(bimodal_counter_r[update_pc_index]!2b11)bimodal_counter_r[update_pc_index]bimodal_counter_r[update_pc_index]2b01;if(gshare_counter_r[update_index_i]!2b11)gshare_counter_r[update_index_i]gshare_counter_r[update_index_i]2b01;endelsebeginif(bimodal_counter_r[update_pc_index]!2b00)bimodal_counter_r[update_pc_index]bimodal_counter_r[update_pc_index]-2b01;if(gshare_counter_r[update_index_i]!2b00)gshare_counter_r[update_index_i]gshare_counter_r[update_index_i]-2b01;endif(update_bimodal_taken_i!update_gshare_taken_i)beginif(update_gshare_taken_iupdate_taken_i)beginif(chooser_counter_r[update_pc_index]!2b11)chooser_counter_r[update_pc_index]chooser_counter_r[update_pc_index]2b01;endelsebeginif(chooser_counter_r[update_pc_index]!2b00)chooser_counter_r[update_pc_index]chooser_counter_r[update_pc_index]-2b01;end end ghr_r{ghr_r[GHR_W-2:0],update_taken_i};end end endmodule综合后结果可以看到使用量锐减至100以内效果显著。