Chisel实战:为UART通信增加CRC校验的FPGA硬件设计

📅 2026/8/7 23:09:55
Chisel实战:为UART通信增加CRC校验的FPGA硬件设计
这次我们来看一个基于 Chisel 的硬件设计实战项目为 UART 通信增加 CRC 校验。这个项目不是停留在理论讲解而是直接展示如何用 Chisel 这门现代硬件构造语言将一个基础的 UART 模块升级为具备数据校验能力的可靠通信链路。对于正在学习 Chisel、FPGA 开发或者希望提升数字系统设计可靠性的工程师来说这是一个非常实用的工程案例。项目的核心在于将 CRC循环冗余校验算法无缝集成到 UART 的发送和接收流程中。这不仅仅是两个 IP 的简单拼接而是涉及到数据帧格式重构、状态机协同、错误检测与处理等一系列工程问题。通过这个实战你能清晰地看到如何用 Chisel 高效地描述硬件、进行模块化设计并最终在 FPGA 上验证一个完整的、可工作的系统。本文将带你从零开始理解这个“UART with CRC”项目的设计思路、代码结构并完成从仿真到上板的完整验证流程。我们会重点关注 Chisel 如何简化硬件描述、CRC 校验的硬件实现技巧、以及如何利用 FPGA 开发工具链进行综合与调试。无论你是想入门 Chisel还是寻求一个可靠的串口通信方案这篇文章都能提供直接的参考。1. 核心能力速览在深入代码之前我们先快速了解这个项目能做什么以及它的技术特点。能力项说明项目类型基于 Chisel 的硬件设计项目 (RTL 级)核心功能在标准 UART 通信协议基础上为每帧数据增加 CRC 校验字段实现数据传输的差错检测。设计语言Chisel (Scala 硬件构造语言)目标平台FPGA (理论上支持所有主流 FPGA 厂商如 Xilinx, Intel, Lattice 等)验证方式仿真 (Verilator/ treadle) 上板实测 (通过 USB-UART 转换器连接 PC)关键接口标准 UART 串行接口 (TX, RX)可配置波特率、数据位、停止位。CRC 配置支持常见的 CRC 多项式如 CRC-8, CRC-16校验位宽度可配置。设计特点模块化设计发送 (Tx) 与接收 (Rx) 状态机清晰错误标志输出易于集成到更大系统中。资源占用取决于 FPGA 型号、CRC 宽度和 UART 波特率整体为极轻量级设计。适合场景FPGA 学习、嵌入式系统通信加固、Chisel 语言实战、需要可靠串口通信的科研与产品原型开发。这个项目的价值在于提供了一个“从描述到实现”的完整范例。你不仅能看到 Chisel 代码还能学会如何组织项目、编写测试、并进行硬件验证。2. 适用场景与使用边界适合谁用Chisel 学习者如果你已经看过 Chisel 的基础语法但不知道如何用它完成一个实际项目这是一个绝佳的练手案例。FPGA 初学者/爱好者想理解 UART 和 CRC 的硬件实现细节并希望有一个经过验证的、可直接使用的串口 IP 核。嵌入式系统开发者在 FPGA 或 SoC 项目中需要更可靠的串口通信避免因噪声等原因导致数据错误而系统无法察觉。教育工作者可用于数字逻辑设计、硬件描述语言或通信协议相关课程的教学演示。能解决什么问题数据可靠性问题在电气环境恶劣、长距离传输或高速通信时UART 线上的数据可能出错。增加 CRC 校验后接收端可以检测出绝大多数错误从而请求重发或丢弃错误数据保证上层应用拿到的是正确信息。设计方法学问题展示了如何使用 Chisel 进行层次化、参数化的硬件设计比直接编写 Verilog/VHDL 更简洁、更不易出错。验证流程问题项目通常包含完整的测试平台 (Testbench)演示了如何对硬件设计进行仿真验证这是产品级开发的关键步骤。不适合什么场景仅需软件串口如果你的应用仅在 MCU 上用软件模拟 UART本项目提供的硬件设计不直接适用但其 CRC 校验算法思想可供参考。追求极致吞吐量增加 CRC 校验会增加每帧数据的开销额外的校验位传输时间在极端追求带宽的应用中需权衡。替代专业通信协议对于需要复杂链路层控制如流量控制、重传机制的场景简单的 CRCUART 不够应考虑使用 SPI、I2C 或更专业的工业总线协议。安全与合规边界本项目为开源硬件设计用于学习和研究。在实际产品中使用时请注意通信安全CRC 仅用于检错不具备加密或防篡改功能。如需通信安全需在此基础上增加加密算法。专利与标准使用的 CRC 多项式可能是某些标准的组成部分用于商业产品时请留意相关知识产权。电气规范UART 电平需符合目标平台的电气标准如 3.3V LVCMOS连接外部设备时注意电平转换避免损坏硬件。3. 环境准备与前置条件要运行和修改这个 Chisel 项目你需要搭建一个完整的硬件开发环境。这不仅仅是安装一个 IDE而是一套工具链。3.1 软件环境清单Java Development Kit (JDK)Chisel 基于 Scala而 Scala 运行在 JVM 上。推荐安装 JDK 8 或 JDK 11。# 检查Java版本 java -versionScala 构建工具 (sbt)这是管理 Chisel 项目依赖、编译和运行测试的主要工具。请从官网安装最新稳定版。# 检查sbt版本 sbt sbtVersionChisel 3本项目的基础框架。通常通过项目的build.sbt文件定义版本无需单独安装。仿真工具Verilator推荐将 Verilog 转换为 C 模型进行高速仿真。需要单独安装。TreadleChisel 自带的仿真器轻量快捷适合快速调试。FPGA 开发工具用于上板Vivado(Xilinx) 或Quartus(Intel) 或Radiant(Lattice)用于综合、布局布线、生成比特流和下载。一个 USB-UART 转换器如 CP2102, FT232, CH340 等及其驱动程序。代码编辑器VS Code配合 Scala 插件或 IntelliJ IDEA配合 Scala 插件均可。3.2 硬件环境清单开发主机任何能运行上述软件的 Windows, Linux 或 macOS 系统。FPGA 开发板任一款带有 FPGA 芯片和至少一个可用 GPIO 引脚用于连接 UART TX/RX的开发板。例如Xilinx: Basys 3, Arty A7, Pynq-Z2Intel: DE10-Lite, Cyclone V SoC FPGA 开发板Lattice: iCE40UP5K 开发板USB-UART 调试器用于连接 FPGA 的 UART 引脚和电脑的 USB 口。杜邦线用于连接 FPGA GPIO 与 USB-UART 调试器。3.3 项目源码获取通常这类项目托管在 GitHub 或 GitLab 上。假设项目结构如下uart_crc_chisel/ ├── build.sbt # 项目构建定义 ├── src/ │ ├── main/ │ │ └── scala/ │ │ └── mylib/ │ │ ├── UartTx.scala # UART发送模块 │ │ ├── UartRx.scala # UART接收模块 │ │ ├── Crc.scala # CRC计算模块 │ │ └── UartWithCrc.scala # 顶层集成模块 │ └── test/ │ └── scala/ │ └── mylib/ │ └── UartWithCrcSpec.scala # 测试平台 ├── verilog/ # 生成的Verilog文件 └── README.md使用 Git 克隆项目到本地git clone 项目仓库地址 cd uart_crc_chisel4. 安装部署与启动方式Chisel 项目的“启动”指的是编译、生成 Verilog 以及运行仿真测试。它不像软件服务那样有一个长期运行的后台进程。4.1 依赖安装与项目编译进入项目根目录使用 sbt 工具。首次运行会下载所有依赖包括 Chisel、Scala 编译器、测试库等可能需要一些时间。# 进入项目目录 cd /path/to/uart_crc_chisel # 启动sbt交互式环境 sbt进入 sbt 后可以执行以下常用命令# 编译整个项目 compile # 运行所有测试会在内存中进行仿真 test # 生成Verilog代码将Chisel转换为Verilog runMain mylib.UartWithCrcDriverUartWithCrcDriver是一个自定义的App它实例化顶层模块并调用 Chisel 的emitVerilog方法。你需要在源码中找到或创建它。4.2 生成 Verilog 代码生成 Verilog 是硬件设计的关键一步。生成的代码位于./generated/或./verilog/目录下。例如一个简单的 Driver 可能长这样// src/main/scala/mylib/UartWithCrcDriver.scala package mylib import chisel3._ import chisel3.stage.ChiselStage object UartWithCrcDriver extends App { // 定义模块参数 val params new UartWithCrcParams( frequency 100000000, // 100 MHz 系统时钟 baudRate 115200, dataBits 8, stopBits 1, crcWidth 16, crcPoly x16x15x21 // CRC-16-IBM ) // 生成Verilog (new ChiselStage).emitVerilog(new UartWithCrc(params), args) }运行后你将得到UartWithCrc.v文件这就是可以用于 FPGA 综合的 RTL 代码。4.3 启动仿真测试在 sbt 中运行test会执行src/test/scala/下的所有测试规范。一个典型的测试会模拟发送带 CRC 的数据帧并验证接收端是否能正确解码或检测错误。sbt:uart_crc_chisel test [info] UartWithCrcSpec: [info] - UartWithCrc should correctly transmit and receive a frame with CRC [info] - UartWithCrc should detect an error when data is corrupted [info] Run completed in 1 second, 252 milliseconds.看到所有测试通过是设计功能正确的第一道保障。5. 功能测试与效果验证验证分为两步软件仿真和硬件上板。仿真是快速迭代和调试的基础上板是最终的性能与功能确认。5.1 仿真测试验证逻辑正确性仿真测试在 Chisel Testers2 或类似框架中完成。我们来看两个核心测试场景。测试 1正常收发流程测试目的验证完整的发送-接收流程CRC 生成与校验均正常。操作步骤测试平台实例化UartWithCrc模块。模拟上层逻辑向发送模块写入一字节数据0x55。仿真器模拟 UART 线路将发送模块的 TX 信号连接到接收模块的 RX 信号。触发接收模块开始接收。检查接收模块是否在正确的时间点输出数据0x55并且其dataValid信号拉高crcError信号保持低。判断成功dataValid为高且crcError为低同时输出数据等于输入数据。测试 2错误检测流程测试目的验证当传输数据出现比特错误时CRC 校验能有效检测并报错。操作步骤同样发送数据0x55。在仿真中人为地翻转UART 线上传输的某一个比特例如将某个数据位从 1 改为 0。接收模块完成接收后。检查接收模块的dataValid信号应为低或有一个专门的error信号拉高crcError信号应拉高。判断成功crcError信号有效且错误数据不会被dataValid确认。测试代码片段示例// 简化版的测试思路 (ChiselTest) test(new UartWithCrc(params)) { c // 1. 准备发送数据 c.io.txData.poke(0x55.U) c.io.txStart.poke(true.B) // ... 经过若干时钟周期后释放 txStart // 2. 将内部TX信号连接到内部RX信号在测试中模拟环路 // 注意实际测试中可能需要从端口引出或直接内部连接 // 3. 监控接收端 c.clock.step(1000) // 等待一帧传输完成 c.io.rxDataValid.expect(true.B) c.io.rxData.expect(0x55.U) c.io.rxCrcError.expect(false.B) }5.2 上板实测连接真实世界仿真通过后就可以进行上板验证了。这是最令人兴奋的一步。步骤 1FPGA 工程集成创建 FPGA 工程在 Vivado/Quartus 中为你的开发板创建一个新项目。添加源文件将生成的UartWithCrc.v以及所有依赖的 Verilog 文件如可能单独生成的UartTx.v,UartRx.v,Crc.v添加到工程中。编写顶层模块创建一个新的顶层 Verilog 文件如top.v实例化UartWithCrc模块并将其tx和rx信号分配到 FPGA 的具体引脚上。module top( input wire clk, // 系统时钟 input wire rst_n, // 复位 output wire uart_tx, // 连接到USB-UART的RX input wire uart_rx // 连接到USB-UART的TX ); UartWithCrc #( .CLOCK_FREQ(100_000_000), .BAUD_RATE(115200), .DATA_BITS(8), .STOP_BITS(1), .CRC_WIDTH(16), .CRC_POLY(16h8005) ) u_uart_crc ( .clock(clk), .reset(!rst_n), // 注意复位极性 .io_tx(uart_tx), .io_rx(uart_rx), // ... 连接其他控制信号如数据输入/输出总线 ); endmodule引脚约束根据开发板原理图将clk,rst_n,uart_tx,uart_rx映射到实际的 FPGA 引脚号。这是通过约束文件 (.xdc 或 .qsf) 完成的。综合、实现、生成比特流运行完整的 FPGA 编译流程。步骤 2硬件连接将 USB-UART 调试器的TX引脚连接到 FPGA 的RX引脚对应uart_rx。将 USB-UART 调试器的RX引脚连接到 FPGA 的TX引脚对应uart_tx。将 USB-UART 调试器的GND连接到 FPGA 的GND。切勿连接 VCC除非确认电平兼容。步骤 3测试验证下载比特流将生成的.bit或.sof文件下载到 FPGA。打开串口助手在电脑上打开串口调试助手如 Putty, Tera Term, 或国产的 XCOM, SSCOM选择 USB-UART 对应的 COM 口配置正确的波特率如 115200、数据位8、停止位1、无校验位。自发自收测试Loopback在顶层设计中可以将发送数据总线与接收数据总线在 FPGA 内部短接或通过一个简单状态机控制。上电后FPGA 自动发送一串带 CRC 的数据。观察串口助手是否收到可读的字符。如果收到乱码可能是波特率不对或引脚接反。如果能收到预设的字符如 “Hello CRC!”说明发送通路正常。PC 与 FPGA 双向通信测试从串口助手向 FPGA 发送一个字节如0x41即字符 ‘A’。设计一个简单的 FPGA 逻辑将接收到的数据经 CRC 校验无误后原样发回。如果在串口助手发送后能立刻收到相同的字符 ‘A’说明接收和 CRC 校验通路均正常。错误注入测试使用能自定义发送十六进制数据的串口工具发送一个故意修改了 CRC 校验位的错误数据帧。观察 FPGA 是否不回应或回应一个错误标志这证明 CRC 检错功能生效。6. 接口 API 与模块集成对于硬件设计“接口 API”指的是模块的硬件接口Verilog 的module端口。理解这些端口是集成和使用该模块的关键。6.1 顶层模块接口详解一个设计良好的UartWithCrc模块可能包含如下主要接口class UartWithCrcIO(params: UartParams) extends Bundle { // UART 物理接口 val tx Output(Bool()) // 串行发送线 val rx Input(Bool()) // 串行接收线 // 发送侧 FIFO 式接口供上层逻辑写入待发送数据 val txData Input(UInt(params.dataBits.W)) val txValid Input(Bool()) val txReady Output(Bool()) // 为高时表示可以接收新数据 // 接收侧 FIFO 式接口向上层逻辑输出已接收且校验正确的数据 val rxData Output(UInt(params.dataBits.W)) val rxValid Output(Bool()) val rxReady Input(Bool()) // 为高时表示上层可以接收数据 // 状态与错误指示 val crcError Output(Bool()) // 高电平表示上一帧CRC校验失败 val frameError Output(Bool()) // 高电平表示帧格式错误如停止位不对 val busy Output(Bool()) // 高电平表示正在发送或接收 }6.2 如何集成到你的系统假设你有一个基于 Chisel 的 SoC 设计其中包含一个 CPU 核和一个 Wishbone 总线你想将 UART 作为外设挂载上去。封装为总线从设备你需要编写一个UartWithCrcController模块它实现 Wishbone或 AXI4-Lite从机接口内部例化UartWithCrc并将总线的读写操作翻译成对txData/txValid和rxData/rxValid的控制。地址映射为 UART 分配一个或多个总线地址。例如0x1000_0000: 数据寄存器写入则发送读取则获取接收到的数据0x1000_0004: 状态寄存器读取busy,crcError,txReady,rxValid等状态位中断支持可以扩展设计当接收到一帧正确数据或发生 CRC 错误时产生一个中断信号给 CPU提高系统效率。6.3 “批量任务”在硬件中的体现硬件中的“批量任务”通常指连续发送或接收多个数据帧。这通过上层状态机或 DMA 控制器来实现。连续发送上层逻辑在txReady为高时持续将数据写入txData并拉高txValid。UartWithCrc模块内部会自动为每个字节计算并附加 CRC然后通过 UART 串行发出。连续接收当rxValid为高时上层逻辑应及时读取rxData并拉高rxReady以准备接收下一帧。如果忽略rxValid可能会丢失数据。7. 资源占用与性能观察对于 FPGA 设计资源占用和性能最高时钟频率是核心指标。7.1 如何获取资源占用报告在 Vivado/Quartus 完成综合Synthesis和实现Implementation后工具会生成详细的资源报告。查找报告在 Vivado 中打开 “Project Summary” 或 “Report Utilization”。在 Quartus 中查看 “Compilation Report - Flow Summary”。关注关键指标LUTs (Look-Up Tables)实现组合逻辑的主要资源。UART 和 CRC 都是顺序逻辑占用 LUT 数量不多通常在几十到几百个之间具体取决于 CRC 宽度和实现方式串行 vs 并行。FFs (Flip-Flops)寄存器数量。用于存储状态、计数器、移位寄存器等。UART 的波特率生成器和移位寄存器会占用一定数量的 FFs。BRAM/Block Memory本项目通常不使用块内存除非实现了深度 FIFO。时钟频率 (Fmax)报告会给出设计能稳定运行的最高时钟频率。UART 波特率通常远低于 FPGA 主频如 115200 bps vs 100 MHz因此时序约束很容易满足。7.2 性能分析与优化点波特率精度UART 的波特率由系统时钟分频得到。分频系数divisor clock_freq / baud_rate可能不是整数。使用非整数分频会引入累积误差。优化方法是使用更高精度的分频器如小数分频或选择系统时钟与目标波特率成整数倍关系。CRC 计算延迟串行 CRC每个时钟周期处理 1 比特计算一个字节的 CRC 需要 8 个周期。延迟低占用资源少。并行 CRC一个时钟周期内计算一个字节的 CRC。延迟为 1 个周期但消耗更多 LUT 资源。在高速数据流中并行 CRC 是必要的。本项目作为教学示例可能采用串行实现这足以满足标准 UART 速率通常 3 Mbps。吞吐量瓶颈整个链路的吞吐量受限于 UART 的波特率。增加 CRC 会引入少量额外开销传输校验位的时间但相对于数据位这个开销很小例如对于 8 位数据16 位 CRC开销为 16/(816)≈66%但实际有效数据率需考虑起始位、停止位公式为有效速率 (数据位) / (总位数) * 波特率。8. 常见问题与排查方法在开发和调试过程中你肯定会遇到各种问题。下面是一个快速排查指南。问题现象可能原因排查方式解决方案仿真测试失败1. 测试激励 (Testbench) 编写错误。2. Chisel 代码逻辑错误。3. 时钟或复位信号处理不当。1. 仔细阅读测试失败信息定位到第一个断言失败的地方。2. 使用printf在仿真中打印关键信号值。3. 使用波形查看器如 Verilator 生成 VCD 文件用 GTKWave 查看。1. 对照 UART/CRC 时序图检查状态机转换和计数器逻辑。2. 检查复位后初始状态是否正确。3. 简化测试从最简单的单字节收发开始。综合失败1. 语法错误。2. 存在不可综合的 Chisel 构造如某些动态索引。3. 模块端口不匹配。1. 查看综合工具的错误日志通常会有详细的行号和信息。2. 检查生成的 Verilog 代码是否有明显问题。1. 修正 Chisel 代码中的语法错误。2. 确保所有RegInit、when、switch语句都在可综合的范围内。3. 检查模块实例化时的参数和端口连接。上板后无输出1. 引脚分配错误。2. 时钟未连接或频率不对。3. 复位信号极性或时序不对。4. USB-UART 驱动未安装或串口配置错误。1. 使用板载 LED 做一个“心跳灯”测试确认 FPGA 配置成功且代码在运行。2. 用示波器或逻辑分析仪探测 UART TX 引脚看是否有波形。3. 检查串口助手参数波特率、数据位、停止位是否与设计一致。1. 双重检查约束文件中的引脚编号和电平标准。2. 确认顶层模块的时钟和复位信号正确连接到外部晶振和按键。3. 在代码中让 TX 引脚周期性发送特定字符如 0x55用示波器看波形是否符合 UART 格式。收到乱码1.波特率不匹配最常见。2. 数据位、停止位配置不匹配。3. 线路干扰。1. 计算分频系数divisor clk_freq / baud_rate。确认实际值。2. 用示波器测量一个位的时间宽度反推实际波特率。1. 确保设计中的baudRate参数与串口助手设置完全一致。2. 检查系统时钟频率clk_freq是否准确有些开发板时钟输入经过 PLL 分频/倍频。3. 尝试降低波特率如 9600测试。CRC 错误标志常亮或不亮1. CRC 计算模块实现错误。2. 发送和接收端的 CRC 多项式或初始值不一致。3. 数据帧边界判断错误。1. 在仿真中对比软件计算的 CRC 值和硬件计算的 CRC 值。2. 检查发送端是否将 CRC 附加在数据后一起移位发出接收端是否以相同方式计算和比较。1. 编写一个简单的 Scala/Python 脚本用软件实现相同的 CRC 算法与仿真结果对比。2. 确保发送和接收模块使用完全相同的Crc子模块实例或参数。只能收发一次数据状态机未正确回到空闲 (IDLE) 状态。仿真中观察状态机信号看完成一帧收发后是否回到初始状态。检查状态机代码确保在所有分支包括错误处理的最后都能跳转回 IDLE 状态。9. 最佳实践与使用建议基于此项目可以延伸出许多最佳实践帮助你更好地进行硬件开发。参数化设计本项目中的波特率、数据位、CRC 多项式等都应设计为参数。这极大提高了代码的复用性。在 Chisel 中使用case class来封装所有参数是很好的做法。case class UartWithCrcParams( clockFreqHz: Int 100000000, baudRate: Int 115200, dataBits: Int 8, stopBits: Int 1, crcWidth: Int 16, crcPoly: String CRC-16-CCITT )完善的仿真测试在test目录下不仅要有基础功能测试还应增加边界测试、随机测试和错误注入测试。使用scalatest的Property-based testing可以自动生成大量随机测试向量。清晰的文档与注释在 Scala/Chisel 代码中使用 Scaladoc 风格为模块、IO 端口和关键函数添加注释。在README.md中写明项目概述、环境搭建步骤、参数配置方法和测试流程。版本控制与模块化将 UART 核心、CRC 核心和顶层集成模块分开甚至作为独立的库发布。这样其他项目可以轻松引用你的 UART 或 CRC 模块。上板前的充分仿真永远不要直接上板调试。确保仿真测试覆盖率足够高特别是对复位、异常情况如连续快速发送的测试。利用 FPGA 调试工具上板后如果出现问题可以使用 Vivado 的 ILA (Integrated Logic Analyzer) 或 Quartus 的 SignalTap 来抓取内部信号的真实波形这是最强大的调试手段。安全与鲁棒性考量对输入信号rx进行同步和消抖处理防止亚稳态。在状态机中增加超时机制防止因线路干扰卡死在某个状态。如果用于关键通信可以考虑使用更强大的校验算法如 CRC-32或增加重传机制。10. 总结与下一步这个“为 UART 增加 CRC 校验”的 Chisel 实战项目完整地展示了一个数字系统模块从设计、仿真到上板验证的全过程。它不仅仅是一个可用的串口 IP更是一个学习现代硬件设计方法的优秀模板。最值得尝试的点在于你亲手用高级语言Chisel/Scala描述了一个硬件电路并通过工具链将它变成了在 FPGA 上真实运行的逻辑。这个过程极大地抽象了硬件细节让你能更专注于算法和架构。最先应该验证的功能是环路测试Loopback。确保 FPGA 能自发自收一个简单的字符串这是整个通信链路正常工作的基石。然后再通过 PC 串口工具进行双向通信测试。最容易踩的坑通常是波特率不匹配和引脚分配错误。务必用示波器或逻辑分析仪确认 TX 引脚上的波形符合预期。另一个常见问题是 Chisel 生成代码中的复位极性需要与 FPGA 开发板上的实际复位按钮匹配。后续可以扩展的方向非常多性能提升将串行 CRC 计算改为并行计算以支持更高的 UART 波特率。功能增强增加硬件流控RTS/CTS、软件流控XON/XOFF、自动波特率检测、多字节 FIFO 缓冲等功能。协议栈集成将此模块作为底层物理层之上实现一个简单的 SLIP 或 HDLC 帧协议用于传输更长的数据包。系统集成将它作为一个外设集成到一个 RISC-V 软核处理器如 Rocket Chip 或 VexRiscv的 SoC 中实现通过串口进行命令交互和程序加载。形式化验证使用 Chisel 的配套工具如 ChiselVerify或专业的形式化验证工具对状态机进行更严格的正确性证明。建议将本项目的代码作为起点结合官方文档和社区资源逐步探索更复杂的硬件设计世界。掌握 Chisel 和这种从算法到硬件的完整流程将会是你硬件开发生涯中一项极具竞争力的技能。