🎯 圆心 · 目标(每环都从这里出发)
造一台 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契约 → ㉘权重内存化 → ㉙权重预取双缓冲 → ㉚权重分块 → ㉛矩阵行块 → ㉜行块自增 → ㉝起始块号可编程 → ㉞段表连扫 → ㉟段表流式取 → ㊱…

本环:扫这一段的时候,下一条表字已经在路上了

① 目标是什么

还是同一个圆心:一台开机只有一个 AI 的手机。上一环硬件确实会自己读段表了,可读法是「停在边界上等表」——每到一个段边界,引擎先把扫描停下,进 ST_TBLD/ST_TBLW 两个专用状态等表字从 SRAM 回来(发地址 + 采样,实打实两拍)。真芯片上表的读取(主存访问)是几十上百拍的延迟,这么「停一次等一次」会把延迟整个暴露在关键路径上,段越多停越多次。
而段表本来就住在内存里、长得可以很长(大矩阵分几十上百段),正确的做法是边扫边取:扫当前这一段的时候,就把下一条表字从(与权重共用的)流式通道里取回来、存进一个前瞻缓冲;走到段边界时直接换段,不停下扫描等表。

② 怎么实现(不脱圆心)

· 前瞻缓冲:lk_data 一个表字 + lk_valid 一位——缓冲里装的是「下一条」表字(当前段还在扫,下一段已经到手);
· 借一拍:预取就借 ST_COMP 那一拍——部分积算在片上(累加发生在寄存器里),SRAM 读口本来空着,同一拍把表地址摆上、读使能拉高,表字下一拍就落进缓冲;扫描一个额外周期都不花(读使能因此改成组合:寄存的取权重 + 组合的预取,两者永不重叠);
· 边界三档:缓冲有货 → 零额外周期直接换段(lk_use_now);缓冲空着(比如本段只有一块、来不及预取)→ 边界那一拍当场取,下一拍装上开扫(1 拍);都没赶上 → 退回第 34 环的阻塞式读表(2 拍);
· 只扩不推翻:RB_TBLP=0 = 第 34 环老语义(边界阻塞两拍读表),一个状态没删;开/关预取跑同一张表,算出来的整行必须逐位一致;前 34 圈地址映射一字不改;
· 硬证据探针:0x3F4 RB_TBLPF(走流式通道取回几条)、0x3F8 RB_TBLUS(边界零额外周期换段的段数——这个数 > 0 就是「边扫边取」真发生了)、0x3FC RB_TBLST(退回阻塞读表的条数,预取路径应为 0)、0x634 RB_TBLCYC(本次启动周期数)、0x638 SCREEN10。

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

改 rtl/row_blk.sv(新增 tbl_pf 输入 + lk_data/lk_valid/lk_req 前瞻缓冲与预取通路 + 新状态 ST_LKW + 读使能改为组合 w_rd_en_r | tbl_rd_now + 表字装载抽成公共块,三条来路共用),新增 tb/tb_row_blk35.sv(单元仿真,两个不同大小的矩阵 + 开/关预取周期对照);min_bus 挂 0x3F0 RB_TBLP / 0x3F4 RB_TBLPF / 0x3F8 RB_TBLUS / 0x3FC RB_TBLST / 0x634 RB_TBLCYC / 0x638 SCREEN10 并新增第十观察点 screen10_out;circle35/gen_boot35.py 生成最小 OS(第 35 环试验段);tb/tb_min_soc35.sv 协同仿真。

// rtl/row_blk.sv(节选):段表流式取——借一拍空闲的流式通道,边界不再等表
// 预取就发生在 ST_COMP 那一拍(部分积算在片上,SRAM 读口空着)
wire lk_use_now   = (st == ST_COMP) && !seg_next && tbl_r && tbl_more
                    && tbl_pf_r && lk_valid;
wire lk_issue_now = (st == ST_COMP) && tbl_r && tbl_pf_r && tbl_more
                    && !lk_valid && !lk_req;
assign w_rd_en = w_rd_en_r | lk_issue_now;   // 组合读使能:借一拍,不花额外周期

