build_micropython_glue.c 14.5 KB
Newer Older
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
/* Buildsupport is (c) 2008-2015 European Space Agency
 * contact: maxime.perrotin@esa.int
 * License is LGPL, check LICENSE file */
/* build_sdl_glue.c

  this program generates the code to interface an objectgeode generated application with the assert virtual machine
  It creates X_mpy_bindings.h and X_mpy_bindings.c.
  
 */

#define ID "$Id: build_sdl_glue.c 414 2009-12-04 16:21:52Z maxime1008 $"

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <sys/stat.h>

#include "my_types.h"
#include "practical_functions.h"

static FILE *mpy_bind_h, *mpy_bind_c;

static bool gen_this_ri(Interface * i)
{
    /* 
     * There can be duplicate RI name but one sync, the other async
     * In that case, discard the async one (generated by VT to allow
     * a mix of sync and async PI in one block
     */
    if (asynch == i->synchronism) {
        FOREACH(interface, Interface, i->parent_fv->interfaces, {
            if (RI == interface->direction &&
                !strcmp(interface->name, i->name) &&
                synch == interface->synchronism) {
                return false;
            }

        });
    }

    return true;
}

void micropython_mpy_bind_preamble(FV * fv)
{
    if (NULL == mpy_bind_h || NULL == mpy_bind_c)
	return;

    int hasparam = 0;

    /* Check if any interface needs ASN.1 types */
    FOREACH(i, Interface, fv->interfaces, {
            CheckForAsn1Params(i, &hasparam);}
    );

    fprintf(mpy_bind_h,
            "/* This file was generated automatically by build_micropython_glue.c: DO NOT MODIFY IT ! */\n\n");
    fprintf(mpy_bind_h,
            "/* Declaration of the functions that have to be provided by the user */\n\n");
    fprintf(mpy_bind_h,
            "#ifndef __USER_CODE_H_%s__\n#define __USER_CODE_H_%s__\n\n",
            fv->name, fv->name);

    fprintf(mpy_bind_h, "#include <stdint.h>\n\n");

    if (hasparam) {
        fprintf(mpy_bind_h, "#include \"C_ASN1_Types.h\"\n\n");
    }

    fprintf(mpy_bind_h,
            "#ifdef __cplusplus\n"
            "extern \"C\" {\n" 
            "#endif\n\n");

    fprintf(mpy_bind_h, "void %s_startup();\n\n", fv->name);

    fprintf(mpy_bind_c, "#include \"py/runtime.h\"\n");
    fprintf(mpy_bind_c, "#include \"py/gc.h\"\n");
    fprintf(mpy_bind_c, "#include \"py/stackctrl.h\"\n");
    fprintf(mpy_bind_c, "#include \"py/pystack.h\"\n");
    fprintf(mpy_bind_c, "#include \"mputil.h\"\n");
    fprintf(mpy_bind_c, "#include \"%s_mpy_bindings.h\"\n", fv->name);
    fprintf(mpy_bind_c, "#include \"%s.mpy.h\"\n\n", fv->name);

85
86
87
88
    if (hasparam) {
        fprintf(mpy_bind_c, "#include \"MicroPython_ASN1_Types.h\"\n\n");
    }

89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
    if (has_context_param(fv)) {
        char *fv_no_underscore =
            underscore_to_dash(fv->name, strlen(fv->name));
        fprintf(mpy_bind_c,
                "/* Function static data is declared in this file : */\n");
        fprintf(mpy_bind_c, "#include \"Context-%s.h\"\n\n",
                fv_no_underscore);
        free(fv_no_underscore);
    }

    fprintf(mpy_bind_c, "mp_state_ctx_t *mp_current_ctx;\n"); // TODO there should only be one of these per executable
    fprintf(mpy_bind_c, "static mp_state_ctx_t mp_ctx;\n");
    fprintf(mpy_bind_c, "static uint64_t mp_heap[4096];\n");
    fprintf(mpy_bind_c, "static mp_obj_t mp_pystack[4096];\n\n");

    FOREACH(i, Interface, fv->interfaces, {
        if (i->direction == PI) {
            fprintf(mpy_bind_c, "static mp_obj_t mp_global_%s_PI_%s;\n\n", i->parent_fv->name, i->name);
        }
    });

110
    fprintf(mpy_bind_c, "void %s_startup() {\n", fv->name);
111
112
113
114
115
116
117
118
119

    fprintf(mpy_bind_c,
        "    /* MicroPython VM initialisation */\n"
        "    mp_current_ctx = &mp_ctx;\n"
        "    mp_stack_ctrl_init();\n"
        "    mp_stack_set_limit(8192);\n"
        "    gc_init(mp_heap, (uint8_t*)mp_heap + sizeof(mp_heap));\n"
        "    mp_pystack_init(mp_pystack, (uint8_t*)mp_pystack + sizeof(mp_pystack));\n"
        "    mp_init();\n"
120
        "    mp_taste_types_init();\n"
121
122
123
        "    mp_exec_mpy(mpy_script_data, mpy_script_len);\n"
    );

124
    /* Start exception handling block to catch errors in startup code */
125
    fprintf(mpy_bind_c,
126
127
128
        "    nlr_buf_t nlr;\n"
        "    if (nlr_push(&nlr) == 0) {\n"
    );
129

130
    /* Load all of the PI functions */
131
132
133
    FOREACH(i, Interface, fv->interfaces, {
        if (i->direction == PI) {
            fprintf(mpy_bind_c,
134
                "        mp_global_%s_PI_%s = mp_load_global(MP_QSTR_%s_PI_%s);\n",
135
136
137
138
                    i->parent_fv->name, i->name, i->parent_fv->name, i->name);
        }
    });

139
    /* Load and execute the startup function */
140
    fprintf(mpy_bind_c,
141
142
143
144
145
146
147
148
149
150
        "        mp_call_function_0(mp_load_global(MP_QSTR_%s_startup));\n",
        fv->name
    );

    /* Clean up the exception handling */
    fprintf(mpy_bind_c,
        "        nlr_pop();\n"
        "    } else {\n"
        "        mp_obj_print_exception(&mp_plat_print, MP_OBJ_FROM_PTR(nlr.ret_val));\n"
        "    }\n"
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
    );

    fprintf(mpy_bind_c, "}\n\n");
}

