第 52 环 · 会话清单(一条 npu.sess.list 列出所有会话)
第 51 环让开机只回到最后一场。可手机上的对话窗口不止一场:用户同时开着「今天的工作」「家里的事」「查资料」。目录里其实住着六场,硬件却只会回答「最后一场是谁」。
软件当然可以自己 find 一个个会话号——但会话号是用户/服务起的,OS 手里没有一张完整名单,扫不出来。要让 AI 在开机时说「你有三场没聊完」,硬件必须能一次把目录里活着的会话交出来。
这一环加一条 npu.sess.list:扫六个目录项,把活着的那几场压成一张小表写回内存;OS 用已有的窥视口读表,不新开内存口。
目录引擎新增 list(cmd=7)——只读,不改目录。扫描六个目录项:valid 为 1 就记下 {槽号, 会话号, 字数};扫完把结果写成定长 13 字的小表:
0x1C0 会话数 N
0x1C1 {槽号[2:0], 13'b0, sid[15:0]} ← 第 1 场
0x1C2 {16'b0, words[15:0]} ← 第 1 场的字数
0x1C3 {槽号[2:0], 13'b0, sid[15:0]} ← 第 2 场
...
0x1CB 第 6 场
0x1CC 第 6 场字数 (空位一律写 0)
表按「清单序号」紧凑排,不按槽号留空。目录是稀疏的:释放了槽 1,活着的仍是槽 0 和槽 2;清单必须写成第 1、2 条,而不是在第 1 条的位置留个洞。槽号单独放在每条的高 3 位——OS 既知道「有多少场」,也知道「每场住哪槽」。
定长表 + 空位写 0。清单短了不能只写前面几条:上一条清单的尾巴还留在内存里,OS 按固定表读就会读出「幽灵会话」。每次 list 都把 13 个字写满,没有的场次写 0。
开关场引擎新增 list 命令(cmd=5):转给目录、等完成、把「有几场」带回;不动当前会话、不搬 K/V、不改目录。空内存/刚重建的目录返回 0 场 + ok,不是错误(list 也不顺手建目录)。
ISA:核升 v17,custom-1 加 funct3=110:npu.sess.list(无操作数)。EX 拍一个脉冲进开关场引擎;npu.rd 新选源 30 读回「有几场」。MMIO 老路原样保留:0xC00 SS_CMD=7、0xC5C SS_LCNT、0xD18 SCREEN28。
软硬协同的约定:① 目录是会话索引的唯一真相,OS 不再维护第二份名单;② list 是纯读操作,任何「列一下」都不该改变会话状态;③ 结果表的地址/格式定死(0x1C0,定长 13 字),OS 用现有窥视口读,不为一个查询新开总线口;④ 空目录是正常状态,不是错误。
协同仿真 tb_min_soc52 在第 51 环全部流程跑完后(目录已重建、无当前会话)继续:
| 步骤 | 做什么 | 结果 |
|---|---|---|
| 造三场 | open+commit:A 0x71/9字、B 0x72/4字、C 0x73/15字 | 槽 0 / 1 / 2,used=3 |
| 清单 | 一条 npu.sess.list | npu.rd sel=30 = 3 |
| 读表 | ARC_PEEK 0x1C0 起 | 3 | 槽0/0x71 | 9 | 槽1/0x72 | 4 | 槽2/0x73 | 15 |
| 释放 B | free 0x72 → 再 list | 2 条:槽0/0x71、槽2/0x73;空位读回 0 |
| 只读 | find 0x71 读摘要 | == commit 时的 0x0202A1 |
| 零配置 | 读 SX_CORE | 前后一位没涨(核没写入口寄存器) |
| 空目录 | 重建后 list | 0 场、ok、表字 0 写 0(不建目录) |
主通路未动:SCREEN=0xF905FD04、SCREEN2=0x02040404、SCREEN23~27 与第 25~51 环逐位一致。单元测试 tb_sess_list 覆盖空目录/三场/只读/释放/六场/重建六种情形;相邻的 sess_switch 与第 51 环协同仿真也一并复跑通过。
其一(槽号不等于清单序号)。第一版把 sid 按目录槽号下标存:l_sid[slot]=sid。三场满时看不出问题;一释放中间的槽 1,活着的槽是 0 和 2,清单第 1 条读的却是 l_sid[1]——空槽的残值。修法:另开一个紧凑下标 lidx,l_sid[lidx]=sid、l_slot[lidx]=扫描到的槽号——「住哪」和「排第几」是两个维度。
其二(字数在 w3 的高半字)。目录项 w3 的格式是 {words[15:0], 8'b0, kcnt, vcnt},list 却取了 [15:0],读出来的是 kcnt/vcnt(3 或 4),不是 9/4/15。修法:取 [31:16]——复用已有格式时先回去看打包那一行。
其三(短清单的尾巴会骗人)。释放一场后再 list 只写 1+2×2=5 个字,上一次 3 场留下的第 3 条还在 0x1C5,OS 按固定表读会看到「幽灵会话」。修法:表定长 13 字,空位写 0,每次全写满——定长表要么全写,要么就别定长。
其四(空目录也是正常答案)。list 走的是读表头那条路:魔术字不对时若按老逻辑处理会置 err,或顺手建目录。list 必须是纯查询:空内存就返回 0 场、写一张只有 0 的表、不建目录、不置错。
Salt OS 手机开机只有一个 AI,没有桌面、没有图标。用户不该看到「会话管理」这种系统界面——但 AI 需要知道「你们之前聊过几场、都到哪儿了」。这一环把这份名单做成硬件的一条指令:AI 开机问一句,目录一次交全。
对平台的意义:会话清单是第三方服务接进来的目录。谁在什么时候开过哪场、聊到多少字,硬件一条指令就交出来;平台上的服务可以围绕这些会话继续长,而不是各自再维护一份用户上下文。从「记得上一场」到「记得每一场」,记忆开始变成一张可查询的地图。
清单已经能列出来,可开机流程还没用它:npu.boot 仍然只续最后一场。下一环把 list 接进开机——AI 开机先说「你有三场没聊完」,用户点一句就进对应的那场;从「能列出每一场」,到「开机就会用这份名单」。