SPD5详解

2023-05-16

SPD介绍

SPD(serial presence detect),即串行存在检测,是DIMM的相关描述信息。

在每根内存条上,都有一份SPD数据,这份数据保存在一个可擦写的eeprom芯片中。SPD数据记录了该内存的许多重要信息,诸如内存的芯片及模组厂商、工作频率、工作电压、速度、容量、电压与行、列地址带宽等参数。SPD数据一般都是在出厂前,由DIMM制造商根据内存芯片的实际性能写入到eeprom芯片中。

SPD 中的数据主要是供 BIOS 在引导阶段给初始化内存时使用的,如果数据有误或者没有数据将导致内存初始化失败。随着技术发展尤其是 CXL 技术的发展,出现了多种支持 DDR 扩展的外设,这种情况下 SPD 还可能被外设的 fw 读取来进行初始化内存。

注:如无特别说明,本文档基于 SPD5 进行说明。

EEPROM 数据

不同类型的DDR,他们的SPD数据长度和格式可能会不一样,比如:

  • DDR2、DDR3的DIMM,对应的SPD数据长度为256B;
  • DDR4的DIMM,对应的SPD数据长度为512B;
  • DDR5的DIMM,对应的SPD数据长度为1024B。

但是,在这些不同长度的SPD数据中,有一些字段偏移可能是不兼容的。对于一些很基础的信息,他们的格式是一致的,比如DDR4与DDR3中,第0-5字节,他们表示的含义是相同的,其他则可能就不同。
下图是 DDR5 中 SPD 的数据布局:

 其中 annexes N.1.x 表示不同类型的内存设备会有不同的格式,具体参考这些章节。

  • Annex A.1: Solder down memory applications
  • Annex A.2: UDIMMs
  • Annex A.3: RDIMM
  • Annex A.4: LRDIMM
  • Annex A.5: DDIMM
  • Annex A.6: NVDIMM-N
  • Annex A.7: NVDIMM-P

DDR5 可以划分为多个 block:

  • Blocks 0~1: Base Configuration and DRAM Parameters
  • Block 2: Reserved for future use
  • Blocks 3~6: Module Specific Parameters
  • Block 7: Reserved for future use
  • Blocks 8~9: Manufacturing Information
  • Blocks 10~15: End User Programmable

共 16 个 bolck, 每个 block 包含64bytes,是一个写保护单元。即在 DDR5 的 SPD 中,写保护是按照 block 来进行的。

DDR5 SPD Revision

DDR5 SPD Revision 按照 section 划分,每个 section 都有自己的 revision bytes。

 需要注意的是,revision 分成两个部分 x.y,两个部分的数值都是只增不减,如果高位增加,低位也不会降低。比如版本从 1.2 升到 1.3,下一版升高版本时应该是 3.3。

即使在编码级别增加之后,添加级别也不会降低。例如,如果当前 SPD 修订级别为 1.2,并且编码级别的更改获得批准,则下一个修订级别将是 2.2。如果对修订 2.2 的补充获得批准,下一个修订将是 2.3。然而,编码级别的更改极为罕见,因为它们会导致与旧系统不兼容。

数据格式

这里只显示几个常用的字节的数据格式,所有的数据请查看《JESD400-5_DDR5 Serial Presence Detect(SPD) Contents_Rev 0.89》

Byte 0 (0x000): Number of Bytes in SPD Device
这个字节表示 SPD 的数据长度。

Byte 1 (0x001): SPD Revision for Base Configuration Parameters
这个字节表示 SPD 中 EEPROM 匹配的版本,分为 Encoding Level (高半字节) 和 Additions Level (低半字节)两个部分。其中 Encoding Level 表示发行版本,软件需要读取这部分内容以确定其合法性以及准确性。Additions Level 是可选的,定义了哪些附加字节或属性位。

Byte 2 (0x002): Key Byte / Host Bus Command Protocol Type
这个 byte 表示DDR 的版本和类别等信息,BIOS 会根据这个 byte 的值来确定如何解析整个 EEPROM 的内容。
同时这个 byte 也决定了后面的 block 3-6 里面包含的内容。

