Skip to content

RFC: emscripten: Got something to compile and link. #1561

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
wants to merge 1 commit into from
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
73 changes: 73 additions & 0 deletions emscipten/Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
include ../py/mkenv.mk

# qstr definitions (must come before including py.mk)
QSTR_DEFS = qstrdefsport.h

override CSUPEROPT = -O0

# include py core make definitions
include ../py/py.mk

# emscripten doesn't know how to deal with .S files. So we remove all of the
# nlr files and add back nlrsetjmp.o

PY_O_BASENAME := $(filter-out nlr%, $(PY_O_BASENAME)) nlrsetjmp.o


CC = emcc
CPP = gcc -E

INC += -I.
INC += -I..
INC += -I../lib/mp-readline
INC += -I../stmhal
INC += -I$(BUILD)

CFLAGS = $(INC) -Wall -Werror -ansi -std=gnu99 $(COPT)

#Debugging/Optimization
ifeq ($(DEBUG), 1)
CFLAGS += -O0 -ggdb
else
CFLAGS += -O0 -DNDEBUG
endif

LD = emcc
LDFLAGS = -m32 -Wl,-Map=$@.map,--cref

LIBS =

SRC_C = \
main.c \
uart_core.c \
uart_extra.c \
stmhal/printf.c \
lib/utils/pyexec.c \
lib/libc/string0.c \
lib/mp-readline/readline.c \

OBJ = $(PY_O) $(addprefix $(BUILD)/, $(SRC_C:.c=.o))

all: $(BUILD)/micropython.html

$(BUILD)/micropython.bc: $(OBJ)
$(ECHO) "LINK $@"
$(Q)$(LD) $(LDFLAGS) -o $@ $^ $(LIBS)

$(BUILD)/micropython.html: $(BUILD)/micropython.bc
emcc $^ -o $@

run: $(BUILD)/micropython.html
emrun $^

test: $(BUILD)/micropython.bc
$(Q)/bin/echo -e "print('hello world!', list(x+1 for x in range(10)), end='eol\\\\n')\\r\\n\\x04" | $(BUILD)/firmware.elf | tail -n2 | grep "^hello world! \\[1, 2, 3, 4, 5, 6, 7, 8, 9, 10\\]eol"

include ../py/mkrules.mk


# make CC=emcc CPP='gcc -E' CFLAGS_EXTRA=-DMICROPY_NLR_SETJMP MICROPY_PY_FFI=0 STRIP=echo SIZE=echo V=1
#
# mv micropython micropython.bc
# emcc micropython.bc -o micropython.html
# emrun micropython.html
96 changes: 96 additions & 0 deletions emscipten/main.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
#include <stdint.h>
#include <stdio.h>
#include <string.h>

#include "py/nlr.h"
#include "py/compile.h"
#include "py/runtime.h"
#include "py/repl.h"
#include "py/gc.h"
#include "pyexec.h"

void do_str(const char *src, mp_parse_input_kind_t input_kind) {
mp_lexer_t *lex = mp_lexer_new_from_str_len(MP_QSTR__lt_stdin_gt_, src, strlen(src), 0);
if (lex == NULL) {
printf("MemoryError: lexer could not allocate memory\n");
return;
}

nlr_buf_t nlr;
if (nlr_push(&nlr) == 0) {
qstr source_name = lex->source_name;
mp_parse_tree_t parse_tree = mp_parse(lex, input_kind);
mp_obj_t module_fun = mp_compile(&parse_tree, source_name, MP_EMIT_OPT_NONE, true);
mp_call_function_0(module_fun);
nlr_pop();
} else {
// uncaught exception
mp_obj_print_exception(&mp_plat_print, (mp_obj_t)nlr.ret_val);
}
}

static char *stack_top;
static char heap[2048];

int main(int argc, char **argv) {
int stack_dummy;
stack_top = (char*)&stack_dummy;

#if MICROPY_ENABLE_GC
gc_init(heap, heap + sizeof(heap));
#endif
mp_init();
#if MICROPY_REPL_EVENT_DRIVEN
pyexec_event_repl_init();
for (;;) {
int c = mp_hal_stdin_rx_chr();
if (pyexec_event_repl_process_char(c)) {
break;
}
}
#else
pyexec_friendly_repl();
#endif
//do_str("print('hello world!', list(x+1 for x in range(10)), end='eol\\n')", MP_PARSE_SINGLE_INPUT);
//do_str("for i in range(10):\r\n print(i)", MP_PARSE_FILE_INPUT);
mp_deinit();
return 0;
}

void gc_collect(void) {
// WARNING: This gc_collect implementation doesn't try to get root
// pointers from CPU registers, and thus may function incorrectly.
void *dummy;
gc_collect_start();
gc_collect_root(&dummy, ((mp_uint_t)stack_top - (mp_uint_t)&dummy) / sizeof(mp_uint_t));
gc_collect_end();
gc_dump_info();
}

