File size: 10,353 Bytes
2049fc8
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
// TinyLLama-v0 on the chipformer RV32 machine: int4 weights and 16-bit scales in the 20-bit WROM,
// embedding and scales read with LWROM, WBB emitted whenever a base crosses 32768.
#include <stdint.h>
#include "rt.h"
#include "weights_tl.h"

#ifndef NTOK
#define NTOK 4
#endif
#define W 32

#define VDOT(acc, a, b) __asm__ volatile(".insn r 0x0B, 5, 0, %0, %1, %2" : "+r"(acc) : "r"(a), "r"(b))
#define SMAQA(acc, a, b) __asm__ volatile(".insn r 0x0B, 7, 0, %0, %1, %2" : "+r"(acc) : "r"(a), "r"(b))
#define WBB(v) __asm__ volatile(".insn r 0x0B, 6, 1, zero, %0, zero" :: "r"(v))
#define WBSET(v) __asm__ volatile(".insn r 0x0B, 6, 0, zero, %0, zero" :: "r"(v))
static inline uint32_t lwrom(uint32_t a) {
    uint32_t r;
    __asm__ volatile(".insn r 0x0B, 6, 2, %0, %1, zero" : "=r"(r) : "r"(a));
    return r;
}

static int32_t x[DIM], xb[DIM], q[DIM], kk[KVD], vv[KVD], hb[HID], hb2[HID];
static int8_t xq[256] __attribute__((aligned(4)));
static int8_t kq[NL][W][KVD] __attribute__((aligned(4)));
static int8_t vt[NL][KVD][W] __attribute__((aligned(4)));
static int8_t pp[W] __attribute__((aligned(4)));
static int32_t vmax;
#define DBG(i, v) (((volatile int32_t *)0xE000)[(i)] = (v))

static inline int32_t mulh(int32_t a, int32_t b) { return (int32_t)(((int64_t)a * b) >> 32); }
#define TRACK(v) do { int32_t a_ = (v) < 0 ? -(v) : (v); if (a_ > vmax) vmax = a_; } while (0)

static int32_t quantize(const int32_t *v, int n, int32_t amax) {
    if (amax < 256) amax = 256;
    int32_t r = 0x7F000000 / amax, h = amax / 254;
#pragma GCC unroll 4
    for (int i = 0; i < n; i++) xq[i] = (int8_t)mulh((v[i] + h) << 8, r);
    return amax;
}

static int32_t norm_f(void) {
    int32_t ss = 0;
#pragma GCC unroll 8
    for (int i = 0; i < DIM; i++) ss += xq[i] * xq[i];
    uint32_t m = (uint32_t)ss << 10, r = 0, b = 1u << 30;
    while (b > m) b >>= 2;
    while (b) {
        if (m >= r + b) { m -= r + b; r = (r >> 1) + b; } else r >>= 1;
        b >>= 2;
    }
    return (int32_t)((0x80000000u / r) << 10);
}

static int32_t plain_f(int32_t amax) { return (int32_t)(((uint32_t)amax << 9) / 127 << 8); }

extern void vk_8_init_scaled(int32_t *, int, int, const int32_t *, int32_t);
extern void vk_8_init_raw(int32_t *, int, int, const int32_t *, int32_t);
extern void vk_8_acc_raw(int32_t *, int, int, const int32_t *, int32_t);
const int8_t *vk_x;

static void matvec(int32_t *out, const int32_t *starts, int nchunk, int32_t sc, int rows, int32_t f) {
    int cu[4], co[4];
    for (int c = 0; c < nchunk; c++) { cu[c] = starts[c] >> 10; co[c] = starts[c] & 0x3FF; }
    int su = sc >> 10, so = sc & 0x3FF;
    for (int r = 0; r < rows; r += 4) {
        uint32_t w0 = lwrom((su << 10) | so); so++; if (so >= 960) { su++; so = 0; }
        uint32_t w1 = lwrom((su << 10) | so); so++; if (so >= 960) { su++; so = 0; }
        int32_t S4[4] = {(int32_t)(w0 & 0xFFFF), (int32_t)((w0 >> 16) & 0xFFFF),
                         (int32_t)(w1 & 0xFFFF), (int32_t)((w1 >> 16) & 0xFFFF)};
        if (nchunk == 1) {
            vk_x = xq;
            vk_8_init_scaled(out + r, (cu[0] << 10) | co[0], 4, S4, f);
        } else {
            for (int c = 0; c < nchunk; c++) {
                vk_x = xq + 64 * c;
                int32_t base = (cu[c] << 10) | co[c];
                if (c == 0) vk_8_init_raw(out + r, base, 4, 0, 0);
                else vk_8_acc_raw(out + r, base, 4, 0, 0);
            }
            for (int k = 0; k < 4; k++) out[r + k] = mulh(out[r + k] * S4[k], f);
        }
        for (int c = 0; c < nchunk; c++) {
            co[c] += 32;
            if (co[c] + 32 > 960) { cu[c]++; co[c] = 0; }
        }
    }
}

