从零开始设计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以内效果显著。

相关新闻

电商搜索的语义理解与重排序:向量检索、交叉编码器与特征融合的推理优化

电商搜索的语义理解与重排序:向量检索、交叉编码器与特征融合的推理优化

电商搜索的语义理解与重排序:向量检索、交叉编码器与特征融合的推理优化 一、电商搜索的三阶段范式与性能瓶颈 电商搜索管道分为三个阶段:召回(Recall)、粗排(Pre-rank)、精排(Re-rank&#x…

2026/7/25 1:37:10 阅读更多 →
21天学pcie--GT/s 和 Gbps 的区别(

21天学pcie--GT/s 和 Gbps 的区别(

目录 七、GT/s 和 Gbps 的区别(90% 的人都混淆过) 1️⃣ 先给一句话定义 2️⃣ 用“高铁”来类比(非常好懂) 3️⃣ Gen1 举例:最经典的误解来源

2026/7/25 1:37:10 阅读更多 →
高并发下的异步缓存设计:基于 Tokio 的多级缓存与一致性哈希分布的协同方案

高并发下的异步缓存设计:基于 Tokio 的多级缓存与一致性哈希分布的协同方案

高并发下的异步缓存设计:基于 Tokio 的多级缓存与一致性哈希分布的协同方案 一、缓存架构的并发困境 典型电商系统在流量高峰期需要同时处理数万 QPS 的请求,缓存层是第一道防线。单级缓存(仅本地内存或仅 Redis)在极端并发下的瓶…

2026/7/25 1:37:10 阅读更多 →

最新新闻

阿里开源前端AI代理Page Agent:零后端依赖,用自然语言控制网页

阿里开源前端AI代理Page Agent:零后端依赖,用自然语言控制网页

这次我们来看一个阿里开源的前端 AI 代理项目 Page Agent。它不是一个需要本地部署、消耗显存的 AI 模型,而是一个纯前端的 JavaScript 库,核心目标是让你能用自然语言直接控制网页界面。简单来说,你可以在自己的网页里嵌入一段脚本,用户就能通过聊天框或语音指令,让 AI 自…

2026/7/25 1:45:12 阅读更多 →
基于LangChain与ReAct机制构建AI智能体:从原理到实战

基于LangChain与ReAct机制构建AI智能体:从原理到实战

这次我们来看一个能让你亲手搭建 AI 智能体的实战项目。市面上各种 AI Agent 平台层出不穷,但如果你想知道它们背后的运作机制,甚至想自己动手造一个,那么 LangChain 框架和 ReAct 机制就是你必须掌握的核心技术。这篇文章不讲空泛的概念,直接带你从零开始,用代码实现一个…

2026/7/25 1:45:12 阅读更多 →
阿里开源Page Agent:一行代码让网页听懂人话,实现自然语言交互

阿里开源Page Agent:一行代码让网页听懂人话,实现自然语言交互

这次我们来看一个近期在 GitHub 上热度很高的项目:由阿里巴巴开源的 Page Agent 。这是一个运行在网页内部的 JavaScript GUI 智能体,核心目标是用自然语言直接控制网页界面。简单来说,它能让你的网页“听懂人话”,用户说“点击登录按钮”或“在搜索框里输入关键词”,它…

2026/7/25 1:45:12 阅读更多 →
操作系统页缓存:被忽视的高性能隐形之王,Redis并非唯一选择

操作系统页缓存:被忽视的高性能隐形之王,Redis并非唯一选择

最近在技术社区里,Redis 几乎成了“高性能”和“缓存”的代名词。一提到缓存,很多开发者的第一反应就是:“上 Redis!” 仿佛没有 Redis,系统就无法应对高并发。 但你是否想过,在你部署 Redis 之前&#xf…

2026/7/25 1:45:12 阅读更多 →
Docker与Kubernetes从零到一实战:容器化与集群编排保姆级教程

Docker与Kubernetes从零到一实战:容器化与集群编排保姆级教程

最近在帮团队做容器化改造时,发现很多刚接触云原生的小伙伴对 Docker 和 Kubernetes 的学习路径感到迷茫。网上的资料要么过于零散,要么版本老旧,照着操作总是遇到各种环境问题。为了让大家能快速上手,我结合最新的技术栈和实战经…

2026/7/25 1:45:12 阅读更多 →
TAS3251音频DSP寄存器配置实战:CRC/XOR校验与时钟树详解

TAS3251音频DSP寄存器配置实战:CRC/XOR校验与时钟树详解

1. 项目概述:从寄存器手册到实战配置如果你正在调试一块基于TAS3251的音频板,发现I2S信号时有时无,或者DSP处理后的声音偶尔出现爆音,那么问题很可能出在两个方面:数据在传输过程中出错了,或者给各个模块的…

2026/7/25 1:44:12 阅读更多 →

日新闻

突破文档下载限制:kill-doc让你看到的都能保存

突破文档下载限制:kill-doc让你看到的都能保存

突破文档下载限制:kill-doc让你看到的都能保存 【免费下载链接】kill-doc 看到经常有小伙伴们需要下载一些免费文档,但是相关网站浏览体验不好各种广告,各种登录验证,需要很多步骤才能下载文档,该脚本就是为了解决您的…

2026/7/25 0:00:35 阅读更多 →
C++ string类模拟实现:从深拷贝到内存管理的完整指南

C++ string类模拟实现:从深拷贝到内存管理的完整指南

1. 项目概述:为什么我们要“手撕”string类?在C的学习道路上,尤其是从C语言过渡到C的“初阶”阶段,string类绝对是一个绕不开的核心。标准库里的std::string用起来太方便了,、find、substr,几个操作符和函数…

2026/7/25 0:00:35 阅读更多 →
三角洲寻宝鼠工具:高效文件搜索与资源管理实战指南

三角洲寻宝鼠工具:高效文件搜索与资源管理实战指南

1. 先搞清楚“三角洲寻宝鼠”到底是什么工具从名称来看,“三角洲寻宝鼠”更像是一个资源查找或文件检索类工具,而不是游戏或娱乐软件。这类工具的核心价值在于帮助用户快速定位特定资源,比如文档、图片、压缩包或特定格式的文件。如果你经常需…

2026/7/25 0:00:35 阅读更多 →

周新闻

Go语言静态资源打包方案对比与实践指南

Go语言静态资源打包方案对比与实践指南

1. 项目背景与核心需求在Go语言开发中,我们经常需要处理静态资源文件的打包问题。无论是Web应用的模板文件、前端资源,还是配置文件、证书等,都需要随程序一起分发。传统做法是将这些文件与编译后的二进制文件放在同一目录下,但这…

2026/7/24 3:59:20 阅读更多 →
Go语言实现高性能LDAP认证服务的架构与实践

Go语言实现高性能LDAP认证服务的架构与实践

1. 项目背景与核心价值LDAP(轻量级目录访问协议)作为企业级身份认证的黄金标准,已经服务了超过80%的财富500强公司。我在金融科技领域实施统一认证体系时,发现传统Java方案存在启动慢、内存占用高等痛点。而Go语言凭借其协程并发模…

2026/7/24 1:23:39 阅读更多 →
【AI面试官实战指南】:用ChatGPT模拟10类高频技术岗面试,3天提升应答精准度92%

【AI面试官实战指南】:用ChatGPT模拟10类高频技术岗面试,3天提升应答精准度92%

更多请点击: https://intelliparadigm.com 第一章:AI面试官实战指南的核心价值与适用场景 AI面试官并非替代人类HR的“黑箱工具”,而是以可解释、可审计、可迭代的方式,赋能招聘全链路的关键基础设施。其核心价值在于将主观经验沉…

2026/7/24 18:52:18 阅读更多 →

月新闻