🎯 圆心 · 目标(每环都从这里出发)
造一台 Salt OS 手机:基于 DeepSeek 的 AI 操作系统,iPhone 4S 外形(含底部圆形 Home 键),开机只有一个 AI(无桌面、无图标),软硬协同设计(OS + 芯片 + 主板一起做),为别人搭台、让别人在平台上赚钱。

🧭 完整框架(同心圆)

①文字闭环 · ②技术深入 · ③挂SRAM · ④权重INT4 · ⑤激活INT4 · ⑥NPU.STORE · ⑦KV Cache · ⑧注意力QK^T · ⑨Softmax · ⑩加权V · ⑪前馈FFN · ⑫残差·LayerNorm · ⑬多层堆叠 · ⑭QKV投影 · ⑮K/V分离 · ⑯自回归解码 · ⑰连续生成 · ⑱采样 · ⑲KV环形缓冲 · ⑳滑窗注意力 · ㉑多头注意力 · ㉒输出投影 W_o · ㉓多头块入残差流 · ㉔多头块进解码循环 · ㉕整层一块 · ㉖整网一块 · ㉗ISA契约 · ㉘权重内存化 · ㉙权重预取双缓冲 · ㉚权重分块 · ㉛矩阵行块 · ㉜行块自增 · ㉝起始块号可编程 · ㉞段表连扫 · ㉟段表流式取 · ㊱行块矩阵扫 ISA 化 · ㊲描述符链 · ㊳链槽直喂 · ㊴主路走链 · ㊵链预投下层 · ㊶跨趟预投 · ㊷权重池三 bank · ㊸权重池 ISA 化 · ㊹一步生成 ISA 化 · ㊺整段生成 ISA 化 · ㊻对话回路 · ㊼对话 ISA 化 · ㊽会话记忆归档 · ㊾多会话槽位 · ㊿会话槽位 ISA 化 · 51 开机续聊 · 52 会话清单 · 53 开机用上清单 · 54 问候接话 · 55 删掉一场 · 56 会话改名 · 57 名字进问候 · 58 问候念清单 · 59 按名字接话 · 60 叫错名字也回一句 · 61 反问给选项 · 62 按序号点选 · 63 序号用于删除 · 64 删除回执念名字 · 65 删除可撤回 · 66 撤回回执念名字 · 67 撤回即续聊 · 68 续聊先开口 → 69 开口带名字

本环:接回来之后,AI 先开口

① 目标(这一环要解决什么)

第 67 环把「这一场回到对话」做进了芯片:撤回成功之后,继电器自己发一条 enter,把归档里的 K/V 按时间序恢复回片内环。用户再说「那明天呢」,AI 接得上。

可开口的第一步仍在用户手里。接回来之后屏幕是空的,AI 安静地等用户先说话——这不是对话窗口,是命令行。用户回到一场没聊完的对话,AI 应该先开口:「我们刚才说到哪儿了」,而不是盯着一个空输入框。

这一环让「接回」之后自动接一段「先开口」:从刚恢复的记忆里取话头,自己生成一句,用户一个字节都没输入。

② 实现(做了什么)

一段接力,不混语义。继电器 resume_link 只管「这一场回到对话」(enter + 恢复 K/V);先开口是生成,要借整段生成引擎与采样器。新增 rtl/resume_speak.sv:

  • 盯住继电器的 done,而且只认 ok=1 且 mem_ok=1——真读回了旧上下文才开口;恢复失败/空场一个字不说;
  • 话头从刚恢复的这段记忆里取:用归档摘要的低位当这一句的起始 token(digest 是整个会话 K/V 载荷的指纹,同一场每次接回都一样、换一场就变);
  • 把采样器种子在同一拍装成固定值 0xA5:同一场接回两次说同一句话,不是随机噪音;
  • 自己发一段整段生成(gen_start + prompt),走的是与 npu.generate 完全相同的整段生成引擎(同一份 step / 整网 / 采样通路),不另造一套解码;
  • 一句生成完才落 done,把 token 序列 / 步数 / 末 token 留在片上探针里;
  • 每次接回只说一次:done 保持高电平期间不重复开口,下一次撤回(done 回落再起)才说第二句。