static void rope(int32_t *v, int pos, int n) {
    const int16_t *t = ROPE + pos * HS;
    for (int i = 0; i < n; i += 2) {
        int32_t c = t[i % HS], s = t[i % HS + 1], a = v[i] >> 6, b = v[i + 1] >> 6;
        v[i] = (a * c - b * s) >> 8;
        v[i + 1] = (a * s + b * c) >> 8;
    }
}

static inline int8_t q8_of(int32_t v, int32_t r, int32_t h) {
    int32_t t = mulh((v + (v < 0 ? -h : h)) << 8, r);
    return (int8_t)(t > 127 ? 127 : t < -127 ? -127 : t);
}
static inline uint32_t pack4(const int8_t *b) {
    return (uint8_t)b[0] | (uint8_t)b[1] << 8 | (uint8_t)b[2] << 16 | (uint32_t)(uint8_t)b[3] << 24;
}

_Static_assert(HS == 4, "attend packs one 32-bit word per head");

static void attend(int l, int h, int n) {
    const int32_t *qv = q + h * HS;
    int32_t amax = 256;
    for (int j = 0; j < HS; j++) { int32_t a = qv[j] < 0 ? -qv[j] : qv[j]; if (a > amax) amax = a; }
    int32_t r = 0x7F000000 / amax, hf = amax / 254;
    int8_t b[HS];
    for (int j = 0; j < HS; j++) b[j] = q8_of(qv[j], r, hf);
    uint32_t q0 = pack4(b);
    int64_t ca64 = ((((int64_t)amax * KMAX[l]) >> 10) * ATT_C) >> 16;
    int32_t ca = ca64 > INT32_MAX ? INT32_MAX : (int32_t)ca64;
    int32_t sc[W], m = INT32_MIN;
    for (int t = 0; t < n; t++) {
        const uint32_t *kw = (const uint32_t *)&kq[l][t][h * HS];
        int32_t s = 0;
        SMAQA(s, q0, kw[0]);
        sc[t] = s;
        if (s > m) m = s;
    }
    int32_t sum = 0;
    for (int t = 0; t < n; t++) {
        int32_t i = mulh(m - sc[t], ca);
        int32_t p = (i >= 0 && i < 256) ? P8[i] : 0;
        pp[t] = (int8_t)p;
        sum += p;
    }
    int nw = (n + 3) >> 2;
    for (int t = n; t < 4 * nw; t++) pp[t] = 0;
    int32_t o[HS] = {0};
    for (int w = 0; w < nw; w++) {
        uint32_t p0 = ((const uint32_t *)pp)[w];
        for (int j = 0; j < HS; j++) {
            uint32_t vw = ((const uint32_t *)vt[l][h * HS + j])[w];
            SMAQA(o[j], p0, vw);
        }
    }
    int32_t rr = (VMAX[l] << 12) / (127 * sum);
    for (int j = 0; j < HS; j++) {
        xb[h * HS + j] = (int32_t)(((int64_t)o[j] * rr) >> 12);
        TRACK(xb[h * HS + j]);
    }
}

static void pnum(int32_t v) {
    char b[12]; int n = 0, neg = v < 0;
    uint32_t u = neg ? -(uint32_t)v : (uint32_t)v;
    if (!u) b[n++] = '0';
    while (u) { b[n++] = (char)('0' + u % 10); u /= 10; }
    if (neg) rv_putchar('-');
    while (n) rv_putchar(b[--n]);
    rv_putchar(' ');
}

static void embed(int tok, int32_t S) {
    int g = tok >> 2, rr = tok & 3;
    int total = (G_EMB & 0x3FF) + g * 32;
    int unit = (G_EMB >> 10) + total / 960, off = total % 960;
    int32_t base = ((unit << 10) | off) + rr * 8;
    for (int k = 0; k < 8; k++) {
        uint32_t w = lwrom(base + k);
        for (int j = 0; j < 8; j++) {
            int32_t v = (int32_t)((w >> (4 * j)) & 15) - 8;
            x[8 * k + j] = (int32_t)((int64_t)v * S * 2);
        }
    }
    for (int i = 0; i < DIM; i++) TRACK(x[i]);
}

static int32_t emb_scale(int tok) {
    int g = tok >> 2, rr = tok & 3;
    int total = (SC_EMB & 0x3FF) + g * 2 + (rr >> 1);
    int su = (SC_EMB >> 10) + total / 960, so = total % 960;
    uint32_t sw = lwrom((su << 10) | so);
    return (int32_t)((sw >> (16 * (rr & 1))) & 0xFFFF);
}

