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