
小引:
今天我们就去看看常春藤盟校Cornell University 康奈尔大学开设的FPGA项目课程,大部分课程是有源码的,而且和国内使用习惯类似都是Verilog开发,还是很有借鉴意义的。
项目链接
https://people.ece.cornell.edu/land/courses/ece5760/FinalProjects/
项目介绍
2024年春季 开发板:CycloneV DE1-SoC
Cyclone V SoC 上的多边形光栅化图形处理单元

概述

目标是在 Cyclone V SoC 上设计一个多边形光栅化图形处理单元 (GPU)。
开发了一个基本的渲染管线,其中包含硬编码的顶点/片段着色器,该管线在仿真中运行良好。渲染管线包括顶点变换、三角形平铺、三角形光栅化/插值和片段变换。还开发了一个并行 SIMD 处理器核心网格,支持 4 字向量运算和 16 字矩阵运算。这些 SIMD 处理器还支持同步多线程,允许两个独立的线程上下文共享计算资源。这些处理器计划用于替换渲染管线中硬编码的顶点/片段着色器。渲染和 SIMD 处理器均使用一个 27 位浮点库,该库旨在充分利用 18 位硬件乘法器。为了验证设计,还搭建了一个基本的 UVM 框架以方便测试。
高层设计
SIMD核心执行流水线
处理器的每个核心都配备多个硬件线程,对于软件应用程序而言,这些线程如同独立的处理器,拥有各自的程序计数器和通用寄存器组。尽管这些线程在运行上相互独立,但它们共享核心内的关键资源,例如算术流水线和 L1 缓存。这种多线程方法的主要目标是最大限度地利用这些共享资源。当线程因缓存未命中或数据依赖而发生停顿时,核心能够将操作切换到另一个线程,从而确保程序的连续执行。核心会尽可能地在每个周期内循环执行来自不同线程的指令。
如果某条指令触发了数据缓存未命中、分支跳转或异常,核心会通过使受影响线程后续发出的指令失效来做出响应。如果是分支跳转,程序计数器会被重置为新分支的目标地址,程序会从该跳转点继续执行。如果是缓存未命中,相应的线程会暂时停止,直到内存子系统获取到必要的数据,然后程序会从中断点继续执行。
该处理器架构包含 16 条并行算术流水线,每条流水线与一条向量通道对齐,从而增强了其处理向量化数据的能力。标量运算仅使用第一条流水线,而涉及标量和向量操作数的指令则通过在所有通道中复制标量值来实现。此外,指令还可以通过掩码寄存器灵活地指定对特定向量通道的更新,从而实现选择性和高效的数据处理。
该处理器采用深度流水线设计,实现了更高的时钟频率,从而优化了性能。下图展示了单个核心的执行流水线,概述了核心内数据流和指令处理所涉及的复杂阶段和过程。

渲染管线(初始)
最初的GPU方案是让SDRAM存储所有3D模型信息以及两个帧缓冲区,分别存储各自的颜色缓冲区和深度缓冲区。这样可以实现双缓冲,防止画面撕裂。十字形路由器负责在VGA和渲染管线之间分配SDRAM内存的读写操作,使它们能够共享同一个端口。深度缓存用于保存最近使用的深度值,减少对SDRAM的读写操作;所有颜色值都写入SDRAM,因为这样不太可能导致管线阻塞。最终,由于物理资源和时间的限制,不得不对设计进行重大修改。

光栅化渲染
光栅化渲染的目的是将一组数据转换为像素网格。在本例中,数据是一组三维顶点,其中每三个顶点构成一个独立的三角形。为了便于在这个空间中进行操作,我们使用齐次坐标,它在传统的线性变换基础上增加了一个非线性平移分量。在齐次坐标中,向量由四个分量 (x, y, z, w) 组成,其中 w=0 表示三维向量,w=1 表示三维点。

