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

🧭 完整框架(同心圆)

①文字闭环 → ②技术深入 → ③挂SRAM → ④权重INT4 → ⑤激活INT4 → ⑥NPU.STORE → ⑦KV Cache → ⑧注意力QK^T → ⑨Softmax → ⑩加权V → …

本环:把「谁更相关」变成「各占几分」

① 目标是什么

同一个圆心:一台开机只有一个 AI 的手机。上一环芯片能算出「当前这个字跟历史上每个字有多相关」的原始分数了;但分数只是「谁高谁低」,还没法直接用——真正要的是「各占几分」:一串加起来正好是 1 的权重。大的更大、小的趋近 0,这样后面才能拿权重去加权历史信息。这一步就是 Softmax 归一化。本环给芯片造一台 Softmax 引擎。

② 怎么实现(不脱圆心)

延续「端上算力紧凑、内存带宽优先」的主线,把 Softmax 做进硬件,且全部用定点/近似,不用浮点:
· 防溢出:先减最大值再取指数(exp(score − max)),最大那个恒为 1.0,避免指数爆掉;
· 指数用 8 位定点查表(e^-d × 256),256 = 1.0;
· 除法用移位相减(restoring)17 拍实现。
同时这一环把 OS 的驱动方式升级了:不再用固定空等,而是轮询 busy 寄存器——真设备驱动的写法(发起 → 等就绪 → 取结果)。

③ 本环做了什么(真代码)

新增 rtl/softmax.sv:分数读端口 + 权重写端口 + 三趟遍历 FSM——

趟1 MAX:走一遍所有分数,找最大值(数值稳定)
趟2 EXP:算 exp(score−max) 查表(Q8),累加得 sum_exp
趟3 DIV:每个槽位 (exp<<8)/sum_exp → Q8 权重,写回权重 RAM

attn_qk.sv 增加「分数落盘」端口:算分时把每个槽位的分数写进片上分数 RAM(上一环只取了最大值)。min_bus.sv 挂载 softmax + 分数 RAM + 权重 RAM,映射:

0x048 → SM_START    写 1 → 触发三趟归一化
0x04C → SM_SUM_EXP  读 exp 之和(归一化分母)
0x050 → SM_MAX      读本趟最大分数
0x054 → SM_W_ADDR   写槽位号 → 选中权重
0x058 → SM_W_DATA   读该槽位 Q8 权重(256 = 1.0)
0x05C → SM_BUSY     读引擎忙闲

软硬协同还顺手补了两处真实缺陷(都是为了让轮询驱动能用):
· 核 v5:分支在 IF 拍判决、靠转发取数;若它依赖的 load 还在 ID/EX,旧值会导致跳错——新增「载入-分支冒险 IF 冻结」,直到 load 走到 MEM 才放行;
· 状态寄存器无空窗:核写完 START 立刻读 BUSY 必须为 1(把「刚下发那拍」也算进忙),否则驱动会误判完成冲过去。

④ 怎么算成(闭环验证)
分数 8 / 7 / 8 / 8 → max=8,sum_exp=862,权重 Q8 = [76, 27, 76, 76](合计 255 ≈ 256 = 1.0)→ 屏幕 0x35E4C · RESULT=PASS
单元仿真(找最大 / exp 求和 / 除法归一化 / 有符号 / 全相等分数)+ 核-OS-注意力-Softmax 协同仿真 + 全量回归 全部通过

归一化的意义在这里看得很清楚:原始分数 8 和 7 只差 1,归一化后权重却是 76 : 27——差了近 3 倍,相关的那一项被显著放大,不相关的被压小。权重合计 255(≈256=1.0,最后 1 是定点截断误差),说明确实是「概率分布」。屏幕 = (862<<8)|76 = 0x35E4C = 220748——证明芯片能算出一串真正可用的注意力权重。

⑤ 回到目标

本环走完一整圈:目标 → AI 要「按相关度分配注意力」 → 硬件三趟算出归一化权重 → 权重和≈1/放大比例/有符号校验跑通 → 回到目标。注意力从「打分」走到「分权重」,且驱动方式升级成真正的设备轮询。下一步,权重就能拿去加权历史信息 V——注意力的输出就齐了。离一台本地跑大模型的手机,又近一圈。