SoC集成 — CPU+UART+RAM
CPU+UART+RAM系统集成
📖 片上系统集成
单个CPU核心不能独立工作——它需要内存、外设、总线、时钟复位。SoC(System-on-Chip)集成将这些组件连接在一起,形成一个完整的计算系统。本课实现一个最小的SoC:RV32I核心 + 4KB RAM + UART发送器。
最小RISC-V SoC结构:
┌─────────────────────────────────────────┐
│ SoC Top │
│ │
│ ┌──────────┐ Bus ┌──────────┐ │
│ │ RV32I │◄─────►│ 4KB RAM │ │
│ │ CPU Core │ │ (0x0000) │ │
│ │ │ └──────────┘ │
│ │ PC=0x0 │ │
│ │ Reg[32] │ Bus ┌──────────┐ │
│ │ ALU │◄─────►│ UART │──TX──► │
│ │ Decode │ │ (0x1000) │ │
│ └──────────┘ └──────────┘ │
│ │ │
│ clk/rst_n │
└─────────────────────────────────────────┘
地址映射:
0x0000 - 0x0FFF: RAM (4KB)
0x1000 - 0x1FFF: UART寄存器
启动流程:
1. reset → PC=0x0000 (从RAM开始执行)
2. 执行RAM中的程序
3. 通过ECALL触发UART发送
| 组件 | 功能 | 接口 |
| CPU Core | 取指/译码/执行 | 指令/数据总线 |
| RAM | 存储指令和数据 | 读写端口 |
| UART TX | 串口发送 | 数据+忙标志 |
| Bus | 地址解码和路由 | 主从接口 |
UART串口协议
UART是最简单的串行通信协议:1位起始位(0) + 8位数据 + 1位停止位(1),共10位。115200波特率下,每位持续约8.68μs。
真实SoC使用TileLink或AXI总线替代简单的地址解码。TileLink是RISC-V生态的首选总线协议,Rocket Chip和BOOM都使用TileLink。
🖥️ Verilog实现
// Lesson 29: Simple SoC — CPU + UART + RAM
module simple_soc #(parameter XLEN=32)(input wire clk, rst_n, output reg uart_tx, uart_busy);
reg [7:0] mem [0:4095]; reg [XLEN-1:0] pc; reg [31:0] reg_file [0:31]; reg [31:0] instr;
reg [7:0] tx_data; reg [3:0] tx_count; reg [15:0] tx_baud; reg tx_active;
always @(posedge clk or negedge rst_n) begin
if(!rst_n) begin pc<=0; uart_tx<=1; uart_busy<=0; tx_active<=0; tx_count<=0; tx_baud<=0; end
else begin instr={mem[pc+3],mem[pc+2],mem[pc+1],mem[pc]}; pc<=pc+4;
case(instr[6:0]) 7'b0010011:reg_file[instr[11:7]]<=reg_file[instr[19:15]]+{{20{instr[31]}},instr[31:20]};
7'b0110011:reg_file[instr[11:7]]<=reg_file[instr[19:15]]+reg_file[instr[24:20]];
7'b1110011:if(!tx_active) begin tx_data<=reg_file[10][7:0]; tx_active<=1; tx_count<=0;
tx_baud<=0; uart_busy<=1; uart_tx<=0; end default:; endcase
if(tx_active) begin tx_baud<=tx_baud+1;
if(tx_baud==434) begin tx_baud<=0;
if(tx_count<8) begin uart_tx<=tx_data[tx_count]; tx_count<=tx_count+1; end
else if(tx_count==8) begin uart_tx<=1; tx_count<=tx_count+1; end
else begin tx_active<=0; uart_busy<=0; end end end end end
endmodule
Verilator仿真验证通过 — SoC执行ADDI指令,PC正确推进
代码解析
- CPU Core:简化的RV32I核心,3阶段(取指/译码/执行合一)
- mem[0:4095]:4KB字节寻址RAM
- UART TX:移位寄存器 + 波特率计数器
- ECALL:触发UART发送x10(a0)的值
📊 真实RISC-V SoC对比
| SoC | CPU | 外设 | 总线 | 用途 |
| SiFive E310 | E31 (RV32I) | UART,SPI,PWM | TileLink | MCU |
| PULPissimo | RI5CY (RV32IMC) | UART,I2S,DMA | APB/AXI | IoT |
| OpenTitan | Ibex (RV32IMC) | UART,SPI,HMAC | TileLink | 安全 |
| 本课SoC | 简化RV32I | UART | 直接映射 | 教学 |
真实SoC的关键区别:总线协议(TileLink/AXI)、中断控制器(PLIC)、定时器(CLINT)、调试接口(JTAG/Debug Module)。本课省略了这些以聚焦核心概念。
🧪 实验练习
- 在当前实现基础上添加异常处理支持
- 实现流水线仿真,观察波形中的关键信号变化
- 添加性能计数器:统计吞吐量、延迟、利用率
- 与前几课的模块集成,构建更完整的系统
CPU+UART+RAM系统集成 — 从核心到系统的跨越
思考题:为什么真实SoC使用TileLink而不是直接地址映射?总线协议解决了什么问题?
参考资料:SiFive E310 Manual | TileLink Spec | PULP Platform | OpenTitan
📚 深入理解与实践建议
掌握本课内容需要结合理论学习和动手实践:
- 阅读源码:BOOM(Chisel)和Rocket(Chisel)是RISC-V处理器设计的最佳参考实现
- 修改实验:修改本课的Verilog代码,观察行为变化
- 波形仿真:使用GTKWave查看关键信号的时序关系
- 对比分析:将本课模块与前几课模块集成,测试端到端功能
开发环境
| 工具 | 用途 | 安装 |
| Verilator 5.020 | Verilog编译仿真 | sudo apt install verilator |
| iverilog | 轻量仿真 | sudo apt install iverilog |
| GTKWave | 波形查看 | sudo apt install gtkwave |
| RISC-V GCC | 交叉编译 | apt install gcc-riscv64-unknown-elf |
| QEMU | 系统仿真 | apt install qemu-system-misc |
📖 推荐阅读
- Computer Organization and Design: RISC-V Edition — Patterson & Hennessy — 数字设计的圣经
- RISC-V Reader — Waterman & Asanović — RISC-V ISA的精炼介绍
- Computer Architecture: A Quantitative Approach — Hennessy & Patterson — 高级架构设计
- 数字设计和计算机体系结构 — Harris & Harris — 硬件设计入门
在线资源
- RISC-V International: riscv.org — 官方规范和文档
- Rocket Chip: github.com/chipsalliance/rocket-chip — 开源RISC-V处理器
- Chipyard: chipyard.readthedocs.io — SoC设计框架
- OpenHW Group: openhwgroup.org — 开源硬件社区
🔧 开发工具链与实践环境
本课程推荐以下开发工具链:
| 工具 | 用途 | 安装命令 |
| Verilator | Verilog编译/仿真 | sudo apt install verilator |
| iverilog | 轻量Verilog仿真 | sudo apt install iverilog |
| GTKWave | 波形查看 | sudo apt install gtkwave |
| RISC-V GCC | 交叉编译 | apt install gcc-riscv64-unknown-elf |
| QEMU | 系统仿真 | apt install qemu-system-misc |
| Spike | ISA模拟器 | 从源码编译 |
快速验证
# 编译本课Verilog代码
cd verilog/
iverilog -o tb_test *.v
vvp tb_test
# Verilator lint检查
verilator --lint-only -Wno-BLKLOOPINIT *.v
# 应无Error输出
🎯 课程知识体系
RISC-V高级设计课程 (30课):
基础(L01-06): 特权架构→CSR→异常→中断→PLIC→CLINT
内存(L07-12): SV39 MMU→TLB→Cache系列
算术(L13-14): 乘法器→除法器
乱序(L15-19): OoO核心→ROB→寄存器重命名→记分牌→Tomasulo
预测(L20-21): 2位预测→BTB
扩展(L22-26): RVC→RVM→RVA→RVF→RVD
系统(L27-30): PMP→解码器→SoC→启动流程
每一课都是下一课的基础:
没有特权架构 → 无法理解CSR
没有CSR → 无法实现异常处理
没有异常处理 → 无法实现中断
没有中断 → 无法实现PLIC/CLINT
没有虚拟内存 → 无法运行Linux
没有Cache → 性能灾难
没有乱序执行 → ILP受限
没有分支预测 → 流水线气泡严重
🔬 实验扩展:进阶挑战
完成基础实验后,尝试以下进阶挑战:
- 性能优化:使用流水线技术减少关键路径延迟
- 面积优化:资源共享、操作数合并、时钟门控
- 功耗优化:添加时钟门控、操作数隔离
- 形式验证:使用Yosys formal验证功能正确性
- FPGA综合:在Xilinx/Intel FPGA上实现并测量时序
调试技巧
- 使用
$display打印关键状态变化
- 使用
$dumpfile/$dumpvars生成VCD波形
- 用GTKWave查看信号时序关系
- 对比Spike模拟器的参考输出
🎯 课程知识体系
RISC-V高级设计课程 (30课):
基础(L01-06): 特权架构→CSR→异常→中断→PLIC→CLINT
内存(L07-12): SV39 MMU→TLB→直接映射Cache→组相联→写回→分离Cache
算术(L13-14): Booth乘法器→恢复余数除法器
乱序(L15-19): OoO核心→ROB→寄存器重命名→记分牌→Tomasulo
预测(L20-21): 2位饱和计数器→BTB分支目标缓冲
扩展(L22-26): RVC压缩→RVM乘除→RVA原子→RVF单精度→RVD双精度
系统(L27-30): PMP保护→全解码器→SoC集成→启动流程
本课是第29课,在整体课程中承上启下。每一课都构建在前一课的基础上,建议按顺序学习。
📚 推荐阅读
- Computer Organization and Design: RISC-V Edition — Patterson & Hennessy
- RISC-V Reader — Waterman & Asanović
- Computer Architecture: A Quantitative Approach — Hennessy & Patterson
在线资源
- RISC-V International: riscv.org
- BOOM: github.com/riscv-boom/riscv-boom
- Chipyard: chipyard.readthedocs.io
- OpenHW Group: openhwgroup.org