射影几何
为了渲染图像,定义一个平面(即屏幕),并将场景中的物体投影到该平面上。为了标准化计算,可以定义一个从 (-1,-1,z) 到 (1,1,z) 的平面,并想象将从我们视角 (x0, y0, z0) 到 (x1, y1, z1) 可见的所有物体线性变换到 (-1,-1,-1) 和 (1,1,1) 之间的空间。这被称为归一化设备坐标,它引入了近裁剪面和远裁剪面的概念。如果只渲染位于 (-1,-1,-1) 和 (1,1,1) 之间的像素,那么永远无法看到比 z0 更近或比 z1 更远的物体。
然而,如果简单地将所有物体投影到该平面上,则无论距离远近,物体看起来都一样大。这被称为正交投影,它适用于蓝图或 CAD,但不能准确地表示人眼感知世界的方式。为了在渲染中实现逼真的透视效果,需要让远处的物体看起来更小。不用长方体,而是用长方体来实现这一点。这样一来,靠近远裁剪平面的空间会被压缩到与靠近近裁剪平面的空间相同的正方形内,从而产生远处物体更小的错觉。

三角栅格化
本文选择了一种基于边缘函数的三角形栅格化方法。其基本思想是,表示一条直线的向量与从该直线到点 p 的向量的二维叉积,结果等于由这两个向量构成的平行四边形的有符号面积。如果 p 位于直线的一侧,则叉积为正;如果 p 位于直线的另一侧,则叉积为负。通过将正边定义为“内部”,并检查三角形的三条边,可以通过检查所有有符号面积是否均为正来确定任意给定点是否位于三角形内部。这种叉积被称为边缘函数,因为它可用于确定一个点位于边缘的一侧还是另一侧。边缘函数的优势在于它是线性的,这使得我们可以轻松地仅使用加法和减法来迭代单位位移,从而节省硬件乘法器。另一个优势是,“背面”三角形在位于三角形内部时所有面积均为负值,这使得我们可以快速跳过它们并节省计算量。


对于插值,我们使用重心坐标来适当地赋予顶点的每个属性权重。重心坐标也等于由每条边和点 p 构成的子三角形面积与完整三角形面积之比。因此,我们可以利用上面计算出的面积(平行四边形的面积是其子三角形面积的两倍)来计算重心坐标。
透视校正
在进行插值之前,必须先对重心坐标进行透视校正。这是因为当前的重心坐标是屏幕表面上的线性坐标,没有考虑三角形的深度。校正方法是:将每个重心坐标乘以其顶点深度的倒数(或者直接乘以另外两个顶点深度的乘积)。

最后,任意点的插值属性是三个顶点属性值乘以透视校正后的重心坐标值的总和。
深度测试
渲染的另一个关键方面是,较近的物体可能会遮挡较远的物体。如果我们简单地按顺序处理所有接收到的三角形,那么较远的三角形可能会在处理后覆盖之前渲染的较近的三角形。虽然可以按距离远近对三角形进行排序,或者要求输入数据已经排序,但这会导致一个棘手的问题:如果三角形 A 的某些部分遮挡了三角形 B,而三角形 B 的某些部分又遮挡了三角形 A(例如,当三角形相交时)。
一个更常见、更直接的解决方案是存储已渲染的最近像素的深度,并丢弃深度小于该最近像素的像素。这种方法称为深度测试,它对于每个像素,如果其深度小于当前存储的深度,则将其深度存储到深度缓冲区中。然而,这会占用我们本已有限的片上内存,因为我们现在需要同时存储像素的颜色和深度。我们通过将大容量存储卸载到 SDRAM,并将片上内存用作缓存来解决这个问题。
设计限制/权衡
内存限制
如上文深度测试部分简要提及,我们的片上内存非常有限。甚至不足以存储 640x480 屏幕所需的 16 位颜色,因此不得不缩小屏幕尺寸或使用片外 SDRAM 来存储必要数据。选择使用片外 SDRAM 进行大容量存储,并将片上内存用作缓存。为了 实现这一点,将颜色/深度缓冲区组织成 32 x 32 像素的图块,这些图块可以在 SDRAM 和片上缓存之间移动以进行渲染。选择 32 x 32 像素是为了使屏幕能够均匀分布在 20 x 15 个图块上,而选择图块则是为了实现二维空间局部性。内存也按图块而不是按行和列进行组织。每个图块占用 4KB 的连续空间,其中前 2KB 存储颜色,后 2KB 存储深度,两者均为 16 位分辨率。每个数据块都以连续的方式排列在SDRAM的顶部。我们还利用两个这样的缓冲区来实现双缓冲,从而防止画面撕裂。
硬件/程序设计
浮点处理单元
选择使用 27 位浮点数,因为它的尾数为 18 位,正好可以匹配 SoC 上 18x18 的硬件乘法器。此外,这种格式便于数据转换,因为它本质上就是截断尾数最后 5 位的 IEEE 32 位浮点数。
SIMD处理器
指令解码
在处理器指令解码阶段,解码逻辑会识别每条指令所需的寄存器操作数。该阶段会从指令数据中精确提取这些寄存器的索引,并将它们分配到寄存器文件中的相应端口。此外,它还会将指令分配到特定的执行流水线,这是简化处理流程的关键步骤。
该阶段在整个执行流水线中也扮演着至关重要的角色,它为后续阶段提供必要的数据。它有助于跟踪指令的执行路径和调度,这对于高效管理处理器资源至关重要。此外,解码阶段收集的信息对于监控和解决寄存器写回过程中可能出现的任何潜在冲突也至关重要,例如确保没有两条指令会错误地覆盖彼此的结果。这种精细的协调有助于维护处理器操作的数据完整性和一致性,从而提高性能和可靠性。
UVM 测试框架