ST_COMP: begin
    ... 部分积累加进 acc ...
    if (seg_next) begin                       // 本段还有下一块
        blk_r <= blk_r + 1'b1;
        if (lk_issue_now) lk_req <= 1'b1;     // 顺手把下一条表字取回来
    end else if (bnd_now) begin               // 段边界:该翻下一条表了
        if (lk_use_now) begin                 // 缓冲有货 → 零额外周期换段
            lk_valid <= 1'b0;
            tbl_idx_r <= tbl_idx_r + 8'd1;
            st <= ST_FETCH;
        end else if (lk_issue_now) begin      // 缓冲空 → 当场取(只花 1 拍)
            lk_req <= 1'b1; st <= ST_LKW;
        end else st <= ST_TBLD;               // 兜底:第34环阻塞读表(2 拍)
    end
end

// 预取回来的表字下一拍落进前瞻缓冲(表与权重共用同一条流式通道)
if (lk_req && w_rd_valid && (st != ST_LKW)) begin
    lk_data <= w_rd_data; lk_valid <= 1'b1; lk_req <= 1'b0;
end
④ 怎么算成(闭环验证)

测试矩阵 W = [1,2,-1,0 / 0,1,1,-2 / -1,0,2,1 / 2,-1,0,1]、x = [3,-2,5,-4],手算 y = W·x = [-6,11,3,4]。同一张段表(起 0 长 2 / 起 2 长 1 / 起 3 长 1)先关预取、再开预取各跑一遍,最小 OS 在芯片上真跑:

动作结果说明
关预取(第 34 环老路)acc = [-6, 11, 3, 4]= W·x;RB_TBLST = 2(两个段边界都停下等表)
开预取(本环主路)acc = [-6, 11, 3, 4]与关预取逐位一致(只改了「谁等谁」)
流式通道取回的表条数(RB_TBLPF)2段 0 扫着时预取段 1;段 1 边界当场取段 2
零额外周期换段(RB_TBLUS)1边扫边取的硬证据:有一段是直接从前瞻缓冲换过去的
退回阻塞读表(RB_TBLST)0一次都没停下来等表
周期数(RB_TBLCYC)开预取 省 5 拍一个边界命中缓冲省 3 拍 + 一个当场取省 2 拍
改写表第 0 条 → 起 1、长 1(开预取)acc = [-5, 13, 3, 4]预取回来的表字真从内存来(改表结果就变)
SCREEN10 = 0x02010005
流式取的条数 2 | 零停顿换段的段数 1 | 退回阻塞读表的条数 0 | 省下的拍数 5
次字节 1 = 有一段是直接从前瞻缓冲换过去的;第三字节 0 = 一次都没停下等表

单元仿真 tb_row_blk35 把这条通路钉死(两个实例、开/关预取逐组对照):4×4 矩阵 2 段表 → 开预取 31 拍 < 关预取 34 拍(省 3)、RB_TBLUS=1、RB_TBLST=0;3 段表 → 32 < 37(省 5);每段只有一块的短段表 → 34 < 40(省 6,来不及预取也当场取、一条都没退回阻塞读表);8×8、16 块大矩阵 3 段(0..5/6..11/12..15)→ 开预取 115 拍 < 关预取 121 拍(省 6),RB_TBLPF=2、RB_TBLUS=2、RB_TBLST=0,3 段累加与一次整扫逐位一致([-44,13,25,-44,13,25,-44,13]);改写表第 2 条 → 结果跟着变(预取回来的表字真从内存来);空表不挂死;RB_TBLP=0 时前 34 圈老路径逐位一致。协同仿真 tb_min_soc35:SCREEN = 0xF905FD04、SCREEN2 = 0x02040404、SCREEN3 = 0x04000204、SCREEN4 = 0x10200707、SCREEN5 = 0x04081807、SCREEN6 = 0x0402FFFA、SCREEN7 = 0x0403FA04、SCREEN8 = 0x0102FAFB、SCREEN9 = 0x03E3FAFB 与第 25~34 环逐位一致(本环只给行块引擎加了一条流式取表通路,主通路一个字没动);采样序列 [0,2,0,0,0,3]、第 6 步吐停止符 3 而停;全量回归 55 项全绿。

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

从「硬件自己读表」走到「边扫边取、边界不等表」——表读的延迟被扫描本身盖住了:扫这一段的时候,下一段已经到手。真芯片上表的读取是几十上百拍的主存访问,「停下等」和「边走边取」差的就是 NPU 的利用率;段越多,省得越多。段表住在内存里、被硬件一条条流进来,核从「扫描的执行者」彻底退成「声明者」。芯片离「跑真 DeepSeek 权重」又近一层。