build_micropython_glue.c 14.9 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
    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);
    }

99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
    fprintf(mpy_bind_c,
        "typedef struct {\n"
        "    mp_obj_base_t base;\n"
        "    size_t len;\n"
        "    mp_obj_t items[2];\n"
        "} mp_obj_tuple_wrap_t;\n\n");

    fprintf(mpy_bind_c, "extern mp_obj_type_t mp_type_mutable_attrtuple;\n\n");

    fprintf(mpy_bind_c, "static qstr wrap_fields[1] = {MP_QSTR_val};\n\n");

    fprintf(mpy_bind_c,
        "static mp_obj_t mp_obj_new_wrap(mp_obj_t arg) {\n"
        "    mp_obj_tuple_wrap_t *o = m_new_obj(mp_obj_tuple_wrap_t);\n"
        "    o->base.type = &mp_type_mutable_attrtuple;\n"
        "    o->len = 1;\n"
        "    o->items[0] = arg;\n"
        "    o->items[1] = MP_OBJ_FROM_PTR(wrap_fields);\n"
        "    return MP_OBJ_FROM_PTR(o);\n"
        "}\n"
        "MP_DEFINE_CONST_FUN_OBJ_1(mp_obj_new_wrap_obj, mp_obj_new_wrap);\n\n");

121
122
123
124
125
126
127
128
129
130
131
    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);
        }
    });

132
    fprintf(mpy_bind_c, "void %s_startup() {\n", fv->name);
133
134
135
136
137
138
139
140
141

    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"
142
        "    mp_taste_types_init();\n"
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
        "    mp_exec_mpy(mpy_script_data, mpy_script_len);\n"
    );

    fprintf(mpy_bind_c,
        "    mp_obj_t global_startup = mp_load_global(MP_QSTR_%s_startup);\n", fv->name);

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

    fprintf(mpy_bind_c,
            "    mp_call_function_0(global_startup);\n"
    );

    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");
210
    fprintf(mpy_bind_c, "    mp_obj_t args[%zd];\n", n_args);
211
212
213
214
215
216
    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"
    );
217

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

236
237
238
    /* Encode the incoming OUT data to MicroPython objects */
    FOREACH (p, Parameter, i->out, {
        fprintf(mpy_bind_c,
239
            "        mp_obj_tuple_wrap_t wrap%zu = {{&mp_type_mutable_attrtuple}, 1, {MP_OBJ_NULL, MP_OBJ_FROM_PTR(wrap_fields)}};\n"
240
241
            "        #ifdef MICROPY_TASTE_NEED_DATA_FOR_%s\n"
            "        mp_obj_asn1Scc%s_t OUT_%s_data;\n"
242
            "        wrap%zu.items[0] = mp_obj_encode_asn1Scc%s(OUT_%s, &OUT_%s_data);\n"
243
            "        #else\n"
244
            "        wrap%zu.items[0] = mp_obj_encode_asn1Scc%s(OUT_%s, NULL);\n"
245
            "        #endif\n"
246
            "        args[%zu] = &wrap%zu;\n",
247
248
249
250
251
252
253
254
255
            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;
    });
256
257

    /* Call the MicroPython function */
258
    fprintf(mpy_bind_c,
259
        "        mp_call_function_n_kw(mp_global_%s_PI_%s, %zu, 0, args);\n",
260
261
262
263
264
265
266
        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,
267
            "        mp_obj_decode_asn1Scc%s(wrap%zu.items[0], OUT_%s);\n",
268
269
270
271
272
273
            p->type, n_args, p->name);
        n_args += 1;
    });

    /* Clean up the exception handling */
    fprintf(mpy_bind_c,
274
275
276
277
278
        "        nlr_pop();\n"
        "    } else {\n"
        "        mp_obj_print_exception(&mp_plat_print, MP_OBJ_FROM_PTR(nlr.ret_val));\n"
        "    }\n"
        "}\n"
279
        "\n"
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
313
314
315
316
317
318
319
320
    );

    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,
321
322
        "STATIC mp_obj_t %s_RI_%s_wrap(size_t n_args, const mp_obj_t *args) {\n"
        "    (void)n_args;\n",
323
324
        i->parent_fv->name, i->name
    );
325
326

    /* Decode the incoming IN MicroPython objects to data */
327
328
329
    n_args = 0;
    FOREACH (p, Parameter, i->in, {
        fprintf(mpy_bind_c,
330
            "    asn1Scc%s asn_IN_%s;\n"
331
            "    mp_obj_decode_asn1Scc%s(args[%zu], &asn_IN_%s);\n",
332
333
            p->type, p->name,
            p->type, n_args, p->name);
334
335
        n_args += 1;
    });
336
337
338
    size_t n_in_args = n_args;

    /* Create local state for the OUT data */
339
340
341
342
343
344
    FOREACH (p, Parameter, i->out, {
        fprintf(mpy_bind_c,
            "    asn1Scc%s asn_OUT_%s;\n",
            p->type, p->name);
        n_args += 1;
    });
345
346

    /* Call the RI */
347
348
349
350
351
352
353
354
355
356
357
358
    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");

359
360
361
362
363
    /* 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,
364
            "    ((mp_obj_tuple_t*)MP_OBJ_TO_PTR(args[%zu]))->items[0] = mp_obj_encode_asn1Scc%s(&asn_OUT_%s, MP_OBJ_TO_PTR(((mp_obj_tuple_t*)MP_OBJ_TO_PTR(args[%zu]))->items[0]));\n",
365
366
367
368
            n_args, p->type, p->name, n_args);
        n_args += 1;
    });

369
370
371
    fprintf(mpy_bind_c, 
        "    return mp_const_none;\n"
        "}\n"
372
        "STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(%s_RI_%s_obj, %zu, %zu, %s_RI_%s_wrap);\n"
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
402
403
404
        "\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

405
406
    fprintf(mpy_bind_c, "MICROPY_TASTE_ASN_CONSTRUCTORS\n");

407
408
409
    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"
410
        "    { MP_ROM_QSTR(MP_QSTR_Ref), MP_ROM_PTR(&mp_obj_new_wrap_obj) },\n"
411
412
413
414
415
416
417
418
419
420
421
    );

    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
            );
        }
    });
422
    fprintf(mpy_bind_c, "MICROPY_TASTE_ASN_MAP_ENTRIES\n");
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
477
478
479

    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);
    }
}