年底太忙, 后面直播频率降低
上次课内容: 一个简单的SoC
本次课内容:
可将SRAM单元的行为抽象成一个锁存器(假设高电平有效)
DRAM存储单元 = 1根晶体管 + 1个电容
1
; 否则存储0
使用电容存储信息需要解决的问题
0
和1
之间的区别也很小, 很难直接检测1
就会变成0
读出放大器的本质 = 交叉配对反相器
0
或1
1
)电容中的电荷流向位线,
使其电压升高1
在激活状态下, 电容仍然与位线连通
为了解决电容的漏电问题, 需要添加负责定时刷新的电路逻辑, 对DRAM存储单元进行周期性的激活操作
0
; 太频繁,
会降低读写效率
定时刷新的电路逻辑放在哪里?
型号为IS66WVS4M8ALL的PSRAM(Pseudo-SRAM)颗粒
使用方式与SRAM很类似: 只需给出地址, 数据和读写命令, 即可访问颗粒中的数据, 无需关心存储阵列的物理组织结构
PSRAM通常提供两种接口, 可按需选择
基础SPI协议是全双工的 -
master和slave可同时分别通过MOSI
和MISO
发送消息
升级版2.0 - Dual SPI, 半双工的SPI
MOSI
和MISO
同时用于一个方向的传输SCK
时钟内可单向传输2 bitMOSI
/MISO
-> SIO0
(Serial
I/O 0)/SIO1
为了与基础SPI协议的传输方式区分, slave通常提供不同的命令
(命令传输位宽-地址传输位宽-数据传输位宽)
表示一种传输方式型号为W25Q128JV的flash颗粒提供多种读命令, 以读32位数据为例:
命令 | 协议 | 最大频率(MHz) | 三元组 | 命令周期 | 地址周期 | 读延迟 | 数据周期 | 总周期 | 总时间(us) |
---|---|---|---|---|---|---|---|---|---|
03h | 基础SPI | 50 | (1-1-1) | 8 | 24 | 0 | 32 | 64 | 1.28 |
0Bh | 基础SPI | 133 | (1-1-1) | 8 | 24 | 8 | 32 | 72 | 0.54 |
3Bh | Dual SPI | 133 | (1-1-2) | 8 | 24 | 8 | 16 | 56 | 0.42 |
BBh | Dual SPI | 133 | (1-2-2) | 8 | 12 | 4 | 16 | 40 | 0.30 |
无论地址和数据部分按多少位进行传输, 命令部分都按1 bit传输
升级版3.0 - Quad SPI, 简称QSPI,
新增SIO2
和SIO3
SCK
时钟内可单向传输4 bit
命令 | 协议 | 最大频率(MHz) | 三元组 | 命令周期 | 地址周期 | 读延迟 | 数据周期 | 总周期 | 总时间(us) |
---|---|---|---|---|---|---|---|---|---|
6Bh | QSPI | 133 | (1-1-4) | 8 | 24 | 8 | 8 | 48 | 0.36 |
EBh | QSPI | 133 | (1-4-4) | 8 | 6 | 6 | 8 | 28 | 0.21 |
升级版4.0 - QPI, 支持命令按4 bit传输, 即(4-4-4)
根据手册给PSRAM颗粒发送正确的指令序列
EBh
表示通过QSPI传输方式读数据以读32位数据为例:
命令 | 协议 | 最大频率(MHz) | 三元组 | 命令周期 | 地址周期 | 读延迟 | 数据周期 | 总周期 | 总时间(us) |
---|---|---|---|---|---|---|---|---|---|
03h | 基础SPI | 33 | (1-1-1) | 8 | 24 | 0 | 32 | 64 | 1.94 |
0Bh | 基础SPI | 104 | (1-1-1) | 8 | 24 | 8 | 32 | 72 | 0.69 |
EBh | QSPI | 104 | (1-4-4) | 8 | 6 | 6 | 8 | 28 | 0.27 |
命令 | 协议 | 最大频率(MHz) | 三元组 | 命令周期 | 地址周期 | 读延迟 | 数据周期 | 总周期 | 总时间(us) |
---|---|---|---|---|---|---|---|---|---|
03h | QSPI | 84 | (4-4-4) | 2 | 6 | 4 | 8 | 20 | 0.24 |
0Bh | QSPI | 84 | (4-4-4) | 2 | 6 | 4 | 8 | 20 | 0.24 |
EBh | QSPI | 104 | (4-4-4) | 2 | 6 | 6 | 8 | 22 | 0.21 |
ysyxSoC/perip/psram/efabless/EF_PSRAM_CTRL.v
上层软件不关心SPI的通信过程, 需要控制器提供SPI传输的功能抽象
ysyxSoC/perip/psram/efabless/EF_PSRAM_CTRL_wb.v
-
wishbone协议ysyxSoC/perip/psram/psram_top_apb.v
-
我们将它封装成APB协议a = *(int *)(PSRAM_BASE + 4)
lw a0, 4(a1)
araddr = 0x8000_0004
, …araddr
解析出PSRAM的地址4
4
作为PSRAM读命令的参数,
通过QSPI发送psram_cmd
psram_cmd
中解析出命令EBh
和地址0x4
,
向存储阵列发送激活命令0x4
译码成选择信号,
并驱动存储阵列的字线
wishbone.wb_dat_o
信号 -> APB.prdata
信号
-> AXI-Lite.rdata
信号 -> a0
寄存器 ->
a
变量型号为IS66WVS4M8ALL的PSRAM颗粒可以提供4MB的存储空间
但大程序的运行时间较长
分析: 数据段和堆区分配到PSRAM, 但取指仍然需要访问flash
结果: 从flash中取出1条指令, 前后需要花费约150个CPU时钟
如何优化?
既然PSRAM容量大, 而且支持(1-4-4)甚至(4-4-4)的传输方式, 为什么不将代码段也分配到PSRAM中呢?
PSRAM的本质是一种DRAM, 是易失性存储, 因此也需要从flash中加载
程序中的大部分代码都需要重复执行: 循环, 函数调用
由谁来加载 - 当然是bootloader了
若程序较大, bootloader加载程序的过程也会较长
类似地, 能否将 “bootloader加载程序”的代码先加载到访问效率更高的存储器中, 然后再执行 “bootloader加载程序”的功能?
二级bootloader = FSBL(first stage bootloader) + SSBL(second ~)
SSBL的代码很小, 可将其加载到SRAM中执行, 进一步提升执行效率
采用并行总线接口的主流DRAM颗粒 - SDRAM(Synchronous DRAM)
还有异步DRAM, 总线信号中没有时钟, 但目前基本上被SDRAM替代
型号为MT48LC16M16A2的SDR SDRAM颗粒有39根引脚
CLK
, CKE
- 时钟信号和时钟使能信号CS#
, WE#
, CAS#
,
#RAS
- 命令信号BA[1:0]
- 存储体地址A[12:0]
- 地址DQ[15:0]
- 数据
DQM[1:0]
- 数据掩码和PSRAM不同, SDRAM总线中包含存储体地址BA
SDRAM颗粒的存储阵列是一个多维结构
typedef bit word[16]; word MT48LC16M16A2[4][8192][512];
// 0 1 4 3 2
// sizeof(MT48LC16M16A2) = 4 * 8192 * 512 * 16 bit = 256Mb = 32MB
要访问一个存储字, 需要给出存储体地址(bank address), 行地址(row address)和列地址(column address)
不同版本的SDRAM标准, 颗粒的命令稍有不同, 要RTFM
CS# | RAS# | CAS# | WE# | 命令名称 | 命令含义 |
---|---|---|---|---|---|
1 | X | X | X | COMMAND INHIBIT | 无命令 |
0 | 1 | 1 | 1 | NO OPERATION | NOP |
0 | 0 | 1 | 1 | ACTIVE | 激活目标存储体的一行 |
0 | 1 | 0 | 1 | READ | 读出目标存储体的一列 |
0 | 1 | 0 | 0 | WRITE | 写入目标存储体的一列 |
0 | 1 | 1 | 0 | BURST TERMINATE | 停止当前的突发传输 |
0 | 0 | 1 | 0 | PRECHARGE | 关闭存储体的已激活行(预充电) |
0 | 0 | 0 | 1 | AUTO REFRESH | 刷新 |
0 | 0 | 0 | 0 | LOAD MODE REGISTER | 设置Mode寄存器 |
和PSRAM不同, 刷新作为命令提供给控制器
突发传输 = 一次事务(transaction)中包含多次连续的数据传输
从发出READ命令, 到通过DQ
总线返回数据,
存在一定的读延迟
假设CAS latency = 2, 读出连续的8字节
逻辑上需要\(\log_2(32\mathrm{MB} / 16\mathrm{b}) = 24\)根地址线, 但地址端口只有13位, 因此地址需要分时传输
上层软件不关心控制器和颗粒之间的通信过程, 需要控制器提供相应的功能抽象
ysyxSoC/perip/sdram/core_sdram_axi4/
sdram_axi_core.v
- RTFSC
ysyxSoC/perip/sdram/sdram_top_apb.v
-
我们将它封装成APB协议a = *(int *)(SDRAM_BASE + 4)
lw a0, 4(a1)
araddr = 0xa000_0004
, …araddr
解析出SDRAM的地址4
,
生成命令序列向SDRAM颗粒发送0x4
译码成选择信号
APB.prdata
信号 -> AXI-Lite.rdata
信号 ->
a0
寄存器 -> a
变量在电路中, 通常大 = 慢
如今的内存条动辄就4GB, 如何兼顾容量和速度?
如何扩展?
回顾: 存储器逻辑上是个二维矩阵 - 每行存储一个字, 行号 = 地址
两个维度的扩展:
SoC中集成多个内存控制器, 可独立工作, 分别连接一个通道的内存条
TX
和RX
两根导线
PS2_CLK
和PS2_DATA
两根导线
HS
,
垂直同步信号VS
, 有效信号VALID
之前介绍的设备控制器都位于SoC中, 需要占用一定的流片面积
一个想法: 将总线延伸到芯片外部
但这个方案需要考虑引脚的数量
araddr
, awaddr
,
rdata
和wdata
已经占用128个引脚
减少引脚数量 -> 对引脚进行分时复用(和SDRAM分时传输地址类似)
全双工, 单方向除了32个数据信号之外, 还有时钟, 复位和有效信号
可通过桥接实现AXI的片间传输
--------------------------------+ +--------------------------------
chip 1 | | chip 2
AXI <=> TileLink <=> ChipLink <---------> ChipLink <=> TileLink <=> AXI
| |
--------------------------------+ +--------------------------------
数据位宽减少到8位时, 只需要占用22个引脚
若对端芯片是个FPGA, 还能获得灵活的扩展能力