8000 Dynamic native modules v2 by dpgeorge · Pull Request #1627 · micropython/micropython · GitHub
[go: up one dir, main page]

Skip to content

Dynamic native modules v2 #1627

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions examples/modx/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
build-*/
40 changes: 40 additions & 0 deletions examples/modx/Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
include ../../py/mkenv.mk

INC = -I. -I../..

CFLAGS = $(INC) -Wall -Werror -ansi -std=gnu99 -fPIC -fno-stack-protector -Os

ARCH = native

ifeq ($(ARCH), m4)
CROSS_COMPILE = arm-none-eabi-
CFLAGS_CORTEX_M4 = -mthumb -mtune=cortex-m4 -mabi=aapcs-linux -mcpu=cortex-m4 -mfpu=fpv4-sp-d16 -mfloat-abi=hard -fsingle-precision-constant -Wdouble-promotion
CFLAGS += -nostdlib $(CFLAGS_CORTEX_M4)
else ifeq ($(ARCH), m0)
CROSS_COMPILE = arm-none-eabi-
CFLAGS_CORTEX_M0 = -mthumb --short-enums -mtune=cortex-m0 -mcpu=cortex-m0 -mfloat-abi=soft -fno-builtin
CFLAGS += -nostdlib $(CFLAGS_CORTEX_M0)
else ifeq ($(ARCH), native)
# we're not cross compiling
ARCH = native
else
$(error Unknown architecture)
endif

BUILD=build-$(ARCH)

all: $(BUILD)/modx.mpy

clean:
$(RM) -rf $(BUILD)

$(BUILD)/modx.mpy: $(BUILD)/modx.elf
$(OBJCOPY) -O binary -j .all $< $@
$(PYTHON) elftompy.py $@

$(BUILD)/modx.elf: $(BUILD)/modx.o
$(LD) -T persistnative.ld -o $@ $<

$(BUILD)/modx.o: modx.c
$(MKDIR) -p $(BUILD)
$(CC) $(CFLAGS) -o $@ -c $<
24 changes: 24 additions & 0 deletions examples/modx/elftompy.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
"""
This tool is ultimately intended to convert a .elf to a .mpy file.
But for now all it does is patch the text size within a .mpy file.

Usage (after building modx.mpy):

$ python elftompy.py modx.mpy

This will make modx.mpy ready for importing.
"""

import sys

def process_file(filename):
with open(filename, 'rb') as f:
data = bytearray(f.read())
size = len(data) - 16
data[8] = size & 0xff
data[9] = size >> 8
with open(filename, 'wb') as f:
f.write(data)

if __name__ == '__main__':
process_file(sys.argv[1])
Empty file.
53 changes: 53 additions & 0 deletions examples/modx/modx.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
#include "py/persistnative.h"

#define QSTR_DEFINES \
QDEF(VAL1, "VAL1") \
QDEF(VAL2, "VAL2") \
QDEF(VAL3, "VAL3") \
QDEF(add1, "add1") \
QDEF(make_list, "make_list") \

enum {
#define QDEF(id, str) MP_LOCAL_QSTR_ ## id,
QSTR_DEFINES
#undef QDEF
MP_LOCAL_QSTR_number_of,
};

STATIC mp_obj_t modx_add1(CONTEXT mp_obj_t x) {
return RT(mp_binary_op)(MP_BINARY_OP_ADD, x, MP_OBJ_NEW_SMALL_INT(1));
}

STATIC mp_obj_t modx_make_list(CONTEXT mp_obj_t x, mp_obj_t y) {
mp_obj_t list[6] = {
MP_OBJ_NEW_SMALL_INT(1),
MP_OBJ_NEW_SMALL_INT(2),
CONST(_ellipsis),
MP_OBJ_NEW_QSTR(QSTR(make_list)),
x,
y,
};
return RT(mp_obj_new_list)(6, list);
}

MP_PERSISTENT_NATIVE_HEADER

