3. RTL代码结构解析:蜂鸟E203的“骨架”与“内脏”
好,咱们进入第三章。这一章我打算带你把蜂鸟E203的RTL代码翻个底朝天。说白了,就是搞清楚它的“骨架”怎么搭的,“内脏”怎么长的。很多初学者拿到代码就懵,不知道从哪看起。我当年也是这样,对着一个工程目录发呆半小时。
别急,咱们一步步来。先看目录结构,再拆核心模块,最后聊聊总线和存储。看完这章,你至少能闭着眼睛画出E203的顶层框图。
3.1 蜂鸟E203 RTL目录结构:别在文件海洋里迷路
打开E203的RTL目录,你会看到一堆文件夹。别慌,其实就几大类。我个人习惯先看顶层,再往下钻。
| 目录/文件 | 作用 | 我的备注 |
|---|---|---|
rtl/e203/core |
核心模块,CPU的大脑 | 最常改的地方,性能调优主战场 |
rtl/e203/soc |
系统级集成,总线、外设都在这里 | 加外设、改地址映射时来这 |
rtl/e203/mem |
存储子系统,ITCM/DTCM | 跑裸机程序时重点关注 |
rtl/e203/periphs |
外设模块,比如GPIO、UART | 驱动开发时用得着 |
rtl/e203/debug |
调试模块,JTAG相关 | 做调试器适配时才碰 |
你看,结构很清晰。核心、系统、存储、外设、调试,五大块。我建议你从e203_top.v开始看,它是整个芯片的顶层,把所有模块串起来。
grep -r "module" rtl/ 快速列出所有模块名,比翻文件夹快多了。
3.2 核心模块(Core)详解:CPU的“五脏六腑”
核心模块在rtl/e203/core下,这是E203的心脏。我拆开给你看。
3.2.1 流水线结构:两级流水,简单粗暴
E203用的是两级流水线:取指+执行。为什么这么设计?说白了就是为了低功耗、小面积。你想想看,高性能处理器动辄十几级流水,但E203的目标是IoT场景,够用就行。
- 取指阶段(IFU): 从ITCM取指令,做简单预解码。
- 执行阶段(EXU): 真正的干活阶段,解码、执行、访存、写回全在这。
我记得第一次看E203的代码时,觉得这流水线也太“寒酸”了。但后来在项目中跑实际负载才发现,两级流水避免了大部分控制冒险,编译器稍微优化一下,性能并不差。
3.2.2 关键子模块:IFU、EXU、 LSU
核心模块里,有三个子模块你必须要搞懂:
| 模块 | 全称 | 职责 | 避坑点 |
|---|---|---|---|
| IFU | Instruction Fetch Unit | 取指令、分支预测(静态) | 分支预测错误会浪费一个周期 |
| EXU | Execution Unit | 算术逻辑运算、跳转 | 乘法指令是迭代的,注意延迟 |
| LSU | Load Store Unit | 数据访存,处理DTCM访问 | 未对齐访问会触发异常 |
我曾经在调试一个死循环问题时,折腾了两天才发现是LSU的地址计算逻辑有个边界条件没处理好。嗯,从那以后我养成了一个习惯:先检查LSU的地址对齐。
3.3 系统总线与外设模块:怎么把东西连起来
E203用的是ICB总线(Internal Chip Bus),这是蜂鸟自研的简单总线协议。说白了,就是一套“主-从”握手规则。
3.3.1 ICB总线协议:简单到令人发指
ICB只有几个信号:
icb_cmd_valid/icb_cmd_ready:命令通道握手icb_rsp_valid/icb_rsp_ready:响应通道握手icb_cmd_addr/icb_cmd_read/icb_cmd_wdata:命令内容
你想想看,比起AXI那套复杂的通道和乱序支持,ICB简直就是一股清流。我建议你在做仿真时,先盯着这几个信号看,总线通不通一眼就能看出来。
3.3.2 外设模块:GPIO、UART怎么挂上去的
外设通过ICB总线挂在系统上。每个外设都有一个基地址,CPU通过load/store指令访问它们。
举个例子,GPIO模块的地址映射:
// 地址映射示例(简化版)
#define GPIO_BASE 0x10000000
#define GPIO_OUT (*(volatile uint32_t *)(GPIO_BASE + 0x00))
#define GPIO_IN (*(volatile uint32_t *)(GPIO_BASE + 0x04))
#define GPIO_DIR (*(volatile uint32_t *)(GPIO_BASE + 0x08))
写GPIO_OUT = 0xFF,就能让8个GPIO引脚同时输出高电平。简单吧?
volatile,否则编译器优化会把你坑惨。我曾经在调试UART时,数据死活发不出去,最后发现是编译器把写操作优化掉了。
3.4 存储子系统(ITCM/DTCM)设计:程序和数据放哪
E203没有传统的Cache,而是用了TCM(Tightly Coupled Memory)。说白了,就是直接把SRAM挂在CPU旁边,访问延迟固定,一个周期搞定。
3.4.1 ITCM:指令紧耦合存储器
ITCM存指令。E203默认大小是64KB,地址从0x80000000开始。为什么用这个地址?因为RISC-V规范里,这是默认的指令起始地址。
- 优点: 访问延迟确定,适合实时性要求高的场景。
- 缺点: 容量固定,不能像Cache那样动态利用。
3.4.2 DTCM:数据紧耦合存储器
DTCM存数据,默认也是64KB。地址从0x90000000开始。LSU模块直接访问DTCM,没有Cache的缓存一致性问题。
我遇到过一个问题:程序跑着跑着突然崩溃,查了半天发现是ITCM和DTCM的地址范围重叠了。嗯,这种低级错误,犯过一次就再也不会犯了。
3.4.3 存储子系统结构图
下面这张图,是我手绘风格的SVG,展示了E203的存储子系统结构:
从图上你能看到:Core直接连ITCM和DTCM,不走总线。外设则通过ICB总线挂载。这种设计的好处是,CPU访问指令和数据时没有总线竞争,性能有保障。
3.5 本章小结:你该记住什么
好,这一章的内容就这些。我带你看了目录结构、拆了核心模块、聊了总线、画了存储。你至少应该记住:
- E203的RTL分五大块:core、soc、mem、periphs、debug
- 核心模块是两级流水:IFU取指,EXU执行,LSU访存
- 总线是ICB协议,简单但够用
- 存储用ITCM/DTCM,没有Cache