Byte 3 (0x003): Key Byte / Module Type
这个 byte 表示了 SPD 对应的内存的类型,分为3段表示,bit[3:0]表示 SDRAM 类型,bit[6:4] 表示内存设备类型, bit[7]区分有无混合类型。
所谓混合类型是指该内存设备除 SDRAM 外还有其他模块用于数据存储。

 其他 EEPROM 内容参见: JESD400-5 DDR5 Serial Presence Detect (SPD) Contents

SPD 寄存器

前面描述的 1KB 内容是 EEPROM 的数据,这些数据保存了关于 SDRAM 和 DDR 的配置和性能信息等。对于 SPD 和 EEPROM 本身,还有128个寄存器(每个寄存器 8bits) "MR0 - MR127" 来进行描述和配置。

Register Map

  •  ROE : Read Only and Persistent
  • RV : Reserved
  • RW : Read and Write
  • RWE : Read Write and Persistent
  • RO : Read Only
  • 1O : Write 1 Only

Register Description

这里只记录部分用到过的寄存器的内容。

MR0 - Device Type; Most Significant Byte

MR1 - Device Type; Least Significant Byte

MR11 - I2C Legacy Mode Device Configuration

这个寄存器设置了 SPD 作为 I2C Slave 时使用的地址模式,1Byte地址或者2Byte地址。使用 1Byte 地址模式时,I2C 的数据包中地址仅占 7bits,只能访问到 128 bytes 范围内的内容,而 EEPROM 占 1KB,所以后面要使用 page 来进行页面选择。使用 2 Bytes 地址模式时,I2C 数据包地址占两个 Bytes,可以直接访问所有的偏移,不需要使用 page。

Note1:Once any register bit is set to ‘1’, it can only be cleared when the SPD5 Hub device is in offline tester mode of operation.

Note2:The write (or update) transaction to this register must be followed by STOP operation to allow SPD5 Hub device to update the setting.

其他寄存器内容参见:JESD300-5 SPD5118, SPD5108 Hub and Serial Presence Detect Device Standard

I2C 访问 SPD

访问 SPD 指的是访问 SPD 内的寄存器或者 EEPROM。前面的内容提到,SPD5 有128个配置寄存器,一个 1KB 大小的 EEPROM,这两者空间的偏移都是从 0x00 开始(寄存器:0x00 - 0x7F,EEPROM:0x000 - 0x3FF)。但是这两个空间又同时不在系统的 MMIO 空间中,要使用 I2C/I3C 协议来对它们进行访问,此时如何区分这两个空间就很关键了。

SPD5 Slave Address

系统软件对 SPD 的访问一般是通过 I2C/I3C 协议来进行的,SPD 作为 Slave device MIPI 分配有固定的 address。SPD 的 7-bit Address 中高 4 位固定为 ‘a’,低 3 位根据 Hub 的不同有不同的值。其地址分配如下:

 

I2C Slave Protocol - Host to SPD5 Hub Device

前面提到的 EEPROM 和 SPD Registers 都属于 SPD5 Hub Device 本身的内容,所以它们使用的 Slave Address 就是 0xaX。后面我们我们还将看到 PMIC 和 RCD 等内容则属于 SPD5 Hub Local Device,此时可以将 SPD5 理解为一个 Hub,其下还可以挂接不同的 PMIC 和 RCD 等作为下游设备挂接到 SPD5 Hub 下,理所当然地它们拥有不同的 Slave Address。

I2C 访问 SPD5 Hub Device 和 访问 SPD5 Hub Local Device 使用的协议包格式是不一样的,这里主要讲前者。

前面讲 MR11 寄存器时有提到,SPD5 支持两种地址模式,默认情况下采用的是 2bytes 模式.如果主动修改,也是可以使用 1byte 模式的,但只能应用于 SPD5 Hub Device,不能应用于 PMIC 和 RCD 等。所以 I2C 协议的数据包也会有两种格式。

SPD 寄存器和 EEPROM 的偏移都是从 0 开始的,所以数据包中定义了一个 MemReg bit 来表示访问的是哪一个区域。

注:SPD4 或之前只有 1byte 模式一种。

Write Operation - Data Packet

MemReg = 0 : 访问 SPD 寄存器,此时 Blk Addr 被当作高位地址
MemReg = 1 : 访问 EEPROM

