新闻详情

新闻详情

首页 / 资讯中心 / 详情

FPGA软核开发避坑指南:MicroBlaze的BIT与ELF整合全解析

发布时间:2026/9/28 2:06:08来源:尧图网络
FPGA软核开发避坑指南:MicroBlaze的BIT与ELF整合全解析
做MicroBlaze开发的同学应该都遇到过这种场景Vivado里综合、实现、生成BIT文件一切正常SDK里C代码编译出ELF也毫无报错但板子就是跑不起来。之前有位做毕业设计的同学把工程发我说上电后LED完全不闪我一看他把BIT烧进FPGA之后就拔了下载线ELF根本没下载也没有做任何固化整合。这类问题我见得太多次了本质上不是代码问题而是没搞明白BIT和ELF的关系以及整合这两个字到底意味着什么。这篇文章我想把MicroBlaze开发中BIT与ELF文件整合这件事彻底讲透。你会看到在线调试时怎么把软硬件一起拉起来也会看到固化模式下如何用一条命令链把ELF直接熔进BIT、再生成QSPI Flash镜像最后是这几年我实际踩过的各种坑和排查思路。适合刚接触MicroBlaze的FPGA工程师也适合被明明都能编译但板子不动折磨到怀疑人生的同学。1. 为什么这件事绕不开BIT和ELF本来就是一体的1.1 一片FPGA里谁是身体谁是灵魂MicroBlaze和常见的ARM核有一个本质区别它不是板上现成的物理芯片而是用FPGA里的LUT、FF、BRAM、DSP这些资源当场拼装出来的一块软核CPU。BIT文件就是你用FPGA资源造出这台CPU以及整套外设系统的施工图纸。没有BITFPGA上电后就是一堆空白逻辑单元MicroBlaze根本不存在。ELF文件则是这台被造出来的CPU上要运行的指令和数据相当于给这台CPU安装的应用程序。这么说吧BIT是身体ELF是灵魂两者本来就应该合在一起工作。但工具链把它们的产生过程拆成了两个世界——Vivado管硬件综合布线SDK管软件编译链接。于是很多新人误以为BIT烧进去 FPGA工作ELF放进工程 程序跑起来实际上两个文件彼此独立只有按正确的方式把它们整合到同一个时空里系统才能真正跑起来。1.2 程序在BRAM里和在DDR里整合方式是两回事MicroBlaze的程序可以放在片内BRAM也可以放在外部DDR整合方式完全不同。当程序放在BRAM时ELF里的代码段和数据段会被解析成BRAM的初始化值直接写进BIT文件。FPGA上电配置完成后MicroBlaze从BRAM 0x0地址开始取指令程序天然就位。当程序放在DDR里时问题就复杂了DDR控制器本身也是FPGA逻辑的一部分在BIT加载之前外部DDR物理上是不可用的。所以程序没法直接从Flash里的BIT进入DDR必须有一个引导层Bootloader先由BRAM里的代码执行完成DDR初始化再把程序从Flash搬到DDR里运行。我见过不少同学在DDR方案上卡死就是因为没有意识到整合这个词在BRAM和DDR场景下根本不是同一个操作。BRAM方案用一条updatemem命令就能完成整合DDR方案则需要设计Bootloader、生成启动镜像复杂度完全不是一个量级。这篇文章先以入门最常用的BRAM方案为主线讲清楚DDR方案的原理放在后面单独说。1.3 整合还分调试态和固化态很多教程会把在SDK里点Run程序跑起来了称为整合完成严格来说这只是调试态的临时整合。调试态整合的本质是BIT通过JTAG下载到FPGAELF通过JTAG下载到内存两个文件都存在于当前这个上电周期的FPGA里。电源一断FPGA配置丢失内存数据也全都没了。这是开发调试阶段的做法不是产品交付形态。固化态整合的本质是把ELF预先处理好嵌入BIT生成MCS/BIN镜像烧写到QSPI Flash里。上电后FPGA从Flash主动加载配置程序在BRAM或引导流程中自动就位整个过程不依赖电脑和下载线。所以后面我会按两条路径分别展开第二章讲调试态怎么快速整合第三章讲固化态怎么用命令链一次做完。千万别跳过任何一章因为很多坑恰恰出在调试态跑得好好的一固化就翻车的切换点上。2. 在线调试的整合做法SDK里把软硬件一起拉起来2.1 导出硬件时没勾bitstream是第一个坑在Vivado中完成综合实现、生成BIT之后下一步是File → Export Hardware。这里有个非常容易忽略的选项Include bitstream。默认情况下Vivado导出硬件时是不带bitstream的导出的硬件平台文件老版本是.hdf新版本是.xsa只包含硬件描述和地址映射。你在SDK里点Program FPGA时会发现没有任何bit文件可选或者SDK里跑的硬件平台和最新综合出来的BIT根本对不上。正确的操作是先确保Implementation已经跑完然后Export Hardware时勾选Include bitstream。这样导出的平台文件里才会包含BIT和MMI文件。很多改了硬件但SDK里没变化的问题追根溯源都是这里。另外要提醒的是导出硬件这个动作必须在每次修改Block Design并重新Generate Bitstream之后重复做。不要指望Vivado会自动把最新的BIT同步到SDK它不会。2.2 标准三步Program FPGA、下载ELF、点击运行打开SDK后先要确认两件事工作空间里有没有硬件平台.hdf/.xsa以及有没有编译好的Application工程。然后按固定顺序操作菜单栏选择Xilinx → Program FPGA。弹出窗口里会自动填入导出时携带的BIT文件路径点击Program。这一步把硬件逻辑下载到FPGAMicroBlaze和外设开始存在于FPGA内但此时CPU还没执行任何程序指令。在Application工程上右键选择Run As → Launch on Hardware (System Debugger)。SDK会通过JTAG把ELF文件下载到内存中。程序放在BRAM就直接写BRAM程序放在DDR则要求BIT里的DDR控制器已经完成初始化。点击Resume按钮让CPU从复位向量开始执行。如果程序逻辑正常串口打印或LED翻转等效果就会出现。这里要特别注意顺序必须先Program FPGA再下载ELF。顺序反了的话CPU还不存在ELF往哪里下载都没有意义。SDK有时候会在Run Configuration里自动勾选Program FPGA但前提是它能在硬件平台文件里找到bit这就是为什么2.1里的Include bitstream那么重要。2.3 调试态整合成功的判断标准在线调试时怎么判断BIT和ELF真的整合对了很多人以为程序能跑就是整合好了其实不够严谨。我的判断标准是三层第一层串口或LED输出符合预期说明程序逻辑基本正确第二层你访问的外设地址和Block Design里的地址一致GPIO翻转正常UART发送正常DDR读写校验通过说明ELF的地址映射和当前BIT是匹配的第三层在SDK里修改一段代码重新编译、重新Run行为随之变化说明硬件平台和软件工程是同步的。如果第一层通过但第二层卡住比如UART乱码、GPIO没反应大概率是硬件发生了修改比如外设基地址变了、时钟频率变了但SDK里的硬件平台还是旧的。这种情况回到Vivado重新综合、导出然后在SDK里选择File → Update Hardware Platform或重新启动SDK指向新工作空间不要硬着头皮往下调。调试态整合是开发效率的保障但它解决不了上电自启动的问题。接下来才是本文的重头戏——固化整合。3. 固化整合的命令链从ELF到能上电自启的MCS3.1 先搞懂MMI文件在中间扮演什么角色在讲命令之前必须先认识MMI文件。MMI全称Microprocessor Memory Map它是Vivado在实现过程中生成的、描述MicroBlaze地址空间与FPGA物理BRAM映射关系的文件。你可以在导出硬件后的目录里找到它通常在实现运行目录下名字类似system_wrapper.mmi。打开看一眼里面是XML格式记录了MicroBlaze的每个内存段如本地BRAM的地址段对应FPGA里哪些BRAM块以及这些BRAM的初始化文件路径。为什么需要MMI因为BIT文件是一大坨加密的位流数据普通人没法直接在里面找0x100这个地址的指令该放在哪一位。MMI相当于分配表告诉updatemem工具ELF里的某个加载段应该写到BIT文件中的哪个BRAM初始位置。没有MMI整合就无从谈起。所以有个铁律MMI文件必须和BIT来自同一次实现。如果你改了Block Design重新综合却拿旧的MMI去处理新的BIT结果一定是启动即崩溃。3.2 用updatemem把ELF写进BIT前期的准备工作是SDK里已经编译好了最终版本的应用ELF并且你确定这个ELF的链接脚本和当前BRAM配置是匹配的。然后在Vivado的Tcl Console或者系统命令行中执行updatemem -meminfo ./hw/system_wrapper.mmi \ -bit ./hw/system_wrapper.bit \ -proc system_i/microblaze_0 \ -data ./sdk/app/Debug/app.elf \ -outbit ./output/system_wrapper_app.bit逐参数说明一下-meminfo指定MMI文件路径要求与-bit同源。-bit输入BIT文件也就是纯硬件位流。-procMicroBlaze在处理系统里的实例路径在Block Design里通常叫microblaze_0顶层例化后完整路径是system_i/microblaze_0。如果你的Block Design名称不叫system_wrapper就按实际顶层模块名替换。-data指定要整合的ELF文件。updatemem会读取ELF里所有可加载段根据MMI映射关系写入对应的BRAM初始化区。-outbit输出整合后的BIT文件名。千万别直接覆盖原BIT否则后续出了问题连回退的余地都没有。我见过有人在多核系统里用这个命令需要注意如果Block Design里有多个MicroBlaze-proc参数必须指定完整路径且一个处理器实例对应执行一次updatemem。整合完第一个CPU的程序后再以同样的BIT作为输入整合第二个CPU的程序以此类推。执行完成后终端会打印类似Merging app.elf into bitstream的信息。如果没有报错你就得到了一个自包含的BIT文件——既有硬件逻辑又有程序初始值。3.3 确认整合成功的三种方法第一次用updatemem的人最担心的就是到底成功没有。我分享三个验证办法第一看输出信息。updatemem如果成功会在结尾明确提示merge完成如果ELF里的加载段在MMI中找不到对应BRAM或者地址超出范围它会直接报错退出不会默默产出半成品。第二把整合后的BIT通过JTAG下载到FPGA。注意这里不需要再下载ELF下载完BIT后直接点Run运行MicroBlaze。如果程序正常跑起来说明整合有效这个验证方法最直接。第三使用FPGA的在线调试工具或者串口监测。比如程序里设了一个上电后翻转LED的逻辑下载整合BIT后看到LED动作就说明CPU拿到了正确指令。这三个办法里我最推荐第二个因为它能顺带验证硬件平台和软件程序是否真正匹配。如果你发现JTAG加载整合BIT后程序不跑不要急着烧Flash先回到SDK用调试态整合跑一遍逐步缩小是整合问题还是代码问题。3.4 write_cfgmem生成QSPI Flash镜像整合后的BIT只是可以下载到FPGA的位流但QSPI Flash不认识BIT格式它烧录的是MCS或BIN镜像。这一步需要用到Vivado Tcl Console里的write_cfgmem命令。我的习惯是先生成BIN格式因为它是最通用的格式后续不管用什么烧录器都能处理write_cfgmem -force -format bin -size 16 -interface SPIx1 \ -loadbit up 0x0 ./output/system_wrapper_app.bit \ -file ./output/system_wrapper_app.bin关键参数这里解释一下-sizeFlash容量单位是MB。比如S25FL128S是16MB就写16W25Q64是8MB就写8。-interfaceSPI接口模式常见SPIx1或SPIx4。这个必须和板卡上QSPI Flash的实际连接以及启动模式匹配选错了上电必翻车。-loadbit up 0x0 ...表示从Flash地址0x0开始存放BIT数据up表示地址递增方向。-force参数也很关键如果你之前生成过同名文件不加-force它会停下来问你确认在批处理脚本里就是挂起。所以脚本里我习惯总是带上。如果你更习惯用Vivado图形界面也可以在Hardware Manager里右键FPGA器件选择Add Configuration Memory Device然后在弹出的窗口里直接选择MCS/BIN文件烧写。GUI的好处是Flash型号可以从列表里选不容易写错但整套流程要手动点很多次不适合反复执行。3.5 烧录QSPI并验证上电自启动拿到BIN文件后烧录到QSPI Flash的推荐路径是把下载器连上板卡打开Vivado Hardware ManagerOpen Target。右键FPGA器件选择Add Configuration Memory Device在弹出的Flash型号列表里找到你板卡上的那颗Flash比如Spansion s25fl128s系列。这里要注意部分板卡支持多个Flash型号选错会导致读ID失败。选中Flash后右键它选择Program Configuration Memory Device加载BIN或MCS文件Programming。烧写完成后别急着断电。先确认板卡的启动模式跳线已经切到QSPI/SPI Flash启动然后重新上电。如果程序能自己跑起来就说明固化整合的所有环节都打通了。有个细节我吃过大亏烧录完Flash后板卡上电但程序不跑检查了一圈发现是启动模式跳线还停在JTAG模式。FPGA上电后只等JTAG完全不理会Flash里的内容。所以上电不跑优先查跳线应该成为肌肉记忆。4. 链接脚本与启动地址动不动就翻车的内存地图4.1 lscript.ld和BRAM的对应关系MicroBlaze应用工程里SDK会自动生成一个链接脚本lscript.ld它定义了程序各个段vector、text、data、bss、heap、stack的放置位置。可以把它理解成一张内存地图告诉链接器代码放在哪个地址、数据放在哪个地址、堆栈又放在哪里。默认情况下如果Block Design里给MicroBlaze配了32KB本地BRAM那么lscript.ld里memory区域大概是0x00000000到0x00008000vectors段从0x0开始text段紧随其后最后是heap和stack。整合时updatemem就是按照ELF里各个段的地址去找MMI里对应的BRAM位置。所以链接脚本里写的地址必须和Block Design里BRAM的真实地址范围一致。一旦不一致整合就会出问题——不是在updatemem阶段报地址越界就是生成了镜像但上电后程序跑飞。4.2 修改BRAM容量后必须跟着动的三个地方我在实际项目里不止一次修改过MicroBlaze的本地存储器大小每次都要确认三处保持一致第一处Block Design里MicroBlaze Local Memory的大小。这个好理解你在图形界面里改。第二处BSP的链接脚本。当你修改硬件平台并重新导出后SDK里的BSP会根据新硬件信息自动更新内存区域。但如果你手动改过lscript.ld或者把BSP工程从旧平台拷到新平台就可能出现设计用的是128KB BRAMlscript.ld里却还是32KB的情况。解决办法是在BSP工程上右键选择Regenerate BSP Sources让它重新生成链接脚本。第三处heap和stack的大小。修改BRAM容量后BSP默认的heap和stack往往不会自动变大。尤其当你开始用printf、跑文件系统或调用复杂的库函数时堆栈溢出会导致程序随机跑飞、进入异常向量甚至完全无响应。建议在BSP Settings里把heap和stack调到一个合理值比如单线程裸机程序栈给16KB到32KB一般够用堆根据动态内存使用情况设定。4.3 程序在DDR时为什么必须多一个引导层前面提到过程序放DDR时没法像BRAM那样直接打进BIT。原因很朴素DDR控制器是FPGA逻辑逻辑还没加载时DDR物理上是不可寻址的CPU从复位地址0x0拿到第一条指令时那段指令不可能在DDR里。所以DDR方案的通用做法是BRAM里驻留一个Bootloader它负责做三件事——通过ICAP或其他配置接口把完整的主设计逻辑加载进FPGA、初始化DDR控制器、从Flash把应用ELF搬运到DDR指定地址然后跳转过去执行。这个Bootloader在SDK的Application工程模板里可以直接创建名字就是Bootloader。它和普通应用工程的区别在于它需要放进BRAM跑所以链接脚本必须把它的代码放在0x0开始的BRAM区域而主应用链接脚本里vectors和text则需要定位到DDR的地址范围。DDR方案还需要把Bootloader和主应用打包成一个启动镜像。在SDK里通过Create Boot Image向导依次加入Bootloader.elf和主应用ELF生成BIN文件再配合Bootloop BIT和主设计BIT进行Flash布局。这个体系比BRAM方案复杂不少第一次上手建议先跑通BRAM版本理解了整合的本质之后再往引导方向扩展。5. 高频踩坑清单每个坑都附排查链路5.1 找不到调试模块SDK报错cant find CPU现象在线调试时SDK提示无法连接目标CPU或者下载ELF时卡在JTAG初始化。排查链路先检查Block Design里有没有MicroBlaze Debug ModuleMDM。MDM是MicroBlaze在线调试的必要IP没有它SDK无法通过JTAG访问CPU的调试端口。如果你在设计时图省事没有添加MDM所有在线下载ELF的操作都会失败。解决办法是在Block Design里添加MDM把它的Debug接口连到MicroBlaze的Debug引脚上然后重新综合、导出、下载。顺带说一句固化整合其实不依赖MDMupdatemem直接操作位流不需要CPU在线所以这个坑主要影响调试态。5.2 updatemem的地址报错先查readelf再查lscript.ld现象updatemem报类似Address 0xXXXX is out of range或Segment too big的错误。排查链路先用readelf -l app.elf查看ELF里各加载段的地址和大小再用文本编辑器打开MMI文件确认BRAM地址范围。如果ELF的加载段地址确实超出了MMI记录的范围问题几乎都出在链接脚本和硬件配置不一致上。我遇到最多的情况是Block Design里BRAM只有32KB但BSP的lscript.ld因为某种原因还是64KB的配置或者代码里定义了超大的全局数组导致data段超过了BRAM容量。前者重新生成BSP即可后者就要重新规划内存布局把大数据挪到DDR或者扩大BRAM。还有一种隐蔽情况系统的Block Design名称和updatemem命令里-proc的路径不一致。多核系统里尤其容易错建议打开Block Design的Address Editor确认MicroBlaze实例的完整路径再填到命令里。5.3 上电不运行从JTAG试跑到Flash地址的顺序排查现象MCS/BIN烧进Flash后重新上电没有任何反应。排查链路一定按顺序来不要上来就怀疑Flash颗粒坏了。第一步先用JTAG加载整合后的BIT到FPGA里看看程序能不能跑。如果JTAG加载后能跑说明整合本身没问题问题出在烧写环节如果JTAG加载后也不跑说明整合有问题回到updatemem阶段排查。第二步确认烧写时的Flash地址从0x0开始。常见错误是把BIN烧到了其他偏移地址FPGA从Flash 0x0读配置时读出一堆无效数据自然跑不起来。第三步确认启动模式跳线。很多开发板默认跳线在JTAG模式QSPI启动需要手动切换这个检查只需要几秒钟但经常让人绕一大圈。第四步确认write_cfgmem的interface与实际Flash连接匹配。SPIx1和SPIx4的位流布局不一样写错了就算Flash里有数据FPGA也解析不了。5.4 修改代码后忘了重新整合现象调试态跑得好好的重新生成的ELF烧进Flash后板子行为还是老样子仿佛改的代码根本没进去。原因非常简单你改了程序编译出了新ELF也烧了Flash但Flash里的BIT还是旧ELF整合出来的那份。烧Flash时用的是旧整合BIT新ELF根本没被用到。这个坑最大的迷惑性在于SDK调试态一切正常生产过程却反复出问题。我现在的习惯是把整合流程脚本化下一章详细讲每次编译完ELF后执行一条命令就完成新ELF 当前BIT的整合再也不会出现烧进去的是上一版这种低级事故。5.5 工具链版本差异带来的updatemem路径问题现象在命令行里输入updatemem提示找不到命令或者在SDK终端里能跑但系统终端里跑不了。原因updatemem是Vivado自带工具不同版本安装目录不同。Vivado 2018.3及以前可执行文件在安装目录/Vivado/版本/bin下2019.2之后的Vitis时代工具链位置又变了。如果你在系统命令行直接敲updatemem需要先把对应目录加到PATH环境变量里。更省事的做法是直接在Vivado的Tcl Console里执行updatemem因为Tcl Console里工具路径是配好的而且还能顺带使用write_cfgmem整条命令链都在同一个环境完成避免环境变量混乱。6. 把整合固化成一个可重复的脚本习惯6.1 为什么我坚持用命令行而不是GUI点来点去固化整合涉及updatemem和write_cfgmem两步GUI也能做但每次都要记住路径、选择文件、确认Flash型号重复劳动且容易错。命令行最大的优势是可重复、可记录、可交给持续集成。把命令写进脚本后代码改完编译完执行一次脚本就能产出最终的烧写镜像。脚本本身放到版本管理里还能追溯某个版本的Flash镜像到底是用哪个BIT和哪个ELF生成的这对项目交付非常重要。6.2 一个可以直接改用的Makefile示例下面是我在Linux环境下常用的Makefile骨架Windows下思路一样把命令换成Vivado Tcl批处理模式即可# 路径按实际工程修改 BIT : ./hw/system_wrapper.bit MMI : ./hw/system_wrapper.mmi ELF : ./sdk/app/Debug/app.elf OUT : ./output all: bin bit: mkdir -p $(OUT) updatemem -meminfo $(MMI) -bit $(BIT) \ -proc system_i/microblaze_0 \ -data $(ELF) \ -outbit $(OUT)/system_wrapper_app.bit mcs: bit vivado -mode batch -source gen_flash.tcl bin: bit vivado -mode batch -source gen_flash.tcl clean: rm -rf $(OUT)其中gen_flash.tcl是独立的Tcl脚本内容很简单write_cfgmem -force -format bin -size 16 -interface SPIx1 \ -loadbit up 0x0 ./output/system_wrapper_app.bit \ -file ./output/system_wrapper_app.bin两个细节提醒Makefile里命令前面必须是Tab字符不能是空格否则会报错get_proc路径如果有多核系统建议单独定义一个变量集中管理方便改动。有了这个脚本日常修改代码后的动作就变成SDK里重新编译ELF → 命令行执行make bin→ Hardware Manager烧写BIN。三步变成两步整合这一步被脚本固化彻底告别手动拼命令的日子。6.3 用版本控制管理产出物联动脚本化之后还有一个让我受益很久的习惯每次生成整合BIT和烧写镜像时我会把以下三个文件打上同一个版本标记源BIT、源ELF、整合后的BIN。因为三者是严格联动的只要BIT或ELF其中任何一个变化BIN就必须重新生成。在实际项目里出现过A同事更新了硬件设计B同事用旧BIT整合了新ELF烧到板子上功能异常的惨痛教训。后来规定任何硬件改动后负责整合的人必须重新跑完整套脚本不允许只更新其中一个源文件。版本管理里保存BIN对应的BIT和ELF来源信息出问题时能直接回溯省去了大量扯皮时间。这些习惯看起来简单但确实让我在MicroBlaze相关的项目里少走了很多弯路。整合这件事本质上就是让硬件描述和软件程序在时间和空间上准确对齐理解了MMI、链接脚本、Flash启动这三根支柱剩下的都是熟练工。
网站建设高端定制企业官网
RELATED

