1. 一台带FPGA芯片组的家用电脑,到底在解决什么问题
第一次看到“Kromi One”这个项目标题的时候,我脑子里蹦出来的第一个念头是:又有人想用FPGA做家用电脑了。这个念头不是嘲讽,而是因为FPGA做计算机这件事,在圈子里属于那种“每隔几年就有人重新发明一遍”的经典命题。但仔细看完这个标题的措辞——“a new home computer with its own FPGA chipset”,关键词落在“home computer”和“its own FPGA chipset”上,这就跟那些拿现成开发板拼一个能跑Linux的玩具完全不是一回事了。
先说清楚Kromi One是什么。它是一台面向家庭场景的整机电脑,核心卖点在于它搭载了一套自研的FPGA芯片组,而不是像普通PC那样用一颗CPU加一颗南桥芯片的固定组合。FPGA在这里扮演的角色,是把传统意义上由专用芯片完成的那些功能——比如显示输出、存储控制器、音频接口、外设桥接——用可编程逻辑来实现。换句话说,这台机器的“主板芯片组”不是焊死的固定功能芯片,而是一块可以被重新配置的逻辑阵列。
它能做什么?最直接的价值是硬件层面的可重构性。你可以今天把它配置成一台复古游戏机,明天把它刷成一台视频处理终端,后天把它变成一台低延迟的音频工作站。这种灵活性在传统PC上是做不到的,因为传统PC的芯片组功能是出厂就定死的。它解决的问题,本质上是“一台机器能不能在硬件层面适应多种完全不同的使用场景”,而不是靠软件模拟去凑合。
适合谁来参考?我觉得有三类人值得关注。第一类是对计算机体系结构感兴趣、想动手折腾硬件逻辑的开发者;第二类是需要特定低延迟或确定性响应场景的工程师,比如音频处理、工业控制、复古计算;第三类是单纯对“电脑还能这么做”感到好奇的技术爱好者。如果你只是想买台机器上网办公,那这台机器的思路对你参考价值不大,但如果你想知道一台电脑的底层还能怎么玩,那它的设计思路值得拆开看看。
2. 为什么是FPGA芯片组,而不是传统南桥或SoC
2.1 传统PC芯片组的固定功能困境
要理解Kromi One为什么选FPGA做芯片组,得先看传统PC是怎么干的。一颗现代x86处理器负责计算,旁边挂一颗芯片组(以前叫南桥北桥,现在整合成PCH),这颗芯片组的功能是固定的:它提供多少个USB口、多少个SATA通道、PCIe怎么分配、音频怎么走,全是硅片出厂时就定好的。你买了一块主板,它的扩展能力就锁死了。
这种设计的好处是成本低、驱动成熟、生态稳定。但坏处也很明显:如果你需要一个传统芯片组不提供的功能,比如一个超低延迟的并行总线接口,或者一个特定时序的显示输出,你只能通过外挂额外的芯片或者用软件去模拟。软件模拟的延迟和确定性,在硬实时场景下往往不够看。
Kromi One选择FPGA做芯片组,本质上是用“可编程逻辑”替代“固定功能逻辑”。FPGA内部是大量的查找表和触发器,你可以用硬件描述语言把它们连成任何你想要的数字电路。今天连成一个SPI控制器,明天连成一个自定义的视频时序发生器,后天连成一个多通道PWM控制器,全都靠重新综合比特流来实现。
2.2 FPGA做芯片组的三个核心优势
第一个优势是接口定制能力。传统芯片组的接口协议是固定的,你没法改。但FPGA可以让你实现任何时序的接口。比如你想接一个老式的并口打印机,或者一个非标准时序的传感器,FPGA可以直接生成对应的时序逻辑,不需要额外的桥接芯片。这在复古计算和工业控制场景里非常实用。
第二个优势是确定性延迟。FPGA的逻辑是并行执行的,没有操作系统调度、没有中断延迟、没有缓存未命中。一个信号从输入引脚到输出引脚,延迟是几个时钟周期,可以精确计算。这对于音频处理、电机控制、视频同步这类对时序敏感的应用来说,是软件方案很难达到的。
第三个优势是硬件可升级。传统电脑的芯片组功能在出厂后就固定了,最多通过BIOS更新修修bug。但FPGA芯片组可以通过加载不同的比特流,变成完全不同的硬件。今天你的机器是一个显示控制器,明天加载另一个比特流,它就变成了一个网络处理器。这种“硬件层面的可升级性”是Kromi One最核心的差异化点。
2.3 代价是什么:成本、功耗与开发门槛
当然,FPGA做芯片组不是没有代价的。首先是成本。FPGA芯片本身比同等功能的专用芯片贵不少,尤其是需要一定逻辑资源和高速收发器的型号。其次是功耗。FPGA的静态功耗和动态功耗通常高于专用芯片,因为它的逻辑资源是通用的,不像专用芯片那样可以针对特定功能做优化。最后是开发门槛。写Verilog或VHDL跟写C语言完全是两回事,需要理解时序、时钟域、复位策略这些硬件概念,不是随便找个程序员就能上手的。
Kromi One作为一台家用电脑,必须在这三者之间找到平衡。从项目定位来看,它显然不是要跟主流PC拼性价比,而是瞄准了一个特定的小众市场:那些愿意为可重构性和确定性延迟买单的用户。这个定位决定了它的FPGA选型不会追求最大最快的型号,而是够用就好,重点是把开发工具链和文档做扎实,让用户能真正用起来。
3. 核心细节拆解:FPGA芯片组里到底跑了什么
3.1 显示输出子系统
一台家用电脑,显示输出是刚需。Kromi One的FPGA芯片组里,显示子系统大概率是用FPGA逻辑实现了一个视频时序发生器加帧缓冲控制器。传统PC的显示输出由GPU负责,GPU内部有专门的显示控制器硬件。FPGA方案则是用逻辑资源搭出一个类似的控制器,从帧缓冲里读像素数据,按照VGA或HDMI的时序要求输出。
这里的关键参数是像素时钟和时序参数。以720p@60Hz为例,像素时钟是74.25MHz,每行1650个像素时钟,其中1280个是有效像素,370个是消隐区;每帧750行,其中720行有效,30行消隐。这些参数必须精确生成,否则显示器无法锁定信号。FPGA实现的好处是,你可以随时修改这些参数,比如输出一个非标准的分辨率或刷新率,只要显示器能接受就行。
帧缓冲的带宽是另一个关键点。720p@60Hz的像素数据率是74.25M像素/秒,每个像素按24位色深算,就是1.78Gbps的读带宽。FPGA内部的Block RAM通常不够存一整帧,所以需要外挂DDR内存。FPGA通过自己的内存控制器访问DDR,这个控制器的时序参数需要根据具体的内存颗粒来调整。这部分是实操中比较容易踩坑的地方,后面会细说。
3.2 存储控制器与启动流程
Kromi One作为一台电脑,需要有启动介质。传统PC从BIOS/UEFI开始,然后加载操作系统。FPGA方案可以走两条路:一条是FPGA自己实现一个存储控制器,从SD卡或eMMC读取比特流和操作系统镜像;另一条是用一颗小的辅助处理器来负责启动,FPGA作为外设被配置。
从项目标题的“its own FPGA chipset”来看,更可能是前者:FPGA芯片组自己管理启动流程。这意味着FPGA内部需要实现一个SPI或SDIO控制器,用来读取存储卡上的数据。启动时,FPGA首先加载自己的比特流(可能从板载Flash),然后配置各个子系统,最后把控制权交给CPU。
这里有个细节值得注意:FPGA的比特流加载本身就需要一个配置控制器。通常FPGA厂商会提供硬核配置逻辑,支持从SPI Flash主动加载。Kromi One如果要做成“家用电脑”的形态,启动流程必须足够简单,用户按下电源键就能进系统,而不是先接JTAG线烧录比特流。所以板载配置Flash和启动管理逻辑是必不可少的。
3.3 音频与外设接口
音频输出在FPGA里通常用I2S或PWM实现。I2S是标准音频接口,需要精确的位时钟和帧时钟。FPGA可以生成这些时钟,并从帧缓冲或DMA通道读取音频样本。PWM方案则更简单,用高速PWM调制音频信号,外接一个低通滤波器就能输出模拟音频。两种方案各有优劣,I2S音质更好但需要外置DAC,PWM成本低但音质受限于PWM频率和滤波器设计。
外设接口方面,USB是家用电脑绕不开的。FPGA实现USB主机控制器是可行的,但工作量不小,需要处理USB协议栈的底层时序。更常见的做法是用一颗专用的USB控制器芯片,FPGA通过SPI或并口跟它通信。这样FPGA芯片组负责管理USB控制器的寄存器,而不需要自己实现完整的USB协议。Kromi One大概率走了这条路线,因为从项目定位看,它需要控制开发复杂度,不可能所有东西都从零写。
4. 实操过程:从零搭建一个FPGA芯片组的核心环节
4.1 工具链选型与工程结构
如果你要复现类似Kromi One的设计,第一步是选工具链。主流的FPGA厂商都有自己的IDE,比如Xilinx的Vivado、Intel的Quartus、Lattice的Diamond。选哪个取决于你用的FPGA型号。对于家用电脑这种项目,Lattice的ECP5或Xilinx的Artix-7是比较常见的选择,因为它们的逻辑资源够用,价格相对亲民,而且有开源工具链支持。
开源工具链方面,Yosys做综合,nextpnr做布局布线,Trellis或Project IceStorm做比特流生成,这套组合对Lattice ECP5的支持已经比较成熟。用开源工具链的好处是流程透明,你可以看到每一步在干什么,出了问题也容易排查。商业工具链的优势是时序收敛更容易,IP核更丰富,但授权费用不低。
工程结构上,我建议按功能划分目录:rtl/放Verilog或VHDL源码,sim/放仿真测试平台,constraints/放引脚约束和时序约束,scripts/放综合和布局布线的脚本。每个功能模块单独一个文件,顶层文件负责例化和互连。这样结构清晰,后期改起来不容易乱。
4.2 时钟域规划与复位策略
FPGA设计里最容易出问题的地方就是时钟和复位。Kromi One的芯片组里至少有两个时钟域:一个是系统时钟,可能来自板载晶振,频率在50MHz到100MHz之间;另一个是显示像素时钟,频率取决于分辨率和刷新率。这两个时钟域之间需要做跨时钟域处理,否则会出现亚稳态问题。
跨时钟域处理的基本方法是使用双触发器同步器或异步FIFO。对于单比特信号,双触发器同步器就够了;对于多比特数据,必须用异步FIFO或握手协议。我见过不少新手直接在不同时钟域之间连信号,仿真时看着正常,上板就随机出错,排查起来非常痛苦。
复位策略上,建议使用同步复位而不是异步复位。同步复位对时序更友好,不容易产生复位毛刺。复位信号也需要做跨时钟域同步,确保每个时钟域都能正确复位。另外,复位释放的时机要注意,最好在时钟稳定之后再释放复位,避免上电时的不确定状态。
4.3 显示时序发生器的Verilog实现要点
显示时序发生器是FPGA芯片组里比较核心的模块。它的任务是生成行同步、场同步、数据有效信号,以及像素坐标。下面是一个简化的720p时序发生器核心逻辑的伪代码描述:
// 参数定义 parameter H_ACTIVE = 1280; parameter H_FRONT = 110; parameter H_SYNC = 40; parameter H_BACK = 220; parameter H_TOTAL = H_ACTIVE + H_FRONT + H_SYNC + H_BACK; parameter V_ACTIVE = 720; parameter V_FRONT = 5; parameter V_SYNC = 5; parameter V_BACK = 20; parameter V_TOTAL = V_ACTIVE + V_FRONT + V_SYNC + V_BACK; // 行计数器和场计数器 always @(posedge pixel_clk) begin if (h_cnt == H_TOTAL - 1) begin h_cnt <= 0; if (v_cnt == V_TOTAL - 1) v_cnt <= 0; else v_cnt <= v_cnt + 1; end else begin h_cnt <= h_cnt + 1; end end // 同步信号生成 assign h_sync = ~(h_cnt >= H_ACTIVE + H_FRONT && h_cnt < H_ACTIVE + H_FRONT + H_SYNC); assign v_sync = ~(v_cnt >= V_ACTIVE + V_FRONT && v_cnt < V_ACTIVE + V_FRONT + V_SYNC); assign de = (h_cnt < H_ACTIVE) && (v_cnt < V_ACTIVE);这段逻辑看起来简单,但实际调试时要注意几个点。第一,同步信号的极性要跟显示器匹配,有些显示器要求正极性,有些要求负极性。第二,消隐区的长度要符合显示器的要求,太短可能导致显示器无法锁定。第三,像素时钟的抖动要控制好,FPGA的PLL输出时钟通常质量不错,但布线时要避免长距离走线引入抖动。
4.4 内存控制器的参数计算与调试
如果显示子系统需要外挂DDR内存做帧缓冲,内存控制器的调试是绕不过去的坎。DDR内存的时序参数非常多,包括CAS延迟、RAS到CAS延迟、预充电时间、刷新周期等等。这些参数必须根据具体的内存颗粒手册来设置,不能随便填。
以一颗常见的DDR3颗粒为例,假设工作频率是400MHz(DDR3-800),CAS延迟CL=6,那么读命令发出后需要6个时钟周期数据才有效。RAS到CAS延迟tRCD=6,预充电时间tRP=6,行激活到预充电的最小时间tRAS=15。这些参数在FPGA的内存控制器IP里通常有对应的配置项,你需要根据颗粒手册填入正确的值。
调试内存控制器时,我建议先用一个简单的测试模式:往内存里写一个已知的数据模式,然后读回来对比。如果读回的数据不对,先降低频率试试,排除时序问题。如果降频后正常,说明时序参数太激进,需要放宽。如果降频后还是不对,检查引脚约束和PCB走线,DDR的走线等长要求比较严格,差太多会导致采样错误。
5. 常见问题与排查技巧实录
5.1 FPGA综合报错:时序不收敛怎么办
时序不收敛是FPGA开发中最常见的问题之一。综合工具报告建立时间或保持时间违例,意味着信号在时钟沿到来之前没有稳定下来,或者稳定得太早被下一个时钟沿采到。解决思路有几个方向。
第一,降低时钟频率。这是最直接的办法,但会影响性能。如果系统时钟是100MHz,降到75MHz可能就收敛了。第二,优化关键路径。找到时序报告里违例最严重的路径,看看是不是组合逻辑层数太多,插入一级寄存器打拍。第三,调整布局布线策略。商业工具通常有多种策略可选,比如面积优先、时序优先、功耗优先,换一种策略可能就收敛了。第四,加时序约束。有时候工具不知道某些路径是伪路径或多周期路径,你需要用约束文件告诉它,让它不要在这些路径上浪费优化资源。
5.2 上板后显示花屏或不同步
显示花屏通常有几个原因。第一,像素时钟不稳定。用示波器量一下像素时钟引脚,看看频率和抖动是否正常。第二,帧缓冲数据错误。如果内存控制器有问题,读出来的像素数据就是乱的。第三,时序参数跟显示器不匹配。换一台显示器试试,如果换了就好了,说明是显示器兼容性问题。第四,PCB走线问题。高速差分信号对走线阻抗和等长有要求,走线不好会导致信号完整性下降。
排查顺序建议从简到繁:先换显示器,再查时钟,再查内存,最后查PCB。我遇到过好几次花屏最后发现是显示器不支持某个非标准分辨率,换回标准分辨率就正常了。
5.3 启动失败:比特流加载不了
FPGA上电后比特流加载失败,可能的原因包括:配置Flash里的比特流损坏、配置时钟频率不对、配置模式引脚设置错误、电源电压不达标。排查时先用JTAG直接下载比特流,如果JTAG能成功而Flash启动失败,说明问题在Flash或配置电路。检查Flash的SPI模式是否正确,配置时钟是否在FPGA允许的范围内,电源上电时序是否符合要求。
5.4 常见问题速查表
| 问题现象 | 可能原因 | 排查方法 | 解决措施 |
|---|---|---|---|
| 时序不收敛 | 关键路径太长 | 查看时序报告 | 插入寄存器、降频、换布局策略 |
| 显示花屏 | 像素时钟抖动 | 示波器测量 | 优化PLL配置、改善电源滤波 |
| 显示不同步 | 时序参数不匹配 | 换显示器测试 | 调整消隐区参数、匹配极性 |
| 内存读写错误 | 时序参数太激进 | 降频测试 | 放宽CAS、tRCD等参数 |
| 比特流加载失败 | Flash配置错误 | JTAG对比测试 | 检查SPI模式、配置时钟 |
| 系统随机死机 | 跨时钟域亚稳态 | 仿真检查 | 加同步器、异步FIFO |
| 音频有杂音 | PWM频率不够 | 频谱分析 | 提高PWM频率、优化滤波器 |
6. 这套方案的影响范围与适用边界
6.1 对复古计算与硬件爱好者的价值
Kromi One这类FPGA电脑对复古计算社区来说是个好消息。传统上,玩复古计算要么用原装老机器(可靠性差、配件难找),要么用软件模拟器(延迟和兼容性不完美)。FPGA方案提供了一条中间路线:用现代硬件精确复现老机器的时序行为,同时保持硬件的可维护性。比如你可以用FPGA精确模拟一台老式游戏机的视频和音频时序,软件模拟器很难做到这种级别的精确度。
对硬件爱好者来说,FPGA芯片组意味着他们可以深入修改机器的底层行为。传统PC的芯片组是黑盒,你只能通过驱动和BIOS去影响它。FPGA芯片组是白盒,你可以直接改逻辑,改变硬件的行为。这种自由度对于学习和实验来说非常有价值。
6.2 在工业与嵌入式场景的潜在应用
虽然Kromi One定位是家用电脑,但它的FPGA芯片组思路在工业和嵌入式场景也有参考价值。工业场景经常需要非标准的接口和确定性的响应时间,传统PC方案要么加扩展卡,要么用专用的工控板。FPGA芯片组可以在一台机器上同时满足多种接口需求,而且延迟可控。
嵌入式场景里,FPGA的可重构性意味着同一块硬件可以适应不同的产品型号。比如一家公司做了一系列设备,接口需求各不相同,传统做法是每款设备设计一块主板。用FPGA芯片组的话,可以共用一块硬件,通过加载不同的比特流来适配不同型号。这能显著降低库存和开发成本。
6.3 局限性与不适用场景
当然,这套方案不是万能的。对于需要高性能通用计算的场景,FPGA芯片组帮不上忙,CPU的性能才是瓶颈。对于成本极度敏感的量产产品,FPGA的成本和功耗劣势很明显,专用芯片方案更合适。对于需要成熟生态和丰富软件支持的用户,FPGA电脑的软件生态还在建设中,不能指望它跑主流商业软件。
另外,FPGA开发本身的门槛不低。如果你没有数字逻辑设计的基础,想上手改Kromi One的芯片组逻辑会比较吃力。这不是那种“刷个固件就能玩”的项目,而是需要真正理解硬件描述语言和时序概念。所以它更适合有一定硬件基础的开发者,而不是普通消费者。
7. 我个人在FPGA电脑项目上踩过的坑
说几个我在类似项目里实际踩过的坑,希望能帮你省点时间。第一个坑是低估了跨时钟域问题的隐蔽性。仿真的时候一切正常,上板之后随机出错,而且出错概率跟温度有关。后来发现是两个时钟域之间的信号没有做同步,温度变化导致时序偏移,偶尔采到亚稳态。加了两级同步器之后问题消失。这个坑的教训是:只要信号跨时钟域,就必须做同步,没有例外。
第二个坑是内存控制器的时序参数照搬开发板。开发板上的内存颗粒跟自己做板用的颗粒可能不是同一个型号,时序参数不能直接抄。必须查自己用的颗粒手册,按手册填参数。我当初偷懒抄了开发板的参数,结果跑高频时随机出错,降频就正常。后来查手册发现tRCD参数差了2个周期,改过来就稳了。
第三个坑是电源滤波不够导致PLL失锁。FPGA的PLL对电源噪声比较敏感,如果电源滤波电容不够或者布局不好,PLL输出时钟会抖动甚至失锁。表现是系统随机死机或者显示闪烁。后来在PLL电源引脚旁边加了几个小电容,问题解决。这个坑的教训是:FPGA的电源设计不能省,该加的滤波电容一个都不能少。
第四个坑是比特流加载模式配置错误。FPGA通常支持多种配置模式,比如主动SPI、被动SPI、JTAG等。模式引脚的电平决定了用哪种模式。我当初把模式引脚焊错了,导致上电后FPGA不加载Flash里的比特流,一直等JTAG。查了半天才发现是模式引脚的问题。这个坑的教训是:上电前先确认配置模式引脚的设置,别等板子焊好了再改。
最后分享一个小技巧:在FPGA设计里,尽量用同步复位,并且复位信号要做跨时钟域同步。异步复位虽然看起来简单,但复位释放的时机如果跟时钟沿太近,会导致触发器进入亚稳态。同步复位配合复位同步器,可以避免这个问题。另外,复位信号最好在全局时钟稳定之后再释放,可以用一个计数器延时几百个周期再释放复位,确保所有时钟都稳定了。
这个项目后续还可以这样扩展:如果你对FPGA芯片组感兴趣,可以先从一个小模块开始,比如实现一个简单的VGA时序发生器,用开发板输出一个彩条测试图。跑通之后再逐步加入内存控制器、音频接口、USB控制器。不要一上来就想做整台电脑,那样很容易卡在某个环节失去信心。分模块验证,每个模块单独测试通过之后再集成,这是FPGA项目的正确打开方式。