内存域 (MemDomain) 实现
概述
内存域模块是 BuckyBall 框架中负责内存管理和数据传输的核心组件。该模块位于 framework/builtin/memdomain
路径下,实现了高性能的内存子系统,包括内存控制器、DMA 引擎、TLB 管理和地址转换等功能。
内存域在整个系统架构中扮演关键角色,为上层的处理器核心和加速器提供统一的内存访问接口,同时管理片上存储器(scratchpad、accumulator)和外部内存之间的数据流动。
二、文件结构
memdomain/
├── MemDomain.scala - 内存域顶层模块
├── MemController.scala - 内存控制器
├── MemLoader.scala - 内存加载器
├── MemStorer.scala - 内存存储器
├── DomainDecoder.scala - 域解码器
├── DISA.scala - 地址空间管理
├── dma/ - DMA 引擎实现
├── mem/ - 存储器管理
├── rs/ - 保留站实现
└── tlb/ - TLB 管理
三、核心组件
MemDomain - 内存域顶层模块
MemDomain 是内存域的顶层模块,负责:
- 集成所有内存子系统组件
- 提供统一的外部接口
- 管理 DMA 和 Ball 域的访问协调
主要接口:
class MemDomain extends Module {
val io = IO(new Bundle {
// 全局解码器输入
val gDecoderIn = Flipped(Decoupled(new PostGDCmd))
// Ball 域 SRAM 接口
val ballDomain = new Bundle {
val sramRead = Vec(sp_banks, new SramReadIO)
val sramWrite = Vec(sp_banks, new SramWriteIO)
val accRead = Vec(acc_banks, new SramReadIO)
val accWrite = Vec(acc_banks, new SramWriteIO)
}
// DMA 接口
val dma = new Bundle {
val read = new Bundle {
val req = Decoupled(new BBReadRequest)
val resp = Flipped(Decoupled(new BBReadResponse))
}
val write = new Bundle {
val req = Decoupled(new BBWriteRequest)
val resp = Flipped(Decoupled(new BBWriteResponse))
}
}
// TLB 接口
val tlb = Vec(2, Flipped(new BBTLBIO))
val ptw = Vec(2, new TLBPTWIO)
val tlbExp = Vec(2, new BBTLBExceptionIO)
})
}
MemController - 内存控制器
MemController 封装了 scratchpad 和 accumulator 的控制逻辑:
功能特性:
- 双端口设计: 同时支持 DMA 和 Ball 域访问
- 存储器抽象: 提供统一的存储器访问接口
- 资源管理: 管理 scratchpad 和 accumulator 资源
接口设计:
class MemController extends Module {
val io = IO(new Bundle {
// DMA 接口 - 用于 MemLoader 和 MemStorer
val dma = new Bundle {
val sramRead = Vec(sp_banks, new SramReadIO)
val sramWrite = Vec(sp_banks, new SramWriteIO)
val accRead = Vec(acc_banks, new SramReadIO)
val accWrite = Vec(acc_banks, new SramWriteIO)
}
// Ball 域接口 - 用于 BallController
val ballDomain = new Bundle {
val sramRead = Vec(sp_banks, new SramReadIO)
val sramWrite = Vec(sp_banks, new SramWriteIO)
val accRead = Vec(acc_banks, new SramReadIO)
val accWrite = Vec(acc_banks, new SramWriteIO)
}
})
}
存储器架构
Scratchpad 存储器:
- 用途: 存储输入数据和中间结果
- 配置:
b.sp_banks
个 bank,每个b.spad_bank_entries
条目 - 位宽:
b.spad_w
位数据位宽 - 访问模式: 支持随机访问和顺序访问
Accumulator 存储器:
- 用途: 存储累加结果和最终输出
- 配置:
b.acc_banks
个 bank,每个b.acc_bank_entries
条目 - 位宽:
b.acc_w
位数据位宽 - 访问模式: 主要用于累加操作
四、数据流架构
访问路径
外部内存 ←→ DMA引擎 ←→ MemController ←→ Scratchpad/Accumulator
↕
Ball域加速器
双端口访问机制
MemController 实现了双端口访问机制:
- DMA 端口: 用于与外部内存的数据传输
- Ball 域端口: 用于加速器的计算访问
// 连接示例
io.dma.sramRead <> spad.io.dma.sramread
io.ballDomain.sramRead <> spad.io.exec.sramread
五、子模块说明
dma/ - DMA 引擎
实现高性能的直接内存访问:
- BBStreamReader: 流式数据读取器
- BBStreamWriter: 流式数据写入器
- 地址转换: 集成 TLB 支持虚拟地址
mem/ - 存储器管理
包含存储器的具体实现:
- Scratchpad: 片上暂存器实现
- SRAM接口: 标准化的存储器访问接口
- Bank管理: 多 bank 并行访问支持
tlb/ - TLB 管理
提供虚拟地址转换服务:
- BBTLBCluster: TLB 集群管理器
- 地址转换: 虚拟到物理地址映射
- 异常处理: TLB 缺失和权限异常
rs/ - 保留站
内存域专用的保留站实现:
- 指令调度: 内存访问指令的调度
- 依赖管理: 内存访问依赖关系管理
六、配置参数
关键配置项
class CustomBuckyBallConfig {
val sp_banks = 4 // Scratchpad bank 数量
val spad_bank_entries = 1024 // 每个 bank 的条目数
val spad_w = 64 // Scratchpad 数据位宽
val spad_mask_len = 8 // 掩码长度
val acc_banks = 2 // Accumulator bank 数量
val acc_bank_entries = 512 // 每个 bank 的条目数
val acc_w = 64 // Accumulator 数据位宽
val acc_mask_len = 8 // 掩码长度
}
性能调优
- Bank 数量: 影响并行访问能力
- 条目数量: 影响存储容量
- 数据位宽: 影响传输带宽
- TLB 大小: 影响地址转换性能
七、使用示例
基本配置
// 实例化内存域
implicit val config = new CustomBuckyBallConfig
val memDomain = Module(new MemDomain)
// 连接全局解码器
memDomain.io.gDecoderIn <> globalDecoder.io.memDomainOut
// 连接 Ball 域
ballController.io.sramRead <> memDomain.io.ballDomain.sramRead
ballController.io.sramWrite <> memDomain.io.ballDomain.sramWrite
DMA 操作
// 配置 DMA 读取
memDomain.io.dma.read.req.valid := true.B
memDomain.io.dma.read.req.bits.addr := sourceAddress
memDomain.io.dma.read.req.bits.len := transferLength
// 处理 DMA 响应
when(memDomain.io.dma.read.resp.valid) {
// 处理读取的数据
val data = memDomain.io.dma.read.resp.bits.data
}
八、性能特性
并发访问
- 双端口设计: DMA 和 Ball 域可并发访问
- 多 Bank 并行: 支持多个 bank 的并行操作
- 流水线处理: 实现深度流水线提高吞吐量
带宽优化
- 智能调度: 优化内存访问调度
- 缓存策略: 实现数据缓存和预取
- 带宽管理: 动态分配访问带宽
九、调试和监控
状态监控
- 访问统计: 监控各个 bank 的访问频率
- 带宽利用率: 监控实际带宽使用情况
- TLB 命中率: 监控地址转换性能
性能分析
- 延迟统计: 测量内存访问延迟
- 吞吐量监控: 监控数据传输吞吐量
- 冲突检测: 检测访问冲突和瓶颈