From a1c1d4271061eff9f4bb4a0c9c31bb68c7f1514d Mon Sep 17 00:00:00 2001 From: Roland Takacs <1487864+rtakacs@users.noreply.github.com> Date: Thu, 2 Dec 2021 15:33:29 +0100 Subject: [PATCH] Update Zephyr target to 2.7.0 (#4838) JerryScript-DCO-1.0-Signed-off-by: Roland Takacs roland.takacs@h-lab.eu --- .github/workflows/gh-actions.yml | 2 +- targets/zephyr/CMakeLists.txt | 51 +++-- targets/zephyr/Makefile.travis | 25 ++- targets/zephyr/Makefile.zephyr | 170 ---------------- targets/zephyr/README.md | 153 +++++++------- targets/zephyr/docs/arduino_101.jpg | Bin 22138 -> 0 bytes targets/zephyr/src/Makefile | 22 -- targets/zephyr/src/jerry-module.c | 302 ++++++++++++++++++++++++++++ targets/zephyr/src/jerry-port.c | 153 ++++++++++++-- 9 files changed, 551 insertions(+), 327 deletions(-) delete mode 100644 targets/zephyr/Makefile.zephyr delete mode 100644 targets/zephyr/docs/arduino_101.jpg delete mode 100644 targets/zephyr/src/Makefile create mode 100644 targets/zephyr/src/jerry-module.c diff --git a/.github/workflows/gh-actions.yml b/.github/workflows/gh-actions.yml index 5ea7af976a..c984c28036 100644 --- a/.github/workflows/gh-actions.yml +++ b/.github/workflows/gh-actions.yml @@ -259,7 +259,7 @@ jobs: - run: make -f ./targets/mbedos5/Makefile.travis install - run: make -f ./targets/mbedos5/Makefile.travis script - Zephyr_Qemu_x86_Build_Test: + Zephyr_STM32F4_Build_Test: runs-on: ubuntu-latest steps: - uses: actions/checkout@v2 diff --git a/targets/zephyr/CMakeLists.txt b/targets/zephyr/CMakeLists.txt index 30b7c7ba60..ce6be95efb 100644 --- a/targets/zephyr/CMakeLists.txt +++ b/targets/zephyr/CMakeLists.txt @@ -11,38 +11,35 @@ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. -cmake_minimum_required(VERSION 3.8) -include($ENV{ZEPHYR_BASE}/cmake/app/boilerplate.cmake NO_POLICY_SCOPE) +cmake_minimum_required(VERSION 3.20.0) + +find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE}) project(NONE) -target_sources(app PRIVATE src/main-zephyr.c src/jerry-port.c src/getline-zephyr.c) +set(JERRY_BASE ${CMAKE_SOURCE_DIR}/../..) + +# Build JerryScript +execute_process(COMMAND ${JERRY_BASE}/tools/build.py + --clean + --lto=OFF + --jerry-cmdline=OFF + --jerry-math=ON + --amalgam=ON + --mem-heap=70 + --profile=es.next + --compile-flag=--sysroot=${ZEPHYR_BASE} + --toolchain=${JERRY_BASE}/cmake/toolchain_mcu_stm32f4.cmake) +# Define library targets add_library(jerry-core STATIC IMPORTED) add_library(jerry-ext STATIC IMPORTED) -set_target_properties(jerry-core PROPERTIES IMPORTED_LOCATION - ${CMAKE_CURRENT_BINARY_DIR}/../obj/lib/libjerry-core.a) -set_target_properties(jerry-core PROPERTIES INTERFACE_INCLUDE_DIRECTORIES - ${CMAKE_CURRENT_SOURCE_DIR}/../../jerry-core/include) -set_target_properties(jerry-ext PROPERTIES IMPORTED_LOCATION - ${CMAKE_CURRENT_BINARY_DIR}/../obj/lib/libjerry-ext.a) -set_target_properties(jerry-ext PROPERTIES INTERFACE_INCLUDE_DIRECTORIES - ${CMAKE_CURRENT_SOURCE_DIR}/../../jerry-ext/include) -target_link_libraries(app PUBLIC jerry-core jerry-ext) -zephyr_get_include_directories_for_lang_as_string(C includes) -zephyr_get_system_include_directories_for_lang_as_string(C system_includes) -zephyr_get_compile_definitions_for_lang_as_string(C definitions) -zephyr_get_compile_options_for_lang_as_string(C options) - -add_custom_target( - outputexports - COMMAND echo CC="${CMAKE_C_COMPILER}" - COMMAND echo Z_CFLAGS=${system_includes} ${includes} ${definitions} ${options} - COMMAND echo NOSTDINC_FLAGS=${system_includes} - COMMAND echo ZEPHYRINCLUDE=${includes} - COMMAND echo KBUILD_CFLAGS=${definitions} ${options} - VERBATIM - USES_TERMINAL -) +# Define include directories and archives +set_target_properties(jerry-core PROPERTIES IMPORTED_LOCATION ${JERRY_BASE}/build/lib/libjerry-core.a) +set_target_properties(jerry-core PROPERTIES INTERFACE_INCLUDE_DIRECTORIES ${JERRY_BASE}/jerry-core/include) +set_target_properties(jerry-ext PROPERTIES IMPORTED_LOCATION ${JERRY_BASE}/build/lib/libjerry-ext.a) +set_target_properties(jerry-ext PROPERTIES INTERFACE_INCLUDE_DIRECTORIES ${JERRY_BASE}/jerry-ext/include) +target_sources(app PRIVATE src/main-zephyr.c src/getline-zephyr.c src/jerry-port.c src/jerry-module.c) +target_link_libraries(app PUBLIC jerry-core jerry-ext) diff --git a/targets/zephyr/Makefile.travis b/targets/zephyr/Makefile.travis index 0b22bbefc1..93f0996693 100644 --- a/targets/zephyr/Makefile.travis +++ b/targets/zephyr/Makefile.travis @@ -23,16 +23,16 @@ all: # Install tools via apt. install-apt-get-deps: - sudo apt-get install -q -y gperf dfu-util device-tree-compiler + sudo apt-get install -q -y gperf dfu-util device-tree-compiler gcc-arm-none-eabi # Install Zephyr SDK. -install-zephyr-sdk: - wget https://github.com/zephyrproject-rtos/sdk-ng/releases/download/v0.13.0/zephyr-sdk-0.13.0-linux-x86_64-setup.run -O ../zephyr-sdk-0.13.0-linux-x86_64-setup.run - sh ../zephyr-sdk-0.13.0-linux-x86_64-setup.run -- -y -d $(CURDIR)/../zephyr-sdk-0.13.0 +install-zephyr-toolchain: + wget https://github.com/zephyrproject-rtos/sdk-ng/releases/download/v0.13.2/zephyr-toolchain-arm-0.13.2-linux-x86_64-setup.run -O ../zephyr-toolchain-arm-0.13.2-linux-x86_64-setup.run + sh ../zephyr-toolchain-arm-0.13.2-linux-x86_64-setup.run -- -y -d $(CURDIR)/../zephyr-toolchain-0.13.2 # Fetch Zephyr Project repository and install python dependencies. install-zephyr: - git clone https://github.com/zephyrproject-rtos/zephyr.git ../zephyr -b v2.5-branch + git clone https://github.com/zephyrproject-rtos/zephyr.git ../zephyr -b v2.7.0 pip3 install -U pip pip3 install -U setuptools pip3 install -r ../zephyr/scripts/requirements.txt @@ -43,16 +43,21 @@ install-cmake: cmake --version # Perform all the necessary (JerryScript-independent) installation steps. -install-noapt: install-zephyr-sdk install-zephyr install-cmake +install-noapt: install-zephyr-toolchain install-zephyr install-cmake install: install-apt-get-deps install-noapt ## Targets for building Zephyr with JerryScript. +# Initialize west meta-tool +init-west: + west init -l $(CURDIR)/../zephyr + west update hal_stm32 cmsis + west zephyr-export + # Build the firmware (Zephyr with JerryScript). SHELL=bash -script: +script: init-west export ZEPHYR_TOOLCHAIN_VARIANT=zephyr && \ - export ZEPHYR_SDK_INSTALL_DIR=$(CURDIR)/../zephyr-sdk-0.13.0 && \ - source ../zephyr/zephyr-env.sh && \ - $(MAKE) -f ./targets/zephyr/Makefile.zephyr BOARD=qemu_x86 + export ZEPHYR_SDK_INSTALL_DIR=$(CURDIR)/../zephyr-toolchain-0.13.2 && \ + west build -d $(CURDIR)/../build -p auto -b stm32f4_disco targets/zephyr/ -- -G'Unix Makefiles' diff --git a/targets/zephyr/Makefile.zephyr b/targets/zephyr/Makefile.zephyr deleted file mode 100644 index d182df34d7..0000000000 --- a/targets/zephyr/Makefile.zephyr +++ /dev/null @@ -1,170 +0,0 @@ -# Copyright JS Foundation and other contributors, http://js.foundation -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -.DEFAULT_GOAL := all - -ifeq ($(.DEFAULT_GOAL),) - $(warning no default goal is set) -endif - -BOARD ?= qemu_x86 -CONF_FILE = prj.conf -export BOARD - -TARGET_ZEPHYR ?= ./targets/zephyr -TARGET_ZEPHYR_SRC_DIR = $(TARGET_ZEPHYR)/src - -COMPONENTS ?= jerry-core jerry-ext -JERRYHEAP ?= 16 -JERRYPROFILE ?= minimal - -# Include functionality like regular expressions -# check Jerry script documentation -# -# -cp -# -cp_minimal -# -cp_minimal-mem_stats -# -mem_stats -# -mem_stress_test - -ifndef ZEPHYR_BASE -$(error Missing Zephyr base, did you source zephyr-env.sh? ) -endif - -INTERM = build/$(BOARD)/obj -OUTPUT = build/$(BOARD)/zephyr - -include $(OUTPUT)/Makefile.export - -EXT_CFLAGS := -fno-asynchronous-unwind-tables -fno-omit-frame-pointer -EXT_CFLAGS += -fno-stack-protector -fno-strict-overflow -ffreestanding -EXT_CFLAGS += -fno-reorder-functions -fno-defer-pop -fdata-sections -EXT_CFLAGS += -ffunction-sections -fno-inline-functions - -EXT_CFLAGS += $(KBUILD_CFLAGS) $(NOSTDINC_FLAGS) $(subst -I,-isystem,$(ZEPHYRINCLUDE)) - -EXT_CFLAGS += -Wall -Wno-format-zero-length -Wno-pointer-sign -EXT_CFLAGS += -Werror=format -Werror=implicit-int -Wno-unused-but-set-variable -EXT_CFLAGS += -Wno-main -Wno-strict-aliasing -Wno-old-style-declaration -EXT_CFLAGS += -Wno-error=format= -EXT_CFLAGS += -D_XOPEN_SOURCE=700 - -EXT_CFLAGS += -Wno-error=conversion - -EXTERNAL_LIB = $(INTERM)/lib/libjerry-core.a $(INTERM)/lib/libjerry-ext.a - -LIBS = jerry-core jerry-ext - -BUILD_CONFIG = O="$(OUTPUT)" V=$(V) USER_LIBS="$(LIBS)" USER_LIB_INCLUDE_DIR="-L $(CURDIR)/$(INTERM)/lib" TARGET_ZEPHYR=$(TARGET_ZEPHYR) - -.PHONY: all -all: zephyr - -$(EXTERNAL_LIB): -ifdef V - @echo "- JERRY SCRIPT -------------------------------------------------" -endif - mkdir -p $(INTERM) - mkdir -p $(OUTPUT) - cmake -B$(INTERM) -H./ \ - -DCMAKE_SYSTEM_NAME=Zephyr \ - -DCMAKE_C_COMPILER="$(subst ccache ,,$(CC))" \ - -DCMAKE_C_COMPILER_WORKS=TRUE \ - -DENABLE_LTO=OFF \ - -DJERRY_CMDLINE=OFF \ - -DJERRY_PROFILE=$(JERRYPROFILE) \ - -DJERRY_ERROR_MESSAGES=ON \ - -DCMAKE_BUILD_TYPE=MinSizeRel \ - -DCMAKE_VERBOSE_MAKEFILE=$(V) \ - -DJERRY_GLOBAL_HEAP_SIZE=$(JERRYHEAP) \ - -DEXTERNAL_COMPILE_FLAGS="$(EXT_CFLAGS)" \ - $(EXT_JERRY_FLAGS) - - make -C $(INTERM) $(COMPONENTS) V=1 - -$(OUTPUT)/Makefile.export: $(OUTPUT)/Makefile - make --no-print-directory -C $(OUTPUT) outputexports CMAKE_COMMAND=: >$@ - -$(OUTPUT)/Makefile: - mkdir -p $(OUTPUT) && cmake -DBOARD=$(BOARD) -DCONF_FILE=$(CONF_FILE) -B$(OUTPUT) -Htargets/zephyr/ - -zephyr: jerry -ifdef V - @echo "- ZEPHYR -------------------------------------------------------" -endif - +make -C $(OUTPUT) - @echo "Finished" - @size $(OUTPUT)/zephyr/zephyr.elf - -jerry: $(EXTERNAL_LIB) - @touch $(EXTERNAL_LIB) - -GENERIC_TARGETS = run qemugdb flash debug debugserver -KCONFIG_TARGETS = \ - initconfig config nconfig menuconfig xconfig gconfig \ - oldconfig silentoldconfig defconfig savedefconfig \ - allnoconfig allyesconfig alldefconfig randconfig \ - listnewconfig olddefconfig -CLEAN_TARGETS = mrproper - -$(GENERIC_TARGETS): jerry -$(CLEAN_TARGETS): clean - -$(GENERIC_TARGETS) $(KCONFIG_TARGETS) $(CLEAN_TARGETS): -ifdef V - @echo "- ZEPHYR -------------------------------------------------------" -endif - make -C $(OUTPUT) $@ - -dfu-x86: all - @- dfu-util -a x86_app -D build/$(BOARD)/zephyr/zephyr.bin; \ - if [ $$? -eq 0 ] ; then echo "\nYour program will launch in 5 seconds." ; \ - else echo "\nProgram didn't flash, try pressing the reset buttons \nand wait a second for the bootloader to load, \nor flash again the factory bootloader."; fi - -usage: -help: - @echo Usage: - @echo showconfig Show parameters and configuration - @echo flash Flash into board - @echo all Compile jerryscript and zephyr - -showconfig: - @echo "- CONFIGURATION ------------------------------------------------" - @echo "INTERM = $(INTERM)" - @echo "OUTPUT = $(OUTPUT)" - @echo "CC = $(CC) " - @echo "BOARD = $(ZEPHYR_BASE)/boards/$(BOARD)/Makefile.board " - @echo "TOOLCHAIN = $(ZEPHYR_BASE)/scripts/Makefile.toolchain.$(ZEPHYR_GCC_VARIANT) " - @echo "TOOLCHAIN_CFLAGS = $(TOOLCHAIN_CFLAGS) " - @echo "CROSS_COMPILE = $(CROSS_COMPILE) " - @echo "TOOLCHAIN_LIBS = $(TOOLCHAIN_LIBS) " - @echo "LIBS = $(LIBS) " - @echo "BUILD_CONFIG = $(BUILD_CONFIG) " - make -f $(TARGET_ZEPHYR)/Makefile $(BUILD_CONFIG) showconfig - -clean: -ifdef V - @echo "- CLEANING JERRY SCRIPT ----------------------------------------" -endif - rm -rf $(INTERM) $(TARGET_ZEPHYR_SRC_DIR)/*.o -ifdef V - @echo "- CLEANING ZEPHYR ----------------------------------------------" -endif - make -f $(TARGET_ZEPHYR)/Makefile $(BUILD_CONFIG) clean - -pristine: clean -ifdef V - @echo "- CLEANING BUILD DIRECTORY -------------------------------------" -endif - rm -rf build/ diff --git a/targets/zephyr/README.md b/targets/zephyr/README.md index 8e52f016f2..2cdd4f1793 100644 --- a/targets/zephyr/README.md +++ b/targets/zephyr/README.md @@ -1,128 +1,129 @@ ### About -This folder contains files to integrate JerryScript with Zephyr RTOS -(https://zephyrproject.org/). +This folder contains files to run JerryScript on +[STM32F4-Discovery board](https://www.st.com/en/evaluation-tools/stm32f4discovery.html) with +[Zephyr](https://zephyrproject.org/). +The document had been validated on Ubuntu 20.04 operating system. -### How to build +#### 1. Setup the build environment -#### 1. Preface +Clone the necessary projects into a `jerry-zephyr` directory. +The latest tested working version of Zephyr is `v2.7.0`. -1. Directory structure +```sh +mkdir jerry-zephyr && cd jerry-zephyr -Assume `harmony` as the path to the projects to build. -The folder tree related would look like this. +git clone https://github.com/jerryscript-project/jerryscript.git +git clone https://github.com/zephyrproject-rtos/zephyr -b v2.7.0 +# Zephyr requires its toolchain. +wget https://github.com/zephyrproject-rtos/sdk-ng/releases/download/v0.13.2/zephyr-toolchain-arm-0.13.2-linux-x86_64-setup.run ``` -harmony + +The following directory structure has been created: + +``` +jerry-zephyr + jerryscript | + targets - | + zephyr - + zephyr-project + | + zephyr + + zephyr + + zephyr-toolchain-arm-0.13.2-linux-x86_64-setup.run ``` +#### 2. Install dependencies of the projects -2. Target boards/emulations - -Following Zephyr boards are known to work: qemu_x86, qemu_cortex_m3, -frdm_k64f. But generally, any board supported by Zephyr should work, -as long as it has enough Flash and RAM (boards which don't have -enough of those, will simply have link-time errors of ROM/RAM -overflow). +```sh +# Assuming you are in jerry-zephyr folder. +jerryscript/tools/apt-get-install-deps.sh +# Tool dependencies of Zephyr. +sudo apt install --no-install-recommends \ + git cmake ninja-build gperf ccache dfu-util device-tree-compiler \ + python3-dev python3-pip python3-setuptools python3-tk python3-wheel \ + xz-utils file make gcc gcc-multilib g++-multilib libsdl2-dev -#### 2. Prepare Zephyr +# Install Python dependencies of Zephyr. +pip3 install --user -r zephyr/scripts/requirements.txt -Follow [this](https://www.zephyrproject.org/doc/getting_started/getting_started.html) page to get -the Zephyr source and configure the environment. +# Install Zephyr toolchain. +chmod +x zephyr-toolchain-arm-0.13.2-linux-x86_64-setup.run +./zephyr-toolchain-arm-0.13.2-linux-x86_64-setup.run -- -y -d ${PWD}/zephyr-toolchain-0.13.2 +``` -If you just start with Zephyr, you may want to follow "Building a Sample -Application" section in the doc above and check that you can flash your -target board. +Note: CMake 3.20 is required. If the installed CMake is older, upgrade it for example [this way](https://apt.kitware.com/). -Remember to source the Zephyr environment as explained in the zephyr documentation: +#### 3. Initialize west meta-tool for Zephyr ``` -cd zephyr-project -source zephyr-env.sh +# Assuming you are in jerry-zephyr folder. +west init -l zephyr +west update hal_stm32 cmsis +west zephyr-export +``` -export ZEPHYR_GCC_VARIANT=zephyr -export ZEPHYR_SDK_INSTALL_DIR=<sdk installation directory> +#### 4. Build Zephyr (with JerryScript) + +``` +# Assuming you are in jerry-zephyr folder. +west build -p auto -b stm32f4_disco jerryscript/targets/zephyr/ ``` -#### 3. Build JerryScript for Zephyr QEMU +The created binary is a `zephyr.elf` named file located in `jerry-zephyr/build/zephyr/bin/` folder. -The easiest way is to build and run on a QEMU emulator: +#### 5. Flash -For x86 architecture: +Install `udev` rules which allows to flash STM32F4-Discovery as a regular user: ``` -make -f ./targets/zephyr/Makefile.zephyr BOARD=qemu_x86 run +# Assuming you are in jerry-zephyr folder. +sudo cp zephyr-toolchain-0.13.2/sysroots/x86_64-pokysdk-linux/usr/share/openocd/contrib/60-openocd.rules /etc/udev/rules.d +sudo udevadm control --reload ``` -For ARM (Cortex-M) architecture: +Connect Mini-USB for charging and flasing the device. ``` -make -f ./targets/zephyr/Makefile.zephyr BOARD=qemu_cortex_m3 run +# Assuming you are in jerry-zephyr folder. +west flash ``` -#### 4. Build for a real board +#### 6. Connect to the device -Below, we build for NXP FRDM-K64F board (`frdm_k64f` Zephyr board -identifier). Building for other boards is similar. You are expected -to read [Supported Boards](https://docs.zephyrproject.org/latest/boards/index.html) -section in the Zephyr documentation for more information about -Zephyr's support for a particular board, means to flash binaries, -etc. +Use `USB To TTL Serial Converter` for serial communication. STM32F4-Discovery pins are mapped by Zephyr as follows: ``` -# assuming you are in top-level folder -cd jerryscript -make -f ./targets/zephyr/Makefile.zephyr BOARD=frdm_k64f + STM32f4-Discovery PA2 pin is configured for TX. + STM32f4-Discovery PA3 pin is configured for RX. ``` -At the end of the build, you will be given a path to and stats about -the ELF binary: +* Connect `STM32f4-Discovery` **PA2** pin to **RX** pin of `USB To TTL Serial Converter` +* Connect `STM32f4-Discovery` **PA3** pin to **TX** pin of `USB To TTL Serial Converter` +* Connect `STM32f4-Discovery` **GND** pin to **GND** pin of `USB To TTL Serial Converter` -``` -... -Finished - text data bss dec hex filename - 117942 868 24006 142816 22de0 build/frdm_k64f/zephyr/zephyr/zephyr.elf -``` +The device should be visible as `/dev/ttyUSB0`. Use `minicom` communication program with `115200`. -Flashing the binary depends on a particular board used (see links above). -For the FRDM-K64F used as the example, you should copy the *raw* binary -file corresponding to the ELF file above (at -`build/frdm_k64f/zephyr/zephyr/zephyr.bin`) to the USB drive appearing -after connecting the board to a computer: +* In `minicom`, set `Add Carriage Ret` to `off` in by `CTRL-A -> Z -> U` key combinations. +* In `minicom`, set `Hardware Flow Control` to `no` by `CTRL-A -> Z -> O -> Serial port setup -> F` key combinations. +```sh +sudo minicom --device=/dev/ttyUSB0 --baud=115200 ``` -cp build/frdm_k64f/zephyr/zephyr/zephyr.bin /media/pfalcon/DAPLINK/ -``` - -To interact with JerryScript, connect to a board via serial connection -and press Reset button (you first should wait while LEDs on the board -stop blinking). For `frdm_k64f`: -``` -picocom -b115200 /dev/ttyACM0 -``` +Press `RESET` on the board to get the initial message with JerryScript command prompt: -You should see something similar to this: ``` -JerryScript build: Aug 11 2021 16:03:07 +*** Booting Zephyr OS build v2.7.99-1786-ga08b65ef42db *** +JerryScript build: Nov 25 2021 14:17:17 JerryScript API 3.0.0 -Zephyr version 2.6.99 +Zephyr version 2.7.99 js> ``` -Run the example javascript command test function -``` -js> var test=0; for (t=100; t<1000; t++) test+=t; print ('Hi JS World! '+test); -Hi JS World! 494550 -``` +Run the following JavaScript example: -Try a more complex function: ``` -js> function hello(t) {t=t*10;return t}; print("result"+hello(10.5)); +js> var test = 0; for (t = 100; t < 1000; t++) test += t; print ('Hello World! ' + test); +Hello World! 494550 +undefined ``` diff --git a/targets/zephyr/docs/arduino_101.jpg b/targets/zephyr/docs/arduino_101.jpg deleted file mode 100644 index b05683c0233a978313e330f7a27e12d61e2bc95a..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 22138 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ⅅ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 VirnP%Aq+HhMUR8$^H7$5|Jk?76kz}W diff --git a/targets/zephyr/src/Makefile b/targets/zephyr/src/Makefile deleted file mode 100644 index 7801a1cf0b..0000000000 --- a/targets/zephyr/src/Makefile +++ /dev/null @@ -1,22 +0,0 @@ -# Copyright JS Foundation and other contributors, http://js.foundation -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -ifdef V -$(info Compiling application) -endif - -# Adding path for jerry script APIs -ZEPHYRINCLUDE += $(JERRY_INCLUDE) - -obj-y += main-zephyr.o getline-zephyr.o jerry-port.o diff --git a/targets/zephyr/src/jerry-module.c b/targets/zephyr/src/jerry-module.c new file mode 100644 index 0000000000..97f92dcfdb --- /dev/null +++ b/targets/zephyr/src/jerry-module.c @@ -0,0 +1,302 @@ +/* Copyright JS Foundation and other contributors, http://js.foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include <stdio.h> +#include <string.h> +#include <stdlib.h> +#include <unistd.h> + +#include "jerryscript.h" +#include "jerryscript-port.h" + +/** + * Computes the end of the directory part of a path. + * + * @return end of the directory part of a path. + */ +static size_t +jerry_port_get_directory_end (const jerry_char_t *path_p) /**< path */ +{ + const jerry_char_t *end_p = path_p + strlen ((const char *) path_p); + + while (end_p > path_p) + { + if (end_p[-1] == '/') + { + return (size_t) (end_p - path_p); + } + + end_p--; + } + + return 0; +} /* jerry_port_get_directory_end */ + +/** + * Normalize a file path. + * + * @return a newly allocated buffer with the normalized path if the operation is successful, + * NULL otherwise + */ +static jerry_char_t * +jerry_port_normalize_path (const jerry_char_t *in_path_p, /**< path to the referenced module */ + size_t in_path_length, /**< length of the path */ + const jerry_char_t *base_path_p, /**< base path */ + size_t base_path_length) /**< length of the base path */ +{ + char *path_p; + + if (base_path_length > 0) + { + path_p = (char *) malloc (base_path_length + in_path_length + 1); + + if (path_p == NULL) + { + return NULL; + } + + memcpy (path_p, base_path_p, base_path_length); + memcpy (path_p + base_path_length, in_path_p, in_path_length); + path_p[base_path_length + in_path_length] = '\0'; + } + else + { + path_p = (char *) malloc (in_path_length + 1); + + if (path_p == NULL) + { + return NULL; + } + + memcpy (path_p, in_path_p, in_path_length); + path_p[in_path_length] = '\0'; + } + + return (jerry_char_t *) path_p; +} /* jerry_port_normalize_path */ + +/** + * A module descriptor. + */ +typedef struct jerry_port_module_t +{ + struct jerry_port_module_t *next_p; /**< next_module */ + jerry_char_t *path_p; /**< path to the module */ + size_t base_path_length; /**< base path length for relative difference */ + jerry_value_t realm; /**< the realm of the module */ + jerry_value_t module; /**< the module itself */ +} jerry_port_module_t; + +/** + * Native info descriptor for modules. + */ +static const jerry_object_native_info_t jerry_port_module_native_info = +{ + .free_cb = NULL, +}; + +/** + * Default module manager. + */ +typedef struct +{ + jerry_port_module_t *module_head_p; /**< first module */ +} jerry_port_module_manager_t; + +/** + * Release known modules. + */ +static void +jerry_port_module_free (jerry_port_module_manager_t *manager_p, /**< module manager */ + const jerry_value_t realm) /**< if this argument is object, release only those modules, + * which realm value is equal to this argument. */ +{ + jerry_port_module_t *module_p = manager_p->module_head_p; + + bool release_all = !jerry_value_is_object (realm); + + jerry_port_module_t *prev_p = NULL; + + while (module_p != NULL) + { + jerry_port_module_t *next_p = module_p->next_p; + + if (release_all || module_p->realm == realm) + { + free (module_p->path_p); + jerry_release_value (module_p->realm); + jerry_release_value (module_p->module); + + free (module_p); + + if (prev_p == NULL) + { + manager_p->module_head_p = next_p; + } + else + { + prev_p->next_p = next_p; + } + } + else + { + prev_p = module_p; + } + + module_p = next_p; + } +} /* jerry_port_module_free */ + +/** + * Initialize the default module manager. + */ +static void +jerry_port_module_manager_init (void *user_data_p) +{ + ((jerry_port_module_manager_t *) user_data_p)->module_head_p = NULL; +} /* jerry_port_module_manager_init */ + +/** + * Deinitialize the default module manager. + */ +static void +jerry_port_module_manager_deinit (void *user_data_p) /**< context pointer to deinitialize */ +{ + jerry_value_t undef = jerry_create_undefined (); + jerry_port_module_free ((jerry_port_module_manager_t *) user_data_p, undef); + jerry_release_value (undef); +} /* jerry_port_module_manager_deinit */ + +/** + * Declare the context data manager for modules. + */ +static const jerry_context_data_manager_t jerry_port_module_manager = +{ + .init_cb = jerry_port_module_manager_init, + .deinit_cb = jerry_port_module_manager_deinit, + .bytes_needed = sizeof (jerry_port_module_manager_t) +}; + +/** + * Default module resolver. + * + * @return a module object if resolving is successful, an error otherwise + */ +jerry_value_t +jerry_port_module_resolve (const jerry_value_t specifier, /**< module specifier string */ + const jerry_value_t referrer, /**< parent module */ + void *user_p) /**< user data */ +{ + (void) user_p; + + jerry_port_module_t *module_p; + const jerry_char_t *base_path_p = NULL; + size_t base_path_length = 0; + + if (jerry_get_object_native_pointer (referrer, (void **) &module_p, &jerry_port_module_native_info)) + { + base_path_p = module_p->path_p; + base_path_length = module_p->base_path_length; + } + + jerry_size_t in_path_length = jerry_get_utf8_string_size (specifier); + jerry_char_t *in_path_p = (jerry_char_t *) malloc (in_path_length + 1); + jerry_string_to_utf8_char_buffer (specifier, in_path_p, in_path_length); + in_path_p[in_path_length] = '\0'; + + jerry_char_t *path_p = jerry_port_normalize_path (in_path_p, in_path_length, base_path_p, base_path_length); + + if (path_p == NULL) + { + return jerry_create_error (JERRY_ERROR_COMMON, (const jerry_char_t *) "Out of memory"); + } + + jerry_value_t realm = jerry_get_global_object (); + + jerry_port_module_manager_t *manager_p; + manager_p = (jerry_port_module_manager_t *) jerry_get_context_data (&jerry_port_module_manager); + + module_p = manager_p->module_head_p; + + while (module_p != NULL) + { + if (module_p->realm == realm + && strcmp ((const char *) module_p->path_p, (const char *) path_p) == 0) + { + free (path_p); + free (in_path_p); + jerry_release_value (realm); + return jerry_acquire_value (module_p->module); + } + + module_p = module_p->next_p; + } + + size_t source_size; + uint8_t *source_p = jerry_port_read_source ((const char *) path_p, &source_size); + + if (source_p == NULL) + { + free (path_p); + free (in_path_p); + jerry_release_value (realm); + /* TODO: This is incorrect, but makes test262 module tests pass + * (they should throw SyntaxError, but not because the module cannot be found). */ + return jerry_create_error (JERRY_ERROR_SYNTAX, (const jerry_char_t *) "Module file not found"); + } + + jerry_parse_options_t parse_options; + parse_options.options = JERRY_PARSE_MODULE | JERRY_PARSE_HAS_RESOURCE; + parse_options.resource_name = jerry_create_string_sz ((const jerry_char_t *) in_path_p, in_path_length); + + jerry_value_t ret_value = jerry_parse (source_p, + source_size, + &parse_options); + + jerry_release_value (parse_options.resource_name); + jerry_port_release_source (source_p); + free (in_path_p); + + if (jerry_value_is_error (ret_value)) + { + free (path_p); + jerry_release_value (realm); + return ret_value; + } + + module_p = (jerry_port_module_t *) malloc (sizeof (jerry_port_module_t)); + + module_p->next_p = manager_p->module_head_p; + module_p->path_p = path_p; + module_p->base_path_length = jerry_port_get_directory_end (module_p->path_p); + module_p->realm = realm; + module_p->module = jerry_acquire_value (ret_value); + + jerry_set_object_native_pointer (ret_value, module_p, &jerry_port_module_native_info); + manager_p->module_head_p = module_p; + + return ret_value; +} /* jerry_port_module_resolve */ + +/** + * Release known modules. + */ +void +jerry_port_module_release (const jerry_value_t realm) /**< if this argument is object, release only those modules, + * which realm value is equal to this argument. */ +{ + jerry_port_module_free ((jerry_port_module_manager_t *) jerry_get_context_data (&jerry_port_module_manager), + realm); +} /* jerry_port_module_release */ diff --git a/targets/zephyr/src/jerry-port.c b/targets/zephyr/src/jerry-port.c index 016510696d..5677821834 100644 --- a/targets/zephyr/src/jerry-port.c +++ b/targets/zephyr/src/jerry-port.c @@ -13,12 +13,32 @@ * limitations under the License. */ -#include <stdarg.h> - #include <zephyr.h> +#include <stdarg.h> +#include <stdlib.h> #include "jerryscript-port.h" +/** + * JerryScript log level + */ +static jerry_log_level_t jerry_log_level = JERRY_LOG_LEVEL_ERROR; + +/** + * Sets log level. + */ +void set_log_level (jerry_log_level_t level) +{ + jerry_log_level = level; +} /* set_log_level */ + +/** + * Aborts the program. + */ +void jerry_port_fatal (jerry_fatal_code_t code) +{ + exit (1); +} /* jerry_port_fatal */ /** * Provide log message implementation for the engine. @@ -28,35 +48,81 @@ jerry_port_log (jerry_log_level_t level, /**< log level */ const char *format, /**< format string */ ...) /**< parameters */ { - (void) level; /* ignore log level */ - - va_list args; - va_start (args, format); - vfprintf (stderr, format, args); - va_end (args); + if (level <= jerry_log_level) + { + va_list args; + va_start (args, format); + vfprintf (stderr, format, args); + va_end (args); + } } /* jerry_port_log */ +/** + * Determines the size of the given file. + * @return size of the file + */ +static size_t +jerry_port_get_file_size (FILE *file_p) /**< opened file */ +{ + fseek (file_p, 0, SEEK_END); + long size = ftell (file_p); + fseek (file_p, 0, SEEK_SET); + + return (size_t) size; +} /* jerry_port_get_file_size */ /** - * Provide fatal message implementation for the engine. + * Opens file with the given path and reads its source. + * @return the source of the file */ -void jerry_port_fatal (jerry_fatal_code_t code) +uint8_t * +jerry_port_read_source (const char *file_name_p, /**< file name */ + size_t *out_size_p) /**< [out] read bytes */ { - jerry_port_log (JERRY_LOG_LEVEL_ERROR, "Jerry Fatal Error!\n"); - while (true); -} /* jerry_port_fatal */ + FILE *file_p = fopen (file_name_p, "rb"); + + if (file_p == NULL) + { + jerry_port_log (JERRY_LOG_LEVEL_ERROR, "Error: failed to open file: %s\n", file_name_p); + return NULL; + } + + size_t file_size = jerry_port_get_file_size (file_p); + uint8_t *buffer_p = (uint8_t *) malloc (file_size); + + if (buffer_p == NULL) + { + fclose (file_p); + + jerry_port_log (JERRY_LOG_LEVEL_ERROR, "Error: failed to allocate memory for module"); + return NULL; + } + + size_t bytes_read = fread (buffer_p, 1u, file_size, file_p); + + if (!bytes_read) + { + fclose (file_p); + free (buffer_p); + + jerry_port_log (JERRY_LOG_LEVEL_ERROR, "Error: failed to read file: %s\n", file_name_p); + return NULL; + } + + fclose (file_p); + *out_size_p = bytes_read; + + return buffer_p; +} /* jerry_port_read_source */ /** - * Implementation of jerry_port_get_current_time. - * - * @return current timer's counter value in milliseconds + * Release the previously opened file's content. */ -double -jerry_port_get_current_time (void) +void +jerry_port_release_source (uint8_t *buffer_p) /**< buffer to free */ { - int64_t ms = k_uptime_get(); - return (double) ms; -} /* jerry_port_get_current_time */ + free (buffer_p); +} /* jerry_port_release_source */ /** * Dummy function to get the time zone adjustment. @@ -70,6 +136,18 @@ jerry_port_get_local_time_zone_adjustment (double unix_ms, bool is_utc) return 0; } /* jerry_port_get_local_time_zone_adjustment */ +/** + * Dummy function to get the current time. + * + * @return 0 + */ +double +jerry_port_get_current_time (void) +{ + int64_t ms = k_uptime_get(); + return (double) ms; +} /* jerry_port_get_current_time */ + /** * Provide the implementation of jerry_port_print_char. * Uses 'printf' to print a single character to standard output. @@ -79,3 +157,36 @@ jerry_port_print_char (char c) /**< the character to print */ { printf ("%c", c); } /* jerry_port_print_char */ + +/** + * Provide implementation of jerry_port_sleep. + */ +void jerry_port_sleep (uint32_t sleep_time) /**< milliseconds to sleep */ +{ + k_usleep ((useconds_t) sleep_time * 1000); +} /* jerry_port_sleep */ + +/** + * Pointer to the current context. + */ +static jerry_context_t *current_context_p = NULL; + +/** + * Set the current_context_p as the passed pointer. + */ +void +jerry_port_default_set_current_context (jerry_context_t *context_p) /**< points to the created context */ +{ + current_context_p = context_p; +} /* jerry_port_default_set_current_context */ + +/** + * Get the current context. + * + * @return the pointer to the current context + */ +jerry_context_t * +jerry_port_get_current_context (void) +{ + return current_context_p; +} /* jerry_port_get_current_context */