4. SoC硬件平台概览

在RISC-V SoC系统软件开发中,软件工程师面对的不是一颗抽象的CPU,而是一个由总线互连、地址空间、中断网络和一组外设寄存器共同构成的硬件平台。理解这些硬件对象的组织方式,是编写启动代码、设备驱动和板级支持包的前提。本章从软件视角出发,梳理SoC硬件平台的核心模型。

一、总线架构:软件看到的数据通路

SoC内部通常采用分层总线结构。以典型的RISC-V SoC为例,CPU核心通过本地总线连接到总线矩阵,再由总线矩阵分发到片上SRAM、Flash控制器、DMA以及各类外设。软件并不直接“操作总线”,但总线架构决定了访问延迟、带宽和并发能力。

常见总线包括AXI、AHB、APB等。AXI用于高带宽主从设备,如DDR控制器和DMA;APB用于低速外设,如UART、GPIO、定时器。软件在访问不同外设时,会感受到明显的速度差异。例如,连续读写UART数据寄存器与连续读写片上SRAM,其吞吐量可能相差两个数量级。

在驱动开发中,若发现外设访问异常缓慢,应首先确认该外设挂载在哪条总线上,以及是否存在总线桥接带来的额外等待周期。

二、存储映射:地址即设备

RISC-V采用统一编址方式,外设寄存器被映射到物理地址空间中的固定区域。CPU通过load/store指令访问这些地址,就像访问内存一样。存储映射表是SoC硬件平台最重要的“地图”。

典型的存储映射如下表所示:

地址范围 区域 典型用途
0x0000_0000 - 0x0000_FFFF Boot ROM 上电启动代码
0x0200_0000 - 0x0200_FFFF CLINT 定时器与软件中断
0x0C00_0000 - 0x0C00_0FFF PLIC 平台级中断控制器
0x1000_0000 - 0x1000_0FFF UART0 串口控制台
0x1001_0000 - 0x1001_0FFF GPIO 通用输入输出
0x8000_0000 - 0x8FFF_FFFF DDR 主内存

软件通过宏定义或设备树描述这些地址。例如:

#define UART0_BASE      0x10000000UL
#define UART0_RBR       (UART0_BASE + 0x00)
#define UART0_THR       (UART0_BASE + 0x00)
#define UART0_LSR       (UART0_BASE + 0x05)

static inline void uart_putc(char c)
{
    while ((readb(UART0_LSR) & 0x20) == 0)
        ;
    writeb(c, UART0_THR);
}

三、中断控制器与定时器:事件驱动的基础

RISC-V的中断体系由CLINT和PLIC共同构成。CLINT负责软件中断和机器定时器中断,PLIC负责外部设备中断的汇聚与分发。软件通过配置PLIC的优先级、使能位和阈值,决定哪些外设中断可以送达CPU。

定时器通常分为两类:CLINT中的mtime/mtimecmp提供机器模式定时器;外设中的Timer模块可产生周期性中断。在裸机环境中,定时器中断常用于系统节拍;在Linux中,则通过时钟框架注册为clocksource和clockevent。

中断控制器配置错误是嵌入式开发中最常见的“系统无响应”原因之一。若外设中断已触发但CPU未进入中断服务程序,应依次检查PLIC使能位、优先级阈值、CPU中断全局使能以及mie/mstatus寄存器。

四、UART与GPIO:最基础的外设模型

UART和GPIO是SoC中最简单也最常用的外设。UART通常包含数据寄存器、状态寄存器和控制寄存器,软件通过轮询或中断方式收发数据。GPIO则通过方向寄存器和数据寄存器控制引脚电平,常用于LED、按键和片选信号。

以GPIO点灯为例,典型操作流程为:使能GPIO时钟、配置引脚为输出、写入电平值。在Linux中,这些操作被抽象为gpiod接口;在裸机中,则直接操作寄存器。

/* 裸机GPIO输出示例 */
#define GPIO_BASE   0x10010000UL
#define GPIO_DIR    (GPIO_BASE + 0x00)
#define GPIO_OUT    (GPIO_BASE + 0x04)

void gpio_led_on(void)
{
    writel(readl(GPIO_DIR) | (1 << 3), GPIO_DIR);
    writel(readl(GPIO_OUT) | (1 << 3), GPIO_OUT);
}

五、外设模型对比与选型思路

不同外设在软件模型上差异明显。下表从访问方式、中断能力和典型驱动框架三个维度进行对比:

外设 访问方式 中断能力 典型驱动框架
UART 寄存器读写 支持 tty/serial
GPIO 寄存器读写 部分支持 gpiolib
Timer 寄存器读写 支持 clocksource/clockevent
PLIC 寄存器读写 中断汇聚 irqchip
DMA 寄存器+描述符 支持 dmaengine

六、案例:从零搭建一个串口控制台

假设我们在一块RISC-V SoC上实现最小串口控制台。步骤如下:

  1. 根据存储映射表找到UART0基地址。
  2. 配置UART波特率、数据位和停止位。
  3. 实现putc和getc函数,分别写THR和读RBR。
  4. 在启动代码中初始化UART,并重定向printf。
  5. 若需中断接收,配置PLIC使能UART中断,并注册中断服务程序。

这一过程覆盖了存储映射、外设寄存器操作和中断控制三个核心知识点,是理解SoC硬件平台的最佳切入点。

七、常见误区与复盘

  • 误区一:认为所有外设访问速度相同。实际上APB外设与DDR的访问延迟差异巨大,驱动中应避免在中断上下文频繁访问慢速外设。
  • 误区二:忽略存储映射的地址对齐要求。部分外设寄存器要求32位对齐访问,使用8位访问可能导致总线错误。
  • 误区三:中断使能顺序错误。应先配置外设中断源,再配置PLIC,最后打开CPU全局中断。
  • 误区四:未处理中断清除。若中断服务程序未清除外设中断标志,会导致中断反复触发。
复盘建议:在Bring-up阶段,先用轮询方式验证UART和GPIO,再逐步引入中断和定时器。每验证一个外设,就更新存储映射表和中断分配表,形成可持续维护的板级文档。
RISC-V SoC 硬件平台软件视图 RISC-V Core RV32/RV64 + CSR 总线矩阵 / 互连 AXI · AHB · APB Bridge 存储子系统 DDR · SRAM · Flash CLINT mtime / mtimecmp 软件中断 · 定时器中断 PLIC 优先级 · 使能 · 阈值 外部中断汇聚分发 UART0 THR · RBR · LSR 串口控制台 GPIO DIR · OUT · IN LED · 按键 · 片选 Timer 周期中断 · 计数 系统节拍 DMA 描述符 · 通道 高带宽搬运 中断请求线 0x0200_0000 0x0C00_0000 0x1000_0000 0x1001_0000 总线连接 中断信号 计算/存储 低速外设 中断控制