相关资讯

更多精彩内容,欢迎继续阅读

较早相关资讯

最新相关资讯

手腕骨折检测:YOLOv8引入注意力机制的完整实战指南 2026/9/28 3:05:52

手腕骨折检测:YOLOv8引入注意力机制的完整实战指南

简介:面向医学影像分析与计算机视觉开发者,这是一套基于Pytorch与YOLOv8、融合注意力机制的手腕骨折检测实战项目。在传统YOLOv8基础上引入注意力模块,使模型能聚焦腕部关键区域,提升骨折特征识别精度与效率,适用于辅助…

阅读更多 →
深度强化学习股票交易策略:从MDP设计到回测避坑指南 2026/9/28 3:05:52

深度强化学习股票交易策略:从MDP设计到回测避坑指南

简介:一套基于深度强化学习的自动化股票交易策略设计源码,面向量化研究者、金融分析师和具备Python基础的开发者,解决人工交易受情绪影响、难以适应市场动态变化的问题。项目用PPO、A2C、DDPG三种Actor-Critic算法训练交易代理,覆…

阅读更多 →
YOLOv8结合注意力机制的手腕骨折检测与部署实战 2026/9/28 3:05:45

YOLOv8结合注意力机制的手腕骨折检测与部署实战

简介:一份面向医学影像分析与计算机视觉开发者/学习者的手腕骨折检测实战资源,基于 Pytorch 与 YOLOv8,并引入注意力机制强化模型对骨折区域的关注,适用于快速搭建检测算法、开展医学图像识别实验或作为毕业设计参考。资源共 158 …

