🎯 圆心 · 目标(每环都从这里出发)
造一台 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 化 → ㊹…

本环:整池配置,一条指令说完

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

第 39~42 环把权重的「来路」一步步做进硬件:描述符链决定权重住在哪、投给谁;预投与三 bank 权重池决定「什么时候投、提前几层」。硬件已经会自己干活了,可开启这套能力的钥匙还在软件手里——核要写六条 sw:

WC_MODE / WC_TBLS / WC_N      → 走不走链、链在哪、链多长
WC_PF   / WC_XP   / WC_PF2     → 投不投下层、投不投下趟、池子深不深

六个寄存器分散在三个页里,顺序写错一个,输出就可能静默变差(池子没开、预投没开,只是慢,不会报错)。真芯片上「这组配置」是一次有语义的决定,不是六次独立寄存器的偶然组合。本环把它收进 ISA:一条 npu.pool 说完。

② 实现(做了什么)

核升 v11,开一个全新的主 opcode custom-1(0101011),前 42 圈的 custom-0 指令编码一位不动:

npu.pool  rs1, rs2
  rs1 = {池深[7:4], 池深2[3], 跨趟预投[2], 预投下层[1], 走链[0]}
  rs2 = {链长[15:8], 链基址[5:0]}

EX 拍的两个操作数直接就是整池配置与链描述符,min_bus 在同一拍一次性锁进六个硬件寄存器——核一个配置寄存器都不写。池深字段有两种写法并行支持:rs1[3] 直接开三 bank,或 rs1[7:4]=2 表示「预投深度 2」(同样落到三 bank),硬件取或。

为把「核不逐个写」变成可量化的硬证据,新增只读探针 POOL_WCORE:数核真正用 sw 写六个池配置寄存器的次数。指令路径下它是 0,老路六条 sw 是 6——和 R38 的 SF_CORE(0 vs 20)是同一把尺子。

新页 0x874~0x88C:POOL_CFG(指令配置词)、POOL_DESC(链描述符)、POOL_N(执行次数)、POOL_WCORE(核写配置次数)、POOL_RST(清计数)、SCREEN18。前 42 圈地址映射一字不改。

③ 怎么验证(硬证据)
证据结果说明
指令路径核写配置次数POOL_WCORE = 0一条 npu.pool,六个配置寄存器一个都没被 sw 写
老路逐条 sw 写配置POOL_WCORE = 6同一把尺子的基线:六条 sw 才说清一件事
两条来路的六个寄存器读回逐位一致MODE/TBLS/N/PF/XP/PF2 全同(递增不推翻)
配置词与描述符自报0x002F / 0x0A34 / N=1核没写过这三个只读探针,值只可能来自指令那一拍
池深字段 2 → 1 → 2WC_PF2: 1 → 0 → 1池深真管事:三 bank ↔ 两 bank 乒乓
一条指令配出的池跑整网Q 趟 == A 趟输出 0xF905FD04,lane0 = 0x07;配置真被引擎消费
全零配置六个寄存器全归零,POOL_N 照数关池也是一条真指令,不是「没执行」
老路 / 主通路逐位一致SCREEN/2/3/17 与前几环同值,老路径一条没删
SCREEN18 = 0x02010007
池深 2(三 bank)| POOL_N = 1(指令执行一次)| Q 趟 lane0 = 7(与 A 趟同值)

单元仿真 tb_isa_pool:老路 POOL_WCORE=6 ↔ 指令路径 0;六个寄存器读回逐位一致;池深 2/1 让 WC_PF2 跟着 1/0;全零配置全关且 POOL_N 照数。

协同仿真 tb_min_soc43:SCREEN = 0xF905FD04、SCREEN2 = 0x02040404、SCREEN3 = 0x04000204、SCREEN17 = 0x07060007 与第 25~42 环逐位一致;一条 npu.pool 配出的池子跑完整网,Q 趟输出与 A 趟相同;采样序列仍是 [0,2,0,0,0,3]。全量回归 73 项全绿。

④ 调试中钉住的钉子

其一(写口有、读口没有)。WC_PF(0x83C)和 WC_XP(0x84C)从第 40/41 环起就能写、能生效,但 min_bus 的读译码表一直漏着这两个索引——读回恒 0。老测试从没读过它们,所以一直没暴露;本环一读回就假失败。写口和读口是两张表,加寄存器两边都要加(与 R42 的 WC_PF2 是同一类错)。

其二(12 bit 有符号偏移)。0x880(a7) 在 a7=0x800 时偏移 0x80,没问题;但 0x874(a7)/0x880(a7) 这种「页内再往后」的地址一旦超过 0x7FF 就汇编不过(12 bit 有符号立即数)。改成以 0x870 为基址的 a6,全部落在 ±2KB 内。

其三(config 词的第 2 位)。0x2B 与 0x2F 只差一位:前者把「跨趟预投」漏成了 0,硬件照样跑、输出也照样一致(只影响等待),自检却在 WC_XP 上暴露。配置位的对错不一定体现在结果上,必须逐位读回。

其四(指令脉冲只活一拍)。npu.pool 在 EX 拍只亮一个周期;锁存必须在 min_bus 的每拍默认块里做,且与 dmem_wen 译码同拍共存,不能写成「先写后判」的优先级链——否则同一个周期里指令配置会被后面的判断覆盖。

⑤ 回到目标(这环让目标前进了多少)

到这一环,权重通路对软件只剩一句话:「用这套池子,跑这一网」。链在哪、投几层、池子多深,全在一条指令的两个操作数里。核不再逐个摸寄存器,驱动不再靠「记得按顺序写六个数」——这正是软硬协同里 ISA 该干的活:把一组必须一起成立的硬件状态,收成一个不可分割的语义。

对一台手机的意义:模型每生成一个 token 都要重配一遍权重通路;配置从六次总线写变成一次指令,省下的是每次解码的固定开销,也让编译器/驱动更难写错。到后面做「一条指令跑完一次完整解码」时,这一层就是那块最稳的地基。