void micropython_add_PI_to_glue(Interface * i)
{
    if (NULL == mpy_bind_h)
        return;

    char *signature = make_string("void %s_PI_%s(",
                                  i->parent_fv->name,
                                  i->name);
    char *signature_py = make_string("def %s_PI_%s(",
                                     i->parent_fv->name,
                                     i->name);

    size_t sig_len = strlen(signature);
    char *sep = make_string(",\n%*s", sig_len, "");
    size_t n_args = 0;

    fprintf(mpy_bind_h, "%s", signature);
    fprintf(mpy_bind_c, "%s", signature);

    FOREACH (p, Parameter, i->in, {
        char *sort = make_string("%sconst asn1Scc%s *",
                                 n_args ? sep: "",
                                 p->type);
        fprintf(mpy_bind_h, "%s", sort);
        fprintf(mpy_bind_c, "%sIN_%s",
                             sort,
                             p->name);
        free(sort);
        n_args += 1;
    });

    FOREACH (p, Parameter, i->out, {
        char *sort = make_string("%sasn1Scc%s *",
                                 n_args ? sep: "",
                                 p->type);
        fprintf(mpy_bind_h, "%s", sort);
        fprintf(mpy_bind_c, "%sOUT_%s",
                             sort,
                             p->name);
        free(sort);
        n_args += 1;
    });

    fprintf(mpy_bind_h, ");\n\n");
    fprintf(mpy_bind_c, ")\n{\n");
    fprintf(mpy_bind_c, "    mp_current_ctx = &mp_ctx;\n");
202
    fprintf(mpy_bind_c, "    mp_obj_t args[%zd];\n", n_args);
203
204
205
206
207
208
    fprintf(mpy_bind_c,
        "    mp_stack_ctrl_init();\n"
        "    mp_stack_set_limit(2048);\n"
        "    nlr_buf_t nlr;\n"
        "    if (nlr_push(&nlr) == 0) {\n"
    );
209

210
    /* Encode the incoming IN data to MicroPython objects */
211
212
213
    n_args = 0;
    FOREACH (p, Parameter, i->in, {
        fprintf(mpy_bind_c,
214
215
            "        #ifdef MICROPY_TASTE_NEED_DATA_FOR_%s\n"
            "        mp_obj_asn1Scc%s_t IN_%s_data;\n"
216
            "        args[%zd] = mp_obj_encode_asn1Scc%s(IN_%s, &IN_%s_data);\n"
217
            "        #else\n"
218
            "        args[%zd] = mp_obj_encode_asn1Scc%s(IN_%s, NULL);\n"
219
220
221
222
223
            "        #endif\n",
            p->type,
            p->type, p->name,
            n_args, p->type, p->name, p->name,
            n_args, p->type, p->name);
224
225
        n_args += 1;
    });
226
    size_t n_in_args = n_args;
227

228
229
230
    /* Encode the incoming OUT data to MicroPython objects */
    FOREACH (p, Parameter, i->out, {
        fprintf(mpy_bind_c,
231
            "        mp_obj_access_t access%zu = MP_OBJ_ACCESS_INIT(MP_OBJ_NULL);\n"
232
233
            "        #ifdef MICROPY_TASTE_NEED_DATA_FOR_%s\n"
            "        mp_obj_asn1Scc%s_t OUT_%s_data;\n"
234
            "        access%zu.items[0] = mp_obj_encode_asn1Scc%s(OUT_%s, &OUT_%s_data);\n"
235
            "        #else\n"
236
            "        access%zu.items[0] = mp_obj_encode_asn1Scc%s(OUT_%s, NULL);\n"
237
            "        #endif\n"
238
            "        args[%zu] = &access%zu;\n",
239
240
241
242
243
244
245
246
247
            n_args,
            p->type,
            p->type, p->name,
            n_args, p->type, p->name, p->name,
            n_args, p->type, p->name,
            n_args, n_args
        );
        n_args += 1;
    });
248
249

    /* Call the MicroPython function */
250
    fprintf(mpy_bind_c,
251
        "        mp_call_function_n_kw(mp_global_%s_PI_%s, %zu, 0, args);\n",
252
253
254
255
256
257
258
        i->parent_fv->name, i->name, n_args
    );

    /* Decode the outgoing OUT MicroPython objects to data */
    n_args = n_in_args;
    FOREACH (p, Parameter, i->out, {
        fprintf(mpy_bind_c,
259
            "        mp_obj_decode_asn1Scc%s(access%zu.items[0], OUT_%s);\n",
260
261
262
263
264
265
            p->type, n_args, p->name);
        n_args += 1;
    });

    /* Clean up the exception handling */
    fprintf(mpy_bind_c,
266
267
268
269
270
        "        nlr_pop();\n"
        "    } else {\n"
        "        mp_obj_print_exception(&mp_plat_print, MP_OBJ_FROM_PTR(nlr.ret_val));\n"
        "    }\n"
        "}\n"
271
        "\n"
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
    );

    free(signature);
    free(signature_py);
    free(sep);
}