MP_PERSISTENT_NATIVE_INIT
void init(CONTEXT_ALONE) {
// create qstrs
{
qstr *q = pnd->qstr_table;
#define QDEF(id, str) *q++ = RT(qstr_from_str)(str);
QSTR_DEFINES
#undef QDEF
}

// constants
RT(mp_store_global)(QSTR(VAL1), CONST(_true));
RT(mp_store_global)(QSTR(VAL2), MP_OBJ_NEW_SMALL_INT(123));
RT(mp_store_global)(QSTR(VAL3), MP_OBJ_NEW_QSTR(QSTR(VAL3)));

// functions
RT(mp_store_global)(QSTR(add1), MAKE_FUN_1(modx_add1));
RT(mp_store_global)(QSTR(make_list), MAKE_FUN_2(modx_make_list));
}
72 changes: 72 additions & 0 deletions examples/modx/mpconfigport.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
/*
* This file is part of the Micro Python project, http://micropython.org/
*
* The MIT License (MIT)
*
* Copyright (c) 2013, 2014 Damien P. George
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/

#include <stdint.h>

// options to control how Micro Python is built

#define MICROPY_ALLOC_PATH_MAX (PATH_MAX)
#define MICROPY_PERSISTENT_NATIVE (1)
#define MICROPY_COMP_MODULE_CONST (1)
#define MICROPY_ENABLE_GC (1)
#define MICROPY_ENABLE_FINALISER (1)
#define MICROPY_STACK_CHECK (1)
#define MICROPY_MEM_STATS (1)
#define MICROPY_DEBUG_PRINTERS (1)
#define MICROPY_HELPER_REPL (1)
#define MICROPY_HELPER_LEXER_UNIX (1)
#define MICROPY_ENABLE_SOURCE_LINE (1)
#define MICROPY_FLOAT_IMPL (MICROPY_FLOAT_IMPL_DOUBLE)
#define MICROPY_LONGINT_IMPL (MICROPY_LONGINT_IMPL_MPZ)
#define MICROPY_STREAMS_NON_BLOCK (1)
#define MICROPY_OPT_COMPUTED_GOTO (1)
#define MICROPY_OPT_CACHE_MAP_LOOKUP_IN_BYTECODE (1)
#define MICROPY_CAN_OVERRIDE_BUILTINS (1)
#define MICROPY_MODULE_EXTERN (1)
#define MICROPY_PY_BUILTINS_STR_UNICODE (1)
#define MICROPY_PY_BUILTINS_MEMORYVIEW (1)
#define MICROPY_PY_BUILTINS_FROZENSET (1)
#define MICROPY_PY_BUILTINS_COMPILE (1)
#define MICROPY_PY_MICROPYTHON_MEM_INFO (1)
#define MICROPY_PY_SYS_EXIT (1)
#define MICROPY_PY_SYS_PLATFORM "linux"
#define MICROPY_PY_SYS_MAXSIZE (1)
#define MICROPY_PY_SYS_STDFILES (1)
#define MICROPY_PY_CMATH (1)
#define MICROPY_PY_IO_FILEIO (1)
#define MICROPY_PY_GC_COLLECT_RETVAL (1)

// type definitions for the specific machine

typedef intptr_t mp_int_t;
typedef uintptr_t mp_uint_t;

// Cannot include <sys/types.h>, as it may lead to symbol name clashes
#if _FILE_OFFSET_BITS == 64 && !defined(__LP64__)
typedef long long mp_off_t;
#else
typedef long mp_off_t;
#endif
16 changes: 16 additions & 0 deletions examples/modx/persistnative.ld
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
/*
GNU linker script for MPY external modules
*/

SECTIONS
{
.all :
{
. = ALIGN(4);
KEEP(*(.mpyheader))
KEEP(*(.mpytext))
*(.text*)
*(.rodata*)
. = ALIGN(4);
}
}
1 change: 1 addition & 0 deletions ports/unix/mpconfigport.h
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@

