Commit 4cc6054b authored by Damien George's avatar Damien George
Browse files

leon: Add leon-for-tests component.

parent 0065407f
# This file is part of the MicroPython port to LEON platforms
# Copyright (c) 2015-2016 George Robotics Limited
#
# Provided to the European Space Agency as part of the project "Porting of
# MicroPython to LEON platforms", contract number 4000114080/15/NL/FE/as.
#
# This Makefile builds the LEON port used for running the test suite.
# the location of the MIcroPython LEON support code
LEON_COMMON = leon-common
LEON_COMMON_FROM_HERE = ../$(LEON_COMMON)
include ../py/mkenv.mk
# qstr definitions (must come before including py.mk)
QSTR_DEFS = $(LEON_COMMON_FROM_HERE)/qstrdefsport.h
# include py core make definitions
include ../py/py.mk
# the toolchain needs two things:
# - the sparc-rtems compiler: (TOOL_BASE)
# - the precompiled RTEMS (RTEMS_BASE)
TOOL_BASE = /home/notroot/Download/rtems-4.8/bin
RTEMS_BASE = /home/notroot/Download/rtems-4.8/sparc-rtems/leon2
CROSS_COMPILE = $(TOOL_BASE)/sparc-rtems-
LD = $(CROSS_COMPILE)gcc
OBJDUMP = $(CROSS_COMPILE)objdump
# RTEMS lib needs
GCCSPECS = -B$(RTEMS_BASE)/lib/ -specs bsp_specs -qrtems
INC =
INC += -I. -I.. -I$(BUILD) -I$(LEON_COMMON_FROM_HERE)
INC += -I$(RTEMS_BASE)/lib/include
CFLAGS =
CFLAGS += $(GCCSPECS)
CFLAGS += $(INC) -Wall -Werror -ansi -std=gnu99 $(COPT) -mcpu=v8
# Use this to optimise the static hash tables
CFLAGS += -no-integrated-cpp -B$(shell pwd)/../tools
# Debugging/Optimization
ifeq ($(DEBUG), 1)
CFLAGS += -O0 -ggdb
else
CFLAGS += -Os -DNDEBUG
endif
LDFLAGS =
LDFLAGS += $(GCCSPECS)
LDFLAGS += -L$(RTEMS_BASE)/lib
LIBS = -lm
SRC_C = \
main.c \
lib/libc/string0.c \
$(LEON_COMMON)/mputil.c \
$(LEON_COMMON)/mpvmmanage.c \
$(LEON_COMMON)/mphalport.c \
$(LEON_COMMON)/modtime.c \
$(LEON_COMMON)/modrtems.c \
$(LEON_COMMON)/modrtemstask.c \
$(LEON_COMMON)/modrtemsqueue.c \
$(LEON_COMMON)/modrtemstimer.c \
SRC_S = \
$(LEON_COMMON)/gchelper.s \
OBJ = $(PY_O) $(addprefix $(BUILD)/, $(SRC_C:.c=.o) $(SRC_S:.s=.o))
all: $(BUILD)/firmware.elf $(BUILD)/firmware.srec $(BUILD)/firmware.tab
$(BUILD)/firmware.elf: $(OBJ)
$(ECHO) "LINK $@"
$(Q)$(LD) $(LDFLAGS) -o $@ $(OBJ) $(LIBS)
$(Q)$(SIZE) $@
$(BUILD)/firmware.srec: $(BUILD)/firmware.elf
$(ECHO) "SREC $@"
$(Q)$(OBJCOPY) -O srec $< $@
$(BUILD)/firmware.tab: $(BUILD)/firmware.elf
$(ECHO) "TAB $@"
$(Q)$(OBJDUMP) --syms $< > $@
include ../py/mkrules.mk
/*
* This file is part of the MicroPython port to LEON platforms
* Copyright (c) 2015-2016 George Robotics Limited
*
* Provided to the European Space Agency as part of the project "Porting of
* MicroPython to LEON platforms", contract number 4000114080/15/NL/FE/as.
*/
#include <stdio.h>
#include <rtems.h>
#include <bsp.h>
#define CONFIGURE_INIT
#define CONFIGURE_INIT_TASK_ENTRY_POINT Init
#define CONFIGURE_APPLICATION_NEEDS_CONSOLE_DRIVER
#define CONFIGURE_APPLICATION_NEEDS_CLOCK_DRIVER
#define CONFIGURE_MAXIMUM_TASKS (12)
#define CONFIGURE_RTEMS_INIT_TASKS_TABLE
#define CONFIGURE_EXTRA_TASK_STACKS (20 * RTEMS_MINIMUM_STACK_SIZE)
rtems_task Init(rtems_task_argument argument);
rtems_task mp_manager_task(rtems_task_argument unused);
rtems_task mp_worker_task(rtems_task_argument unused);
#include <rtems/confdefs.h>
#define MICROPY_RTEMS_TASK_ATTRIBUTES (RTEMS_APPLICATION_TASK | RTEMS_FLOATING_POINT)
#define MICROPY_RTEMS_STACK_SIZE (RTEMS_MINIMUM_STACK_SIZE * 3)
#define MICROPY_RTEMS_HEAP_SIZE (48 * 1024)
#define MICROPY_RTEMS_NUM_TASKS (10)
/******************************************************************************/
// RTEMS initialisation task
// this task runs at highest priority and is non-preemptive
rtems_task Init(rtems_task_argument ignored) {
// set the time
rtems_time_of_day time;
time.year = 2016;
time.month = 1;
time.day = 1;
time.hour = 0;
time.minute = 0;
time.second = 0;
time.ticks = 0;
rtems_clock_set(&time);
// initialise the message queue subsystem
_Message_queue_Manager_initialization(4);
// initialise the timer subsystem
_Timer_Manager_initialization(2);
// start the manager task to do the rest of the work
rtems_name task_name = rtems_build_name('M', 'P', 'M', 'A');
rtems_id task_id;
rtems_status_code status;
status = rtems_task_create(
task_name, 1, RTEMS_MINIMUM_STACK_SIZE, RTEMS_DEFAULT_MODES,
MICROPY_RTEMS_TASK_ATTRIBUTES, &task_id
);
status = rtems_task_start(task_id, mp_manager_task, 0);
rtems_task_delete(RTEMS_SELF);
}
/******************************************************************************/
// MicroPython manager task
// these variables define the location of the externally-loaded .mpy files
#define MPY_MEM_BASE (0x40100000)
#define MPY_MEM_STRIDE (0x00010000)
#include "py/mphal.h"
// this function is used as a hook to set a breakpoint to terminate emu
void emu_terminate(void) {
printf("emu_terminate\n");
}
rtems_task mp_manager_task(rtems_task_argument ignored) {
printf("\nMicroPython manager task started\n");
// detect the number of tasks needed by looking for valid scripts
int num_tasks = 0;
for (int i = 0; i < MICROPY_RTEMS_NUM_TASKS; ++i) {
const void *mpy_base = (const void*)(MPY_MEM_BASE + MPY_MEM_STRIDE * i);
size_t mpy_len = *(const uint32_t*)mpy_base;
const uint8_t *mpy_data = (const uint8_t*)(mpy_base + 4);
if (mpy_len > 0 && mpy_data[0] == 'M') {
num_tasks += 1;
} else {
break;
}
}
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();
rtems_name task_name[MICROPY_RTEMS_NUM_TASKS];
rtems_id task_id[MICROPY_RTEMS_NUM_TASKS];
// spawn all worker tasks
for (int i = 0; i < num_tasks; ++i) {
rtems_status_code status;
task_name[i] = rtems_build_name('M', 'P', '0', '0' + i);
status = rtems_task_create(
task_name[i], 1, MICROPY_RTEMS_STACK_SIZE, RTEMS_DEFAULT_MODES,
MICROPY_RTEMS_TASK_ATTRIBUTES, &task_id[i]
);
if (status != RTEMS_SUCCESSFUL) {
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) {
printf("Error starting task #%u: %u\n", i, status);
emu_terminate();
}
}
// wait for all scripts to finish
for (;;) {
rtems_task_wake_after(200);
int num_tasks_complete = 0;
for (int i = 0; i < num_tasks; ++i) {
uint32_t note;
rtems_task_get_note(task_id[i], RTEMS_NOTEPAD_0, &note);
if (note != 0) {
num_tasks_complete += 1;
}
}
if (num_tasks_complete == num_tasks) {
mp_hal_stdout_disable_hexlify();
emu_terminate();
}
}
}
/******************************************************************************/
// MicroPython worker task
#include "py/runtime.h"
#include "py/gc.h"
#include "py/stackctrl.h"
#include "mputil.h"
// these settings are used to check the heap for overflow
#define HEAP_PRE (128)
#define HEAP_POST (128)
#define HEAP_SIZE (HEAP_PRE + MICROPY_RTEMS_HEAP_SIZE + HEAP_POST)
static mp_state_ctx_t mp_state_ctx[MICROPY_RTEMS_NUM_TASKS];
static byte mp_heap[MICROPY_RTEMS_NUM_TASKS * HEAP_SIZE];
void pattern_fill(void *p_in, size_t len) {
uint32_t *p = (uint32_t*)p_in;
while (len >= 4) {
*p++ = 0xdea110c8;
len -= 4;
}
}
void *pattern_search(void *p_in, size_t len) {
uint32_t *p = (uint32_t*)p_in;
while (len >= 4) {
if (*p != 0xdea110c8) {
return p;
}
p += 1;
len -= 4;
}
return NULL;
}
rtems_task mp_worker_task(rtems_task_argument task_index) {
// set the MicroPython context for this task
_Thread_Executing->Start.numeric_argument = (uint32_t)&mp_state_ctx[task_index];
// initialise the stack limit checking
mp_stack_ctrl_init();
mp_stack_set_limit(MICROPY_RTEMS_STACK_SIZE - 2048);
// write a pattern to the stack to check for overflow
uint32_t dummy;
byte *stack_start = (byte*)&dummy - (MICROPY_RTEMS_STACK_SIZE - 256);
const size_t stack_len = MICROPY_RTEMS_STACK_SIZE - 256 - 32;
pattern_fill(stack_start, stack_len);
// initialise the heap, with a special pattern to check for overflow
byte *heap_start = &mp_heap[task_index * HEAP_SIZE];
pattern_fill((uint32_t*)heap_start, HEAP_SIZE);
gc_init(heap_start + HEAP_PRE, heap_start + HEAP_PRE + MICROPY_RTEMS_HEAP_SIZE);
// initialise the MicroPython runtime
mp_init();
// get the precompiled bytecode from the fixed address in RAM
const void *mpy_base = (const void*)(MPY_MEM_BASE + MPY_MEM_STRIDE * task_index);
size_t mpy_len = *(const uint32_t*)mpy_base;
const byte *mpy_data = (const byte*)(mpy_base + 4);
// execute the bytecode
uint32_t retval = mp_exec_mpy(mpy_data, mpy_len);
// check the return value
if (retval != 0) {
mp_printf(&mp_plat_print, "retval = %u\n", (uint)retval);
}
// deinitialise the MicroPython runtime
mp_deinit();
// check for stack overflow
{
void *p = pattern_search(stack_start, stack_len);
size_t usage = (byte*)&dummy - (byte*)p;
size_t avail = (byte*)&dummy - stack_start;
if (usage + 128 > avail) {
mp_printf(&mp_plat_print, "stack got too low at %u / %u\n", (uint)usage, (uint)avail);
}
//mp_printf(&mp_plat_print, "stack usage: %u / %u\n", (uint)usage, (uint)avail);
}
// check for heap overflow
{
uint32_t *p = pattern_search((uint32_t*)heap_start, HEAP_PRE);
if (p != NULL) {
mp_printf(&mp_plat_print, "pre-heap corruption at %p (heap_start=%p)\n", p, heap_start + HEAP_PRE);
}
p = pattern_search((uint32_t*)(heap_start + HEAP_PRE + MICROPY_RTEMS_HEAP_SIZE), HEAP_POST);
if (p != NULL) {
mp_printf(&mp_plat_print, "post-heap corruption at %p (heap_end=%p)\n", p, heap_start + HEAP_PRE + MICROPY_RTEMS_HEAP_SIZE);
}
}
// indicate that the script has completed
rtems_task_set_note(RTEMS_SELF, RTEMS_NOTEPAD_0, 1);
// wait for termination
for (;;) {
rtems_task_wake_after(200);
}
}
/*
* This file is part of the MicroPython port to LEON platforms
* Copyright (c) 2015-2016 George Robotics Limited
*
* Provided to the European Space Agency as part of the project "Porting of
* MicroPython to LEON platforms", contract number 4000114080/15/NL/FE/as.
*/
// options to control how MicroPython is built
#define MICROPY_NLR_SETJMP (1)
#define MICROPY_ALLOC_PATH_MAX (128)
#define MICROPY_PERSISTENT_CODE_LOAD (1)
#define MICROPY_EMIT_X64 (0)
#define MICROPY_EMIT_THUMB (0)
#define MICROPY_EMIT_INLINE_THUMB (0)
#define MICROPY_ENABLE_COMPILER (0)
#define MICROPY_COMP_MODULE_CONST (0)
#define MICROPY_COMP_CONST (0)
#define MICROPY_COMP_DOUBLE_TUPLE_ASSIGN (1)
#define MICROPY_COMP_TRIPLE_TUPLE_ASSIGN (1)
#define MICROPY_MEM_STATS (0)
#define MICROPY_DEBUG_PRINTERS (0)
#define MICROPY_ENABLE_GC (1)
#define MICROPY_ENABLE_IMMORTAL_GC (0)
#define MICROPY_ENABLE_FINALISER (1)
#define MICROPY_STACK_CHECK (1)
#define MICROPY_REPL_EVENT_DRIVEN (0)
#define MICROPY_HELPER_REPL (1)
#define MICROPY_HELPER_LEXER_UNIX (0)
#define MICROPY_ENABLE_SOURCE_LINE (1)
#define MICROPY_ENABLE_DOC_STRING (0)
#define MICROPY_ERROR_REPORTING (MICROPY_ERROR_REPORTING_NORMAL)
#define MICROPY_OPT_COMPUTED_GOTO (1)
#define MICROPY_OPT_CACHE_MAP_LOOKUP_IN_BYTECODE (0)
#define MICROPY_MODULE_WEAK_LINKS (1)
#define MICROPY_MODULE_FROZEN (0)
#define MICROPY_CPYTHON_COMPAT (1)
#define MICROPY_LONGINT_IMPL (MICROPY_LONGINT_IMPL_MPZ)
#define MICROPY_FLOAT_IMPL (MICROPY_FLOAT_IMPL_DOUBLE)
#define MICROPY_PY_FUNCTION_ATTRS (1)
#define MICROPY_PY_BUILTINS_STR_UNICODE (1)
#define MICROPY_PY_BUILTINS_STR_SPLITLINES (1)
#define MICROPY_PY_BUILTINS_BYTEARRAY (1)
#define MICROPY_PY_BUILTINS_MEMORYVIEW (1)
#define MICROPY_PY_BUILTINS_ENUMERATE (1)
#define MICROPY_PY_BUILTINS_FROZENSET (1)
#define MICROPY_PY_BUILTINS_REVERSED (1)
#define MICROPY_PY_BUILTINS_SET (1)
#define MICROPY_PY_BUILTINS_SLICE (1)
#define MICROPY_PY_BUILTINS_PROPERTY (1)
#define MICROPY_PY___FILE__ (1)
#define MICROPY_PY_MICROPYTHON_MEM_INFO (1)
#define MICROPY_PY_SYS_EXIT (1)
#define MICROPY_PY_SYS_MAXSIZE (1)
#define MICROPY_PY_SYS_MODULES (0)
#define MICROPY_PY_SYS_STDFILES (0)
#define MICROPY_PY_SYS_STDIO_BUFFER (1)
#define MICROPY_PY_SYS_PLATFORM "leon2"
#define MICROPY_PY_COLLECTIONS_ORDEREDDICT (1)
#define MICROPY_PY_GC (1)
#define MICROPY_PY_ARRAY (1)
#define MICROPY_PY_ARRAY_SLICE_ASSIGN (1)
#define MICROPY_PY_ATTRTUPLE (1)
#define MICROPY_PY_COLLECTIONS (1)
#define MICROPY_PY_MATH (1)
#define MICROPY_PY_CMATH (1)
#define MICROPY_PY_UJSON (1)
#define MICROPY_PY_UBINASCII (1)
#define MICROPY_PY_IO (0)
#define MICROPY_PY_STRUCT (1)
#define MICROPY_PY_SYS (1)
#define MICROPY_ENABLE_EMERGENCY_EXCEPTION_BUF (1)
#define MICROPY_EMERGENCY_EXCEPTION_BUF_SIZE (256)
// builtin modules
extern const struct _mp_obj_module_t mp_module_time;
extern const struct _mp_obj_module_t mp_module_rtems;
#define MICROPY_PORT_BUILTIN_MODULES \
{ MP_ROM_QSTR(MP_QSTR_time), MP_ROM_PTR(&mp_module_time) }, \
{ MP_ROM_QSTR(MP_QSTR_rtems), MP_ROM_PTR(&mp_module_rtems) }, \
// definitions specific to SPARC
#define MP_ENDIANNESS_BIG (1)
#define MICROPY_MAKE_POINTER_CALLABLE(p) ((void*)p)
#define MICROPY_SPARC_NUM_REG_WINDOWS (8)
#include <stdint.h>
#if 0
// configuration for 32-bit object word size
#define MICROPY_OBJ_REPR (MICROPY_OBJ_REPR_A)
#define BYTES_PER_WORD (4)
#define UINT_FMT "%u"
#define INT_FMT "%d"
typedef int mp_int_t;
typedef unsigned mp_uint_t;
#else
// configuration for 64-bit NaN boxing
#define MICROPY_OBJ_REPR (MICROPY_OBJ_REPR_D)
#define BYTES_PER_WORD (8)
typedef int64_t mp_int_t;
typedef uint64_t mp_uint_t;
#define UINT_FMT "%llu"
#define INT_FMT "%lld"
#endif
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;
// We need to provide a declaration/definition of alloca()
#include <alloca.h>
// INFINITY is not defined by toolchain
#ifndef INFINITY
#define INFINITY (__builtin_inff())
#endif
// We define our own state accessor macros
#include <rtems.h>
#define MP_STATE_PTR ((mp_state_ctx_t*)_Thread_Executing->Start.numeric_argument)
#define MP_STATE_CTX(x) (MP_STATE_PTR->x)
#define MP_STATE_VM(x) (MP_STATE_PTR->vm.x)
#define MP_STATE_MEM(x) (MP_STATE_PTR->mem.x)
#define MP_STATE_PORT MP_STATE_VM
// Hook for the VM
#define MICROPY_VM_HOOK_COUNT (1)
#define MICROPY_VM_HOOK_INIT uint vm_hook_count = MICROPY_VM_HOOK_COUNT;
#define MICROPY_VM_HOOK_LOOP \
if (--vm_hook_count == 0) { \
vm_hook_count = MICROPY_VM_HOOK_COUNT; \
MARK_EXC_IP_SELECTIVE(); \
extern void mp_vm_hook(const mp_code_state *code_state); \
mp_vm_hook(code_state); \
}
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment