diff --git a/CMakeLists.txt b/CMakeLists.txt index ebe6d569f93d45ade2e893f711661c2106bca898..f7b00a886f2f224c920dce2f807e3dc59d050494 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -2,6 +2,9 @@ cmake_minimum_required(VERSION 2.6.2) PROJECT(dOSEK) +# Include the configuration +include(${PROJECT_BINARY_DIR}/config.cmake) + # ASM language defaults to the clang assembler in the Bellolabs. # It is required since arch/i386/idt.S uses macros that do not # work with gnu assembler without any changes. @@ -11,9 +14,49 @@ enable_language(ASM) # assembler files with a lower case ".s" as file extension. # Upper case "*.S" is still matched by the ASM language and is # therefore compiled with clang. -enable_language(ASM-ATT) +if (NOT(${CONFIG_ARCH} STREQUAL "patmos")) + enable_language(ASM-ATT) +endif() + +# Generate the toolchain configuration (toolchain.cmake, etc.) +execute_process(COMMAND ${PROJECT_SOURCE_DIR}/toolchain/detect ${CONFIG_ARCH} ${PROJECT_BINARY_DIR}/) + +include(${PROJECT_BINARY_DIR}/toolchain.cmake) + +# Set the default compiler toolchain to target +SET(CMAKE_C_COMPILER ${TC_TARGET_CC}) +set(CMAKE_C_FLAGS "${TC_TARGET_CFLAGS} -g -c -emit-llvm -include ${PROJECT_BINARY_DIR}/dosek_config.h") + +SET(CMAKE_CXX_COMPILER ${TC_TARGET_CXX}) +set(CMAKE_CXX_FLAGS "${TC_TARGET_CXXFLAGS} -std=c++11 -g -c -emit-llvm -include ${PROJECT_BINARY_DIR}/dosek_config.h") + +SET(CMAKE_ASM_COMPILER ${TC_TARGET_AS}) +set(CMAKE_ASM_FLAGS "${TC_TARGET_ASMFLAGS} -include ${PROJECT_BINARY_DIR}/dosek_config.h") +set(CMAKE_ASM-ATT_FLAGS "${TC_TARGET_ASM_ATTFLAGS}") +set(CMAKE_EXE_LINKER_FLAGS "${TC_TARGET_LDFLAGS}") +set(CMAKE_SHARED_LIBRARY_LINK_C_FLAGS) + +# we use our own linker (python) script, that calls llvm-link, llc and the system linker +# setting CMAKE_*_LINK_EXECUTABLE at this point in the CMake run seems a bit unusual, but works as intended +set(LINK_EXECUTABLE "${PROJECT_SOURCE_DIR}/toolchain/llvm-link.py --toolchain-file ${PROJECT_BINARY_DIR}/toolchain.pydict <LINK_FLAGS> <OBJECTS> <LINK_LIBRARIES> -o <TARGET>") +set(CMAKE_C_LINK_EXECUTABLE_HOST "${CMAKE_C_LINK_EXECUTABLE}") +set(CMAKE_CXX_LINK_EXECUTABLE_HOST "${CMAKE_CXX_LINK_EXECUTABLE}") +set(CMAKE_C_LINK_EXECUTABLE "${LINK_EXECUTABLE}") +set(CMAKE_CXX_LINK_EXECUTABLE "${LINK_EXECUTABLE}") + + +# Subdirectories can use this macro to use the host compiler +macro(USE_HOST_COMPILER) + SET(CMAKE_C_COMPILER ${TC_HOST_CC}) + SET(CMAKE_CXX_COMPILER ${TC_HOST_CXX}) + set(CMAKE_C_FLAGS "") + set(CMAKE_CXX_FLAGS "-std=c++11") + set(CMAKE_EXE_LINKER_FLAGS "") + set_directory_properties(PROPERTIES INCLUDE_DIRECTORIES "") + set(CMAKE_C_LINK_EXECUTABLE "${CMAKE_C_LINK_EXECUTABLE_HOST}") + set(CMAKE_CXX_LINK_EXECUTABLE "${CMAKE_CXX_LINK_EXECUTABLE_HOST}") +endmacro() -enable_testing() set(PROJECT_VERSION "1.1" CACHE STRING "Project version number") set(PROJECT_RELEASE "stable" CACHE STRING "Project release") @@ -27,7 +70,6 @@ if(DEBUGGING) add_definitions(-DDEBUG=1) endif() -include(${CMAKE_CURRENT_BINARY_DIR}/config.cmake) option(FAIL_TRACE_ALL "Trace all binaries" OFF) if(FAIL_TRACE_ALL) @@ -46,12 +88,6 @@ set(EXECUTABLE_OUTPUT_PATH ${PROJECT_BINARY_DIR}) set(CMAKE_MODULE_PATH "${PROJECT_SOURCE_DIR}/toolchain") ## Setup platform independent compiler flags -# ffunction/data-sections needed to link functions/data into different sections based on name(space) -# fno-zero-initialized-in-bss puts all variables into data instead of bss section (for data-section grouping) -set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${ISA_C_FLAGS} -ffunction-sections -fdata-sections -fno-zero-initialized-in-bss -nostdlib -fno-builtin") -set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${ISA_CXX_FLAGS} ${CMAKE_C_FLAGS} -fno-exceptions -std=c++11") -set(CMAKE_ASM-ATT_FLAGS "${CMAKE_ASM-ATT_FLAGS} ${ISA_ASM-ATT_FLAGS}") -set(CMAKE_ASM_FLAGS "${CMAKE_ASM_FLAGS} ${ISA_ASM_FLAGS}") # Find python find_program(PYTHON "python") @@ -68,10 +104,6 @@ include(helpers) dosek_include_dir(${PROJECT_SOURCE_DIR}) dosek_include_dir(${PROJECT_SOURCE_DIR}/os) dosek_include_dir(${PROJECT_BINARY_DIR}) -set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -include ${PROJECT_BINARY_DIR}/dosek_config.h") -set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -include ${PROJECT_BINARY_DIR}/dosek_config.h") -set(CMAKE_ASM_FLAGS "${CMAKE_ASM_FLAGS} -include ${PROJECT_BINARY_DIR}/dosek_config.h") - # Documentation add_subdirectory(toolchain/doxygen) diff --git a/README.md b/README.md index 8af0753ef0e24fc88a8ffd85e5de9d0204ec59ad..0381b1b1de4ab5045516c3382d2431b62e856bdf 100644 --- a/README.md +++ b/README.md @@ -16,11 +16,7 @@ dependability as the first-class design goal targeting safety-critical, embedded applications, the system provides an OSEK/AUTOSAR-conform interface (currently ECC1). -Currently, dOSEK supports three platforms: - -- x86: 32-Bit version of dOSEK that runs on bare metal -- posix: 32-Bit version of dOSEK that runs on Linux/x86 -- arm: Port to the Panda Board/zedboard (currently WIP) +**This repository contains the PATMOS version of dOSEK used for SysWCET** For more information about the dOSEK concepts, see https://www4.cs.fau.de/Research/dOSEK/ @@ -28,56 +24,19 @@ For more information about the dOSEK concepts, see Software Requirements --------------------- - apt-get install binutils-dev build-essential clang-3.4 cmake \ - g++-multilib gcc-multilib git grub-common grub-pc-bin \ - llvm-3.3-dev llvm-3.3-runtime python-minimal python3 \ - python3-lxml python3-pyparsing python3-pip \ - qemu-system-x86 xorriso - - LLVM_CONFIG_PATH=/usr/bin/llvm-config-3.3 pip3 install llvmpy - -For the ARM version, you will additionally need - - gcc-arm-none-eabi gdb-arm-none-eabi qemu-system-arm +For Building -------- dOSEK uses cmake as a build system. -We recommend to make an out-of-source build -To build and run all test-cases you have to type: - - mkdir build; cd build - <Path to dOSEK>/new_build_env.py - make build_and_test - -To get help about the available targets use +We recommend to make an out-of-source build: - make help # long help - make h # short help -`after_first_checkout.sh` is only necessary, if you are going to -contribute via our gerrit code review system. - -Docker Images -------------- - -[](https://registry.hub.docker.com/u/danceos/dosek-base/) - - -We provide [docker.io](http://www.docker.com) images for a basic -build environment. These images provide an SSH port and access to an -Ubuntu machine that contains all build dependencies. You can either -build the images yourself with - - cd scripts/docker; make - make run - make ssh - -or you can pull it directly from the docker Hub + mkdir build; cd build + ../new_build_env.py -a patmos --generate-pml=true - docker pull danceos/dosek-base - cd scripts/docker; make run; make ssh +To evaluate the Worst-Case Response Time of the aborted computation +benchmark, please run: -In either cases, the password is `dosek`. In the default -configuration, no SSH port will be exposed to the outside world. + make wcet-bench-timing-aborted_computation CIRCUIT=0 VERBOSE=2 diff --git a/app/bcc1/complex1/a.cc b/app/bcc1/complex1/a.cc index 50704d4b842813b57a6e995f829cbf1dd98eafe7..7ef2b62042592b14aafaf7a3d41f2be827f74e9b 100644 --- a/app/bcc1/complex1/a.cc +++ b/app/bcc1/complex1/a.cc @@ -56,4 +56,3 @@ void PreIdleHook() { ShutdownMachine(); } } - diff --git a/app/bcc1/depsvc/CMakeLists.txt b/app/bcc1/depsvc/CMakeLists.txt index ee174c27921125a23f81c475304418927546dbaf..149f7e70d4bd97bc17b9a9f38ecc4c690d19f18d 100644 --- a/app/bcc1/depsvc/CMakeLists.txt +++ b/app/bcc1/depsvc/CMakeLists.txt @@ -1,4 +1,4 @@ -if( (${DOSEK_ARCHITECTURE} STREQUAL "posix") OR (${DOSEK_ARCHITECTURE} STREQUAL "i386") ) +if( (${CONFIG_ARCH} STREQUAL "posix") OR (${CONFIG_ARCH} STREQUAL "i386") ) DOSEK_BINARY ( NAME bcc1_depsvc LIBS libdepsvc libtest diff --git a/app/bcc1/task1/a.cc b/app/bcc1/task1/a.cc index 771db772e01020ea356347948d37b52d0f5bf69f..73bdba1b49cc0674777266da3fa05891e0b6fd13 100644 --- a/app/bcc1/task1/a.cc +++ b/app/bcc1/task1/a.cc @@ -23,23 +23,28 @@ DeclareTask(Handler13); TEST_MAKE_OS_MAIN( StartOS(0) ) TASK(Handler11) { - volatile int i = 1; - while (i < 200000) i++; - - test_trace('a'); - ActivateTask(Handler12); - i = 0; - while (i < 200000) i++; - test_trace('b'); - ActivateTask(Handler13); - test_trace('c'); - TerminateTask(); +#if !defined(CONFIG_ARCH_PATMOS) + volatile int i = 1; + while (i < 200000) i++; +#endif + + test_trace('a'); + ActivateTask(Handler12); + + +#if !defined(CONFIG_ARCH_PATMOS) + i = 0; + while (i < 200000) i++; +#endif + test_trace('b'); + ActivateTask(Handler13); + test_trace('c'); + TerminateTask(); } TASK(Handler12) { - //testme[1024*2] = 42; - test_trace('2'); - TerminateTask(); + test_trace('2'); + TerminateTask(); } TASK(Handler13) { diff --git a/app/bcc1/task1/b.cc b/app/bcc1/task1/b.cc index 7827091ea2d05522fec0c13ca4f0bc200d9e5307..cdaf2f280644b0386390b9eb45f2c747b3d74257 100644 --- a/app/bcc1/task1/b.cc +++ b/app/bcc1/task1/b.cc @@ -64,4 +64,3 @@ void PreIdleHook() { test_finish(); ShutdownMachine(); } - diff --git a/app/benchmark/timing/CMakeLists.txt b/app/benchmark/timing/CMakeLists.txt new file mode 100644 index 0000000000000000000000000000000000000000..aee9bb4713366d10cf93f2e7aca110439197fee5 --- /dev/null +++ b/app/benchmark/timing/CMakeLists.txt @@ -0,0 +1,76 @@ +# Evalutation Scenario #1 +DOSEK_BINARY( + NAME bench-timing-tmr + SYSTEM_DESC tmr.oil + LIBS libtest timing + SOURCES tmr.cc + ) + +# Evaluation Scenario #2 + +DOSEK_BINARY( + NAME bench-timing-computation_alarm + SYSTEM_DESC computation-alarm.oil + LIBS libtest timing + SOURCES computation-alarm.cc +) + +DOSEK_BINARY( + NAME bench-timing-activate_task + SYSTEM_DESC activate-task.oil + LIBS libtest timing + SOURCES activate-task.cc +) + +DOSEK_BINARY( + NAME bench-timing-simple_interrupt + SYSTEM_DESC simple-interrupt.oil + LIBS libtest timing + SOURCES simple-interrupt.cc +) + + +DOSEK_BINARY( + NAME bench-timing-wait_event + SYSTEM_DESC wait-event.oil + LIBS libtest timing + SOURCES wait-event.cc +) + + +DOSEK_BINARY( + NAME bench-timing-interrupt_reaction + SYSTEM_DESC interrupt-reaction.oil + LIBS libtest timing + SOURCES interrupt-reaction.cc +) + +DOSEK_BINARY( + NAME bench-timing-computation_irq + SYSTEM_DESC irq-task.oil + LIBS libtest timing + SOURCES computation-irq.cc +) + + +DOSEK_BINARY( + NAME bench-timing-aborted_computation + SYSTEM_DESC aborted-computation.oil + LIBS timing + SOURCES aborted-computation.cc +) + +DOSEK_BINARY( + NAME bench-timing-alarm + SYSTEM_DESC alarm.oil + LIBS libtest timing + SOURCES alarm.cc +) + + +DOSEK_BINARY( + NAME bench-timing-copter + SYSTEM_DESC copter.oil + LIBS libtest timing + SOURCES copter.cc +) diff --git a/app/benchmark/timing/aborted-computation.cc b/app/benchmark/timing/aborted-computation.cc new file mode 100644 index 0000000000000000000000000000000000000000..54bdca763285af9d9c8c81b855c703f24540e1ee --- /dev/null +++ b/app/benchmark/timing/aborted-computation.cc @@ -0,0 +1,52 @@ +#include "os.h" +#include "syscall.h" +#include "timing.h" + +TIMING_MAKE_OS_MAIN( StartOS(0) ) + +DeclareTask(Control); +DeclareTask(Computation); +DeclareEvent(ComputationFinished); +DeclareEvent(ComputationAborted); + + +GENERATE_TIME_CONSUMER(computation, 5000) + +extern "C" { + void timing_entry() { + timing_start(0); + ActivateTask(Computation); + ClearEvent(ComputationFinished | ComputationAborted); + WaitEvent(ComputationFinished | ComputationAborted); + timing_end(TIMING_POINT_NO_INTERRUPTS_IN_BLOCK | 0); + } +} + + +TASK(Control) { + timing_entry(); + + /* ABB Split Point */ + DisableAllInterrupts(); + EnableAllInterrupts(); + timing_dump(); + ShutdownMachine(); + + TerminateTask(); +} + +TASK(Computation) { + computation(); + Machine::trigger_interrupt_from_user(37); + SetEvent(Control, ComputationFinished); + TerminateTask(); +} + + +ISR2(Abort) { + SetEvent(Control, ComputationAborted); +} + +void PreIdleHook() { + timing_dump(); +} diff --git a/app/benchmark/timing/aborted-computation.oil b/app/benchmark/timing/aborted-computation.oil new file mode 100644 index 0000000000000000000000000000000000000000..2ab2772bce15520163f462702de22087d7ad7aca --- /dev/null +++ b/app/benchmark/timing/aborted-computation.oil @@ -0,0 +1,39 @@ +CPU TestSystem { + + OS TestSystem { + STATUS = STANDARD; + ERRORHOOK = FALSE; + STARTUPHOOK = FALSE; + SHUTDOWNHOOK = FALSE; + PRETASKHOOK = FALSE; + POSTTASKHOOK = FALSE; + }; + + TASK Control { + SCHEDULE = FULL; + PRIORITY = 5; + ACTIVATION = 1; + AUTOSTART = TRUE; + EVENT = ComputationFinished; + EVENT = ComputationAborted; + }; + + TASK Computation { + SCHEDULE = FULL; + PRIORITY = 1; + ACTIVATION = 1; + AUTOSTART = FALSE; + }; + + ISR Abort { + CATEGORY = 2; + PRIORITY = 10; + DEVICE = 37; + MINIAT = 10000; + }; + + EVENT ComputationFinished { MASK = AUTO; }; + EVENT ComputationAborted { MASK = AUTO; }; + +}; + diff --git a/app/benchmark/timing/activate-task.cc b/app/benchmark/timing/activate-task.cc new file mode 100644 index 0000000000000000000000000000000000000000..916c044ed63d60799eb0e2d0df31246cc90159dd --- /dev/null +++ b/app/benchmark/timing/activate-task.cc @@ -0,0 +1,72 @@ +#include "os.h" +#include "test/test.h" +#include "timing.h" +#include "machine.h" + +DeclareTask(Handler11); +DeclareTask(Handler12); +DeclareTask(Handler13); + +TIMING_MAKE_OS_MAIN( StartOS(0) ) + +GENERATE_TIME_CONSUMER(timing_1, 100) +GENERATE_TIME_CONSUMER(timing_2, 100) + +extern "C" { + void timing_entry_0() { + /* Timing Circuit 0: + - ActivateTask will not dispatch to Handler 12 + */ + timing_start(0); + ActivateTask(Handler12); + timing_end(0); + } + + void timing_entry_1() { + /* The Timing Circuit 1 has the following properties: + - Activate Task will always Dispatch to upper Task + */ + timing_start(1); + ActivateTask(Handler13); + timing_end(1); + } + + void timing_entry_2() { + /* The Timing Circuit 2 has the following properties: + - Terminate and goto immediate task. + */ + timing_start(2); + TerminateTask(); + } + +} + +TASK(Handler11) { + timing_entry_0(); + + /* ABB Split Point */ + DisableAllInterrupts(); + EnableAllInterrupts(); + + timing_entry_1(); + + /* ABB Split Point */ + DisableAllInterrupts(); + EnableAllInterrupts(); + + timing_entry_2(); +} + +TASK(Handler12) { + TerminateTask(); +} + +TASK(Handler13) { + TerminateTask(); +} + +void PreIdleHook() { + timing_end(2); + /* The benchmark has ended, trap into dump. Shutdown included. */ + timing_dump(); +} diff --git a/app/benchmark/timing/activate-task.oil b/app/benchmark/timing/activate-task.oil new file mode 100644 index 0000000000000000000000000000000000000000..762091f4bcfab812999901ae2af27602fd06e4a6 --- /dev/null +++ b/app/benchmark/timing/activate-task.oil @@ -0,0 +1,35 @@ +CPU TestSystem { + + OS TestSystem { + STATUS = STANDARD; + ERRORHOOK = FALSE; + STARTUPHOOK = FALSE; + SHUTDOWNHOOK = FALSE; + PRETASKHOOK = FALSE; + POSTTASKHOOK = FALSE; + }; + + TASK Handler11 { + SCHEDULE = FULL; + PRIORITY = 4; + ACTIVATION = 1; + AUTOSTART = TRUE; + }; + + TASK Handler12 { + SCHEDULE = FULL; + PRIORITY = 3; + ACTIVATION = 1; + AUTOSTART = FALSE; + }; + + TASK Handler13 { + SCHEDULE = FULL; + PRIORITY = 5; + ACTIVATION = 1; + AUTOSTART = FALSE; + }; + + +}; + diff --git a/app/benchmark/timing/alarm.cc b/app/benchmark/timing/alarm.cc new file mode 100644 index 0000000000000000000000000000000000000000..53793813656bfad54f798cc76d6c0b1fe1996602 --- /dev/null +++ b/app/benchmark/timing/alarm.cc @@ -0,0 +1,65 @@ +/** + * @file + * @ingroup unit_tests + * @test Test repeated alarn task activation while performing syscalls + */ + +#include "test/test.h" +#include "os/os.h" +#include "timing.h" + + +DeclareTask(Task1); +DeclareTask(Task2); +DeclareTask(Task3); +DeclareTask(Task4); +DeclareCounter(C1); + +TEST_MAKE_OS_MAIN( StartOS(0) ) +GENERATE_TIME_CONSUMER(timing_0, 1000) + +TASK(Task1) { + ActivateTask(Task2); + ChainTask(Task2); +} + +TASK(Task2) { + timing_0(); + TerminateTask(); +} + +TASK(Task3) { + + timing_start(0); + timing_loop_bound(30, 30) for (unsigned i = 0; i < 30; i++) { + ActivateTask(Task1); + } + timing_0(); + timing_end(0); + + /* ABB Split Point */ + DisableAllInterrupts(); + EnableAllInterrupts(); + + timing_start(1); + timing_loop_bound(30, 30) for (unsigned i = 0; i < 30; i++) { + timing_0(); + } + timing_end(1); + + /* ABB Split Point */ + DisableAllInterrupts(); + EnableAllInterrupts(); + + + + timing_dump(); + ShutdownMachine(); + + TerminateTask(); +} + + +TASK(Task4) { + TerminateTask(); +} diff --git a/app/benchmark/timing/alarm.oil b/app/benchmark/timing/alarm.oil new file mode 100644 index 0000000000000000000000000000000000000000..3af91ed8a6aa82fdadba14f15f60315644434b0a --- /dev/null +++ b/app/benchmark/timing/alarm.oil @@ -0,0 +1,57 @@ +CPU TestSystem { + + OS TestSystem { + STATUS = STANDARD; + ERRORHOOK = FALSE; + STARTUPHOOK = FALSE; + SHUTDOWNHOOK = FALSE; + PRETASKHOOK = FALSE; + POSTTASKHOOK = FALSE; + }; + + TASK Task1 { + SCHEDULE = FULL; + PRIORITY = 2; + ACTIVATION = 1; + AUTOSTART = FALSE; + }; + + TASK Task2 { + SCHEDULE = FULL; + PRIORITY = 3; + ACTIVATION = 1; + AUTOSTART = FALSE; + }; + + TASK Task3 { + SCHEDULE = FULL; + PRIORITY = 1; + ACTIVATION = 1; + AUTOSTART = TRUE; + }; + + TASK Task4 { + SCHEDULE = FULL; + PRIORITY = 4; + ACTIVATION = 1; + AUTOSTART = FALSE; + }; + + ALARM A1 { + COUNTER = C1; + ACTION = ACTIVATETASK { + TASK = Task4; + }; + AUTOSTART = TRUE { + ALARMTIME = 1; + CYCLETIME = 3; + }; + }; + + COUNTER C1 { + MAXALLOWEDVALUE = 50000; + TICKSPERBASE = 1; + MINCYCLE = 1; + }; +}; + diff --git a/app/benchmark/timing/all.sh b/app/benchmark/timing/all.sh new file mode 100755 index 0000000000000000000000000000000000000000..cc159543626f7cf751a5df73eedac7e24825881b --- /dev/null +++ b/app/benchmark/timing/all.sh @@ -0,0 +1,28 @@ +#!/bin/bash + +ALL_PWD=$(pwd) +cd "$(dirname "$0")" + +# Evaluationszenarien #1, #2 und #3 +./run bench-timing-tmr 0 +export NO_HEADER=1 +./run bench-timing-aborted_computation 0 +./run bench-timing-computation_alarm 0 + +./run bench-timing-activate_task 0 +./run bench-timing-activate_task 1 +./run bench-timing-activate_task 2 +#./run bench-timing-simple_interrupt 0 +#./run bench-timing-computation_irq 0 +./run bench-timing-interrupt_reaction 0 +./run bench-timing-wait_event 0 +#./run bench-timing-simple_interrupt 1 +#./run bench-timing-alarm 0 + +TIMING=$(pwd) +# Manual Analysis +cd ../../../build; +${TIMING}/manual-syswcet.py --all -d bench-timing-manual.dref -vv + + +cd ${ALL_PWD} diff --git a/app/benchmark/timing/benchmarks.org b/app/benchmark/timing/benchmarks.org new file mode 100644 index 0000000000000000000000000000000000000000..63ab7eb594404b208647d8d218fed9d31b2f682c --- /dev/null +++ b/app/benchmark/timing/benchmarks.org @@ -0,0 +1,357 @@ +* Legend +TC(X): A time consumer with X loop iterations + +* Evaluation #1: Triple Modular Redundancy + A higher priority task is activated in a bounded loop. + +** Code +0: timing_start() +1: for (i = 0; i < 3; i++) { +2: ActivateTask(Computation) +3: } +4: timing_end() + +Compuation: +10: TC(50) +11: TerminateTask() + +** Sequence +[0, 1, 2 10, 11, 3, 1, 10, 11, 3, 1, 10, 11, 3, 4] +** Results +#+begin_src sh +./run bench-timing-tmr 0 +#+end_src + +#+RESULTS: +| Name | GCFG Nodes | Bound | IRQs | Ticks | Alarms | +| bench-timing-tmr-0 | 9 | 3319 | 0 | 0 | 0 | +* Evaluation #2: Alarm-interrupted Compuation +Long Computation, Alarm that triggers three times. + +** Result +#+begin_src sh +./run bench-timing-computation_alarm 0 +#+end_src + +#+RESULTS: +| Name | GCFG Nodes | Bound | IRQs | Ticks | Alarms | +| bench-timing-computation_alarm-0 | 13 | 765667 | 8 | 8 | 3 | + +* Evaluation #3: Aborted Computation +A task activates a lower priority task, waits for its termination or +that an abort interrupt occurs. + +- Results + #+begin_src sh + ./run bench-timing-aborted_computation 0 + #+end_src + + #+RESULTS: + | Name | GCFG Nodes | Bound | IRQs | Ticks | Alarms | + | bench-timing-aborted_computation-0 | 35 | 56265 | 1 | 0 | 0 | + + +* ActivateTask without Dispatch +The ActivateTask activates a lower priority task, therefore, no +redispatch is issued. + +- Code + #+begin_example + 1: + 2: ActivateTask(LowerPriorityTask) + 3: + #+end_example + +- Sequence + [1, 2, 3] + +** Results +#+NAME: bench-timing-activate_task-0 +#+begin_src sh +./run bench-timing-activate_task 0 +#+end_src + +- With Instruction Timing Model + #+RESULTS[36b93979486aed5dd66edef25fadfd7214967f9f]: bench-timing-activate_task-0 + | GCFG Nodes | Bound | IRQs | Ticks | Alarms | + | 3 | 2015 | 0 | 0 | 0 | + +- With Cycle Timing Model + | GCFG Nodes | Bound | IRQs | Ticks | Alarms | + | 3 | 2718 | 0 | 0 | 0 | + +* ActivateTask with Dispatch +The ActivateTask activates a higher priority task, the operating +system decides to jump to HPT and returns to the initial task +afterwards. + +** Code +4: TC(100) +5: ActivateTask(HighPriorityTask) +6: TC(50) + +HighPriorityTask: +11: TC(200) +12: TerminateTask() + +** Sequence +[4, 5, 11, 12, 6] + +** Results +#+begin_src sh +./run bench-timing-activate_task 1 +#+end_src + +#+RESULTS: +| GCFG Nodes | Bound | IRQs | Ticks | Alarms | +| 6 | 4514 | 0 | 0 | 0 | + +- With Cycle Timing Model + | GCFG Nodes | Bound | IRQs | Ticks | Alarms | + | 6 | 6089 | 0 | 0 | 0 | + +* TerminateTask with Dispatch and Return to Idle +The benchmark starts in a high priority task, which terminates. A +lower priority task is already marked as runnable, and is, therefore, +dispatched after the first terminate task. The lower-priority task +terminates as well, and the scenario ends in the idle loop. + +** Code +7: TerminateTask() + +LowerPriorityTask: +21: TC(50) +22: TerminateTask() + +Idle: +30: timing_end() + +** Sequence +[7, 21, 22, 30] + +** Results +#+begin_src sh +./run bench-timing-activate_task 2 +#+end_src + +#+RESULTS: +| GCFG Nodes | Bound | IRQs | Ticks | Alarms | +| 6 | 1191 | 0 | 0 | 0 | + +- With Cycle Timing Model + | GCFG Nodes | Bound | IRQs | Ticks | Alarms | + | 6 | 1551 | 0 | 0 | 0 | + +* A task waits for an event, another one sets it +The benchmarks starts with two tasks ready. The higher priorty, +currently running task, is going to sleep for an event. The lower +priority task is scheduled, sets the event, and is immediately +suspended in favour of the high-priority task. + +** Code +Task1: +1: +2: WaitEvent(Event) +3: timing_end() + +Task2: +10: SetEvent(Task1, Event) +11: TerminateTask() + +** Sequence + [1, 2, 10, 3] +** Results +#+begin_src sh +./run bench-timing-wait_event 0 +#+end_src + +#+RESULTS: +| GCFG Nodes | Bound | IRQs | Ticks | Alarms | +| 6 | 2927 | 0 | 0 | 0 | + +- With Cycle Timing Model + | GCFG Nodes | Bound | IRQs | Ticks | Alarms | + | 6 | 3922 | 0 | 0 | 0 | +* Interrupt Response Time of a System +Starting from the first instruction of the interrupt. How long does it +take till a task executes its first instruction. + +** Code +ISR: +1: timing_start() +2: ActivateTask(T1) +3: iret + +T1: +10: timing_end() + +** Results +#+begin_src sh +./run bench-timing-interrupt_reaction 0 +#+end_src + +#+RESULTS: +| Name | GCFG Nodes | Bound | IRQs | Ticks | Alarms | +| bench-timing-interrupt_reaction-0 | 12 | 464 | 1 | 0 | 0 | + + +* OBSOLETE A computation is interrupted once +A computation block is interrupted by an external interrupt with a +defined minimal interarrival time. + +** Code +1: TC(100) + +Interrupt: (minimal interarrival time=10000) +21: TC(100) + +** Sequence +[1, 21, 1'] + +** Results +#+begin_src sh +./run bench-timing-simple_interrupt 0 +#+end_src + +#+RESULTS: +| GCFG Nodes | Bound | IRQs | Ticks | Alarms | +| 4 | 2572 | 1 | 0 | 0 | + +- With Cycle Timing Model + | GCFG Nodes | Bound | IRQs | Ticks | Alarms | + | 4 | 3708 | 1 | 0 | 0 | + +* OBSOLETE A long computation is interrupted several times +A long-running computation block is interrupted by an external +interrupt with a defined minimal interarrival time. The interrupt +triggers multiple times. + +** Code +1: TC(2100) + +Interrupt: (minimal interarrival time=10000) +21: iret + +** Sequence +[1, 21, 1', 21, 1', 21, 1', 21, 1'] + +** Results +#+begin_src sh +./run bench-timing-computation_irq 0 +#+end_src + +#+RESULTS: +| GCFG Nodes | Bound | IRQs | Ticks | Alarms | +| 4 | 23783 | 3 | 0 | 0 | + +- With Cycle Timing Model + | GCFG Nodes | Bound | IRQs | Ticks | Alarms | + | 4 | 33391 | 4 | 0 | 0 | + +* OBSOLETE ActivateTask, Interrupt + A task activates a higher priority one, is suspeded, and resumed + after termination of the higher priority one. At all times an + interrupt with a minimal interarrival time is possible. +** Code +Task1: +0: timing_start() +1: TC(100) +2: ActivateTask(Task2) +3: TC(100) +4: timing_end() + +Task2: +10: TC(100) +11: TerminateTask() + +ISR: +20: TC(100) + +** Sequence + [1, 20, 1', 2, 10, 11, 3] +** Results +#+begin_src sh +./run bench-timing-simple_interrupt 1 +#+end_src + +#+RESULTS: +| GCFG Nodes | Bound | IRQs | Ticks | Alarms | +| 9 | 3942 | 1 | 0 | 0 | + +- With Cycle Timing Model + | GCFG Nodes | Bound | IRQs | Ticks | Alarms | + | 9 | 5555 | 1 | 0 | 0 | + +* OBSOLETE Complex Interaction Patterns + Alarm + In Task3, a loop activates a high-priority task Task1 30 times. Task1 + activates Task2 and chains its execution then to Task2. Task2 spends + some time on computation. After the loop in Task1 terminates, there + is more computation in Task3. + + On top of this loop pattern an timer is ticking, and drives an alarm + which triggers with a cycletime of 3. The alarm activates Task4 +** Code +Task3: +0: timing_start() +1: for (i = 0; i < 30; i++) +2: ActivateTask(Task1); +3: TC(1000) +4: timing_end() + +Task1: +10: ActivateTask(Task2) +11: ChainTask(Task2) + +Task2: +30: TC(100)) +31: TerminateTask() + +Task4: +40: TerminateTask() + +InterruptHandler // minimal interarrival time = 100000 +41: if CheckAlarm(Alarm) // cycletime = 3 +42: ActivateTask(Task4); +** Sequence +[.. complex ...] +** Results +#+begin_src sh +./run bench-timing-alarm 0 +#+end_src + +#+RESULTS: +| Name | GCFG Nodes | Bound | IRQs | Ticks | Alarms | +| bench-timing-alarm-0 | 125 | 721906 | 8 | 8 | 3 | + +- With Cycle Timing Model + | GCFG Nodes | Bound | IRQs | Ticks | Alarms | + | 125 | 981666 | 10 | 10 | 4 | +* I4Copter: SignalProcessing +How long does the signal processing of the I4Copter take in the worst +case? (3 Tasks, 3 Alarms, 1 Interrupt). +** Results +#+begin_src sh +./run bench-timing-copter 0 +#+end_src + +#+RESULTS: +| GCFG Nodes | Bound | IRQs | Ticks | Alarms | +| 7582 | 10773 | 2 | 1 | 2 | +* All Results +#+begin_src sh +./all.sh +#+end_src + +#+RESULTS: +| Name | GCFG Nodes | Bound | IRQs | Ticks | Alarms | +| bench-timing-activate_task-0 | 3 | 2015 | 0 | 0 | 0 | +| bench-timing-activate_task-1 | 6 | 4514 | 0 | 0 | 0 | +| bench-timing-activate_task-2 | 6 | 1172 | 0 | 0 | 0 | +| bench-timing-simple_interrupt-0 | 4 | 2570 | 1 | 0 | 0 | +| bench-timing-computation_irq-0 | 4 | 23777 | 3 | 0 | 0 | +| bench-timing-interrupt_reaction-0 | 12 | 473 | 1 | 0 | 0 | +| bench-timing-wait_event-0 | 6 | 2927 | 0 | 0 | 0 | +| bench-timing-simple_interrupt-1 | 9 | 3940 | 1 | 0 | 0 | +| bench-timing-tmr-0 | 9 | 3331 | 0 | 0 | 0 | +| bench-timing-aborted_computation-0 | 32 | 56250 | 1 | 0 | 0 | +| bench-timing-alarm-0 | 125 | 721906 | 8 | 8 | 3 | diff --git a/app/benchmark/timing/computation-alarm.cc b/app/benchmark/timing/computation-alarm.cc new file mode 100644 index 0000000000000000000000000000000000000000..b05ef80c79e0c4999f2a85b4d4aa5a4e81427d3b --- /dev/null +++ b/app/benchmark/timing/computation-alarm.cc @@ -0,0 +1,52 @@ +/** + * @file + * @ingroup unit_tests + * @test Test repeated alarn task activation while performing syscalls + */ + +#include "test/test.h" +#include "os/os.h" +#include "timing.h" + + +DeclareTask(Task1); +DeclareTask(Task4); +DeclareCounter(C1); + +TIMING_MAKE_OS_MAIN( StartOS(0) ) +GENERATE_TIME_CONSUMER(computation_0, 2300) +GENERATE_TIME_CONSUMER(computation_1, 50) + + +int alarm_count; + +extern "C" { + noinline void timing_entry(void) { + timing_loop_bound(30, 30) for (unsigned i = 0; i < 30; i++) { + computation_0(); + } + } +} + +TASK(Task3) { + timing_start(0); + timing_entry(); + timing_end(0); + + /* ABB Split Point */ + DisableAllInterrupts(); + EnableAllInterrupts(); + + /* Dump Timing and shutdown machine. */ + kout << "alarm count " << alarm_count << endl; + timing_dump(); + + TerminateTask(); +} + + +TASK(Task4) { + alarm_count++; + computation_1(); + TerminateTask(); +} diff --git a/app/benchmark/timing/computation-alarm.oil b/app/benchmark/timing/computation-alarm.oil new file mode 100644 index 0000000000000000000000000000000000000000..f5a28f3d5dfe248f98bc08c6afe229307af4a2ab --- /dev/null +++ b/app/benchmark/timing/computation-alarm.oil @@ -0,0 +1,43 @@ +CPU TestSystem { + + OS TestSystem { + STATUS = STANDARD; + ERRORHOOK = FALSE; + STARTUPHOOK = FALSE; + SHUTDOWNHOOK = FALSE; + PRETASKHOOK = FALSE; + POSTTASKHOOK = FALSE; + }; + + TASK Task3 { + SCHEDULE = FULL; + PRIORITY = 1; + ACTIVATION = 1; + AUTOSTART = TRUE; + }; + + TASK Task4 { + SCHEDULE = FULL; + PRIORITY = 4; + ACTIVATION = 1; + AUTOSTART = FALSE; + }; + + ALARM A1 { + COUNTER = C1; + ACTION = ACTIVATETASK { + TASK = Task4; + }; + AUTOSTART = TRUE { + ALARMTIME = 1; + CYCLETIME = 3; + }; + }; + + COUNTER C1 { + MAXALLOWEDVALUE = 50000; + TICKSPERBASE = 1; + MINCYCLE = 1; + }; +}; + diff --git a/app/benchmark/timing/computation-irq.cc b/app/benchmark/timing/computation-irq.cc new file mode 100644 index 0000000000000000000000000000000000000000..6dbd8fad865a7f4e71a1175f825001237b3203a0 --- /dev/null +++ b/app/benchmark/timing/computation-irq.cc @@ -0,0 +1,35 @@ +#include "os.h" +#include "test/test.h" +#include "syscall.h" +#include "timing.h" + +TEST_MAKE_OS_MAIN( StartOS(0) ) + +DeclareTask(H1); + + +GENERATE_TIME_CONSUMER(timing_0, 2100) + + +TASK(H1) { + timing_start(0); + timing_0(); + timing_end(0); + + /* ABB Split Point */ + DisableAllInterrupts(); + EnableAllInterrupts(); + timing_dump(); + ShutdownMachine(); + + TerminateTask(); +} + + +ISR2(ISR1) { +} + +void PreIdleHook() { + timing_dump(); + ShutdownMachine(); +} diff --git a/app/benchmark/timing/copter.cc b/app/benchmark/timing/copter.cc new file mode 100644 index 0000000000000000000000000000000000000000..1038ecab682291757df23dd200f31d664b58b722 --- /dev/null +++ b/app/benchmark/timing/copter.cc @@ -0,0 +1,154 @@ +#include "os.h" +#include "test/test.h" +#include "timing.h" +#include "machine.h" + +//extern "C" volatile uint32_t random_source =0 ; +DeclareTask(SignalGatherInitiateTask); +DeclareTask(SignalGatherFinishedTask); +DeclareTask(SignalGatherTimeoutTask); +DeclareTask(SignalProcessingActuateTask); +DeclareTask(SignalProcessingAttitudeTask); +DeclareTask(ActuateTask); +DeclareTask(FlightControlAttitudeTask); +DeclareTask(FlightControlActuateTask); +DeclareTask(MavlinkSendTask); +DeclareTask(CopterControlTask); +DeclareTask(MavlinkRecvHandler); + +DeclareResource(SPIBus); + +DeclareAlarm(CopterControlWatchdogAlarm); + +TIMING_MAKE_OS_MAIN( StartOS(0) ) + +//GENERATE_TIME_CONSUMER(calculation, 100) +//GENERATE_TIME_CONSUMER(calculation_short, 10) +#define calculation() do {} while(0) +#define calculation_short() do {} while(0) + +int round; + +TASK(SignalGatherInitiateTask) { + timing_start(0); + GetResource(SPIBus); + calculation(); + if ((round % 2) == 0) { + ActivateTask(SignalGatherTimeoutTask); + } else { + ActivateTask(SignalGatherFinishedTask); + } + round ++; + calculation(); + ReleaseResource(SPIBus); + calculation(); + TerminateTask(); +} + +TASK(SignalGatherFinishedTask) { + calculation(); + ActivateTask(SignalProcessingAttitudeTask); + calculation(); + ActivateTask(SignalProcessingActuateTask); + calculation(); + TerminateTask(); +} + +TASK(SignalGatherTimeoutTask) { + calculation(); + GetResource(SPIBus); + calculation(); + ReleaseResource(SPIBus); + calculation(); + ChainTask(SignalGatherFinishedTask); +} + +volatile int calculate; + +TASK(SignalProcessingActuateTask) { + calculation(); + TerminateTask(); +} + +TASK(SignalProcessingAttitudeTask) { + calculation(); + timing_end(0); + TerminateTask(); +} + +TASK(FlightControlTask) { + timing_start(1 | TIMING_POINT_IS_HIGHEST_PRIO); + calculation(); + ActivateTask(FlightControlAttitudeTask); + ActivateTask(FlightControlActuateTask); + ActivateTask(MavlinkSendTask); + calculation(); + TerminateTask(); +} + +TASK(FlightControlAttitudeTask) { + calculation(); + TerminateTask(); +} + +TASK(FlightControlActuateTask) { + calculation(); + TerminateTask(); +} + +TASK(MavlinkSendTask) { + calculation(); + GetResource(SPIBus); + calculation_short(); + Machine::trigger_interrupt_from_user(37); + ReleaseResource(SPIBus); + calculation(); + timing_end(1); + TerminateTask(); +} + +TASK(CopterControlTask) { + + calculation(); + SuspendAllInterrupts(); + calculation_short(); + ResumeAllInterrupts(); + calculation(); + + /* Saves 8000 states + if (round < 5) { + CancelAlarm(CopterControlWatchdogAlarm); + SetRelAlarm(CopterControlWatchdogAlarm, 100, 100); + } + calculation(); + */ + + timing_end(2); + + TerminateTask(); +} + +ISR2(MavlinkRecvHandler) { + timing_start(2 | TIMING_POINT_START_INTERRUPT_FROM_IDLE); + calculation_short(); + ActivateTask(CopterControlTask); + calculation_short(); +} + +TASK(CopterControlWatchdogTask) { + calculation(); + TerminateTask(); +} + + +void PreIdleHook() { + static int count = 0; + kout << "---\n"; + timing_print(); + if (++count > 5) { + } + + if (count == 100) { + timing_dump(); + } +} diff --git a/app/benchmark/timing/copter.oil b/app/benchmark/timing/copter.oil new file mode 100644 index 0000000000000000000000000000000000000000..f3e528d893bccea635980bf4bef24650aeafcac2 --- /dev/null +++ b/app/benchmark/timing/copter.oil @@ -0,0 +1,168 @@ +CPU CopterMock { + + OS Coptermock { + STATUS = STANDARD; + ERRORHOOK = FALSE; + STARTUPHOOK = FALSE; + SHUTDOWNHOOK = FALSE; + PRETASKHOOK = FALSE; + POSTTASKHOOK = FALSE; + }; + + TASKGROUP SignalGatherGroup { + PROMISE = SERIALIZED; + }; + + TASK SignalGatherInitiateTask { + SCHEDULE = FULL; + PRIORITY = 24; + ACTIVATION = 1; + AUTOSTART = FALSE; + RESOURCE = SPIBus; + TASKGROUP = SignalGatherGroup; + }; + + TASK SignalGatherFinishedTask { + SCHEDULE = FULL; + PRIORITY = 25; + ACTIVATION = 1; + AUTOSTART = FALSE; + RESOURCE = SPIBus; + TASKGROUP = SignalGatherGroup; + }; + + TASK SignalGatherTimeoutTask { + SCHEDULE = FULL; + PRIORITY = 23; + ACTIVATION = 1; + AUTOSTART = FALSE; + RESOURCE = SPIBus; + TASKGROUP = SignalGatherGroup; + }; + + TASK SignalProcessingActuateTask { + SCHEDULE = FULL; + PRIORITY = 22; + ACTIVATION = 1; + AUTOSTART = FALSE; + TASKGROUP = SignalGatherGroup; + }; + + TASK SignalProcessingAttitudeTask { + SCHEDULE = FULL; + PRIORITY = 21; + ACTIVATION = 1; + AUTOSTART = FALSE; + TASKGROUP = SignalGatherGroup; + }; + + /* Actuate Tasks */ + TASKGROUP FlightControlGroup { + PROMISE = SERIALIZED; + }; + + TASK FlightControlTask { + SCHEDULE = NON; + PRIORITY = 11; + ACTIVATION = 1; + AUTOSTART = FALSE; + TASKGROUP = FlightControlGroup; + }; + + TASK FlightControlAttitudeTask { + SCHEDULE = FULL; + PRIORITY = 12; + ACTIVATION = 1; + AUTOSTART = FALSE; + TASKGROUP = FlightControlGroup; + }; + + TASK FlightControlActuateTask { + SCHEDULE = FULL; + PRIORITY = 13; + ACTIVATION = 1; + AUTOSTART = FALSE; + TASKGROUP = FlightControlGroup; + }; + + TASK MavlinkSendTask { + SCHEDULE = FULL; + PRIORITY = 10; + ACTIVATION = 1; + AUTOSTART = FALSE; + TASKGROUP = FlightControlGroup; + }; + + /* Watchdog Task */ + TASKGROUP WatchdogGroup { + PROMISE = SERIALIZED; + }; + TASK CopterControlWatchdogTask { + SCHEDULE = NON; + PRIORITY = 1; + ACTIVATION = 1; + AUTOSTART = FALSE; + TASKGROUP = WatchdogGroup; + }; + + /* Remote Control Task */ + TASKGROUP MavlinkReceiveGroup { + PROMISE = SERIALIZED; + }; + + TASK CopterControlTask { + SCHEDULE = FULL; + PRIORITY = 5; + ACTIVATION = 1; + AUTOSTART = FALSE; + TASKGROUP = MavlinkReceiveGroup; + }; + ISR MavlinkRecvHandler { + CATEGORY = 2; + PRIORITY = 100; + DEVICE = 37; + TASKGROUP = MavlinkReceiveGroup; + MINIAT = 200000; + }; + + RESOURCE SPIBus { + RESOURCEPROPERTY = STANDARD; + }; + + ALARM SignalGatherAlarm { + COUNTER = C1; + ACTION = ACTIVATETASK { + TASK = SignalGatherInitiateTask; + }; + AUTOSTART = TRUE { + ALARMTIME = 10; + CYCLETIME = 30; + }; + }; + + ALARM FlightControlAlarm { + COUNTER = C1; + ACTION = ACTIVATETASK { + TASK = FlightControlTask; + }; + AUTOSTART = TRUE { + ALARMTIME = 10; + CYCLETIME = 90; + }; + }; + + ALARM CopterControlWatchdogAlarm { + COUNTER = C1; + ACTION = ACTIVATETASK { + TASK = CopterControlWatchdogTask; + }; + }; + + COUNTER C1 { + MAXALLOWEDVALUE = 50000; + TICKSPERBASE = 1; + MINCYCLE = 1; + }; + +}; + diff --git a/app/benchmark/timing/interrupt-reaction.cc b/app/benchmark/timing/interrupt-reaction.cc new file mode 100644 index 0000000000000000000000000000000000000000..e2b0a547fc233b76f1d59f356d91f53fe570b194 --- /dev/null +++ b/app/benchmark/timing/interrupt-reaction.cc @@ -0,0 +1,30 @@ +#include "os.h" +#include "test/test.h" +#include "syscall.h" +#include "timing.h" + +TEST_MAKE_OS_MAIN( StartOS(0) ) + +DeclareTask(H2); + + +TASK(H1) { + timing_start(0 | TIMING_POINT_START_INTERRUPT_IN_BLOCK); + Machine::trigger_interrupt_from_user(37); + /* IRQ + H2 */ + + + timing_dump(); + TerminateTask(); +} + + +ISR2(ISR1) { + ActivateTask(H2); +} + + +TASK(H2) { + timing_end(0); + TerminateTask(); +} diff --git a/app/benchmark/timing/interrupt-reaction.oil b/app/benchmark/timing/interrupt-reaction.oil new file mode 100644 index 0000000000000000000000000000000000000000..eb6dc7542472337975d8fd17beb9769c394a58ee --- /dev/null +++ b/app/benchmark/timing/interrupt-reaction.oil @@ -0,0 +1,35 @@ +CPU TestSystem { + + OS TestSystem { + STATUS = STANDARD; + ERRORHOOK = FALSE; + STARTUPHOOK = FALSE; + SHUTDOWNHOOK = FALSE; + PRETASKHOOK = FALSE; + POSTTASKHOOK = FALSE; + }; + + TASK H1 { + SCHEDULE = FULL; + PRIORITY = 4; + ACTIVATION = 1; + AUTOSTART = TRUE; + }; + + + TASK H2 { + SCHEDULE = FULL; + PRIORITY = 5; + ACTIVATION = 1; + AUTOSTART = FALSE; + }; + + ISR ISR1 { + CATEGORY = 2; + PRIORITY = 10; + DEVICE = 37; + MINIAT = 10000; + }; + +}; + diff --git a/app/benchmark/timing/irq-task.oil b/app/benchmark/timing/irq-task.oil new file mode 100644 index 0000000000000000000000000000000000000000..42d13249c300ca44c5d3acc506ef9acc1fa9c57c --- /dev/null +++ b/app/benchmark/timing/irq-task.oil @@ -0,0 +1,27 @@ +CPU TestSystem { + + OS TestSystem { + STATUS = STANDARD; + ERRORHOOK = FALSE; + STARTUPHOOK = FALSE; + SHUTDOWNHOOK = FALSE; + PRETASKHOOK = FALSE; + POSTTASKHOOK = FALSE; + }; + + TASK H1 { + SCHEDULE = FULL; + PRIORITY = 5; + ACTIVATION = 1; + AUTOSTART = TRUE; + }; + + ISR ISR1 { + CATEGORY = 2; + PRIORITY = 10; + DEVICE = 37; + MINIAT = 10000; + }; + +}; + diff --git a/app/benchmark/timing/manual-syswcet.py b/app/benchmark/timing/manual-syswcet.py new file mode 100755 index 0000000000000000000000000000000000000000..fd13aac3a2f4a62399cd14fe87553c2d083c67b2 --- /dev/null +++ b/app/benchmark/timing/manual-syswcet.py @@ -0,0 +1,353 @@ +#!/usr/bin/env python3 + +import sys +import os +import shlex +import subprocess +from argparse import ArgumentParser + +import shlex +import subprocess +import threading +import re +import logging +import tempfile + +class Execution: + def __init__(self, command, proc): + self.command = command + self.proc = proc + + def print_details(self): + print("command: " + self.command) + print("stderr:\n" + self.stderr.decode("utf-8")) + print("stdout:\n" + str(self.stdout)) + print("retcode: " + str(self.retcode)) + + def assert_retcode(self, expected): + if expected != self.retcode: + self.print_details() + assert False, "Command returned with retcode %r" % self.retcode + + def wait(self, expected_retcode = None): + (self.stdout, self.stderr) = self.proc.communicate() + self.retcode = self.proc.returncode + + if None != expected_retcode: + self.assert_retcode(expected_retcode) + +def run(cmd, stdin_data = None): + "Run `cmd` and return a dict containing cmd, retcode, stdout and stderr" + + proc = subprocess.Popen(shlex.split(cmd), stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE, bufsize=0) + if None != stdin_data: + proc.stdin.write(stdin_data) + + return Execution(cmd, proc) + +def run_wait(cmd, stdin_data = None): + "Run `cmd` and return a dict containing cmd, retcode, stdout and stderr" + + proc = subprocess.Popen(shlex.split(cmd), stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE, bufsize=0) + Exec = Execution(cmd, proc) + + (Exec.stdout, Exec.stderr) = Exec.proc.communicate(stdin_data) + Exec.retcode = Exec.proc.returncode + + return Exec + +proc = None +def run_wait_timeout(cmd, stdin_data, timeout): + global proc + + def exec_function(): + global proc + proc = run_wait(cmd, stdin_data) + + thread = threading.Thread(target=exec_function) + thread.start() + thread.join( timeout * 60 ) + + if thread.is_alive(): + proc.proc.kill() + thread.join() + + proc.retcode = None + return proc + + return proc + +RELATIVE_BUILD_DIR = '../../../build' +DREF_KEY = 'MANUAL/cycles' + +def parse_args(): + parser = ArgumentParser(description="script for manual evaluation of sysbench") + + parser.add_argument('-b', '--bench', dest='bench', + help='the benchmark under analysis', + choices=['tmr','computation_alarm','aborted_computation', 'copter', + 'activate_task', 'wait_event', 'interrupt_reaction'], + required=False, default=None) + + parser.add_argument('-d', '--dref', dest='dref_file', + help='file for the manual results', + required=False, default="bench-timing-manual.dref") + + parser.add_argument('-a', '--all', dest='all', action='store_true', + help='process all benchmarks', + required=False, default=False) + + parser.add_argument('-v', '--verbose', dest='verbose', action='store_true', + help='activate verbose output', + required=False, default=False) + + + return parser, parser.parse_args() + + +def dref_get_value(key, file): + with open(file, 'r') as f: + for line in f.readlines(): + pattern=r'^\\drefset{' + key + r'}{(\d+)}$' + match = re.search(pattern, line) + if match: + cy = match.group(1) + return cy + + return None + +def get_elf(args_bench): + build_dir = os.path.abspath(RELATIVE_BUILD_DIR) + if not os.path.exists(build_dir): + sys.exit("build directory missing: %s" % build_dir) + + elf=os.path.join(build_dir, 'bench-timing-' + args_bench) + + return elf + +def setup_paths(args_bench): + elf = get_elf(args_bench) + build_dir = os.path.abspath(RELATIVE_BUILD_DIR) + bench_out_dir = os.path.join(build_dir, ) + system_pml = os.path.join(build_dir, 'bench-timing-%s-system.pml'%(args_bench)) + gcfg_pml = os.path.join(build_dir, 'bench-timing-%s-gcfg.pml'%(args_bench)) + + return (elf, system_pml, gcfg_pml) + + +def dref_key(dref_file, key, value): + logging.info("drefset: %s = %d", key, value) + content = [] + if os.path.exists(dref_file): + with open(dref_file) as fd: + content += [x.strip() for x in fd.readlines()] + key = '\\drefset{/%s/%s}' %(key, DREF_KEY) + line = '%s{%s}' %(key, value) + found = False + for idx in range(0, len(content)): + if content[idx].startswith(key): + content[idx] = line + found = True + break + if not found: + content.append(line) + with open(dref_file, "w+") as fd: + fd.write("\n".join(content) + "\n") + +def get_cycles_from_entry(entry, bench, flow_facts = []): + elf, system_pml, gcfg_pml = setup_paths(bench) + + (fd, dref) = tempfile.mkstemp() + cmd = 'platin wcet -i ' + system_pml + ' -i ' + gcfg_pml + \ + ' --binary ' + elf + ' --wca-count-instructions ' + \ + ' --disable-ait --wca-detect-gurobi --dref-stats ' + dref + \ + ' -e ' + entry # GCFG:timing-' + str(circuit) + for ff in flow_facts: + cmd += " --add-flowfact " + repr(ff) + proc = run_wait(cmd, None) + proc.assert_retcode(0) + cy_entry = int(dref_get_value('/WCA/cycles', dref)) + logging.info("%s, %s = %d", bench, entry, cy_entry) + os.unlink(dref) + os.close(fd) + return cy_entry + +def add_events_with_iat(cy_base, events = []): + cy_total = cy_base + cy_total_last = None + occurences = {} + while cy_total != cy_total_last: + cy_total_last = cy_total + cy_total = cy_base + for (iat, cyc, name) in events: + occ = (int(cy_total) // int(iat)) + 1 + cy_total += occ * cyc + occurences[name] = (occ, occ * cyc) + return cy_total, occurences + + +def main(): + parser, args = parse_args() + + if "VERBOSE" in os.environ: + args.verbose = True + + if args.verbose: + logging.basicConfig(level=logging.DEBUG) + + logging.info("Updating %s", args.dref_file) + args.dref_file = os.path.abspath(args.dref_file) + + # cd "$(dirname "$0")" + dirname = os.path.dirname(os.path.realpath(__file__)) + os.chdir(dirname) + + # 1. tmr (non-hierarchical call chains) + if args.all or args.bench == 'tmr': + args.bench = 'tmr' + cy_timing_entry = get_cycles_from_entry('timing_entry', args.bench) + cy_computation = get_cycles_from_entry('OSEKOS_TASK_FUNC_Calculation', args.bench) + + # take three times the entry + cy_total = cy_timing_entry + cy_computation * 3 + + dref_key(args.dref_file, "tmr", int(cy_total)) + + + # 2. computation IRQ (operating system semantic) + if args.all or args.bench == 'computation_alarm': + args.bench = 'computation_alarm' + cy_timing_entry = get_cycles_from_entry('timing_entry', args.bench) + cy_task4 = get_cycles_from_entry('OSEKOS_TASK_FUNC_Task4', args.bench) + cy_isr = get_cycles_from_entry('irq_entry', args.bench, ["irq_entry : <> : timer_isr = 1"]) + + iat_timer = 100000 + iat_task4 = 3 * iat_timer + + cy_total, occurences = add_events_with_iat( + cy_timing_entry, [(iat_timer, cy_isr, "timer"), (iat_task4, cy_task4, "alarms")]) + + logging.info("%s = %d", occurences, cy_total) + + dref_key(args.dref_file, "computation alarm", int(cy_total)) + dref_key(args.dref_file, "computation alarm/computation", int(cy_timing_entry)) + + + # 3 aborted computation (interrupt handling) + if args.all or args.bench == 'aborted_computation': + args.bench = 'aborted_computation' + cy_timing_entry = get_cycles_from_entry('timing_entry', args.bench) + cy_computation = get_cycles_from_entry('timing_entry', args.bench) + + cy_computation = get_cycles_from_entry('OSEKOS_TASK_FUNC_Computation', args.bench) + cy_ISR_abort = get_cycles_from_entry('irq_entry', args.bench, ["irq_entry : <> : OSEKOS_ISR_Abort = 1"]) + + iat_isr = 10000 + + cy_total, occurences = add_events_with_iat( + cy_timing_entry + cy_computation, [(iat_isr, cy_ISR_abort, "isr")]) + + dref_key(args.dref_file, "aborted computation", int(cy_total)) + dref_key(args.dref_file, "aborted computation/computation", int(cy_computation)) + + + # 4 syscall benchmarks + if args.all or args.bench == 'activate_task': + args.bench = 'activate_task' + cy_timing_0 = get_cycles_from_entry('timing_entry_0', args.bench) + dref_key(args.dref_file, "activate 0", int(cy_timing_0)) + + cy_timing_1 = get_cycles_from_entry('timing_entry_1', args.bench) + cy_Handler13 = get_cycles_from_entry('OSEKOS_TASK_FUNC_Handler13', args.bench) + dref_key(args.dref_file, "activate 1", int(cy_timing_1+cy_Handler13)) + + cy_timing_2 = get_cycles_from_entry('timing_entry_2', args.bench) + cy_Handler12 = get_cycles_from_entry('OSEKOS_TASK_FUNC_Handler12', args.bench) + cy_idle = get_cycles_from_entry('__OS_HOOK_PreIdleHook', args.bench) + + dref_key(args.dref_file, "activate 2", int(cy_timing_2+cy_Handler12+cy_idle)) + + if args.all or args.bench == 'wait_event': + args.bench = 'wait_event' + cy_timing_entry = get_cycles_from_entry('timing_entry', args.bench) + cy_H2 = get_cycles_from_entry('OSEKOS_TASK_FUNC_H2', args.bench, + ["OSEKOS_TASK_FUNC_H2 : <> : /OSEKOS_TerminateTask_.*/ = 0"]) + dref_key(args.dref_file, "wait event", int(cy_timing_entry + cy_H2)) + + if args.all or args.bench == 'interrupt_reaction': + args.bench = 'interrupt_reaction' + cy_ISR = get_cycles_from_entry('irq_entry', args.bench, ["irq_entry : <> : OSEKOS_ISR_ISR1 = 1"]) + cy_H2 = get_cycles_from_entry('OSEKOS_TASK_FUNC_H2', args.bench, + ["OSEKOS_TASK_FUNC_H2 : <> : /OSEKOS_TerminateTask_.*/ = 0"]) + + dref_key(args.dref_file, "interrupt reaction", int(cy_ISR + cy_H2)) + + + if args.all or args.bench == 'copter': + args.bench = 'copter' + iat_timer = 100000 + cy_timer_isr = get_cycles_from_entry('irq_entry', args.bench, ["irq_entry : <> : timer_isr = 1"]) + + iat_mavlink = 200000 + cy_ISR_Mavlink = get_cycles_from_entry('irq_entry', args.bench, ["irq_entry : <> : OSEKOS_ISR_MavlinkRecvHandler = 1"]) + + cy_threads = {} + for thread in ( + 'SignalGatherInitiateTask', + 'SignalGatherFinishedTask', + 'SignalGatherTimeoutTask', + 'SignalProcessingActuateTask', + 'SignalProcessingAttitudeTask', + 'FlightControlTask', + 'FlightControlAttitudeTask', + 'FlightControlActuateTask', + 'MavlinkSendTask', + 'CopterControlWatchdogTask', + 'CopterControlTask', + ): + cy_threads[thread] = get_cycles_from_entry('OSEKOS_TASK_FUNC_'+thread, 'copter') + + cy_signal_processing = cy_threads['SignalGatherInitiateTask'] +\ + cy_threads['SignalGatherFinishedTask'] +\ + cy_threads['SignalGatherTimeoutTask'] + \ + cy_threads['SignalProcessingActuateTask'] +\ + cy_threads['SignalProcessingAttitudeTask'] + + cy_copter_0,occurences = add_events_with_iat( + cy_signal_processing, + [(iat_timer, cy_timer_isr, 'timer'), (iat_mavlink, cy_ISR_Mavlink, 'mavlink')] + ) + logging.info("copter 0: %s", occurences) + dref_key(args.dref_file, "copter 0", cy_copter_0) + + + cy_flight_control = cy_threads['FlightControlTask'] + \ + cy_threads['FlightControlAttitudeTask'] +\ + cy_threads['FlightControlActuateTask'] + \ + cy_threads['MavlinkSendTask'] + + + cy_copter_1, occurences = add_events_with_iat( + cy_flight_control, + [(iat_timer, cy_timer_isr, 'timer'), (3 * iat_timer, cy_signal_processing, 'signal-processing'), + (iat_mavlink, cy_ISR_Mavlink, 'mavlink')] + ) + + logging.info("copter 1: %s", occurences) + dref_key(args.dref_file, "copter 1", cy_copter_1) + + cy_rc_control = cy_ISR_Mavlink + \ + cy_threads['CopterControlTask'] + + cy_copter_2, occurences = add_events_with_iat( + cy_rc_control, + [(iat_timer, cy_timer_isr, 'timer'), + (3 * iat_timer, cy_signal_processing, 'signal-processing'), + (9 * iat_timer, cy_flight_control, 'flight-control'), + ] + ) + + logging.info("copter 2: %s", occurences) + dref_key(args.dref_file, "copter 2", cy_copter_2) +if __name__=='__main__': + main() diff --git a/app/benchmark/timing/run b/app/benchmark/timing/run new file mode 100755 index 0000000000000000000000000000000000000000..ff85235e9426f9241306695411be529b1c5bc517 --- /dev/null +++ b/app/benchmark/timing/run @@ -0,0 +1,56 @@ +#!/bin/bash + +if [ $# -ne 2 ]; then + echo "usage: $0 bench-target circuit" >&2 + exit 1 +fi + +BM=$1; shift +CIRCUIT=$1; shift + +RUN_PWD=$(pwd) +cd "$(dirname "$0")" + +cd ../../../build; + +# file created by platin's --dref-stats option +OUTFILE="${BM}.${CIRCUIT}.dref" + +echo Building $BM >&2 +make $BM >&2 + +echo Analysis $BM CIRCUIT=$CIRCUIT >&2 +make wcet-$BM CIRCUIT=$CIRCUIT >&2 + +# Get numer of states for circuit +function key() { + grep "$1" ${OUTFILE} | sed 's/.*}{//; s/}//' +} + +if [ -z "$NO_HEADER" ]; then + echo -e "Name\tGCFG Nodes\tBound\tIRQs\tTicks\tAlarms" +fi +echo -e "${BM}-${CIRCUIT}\t$(key "gcfg nodes")\t$(key "WCA/cycles")\t$(key "WCA/interrupt requests")\t$(key "timer ticks")\t$(key "alarm activations")" + +echo Running $BM >&2 +TRACE_OUTPUT=$(tempfile) +make test-$BM &> $TRACE_OUTPUT + +out_circuit=0 +# iterate over all circuits dumped by the simulation +for i in $(grep -P timing-[0-9]+ ${TRACE_OUTPUT} | cut -d' ' -f 2); do + + # the trace will dump all circuits + # However, only the current CIRCUIT is required + if [ "${out_circuit}" -eq "${CIRCUIT}" ]; then + echo "\drefset{/TRACE/cycles}{${i}}" >> ${OUTFILE} + fi + + out_circuit=$(expr ${out_circuit} + 1) +done + +if [ x"$CIRCUIT" = x"0" ]; then + platin blocking-time -i $BM-system.pml --wca-detect-gurobi --dref-stats $BM.dref +fi + +cd ${RUN_PWD} diff --git a/app/benchmark/timing/simple-interrupt.cc b/app/benchmark/timing/simple-interrupt.cc new file mode 100644 index 0000000000000000000000000000000000000000..f0a095928a3f5aa96adebe1276c4e9e95fe6edc9 --- /dev/null +++ b/app/benchmark/timing/simple-interrupt.cc @@ -0,0 +1,59 @@ +#include "os.h" +#include "test/test.h" +#include "syscall.h" +#include "timing.h" + +TEST_MAKE_OS_MAIN( StartOS(0) ) + +DeclareTask(H1); +DeclareTask(H2); +DeclareTask(H3); + + +GENERATE_TIME_CONSUMER(timing_0_before, 100) +GENERATE_TIME_CONSUMER(timing_irq, 100) + +GENERATE_TIME_CONSUMER(timing_1_before, 100) +GENERATE_TIME_CONSUMER(timing_1_middle, 100) +GENERATE_TIME_CONSUMER(timing_1_after, 100) + + +TASK(H1) { + test_trace('1'); + TerminateTask(); +} + +TASK(H2) { + timing_start(0); + timing_0_before(); + Machine::trigger_interrupt_from_user(37); + timing_end(0); + + /* ABB Split Point */ + DisableAllInterrupts(); + EnableAllInterrupts(); + + timing_start(1); + timing_1_before(); + Machine::trigger_interrupt_from_user(37); + ActivateTask(H3); + timing_1_after(); + timing_end(1); + + + TerminateTask(); +} + +TASK(H3) { + timing_1_middle(); + TerminateTask(); +} + +ISR2(ISR1) { + timing_irq(); +} + +void PreIdleHook() { + timing_dump(); + ShutdownMachine(); +} diff --git a/app/benchmark/timing/simple-interrupt.oil b/app/benchmark/timing/simple-interrupt.oil new file mode 100644 index 0000000000000000000000000000000000000000..4f9f1227948a6fcd62a3a0304060f0e52c8c3d32 --- /dev/null +++ b/app/benchmark/timing/simple-interrupt.oil @@ -0,0 +1,41 @@ +CPU TestSystem { + + OS TestSystem { + STATUS = STANDARD; + ERRORHOOK = FALSE; + STARTUPHOOK = FALSE; + SHUTDOWNHOOK = FALSE; + PRETASKHOOK = FALSE; + POSTTASKHOOK = FALSE; + }; + + TASK H1 { + SCHEDULE = FULL; + PRIORITY = 5; + ACTIVATION = 1; + AUTOSTART = FALSE; + }; + + TASK H2 { + SCHEDULE = FULL; + PRIORITY = 4; + ACTIVATION = 1; + AUTOSTART = TRUE; + }; + + TASK H3 { + SCHEDULE = FULL; + PRIORITY = 3; + ACTIVATION = 1; + AUTOSTART = FALSE; + }; + + ISR ISR1 { + CATEGORY = 2; + PRIORITY = 10; + DEVICE = 37; + MINIAT = 10000; + }; + +}; + diff --git a/app/benchmark/timing/tmr.cc b/app/benchmark/timing/tmr.cc new file mode 100644 index 0000000000000000000000000000000000000000..fa5a5f6493027b4124789ba0f1fad615b4643fc3 --- /dev/null +++ b/app/benchmark/timing/tmr.cc @@ -0,0 +1,41 @@ +#include "os.h" +#include "timing.h" +#include "machine.h" + +DeclareTask(Control); +DeclareTask(Calculation); + +TIMING_MAKE_OS_MAIN( StartOS(0) ) + +GENERATE_TIME_CONSUMER(calculation, 50) + +/* We put the timing circuit into an extra non inlinable function, in + * order to make tradtional analysis simpler. + */ +extern "C" { + noinline void timing_entry() { + timing_start(0); + + timing_loop_bound(2, 3) for (unsigned i = 0; i < 3; i++) { + ActivateTask(Calculation); + } + timing_end(0); + } +} + +TASK(Control) { + + timing_entry(); + + TerminateTask(); +} + +TASK(Calculation) { + calculation(); + TerminateTask(); +} + +void PreIdleHook() { + /* Dump and Shutdown */ + timing_dump(); +} diff --git a/app/benchmark/timing/tmr.oil b/app/benchmark/timing/tmr.oil new file mode 100644 index 0000000000000000000000000000000000000000..3af35b37e87c40db09f3682ab9144fb8850e4d64 --- /dev/null +++ b/app/benchmark/timing/tmr.oil @@ -0,0 +1,27 @@ +CPU TestSystem { + + OS TestSystem { + STATUS = STANDARD; + ERRORHOOK = FALSE; + STARTUPHOOK = FALSE; + SHUTDOWNHOOK = FALSE; + PRETASKHOOK = FALSE; + POSTTASKHOOK = FALSE; + }; + + TASK Control { + SCHEDULE = FULL; + PRIORITY = 5; + ACTIVATION = 1; + AUTOSTART = TRUE; + }; + + TASK Calculation { + SCHEDULE = FULL; + PRIORITY = 6; + ACTIVATION = 1; + AUTOSTART = FALSE; + }; + +}; + diff --git a/app/benchmark/timing/wait-event.cc b/app/benchmark/timing/wait-event.cc new file mode 100644 index 0000000000000000000000000000000000000000..b2648a343639c22ee7974f8a51f5c6ce6985f7c7 --- /dev/null +++ b/app/benchmark/timing/wait-event.cc @@ -0,0 +1,39 @@ +#include "os.h" +#include "timing.h" +#include "machine.h" + +DeclareTask(H1); +DeclareTask(H2); +DeclareTask(H3); +DeclareEvent(E1); +DeclareEvent(E2); + + +bool done; +extern "C" { + void timing_entry() { + timing_start(0); + WaitEvent(E1); + timing_end(0); + } +} + +TASK(H1) { + ActivateTask(H2); + + timing_entry(); + + /* ABB Split Point */ + DisableAllInterrupts(); + EnableAllInterrupts(); + + timing_dump(); + ShutdownMachine(); + + TerminateTask(); +} + +TASK(H2) { + SetEvent(H1, E1); + TerminateTask(); +} diff --git a/app/benchmark/timing/wait-event.oil b/app/benchmark/timing/wait-event.oil new file mode 100644 index 0000000000000000000000000000000000000000..b6bc685fd098eba87358b9902de40a62aa5ee906 --- /dev/null +++ b/app/benchmark/timing/wait-event.oil @@ -0,0 +1,38 @@ +CPU TestSystem { + + OS TestSystem { + STATUS = STANDARD; + ERRORHOOK = FALSE; + STARTUPHOOK = FALSE; + SHUTDOWNHOOK = FALSE; + PRETASKHOOK = FALSE; + POSTTASKHOOK = FALSE; + }; + + TASK H1 { + SCHEDULE = FULL; + PRIORITY = 4; + ACTIVATION = 1; + AUTOSTART = TRUE; + EVENT = E1; + EVENT = E2; + }; + + TASK H2 { + SCHEDULE = FULL; + PRIORITY = 3; + ACTIVATION = 1; + AUTOSTART = FALSE; + EVENT = E2; + }; + + EVENT E1 { + MASK = AUTO; + }; + + EVENT E2 { + MASK = AUTO; + }; + +}; + diff --git a/app/keso/gc_coffebreak/CMakeLists.txt b/app/keso/gc_coffebreak/CMakeLists.txt index 4bca863afe77bd52e3d19096a6b458704a4e88a6..7b8d7411acbc2c69ed747ce452a7b9ef2b31b7c1 100644 --- a/app/keso/gc_coffebreak/CMakeLists.txt +++ b/app/keso/gc_coffebreak/CMakeLists.txt @@ -7,7 +7,7 @@ FILE(GLOB_RECURSE KESO_SOURCES "keso_gc_coffebreak/*.cpp") config_valid(VALID --mpu false --systemcalls normal) -if(VALID) +if(VALID AND (NOT "${CONFIG_ARCH}" STREQUAL "patmos")) DOSEK_BINARY( NAME keso_gc_coffebreak @@ -20,6 +20,3 @@ DOSEK_BINARY( ) endif() - - - diff --git a/app/keso/hello_world/CMakeLists.txt b/app/keso/hello_world/CMakeLists.txt index d842d402e68cc75583265bd3af74014256bce887..2b6e9057e9dcfa645bcff4a8aef5a8e07d1bfd24 100644 --- a/app/keso/hello_world/CMakeLists.txt +++ b/app/keso/hello_world/CMakeLists.txt @@ -7,7 +7,8 @@ FILE(GLOB_RECURSE KESO_SOURCES "keso_helloworld/*.cpp") config_valid(VALID --systemcalls normal) -if(VALID) +if(VALID AND (NOT "${CONFIG_ARCH}" STREQUAL "patmos")) + DOSEK_BINARY( NAME keso_helloworld @@ -17,5 +18,3 @@ DOSEK_BINARY( ) endif() - - diff --git a/arch/CMakeLists.txt b/arch/CMakeLists.txt index 88a8daf35ef31077b057b439f5e644a5c78bf470..cfab6fc0c85331cf3e99b03fa5bf37040ffed080 100644 --- a/arch/CMakeLists.txt +++ b/arch/CMakeLists.txt @@ -1,14 +1,15 @@ # Hardware dependent code -if(BUILD_i386) - add_subdirectory(i386) -elseif(BUILD_ARM) - add_subdirectory(arm) -elseif(BUILD_posix) - add_subdirectory(posix) +if(${CONFIG_ARCH} STREQUAL "i386") + add_subdirectory(i386) +elseif(${CONFIG_ARCH} STREQUAL "ARM") + add_subdirectory(arm) +elseif(${CONFIG_ARCH} STREQUAL "posix") + add_subdirectory(posix) +elseif(${CONFIG_ARCH} STREQUAL "patmos") + add_subdirectory(patmos) else() - message(FATAL_ERROR "Hardware platform not found :(") + message(FATAL_ERROR "Hardware platform not found :(") endif() ## Generic startup code add_subdirectory(generic) - diff --git a/arch/arm/CMakeLists.txt b/arch/arm/CMakeLists.txt index b399f02e64412214482815aad62e104d60be7bcd..3fdf2e363f10d86607d2db30046be629bf6a410e 100644 --- a/arch/arm/CMakeLists.txt +++ b/arch/arm/CMakeLists.txt @@ -66,9 +66,6 @@ set(ARCH_INCLUDE_DIRS ${ARCH_INCLUDE_DIRS} ${CMAKE_CURRENT_SOURCE_DIR} CACHE INT # Set linker script template set(LINKER_TEMPLATE ${CMAKE_CURRENT_SOURCE_DIR}/linker.ld.in CACHE INTERNAL STRING) -# Find objdump for pagetable generation -find_program(OBJDUMP "${ARCH_PREFIX}objdump") - # ARM dOSEK executable macro # usage: dosek_executable(ELFFILE ... [DEFINTIONS ...]) # Creates dOSEK executable named ELFFILE. All parameters after ELFFILE until @@ -100,18 +97,8 @@ macro(dosek_executable ELFFILE) set_target_properties(${PRELINK} PROPERTIES RUNTIME_OUTPUT_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}) target_link_libraries(${PRELINK} ${TARGET_LIBS}) - # Generate pagetables from first executable - # set(PAGETABLES ${ELFNAME}-pagetables.cc) - # set(GENERATOR ${PROJECT_SOURCE_DIR}/arch/i386/generate-pagetables.py) - # add_custom_command( - # DEPENDS ${PRELINK} ${GENERATOR} - # COMMAND ${PYTHON} ${GENERATOR} -o ${OBJDUMP} -c ${PAGETABLES} -e ${PRELINK} - # COMMENT "Generating static page tables for ${ELFFILE}" - # OUTPUT ${PAGETABLES} - # ) - # The actual executable - add_executable(${ELFFILE} ${ADD_EXECUTABLE_OPTIONS} ${SOURCES} )# ${PAGETABLES}) + add_executable(${ELFFILE} ${ADD_EXECUTABLE_OPTIONS} ${SOURCES} ) target_link_libraries(${ELFFILE} ${TARGET_LIBS}) # set definitions @@ -127,16 +114,10 @@ macro(dosek_executable ELFFILE) set(LINKER_SCRIPT ${CMAKE_CURRENT_BINARY_DIR}/${ELFNAME}_linker.ld) endif() set_target_properties(${ELFFILE} ${PRELINK} PROPERTIES - LINK_FLAGS "-lgcc -Wl,-T ${LINKER_SCRIPT} ${ISA_LD_FLAGS} --linker-prefix=${CMAKE_CURRENT_BINARY_DIR}/${ELFFILE}" + LINK_FLAGS "-lgcc -Wl,-T ${LINKER_SCRIPT} ${TC_TARGET_LDFLAGS} --linker-prefix=${CMAKE_CURRENT_BINARY_DIR}/${ELFFILE}" LINK_DEPENDS ${LINKER_SCRIPT}) - # we use our own linker (python) script, that calls llvm-link, llc and the system linker - # setting CMAKE_*_LINK_EXECUTABLE at this point in the CMake run seems a bit unusual, but works as intended - set(LINK_EXECUTABLE "${PROJECT_SOURCE_DIR}/toolchain/llvm-link.py --clang ${CMAKE_C_COMPILER} --llvm-dir ${CCDIR} <LINK_FLAGS> <OBJECTS> <LINK_LIBRARIES> -o <TARGET>") - set(CMAKE_C_LINK_EXECUTABLE "${LINK_EXECUTABLE} <CMAKE_C_LINK_FLAGS>") - set(CMAKE_CXX_LINK_EXECUTABLE "${LINK_EXECUTABLE} <CMAKE_CXX_LINK_FLAGS>") - - # add to executables list + # add to executables list set(EXECUTABLES ${EXECUTABLES} ${ELFFILE} CACHE INTERNAL STRING) # Add Platform specific stuff @@ -152,4 +133,3 @@ macro(dosek_add_test FN) set_tests_properties(${FN} PROPERTIES PASS_REGULAR_EXPRESSION "SUCCESS.+ALL OK" FAIL_REGULAR_EXPRESSION "FAIL" TIMEOUT 20) add_dependencies( tests ${FN} ) endmacro() - diff --git a/arch/generic/CMakeLists.txt b/arch/generic/CMakeLists.txt index bbc5a627ded6eeeadd8fcfd7681d31d745d4973d..fbc3551ff330e63b311c3cc52ce521f22cb42d4a 100644 --- a/arch/generic/CMakeLists.txt +++ b/arch/generic/CMakeLists.txt @@ -1,5 +1,7 @@ set(SRCS - startup.cc + startup.cc + timing-arch.cc + ) # Add to include directories diff --git a/arch/i386/atomics.h b/arch/generic/atomics.h similarity index 100% rename from arch/i386/atomics.h rename to arch/generic/atomics.h diff --git a/arch/generic/ostream.h b/arch/generic/ostream.h index 914a6e0b9458a0e5ba51351b01b6dd032793242a..62d3d9469852cc6db6cd2f2c4e437d59f27b47a4 100644 --- a/arch/generic/ostream.h +++ b/arch/generic/ostream.h @@ -55,6 +55,8 @@ public: * \param ptr The pointer to be displayed **/ O_Stream<T>& operator<<(void* ptr); + O_Stream<T>& operator<<(const void* ptr); + /** * \name Display a zero terminated string @@ -229,6 +231,12 @@ O_Stream<T>& O_Stream<T>::operator << (void* value) { return *this; } +template<typename T> +O_Stream<T>& O_Stream<T>::operator << (const void* value) { + return (*this) << const_cast<void*>(value); +} + + template<typename T> O_Stream<T>& O_Stream<T>::operator << (O_Stream<T>& (*stream) (O_Stream<T>&)) { return (*stream)(*this); diff --git a/arch/generic/timing-arch.cc b/arch/generic/timing-arch.cc new file mode 100644 index 0000000000000000000000000000000000000000..e7adca6b13bc2c043935b8cdd0bf457a58bf6cdb --- /dev/null +++ b/arch/generic/timing-arch.cc @@ -0,0 +1,4 @@ +extern "C" int __attribute__((weak)) arch_timing_get() { + static int time; + return ++time; +} diff --git a/arch/generic/timing-arch.h b/arch/generic/timing-arch.h new file mode 100644 index 0000000000000000000000000000000000000000..3e3311753493d832bc63b357866d8ecde51a55f8 --- /dev/null +++ b/arch/generic/timing-arch.h @@ -0,0 +1,4 @@ +#ifndef __ARCH_GENERIC_TIMING +#define __ARCH_GENERIC_TIMING + +#endif diff --git a/arch/i386/CMakeLists.txt b/arch/i386/CMakeLists.txt index 0852751e63cf5ddef83cb7e7b7ee2f312a886ab4..57535539751a1726539c7ff6244f1bc831444d40 100644 --- a/arch/i386/CMakeLists.txt +++ b/arch/i386/CMakeLists.txt @@ -33,7 +33,7 @@ set(SRCS mp.s constructors.cc startup.cc - startup.S + startup.S gdt.cc idt.cc idt.S @@ -47,8 +47,8 @@ set(SRCS dispatch.cc syscall.cc reschedule-ast.cc - machine.cc - memutil.cc + machine.cc + memutil.cc ) # If Paging is disabled, we do not add the paging routines @@ -105,7 +105,7 @@ macro(dosek_executable ELFFILE) add_custom_command( DEPENDS ${PRELINK} ${GENERATOR} COMMAND ${PYTHON} ${GENERATOR} - -o ${CROSS_OBJDUMP} -c ${PAGETABLES} -e ${PRELINK} + -o ${TC_TARGET_GNU_OBJDUMP} -c ${PAGETABLES} -e ${PRELINK} --config "${PROJECT_BINARY_DIR}/config.dict" COMMENT "Generating static page tables for ${ELFFILE}" OUTPUT ${PAGETABLES} @@ -113,12 +113,12 @@ macro(dosek_executable ELFFILE) # The actual executable. # If we build with an pagetable, we add it as a dependency -if(CONFIG_ARCH_MPU) - add_executable(${ELFFILE} ${ADD_EXECUTABLE_OPTIONS} ${SOURCES} ${PAGETABLES}) -else() - add_executable(${ELFFILE} ${ADD_EXECUTABLE_OPTIONS} ${SOURCES}) -endif() - target_link_libraries(${ELFFILE} ${TARGET_LIBS}) + if(CONFIG_ARCH_MPU) + add_executable(${ELFFILE} ${ADD_EXECUTABLE_OPTIONS} ${SOURCES} ${PAGETABLES}) + else() + add_executable(${ELFFILE} ${ADD_EXECUTABLE_OPTIONS} ${SOURCES}) + endif() + target_link_libraries(${ELFFILE} ${TARGET_LIBS}) # set definitions if(DOSEK_EXECUTABLE_DEFINITIONS) @@ -133,15 +133,9 @@ endif() set(LINKER_SCRIPT ${CMAKE_CURRENT_BINARY_DIR}/${ELFNAME}_linker.ld) endif() set_target_properties(${ELFFILE} ${PRELINK} PROPERTIES - LINK_FLAGS "-lgcc -Wl,-T ${LINKER_SCRIPT} ${ISA_LD_FLAGS} --linker-prefix=${CMAKE_CURRENT_BINARY_DIR}/${ELFFILE}" + LINK_FLAGS "-lgcc -Wl,-T ${LINKER_SCRIPT} ${TC_TARGET_LDFLAGS} --linker-prefix=${CMAKE_CURRENT_BINARY_DIR}/${ELFFILE}" LINK_DEPENDS ${LINKER_SCRIPT}) - # we use our own linker (python) script, that calls llvm-link, llc and the system linker - # setting CMAKE_*_LINK_EXECUTABLE at this point in the CMake run seems a bit unusual, but works as intended - set(LINK_EXECUTABLE "${PROJECT_SOURCE_DIR}/toolchain/llvm-link.py --clang ${CMAKE_C_COMPILER} --march x86 --mcpu ${CMAKE_C_ARCH} -mattr=+popcnt --llvm-dir ${CCDIR} --ar ${CMAKE_AR} <LINK_FLAGS> <OBJECTS> <LINK_LIBRARIES> -o <TARGET>") - set(CMAKE_C_LINK_EXECUTABLE "${LINK_EXECUTABLE} <CMAKE_C_LINK_FLAGS>") - set(CMAKE_CXX_LINK_EXECUTABLE "${LINK_EXECUTABLE} <CMAKE_CXX_LINK_FLAGS>") - # add to executables list set(EXECUTABLES ${EXECUTABLES} ${ELFFILE} CACHE INTERNAL STRING) endmacro() @@ -152,4 +146,3 @@ macro(dosek_add_test FN) set_tests_properties(${FN} PROPERTIES PASS_REGULAR_EXPRESSION "SUCCESS.+ALL OK" FAIL_REGULAR_EXPRESSION "FAIL" TIMEOUT 20) add_dependencies( tests ${FN} ) endmacro() - diff --git a/arch/i386/dispatch.cc b/arch/i386/dispatch.cc index 158e4dbb942bcaa0001b1f88b2ad8b4787ab1a6f..a788132528aa7145e28ceb6beb4a3e0c41dbd1c5 100644 --- a/arch/i386/dispatch.cc +++ b/arch/i386/dispatch.cc @@ -36,7 +36,7 @@ volatile bool not_first_dispatch; * This interrupt is called after the next task is determined by the scheduler in ring 3 * and performs the actual dispatching in ring 0. */ -IRQ_HANDLER(IRQ_DISPATCH) { +ISR(IRQ_DISPATCH) { #ifdef CONFIG_DEPENDABILITY_ENCODED // decode task ID uint16_t id = dispatch_task.decode(); diff --git a/arch/i386/idt.cc b/arch/i386/idt.cc index e5ac94f843d524123b6f8f56dd2cb7f5a3153475..9c86309f3880ff19eccf6749d472da96b8fa5c06 100644 --- a/arch/i386/idt.cc +++ b/arch/i386/idt.cc @@ -25,7 +25,6 @@ ISR(unhandled) { // send end-of-interrupt (unless exception) if(intno > 31) LAPIC::send_eoi(); - CALL_HOOK(FaultDetectedHook, TRAPdetected, intno, cpu->eip); // print and halt when debugging uint32_t ip = cpu->eip; @@ -35,16 +34,16 @@ ISR(unhandled) { kout << hex << ip; kout << endl; + CALL_HOOK(FaultDetectedHook, TRAPdetected, intno, cpu->eip); + Machine::halt(); } // NMI error handler -IRQ_HANDLER(2) { +ISR(2) { CALL_HOOK(FaultDetectedHook, TRAPdetected, 0, 0); - // TODO: anything useful left to do? - debug << "PANIC" << endl; Machine::halt(); } diff --git a/arch/i386/lapic.cc b/arch/i386/lapic.cc index 44b8c7b024c9fd5fa5182c5e9b21a09c25588f34..fc10a1ed0e45fa53365ed9b5d7ed120231ec3c91 100644 --- a/arch/i386/lapic.cc +++ b/arch/i386/lapic.cc @@ -30,7 +30,7 @@ void LAPIC::init() { /** \brief Spurious interrupt handler */ -IRQ_HANDLER(255) { +ISR(255) { // count spurious interrupt spurious_interrupts++; diff --git a/arch/i386/machine.cc b/arch/i386/machine.cc index 2ab245f6e321217512473b0d00433ac1ed66465b..1f119f4fe0ceaac1ec65e1d214bb3bdd2fa78a7a 100644 --- a/arch/i386/machine.cc +++ b/arch/i386/machine.cc @@ -7,10 +7,8 @@ using namespace arch; // new syscall to trigger interrupt using local APIC // for now, any function can be called using syscall(), // so it is easy to add this for this test. -noinline void __OS_trigger_syscall() { - uint8_t irq; - asm volatile("" : "=a"(irq)); - Machine::trigger_interrupt(irq); +noinline void __OS_trigger_syscall(uint32_t irq) { + Machine::trigger_interrupt((uint8_t) irq); } void Machine::trigger_interrupt_from_user(uint8_t irq) { @@ -25,4 +23,3 @@ void Machine::trigger_interrupt_from_user(uint8_t irq) { while (x < 100) x++; } #endif - diff --git a/arch/i386/machine.h b/arch/i386/machine.h index 962c1a8af41341e0b16e5722c8d52442e9f78bf8..ab614da8d17c67d6631b38a68abc609dcea9027b 100644 --- a/arch/i386/machine.h +++ b/arch/i386/machine.h @@ -293,6 +293,6 @@ struct Machine #define __asm_label(a) #a #define _asm_label(a) __asm_label(a) -#define asm_label(label) asm volatile (".asm_label." label "_%=:" :: "m" (*(void *)0)) +#define asm_label(label) asm volatile (".L." label "_%=:" :: "m" (*(int *)0)) #endif // __MACHINE_H__ diff --git a/arch/i386/memutil.cc b/arch/i386/memutil.cc index d1f15bf701722db6b14e55e3621d1f2196de0c45..a67769b1386737c32f973ac56489d7fd034b3d88 100644 --- a/arch/i386/memutil.cc +++ b/arch/i386/memutil.cc @@ -37,3 +37,9 @@ extern "C" void memset(void *dest, int pat, size_t size) destination[i] = pattern; } } + +extern "C" int strlen(char *dst) { + int i = 0; + while (*dst) { i++; dst++; } + return i; +} diff --git a/arch/i386/output.h b/arch/i386/output.h index 68379ab256d842df0457051cc975dd39df1f7d82..f70df5255c10400ef1a229fc8a3c3eb5088733ce 100644 --- a/arch/i386/output.h +++ b/arch/i386/output.h @@ -7,7 +7,6 @@ #define __OUTPUT_H__ #include "arch/generic/ostream.h" - #ifndef FAIL #if DEBUG diff --git a/arch/i386/reschedule-ast.cc b/arch/i386/reschedule-ast.cc index a5a03e4f25f0cf032b72e7b3fae1228a9fbfcb3f..b6b5c140fa0120f233857e81deaf4c5be8765d2c 100644 --- a/arch/i386/reschedule-ast.cc +++ b/arch/i386/reschedule-ast.cc @@ -22,7 +22,7 @@ static const uint32_t iret_schedule[] = { }; #endif -IRQ_HANDLER(IRQ_RESCHEDULE) { +ISR(IRQ_RESCHEDULE) { #ifndef CONFIG_ARCH_PRIVILEGE_ISOLATION // If we have no privilege isolation, we have to switch to the os_stack asm volatile ("mov %0, %%esp;" :: "i"(&(_estack_os) - 2048)); diff --git a/arch/i386/serial.cc b/arch/i386/serial.cc index 09ab3815aa197ff672e131f946ca1a4f2f2e3349..878f23bb44a957ce18a85faa1e9c3d5932151fb1 100644 --- a/arch/i386/serial.cc +++ b/arch/i386/serial.cc @@ -18,10 +18,10 @@ Serial::Serial(ports port) : PORT((uint16_t) port) { void Serial::putchar(char character) { // wait while transmit not empty - bool empty; + bool empty; int i = 10000; do { empty = (inb(PORT + 5) & 0x20); - } while(!empty); + } while(!empty && --i > 0) ; outb(PORT, character); } diff --git a/arch/i386/syscall.cc b/arch/i386/syscall.cc index 2717a258f9e14cc15a76bb048df369db05574d06..1bb030152449283e4e835eb0f107885590391083 100644 --- a/arch/i386/syscall.cc +++ b/arch/i386/syscall.cc @@ -78,45 +78,49 @@ extern "C" void sysenter_syscall() { } -/** \brief Syscall interrupt handler. This handler is used for direct - syscalls that do not run in userspace, but in kernelmode */ -IRQ_HANDLER(IRQ_SYSCALL) { - // get arguments from registers - // also, store pointer to context in %esi before we change %esp - void* fun; - uint32_t arg1, arg2, arg3; - asm volatile("" : "=a"(arg1), "=b"(arg2), "=S"(arg3), "=d"(fun)); - // block ISR2s by raising APIC task priority - LAPIC::set_task_prio(128); + extern "C" void irq_syscall_handler(void * fun, uint32_t arg1) { + // block ISR2s by raising APIC task priority + LAPIC::set_task_prio(128); - // reenable ISR1s - Machine::enable_interrupts(); + // reenable ISR1s + Machine::enable_interrupts(); #ifdef CONFIG_ARCH_MPU - // save page directory - uint32_t pd; - asm volatile("mov %%cr3, %0" : "=D"(pd)); + // save page directory + uint32_t pd; + asm volatile("mov %%cr3, %0" : "=D"(pd)); - // change to OS page directory - PageDirectory::enable(pagedir_os); + // change to OS page directory + PageDirectory::enable(pagedir_os); #endif - // call syscall function with arguments - asm volatile("call *%0" :: "r"(fun), "a"(arg1), "b"(arg2), "S"(arg3)); + // call syscall function with arguments + ((void (*)(uint32_t))fun)(arg1); #ifdef CONFIG_ARCH_MPU - // restore page directory - asm volatile("mov %0, %%cr3" :: "D"(pd)); + // restore page directory + PageDirectory::enable(pd); #endif - // reenable ISR2s by resetting APIC task priority - Machine::disable_interrupts(); - LAPIC::set_task_prio(0); + // reenable ISR2s by resetting APIC task priority + Machine::disable_interrupts(); + LAPIC::set_task_prio(0); + +} - // return from interrupt and proceed with caller in ring 3 - Machine::return_from_interrupt(); +/** \brief Syscall interrupt handler. This handler is used for direct + syscalls that do not run in userspace, but in kernelmode */ +IRQ_HANDLER(IRQ_SYSCALL) { + asm volatile( + "push %eax;" + "push %edx;" + "call irq_syscall_handler;" + "pop %eax;" + "pop %edx;" + "iret;" + ); } diff --git a/arch/patmos/CMakeLists.txt b/arch/patmos/CMakeLists.txt new file mode 100644 index 0000000000000000000000000000000000000000..8a81981d06d3f035f30b4d7d9435d98247626caa --- /dev/null +++ b/arch/patmos/CMakeLists.txt @@ -0,0 +1,110 @@ +# -1: synchroneous interrupts with executed instructions + +SET(PASIM_FREQ -1 CACHE INTERNAL STRING) + +set(SRCS + crt0.c + crtbegin.c + dispatch.cc + startup.cc + output.cc + tcb.cc + irq.cc + typecheck.cc + crtend.c + timing-arch.cc +) + +# Create arch library +add_library(arch ${SRCS}) +target_link_libraries(arch generic) + +# Add to include directories +dosek_include_dir(${CMAKE_CURRENT_SOURCE_DIR}) +set(ARCH_INCLUDE_DIRS ${ARCH_INCLUDE_DIRS} ${CMAKE_CURRENT_SOURCE_DIR} CACHE INTERNAL STRING) + +# Get pasim binary +find_program(PASIM "pasim") +if(NOT PASIM) + message(WARNING "[${PROJECT_NAME} No PASIM found, not generating PASIM targets!") + return() +endif() + +# POSIX dOSEK executable macro +macro(dosek_executable ELFFILE) + set(options "EXCLUDE_FROM_ALL") + set(oneValueArgs "LINKER_SCRIPT") + set(multiValuedParameters DEFINITIONS LIBS SOURCES) + cmake_parse_arguments(DOSEK_EXECUTABLE "${options}" "${oneValueArgs}" "${multiValuedParameters}" ${ARGN} ) + + set(SOURCES ${DOSEK_EXECUTABLE_SOURCES} ${DOSEK_EXECUTABLE_UNPARSED_ARGUMENTS}) + set(DEFINITIONS ${DOSEK_EXECUTABLE_DEFINITIONS}) + set(ADD_EXECUTABLE_OPTIONS "") + if(${DOSEK_EXECUTABLE_EXCLUDE_FROM_ALL} STREQUAL "TRUE") + set(ADD_EXECUTABLE_OPTIONS "EXCLUDE_FROM_ALL") + endif() + + get_filename_component(ELFNAME ${ELFFILE} NAME_WE) + + # libraries to link with application + set(TARGET_LIBS os arch ${DOSEK_EXECUTABLE_LIBS}) + + # The actual executable + add_executable(${ELFFILE} ${ADD_EXECUTABLE_OPTIONS} ${SOURCES}) + target_link_libraries(${ELFFILE} ${TARGET_LIBS}) + + # set definitions + if(DOSEK_EXECUTABLE_DEFINITIONS) + set_target_properties(${ELFFILE} PROPERTIES COMPILE_DEFINITIONS ${DOSEK_EXECUTABLE_DEFINITIONS}) + endif() + + SET(SYSTEM_PML_wo_symbols "${CMAKE_CURRENT_BINARY_DIR}/${ELFFILE}/system.pml") + SET(SYSTEM_PML "${PROJECT_BINARY_DIR}/${ELFFILE}-system.pml") + set_target_properties(${ELFFILE} PROPERTIES + LINK_FLAGS "--linker-prefix=${CMAKE_CURRENT_BINARY_DIR}/${ELFFILE} -mserialize=${SYSTEM_PML_wo_symbols} -mserialize-all") + + # Extract Symbols from binary into system.pml + add_custom_command(TARGET ${ELFFILE} POST_BUILD + COMMENT "[${ELFFILE}] Extracting symbols into system.pml" + OUTPUTS ${SYSTEM_PML} + COMMAND ${TC_TARGET_PLATIN} extract-symbols -i ${SYSTEM_PML_wo_symbols} -o ${SYSTEM_PML} + --objdump-command ${TC_TARGET_LLVM_OBJDUMP} + ${PROJECT_BINARY_DIR}/${ELFFILE} + ) + + if(CONFIG_TIMING_GENERATE_PML) + # Copy the gcfg.pml to the main directory + SET(GCFG_PML "${PROJECT_BINARY_DIR}/${ELFFILE}-gcfg.pml") + + add_custom_command(TARGET ${ELFFILE} POST_BUILD + OUTPUTS ${GCFG_PML} + COMMAND cp ${CMAKE_CURRENT_BINARY_DIR}/${ELFFILE}/gcfg.pml ${PROJECT_BINARY_DIR}/${ELFFILE}-gcfg.pml + ) + + # target to run the static analysis with platin + add_custom_target(wcet-${ELFFILE} + COMMENT "Timing Analysis for ${ELFFILE}" + DEPENDS ${ELFFILE} + COMMAND ${TC_TARGET_PLATIN} wcet -i ${SYSTEM_PML} -i ${GCFG_PML} --binary ${ELFFILE} + --wca-count-instructions --disable-ait --wca-detect-gurobi + --dref-stats ${PROJECT_BINARY_DIR}/${ELFFILE}.`printenv CIRCUIT`.dref + -e GCFG:timing-`printenv CIRCUIT`) + + # target to run a simulation with pasim + add_custom_target(test-${ELFFILE} + DEPENDS ${ELFFILE} + COMMENT "[${PROJECT_NAME}] Running ${ELFFILE} in pasim." + COMMAND ${PASIM} $<TARGET_FILE:${ELFFILE}> --freq ${PASIM_FREQ}) + + endif() + + # add to executables list + set(EXECUTABLES ${EXECUTABLES} ${ELFFILE} CACHE INTERNAL STRING) +endmacro() + +macro(dosek_add_test FN) + add_test( ${FN} + pasim --freq ${PASIM_FREQ} ${PROJECT_BINARY_DIR}/${FN}) + set_tests_properties(${FN} PROPERTIES PASS_REGULAR_EXPRESSION "SUCCESS.+ALL OK" FAIL_REGULAR_EXPRESSION "FAIL" TIMEOUT 10) + add_dependencies( tests ${FN} ) +endmacro() diff --git a/arch/patmos/crt0.c b/arch/patmos/crt0.c new file mode 100644 index 0000000000000000000000000000000000000000..c68bdd1e3d965a76de604855f5e0e938a9d2a3af --- /dev/null +++ b/arch/patmos/crt0.c @@ -0,0 +1,201 @@ +// Copyright 2012 Florian Brandner +// +// This file is part of the newlib C library for the Patmos processor. +// +// This file is free software: you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This code is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public License +// (COPYING3.LIB). If not, see <http://www.gnu.org/licenses/>. + +#include "patmos-cpu.h" + +//****************************************************************************** +/// start and end of BSS section +extern int __bss_start, _end; + +/// top of stack cache and shadow stack +extern int _shadow_stack_base, _stack_cache_base; + +//****************************************************************************** +typedef void (*funptr_t)(void); + +/// init - initializer, used to call static constructors. +extern funptr_t __init_array_begin[0]; +extern funptr_t __init_array_end[0]; +void __init(void) __attribute__((noinline)); + +/// fini - finalizer, used to call static destructors. +extern funptr_t __fini_array_begin[0]; +extern funptr_t __fini_array_end[0]; +void __fini(void) __attribute__((noinline)); + +//****************************************************************************** + +/// main - main function. +/// Note: LLVM currently silently ignores attributes for extern functions! +extern int main(int argc, char **argv) __attribute__((noinline)); + +/// memset - set memory content. +void *memset(void *s, int c, unsigned long n); + +/// atexit - register call backs on program termination. +extern int atexit(void (*function)(void)); + +/// exit - terminate program. +extern void exit(int status) __attribute__((noinline)); + +//****************************************************************************** +/// __env - values of environment vairables. +char *__env[1] = {0}; + +/// environ - values of environment vairables. +char **environ = __env; + +/// MAX_CORES - the maximum number of cores +#define MAX_CORES 64 +/// _loader_baseaddr - the base address of the loading function (one per core) +unsigned _loader_baseaddr[MAX_CORES]; +/// _loader_off - the offset of the loading function (one per core) +unsigned _loader_off[MAX_CORES]; + + +// Forward declaration of __start for _start. +void __start(); + +//****************************************************************************** +/// _start - main entry function to all patmos executables. +/// Setup the stack frame and invoke __start. +void _start() __attribute__((naked,used)); +void _start() +{ + // retrieve the id of the current core + const int id = *((_iodev_ptr_t)(__PATMOS_CPUINFO_COREID)); + + // --------------------------------------------------------------------------- + // store return information of caller + asm volatile ("mfs $r29 = $srb;" + "swm [%0] = $r29;" + "mfs $r29 = $sro;" + "swm [%1] = $r29;" + : : "r" (&_loader_baseaddr[id]), "r" (&_loader_off[id])); + + // --------------------------------------------------------------------------- + // setup stack frame and stack cache. + + // compute effective stack addresses (needed for CMPs) + int stack_size = + (unsigned)&_stack_cache_base - (unsigned)&_shadow_stack_base; + + // make sure to have a positive stack size + // workaround for -O0: avoid branch, perform abs(stack_size) via bit twiddling + int const mask = stack_size >> (sizeof(int) * 8 - 1); + stack_size = (stack_size + mask) ^ mask; + + const unsigned shadow_stack_base = + (unsigned)&_shadow_stack_base - 2*stack_size*id; + const unsigned stack_cache_base = + (unsigned)&_stack_cache_base - 2*stack_size*id; + + // --------------------------------------------------------------------------- + // setup stack frame and stack cache. + asm volatile ("mov $r31 = %0;" // initialize shadow stack pointer" + "mts $ss = %1;" // initialize the stack cache's spill pointer" + "mts $st = %1;" // initialize the stack cache's top pointer" + : : "r" (shadow_stack_base), "r" (stack_cache_base)); + + // --------------------------------------------------------------------------- + // continue in __start + + // We use asm here to prevent LLVM from messing with the stack. + // Calling (or actually any kind of more complex C code) is not supported by + // the compiler, since it does not manage the stack in naked functions. If it + // spills registers at -O0, this can lead to stack corruption. + // It would work in this case since it is a non-returning tail call without + // arguments, but we should rather be defensive in system code. + // If LLVM would inline the call, we could get code requiring spills into this + // function (but the noinline attribute prevents this anyway). + // If we need to analyse this code, we can easily extend the compiler and + // platin to support inline asm (and we should, anyway!). + asm volatile ("call %0;" // resume in the no-return __start function + "nop ;" + "nop ;" + "nop ;" // no need for a 'ret' + : : "r" (&__start)); +} + +/// __start - Main driver for program setup and execution. +/// Initialize data structures, invoke main, et cetera. +/// TODO needs a better name to make it more distinguishable from _start. +void __start() __attribute__((noinline)); +void __start() +{ + // --------------------------------------------------------------------------- + // call initializers + __init(); + + // --------------------------------------------------------------------------- + // invoke main -- without command line options + + // LLVM does not attach function attributes to declarations, we cannot mark + // main as noinline in this file. + // Thus, we again use inline asm here for the call, but this time to prevent + // inlining *of main* to avoid breaking evaluation and debugging scripts. + // We also keep the call to exit while we are at it, to make debugging traces + // easier. + asm volatile ("call %0;" // invoke main function + "li $r3 = 0;" // argc + "li $r4 = 0;" // argv + "nop ;" + "call %1;" // terminate program and invoke exit + "mov $r3 = $r1;" // get exit code (in delay slot) + "nop ;" + "nop ;" + : : "r" (&main), "r" (&exit) + : "$r1", "$r2", "$r3", "$r4", "$r5", "$r6", "$r7", "$r8", + "$r9", "$r10", "$r11", "$r12", "$r13", "$r14", "$r15", "$r16", + "$r17", "$r18", "$r19", "$r20"); + + // --------------------------------------------------------------------------- + // in case this returns + while(1) /* do nothing */; +} + +/// init - initializer, used to call static constructors. +void __init(void) { + for (funptr_t *i = __init_array_begin; i < __init_array_end; i++) { + (*i)(); + } +} + +/// fini - finalizer, used to call static destructors. +void __fini(void) { + for (funptr_t *i = __fini_array_end-1; i >= __fini_array_begin; --i) { + (*i)(); + } +} + + + +void exit(int status) +{ + // retrieve the id of the current core + const int id = *((_iodev_ptr_t)(__PATMOS_CPUINFO_COREID)); + + // return to loader; halts if baseaddr and off are 0 + asm volatile ("mts $srb = %0;" + "mts $sro = %1;" + "mov $r1 = %2;" // store exit code + "ret;" + "nop;" + "nop;" + "nop;" + : : "r" (_loader_baseaddr[id]), "r" (_loader_off[id]), "r" (status)); +} diff --git a/arch/patmos/crtbegin.c b/arch/patmos/crtbegin.c new file mode 100644 index 0000000000000000000000000000000000000000..ff778fb7da5bf58d68899f3e1350c7e8f74df6e3 --- /dev/null +++ b/arch/patmos/crtbegin.c @@ -0,0 +1,5 @@ +typedef void (*funptr_t)(void); +// Use a fake constructor/destructor "priority" to make the symbols +// end up in the right place. +funptr_t __init_array_begin[0] __attribute__((section(".init_array.0"), used)) = { }; +funptr_t __fini_array_begin[0] __attribute__((section(".fini_array.0"), used)) = { }; diff --git a/arch/patmos/crtend.c b/arch/patmos/crtend.c new file mode 100644 index 0000000000000000000000000000000000000000..7635cdedf77136ab4696de6caf56065e9a66bba6 --- /dev/null +++ b/arch/patmos/crtend.c @@ -0,0 +1,3 @@ +typedef void (*funptr_t)(void); +funptr_t __init_array_end[0] __attribute__((section(".init_array"), used)) = { }; +funptr_t __fini_array_end[0] __attribute__((section(".fini_array"), used)) = { }; diff --git a/arch/patmos/dispatch.cc b/arch/patmos/dispatch.cc new file mode 100644 index 0000000000000000000000000000000000000000..bd50588460607a25206a2f6bd0d516cc8510b6b8 --- /dev/null +++ b/arch/patmos/dispatch.cc @@ -0,0 +1,25 @@ +#include "dispatch.h" + + +extern "C" noinline void idle_loop(void) { + CALL_HOOK(PreIdleHook); +idle_loop_again: + Machine::sleep(); + goto idle_loop_again; +} + + +namespace arch { + +/* The IDLE Thread */ +static char __attribute__((aligned(4096))) idlestack[IDLESTACKSIZE]; +static char __attribute__((aligned(4096))) idlestack_shadow[IDLESTACKSIZE]; +static context_t idle_context; +TCB Dispatcher::m_idle(idle_loop, + idlestack, IDLESTACKSIZE, + idlestack_shadow, 4096, + &idle_context); +const TCB* Dispatcher::m_current = 0; + + +}; diff --git a/arch/patmos/dispatch.h b/arch/patmos/dispatch.h new file mode 100644 index 0000000000000000000000000000000000000000..1af534bfb7c9e3457e3ff6e19fc220bca9fa506a --- /dev/null +++ b/arch/patmos/dispatch.h @@ -0,0 +1,91 @@ +#ifndef __DISPATCH_H__ +#define __DISPATCH_H__ + +#include "os/util/inline.h" +#include "os/scheduler/task.h" + +#include "output.h" +#include "tcb.h" +#include "os/hooks.h" + +namespace arch { + +static const int IDLESTACKSIZE = 4096; + +class Dispatcher { + static const TCB* m_current; + static TCB m_idle; + + + static forceinline void doDispatch(const TCB *from, const TCB *to) { + // update current context + m_current = to; + + + /* If we do not reset the idle loop, when leaving it the + PreIdleHook is not called correctly on the next dispatch + to idle */ + if (from != &m_idle && to == &m_idle ) { + m_idle.reset(); + } + if (from && !from->is_running()) { + from = 0; + } + + CALL_HOOK(PreTaskHook); + + TCB::context_switch(from, to); + } + +public: + + static void init(void) { + // setup idle context + m_idle.reset(); + } + + + static forceinline void Idle(void) { + doDispatch(m_current, &m_idle); + } + + static forceinline void Prepare(const os::scheduler::Task& task) { + task.tcb.reset(); + } + + + static forceinline void Destroy(const os::scheduler::Task& task) { + task.tcb.reset(); + } + + static forceinline void Dispatch(const os::scheduler::Task &next, + const os::scheduler::Task *current = 0) { + // Do not resume yourself... + const TCB *cur = current ? ¤t->tcb : m_current; + if(cur == &next.tcb) { + // kout << "Dispatch to ID " << (int)next.id << " via return" << endl; + return; + } + + // kout << "Dispatch to ID: " << (int)next.id << " " << ((void *)&next.tcb) << endl; + // kout << "ptr=" << (void*)next.tcb.dynamic_context->s7 << endl; + + doDispatch(cur, &next.tcb); + } + + static forceinline void ResumeToTask(const os::scheduler::Task &next, + const os::scheduler::Task *current = 0) { + Dispatch(next, current); + } + + static forceinline void StartToTask(const os::scheduler::Task next, + const os::scheduler::Task *current = 0) { + Dispatch(next, current); + } + +}; + +} // namespace arch + + +#endif // __DISPATCH_H__ diff --git a/arch/patmos/irq-dispatch.cc.in b/arch/patmos/irq-dispatch.cc.in new file mode 100644 index 0000000000000000000000000000000000000000..26df05d9802290ee43855714c02dbf5601ef2a65 --- /dev/null +++ b/arch/patmos/irq-dispatch.cc.in @@ -0,0 +1,26 @@ +namespace arch { + +extern "C" noinline void timer_isr(const IRQ::Context &) { + arch::IRQ::set_timer_interval(1); + os::Counter::tick(); +} + +extern "C" noinline void unexpected_interrupt(const IRQ::Context &x) { + // kout << "unexpected interrupt " << x.vector << endl; + Machine::shutdown(); +} + + +typedef void (*isr_handler_t)(const IRQ::Context &context); + +isr_handler_t isr_handlers[32] = { + {{{!isr_handler_initializer}}} +}; + +inlinehint void static_irq_dispatch(uint8_t vector) { + IRQ::Context context; + context.vector = vector; + isr_handlers[vector](context); +} + +} // arch diff --git a/arch/patmos/irq.cc b/arch/patmos/irq.cc new file mode 100644 index 0000000000000000000000000000000000000000..be84d8d2e638beca8dddb018622f6feaaafbb6e6 --- /dev/null +++ b/arch/patmos/irq.cc @@ -0,0 +1,206 @@ +#include "output.h" +#include "irq.h" +#include "patmos-cpu.h" +#include "os/counter.h" +#include "os/scheduler/scheduler.h" + +namespace arch { + +extern "C" void irq_entry(void); +void guardian(void); +inlinehint extern void static_irq_dispatch(uint8_t source); + +static int ast_level; +static bool ast_requested; + +void IRQ::init() { + int i; + // only install handlers if in privileged mode + if (*((_iodev_ptr_t)(__PATMOS_EXCUNIT_STATUS)) & 0x2) { + for (i = 0; i < 32; i++) { + *((_IODEV exc_handler_t *)(__PATMOS_EXCUNIT_VEC + 4*i)) = &irq_entry; + } + } + + // Unmask all interrupts + EXC_MASK = ~0; +} + +bool IRQ::in_interrupt() { + return ast_level > 0; +} + +void IRQ::request_ast() { + ast_requested = true; +} + + +void IRQ::set_timer_interval(int ms) { + // Get current time + unsigned int u; + unsigned int l; + + __PATMOS_RTC_RD_TIME_LOW(l); + __PATMOS_RTC_RD_TIME_UP(u); + + uint64_t time_cur = (((uint64_t)u) << 32) | l; + + // Time til next interrupt + uint64_t time_inter = 100000; + + uint64_t time_new = time_cur + time_inter; + + __PATMOS_RTC_WR_INTERVAL_TIME_LOW((unsigned)(time_new)); + __PATMOS_RTC_WR_INTERVAL_TIME_UP((unsigned)(time_new >> 32)); +} + + +__attribute__((naked)) void irq_entry() { + asm volatile( + // Reset r0 to 0 + "and $r0 = $r0, 0x0;" + // Make enough room for callee save registers + "sub $r31 = $r31, (37 * 4);" + "swm [$r31 + 0] = $r1;" + "swm [$r31 + 1] = $r2;" + "swm [$r31 + 2] = $r3;" + "swm [$r31 + 3] = $r4;" + "swm [$r31 + 4] = $r5;" + "swm [$r31 + 5] = $r6;" + "swm [$r31 + 6] = $r7;" + "swm [$r31 + 7] = $r8;" + "swm [$r31 + 8] = $r9;" + "swm [$r31 + 9] = $r10;" + "swm [$r31 + 10] = $r11;" + "swm [$r31 + 11] = $r12;" + "swm [$r31 + 12] = $r13;" + "swm [$r31 + 13] = $r14;" + "swm [$r31 + 14] = $r15;" + "swm [$r31 + 15] = $r16;" + "swm [$r31 + 16] = $r17;" + "swm [$r31 + 17] = $r18;" + "swm [$r31 + 18] = $r19;" + "swm [$r31 + 19] = $r20;" + "swm [$r31 + 36] = $r29;" + // Spill Cached stack + "mfs $r5 = $ss;" + "mfs $r6 = $st;" + "sub $r2 = $r5, $r6;" + "sspill $r2;" + "swm [$r31 + 20] = $r2;" + + // Save Exception Status + "li $r2 = 0xF0010000;" + "lwl $r3 = [$r2 + 0];" + "nop;" + "swm [$r31 + 35] = $r3;" + // Store special purpose registers +#define STORE_SPECIAL(reg, off) \ + "mfs $r2 = $" # reg "\n\t" \ + "swm [$r31 + " # off"] = $r2\n\t" + + STORE_SPECIAL(s0, 21) + STORE_SPECIAL(s1, 22) + STORE_SPECIAL(s2, 23) + STORE_SPECIAL(s3, 24) + STORE_SPECIAL(s4, 25) + STORE_SPECIAL(s7, 26) + STORE_SPECIAL(s8, 27) + STORE_SPECIAL(s9, 28) + STORE_SPECIAL(s10, 29) + STORE_SPECIAL(s11, 30) + STORE_SPECIAL(s12, 31) + STORE_SPECIAL(s13, 32) + STORE_SPECIAL(s14, 33) + STORE_SPECIAL(s15, 34) + ); + + guardian(); + + +exit: + + asm volatile( + // Loadspecial purpose registers + ".LSPLIT_irq_entry_return:\n" +#define LOAD_SPECIAL(reg, off) \ + "lwm $r2 = [$r31 + " # off"]\n\t" \ + "nop\n\t" \ + "mts $" # reg " = $r2\n\t" \ + + LOAD_SPECIAL(s0, 21) + LOAD_SPECIAL(s1, 22) + LOAD_SPECIAL(s2, 23) + LOAD_SPECIAL(s3, 24) + LOAD_SPECIAL(s4, 25) + LOAD_SPECIAL(s7, 26) + LOAD_SPECIAL(s8, 27) + LOAD_SPECIAL(s9, 28) + LOAD_SPECIAL(s10, 29) + LOAD_SPECIAL(s11, 30) + LOAD_SPECIAL(s12, 31) + LOAD_SPECIAL(s13, 32) + LOAD_SPECIAL(s14, 33) + LOAD_SPECIAL(s15, 34) + + // Spill Cached stack + "lwm $r2 = [$r31 + 20];" + + // Load almost all general purpose registers + "lwm $r4 = [$r31 + 3];" + "lwm $r5 = [$r31 + 4];" + "lwm $r6 = [$r31 + 5];" + "lwm $r7 = [$r31 + 6];" + "lwm $r8 = [$r31 + 7];" + "lwm $r9 = [$r31 + 8];" + "lwm $r10 = [$r31 + 9];" + "lwm $r11 = [$r31 + 10];" + "lwm $r12 = [$r31 + 11];" + "lwm $r13 = [$r31 + 12];" + "lwm $r14 = [$r31 + 13];" + "lwm $r15 = [$r31 + 14];" + "lwm $r16 = [$r31 + 15];" + "lwm $r17 = [$r31 + 16];" + "lwm $r18 = [$r31 + 17];" + "lwm $r19 = [$r31 + 18];" + "lwm $r20 = [$r31 + 19];" + "lwm $r29 = [$r31 + 36];" + "nop;" + "sens $r2;" + // Recover Exception Status + "li $r2 = 0xF0010000;" + "lwm $r3 = [$r31 + 35];" + "nop;" + "swl [$r2 + 0] = $r3;" + "lwm $r1 = [$r31 + 0];" + "lwm $r2 = [$r31 + 1];" + "lwm $r3 = [$r31 + 2];" + "add $r31 = $r31, (37 * 4);" + "xretnd;" + ); + + (void) &&exit; + + __builtin_unreachable(); +} + + +noinline void guardian(void) { + unsigned source = *((_iodev_ptr_t)(__PATMOS_EXCUNIT_SRC)); + unsigned base, off; + /* asm volatile("mfs %0 = $sxb;" + "mfs %1 = $sxo;" + : "=r" (base), "=r" (off)); */ + ast_level++; + static_irq_dispatch(source); + ast_level--; + + if (ast_level == 0 && ast_requested) { + ast_requested = false; + __OS_ASTSchedule(0); + } +} + + + +} // arch diff --git a/arch/patmos/irq.h b/arch/patmos/irq.h new file mode 100644 index 0000000000000000000000000000000000000000..6ed9e185e1a5f1b69795a041566a001b410f471d --- /dev/null +++ b/arch/patmos/irq.h @@ -0,0 +1,24 @@ +#ifndef __PATMOS_IRQ_H +#define __PATMOS_IRQ_H + +namespace arch { + +struct IRQ { + static void init(); + static void set_timer_interval(int ms); + static void request_ast(); + static bool in_interrupt(); + + enum { + ISR_TIMER = 17, + }; + + struct Context { + int vector; + }; +}; + +}; +extern "C" void timing_dump_trap(const arch::IRQ::Context &x); + +#endif diff --git a/arch/patmos/machine.h b/arch/patmos/machine.h new file mode 100644 index 0000000000000000000000000000000000000000..1d760521ed3f7887cf3533ddf7dadec916fd7dbf --- /dev/null +++ b/arch/patmos/machine.h @@ -0,0 +1,115 @@ +#ifndef __MACHINE_H__ +#define __MACHINE_H__ + +#include "stdint.h" +#include "os/util/inline.h" +#include "patmos-cpu.h" +#include "output.h" + + +/** + * \brief Machine dependent special instructions. + * This struct provides static forceinline methods implementing some machine + * specific instructions. + */ +extern "C" void exit(int); + +class Machine +{ +public: + + static void init(void) { + } + + /** + * \brief Emits a nop opcode. (nop) + */ + static forceinline void nop(void) { + asm volatile ("nop"); + }; + + /** + * \brief Halts the machine. (hlt) + */ + static forceinline void halt(void) { + exit(2); + } + + static forceinline void sleep(void) { + EXC_SLEEP = 1; + } + + static forceinline void debug_trap(void) { + unreachable(); + } + + /** + * \brief Disable all interrupts + */ + static noinline void disable_interrupts() { + EXC_STATUS &= ~1; + } + + /** + * \brief Enable all interrupts + */ + static noinline void enable_interrupts() { + EXC_STATUS |= 1; + } + + /** + * \brief Return if interrupts are enabled + */ + static forceinline bool interrupts_enabled(void) { + return EXC_STATUS & 1; + } + + /** + * \brief Unreachable code + * Will trigger interrupt if this is actually executed. + */ + static forceinline void unreachable(void) { + __builtin_unreachable(); // allow compiler optimization + } + + + /** + * \brief Shutdown machine using ACPI + * The static ACPI values used work for QEMU and Bochs but probably not on real PCs! + */ + static forceinline void shutdown(void) { + debug << "Machine::shutdown!\n"; + // No unreachable() here, otherwise the generator will be unhappy! + + // The call to exit is required, because there might be a ressources + // (like threads) that must be cleaned up and will not be stopped by + // just using the SYS_exit syscall. The inline assembler is used to + // hide it from the generator. + exit(0); + } + + /** + * \brief Trigger an interrupt + */ + static constexpr forceinline uint8_t encode_interrupt(uint8_t irq) { + // If you change this, you have to change the patmos generator + return (irq % 16) + 16; + } + + static forceinline void trigger_interrupt(uint8_t irq) { + EXC_PEND |= 1 << encode_interrupt(irq); + nop(); nop(); nop(); + nop(); nop(); nop(); + } + static forceinline void trigger_interrupt_from_user(uint8_t irq) { + trigger_interrupt(irq); + } +}; + +#define __asm_label(a) #a +#define _asm_label(a) __asm_label(a) +// #define asm_label(label) asm volatile (".asm_label." label "_%=:" :: "m" (*(void *)0)) +#define asm_label(label) + + +#endif // __MACHINE_H__ diff --git a/arch/patmos/output.cc b/arch/patmos/output.cc new file mode 100644 index 0000000000000000000000000000000000000000..6c52b214c028d63ecada4c52ba8ea00b2c2c4aec --- /dev/null +++ b/arch/patmos/output.cc @@ -0,0 +1,18 @@ +/** + * @file + * @ingroup posix + * @brief Default output streams + */ + +#include "output.h" + +#if DEBUG + +Terminal kout, debug; + +#else // DEBUG + +Terminal kout; +Null_Stream debug; + +#endif // DEBUG diff --git a/arch/patmos/output.h b/arch/patmos/output.h new file mode 100644 index 0000000000000000000000000000000000000000..4a999e1e4f1b5d88c24eb1ae58fd81b3fcc4cd9d --- /dev/null +++ b/arch/patmos/output.h @@ -0,0 +1,24 @@ +/** + * @file + * @ingroup posix + * @brief Default output streams + */ +#ifndef __OUTPUT_H__ +#define __OUTPUT_H__ + +#include "terminal.h" + +#if DEBUG + +// debugging: print kout+debug on stdout/stderr +extern Terminal kout; +extern Terminal debug; + +#else // DEBUG + +extern Terminal kout; +extern Null_Stream debug; + +#endif // DEBUG + +#endif // __OUTPUT_H__ diff --git a/arch/patmos/patmos-cpu.h b/arch/patmos/patmos-cpu.h new file mode 100644 index 0000000000000000000000000000000000000000..b26da0acd90b4dde3aecdf1cc2432f640bc93b8a --- /dev/null +++ b/arch/patmos/patmos-cpu.h @@ -0,0 +1,158 @@ +// Copyright 2012 Florian Brandner +// +// This file is part of the newlib C library for the Patmos processor. +// +// This file is free software: you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This code is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public License +// (COPYING3.LIB). If not, see <http://www.gnu.org/licenses/>. +// +// Some Patmos specific defines (e.g., concerning the UART coming with Patmos). + +#ifndef __PATMOS__H +#define __PATMOS__H + +#define _IODEV __attribute__((address_space(1))) + +typedef _IODEV unsigned int volatile * const _iodev_ptr_t; + +/// The base address of the cpuinfo device +#define __PATMOS_CPUINFO_BASE 0xF0000000 +#define __PATMOS_CPUINFO_COREID (__PATMOS_CPUINFO_BASE + 0x00) + +/// The base address of the performance-counters device +#define __PATMOS_PERF_BASE (__PATMOS_CPUINFO_BASE + 0x30000) + +/// The base address of the exception unit +#define __PATMOS_EXCUNIT_BASE 0xF0010000 +#define __PATMOS_EXCUNIT_STATUS (__PATMOS_EXCUNIT_BASE + 0x00) +#define __PATMOS_EXCUNIT_SRC (__PATMOS_EXCUNIT_BASE + 0x0c) +#define __PATMOS_EXCUNIT_VEC (__PATMOS_EXCUNIT_BASE + 0x80) + +/// The exception handler type. +typedef void (*exc_handler_t)(void); + +/// The base address of the timer device +#define __PATMOS_TIMER_BASE 0xF0020000 + +/// The address of the UART device +#define __PATMOS_UART_BASE 0xF0080000 + +/// Bit mask for the transmit-ready bit (TRE) +#define __PATMOS_UART_TRE 1 + +/// Bit mask for the data-available bit (DAV) +#define __PATMOS_UART_DAV 2 + +/// Bit mask for the parity-error bit (PAE) +#define __PATMOS_UART_PAE 4 + +/// Address to access the status register of the UART coming with Patmos +#define __PATMOS_UART_STATUS_ADDR (__PATMOS_UART_BASE+0x0) + +/// Address to access the data register of the UART coming with Patmos +#define __PATMOS_UART_DATA_ADDR (__PATMOS_UART_BASE+0x04) + +/// Macro to read the UART's status register +#define __PATMOS_UART_STATUS(res) res = *((_iodev_ptr_t)__PATMOS_UART_STATUS_ADDR); + +/// Macro to read the UART's data register +#define __PATMOS_UART_RD_DATA(res) res = *((_iodev_ptr_t)__PATMOS_UART_DATA_ADDR); + +/// Macro to write the UART's control register +#define __PATMOS_UART_WR_CTRL(data) *((_iodev_ptr_t)__PATMOS_UART_STATUS_ADDR) = data; + +/// Macro to write the UART's data register +#define __PATMOS_UART_WR_DATA(data) *((_iodev_ptr_t)__PATMOS_UART_DATA_ADDR) = data; + +/* +* Exception Management +*/ + +/* The status register of the exception unit */ +#define EXC_STATUS (*((_iodev_ptr_t)(__PATMOS_EXCUNIT_BASE+0x00))) + +/* The interrupt mask register */ +#define EXC_MASK (*((_iodev_ptr_t)(__PATMOS_EXCUNIT_BASE+0x04))) + +/* The pending interrupts register */ +#define EXC_PEND (*((_iodev_ptr_t)(__PATMOS_EXCUNIT_BASE+0x08))) + +/* The exception source register */ +#define EXC_SOURCE (*((_iodev_ptr_t)(__PATMOS_EXCUNIT_BASE+0x0c))) + +/* The pending interrupts register */ +#define EXC_SLEEP (*((_iodev_ptr_t)(__PATMOS_EXCUNIT_BASE+0x10))) + + +/* + * End of Exception Management + */ + +// Address to access the cycle counter low register of the RTC +#define __PATMOS_RTC_CYCLE_UP_ADDR (__PATMOS_TIMER_BASE+0x00) + +// Address to access the cycle counter up register of the RTC +#define __PATMOS_RTC_CYCLE_LOW_ADDR (__PATMOS_TIMER_BASE+0x04) + +// Address to access the time in microseconds low register of the RTC +#define __PATMOS_RTC_TIME_UP_ADDR (__PATMOS_TIMER_BASE+0x08) + +// Address to access the time in microseconds up register of the RTC +#define __PATMOS_RTC_TIME_LOW_ADDR (__PATMOS_TIMER_BASE+0x0c) + +// Address to access the interrupt interval register of the RTC +#define __PATMOS_RTC_INTERVAL_ADDR (__PATMOS_TIMER_BASE+0x10) + +// Address to access the ISR address register of the RTC +#define __PATMOS_RTC_ISR_ADDR (__PATMOS_TIMER_BASE+0x14) + +// Address to access the exception unit +#define __PATMOS_RTC_EXCUNIT_ADDR (&_excunit_base) + +// Macro to read the RTC's cycle counter low register of the RTC +#define __PATMOS_RTC_RD_CYCLE_LOW(res) res = *((_iodev_ptr_t)__PATMOS_RTC_CYCLE_LOW_ADDR); + +// Macro to read the RTC's cycle counter up register of the RTC +#define __PATMOS_RTC_RD_CYCLE_UP(res) res = *((_iodev_ptr_t)__PATMOS_RTC_CYCLE_UP_ADDR); + +// Macro to read the performance counter's low register +#define __PATMOS_PERF_RD(res) res = *((_iodev_ptr_t)__PATMOS_PERF_BASE); + + +// Macro to read the RTC's time in microseconds low register of the RTC +#define __PATMOS_RTC_RD_TIME_LOW(res) res = *((_iodev_ptr_t)__PATMOS_RTC_TIME_LOW_ADDR); + +// Macro to read the RTC's time in microseconds up register of the RTC +#define __PATMOS_RTC_RD_TIME_UP(res) res = *((_iodev_ptr_t)__PATMOS_RTC_TIME_UP_ADDR); + +// Macro to write the RTC's cycle counter low register +#define __PATMOS_RTC_WR_CYCLE_LOW(val) *((_iodev_ptr_t)__PATMOS_RTC_CYCLE_LOW_ADDR) = val; + +// Macro to write the RTC's cycle counter up register +#define __PATMOS_RTC_WR_CYCLE_UP(val) *((_iodev_ptr_t)__PATMOS_RTC_CYCLE_UP_ADDR) = val; + +// Macro to write the RTC's interrupt interval in microseconds low register +#define __PATMOS_RTC_WR_INTERVAL_TIME_LOW(interval) *((_iodev_ptr_t)__PATMOS_RTC_TIME_LOW_ADDR) = interval; + +// Macro to write the RTC's interrupt interval in microseconds up register +#define __PATMOS_RTC_WR_INTERVAL_TIME_UP(interval) *((_iodev_ptr_t)__PATMOS_RTC_TIME_UP_ADDR) = interval; + +// Read exception status register +#define __PATMOS_RTC_RD_EXC_STATUS(res) res = *((_iodev_ptr_t)__PATMOS_RTC_EXCUNIT_ADDR); + +// Macro to write the RTC's ISR address register +#define __PATMOS_RTC_WR_ISR(address) *((_iodev_ptr_t)__PATMOS_RTC_ISR_ADDR) = address; + + + + +#endif // __PATMOS__H diff --git a/arch/patmos/reschedule-ast.h b/arch/patmos/reschedule-ast.h new file mode 100644 index 0000000000000000000000000000000000000000..ebfd6d5d1f6028fe89ff73563a981946e05e2782 --- /dev/null +++ b/arch/patmos/reschedule-ast.h @@ -0,0 +1,16 @@ +#ifndef __RESCHEDULE_AST_H__ +#define __RESCHEDULE_AST_H__ + +#include "os/util/inline.h" +#include "irq.h" + +namespace arch { + +/** \brief Request the reschedule AST to run after all other interrupts compelete. */ + forceinline void request_reschedule_ast() { + IRQ::request_ast(); + } + +} // namespace arch + +#endif // __RESCHEDULE_AST_H__ diff --git a/arch/patmos/startup.cc b/arch/patmos/startup.cc new file mode 100644 index 0000000000000000000000000000000000000000..c19c61e3ddc00ef9fdb08d705d6231f0809b0821 --- /dev/null +++ b/arch/patmos/startup.cc @@ -0,0 +1,30 @@ +#include "dispatch.h" +#include "irq.h" + +/** Initialisation stub for generic startup code */ +extern "C" void init_generic(); + +using namespace arch; + +extern "C" __attribute__((weak)) void test_prepare() {} + +//!< i386 specific startup code +void arch_startup() +{ + IRQ::init(); + + Dispatcher::init(); + + // Proceed to generic initialisation + init_generic(); +} + +//!< PATMOS execution starts in main. +//!< Here, all constructors are already called. The actual entry is in crt0.c + +int main(int argc, char**argv){ + (void) argc; + (void) argv; + arch_startup(); + return 0; +} diff --git a/arch/patmos/stdint.h b/arch/patmos/stdint.h new file mode 100644 index 0000000000000000000000000000000000000000..3b0d9c30c47fc767a04a30f31f2649d2e1fca12f --- /dev/null +++ b/arch/patmos/stdint.h @@ -0,0 +1,24 @@ +#ifndef __TYPES_H +#define __TYPES_H + + +#define SYSTEM_BITS (32) + +typedef unsigned char uint8_t; +typedef unsigned short uint16_t; +typedef unsigned int uint32_t; +typedef unsigned long long uint64_t; +typedef unsigned long uintptr_t; + +typedef unsigned int size_t; + +typedef char int8_t; +typedef short int16_t; +typedef int int32_t; +typedef long long int64_t; +typedef long intptr_t; + +typedef signed long ptrdiff_t; + + +#endif diff --git a/arch/patmos/syscall.h b/arch/patmos/syscall.h new file mode 100644 index 0000000000000000000000000000000000000000..a75d5b762557f5d52c20020dfbf5839ad354bb55 --- /dev/null +++ b/arch/patmos/syscall.h @@ -0,0 +1,32 @@ +/** + * @file + * @ingroup posix + * @brief Posix system call interface + */ + +#ifndef __SYSCALL_H__ +#define __SYSCALL_H__ + +#include "os/util/inline.h" +#include "machine.h" +#include "output.h" +#include "irq.h" + +namespace arch { + +template<typename F, typename A=int> +forceinline void syscall(const F fun, A arg=0, __attribute__((unused)) bool direct=false) { + Machine::disable_interrupts(); + fun(arg); + Machine::enable_interrupts(); +} + + +/** \brief Return true if calling code is running as part of a syscall */ +forceinline bool in_syscall() { + return !IRQ::in_interrupt(); // When we are in an interrupt, we are +} + +} // namespace arch + +#endif // __SYSCALL_H__ diff --git a/arch/patmos/tcb.cc b/arch/patmos/tcb.cc new file mode 100644 index 0000000000000000000000000000000000000000..da7d7529a5f8767f52312b1ee3a58851252fc769 --- /dev/null +++ b/arch/patmos/tcb.cc @@ -0,0 +1,141 @@ +#include "tcb.h" + +using namespace arch; + +void arch::TCB::reset() const { + dynamic_context->is_running = false; + + // Setting base function address to return to + dynamic_context->s7 = (uint32_t)thread_entry; + dynamic_context->s8 = 0; + + + // Setting stack pointer and spill pointer + dynamic_context->sgap = 0; + dynamic_context->s6 = (uint32_t) stack_address + stack_size - 4; + dynamic_context->r31 = (uint32_t) shadow_stack_address + shadow_stack_size - 4; + +} + + +static noinline __attribute__((naked)) +void context_load(const TCB *to) { + asm volatile ( + "mfs $r12 = $s5 \n" + "mfs $r13 = $s6 \n" + "nop\n" + "sub $r12 = $r12, $r13 \n" + "sspill $r12 \n" + // Restore from here + "lwc $r20 = [%0 + 0] \n" + "lwc $r21 = [%0 + 1] \n" + "lwc $r22 = [%0 + 2] \n" + "lwc $r23 = [%0 + 3] \n" + "lwc $r24 = [%0 + 4] \n" + "lwc $r25 = [%0 + 5] \n" + "lwc $r26 = [%0 + 6] \n" + "lwc $r27 = [%0 + 7] \n" + "lwc $r28 = [%0 + 8] \n" + "lwc $r29 = [%0 + 9] \n" + "lwc $r30 = [%0 + 10] \n" + "lwc $r31 = [%0 + 11] \n" + "lwc $r9 = [%0 + 12] \n" + "lwc $r10 = [%0 + 13] \n" + "lwc $r11 = [%0 + 14] \n" + "lwc $r12 = [%0 + 15] \n" + "lwc $r13 = [%0 + 16] \n" + "lwc $r14 = [%0 + 17] \n" + "lwc $r15 = [%0 + 18] \n" + "mts $s2 = $r10 \n" + "mts $s5 = $r13 \n" + "mts $s6 = $r13 \n" + "mts $s7 = $r14 \n" + "mts $s8 = $r15 \n" + "nop\n" + "sens $r12 \n" + "mts $s3 = $r11 \n" + "mts $s0 = $r9 \n" + : : "r"(to->dynamic_context) + ); +switch_context_load: + (void) && switch_context_load; + +} + + +static noinline __attribute__((naked)) +void context_save_and_load(const TCB * from, const TCB *to) { + asm volatile ( + "swc [%0 + 0] = $r20 \n" + "swc [%0 + 1] = $r21 \n" + "swc [%0 + 2] = $r22 \n" + "swc [%0 + 3] = $r23 \n" + "swc [%0 + 4] = $r24 \n" + "swc [%0 + 5] = $r25 \n" + "swc [%0 + 6] = $r26 \n" + "swc [%0 + 7] = $r27 \n" + "swc [%0 + 8] = $r28 \n" + "swc [%0 + 9] = $r29 \n" + "swc [%0 + 10] = $r30 \n" + "swc [%0 + 11] = $r31 \n" + "mfs $r9 = $s0 \n" + "mfs $r10 = $s2 \n" + "mfs $r11 = $s3 \n" + "mfs $r12 = $s5 \n" + "mfs $r13 = $s6 \n" + "mfs $r14 = $s7 \n" + "mfs $r15 = $s8 \n" + "sub $r12 = $r12, $r13 \n" + "sspill $r12 \n" + "swc [%0 + 12] = $r9 \n" + "swc [%0 + 13] = $r10 \n" + "swc [%0 + 14] = $r11 \n" + "swc [%0 + 15] = $r12 \n" + "swc [%0 + 16] = $r13 \n" + "swc [%0 + 17] = $r14 \n" + "swc [%0 + 18] = $r15 \n" + // Restore from here + "lwc $r20 = [%1 + 0] \n" + "lwc $r21 = [%1 + 1] \n" + "lwc $r22 = [%1 + 2] \n" + "lwc $r23 = [%1 + 3] \n" + "lwc $r24 = [%1 + 4] \n" + "lwc $r25 = [%1 + 5] \n" + "lwc $r26 = [%1 + 6] \n" + "lwc $r27 = [%1 + 7] \n" + "lwc $r28 = [%1 + 8] \n" + "lwc $r29 = [%1 + 9] \n" + "lwc $r30 = [%1 + 10] \n" + "lwc $r31 = [%1 + 11] \n" + "lwc $r9 = [%1 + 12] \n" + "lwc $r10 = [%1 + 13] \n" + "lwc $r11 = [%1 + 14] \n" + "lwc $r12 = [%1 + 15] \n" + "lwc $r13 = [%1 + 16] \n" + "lwc $r14 = [%1 + 17] \n" + "lwc $r15 = [%1 + 18] \n" + "mts $s2 = $r10 \n" + "mts $s5 = $r13 \n" + "mts $s6 = $r13 \n" + "mts $s7 = $r14 \n" + "mts $s8 = $r15 \n" + "nop\n" + "sens $r12 \n" + "mts $s3 = $r11 \n" + "mts $s0 = $r9 \n" + : : "r" (from->dynamic_context), "r"(to->dynamic_context) + ); +switch_context_save_and_load: + (void) && switch_context_save_and_load; + +} + +void arch::TCB::context_switch(const TCB *from, const TCB* to) { + to->dynamic_context->is_running = true; + + if (from != 0) { + context_save_and_load(from, to); + } else { + context_load(to); + } +} diff --git a/arch/patmos/tcb.h b/arch/patmos/tcb.h new file mode 100644 index 0000000000000000000000000000000000000000..8c0b269b813551a26a3f1606f8b71d494e44a84a --- /dev/null +++ b/arch/patmos/tcb.h @@ -0,0 +1,89 @@ +#ifndef __ARCH_PATMOS_TCB +#define __ARCH_PATMOS_TCB + +#include "machine.h" +#include "os/util/assert.h" + +// extern "C" void *OS_basic_task_stackptr; +// extern "C" uint8_t shared_basic_stack[]; + +namespace arch { struct TCB; } + +namespace arch { + + typedef struct { + uint32_t r20; + uint32_t r21; + uint32_t r22; + uint32_t r23; + uint32_t r24; + uint32_t r25; + uint32_t r26; + uint32_t r27; + // Frame pointer used by compiler + uint32_t r28; + // Stack pointer used by compiler + uint32_t r29; + uint32_t r30; + uint32_t r31; + + // Predicate registers status + uint32_t s0; + uint32_t s2; + uint32_t s3; + uint32_t sgap; + // First frame spilled to main memory + uint32_t s6; + uint32_t s7; + uint32_t s8; + //uint32_t s9; + //uint32_t s10; + + + // From here our layout can vary + bool is_running; + } context_t; + + + void context_create(context_t *ctx, void * stack_addr, uint32_t stack_size, + void * shadow_stack_addr, uint32_t shadow_stack_size, + void (*entry) ()); + noinline __attribute__((naked)) void switch_to(context_t *from, context_t *to); + + + struct TCB { + typedef void (* const thread_entry_t)(void); + + thread_entry_t thread_entry; + + // Task Stack + void * const stack_address; + const uint32_t stack_size; + + // Shadow Stack + void * const shadow_stack_address; + const uint32_t shadow_stack_size; + + context_t * const dynamic_context; + + constexpr TCB(thread_entry_t f, + void * stack_address, uint32_t stack_size, + void * shadow_stack_address, uint32_t shadow_stack_size, + context_t *dynamic_context) + : thread_entry(f), + stack_address(stack_address), stack_size(stack_size), + shadow_stack_address(shadow_stack_address), shadow_stack_size(shadow_stack_size), + dynamic_context(dynamic_context) {}; + + + void reset() const; + + static void context_switch(const TCB *from, const TCB *to); + + bool is_running(void) const { + return dynamic_context->is_running; + } + }; + +}; +#endif diff --git a/arch/patmos/terminal.h b/arch/patmos/terminal.h new file mode 100644 index 0000000000000000000000000000000000000000..7b6bfd8eb469627343289969c5d35d826827ef99 --- /dev/null +++ b/arch/patmos/terminal.h @@ -0,0 +1,34 @@ +#ifndef __TERMINAL_H__ +#define __TERMINAL_H__ + +#include <stdint.h> +#include "arch/generic/ostream.h" +#include "patmos-cpu.h" + + + +typedef enum Color { + BLACK = 0, + RED = 1, + GREEN = 2, + YELLOW = 3, + BLUE = 4, + MAGENTA = 5, + CYAN = 6, + WHITE = 7, +} Color; + +class Terminal : public O_Stream<Terminal> { +public: + void putchar(char c) { + // write data to the UART. + __PATMOS_UART_WR_DATA(c); + }; + + void setcolor(Color fg, Color bg) { + (void) fg; + (void) bg; + }; +}; + +#endif // __TERMINAL_H__ diff --git a/arch/patmos/timing-arch.cc b/arch/patmos/timing-arch.cc new file mode 100644 index 0000000000000000000000000000000000000000..a76a66a680b2b234ee11bfad1f67452815ba958d --- /dev/null +++ b/arch/patmos/timing-arch.cc @@ -0,0 +1,13 @@ +#include "timing-arch.h" +#include "os/timing.h" +#include "irq.h" +#include "machine.h" + +int __attribute__((weak)) timing_print() {}; + + +void timing_dump_trap(const arch::IRQ::Context & x) { + (void) x; + timing_print(); + Machine::shutdown(); +} diff --git a/arch/patmos/timing-arch.h b/arch/patmos/timing-arch.h new file mode 100644 index 0000000000000000000000000000000000000000..26a2b633ad1ad903ca898fc4abfb4f86db789d11 --- /dev/null +++ b/arch/patmos/timing-arch.h @@ -0,0 +1,28 @@ +#ifndef __ARCH_PATMOS_TIMING_H +#define __ARCH_PATMOS_TIMING_H + +#include "os/util/inline.h" +#include "patmos-cpu.h" +#include "stdint.h" + +extern "C" { + +// #define USE_CYCLES_FOR_TIMING + +static inlinehint uint64_t arch_timing_get() { +#ifdef USE_CYCLES_FOR_TIMING + uint32_t l, h; + __PATMOS_RTC_RD_CYCLE_LOW(l); + __PATMOS_RTC_RD_CYCLE_UP(h); + + return ((uint64_t)h << 32) | l; +#else + uint32_t instrs; + __PATMOS_PERF_RD(instrs) + return (uint64_t)instrs; +#endif +} + +} + +#endif diff --git a/arch/patmos/typecheck.cc b/arch/patmos/typecheck.cc new file mode 100644 index 0000000000000000000000000000000000000000..e6be0cf054c043334e4a25742ad0ac4d039cb015 --- /dev/null +++ b/arch/patmos/typecheck.cc @@ -0,0 +1,21 @@ +#include <stdint.h> + +//sanity checks +char __type_error__[( + + sizeof(uint8_t) == 1 && + sizeof(uint16_t) == 2 && + sizeof(uint32_t) == 4 && + sizeof(uint64_t) == 8 && + sizeof(uintptr_t) == 4 && + + sizeof(size_t) == (SYSTEM_BITS/8) && + + sizeof(int8_t) == 1 && + sizeof(int16_t) == 2 && + sizeof(int32_t) == 4 && + sizeof(int64_t) == 8 && + sizeof(intptr_t) == 4 && + + 1) ? 0 : -1 +]; diff --git a/arch/posix/CMakeLists.txt b/arch/posix/CMakeLists.txt index eb29df1b0877aa99a5906ccd9f922a6b02906366..285fd648fc5317cf98621cefcf485f806200075f 100644 --- a/arch/posix/CMakeLists.txt +++ b/arch/posix/CMakeLists.txt @@ -68,18 +68,10 @@ macro(dosek_executable ELFFILE) set_target_properties(${ELFFILE} PROPERTIES COMPILE_DEFINITIONS ${DOSEK_EXECUTABLE_DEFINITIONS}) endif() - # Set custom linker script/flags # libgcc added here to be used as needed (compiler helper functions)and not included in full set_target_properties(${ELFFILE} PROPERTIES LINK_FLAGS - "-lgcc ${ISA_LD_FLAGS} --linker-prefix=${CMAKE_CURRENT_BINARY_DIR}/${ELFFILE}") - - - # we use our own linker (python) script, that calls llvm-link, llc and the system linker - # setting CMAKE_*_LINK_EXECUTABLE at this point in the CMake run seems a bit unusual, but works as intended - set(LINK_EXECUTABLE "${PROJECT_SOURCE_DIR}/toolchain/llvm-link.py -Wl,-T${LINKER_SCRIPT} --clang ${CMAKE_C_COMPILER} --march x86 --mcpu ${CMAKE_C_ARCH} --llvm-dir ${CCDIR} <LINK_FLAGS> <OBJECTS> <LINK_LIBRARIES> -o <TARGET>") - set(CMAKE_C_LINK_EXECUTABLE "${LINK_EXECUTABLE} <CMAKE_C_LINK_FLAGS>") - set(CMAKE_CXX_LINK_EXECUTABLE "${LINK_EXECUTABLE} <CMAKE_CXX_LINK_FLAGS>") + "-lgcc ${TC_TARGET_LDFLAGS} --linker-prefix=${CMAKE_CURRENT_BINARY_DIR}/${ELFFILE}") # add to executables list set(EXECUTABLES ${EXECUTABLES} ${ELFFILE} CACHE INTERNAL STRING) diff --git a/arch/posix/atomics.h b/arch/posix/atomics.h deleted file mode 100644 index 32097cbac2cf8111efead36925ddb2e2cf046652..0000000000000000000000000000000000000000 --- a/arch/posix/atomics.h +++ /dev/null @@ -1,25 +0,0 @@ -#ifndef _UTIL_ATOMICS_H -#define _UTIL_ATOMICS_H - -namespace arch { - template<typename P, typename V> - static bool compare_and_swap(P *ptr, V oldval, V newval) { - return __sync_bool_compare_and_swap(ptr, oldval, newval); - } - - template<typename P, typename V> - static V atomic_fetch_and_add(P *ptr, V value) { - return __sync_fetch_and_add(ptr, value); - } - - template<typename P, typename V> - static V atomic_fetch_and_sub(P *ptr, V value) { - return __sync_fetch_and_sub(ptr, value); - } - - static void atomic_memory_barrier() { - __atomic_thread_fence(__ATOMIC_SEQ_CST); - } -} - -#endif diff --git a/config/__init__.py b/config/__init__.py index 79b2ce97a87347c5223d18761491a2d05b4242fa..6269d31d9ed483ad713a668fe566107fab27bea5 100755 --- a/config/__init__.py +++ b/config/__init__.py @@ -24,7 +24,7 @@ class _toCMakeConfig: if isinstance(ty, Int): return str(value) if isinstance(ty, (String, OneOf)): - return repr(ty.to_string(value)) + return '"%s"' % repr(ty.to_string(value))[1:-1] def cmake_type(self, ty): return {Boolean: "BOOL", diff --git a/config/config_tree.py b/config/config_tree.py index 9e024b75e06c71ca9f3a9d54176c4adedb907865..c8043f33121c22213ef1446289fcef8c364b533d 100644 --- a/config/config_tree.py +++ b/config/config_tree.py @@ -88,7 +88,7 @@ class ConfigurationTreeStack(object): (val, ty) = self.get(name[0]) if isinstance(val, ConfigurationTreeStack): return val.get(name[1:]) - assert len(name) == 1, val + assert len(name) == 1, [val, name] return (val, ty) ret = [] for x in self.__stack: diff --git a/config/model.py b/config/model.py index 80c4312cc98976f96b524302cd61ab756fee9633..558496a4bd7d26657bf593bcb8f179aac1967cf5 100644 --- a/config/model.py +++ b/config/model.py @@ -8,18 +8,22 @@ model = ConfigurationTree({ 'generator': OneOf(["make", "ninja", "eclipse"], short_help = "Build System"), 'arch': { - "self" : OneOf(["i386", "ARM", "posix"], + "self" : OneOf(["i386", "ARM", "posix", "patmos"], short_help = "CPU Architecture"), 'mpu': Boolean(short_help = "Use Memory Protection"), + # config-constraint-: (arch.self == patmos || arch.self == posix) -> !arch.mpu 'idle-halt': Boolean(short_help = "Idle loop halts processor", default_value = expr("self == i386 || self == ARM")), # config-constraint-: arch.idle-halt -> !(arch.self == posix) + # config-constraint-: arch.idle-halt -> !(arch.self == patmos) + 'privilege-isolation': Boolean(short_help = "Enable Priviledge isolation", default_value = expr("self == i386 || self == ARM")), # config-constraint-: arch.privilege-isolation -> (arch.self == i386 || arch.self == ARM) - # config-constraint-: !arch.privilege-isolation -> (arch.self == i386 || arch.self == posix) + # config-constraint-: arch.privilege-isolation -> !(arch.self == patmos) + # config-constraint-: !arch.privilege-isolation -> (arch.self == i386 || arch.self == posix || arch.self == patmos) }, 'os' : { 'ignore-interrupt-systemcalls': Boolean(short_help = "Do not analyze DisableInterrupt() etc."), @@ -38,7 +42,6 @@ model = ConfigurationTree({ 'semi-extended-tasks': Boolean(short_help = "Should semi-extended-tasks be enabled?"), # config-constraint-: os.semi-extended-tasks -> !dependability.encoded # config-constraint-: os.semi-extended-tasks -> os.basic-tasks - }, 'dependability' : { 'encoded': Boolean(short_help = "Encoded OS Operations"), @@ -53,8 +56,14 @@ model = ConfigurationTree({ 'cfg-regions': Boolean(short_help = "Introduce CFG Region Checks"), 'failure-logging': Boolean(short_help = "Failure Logging"), }, + 'timing': { + 'generate-pml': Boolean(short_help = "Generates a GCFG PML for all timing circuits"), + # config-constraint-: timing.generate-pml -> (arch.self == patmos) + }, 'verify' : { 'generate-mockup': Boolean(short_help = "A application mockup is generated"), + 'generate-ssm': Boolean(short_help = "Use SSE to generate a more compact STG", + default_value=expr("generate-mockup")), }, 'app': { 'name': String(short_help = "Name of one application"), diff --git a/doc/concepts/verification-diagram.svg b/doc/concepts/verification-diagram.svg new file mode 100644 index 0000000000000000000000000000000000000000..9ff6b36570f35b5653935b82cbe8328571dc10a5 --- /dev/null +++ b/doc/concepts/verification-diagram.svg @@ -0,0 +1,1731 @@ +<?xml version="1.0" encoding="UTF-8" standalone="no"?> +<!-- Created with Inkscape (http://www.inkscape.org/) --> + +<svg + xmlns:dc="http://purl.org/dc/elements/1.1/" + xmlns:cc="http://creativecommons.org/ns#" + xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" + xmlns:svg="http://www.w3.org/2000/svg" + xmlns="http://www.w3.org/2000/svg" + xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" + xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" + width="297mm" + height="420mm" + viewBox="0 0 1052.3622 1488.189" + id="svg2" + version="1.1" + inkscape:version="0.91 r13725" + sodipodi:docname="diagramm-gross.svg"> + <defs + id="defs4"> + <marker + inkscape:isstock="true" + style="overflow:visible;" + id="marker12867" + refX="0.0" + refY="0.0" + orient="auto" + inkscape:stockid="Arrow2Mend"> + <path + transform="scale(0.6) rotate(180) translate(0,0)" + d="M 8.7185878,4.0337352 L -2.2072895,0.016013256 L 8.7185884,-4.0017078 C 6.9730900,-1.6296469 6.9831476,1.6157441 8.7185878,4.0337352 z " + style="fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round;stroke:#000000;stroke-opacity:1;fill:#000000;fill-opacity:1" + id="path12869" /> + </marker> + <marker + inkscape:stockid="Arrow2Mend" + orient="auto" + refY="0.0" + refX="0.0" + id="marker12603" + style="overflow:visible;" + inkscape:isstock="true" + inkscape:collect="always"> + <path + id="path12605" + style="fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round;stroke:#000000;stroke-opacity:1;fill:#000000;fill-opacity:1" + d="M 8.7185878,4.0337352 L -2.2072895,0.016013256 L 8.7185884,-4.0017078 C 6.9730900,-1.6296469 6.9831476,1.6157441 8.7185878,4.0337352 z " + transform="scale(0.6) rotate(180) translate(0,0)" /> + </marker> + <marker + inkscape:isstock="true" + style="overflow:visible;" + id="marker12345" + refX="0.0" + refY="0.0" + orient="auto" + inkscape:stockid="Arrow2Mend" + inkscape:collect="always"> + <path + transform="scale(0.6) rotate(180) translate(0,0)" + d="M 8.7185878,4.0337352 L -2.2072895,0.016013256 L 8.7185884,-4.0017078 C 6.9730900,-1.6296469 6.9831476,1.6157441 8.7185878,4.0337352 z " + style="fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round;stroke:#000000;stroke-opacity:1;fill:#000000;fill-opacity:1" + id="path12347" /> + </marker> + <marker + inkscape:stockid="Arrow2Mend" + orient="auto" + refY="0.0" + refX="0.0" + id="Arrow2Mend" + style="overflow:visible;" + inkscape:isstock="true" + inkscape:collect="always"> + <path + id="path5000" + style="fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round;stroke:#000000;stroke-opacity:1;fill:#000000;fill-opacity:1" + d="M 8.7185878,4.0337352 L -2.2072895,0.016013256 L 8.7185884,-4.0017078 C 6.9730900,-1.6296469 6.9831476,1.6157441 8.7185878,4.0337352 z " + transform="scale(0.6) rotate(180) translate(0,0)" /> + </marker> + <marker + inkscape:stockid="Arrow2Lend" + orient="auto" + refY="0.0" + refX="0.0" + id="marker11857" + style="overflow:visible;" + inkscape:isstock="true"> + <path + id="path11859" + style="fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round;stroke:#000000;stroke-opacity:1;fill:#000000;fill-opacity:1" + d="M 8.7185878,4.0337352 L -2.2072895,0.016013256 L 8.7185884,-4.0017078 C 6.9730900,-1.6296469 6.9831476,1.6157441 8.7185878,4.0337352 z " + transform="scale(1.1) rotate(180) translate(1,0)" /> + </marker> + <marker + inkscape:isstock="true" + style="overflow:visible;" + id="marker11625" + refX="0.0" + refY="0.0" + orient="auto" + inkscape:stockid="Arrow2Lend"> + <path + transform="scale(1.1) rotate(180) translate(1,0)" + d="M 8.7185878,4.0337352 L -2.2072895,0.016013256 L 8.7185884,-4.0017078 C 6.9730900,-1.6296469 6.9831476,1.6157441 8.7185878,4.0337352 z " + style="fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round;stroke:#000000;stroke-opacity:1;fill:#000000;fill-opacity:1" + id="path11627" /> + </marker> + <marker + inkscape:isstock="true" + style="overflow:visible;" + id="marker11393" + refX="0.0" + refY="0.0" + orient="auto" + inkscape:stockid="Arrow2Lend"> + <path + transform="scale(1.1) rotate(180) translate(1,0)" + d="M 8.7185878,4.0337352 L -2.2072895,0.016013256 L 8.7185884,-4.0017078 C 6.9730900,-1.6296469 6.9831476,1.6157441 8.7185878,4.0337352 z " + style="fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round;stroke:#000000;stroke-opacity:1;fill:#000000;fill-opacity:1" + id="path11395" /> + </marker> + <marker + inkscape:stockid="Arrow2Lend" + orient="auto" + refY="0.0" + refX="0.0" + id="marker11125" + style="overflow:visible;" + inkscape:isstock="true" + inkscape:collect="always"> + <path + id="path11127" + style="fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round;stroke:#000000;stroke-opacity:1;fill:#000000;fill-opacity:1" + d="M 8.7185878,4.0337352 L -2.2072895,0.016013256 L 8.7185884,-4.0017078 C 6.9730900,-1.6296469 6.9831476,1.6157441 8.7185878,4.0337352 z " + transform="scale(1.1) rotate(180) translate(1,0)" /> + </marker> + <marker + inkscape:isstock="true" + style="overflow:visible;" + id="marker10669" + refX="0.0" + refY="0.0" + orient="auto" + inkscape:stockid="Arrow2Lend" + inkscape:collect="always"> + <path + transform="scale(1.1) rotate(180) translate(1,0)" + d="M 8.7185878,4.0337352 L -2.2072895,0.016013256 L 8.7185884,-4.0017078 C 6.9730900,-1.6296469 6.9831476,1.6157441 8.7185878,4.0337352 z " + style="fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round;stroke:#000000;stroke-opacity:1;fill:#000000;fill-opacity:1" + id="path10671" /> + </marker> + <marker + inkscape:stockid="Arrow2Lend" + orient="auto" + refY="0.0" + refX="0.0" + id="marker10417" + style="overflow:visible;" + inkscape:isstock="true" + inkscape:collect="always"> + <path + id="path10419" + style="fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round;stroke:#000000;stroke-opacity:1;fill:#000000;fill-opacity:1" + d="M 8.7185878,4.0337352 L -2.2072895,0.016013256 L 8.7185884,-4.0017078 C 6.9730900,-1.6296469 6.9831476,1.6157441 8.7185878,4.0337352 z " + transform="scale(1.1) rotate(180) translate(1,0)" /> + </marker> + <marker + inkscape:isstock="true" + style="overflow:visible;" + id="marker10207" + refX="0.0" + refY="0.0" + orient="auto" + inkscape:stockid="Arrow2Lend" + inkscape:collect="always"> + <path + transform="scale(1.1) rotate(180) translate(1,0)" + d="M 8.7185878,4.0337352 L -2.2072895,0.016013256 L 8.7185884,-4.0017078 C 6.9730900,-1.6296469 6.9831476,1.6157441 8.7185878,4.0337352 z " + style="fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round;stroke:#000000;stroke-opacity:1;fill:#000000;fill-opacity:1" + id="path10209" /> + </marker> + <marker + inkscape:stockid="Arrow2Lend" + orient="auto" + refY="0.0" + refX="0.0" + id="marker10003" + style="overflow:visible;" + inkscape:isstock="true" + inkscape:collect="always"> + <path + id="path10005" + style="fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round;stroke:#000000;stroke-opacity:1;fill:#000000;fill-opacity:1" + d="M 8.7185878,4.0337352 L -2.2072895,0.016013256 L 8.7185884,-4.0017078 C 6.9730900,-1.6296469 6.9831476,1.6157441 8.7185878,4.0337352 z " + transform="scale(1.1) rotate(180) translate(1,0)" /> + </marker> + <marker + inkscape:isstock="true" + style="overflow:visible;" + id="marker9655" + refX="0.0" + refY="0.0" + orient="auto" + inkscape:stockid="Arrow2Lend" + inkscape:collect="always"> + <path + transform="scale(1.1) rotate(180) translate(1,0)" + d="M 8.7185878,4.0337352 L -2.2072895,0.016013256 L 8.7185884,-4.0017078 C 6.9730900,-1.6296469 6.9831476,1.6157441 8.7185878,4.0337352 z " + style="fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round;stroke:#000000;stroke-opacity:1;fill:#000000;fill-opacity:1" + id="path9657" /> + </marker> + <marker + inkscape:stockid="Arrow2Lend" + orient="auto" + refY="0.0" + refX="0.0" + id="marker9445" + style="overflow:visible;" + inkscape:isstock="true" + inkscape:collect="always"> + <path + id="path9447" + style="fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round;stroke:#000000;stroke-opacity:1;fill:#000000;fill-opacity:1" + d="M 8.7185878,4.0337352 L -2.2072895,0.016013256 L 8.7185884,-4.0017078 C 6.9730900,-1.6296469 6.9831476,1.6157441 8.7185878,4.0337352 z " + transform="scale(1.1) rotate(180) translate(1,0)" /> + </marker> + <marker + inkscape:isstock="true" + style="overflow:visible;" + id="marker9259" + refX="0.0" + refY="0.0" + orient="auto" + inkscape:stockid="Arrow2Lend" + inkscape:collect="always"> + <path + transform="scale(1.1) rotate(180) translate(1,0)" + d="M 8.7185878,4.0337352 L -2.2072895,0.016013256 L 8.7185884,-4.0017078 C 6.9730900,-1.6296469 6.9831476,1.6157441 8.7185878,4.0337352 z " + style="fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round;stroke:#000000;stroke-opacity:1;fill:#000000;fill-opacity:1" + id="path9261" /> + </marker> + <marker + inkscape:stockid="Arrow2Lend" + orient="auto" + refY="0.0" + refX="0.0" + id="marker9079" + style="overflow:visible;" + inkscape:isstock="true" + inkscape:collect="always"> + <path + id="path9081" + style="fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round;stroke:#000000;stroke-opacity:1;fill:#000000;fill-opacity:1" + d="M 8.7185878,4.0337352 L -2.2072895,0.016013256 L 8.7185884,-4.0017078 C 6.9730900,-1.6296469 6.9831476,1.6157441 8.7185878,4.0337352 z " + transform="scale(1.1) rotate(180) translate(1,0)" /> + </marker> + <marker + inkscape:isstock="true" + style="overflow:visible;" + id="marker8905" + refX="0.0" + refY="0.0" + orient="auto" + inkscape:stockid="Arrow2Lend" + inkscape:collect="always"> + <path + transform="scale(1.1) rotate(180) translate(1,0)" + d="M 8.7185878,4.0337352 L -2.2072895,0.016013256 L 8.7185884,-4.0017078 C 6.9730900,-1.6296469 6.9831476,1.6157441 8.7185878,4.0337352 z " + style="fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round;stroke:#000000;stroke-opacity:1;fill:#000000;fill-opacity:1" + id="path8907" /> + </marker> + <marker + inkscape:stockid="Arrow2Lend" + orient="auto" + refY="0.0" + refX="0.0" + id="marker8737" + style="overflow:visible;" + inkscape:isstock="true" + inkscape:collect="always"> + <path + id="path8739" + style="fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round;stroke:#000000;stroke-opacity:1;fill:#000000;fill-opacity:1" + d="M 8.7185878,4.0337352 L -2.2072895,0.016013256 L 8.7185884,-4.0017078 C 6.9730900,-1.6296469 6.9831476,1.6157441 8.7185878,4.0337352 z " + transform="scale(1.1) rotate(180) translate(1,0)" /> + </marker> + <marker + inkscape:isstock="true" + style="overflow:visible;" + id="marker8575" + refX="0.0" + refY="0.0" + orient="auto" + inkscape:stockid="Arrow2Lend" + inkscape:collect="always"> + <path + transform="scale(1.1) rotate(180) translate(1,0)" + d="M 8.7185878,4.0337352 L -2.2072895,0.016013256 L 8.7185884,-4.0017078 C 6.9730900,-1.6296469 6.9831476,1.6157441 8.7185878,4.0337352 z " + style="fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round;stroke:#000000;stroke-opacity:1;fill:#000000;fill-opacity:1" + id="path8577" /> + </marker> + <marker + inkscape:stockid="Arrow2Lend" + orient="auto" + refY="0.0" + refX="0.0" + id="marker8001" + style="overflow:visible;" + inkscape:isstock="true" + inkscape:collect="always"> + <path + id="path8003" + style="fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round;stroke:#000000;stroke-opacity:1;fill:#000000;fill-opacity:1" + d="M 8.7185878,4.0337352 L -2.2072895,0.016013256 L 8.7185884,-4.0017078 C 6.9730900,-1.6296469 6.9831476,1.6157441 8.7185878,4.0337352 z " + transform="scale(1.1) rotate(180) translate(1,0)" /> + </marker> + <marker + inkscape:isstock="true" + style="overflow:visible;" + id="marker7839" + refX="0.0" + refY="0.0" + orient="auto" + inkscape:stockid="Arrow2Lend" + inkscape:collect="always"> + <path + transform="scale(1.1) rotate(180) translate(1,0)" + d="M 8.7185878,4.0337352 L -2.2072895,0.016013256 L 8.7185884,-4.0017078 C 6.9730900,-1.6296469 6.9831476,1.6157441 8.7185878,4.0337352 z " + style="fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round;stroke:#000000;stroke-opacity:1;fill:#000000;fill-opacity:1" + id="path7841" /> + </marker> + <marker + inkscape:stockid="Arrow2Lend" + orient="auto" + refY="0.0" + refX="0.0" + id="marker7539" + style="overflow:visible;" + inkscape:isstock="true" + inkscape:collect="always"> + <path + id="path7541" + style="fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round;stroke:#000000;stroke-opacity:1;fill:#000000;fill-opacity:1" + d="M 8.7185878,4.0337352 L -2.2072895,0.016013256 L 8.7185884,-4.0017078 C 6.9730900,-1.6296469 6.9831476,1.6157441 8.7185878,4.0337352 z " + transform="scale(1.1) rotate(180) translate(1,0)" /> + </marker> + <marker + inkscape:isstock="true" + style="overflow:visible;" + id="marker7169" + refX="0.0" + refY="0.0" + orient="auto" + inkscape:stockid="Arrow2Lend" + inkscape:collect="always"> + <path + transform="scale(1.1) rotate(180) translate(1,0)" + d="M 8.7185878,4.0337352 L -2.2072895,0.016013256 L 8.7185884,-4.0017078 C 6.9730900,-1.6296469 6.9831476,1.6157441 8.7185878,4.0337352 z " + style="fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round;stroke:#000000;stroke-opacity:1;fill:#000000;fill-opacity:1" + id="path7171" /> + </marker> + <marker + inkscape:isstock="true" + style="overflow:visible;" + id="marker6825" + refX="0.0" + refY="0.0" + orient="auto" + inkscape:stockid="Arrow2Lend" + inkscape:collect="always"> + <path + transform="scale(1.1) rotate(180) translate(1,0)" + d="M 8.7185878,4.0337352 L -2.2072895,0.016013256 L 8.7185884,-4.0017078 C 6.9730900,-1.6296469 6.9831476,1.6157441 8.7185878,4.0337352 z " + style="fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round;stroke:#000000;stroke-opacity:1;fill:#000000;fill-opacity:1" + id="path6827" /> + </marker> + <marker + inkscape:stockid="Arrow2Lend" + orient="auto" + refY="0.0" + refX="0.0" + id="marker6687" + style="overflow:visible;" + inkscape:isstock="true" + inkscape:collect="always"> + <path + id="path6689" + style="fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round;stroke:#000000;stroke-opacity:1;fill:#000000;fill-opacity:1" + d="M 8.7185878,4.0337352 L -2.2072895,0.016013256 L 8.7185884,-4.0017078 C 6.9730900,-1.6296469 6.9831476,1.6157441 8.7185878,4.0337352 z " + transform="scale(1.1) rotate(180) translate(1,0)" /> + </marker> + <marker + inkscape:isstock="true" + style="overflow:visible;" + id="marker6555" + refX="0.0" + refY="0.0" + orient="auto" + inkscape:stockid="Arrow2Lend" + inkscape:collect="always"> + <path + transform="scale(1.1) rotate(180) translate(1,0)" + d="M 8.7185878,4.0337352 L -2.2072895,0.016013256 L 8.7185884,-4.0017078 C 6.9730900,-1.6296469 6.9831476,1.6157441 8.7185878,4.0337352 z " + style="fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round;stroke:#000000;stroke-opacity:1;fill:#000000;fill-opacity:1" + id="path6557" /> + </marker> + <marker + inkscape:stockid="Arrow2Lend" + orient="auto" + refY="0.0" + refX="0.0" + id="marker6429" + style="overflow:visible;" + inkscape:isstock="true" + inkscape:collect="always"> + <path + id="path6431" + style="fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round;stroke:#000000;stroke-opacity:1;fill:#000000;fill-opacity:1" + d="M 8.7185878,4.0337352 L -2.2072895,0.016013256 L 8.7185884,-4.0017078 C 6.9730900,-1.6296469 6.9831476,1.6157441 8.7185878,4.0337352 z " + transform="scale(1.1) rotate(180) translate(1,0)" /> + </marker> + <marker + inkscape:isstock="true" + style="overflow:visible;" + id="marker6309" + refX="0.0" + refY="0.0" + orient="auto" + inkscape:stockid="Arrow2Lend" + inkscape:collect="always"> + <path + transform="scale(1.1) rotate(180) translate(1,0)" + d="M 8.7185878,4.0337352 L -2.2072895,0.016013256 L 8.7185884,-4.0017078 C 6.9730900,-1.6296469 6.9831476,1.6157441 8.7185878,4.0337352 z " + style="fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round;stroke:#000000;stroke-opacity:1;fill:#000000;fill-opacity:1" + id="path6311" /> + </marker> + <marker + inkscape:stockid="Arrow2Lend" + orient="auto" + refY="0.0" + refX="0.0" + id="marker6195" + style="overflow:visible;" + inkscape:isstock="true" + inkscape:collect="always"> + <path + id="path6197" + style="fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round;stroke:#000000;stroke-opacity:1;fill:#000000;fill-opacity:1" + d="M 8.7185878,4.0337352 L -2.2072895,0.016013256 L 8.7185884,-4.0017078 C 6.9730900,-1.6296469 6.9831476,1.6157441 8.7185878,4.0337352 z " + transform="scale(1.1) rotate(180) translate(1,0)" /> + </marker> + <marker + inkscape:isstock="true" + style="overflow:visible;" + id="marker5889" + refX="0.0" + refY="0.0" + orient="auto" + inkscape:stockid="Arrow2Lend" + inkscape:collect="always"> + <path + transform="scale(1.1) rotate(180) translate(1,0)" + d="M 8.7185878,4.0337352 L -2.2072895,0.016013256 L 8.7185884,-4.0017078 C 6.9730900,-1.6296469 6.9831476,1.6157441 8.7185878,4.0337352 z " + style="fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round;stroke:#000000;stroke-opacity:1;fill:#000000;fill-opacity:1" + id="path5891" /> + </marker> + <marker + inkscape:stockid="Arrow2Lend" + orient="auto" + refY="0.0" + refX="0.0" + id="marker5797" + style="overflow:visible;" + inkscape:isstock="true" + inkscape:collect="always"> + <path + id="path5799" + style="fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round;stroke:#000000;stroke-opacity:1;fill:#000000;fill-opacity:1" + d="M 8.7185878,4.0337352 L -2.2072895,0.016013256 L 8.7185884,-4.0017078 C 6.9730900,-1.6296469 6.9831476,1.6157441 8.7185878,4.0337352 z " + transform="scale(1.1) rotate(180) translate(1,0)" /> + </marker> + <marker + inkscape:isstock="true" + style="overflow:visible;" + id="marker5713" + refX="0.0" + refY="0.0" + orient="auto" + inkscape:stockid="Arrow2Lend" + inkscape:collect="always"> + <path + transform="scale(1.1) rotate(180) translate(1,0)" + d="M 8.7185878,4.0337352 L -2.2072895,0.016013256 L 8.7185884,-4.0017078 C 6.9730900,-1.6296469 6.9831476,1.6157441 8.7185878,4.0337352 z " + style="fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round;stroke:#000000;stroke-opacity:1;fill:#000000;fill-opacity:1" + id="path5715" /> + </marker> + <marker + inkscape:stockid="Arrow2Lend" + orient="auto" + refY="0.0" + refX="0.0" + id="marker5635" + style="overflow:visible;" + inkscape:isstock="true" + inkscape:collect="always"> + <path + id="path5637" + style="fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round;stroke:#000000;stroke-opacity:1;fill:#000000;fill-opacity:1" + d="M 8.7185878,4.0337352 L -2.2072895,0.016013256 L 8.7185884,-4.0017078 C 6.9730900,-1.6296469 6.9831476,1.6157441 8.7185878,4.0337352 z " + transform="scale(1.1) rotate(180) translate(1,0)" /> + </marker> + <marker + inkscape:isstock="true" + style="overflow:visible;" + id="marker5563" + refX="0.0" + refY="0.0" + orient="auto" + inkscape:stockid="Arrow2Lend" + inkscape:collect="always"> + <path + transform="scale(1.1) rotate(180) translate(1,0)" + d="M 8.7185878,4.0337352 L -2.2072895,0.016013256 L 8.7185884,-4.0017078 C 6.9730900,-1.6296469 6.9831476,1.6157441 8.7185878,4.0337352 z " + style="fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round;stroke:#000000;stroke-opacity:1;fill:#000000;fill-opacity:1" + id="path5565" /> + </marker> + <marker + inkscape:stockid="Arrow2Lend" + orient="auto" + refY="0.0" + refX="0.0" + id="marker5497" + style="overflow:visible;" + inkscape:isstock="true" + inkscape:collect="always"> + <path + id="path5499" + style="fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round;stroke:#000000;stroke-opacity:1;fill:#000000;fill-opacity:1" + d="M 8.7185878,4.0337352 L -2.2072895,0.016013256 L 8.7185884,-4.0017078 C 6.9730900,-1.6296469 6.9831476,1.6157441 8.7185878,4.0337352 z " + transform="scale(1.1) rotate(180) translate(1,0)" /> + </marker> + <marker + inkscape:isstock="true" + style="overflow:visible;" + id="marker5437" + refX="0.0" + refY="0.0" + orient="auto" + inkscape:stockid="Arrow2Lend" + inkscape:collect="always"> + <path + transform="scale(1.1) rotate(180) translate(1,0)" + d="M 8.7185878,4.0337352 L -2.2072895,0.016013256 L 8.7185884,-4.0017078 C 6.9730900,-1.6296469 6.9831476,1.6157441 8.7185878,4.0337352 z " + style="fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round;stroke:#000000;stroke-opacity:1;fill:#000000;fill-opacity:1" + id="path5439" /> + </marker> + <marker + inkscape:stockid="Arrow2Lend" + orient="auto" + refY="0.0" + refX="0.0" + id="marker5383" + style="overflow:visible;" + inkscape:isstock="true" + inkscape:collect="always"> + <path + id="path5385" + style="fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round;stroke:#000000;stroke-opacity:1;fill:#000000;fill-opacity:1" + d="M 8.7185878,4.0337352 L -2.2072895,0.016013256 L 8.7185884,-4.0017078 C 6.9730900,-1.6296469 6.9831476,1.6157441 8.7185878,4.0337352 z " + transform="scale(1.1) rotate(180) translate(1,0)" /> + </marker> + <marker + inkscape:isstock="true" + style="overflow:visible;" + id="marker5335" + refX="0.0" + refY="0.0" + orient="auto" + inkscape:stockid="Arrow2Lend" + inkscape:collect="always"> + <path + transform="scale(1.1) rotate(180) translate(1,0)" + d="M 8.7185878,4.0337352 L -2.2072895,0.016013256 L 8.7185884,-4.0017078 C 6.9730900,-1.6296469 6.9831476,1.6157441 8.7185878,4.0337352 z " + style="fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round;stroke:#000000;stroke-opacity:1;fill:#000000;fill-opacity:1" + id="path5337" /> + </marker> + <marker + inkscape:stockid="Arrow2Lend" + orient="auto" + refY="0.0" + refX="0.0" + id="marker5293" + style="overflow:visible;" + inkscape:isstock="true" + inkscape:collect="always"> + <path + id="path5295" + style="fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round;stroke:#000000;stroke-opacity:1;fill:#000000;fill-opacity:1" + d="M 8.7185878,4.0337352 L -2.2072895,0.016013256 L 8.7185884,-4.0017078 C 6.9730900,-1.6296469 6.9831476,1.6157441 8.7185878,4.0337352 z " + transform="scale(1.1) rotate(180) translate(1,0)" /> + </marker> + <marker + inkscape:isstock="true" + style="overflow:visible;" + id="marker5257" + refX="0.0" + refY="0.0" + orient="auto" + inkscape:stockid="Arrow2Lend" + inkscape:collect="always"> + <path + transform="scale(1.1) rotate(180) translate(1,0)" + d="M 8.7185878,4.0337352 L -2.2072895,0.016013256 L 8.7185884,-4.0017078 C 6.9730900,-1.6296469 6.9831476,1.6157441 8.7185878,4.0337352 z " + style="fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round;stroke:#000000;stroke-opacity:1;fill:#000000;fill-opacity:1" + id="path5259" /> + </marker> + <marker + inkscape:stockid="Arrow2Lend" + orient="auto" + refY="0.0" + refX="0.0" + id="Arrow2Lend" + style="overflow:visible;" + inkscape:isstock="true" + inkscape:collect="always"> + <path + id="path4994" + style="fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round;stroke:#000000;stroke-opacity:1;fill:#000000;fill-opacity:1" + d="M 8.7185878,4.0337352 L -2.2072895,0.016013256 L 8.7185884,-4.0017078 C 6.9730900,-1.6296469 6.9831476,1.6157441 8.7185878,4.0337352 z " + transform="scale(1.1) rotate(180) translate(1,0)" /> + </marker> + </defs> + <sodipodi:namedview + id="base" + pagecolor="#ffffff" + bordercolor="#666666" + borderopacity="1.0" + inkscape:pageopacity="0.0" + inkscape:pageshadow="2" + inkscape:zoom="0.49497475" + inkscape:cx="1008.5432" + inkscape:cy="715.55041" + inkscape:document-units="px" + inkscape:current-layer="layer1" + showgrid="false" + inkscape:window-width="1680" + inkscape:window-height="1050" + inkscape:window-x="0" + inkscape:window-y="0" + inkscape:window-maximized="0"> + <inkscape:grid + type="xygrid" + id="grid4624" /> + </sodipodi:namedview> + <metadata + id="metadata7"> + <rdf:RDF> + <cc:Work + rdf:about=""> + <dc:format>image/svg+xml</dc:format> + <dc:type + rdf:resource="http://purl.org/dc/dcmitype/StillImage" /> + <dc:title /> + </cc:Work> + </rdf:RDF> + </metadata> + <g + inkscape:label="Layer 1" + inkscape:groupmode="layer" + id="layer1" + transform="translate(0,435.82677)"> + <g + id="g4634" + transform="translate(72.5,20)"> + <g + id="g4629"> + <text + xml:space="preserve" + style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:22.5px;line-height:125%;font-family:'Linux Biolinum';-inkscape-font-specification:'Linux Biolinum, Normal';text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" + x="60.568542" + y="-375.93259" + id="text4316" + sodipodi:linespacing="125%"><tspan + sodipodi:role="line" + id="tspan4318" + x="60.568542" + y="-375.93259">OSEK 233</tspan></text> + <rect + style="fill:none;fill-opacity:1;stroke:#000000;stroke-width:1.75226176;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" + id="rect4423" + width="154.07315" + height="58.991505" + x="40" + y="-412.63782" /> + </g> + <g + id="g4619"> + <text + xml:space="preserve" + style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:22.5px;line-height:125%;font-family:'Linux Biolinum';-inkscape-font-specification:'Linux Biolinum, Normal';text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" + x="56.568542" + y="-287.1001" + id="text4320" + sodipodi:linespacing="125%"><tspan + sodipodi:role="line" + id="tspan4322" + x="56.568542" + y="-287.1001">OIL</tspan></text> + <rect + style="fill:none;fill-opacity:1;stroke:#000000;stroke-width:2.5530622;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" + id="rect4425" + width="152.99013" + height="53.995174" + x="40.682632" + y="-321.16873" /> + </g> + <rect + y="-422.63782" + x="30" + height="165.00002" + width="175" + id="rect4427" + style="fill:none;fill-opacity:1;stroke:#000000;stroke-width:1.93440902;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" /> + </g> + <g + id="g4645" + transform="translate(41.018677,-21.558284)"> + <text + sodipodi:linespacing="125%" + id="text4324" + y="-320.7233" + x="333.33005" + style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:22.5px;line-height:125%;font-family:'Linux Biolinum';-inkscape-font-specification:'Linux Biolinum, Normal';text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" + xml:space="preserve"><tspan + y="-320.7233" + x="333.33005" + id="tspan4326" + sodipodi:role="line">App.cc</tspan></text> + <rect + y="-352.89163" + x="321.81726" + height="49.999989" + width="90" + id="rect4429" + style="fill:none;fill-opacity:1;stroke:#000000;stroke-width:2;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" /> + </g> + <g + id="g4650" + transform="translate(22.835938,-44.686877)"> + <text + sodipodi:linespacing="125%" + id="text4328" + y="-196.14574" + x="351.53308" + style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:22.5px;line-height:125%;font-family:'Linux Biolinum';-inkscape-font-specification:'Linux Biolinum, Normal';text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" + xml:space="preserve"><tspan + y="-196.14574" + x="351.53308" + id="tspan4330" + sodipodi:role="line">App.ll</tspan></text> + <rect + y="-227.6378" + x="340" + height="49.999996" + width="90" + id="rect4431" + style="fill:none;fill-opacity:1;stroke:#000000;stroke-width:2;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" /> + </g> + <g + id="g4655" + transform="translate(6.262299,-64.502917)"> + <text + sodipodi:linespacing="125%" + id="text4332" + y="-80.304787" + x="325.26913" + style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:22.5px;line-height:125%;font-family:'Linux Biolinum';-inkscape-font-specification:'Linux Biolinum, Normal';text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" + xml:space="preserve"><tspan + y="-80.304787" + x="325.26913" + id="tspan4334" + sodipodi:role="line">source-system.ll</tspan></text> + <rect + y="-113.35384" + x="313.14728" + height="55.716038" + width="176.85272" + id="rect4433" + style="fill:none;fill-opacity:1;stroke:#000000;stroke-width:2;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" /> + </g> + <g + id="g4688" + transform="translate(39.208199,12.928935)"> + <text + sodipodi:linespacing="125%" + id="text4336" + y="-151.40059" + x="563.68542" + style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:22.5px;line-height:125%;font-family:'Linux Biolinum';-inkscape-font-specification:'Linux Biolinum, Normal';text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" + xml:space="preserve"><tspan + y="-151.40059" + x="563.68542" + id="tspan4338" + sodipodi:role="line">structure</tspan></text> + <rect + y="-188.10513" + x="551.54327" + height="60.467327" + width="108.45673" + id="rect4435" + style="fill:none;fill-opacity:1;stroke:#000000;stroke-width:2;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" /> + </g> + <g + id="g4660" + transform="translate(12.361237,-87.19796)"> + <text + sodipodi:linespacing="125%" + id="text4340" + y="15.075817" + x="329.30972" + style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:22.5px;line-height:125%;font-family:'Linux Biolinum';-inkscape-font-specification:'Linux Biolinum, Normal';text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" + xml:space="preserve"><tspan + y="15.075817" + x="329.30972" + id="tspan4342" + sodipodi:role="line">syscall namen</tspan></text> + <rect + y="-18.507681" + x="313.03909" + height="56.784916" + width="164.87122" + id="rect4439" + style="fill:none;fill-opacity:1;stroke:#000000;stroke-width:1.78362823;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" /> + </g> + <g + id="g4665" + transform="translate(1.512677,5.053679)"> + <text + sodipodi:linespacing="125%" + id="text4344" + y="-69.137642" + x="589.68353" + style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:22.5px;line-height:125%;font-family:'Linux Biolinum';-inkscape-font-specification:'Linux Biolinum, Normal';text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" + xml:space="preserve"><tspan + style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:22.5px;line-height:125%;font-family:'Linux Biolinum';-inkscape-font-specification:'Linux Biolinum, Normal';text-align:start;writing-mode:lr-tb;text-anchor:start" + y="-69.137642" + x="589.68353" + id="tspan4346" + sodipodi:role="line">Generator</tspan><tspan + style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:22.5px;line-height:125%;font-family:'Linux Biolinum';-inkscape-font-specification:'Linux Biolinum, Normal';text-align:start;writing-mode:lr-tb;text-anchor:start" + id="tspan4437" + y="-41.012642" + x="589.68353" + sodipodi:role="line">(merge ABB)</tspan></text> + <ellipse + ry="43.685028" + rx="108.08632" + cy="-59.815742" + cx="643.46716" + id="path4443" + style="fill:none;fill-opacity:1;stroke:#000000;stroke-width:2;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" /> + </g> + <g + id="g4671" + transform="translate(-0.02016,-97.17764)"> + <text + sodipodi:linespacing="125%" + id="text4348" + y="134.65712" + x="593.96973" + style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:22.5px;line-height:125%;font-family:'Linux Biolinum';-inkscape-font-specification:'Linux Biolinum, Normal';text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" + xml:space="preserve"><tspan + y="134.65712" + x="593.96973" + id="tspan4350" + sodipodi:role="line">ABB CFGs</tspan></text> + <rect + y="102.3622" + x="580" + height="50.000004" + width="130" + id="rect4445" + style="fill:none;fill-opacity:1;stroke:#000000;stroke-width:2;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" /> + </g> + <g + id="g13171"> + <rect + y="6.6819081" + x="877.97968" + height="50" + width="100" + id="rect4447" + style="fill:#53dbff;fill-opacity:1;stroke:#000000;stroke-width:2;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" /> + <text + sodipodi:linespacing="125%" + id="text4352" + y="38.444485" + x="890.77179" + style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:22.5px;line-height:125%;font-family:'Linux Biolinum';-inkscape-font-specification:'Linux Biolinum, Normal';text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" + xml:space="preserve"><tspan + y="38.444485" + x="890.77179" + id="tspan4354" + sodipodi:role="line">App.cc'</tspan></text> + </g> + <g + id="g4698" + transform="translate(-29.365581,8.831921)"> + <text + sodipodi:linespacing="125%" + id="text4356" + y="153.87291" + x="874.79211" + style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:22.5px;line-height:125%;font-family:'Linux Biolinum';-inkscape-font-specification:'Linux Biolinum, Normal';text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" + xml:space="preserve"><tspan + y="153.87291" + x="874.79211" + id="tspan4358" + sodipodi:role="line">source-system.ll'</tspan></text> + <rect + y="121.00154" + x="864.69055" + height="51.360653" + width="185.30945" + id="rect4449" + style="fill:none;fill-opacity:1;stroke:#000000;stroke-width:2;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" /> + </g> + <g + id="g4703" + transform="translate(-17.020305,15.888318)"> + <text + sodipodi:linespacing="125%" + id="text4360" + y="224.05739" + x="872.77179" + style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:22.5px;line-height:125%;font-family:'Linux Biolinum';-inkscape-font-specification:'Linux Biolinum, Normal';text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" + xml:space="preserve"><tspan + y="224.05739" + x="872.77179" + id="tspan4362" + sodipodi:role="line">system binary'</tspan></text> + <rect + y="192.3622" + x="860" + height="49.999996" + width="170" + id="rect4451" + style="fill:none;fill-opacity:1;stroke:#000000;stroke-width:2;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" /> + </g> + <g + id="g13162"> + <ellipse + ry="48.367451" + rx="110.19458" + cy="333.67432" + cx="927.97968" + id="path4453" + style="fill:#53dbff;fill-opacity:1;stroke:#000000;stroke-width:2;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" /> + <text + sodipodi:linespacing="125%" + id="text4394" + y="327.35718" + x="926.54047" + style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:22.5px;line-height:125%;font-family:'Linux Biolinum';-inkscape-font-specification:'Linux Biolinum, Normal';text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" + xml:space="preserve"><tspan + style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:22.5px;line-height:125%;font-family:'Linux Biolinum';-inkscape-font-specification:'Linux Biolinum, Normal';text-align:center;writing-mode:lr-tb;text-anchor:middle" + y="327.35718" + x="926.54047" + id="tspan4396" + sodipodi:role="line">Magische Probier</tspan><tspan + style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:22.5px;line-height:125%;font-family:'Linux Biolinum';-inkscape-font-specification:'Linux Biolinum, Normal';text-align:center;writing-mode:lr-tb;text-anchor:middle" + id="tspan4398" + y="355.48218" + x="926.54047" + sodipodi:role="line">Box</tspan></text> + </g> + <g + id="g4857" + transform="translate(-20.571429,-45.714286)"> + <text + sodipodi:linespacing="125%" + id="text4376" + y="423.81677" + x="562.66595" + style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:22.5px;line-height:125%;font-family:'Linux Biolinum';-inkscape-font-specification:'Linux Biolinum, Normal';text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" + xml:space="preserve"><tspan + style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:22.5px;line-height:125%;font-family:'Linux Biolinum';-inkscape-font-specification:'Linux Biolinum, Normal';text-align:center;writing-mode:lr-tb;text-anchor:middle" + y="423.81677" + x="562.66595" + id="tspan4378" + sodipodi:role="line">Generator</tspan><tspan + style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:22.5px;line-height:125%;font-family:'Linux Biolinum';-inkscape-font-specification:'Linux Biolinum, Normal';text-align:center;writing-mode:lr-tb;text-anchor:middle" + id="tspan4380" + y="451.94177" + x="562.66595" + sodipodi:role="line">(SSF/Flow-Analyse)</tspan></text> + <ellipse + ry="60.776478" + rx="122.65497" + cy="433.13867" + cx="562.65497" + id="path4455" + style="fill:none;fill-opacity:1;stroke:#000000;stroke-width:2;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" /> + </g> + <g + id="g4768" + transform="translate(43.609345,-47.142787)"> + <text + sodipodi:linespacing="125%" + id="text4364" + y="85.783752" + x="69.079865" + style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:22.5px;line-height:125%;font-family:'Linux Biolinum';-inkscape-font-specification:'Linux Biolinum, Normal';text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" + xml:space="preserve"><tspan + style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:22.5px;line-height:125%;font-family:'Linux Biolinum';-inkscape-font-specification:'Linux Biolinum, Normal';text-align:start;writing-mode:lr-tb;text-anchor:start" + y="85.783752" + x="69.079865" + id="tspan4366" + sodipodi:role="line">Generator</tspan><tspan + style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:22.5px;line-height:125%;font-family:'Linux Biolinum';-inkscape-font-specification:'Linux Biolinum, Normal';text-align:start;writing-mode:lr-tb;text-anchor:start" + id="tspan4368" + y="113.90875" + x="69.079865" + sodipodi:role="line">(enumerate/SSE)</tspan></text> + <ellipse + ry="42.375416" + rx="106.39066" + cy="94.73761" + cx="146.39066" + id="path4457" + style="fill:none;fill-opacity:1;stroke:#000000;stroke-width:2;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" /> + </g> + <g + id="g4851" + transform="translate(-2.939133,-122.92868)"> + <text + sodipodi:linespacing="125%" + id="text4370" + y="493.51733" + x="192.95012" + style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:22.5px;line-height:125%;font-family:'Linux Biolinum';-inkscape-font-specification:'Linux Biolinum, Normal';text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" + xml:space="preserve"><tspan + style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:22.5px;line-height:125%;font-family:'Linux Biolinum';-inkscape-font-specification:'Linux Biolinum, Normal';text-align:center;writing-mode:lr-tb;text-anchor:middle" + y="493.51733" + x="192.95012" + id="tspan4372" + sodipodi:role="line">Generator</tspan><tspan + style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:22.5px;line-height:125%;font-family:'Linux Biolinum';-inkscape-font-specification:'Linux Biolinum, Normal';text-align:center;writing-mode:lr-tb;text-anchor:middle" + id="tspan4374" + y="521.64233" + x="192.95012" + sodipodi:role="line">(merge/Construct GCFG)</tspan></text> + <ellipse + ry="50.477039" + rx="132.93913" + cy="502.83923" + cx="192.93913" + id="path4459" + style="fill:none;fill-opacity:1;stroke:#000000;stroke-width:2;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" /> + </g> + <g + id="g4947" + transform="translate(-47.66069,-192.08773)"> + <text + sodipodi:linespacing="125%" + id="text4382" + y="887.30475" + x="158.91069" + style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:22.5px;line-height:125%;font-family:'Linux Biolinum';-inkscape-font-specification:'Linux Biolinum, Normal';text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" + xml:space="preserve"><tspan + y="887.30475" + x="158.91069" + id="tspan4384" + sodipodi:role="line">Generator Coder</tspan></text> + <ellipse + ry="33.07526" + rx="96.232117" + cy="879.55945" + cx="237.66069" + id="path4463" + style="fill:none;fill-opacity:1;stroke:#000000;stroke-width:2.51954889;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" /> + </g> + <g + id="g4952" + transform="translate(-7.506905,-187.06884)"> + <text + sodipodi:linespacing="125%" + id="text4419" + y="974.07507" + x="157.33868" + style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:22.5px;line-height:125%;font-family:'Linux Biolinum';-inkscape-font-specification:'Linux Biolinum, Normal';text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" + xml:space="preserve"><tspan + y="974.07507" + x="157.33868" + id="tspan4421" + sodipodi:role="line">dosec.cc</tspan></text> + <rect + y="939.75012" + x="135.01381" + height="52.612072" + width="124.98619" + id="rect4465" + style="fill:none;fill-opacity:1;stroke:#000000;stroke-width:2;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" /> + </g> + <g + id="g4957" + transform="translate(86.127602,-15.194316)"> + <text + sodipodi:linespacing="125%" + id="text4386" + y="884.85437" + x="60.432457" + style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:22.5px;line-height:125%;font-family:'Linux Biolinum';-inkscape-font-specification:'Linux Biolinum, Normal';text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" + xml:space="preserve"><tspan + y="884.85437" + x="60.432457" + id="tspan4388" + sodipodi:role="line">Compiler</tspan></text> + <ellipse + ry="27.279163" + rx="73.872398" + cy="879.64136" + cx="103.8724" + id="path4467" + style="fill:none;fill-opacity:1;stroke:#000000;stroke-width:2;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" /> + </g> + <g + id="g4962" + transform="translate(73.419136,-44.64976)"> + <text + sodipodi:linespacing="125%" + id="text4390" + y="1002.5957" + x="45.344467" + style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:22.5px;line-height:125%;font-family:'Linux Biolinum';-inkscape-font-specification:'Linux Biolinum, Normal';text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" + xml:space="preserve"><tspan + y="1002.5957" + x="45.344467" + id="tspan4392" + sodipodi:role="line">System-Binary</tspan></text> + <rect + y="968.25049" + x="33.16172" + height="54.111706" + width="166.83829" + id="rect4469" + style="fill:none;fill-opacity:1;stroke:#000000;stroke-width:2;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" /> + </g> + <text + xml:space="preserve" + style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:30px;line-height:125%;font-family:'Linux Biolinum';-inkscape-font-specification:'Linux Biolinum, Normal';text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" + x="380" + y="-337.63782" + id="text4676" + sodipodi:linespacing="125%"><tspan + sodipodi:role="line" + id="tspan4678" + x="380" + y="-337.63782" /></text> + <text + xml:space="preserve" + style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:22.5px;line-height:125%;font-family:'Linux Biolinum';-inkscape-font-specification:'Linux Biolinum, Normal';text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" + x="430" + y="-293.19626" + id="text4680" + sodipodi:linespacing="125%"><tspan + sodipodi:role="line" + id="tspan4682" + x="430" + y="-293.19626">clang</tspan></text> + <text + xml:space="preserve" + style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:22.5px;line-height:125%;font-family:'Linux Biolinum';-inkscape-font-specification:'Linux Biolinum, Normal';text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" + x="504.24622" + y="-205.7417" + id="text4684" + sodipodi:linespacing="125%"><tspan + sodipodi:role="line" + id="tspan4686" + x="504.24622" + y="-205.7417">extractor</tspan></text> + <flowRoot + xml:space="preserve" + id="flowRoot4708" + style="fill:black;stroke:none;stroke-opacity:1;stroke-width:1px;stroke-linejoin:miter;stroke-linecap:butt;fill-opacity:1;font-family:'Linux Biolinum';font-style:normal;font-weight:normal;font-size:22.5px;line-height:125%;letter-spacing:0px;word-spacing:0px;-inkscape-font-specification:'Linux Biolinum, Normal';font-stretch:normal;font-variant:normal;text-anchor:start;text-align:start;writing-mode:lr"><flowRegion + id="flowRegion4710"><rect + id="rect4712" + width="290" + height="220" + x="860" + y="738.18896" /></flowRegion><flowPara + id="flowPara4714" /></flowRoot> <text + xml:space="preserve" + style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:22.5px;line-height:125%;font-family:'Linux Biolinum';-inkscape-font-specification:'Linux Biolinum, Normal';text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" + x="951.09015" + y="98.448753" + id="text4722" + sodipodi:linespacing="125%"><tspan + sodipodi:role="line" + id="tspan4724" + x="951.09015" + y="98.448753">clang</tspan></text> + <path + style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;marker-end:url(#Arrow2Lend)" + d="m 407.83594,-324.44993 0,52.12525" + id="path4967" + inkscape:connector-type="polyline" + inkscape:connector-curvature="0" + inkscape:connection-start="#g4645" + inkscape:connection-end="#g4650" /> + <path + style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;marker-end:url(#marker5257)" + d="m 407.83594,-222.32468 0,44.46792" + id="path5249" + inkscape:connector-type="polyline" + inkscape:connector-curvature="0" + inkscape:connection-start="#g4650" + inkscape:connection-end="#g4655" /> + <path + style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;marker-end:url(#marker5293)" + d="m 407.59655,-199.41986 235.87062,0 0,22.72843" + id="path5285" + inkscape:connector-curvature="0" /> + <path + style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;marker-end:url(#marker5335)" + d="m 644.97984,-114.70887 0,16.261778" + id="path5327" + inkscape:connector-type="polyline" + inkscape:connector-curvature="0" + inkscape:connection-start="#g4688" + inkscape:connection-end="#g4665" /> + <path + style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;marker-end:url(#marker5383)" + d="m 644.97984,-11.077035 0,16.2615929" + id="path5375" + inkscape:connector-type="polyline" + inkscape:connector-curvature="0" + inkscape:connection-start="#g4665" + inkscape:connection-end="#g4671" /> + <path + style="display:inline;fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:1.08828819px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;marker-end:url(#marker5437)" + d="m 488.91383,-65.371578 50.72868,0.04301" + id="path5429" + inkscape:connector-type="polyline" + inkscape:connector-curvature="0" /> + <path + style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;marker-end:url(#marker5497)" + d="m 927.97969,56.681908 0,73.151552" + id="path5489" + inkscape:connector-type="polyline" + inkscape:connector-curvature="0" + inkscape:connection-end="#g4698" /> + <path + style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;marker-end:url(#marker5563)" + d="m 927.97969,181.19412 0,27.0564" + id="path5555" + inkscape:connector-type="polyline" + inkscape:connector-curvature="0" + inkscape:connection-start="#g4698" + inkscape:connection-end="#g4703" /> + <path + style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;marker-end:url(#marker5635)" + d="m 927.97969,258.25051 0,27.05636" + id="path5627" + inkscape:connector-type="polyline" + inkscape:connector-curvature="0" + inkscape:connection-start="#g4703" /> + <path + style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;marker-end:url(#marker5713)" + d="m 927.97969,382.04177 0,27.05638" + id="path5705" + inkscape:connector-type="polyline" + inkscape:connector-curvature="0" /> + <path + style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;marker-end:url(#marker5797)" + d="m 709.97984,31.086414 167.99985,2.330945" + id="path5789" + inkscape:connector-type="polyline" + inkscape:connector-curvature="0" + inkscape:connection-start="#g4671" /> + <path + style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;marker-end:url(#marker5889)" + d="M 190,-237.6378 190,5.2194071" + id="path5881" + inkscape:connector-type="polyline" + inkscape:connector-curvature="0" + inkscape:connection-start="#g4634" + inkscape:connection-end="#g4768" /> + <path + style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;marker-end:url(#marker6195)" + d="m 190,430.38759 0,31.87453" + id="path6187" + inkscape:connector-type="polyline" + inkscape:connector-curvature="0" + inkscape:connection-start="#g4851" /> + <path + style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;marker-end:url(#marker6309)" + d="m 190,622.26214 0,32.13432" + id="path6301" + inkscape:connector-type="polyline" + inkscape:connector-curvature="0" + inkscape:connection-end="#g4947" /> + <path + style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;marker-end:url(#marker6429)" + d="m 190,720.54698 0,32.1343" + id="path6421" + inkscape:connector-type="polyline" + inkscape:connector-curvature="0" + inkscape:connection-start="#g4947" + inkscape:connection-end="#g4952" /> + <path + style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;marker-end:url(#marker6555)" + d="m 190,805.29335 0,31.87453" + id="path6547" + inkscape:connector-type="polyline" + inkscape:connector-curvature="0" + inkscape:connection-start="#g4952" + inkscape:connection-end="#g4957" /> + <path + style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;marker-end:url(#marker6687)" + d="m 190,891.7262 0,31.87453" + id="path6679" + inkscape:connector-type="polyline" + inkscape:connector-curvature="0" + inkscape:connection-start="#g4957" + inkscape:connection-end="#g4962" /> + <path + style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;marker-end:url(#marker6825)" + d="m 325,-77.63781 -40,0 0,-135 121.96954,0" + id="path6817" + inkscape:connector-curvature="0" + sodipodi:nodetypes="cccc" /> + <text + xml:space="preserve" + style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:22.5px;line-height:125%;font-family:'Linux Biolinum';-inkscape-font-specification:'Linux Biolinum, Normal';text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" + x="720" + y="-137.64761" + id="text6985" + sodipodi:linespacing="125%"><tspan + sodipodi:role="line" + id="tspan6987" + x="720" + y="-137.64761">CFGs</tspan></text> + <g + id="g8167" + transform="translate(0,20)"> + <text + sodipodi:linespacing="125%" + id="text4493" + y="225.59927" + x="90.147278" + style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:18.14643669px;line-height:125%;font-family:'Linux Biolinum';-inkscape-font-specification:'Linux Biolinum, Normal';text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" + xml:space="preserve"><tspan + y="225.59927" + x="90.147278" + id="tspan4495" + sodipodi:role="line">ABB1</tspan></text> + <text + sodipodi:linespacing="125%" + id="text4497" + y="181.49545" + x="159.35971" + style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:18.14643669px;line-height:125%;font-family:'Linux Biolinum';-inkscape-font-specification:'Linux Biolinum, Normal';text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" + xml:space="preserve"><tspan + y="181.49545" + x="159.35971" + id="tspan4499" + sodipodi:role="line">ABB2</tspan></text> + <text + sodipodi:linespacing="125%" + id="text4501" + y="260.59448" + x="159.35971" + style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:18.14643669px;line-height:125%;font-family:'Linux Biolinum';-inkscape-font-specification:'Linux Biolinum, Normal';text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" + xml:space="preserve"><tspan + y="260.59448" + x="159.35971" + id="tspan4503" + sodipodi:role="line">ABB3</tspan></text> + <text + sodipodi:linespacing="125%" + id="text4505" + y="260.48108" + x="251.56738" + style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:18.14643669px;line-height:125%;font-family:'Linux Biolinum';-inkscape-font-specification:'Linux Biolinum, Normal';text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" + xml:space="preserve"><tspan + y="260.48108" + x="251.56738" + id="tspan4507" + sodipodi:role="line">ABB4</tspan></text> + <rect + y="101.84472" + x="61.428574" + height="175.71426" + width="257.14285" + id="rect4509" + style="fill:none;fill-opacity:1;stroke:#000000;stroke-width:2;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" /> + <g + id="g7500"> + <circle + style="fill:none;fill-opacity:1;stroke:#000000;stroke-width:2;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" + id="path4471" + cx="107.14286" + cy="187.55899" + r="15.275557" /> + <rect + style="fill:none;fill-opacity:1;stroke:#000000;stroke-width:2;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" + id="rect4792" + width="40" + height="40" + x="87.14286" + y="167.55899" /> + </g> + <g + id="g7504"> + <circle + r="15.275557" + cy="143.27327" + cx="178" + id="circle4800" + style="fill:none;fill-opacity:1;stroke:#000000;stroke-width:2;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" /> + <rect + y="123.27327" + x="158" + height="40" + width="40" + id="rect4802" + style="fill:none;fill-opacity:1;stroke:#000000;stroke-width:2;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" /> + </g> + <g + id="g7508"> + <circle + style="fill:none;fill-opacity:1;stroke:#000000;stroke-width:2;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" + id="circle4806" + cx="178" + cy="223.27327" + r="15.275557" /> + <rect + style="fill:none;fill-opacity:1;stroke:#000000;stroke-width:2;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" + id="rect4808" + width="40" + height="40" + x="158" + y="203.27327" /> + </g> + <g + id="g7512"> + <circle + style="fill:none;fill-opacity:1;stroke:#000000;stroke-width:2;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" + id="circle4812" + cx="268.28574" + cy="146.13042" + r="15.275557" /> + <rect + style="fill:none;fill-opacity:1;stroke:#000000;stroke-width:2;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" + id="rect4814" + width="46.285706" + height="117.14288" + x="245.14287" + y="126.13041" /> + <circle + r="15.275557" + cy="221.8447" + cx="268.28574" + id="circle4818" + style="fill:none;fill-opacity:1;stroke:#000000;stroke-width:2;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" /> + </g> + <path + sodipodi:nodetypes="cc" + inkscape:connector-curvature="0" + id="path7517" + d="m 120,177.36219 43.57143,-24.28571" + style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;marker-end:url(#marker7169)" /> + <path + sodipodi:nodetypes="cc" + inkscape:connector-curvature="0" + id="path7531" + d="m 120,197.36219 43.57143,19.28571" + style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;marker-end:url(#marker7539)" /> + <path + inkscape:connector-curvature="0" + id="path7831" + d="m 195,222.36219 55,0" + style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;marker-end:url(#marker7839)" /> + <path + inkscape:connector-curvature="0" + id="path7993" + d="m 195,142.36219 55,0" + style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;marker-end:url(#marker8001)" /> + </g> + <path + style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;marker-end:url(#marker8575)" + d="m 190,89.970239 0,31.874481" + id="path8567" + inkscape:connector-type="polyline" + inkscape:connector-curvature="0" + inkscape:connection-start="#g4768" + inkscape:connection-end="#g8167" /> + <path + style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;marker-end:url(#marker8737)" + d="m 190,297.55898 0,31.87453" + id="path8729" + inkscape:connector-type="polyline" + inkscape:connector-curvature="0" + inkscape:connection-start="#g8167" + inkscape:connection-end="#g4851" /> + <g + id="g9635" + transform="translate(0,20)"> + <g + transform="translate(50,9.8999414)" + id="g4940"> + <rect + y="432.36218" + x="20" + height="160.00002" + width="240" + id="rect4881" + style="fill:none;fill-opacity:1;stroke:#000000;stroke-width:2;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" /> + <rect + y="496.64789" + x="38.57143" + height="40" + width="40" + id="rect4887" + style="fill:none;fill-opacity:1;stroke:#000000;stroke-width:2;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" /> + <rect + style="fill:none;fill-opacity:1;stroke:#000000;stroke-width:2;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" + id="rect4893" + width="40" + height="40" + x="109.42857" + y="452.36218" /> + <rect + y="532.36218" + x="109.42857" + height="40" + width="40" + id="rect4899" + style="fill:none;fill-opacity:1;stroke:#000000;stroke-width:2;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" /> + <rect + y="455.2193" + x="196.57144" + height="117.14288" + width="46.285706" + id="rect4905" + style="fill:none;fill-opacity:1;stroke:#000000;stroke-width:2;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" /> + </g> + <path + inkscape:connector-curvature="0" + id="path8897" + d="m 127.85714,505.93362 30.35715,-16.78571" + style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;marker-end:url(#marker8905)" /> + <path + inkscape:connector-curvature="0" + id="path9071" + d="m 129.64286,541.29077 28.21428,15.35714" + style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;marker-end:url(#marker9079)" /> + <path + inkscape:connector-curvature="0" + id="path9251" + d="m 200.35714,565.93363 45,0" + style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;marker-end:url(#marker9259)" /> + <path + inkscape:connector-curvature="0" + id="path9437" + d="m 200.35714,483.43362 45,0" + style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;marker-end:url(#marker9445)" /> + </g> + <path + style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;marker-end:url(#marker9655)" + d="m 320,-147.63781 -300,0 0,1000.00004 100,0" + id="path9647" + inkscape:connector-curvature="0" + sodipodi:nodetypes="cccc" /> + <path + style="display:inline;fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;marker-end:url(#marker10003)" + d="M 579.97984,30.629794 290.41886,32.613218" + id="path9995" + inkscape:connector-type="polyline" + inkscape:connector-curvature="0" + inkscape:connection-start="#g4671" /> + <path + style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;marker-end:url(#marker10207)" + d="m 640,55.933619 0,296.428571" + id="path10199" + inkscape:connector-curvature="0" + sodipodi:nodetypes="cc" /> + <path + style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;marker-end:url(#marker10417)" + d="m 188.57143,-27.63781 291.42857,0 0,360" + id="path10409" + inkscape:connector-curvature="0" + sodipodi:nodetypes="ccc" /> + <path + style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;marker-end:url(#marker10669)" + d="m 540,448.32158 0,84.04061 -228.5863,0" + id="path10661" + inkscape:connector-curvature="0" + sodipodi:nodetypes="ccc" /> + <text + xml:space="preserve" + style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:22.5px;line-height:125%;font-family:'Linux Biolinum';-inkscape-font-specification:'Linux Biolinum, Normal';text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" + x="-228.40007" + y="50.637924" + id="text11033" + sodipodi:linespacing="125%" + transform="matrix(0,-1,1,0,0,0)"><tspan + sodipodi:role="line" + id="tspan11035" + x="-228.40007" + y="50.637924">STG</tspan></text> + <text + xml:space="preserve" + style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:22.5px;line-height:125%;font-family:'Linux Biolinum';-inkscape-font-specification:'Linux Biolinum, Normal';text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" + x="-569.78381" + y="58.691689" + id="text11037" + sodipodi:linespacing="125%" + transform="matrix(0,-1,1,0,0,0)"><tspan + sodipodi:role="line" + id="tspan11039" + x="-569.78381" + y="58.691689">GCFG</tspan></text> + <text + xml:space="preserve" + style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:22.5px;line-height:125%;font-family:'Linux Biolinum';-inkscape-font-specification:'Linux Biolinum, Normal';text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#008080;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;" + x="740" + y="22.362194" + id="text11041" + sodipodi:linespacing="125%"><tspan + sodipodi:role="line" + id="tspan11043" + x="740" + y="22.362194">Mockup</tspan></text> + <path + style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;marker-end:url(#marker11125)" + d="m 251.42857,772.36223 528.57143,0 0,-540.00004 60,0" + id="path11117" + inkscape:connector-curvature="0" + sodipodi:nodetypes="cccc" /> + <text + xml:space="preserve" + style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:22.5px;line-height:125%;font-family:'Linux Biolinum';-inkscape-font-specification:'Linux Biolinum, Normal';text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" + x="500" + y="760.36218" + id="text11381" + sodipodi:linespacing="125%"><tspan + sodipodi:role="line" + id="tspan11383" + x="500" + y="760.36218">clang</tspan></text> + <g + id="g13141" + transform="translate(0,20)"> + <g + transform="translate(47.979695,-203.26403)" + id="g4738"> + <circle + style="fill:none;fill-opacity:1;stroke:#000000;stroke-width:2;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" + id="path4594" + cx="812.72333" + cy="613.93634" + r="10.308278" /> + <circle + r="10.308278" + cy="633.16943" + cx="880.50647" + id="circle4600" + style="fill:none;fill-opacity:1;stroke:#000000;stroke-width:2;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" /> + <circle + style="fill:none;fill-opacity:1;stroke:#000000;stroke-width:2;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" + id="circle4602" + cx="846.29675" + cy="613.93634" + r="10.308278" /> + <rect + style="fill:none;fill-opacity:1;stroke:#000000;stroke-width:2;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" + id="rect4604" + width="180" + height="60.000011" + x="790" + y="592.36218" /> + <circle + r="10.308278" + cy="613.95667" + cx="915.75891" + id="circle4734" + style="fill:none;fill-opacity:1;stroke:#000000;stroke-width:2;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" /> + <circle + r="10.308278" + cy="613.95667" + cx="949.33234" + id="circle4736" + style="fill:none;fill-opacity:1;stroke:#000000;stroke-width:2;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" /> + </g> + <path + inkscape:connector-curvature="0" + id="path11385" + d="m 918.57143,424.14791 -13.92857,-8.92857" + style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;marker-end:url(#Arrow2Mend)" /> + <path + inkscape:connector-curvature="0" + id="path12337" + d="m 882.85714,410.21934 -10.71428,0" + style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;marker-end:url(#marker12345)" /> + <path + inkscape:connector-curvature="0" + id="path12595" + d="m 938.57143,424.86219 14.28571,-9.64285" + style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;marker-end:url(#marker12603)" /> + <path + inkscape:connector-curvature="0" + id="path12859" + d="m 974.64286,410.57648 11.07143,0" + style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;marker-end:url(#marker12867)" /> + </g> + <text + xml:space="preserve" + style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:22.5px;line-height:125%;font-family:'Linux Biolinum';-inkscape-font-specification:'Linux Biolinum, Normal';text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" + x="-245.60925" + y="468.2764" + id="text13154" + sodipodi:linespacing="125%" + transform="matrix(0,-1,1,0,0,0)"><tspan + sodipodi:role="line" + id="tspan13156" + x="-245.60925" + y="468.2764">Variante</tspan></text> + </g> +</svg> diff --git a/doc/logo.png b/doc/logo.png new file mode 100644 index 0000000000000000000000000000000000000000..82b0f4ef666577aa0806fb1e11a5768e398cd757 Binary files /dev/null and b/doc/logo.png differ diff --git a/generator/analysis/ABBMergePass.py b/generator/analysis/ABBMergePass.py index 5328fd7fcf47ab995b796965d0af6f7b918a7106..1c1ae6852780959a5eb95e1e5a0410e0c2749a3c 100644 --- a/generator/analysis/ABBMergePass.py +++ b/generator/analysis/ABBMergePass.py @@ -101,11 +101,18 @@ class ABBMergePass(Analysis): parent_function = entry_abb.function - # adopt basic blocks + # adopt basic blocks and call sites for abb in (inner_abbs | {exit_abb}) - {entry_abb}: for bb in abb.basic_blocks: entry_abb.basic_blocks.append(bb) # adopt llvm basic blocks + # Collect all call sites + entry_abb.call_sites.extend(abb.call_sites) + # We merge everything into the entry block of a region. + # Therefore, we just update the exit node of the entry to + # preserve a correct entry/exit region + entry_abb.basic_block_exit = exit_abb.basic_block_exit + # adopt outgoing edges for target in exit_abb.get_outgoing_nodes(E.function_level): exit_abb.remove_cfg_edge(target, E.function_level) diff --git a/generator/analysis/AtomicBasicBlock.py b/generator/analysis/AtomicBasicBlock.py index 0f60a85b73b55e979d8227ca0cfe775e246f3e6e..38481727d3a9f5e3fde7aa9f4e965931cab40a89 100644 --- a/generator/analysis/AtomicBasicBlock.py +++ b/generator/analysis/AtomicBasicBlock.py @@ -32,9 +32,17 @@ class AtomicBasicBlock(Node): # Function called in this ABB self.directly_called_function = None self.directly_called_function_name = None + self.call_sites = [] # List of all LLVM Basic Block Names + assert len(llvmbbs) <= 1, llvmbbs + if llvmbbs: + self.basic_block_entry = llvmbbs[0] + self.basic_block_exit = llvmbbs[0] + else: + self.basic_block_entry = None + self.basic_block_exit = None self.basic_blocks = llvmbbs # How many sporadic events can fire from here. This field will diff --git a/generator/analysis/LLVMPYAnalysis.py b/generator/analysis/LLVMPYAnalysis.py index 8d9b82b5e7131359c6e445065170cf2373d66a24..5b260ebfbb76b686debb8fe9431c7660948c0983 100644 --- a/generator/analysis/LLVMPYAnalysis.py +++ b/generator/analysis/LLVMPYAnalysis.py @@ -145,8 +145,10 @@ class LLVMPYAnalysis(Analysis): # Block contains a call if "call" in bb_struct: - callee = bb_struct["call"] + (callee, args) = bb_struct["call"], bb_struct["arguments"] + abbs[bb_name].directly_called_function_name = callee + abbs[bb_name].call_sites.append( (bb_name, callee, args) ) callee = self.system_graph.find(Function, callee) if callee: abbs[bb_name].directly_called_function = callee diff --git a/generator/analysis/OILReadPass.py b/generator/analysis/OILReadPass.py index 54b8b35480996ec7856f35d4ffa82607081a7ef9..5b7358914711585a26cfc0f329ce0c71f5054d0a 100644 --- a/generator/analysis/OILReadPass.py +++ b/generator/analysis/OILReadPass.py @@ -189,6 +189,7 @@ class OILReadPass(Analysis): pred_syscall.add_cfg_edge(cc, E.function_level) else: subtask.set_entry_abb(cc) + alarm_object.carried_checkalarm = cc subtask.add_atomic_basic_block(alarm_object.carried_syscall) cc.add_cfg_edge(alarm_object.carried_syscall, E.function_level) @@ -222,5 +223,3 @@ class OILReadPass(Analysis): for obj in oil.getCheckedObjects(): graph._checkedObjects[obj.name] = obj - - diff --git a/generator/analysis/OILSystemDescription.py b/generator/analysis/OILSystemDescription.py index 6a8ec28529d01bf7b77a3ce5ec95252128b84d55..03a7019059d214e51972a07131ecccb053b992da 100755 --- a/generator/analysis/OILSystemDescription.py +++ b/generator/analysis/OILSystemDescription.py @@ -304,9 +304,9 @@ class Task(OILObject): for appmode in param[2:]: if appmode[0] == "APPMODE": self.autostart_appmodes[appmode[1]] = appmode[1] - if param[0] == "RESOURCE": + elif param[0] == "RESOURCE": self.resources[param[1]] = param[1]; - if param[0] == "EVENT": + elif param[0] == "EVENT": self.events[param[1]] = param[1]; @property @@ -377,6 +377,8 @@ class ISR(OILObject): self.autostart = False self.static_priority = None self.is_isr = True + self.__interarival_times = {'min': None, 'max': None} + def get_device(self): assert self.DEVICE, "No device number set for ISR '" + self.name + "'" @@ -393,12 +395,21 @@ class ISR(OILObject): def isr_device(self): return self.get_device() + @property + def interarival_times(self): + return self.__interarival_times + + def evaluate(self, oil): super(ISR, self).evaluate(oil) for param in oil[1]: if param[0] == "RESOURCE": self.resources[param[1]] = param[1] + elif param[0] == "MINIAT": + self.__interarival_times['min'] = int(param[1]) + elif param[0] == "MAXIAT": + self.__interarival_times['max'] = int(param[1]) def __str__(self): ret = super(ISR, self).__str__() diff --git a/generator/analysis/SystemGraph.py b/generator/analysis/SystemGraph.py index b55f647a2de1d93ae0c683c0ca5b3018a27060dc..0dc95b8f81454376b22b19481205be6c8df44f1d 100644 --- a/generator/analysis/SystemGraph.py +++ b/generator/analysis/SystemGraph.py @@ -25,6 +25,8 @@ class SystemGraph(GraphObject, PassManager): self.autostart = True self.basic_task = False self.max_activations = 0 + self.interarival_times = {'min': None, 'max': None} + def __init__(self, configuration): GraphObject.__init__(self, "SystemGraph", root=True) diff --git a/generator/analysis/types.py b/generator/analysis/types.py index 7753ed8a004d39cf95bc72144b2ec9863c48dca8..22a61e5b05a0b55332b7de18b43d366692af62c1 100644 --- a/generator/analysis/types.py +++ b/generator/analysis/types.py @@ -15,6 +15,11 @@ class ControlFlowEdgeLevel(IntEnum): state_flow = 20 state_flow_irq = 21 + timing_edge_0 = 30 + timing_edge_1 = 31 + + + @classmethod def color(cls, level): @@ -26,6 +31,8 @@ class ControlFlowEdgeLevel(IntEnum): cls.state_transition: 'black', cls.state_flow: 'darkorchid2', cls.state_flow_irq: 'gold1', + cls.timing_edge_0: 'violet', + cls.timing_edge_1: 'orange', } return ret[level] diff --git a/generator/attributor/CMakeLists.txt b/generator/attributor/CMakeLists.txt index 2258059d8b679cba519fd50ec5df172d2e66a018..19045980a11657bff0a0138d17b4c5a90333a2af 100644 --- a/generator/attributor/CMakeLists.txt +++ b/generator/attributor/CMakeLists.txt @@ -1,21 +1,24 @@ +# WARNING: THIS SUBDIRECTORY IS COMPILED FOR HOST +USE_HOST_COMPILER() + # Get the directory of llvm by using llvm-config. also remove whitespaces. -execute_process(COMMAND ${LLVM_CONFIG_EXE} --includedir +execute_process(COMMAND ${TC_TARGET_LLVM_CONFIG} --includedir OUTPUT_VARIABLE LLVM_INCLUDE_DIRS OUTPUT_STRIP_TRAILING_WHITESPACE ) -execute_process(COMMAND ${LLVM_CONFIG_EXE} --cxxflags +execute_process(COMMAND ${TC_TARGET_LLVM_CONFIG} --cxxflags OUTPUT_VARIABLE LLVM_CXX_FLAGS OUTPUT_STRIP_TRAILING_WHITESPACE ) - execute_process(COMMAND ${LLVM_CONFIG_EXE} --ldflags + execute_process(COMMAND ${TC_TARGET_LLVM_CONFIG} --ldflags OUTPUT_VARIABLE LLVM_LD_FLAGS OUTPUT_STRIP_TRAILING_WHITESPACE ) -execute_process(COMMAND ${LLVM_CONFIG_EXE} --libs all +execute_process(COMMAND ${TC_TARGET_LLVM_CONFIG} --libs all OUTPUT_VARIABLE LLVM_LIBS OUTPUT_STRIP_TRAILING_WHITESPACE ) - include_directories(${LLVM_INCLUDE_DIRS}) -set(CMAKE_CXX_FLAGS "-fno-rtti -std=c++11 ${LLVM_CXX_FLAGS}") + +set(CMAKE_CXX_FLAGS "-fno-rtti -std=c++11 ${LLVM_CXX_FLAGS} -Wl,-rpath=${TC_TARGET_LLVM_ROOT}/lib") set(CMAKE_EXE_LINKER_FLAGS "${LLVM_LD_FLAGS}") # Now build our tools diff --git a/generator/attributor/main.cc b/generator/attributor/main.cc index 4a916e5098cc8845c154fbc62f10251cc10bedfc..4b1cfefd93d7254cba80cbc77f5ebae393c1d7fb 100644 --- a/generator/attributor/main.cc +++ b/generator/attributor/main.cc @@ -12,13 +12,27 @@ // //===----------------------------------------------------------------------===// -//3.6 #include <llvm/Linker/Linker.h> -//3.6 #include <llvm/IR/Verifier.h> -//3.6 #include <llvm/IR/CFG.h> +#include <llvm/Config/llvm-config.h> + +#if LLVM_VERSION_MAJOR >= 3 && LLVM_VERSION_MINOR >= 8 +#undef LLVM_LEGACY +#else +#define LLVM_LEGACY 1 +#endif +#ifdef LLVM_LEGACY + #include <llvm/Support/CFG.h> #include <llvm/Linker.h> #include <llvm/Analysis/Verifier.h> +#else + +#include <llvm/Linker/Linker.h> +#include <llvm/IR/Verifier.h> +#include <llvm/IR/CFG.h> + +#endif + #include <llvm/Bitcode/ReaderWriter.h> #include <llvm/IR/LLVMContext.h> #include <llvm/IR/Instructions.h> @@ -77,12 +91,18 @@ static inline std::unique_ptr<Module> LoadFile(const char *argv0, const std::str LLVMContext& Context) { SMDiagnostic Err; if (Verbose) errs() << "Loading '" << FN << "'\n"; - //3.6 std::unique_ptr<Module> Result = 0; - //3.6 Result = parseIRFile(FN, Err, Context); + +#ifdef LLVM_LEGACY Module* Result = 0; Result = ParseIRFile(FN, Err, Context); if (Result) return std::unique_ptr<Module>(Result); // Load successful! +#else + + std::unique_ptr<Module> Result = 0; + Result = parseIRFile(FN, Err, Context); + if (Result) return Result; +#endif Err.print(argv0, errs()); return NULL; @@ -90,10 +110,16 @@ static inline std::unique_ptr<Module> LoadFile(const char *argv0, const std::str int main(int argc, char **argv) { // Print a stack trace if we signal out. +#ifdef LLVM_LEGACY sys::PrintStackTraceOnErrorSignal(); + LLVMContext &Context = getGlobalContext(); +#else + sys::PrintStackTraceOnErrorSignal(argv[0]); + LLVMContext Context; +#endif PrettyStackTraceProgram X(argc, argv); - LLVMContext &Context = getGlobalContext(); + llvm_shutdown_obj Y; // Call llvm_shutdown() on exit. cl::ParseCommandLineOptions(argc, argv, "llvm dosek attributor\n"); @@ -151,8 +177,15 @@ int main(int argc, char **argv) { if (DumpAsm) errs() << "Here's the assembly:\n" << *Composite; +#ifdef LLVM_LEGACY std::string EC; tool_output_file Out(OutputFilename.c_str(), EC, sys::fs::F_None); +#else + std::error_code ECC; + tool_output_file Out(OutputFilename, ECC, sys::fs::F_None); + std::string EC = ECC.message(); +#endif + if (EC != "") { errs() << EC << '\n'; return 1; diff --git a/generator/coder/__init__.py b/generator/coder/__init__.py index 9e87b5b73ebd71ceb7e1f9594bf4dd61fbfa93dc..f8e90d69fa29fd5c759576a13cc3c38f8e00be53 100644 --- a/generator/coder/__init__.py +++ b/generator/coder/__init__.py @@ -4,6 +4,8 @@ from .arch_generic import GenericArch from .arch_x86 import X86Arch from .arch_arm import ARMArch from .arch_posix import PosixArch +from .arch_patmos import PatmosArch + from .os_generic import GenericOS from .os_encoded import EncodedOS, SignatureGenerator diff --git a/generator/coder/arch_patmos.py b/generator/coder/arch_patmos.py new file mode 100644 index 0000000000000000000000000000000000000000..0b640ff3aa37bf459c7c657c4125d98df3bca849 --- /dev/null +++ b/generator/coder/arch_patmos.py @@ -0,0 +1,134 @@ +from .arch_generic import GenericArch +from .elements import * +import logging +from generator.analysis.Subtask import Subtask + + +class PatmosArch(GenericArch): + def __init__(self): + super(PatmosArch, self).__init__() + + # config-constraint-: (arch.self == patmos) -> !arch.mpu + def generate_linkerscript(self): + """PATMOS does not require a linker script""" + with self.generator.open_file("linker.ld") as fd: + fd.write("IGNORED IN PATMOS") + + def generate_dataobjects(self): + """Generate all dataobjects for the system""" + self.generate_dataobjects_task_stacks() + self.generate_dataobjects_task_entries() # From GenericArch + self.generate_dataobjects_tcbs() + self.generate_dataobject_resources() # We have to generate resource objects, since the patmos compiler is weird. + + def generate_dataobjects_task_stacks(self): + """Generate the stacks for the tasks, including the task pointers""" + # Ignore the Idle thread and ISR subtasks + for subtask in self.system_graph.real_subtasks: + stacksize = subtask.get_stack_size() + stack = DataObjectArray("uint8_t", subtask.name + "_stack", stacksize, + extern_c = True, alignment = 4096) + shadow_stack = DataObjectArray("uint8_t", subtask.name + "_shadow_stack", stacksize, + extern_c = True, alignment = 4096) + self.generator.source_file.data_manager.add(stack) + self.generator.source_file.data_manager.add(shadow_stack) + + + dynamic_context = DataObject("arch::context_t", "OS_" + subtask.name + "_dynamic_context") + self.generator.source_file.data_manager.add(dynamic_context, namespace = ("arch",)) + + subtask.impl.stack = (stack, shadow_stack) + subtask.impl.stackptr = dynamic_context + subtask.impl.stacksize = stacksize + + def generate_dataobjects_tcbs(self): + self.generator.source_file.include("tcb.h") + for subtask in self.system_graph.real_subtasks: + initializer = "(&%s, %s, %s, %s, %s, &%s)" % ( + subtask.impl.entry_function.name, + subtask.impl.stack[0].name, + subtask.impl.stacksize, + subtask.impl.stack[1].name, + subtask.impl.stacksize, + subtask.impl.stackptr.name, + ) + + tcb = DataObject("const arch::TCB", "OS_" + subtask.name + "_tcb", + initializer) + tcb.allocation_prefix = "constexpr " + self.generator.source_file.data_manager.add(tcb, namespace = ("arch",)) + subtask.impl.tcb_descriptor = tcb + + def generate_dataobject_resources(self): + for resource in self.system_graph.resources: + res = DataObject("const ResourceType", "OSEKOS_RESOURCE_" + resource.name, + str(resource.conf.static_priority), + extern_c=True) + self.generator.source_file.data_manager.add(res) + + + + def generate_isr(self, isr): + isr_desc = self.generator.system_graph.get(Subtask, isr.name) + + kickoff, iret = isr.entry_abb, isr.exit_abb + kickoff_size = kickoff.impl.kernelspace.statement_count() \ + + kickoff.impl.pre_hook.statement_count() \ + + kickoff.impl.post_hook.statement_count() + iret_size = iret.impl.kernelspace.statement_count() \ + + iret.impl.pre_hook.statement_count() \ + + iret.impl.post_hook.statement_count() + + if kickoff_size: + logging.warning("Removing Statements from ISR kickoff: %s" % isr_desc) + if iret_size: + logging.warning("Removing Statements from ISR kickoff: %s" % isr_desc) + + forward = FunctionDeclaration(isr.function_name, + "void", ["const arch::IRQ::Context &"], + extern_c=True) + self.generator.source_file.function_manager.add(forward) + + + def generate_isr_table(self, isrs): + self.generator.source_file.include("machine.h") + for isr in isrs: + self.generate_isr(isr) + + # Add static_irq_dispatch file + tmpl = IRQDispatch(self, "arch/patmos/irq-dispatch.cc.in") + self.generator.source_file.declarations.append(tmpl.expand()) + + if len(self.system_graph.counters) > 0: + self.call(self.system_graph.impl.StartOS, + "arch::IRQ::set_timer_interval", "void", ["10"], + prepend = True) + + + def generate_kernelspace(self, userspace, abb, arguments): + # Use the inline kernelspace variant + return self.generate_kernelspace__inline(userspace, abb, arguments) + + def get_syscall_argument(self, block, i): + name, typename = block.arguments()[i] + return VariableDefinition(typename, name) + +class IRQDispatch(CodeTemplate): + def __init__(self, rules, template): + CodeTemplate.__init__(self, rules.generator, template) + self.rules = rules + self.system_graph = self.generator.system_graph + + def isr_handler_initializer(self, snippet, args): + handlers = [None] * 32 + handlers[2] = "timing_dump_trap" + if len(self.system_graph.counters) > 0: + handlers[17] = "timer_isr" + for isr in self.system_graph.isrs: + i = (isr.handler.conf.isr_device % 16) + 16 + assert handlers[i] is None, "duplicate interrupt number" + handlers[i] = isr.handler.function_name + for i in range(0, 32): + if handlers[i] is None: + handlers[i] = "unexpected_interrupt"; + return ",\n ".join(handlers) diff --git a/generator/coder/elements/DataObjectManager.py b/generator/coder/elements/DataObjectManager.py index 74ab6f219f7428cddb2b7825a3cfa209da3dfb27..6b46a1b65fb3ad52dbe184ffc9963e1d06fea9db 100755 --- a/generator/coder/elements/DataObjectManager.py +++ b/generator/coder/elements/DataObjectManager.py @@ -20,7 +20,7 @@ class DataObject: def __init__(self, typename, name, static_initializer = None, dynamic_initializer = False, - extern_c = False): + extern_c = False, alignment=None): self.typename = typename self.name = name self.static_initializer = static_initializer @@ -30,13 +30,20 @@ class DataObject: self.extern_c = extern_c self.declaration_prefix = "" self.allocation_prefix = "" + self.alignment = alignment - def source_element_declaration(self): - """Builds an extern declaration of the data object""" + def generate_prefix(self): prefix = "extern " if self.extern_c: prefix += '"C" ' - return Statement(self.declaration_prefix + prefix + self.typename + " " + self.name) + if self.alignment: + prefix += "__attribute__((aligned(%s))) " % self.alignment + return self.declaration_prefix + prefix + + def source_element_declaration(self): + """Builds an extern declaration of the data object""" + + return Statement(self.generate_prefix() + self.typename + " " + self.name) def source_element_allocation(self): """Builds an allocation statement for the object. @@ -86,16 +93,13 @@ class ExternalDataObject(DataObject): return "" class DataObjectArray(DataObject): - def __init__(self, typename, name, elements, dynamic_initializer = False, extern_c = False): + def __init__(self, typename, name, elements, dynamic_initializer = False, extern_c = False, alignment=None): DataObject.__init__(self, typename, name, None, dynamic_initializer, - extern_c) + extern_c, alignment) self.elements = elements def source_element_declaration(self): - prefix = "extern " - if self.extern_c: - prefix += '"C" ' - return Statement(self.declaration_prefix + prefix + self.typename + return Statement(self.generate_prefix() + self.typename + " " + self.name + "[" + self.elements + "]") def source_element_initializer(self): @@ -193,5 +197,3 @@ class DataObjectManager: def source_element_initializer(self): # assert False, "Not implemented yet" return [] - - diff --git a/generator/coder/elements/FunctionManager.py b/generator/coder/elements/FunctionManager.py index 7a22b1daf4ea2a6662d08478713aa1e925a66406..dfa363230ec46bddcce453fa39592b5ad0808957 100755 --- a/generator/coder/elements/FunctionManager.py +++ b/generator/coder/elements/FunctionManager.py @@ -72,6 +72,9 @@ class Function: def return_statement(self, expression): self.add(Statement("return %s" % expression)) + def statement_count(self): + return sum([x.statement_count() for x in self.statements]) + class FunctionDeclaration(Function): def __init__(self, name, rettype="void", argstype=[], extern_c = False, attributes = None): @@ -154,4 +157,3 @@ class FunctionManager: ret.append(func.source_element_definitions()) ret.append("\n}\n") return ret - diff --git a/generator/coder/elements/SourceElement.py b/generator/coder/elements/SourceElement.py index 4fce3afa1fb1435cc9adcf2c2ae9a4636e68980e..4cce2da67d5c6d1bb313dd49fecf78dd2271c69a 100755 --- a/generator/coder/elements/SourceElement.py +++ b/generator/coder/elements/SourceElement.py @@ -11,6 +11,9 @@ from generator.tools import format_source_tree class SourceElement(): def __init__(self): pass + def statement_count(self): + return 0 + class Comment(SourceElement): def __init__(self, text): @@ -94,6 +97,9 @@ class Block(SourceElement): def return_statement(self, expression): block.add(Statement("return %s" % expression)) + def statement_count(self): + return sum([x.statement_count() for x in self.inner]) + def __str__(self): return "<<" + ", ".join([str(x) for x in self.inner]) + ">>" @@ -123,6 +129,9 @@ class Statement(SourceElement): def expand(self, generator): return [Indent(), self.statement + ";\n"] + def statement_count(self): + return 1; + class Indent(SourceElement): def __init__(self): SourceElement.__init__(self) @@ -167,6 +176,9 @@ class FunctionCall(SourceElement): return [Statement(statement)] + def statement_count(self): + return 1 + class Hook(Block): def __init__(self, name, arguments = None): Block.__init__(self, arguments = arguments) @@ -177,4 +189,3 @@ class Hook(Block): def __str__(self): return "<Hook: %s>" % self.name - diff --git a/generator/coder/os_generic.py b/generator/coder/os_generic.py index ede5c3d1b7f9bd346cc107550b9e4a7c1f866a1a..180016e1d3f576e51a1113bb78b2ba70d85a4395 100644 --- a/generator/coder/os_generic.py +++ b/generator/coder/os_generic.py @@ -114,6 +114,18 @@ class GenericOS(BaseCoder): extern_c = True) self.generator.source_file.data_manager.add(iddesc); + for res in self.system_graph.resources: + iddesc = DataObject("const ResourceType", "OSEKOS_RESOURCE_" + res.name, + static_initializer = str(res.conf.static_priority), + extern_c = True) + self.generator.source_file.data_manager.add(iddesc); + + for counter in self.system_graph.counters: + iddesc = DataObject("const CounterType", "OSEKOS_COUNTER_" + counter.conf.name, + static_initializer = "0", + extern_c = True) + self.generator.source_file.data_manager.add(iddesc); + events = {} for event in self.system_graph.events: event.impl = EventImpl() @@ -206,5 +218,3 @@ class GenericOS(BaseCoder): multiplexer.add("\t\treturn crc32(OS_all_CheckedObjects[arg0].location, OS_all_CheckedObjects[arg0].size);\n") multiplexer.add("\t}\n") self.generator.source_file.function_manager.add(multiplexer, "dep") - - diff --git a/generator/coder/syscall_full.py b/generator/coder/syscall_full.py index 0585ea69b253e84b23857f8b7edd45ac555d7c36..0c99a72a54b787f12ecabcdf134f4bb66600fbbf 100644 --- a/generator/coder/syscall_full.py +++ b/generator/coder/syscall_full.py @@ -108,7 +108,8 @@ class FullSystemCalls(BaseCoder): self.call(kernelspace, "scheduler_.ActivateTask_impl", "void", - [self.task_desc(syscall.arguments[0])]) + [self.task_desc(syscall.arguments[0]), + "/* from_interrupt */ %s" % str(syscall.subtask.conf.is_isr).lower()]) def ChainTask(self, syscall, userspace, kernelspace): self.call(kernelspace, @@ -199,7 +200,9 @@ class FullSystemCalls(BaseCoder): kernelspace.add(Statement("%s.do_tick()" % counter.impl.name)) for alarm in self.system_graph.alarms: if alarm.conf.counter == counter: - kernelspace.add(Statement("AlarmCheck%s()" % alarm.impl.name)) + alarm.carried_syscall.function = abb.function + check_alarm = self.alarms(self).generate_check_alarm_softcounter(alarm) + kernelspace.add(Statement(check_alarm)) kernelspace.add(Comment("Dispatch directly back to Userland")) self.call(kernelspace, "Dispatcher::ResumeToTask", @@ -381,55 +384,68 @@ class AlarmTemplate(CodeTemplate): return ret - def check_alarms(self, snippet, args): - if not self.system_graph.AlarmHandlerSubtask: - return [] - ret = [] - # The AlarmHandlerSubtask carries a _sorted_ list of alarms - kickoff = self.system_graph.AlarmHandlerSubtask.entry_abb - iret = self.system_graph.AlarmHandlerSubtask.exit_abb - - ret += [" " + kickoff.generated_function_name() + "();\n"] - for alarm in self.system_graph.AlarmHandlerSubtask.alarms: - ret += [" AlarmCheck%s();\n" % alarm.impl.name] - ret += [" " + iret.generated_function_name() + "();\n"] - return ret - - def __generate_softcounter_event(self, alarm): + def generate_check_alarm_softcounter(self, alarm): + args = {"alarm": alarm.impl.name} abb = alarm.carried_syscall + ret = self.expand_snippet("if_alarm", **args) + "\n" userspace, kernelspace = Block(), Block() + if abb.isA(S.ActivateTask): self.rules.syscall_rules.ActivateTask(abb, userspace, kernelspace) else: self.rules.syscall_rules.SetEvent(abb, userspace, kernelspace) - return "".join(kernelspace.expand(None)) + ret += "".join(kernelspace.expand(None)) + ret += self.expand_snippet("endif_alarm", **args) + "\n" + + return ret + + def generate_check_alarm(self, alarm): + callback_name = "OSEKOS_ALARMCB_%s" % (alarm.name) + has_callback = (self.system_graph.find(GraphFunction, callback_name) != None) + args = {"alarm": alarm.impl.name} + # Add a label to identify this basic block + ret = "" + ret += " abb_%(label)s: (void) &&abb_%(label)s;\n" %{ + "label": alarm.carried_checkalarm.generated_function_name() + } + ret += self.expand_snippet("if_alarm", **args) + "\n" + # This alarm has an callback + if has_callback: + # Add a Declaration + decl = FunctionDeclaration(callback_name, extern_c = True) + self.generator.source_file.function_manager.add(decl) + ret += self.expand_snippet("alarm_alarmcallback", callback = callback_name) + "\n" + + carried = alarm.carried_syscall + # SetEvent needs two arguments + if alarm.conf.event: + arglist = "(0, 0)" + else: + arglist = "(0)" + # Add a label to identify this basic block + ret += " abb_%(label)s: (void) &&abb_%(label)s;\n" %{ + "label": carried.generated_function_name() + } + ret += " " + carried.generated_function_name() + arglist + ";\n" + ret += self.expand_snippet("endif_alarm", **args) + "\n" + + return ret def generate_check_alarms(self, snippet, args): + if not self.system_graph.AlarmHandlerSubtask: + return [] ret = [] - for alarm in self.system_graph.alarms: - callback_name = "OSEKOS_ALARMCB_%s" % (alarm.name) - has_callback = (self.system_graph.find(GraphFunction, callback_name) != None) - args = {"alarm": alarm.impl.name} - ret += self.expand_snippet("if_alarm", **args) + "\n" - # This alarm has an callback - if has_callback: - # Add a Declaration - decl = FunctionDeclaration(callback_name, extern_c = True) - self.generator.source_file.function_manager.add(decl) - ret += self.expand_snippet("alarm_alarmcallback", callback = callback_name) + "\n" + # The AlarmHandlerSubtask carries a _sorted_ list of alarms + kickoff = self.system_graph.AlarmHandlerSubtask.entry_abb + iret = self.system_graph.AlarmHandlerSubtask.exit_abb + ret += [" " + kickoff.generated_function_name() + "();\n"] + for alarm in self.system_graph.alarms: if alarm.conf.counter.conf.softcounter: - ret += self.__generate_softcounter_event(alarm) - else: - carried = alarm.carried_syscall - # SetEvent needs two arguments - if alarm.conf.event: - arglist = "(0, 0)" - else: - arglist = "(0)" - ret += " " + carried.generated_function_name() + arglist + ";\n" - ret += self.expand_snippet("endif_alarm", **args) + "\n" + continue + ret += [self.generate_check_alarm(alarm)] + ret += [" " + iret.generated_function_name() + "();\n"] return ret diff --git a/generator/extractor/CMakeLists.txt b/generator/extractor/CMakeLists.txt index 16668f9eff00accab4e4874f942b808fdd365ad6..ecc13ed9c6ed966240b6c1e10260f5bb8b50b3d2 100644 --- a/generator/extractor/CMakeLists.txt +++ b/generator/extractor/CMakeLists.txt @@ -1,21 +1,24 @@ +# WARNING: THIS SUBDIRECTORY IS COMPILED FOR HOST +USE_HOST_COMPILER() + # Get the directory of llvm by using llvm-config. also remove whitespaces. -execute_process(COMMAND ${LLVM_CONFIG_EXE} --includedir +execute_process(COMMAND ${TC_TARGET_LLVM_CONFIG} --includedir OUTPUT_VARIABLE LLVM_INCLUDE_DIRS OUTPUT_STRIP_TRAILING_WHITESPACE ) -execute_process(COMMAND ${LLVM_CONFIG_EXE} --cxxflags +execute_process(COMMAND ${TC_TARGET_LLVM_CONFIG} --cxxflags OUTPUT_VARIABLE LLVM_CXX_FLAGS OUTPUT_STRIP_TRAILING_WHITESPACE ) - execute_process(COMMAND ${LLVM_CONFIG_EXE} --ldflags + execute_process(COMMAND ${TC_TARGET_LLVM_CONFIG} --ldflags OUTPUT_VARIABLE LLVM_LD_FLAGS OUTPUT_STRIP_TRAILING_WHITESPACE ) -execute_process(COMMAND ${LLVM_CONFIG_EXE} --libs all +execute_process(COMMAND ${TC_TARGET_LLVM_CONFIG} --libs all OUTPUT_VARIABLE LLVM_LIBS OUTPUT_STRIP_TRAILING_WHITESPACE ) include_directories(${LLVM_INCLUDE_DIRS}) -set(CMAKE_CXX_FLAGS "-fno-rtti -std=c++11 ${LLVM_CXX_FLAGS}") +set(CMAKE_CXX_FLAGS "-fno-rtti -std=c++11 ${LLVM_CXX_FLAGS} -Wl,-rpath=${TC_TARGET_LLVM_ROOT}/lib") set(CMAKE_EXE_LINKER_FLAGS "${LLVM_LD_FLAGS}") # Now build our tools diff --git a/generator/extractor/main.cc b/generator/extractor/main.cc index f0bc97227f859b86018829b4f108f2944fceef3a..b3213500f38c8692d5b85b95e5215494532ade0e 100644 --- a/generator/extractor/main.cc +++ b/generator/extractor/main.cc @@ -12,13 +12,29 @@ // //===----------------------------------------------------------------------===// -//3.6 #include <llvm/Linker/Linker.h> -//3.6 #include <llvm/IR/Verifier.h> -//3.6 #include <llvm/IR/CFG.h> +#include <llvm/Config/llvm-config.h> + +#if LLVM_VERSION_MAJOR >= 3 && LLVM_VERSION_MINOR >= 6 +#undef LLVM_LEGACY +#else +#define LLVM_LEGACY 1 +#endif +#ifdef LLVM_LEGACY + #include <llvm/Support/CFG.h> #include <llvm/Linker.h> #include <llvm/Analysis/Verifier.h> +#else + +#include <llvm/Linker/Linker.h> +#include <llvm/IR/Verifier.h> +#include <llvm/IR/CFG.h> +#include <llvm/IR/DebugInfoMetadata.h> + +#endif + + #include <llvm/Bitcode/ReaderWriter.h> #include <llvm/IR/LLVMContext.h> #include <llvm/IR/Instructions.h> @@ -85,12 +101,20 @@ static inline std::unique_ptr<Module> LoadFile(const char *argv0, const std::str LLVMContext& Context) { SMDiagnostic Err; if (Verbose) errs() << "Loading '" << FN << "'\n"; - //3.6 std::unique_ptr<Module> Result = 0; - //3.6 Result = parseIRFile(FN, Err, Context); + +#ifdef LLVM_LEGACY Module* Result = 0; Result = ParseIRFile(FN, Err, Context); if (Result) return std::unique_ptr<Module>(Result); // Load successful! +#else + + std::unique_ptr<Module> Result = 0; + Result = parseIRFile(FN, Err, Context); + if (Result) return Result; +#endif + + Err.print(argv0, errs()); return NULL; @@ -127,16 +151,17 @@ static inline void SplitBasicBlocks(Module &module) { } } -static inline void AddKickoffFunctionCalls(Module & module) { +static inline void AddKickoffFunctionCalls(Module & module, LLVMContext &Context) { std::vector<Type *> args; - FunctionType *kickoff_type = FunctionType::get(Type::getVoidTy(getGlobalContext()), args, false); + FunctionType *kickoff_type = FunctionType::get(Type::getVoidTy(Context), args, false); unsigned task_count = 0; for (auto &function : module) { + BasicBlock &bb = *function.begin(); - IRBuilder<> Builder(getGlobalContext()); + IRBuilder<> Builder(Context); if (function.getName().startswith("OSEKOS_TASK_FUNC")) { - Instruction *inst = &*bb.begin(); - Builder.SetInsertPoint(inst); + Instruction *inst = &*bb.begin(); + Builder.SetInsertPoint(inst); std::stringstream ss; ss << "OSEKOS_kickoff_" << task_count++; @@ -144,7 +169,11 @@ static inline void AddKickoffFunctionCalls(Module & module) { Function::ExternalLinkage, ss.str(), &module); std::vector<Value*> ArgsV; - Builder.CreateCall(F, ArgsV); + CallInst *CS = Builder.CreateCall(F, ArgsV); +#ifndef LLVM_LEGACY + CS->setDebugLoc(DebugLoc::get(function.getSubprogram()->getLine(), + 0, function.getSubprogram())); +#endif // Split after Call BasicBlock::iterator it = bb.begin(); @@ -283,19 +312,24 @@ static inline void DumpModuleStructure(Module &module) { out << "}\n"; } -static inline void TransformModule(Module &module) { +static inline void TransformModule(Module &module, LLVMContext &Context) { SplitBasicBlocks(module); - AddKickoffFunctionCalls(module); + AddKickoffFunctionCalls(module, Context); RenameSystemcalls(module); DumpModuleStructure(module); } int main(int argc, char **argv) { // Print a stack trace if we signal out. +#ifdef LLVM_LEGACY sys::PrintStackTraceOnErrorSignal(); + LLVMContext &Context = getGlobalContext(); +#else + sys::PrintStackTraceOnErrorSignal(argv[0]); + LLVMContext Context; +#endif PrettyStackTraceProgram X(argc, argv); - LLVMContext &Context = getGlobalContext(); llvm_shutdown_obj Y; // Call llvm_shutdown() on exit. cl::ParseCommandLineOptions(argc, argv, "llvm dosek extractor\n"); @@ -309,7 +343,11 @@ int main(int argc, char **argv) { return 1; } +#ifdef LLVM_LEGACY Linker L(Composite.get()); +#else + Linker L(*Composite); +#endif for (unsigned i = BaseArg+1; i < InputFilenames.size(); ++i) { auto M = LoadFile(argv[0], InputFilenames[i], Context); if (M.get() == 0) { @@ -319,8 +357,12 @@ int main(int argc, char **argv) { if (Verbose) errs() << "Linking in '" << InputFilenames[i] << "'\n"; - std::string ErrorMessage; + std::string ErrorMessage; +#ifdef LLVM_LEGACY if (L.linkInModule(M.get(), &ErrorMessage)) { +#else + if (L.linkInModule(std::move(M))) { +#endif errs() << argv[0] << ": link error in '" << InputFilenames[i] << "': " << ErrorMessage << "\n"; return 1; @@ -334,13 +376,19 @@ int main(int argc, char **argv) { //---- SNIP ---- // Here, we add our custom extractor - TransformModule(*Composite); + TransformModule(*Composite, Context); //-------------- if (DumpAsm) errs() << "Here's the assembly:\n" << *Composite; +#ifdef LLVM_LEGACY std::string EC; tool_output_file Out(OutputFilename.c_str(), EC, sys::fs::F_None); +#else + std::error_code ECC; + tool_output_file Out(OutputFilename, ECC, sys::fs::F_None); + std::string EC = (! ECC) ? "" : ECC.message(); +#endif if (EC != "") { errs() << EC << '\n'; return 1; diff --git a/generator/main.py b/generator/main.py index 255ff97713ee506202e1e67d28cc869e08906d78..9314904f49ef99ba08c31639d2b207e616540251 100755 --- a/generator/main.py +++ b/generator/main.py @@ -185,6 +185,9 @@ if __name__ == "__main__": pass_manager.register_analysis(VerifyGenerateMockup(options.mockup, options.prefix)) + # Timing Passes + pass_manager.register_analysis(GeneratePML()) + # Statistics modules pass_manager.register_analysis(GlobalControlFlowMetric("%s/%s_metric" % (options.prefix, conf.app.name))) @@ -195,6 +198,8 @@ if __name__ == "__main__": arch_rules = ARMArch() elif conf.arch.self == "posix": arch_rules = PosixArch() + elif conf.arch.self == "patmos": + arch_rules = PatmosArch() else: panic("Unknown --arch=%s", conf.arch.self) @@ -218,6 +223,11 @@ if __name__ == "__main__": pass_manager.enqueue_analysis("InterruptControlAnalysis") syscall_rules = FullSystemCalls() + if conf.verify.generate_ssm: + pass_manager.get_pass("sse").use_app_fsm = True + pass_manager.enqueue_analysis("app-fsm") + pass_manager.enqueue_analysis("system-fsm") + elif conf.os.systemcalls == "fsm_pla": pass_manager.get_pass("sse").use_app_fsm = True pass_manager.enqueue_analysis("app-fsm") @@ -246,6 +256,9 @@ if __name__ == "__main__": if conf.verify.generate_mockup: additional_passes.append("VerifyGenerateMockup"); + if conf.timing.generate_pml: + additional_passes.append("GeneratePML"); + for each in additional_passes: P = pass_manager.get_pass(each) if not P: diff --git a/generator/stats_binary.py b/generator/stats_binary.py index a0aeae6c7640fe77b103878970cc6cd4565b0e57..ffce5a16e33ef42b49fb19e98f29ba66b2c42113 100755 --- a/generator/stats_binary.py +++ b/generator/stats_binary.py @@ -45,7 +45,7 @@ def read_regions(objdump, elf_file): return regions -def read_symbols(elffile, nm = "nm"): +def read_symbols(elffile, nm): out = subprocess.check_output([nm, "-t", "dec", "-C", "-S", "-f", "sysv", elffile]) ret = [] for line in out.split("\n"): @@ -94,8 +94,8 @@ if __name__ == "__main__": metavar="STATS_DICT", help="the dict with the statistics") parser.add_option("", "--elf", metavar="ELF", help="The elf file") - parser.add_option("", "--nm", - metavar="NM", help="The nm program (e.g., i386-elf-nm") + parser.add_option("", "--toolchain-file", + metavar="Toolchain") (options, args) = parser.parse_args() @@ -103,10 +103,8 @@ if __name__ == "__main__": parser.print_help() sys.exit(-1) - if options.nm: - symbols = read_symbols(options.elf, options.nm) - else: - symbols = read_symbols(options.elf) + toolchain = eval(open(options.toolchain_file).read()) + symbols = read_symbols(options.elf, toolchain['target']['gnu-nm']) stats = Statistics.load(options.stats_dict) for abb in stats.find_all("AtomicBasicBlock").values(): @@ -117,4 +115,3 @@ if __name__ == "__main__": abb["generated-codesize"] += get_size(symbols, func) stats.save(options.stats_dict) - diff --git a/generator/transform/GeneratePML.py b/generator/transform/GeneratePML.py new file mode 100644 index 0000000000000000000000000000000000000000..17230483af647ab679926a2e9954f641731fb094 --- /dev/null +++ b/generator/transform/GeneratePML.py @@ -0,0 +1,545 @@ +from generator.analysis.Analysis import Analysis, PassInformation +from generator.analysis import SavedStateTransition, Function +from generator.analysis.AtomicBasicBlock import E, S +from generator.analysis.common import * +from collections import defaultdict +import os +import logging +import yaml +import networkx + +def is_TIMING_POINT_STOP_BEFORE(flags): + return (flags & 1) == 1 + +def is_TIMING_POINT_START_INTERRUPT_IN_BLOCK(flags): + return (flags & 1) == 1 + +def is_TIMING_POINT_NO_INTERRUPTS_IN_BLOCK(flags): + return (flags & 2) == 2 + +def is_TIMING_POINT_IS_HIGHEST_PRIO(flags): + return (flags & 4) == 4 + +def is_TIMING_POINT_START_FROM_IDLE(flags): + return (flags & 8) == 8 + + + +class GeneratePML(Analysis, GraphObject): + """ FIXME + + """ + info = PassInformation( + name = "GeneratePML", + requires = ["sse"], + used_cfg_edges = {E.function_level, E.timing_edge_0, E.timing_edge_1} + ) + + def __init__(self): + Analysis.__init__(self) + GraphObject.__init__(self, "GeneratePML", root = True) + + def graph_subobjects(self): + subobjects = [] + for circuit in self.circuits: + if len(circuit['all_states']) > 500: + continue + + mapping = {} + for state in circuit['all_states'].values(): + color = 'green' + if id(state) in circuit['end_states']: + color = 'red' + if id(state) in circuit['start_states']: + color='blue' + label="N%d:%s/%s" %(circuit['state_to_idx'][id(state)], + state.current_subtask, + state.current_abb) + node = GraphObjectContainer(label, color=color) + mapping[id(state)] = node + subobjects.append(node) + + for a in circuit['all_states'].values(): + for b in a.get_outgoing_nodes(SavedStateTransition): + if id(b) in circuit['all_states']: + mapping[id(a)].edges.append( + Edge(mapping[id(a)], mapping[id(b)])) + + return subobjects + + + def get_circuit_states(self, start_abbs, end_abbs): + def priority_map(state): + ret = {} + for subtask in self.system_graph.subtasks: + abb = state.get_continuation(subtask) or state.current_abb + if not state.is_surely_ready(subtask): + continue + if subtask.conf.is_isr or subtask.is_idle_thread(): + continue + ret[subtask] = (subtask.conf.static_priority, abb.dynamic_priority) + return ret + + # 1. Find all starting states + sse = self.system_graph.get_pass("sse") + start_states, end_states = {}, {} + for state in sse.states: + if state.current_abb in start_abbs: + # If the current state's ABB is marked to be consider + # only the followup isr states, then make it so. + if is_TIMING_POINT_START_INTERRUPT_IN_BLOCK(start_abbs[state.current_abb]): + assert not state.current_subtask.conf.is_isr + for nstate in state.get_outgoing_nodes(SavedStateTransition): + if not nstate.current_subtask.conf.is_isr: + continue + start_states[id(nstate)] = nstate + elif is_TIMING_POINT_IS_HIGHEST_PRIO(start_abbs.get(state.current_abb,0)): + # The current running subtask must be of the + # highest priority to be a good starting point + + # Find the highest possible subtask, excluding interrupts + prios = list(sorted(priority_map(state).items(), + key=lambda x: x[1][1], + reverse=True)) + if prios \ + and not prios[0][0].conf.preemptable \ + and any([x[1][0] > prios[0][1][0] for x in prios[1:]]): + pass # Ignore state + else: + start_states[id(state)] = state + elif is_TIMING_POINT_START_FROM_IDLE(start_abbs.get(state.current_abb,0)): + # Only IRQ states from idle are allowed + if len(priority_map(state)) == 0: + start_states[id(state)] = state + else: + start_states[id(state)] = state + + # 2. DFS starting from the first element in the graph. + # 2.1 All end states are definitly part of the graph + good_states = { } + def add_to_good_states(path, curr): + for x in path + [curr]: + good_states[id(x)] = x + def dfs(path, curr): + # Uncomment for debugging purposes + # print("V", [(x.current_subtask, x.current_abb) for x in path + [curr]]) + state_loop = id(curr) in [id(x) for x in path] + hit_on_good_state = id(curr) in good_states + is_end_state = curr.current_abb in end_abbs + + if state_loop or hit_on_good_state or is_end_state: + # print("A") + # Add the path to the good states + add_to_good_states(path, curr) + + assert not is_end_state or not is_TIMING_POINT_STOP_BEFORE(end_abbs[curr.current_abb]),\ + "TIMING_POINT_STOP_BEFORE should not be directly visited" + + if is_end_state: + end_states[id(curr)] = curr + + # Stop DFS, if we were here already + if id(curr) in visited: + return + + visited.add(id(curr)) + path = path + [curr] + for succ in curr.get_outgoing_nodes(SavedStateTransition): + abb = curr.current_abb + nabb = succ.current_abb + # Edges that origin from an end state to the same + # subtask are not taken. + if is_end_state and succ.current_subtask == curr.current_subtask: + continue + if is_TIMING_POINT_STOP_BEFORE(end_abbs.get(nabb,0)): + end_states[id(curr)] = curr + add_to_good_states(path, curr) + continue + if (is_TIMING_POINT_NO_INTERRUPTS_IN_BLOCK(end_abbs.get(abb,0)) or \ + is_TIMING_POINT_NO_INTERRUPTS_IN_BLOCK(start_abbs.get(abb,0))) and \ + nabb.subtask.conf.is_isr: + continue + dfs(path, succ) + + visited = set() + for state in start_states.values(): + dfs([], state) + + # for state in good_states.values(): + # print(state.current_abb) + for state in good_states.values(): + if state.current_abb.isA(S.Idle): + logging.warning("Idle state part of circuit... unanalyzable") + + # Every State can only occur only once in the result + return start_states, good_states, end_states + + def find_irq_regions(self, all_states): + """ Find all IRQ regions in a circuit. A IRQ region has one ISR kickoff, and N ISR exits""" + for state in all_states.values(): + if state.current_subtask and state.current_subtask.conf.is_isr \ + and state.current_abb.isA(S.kickoff): + assert len(state.get_incoming_nodes(SavedStateTransition)) == 1,\ + "Invalid ISR kickoff state" + # Find all state till the next IRET + stack = [state] + visited = set() + entry = state + exits = {} + states = [] + while stack: + p = stack.pop() + if id(p) in visited: + continue + visited.add(id(p)) + states.append(p) + if p.current_abb.isA(S.iret): + assert len(p.get_outgoing_nodes(SavedStateTransition)) == 1,\ + "Unexpected IRET state" + exits[id(p)] = p + else: + for n in p.get_outgoing_nodes(SavedStateTransition): + if id(n) in all_states: + stack.append(n) + else: + exits[id(p)] = p + yield {'entry': entry, 'states': states, 'exits': exits.values()} + + def add_cfg_edges(self, circuit_number, all_states): + """Draw Edges (only for visualization) between the connected ABBs""" + edges = set([]) + edge_type = [E.timing_edge_0, E.timing_edge_1][circuit_number % 2] + for a in all_states.values(): + for b in a.get_outgoing_nodes(SavedStateTransition): + if id(b) not in all_states: + continue + if (a.current_abb, b.current_abb) in edges: + continue + edges.add((a.current_abb, b.current_abb)) + a.current_abb.add_cfg_edge(b.current_abb, edge_type) + + def frequency_variable(self, hint = ""): + """Returns the name of a new flow variable.""" + tmp = self.flow_frequency_variable_counter + self.flow_frequency_variable_counter += 1 + return "flow_var_" + hint + "_" + str(tmp) + + def add_circuit_to_pml(self, pml, circuit_number, + start_states, all_states, end_states, + loops): + """Adds the global-cfg field to the PML""" + gcfg = {'name': 'timing-%d' % circuit_number, + 'level': 'bitcode', + 'entry-nodes': [], + 'exit-nodes': [], + 'blocks': [], + 'nodes': [], + } + def add_block(data): + i = len(gcfg['blocks']) + data['index'] = i + gcfg['blocks'].append(data) + return i, data + def delete_block(idx): + assert False + gcfg['blocks'][idx] = None + + # First we generate the artificial blocks + isr_entry_abb_idx, _ = add_block({'function': 'irq_entry', 'name':"isr_entry_block"}) + + # Assign an idx to every state and abb. States are monotonly + # increasing numbers that refence objects in the PML + abb_to_idx = {} + state_to_idx = {} + def idx(obj): + if id(obj) in state_to_idx: + return state_to_idx[id(obj)] + return abb_to_idx[obj] + + timer_function_name = '_ZN2os7Counter4tickEv' + + # Some states are part of a toplevel loop + state_to_loops = defaultdict(lambda: list()) + for loop, states in loops.items(): + for state in states: + state_to_loops[id(state)].append(loop) + + for state in all_states.values(): + # We first assign an id to the state + state_to_idx[id(state)] = len(state_to_idx) + + # We have to add an ABB object to the PML, for every ABB we newly ancounter + abb = state.current_abb + if abb not in abb_to_idx: + # ISR entry and Exit Nodes are filled separatly + if abb.isA([S.iret, S.Idle]) or (abb.isA(S.kickoff) and abb.subtask.conf.is_isr): + continue + + # There is no ABB record yet + abb_to_idx[abb], record = add_block( + {'subtask': str(abb.subtask), + 'function': abb.function.function_name, + 'name': str(abb), + 'entry-block': abb.basic_block_entry, + 'exit-block': abb.basic_block_exit, + }) + + if abb.subtask == self.system_graph.AlarmHandlerSubtask: + record['function'] = timer_function_name + label = "abb_" + abb.generated_function_name(); + record['entry-block'] = label + record['exit-block'] = label + + if abb.subtask.is_idle_thread(): + record['function'] = 'idle_loop' + if abb.isA(S.kickoff): + record['entry-block'] = 'entry' + record['exit-block'] = 'entry' + else: + record['entry-block'] = 'idle_loop_again' + record['exit-block'] = 'idle_loop_again' + + + + # After having an index for every state, we can mark states as + # entry or exit nodes. + for state in start_states.values(): + gcfg['entry-nodes'].append(idx(state)) + for state in end_states.values(): + gcfg['exit-nodes'].append(idx(state)) + + + transition_count = 0 + # Add all state records to the gcfg + for state in all_states.values(): + successors = [x for x in state.get_outgoing_nodes(SavedStateTransition) + if id(x) in all_states] + transition_count += len(successors) + local_successors = [idx(x) for x in successors if x.current_subtask == state.current_subtask] + global_successors = [idx(x) for x in successors if x.current_subtask != state.current_subtask] + + successors = [idx(x) for x in successors if id(x) in all_states] + data = {'index': idx(state), + 'local-successors': local_successors, + 'global-successors': global_successors} + # Annotate that states are part of a loop + if id(state) in state_to_loops: + data['loops'] = state_to_loops[id(state)] + + if state.current_abb in abb_to_idx: + data['abb'] = abb_to_idx[state.current_abb] + data['abb-name'] = str(state.current_abb) + elif state.current_abb.isA(S.Idle): + data['abb-name'] = "Idle" + data['cost'] = 0 + else: + data['abb-name'] = str(state.current_abb) + " WEIRDO" + + gcfg['nodes'].append(data) + + irq_entry_variables = defaultdict(list) + + # Transform IRQ Regions + ast_requests = set() + for region in self.find_irq_regions(all_states): + isr_entry = region['entry'] + isr_entry_data = gcfg['nodes'][idx(isr_entry)] + + # Give the isr_entry block a flow variable. This flow + # variable, will capture how often an interrupt is + # activated. + var = self.frequency_variable("isr_entry") + irq_entry_variables[isr_entry.current_subtask].append(var) + isr_entry_data['frequency-variable'] = var + isr_entry_data['isr_entry'] = True + + # The ISR entry function (for PATMOS) is the isr_entry + # function. The original ABB is marked as zero cost (it + # will not be referenced from anywhere!) + isr_entry_data['abb'] = isr_entry_abb_idx + isr_entry_data['abb-name'] = 'isr_entry' + + for isr_exit in region['exits']: + if id(isr_exit) not in state_to_idx: + continue + isr_exit_data = gcfg['nodes'][idx(isr_exit)] + assert isr_exit.definite_after(SavedStateTransition) is not None,\ + str(isr_exit) + # Mark isr_exit node as zero cost. + isr_exit_data['cost'] = 0 + + # All but the isr_entry block do not force the control + # flow. This is necessary, since they are embedded into + # the isr_entry state + for state in region['states']: + assert id(state) in state_to_idx + state_data = gcfg['nodes'][idx(state)] + state_data['abb-name'] = str(state.current_abb) + if state != isr_entry: + state_data['microstructure'] = True + + if state.current_abb.isA([S.ActivateTask, S.SetEvent]): + ast_requests.add(state.current_abb) + + pml['global-cfgs'].append(gcfg) + if 'flowfacts' not in pml: + pml['flowfacts'] = [] + + + for subtask, variables in irq_entry_variables.items(): + # FIXME: This is the timer isr interarrival time. This + # shouldn't be a constant. + if subtask == self.system_graph.AlarmHandlerSubtask: + subtask.conf.interarival_times['min'] = 100000 + + if subtask.conf.interarival_times['min']: + iat = subtask.conf.interarival_times['min'] + lhs = [{'factor': 1, 'program-point': {'frequency-variable': x}} for x in variables] + pml['flowfacts'].append({ + 'scope': {'gcfg': gcfg['name']}, + 'level': 'gcfg', + 'lhs': lhs, + 'op': 'minimal-interarrival-time', + 'rhs': subtask.conf.interarival_times['min'], + 'origin': 'user', + 'classification': 'system-global', + }) + + # Alarm Activation flowfact + for alarm in self.system_graph.alarms: + # FIXME: Only a mock for static alarms + if alarm.conf.armed: + check_alarm = "abb_" + alarm.carried_checkalarm.generated_function_name() + action_abb = "abb_" + alarm.carried_syscall.generated_function_name() + cycletime = alarm.conf.cycletime + pml['flowfacts'].append({ + 'scope': {'function': timer_function_name}, + 'rhs': 1, + 'level': 'bitcode', + 'lhs': [{'factor': cycletime, + 'program-point': { + 'function': timer_function_name, + 'block': action_abb, + }}, + {'factor': -1, + 'program-point': {'constant-value': cycletime - 1} + }], + 'op': 'less-equal', + 'origin': 'user.bc', + 'classification': 'system-global', + }) + logging.info(" %s triggers every %d-nth time", alarm.conf.name, cycletime) + + # The number of AST Reschedule events is the number actcual + # ast_reschedule requests + lhs = [] + for abb in ast_requests: + data = gcfg['blocks'][idx(abb)] + var = self.frequency_variable("ast_request") + data['frequency-variable'] = var + lhs.append({'factor': -1, 'program-point': {'frequency-variable': var}}) + + pml['flowfacts'].append({ + 'scope': {'function': "__OS_ASTSchedule"}, + 'level': 'machinecode', + 'classification': 'system-global', + 'rhs': -1, + 'op': 'less-equal', + 'origin': 'user', + 'lhs': lhs +, }) + + logging.info(" %s: %d states, (->s: %d, s-> %d), %d loops, %d transitions", gcfg['name'], + len(gcfg['nodes']), + len(start_states), + len(end_states), + len(loops), + transition_count) + return state_to_idx + + def find_loops(self, all_states): + # Create Directed Graph + G = networkx.DiGraph() + + # Add a list of nodes: + G.add_nodes_from(all_states.keys()) + logging.debug(" searching loops in %d-node graph (networkx)", len(all_states)) + + for a in all_states.values(): + for b in a.get_outgoing_nodes(SavedStateTransition): + if id(b) in all_states: + G.add_edge(id(a), id(b)) + + loops = {} + for loop in networkx.simple_cycles(G): + loop_id = len(loops) + loops[loop_id] = [all_states[state_id] for state_id in loop] + return loops + + def do(self): + self.flow_frequency_variable_counter = 0 + # If there is a call in PreIdleHook, add fake it that the + # kickoff ABB calls the PreIdleHook. + idle = self.system_graph.find(Function, "__OS_HOOK_DEFINED_PreIdleHook") + if idle: + kickoff = self.system_graph.idle_subtask.entry_abb + for abb in idle.abbs: + kickoff.call_sites.extend(abb.call_sites) + abb.call_sites = [] + + # We search for all circuits, the user has annotated with + # function calls in his application + circuits = defaultdict(lambda : {'start': {}, 'end': {}}) + for abb in self.system_graph.abbs: + for (bb, func, args) in abb.call_sites: + if func in ('timing_start', 'timing_end'): + circuit = args[0] & 0xff + options = args[0] >> 8 + if func == "timing_start": + if abb.subtask.conf.is_isr: + logging.info(" timing-%d starts with IRQ activation", circuit) + before = abb.definite_before(E.function_level) + assert before.isA(S.kickoff), "Can start analysis only at beginning of ISR" + circuits[circuit]["start"][before] = options + else: + circuits[circuit]["start"][abb] = options + if func == "timing_end": + circuits[circuit]["end"][abb] = options + # Finds all states in between + pml = {'format': 'pml-0.1', + 'triple': 'patmos-unknown-unknown-elf', + 'global-cfgs': [] + } + + self.circuits = [] + for circuit_number, data in circuits.items(): + start_states, all_states, end_states = self.get_circuit_states(data["start"], data["end"]) + + #print([x.current_abb for x in start_states.values()]) + #print([x.current_abb for x in all_states.values()]) + #print([x.current_abb for x in end_states.values()]) + assert all([id_ in all_states for id_ in start_states]), \ + "All start states must be part of the all_state set" + assert all([id_ in all_states for id_ in end_states]), \ + "All end states must be part of the all_state set" + + # Copy circuit into graph (combined ABB->ABB edges) + self.add_cfg_edges(circuit_number, all_states) + + # Add Circuit to PML + loops = self.find_loops(all_states) + state_to_idx = self.add_circuit_to_pml(pml, circuit_number, + start_states, all_states, end_states, + loops) + + self.circuits.append({"index": circuit_number, + 'state_to_idx': state_to_idx, + 'start_states': start_states, + 'all_states': all_states, + 'end_states': end_states}) + + + fn = os.path.join(os.path.dirname(self.system_graph.basefilename), + "gcfg.pml") + with open(fn, "w+") as fd: + yaml.dump(pml, fd) diff --git a/generator/transform/__init__.py b/generator/transform/__init__.py index 392d9ef50fb9844ba4d094648240f02b4758b983..31b781bf6ac2ce479334bb3c851dbf894c47e023 100644 --- a/generator/transform/__init__.py +++ b/generator/transform/__init__.py @@ -6,3 +6,4 @@ from .GenerateAssertions import * from .LogicMinimizer import LogicMinimizer from .AnotateStackSwitchFunctions import AnotateStackSwitchFunctions from .VerifyGenerateMockup import VerifyGenerateMockup +from .GeneratePML import GeneratePML diff --git a/new_build_env.py b/new_build_env.py index 55b0a0f6cf88e5861d784357d6d61225bdccb4ab..10bdd3cdc42baf5a63081dd56dd7785eb2ec7840 100755 --- a/new_build_env.py +++ b/new_build_env.py @@ -1,4 +1,4 @@ -#!/usr/bin/python +#!/usr/bin/python3 import os import sys @@ -30,7 +30,7 @@ def main(): parser.add_option('-c', '--clean', dest='CLEAN', action="store_true", default = False, help="Remove all files from current directory before") - parser.add_option('-v', '--verbose', dest='verbose', action='count', + parser.add_option('-v', '--verbose', dest='verbose', action='count', default=0, help="Increase verbosity (specify multiple times for more)") parser.add_option('', '--fail-trace-all', dest='FAIL_TRACE_ALL', default = "no", help="Trace all testcases") @@ -67,9 +67,6 @@ def main(): # Don't think too much about it options = eval(str(options)) - toolchain_file = "%(REPODIR)s/toolchain/%(ARCH)s.cmake" % {"ARCH": conf.arch.self, - "REPODIR": base_dir} - logging.info("Toolchain File: %s", toolchain_file) config.check_constraints(config.constraints, conf) if options["CLEAN"]: @@ -87,7 +84,6 @@ def main(): fd.write(pprint.pformat(cmdline_config)) subprocess.call(["cmake", "-DCMAKE_EXPORT_COMPILE_COMMANDS=ON", - '-DCMAKE_TOOLCHAIN_FILE=%s' % toolchain_file, "-DCMAKE_BUILD_TYPE=Release", "-G", generator_dict[conf.generator], "-DFAIL_TRACE_ALL=%s" % options["FAIL_TRACE_ALL"], diff --git a/os/CMakeLists.txt b/os/CMakeLists.txt index 83a6e9cbbd4e193799e243010e9ce14808499d39..07548102048573d76917d8ce9387152ea757657b 100644 --- a/os/CMakeLists.txt +++ b/os/CMakeLists.txt @@ -6,4 +6,7 @@ set(SRCS add_library(os ${SRCS}) +add_library(timing timing.cc) + + add_subdirectory(scheduler) diff --git a/os/alarm.h.in b/os/alarm.h.in index 79426e7da4b3349d2ce0508a9e098e79360f2baa..2c6d947fbe166be33ca875c9ae7ef539311a6bf4 100644 --- a/os/alarm.h.in +++ b/os/alarm.h.in @@ -3,22 +3,19 @@ namespace os { -{{{snippet:if_alarm:counter,alarm|static void inlinehint AlarmCheck%(alarm)s() { +{{{snippet:if_alarm:counter,alarm| if (%(alarm)s.checkTrigger()) { }}} {{{snippet:endif_alarm:counter,alarm| } -} }}} {{{snippet:alarm_alarmcallback:callback| %(callback)s();}}} -{{{generate:generate_check_alarms}}} void inlinehint Counter::tick() { {{{snippet:increase_counter:name|%(name)s.do_tick(); }}} {{{generate:increase_counters}}} - {{{generate:check_alarms}}} - + {{{generate:generate_check_alarms}}} } } // os diff --git a/os/os.h b/os/os.h index 8724b6707bae3d2452d12c602f144aabf5ac8326..0012ae00e084e5863d966a98306e7dff91bc0db9 100644 --- a/os/os.h +++ b/os/os.h @@ -18,10 +18,22 @@ EXTERN_C_DECL void StartOS(int); ******************************************************************************/ #define dosek_unused __attribute__((unused)) +#ifdef CONFIG_ARCH_PATMOS + +#include "arch/patmos/irq.h" + +#define ISR2(taskname) \ + __attribute__((always_inline)) __attribute__((used)) \ + EXTERN_C_DECL void OSEKOS_ISR_##taskname(const arch::IRQ::Context &) + +#else + #define ISR2(taskname) \ __attribute__((always_inline)) __attribute__((used)) \ EXTERN_C_DECL void OSEKOS_ISR_##taskname(void) +#endif + #define DeclareTask(x) \ extern const TaskType OSEKOS_TASK_ ## x; \ static dosek_unused const TaskType &x = OSEKOS_TASK_ ## x; \ @@ -300,6 +312,9 @@ extern void OSEKOS_ResumeAllInterrupts(); extern void OSEKOS_SuspendOSInterrupts(); extern void OSEKOS_ResumeOSInterrupts(); + + + /****************************************************************************** * * * API Definitions (not supported, not creating any dependencies * diff --git a/os/scheduler/scheduler.h.in b/os/scheduler/scheduler.h.in index 92c9fc5755c49532020937eaaaa009a787823e76..f0f727b1cc3260407b34b480bdf21f8a3e416734 100644 --- a/os/scheduler/scheduler.h.in +++ b/os/scheduler/scheduler.h.in @@ -1,7 +1,9 @@ +namespace os { namespace tasks {};}; namespace os { namespace scheduler { using namespace os::tasks; +using namespace arch; #ifdef CONFIG_DEPENDABILITY_STATE_REPLICATON extern os::redundant::ClassicTMR<os::scheduler::TaskList> state_replicator_; @@ -32,8 +34,8 @@ struct Scheduler { noinline void Reschedule(void); - forceinline void Schedule_impl(void) { - if(in_syscall()) { + forceinline void Schedule_impl(bool from_interrupt=false) { + if(!from_interrupt && in_syscall()) { // in syscall: reschedule directly #ifdef CONFIG_OS_INLINE_SCHEDULER InlinedReschedule(); @@ -59,10 +61,10 @@ struct Scheduler { state_replicator_.update(); } - forceinline void ActivateTask_impl(const Task &task) { - state_replicator_.check(); - SetReady_impl(task); - Schedule_impl(); + forceinline void ActivateTask_impl(const Task &task, bool from_interrupt=false) { + state_replicator_.check(); + SetReady_impl(task); + Schedule_impl(from_interrupt); } forceinline void ChainTask_impl(const Task &from, const Task &to) { diff --git a/os/timing.cc b/os/timing.cc new file mode 100644 index 0000000000000000000000000000000000000000..560e5d13a49d95fbdc19f17c7132b2f664ed2569 --- /dev/null +++ b/os/timing.cc @@ -0,0 +1,36 @@ +#include "timing-arch.h" +#include "os/util/inline.h" +#include "output.h" + +extern "C" { + +extern uint64_t arch_timing_get(); + +constexpr int CIRCUIT_MAX = 10; +static uint64_t circuits[CIRCUIT_MAX]; +static uint32_t circuits_duration[CIRCUIT_MAX]; + +noinline void timing_start(int circuit) { + circuits[circuit & 0xff] = arch_timing_get(); +} + +noinline uint64_t timing_end(int circuit) { + uint64_t end = arch_timing_get(); + uint32_t delta = (uint32_t) end - circuits[circuit & 0xff]; + circuits_duration[circuit & 0xff] = delta; + return delta; +} + +noinline int timing_print() { + unsigned found = 0; + for (unsigned i = 0; i < CIRCUIT_MAX; ++i) { + if (circuits[i]) { + kout << "timing-" << i << " " << circuits_duration[i] << endl; + circuits[i] = 0; + found ++; + } + } + return found; +} + +} diff --git a/os/timing.h b/os/timing.h new file mode 100644 index 0000000000000000000000000000000000000000..8d164883ca8dc1f53516fe18f2f923621a0b638c --- /dev/null +++ b/os/timing.h @@ -0,0 +1,47 @@ +#ifndef __OS_TIMING_H +#define __OS_TIMING_H + +#define STRINGIFY(a) #a + +#if defined(CONFIG_ARCH_PATMOS) +extern "C" { + extern void timing_start(int circuit); + extern uint64_t timing_end(int circuit); + extern int timing_print(); +} +#define timing_dump() asm volatile("trap 2") +#define timing_loop_bound(low, high) _Pragma(STRINGIFY(loopbound min low max high)) +#else +#define timing_start(a) 0 +#define timing_end(a) 0 +#define timing_dump() do { Machine::shutdown(); } while(0) +#define timing_loop_bound(low, high) +#define timing_print() +#endif + +#define TIMING_POINT_NO_INTERRUPTS_IN_BLOCK 0x200 +#define TIMING_POINT_IS_HIGHEST_PRIO 0x400 + + +#define TIMING_POINT_STOP_BEFORE 0x100 + +#define TIMING_POINT_START_INTERRUPT_IN_BLOCK 0x100 +#define TIMING_POINT_START_INTERRUPT_FROM_IDLE 0x800 + + + + +#define GENERATE_TIME_CONSUMER(name, amount) \ + extern "C" int noinline name() { \ + volatile int i = 0; \ + timing_loop_bound(amount, amount) \ + for (; i < amount; i++) {}; \ + return i; \ + } + +#define TIMING_MAKE_OS_MAIN(body) \ + void os_main(void) { \ + body; \ + } + +#endif diff --git a/static_analysis/CMakeLists.txt b/static_analysis/CMakeLists.txt index 69d8a10a485c1edd157f4b086f3c9be1cba37d92..392fca3afd9f03c59c041f6c7f2f11d913dcba9c 100644 --- a/static_analysis/CMakeLists.txt +++ b/static_analysis/CMakeLists.txt @@ -16,10 +16,8 @@ if(CPPCHECK) foreach(dir ${INCLUDEDIRS}) file(APPEND ${CPPINCLUDES} "${dir}\n") endforeach() -# if(BUILD_posix) file(APPEND ${CPPINCLUDES} "/usr/include\n") file(APPEND ${CPPINCLUDES} "/usr/include/linux\n") -# endif() add_custom_target( cppcheck @@ -100,7 +98,7 @@ endif() find_program(PYLINT /proj/i4danceos/tools/pylint/pylint pylint) if(PYLINT) add_custom_command( - COMMAND find ./ -iname \"*.py\" | PYTHONPATH=${PROJECT_SOURCE_DIR} xargs ${PYLINT} + COMMAND find ./ -iname \"*.py\" | PYTHONPATH=${PROJECT_SOURCE_DIR} xargs ${PYLINT} --msg-template=\"{path}:{line}: [{msg_id}({symbol}) , {obj}] {msg}\" --rcfile=${PROJECT_SOURCE_DIR}/static_analysis/pylint.rc > ${PROJECT_BINARY_DIR}/pylint.txt @@ -116,4 +114,3 @@ else() message(STATUS "[${PROJECT_NAME}] pylint executable not found") endif() - diff --git a/toolchain/ARM.cmake b/toolchain/ARM.cmake deleted file mode 100644 index e43cb1f04bb55ec5edd0412779321d0b71a701b7..0000000000000000000000000000000000000000 --- a/toolchain/ARM.cmake +++ /dev/null @@ -1,90 +0,0 @@ -# Prepare cross compiler -set(CMAKE_SYSTEM_NAME Generic) -set(BUILD_ARM TRUE CACHE BOOL "") -set(CMAKE_C_ARCH "armv7a-none-elf") -set(ARCH_PREFIX "arm-none-eabi-") - -find_program(CROSS_GCC "${ARCH_PREFIX}gcc") - -# gcc -print-search-dirs first line: install: ... -execute_process(COMMAND ${CROSS_GCC} -print-search-dirs OUTPUT_VARIABLE GCC_SEARCH_PATH OUTPUT_STRIP_TRAILING_WHITESPACE) -STRING(REGEX REPLACE "^install: ([^ ]+)\n.*" "\\1" CROSS_ROOT_PATH ${GCC_SEARCH_PATH}) - -find_program(CROSS_AR "${ARCH_PREFIX}ar") -find_program(CROSS_AS "${ARCH_PREFIX}as") -find_program(CROSS_NM "${ARCH_PREFIX}nm") -find_program(CROSS_RANLIB "${ARCH_PREFIX}ranlib") -# Find objdump for pagetable generation -find_program(CROSS_OBJDUMP "${ARCH_PREFIX}objdump") -find_program(CROSS_OBJCOPY "${ARCH_PREFIX}objcopy") - - -message(STATUS "Cross compiler root: ${CROSS_ROOT_PATH}") - -# Setup LLVM Tooling -SET(LLVM_RECOMMENDED_VERSION 3.4) - -if(NOT DEFINED ${LLVM_ROOT}) - # find llvm-config. prefers to the one with version suffix, Ex:llvm-config-3.4 - find_program(LLVM_CONFIG_EXE NAMES "llvm-config-${LLVM_RECOMMENDED_VERSION}" "llvm-config") - - # Get the directory of llvm by using llvm-config. also remove whitespaces. - execute_process(COMMAND ${LLVM_CONFIG_EXE} --prefix OUTPUT_VARIABLE LLVM_ROOT - OUTPUT_STRIP_TRAILING_WHITESPACE ) -endif() - -message(STATUS "LLVM root: ${LLVM_ROOT}") - -# Find a compiler which compiles c++ source into llvm bitcode. -# It first finds clang, then it finds llvm-g++ if there is no clang. -find_program(LLVM_C_COMPILER "clang-${LLVM_RECOMMENDED_VERSION}" - NAMES clang llvm-gcc - HINTS ${LLVM_ROOT}/bin ) - -find_program(LLVM_CXX_COMPILER "clang++-${LLVM_RECOMMENDED_VERSION}" - NAMES clang++ llvm-g++ - HINTS ${LLVM_ROOT}/bin ) - - -# Checks whether a LLVM_COMPILER is found, give a warning if not found. -# A warning instread of error is beceuse that we don't need clang during -# building pinavm. -if(${LLVM_C_COMPILER} STREQUAL "LLVM_COMPILER-NOTFOUND") - message(WARNING "Could not find clang or llvm-gcc." - " Please install one of them !") -endif() - -message(STATUS "LLVM C/C++ compiler: ${LLVM_C_COMPILER} ${LLVM_CXX_COMPILER}") - - -# Setup ARM specific flags -set(COMMON_ARM_FLAGS "-target ${CMAKE_C_ARCH} -I/usr/lib/arm-none-eabi/include -mcpu=cortex-a9 -mfloat-abi=soft -mthumb -Xclang -no-implicit-float -ccc-gcc-name ${ARCH_PREFIX}gcc -no-integrated-as -include ${PROJECT_SOURCE_DIR}/arch/arm/types.h") -set(CMAKE_C_FLAGS "${COMMON_ARM_FLAGS} -mfloat-abi=soft -ffreestanding -Wall -Wextra -Qunused-arguments -Wno-undefined-inline" CACHE STRING "CFLAGS") -set(CMAKE_CXX_FLAGS " -fno-exceptions -fno-unwind-tables -fno-rtti" CACHE STRING "CXXFLAGS") -set(CMAKE_ASM_FLAGS "${COMMON_ARM_FLAGS} -Qunused-arguments" CACHE STRING "ASMFLAGS") - -set(CMAKE_EXE_LINKER_FLAGS "-nostartfiles -Wl,--gc-sections" CACHE STRING "LDFLAGS") - -# Setup compilers -set(CCDIR "${LLVM_ROOT}") -set(CMAKE_C_COMPILER ${LLVM_C_COMPILER}) -set(CMAKE_CXX_COMPILER ${LLVM_CXX_COMPILER}) -set(CMAKE_RANLIB "${CCDIR}/bin/llvm-ranlib" CACHE INTERNAL STRING) -set(CMAKE_AR "${CCDIR}/bin/llvm-ar" CACHE INTERNAL STRING) - -SET(CMAKE_FIND_ROOT_PATH ${CROSS_ROOT_PATH}) -SET(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER) -SET(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY) -SET(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY) - -## Add *additional* architecture specific compiler flags here. -# Note that the flags set in toolchain.cmake are still present and used. -set(ISA_C_FLAGS "-S -emit-llvm -O0" CACHE INTERNAL STRING) -set(ISA_CXX_FLAGS "" CACHE INTERNAL STRING) -set(ISA_ASM_FLAGS "${COMMON_ARM_FLAGS}" CACHE INTERNAL STRING) -set(ISA_LD_FLAGS "${COMMON_ARM_FLAGS} -static -nostdlib -Qunused-arguments -Wl,--build-id=none" CACHE INTERNAL STRING) - -# ENABLE ARM platform -set(BUILD_ARM "on" CACHE INTERNAL STRING) -set(DOSEK_ARCHITECTURE "ARM") - diff --git a/toolchain/app.cmake b/toolchain/app.cmake index f59a3ab0fa4722235b588c1ffaba9a213c8df1e5..7d0eac561d8252917fd110ba80ad82f4790efb79 100644 --- a/toolchain/app.cmake +++ b/toolchain/app.cmake @@ -42,9 +42,9 @@ MACRO(DOSEK_BINARY_EXECUTABLE NAME SOURCES SYSTEM_DESC VERIFY_SCRIPT DEFINITIONS file(MAKE_DIRECTORY ${dirname}) add_custom_command(OUTPUT ${llvm_bytecode} COMMAND ${CMAKE_C_COMPILER} - ARGS ${COMPILER_FLAGS} - ARGS ${DEFINITIONS_CMDLINE} - ARGS -S -emit-llvm -O0 -m32 -std=c++11 ${DEFINITON_FLAGS} + ARGS ${COMPILER_FLAGS} + # ARGS ${definitions} + ARGS -S -emit-llvm -O0 -m32 -std=c++11 ${DEFINITON_FLAGS} ARGS ${INCLUDEDIRS_FLAGS} ${CMAKE_CURRENT_SOURCE_DIR}/${src} -o ${llvm_bytecode} MAIN_DEPENDENCY ${src} DEPENDS ${src} @@ -61,6 +61,7 @@ MACRO(DOSEK_BINARY_EXECUTABLE NAME SOURCES SYSTEM_DESC VERIFY_SCRIPT DEFINITIONS # All python source files are a dependency file(GLOB_RECURSE PYTHON_SOURCE "${DOSEK_GENERATOR_DIR}/*.py") file(GLOB_RECURSE OS_TEMPLATES "${PROJECT_SOURCE_DIR}/os/*.in") + file(GLOB_RECURSE ARCH_TEMPLATES "${PROJECT_SOURCE_DIR}/arch/${CONFIG_ARCH}/*.in") if(EXISTS "${VERIFY_SCRIPT}") if (IS_DIRECTORY "${VERIFY_SCRIPT}") SET(VERIFY_SCRIPT "") @@ -79,7 +80,7 @@ MACRO(DOSEK_BINARY_EXECUTABLE NAME SOURCES SYSTEM_DESC VERIFY_SCRIPT DEFINITIONS # Generating DOSEK System add_custom_command(OUTPUT "${DOSEK_GENERATED_SOURCE}" "${DOSEK_GENERATED_LINKER}" "${DOSEK_SOURCE_SYSTEM}" DEPENDS llvm-attributor llvm-extractor ${PYTHON_SOURCE} "${SYSTEM_DESC}" ${DOSEK_BINARY_LLVM_BYTECODE} ${SYSDESCS} - ${VERIFY_SCRIPT} ${OS_TEMPLATES} ${LINKER_TEMPLATE} + ${VERIFY_SCRIPT} ${OS_TEMPLATES} ${ARCH_TEMPLATES} ${LINKER_TEMPLATE} COMMAND ${CMAKE_COMMAND} -E remove -f ${DOSEK_OUTPUT_DIR}/gen_*.dot COMMAND ${DOSEK_GENERATOR} --config "${PROJECT_BINARY_DIR}/config.dict" @@ -134,18 +135,18 @@ MACRO(DOSEK_BINARY) set(DOSEK_VERIFY_SCRIPT "${CMAKE_CURRENT_SOURCE_DIR}/${DOSEK_BINARY_VERIFY}") SET(NAME "${DOSEK_BINARY_NAME}") - DOSEK_BINARY_EXECUTABLE(${NAME} "${DOSEK_BINARY_SOURCES}" ${DOSEK_SYSTEM_DESC} ${DOSEK_VERIFY_SCRIPT} + DOSEK_BINARY_EXECUTABLE(${NAME} "${DOSEK_BINARY_SOURCES}" ${DOSEK_SYSTEM_DESC} ${DOSEK_VERIFY_SCRIPT} "" "${DOSEK_BINARY_LIBS}" "${DOSEK_BINARY_GENERATOR_ARGS}") add_custom_command(TARGET ${NAME} POST_BUILD COMMENT "Gathering binary statistics for ${NAME}" COMMAND ${DOSEK_GENERATOR_DIR}/stats_binary.py --stats-dict ${DOSEK_OUTPUT_DIR}/stats.dict.py --elf ${PROJECT_BINARY_DIR}/${NAME} - --nm ${CROSS_NM} + --toolchain-file ${PROJECT_BINARY_DIR}/toolchain.pydict ) if((${DOSEK_BINARY_FAIL} STREQUAL "TRUE") OR FAIL_TRACE_ALL) - DOSEK_BINARY_EXECUTABLE(fail-${NAME} "${DOSEK_BINARY_SOURCES}" ${DOSEK_SYSTEM_DESC} ${DOSEK_VERIFY_SCRIPT} + DOSEK_BINARY_EXECUTABLE(fail-${NAME} "${DOSEK_BINARY_SOURCES}" ${DOSEK_SYSTEM_DESC} ${DOSEK_VERIFY_SCRIPT} "FAIL=1" "${DOSEK_BINARY_LIBS}" "${DOSEK_BINARY_GENERATOR_ARGS}") fail_test(${NAME} fail-${NAME}) diff --git a/toolchain/detect b/toolchain/detect new file mode 100755 index 0000000000000000000000000000000000000000..06843cff034c909bf3a02e0d5e306b1feeeb393a --- /dev/null +++ b/toolchain/detect @@ -0,0 +1,174 @@ +#!/usr/bin/python3 + +# This command is used to detect a valid toolchain for building DOSEK. +# It furthermore constructs all tool flags and generates CMake, as +# well as yaml output. + +import sys +import os +import yaml +import subprocess + +def find_program(toolname, path=None): + """Find an absolute path to a toolchain. If no path is given, the + environment path is used to detect the binary""" + + def is_exe(fpath): + return os.path.isfile(fpath) and os.access(fpath, os.X_OK) + if path: + paths = [path] + else: + paths = os.environ["PATH"].split(os.pathsep) + for path in paths: + path = path.strip('"') + exe_file = os.path.join(path, toolname) + if is_exe(exe_file): + return exe_file + +def must(value, msg): + assert value is not None, "detect.py: NOT FOUND: " + msg + return value + + +def cmake_dump(data, stream=None, prefix="TC_"): + def norm(s): + return s.upper().replace("-", "_") + if not stream: + stream = sys.stdout + for k, v in data.items(): + if type(v) is dict: + cmake_dump(v, stream, prefix + norm(k) + "_") + else: + stream.write("SET(%s%s \"%s\" CACHE INTERNAL \"\")\n" % ( + prefix, + norm(k), + repr(str(v))[1:-1] + )) + + +# Toolchain detection steps +def gcc_as_host_compiler(toolchain): + toolchain['host']['cc'] = must(find_program('gcc'), "Host C Compiler") + toolchain['host']['cxx'] = must(find_program('g++'), "Host CXX Compiler") + +# LLVM Config +def llvm_config(toolchain, base="llvm-config", recommended="3.4", hint=None, arch_prefix=""): + # First we find the llvm-config tool + config = find_program("%s-%s" %(arch_prefix+base, recommended), hint) \ + or find_program(arch_prefix+base, hint) \ + or find_program("%s-%s" %(arch_prefix+base, recommended)) \ + or find_program(arch_prefix+base) + must(config, "LLVM Config Tool") + toolchain['target']['llvm-config'] = config + + # Find LLVM Root Directory + llvm_root = subprocess.check_output([config, "--prefix"]).strip().decode('ascii') + llvm_bin = os.path.join(llvm_root, "bin") + toolchain['target']['llvm-root'] = llvm_root + # Find diverse llvm tools + def tool(name): + return must(find_program(arch_prefix + name + "-" + recommended, llvm_bin ) \ + or find_program(arch_prefix + name, llvm_bin) , name) + + toolchain['target']['cc'] = tool('clang') + toolchain['target']['cxx'] = tool('clang++') + + toolchain['target']['opt'] = tool('opt') + toolchain['target']['llc'] = tool('llc') + toolchain['target']['llvm-link'] = tool('llvm-link') + toolchain['target']['llvm-ar'] = tool('llvm-ar') + toolchain['target']['llvm-objdump'] = tool('llvm-objdump') + +def arch_posix(toolchain): + toolchain["target"]["cflags"] = "-Wall -Wextra -m32 -ffunction-sections -fdata-sections -fno-builtin" + toolchain["target"]["cxxflags"] = toolchain["target"]["cflags"] + " -stdlib=libc++ -fno-exceptions -fno-rtti" + toolchain["target"]["asm-attflags"] = "--32" + toolchain["target"]["asmflags"] = "-m32" + toolchain["target"]["ldflags"] = "-m32" + + toolchain['target']['gnu-nm'] = must(find_program("nm"), "Binutils NM") + toolchain['target']['as'] = must(find_program("gcc"), "Binutils AS") + + +def arch_i386(toolchain): + toolchain["target"]["cflags"] = "-m32 -Wall -Wextra -ffreestanding -ffunction-sections -fdata-sections -fno-builtin" + toolchain["target"]["cxxflags"] = toolchain["target"]["cflags"] + " -fno-exceptions -fno-rtti" + toolchain["target"]["asm-attflags"] = "--32" + toolchain["target"]["asmflags"] = "-m32" + + toolchain["target"]["ldflags"] = "-m32 -static -nostdlib -Wl,--build-id=none" + toolchain["target"]["ldflags"] += " -mattr=+popcnt -nozero-initialized-in-bss" + toolchain["target"]["ldflags"] += " -ffreestanding -nostartfiles -march=x86 -mcpu=i386 -Wl,--gc-sections" + + toolchain['target']['gnu-nm'] = must(find_program("nm"), "Binutils NM") + toolchain['target']['as'] = must(find_program("gcc"), "Binutils AS") + + + # Required for the Page Table generation + toolchain['target']['gnu-objdump'] = must(find_program("objdump"), "Binutils OBJDUMP") + +def arch_ARM_A9(toolchain): + p = "arm-none-eabi-" + common = "-target armv7a-none-elf -mcpu=cortex-a9 -mfloat-abi=soft -mthumb -ccc-gcc-name arm-none-eabi-gcc -no-integrated-as" + toolchain["target"]["cflags"] = common + " -Wall -Wextra -I/usr/lib/arm-none-eabi/include " \ + + " -Xclang -no-implicit-float -ffreestanding" + toolchain["target"]["cxxflags"] = toolchain["target"]["cflags"] + " -fno-unwind-tables -fno-exceptions -fno-rtti" + toolchain["target"]["asm-attflags"] = "" + toolchain["target"]["asmflags"] = "-mcpu=cortex-a9 -mthumb" + + toolchain["target"]["ldflags"] = common+ " -nostdlib -static -Wl,--gc-sections" + + toolchain['target']['gnu-nm'] = must(find_program(p + "nm"), "Binutils NM") + toolchain['target']['as'] = must(find_program(p + "gcc"), "Binutils AS") + + # toolchain['target']['gnu-objdump'] = must(find_program(p + "objdump"), "Binutils OBJDUMP") + + +def arch_patmos(toolchain): + toolchain["target"]["cflags"] = "-Wall -Wextra" + toolchain["target"]["cxxflags"] = "-Wall -Wextra -fno-exceptions -fno-rtti" + toolchain["target"]["asm-attflags"] = "" + toolchain["target"]["asmflags"] = "" + + toolchain["target"]["ldflags"] = "-Xgold,-gc-sections -nostdlib -nostartfiles -Xc,-mforce-block-labels" + toolchain["target"]["no-start-group"] = "true" + + + toolchain['target']['gnu-nm'] = must(find_program("patmos-nm"), "Binutils NM") + toolchain['target']['as'] = must(find_program("patmos-llvm-as"), "Binutils AS") + toolchain['target']['platin'] = must(find_program("platin"), "Platin WCET Analyzer") + +if __name__ == "__main__": + arches = {"i386": [(llvm_config, {"hint": "/proj/i4danceos/tools/llvm-3.4/bin", + "recommended": "3.9"}), + arch_i386], + "ARM": [(llvm_config, {"hint": "/proj/i4danceos/tools/llvm-3.4/bin"}), + arch_ARM_A9], + "posix": [(llvm_config, {"hint": "/proj/i4danceos/tools/llvm-3.4/bin"}), + arch_posix, + ], + "patmos": [(llvm_config, {"arch_prefix": "patmos-"}), + arch_patmos]} + if len(sys.argv) < 3 or sys.argv[1] not in arches: + sys.exit("%s <arch> <prefix-dir/>; arches = %s" % (sys.argv[0], arches)) + + toolchain = {'host': {}, 'target': {}} + + generic = [gcc_as_host_compiler] + + # Execute all toolchain detection steps + for P in generic + arches[sys.argv[1]]: + if type(P) is tuple: + P[0](toolchain, **P[1]) + else: + P(toolchain) + + with open(os.path.join(sys.argv[2], "toolchain.cmake"), "w+") as fd: + cmake_dump(toolchain, stream=fd) + with open(os.path.join(sys.argv[2], "toolchain.yaml"), "w+") as fd: + yaml.dump(toolchain, stream=fd) + with open(os.path.join(sys.argv[2], "toolchain.pydict"), "w+") as fd: + fd.write(repr(toolchain) + "\n") + + sys.stderr.write("Target CC: %s\n" % toolchain['target']['cc']) + sys.stderr.write("Target CXX: %s\n" % toolchain['target']['cxx']) diff --git a/toolchain/i386.cmake b/toolchain/i386.cmake deleted file mode 100644 index 9bd6ddbf80cace30a7762a98cf32e243d4449a6e..0000000000000000000000000000000000000000 --- a/toolchain/i386.cmake +++ /dev/null @@ -1,112 +0,0 @@ -# Generic system -# removes -rdynamic from the linker, which llvm-ld does not support. -set(CMAKE_SYSTEM_NAME Generic) - -# LLVM version. -SET(LLVM_RECOMMENDED_VERSION 3.4) - -if(NOT DEFINED ${LLVM_ROOT}) - # find llvm-config. prefers to the one with version suffix, Ex:llvm-config-3.4 - # find llvm-config. prefers to the one with version suffix, Ex:llvm-config-3.4 - find_program(LLVM_CONFIG_EXE NAMES "llvm-config-${LLVM_RECOMMENDED_VERSION}" - PATHS /proj/i4danceos/tools/llvm-${LLVM_RECOMMENDED_VERSION}/bin) - if (NOT LLVM_CONFIG_EXE) - find_program(LLVM_CONFIG_EXE NAMES "llvm-config" - PATHS /proj/i4danceos/tools/llvm-${LLVM_RECOMMENDED_VERSION}/bin) - endif() - - # Get the directory of llvm by using llvm-config. also remove whitespaces. - execute_process(COMMAND ${LLVM_CONFIG_EXE} --prefix OUTPUT_VARIABLE LLVM_ROOT - OUTPUT_STRIP_TRAILING_WHITESPACE ) -endif() - -message(STATUS "LLVM root: ${LLVM_ROOT}") - -# Find a compiler which compiles c source into llvm bitcode. -# It first finds clang, then it finds llvm-g++ if there is no clang. -find_program(LLVM_C_COMPILER "clang-${LLVM_RECOMMENDED_VERSION}" - NAMES clang - HINTS ${LLVM_ROOT}/bin ) -# Find a compiler which compiles c++ source into llvm bitcode. -# It first finds clang, then it finds llvm-g++ if there is no clang. -find_program(LLVM_CXX_COMPILER "clang++-${LLVM_RECOMMENDED_VERSION}" - NAMES clang++ - HINTS ${LLVM_ROOT}/bin ) - - -# Checks whether a LLVM_COMPILER is found, give a warning if not found. -# A warning instread of error is beceuse that we don't need clang during -# building pinavm. -if(${LLVM_C_COMPILER} STREQUAL "LLVM_C_COMPILER-NOTFOUND") - message(FATAL "Could not find clang or llvm-g++." - " Please install one of them !") -endif() - -message(STATUS "LLVM compiler: ${LLVM_C_COMPILER}") - - -if (${CMAKE_HOST_SYSTEM_NAME} STREQUAL "Darwin") - set(ARCH_PREFIX "i386-elf-") - find_program(CROSS_GCC "${ARCH_PREFIX}gcc") - # gcc -print-search-dirs first line: install: ... - execute_process(COMMAND ${CROSS_GCC} -print-search-dirs OUTPUT_VARIABLE GCC_SEARCH_PATH OUTPUT_STRIP_TRAILING_WHITESPACE) - message(status "search dirs: ${GCC_SEARCH_PATH}") - STRING(REGEX REPLACE "^install: ([^ ]+)\n.*" "\\1" CROSS_ROOT_PATH ${GCC_SEARCH_PATH}) - - find_program(CROSS_AR "${ARCH_PREFIX}ar") - find_program(CROSS_NM "${ARCH_PREFIX}nm") - find_program(CROSS_RANLIB "${ARCH_PREFIX}ranlib") - # Find objdump for pagetable generation - find_program(CROSS_OBJDUMP "${ARCH_PREFIX}objdump") - - set(CROSS_COMPILER_FLAGS "-ccc-gcc-name ${ARCH_PREFIX}gcc -target i386-pc-none") - - set(CMAKE_ASM_COMPILER ${ARCH_PREFIX}gcc) - - message(STATUS "Cross compiler root: ${CROSS_ROOT_PATH}") -elseif(${CMAKE_HOST_SYSTEM_NAME} STREQUAL "Linux") - set(CROSS_RANLIB ${LLVM_ROOT}/bin/llvm-ranlib) - set(CROSS_AR ${LLVM_ROOT}/bin/llvm-ar) - find_program(CROSS_OBJDUMP objdump) - find_program(CROSS_NM "${ARCH_PREFIX}nm" "nm") -else() - message(FATAL "Host system not found :(") -endif() - -set(CMAKE_C_ARCH "i386") -set(CMAKE_C_FLAGS "${CROSS_COMPILER_FLAGS} -ffreestanding -march=${CMAKE_C_ARCH} -m32 -Wall -Wextra -Qunused-arguments -Wno-undefined-inline" CACHE STRING "CFLAGS") -set(CMAKE_CXX_FLAGS "${CMAKE_C_FLAGS} -fno-exceptions -fno-rtti" CACHE STRING "CXXFLAGS") -set(CMAKE_ASM_FLAGS "-Qunused-arguments -fno-builtin " CACHE STRING "ASMFLAGS") -set(CMAKE_ASM-ATT_FLAGS "-Qunused-arguments" CACHE STRING "ASMFLAGS") -set(CMAKE_EXE_LINKER_FLAGS "-nostartfiles ${CMAKE_CXX_FLAGS}" CACHE STRING "LDFLAGS") - -set(CCDIR "${LLVM_ROOT}") -set(CMAKE_C_COMPILER ${LLVM_C_COMPILER}) -set(CMAKE_CXX_COMPILER ${LLVM_CXX_COMPILER}) -set(CMAKE_RANLIB "${CROSS_RANLIB}" CACHE INTERNAL STRING) -set(CMAKE_AR "${CROSS_AR}" CACHE INTERNAL STRING) - -SET(CMAKE_FIND_ROOT_PATH ${CROSS_ROOT_PATH}) -SET(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER) -SET(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY) -SET(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY) - -## Add *additional* architecture specific compiler flags here. -# Note that the flags set in toolchain.cmake are still present and used. -set(ISA_C_FLAGS "-S -emit-llvm -O0 -m32" CACHE INTERNAL STRING) -set(ISA_CXX_FLAGS "-m32" CACHE INTERNAL STRING) -set(ISA_ASM_FLAGS "-m32" CACHE INTERNAL STRING) -set(ISA_ASM-ATT_FLAGS "--32" CACHE INTERNAL STRING) -set(ISA_LD_FLAGS "-fno-builtin -m32 -static -nostdlib -Qunused-arguments -Wl,--build-id=none" CACHE INTERNAL STRING) - -set(LD_OUTPUT_FORMAT "elf32-i386" CACHE INTERNAL "LD output format for linker script") - -## The kernel will live at 3GB + 1MB in the virtual -## address space, which will be mapped to 1MB in the -## physical address space. -set(LD_KERNEL_START_ADDRESS 0x100000 CACHE INTERNAL "Start address of the first section.") - -# ENABLE x86 32 platform -set(BUILD_i386 "on" CACHE INTERNAL STRING) -set(DOSEK_ARCHITECTURE "i386") - diff --git a/toolchain/llvm-link.py b/toolchain/llvm-link.py index 5d8def9b09e6c4604377bc4c43ce5b396bd04825..22986df7d79a1d8a1eb223c5c5ec91a85abe5c01 100755 --- a/toolchain/llvm-link.py +++ b/toolchain/llvm-link.py @@ -6,6 +6,7 @@ import shutil import subprocess import os import glob +from collections import OrderedDict def is_llvm_file(file): if not os.path.exists(file): @@ -59,25 +60,28 @@ def check_output(*args, **kwargs): return subprocess.check_output(*args, **kwargs) def llvm_link(files, output): - check_output([os.path.join(args.llvm_dir, "bin", "llvm-link"), - "-o", output] + files) + check_output([toolchain['target']['llvm-link'], "-o", output] + files) return output def llvm_opt(input, output): - check_output([os.path.join(args.llvm_dir, "bin", "opt"), - "-std-compile-opts", "-always-inline", "-o", output, input]) + check_output([toolchain['target']['opt'], "-always-inline", "-o", output, input]) + return output + +def llvm_opt_careful(input, output): + check_output([toolchain['target']['opt'], "-inline", "-constprop", "-dse", "-o", output, input]) return output def llvm_llc(file, output, flags): - check_output([os.path.join(args.llvm_dir, "bin", "llc")] + flags + ["-o", output, file]) + check_output([toolchain['target']['llc']] + flags + ["-o", output, file]) return output def start_ld(flags, objects, output): - # check_output([os.path.join(args.llvm_dir, "bin", "clang")] + ["-Wl,--start-group"] + objects + ["-Wl,--end-group"] - # + flags + ["-c", "-o", output + ".obj"]) + check_output([toolchain['target']['cc'], "-Wl,--start-group"] + objects + ["-Wl,--end-group"] + + flags + ["-o", output]) + +def link_with_clang(bitcode, flags, output): + check_output([toolchain['target']['cc'], bitcode] + flags + ["-o", output]) - check_output([args.clang, "-Wl,--start-group"] + objects + ["-Wl,--end-group"] - + flags + ["-o", output, "-Wl,-gc-sections"]) if __name__ == "__main__": import argparse @@ -85,48 +89,53 @@ if __name__ == "__main__": parser = argparse.ArgumentParser(description='Linker for dOSEK.') parser.add_argument("--output", "-o", metavar='OUT', help='The file to generate') parser.add_argument("--linker-prefix", metavar='PREFIX', help='Output file prefix') - parser.add_argument("--llvm-dir", metavar='LLVM_DIR', help='Where are the llvm binaries located') - parser.add_argument("--march", metavar='MARCH', help='Target Architecture for llc [arm|x86]') - parser.add_argument("--mcpu", metavar='MCPU', help='Target CPU for llc [cortex-a9|i386') - parser.add_argument("--clang", metavar='CLANG_BINARY', help='Clang binary location') - parser.add_argument("--ar", default="/usr/bin/ar", help="ar binary location", metavar="AR") + parser.add_argument("--toolchain-file", metavar='TOOLCHAIN', help="Toolchain configuration") args, unkown_args = parser.parse_known_args() + unkown_args = [x for x in unkown_args if not x == "-rdynamic"] archives = [x for x in unkown_args if x.endswith(".a")] elf_files = [x for x in unkown_args if is_elf_file(x)] llvm_files = [x for x in unkown_args if is_llvm_file(x)] - compiler_flags = [x for x in unkown_args if x.startswith("-mattr")] + compiler_flags = [x for x in unkown_args if \ + x.startswith("-mattr") \ + or x.startswith("-mcpu") \ + or x.startswith("-march") \ + or x.startswith("-mserialize") \ + or x.startswith("-mforce-block-labels") \ + or x in ("-nozero-initialized-in-bss", "-ffunction-sections", "-fdata-sections") + or x.startswith("-O")] + # unique + compiler_flags = list(OrderedDict.fromkeys(compiler_flags)) # Remove file arguments from unkown args linker_flags = [x for x in unkown_args if not(x in archives + elf_files + llvm_files + compiler_flags)] - if args.march: - llc_march = "-march=" + args.march - else: - llc_march = "" - - if args.mcpu: - llc_mcpu = "-mcpu=" + args.mcpu - else: - llc_mcpu = "" + global toolchain + toolchain = eval(open(args.toolchain_file).read()) try: tempdir = tempfile.mkdtemp() - (elf_, llvm_) = aggregate_bitcode(archives, args.ar) + (elf_, llvm_) = aggregate_bitcode(archives, toolchain['target']['llvm-ar']) elf_files += elf_ llvm_files += llvm_ # Link all bitcode files together bitcode = llvm_link(llvm_files, args.linker_prefix + "-stage1.bc") - bitcode_opt = llvm_opt(bitcode, args.linker_prefix + "-stage2.bc") - llc_flags = [llc_march, llc_mcpu, "-filetype=obj", "-ffunction-sections", "-fdata-sections", "-nozero-initialized-in-bss"] - llc_flags += compiler_flags - llc_flags = [x for x in llc_flags if not x == ""] - system_object = llvm_llc(bitcode_opt, args.linker_prefix + ".obj", llc_flags) - start_ld(linker_flags, [system_object] + elf_files, args.output) + if toolchain['target'].get("no-start-group", False): + assert len(elf_files) == 0, "There are ELF files" + elf_files + bitcode_opt = llvm_opt_careful(bitcode, args.linker_prefix + "-stage2.bc") + flags = compiler_flags + linker_flags + link_with_clang(bitcode_opt, flags, args.output) + else: + bitcode_opt = llvm_opt(bitcode, args.linker_prefix + "-stage2.bc") + llc_flags = ["-filetype=obj"] + llc_flags += compiler_flags + llc_flags = [x for x in llc_flags if not x == ""] + system_object = llvm_llc(bitcode_opt, args.linker_prefix + ".obj", llc_flags) + + start_ld(linker_flags, [system_object] + elf_files, args.output) finally: shutil.rmtree(tempdir) pass - diff --git a/toolchain/posix.cmake b/toolchain/posix.cmake deleted file mode 100644 index 9ad909cabc650bfd9d779ed4daf55c13b51b7127..0000000000000000000000000000000000000000 --- a/toolchain/posix.cmake +++ /dev/null @@ -1,106 +0,0 @@ -# Generic system -set(ARCH_PREFIX "") - - -message(STATUS "Cross compiler root: ${CROSS_ROOT_PATH}") - -# LLVM version. -SET(LLVM_RECOMMENDED_VERSION 3.4) - -if(NOT DEFINED ${LLVM_ROOT}) - # find llvm-config. prefers to the one with version suffix, Ex:llvm-config-3.4 - find_program(LLVM_CONFIG_EXE NAMES "llvm-config-${LLVM_RECOMMENDED_VERSION}" - PATHS /proj/i4danceos/tools/llvm-${LLVM_RECOMMENDED_VERSION}/bin) - if (NOT LLVM_CONFIG_EXE) - find_program(LLVM_CONFIG_EXE NAMES "llvm-config" - PATHS /proj/i4danceos/tools/llvm-${LLVM_RECOMMENDED_VERSION}/bin) - endif() - - # Get the directory of llvm by using llvm-config. also remove whitespaces. - execute_process(COMMAND ${LLVM_CONFIG_EXE} --prefix OUTPUT_VARIABLE LLVM_ROOT - OUTPUT_STRIP_TRAILING_WHITESPACE ) -endif() - - -message(STATUS "LLVM root: ${LLVM_ROOT}") - -# Find a compiler which compiles c source into llvm bitcode. -# It first finds clang, then it finds llvm-g++ if there is no clang. -find_program(LLVM_C_COMPILER "clang-${LLVM_RECOMMENDED_VERSION}" - NAMES clang - HINTS ${LLVM_ROOT}/bin ) - - -# Find a compiler which compiles c++ source into llvm bitcode. -# It first finds clang, then it finds llvm-g++ if there is no clang. -find_program(LLVM_CXX_COMPILER "clang++-${LLVM_RECOMMENDED_VERSION}" - NAMES clang++ - HINTS ${LLVM_ROOT}/bin ) - -# Checks whether a LLVM_COMPILER is found, give a warning if not found. -# A warning instread of error is beceuse that we don't need clang during -# building pinavm. -if(${LLVM_C_COMPILER} STREQUAL "LLVM_C_COMPILER-NOTFOUND") - message(WARNING "Could not find clang or llvm-g++." - " Please install one of them !") -endif() - - -set(CMAKE_C_ARCH "i386") -set(CMAKE_C_FLAGS "-Wall -m32 -Wextra -Qunused-arguments -Wno-undefined-inline" CACHE STRING "CFLAGS") -set(CMAKE_CXX_FLAGS "${CMAKE_C_FLAGS} -fno-exceptions -fno-rtti" CACHE STRING "CXXFLAGS") -set(CMAKE_ASM_FLAGS "-Qunused-arguments" CACHE STRING "ASMFLAGS") -set(CMAKE_ASM-TT_FLAGS "-Qunused-arguments" CACHE STRING "ASMFLAGS") - -find_program(CROSS_AR "llvm-ar" HINTS ${LLVM_ROOT}/bin) -find_program(CROSS_NM "nm") -find_program(CROSS_RANLIB "llvm-ranlib" HINTS ${LLVM_ROOT}/bin) -# Find objdump for pagetable generation -find_program(CROSS_OBJDUMP "llvm-objdump") - - -set(CCDIR "${LLVM_ROOT}") -set(CMAKE_C_COMPILER ${LLVM_C_COMPILER}) -set(CMAKE_CXX_COMPILER ${LLVM_CXX_COMPILER}) -set(CMAKE_RANLIB "${CROSS_RANLIB}" CACHE INTERNAL STRING) -set(CMAKE_AR "${CROSS_AR}" CACHE INTERNAL STRING) - - -SET(CMAKE_FIND_ROOT_PATH ${CCDIR}) -SET(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER) -SET(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY) -SET(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY) - -#set(CCDIR "/proj/i4danceos/tools/llvm-3.4") -#set(CMAKE_C_COMPILER ${CCDIR}/bin/clang) -#set(CMAKE_CXX_COMPILER ${CCDIR}/bin/clang++) -#set(CMAKE_CXX_COMPILER ${CCDIR}/bin/clang++) -#set(CMAKE_RANLIB "${CCDIR}/bin/llvm-ranlib" CACHE INTERNAL STRING) -#set(CMAKE_AR "${CCDIR}/bin/llvm-ar" CACHE INTERNAL STRING) -# -#SET(CMAKE_FIND_ROOT_PATH ${CCDIR}) -#SET(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER) -#SET(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY) -#SET(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY) - -## Add *additional* architecture specific compiler flags here. -# Note that the flags set in toolchain.cmake are still present and used. -set(ISA_C_FLAGS "-g -c -emit-llvm" CACHE INTERNAL STRING) -set(ISA_CXX_FLAGS "-g -stdlib=libc++" CACHE INTERNAL STRING) -set(ISA_ASM-ATT_FLAGS "--32" CACHE INTERNAL STRING) -set(ISA_ASM_FLAGS "-m32" CACHE INTERNAL STRING) -set(ISA_LD_FLAGS "-m32 -Qunused-arguments" CACHE INTERNAL STRING) - -#set(LD_OUTPUT_FORMAT "elf32-i386" CACHE INTERNAL "LD output format for linker script") - -## The kernel will live at 3GB + 1MB in the virtual -## address space, which will be mapped to 1MB in the -## physical address space. -#set(LD_KERNEL_START_ADDRESS 0x100000 CACHE INTERNAL "Start address of the first section.") - -# ENABLE posix platform -set(BUILD_posix "on" CACHE INTERNAL STRING) -set(DOSEK_ARCHITECTURE "posix") - - -