#define MICROPY_ALLOC_PATH_MAX (PATH_MAX)
#define MICROPY_PERSISTENT_CODE_LOAD (1)
#define MICROPY_PERSISTENT_NATIVE (1)
#if !defined(MICROPY_EMIT_X64) && defined(__x86_64__)
#define MICROPY_EMIT_X64 (1)
#endif
Expand Down
2 changes: 1 addition & 1 deletion py/asmarm.c
Original file line number Diff line number Diff line change
Expand Up @@ -350,7 +350,7 @@ void asm_arm_b_label(asm_arm_t *as, uint label) {
asm_arm_bcc_label(as, ASM_ARM_CC_AL, label);
}

void asm_arm_bl_ind(asm_arm_t *as, void *fun_ptr, uint fun_id, uint reg_temp) {
void asm_arm_bl_ind(asm_arm_t *as, const void *fun_ptr, uint fun_id, uint reg_temp) {
// If the table offset fits into the ldr instruction
if (fun_id < (0x1000 / 4)) {
emit_al(as, asm_arm_op_mov_reg(ASM_ARM_REG_LR, ASM_ARM_REG_PC)); // mov lr, pc
Expand Down
2 changes: 1 addition & 1 deletion py/asmarm.h
Original file line number Diff line number Diff line change
Expand Up @@ -120,7 +120,7 @@ void asm_arm_pop(asm_arm_t *as, uint reglist);
// control flow
void asm_arm_bcc_label(asm_arm_t *as, int cond, uint label);
void asm_arm_b_label(asm_arm_t *as, uint label);
void asm_arm_bl_ind(asm_arm_t *as, void *fun_ptr, uint fun_id, uint reg_temp);
void asm_arm_bl_ind(asm_arm_t *as, const void *fun_ptr, uint fun_id, uint reg_temp);

#if GENERIC_ASM_API

Expand Down
2 changes: 1 addition & 1 deletion py/asmthumb.c
Original file line number Diff line number Diff line change
Expand Up @@ -356,7 +356,7 @@ void asm_thumb_bcc_label(asm_thumb_t *as, int cond, uint label) {
#define OP_BLX(reg) (0x4780 | ((reg) << 3))
#define OP_SVC(arg) (0xdf00 | (arg))

void asm_thumb_bl_ind(asm_thumb_t *as, void *fun_ptr, uint fun_id, uint reg_temp) {
void asm_thumb_bl_ind(asm_thumb_t *as, const void *fun_ptr, uint fun_id, uint reg_temp) {
/* TODO make this use less bytes
uint rlo_base = ASM_THUMB_REG_R3;
uint rlo_dest = ASM_THUMB_REG_R7;
Expand Down
2 changes: 1 addition & 1 deletion py/asmthumb.h
Original file line number Diff line number Diff line change
Expand Up @@ -235,7 +235,7 @@ void asm_thumb_mov_reg_local_addr(asm_thumb_t *as, uint rlo_dest, int local_num)

void asm_thumb_b_label(asm_thumb_t *as, uint label); // convenience: picks narrow or wide branch
void asm_thumb_bcc_label(asm_thumb_t *as, int cc, uint label); // convenience: picks narrow or wide branch
void asm_thumb_bl_ind(asm_thumb_t *as, void *fun_ptr, uint fun_id, uint reg_temp); // convenience
void asm_thumb_bl_ind(asm_thumb_t *as, const void *fun_ptr, uint fun_id, uint reg_temp); // convenience

#if GENERIC_ASM_API

Expand Down
2 changes: 1 addition & 1 deletion py/asmx64.c
Original file line number Diff line number Diff line change
Expand Up @@ -612,7 +612,7 @@ void asm_x64_call_i1(asm_x64_t *as, void* func, int i1) {
}
*/

void asm_x64_call_ind(asm_x64_t *as, void *ptr, int temp_r64) {
void asm_x64_call_ind(asm_x64_t *as, const void *ptr, int temp_r64) {
assert(temp_r64 < 8);
#ifdef __LP64__
asm_x64_mov_i64_to_r64_optimised(as, (int64_t)ptr, temp_r64);
Expand Down
2 changes: 1 addition & 1 deletion py/asmx64.h
Original file line number Diff line number Diff line change
Expand Up @@ -112,7 +112,7 @@ void asm_x64_exit(asm_x64_t* as);
void asm_x64_mov_local_to_r64(asm_x64_t* as, int src_local_num, int dest_r64);
void asm_x64_mov_r64_to_local(asm_x64_t* as, int src_r64, int dest_local_num);
void asm_x64_mov_local_addr_to_r64(asm_x64_t* as, int local_num, int dest_r64);
void asm_x64_call_ind(asm_x64_t* as, void* ptr, int temp_r32);
void asm_x64_call_ind(asm_x64_t* as, const void* ptr, int temp_r32);

#if GENERIC_ASM_API

Expand Down
2 changes: 1 addition & 1 deletion py/asmx86.c
Original file line number Diff line number Diff line change
Expand Up @@ -469,7 +469,7 @@ void asm_x86_push_local_addr(asm_x86_t *as, int local_num, int temp_r32)
}
#endif

void asm_x86_call_ind(asm_x86_t *as, void *ptr, mp_uint_t n_args, int temp_r32) {
void asm_x86_call_ind(asm_x86_t *as, const void *ptr, mp_uint_t n_args, int temp_r32) {
// TODO align stack on 16-byte boundary before the call
assert(n_args <= 5);
if (n_args > 4) {
Expand Down
2 changes: 1 addition & 1 deletion py/asmx86.h
179B
Original file line number Diff line number Diff line change
Expand Up @@ -110,7 +110,7 @@ void asm_x86_mov_arg_to_r32(asm_x86_t *as, int src_arg_num, int dest_r32);
void asm_x86_mov_local_to_r32(asm_x86_t* as, int src_local_num, int dest_r32);
void asm_x86_mov_r32_to_local(asm_x86_t* as, int src_r32, int dest_local_num);
void asm_x86_mov_local_addr_to_r32(asm_x86_t* as, int local_num, int dest_r32);
void asm_x86_call_ind(asm_x86_t* as, void* ptr, mp_uint_t n_args, int temp_r32);
void asm_x86_call_ind(asm_x86_t* as, const void* ptr, mp_uint_t n_args, int temp_r32);

#if GENERIC_ASM_API

Expand Down
17 changes: 17 additions & 0 deletions py/emitglue.c
Original file line number Diff line number Diff line change
Expand Up @@ -113,6 +113,17 @@ void mp_emit_glue_assign_native(mp_raw_code_t *rc, mp_raw_code_kind_t kind, void
}
#endif

#if MICROPY_PERSISTENT_NATIVE
void mp_emit_glue_assign_persistent_native(mp_raw_code_t *rc, const void *fun_data,
mp_persistent_native_data_t *per_nat_data, size_t n_pos_args) {
rc->kind = MP_CODE_PERSISTENT_NATIVE;
rc->scope_flags = 0;
rc->n_pos_args = n_pos_args;
rc->data.u_persistent_native.fun_data = fun_data;
rc->data.u_persistent_native.per_nat_data = per_nat_data;
}
#endif

mp_obj_t mp_make_function_from_raw_code(const mp_raw_code_t *rc, mp_obj_t def_args, mp_obj_t def_kw_args) {
DEBUG_OP_printf("make_function_from_raw_code %p\n", rc);
assert(rc != NULL);
Expand All @@ -139,6 +150,12 @@ mp_obj_t mp_make_function_from_raw_code(const mp_raw_code_t *rc, mp_obj_t def_ar
fun = mp_obj_new_fun_asm(rc->n_pos_args, rc->data.u_native.fun_data, rc->data.u_native.type_sig);
break;
#endif
#if MICROPY_PERSISTENT_NATIVE
case MP_CODE_PERSISTENT_NATIVE:
fun = mp_obj_new_fun_persistent_native(false, rc->n_pos_args, rc->n_pos_args,
rc->data.u_persistent_native.fun_data, rc->data.u_persistent_native.per_nat_data);
break;
#endif
default:
// rc->kind should always be set and BYTECODE is the only remaining case
assert(rc->kind == MP_CODE_BYTECODE);
Expand Down
47 changes: 47 additions & 0 deletions py/emitglue.h
Original file line number Diff line number Diff line change
Expand Up @@ -37,8 +37,19 @@ typedef enum {
MP_CODE_NATIVE_PY,
MP_CODE_NATIVE_VIPER,
MP_CODE_NATIVE_ASM,
MP_CODE_PERSISTENT_NATIVE,
} mp_raw_code_kind_t;

#if MICROPY_PERSISTENT_NATIVE
typedef struct _mp_persistent_native_data_t {
const void *fun_table;
qstr *qstr_table;
void *data;
} mp_persistent_native_data_t;< D832 /td>

mp_persistent_native_data_t *mp_new_persistent_native_data(size_t num_qstrs);
#endif

typedef struct _mp_raw_code_t {
mp_raw_code_kind_t kind : 3;
mp_uint_t scope_flags : 7;
Expand All @@ -58,6 +69,12 @@ typedef struct _mp_raw_code_t {
const mp_uint_t *const_table;
mp_uint_t type_sig; // for viper, compressed as 2-bit types; ret is MSB, then arg0, arg1, etc
} u_native;
#if MICROPY_PERSISTENT_NATIVE
struct {
const void *fun_data;
mp_persistent_native_data_t *per_nat_data;
} u_persistent_native;
#endif
} data;
} mp_raw_code_t;

Expand All @@ -70,8 +87,38 @@ void mp_emit_glue_assign_bytecode(mp_raw_code_t *rc, const byte *code, mp_uint_t
#endif
mp_uint_t scope_flags);
void mp_emit_glue_assign_native(mp_raw_code_t *rc, mp_raw_code_kind_t kind, void *fun_data, mp_uint_t fun_len, const mp_uint_t *const_table, mp_uint_t n_pos_args, mp_uint_t scope_flags, mp_uint_t type_sig);
#if MICROPY_PERSISTENT_NATIVE
void mp_emit_glue_assign_persistent_native(mp_raw_code_t *rc, const void *fun_data, mp_persistent_native_data_t *per_nat_data, size_t n_pos_args);
#endif

mp_obj_t mp_make_function_from_raw_code(const mp_raw_code_t *rc, mp_obj_t def_args, mp_obj_t def_kw_args);
mp_obj_t mp_make_closure_from_raw_code(const mp_raw_code_t *rc, mp_uint_t n_closed_over, const mp_obj_t *args);

#if MICROPY_PERSISTENT_CODE

#define MP_PERSISTENT_ARCH_X86 (1)
#define MP_PERSISTENT_ARCH_X64 (2)
#define MP_PERSISTENT_ARCH_M0 (3)
#define MP_PERSISTENT_ARCH_M4 (4)
#define MP_PERSISTENT_ARCH_ARM (5)

// Reference for GCC defines:
// http://micro-os-plus.github.io/develop/predefined-macros/

#if defined(__i386__)
#define MP_PERSISTENT_ARCH_CURRENT (MP_PERSISTENT_ARCH_X86)
#elif defined(__x86_64__)
#define MP_PERSISTENT_ARCH_CURRENT (MP_PERSISTENT_ARCH_X64)
#elif defined(__ARM_ARCH_6M__)
#define MP_PERSISTENT_ARCH_CURRENT (MP_PERSISTENT_ARCH_M0)
#elif defined(__ARM_ARCH_7EM__)
#define MP_PERSISTENT_ARCH_CURRENT (MP_PERSISTENT_ARCH_M4)
#elif defined(__arm__) && !defined(__thumb__)
#define MP_PERSISTENT_ARCH_CURRENT (MP_PERSISTENT_ARCH_ARM)
#else
#error unknown machine architecture
#endif

#endif // MICROPY_PERSISTENT_CODE

#endif // MICROPY_INCLUDED_PY_EMITGLUE_H
Loading
0