忙闲没有缝。resume_link 的 busy 落下那一拍,done 才刚为高;若 npu.wait 正好在这一拍看忙闲,会把它看成空闲。这一环给 npu_busy 加了一个组合 pending(接回成功但还没开始开口的那一拍),与 rs_busy 一起把忙闲首尾接上。

接口。新增只读探针页 0xA5C 起:SCREEN43(0xA5C)、RS_SPOKE(0xA60)、RS_SID(0xA64)、RS_SEQ(0xA68)、RS_N(0xA6C)、RS_LAST(0xA70)、RS_BUSY(0xA74)、RS_DONE(0xA78)、RS_SEED(0xA7C)、RS_CORE(0xA80)、RS_RST(0xA84)、RS_PROMPT(0xA88)。前 67 圈地址映射一字不改;ISA 一位没动(仍 npu.undo)。

③ 验证(怎么证明它真的跑通)

单元仿真 tb_resume_speak(生成引擎替身按拍忙闲):

  • 空场(mem_ok=0)→ 不发 gen_start、不报 spoke,但照样落 done(不挂死);
  • 真接回(mem_ok=1,摘要低 2 位=2)→ 发一次 gen_start、prompt=2、layers=2、同拍 seed_we=1 / seed=0xA5;生成期间 busy=1,pending 在开始那拍为高、开始后落;
  • 收回步数/序列/末 token,spoke=1 / done=1 / busy=0;
  • done 保持高电平 → 不二次开口;下一次接回(低→高)→ 说第二句,话头换成摘要低位 1;
  • clear 状态/探针归零。

ISA 协同仿真 tb_isa_resume68(真整颗 SoC):两场会话,0x92 的归档摘要 76CA6F0E(低 2 位=2)、0x93 的摘要 85955090(低 2 位=0)。程序先 npu.forget 2 → npu.undo → npu.wait,再 npu.forget 2 → npu.undo → npu.wait:

  • 两场都 spoke=1:接回之后 AI 自己先开口;
  • RS_CORE=0:核一个生成入口都没写、一条 npu.step/npu.generate 都没发——这一句不是软件点出来的;
  • 两场的话头 A_PROMPT=2 / B_PROMPT=0:取自各自归档摘要低位,不是罐头常数;
  • 第一场说完 CONV_KVTOT=0x0808:接回时 4|4,先开口这一段接着旧上下文每一步都在长;
  • 程序走到 SCREEN=0x68,两次 npu.wait 都没冻死。
RESULT=PASS
撤回接回 → AI 自己开口 → 两场 spoke=1 / CORE=0 / 话头 2 与 0

契约更新:第 67 环的 tb_isa_undo67 里「恢复后 4|4、再一步 5|5」在本环变成「恢复 4|4 + 先开口 1 步 = 5|5、再一步 6|6」——先开口是新的默认行为,旧断言按新契约更新。其余 tb_resume_link、tb_isa_undo66、tb_min_soc64 复跑 RESULT=PASS,主通路 SCREEN=0xF905FD04 与第 25~67 环逐位一致(计算面一个字没动)。

④ 回到目标(这一环让手机多了什么)

只有一个对话窗口的手机,回到一场没聊完的对话,不该先看到空输入框。AI 先开口,用户才知道「它还记得」。这一环把「先开口」也做进了接口契约:话头由记忆决定,生成走同一条解码通路,忙闲不断缝。

更重要的是「谁在说话」:不是 OS 拼一句固定问候,而是硬件在接回之后自己发一段生成,核一个入口寄存器都没写。芯片把现场收好、把话接上,还先开口——对话窗口里唯一的那个人,回来了。