第 13 环 · 多层堆叠(端到端迷你 Transformer)
同一个圆心:一台开机只有一个 AI 的手机。上一环结束,芯片上已经有了一个「可堆叠的 Transformer 块」(注意力 → 残差 → FFN → 残差 → LN)。但真实的 Transformer 是几十层同样的块摞起来,而且不是把几十份硬件画一遍——是同一份硬件被复用 N 次。要让块能被复用,缺的是:层与层之间的残差流(隐藏状态 x)得有地方「活着」。上一环算完一层,残差流就散在寄存器读口上,没有驻留、没有层号,下一层无从接续。本环把这块补上:片上一份残差流寄存器堆,加上一个层控制器,让同一份硬件端到端跑完 2 层——从 token 的初始隐藏状态进场,到第 2 层输出出场,全程在一颗芯片上。
延续「端上算力紧凑、全部定点、栈深靠复用不靠堆硬件」的主线,新增一个很小的模块 layer_stack:
· 片上一份残差流寄存器堆 XSR(4 lane × 8bit,INT8)=当前 token 的隐藏状态 x;
· LST_X:核写一次,把初始隐藏状态装进 XSR,层号归零;
· LST_ADV:每层块跑完,核写一次,硬件把 resid_ln 引擎吐出的归一化输出低 8bit/lane 直接锁回 XSR,层号 +1——这一步是纯硬件数据通路,核只喊一声,不搬运隐藏状态;
· LST_LAYER_N:设定目标层数;done = (层号 ≥ 目标层数),软件轮询它判断整网跑完。
硬件不新增乘法器、不新增存储阵列——只把「残差流住在哪、层号由谁记」这两件事做成寄存器,栈深就任意了。这正是「为别人搭台」的底层思路:算力是可复用的公摊。
新增 rtl/layer_stack.sv:残差流寄存器堆 + 层控制器,硬件数据通路 resid_ln → XSR:
装载: x_wr → XSR = x_in;layer_idx = 0 推进: adv → XSR[l] = ln_in[l][7:0](逐 lane 低字节);layer_idx++ 层数: n_wr → layer_n = n_in 完成: done = (layer_idx >= layer_n)
min_bus.sv 挂载 layer_stack,新映射:
0x0D8 → LST_X 写初始残差流 x → 装进 XSR,层号归零 0x0DC → LST_ADV 写 1 → resid_ln 输出锁回 XSR,层号 +1(硬件数据通路) 0x0E0 → LST_LAYER_N 写目标层数 0x0E4 → LST_X0 读当前残差流 lane0(32bit 有符号) 0x0E8 → LST_X1 读 lane1 0x0EC → LST_X2 读 lane2 0x0F0 → LST_X3 读 lane3 0x0F4 → LST_IDX 读当前已完成层号 0x0F8 → LST_DONE 读整网是否跑完(层号 >= 目标层数)
最小 OS 用同一份硬件依次跑 2 层,每层都是完整的「注意力 → 残差LN → FFN → 残差LN」,跑完 LST_ADV 把残差流推进下一层:
预填充 KV(4 槽) → LST_X 装 x0 → LST_LAYER_N=2 → 配 gamma/beta/W1/W2
for 层 in [1,2]: # Q 逐层不同(0x4321 → 0x1234)
QK^T 算分 → Softmax 归一化 → 加权 V
resid_ln(a=注意力输出, b=XSR) # 残差 + LayerNorm #1
FFN(LN 输出) → resid_ln(a=FFN, b=LN#1) # 残差 + LayerNorm #2
LST_ADV # 块输出锁回 XSR,进下一层
读 XSR → 屏幕
这一环最直观的是两层真的在算同一份硬件、残差流真的在层间传递:
· 层1 用 Q=[1,2,3,4],算分 [1,2,3,4],Softmax 权重 [8,22,60,164],加权 V 得 [0,0,0,1];与初始残差流 [10,-6,4,-8] 做残差+LN 得 [12,-8,5,-9],过 FFN(两层线性+ReLU)得 [17,17,17,17],再残差+LN 得层1输出 [15,-11,6,-12];
· LST_ADV 把这 4 个数写回 XSR,层号 0→1;
· 层2 换 Q=[4,3,2,1],同样的块再算一遍,得 [26,-17,10,-18]——与层1 明显不同,证明第二层真的用了第一层的输出,而不是原地重复;
· 屏幕 0xEE0AEF1A = 3993693978,与软件参考模型逐位一致。
单元仿真另外验证了「重新装载 → 层号归零」(下一个 token 进场)与「走到目标层数 → done 拉高」。至此同一份硬件可依次跑完 N 层,多层堆叠端到端在芯片上闭合。
本环走完一整圈:目标 → 大模型是几十层块摞起来的,只要残差流能驻留、层号能记,同一份硬件就能复用 N 次 → 硬件只加一份小寄存器堆 + 层控制器,把 resid_ln → XSR 做成数据通路,栈深不再吃芯片面积 → 2 层端到端跑通、单元仿真 + 回归全绿 → 回到目标。这块芯片第一次从「一个块」变成「一个能深的小模型」:token 进、经过 N 层块的级联、隐藏状态出。离一台本地跑大模型的手机,又近一圈。下一层要补的是最前面缺的一块拼图——现在的 Q 还是核直接塞进去的常数,真模型里 Q/K/V 都得由输入投影出来。
第 14 环:QKV 投影 · 从残差流算 Q/K/V——把这个「手塞常数 Q」的关节换成真投影:用片上矩阵乘做 x·W_q、x·W_k、x·W_v,Q/K/V 全部由残差流算出,注意力从此端到端自洽。