1byte mode write

 这是 1bytes 模式下,Host 写操作的数据包,只取 Address 的低 6 位,Blk Addr[0] 表示取 page 的低 128bytes 还是高 128bytes。由于最多只能访问 256 bytes,要访问其他 EEPROM 位置需要首先向 MR11[2:0] 写入对应的 page 值。

注:这里的 Blk Addr[0] 和 Address[5:0] 可以看作一个 Address[6:0],这样就避免了分两个位置的麻烦。

其流程如下,注意 Start/Ack/Stop 等信号由硬件发出,不需要程序员参与:

  1. Host 发送 Start 信号 + Slave Addr;
  2. SPD 回 Ack;
  3. Host 发送要写入的地址: [MemReg, Blk Addr[0], Address[5:0]]
  4. SPD 回 Ack;
  5. Host 发送要写入的数据 1byte;
  6. SPD 回 Ack;
  7. 如果写多个数据,重复步骤5和6,此时数据会依次写入 Address 后面的地址;
  8. Host 发送 Stop,结束通信。

2bytes mode write

 可以看到,Address被划分到两个字节中,其中[6:0]与 MemReg 组成第一个字节,剩下的[10:7]保存在第二个字节内。对于 SPD5,2bytes 模式下会将地址限制在 1KB 以内(即0x0 - 0x3FF,地址占 10bits),所以这里的 Blk Addr[4] 的值是无效的。

流程如下:

  1. Host 发送 Start 信号 + Slave Addr;
  2. SPD 回 Ack;
  3. Host 发送地址第一个字节 [MemReg + Address[6:0]];
  4. SPD 回 Ack;
  5. Host 发生地址第二个字节 [Address[10:7]];
  6. SPD 回 Ack;
  7. Host 发送要写入的数据 1byte;
  8. SPD 回 Ack;
  9. 如果写多个数据,重复步骤5和6,此时数据会依次写入 Address 后面的地址;
  10. Host 发送 Stop,结束通信。

Read Operation - Data Packet

使用 I2C 进行读操作时,先写入读取地址,再发起第二次通信进行数据读取。读数据时根据协议要求,第一字节 bit0 应该置1,但这是硬件会去完成的操作,对于软件,我们在写入第一个包后,只需从 I2C 数据寄存器中读取内容即可。

除了第一个消息中不包含要写入的数据,以及写完之后多一个读数据寄存器的步骤,读的操作与写操作基本一致,也通过 MemReg bit来表示读取 EEPROM 或 内部寄存器。

1byte mode read

 我们只要关注前面 W=0 的部分即可。

2bytes mode read

Default Read Address Pointer Mode
除了上述两种读模式之外, SPD5 还提供了一个叫做“默认读”模式,主要是为了提高从同一地址读取关键数据的效率。在这种模式下,只要发送 Slave ID + 读取命令,不需要写入地址即可从某一地址连续读取数据。该地址在 I2C 初始化时即被写入到寄存器 MR18 中,且只能读取寄存器区域的内容。

 相比于 2bytes mode,这种模式可以节省2个字节的包长度。

BIOS 对 SPD 的处理

SPD 的数据按照 section 划分,每个 section 末尾会有两个字节的 CRC 校验值,表示该 section 的数据是否合法。如下图所示:

 BIOS 在处理 SPD 时会按照以下步骤:

step1. 分析 SPD 数据合法性 : 按照图示,读取每一个 section 的 CRC 校验值,如果校验通过表示 SPD 合法。

step2. 判断 DDR type 是否正确 : 通过读取 byte2 来判断当前 DIMM 是否是目标类型。比如 byte2 = 0x12 表示 DDR5。

step3. 验证 SPD 兼容性 : SPD byte1 表示 SPD 的版本信息,当系统比较旧或者发生严重的错误时,强制要求系统停止初始化内存。SPD 版本的增加可能会影响到内部有效数据的长度,但是出于向后兼容的考虑,新的版本的内容通常能覆盖旧的版本。如果 BIOS 仅支持到 SPD 1.2,那么对于1.3 或以上版本的 SPD,BIOS 只能从中提取 1.2 版本定义的信息。

注:在 DDR5 SPD 中 SPD revision 只表示本段的版本,比如 byte1 表示 byte0-127的版本,其他的 section 都有自己单独 revison byte。这样可以使得各个 section 单独更新而不影响其他 section。

