Commit cd85b9fe authored by Damien George's avatar Damien George
Browse files

leon: Add leon-ex-pystone example.

parent 323f2953
......@@ -34,6 +34,7 @@ LEON specific directories:
leon-ex-minimal/ a minimal example of MicroPython
leon-ex-tasks/ an example of MicroPython using multiple tasks
leon-ex-manager/ an example of MicroPython that uses the VM manager
leon-ex-pystone/ an example of MicroPython that runs pystone benchmark
leon-for-tests/ a version of MicroPython for running LEON tests
leon-tests/ the LEON tests
......
build-???
scripts.h
# 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 an example of a minimal LEON port.
# 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
CFLAGS += $(CFLAGS_EXTRA)
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 \
# these are the example Python scripts to compile
SRC_PY = pystone.py
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 $< > $@
main.c: scripts.h
$(BUILD)/%.mpy: %.py
$(ECHO) "PY $<"
$(Q)../leon-compiler/micropython -o $@ $<
scripts.h: $(addprefix $(BUILD)/, $(SRC_PY:.py=.mpy))
$(ECHO) "MPY $@"
$(Q)../tools/mpytool.py tohdr $^ > $@
include ../py/mkrules.mk
load /srec "build-323/firmware.srec"
load /symtab "build-323/firmware.tab"
bre %code(emu_terminate) /TAG=_emu_terminate /CMD={ bre /exit/stop }
set pc=0x40000000
set i6=0x41000000
set o6=0x40FFFE80
step 200000000
load /srec "build-32s/firmware.srec"
load /symtab "build-32s/firmware.tab"
bre %code(emu_terminate) /TAG=_emu_terminate /CMD={ bre /exit/stop }
set pc=0x40000000
set i6=0x41000000
set o6=0x40FFFE80
step 200000000
load /srec "build-643/firmware.srec"
load /symtab "build-643/firmware.tab"
bre %code(emu_terminate) /TAG=_emu_terminate /CMD={ bre /exit/stop }
set pc=0x40000000
set i6=0x41000000
set o6=0x40FFFE80
step 200000000
load /srec "build-64s/firmware.srec"
load /symtab "build-64s/firmware.tab"
bre %code(emu_terminate) /TAG=_emu_terminate /CMD={ bre /exit/stop }
set pc=0x40000000
set i6=0x41000000
set o6=0x40FFFE80
step 200000000
/*
* 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 (4)
#define CONFIGURE_RTEMS_INIT_TASKS_TABLE
#define CONFIGURE_EXTRA_TASK_STACKS (3 * 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 * 2)
#define MICROPY_RTEMS_HEAP_SIZE (48 * 1024)
#define MICROPY_RTEMS_NUM_TASKS (1)
/******************************************************************************/
// 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
#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");
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 < MICROPY_RTEMS_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]
);
status = rtems_task_start(task_id[i], mp_worker_task, i);
}
// wait for termination
for (;;) {
rtems_task_wake_after(100);
}
}
/******************************************************************************/
// MicroPython worker task
#include "py/runtime.h"
#include "py/gc.h"
#include "py/stackctrl.h"
#include "mputil.h"
// include the precompiled bytecode (generated by external tools)
#include "scripts.h"
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_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];
// get a pointer to the heap for this task
byte *heap_start = &mp_heap[task_index * MICROPY_RTEMS_HEAP_SIZE];
// loop and execute all the scripts
for (int script_num = 0; script_num < mpy_script_num; ++script_num) {
// initialise the stack limit checking
mp_stack_ctrl_init();
mp_stack_set_limit(MICROPY_RTEMS_STACK_SIZE - 2048);
// initialise the heap
gc_init(heap_start, heap_start + MICROPY_RTEMS_HEAP_SIZE);
// initialise the MicroPython runtime
mp_init();
// execute the bytecode
uint32_t retval = mp_exec_mpy(mpy_script_data[script_num], mpy_script_len[script_num]);
// check the return value
if (retval != 0) {
mp_printf(&mp_plat_print, "retval = %u\n", (uint)retval);
}
// deinitialise the MicroPython runtime
mp_deinit();
}
// terminate emulator
emu_terminate();
rtems_task_delete(RTEMS_SELF);
}
#!/bin/sh
make BUILD=build-32s CFLAGS_EXTRA='-Os -DMICROPY_USE_64BIT_NAN_BOXING=0'
make BUILD=build-323 CFLAGS_EXTRA='-O3 -DMICROPY_USE_64BIT_NAN_BOXING=0'
make BUILD=build-64s CFLAGS_EXTRA='-Os -DMICROPY_USE_64BIT_NAN_BOXING=1'
make BUILD=build-643 CFLAGS_EXTRA='-O3 -DMICROPY_USE_64BIT_NAN_BOXING=1'
/*
* 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 (0)
#define MICROPY_STACK_CHECK (1)
#define MICROPY_REPL_EVENT_DRIVEN (0)
#define MICROPY_HELPER_REPL (0)
#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 (0)
#define MICROPY_MODULE_FROZEN (0)
#define MICROPY_CPYTHON_COMPAT (0)
#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 (0)
#define MICROPY_PY_UJSON (0)
#define MICROPY_PY_UBINASCII (0)
#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 defined(MICROPY_USE_64BIT_NAN_BOXING) && MICROPY_USE_64BIT_NAN_BOXING
// 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"
#else
// configuration for 32-bit object word size
#define MICROPY_OBJ_REPR (MICROPY_OBJ_REPR_A)
#define BYTES_PER_WORD (4)
typedef int mp_int_t;
typedef unsigned mp_uint_t;
#define UINT_FMT "%u"
#define INT_FMT "%d"
#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); \
}
# Test for MicroPython port to LEON
# Test ID: PERF_CPU_01
# Taken from pystone.py
"""
"PYSTONE" Benchmark Program
Version: Python/1.2 (corresponds to C/1.1 plus 3 Pystone fixes)
Author: Reinhold P. Weicker, CACM Vol 27, No 10, 10/84 pg. 1013.
Translated from ADA to C by Rick Richardson.
Every method to preserve ADA-likeness has been used,
at the expense of C-ness.
Translated from C to Python by Guido van Rossum.
Version History:
Version 1.1 corrects two bugs in version 1.0:
First, it leaked memory: in Proc1(), NextRecord ends
up having a pointer to itself. I have corrected this
by zapping NextRecord.PtrComp at the end of Proc1().
Second, Proc3() used the operator != to compare a
record to None. This is rather inefficient and not
true to the intention of the original benchmark (where
a pointer comparison to None is intended; the !=
operator attempts to find a method __cmp__ to do value
comparison of the record). Version 1.1 runs 5-10
percent faster than version 1.0, so benchmark figures
of different versions can't be compared directly.
Version 1.2 changes the division to floor division.
Under Python 3 version 1.1 would use the normal division
operator, resulting in some of the operations mistakenly
yielding floats. Version 1.2 instead uses floor division
making the benchmark a integer benchmark again.
"""
LOOPS = 1000
from time import time as clock
__version__ = "1.2"
[Ident1, Ident2, Ident3, Ident4, Ident5] = range(1, 6)
class Record:
def __init__(self, PtrComp = None, Discr = 0, EnumComp = 0,
IntComp = 0, StringComp = 0):
self.PtrComp = PtrComp
self.Discr = Discr
self.EnumComp = EnumComp
self.IntComp = IntComp
self.StringComp = StringComp
def copy(self):
return Record(self.PtrComp, self.Discr, self.EnumComp,
self.IntComp, self.StringComp)
TRUE = 1
FALSE = 0
def main(loops=LOOPS):
benchtime, stones = pystones(loops)
print("Pystone(%s) time for %d passes = %g" % \
(__version__, loops, benchtime))
print("This machine benchmarks at %g pystones/second" % stones)
def pystones(loops=LOOPS):
return Proc0(loops)
IntGlob = 0
BoolGlob = FALSE
Char1Glob = '\0'
Char2Glob = '\0'
Array1Glob = [0]*51
Array2Glob = [x[:] for x in [Array1Glob]*51]
PtrGlb = None
PtrGlbNext = None
def Proc0(loops=LOOPS):
global IntGlob
global BoolGlob
global Char1Glob
global Char2Glob
global Array1Glob
global Array2Glob
global PtrGlb
global PtrGlbNext
starttime = clock()
for i in range(loops):
pass
nulltime = clock() - starttime
PtrGlbNext = Record()
PtrGlb = Record()
PtrGlb.PtrComp = PtrGlbNext
PtrGlb.Discr = Ident1
PtrGlb.EnumComp = Ident3
PtrGlb.IntComp = 40
PtrGlb.StringComp = "DHRYSTONE PROGRAM, SOME STRING"
String1Loc = "DHRYSTONE PROGRAM, 1'ST STRING"
Array2Glob[8][7] = 10
starttime = clock()
for i in range(loops):
Proc5()
Proc4()
IntLoc1 = 2
IntLoc2 = 3
String2Loc = "DHRYSTONE PROGRAM, 2'ND STRING"
EnumLoc = Ident2
BoolGlob = not Func2(String1Loc, String2Loc)
while IntLoc1 < IntLoc2:
IntLoc3 = 5 * IntLoc1 - IntLoc2
IntLoc3 = Proc7(IntLoc1, IntLoc2)
IntLoc1 = IntLoc1 + 1
Proc8(Array1Glob, Array2Glob, IntLoc1, IntLoc3)
PtrGlb = Proc1(PtrGlb)
CharIndex = 'A'
while CharIndex <= Char2Glob:
if EnumLoc == Func1(CharIndex, 'C'):
EnumLoc = Proc6(Ident1)
CharIndex = chr(ord(CharIndex)+1)
IntLoc3 = IntLoc2 * IntLoc1
IntLoc2 = IntLoc3 // IntLoc1
IntLoc2 = 7 * (IntLoc3 - IntLoc2) - IntLoc1
IntLoc1 = Proc2(IntLoc1)
benchtime = clock() - starttime - nulltime
if benchtime == 0.0:
loopsPerBenchtime = 0.0
else:
loopsPerBenchtime = (loops / benchtime)
return benchtime, loopsPerBenchtime
def Proc1(PtrParIn):
PtrParIn.PtrComp = NextRecord = PtrGlb.copy()
PtrParIn.IntComp = 5
NextRecord.IntComp = PtrParIn.IntComp
NextRecord.PtrComp = PtrParIn.PtrComp
NextRecord.PtrComp = Proc3(NextRecord.PtrComp)
if NextRecord.Discr == Ident1:
NextRecord.IntComp = 6
NextRecord.EnumComp = Proc6(PtrParIn.EnumComp)
NextRecord.PtrComp = PtrGlb.PtrComp
NextRecord.IntComp = Proc7(NextRecord.IntComp, 10)
else:
PtrParIn = NextRecord.copy()
NextRecord.PtrComp = None
return PtrParIn
def Proc2(IntParIO):
IntLoc = IntParIO + 10
while 1:
if Char1Glob == 'A':
IntLoc = IntLoc - 1
IntParIO = IntLoc - IntGlob
EnumLoc = Ident1
if EnumLoc == Ident1:
break
return IntParIO
def Proc3(PtrParOut):
global IntGlob
if PtrGlb is not None:
PtrParOut = PtrGlb.PtrComp
else:
IntGlob = 100