mp_lexer_t *mp_lexer_new_from_file(const char *filename) {
return NULL;
}

mp_import_stat_t mp_import_stat(const char *path) {
return MP_IMPORT_STAT_NO_EXIST;
}

mp_obj_t mp_builtin_open(uint n_args, const mp_obj_t *args, mp_map_t *kwargs) {
return mp_const_none;
}
MP_DEFINE_CONST_FUN_OBJ_KW(mp_builtin_open_obj, 1, mp_builtin_open);

void nlr_jump_fail(void *val) {
}

void NORETURN __fatal_error(const char *msg) {
while (1);
}

#ifndef NDEBUG
void MP_WEAK __assert_func(const char *file, int line, const char *func, const char *expr) {
printf("Assertion '%s' failed, at file %s:%d\n", expr, file, line);
__fatal_error("Assertion failed");
}
#endif

86 changes: 86 additions & 0 deletions emscipten/mpconfigport.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
#include <stdint.h>

// options to control how Micro Python is built

#define MICROPY_QSTR_BYTES_IN_HASH (1)
#define MICROPY_ALLOC_PATH_MAX (256)
#define MICROPY_ALLOC_PARSE_CHUNK_INIT (16)
#define MICROPY_EMIT_X64 (0)
#define MICROPY_EMIT_THUMB (0)
#define MICROPY_EMIT_INLINE_THUMB (0)
#define MICROPY_COMP_MODULE_CONST (0)
#define MICROPY_COMP_CONST (0)
#define MICROPY_COMP_DOUBLE_TUPLE_ASSIGN (0)
#define MICROPY_COMP_TRIPLE_TUPLE_ASSIGN (0)
#define MICROPY_MEM_STATS (0)
#define MICROPY_DEBUG_PRINTERS (0)
#define MICROPY_ENABLE_GC (1)
#define MICROPY_REPL_EVENT_DRIVEN (0)
#define MICROPY_HELPER_REPL (1)
#define MICROPY_HELPER_LEXER_UNIX (0)
#define MICROPY_ENABLE_SOURCE_LINE (0)
#define MICROPY_ENABLE_DOC_STRING (0)
#define MICROPY_ERROR_REPORTING (MICROPY_ERROR_REPORTING_TERSE)
#define MICROPY_BUILTIN_METHOD_CHECK_SELF_ARG (0)
#define MICROPY_NLR_SETJMP (1)
#define MICROPY_GCREGS_SETJMP (1)
#define MICROPY_PY_BUILTINS_BYTEARRAY (0)
#define MICROPY_PY_BUILTINS_MEMORYVIEW (0)
#define MICROPY_PY_BUILTINS_ENUMERATE (0)
#define MICROPY_PY_BUILTINS_FILTER (0)
#define MICROPY_PY_BUILTINS_FROZENSET (0)
#define MICROPY_PY_BUILTINS_REVERSED (0)
#define MICROPY_PY_BUILTINS_SET (0)
#define MICROPY_PY_BUILTINS_SLICE (0)
#define MICROPY_PY_BUILTINS_PROPERTY (0)
#define MICROPY_PY___FILE__ (0)
#define MICROPY_PY_GC (0)
#define MICROPY_PY_ARRAY (0)
#define MICROPY_PY_ATTRTUPLE (0)
#define MICROPY_PY_COLLECTIONS (0)
#define MICROPY_PY_MATH (0)
#define MICROPY_PY_CMATH (0)
#define MICROPY_PY_IO (0)
#define MICROPY_PY_STRUCT (0)
#define MICROPY_PY_SYS (0)
#define MICROPY_MODULE_FROZEN (0)
#define MICROPY_CPYTHON_COMPAT (0)
#define MICROPY_FLOAT_IMPL (MICROPY_FLOAT_IMPL_DOUBLE)
#define MICROPY_LONGINT_IMPL (MICROPY_LONGINT_IMPL_MPZ)

// type definitions for the specific machine

#define BYTES_PER_WORD (4)

#define MICROPY_MAKE_POINTER_CALLABLE(p) ((void*)((mp_uint_t)(p) | 1))

// This port is intended to be 32-bit, but unfortunately, int32_t for
// different targets may be defined in different ways - either as int
// or as long. This requires different printf formatting specifiers
// to print such value. So, we avoid int32_t and use int directly.
#define UINT_FMT "%u"
#define INT_FMT "%d"
typedef int mp_int_t; // must be pointer size
typedef unsigned mp_uint_t; // must be pointer size

typedef void *machine_ptr_t; // must be of pointer size
typedef const void *machine_const_ptr_t; // must be of pointer size
typedef long mp_off_t;

#define MP_PLAT_PRINT_STRN(str, len) mp_hal_stdout_tx_strn_cooked(str, len)

