Commit 4081e287 authored by Maxime Perrotin's avatar Maxime Perrotin

Merge branch 'upython' into 'master'

Upython

See merge request !1
parents 02ec3974 b0bcca04
......@@ -215,6 +215,8 @@ procedure BuildSupport is
C_Set_Language_To_BlackBox_Device;
when Language_QGenAda => C_Set_Language_To_QGenAda;
when Language_QGenC => C_Set_Language_To_QGenC;
when Language_MicroPython =>
C_Set_Language_To_MicroPython;
when others => Exit_On_Error (True,
"Language is currently not supported: "
& Source_Language'Img);
......
......@@ -162,6 +162,7 @@ package Imported_Routines is
procedure C_Set_Language_To_GUI;
procedure C_Set_Language_To_VHDL;
procedure C_Set_Language_To_System_C;
procedure C_Set_Language_To_MicroPython;
procedure C_Set_Native_Encoding;
procedure C_Set_UPER_Encoding;
procedure C_Set_ACN_Encoding;
......@@ -249,6 +250,8 @@ private
pragma Import (C, C_Set_Language_To_GUI, "Set_Language_To_GUI");
pragma Import (C, C_Set_Language_To_VHDL, "Set_Language_To_VHDL");
pragma Import (C, C_Set_Language_To_System_C, "Set_Language_To_System_C");
pragma Import (C, C_Set_Language_To_MicroPython,
"Set_Language_To_MicroPython");
pragma Import (C, C_Set_UPER_Encoding, "Set_UPER_Encoding");
pragma Import (C, C_Set_ACN_Encoding, "Set_ACN_Encoding");
pragma Import (C, C_Set_Native_Encoding, "Set_Native_Encoding");
......
......@@ -62,6 +62,9 @@ void c_preamble(FV * fv)
else if (rtds == fv->language) {
fprintf(vm_if, "#include \"glue_%s.h\"\n\n", fv->name);
}
else if (micropython == fv->language) {
fprintf(vm_if, "#include \"%s_mpy_bindings.h\"\n\n", fv->name);
}
if (hasparam) {
fprintf(vm_if, "#include \"C_ASN1_Types.h\"\n\n");
......@@ -714,7 +717,8 @@ void GLUE_C_Backend(FV * fv)
if (c == fv->language || gui == fv->language || ada == fv->language || vdm == fv->language
|| qgenada == fv->language || qgenc == fv->language
|| rtds == fv->language || cpp == fv->language || opengeode == fv->language) {
|| rtds == fv->language || cpp == fv->language || opengeode == fv->language
|| micropython == fv->language) {
Init_C_Glue_Backend(fv);
FOREACH(i, Interface, fv->interfaces, {
GLUE_C_ProvidedInterface(i);
......
/* 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);
if (hasparam) {
fprintf(mpy_bind_c, "#include \"MicroPython_ASN1_Types.h\"\n\n");
}
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,
"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");
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);
}
});
fprintf(mpy_bind_c, "void %s_startup() {\n", fv->name);
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"
" mp_taste_types_init();\n"
" 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");
fprintf(mpy_bind_c, " mp_obj_t args[%u];\n", n_args);
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"
);
/* Encode the incoming IN data to MicroPython objects */
n_args = 0;
FOREACH (p, Parameter, i->in, {
fprintf(mpy_bind_c,
" #ifdef MICROPY_TASTE_NEED_DATA_FOR_%s\n"
" mp_obj_asn1Scc%s_t IN_%s_data;\n"
" args[%u] = mp_obj_encode_asn1Scc%s(IN_%s, &IN_%s_data);\n"
" #else\n"
" args[%u] = mp_obj_encode_asn1Scc%s(IN_%s, NULL);\n"
" #endif\n",
p->type,
p->type, p->name,
n_args, p->type, p->name, p->name,
n_args, p->type, p->name);
n_args += 1;
});
size_t n_in_args = n_args;
/* Encode the incoming OUT data to MicroPython objects */
FOREACH (p, Parameter, i->out, {
fprintf(mpy_bind_c,
" mp_obj_tuple_wrap_t wrap%u = {{&mp_type_mutable_attrtuple}, 1, {MP_OBJ_NULL, MP_OBJ_FROM_PTR(wrap_fields)}};\n"
" #ifdef MICROPY_TASTE_NEED_DATA_FOR_%s\n"
" mp_obj_asn1Scc%s_t OUT_%s_data;\n"
" wrap%u.items[0] = mp_obj_encode_asn1Scc%s(OUT_%s, &OUT_%s_data);\n"
" #else\n"
" wrap%u.items[0] = mp_obj_encode_asn1Scc%s(OUT_%s, NULL);\n"
" #endif\n"
" args[%u] = &wrap%u;\n",
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;
});
/* Call the MicroPython function */
fprintf(mpy_bind_c,
" mp_call_function_n_kw(mp_global_%s_PI_%s, %u, 0, args);\n",
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,
" mp_obj_decode_asn1Scc%s(wrap%u.items[0], OUT_%s);\n",
p->type, n_args, p->name);
n_args += 1;
});
/* 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"
"}\n"
"\n"
);
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,
"STATIC mp_obj_t %s_RI_%s_wrap(size_t n_args, const mp_obj_t *args) {\n"
" (void)n_args;\n",
i->parent_fv->name, i->name
);
/* Decode the incoming IN MicroPython objects to data */
n_args = 0;
FOREACH (p, Parameter, i->in, {
fprintf(mpy_bind_c,
" asn1Scc%s asn_IN_%s;\n"
" mp_obj_decode_asn1Scc%s(args[%u], &asn_IN_%s);\n",
p->type, p->name,
p->type, n_args, p->name);
n_args += 1;
});
size_t n_in_args = n_args;
/* Create local state for the OUT data */
FOREACH (p, Parameter, i->out, {
fprintf(mpy_bind_c,
" asn1Scc%s asn_OUT_%s;\n",
p->type, p->name);
n_args += 1;
});
/* Call the RI */
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");
/* 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,
" ((mp_obj_tuple_t*)MP_OBJ_TO_PTR(args[%u]))->items[0] = mp_obj_encode_asn1Scc%s(&asn_OUT_%s, MP_OBJ_TO_PTR(((mp_obj_tuple_t*)MP_OBJ_TO_PTR(args[%u]))->items[0]));\n",
n_args, p->type, p->name, n_args);
n_args += 1;
});
fprintf(mpy_bind_c,
" return mp_const_none;\n"
"}\n"
"STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(%s_RI_%s_obj, %u, %u, %s_RI_%s_wrap);\n"
"\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
fprintf(mpy_bind_c, "MICROPY_TASTE_ASN_CONSTRUCTORS\n");
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"
" { MP_ROM_QSTR(MP_QSTR_Ref), MP_ROM_PTR(&mp_obj_new_wrap_obj) },\n"
);
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
);
}
});
fprintf(mpy_bind_c, "MICROPY_TASTE_ASN_MAP_ENTRIES\n");
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);
}
}
/* Buildsupport is (c) 2008-2016 European Space Agency
* contact: maxime.perrotin@esa.int
* License is LGPL, check LICENSE file */
/* build_c_skeletons.c
this program generates empty C functions respecting the interfaces defined
in the interface view. it provides functions to invoke RI.
updated 10/06/2016: properly align params and use FOREACH
updated 20/04/2009 to disable in case "-onlycv" flag is set
updated 8/10/2009 to rename the user_code.h/c to FV_name.h/c like in the Ada backend
*/
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <sys/stat.h>
#include <stdbool.h>
#include <assert.h>
#include "my_types.h"
#include "practical_functions.h"
static FILE *user_code_py = NULL;
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;
}
/* Import the RI into the module-level namespace of the Python script */
void import_RI_to_MicroPython_skel(Interface * i)
{
if (NULL == user_code_py)
return;
bool comma = false;
fprintf(user_code_py, "# %s_RI_%s(", i->parent_fv->name, i->name);
FOREACH (p, Parameter, i->in, {
fprintf(user_code_py, "%sIN_%s: asn1Scc%s",
comma ? ", " : "", p->name, p->type);
comma = true;
});
FOREACH (p, Parameter, i->out, {
fprintf(user_code_py,"%sOUT_%s: asn1Scc%s",
comma ? ", " : "", p->name, p->type);
comma = true;
});
fprintf(user_code_py, ")\n");
fprintf(user_code_py, "from taste import %s_RI_%s\n", i->parent_fv->name, i->name);
}
/* Generate the preamble of the skeleton script */
void micropython_skel_preamble(FV * fv)
{
int hasparam = 0;
/* Check if any interface needs ASN.1 types */
FOREACH(i, Interface, fv->interfaces, {
CheckForAsn1Params(i, &hasparam);}
);
/* c. user_code.py preamble (if applicable) */
if (NULL != user_code_py) {
fprintf(user_code_py,
"# User code: This file will not be overwritten by TASTE.\n\n");
fprintf(user_code_py, "import micropython\n");
fprintf(user_code_py, "from taste import * # import all ASN types\n\n");
FOREACH(i, Interface, fv->interfaces, {
if (i->direction == RI && gen_this_ri(i)) {
import_RI_to_MicroPython_skel(i);
}
});
fprintf(user_code_py, "\n");
// TODO need to generate dummy variables for the types
if (has_context_param(fv)) {
char *fv_no_underscore =
underscore_to_dash(fv->name, strlen(fv->name));
fprintf(user_code_py,
"/* Function static data is declared in this file : */\n");
fprintf(user_code_py, "#include \"Context-%s.h\"\n\n",
fv_no_underscore);
free(fv_no_underscore);
}
fprintf(user_code_py, "def %s_startup():\n", fv->name);