构建了一个用于测试该组件的UVM框架。以下是框架结构的介绍:
TB_TOP_UVM(顶层测试平台)
这是UVM测试平台层级结构中的最高层组件。它作为整个UVM测试环境的容器,包括DUV的实例化、接口以及UVM环境本身。顶层组件负责初始化测试并为验证过程做好准备。
接口(输入接口,输出接口)
输入接口 (IN_INTERFACE):此接口模块管理 DUV 的输入。它定义了输入到 DUV 的协议和信号级交互,确保 DUV 接收到正确且及时的测试数据。输出接口 (OUT_INTERFACE):与输入接口类似,但用于输出。此模块捕获并处理来自 DUV 的输出,以便于对结果进行进一步分析和验证,确保与预期结果一致。
DUV(设计验证)
该模块是验证过程的真正目标。它代表了新的或修改后的硬件设计,需要进行严格测试,以确保其满足规定的要求,并在所有运行条件下都能按预期运行。
内存
该组件模拟了DUV与之交互的存储元件。对于验证DUV在数据存储和检索场景中的行为(模拟真实世界的存储交互)的测试而言,它至关重要。
UVM_TEST
此组件定义了要运行的具体测试场景。它配置了UVM环境和其他测试参数。每个UVM_TEST通常都针对验证DUV的不同方面或模拟不同的运行条件而定制。
UVM_ENV(UVM环境)
UVM_ENV 是一个综合容器,其中包含各种 UVM 组件,例如代理、监视器和记分板。它负责管理这些组件之间的交互,并确保在整个测试过程中运行一致。
UVM_AGENT
UVM代理是模块化单元,通常包含UVM驱动器、UVM序列器和UVM监视器。每个代理都专注于DUV接口或功能的特定部分,负责将测试序列驱动到DUV中并监视其产生的行为。
UVM_DRIVER
驱动器从序列器获取序列项,并根据这些序列项主动将信号驱动到总线或接口上。它在测试期间如何向DUV施加激励信号方面起着直接作用。
UVM_SEQUENCER
序列器生成指令项,这些指令项决定了驾驶员需要执行的操作。它控制这些操作的时机和顺序,这对于测试的连贯性和有效性至关重要。
UVM_MONITOR
监测器是用于监测深潜器接口活动而不影响其运行的观测组件。它们收集分析所需的数据,并将结果与预期行为进行比对。
UVM_SCOREBOARD
记分板将DUV的实际输出与预期输出进行比较,以验证其正确性。这对于判断测试场景的成功或失败以及识别差异至关重要。
UVM_AGENT_OUT、UVM_MONITOR_OUT
这些很可能是额外的监控和接口组件,旨在处理DUV的其他特定输出或辅助接口。它们通过监控DUV行为的各个方面来确保全面 覆盖。
测试计划
还用SystemVerilog编写了一个指令生成器。

它可以生成我们想要的指令,也可以生成随机指令。例如:




GPU
GPU大致可以分为4个部分。
内存管理单元 VGA控制器 GPU状态机 渲染管线


