# 阶段六：SPI 模拟配置控制器（23–24）

这是待实现的结课项目规格，不是现有 Master 的功能，也不是已运行的参考设计。目标：通过 SPI 写入 12 位模拟码字和使能位，在指定安全窗口原子生效，并可读回状态。

## 23：先冻结可以验证的规格

### 架构与输入假设

首版选择过采样 Slave：系统 clk=50 MHz，全部功能寄存器由 clk 驱动。外部 SCLK、CS、MOSI 经同步、事件检测与稳定窗口分析，形成串行前端；寄存器层和更新控制层位于同一 clk 域。SCLK 域 + mailbox 是进阶替代实验，不混用两套约束。

外部接口 Mode 0、MSB first、一个从设备，每帧 24 个 SCLK 周期，最大 1 MHz。高、低电平各至少 500 ns；CS 拉低到首个上升沿、末个下降沿到 CS 释放各至少 200 ns；两帧 CS 高间隔至少 200 ns。MOSI 在每个外部上升沿前后至少 100 ns 稳定。safe_update 来自 clk 域。

这些窗口是本实验明确提出的源端约束，需要主机遵守，不宣称适用于任意 SPI 器件。典型两级同步加检测可能用数个 clk 周期；实现者必须推导 RTL 的最大检测/更新延迟，确认在 100 ns 教学预算内，并证明 MOSI 相对检测沿稳定。若实际结构超出预算，调整架构或规格并重新验证。

MISO 的本位必须在主机采样上升沿前至少 100 ns 有效，并在之后至少 100 ns 保持。下一位在检测到外部下降沿后准备，输出传播延迟也计入预算。CS 高时单从设备 MISO 返回 0，允许去选中检测与输出传播时间，不使用它驱动多从设备共用总线；多从设备的三态/OE 交接需要另写规格。

复位 rst_n 同步低有效，低覆盖至少一个 clk 上升沿。复位中止串行帧和 pending 更新，active_code=0、active_enable=0，所有状态清零，不产生应用完成脉冲。

### 串行帧格式

| 字节 | MOSI | MISO |
|---|---|---|
| 0 | bit7=W，bit6:0=地址；W=1 写，W=0 读 | 固定 00 |
| 1 | 写数据[15:8]；读操作为 00 | 读快照[15:8]；写为 00 |
| 2 | 写数据[7:0]；读操作为 00 | 读快照[7:0]；写为 00 |

读快照在内部确认第八个采样事件并解析读命令时一次性获取，之后这一帧不受 active/status 变化影响。第一个响应数据位必须在第九个外部上升沿之前满足预算。不要等到第九个上升沿才开始准备。

解析命令时仅保存快照，MISO 保持命令字节的末位 0；检测到第八个下降事件后才驱动快照 bit15，后续数据位也在下降事件后更新，保证命令最后一个采样沿的 hold。非法地址读返回 0000，并在帧结束时报告错误；读帧的两个 MOSI 占位字节必须为 00，否则也视为错误帧。

同一个 clk 边沿若刚好发生 active 更新，读快照按边沿之前的寄存器值获取。读数据的“新鲜度”因此有精确定义。

写操作只在检测 CS 释放后且该帧恰好为 24 个有效采样沿、地址和数据合法时接受。移位期间没有寄存器写副作用。短帧、长帧、非法地址/访问、保留位非零设 frame_error，原配置保持。长帧不能让计数器回绕成合法长度；使用饱和计数或额外 overflow 标志。

读数据会在帧未结束时发送，接收方只将正确长度和边界的帧作为有效结果。读没有清状态等副作用。复位中止帧不额外置 frame_error。

### 地址与访问语义

所有数据 16 位，高位未定义部分写入必须为 0，读取为 0。

| 地址 | 名称 | 属性 | 有效位/含义 | 复位 |
|---|---|---|---|---:|
| 00 | SHADOW_CODE | RW | [11:0] 码字 | 0 |
| 01 | SHADOW_ENABLE | RW | [0] 使能 | 0 |
| 02 | COMMIT | W1P，读 0 | [0]=1 提交当前影子快照；0 无操作 | 0 |
| 03 | ACTIVE_CODE | RO | [11:0] 当前有效码字 | 0 |
| 04 | ACTIVE_ENABLE | RO | [0] 当前有效使能 | 0 |
| 05 | STATUS | RO | [0] pending，[1] busy_reject，[2] frame_error | 0 |
| 06 | CLEAR_STATUS | W1C，读 0 | [1] 清 busy_reject，[2] 清 frame_error | 0 |