void micropython_add_RI_to_glue(Interface * i)
{
    if (NULL == mpy_bind_h)
        return;

    char *signature = make_string("extern void %s_RI_%s(",
                                  i->parent_fv->name,
                                  i->name);

    size_t sig_len = strlen(signature);
    char *sep = make_string(",\n%*s", sig_len, "");
    size_t n_args = 0;

    fprintf(mpy_bind_c, "%s", signature);

    FOREACH (p, Parameter, i->in, {
        fprintf(mpy_bind_c, "%sconst asn1Scc%s *",
                             n_args ? sep: "",
                             p->type);
        n_args += 1;
    });

    FOREACH (p, Parameter, i->out, {
        fprintf(mpy_bind_c,"%sasn1Scc%s *",
                            n_args ? sep: "",
                            p->type);
        n_args += 1;
    });

    fprintf(mpy_bind_c, ");\n\n");
    free(signature);
    free(sep);

    fprintf(mpy_bind_c,
313
314
        "STATIC mp_obj_t %s_RI_%s_wrap(size_t n_args, const mp_obj_t *args) {\n"
        "    (void)n_args;\n",
315
316
        i->parent_fv->name, i->name
    );
317
318

    /* Decode the incoming IN MicroPython objects to data */
319
320
321
    n_args = 0;
    FOREACH (p, Parameter, i->in, {
        fprintf(mpy_bind_c,
322
            "    asn1Scc%s asn_IN_%s;\n"
323
            "    mp_obj_decode_asn1Scc%s(args[%zu], &asn_IN_%s);\n",
324
325
            p->type, p->name,
            p->type, n_args, p->name);
326
327
        n_args += 1;
    });
328
329
330
    size_t n_in_args = n_args;

    /* Create local state for the OUT data */
331
332
333
334
335
336
    FOREACH (p, Parameter, i->out, {
        fprintf(mpy_bind_c,
            "    asn1Scc%s asn_OUT_%s;\n",
            p->type, p->name);
        n_args += 1;
    });
337
338

    /* Call the RI */
339
340
341
342
343
344
345
346
347
348
349
350
    fprintf(mpy_bind_c, "    %s_RI_%s(", i->parent_fv->name, i->name);
    n_args = 0;
    FOREACH (p, Parameter, i->in, {
        fprintf(mpy_bind_c, "%s&asn_IN_%s", n_args ? ", " : "", p->name);
        n_args += 1;
    });
    FOREACH (p, Parameter, i->out, {
        fprintf(mpy_bind_c, "%s&asn_OUT_%s", n_args ? ", " : "", p->name);
        n_args += 1;
    });
    fprintf(mpy_bind_c, ");\n");

351
352
353
354
    if (i->out != NULL) {
        fprintf(mpy_bind_c, "    mp_obj_t *access_items;\n");
    }

355
356
357
358
359
    /* Encode the OUT data to MicroPython objects */
    n_args = n_in_args;
    FOREACH (p, Parameter, i->out, {
        /* TODO verify that the argument objects are of the correct type */
        fprintf(mpy_bind_c,
360
361
362
            "    access_items = mp_obj_access_get_items(args[%zu]);\n"
            "    access_items[0] = mp_obj_encode_asn1Scc%s(&asn_OUT_%s, MP_OBJ_TO_PTR(access_items[0]));\n",
            n_args, p->type, p->name);
363
364
365
        n_args += 1;
    });

366
367
368
    fprintf(mpy_bind_c, 
        "    return mp_const_none;\n"
        "}\n"
369
        "STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(%s_RI_%s_obj, %zu, %zu, %s_RI_%s_wrap);\n"
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
        "\n",
        i->parent_fv->name, i->name,
        n_args, n_args,
        i->parent_fv->name, i->name
    );
}