// extra built in names to add to the global namespace
extern const struct _mp_obj_fun_builtin_t mp_builtin_open_obj;
#define MICROPY_PORT_BUILTINS \
{ MP_OBJ_NEW_QSTR(MP_QSTR_open), (mp_obj_t)&mp_builtin_open_obj },

// We need to provide a declaration/definition of alloca()
#include <alloca.h>

#define MICROPY_HW_BOARD_NAME "emscripten"
#define MICROPY_HW_MCU_NAME "unknown-cpu"

#define MP_STATE_PORT MP_STATE_VM

#define MICROPY_PORT_ROOT_POINTERS \
const char *readline_hist[8];
2 changes: 2 additions & 0 deletions emscipten/mphalport.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
static inline mp_uint_t mp_hal_ticks_ms(void) { return 0; }
static inline void mp_hal_set_interrupt_char(char c) {}
1 change: 1 addition & 0 deletions emscipten/qstrdefsport.h
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
// qstrs specific to this port
20 changes: 20 additions & 0 deletions emscipten/uart_core.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
#include <unistd.h>
#include "py/mpconfig.h"

/*
* Core UART functions to implement for a port
*/

// Receive single character
int mp_hal_stdin_rx_chr(void) {
unsigned char c = 0;
int r = read(0, &c, 1);
(void)r;
return c;
}

// Send string of given length
void mp_hal_stdout_tx_strn(const char *str, mp_uint_t len) {
int r = write(1, str, len);
(void)r;
}
26 changes: 26 additions & 0 deletions emscipten/uart_extra.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
#include <string.h>
#include <unistd.h>
#include "py/mpconfig.h"
#include "py/mphal.h"

/*
* Extra UART functions
* These can be either optimized for a particular port, or reference,
* not very optimal implementation below can be used.
*/

// Send "cooked" string of length, where every occurance of
// LF character is replaced with CR LF.
void mp_hal_stdout_tx_strn_cooked(const char *str, mp_uint_t len) {
while (len--) {
if (*str == '\n') {
mp_hal_stdout_tx_strn("\r", 1);
}
mp_hal_stdout_tx_strn(str++, 1);
}
}

// Send zero-terminated string
void mp_hal_stdout_tx_str(const char *str) {
mp_hal_stdout_tx_strn(str, strlen(str));
}
6 changes: 3 additions & 3 deletions py/obj.h
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,7 @@ typedef struct _mp_obj_base_t mp_obj_base_t;
static inline bool MP_OBJ_IS_SMALL_INT(mp_const_obj_t o)
{ return ((((mp_int_t)(o)) & 1) != 0); }
#define MP_OBJ_SMALL_INT_VALUE(o) (((mp_int_t)(o)) >> 1)
#define MP_OBJ_NEW_SMALL_INT(small_int) ((mp_obj_t)((((mp_int_t)(small_int)) << 1) | 1))
#define MP_OBJ_NEW_SMALL_INT(small_int) ((mp_obj_t)((((mp_uint_t)(small_int)) << 1) | 1))

static inline bool MP_OBJ_IS_QSTR(mp_const_obj_t o)
{ return ((((mp_int_t)(o)) & 3) == 2); }
Expand All @@ -102,7 +102,7 @@ static inline bool MP_OBJ_IS_OBJ(mp_const_obj_t o)
static inline bool MP_OBJ_IS_SMALL_INT(mp_const_obj_t o)
{ return ((((mp_int_t)(o)) & 3) == 1); }
#define MP_OBJ_SMALL_INT_VALUE(o) (((mp_int_t)(o)) >> 2)
#define MP_OBJ_NEW_SMALL_INT(small_int) ((mp_obj_t)((((mp_int_t)(small_int)) << 2) | 1))
#define MP_OBJ_NEW_SMALL_INT(small_int) ((mp_obj_t)((((mp_uint_t)(small_int)) << 2) | 1))

static inline bool MP_OBJ_IS_QSTR(mp_const_obj_t o)
{ return ((((mp_int_t)(o)) & 3) == 3); }
Expand All @@ -128,7 +128,7 @@ static inline bool MP_OBJ_IS_OBJ(mp_const_obj_t o)
static inline bool MP_OBJ_IS_SMALL_INT(mp_const_obj_t o)
{ return ((((mp_int_t)(o)) & 1) != 0); }
#define MP_OBJ_SMALL_INT_VALUE(o) (((mp_int_t)(o)) >> 1)
#define MP_OBJ_NEW_SMALL_INT(small_int) ((mp_obj_t)((((mp_int_t)(small_int)) << 1) | 1))
#define MP_OBJ_NEW_SMALL_INT(small_int) ((mp_obj_t)((((mp_uint_t)(small_int)) << 1) | 1))

#define mp_const_float_e ((mp_obj_t)((0x402df854 & ~3) | 2))
#define mp_const_float_pi ((mp_obj_t)((0x40490fdb & ~3) | 2))
Expand Down
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy