第 43 环 · 权重池 ISA 化(一条 npu.pool 锁住整池)
第 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 → 2 | WC_PF2: 1 → 0 → 1 | 池深真管事:三 bank ↔ 两 bank 乒乓 |
| 一条指令配出的池跑整网 | Q 趟 == A 趟 | 输出 0xF905FD04,lane0 = 0x07;配置真被引擎消费 |
| 全零配置 | 六个寄存器全归零,POOL_N 照数 | 关池也是一条真指令,不是「没执行」 |
| 老路 / 主通路 | 逐位一致 | SCREEN/2/3/17 与前几环同值,老路径一条没删 |
单元仿真 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 都要重配一遍权重通路;配置从六次总线写变成一次指令,省下的是每次解码的固定开销,也让编译器/驱动更难写错。到后面做「一条指令跑完一次完整解码」时,这一层就是那块最稳的地基。
池子已经能一条指令配好,可一次解码仍要核发 npu.net → npu.wait → npu.rd,再自己调 LM 头、采样器、生成控制器——「一步生成」在软件里仍是一串动作。下一环把这串也收进一条 npu.step:一条指令跑完「整网 → LM 头 → 采样 → 登记」,核只读回 next_token 与 done。