int Init_MicroPython_Glue_Backend(FV * fv)
{
    char *path = NULL, *filename = NULL;
    if (NULL != fv->system_ast->context->output)
	build_string(&path, fv->system_ast->context->output,
		      strlen(fv->system_ast->context->output));
    build_string(&path, fv->name, strlen(fv->name));
    build_string(&filename, fv->name, strlen(fv->name));
    build_string(&filename, "_mpy_bindings.c", strlen("_mpy_bindings.c"));
    create_file(path, filename, &mpy_bind_c);
    filename[strlen(filename) - 1] = 'h';
    create_file(path, filename, &mpy_bind_h);
    free(path);
    free(filename);
    if (NULL == mpy_bind_c || NULL == mpy_bind_h)
	return -1;

    micropython_mpy_bind_preamble(fv);
    return 0;
}

void End_MicroPython_Glue_Backend(FV *fv)
{
    // Generate the taste module

402
403
    fprintf(mpy_bind_c, "MICROPY_TASTE_ASN_CONSTRUCTORS\n");

404
405
406
    fprintf(mpy_bind_c,
        "STATIC const mp_rom_map_elem_t taste_module_globals_table[] = {\n"
        "    { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_taste) },\n"
407
        "    { MP_ROM_QSTR(MP_QSTR_Access), MP_ROM_PTR(&mp_obj_new_access_obj) },\n"
408
409
410
411
412
413
414
415
416
417
418
    );

    FOREACH(i, Interface, fv->interfaces, {
        if (i->direction == RI && gen_this_ri(i)) {
            fprintf(mpy_bind_c,
                "    { MP_ROM_QSTR(MP_QSTR_%s_RI_%s), MP_ROM_PTR(&%s_RI_%s_obj) },\n",
                i->parent_fv->name, i->name,
                i->parent_fv->name, i->name
            );
        }
    });
419
    fprintf(mpy_bind_c, "MICROPY_TASTE_ASN_MAP_ENTRIES\n");
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476

    fprintf(mpy_bind_c,
        "};\n"
        "\n"
        "STATIC MP_DEFINE_CONST_DICT(taste_module_globals, taste_module_globals_table);\n"
        "\n"
        "const mp_obj_module_t mp_module_taste = {\n"
        "    .base = { &mp_type_module },\n"
        "    .globals = (mp_obj_dict_t*)&taste_module_globals,\n"
        "};\n"
    );

    if (NULL != mpy_bind_h) {
        fprintf(mpy_bind_h,
            "#ifdef __cplusplus\n"
            "}\n" 
            "#endif\n\n");
        fprintf(mpy_bind_h, "\n#endif\n");
        close_file(&mpy_bind_h);
    }

    close_file(&mpy_bind_c);
} 

/* Function to process one interface of the FV */
void GLUE_MicroPython_Interface(Interface * i)
{
    switch (i->direction) {
    case PI:
        micropython_add_PI_to_glue(i);
        break;

    case RI:
        if (gen_this_ri(i)) {
            micropython_add_RI_to_glue(i);
        }
        break;

    default:
        break;
    }
}


// External interface (the one and unique)
void GLUE_MicroPython_Backend(FV * fv)
{
    if (fv->system_ast->context->onlycv)
	return;
    if (micropython == fv->language) {
        Init_MicroPython_Glue_Backend(fv);
	FOREACH(i, Interface, fv->interfaces, {
	    GLUE_MicroPython_Interface(i);
	})
	End_MicroPython_Glue_Backend(fv);
    }
}