3. RTL代码结构解析:Core、Mem、Periph三大模块划分

拿到一份RTL代码,很多人第一反应是直接打开顶层文件,然后被密密麻麻的连线吓退。我刚开始看蜂鸟E203的时候也是这样,后来发现一个窍门——先看目录结构,再看模块划分。说白了,代码的组织方式就是设计者的思维导图。

蜂鸟E203的RTL代码,核心就三个大模块:Core(处理器核心)、Mem(存储子系统)、Periph(外设)。这三个模块各司其职,互相配合。今天我就带你把这三大块拆开揉碎,看看里面到底藏着什么。

一句话总结:Core负责算,Mem负责存,Periph负责跟外界打交道。三者通过总线连在一起,构成了一个完整的SoC。

3.1 顶层目录结构

我们先看看蜂鸟E203的RTL目录长什么样。你打开e203_rtl目录,会看到下面这些子目录:

e203_rtl/
├── core/          # 处理器核心
├── mem/           # 存储子系统
├── periph/        # 外设模块
├── soc/           # 顶层SoC集成
├── debug/         # 调试模块
└── lib/           # 通用库文件

嗯,这里要注意,soc目录是顶层集成,它把core、mem、periph三个大模块粘在一起。debug目录放的是JTAG调试相关的逻辑,lib目录则是一些通用的寄存器文件、FIFO、同步器之类的库单元。

我个人习惯,拿到一个新项目的RTL,第一件事就是看soc目录下的顶层文件。它会告诉你整个芯片的骨架是什么样子的。

3.2 Core模块:处理器的“大脑”

Core模块是蜂鸟E203的心脏。它实现了RISC-V RV32IMAC指令集架构。你想想看,所有程序的执行、数据的计算、控制流的跳转,全在这里完成。

打开core目录,你会看到这些关键文件:

文件名 作用
e203_core.v Core顶层,实例化所有子模块
e203_ifu.v 指令取指单元(Instruction Fetch Unit)
e203_idu.v 指令译码单元(Instruction Decode Unit)
e203_exu.v 执行单元(Execution Unit),包含ALU、乘法器、除法器
e203_lsu.v 加载存储单元(Load Store Unit),处理内存访问
e203_csr.v 控制状态寄存器模块(CSR)

我在项目中遇到过一个问题:指令取指和数据访问冲突了,导致CPU卡死。后来查了半天,发现是IFU和LSU在争抢同一个内存端口。蜂鸟E203的设计里,IFU和LSU是分开的,各走各的路,这就避免了这种冲突。说白了,这就是经典的哈佛架构思想——指令和数据走不同的通道。

小技巧:如果你想快速了解Core的流水线结构,直接看e203_core.v里的模块实例化顺序。从上到下,就是指令从取指到写回的全流程。

3.3 Mem模块:存储子系统

Mem模块负责管理所有的存储资源。蜂鸟E203的存储架构很有意思,它把ITCM(指令紧耦合存储器)和DTCM(数据紧耦合存储器)直接挂在Core旁边,访问延迟极低。

关键文件一览:

文件名 作用
e203_mem.v 存储子系统顶层
e203_itcm.v 指令紧耦合存储器控制器
e203_dtcm.v 数据紧耦合存储器控制器
e203_biu.v 总线接口单元(Bus Interface Unit),连接系统总线

为什么要有ITCM和DTCM?你想想看,如果每次取指令都要走系统总线,那延迟得多大。蜂鸟E203把最常用的指令和数据放在TCM里,Core可以直接访问,不需要经过总线仲裁。我在做性能调优的时候,把关键代码段和数据段都放在TCM里,性能提升非常明显。

注意:TCM的大小是有限的。蜂鸟E203默认的ITCM是64KB,DTCM是64KB。如果你把程序塞得太大,超出TCM范围,就会触发总线访问,性能会急剧下降。我曾经踩过这个坑,一个循环体太大,放不进ITCM,结果跑起来慢了好几倍。

3.4 Periph模块:外设接口

Periph模块是处理器跟外部世界打交道的桥梁。蜂鸟E203的外设不算多,但够用。主要包括:

  • GPIO:通用输入输出,控制LED、按键之类的东西
  • UART:串口通信,调试和打印信息全靠它
  • SPI:连接Flash、传感器等SPI设备
  • Timer:定时器,用于计时和产生中断
  • PLIC:平台级中断控制器,管理所有外部中断

关键文件:

文件名 作用
e203_periph.v 外设模块顶层
e203_gpio.v GPIO控制器
e203_uart.v UART控制器
e203_spi.v SPI控制器
e203_timer.v 定时器
e203_plic.v 中断控制器

外设模块的设计有一个共同点:它们都通过内存映射的方式跟Core交互。也就是说,Core读写某个外设,就像读写内存一样简单。每个外设被分配了一段地址空间,Core往那个地址写数据,外设就能收到指令。

3.5 三大模块的互联关系

这三个模块不是孤立的,它们通过总线连在一起。蜂鸟E203使用了一种叫做ICB(Internal Chip Bus)的内部总线协议。ICB是蜂鸟E203自己定义的一套简单总线协议,说白了就是一套握手规则。

下面这张图展示了三大模块之间的连接关系:

蜂鸟E203三大模块互联架构图 蜂鸟E203三大模块互联架构 Core 处理器核心 IFU / IDU / EXU / LSU Mem 存储子系统 ITCM / DTCM / BIU Periph 外设模块 GPIO / UART / SPI / Timer ICB总线 ICB总线 关键说明 Core通过ICB总线访问Mem和Periph ITCM/DTCM直连Core,延迟最低;外设通过BIU桥接访问 数据流路径 指令流:Core → IFU → ITCM → 取指 数据流:Core → LSU → DTCM / BIU → 外设 中断流:外设 → PLIC → Core → 中断处理

从这张图可以看得很清楚:Core是中心,Mem和Periph是它的左右手。Core通过ICB总线访问Mem和Periph。但这里有个细节——ITCM和DTCM是直连Core的,不走总线仲裁。这意味着Core访问TCM的速度非常快,一个时钟周期就能完成。

而访问外设呢?Core需要先通过BIU(总线接口单元)桥接到系统总线,然后再访问外设。这个路径就长了,延迟也大了。所以,如果你对性能有要求,尽量把数据放在TCM里,而不是外设的寄存器里。

3.6 关键文件与目录作用总结

最后,我把所有关键目录和文件的作用整理成一个表格,方便你查阅:

目录/文件 作用 备注
core/ 处理器核心,包含IFU、IDU、EXU、LSU、CSR 性能调优的重点区域
mem/ 存储子系统,包含ITCM、DTCM、BIU TCM大小可配置
periph/ 外设模块,包含GPIO、UART、SPI、Timer、PLIC 根据需求裁剪
soc/ 顶层SoC集成,连接Core、Mem、Periph 从这里开始看代码
debug/ JTAG调试模块 调试时用到
lib/ 通用库单元,如寄存器、FIFO、同步器 可复用的基础模块

我的建议:刚开始接触蜂鸟E203的RTL代码,不要试图一口气看完所有文件。先看soc目录下的顶层文件,了解整体架构。然后看core目录下的e203_core.v,理解流水线结构。最后再深入到各个子模块。这样循序渐进,效率最高。

好了,这一章的内容就到这里。记住三大模块的划分和各自的作用,后面我们做配置和性能调优的时候,会反复用到这些知识。