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

本环:把注意力最前面那块拼图补上——Q/K/V 由残差流投影出来

① 目标是什么

同一个圆心:一台开机只有一个 AI 的手机。前面十三圈,芯片上已经有了一个「能摞起来的 Transformer 块」,残差流也能贯穿多层。但注意力的最前面一直缺一块拼图:Q/K/V 是核直接手塞进去的常数和预填向量。真模型里,查询 Q、钥匙 K、值 V 全都要由当前输入的隐藏状态 x(残差流)经三个权重矩阵投影出来——Q = Wq·x、K = Wk·x、V = Wv·x。这一环把这三个投影做成片上一个引擎:残差流一进来,Q/K/V 由硬件一次算出,注意力从此端到端自洽,软件再也不用手塞常数。

② 怎么实现(不脱圆心)

延续「端上算力紧凑、全部定点、权重 INT4、激活 INT8」的主线,新增一个很小的模块 qkv_proj:
· 输入是残差流 x(4 lane × 8bit);配三个 4×4 INT4 权重矩阵 Wq/Wk/Wv;
· 一次算出 Q/K/V 三组向量,每组同时吐两种精度:8bit 全精度(可读回、供后续层用)+ INT4 饱和打包(直接喂注意力算分与 KV Cache——算分引擎的 Q 是 INT4 契约,KV 槽位载荷也是 INT4 打包);
· 投影输出按 INT4 饱和,等价于把「投影后量化」这一步落在硬件数据通路上,不额外吃乘加器;
· QKV 寄存器另开一页(0x200 起),一行守卫把新页和前面 13 圈的地址映射隔开,老映射一个字不动——只扩不推翻。

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

新增 rtl/qkv_proj.sv:三路投影 + 8bit/INT4 双精度输出,组合逻辑一次算完:

投影:  q[d] = Σ_i Wq[d][i]·x[i]     (INT4 权重 × INT8 激活,32bit 累加)
        k[d] = Σ_i Wk[d][i]·x[i]
        v[d] = Σ_i Wv[d][i]·x[i]
输出:  q8/k8/v8 = 饱和到 [-128,127]   (8bit 全精度)
        q4/k4/v4 = 饱和到 [-8,7] 后打包  (INT4,喂注意力 / KV Cache)

min_bus.sv 挂载 qkv_proj,新映射(QKV 页,0x200 起):

0x200 → QKV_X      投影输入:残差流 x(4×8bit)
0x204/0x208 → QKV_WQ_LO/HI   Wq(4×4 INT4)
0x20C/0x210 → QKV_WK_LO/HI   Wk
0x214/0x218 → QKV_WV_LO/HI   Wv
0x21C → QKV_START  写 1 → 触发三路投影
0x220~0x22C → QKV_Q0~3   读 Q 各 lane(8bit 全精度,符号扩展)
0x230~0x23C → QKV_K0~3   读 K 各 lane
0x240~0x24C → QKV_V0~3   读 V 各 lane
0x250 → QKV_Q4     读 Q 的 INT4 饱和打包 → 直接喂 ATTN_Q
0x254 → QKV_K4     读 K 的 INT4 饱和打包 → 直接喂 KVC_DATA
0x258 → QKV_V4     读 V 的 INT4 饱和打包
0x25C → QKV_BUSY   投影引擎忙闲(含刚下发那拍,无空窗)

最小 OS:残差流进 → 投影出 Q/K/V → 投影出的 K 作为一条新 token 追加进 KV Cache、投影出的 Q(INT4 饱和打包)直接喂算分引擎,接着走完一个完整块:

LST_X(x0) → QKV 投影(x→Q/K/V)
    ATTN_Q ← Q4(投影出的 Q)        KVC_APPEND(K4)(投影出的 K 进历史)
    QK^T → Softmax → 加权 V
    RSN(a=注意力输出, b=当前残差流)   # 残差 + LayerNorm #1
    FFN(LN 输出)                     # 前馈两层
    RSN(a=FFN 输出, b=LN#1)          # 残差 + LayerNorm #2
    LST_ADV                          # 块输出锁回 XSR
读回 XSR → 屏幕
④ 怎么算成(闭环验证)
投影 Q=[3,5,6,2] → 注意力 → 最终残差流 [16,-11,8,-14] → 屏幕 0xF208F510 · RESULT=PASS
单元仿真(三路矩阵乘 + 8bit/INT4 饱和打包)+ 核-OS-投影-块协同仿真 + 全量回归 14 项 全部通过

这一环最直观的是Q/K/V 真的由残差流算出来了,而且每一步都能手算对得上:
· 残差流 x=[6,-4,3,-5],配 Wq(混合阵)、Wk(单位阵)、Wv(每行 [1,1,0,0])→ 硬件一次算出 Q=[3,5,6,2](P=0x2653)、K=[6,-4,3,-5](P=0xB3C6)、V=[2,2,2,2](P=0x2222)——Q ≠ x,证明它真是被矩阵「投」出来的;
· 投影出的 K 追加成第 3 条历史(KV 槽 0x0001 / 0x0010 / 0xB3C6),投影出的 Q 直接进算分引擎:分数 [3,5,6],Softmax 权重 [9,66,180](三条历史都参与加权),加权 V 得 [4,-3,2,-4];
· 再走残差+LN → FFN → 残差+LN:LN1=[13,-8,7,-11],FFN=[20,20,20,20],最终残差流 [16,-11,8,-14];
· 屏幕 0xF208F510 = 4060673296,与软件参考模型逐位一致。
单元仿真另外验证了饱和路径(8bit 不饱和、4bit 饱和:q8=[12,-8,6,-10] → q4=[7,-8,6,-8])。至此注意力的 Q 不再由核手塞常数,Q/K/V 全部来自残差流投影,一个块的注意力和它的输入真正自洽。

⑤ 回到目标

本环走完一整圈:目标 → 大模型里 Q/K/V 必须由隐藏状态投影得到,手塞常数的注意力是假的自洽 → 硬件只加一个小引擎(三个 4×4 INT4 矩阵乘 + 饱和打包),Q/K/V 全在片上算出 → 投影-注意力-残差-FFN 端到端跑通、单元仿真 + 回归全绿 → 回到目标。这块芯片上的注意力第一次「长在自己身上」:输入残差流进来,Q/K/V 自己投出来,不用外面喂。离一台本地跑大模型的手机,又近一圈。下一层要补两块:现在 K/V 还共用一个槽位载荷(最小系统的简化),且投影还没接进多层块——下一圈把 K/V 拆开,让每一层都自己投影。