69 个版本 (36 个重大更改)
0.46.0 | 2023年7月2日 |
---|---|
0.44.2 | 2023年3月25日 |
0.41.1 | 2022年12月2日 |
0.38.6 | 2022年9月15日 |
0.2.0 | 2021年11月30日 |
#277 in 硬件支持
每月108 次下载
用于 10 个crates (9直接使用)
1MB
18K SLoC
rust-hdl
** 使用 Rust 编写 FPGA 固件!**
RustHDL 是一个 crate,允许您使用 Rust 编写 FPGA 固件!具体来说,rust-hdl
将 Rust 的子集编译成 Verilog,这样您可以使用标准工具为您的 FPGA 生成固件。它还提供了用于模拟、验证和分析的工具,以及强类型接口,以确保您的设计在前往测试台之前能够正常工作。工作流程与 GPU 编程非常相似。您使用 Rust 编写一切,包括编译到硬件上的更新 kernel
。您可以在 Rust 环境的安全舒适中模拟和验证一切,然后转到标准综合工具以获取编程 FPGA 的文件。
链接
您可能需要
特性
- 安全 - 使用 Rust 在编译时通过强类型接口检查固件的合法性,同时在运行时、综合和设备上。
- 快速 - 直接从 Rust 代码中运行您的设计的模拟,具有相当不错的模拟性能。
- 可读性 - RustHDL 为综合和实现输出 Verilog 代码,并努力确保代码可读易懂,以防您需要解决时序问题或其他冲突。
- 可重用性 - RustHDL 支持参数化使用的模板化固件,以及基于结构体的简单组合模型。
- 内置工具 - RustHDL 包含一系列基本的固件小部件,提供 FIFO、RAM 和 ROM、触发器、SPI 组件、PWM 等,让您可以快速入门。
- 免费 - 虽然您可以使用 RustHDL 封装现有的 IP 内核,但 RustHDL 代码和固件都是开源的,并且免费使用(即言论自由和啤酒自由)。
- 经过测试 - RustHDL 已被用于编写在商业产品中发货的固件。这包括相当复杂的设计,这些设计几乎使用了中等大小 FPGA 的所有功能,并利用了 FPGA 本身的专用硬件。
快速入门
FPGA固件领域的 definitive example 是一个简单的LED闪烁器。这通常涉及到一个以预定义的频率馈送到FPGA的时钟,以及一个可以控制LED的输出信号。由于我们不知道使用的是哪种FPGA,我们首先在仿真中这样做。我们希望每秒闪烁250毫秒,时钟速度是(一个滑稽的慢)10kHz。下面是一个最小的可工作Blinky!示例
use std::time::Duration;
use rust_hdl::docs::vcd2svg::vcd_to_svg;
use rust_hdl::prelude::*;
const CLOCK_SPEED_HZ : u64 = 10_000;
#[derive(LogicBlock)] // <- This turns the struct into something you can simulate/synthesize
struct Blinky {
pub clock: Signal<In, Clock>, // <- input signal, type is clock
pulser: Pulser, // <- sub-circuit, a widget that generates pulses
pub led: Signal<Out, Bit>, // <- output signal, type is single bit
}
impl Default for Blinky {
fn default() -> Self {
Self {
clock: Default::default(),
pulser: Pulser::new(CLOCK_SPEED_HZ, 1.0, Duration::from_millis(250)),
led: Default::default(),
}
}
}
impl Logic for Blinky {
#[hdl_gen] // <- this turns the update function into an HDL Kernel that can be turned into Verilog
fn update(&mut self) {
// v-- write to the .next member v-- read from .val() method
self.pulser.clock.next = self.clock.val();
self.pulser.enable.next = true.into();
self.led.next = self.pulser.pulse.val();
}
}
fn main() {
// v--- build a simple simulation (1 testbench, single clock)
let mut sim = simple_sim!(Blinky, clock, CLOCK_SPEED_HZ, ep, {
let mut x = ep.init()?;
wait_clock_cycles!(ep, clock, x, 4*CLOCK_SPEED_HZ);
ep.done(x)
});
// v--- construct the circuit
let mut uut = Blinky::default();
uut.connect_all();
sim.run_to_file(Box::new(uut), 5 * SIMULATION_TIME_ONE_SECOND, "blinky.vcd").unwrap();
vcd_to_svg("/tmp/blinky.vcd","images/blinky_all.svg",&["uut.clock", "uut.led"], 0, 4_000_000_000_000).unwrap();
vcd_to_svg("/tmp/blinky.vcd","images/blinky_pulse.svg",&["uut.clock", "uut.led"], 900_000_000_000, 1_500_000_000_000).unwrap();
}
运行上面的代码(强烈推荐使用发布运行)将生成一个vcd
文件(这是FPGA和硬件的一般跟踪文件)。您可以使用例如gtkwave
打开此文件。如果您有Alchitry Cu板,您可以通过单次调用为这个例子生成位流。这稍微复杂一些,所以我们将详细说明。它还将把那个vcd
文件转换为svg
,您可以用普通网页浏览器查看。这是整个模拟的最终结果:以下是放大显示LED脉冲的图片:
RustHDL背后的流程如下
- 电路使用简单的
struct
进行建模,由其他电路元素和连接它们的信号线组成。 - 在结构体上添加
#[derive(LogicBlock)]
注解,为RustHDL添加自动生成的代码。 - 在您的
struct
上实现impl Logic
,并提供一个fn update(&mut self)
方法,这是HDL更新内核。 - 它被标注为
#[hdl_gen]
属性,从Rust代码生成HDL - 然后您可以模拟和综合您的设计——无论是通过软件,还是使用适当的BSP和工具链。
其余的都是细节。一些需要注意的最终事项。
- RustHDL是Rust的一个严格的子集。Rust编译器必须首先满足您的设计。这意味着类型、穷举枚举匹配等。
- 目标是消除在其他HDL中容易犯的一类错误,通过编译时的检查、运行时的静态分析和测试平台来实现。
- 尽管性能总是可以改进,但RustHDL相当快,尤其是在发布模式下。
许可证:MIT
依赖项
~8.5MB
~149K SLoC