阅读更多 →
Operit 记忆空间 Profile 文档体系全解析:从全局 `user.md` 到“一空间一文档“的存储、迁移、运行时注入与独立配置 UI 2026/9/28 3:05:45

Operit 记忆空间 Profile 文档体系全解析:从全局 `user.md` 到“一空间一文档“的存储、迁移、运行时注入与独立配置 UI

AI Agent人工智能大模型AI 应用工具调用本地部署MCP ClientsAgent 记忆 【免费下载链接】Operit The most powerful AI agent and AI chat software on Android/Operit是一款Android上能力最为强大、发展最久的AI Agent 项目地址: https://gitcode.com/gh_mirrors/o…

阅读更多 →
better-sqlite3 贡献指南:从 C++ 原生插件到发布流程的完整协作规范 2026/9/28 3:05:45

better-sqlite3 贡献指南:从 C++ 原生插件到发布流程的完整协作规范

数据库嵌入式数据库 【免费下载链接】better-sqlite3 The fastest and simplest library for SQLite3 in Node.js. 项目地址: https://gitcode.com/gh_mirrors/be/better-sqlite3 点击查看 免费下载 本篇技术指南围绕 better-sqlite3 的官方贡献文档(do…

阅读更多 →
YOLO车辆检测数据集处理:从解压到训练的全流程指南 2026/9/28 3:05:45

YOLO车辆检测数据集处理:从解压到训练的全流程指南

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

阅读更多 →

今日资讯

本周资讯

本月资讯

看完文章仍有疑问?

联系尧图顾问,获取一对一建站咨询

立即免费咨询 📞 400-888-8888
📞 ✉