step4. 确定内存模块类型 : 这里的模块类型是指 RDIMM, UDIMM 等,由 byte3 表示。

Module Type

Byte 3

Solder Down

0x0B

UDIMM

0x02

SO-DIMM

0x03

RDIMM

0x01

LRDIMM

0x04

DDIMM

0x07

NVDIMM-N Hybrid

0x9x

NVDIMM-P Hybrid

0xAx

 step5. 确定内存基本配置 : 分析 byte0-127, 所有的模块类型都需要分析这部分内容。

step6. 配置标准的内存模块接口 : 分析 byte192 - 447。

参考资料

一步一步带你理解DDR基本原理_百里杨的博客-CSDN博客_ddr层次

JESD400-5 DDR5 Serial Presence Detect (SPD) Contents

JESD300-5 SPD5118, SPD5108 Hub and Serial Presence Detect Device Standard

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

SPD5详解 的相关文章

  • 程序员的5个级别,你属于哪一个等级?

    码农和程序员虽说是调侃 xff0c 但是实质上还真的是不一样 还别说 xff0c 程序员还是有分等级的 比如有技术专家 xff0c 初级专员等 程序员的级别不同 xff0c 薪水也是有着天壤之别 免费领取Python学习资料可以加小编的微信
  • FutureTask的使用示例

    今天看书 xff0c 有关于 FutureTask 的介绍 xff0c 感觉还蛮有意思的 xff0c 可以用它来做一些比较花时间的事情 下面打个通俗的比方来说明一下它的用处 xff1a 比如 xff0c 早上一大早的去公交站台等公交 xff
  • 用脚本创建快捷方式

    64 echo off set shortCutPath 61 C Documents and Settings administrator 桌面 set shortCutName 61 报表 set StartPath 61 起始位置 s
  • activemq配置wss协议

    wss是加密协议 xff0c 必须配置https证书 span class token operator lt span sslContext span class token operator gt span span class tok
  • MATLAB 初学者 课堂笔记

    1 预定义变量 xff1a pi i j inf xff1a 无穷大 eps a xff1a a 与大于 a 的最小的浮点数之间的距离 xff0c 距离越小表示精度越高 默认a 61 1 2 矩阵运算 xff1a 左除 C 61 A B 6
  • 备赛笔记:Opencv学习:颜色识别

    OpenCV颜色识别一般要以下步骤 xff1a 1 颜色空间转换 xff0c 将BGR转换为HSV xff0c 用色调区分颜色 2 按照阈值滤出所识别的颜色 3 消除噪点 xff0c 平滑边界 3 提取连续域 xff0c 提取要识别的颜色
  • 树莓派buster安装ROS完整记录

    我敢说这一教程全网找不到相同的 我今天在安装ROS时查了各方教程 xff1a 官方Wiki xff0c Google xff0c CSDN都各查了不下10篇 xff0c 终于综合各教程内容花了大半天下好了 使用硬件及软件 xff1a 树莓派
  • Linux操作系统原理与应用06:系统调用

    目录 1 Linux中的各种接口 1 1 LSB标准 1 2 Linux API 1 2 1 概述 1 2 2 Linux内核系统调用接口 1 2 3 C标准库 1 3 Linux ABI 1 4 内核API 1 5 系统调用与各种接口的关
  • 将csdn博客转换成makedown形式的文件并保存

    span class token comment 作者 Rain span span class token keyword import span re span class token keyword import span parse
  • VIBE:3D人体姿态预测项目复现笔记

    VIBE是一个的3D人体姿态预测开源项目 xff0c 需要基于该项目作一些开发 xff0c 首先需要能够搭建和是的环境成功复现它 不过 xff0c 这个项目的复现的 xff0c 真的不是一星半点的艰难 1 系统选择 之前一直用的Window
  • geometry_msgs设计的几个消息类型,定义的数据类型详解

    Point 点 float64 x xff0c float64 y xff0c float64 z Point32 float32 x xff0c float32 y xff0c float32 z 一般使用Point xff0c 大规模点
  • 分享个好用的开源录屏工具 Captura

    百度 或 点击 Captura 8 0 Download 进入官网下载 安装后是 如果折起来是这样 xff1a 红色框框那个是折叠按钮 红色圆形按钮是 开始录制 结束录制 和其他的录制按钮样式 xff0c 都差不多 xff0c 自行探索吧
  • 使用 aptitude解决ubuntu下apt-get install g++依赖问题

    问题描述 xff1a ubuntu下运行C 43 43 程序 xff0c 给出了如下错误提示 程序 g 43 43 尚未安装 使用以下命令安装 xff1a sudo apt get install g 43 43 执行 得出如下错误 正在读
  • 学习笔记-Raspberry Pi Zero W-4:串口(UART)的配置和使用

    4 1 开启UART 据官方所言 xff08 https www raspberrypi org documentation configuration uart md xff09 xff1a 树莓派CPU内部有两个串口 xff0c 一个P
  • CAAnimation——基本动画,关键帧动画和贝塞尔路径

    概述 在做对于图层的动画效果时 xff0c 往往直接改变属性或者使用隐式动画是不能满足我们的需求的 xff0c 所以我们就用到了显式动画 xff0c CAAnimation 它可以管理重复动画 准确的控制时间和步调 xff0c 并且能设定图
  • IOS详解TableView——性能优化及手工绘制UITableViewCell

    提高表视图的性能 UITableView作为应用中最常用的视图 xff0c 它的性能优化问题几乎是经常提及 下面对在非网络访问情况下的表视图性能优化进行了主要的几点说明 xff1a 1 自定义类或XIB文件时 在系统提供的样式不能满足我们的
  • IOS详解TableView——实现九宫格效果

    根据需求九宫格的效果可以有很多种 九宫格效果应用比较广泛 xff0c 实现也多种多样 xff0c 比如选项抽屉效果 这里写了一个在UITableView上显示九宫格效果的Demo 思路 xff1a 在Cell上初始化自定义按钮 xff0c
  • IOS详解TableView——内置刷新,EGO,以及搜索显示控制器

    这几天因为住的地方的网出了一点问题 xff0c 除了能上Q xff0c 上微博以外其他的网页全都无法登陆 博客也就没有跟进 今天恢复了 xff0c 所以继续更新博客 也希望大家能继续评论或私自给我一些建议或者交流 今天找到了以前一个Tabl
  • Linux设备驱动基础01:Linux设备驱动概述

    目录 1 设备驱动的作用 2 有无操作系统时的设备驱动 2 1 无操作系统 2 1 1 硬件 驱动和应用程序的关系 2 1 2 单任务软件典型架构 2 2 有操作系统 2 2 1 硬件 驱动 操作系统和应用软件的关系 3 Linux设备分类