结果
由于英特尔DMA IP存在问题,且无法满足设计的内存需求,因此未能成功地将设计部署到SoC上。然而,仿真结果表明,如果内存通道配置得当,部署过程应该会相对顺利。对整个GPU的仿真模型包含一个模拟VGA设备,该设备接收vga_signal来自设计的输出,并在触发时将下一帧打印到控制台。利用该模型,能够模拟渲染一些示例图像,这些图像显示在本页顶部。
渲染时间从简单形状的约20毫秒到复杂形状(例如犹他茶壶)的约300毫秒不等。从图像中可以看出,偶尔会出现一些像素丢失或写入错误地址的情况。猜测造成这种情况的原因是渲染管线中各个阶段之间的同步性较差,导致偶尔出现像素丢失或延迟的情况。
项目链接
https://people.ece.cornell.edu/land/courses/ece5760/FinalProjects/s2024/sl2873_yz2949_rm2238/index.html
代码链接
https://people.ece.cornell.edu/land/courses/ece5760/FinalProjects/s2024/sl2873_yz2949_rm2238/index.html
视频链接
无
高频交易员
尝试开发一款用于股票市场的高频交易(HFT)系统。虽然这项设计的实际影响可能仅体现在经济效益上,但该项目让我们得以展示Cyclone V和DE1-SoC组合在硬件加速、并行化和网络化方面的优势。
介绍
高频交易已成为美国乃至全球投资的重要组成部分。根据德意志银行2016年的一份报告,高频交易约占美国交易量的50%,欧洲则占35%。最初,高频交易专注于寻找套利机会,即通过快速交易来有效确保盈利;然而,随着市场基础设施逐渐完善,套利机会变得越来越少、持续时间越来越短,也越来越难以利用。因此,高频交易转向了基于预测的模式,高频交易者试图在极短的时间内预测股票的走势,并利用该预测进行交易。
许多高频交易公司正在使用 FPGA(https://www.theregister.com/2023/09/29/amd_finance_fpga/)来尝试加快其交易算法的速度,这是一个很好的、现实世界的 FPGA 在工业应用实例。
项目资料
这些资料是构思和实施的基础。对于一些基础数学,我们引用了 Jacob Loveless、Sasha Stoikov 和 Rolf Waeber 的工作;对于一些最初的逻辑思想,我们引用了 Arévalo、Andrés、Nino、Jaime、Hernandez、German 和 Sandoval、Javier 的工作。
Jacob Loveless、Sasha Stoikov 和 Rolf Waeber. 2013. 高频交易中的在线算法:竞争性高频交易算法面临的挑战。Queue 11, 8 (2013 年 8 月), 30–41。https ://doi.org/10.1145/2523426.2534976 (https://doi.org/10.1145/2523426.2534976) Arévalo, Andrés & Nino, Jaime & Hernandez, German & Sandoval, Javier. (2016). 基于深度神经网络的高频交易策略. 9773. 424-436. https://doi.org/10.1007/978-3-319-42297-8_40 (https://doi.org/10.1007/978-3-319-42297-8_40)
项目结构

上图概括地描述了我们的设计。为了获取实时数据,使用了 polygon.io,它提供了一个实时股票数据 API。出于我们的目的,使用了入门级订阅,该订阅提供当前股票数据,但比实时数据延迟 15 分钟。由于只是模拟交易员的操作,因为它可以模拟真实情况,所以这种延迟是可以接受的。只能通过此 API 请求 1 秒的数据窗口,这限制了我们的操作速度。但是,可以展示硬件的响应时间,以说明其能够达到的最快响应速度。
SoC 运行一个网络监控程序,通过以太网接收来自笔记本电脑的股票数据包。SoC 将解码数据包,并通过 PIO 端口将信息传输到 FPGA。它还会利用这些数据在连接的 640x480 VGA 显示器上绘制当前股票趋势图,供用户查看。FPGA 将获取当前数据,并执行硬件设计中描述的交易分析。分析完成后,它会将交易信息返回给 SoC,该信息描述了对当前股票趋势的决策以及该决策的“强度”。“强度”指的是如果选择买入或卖出,交易的金额。SoC 使用这些信息来更新系统投资组合的变化,用户可以通过串行输出查看这些变化。在模拟开始时,给每只运行中的股票赋予 10,000 美元,并并行运行 10 只股票。
该程序接收 WebSocket 数据包并构建新的数据包,然后通过 UDP 协议将其转发到 FPGA。每个数据包包含一只股票的信息,长度为 4 个字节。前 5 位表示股票代码(以整数表示),后 27 个字节表示股票价值(以定点数表示)。每当 Polygon API 向某只股票发送更新时,程序都会发送一个这样的数据包。
最初使用 TCP 协议实现了该软件;然而,如果股票数据需要更频繁地传输,UDP 协议可以提升性能。但 UDP 协议会增加数据包损坏或乱序到达的概率;不过,由于笔记本电脑和 FPGA 之间采用的是直连以太网,这种概率仍然很低,可以接受。
由于无法将整个交易系统完全移植到FPGA上,因此牺牲了一些执行时间。网络接口是在SoC而非FPGA上实现的,这使得设计速度受限于PIO的速度。出于安全考虑,SoC没有直接连接到互联网,因此在互联网交易方面也遇到了瓶颈。由于数字信号处理(DSP)模块的依赖性,最多只能并行处理81只股票,这远远超出了测试预期。由于HPS端的资金管理,以及通过硬设置alpha参数(允许设计使用移位操作而不是额外的DSP,这将在数学部分进一步描述),每只股票只能使用一个DSP。
HPS
HPS代码相对简单,它由两个线程组成。第一个线程从stdinFPGA读取股票数据并写入其中,同时读取交易记录,并跟踪账户余额和持仓情况。第二个线程则将来自互联网和FPGA的股票信息和投资组合信息更新到VGA显示屏上。网络数据通过命令传输到标准输入/输出(stdio) netcat。
Verilog
交易算法使用指数加权移动平均线和方差来决定买入、卖出或持有特定股票。关于这两种方法的数学原理,参考了 Loveless、Stoikov 和 Waeber 合著的论文《高频交易中的在线算法:竞争性高频交易算法面临的挑战》。该论文中,作者描述了用于计算平均值和方差的指数算法,这两种算法每次迭代都只需要一个输入,并且在迭代之间只需在内存中存储一个值。这有助于保持平均值和方差计算的每次实例化都是轻量级,从而能够更有效地利用 FPGA 上的可用资源,例如 DSP。我们的想法是,如果保持计算效率,就可以在 FPGA 上计算更多股票的数据。移动平均线的计算如下:

在进行任何数学运算之前,平均值被初始化为第一个输入值。 X0 此后,每个后续平均值都是新输入的一部分与旧平均值的一部分之和。旧平均值的权重为:α,α是平滑因子,它决定了计算过程中对旧数据和新数据的重视程度。换句话说,可以将其视为对新数据的一个低通滤波器。在我们的设计中,α被硬性设定为一个值0.94为了最大限度地减少使用的 DSP 模块数量,将以 为操作数的乘法运算优化为移位运算。0.94要乘以另一个操作数,只需将另一个操作数本身向右移动四次,然后减去它。 0.06多次使用不同的操作数(1−α),将操作数向右移动 4 位。
为了计算方差,采用与计算移动平均值类似的格式。不同之处在于,不是将初始值初始化为第一个输入值,而是将第一个方差值设为 1。之后,使用以下两个公式中的第二个:

由于对轮班进行了优化α如前所述,计算平均值和方差的模块每次实例化仅使用一个 DSP 模块。只有在计算上述方差公式中的平方时才需要实际进行有符号乘法运算。另外,由于 DSP 模块接受 27 位长度的操作数,选择使用 13 位整数(1 位用于符号)和 14 位小数的定点格式。这提供了足够的精度和数值范围,可以准确地捕捉股票价格。

如上所述,我们实现的定点格式。
交易算法
为了实现交易功能,开发了一种K近邻算法(KNN)。该算法旨在捕捉股票当前趋势中的拐点。考虑到速度因素,使用前60秒的数据作为训练集进行比较。算法运行过程如下:
启动时收集 60 秒内的股票价格数据,共 60 个实例。在收集过程中,计算当前价格与 60 秒开始时的开盘价之间的曼哈顿距离(单实例距离)。如果该距离为负值且低于该数据集中的最低距离,则将该距离设置为该数据集中的最低距离。如果该距离为正值且高于该数据集中的最高距离,则将该距离设置为该数据集中的最高距离。收集 60 个实例后,根据当前价格流入情况做出交易决策。如果新价格与 60 秒前的价格之间的距离为负值但高于最低距离,则买入股票。如果新价格与 60 秒前的价格之间的距离为正值但低于最高距离,则卖出股票。如果以上情况均不成立,则持有股票。将新价格添加到数据集中,并移除记录的最旧价格。将新的最旧价格设置为距离的样本价格。
最初的算法与 Arévalo、Andrés、Nino、Jaime、Hernandez、German 和 Sandoval、Javier 的论文中的流程图非常接近。然而,他们的设计更多地运用了深度学习算法,这超出了我们的研究范围。因此,对其进行了抽象,但可能仍然保留一些相似之处。上述 KNN 算法随后在 FPGA 上实现了硬件版本。

交易者KNN部分的线性状态图
为了解释交易器中发生的一些复杂情况,构建了上述基于前向的状态机,该状态机中没有递归。复位时,系统会将所有已使用的寄存器清零,包括距离、价格、交易选择、内存地址和状态转换变量。复位后,状态机将保持交易状态,直到通过 PIO 输入价格变化。价格变化后,状态机检查模拟是否刚刚开始。如果是,则认为内存为空,需要写入数据,从而填充算法中的 60 个相邻节点。内存方面,我们使用 M10K 块,结构为 256 x 32 块(基于此处的示例 12-16 )。我们将距离和价格都写入内存。在内存中,第一个索引是该特定时间点的价格,第二个索引是与 60 秒起始价格的距离。所有价格实例都遵循这种价格对分配方式。在填充最初的 60 个价格时,找出与样本价格相比的最低价格和最高价格,并将这些差异记录在登记簿中。
收集到前 60 个价格后,算法即可进入数学状态进行决策。当有新价格出现时,将其与样本价格进行比较。如果新价格与 60 秒前的价格之间的距离为负值,但高于最低价,则买入股票;如果距离为正值,但低于最高价,则卖出股票;如果以上情况均不成立,则持有股票。将新价格添加到集合中,并移除记录的最旧价格。将新的最旧价格设置为距离的样本价格。将价格及其距离写入内存。以上所有操作均由硬件系统中的 KNN 模块完成。
交易者决定买入或卖出股票后,如何确定交易数量?由于难以设定精确数值,最终决定使用百分比。如果交易者给出的交易数量为 0,则表示这是一个非常弱的决定,因此交易股票/配额的 0%。如果交易者给出的交易数量为 10,则表示这是一个非常强的决定,因此交易股票/配额的 100%。中间值以 10% 为增量递增。那么,这个百分比是如何确定的呢?请看下面的例子:

此示例展示了卖出的情况。实线代表当前价格趋势线,虚线代表平均单位的预测平均价格。在拐点转换时,平均价格会向上或向下移动。这可以用来判断拐点转换的临近程度。示例表明,当平均价格低于趋势线时,即为弱卖出,因为平均价格预期下跌,因此表明价格上涨幅度更大,且交叉点已过。当平均价格高于趋势线时,即为强卖出,因为平均价格预期上涨,因此表明价格下跌,且交叉点尚未出现。买入的情况则相反。一旦确定交易是强卖还是弱卖,就可以利用价格相对于平均价格的变化来确定当前预测的准确性。在手动分析了一些趋势后,选择了以下准确性阈值:
如果变异系数 > 450:准确度低 否则,如果变异系数 > 250:低至中等准确度 否则,如果变化 > 100:中等精度 否则,如果变异系数 > 50:中等偏高准确度 否则:高精度
在最终系统中,设置了 10 个并行交易器来执行所述分析。每个交易器连接到三个 PIO 引脚,分别用于传输价格、交易选择和交易金额。还使用了一个 VGA 子系统,供 SoC 使用。该系统源自 ece5760 课程网站上的示例代码(https://people.ece.cornell.edu/land/courses/ece5760/DE1_SOC/HPS_peripherials/Examples_version_18.html)。这些连接在我们的 Qsys 代码中有所体现。Qsys 代码片段如下所示。

结果
下图展示了设计的大部分成果。图中显示了芯片的整体利用率。虽然密度很高,但仍有大量的剩余资源。这符合预期,因为在测试时并未达到理论最大值。如果让设计处理更多股票,预计利用率会大幅提升。下图展示了交易器一段时间内的运行情况。可以看到它快速做出决策并执行交易。接下来的图放大显示了某个实例,以展示做出决策所需的时间。由于将设计设置为保留历史价格的最低值和最高值,因此它实际上可以在一个时钟周期内决定以给定价格买入或卖出,由于运行频率为 50MHz,这个时钟周期约为20 纳秒。然后,更新 KNN 参数大约需要62-64 个时钟周期。因此,它对变化的反应速度很快,但调整的延迟时间较长。然而,如果传输过程中没有延迟,在给定的误差范围内, 这将使设计速度的绝对最快值限制在 1.3 微秒。显然,实际情况并非如此,但这恰恰证明了 FPGA 的执行速度非常快。



在分析了仿真结果和不同的仿真后,发现该算法表现相当不错。在出现尖角时,交易员会以强劲的势头在低点买入,在高点卖出。确实观察到一些在线性趋势上买卖的异常情况,但正如所预期的,这些情况被认为是弱势的。在几次弱势交易后,算法会切换到相反的交易策略,从而纠正了自身的错误。考虑到由于SoC和FPGA通信的复杂性,无法直接使用实时数据进行测试,这已经是所能期望的最佳结果了。这些仿真结果相当成功,认为该算法在尖角检测方面的准确率约为60-70%,比该领域的其他算法高出约10%。至于设计的安全性,它与其他任何投资一样都存在风险。如果预测错误,它有可能损失所有投入的资金。不过,如果能够完成测试以进一步验证,倾向于投入一些真金白银来检验它的表现。至于易用性方面,用户需要一些基本的编程知识来设置股票参数和提供收入,但除此之外,它几乎是全自动的。
项目链接
https://people.ece.cornell.edu/land/courses/ece5760/FinalProjects/s2024/wb273_sal267_rak277/docs/index.html
代码链接
https://people.ece.cornell.edu/land/courses/ece5760/FinalProjects/s2024/wb273_sal267_rak277/docs/index.html
视频链接
https://youtu.be/nvdbo4Gi_MA?si=5y_gyLajcEw7kae6
总结
本文整理了康奈尔大学 2024 年春季 ECE5760 课程基于 CycloneV DE1-SoC 开发板的 2 个 FPGA 实战项目,全部采用 Verilog 开发,具体项目如下:
项目一:Cyclone V SoC 上的多边形光栅化 GPU
该项目基于 Intel Cyclone V SoC 平台,从底层设计了一个简化版 FPGA GPU,实现了完整的 3D 图形渲染流程,包括顶点变换、三角形光栅化、重心坐标插值、透视校正以及深度测试等模块。同时项目设计了支持向量运算和多线程执行的 SIMD 处理器核心,用于替代传统固定功能 Shader,并结合 Tile 缓存、SDRAM 帧缓冲以及 UVM 验证环境完成系统设计。虽然受限于 DMA 和存储带宽等硬件因素未能最终部署到 SoC,但仿真结果已经实现了基本 3D 模型渲染,展示了 FPGA 在图形计算和自定义 GPU 架构方面的潜力。
项目二:基于 Cyclone V SoC 的 FPGA 高频交易系统
该项目利用 FPGA 的低延迟和并行计算能力,设计了一套面向股票市场数据分析的高频交易(HFT)硬件加速系统。系统通过 HPS 处理网络数据接入,并将实时股票价格传输至 FPGA,由硬件交易引擎执行 EMA(指数移动平均)、方差分析以及 KNN 趋势预测算法,快速生成买入、卖出或持有决策。设计采用定点计算、并行交易模块以及 DSP 资源优化,在 FPGA 上实现了多个交易器同时运行,理论交易判断延迟可达到纳秒级。该项目展示了 FPGA 在金融计算领域中相比软件方案更低延迟、更高确定性的优势。
- -THE END- -
往期精选


FPGA技术江湖广发江湖帖
无广告纯净模式,给技术交流一片净土,从初学小白到行业精英业界大佬等,从军工领域到民用企业等,从通信、图像处理到人工智能等各个方向应有尽有,QQ微信双选,FPGA技术江湖打造最纯净最专业的技术交流学习平台。
FPGA技术江湖微信交流群

加群主微信,备注姓名+学校/公司+专业/岗位进群
FPGA技术江湖QQ交流群

备注姓名+学校/公司+专业/岗位进群