写 RO 或不存在的地址视为 frame_error。CLEAR_STATUS 的 bit0 和其他位保留；STATUS 的 pending 不可软件清除。新错误与清除同周期时新错误优先。

### 提交与应用

pending=0 时 COMMIT=1 被接受，将 shadow_code 和 shadow_enable 同时复制到 pending 快照。pending=1 时再次 commit 被拒绝，置 busy_reject；原 pending 快照保持。shadow 仍可读写，为下一次提交准备。

safe_update=1 且边沿之前 pending=1 时，active 字段一次性更新，pending 清零，applied 脉冲高一个 clk 周期。刚接受 commit 的同一个边沿不立即应用，即使 safe_update=1，也从下一 clk 边沿开始判断。若旧 pending 同周期应用而又收到 commit，仍按旧 pending=1 拒绝新提交，行为确定但不追求最满吞吐。

applied 表示数字 active 更新，模拟电路的最终稳定还要满足自身 settling 要求。没有 safe_update 时允许一直 pending，由上层决定超时策略，不在本模块隐式放行。

### 示例交易

```text
MOSI 80 0A BC：shadow_code = 0xABC
MOSI 81 00 01：shadow_enable = 1
MOSI 82 00 01：提交，pending = 1
safe_update 的有效 clk 边沿：active = {enable=1, code=0xABC}
MOSI 03 00 00：读 ACTIVE_CODE，MISO = 00 0A BC
```

先提交 0xABC，再把 shadow 改成 0x123，最后允许 safe_update：这次 active 仍应是 0xABC，不能引用已经改变的 shadow。

### 练习与验收

分模块实现 spi_frontend、register_bank、config_apply，在独立后续实验目录保存 RTL、testbench、约束和运行脚本。先写模块接口和接受条件，再写代码。保持原 Master 工程和验证契约。

验收测试至少包括：合法读写；所有合法地址；RO/非法/保留位访问；0、1、23、24、25 个采样沿的帧；CS setup/hold 和时钟最小宽度；MOSI/CS/SCLK 相位扫动；pending 中 commit；pending 中 shadow 改写；safe_update 缺失/持续高；commit 与应用同周期；读取快照期间 active 变化；所有阶段复位及恢复；单周期 applied；sticky 清除与新事件并发。

参考模型根据完整 SPI 事务和规格更新寄存器，不复制 DUT 的移位/计数实现。逻辑验证通过后，给出同步输入、输出 MISO、内部寄存器和复位的约束依据；不会因为所有功能寄存器共用 clk 就略去异步接口分析。

## 24：用证据完成设计评审

### 目标和讲解

交付需要能让另一个工程师独立判断功能、时序和接口边界，而不是只有一张 PASS 截图。评审顺序：规格是否完整；实现是否符合规格；验证是否覆盖风险；约束是否有来源；报告是否确实分析了目标场景。

证据包包括：版本化规格和地址表、时钟/复位架构图、RTL 和运行脚本、覆盖矩阵、失败和修复记录、实际仿真结果、映射网表和结构检查、时序约束假设、关键路径解释、未完成项。生成报告与波形放在 Git 忽略的 results 中，提交可复现的源文件和摘要。

先将当前 Master testbench 的独立 slave 验证思路迁移到此项目。随后可做 Master→Slave 集成，但不能用两个 DUT 互相通过作为唯一证明；双方若共享相同位序或时序错误，集成测试可能掩盖问题。

自评每项 0–2 分：0=无法解释/无证据，1=能解释但证据不全，2=解释和证据相符。

| 项目 | 达到 2 分的要求 |
|---|---|
| RTL 电路对应 | 能说明存储、选择、计数和输出结构 |
| 接口规格 | 接受、拒绝、有效窗口与异常行为明确 |
| 验证 | 独立参考、边界覆盖、故障能被发现 |
| 时序约束 | max/min 与物理来源一致，无任意放宽 |
| 配置一致性 | pending 快照和 active 更新可证明 |
| 复位/恢复 | 无假完成、假事务和残留 busy |
| 数模交界 | 定义瞬态、稳定窗口和模拟生效范围 |
| 可复现性 | 源文件、版本、命令与结果可对应 |

满分 16。建议达到 13 分且接口、验证、时序、配置一致性没有 0 分，再增加新功能。这个评分用于学习，不代替工程签核。

### 练习与验收

做一次自我设计评审：挑一条最可能出错的序列，说明规格、RTL、testbench 和时序假设如何共同覆盖它。若具备物理数据，再附布线后 setup/hold、多角和相应物理检查；否则明确“仅到 RTL/逻辑综合”。参考见 [23–24 答案](07_answers.md)。
