SSI 设备与 SPI 闪存模型
QEMU 的同步串行接口(SSI)总线建模控制器与一个选定外设之间的全双工字传输。 包括 m25p80 在内的大多数 SPI 闪存模型都通过该总线连接控制器。
本页说明 SPI 快速读取空周期处理中,控制器模型与闪存模型的职责边界。 这一边界很重要,因为真实控制器通常通过寄存器配置空周期, 闪存模型却只能看到 ssi_transfer() 传入的字节流。
SSI 传输粒度
ssi_transfer() 传输一个 SSI 字。 实现常见 SPI NOR 命令流的闪存模型,通常一次消费一个 8 位字:
命令操作码;
地址字节;
可选模式或连续读取字节;
空字节;
数据字节。
SSI 核心不建模单独时钟边沿,也不建模活动 SPI 数据线数量。 如果真实事务的空阶段以时钟周期表示, 负责在 SSI 总线上生成传输的设备模型必须将其转换为若干空字节传输。
闪存模型的职责
SPI 闪存模型负责闪存命令语义:
识别哪些操作码;
需要多少地址字节;
命令是否包含模式字节;
返回数据前必须消费多少空字节;
不同厂商快速读取命令的行为差异。
m25p80 的 needed_bytes 是字节数,不得存放原始空周期数。 数据手册按周期描述空阶段时,按该阶段总线宽度转换为字节:
dummy_bytes = DIV_ROUND_UP(dummy_cycles * dummy_bus_width, 8)
m25p80 建模的 SPI NOR 快速读取中,空阶段采用与地址阶段相同的宽度。 例如 DOR、QOR 等仅输出阶段使用双线或四线的读取命令, 其命令、地址和空阶段都使用单线,只有数据阶段使用双线或四线。 DIOR、QIOR 等双 I/O 或四 I/O 命令则在地址和空阶段均使用较宽总线。
如果空阶段不能精确表示为整数次 SSI 字节传输, 模型应向上取整并记录这一限制,而不是默默把周期数当成字节数。
控制器模型的职责
控制器模型负责控制器硬件行为:
客户机可见寄存器如何选择命令、地址宽度、总线宽度和空周期数;
客户机是否在发送 FIFO 中提供空字节;
内存映射、直接读取或其他自动模式是否由控制器生成空阶段;
控制器生成传输前后,片选状态如何改变。
客户机通过发送 FIFO 或手动路径写入空字节时, 控制器应像其他客户机字节一样传给 ssi_transfer(),不应替闪存增加额外空传输。
硬件寄存器要求控制器生成空阶段时, 控制器必须先发送空字节,再让数据传输到达闪存模型。 应按照控制器在空阶段使用的总线宽度转换周期数。例如:
单数据线上的 8 个空周期转换为 1 个空字节;
双数据线上的 8 个空周期转换为 2 个空字节;
四数据线上的 8 个空周期转换为 4 个空字节。
控制器不应复制闪存专用操作码表来猜测哪些命令需要空周期。 自动模式已有足够硬件配置判断是否生成空阶段; 手动模式则以客户机提供的字节流为准。
避免重复计算
闪存看到的每个空字节传输都必须只由一方生成:
客户机通过控制器发送空字节时,由控制器转发、闪存消费。
客户机设置空周期寄存器时,由控制器转换为空字节传输、闪存消费。
闪存虽然知道某命令需要空字节,但不在 SSI 总线上创建传输。
不要在控制器中窥探手动模式操作码流,再根据闪存命令注入额外空传输。 这会把闪存命令语义混入控制器,并在闪存正确处理空字节计数后变得脆弱。
源码中的示例
以下模型体现了这一边界:
hw/block/m25p80.c 将快速读取所需空字节数保存在 needed_bytes。 厂商专用辅助函数将手册中的空周期转换为模型预期的字节流。
hw/ssi/aspeed_smc.c 根据寄存器为直接快速读取模式生成空字节传输, 但手动用户模式写入按客户机字节直接转发。
hw/ssi/npcm7xx_fiu.c 将直接读取的空阶段配置转换为读取数据前发送的空字节数量。
审查清单
添加或修改 SPI 闪存控制器或闪存模型时,应检查:
驱动闪存状态机的空阶段计数是否以字节为单位?
如果寄存器保存周期,转换是否基于空阶段的总线宽度?
客户机手动提供的空字节是否直接转发,没有额外注入?
自动生成的空阶段是否由控制器模型处理?
闪存专用操作码知识是否保留在闪存模型,而没有复制到控制器窥探路径?