int main(void) {
    int tok = 1;
    for (int pos = 0; pos < NTOK; pos++) {
        vmax = 0;
        embed(tok, emb_scale(tok));
        DBG(0, x[0]);

        for (int l = 0; l < NL; l++) {
            quantize(x, DIM, vmax);
            int32_t f = norm_f();
            if (l == 0) { DBG(1, xq[0]); DBG(2, f); }
            matvec(q, &G_q[l], 1, SC_q[l], DIM, f);
            matvec(kk, &G_k[l], 1, SC_k[l], DIM, f);
            matvec(vv, &G_v[l], 1, SC_v[l], DIM, f);
            if (l == 0) { DBG(3, q[0]); DBG(4, kk[0]); DBG(5, vv[0]); }

            rope(q, pos, DIM);
            rope(kk, pos, KVD);
            int slot = pos == 0 ? 0 : 1 + (pos - 1) % (W - 1), n = pos + 1 < W ? pos + 1 : W;
            int32_t kr = 0x7F000000 / KMAX[l], kh = KMAX[l] / 254;
            int32_t vr = 0x7F000000 / VMAX[l], vh = VMAX[l] / 254;
            for (int i = 0; i < KVD; i++) {
                kq[l][slot][i] = q8_of(kk[i], kr, kh);
                vt[l][i][slot] = q8_of(vv[i], vr, vh);
            }
            vmax = 0;
            for (int h = 0; h < NH; h++) attend(l, h, n);
            if (l == 0) DBG(6, xb[0]);
            int32_t amax = quantize(xb, DIM, vmax);
            matvec(q, &G_o[l], 1, SC_o[l], DIM, plain_f(amax));
            vmax = 0;
            for (int i = 0; i < DIM; i++) { x[i] += q[i]; TRACK(x[i]); }
            if (l == 0) DBG(7, x[0]);
            quantize(x, DIM, vmax);
            f = norm_f();
            matvec(hb, &G_gate[l], 1, SC_gate[l], HID, f);
            matvec(hb2, &G_up[l], 1, SC_up[l], HID, f);
            vmax = 0;
            for (int i = 0; i < HID; i++) {
                int32_t a = hb[i], s;
                if (a >= 8 << 16) s = a >> 4;
                else if (a < -(8 << 16)) s = 0;
                else s = SILU[(a >> 11) + 256];
                hb[i] = (s * (hb2[i] >> 8)) >> 4;
                TRACK(hb[i]);
            }
            amax = quantize(hb, HID, vmax);
            if (l == 0) DBG(8, hb[0]);
            matvec(q, &G_down[4 * l], 4, SC_down[l], DIM, plain_f(amax));
            vmax = 0;
            for (int i = 0; i < DIM; i++) { x[i] += q[i]; TRACK(x[i]); }
            DBG(9 + l, x[0]);
        }
        quantize(x, DIM, vmax);
        DBG(30, xq[0]); DBG(31, xq[1]); DBG(32, vmax);
        int best = 0, bv = INT32_MIN;
        int unit = G_HEAD >> 10, off = G_HEAD & 0x3FF;
        int su = SC_HEAD >> 10, so = SC_HEAD & 0x3FF;
        int32_t tmp[4];
        for (int g = 0; g < VOCAB / 4; g++) {
            uint32_t w0 = lwrom((su << 10) | so); so++; if (so >= 960) { su++; so = 0; }
            uint32_t w1 = lwrom((su << 10) | so); so++; if (so >= 960) { su++; so = 0; }
            int32_t S4[4] = {(int32_t)(w0 & 0xFFFF), (int32_t)((w0 >> 16) & 0xFFFF),
                             (int32_t)(w1 & 0xFFFF), (int32_t)((w1 >> 16) & 0xFFFF)};
            int32_t base = (unit << 10) | off;
            vk_x = xq;
            vk_8_init_scaled(tmp, base, 4, S4, 1 << 30);
            for (int k = 0; k < 4; k++) if (tmp[k] > bv) { bv = tmp[k]; best = g * 4 + k; }
            off += 32; if (off + 32 > 960) { unit++; off = 0; }
        }
        DBG(100 + pos, best); DBG(200 + pos, bv);
        { int b = best, n = 0; char buf[8];
          if (!b) buf[n++] = '0';
          while (b) { buf[n++] = (char)('0' + b % 10); b /= 10; }
          while (n) rv_putchar(buf[--n]); }
        rv_putchar(' ');
        tok = best;
    }
    rv_putchar('\n');
    return 0;
}