随机推荐

  • IOS回调机制——代理,通知中心以及Block

    Xcode5 0正式版 IOS7和Xcode5正式版在昨天正式可以下载 IOS7不多说了 xff0c 交互设计 xff0c 界面风格 xff0c 操作的简化程度都属于比较领先的水平 这里来说说Xcode5正式版 xff0c 和以前的Xcod
  • IOS飞机大战OC版

    前一阵子看到了很多版本的打飞机游戏 xff0c 有Java版的C 43 43 版本的还有C语言版的 这几天闲着的时候写了一个OC版的 xff0c 也正好是因为答应朋友写这个游戏来把飞机都换成他照片 没有用Cocos2d框架 xff0c 用的
  • Swift的可选链,类型转换和扩展

    可选链 Optional Chaining 可选链是一种请求或调用属性 xff0c 方法 xff0c 子脚本的过程 可选性体现于请求或调用的目标当前可能为nil 若不为nil则成功调用 xff0c 否则返回nil并将链失效 调用可选链的返回
  • iOS小米遥控器的手势监听及UI实现

    这篇文章通过实例实现了一个类似小米手势遥控器的功能页面 效果图如下所示 xff1a 触摸事件的响应通过对系统的触摸实践监听来进行 通过一个数组来对点的集合进行缓存和分析 void touchesBegan NSSet touches wit
  • 博客搬家至Github

    为了使用Markdown写作更方便一些 xff0c 以后将使用github pages来管理博客 地址 xff1a Rannie s Page 欢迎来访
  • C++使用http向服务器发送json数据

    span class token macro property span class token directive hash span span class token directive keyword include span spa
  • 如何使用Git将Github项目拉到本地

    如何使用Git将Github项目拉到本地 前言 因为国内访问GIthub速度比较慢 xff0c 复制粘贴代码又慢效率也低 xff0c 所以建议下载Git工具 xff0c 直接把Github的项目整个下载到本地的文件夹 安装配置git 步骤如
  • 笔记本 - 数据分析百宝箱

    Numpy 一 基本操作 xff1a 属性 xff1a improt numpy as np 生成数组 xff1a array 61 np array 1 2 3 2 3 4 xff0c dtype 61 np int float arra
  • Faiss(5):IndexIVFPQ原理

    说明 原本想尝试自己从头写 xff0c 但看了下网上的各位前辈的博客后 xff0c 感觉自己还是才疏学浅 xff0c 没有理解透彻 xff0c 所以在这里做个搬运工 xff0c 偶尔加些个人的理解在里面 原文链接 xff1a https b
  • cmake(3):编译库和链接可执行文件

    1 说明 在实际开发的过程当中 xff0c 我们会经常需要将部分程序编译成静态或动态库的形式 xff0c 供其他应用程序调用而不是将所有文件一次编译为一个可执行文件 这篇笔记就记录使用cmake编译动态和静态库以及将库链接到可执行文件中的过
  • RTOS原理与实现02:基本任务切换实现

    目录 1 任务定义与切换原理 1 1 任务是什么 1 1 1 任务的外观 1 1 2 任务的内在 1 2 任务切换原理 1 2 1 任务切换的本质 1 2 2 要保存哪些任务运行状态 1 2 3 任务运行状态保存方案 1 3 设计实现 1
  • cmake(5):选择编译器及设置编译器选项

    1 说明 在实际的项目平台中可能安装有多个版本的编译器 xff0c 同时由于不同的功能可能会需要设置不同的编译参数 xff0c 这篇笔记就记录如何选择指定的编译器和配置参数 2 选择编译器 2 1 初始状态 我使用的开发平台默认安装的gcc
  • Faiss(14):IndexIVFPQ的CPU search过程分析

    1 说明 之前分析过了faiss 在GPU中的search过程 xff0c 这里分析一下IndexIVFPQ在CPU中的search过程 xff0c 即不将index拷贝到GPU中 2 过程分析 2 1 python接口 CPU searc
  • cmake(8):install命令详解

    1 说明 之前的示例中有提到使用cmake的install命令来自动安装库和头文件 xff0c 但是只是使用到了install命令很基础很少的部分 xff0c 其实该命令作用十分丰富 xff0c 本篇文档用于说明该命令的详细使用方法 2 i
  • cmake(9):包含指定目录的头文件

    1 说明 在编译程序时 xff0c 如果需要用到外部的头文件 xff0c 而该头文件又没有被添加到系统默认的路径中 xff08 如 xff1a usr include xff0c usr local include和 usr lib gcc
  • cmake(10):使用cmake编译linux驱动或内核模块

    1 说明 这篇笔记用于说明如何使用cmake构建Linux驱动 xff0c 这样可以方便地将driver和app作为一个整体统一构建 2 示例 首先来看一个代码示例 xff0c 为了简化起见 xff0c 我直接在驱动目录下进行构建而没有作为
  • Boost(1):Boost库简介及安装

    1 Boost库介绍 Boost是一个功能强大 构造精巧 跨平台 开源并且完全免费的C 43 43 程序库 xff0c 在1998年由Beman G Dawes发起倡议并建立 使用了许多现代C 43 43 编程技术 xff0c 内容涵盖字符
  • Ubuntu:与Windows共享文件夹

    1 说明 我个人更喜欢在windows下编辑代码或文档 xff0c 而运行环境又经常在Linux环境下进行 xff0c 那么Windows和Linux之间的协作就显得很有必要了 通常有两种方式来实现两个系统之间的文件共享 xff1a 在Li
  • C语言处理参数的 getopt() 函数

    前言 C语言程序主要通过 main 函数的参数来传递命令行参数 xff1a 默认传递命令行参数 int main int argc char argv 其中 argc 表示参数个数 xff08 包含程序本身 xff09 xff0c argv
  • SPD5详解

    SPD介绍 SPD xff08 serial presence detect xff09 xff0c 即串行存在检测 xff0c 是DIMM的相关描述信息 在每根内存条上 xff0c 都有一份SPD数据 xff0c 这份数据保存在一个可擦写