...
 
Commits (17)
This diff is collapsed.
/*
* This file is part of the MicroPython port to LEON platforms
* Copyright (c) 2018 George Robotics Limited
*/
#include "leon-common/leonprintf.h"
static void leon_putc(char c) {
#if RTEMS_4_8_EDISOFT
// RTEMS 4.8 Edisoft has a custom output function provided by leon2serial.c
extern void output_a_character_to_leon2_port0(unsigned char c);
output_a_character_to_leon2_port0(c);
#else
// All other RTEMS versions use this function for output
extern void console_outbyte_polled(int port, unsigned char ch);
console_outbyte_polled(0, c);
#endif
}
int leon_printf(const char *fmt, ...) {
va_list ap;
va_start(ap, fmt);
int ret = leon_vprintf(fmt, ap);
va_end(ap);
return ret;
}
int leon_vprintf(const char *fmt, va_list args) {
int chrs = 0;
while (*fmt != '\0') {
if (*fmt == '%') {
++fmt;
if (*fmt == 'u') {
++fmt;
unsigned int i = va_arg(args, unsigned int);
char buf[32];
char *b = &buf[0];
if (i == 0) {
*b++ = '0';
} else {
while (i && b < &buf[sizeof(buf)]) {
*b++ = '0' + i % 10;
i /= 10;
}
}
while (b > &buf[0]) {
leon_putc(*--b);
chrs += 1;
}
} else if (*fmt != '\0') {
// print any other format specifiers (handles %% correctly)
leon_putc(*fmt++);
chrs += 1;
}
} else {
// print non-format character
leon_putc(*fmt++);
chrs += 1;
}
}
return chrs;
}
/*
* This file is part of the MicroPython port to LEON platforms
* Copyright (c) 2018 George Robotics Limited
*/
#pragma once
#include <stdarg.h>
int leon_printf(const char *fmt, ...);
int leon_vprintf(const char *fmt, va_list args);
......@@ -41,6 +41,7 @@ LIBS += -lm
SRC_C = \
main.c \
lib/libc/string0.c \
$(LEON_COMMON)/leonprintf.c \
$(LEON_COMMON)/mputil.c \
$(LEON_COMMON)/mpvmmanage.c \
$(LEON_COMMON)/mphalport.c \
......
......@@ -91,7 +91,7 @@ rtems_task Init(rtems_task_argument ignored) {
// MicroPython manager task
#include "py/mpstate.h"
#include "py/mpprint.h"
#include "leon-common/leonprintf.h"
#include "mpvmmanage.h"
// include the precompiled bytecode (generated by external tools)
......@@ -102,7 +102,7 @@ static mp_state_ctx_t mp_state_ctx[MICROPY_RTEMS_NUM_TASKS];
static byte mp_heap[MICROPY_RTEMS_NUM_TASKS * MICROPY_RTEMS_HEAP_SIZE];
rtems_task mp_manager_task(rtems_task_argument ignored) {
mp_printf(&mp_plat_print, "\nMicroPython manager task started\n");
leon_printf("\nMicroPython manager task started\n");
rtems_name task_name[MICROPY_RTEMS_NUM_TASKS];
rtems_id task_id[MICROPY_RTEMS_NUM_TASKS];
......@@ -131,12 +131,12 @@ rtems_task mp_manager_task(rtems_task_argument ignored) {
// pause the script
mp_vm_manager_pause(&mp_state_ctx[0], 10000, &line);
mp_printf(&mp_plat_print, "Manager got line %u\n", (uint)line);
leon_printf("Manager got line %u\n", (uint)line);
// step through the script
for (int i = 0; i < 3; ++i) {
mp_vm_manager_step(&mp_state_ctx[0], 10000, &line);
mp_printf(&mp_plat_print, "Manager got line %u\n", (uint)line);
leon_printf("Manager got line %u\n", (uint)line);
}
// resume the script
......
......@@ -41,6 +41,7 @@ LIBS += -lm
SRC_C = \
main.c \
lib/libc/string0.c \
$(LEON_COMMON)/leonprintf.c \
$(LEON_COMMON)/mputil.c \
$(LEON_COMMON)/mphalport.c \
$(LEON_COMMON)/modtime.c \
......
......@@ -86,15 +86,15 @@ rtems_task Init(rtems_task_argument ignored) {
/******************************************************************************/
// MicroPython manager task
#include "py/mpprint.h"
#include "leon-common/leonprintf.h"
// this function is used as a hook to set a breakpoint to terminate emu
void emu_terminate(void) {
mp_printf(&mp_plat_print, "emu_terminate\n");
leon_printf("emu_terminate\n");
}
rtems_task mp_manager_task(rtems_task_argument ignored) {
mp_printf(&mp_plat_print, "\nMicroPython manager task started\n");
leon_printf("\nMicroPython manager task started\n");
rtems_name task_name[MICROPY_RTEMS_NUM_TASKS];
rtems_id task_id[MICROPY_RTEMS_NUM_TASKS];
......
......@@ -43,6 +43,7 @@ LIBS += -lm
SRC_C = \
main.c \
lib/libc/string0.c \
$(LEON_COMMON)/leonprintf.c \
$(LEON_COMMON)/mputil.c \
$(LEON_COMMON)/mphalport.c \
$(LEON_COMMON)/modtime.c \
......
......@@ -82,15 +82,15 @@ rtems_task Init(rtems_task_argument ignored) {
/******************************************************************************/
// MicroPython manager task
#include "py/mpprint.h"
#include "leon-common/leonprintf.h"
// this function is used as a hook to set a breakpoint to terminate emu
void emu_terminate(void) {
mp_printf(&mp_plat_print, "emu_terminate\n");
leon_printf("emu_terminate\n");
}
rtems_task mp_manager_task(rtems_task_argument ignored) {
mp_printf(&mp_plat_print, "\nMicroPython manager task started\n");
leon_printf("\nMicroPython manager task started\n");
rtems_name task_name[MICROPY_RTEMS_NUM_TASKS];
rtems_id task_id[MICROPY_RTEMS_NUM_TASKS];
......
......@@ -41,6 +41,7 @@ LIBS += -lm
SRC_C = \
main.c \
lib/libc/string0.c \
$(LEON_COMMON)/leonprintf.c \
$(LEON_COMMON)/mputil.c \
$(LEON_COMMON)/mphalport.c \
$(LEON_COMMON)/modtime.c \
......
......@@ -85,10 +85,10 @@ rtems_task Init(rtems_task_argument ignored) {
/******************************************************************************/
// MicroPython manager task
#include "py/mpprint.h"
#include "leon-common/leonprintf.h"
rtems_task mp_manager_task(rtems_task_argument ignored) {
mp_printf(&mp_plat_print, "\nMicroPython manager task started\n");
leon_printf("\nMicroPython manager task started\n");
rtems_name task_name[MICROPY_RTEMS_NUM_TASKS];
rtems_id task_id[MICROPY_RTEMS_NUM_TASKS];
......
......@@ -48,6 +48,7 @@ SRC_C = \
lib/libc/strcmp.c \
lib/libc/strlen.c \
lib/libc/strncmp.c \
$(LEON_COMMON)/leonprintf.c \
$(LEON_COMMON)/nearbyint.c \
$(LEON_COMMON)/mputil.c \
$(LEON_COMMON)/mphalport.c \
......
......@@ -97,16 +97,16 @@ rtems_task Init(rtems_task_argument ignored) {
#define MPY_MEM_BASE (0x40200000)
#define MPY_MEM_STRIDE (0x00010000)
#include "py/mpprint.h"
#include "py/mphal.h"
#include "leon-common/leonprintf.h"
// this function is used as a hook to set a breakpoint to terminate emu
void emu_terminate(void) {
mp_printf(&mp_plat_print, "emu_terminate\n");
leon_printf("emu_terminate\n");
}
rtems_task mp_manager_task(rtems_task_argument ignored) {
mp_printf(&mp_plat_print, "\nMicroPython manager task started\n");
leon_printf("\nMicroPython manager task started\n");
// detect the number of tasks needed by looking for valid scripts
int num_tasks = 0;
......@@ -120,7 +120,7 @@ rtems_task mp_manager_task(rtems_task_argument ignored) {
break;
}
}
mp_printf(&mp_plat_print, "Detected %u scripts\n", num_tasks);
leon_printf("Detected %u scripts\n", num_tasks);
// we must use hexlified output so it isn't modified by the UART
mp_hal_stdout_enable_hexlify();
......@@ -137,12 +137,12 @@ rtems_task mp_manager_task(rtems_task_argument ignored) {
MICROPY_RTEMS_TASK_ATTRIBUTES, &task_id[i]
);
if (status != RTEMS_SUCCESSFUL) {
mp_printf(&mp_plat_print, "Error creating task #%u: %u\n", i, status);
leon_printf("Error creating task #%u: %u\n", i, status);
emu_terminate();
}
status = rtems_task_start(task_id[i], mp_worker_task, i);
if (status != RTEMS_SUCCESSFUL) {
mp_printf(&mp_plat_print, "Error starting task #%u: %u\n", i, status);
leon_printf("Error starting task #%u: %u\n", i, status);
emu_terminate();
}
}
......
......@@ -48,6 +48,7 @@ SRC_C = \
lib/libc/strcmp.c \
lib/libc/strlen.c \
lib/libc/strncmp.c \
$(LEON_COMMON)/leonprintf.c \
$(LEON_COMMON)/nearbyint.c \
$(LEON_COMMON)/mputil.c \
$(LEON_COMMON)/mphalport.c \
......
......@@ -97,16 +97,16 @@ rtems_task Init(rtems_task_argument ignored) {
#define MPY_MEM_BASE (0x40200000)
#define MPY_MEM_STRIDE (0x00010000)
#include "py/mpprint.h"
#include "py/mphal.h"
#include "leon-common/leonprintf.h"
// this function is used as a hook to set a breakpoint to terminate emu
void emu_terminate(void) {
mp_printf(&mp_plat_print, "emu_terminate\n");
leon_printf("emu_terminate\n");
}
rtems_task mp_manager_task(rtems_task_argument ignored) {
mp_printf(&mp_plat_print, "\nMicroPython manager task started\n");
leon_printf("\nMicroPython manager task started\n");
// detect the number of tasks needed by looking for valid scripts
int num_tasks = 0;
......@@ -120,7 +120,7 @@ rtems_task mp_manager_task(rtems_task_argument ignored) {
break;
}
}
mp_printf(&mp_plat_print, "Detected %u scripts\n", num_tasks);
leon_printf("Detected %u scripts\n", num_tasks);
// we must use hexlified output so it isn't modified by the UART
mp_hal_stdout_enable_hexlify();
......@@ -137,12 +137,12 @@ rtems_task mp_manager_task(rtems_task_argument ignored) {
MICROPY_RTEMS_TASK_ATTRIBUTES, &task_id[i]
);
if (status != RTEMS_SUCCESSFUL) {
mp_printf(&mp_plat_print, "Error creating task #%u: %u\n", i, status);
leon_printf("Error creating task #%u: %u\n", i, status);
emu_terminate();
}
status = rtems_task_start(task_id[i], mp_worker_task, i);
if (status != RTEMS_SUCCESSFUL) {
mp_printf(&mp_plat_print, "Error starting task #%u: %u\n", i, status);
leon_printf("Error starting task #%u: %u\n", i, status);
emu_terminate();
}
}
......
......@@ -173,5 +173,4 @@ ValueError
-70368744177663
70368744177664
-70368744177664
True
aaaa
......@@ -102,8 +102,12 @@ x = 4611686018427387904 # big
x = -4611686018427387904 # big
# sys.maxsize is a constant mpz, so test it's compatible with dynamic ones
# (sys.maxsize may not be available in all configurations)
import sys
print(sys.maxsize + 1 - 1 == sys.maxsize)
try:
assert sys.maxsize + 1 - 1 == sys.maxsize
except AttributeError:
pass
# test extraction of big int value via mp_obj_get_int_maybe
x = 1 << 70
......
......@@ -21,4 +21,5 @@
-1
-1
-1
-1
TypeError
......@@ -21,6 +21,7 @@ print("0000".find('-1', 3))
print("0000".find('1', 3))
print("0000".find('1', 4))
print("0000".find('1', 5))
print("aaaaaaaaaaa".find("bbb", 9, 2))
try:
'abc'.find(1)
......
......@@ -21,3 +21,4 @@ print("0000".rfind('-1', 3))
print("0000".rfind('1', 3))
print("0000".rfind('1', 4))
print("0000".rfind('1', 5))
print("aaaaaaaaaaa".rfind("bbb", 9, 2))
......@@ -5,30 +5,31 @@ try:
except:
import struct
import sys
maxsize_bits = 0
maxsize = sys.maxsize
while maxsize:
maxsize >>= 1
maxsize_bits += 1
# work out configuration values
is_64bit = maxsize_bits > 32
# 0 = none, 1 = long long, 2 = mpz
ll_type = None
if is_64bit:
if maxsize_bits < 63:
ll_type = 0
else:
if maxsize_bits < 31:
ll_type = 0
if ll_type is None:
one = 1
if one << 65 < one << 62:
ll_type = 1
else:
ll_type = 2
#import sys
#
#maxsize_bits = 0
#maxsize = sys.maxsize
#while maxsize:
# maxsize >>= 1
# maxsize_bits += 1
#
## work out configuration values
#is_64bit = maxsize_bits > 32
## 0 = none, 1 = long long, 2 = mpz
#ll_type = None
#if is_64bit:
# if maxsize_bits < 63:
# ll_type = 0
#else:
# if maxsize_bits < 31:
# ll_type = 0
#if ll_type is None:
# one = 1
# if one << 65 < one << 62:
# ll_type = 1
# else:
# ll_type = 2
is_64bit = False
ll_type = 2 # force mpz
......
# This tests that recursion with iternext doesn't lead to segfault.
N = 200
N = 300
try:
x = (1, 2)
......
......@@ -3,3 +3,4 @@ NotImplementedError
123
1 2
70368744177664
<class 'int'>
......@@ -21,3 +21,7 @@ print(A.x, A.y)
# test overflow of 47-bit small-int in nan-boxing config
i = -0x3fffffffffff
print(-(i - 1))
# test pystack_use()
import micropython
print(type(micropython.pystack_use()))
......@@ -18,7 +18,7 @@ if [ -r VERSION ]; then
exit 1
fi
echo -e "MicroPython port to SPARC/LEON/RTEMS platforms\nCopyright (c) 2015-2017 George Robotics Limited\nVersion $REV\nPackaged on $(date -u)\nSource repository tag $(git describe)" > VERSION
echo -e "MicroPython port to SPARC/LEON/RTEMS platforms\nCopyright (c) 2015-2018 George Robotics Limited\nVersion $REV\nPackaged on $(date -u)\nSource repository tag $(git describe)" > VERSION
/bin/ln -s . micropython-leon-$REV
......
......@@ -35,6 +35,7 @@
#include "py/obj.h"
#include "py/objint.h"
#include "py/runtime.h"
#include "py/stackctrl.h"
#if MICROPY_PY_BUILTINS_FLOAT
#include "py/formatfloat.h"
......@@ -386,6 +387,7 @@ int mp_printf(const mp_print_t *print, const char *fmt, ...) {
}
int mp_vprintf(const mp_print_t *print, const char *fmt, va_list args) {
MP_STACK_CHECK();
int chrs = 0;
for (;;) {
{
......
......@@ -638,6 +638,7 @@ mp_obj_t mp_obj_new_bytearray_by_ref(size_t n, void *items);
mp_obj_t mp_obj_new_int_from_float(mp_float_t val);
mp_obj_t mp_obj_new_complex(mp_float_t real, mp_float_t imag);
#endif
mp_obj_t mp_obj_new_exception_emg(const mp_obj_type_t *exc_type, mp_obj_t arg);
mp_obj_t mp_obj_new_exception(const mp_obj_type_t *exc_type);
mp_obj_t mp_obj_new_exception_arg1(const mp_obj_type_t *exc_type, mp_obj_t arg);
mp_obj_t mp_obj_new_exception_args(const mp_obj_type_t *exc_type, size_t n_args, const mp_obj_t *args);
......
......@@ -298,6 +298,39 @@ MP_DEFINE_EXCEPTION(Exception, BaseException)
MP_DEFINE_EXCEPTION(ResourceWarning, Warning)
*/
// Create a new exception object using only the emergency object/buffer.
// This function will not call any other functions so is safe from recursion,
// does not attemp to allocate on the heap, and uses minimal C stack.
mp_obj_t mp_obj_new_exception_emg(const mp_obj_type_t *exc_type, mp_obj_t arg) {
mp_obj_exception_t *o_exc = &MP_STATE_VM(mp_emergency_exception_obj);
// Populate the exception object, with a default of the empty tuple for args
o_exc->base.type = exc_type;
o_exc->traceback_data = NULL;
o_exc->args = (mp_obj_tuple_t*)&mp_const_empty_tuple_obj;
#if MICROPY_ENABLE_EMERGENCY_EXCEPTION_BUF
// Check if we have some room in the emergency buffer to create a 1-tuple for the args
if (mp_emergency_exception_buf_size >=
EMG_TRACEBACK_ALLOC * sizeof(size_t) + sizeof(mp_obj_tuple_t) + sizeof(mp_obj_t)) {
// Get a pointer into the buffer for the tuple object
mp_obj_tuple_t *o_tuple = (mp_obj_tuple_t*)
((uint8_t*)MP_STATE_VM(mp_emergency_exception_buf) + EMG_TRACEBACK_ALLOC * sizeof(size_t));
// Create the tuple
o_tuple->base.type = &mp_type_tuple;
o_tuple->len = 1;
o_tuple->items[0] = arg;
// Store the tuple of args in the exception object
o_exc->args = o_tuple;
}
#endif
return MP_OBJ_FROM_PTR(o_exc);
}
mp_obj_t mp_obj_new_exception(const mp_obj_type_t *exc_type) {
return mp_obj_new_exception_args(exc_type, 0, NULL);
}
......
......@@ -703,8 +703,13 @@ STATIC mp_obj_t str_finder(size_t n_args, const mp_obj_t *args, int direction, b
end = str_index_to_ptr(self_type, haystack, haystack_len, args[3], true);
}
if (end < start) {
goto out_error;
}
const byte *p = find_subbytes(start, end - start, needle, needle_len, direction);
if (p == NULL) {
out_error:
// not found
if (is_index) {
mp_raise_ValueError("substring not found");
......
......@@ -43,7 +43,7 @@ void *mp_pystack_alloc(size_t n_bytes) {
#endif
if (MP_STATE_THREAD(pystack_cur) + n_bytes > MP_STATE_THREAD(pystack_end)) {
// out of memory in the pystack
nlr_raise(mp_obj_new_exception_arg1(&mp_type_RuntimeError,
nlr_raise(mp_obj_new_exception_emg(&mp_type_RuntimeError,
MP_OBJ_NEW_QSTR(MP_QSTR_pystack_space_exhausted)));
}
void *ptr = MP_STATE_THREAD(pystack_cur);
......
......@@ -1483,7 +1483,7 @@ NORETURN void mp_raise_NotImplementedError(const char *msg) {
#if MICROPY_STACK_CHECK || MICROPY_ENABLE_PYSTACK
NORETURN void mp_raise_recursion_depth(void) {
nlr_raise(mp_obj_new_exception_arg1(&mp_type_RuntimeError,
nlr_raise(mp_obj_new_exception_emg(&mp_type_RuntimeError,
MP_OBJ_NEW_QSTR(MP_QSTR_maximum_space_recursion_space_depth_space_exceeded)));
}
#endif
......@@ -21,6 +21,7 @@ print("0000".find('-1', 3))
print("0000".find('1', 3))
print("0000".find('1', 4))
print("0000".find('1', 5))
print("aaaaaaaaaaa".find("bbb", 9, 2))
try:
'abc'.find(1)
......
......@@ -21,3 +21,4 @@ print("0000".rfind('-1', 3))
print("0000".rfind('1', 3))
print("0000".rfind('1', 4))
print("0000".rfind('1', 5))
print("aaaaaaaaaaa".rfind("bbb", 9, 2))
......@@ -2,6 +2,15 @@
import micropython
# Check for stackless build, which can't call functions without
# allocating a frame on the heap.
try:
def stackless(): pass
micropython.heap_lock(); stackless(); micropython.heap_unlock()
except RuntimeError:
print("SKIP")
raise SystemExit
# some ports need to allocate heap for the emergency exception
try:
micropython.alloc_emergency_exception_buf(256)
......@@ -26,7 +35,7 @@ def main():
except Exception as er:
e = er
micropython.heap_unlock()
print(repr(e)[:50])
print(repr(e)[:10])
# create an exception with a long formatted error message while heap is low
# should use the heap and truncate the message
......@@ -40,8 +49,9 @@ def main():
f(abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz=1)
except Exception as er:
e = er
lst[0] = None
lst = None
print(repr(e))
print(repr(e)[:10])
# raise a deep exception with the heap locked
# should use emergency exception and be unable to resize traceback array
......@@ -53,7 +63,7 @@ def main():
except Exception as er:
e = er
micropython.heap_unlock()
print(repr(e))
print(repr(e)[:13])
# create an exception on the heap with some traceback on the heap, but then
# raise it with the heap locked so it can't allocate any more traceback
......
Exception()
TypeError("unexpected keyword argument 'abcdefghij
TypeError("unexpected keyword argument 'abc",)
RuntimeError('maximum recursion depth exceeded',)
TypeError(
TypeError(
RuntimeError(
Exception('my exception',)