xref: /aosp_15_r20/external/mesa3d/src/freedreno/decode/script.c (revision 6104692788411f58d303aa86923a9ff6ecaded22)
1 /* -*- mode: C; c-file-style: "k&r"; tab-width 4; indent-tabs-mode: t; -*- */
2 
3 /*
4  * Copyright © 2014 Rob Clark <[email protected]>
5  * SPDX-License-Identifier: MIT
6  *
7  * Authors:
8  *    Rob Clark <[email protected]>
9  */
10 
11 #define LUA_COMPAT_APIINTCASTS
12 
13 #include <assert.h>
14 #include <lauxlib.h>
15 #include <lua.h>
16 #include <lualib.h>
17 #include <stdio.h>
18 #include <stdlib.h>
19 #include <string.h>
20 #include "util/u_math.h"
21 
22 #include "cffdec.h"
23 #include "rnnutil.h"
24 #include "script.h"
25 
26 static lua_State *L;
27 
28 #if 0
29 #define DBG(fmt, ...)                                                          \
30    do {                                                                        \
31       printf(" ** %s:%d ** " fmt "\n", __func__, __LINE__, ##__VA_ARGS__);     \
32    } while (0)
33 #else
34 #define DBG(fmt, ...)                                                          \
35    do {                                                                        \
36    } while (0)
37 #endif
38 
39 /* An rnn based decoder, which can either be decoding current register
40  * values, or domain based decoding of a pm4 packet.
41  *
42  */
43 struct rnndec {
44    struct rnn base;
45 
46    /* for pm4 packet decoding: */
47    uint32_t sizedwords;
48    uint32_t *dwords;
49 };
50 
51 static inline struct rnndec *
to_rnndec(struct rnn * rnn)52 to_rnndec(struct rnn *rnn)
53 {
54    return (struct rnndec *)rnn;
55 }
56 
57 static uint32_t
rnn_val(struct rnn * rnn,uint32_t regbase)58 rnn_val(struct rnn *rnn, uint32_t regbase)
59 {
60    struct rnndec *rnndec = to_rnndec(rnn);
61 
62    if (!rnndec->sizedwords) {
63       return reg_val(regbase);
64    } else if (regbase < rnndec->sizedwords) {
65       return rnndec->dwords[regbase];
66    } else {
67       // XXX throw an error
68       return -1;
69    }
70 }
71 
72 /* does not return */
73 static void
error(const char * fmt)74 error(const char *fmt)
75 {
76    fprintf(stderr, fmt, lua_tostring(L, -1));
77    exit(1);
78 }
79 
80 /*
81  * An enum type that can be used as string or number:
82  */
83 
84 struct rnndenum {
85    const char *str;
86    int val;
87 };
88 
89 static int
l_meta_rnn_enum_tostring(lua_State * L)90 l_meta_rnn_enum_tostring(lua_State *L)
91 {
92    struct rnndenum *e = lua_touserdata(L, 1);
93    if (e->str) {
94       lua_pushstring(L, e->str);
95    } else {
96       char buf[32];
97       sprintf(buf, "%u", e->val);
98       lua_pushstring(L, buf);
99    }
100    return 1;
101 }
102 
103 /* so, this doesn't actually seem to be implemented yet, but hopefully
104  * some day lua comes to it's senses
105  */
106 static int
l_meta_rnn_enum_tonumber(lua_State * L)107 l_meta_rnn_enum_tonumber(lua_State *L)
108 {
109    struct rnndenum *e = lua_touserdata(L, 1);
110    lua_pushinteger(L, e->val);
111    return 1;
112 }
113 
114 static const struct luaL_Reg l_meta_rnn_enum[] = {
115    {"__tostring", l_meta_rnn_enum_tostring},
116    {"__tonumber", l_meta_rnn_enum_tonumber},
117    {NULL, NULL} /* sentinel */
118 };
119 
120 static void
pushenum(struct lua_State * L,int val,struct rnnenum * info)121 pushenum(struct lua_State *L, int val, struct rnnenum *info)
122 {
123    struct rnndenum *e = lua_newuserdata(L, sizeof(*e));
124 
125    e->val = val;
126    e->str = NULL;
127 
128    for (int i = 0; i < info->valsnum; i++) {
129       if (info->vals[i]->valvalid && (info->vals[i]->value == val)) {
130          e->str = info->vals[i]->name;
131          break;
132       }
133    }
134 
135    luaL_newmetatable(L, "rnnmetaenum");
136    luaL_setfuncs(L, l_meta_rnn_enum, 0);
137    lua_pop(L, 1);
138 
139    luaL_setmetatable(L, "rnnmetaenum");
140 }
141 
142 /* Expose rnn decode to script environment as "rnn" library:
143  */
144 
145 struct rnndoff {
146    struct rnn *rnn;
147    struct rnndelem *elem;
148    uint64_t offset;
149 };
150 
151 static void
push_rnndoff(lua_State * L,struct rnn * rnn,struct rnndelem * elem,uint64_t offset)152 push_rnndoff(lua_State *L, struct rnn *rnn, struct rnndelem *elem,
153              uint64_t offset)
154 {
155    struct rnndoff *rnndoff = lua_newuserdata(L, sizeof(*rnndoff));
156    rnndoff->rnn = rnn;
157    rnndoff->elem = elem;
158    rnndoff->offset = offset;
159 }
160 
161 static int l_rnn_etype_array(lua_State *L, struct rnn *rnn,
162                              struct rnndelem *elem, uint64_t offset);
163 static int l_rnn_etype_reg(lua_State *L, struct rnn *rnn, struct rnndelem *elem,
164                            uint64_t offset);
165 
166 static int
pushdecval(struct lua_State * L,struct rnn * rnn,uint64_t regval,struct rnntypeinfo * info)167 pushdecval(struct lua_State *L, struct rnn *rnn, uint64_t regval,
168            struct rnntypeinfo *info)
169 {
170    union rnndecval val;
171    switch (rnn_decodelem(rnn, info, regval, &val)) {
172    case RNN_TTYPE_ENUM:
173    case RNN_TTYPE_INLINE_ENUM:
174       pushenum(L, val.i, info->eenum);
175       return 1;
176    case RNN_TTYPE_INT:
177       lua_pushinteger(L, val.i);
178       return 1;
179    case RNN_TTYPE_UINT:
180    case RNN_TTYPE_HEX:
181       lua_pushunsigned(L, val.u);
182       return 1;
183    case RNN_TTYPE_FLOAT:
184       lua_pushnumber(L, uif(val.u));
185       return 1;
186    case RNN_TTYPE_BOOLEAN:
187       lua_pushboolean(L, val.u);
188       return 1;
189    case RNN_TTYPE_INVALID:
190    default:
191       return 0;
192    }
193 }
194 
195 static int
l_rnn_etype(lua_State * L,struct rnn * rnn,struct rnndelem * elem,uint64_t offset)196 l_rnn_etype(lua_State *L, struct rnn *rnn, struct rnndelem *elem,
197             uint64_t offset)
198 {
199    int ret;
200    uint64_t regval;
201    DBG("elem=%p (%d), offset=%lu", elem, elem->type, offset);
202    switch (elem->type) {
203    case RNN_ETYPE_REG:
204       /* if a register has no bitfields, just return
205        * the raw value:
206        */
207       regval = rnn_val(rnn, offset);
208       if (elem->width == 64)
209          regval |= (uint64_t)rnn_val(rnn, offset + 1) << 32;
210       regval <<= elem->typeinfo.shr;
211       ret = pushdecval(L, rnn, regval, &elem->typeinfo);
212       if (ret)
213          return ret;
214       return l_rnn_etype_reg(L, rnn, elem, offset);
215    case RNN_ETYPE_ARRAY:
216       return l_rnn_etype_array(L, rnn, elem, offset);
217    default:
218       /* hmm.. */
219       printf("unhandled type: %d\n", elem->type);
220       return 0;
221    }
222 }
223 
224 /*
225  * Struct Object:
226  * To implement stuff like 'RB_MRT[n].CONTROL' we need a struct-object
227  * to represent the current array index (ie. 'RB_MRT[n]')
228  */
229 
230 static int
l_rnn_struct_meta_index(lua_State * L)231 l_rnn_struct_meta_index(lua_State *L)
232 {
233    struct rnndoff *rnndoff = lua_touserdata(L, 1);
234    const char *name = lua_tostring(L, 2);
235    struct rnndelem *elem = rnndoff->elem;
236    int i;
237 
238    for (i = 0; i < elem->subelemsnum; i++) {
239       struct rnndelem *subelem = elem->subelems[i];
240       if (!strcmp(name, subelem->name)) {
241          return l_rnn_etype(L, rnndoff->rnn, subelem,
242                             rnndoff->offset + subelem->offset);
243       }
244    }
245 
246    return 0;
247 }
248 
249 static const struct luaL_Reg l_meta_rnn_struct[] = {
250    {"__index", l_rnn_struct_meta_index}, {NULL, NULL} /* sentinel */
251 };
252 
253 static int
l_rnn_etype_struct(lua_State * L,struct rnn * rnn,struct rnndelem * elem,uint64_t offset)254 l_rnn_etype_struct(lua_State *L, struct rnn *rnn, struct rnndelem *elem,
255                    uint64_t offset)
256 {
257    push_rnndoff(L, rnn, elem, offset);
258 
259    luaL_newmetatable(L, "rnnmetastruct");
260    luaL_setfuncs(L, l_meta_rnn_struct, 0);
261    lua_pop(L, 1);
262 
263    luaL_setmetatable(L, "rnnmetastruct");
264 
265    return 1;
266 }
267 
268 /*
269  * Array Object:
270  */
271 
272 static int
l_rnn_array_meta_index(lua_State * L)273 l_rnn_array_meta_index(lua_State *L)
274 {
275    struct rnndoff *rnndoff = lua_touserdata(L, 1);
276    int idx = lua_tointeger(L, 2);
277    struct rnndelem *elem = rnndoff->elem;
278    uint64_t offset = rnndoff->offset + (elem->stride * idx);
279 
280    DBG("rnndoff=%p, idx=%d, numsubelems=%d", rnndoff, idx,
281        rnndoff->elem->subelemsnum);
282 
283    /* if just a single sub-element, it is directly a register,
284     * otherwise we need to accumulate the array index while
285     * we wait for the register name within the array..
286     */
287    if (elem->subelemsnum == 1) {
288       return l_rnn_etype(L, rnndoff->rnn, elem->subelems[0], offset);
289    } else {
290       return l_rnn_etype_struct(L, rnndoff->rnn, elem, offset);
291    }
292 
293    return 0;
294 }
295 
296 static const struct luaL_Reg l_meta_rnn_array[] = {
297    {"__index", l_rnn_array_meta_index}, {NULL, NULL} /* sentinel */
298 };
299 
300 static int
l_rnn_etype_array(lua_State * L,struct rnn * rnn,struct rnndelem * elem,uint64_t offset)301 l_rnn_etype_array(lua_State *L, struct rnn *rnn, struct rnndelem *elem,
302                   uint64_t offset)
303 {
304    push_rnndoff(L, rnn, elem, offset);
305 
306    luaL_newmetatable(L, "rnnmetaarray");
307    luaL_setfuncs(L, l_meta_rnn_array, 0);
308    lua_pop(L, 1);
309 
310    luaL_setmetatable(L, "rnnmetaarray");
311 
312    return 1;
313 }
314 
315 /*
316  * Register element:
317  */
318 
319 static int
l_rnn_reg_meta_index(lua_State * L)320 l_rnn_reg_meta_index(lua_State *L)
321 {
322    struct rnndoff *rnndoff = lua_touserdata(L, 1);
323    const char *name = lua_tostring(L, 2);
324    struct rnndelem *elem = rnndoff->elem;
325    struct rnntypeinfo *info = &elem->typeinfo;
326    struct rnnbitfield **bitfields;
327    int bitfieldsnum;
328    int i;
329 
330    switch (info->type) {
331    case RNN_TTYPE_BITSET:
332       bitfields = info->ebitset->bitfields;
333       bitfieldsnum = info->ebitset->bitfieldsnum;
334       break;
335    case RNN_TTYPE_INLINE_BITSET:
336       bitfields = info->bitfields;
337       bitfieldsnum = info->bitfieldsnum;
338       break;
339    default:
340       printf("invalid register type: %d\n", info->type);
341       return 0;
342    }
343 
344    for (i = 0; i < bitfieldsnum; i++) {
345       struct rnnbitfield *bf = bitfields[i];
346       if (!strcmp(name, bf->name)) {
347          uint32_t regval = rnn_val(rnndoff->rnn, rnndoff->offset);
348 
349          regval &= typeinfo_mask(&bf->typeinfo);
350          regval >>= bf->typeinfo.low;
351          regval <<= bf->typeinfo.shr;
352 
353          DBG("name=%s, info=%p, subelemsnum=%d, type=%d, regval=%x", name, info,
354              rnndoff->elem->subelemsnum, bf->typeinfo.type, regval);
355 
356          return pushdecval(L, rnndoff->rnn, regval, &bf->typeinfo);
357       }
358    }
359 
360    printf("invalid member: %s\n", name);
361    return 0;
362 }
363 
364 static int
l_rnn_reg_meta_tostring(lua_State * L)365 l_rnn_reg_meta_tostring(lua_State *L)
366 {
367    struct rnndoff *rnndoff = lua_touserdata(L, 1);
368    uint32_t regval = rnn_val(rnndoff->rnn, rnndoff->offset);
369    struct rnndecaddrinfo *info = rnn_reginfo(rnndoff->rnn, rnndoff->offset);
370    char *decoded;
371    if (info && info->typeinfo) {
372       decoded = rnndec_decodeval(rnndoff->rnn->vc, info->typeinfo, regval);
373    } else {
374       asprintf(&decoded, "%08x", regval);
375    }
376    lua_pushstring(L, decoded);
377    free(decoded);
378    rnn_reginfo_free(info);
379    return 1;
380 }
381 
382 static int
l_rnn_reg_meta_tonumber(lua_State * L)383 l_rnn_reg_meta_tonumber(lua_State *L)
384 {
385    struct rnndoff *rnndoff = lua_touserdata(L, 1);
386    uint32_t regval = rnn_val(rnndoff->rnn, rnndoff->offset);
387 
388    regval <<= rnndoff->elem->typeinfo.shr;
389 
390    lua_pushnumber(L, regval);
391    return 1;
392 }
393 
394 static const struct luaL_Reg l_meta_rnn_reg[] = {
395    {"__index", l_rnn_reg_meta_index},
396    {"__tostring", l_rnn_reg_meta_tostring},
397    {"__tonumber", l_rnn_reg_meta_tonumber},
398    {NULL, NULL} /* sentinel */
399 };
400 
401 static int
l_rnn_etype_reg(lua_State * L,struct rnn * rnn,struct rnndelem * elem,uint64_t offset)402 l_rnn_etype_reg(lua_State *L, struct rnn *rnn, struct rnndelem *elem,
403                 uint64_t offset)
404 {
405    push_rnndoff(L, rnn, elem, offset);
406 
407    luaL_newmetatable(L, "rnnmetareg");
408    luaL_setfuncs(L, l_meta_rnn_reg, 0);
409    lua_pop(L, 1);
410 
411    luaL_setmetatable(L, "rnnmetareg");
412 
413    return 1;
414 }
415 
416 /*
417  *
418  */
419 
420 static int
l_rnn_meta_index(lua_State * L)421 l_rnn_meta_index(lua_State *L)
422 {
423    struct rnn *rnn = lua_touserdata(L, 1);
424    const char *name = lua_tostring(L, 2);
425    struct rnndelem *elem;
426 
427    elem = rnn_regelem(rnn, name);
428    if (!elem)
429       return 0;
430 
431    return l_rnn_etype(L, rnn, elem, elem->offset);
432 }
433 
434 static int
l_rnn_meta_gc(lua_State * L)435 l_rnn_meta_gc(lua_State *L)
436 {
437    // TODO
438    // struct rnn *rnn = lua_touserdata(L, 1);
439    // rnn_deinit(rnn);
440    return 0;
441 }
442 
443 static const struct luaL_Reg l_meta_rnn[] = {
444    {"__index", l_rnn_meta_index},
445    {"__gc", l_rnn_meta_gc},
446    {NULL, NULL} /* sentinel */
447 };
448 
449 static int
l_rnn_init(lua_State * L)450 l_rnn_init(lua_State *L)
451 {
452    const char *gpuname = lua_tostring(L, 1);
453    struct rnndec *rnndec = lua_newuserdata(L, sizeof(*rnndec));
454    _rnn_init(&rnndec->base, 0);
455    rnn_load(&rnndec->base, gpuname);
456    rnndec->sizedwords = 0;
457 
458    luaL_newmetatable(L, "rnnmeta");
459    luaL_setfuncs(L, l_meta_rnn, 0);
460    lua_pop(L, 1);
461 
462    luaL_setmetatable(L, "rnnmeta");
463 
464    return 1;
465 }
466 
467 static int
l_rnn_enumname(lua_State * L)468 l_rnn_enumname(lua_State *L)
469 {
470    struct rnn *rnn = lua_touserdata(L, 1);
471    const char *name = lua_tostring(L, 2);
472    uint32_t val = (uint32_t)lua_tonumber(L, 3);
473    lua_pushstring(L, rnn_enumname(rnn, name, val));
474    return 1;
475 }
476 
477 static int
l_rnn_regname(lua_State * L)478 l_rnn_regname(lua_State *L)
479 {
480    struct rnn *rnn = lua_touserdata(L, 1);
481    uint32_t regbase = (uint32_t)lua_tonumber(L, 2);
482    lua_pushstring(L, rnn_regname(rnn, regbase, 1));
483    return 1;
484 }
485 
486 static int
l_rnn_regval(lua_State * L)487 l_rnn_regval(lua_State *L)
488 {
489    struct rnn *rnn = lua_touserdata(L, 1);
490    uint32_t regbase = (uint32_t)lua_tonumber(L, 2);
491    uint32_t regval = (uint32_t)lua_tonumber(L, 3);
492    struct rnndecaddrinfo *info = rnn_reginfo(rnn, regbase);
493    char *decoded;
494    if (info && info->typeinfo) {
495       decoded = rnndec_decodeval(rnn->vc, info->typeinfo, regval);
496    } else {
497       asprintf(&decoded, "%08x", regval);
498    }
499    lua_pushstring(L, decoded);
500    free(decoded);
501    rnn_reginfo_free(info);
502    return 1;
503 }
504 
505 static const struct luaL_Reg l_rnn[] = {
506    {"init", l_rnn_init},
507    {"enumname", l_rnn_enumname},
508    {"regname", l_rnn_regname},
509    {"regval", l_rnn_regval},
510    {NULL, NULL} /* sentinel */
511 };
512 
513 /* Expose the register state to script enviroment as a "regs" library:
514  */
515 
516 static int
l_reg_written(lua_State * L)517 l_reg_written(lua_State *L)
518 {
519    uint32_t regbase = (uint32_t)lua_tonumber(L, 1);
520    lua_pushnumber(L, reg_written(regbase));
521    return 1;
522 }
523 
524 static int
l_reg_lastval(lua_State * L)525 l_reg_lastval(lua_State *L)
526 {
527    uint32_t regbase = (uint32_t)lua_tonumber(L, 1);
528    lua_pushnumber(L, reg_lastval(regbase));
529    return 1;
530 }
531 
532 static int
l_reg_val(lua_State * L)533 l_reg_val(lua_State *L)
534 {
535    uint32_t regbase = (uint32_t)lua_tonumber(L, 1);
536    lua_pushnumber(L, reg_val(regbase));
537    return 1;
538 }
539 
540 static const struct luaL_Reg l_regs[] = {
541    {"written", l_reg_written},
542    {"lastval", l_reg_lastval},
543    {"val", l_reg_val},
544    {NULL, NULL} /* sentinel */
545 };
546 
547 /* Expose API to lookup snapshot buffers:
548  */
549 
550 uint64_t gpubaseaddr(uint64_t gpuaddr);
551 unsigned hostlen(uint64_t gpuaddr);
552 
553 /* given address, return base-address of buffer: */
554 static int
l_bo_base(lua_State * L)555 l_bo_base(lua_State *L)
556 {
557    uint64_t addr = (uint64_t)lua_tonumber(L, 1);
558    lua_pushnumber(L, gpubaseaddr(addr));
559    return 1;
560 }
561 
562 /* given address, return the remaining size of the buffer: */
563 static int
l_bo_size(lua_State * L)564 l_bo_size(lua_State *L)
565 {
566    uint64_t addr = (uint64_t)lua_tonumber(L, 1);
567    lua_pushnumber(L, hostlen(addr));
568    return 1;
569 }
570 
571 static const struct luaL_Reg l_bos[] = {
572    {"base", l_bo_base}, {"size", l_bo_size}, {NULL, NULL} /* sentinel */
573 };
574 
575 static void
openlib(const char * lib,const luaL_Reg * reg)576 openlib(const char *lib, const luaL_Reg *reg)
577 {
578    lua_newtable(L);
579    luaL_setfuncs(L, reg, 0);
580    lua_setglobal(L, lib);
581 }
582 
583 /* called at start to load the script: */
584 int
script_load(const char * file)585 script_load(const char *file)
586 {
587    int ret;
588 
589    assert(!L);
590 
591    L = luaL_newstate();
592    luaL_openlibs(L);
593    openlib("bos", l_bos);
594    openlib("regs", l_regs);
595    openlib("rnn", l_rnn);
596 
597    ret = luaL_loadfile(L, file);
598    if (ret)
599       error("%s\n");
600 
601    ret = lua_pcall(L, 0, LUA_MULTRET, 0);
602    if (ret)
603       error("%s\n");
604 
605    return 0;
606 }
607 
608 /* called at start of each cmdstream file: */
609 void
script_start_cmdstream(const char * name)610 script_start_cmdstream(const char *name)
611 {
612    if (!L)
613       return;
614 
615    lua_getglobal(L, "start_cmdstream");
616 
617    /* if no handler just ignore it: */
618    if (!lua_isfunction(L, -1)) {
619       lua_pop(L, 1);
620       return;
621    }
622 
623    lua_pushstring(L, name);
624 
625    /* do the call (1 arguments, 0 result) */
626    if (lua_pcall(L, 1, 0, 0) != 0)
627       error("error running function `f': %s\n");
628 }
629 
630 /* called at each DRAW_INDX, calls script drawidx fxn to process
631  * the current state
632  */
633 void
script_draw(const char * primtype,uint32_t nindx)634 script_draw(const char *primtype, uint32_t nindx)
635 {
636    if (!L)
637       return;
638 
639    lua_getglobal(L, "draw");
640 
641    /* if no handler just ignore it: */
642    if (!lua_isfunction(L, -1)) {
643       lua_pop(L, 1);
644       return;
645    }
646 
647    lua_pushstring(L, primtype);
648    lua_pushnumber(L, nindx);
649 
650    /* do the call (2 arguments, 0 result) */
651    if (lua_pcall(L, 2, 0, 0) != 0)
652       error("error running function `f': %s\n");
653 }
654 
655 static int
l_rnn_meta_dom_index(lua_State * L)656 l_rnn_meta_dom_index(lua_State *L)
657 {
658    struct rnn *rnn = lua_touserdata(L, 1);
659    uint32_t offset = (uint32_t)lua_tonumber(L, 2);
660    struct rnndelem *elem;
661 
662    /* TODO might be nicer if the arg isn't a number, to search the domain
663     * for matching bitfields.. so that the script could do something like
664     * 'pkt.WIDTH' insteadl of 'pkt[1].WIDTH', ie. not have to remember the
665     * offset of the dword containing the bitfield..
666     */
667 
668    elem = rnn_regoff(rnn, offset);
669    if (!elem)
670       return 0;
671 
672    return l_rnn_etype(L, rnn, elem, elem->offset);
673 }
674 
675 /*
676  * A wrapper object for rnndomain based decoding of an array of dwords
677  * (ie. for pm4 packet decoding).  Mostly re-uses the register-value
678  * decoding for the individual dwords and bitfields.
679  */
680 
681 static int
l_rnn_meta_dom_gc(lua_State * L)682 l_rnn_meta_dom_gc(lua_State *L)
683 {
684    // TODO
685    // struct rnn *rnn = lua_touserdata(L, 1);
686    // rnn_deinit(rnn);
687    return 0;
688 }
689 
690 static const struct luaL_Reg l_meta_rnn_dom[] = {
691    {"__index", l_rnn_meta_dom_index},
692    {"__gc", l_rnn_meta_dom_gc},
693    {NULL, NULL} /* sentinel */
694 };
695 
696 /* called to general pm4 packet decoding, such as texture/sampler state
697  */
698 void
script_packet(uint32_t * dwords,uint32_t sizedwords,struct rnn * rnn,struct rnndomain * dom)699 script_packet(uint32_t *dwords, uint32_t sizedwords, struct rnn *rnn,
700               struct rnndomain *dom)
701 {
702    if (!L)
703       return;
704 
705    lua_getglobal(L, dom->name);
706 
707    /* if no handler for the packet, just ignore it: */
708    if (!lua_isfunction(L, -1)) {
709       lua_pop(L, 1);
710       return;
711    }
712 
713    struct rnndec *rnndec = lua_newuserdata(L, sizeof(*rnndec));
714 
715    rnndec->base = *rnn;
716    rnndec->base.dom[0] = dom;
717    rnndec->base.dom[1] = NULL;
718    rnndec->dwords = dwords;
719    rnndec->sizedwords = sizedwords;
720 
721    luaL_newmetatable(L, "rnnmetadom");
722    luaL_setfuncs(L, l_meta_rnn_dom, 0);
723    lua_pop(L, 1);
724 
725    luaL_setmetatable(L, "rnnmetadom");
726 
727    lua_pushnumber(L, sizedwords);
728 
729    if (lua_pcall(L, 2, 0, 0) != 0)
730       error("error running function `f': %s\n");
731 }
732 
733 /* helper to call fxn that takes and returns void: */
734 static void
simple_call(const char * name)735 simple_call(const char *name)
736 {
737    if (!L)
738       return;
739 
740    lua_getglobal(L, name);
741 
742    /* if no handler just ignore it: */
743    if (!lua_isfunction(L, -1)) {
744       lua_pop(L, 1);
745       return;
746    }
747 
748    /* do the call (0 arguments, 0 result) */
749    if (lua_pcall(L, 0, 0, 0) != 0)
750       error("error running function `f': %s\n");
751 }
752 
753 /* called at end of each cmdstream file: */
754 void
script_end_cmdstream(void)755 script_end_cmdstream(void)
756 {
757    simple_call("end_cmdstream");
758 }
759 
760 /* called at start of submit/issueibcmds: */
761 void
script_start_submit(void)762 script_start_submit(void)
763 {
764    simple_call("start_submit");
765 }
766 
767 /* called at end of submit/issueibcmds: */
768 void
script_end_submit(void)769 script_end_submit(void)
770 {
771    simple_call("end_submit");
772 }
773 
774 /* called after last cmdstream file: */
775 void
script_finish(void)776 script_finish(void)
777 {
778    if (!L)
779       return;
780 
781    simple_call("finish");
782 
783    lua_close(L);
784    L = NULL;
785 }
786