├── apps ├── assemblyscript │ ├── .gitignore │ ├── app.wasm │ ├── tsconfig.json │ ├── package.json │ ├── build.sh │ ├── app.ts │ ├── wiring.ts │ └── package-lock.json ├── rust │ ├── .gitignore │ ├── app.wasm │ ├── .cargo │ │ └── config.toml │ ├── build.sh │ ├── Cargo.toml │ └── src │ │ ├── app.rs │ │ └── wiring.rs ├── zig │ ├── .gitignore │ ├── app.wasm │ ├── build.sh │ ├── main.zig │ └── wiring.zig ├── wat │ ├── build.sh │ ├── app.wasm │ └── main.wat ├── cpp │ ├── app.wasm │ ├── runtime.c │ ├── build.sh │ ├── app.cpp │ ├── wiring.h │ └── FixedBufferStream.h ├── tinygo │ ├── app.wasm │ ├── build.sh │ ├── app.go │ ├── wiring │ │ └── wiring.go │ └── target.json ├── virgil │ ├── app.wasm │ ├── build.sh │ └── app.v3 └── coremark │ ├── app.wasm │ ├── build.sh │ ├── cvt.c │ ├── coremark.h │ ├── core_util.c │ ├── core_portme.h │ ├── core_portme.c │ ├── core_state.c │ ├── core_matrix.c │ ├── core_main.c │ ├── LICENSE.md │ ├── core_list_join.c │ └── README.md ├── .gitignore ├── docs └── how-it-works.png ├── LICENSE ├── Makefile ├── src ├── wasm-rt-exceptions.h ├── wasm-rt-exceptions-impl.c ├── wasm-rt-impl.h ├── main.cpp ├── wasm-rt-impl-tableops.inc ├── wasm-rt-mem-impl.c ├── wasm-rt-mem-impl-helper.inc ├── wasm-rt-impl.c └── wasm-rt.h ├── platformio.ini └── README.md /apps/assemblyscript/.gitignore: -------------------------------------------------------------------------------- 1 | node_modules/ 2 | -------------------------------------------------------------------------------- /apps/rust/.gitignore: -------------------------------------------------------------------------------- 1 | target/ 2 | Cargo.lock 3 | -------------------------------------------------------------------------------- /apps/zig/.gitignore: -------------------------------------------------------------------------------- 1 | zig-cache/ 2 | *.wasm.o 3 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .pio/ 2 | *.bin 3 | apps/**/app.wat 4 | src/wasm-app* 5 | -------------------------------------------------------------------------------- /apps/wat/build.sh: -------------------------------------------------------------------------------- 1 | set -e 2 | 3 | # Convert WAT to WASM 4 | wat2wasm main.wat -o app.wasm 5 | -------------------------------------------------------------------------------- /apps/cpp/app.wasm: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wasm3/embedded-wasm-apps/HEAD/apps/cpp/app.wasm -------------------------------------------------------------------------------- /apps/rust/app.wasm: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wasm3/embedded-wasm-apps/HEAD/apps/rust/app.wasm -------------------------------------------------------------------------------- /apps/wat/app.wasm: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wasm3/embedded-wasm-apps/HEAD/apps/wat/app.wasm -------------------------------------------------------------------------------- /apps/zig/app.wasm: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wasm3/embedded-wasm-apps/HEAD/apps/zig/app.wasm -------------------------------------------------------------------------------- /apps/tinygo/app.wasm: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wasm3/embedded-wasm-apps/HEAD/apps/tinygo/app.wasm -------------------------------------------------------------------------------- /apps/virgil/app.wasm: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wasm3/embedded-wasm-apps/HEAD/apps/virgil/app.wasm -------------------------------------------------------------------------------- /docs/how-it-works.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wasm3/embedded-wasm-apps/HEAD/docs/how-it-works.png -------------------------------------------------------------------------------- /apps/coremark/app.wasm: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wasm3/embedded-wasm-apps/HEAD/apps/coremark/app.wasm -------------------------------------------------------------------------------- /apps/assemblyscript/app.wasm: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wasm3/embedded-wasm-apps/HEAD/apps/assemblyscript/app.wasm -------------------------------------------------------------------------------- /apps/assemblyscript/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./node_modules/assemblyscript/std/assembly.json", 3 | "include": [ 4 | "./**/*.ts" 5 | ] 6 | } -------------------------------------------------------------------------------- /apps/rust/.cargo/config.toml: -------------------------------------------------------------------------------- 1 | [build] 2 | target = "wasm32-unknown-unknown" 3 | rustflags = [ 4 | "-C", "target-feature=+bulk-memory,+mutable-globals,+sign-ext,+nontrapping-fptoint", 5 | "-C", "link-args=-zstack-size=2048" 6 | ] 7 | 8 | -------------------------------------------------------------------------------- /apps/rust/build.sh: -------------------------------------------------------------------------------- 1 | set -e 2 | 3 | # Compile 4 | cargo build --release 5 | cp ./target/wasm32-unknown-unknown/release/app.wasm ./ 6 | 7 | # Optimize (optional) 8 | wasm-opt -O3 app.wasm -o app.wasm 9 | wasm-strip app.wasm 10 | 11 | # Convert to WAT 12 | wasm2wat --generate-names app.wasm -o app.wat 13 | -------------------------------------------------------------------------------- /apps/assemblyscript/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "license": "MIT", 3 | "scripts": { 4 | "build": "npm run asbuild:optimized", 5 | "asbuild:optimized": "npx asc app.ts -o app.wasm -t app.wat -O3z --noAssert --use abort=" 6 | }, 7 | "devDependencies": { 8 | "assemblyscript": "^0.27.29" 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /apps/assemblyscript/build.sh: -------------------------------------------------------------------------------- 1 | set -e 2 | 3 | # Install AssemblyScript toolchain if needed 4 | if [ ! -d node_modules ] ; then 5 | npm i 6 | fi 7 | 8 | # Compile 9 | npm run build 10 | 11 | # Optimize (optional) 12 | wasm-strip app.wasm 13 | 14 | # Convert to WAT 15 | #wasm2wat --generate-names app.wasm -o app.wat 16 | -------------------------------------------------------------------------------- /apps/rust/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "app" 3 | version = "0.1.0" 4 | authors = ["Volodymyr Shymanskyy "] 5 | edition = "2018" 6 | 7 | [lib] 8 | path = "src/app.rs" 9 | crate-type = ["cdylib"] 10 | 11 | [dependencies] 12 | 13 | [profile.dev] 14 | panic = "abort" 15 | 16 | [profile.release] 17 | panic = "abort" 18 | opt-level = "s" 19 | codegen-units = 1 20 | lto = true 21 | #debug = true 22 | -------------------------------------------------------------------------------- /apps/virgil/build.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/bash 2 | 3 | set -e 4 | 5 | # Prepare 6 | export PATH=/opt/virgil/bin:$PATH 7 | 8 | # Compile 9 | v3c -target=wasm app.v3 10 | 11 | # TODO: /opt/virgil/lib/util/{StringBuilder,Chars,Ints,Longs,Arrays,Utf8,Vector,Ranges}.v3 12 | 13 | # Optimize (optional) 14 | wasm-opt -Os app.wasm -o app.wasm 15 | wasm-strip app.wasm 16 | 17 | # Convert to WAT 18 | wasm2wat --generate-names app.wasm -o app.wat 19 | -------------------------------------------------------------------------------- /apps/cpp/runtime.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | __attribute__((weak)) 4 | size_t strlen(const char *str) { 5 | const char *s; 6 | for (s = str; *s; ++s); 7 | return (s - str); 8 | } 9 | 10 | __attribute__((weak)) 11 | void* memcpy(void* dest, const void* src, size_t n) { 12 | unsigned char* d = dest; 13 | const unsigned char* s = src; 14 | while (n--) { 15 | *d++ = *s++; 16 | } 17 | return dest; 18 | } 19 | 20 | -------------------------------------------------------------------------------- /apps/rust/src/app.rs: -------------------------------------------------------------------------------- 1 | 2 | mod wiring; 3 | use wiring::*; 4 | 5 | const LED: u32 = 2; 6 | 7 | #[no_mangle] 8 | pub extern fn setup() { 9 | pinMode(LED, OUTPUT); 10 | println("🦀 Rust is running!"); 11 | } 12 | 13 | #[no_mangle] 14 | pub extern fn r#loop() { 15 | let s = format!("{} Blink", millis()); 16 | println(&s[..]); 17 | 18 | digitalWrite(LED, HIGH); 19 | delay(100); 20 | digitalWrite(LED, LOW); 21 | delay(900); 22 | } 23 | -------------------------------------------------------------------------------- /apps/assemblyscript/app.ts: -------------------------------------------------------------------------------- 1 | import * as dev from "./wiring" 2 | 3 | let LED = 2 4 | 5 | export function setup(): void { 6 | dev.pinMode(LED, dev.OUTPUT) 7 | 8 | dev.println('🚀 AssemblyScript is running!') 9 | } 10 | 11 | export function loop(): void { 12 | const time = dev.millis() 13 | dev.println(time.toString() + ' Blink') 14 | 15 | dev.digitalWrite(LED, dev.HIGH) 16 | dev.delay(100) 17 | dev.digitalWrite(LED, dev.LOW) 18 | dev.delay(900) 19 | } 20 | -------------------------------------------------------------------------------- /apps/zig/build.sh: -------------------------------------------------------------------------------- 1 | set -e 2 | 3 | # Prepare 4 | export PATH=/opt/zig-linux-x86_64-0.13.0:$PATH 5 | 6 | # Compile 7 | zig build-exe main.zig -target wasm32-freestanding -fno-entry -rdynamic \ 8 | --initial-memory=65536 --max-memory=65536 --stack 2048 \ 9 | -OReleaseSmall -fstrip -femit-bin=app.wasm 10 | 11 | # Optimize (optional) 12 | wasm-opt -Os app.wasm -o app.wasm 13 | wasm-strip app.wasm 14 | 15 | # Convert to WAT 16 | wasm2wat --generate-names app.wasm -o app.wat 17 | -------------------------------------------------------------------------------- /apps/tinygo/build.sh: -------------------------------------------------------------------------------- 1 | set -e 2 | 3 | # Prepare 4 | export GOROOT=/opt/go-v1.23.0 5 | export PATH=/opt/tinygo-v0.33.0/bin:$GOROOT/bin:$PATH 6 | export GO111MODULE=off 7 | 8 | # TODO: https://github.com/tinygo-org/tinygo/issues/4223 9 | 10 | # Compile 11 | tinygo build -target ./target.json -o app.wasm app.go 12 | 13 | # Optimize (optional) 14 | wasm-opt -Os app.wasm -o app.wasm 15 | wasm-strip app.wasm 16 | 17 | # Convert to WAT 18 | wasm2wat --generate-names app.wasm -o app.wat 19 | -------------------------------------------------------------------------------- /apps/coremark/build.sh: -------------------------------------------------------------------------------- 1 | set -e 2 | 3 | export PATH=/opt/wasi-sdk/bin:$PATH 4 | 5 | # Compile 6 | clang --target=wasm32 --no-standard-libraries -Wl,--no-entry \ 7 | -Wl,--stack-first -Wl,-z,stack-size=512 \ 8 | -g0 -s -O3 -DFLAGS_STR="-O3" -I./ -o app.wasm \ 9 | core_list_join.c core_main.c core_matrix.c core_state.c core_util.c core_portme.c cvt.c 10 | 11 | # TODO: -mbulk-memory -mnontrapping-fptoint -msign-ext 12 | 13 | # Convert to WAT 14 | wasm2wat --generate-names app.wasm -o app.wat 15 | -------------------------------------------------------------------------------- /apps/tinygo/app.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | . "./wiring" 5 | "strconv" 6 | ) 7 | 8 | var LED uint = 2 9 | 10 | //export setup 11 | func setup() { 12 | PinMode(LED, OUTPUT) 13 | 14 | Println("🤖 TinyGo is running!") 15 | } 16 | 17 | //export loop 18 | func loop() { 19 | t := strconv.FormatUint(uint64(Millis()), 10) 20 | Println(t + " Blink") 21 | 22 | DigitalWrite(LED, HIGH) 23 | Delay(100) 24 | DigitalWrite(LED, LOW) 25 | Delay(900) 26 | } 27 | 28 | func main() {} 29 | -------------------------------------------------------------------------------- /apps/cpp/build.sh: -------------------------------------------------------------------------------- 1 | set -e 2 | 3 | export PATH=/opt/wasi-sdk/bin:$PATH 4 | 5 | # Compile 6 | clang --target=wasm32 -nostdlib -z stack-size=4096 \ 7 | -Wl,--no-entry -Wl,--stack-first -Wl,--strip-all \ 8 | -Wl,--initial-memory=65536 -Wl,--max-memory=65536 \ 9 | -mbulk-memory -mnontrapping-fptoint -msign-ext -mmutable-globals \ 10 | -Os -I. -o app.wasm app.cpp runtime.c 11 | 12 | # Optimize (optional) 13 | #wasm-opt -Os app.wasm -o app.wasm 14 | #wasm-strip app.wasm 15 | 16 | # Convert to WAT 17 | wasm2wat --generate-names app.wasm -o app.wat 18 | -------------------------------------------------------------------------------- /apps/zig/main.zig: -------------------------------------------------------------------------------- 1 | const w = @import("./wiring.zig"); 2 | const std = @import("std"); 3 | 4 | const LED = 2; 5 | 6 | export fn setup() void { 7 | w.println("⚡ Zig is running!"); 8 | w.pinMode(LED, w.PinMode.OUTPUT); 9 | } 10 | 11 | var buf: [128]u8 = undefined; 12 | 13 | export fn loop() void { 14 | const t = w.millis(); 15 | if (std.fmt.bufPrint(&buf, "{} Blink", .{t})) |res| { 16 | w.println(res); 17 | } else |err| { 18 | err catch {}; 19 | } 20 | 21 | w.digitalWrite(LED, w.Digital.LOW); 22 | w.delay(900); 23 | w.digitalWrite(LED, w.Digital.HIGH); 24 | w.delay(100); 25 | } 26 | -------------------------------------------------------------------------------- /apps/tinygo/wiring/wiring.go: -------------------------------------------------------------------------------- 1 | package wiring 2 | 3 | const ( 4 | LOW = 0 5 | HIGH = 1 6 | 7 | INPUT = 0 8 | OUTPUT = 1 9 | INPUT_PULLUP = 2 10 | ) 11 | 12 | //go:wasm-module wiring 13 | //go:export millis 14 | func Millis() uint 15 | 16 | //go:wasm-module wiring 17 | //go:export delay 18 | func Delay(ms uint) 19 | 20 | //go:wasm-module wiring 21 | //go:export pinMode 22 | func PinMode(pin, mode uint) 23 | 24 | //go:wasm-module wiring 25 | //go:export digitalWrite 26 | func DigitalWrite(pin, value uint) 27 | 28 | //go:wasm-module wiring 29 | //go:export print 30 | func Print(s string) 31 | 32 | func Println(s string) { 33 | Print(s) 34 | Print("\n") 35 | } 36 | -------------------------------------------------------------------------------- /apps/assemblyscript/wiring.ts: -------------------------------------------------------------------------------- 1 | export const LOW = 0; 2 | export const HIGH = 1; 3 | 4 | export const INPUT = 0x0; 5 | export const OUTPUT = 0x1; 6 | export const INPUT_PULLUP = 0x2; 7 | 8 | export declare function millis(): u32; 9 | export declare function delay(ms: u32): void; 10 | export declare function pinMode(pin: u32, mode: u32): void; 11 | export declare function digitalWrite(pin: u32, value: u32): void; 12 | 13 | 14 | @external("print") 15 | declare function _print(ptr: usize, len: usize): void; 16 | 17 | export function print(str: string): void { 18 | const buffer = String.UTF8.encode(str); 19 | _print(changetype(buffer), buffer.byteLength); 20 | } 21 | 22 | export function println(str: string): void { 23 | print(str); 24 | print('\n'); 25 | } 26 | -------------------------------------------------------------------------------- /apps/cpp/app.cpp: -------------------------------------------------------------------------------- 1 | 2 | #include 3 | #include 4 | 5 | const int LED_BUILTIN = 2; 6 | 7 | void setup() { 8 | println("🤩 C++ is running!"); 9 | 10 | // initialize digital pin LED_BUILTIN as an output. 11 | pinMode(LED_BUILTIN, OUTPUT); 12 | } 13 | 14 | // the loop function runs over and over again forever 15 | void loop() { 16 | static char buffer[128]; 17 | FixedBufferStream ss(buffer, sizeof(buffer)); 18 | ss << millis() << " Blink" << ss.endl; 19 | print(ss.get_buffer()); 20 | 21 | digitalWrite(LED_BUILTIN, HIGH); // turn the LED on (HIGH is the voltage level) 22 | delay(100); // wait 100ms 23 | digitalWrite(LED_BUILTIN, LOW); // turn the LED off by making the voltage LOW 24 | delay(900); // wait 900ms 25 | } 26 | -------------------------------------------------------------------------------- /apps/zig/wiring.zig: -------------------------------------------------------------------------------- 1 | pub const PinMode = enum(i32) { 2 | INPUT, 3 | OUTPUT, 4 | INPUT_PULLUP 5 | }; 6 | 7 | pub const Digital = enum(i32) { 8 | LOW, 9 | HIGH 10 | }; 11 | 12 | const wiring = struct { 13 | extern "wiring" fn millis() i32; 14 | extern "wiring" fn delay(ms: i32) void; 15 | extern "wiring" fn pinMode(pin: i32, mode: PinMode) void; 16 | extern "wiring" fn digitalWrite(pin: i32, value: Digital) void; 17 | extern "wiring" fn print(buf: *const u8, len: u32) void; 18 | }; 19 | 20 | // Public functions 21 | 22 | pub const millis = wiring.millis; 23 | pub const delay = wiring.delay; 24 | pub const digitalWrite = wiring.digitalWrite; 25 | pub const pinMode = wiring.pinMode; 26 | 27 | pub fn print(str: []const u8) void { 28 | wiring.print(&str[0], str.len); 29 | } 30 | 31 | pub fn println(str: []const u8) void { 32 | print(str); 33 | print("\n"); 34 | } 35 | -------------------------------------------------------------------------------- /apps/tinygo/target.json: -------------------------------------------------------------------------------- 1 | { 2 | "llvm-target": "wasm32-unknown-unknown", 3 | "cpu": "generic", 4 | "features": "+bulk-memory,+mutable-globals,+nontrapping-fptoint,+sign-ext", 5 | "build-tags": ["tinygo.wasm", "wasm_unknown"], 6 | "goos": "linux", 7 | "goarch": "arm", 8 | "linker": "wasm-ld", 9 | "rtlib": "compiler-rt", 10 | "libc": "wasmbuiltins", 11 | "scheduler": "none", 12 | "gc": "leaking", 13 | "default-stack-size": 4096, 14 | "cflags": [ 15 | "-mbulk-memory", 16 | "-mnontrapping-fptoint", 17 | "-msign-ext" 18 | ], 19 | "ldflags": [ 20 | "--initial-memory=65536", 21 | "--max-memory=65536", 22 | "-zstack-size=4096", 23 | "--stack-first", 24 | "--no-demangle", 25 | "--entry=_initialize" 26 | ], 27 | "extra-files": [ 28 | "src/runtime/asm_tinygowasm.S" 29 | ] 30 | } 31 | -------------------------------------------------------------------------------- /apps/wat/main.wat: -------------------------------------------------------------------------------- 1 | (module 2 | (type $t0 (func (param i32 i32))) 3 | (type $t1 (func)) 4 | (type $t2 (func (param i32))) 5 | 6 | ;; Wiring imports 7 | (import "wiring" "print" (func $print (type $t0))) 8 | (import "wiring" "pinMode" (func $pinMode (type $t0))) 9 | (import "wiring" "digitalWrite" (func $digitalWrite (type $t0))) 10 | (import "wiring" "delay" (func $delay (type $t2))) 11 | 12 | ;; Memory 13 | (memory (export "memory") 1) 14 | (data (i32.const 16) "\e2\9a\99\ef\b8\8f WAT is running!\0a") 15 | (data (i32.const 48) "Blink\0a") 16 | 17 | ;; Functions 18 | (func (export "setup") (type $t1) 19 | (call $print (i32.const 16) (i32.const 23)) ;; Welcome message 20 | 21 | (call $pinMode (i32.const 2) (i32.const 1)) 22 | ) 23 | (func (export "loop") (type $t1) 24 | (call $print (i32.const 48) (i32.const 6)) ;; Blink 25 | 26 | (call $digitalWrite (i32.const 2) (i32.const 1)) 27 | (call $delay (i32.const 100)) 28 | (call $digitalWrite (i32.const 2) (i32.const 0)) 29 | (call $delay (i32.const 900)) 30 | ) 31 | ) 32 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2021 Volodymyr Shymanskyy 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | 2 | .PHONY: all clean 3 | 4 | APP ?= assemblyscript 5 | 6 | all: 7 | -@rm apps/$(APP)/app.wasm 8 | cd apps/$(APP) && ./build.sh 9 | -@rm ./src/wasm-app* 10 | wasm2c --no-debug-names --module-name="app" --num-outputs=8 apps/$(APP)/app.wasm -o src/wasm-app.c 11 | 12 | clean: 13 | -@rm ./src/wasm-app* 14 | -@rm -rf ./build ./.pio 15 | -@rm *_firmware_*.bin 16 | 17 | 18 | ### Particle helpers 19 | 20 | DEVICE ?= "Photon" 21 | DEV_TYPE ?= photon 22 | 23 | particle_compile: all 24 | @particle compile $(DEV_TYPE) ./src/* 25 | 26 | particle_erase: 27 | @particle usb dfu 28 | @particle flash --usb tinker 29 | 30 | particle_upload: all 31 | @particle flash $(DEVICE) ./src/* 32 | 33 | particle_upload_usb: particle_compile 34 | @particle usb dfu 35 | @particle flash --usb *_firmware_*.bin 36 | -@rm *_firmware_*.bin 37 | 38 | particle_monitor: 39 | @particle serial monitor --follow 40 | 41 | particle_run: particle_upload particle_monitor 42 | 43 | 44 | ### PlatformIO helpers 45 | 46 | ENV ?= esp32 47 | 48 | pio_compile: all 49 | @pio run -e $(ENV) 50 | 51 | pio_upload: all 52 | @pio run -e $(ENV) -t upload 53 | 54 | pio_monitor: 55 | @pio device monitor --quiet 56 | 57 | pio_run: pio_upload pio_monitor 58 | 59 | -------------------------------------------------------------------------------- /apps/virgil/app.v3: -------------------------------------------------------------------------------- 1 | 2 | import component wiring { 3 | def millis() -> int; 4 | def delay(t: int); 5 | def pinMode(pin: int, mode: int); 6 | def digitalWrite(pin: int, value: int); 7 | def print(data: Pointer, len: int); 8 | } 9 | 10 | def HIGH = 1; 11 | def LOW = 0; 12 | def INPUT = 0x0; 13 | def OUTPUT = 0x1; 14 | def INPUT_PULLUP = 0x2; 15 | 16 | def print(s: string) { 17 | wiring.print(Pointer.atContents(s), s.length); 18 | } 19 | def println(s: string) { 20 | print(s); 21 | print("\n"); 22 | } 23 | 24 | 25 | var LED_BUILTIN = 2; 26 | 27 | export def setup() { 28 | println("\xE2\x9C\xA8 Virgil is running"); 29 | 30 | wiring.pinMode(LED_BUILTIN, OUTPUT); 31 | } 32 | 33 | export def loop() { 34 | // TODO 35 | //var sb = StringBuilder.new().put1("%d Blink\n", wiring.millis()); 36 | //println(sb.toString()); 37 | 38 | println("Blink"); 39 | 40 | wiring.digitalWrite(LED_BUILTIN, HIGH); // turn the LED on (HIGH is the voltage level) 41 | wiring.delay(100); // wait 100ms 42 | wiring.digitalWrite(LED_BUILTIN, LOW); // turn the LED off by making the voltage LOW 43 | wiring.delay(900); // wait 900ms 44 | } 45 | 46 | def main() { 47 | } 48 | -------------------------------------------------------------------------------- /apps/rust/src/wiring.rs: -------------------------------------------------------------------------------- 1 | #![allow(dead_code)] 2 | #![allow(non_snake_case)] 3 | 4 | #[link(wasm_import_module = "wiring")] 5 | extern { 6 | #[link_name = "millis"] fn _millis() -> u32; 7 | #[link_name = "delay"] fn _delay(ms: u32); 8 | #[link_name = "pinMode"] fn _pinMode(pin: u32, mode: u32); 9 | #[link_name = "digitalWrite"] fn _digitalWrite(pin: u32, value: u32); 10 | #[link_name = "getPinLED"] fn _getPinLED() -> u32; 11 | #[link_name = "print"] fn _print(utf8: *const u8, len: usize); 12 | } 13 | 14 | pub static LOW: u32 = 0; 15 | pub static HIGH: u32 = 1; 16 | 17 | pub static INPUT: u32 = 0x0; 18 | pub static OUTPUT: u32 = 0x1; 19 | pub static INPUT_PULLUP: u32 = 0x2; 20 | 21 | pub fn millis () -> u32 { unsafe { _millis() } } 22 | pub fn delay (ms: u32) { unsafe { _delay(ms); } } 23 | pub fn pinMode (pin: u32, mode: u32) { unsafe { _pinMode(pin, mode) } } 24 | pub fn digitalWrite (pin: u32, value: u32) { unsafe { _digitalWrite(pin, value) } } 25 | pub fn getPinLED () -> u32 { unsafe { _getPinLED() } } 26 | 27 | pub fn print(string: &str) { 28 | unsafe { _print(string.as_ptr(), string.len()) } 29 | } 30 | 31 | pub fn println(string: &str) { 32 | print(string); 33 | print("\n"); 34 | } 35 | -------------------------------------------------------------------------------- /apps/cpp/wiring.h: -------------------------------------------------------------------------------- 1 | #ifndef wiring_wasm_api_h 2 | #define wiring_wasm_api_h 3 | 4 | #include 5 | #include 6 | 7 | #ifdef __cplusplus 8 | #define WASM_EXTERN_C extern "C" 9 | #else 10 | #define WASM_EXTERN_C 11 | #endif 12 | 13 | #define WASM_EXPORT WASM_EXTERN_C __attribute__((used)) __attribute__((visibility ("default"))) 14 | #define WASM_EXPORT_AS(NAME) WASM_EXPORT __attribute__((export_name(NAME))) 15 | #define WASM_IMPORT(MODULE,NAME) __attribute__((import_module(MODULE))) __attribute__((import_name(NAME))) 16 | #define WASM_CONSTRUCTOR __attribute__((constructor)) 17 | 18 | #define LOW 0x0 19 | #define HIGH 0x1 20 | 21 | #define INPUT 0x0 22 | #define OUTPUT 0x1 23 | #define INPUT_PULLUP 0x2 24 | 25 | #ifdef __cplusplus 26 | extern "C" { 27 | #endif 28 | 29 | WASM_IMPORT("wiring","millis") uint32_t millis (void); 30 | WASM_IMPORT("wiring","delay") void delay (uint32_t ms); 31 | WASM_IMPORT("wiring","pinMode") void pinMode (uint32_t pin, uint32_t mode); 32 | WASM_IMPORT("wiring","digitalWrite") void digitalWrite (uint32_t pin, uint32_t value); 33 | WASM_IMPORT("wiring","print") void _print (const char* s, size_t len); 34 | 35 | WASM_EXPORT_AS("setup") void setup(void); 36 | WASM_EXPORT_AS("loop") void loop(void); 37 | 38 | static inline void print (const char* s) { 39 | _print(s, __builtin_strlen(s)); 40 | } 41 | 42 | static inline void println (const char* s) { 43 | print(s); print("\n"); 44 | } 45 | 46 | #ifdef __cplusplus 47 | } 48 | #endif 49 | 50 | #endif // wiring_wasm_api_h 51 | -------------------------------------------------------------------------------- /apps/assemblyscript/package-lock.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "assemblyscript", 3 | "lockfileVersion": 3, 4 | "requires": true, 5 | "packages": { 6 | "": { 7 | "license": "MIT", 8 | "devDependencies": { 9 | "assemblyscript": "^0.27.29" 10 | } 11 | }, 12 | "node_modules/assemblyscript": { 13 | "version": "0.27.29", 14 | "resolved": "https://registry.npmjs.org/assemblyscript/-/assemblyscript-0.27.29.tgz", 15 | "integrity": "sha512-pH6udb7aE2F0t6cTh+0uCepmucykhMnAmm7k0kkAU3SY7LvpIngEBZWM6p5VCguu4EpmKGwEuZpZbEXzJ/frHQ==", 16 | "dev": true, 17 | "dependencies": { 18 | "binaryen": "116.0.0-nightly.20240114", 19 | "long": "^5.2.1" 20 | }, 21 | "bin": { 22 | "asc": "bin/asc.js", 23 | "asinit": "bin/asinit.js" 24 | }, 25 | "engines": { 26 | "node": ">=16", 27 | "npm": ">=7" 28 | }, 29 | "funding": { 30 | "type": "opencollective", 31 | "url": "https://opencollective.com/assemblyscript" 32 | } 33 | }, 34 | "node_modules/binaryen": { 35 | "version": "116.0.0-nightly.20240114", 36 | "resolved": "https://registry.npmjs.org/binaryen/-/binaryen-116.0.0-nightly.20240114.tgz", 37 | "integrity": "sha512-0GZrojJnuhoe+hiwji7QFaL3tBlJoA+KFUN7ouYSDGZLSo9CKM8swQX8n/UcbR0d1VuZKU+nhogNzv423JEu5A==", 38 | "dev": true, 39 | "bin": { 40 | "wasm-opt": "bin/wasm-opt", 41 | "wasm2js": "bin/wasm2js" 42 | } 43 | }, 44 | "node_modules/long": { 45 | "version": "5.2.3", 46 | "resolved": "https://registry.npmjs.org/long/-/long-5.2.3.tgz", 47 | "integrity": "sha512-lcHwpNoggQTObv5apGNCTdJrO69eHOZMi4BNC+rTLER8iHAqGrUVeLh/irVIM7zTw2bOXA8T6uNPeujwOLg/2Q==", 48 | "dev": true 49 | } 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /src/wasm-rt-exceptions.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2018 WebAssembly Community Group participants 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | #ifndef WASM_RT_EXCEPTIONS_H_ 18 | #define WASM_RT_EXCEPTIONS_H_ 19 | 20 | #include "wasm-rt.h" 21 | 22 | #ifdef __cplusplus 23 | extern "C" { 24 | #endif 25 | 26 | /** 27 | * A tag is represented as an arbitrary pointer. 28 | */ 29 | typedef const void* wasm_rt_tag_t; 30 | 31 | /** 32 | * Set the active exception to given tag, size, and contents. 33 | */ 34 | void wasm_rt_load_exception(const wasm_rt_tag_t tag, 35 | uint32_t size, 36 | const void* values); 37 | 38 | /** 39 | * Throw the active exception. 40 | */ 41 | WASM_RT_NO_RETURN void wasm_rt_throw(void); 42 | 43 | /** 44 | * The type of an unwind target if an exception is thrown and caught. 45 | */ 46 | #define WASM_RT_UNWIND_TARGET wasm_rt_jmp_buf 47 | 48 | /** 49 | * Get the current unwind target if an exception is thrown. 50 | */ 51 | WASM_RT_UNWIND_TARGET* wasm_rt_get_unwind_target(void); 52 | 53 | /** 54 | * Set the unwind target if an exception is thrown. 55 | */ 56 | void wasm_rt_set_unwind_target(WASM_RT_UNWIND_TARGET* target); 57 | 58 | /** 59 | * Tag of the active exception. 60 | */ 61 | wasm_rt_tag_t wasm_rt_exception_tag(void); 62 | 63 | /** 64 | * Size of the active exception. 65 | */ 66 | uint32_t wasm_rt_exception_size(void); 67 | 68 | /** 69 | * Contents of the active exception. 70 | */ 71 | void* wasm_rt_exception(void); 72 | 73 | #ifdef __cplusplus 74 | } 75 | #endif 76 | 77 | #endif 78 | -------------------------------------------------------------------------------- /src/wasm-rt-exceptions-impl.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2018 WebAssembly Community Group participants 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | #include "wasm-rt.h" 18 | 19 | #include "wasm-rt-exceptions.h" 20 | 21 | #include 22 | 23 | #define MAX_EXCEPTION_SIZE 256 24 | 25 | static WASM_RT_THREAD_LOCAL wasm_rt_tag_t g_active_exception_tag; 26 | static WASM_RT_THREAD_LOCAL uint8_t g_active_exception[MAX_EXCEPTION_SIZE]; 27 | static WASM_RT_THREAD_LOCAL uint32_t g_active_exception_size; 28 | 29 | static WASM_RT_THREAD_LOCAL wasm_rt_jmp_buf* g_unwind_target; 30 | 31 | void wasm_rt_load_exception(const wasm_rt_tag_t tag, 32 | uint32_t size, 33 | const void* values) { 34 | if (size > MAX_EXCEPTION_SIZE) { 35 | wasm_rt_trap(WASM_RT_TRAP_EXHAUSTION); 36 | } 37 | 38 | g_active_exception_tag = tag; 39 | g_active_exception_size = size; 40 | 41 | if (size) { 42 | memcpy(g_active_exception, values, size); 43 | } 44 | } 45 | 46 | WASM_RT_NO_RETURN void wasm_rt_throw(void) { 47 | WASM_RT_LONGJMP(*g_unwind_target, WASM_RT_TRAP_UNCAUGHT_EXCEPTION); 48 | } 49 | 50 | WASM_RT_UNWIND_TARGET* wasm_rt_get_unwind_target(void) { 51 | return g_unwind_target; 52 | } 53 | 54 | void wasm_rt_set_unwind_target(WASM_RT_UNWIND_TARGET* target) { 55 | g_unwind_target = target; 56 | } 57 | 58 | wasm_rt_tag_t wasm_rt_exception_tag(void) { 59 | return g_active_exception_tag; 60 | } 61 | 62 | uint32_t wasm_rt_exception_size(void) { 63 | return g_active_exception_size; 64 | } 65 | 66 | void* wasm_rt_exception(void) { 67 | return g_active_exception; 68 | } 69 | -------------------------------------------------------------------------------- /src/wasm-rt-impl.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2018 WebAssembly Community Group participants 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | #ifndef WASM_RT_IMPL_H_ 18 | #define WASM_RT_IMPL_H_ 19 | 20 | #include "wasm-rt.h" 21 | 22 | #ifdef _WIN32 23 | #include 24 | #endif 25 | 26 | #ifdef __cplusplus 27 | extern "C" { 28 | #endif 29 | 30 | /** A setjmp buffer used for handling traps. */ 31 | extern WASM_RT_THREAD_LOCAL wasm_rt_jmp_buf g_wasm_rt_jmp_buf; 32 | 33 | #if WASM_RT_STACK_DEPTH_COUNT 34 | /** Saved call stack depth that will be restored in case a trap occurs. */ 35 | extern WASM_RT_THREAD_LOCAL uint32_t wasm_rt_saved_call_stack_depth; 36 | #define WASM_RT_SAVE_STACK_DEPTH() \ 37 | wasm_rt_saved_call_stack_depth = wasm_rt_call_stack_depth 38 | #else 39 | #define WASM_RT_SAVE_STACK_DEPTH() (void)0 40 | #endif 41 | 42 | /** 43 | * Convenience macro to use before calling a wasm function. On first execution 44 | * it will return `WASM_RT_TRAP_NONE` (i.e. 0). If the function traps, it will 45 | * jump back and return the trap that occurred. 46 | * 47 | * ``` 48 | * wasm_rt_trap_t code = wasm_rt_impl_try(); 49 | * if (code != 0) { 50 | * printf("A trap occurred with code: %d\n", code); 51 | * ... 52 | * } 53 | * 54 | * // Call the potentially-trapping function. 55 | * my_wasm_func(); 56 | * ``` 57 | */ 58 | #define wasm_rt_impl_try() \ 59 | (WASM_RT_SAVE_STACK_DEPTH(), wasm_rt_set_unwind_target(&g_wasm_rt_jmp_buf), \ 60 | WASM_RT_SETJMP(g_wasm_rt_jmp_buf)) 61 | 62 | #ifdef __cplusplus 63 | } 64 | #endif 65 | 66 | #endif /* WASM_RT_IMPL_H_ */ 67 | -------------------------------------------------------------------------------- /src/main.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Project: embedded-wasm-apps 3 | * Description: Run sandboxed TinyGo, AssemblyScript, Rust, CPP apps on embedded/IoT devices 4 | * Author: Volodymyr Shymanskyy 5 | * Date: 30.11.2021 6 | */ 7 | 8 | #include "wasm-app.h" 9 | 10 | w2c_app wasm_app; 11 | 12 | #if defined(PARTICLE) 13 | #include "Particle.h" 14 | 15 | SYSTEM_THREAD(ENABLED) 16 | 17 | void w2c_wiring_publish(struct w2c_wiring*, u32 offset) { 18 | Particle.publish((const char*)wasm_app.w2c_memory.data + offset); 19 | } 20 | #elif defined(ARDUINO) 21 | #include "Arduino.h" 22 | #else 23 | #error "Platform not supported" 24 | #endif 25 | 26 | void w2c_wiring_stopWdt(struct w2c_wiring*) { 27 | #if defined(ESP8266) 28 | ESP.wdtDisable(); 29 | *((volatile uint32_t*) 0x60000900) &= ~(1); // Hardware WDT OFF 30 | #elif defined(ESP32) 31 | disableCore0WDT(); 32 | #endif 33 | } 34 | 35 | void w2c_wiring_delay(struct w2c_wiring*, u32 t) { 36 | delay(t); 37 | } 38 | 39 | u32 w2c_wiring_millis(struct w2c_wiring*) { 40 | return millis(); 41 | } 42 | 43 | void w2c_wiring_pinMode(struct w2c_wiring*, u32 pin, u32 mode) { 44 | switch (mode) { 45 | case 0: pinMode(pin, INPUT); break; 46 | case 1: pinMode(pin, OUTPUT); break; 47 | case 2: pinMode(pin, INPUT_PULLUP); break; 48 | } 49 | } 50 | 51 | void w2c_wiring_digitalWrite(struct w2c_wiring*, u32 pin, u32 value) { 52 | digitalWrite(pin, value); 53 | } 54 | 55 | void w2c_wiring_print(struct w2c_wiring*, u32 offset, u32 len) { 56 | Serial.write((const uint8_t*)wasm_app.w2c_memory.data + offset, len); 57 | } 58 | 59 | void os_print_last_error(const char* msg) { 60 | Serial.println(msg); 61 | for(;;) { delay(100); } // Wait forever 62 | } 63 | 64 | __attribute__((weak)) 65 | void w2c_app_0x5Finitialize(w2c_app*) {} 66 | 67 | __attribute__((weak)) 68 | void w2c_app_0x5Fstart(w2c_app*) {} 69 | 70 | void setup() 71 | { 72 | Serial.begin(115200); 73 | #if defined(PARTICLE) 74 | Particle.connect(); 75 | waitUntil(Particle.connected); 76 | #endif 77 | delay(2000); 78 | 79 | Serial.println("Initializing WebAssembly..."); 80 | 81 | wasm_rt_init(); 82 | wasm2c_app_instantiate(&wasm_app, NULL); 83 | 84 | w2c_app_0x5Finitialize(&wasm_app); 85 | w2c_app_0x5Fstart(&wasm_app); 86 | 87 | w2c_app_setup(&wasm_app); 88 | } 89 | 90 | void loop() 91 | { 92 | w2c_app_loop(&wasm_app); 93 | } 94 | 95 | -------------------------------------------------------------------------------- /apps/cpp/FixedBufferStream.h: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | class FixedBufferStream { 4 | private: 5 | char* buffer_; 6 | size_t capacity_; 7 | size_t size_; 8 | 9 | public: 10 | FixedBufferStream(char* buffer, size_t capacity) 11 | : buffer_(buffer), capacity_(capacity), size_(0) { 12 | // Initialize buffer to null characters 13 | if (buffer_ && capacity_ > 0) { 14 | buffer_[0] = '\0'; 15 | } 16 | } 17 | 18 | FixedBufferStream& operator<<(int value) { 19 | // Convert integer to string and append to buffer 20 | char intStr[12]; // Enough to hold -2147483648\0 21 | size_t len = intToString(value, intStr); 22 | append(intStr, len); 23 | return *this; 24 | } 25 | 26 | FixedBufferStream& operator<<(const char* str) { 27 | // Append string to buffer 28 | append(str, __builtin_strlen(str)); 29 | return *this; 30 | } 31 | 32 | FixedBufferStream& operator<<(FixedBufferStream& (*manip)(FixedBufferStream&)) { 33 | // For handling manipulators like std::endl 34 | return manip(*this); 35 | } 36 | 37 | const char* get_buffer() const { 38 | return buffer_; 39 | } 40 | 41 | static FixedBufferStream& endl(FixedBufferStream& stream) { 42 | stream.append("\n", 1); 43 | return stream; 44 | } 45 | 46 | private: 47 | size_t intToString(int value, char* buffer) { 48 | char* p = buffer; 49 | if (value < 0) { 50 | *p++ = '-'; 51 | value = -value; 52 | } 53 | char* start = p; 54 | do { 55 | *p++ = '0' + (value % 10); 56 | value /= 10; 57 | } while (value > 0); 58 | *p = '\0'; 59 | reverse(start, p - 1); 60 | return p - buffer; 61 | } 62 | 63 | void reverse(char* start, char* end) { 64 | while (start < end) { 65 | char temp = *start; 66 | *start++ = *end; 67 | *end-- = temp; 68 | } 69 | } 70 | 71 | void append(const char* str, size_t len) { 72 | if (size_ + len >= capacity_) { 73 | len = capacity_ - size_ - 1; // Reserve space for null terminator 74 | } 75 | if (len > 0) { 76 | __builtin_memcpy(buffer_ + size_, str, len); 77 | size_ += len; 78 | buffer_[size_] = '\0'; // Ensure null termination 79 | } 80 | } 81 | }; 82 | 83 | -------------------------------------------------------------------------------- /platformio.ini: -------------------------------------------------------------------------------- 1 | ; PlatformIO Project Configuration File 2 | ; 3 | ; Build options: build flags, source filter 4 | ; Upload options: custom upload port, speed and extra flags 5 | ; Library options: dependencies, extra library storages 6 | ; Advanced options: extra scripting 7 | ; 8 | ; Please visit documentation for the other options and examples 9 | ; https://docs.platformio.org/page/projectconf.html 10 | 11 | [platformio] 12 | #default_envs = esp32, esp8266 13 | 14 | [env] 15 | framework = arduino 16 | build_src_flags = -O3 -Wno-unused-function -Wno-unused-value 17 | monitor_speed = 115200 18 | 19 | [esp32] 20 | platform = espressif32@6.8.1 21 | upload_speed = 921600 22 | 23 | #monitor_filters = esp32_exception_decoder 24 | #build_type = debug 25 | 26 | build_flags = 27 | -DARDUINO_LOOP_STACK_SIZE=8192 28 | -DCORE_DEBUG_LEVEL=0 29 | 30 | [env:esp32] 31 | extends = esp32 32 | board = esp32dev 33 | 34 | [env:esp32-c3] 35 | extends = esp32 36 | board = esp32-c3-devkitm-1 37 | 38 | build_flags = 39 | ${esp32.build_flags} 40 | -DARDUINO_USB_MODE=1 41 | -DARDUINO_USB_CDC_ON_BOOT=1 42 | 43 | [env:esp32-s2] 44 | extends = esp32 45 | board = esp32-s2-kaluga-1 46 | 47 | [env:esp32-s3] 48 | extends = esp32 49 | board = esp32-s3-devkitc-1 50 | 51 | build_flags = 52 | ${esp32.build_flags} 53 | -DARDUINO_USB_MODE=1 54 | -DARDUINO_USB_CDC_ON_BOOT=1 55 | 56 | [env:esp8266] 57 | platform = espressif8266@4.2.1 58 | board = esp12e 59 | upload_speed = 460800 60 | #board_build.f_cpu = 160000000L 61 | #build_type = debug 62 | #monitor_filters = esp8266_exception_decoder 63 | 64 | build_flags = 65 | -Wl,-Teagle.flash.4m1m.ld 66 | -D PIO_FRAMEWORK_ARDUINO_LWIP2_HIGHER_BANDWIDTH 67 | 68 | [env:rpi-pico] 69 | platform = raspberrypi 70 | board = pico 71 | 72 | [env:rpi-pico-w] 73 | platform = https://github.com/maxgerhardt/platform-raspberrypi.git 74 | board = rpipicow 75 | board_build.core = earlephilhower 76 | 77 | [env:maix-one] 78 | platform = kendryte210 79 | board = sipeed-maix-one-dock 80 | 81 | [env:mkrwifi1010] 82 | platform = atmelsam 83 | board = mkrwifi1010 84 | 85 | [env:arduino101] 86 | platform = intel_arc32 87 | board = genuino101 88 | 89 | [env:mega1284] 90 | platform = atmelavr 91 | board = wildfirev3 92 | 93 | [env:az3166] 94 | platform = ststm32 95 | board = mxchip_az3166 96 | 97 | [env:tinyble] 98 | platform = nordicnrf51 99 | board = seeedTinyBLE 100 | 101 | [env:blenano2] 102 | platform = nordicnrf52 103 | board = redbear_blenano2 104 | 105 | [env:teensy40] 106 | platform = teensy 107 | board = teensy40 108 | upload_protocol = teensy-cli 109 | 110 | -------------------------------------------------------------------------------- /src/wasm-rt-impl-tableops.inc: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2018 WebAssembly Community Group participants 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | // This file is used as a template to generate code for table operations for 18 | // funcref or externref. For this, the file must be included after defining 19 | // either WASM_RT_TABLE_OPS_FUNCREF or WASM_RT_TABLE_OPS_EXTERNREF 20 | 21 | #if defined(WASM_RT_TABLE_OPS_FUNCREF) && defined(WASM_RT_TABLE_OPS_EXTERNREF) 22 | #error \ 23 | "Expected only one of { WASM_RT_TABLE_OPS_FUNCREF, WASM_RT_TABLE_OPS_EXTERNREF } to be defined" 24 | #elif !defined(WASM_RT_TABLE_OPS_FUNCREF) && \ 25 | !defined(WASM_RT_TABLE_OPS_EXTERNREF) 26 | #error \ 27 | "Expected one of { WASM_RT_TABLE_OPS_FUNCREF, WASM_RT_TABLE_OPS_EXTERNREF } to be defined" 28 | #endif 29 | 30 | #ifdef WASM_RT_TABLE_OPS_FUNCREF 31 | #define WASM_RT_TABLE_TYPE wasm_rt_funcref_table_t 32 | #define WASM_RT_TABLE_ELEMENT_TYPE wasm_rt_funcref_t 33 | #define WASM_RT_TABLE_APINAME(name) name##_funcref_table 34 | #else 35 | #define WASM_RT_TABLE_TYPE wasm_rt_externref_table_t 36 | #define WASM_RT_TABLE_ELEMENT_TYPE wasm_rt_externref_t 37 | #define WASM_RT_TABLE_APINAME(name) name##_externref_table 38 | #endif 39 | 40 | void WASM_RT_TABLE_APINAME(wasm_rt_allocate)(WASM_RT_TABLE_TYPE* table, 41 | uint32_t elements, 42 | uint32_t max_elements) { 43 | table->size = elements; 44 | table->max_size = max_elements; 45 | table->data = calloc(table->size, sizeof(WASM_RT_TABLE_ELEMENT_TYPE)); 46 | } 47 | 48 | void WASM_RT_TABLE_APINAME(wasm_rt_free)(WASM_RT_TABLE_TYPE* table) { 49 | free(table->data); 50 | } 51 | 52 | uint32_t WASM_RT_TABLE_APINAME(wasm_rt_grow)(WASM_RT_TABLE_TYPE* table, 53 | uint32_t delta, 54 | WASM_RT_TABLE_ELEMENT_TYPE init) { 55 | uint32_t old_elems = table->size; 56 | uint64_t new_elems = (uint64_t)table->size + delta; 57 | if (new_elems == 0) { 58 | return 0; 59 | } 60 | if ((new_elems < old_elems) || (new_elems > table->max_size)) { 61 | return (uint32_t)-1; 62 | } 63 | void* new_data = 64 | realloc(table->data, new_elems * sizeof(WASM_RT_TABLE_ELEMENT_TYPE)); 65 | if (!new_data) { 66 | return (uint32_t)-1; 67 | } 68 | table->data = new_data; 69 | table->size = new_elems; 70 | for (uint32_t i = old_elems; i < new_elems; i++) { 71 | table->data[i] = init; 72 | } 73 | return old_elems; 74 | } 75 | 76 | #undef WASM_RT_TABLE_APINAME 77 | #undef WASM_RT_TABLE_ELEMENT_TYPE 78 | #undef WASM_RT_TABLE_TYPE 79 | -------------------------------------------------------------------------------- /apps/coremark/cvt.c: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2018 Embedded Microprocessor Benchmark Consortium (EEMBC) 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | #include 17 | 18 | #define CVTBUFSIZE 80 19 | static char CVTBUF[CVTBUFSIZE]; 20 | 21 | static double 22 | modf(double x, double *iptr) 23 | { 24 | union {double f; uint64_t i;} u = {x}; 25 | uint64_t mask; 26 | int e = (int)(u.i>>52 & 0x7ff) - 0x3ff; 27 | 28 | /* no fractional part */ 29 | if (e >= 52) { 30 | *iptr = x; 31 | if (e == 0x400 && u.i<<12 != 0) /* nan */ 32 | return x; 33 | u.i &= 1ULL<<63; 34 | return u.f; 35 | } 36 | 37 | /* no integral part*/ 38 | if (e < 0) { 39 | u.i &= 1ULL<<63; 40 | *iptr = u.f; 41 | return x; 42 | } 43 | 44 | mask = -1ULL>>12>>e; 45 | if ((u.i & mask) == 0) { 46 | *iptr = x; 47 | u.i &= 1ULL<<63; 48 | return u.f; 49 | } 50 | u.i &= ~mask; 51 | *iptr = u.f; 52 | return x - u.f; 53 | } 54 | 55 | static char * 56 | cvt(double arg, int ndigits, int *decpt, int *sign, char *buf, int eflag) 57 | { 58 | int r2; 59 | double fi, fj; 60 | char * p, *p1; 61 | 62 | if (ndigits < 0) 63 | ndigits = 0; 64 | if (ndigits >= CVTBUFSIZE - 1) 65 | ndigits = CVTBUFSIZE - 2; 66 | r2 = 0; 67 | *sign = 0; 68 | p = &buf[0]; 69 | if (arg < 0) 70 | { 71 | *sign = 1; 72 | arg = -arg; 73 | } 74 | arg = modf(arg, &fi); 75 | p1 = &buf[CVTBUFSIZE]; 76 | 77 | if (fi != 0) 78 | { 79 | p1 = &buf[CVTBUFSIZE]; 80 | while (fi != 0) 81 | { 82 | fj = modf(fi / 10, &fi); 83 | *--p1 = (int)((fj + .03) * 10) + '0'; 84 | r2++; 85 | } 86 | while (p1 < &buf[CVTBUFSIZE]) 87 | *p++ = *p1++; 88 | } 89 | else if (arg > 0) 90 | { 91 | while ((fj = arg * 10) < 1) 92 | { 93 | arg = fj; 94 | r2--; 95 | } 96 | } 97 | p1 = &buf[ndigits]; 98 | if (eflag == 0) 99 | p1 += r2; 100 | *decpt = r2; 101 | if (p1 < &buf[0]) 102 | { 103 | buf[0] = '\0'; 104 | return buf; 105 | } 106 | while (p <= p1 && p < &buf[CVTBUFSIZE]) 107 | { 108 | arg *= 10; 109 | arg = modf(arg, &fj); 110 | *p++ = (int)fj + '0'; 111 | } 112 | if (p1 >= &buf[CVTBUFSIZE]) 113 | { 114 | buf[CVTBUFSIZE - 1] = '\0'; 115 | return buf; 116 | } 117 | p = p1; 118 | *p1 += 5; 119 | while (*p1 > '9') 120 | { 121 | *p1 = '0'; 122 | if (p1 > buf) 123 | ++*--p1; 124 | else 125 | { 126 | *p1 = '1'; 127 | (*decpt)++; 128 | if (eflag == 0) 129 | { 130 | if (p > buf) 131 | *p = '0'; 132 | p++; 133 | } 134 | } 135 | } 136 | *p = '\0'; 137 | return buf; 138 | } 139 | 140 | char * 141 | ecvt(double arg, int ndigits, int *decpt, int *sign) 142 | { 143 | return cvt(arg, ndigits, decpt, sign, CVTBUF, 1); 144 | } 145 | 146 | char * 147 | ecvtbuf(double arg, int ndigits, int *decpt, int *sign, char *buf) 148 | { 149 | return cvt(arg, ndigits, decpt, sign, buf, 1); 150 | } 151 | 152 | char * 153 | fcvt(double arg, int ndigits, int *decpt, int *sign) 154 | { 155 | return cvt(arg, ndigits, decpt, sign, CVTBUF, 0); 156 | } 157 | 158 | char * 159 | fcvtbuf(double arg, int ndigits, int *decpt, int *sign, char *buf) 160 | { 161 | return cvt(arg, ndigits, decpt, sign, buf, 0); 162 | } 163 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | [![SWUbanner](https://raw.githubusercontent.com/vshymanskyy/StandWithUkraine/main/banner-direct.svg)](https://vshymanskyy.github.io/StandWithUkraine) 2 | 3 | # embedded-wasm-apps 4 | 5 | Run **native, statically-compiled** apps on any platform, using WebAssembly. 6 | Examples include [ AssemblyScript](apps/assemblyscript/app.ts), 7 | [ Rust](apps/rust/src/app.rs), 8 | [ C/C++](apps/cpp/app.cpp), 9 | [ TinyGo](apps/tinygo/app.go), 10 | [ Zig](apps/zig/main.zig), 11 | [Virgil](apps/virgil/app.v3), 12 | [WAT](apps/wat/main.wat), 13 | etc. 14 | 15 | ## How it works 16 | 17 | This does not use [`Wasm3`](https://github.com/wasm3/wasm3) engine. The approach is similar to [`WasmBoxC`](https://kripken.github.io/blog/wasm/2020/07/27/wasmboxc.html) or [`RLBox`](https://hacks.mozilla.org/2020/02/securing-firefox-with-webassembly/): 18 | 19 | 1. Compile source code to `wasm` 20 | 2. Translate `wasm` to `C` using [`wasm2c`](https://github.com/WebAssembly/wabt/blob/main/wasm2c/README.md) 21 | 3. Compile produced `C`, link with a thin runtime implementation using the **native platform toolchain** 22 | 23 | ![How it works](docs/how-it-works.png) 24 | 25 | ## Benefits 26 | 27 | - Language/toolchain decoupling 28 | - Resilience against attacks (RCE, Control-flow hijacking) 29 | - Sandboxing / SFI (Software Fault Isolation) 30 | - Enables wasm transformations, like instrumentation or [`gas metering`](https://github.com/wasm3/wasm3/blob/main/docs/Cookbook.md#gas-metering) 31 | - Software-based memory virtualization 32 | - Moderate runtime overhead (mostly depends on the source language/runtime) 33 | - Small performance hit (~10-30% slowdown compared to native modules) 34 | - Moderate binary size increase 35 | - Highly portable 36 | 37 | ## Example 38 | 39 | ```log 40 | $ make APP=rust 41 | Finished release [optimized] target(s) in 0.00s 42 | $ pio run -e esp32 -t upload 43 | $ pio device monitor 44 | Initializing WebAssembly... 45 | 🦀 Rust is running! 46 | 47 | $ make APP=assemblyscript 48 | > npm run asbuild:optimized 49 | $ pio run -e esp32 -t upload 50 | $ pio device monitor 51 | Initializing WebAssembly... 52 | 🚀 AssemblyScript is running! 53 | 54 | $ make APP=tinygo 55 | $ pio run -e esp32 -t upload 56 | $ pio device monitor 57 | Initializing WebAssembly... 58 | 🤖 TinyGo is running! 59 | ``` 60 | 61 | ## Building `WASM` apps 62 | 63 | Ensure the required tools are in your `PATH`: 64 | - [`WABT v1.0.36`](https://github.com/WebAssembly/wabt/releases/tag/1.0.36) 65 | - [`Binaryen v118`](https://github.com/WebAssembly/binaryen/releases/tag/version_118) 66 | 67 | ```sh 68 | # AssemblyScript v0.27 (needs Node.js) 69 | make APP=assemblyscript 70 | 71 | # Rust 1.80.1 72 | rustup target add wasm32-unknown-unknown 73 | make APP=rust 74 | 75 | # C/C++ (needs Clang) 76 | make APP=cpp 77 | 78 | # C99 Coremark (needs Clang) 79 | make APP=coremark 80 | 81 | # TinyGo v0.33.0 + Go v1.23.0 82 | make APP=tinygo 83 | 84 | # Zig v0.13.0 85 | make APP=zig 86 | 87 | # Virgil (Aeneas III-7.1632) 88 | make APP=virgil 89 | 90 | # WAT 91 | make APP=wat 92 | ``` 93 | 94 | Resulting WASM file comparison: 95 | 96 | | AS | C/C++ | Coremark | Rust | TinyGo | Virgil | WAT | Zig | 97 | | -------- | ------- | -------- | ------- | ------- | ------- | ------- | ------- | 98 | | 3951 | 864 | 10800 | 12264 | 1227 | 315 | 223 | 1057 | 99 | 100 | 101 | ## Building and running with `PlatformIO` 102 | 103 | ```sh 104 | # For ESP32: 105 | pio run -e esp32 -t upload 106 | 107 | # For ESP8266: 108 | pio run -e esp8266 -t upload 109 | 110 | # For Raspberry Pi Pico: 111 | pio run -e rpi-pico -t upload 112 | 113 | # Open serial monitor 114 | pio device monitor --quiet 115 | ``` 116 | 117 | ## Building and running with `Particle` 118 | 119 | Requires [`particle-cli`](https://docs.particle.io/tutorials/developer-tools/cli/). 120 | Should work on all Particle devices i.e. `Spark Core`, `Photon`, `Electron`, `Argon`, `Boron`, `P2 / Photon2`: 121 | 122 | ```sh 123 | particle flash MyDevice ./src/* 124 | 125 | # Open serial monitor 126 | particle serial monitor --follow 127 | ``` 128 | 129 | ### License 130 | 131 | This project is released under The MIT License (MIT) 132 | -------------------------------------------------------------------------------- /apps/coremark/coremark.h: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2018 Embedded Microprocessor Benchmark Consortium (EEMBC) 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | 16 | Original Author: Shay Gal-on 17 | */ 18 | 19 | /* Topic: Description 20 | This file contains declarations of the various benchmark functions. 21 | */ 22 | 23 | /* Configuration: TOTAL_DATA_SIZE 24 | Define total size for data algorithms will operate on 25 | */ 26 | #ifndef TOTAL_DATA_SIZE 27 | #define TOTAL_DATA_SIZE 2 * 1000 28 | #endif 29 | 30 | #define SEED_ARG 0 31 | #define SEED_FUNC 1 32 | #define SEED_VOLATILE 2 33 | 34 | #define MEM_STATIC 0 35 | #define MEM_MALLOC 1 36 | #define MEM_STACK 2 37 | 38 | #include "core_portme.h" 39 | 40 | #if HAS_STDIO 41 | #include 42 | #endif 43 | #if HAS_PRINTF 44 | #define ee_printf printf 45 | #endif 46 | 47 | /* Actual benchmark execution in iterate */ 48 | void *iterate(void *pres); 49 | 50 | /* Typedef: secs_ret 51 | For machines that have floating point support, get number of seconds as 52 | a double. Otherwise an unsigned int. 53 | */ 54 | #if HAS_FLOAT 55 | typedef double secs_ret; 56 | #else 57 | typedef ee_u32 secs_ret; 58 | #endif 59 | 60 | #if MAIN_HAS_NORETURN 61 | #define MAIN_RETURN_VAL 62 | #define MAIN_RETURN_TYPE void 63 | #elif MAIN_HAS_FLOATRETURN 64 | #define MAIN_RETURN_VAL 0.f 65 | #define MAIN_RETURN_TYPE float 66 | #else 67 | #define MAIN_RETURN_VAL 0 68 | #define MAIN_RETURN_TYPE int 69 | #endif 70 | 71 | void start_time(void); 72 | void stop_time(void); 73 | CORE_TICKS get_time(void); 74 | secs_ret time_in_secs(CORE_TICKS ticks); 75 | 76 | /* Misc useful functions */ 77 | ee_u16 crcu8(ee_u8 data, ee_u16 crc); 78 | ee_u16 crc16(ee_s16 newval, ee_u16 crc); 79 | ee_u16 crcu16(ee_u16 newval, ee_u16 crc); 80 | ee_u16 crcu32(ee_u32 newval, ee_u16 crc); 81 | ee_u8 check_data_types(void); 82 | void * portable_malloc(ee_size_t size); 83 | void portable_free(void *p); 84 | ee_s32 parseval(char *valstring); 85 | 86 | /* Algorithm IDS */ 87 | #define ID_LIST (1 << 0) 88 | #define ID_MATRIX (1 << 1) 89 | #define ID_STATE (1 << 2) 90 | #define ALL_ALGORITHMS_MASK (ID_LIST | ID_MATRIX | ID_STATE) 91 | #define NUM_ALGORITHMS 3 92 | 93 | /* list data structures */ 94 | typedef struct list_data_s 95 | { 96 | ee_s16 data16; 97 | ee_s16 idx; 98 | } list_data; 99 | 100 | typedef struct list_head_s 101 | { 102 | struct list_head_s *next; 103 | struct list_data_s *info; 104 | } list_head; 105 | 106 | /*matrix benchmark related stuff */ 107 | #define MATDAT_INT 1 108 | #if MATDAT_INT 109 | typedef ee_s16 MATDAT; 110 | typedef ee_s32 MATRES; 111 | #else 112 | typedef ee_f16 MATDAT; 113 | typedef ee_f32 MATRES; 114 | #endif 115 | 116 | typedef struct MAT_PARAMS_S 117 | { 118 | int N; 119 | MATDAT *A; 120 | MATDAT *B; 121 | MATRES *C; 122 | } mat_params; 123 | 124 | /* state machine related stuff */ 125 | /* List of all the possible states for the FSM */ 126 | typedef enum CORE_STATE 127 | { 128 | CORE_START = 0, 129 | CORE_INVALID, 130 | CORE_S1, 131 | CORE_S2, 132 | CORE_INT, 133 | CORE_FLOAT, 134 | CORE_EXPONENT, 135 | CORE_SCIENTIFIC, 136 | NUM_CORE_STATES 137 | } core_state_e; 138 | 139 | /* Helper structure to hold results */ 140 | typedef struct RESULTS_S 141 | { 142 | /* inputs */ 143 | ee_s16 seed1; /* Initializing seed */ 144 | ee_s16 seed2; /* Initializing seed */ 145 | ee_s16 seed3; /* Initializing seed */ 146 | void * memblock[4]; /* Pointer to safe memory location */ 147 | ee_u32 size; /* Size of the data */ 148 | ee_u32 iterations; /* Number of iterations to execute */ 149 | ee_u32 execs; /* Bitmask of operations to execute */ 150 | struct list_head_s *list; 151 | mat_params mat; 152 | /* outputs */ 153 | ee_u16 crc; 154 | ee_u16 crclist; 155 | ee_u16 crcmatrix; 156 | ee_u16 crcstate; 157 | ee_s16 err; 158 | /* ultithread specific */ 159 | core_portable port; 160 | } core_results; 161 | 162 | /* Multicore execution handling */ 163 | #if (MULTITHREAD > 1) 164 | ee_u8 core_start_parallel(core_results *res); 165 | ee_u8 core_stop_parallel(core_results *res); 166 | #endif 167 | 168 | /* list benchmark functions */ 169 | list_head *core_list_init(ee_u32 blksize, list_head *memblock, ee_s16 seed); 170 | ee_u16 core_bench_list(core_results *res, ee_s16 finder_idx); 171 | 172 | /* state benchmark functions */ 173 | void core_init_state(ee_u32 size, ee_s16 seed, ee_u8 *p); 174 | ee_u16 core_bench_state(ee_u32 blksize, 175 | ee_u8 *memblock, 176 | ee_s16 seed1, 177 | ee_s16 seed2, 178 | ee_s16 step, 179 | ee_u16 crc); 180 | 181 | /* matrix benchmark functions */ 182 | ee_u32 core_init_matrix(ee_u32 blksize, 183 | void * memblk, 184 | ee_s32 seed, 185 | mat_params *p); 186 | ee_u16 core_bench_matrix(mat_params *p, ee_s16 seed, ee_u16 crc); 187 | -------------------------------------------------------------------------------- /src/wasm-rt-mem-impl.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2018 WebAssembly Community Group participants 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | #include "wasm-rt-impl.h" 18 | 19 | #include 20 | #include 21 | 22 | #ifdef _WIN32 23 | #include 24 | #else 25 | //#include 26 | #endif 27 | 28 | // TODO: Support Custom Page Sizes 29 | // https://github.com/WebAssembly/wabt/issues/2019#issuecomment-2308930257 30 | #define WASM_PAGE_SIZE 65536 31 | 32 | #ifdef WASM_RT_GROW_FAILED_HANDLER 33 | extern void WASM_RT_GROW_FAILED_HANDLER(); 34 | #endif 35 | 36 | #define C11_MEMORY_LOCK_VAR_INIT(name) \ 37 | if (mtx_init(&(name), mtx_plain) != thrd_success) { \ 38 | fprintf(stderr, "Lock init failed\n"); \ 39 | abort(); \ 40 | } 41 | #define C11_MEMORY_LOCK_AQUIRE(name) \ 42 | if (mtx_lock(&(name)) != thrd_success) { \ 43 | fprintf(stderr, "Lock acquire failed\n"); \ 44 | abort(); \ 45 | } 46 | #define C11_MEMORY_LOCK_RELEASE(name) \ 47 | if (mtx_unlock(&(name)) != thrd_success) { \ 48 | fprintf(stderr, "Lock release failed\n"); \ 49 | abort(); \ 50 | } 51 | 52 | #define PTHREAD_MEMORY_LOCK_VAR_INIT(name) \ 53 | if (pthread_mutex_init(&(name), NULL) != 0) { \ 54 | fprintf(stderr, "Lock init failed\n"); \ 55 | abort(); \ 56 | } 57 | #define PTHREAD_MEMORY_LOCK_AQUIRE(name) \ 58 | if (pthread_mutex_lock(&(name)) != 0) { \ 59 | fprintf(stderr, "Lock acquire failed\n"); \ 60 | abort(); \ 61 | } 62 | #define PTHREAD_MEMORY_LOCK_RELEASE(name) \ 63 | if (pthread_mutex_unlock(&(name)) != 0) { \ 64 | fprintf(stderr, "Lock release failed\n"); \ 65 | abort(); \ 66 | } 67 | 68 | #define WIN_MEMORY_LOCK_VAR_INIT(name) InitializeCriticalSection(&(name)) 69 | #define WIN_MEMORY_LOCK_AQUIRE(name) EnterCriticalSection(&(name)) 70 | #define WIN_MEMORY_LOCK_RELEASE(name) LeaveCriticalSection(&(name)) 71 | 72 | #if WASM_RT_USE_MMAP 73 | 74 | #ifdef _WIN32 75 | static void* os_mmap(size_t size) { 76 | void* ret = VirtualAlloc(NULL, size, MEM_RESERVE, PAGE_NOACCESS); 77 | return ret; 78 | } 79 | 80 | static int os_munmap(void* addr, size_t size) { 81 | // Windows can only unmap the whole mapping 82 | (void)size; /* unused */ 83 | BOOL succeeded = VirtualFree(addr, 0, MEM_RELEASE); 84 | return succeeded ? 0 : -1; 85 | } 86 | 87 | static int os_mprotect(void* addr, size_t size) { 88 | if (size == 0) { 89 | return 0; 90 | } 91 | void* ret = VirtualAlloc(addr, size, MEM_COMMIT, PAGE_READWRITE); 92 | if (ret == addr) { 93 | return 0; 94 | } 95 | VirtualFree(addr, 0, MEM_RELEASE); 96 | return -1; 97 | } 98 | 99 | __attribute__((weak)) 100 | void os_print_last_error(const char* msg) { 101 | DWORD errorMessageID = GetLastError(); 102 | if (errorMessageID != 0) { 103 | LPSTR messageBuffer = 0; 104 | // The api creates the buffer that holds the message 105 | size_t size = FormatMessageA( 106 | FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | 107 | FORMAT_MESSAGE_IGNORE_INSERTS, 108 | NULL, errorMessageID, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), 109 | (LPSTR)&messageBuffer, 0, NULL); 110 | (void)size; 111 | printf("%s. %s\n", msg, messageBuffer); 112 | LocalFree(messageBuffer); 113 | } else { 114 | printf("%s. No error code.\n", msg); 115 | } 116 | } 117 | 118 | #else 119 | static void* os_mmap(size_t size) { 120 | int map_prot = PROT_NONE; 121 | int map_flags = MAP_ANONYMOUS | MAP_PRIVATE; 122 | uint8_t* addr = mmap(NULL, size, map_prot, map_flags, -1, 0); 123 | if (addr == MAP_FAILED) 124 | return NULL; 125 | return addr; 126 | } 127 | 128 | static int os_munmap(void* addr, size_t size) { 129 | return munmap(addr, size); 130 | } 131 | 132 | static int os_mprotect(void* addr, size_t size) { 133 | return mprotect(addr, size, PROT_READ | PROT_WRITE); 134 | } 135 | 136 | __attribute__((weak)) 137 | void os_print_last_error(const char* msg) { 138 | perror(msg); 139 | } 140 | 141 | #endif 142 | 143 | static uint64_t get_alloc_size_for_mmap(uint64_t max_pages, bool is64) { 144 | assert(!is64 && "memory64 is not yet compatible with WASM_RT_USE_MMAP"); 145 | #if WASM_RT_MEMCHECK_GUARD_PAGES 146 | /* Reserve 8GiB. */ 147 | const uint64_t max_size = 0x200000000ul; 148 | return max_size; 149 | #else 150 | if (max_pages != 0) { 151 | const uint64_t max_size = max_pages * WASM_PAGE_SIZE; 152 | return max_size; 153 | } 154 | 155 | /* Reserve 4GiB. */ 156 | const uint64_t max_size = 0x100000000ul; 157 | return max_size; 158 | #endif 159 | } 160 | 161 | #endif 162 | 163 | // Include operations for memory 164 | #define WASM_RT_MEM_OPS 165 | #include "wasm-rt-mem-impl-helper.inc" 166 | #undef WASM_RT_MEM_OPS 167 | 168 | // Include operations for shared memory 169 | #define WASM_RT_MEM_OPS_SHARED 170 | #include "wasm-rt-mem-impl-helper.inc" 171 | #undef WASM_RT_MEM_OPS_SHARED 172 | 173 | #undef C11_MEMORY_LOCK_VAR_INIT 174 | #undef C11_MEMORY_LOCK_AQUIRE 175 | #undef C11_MEMORY_LOCK_RELEASE 176 | #undef PTHREAD_MEMORY_LOCK_VAR_INIT 177 | #undef PTHREAD_MEMORY_LOCK_AQUIRE 178 | #undef PTHREAD_MEMORY_LOCK_RELEASE 179 | #undef WIN_MEMORY_LOCK_VAR_INIT 180 | #undef WIN_MEMORY_LOCK_AQUIRE 181 | #undef WIN_MEMORY_LOCK_RELEASE 182 | #undef WASM_PAGE_SIZE 183 | -------------------------------------------------------------------------------- /src/wasm-rt-mem-impl-helper.inc: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2018 WebAssembly Community Group participants 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | // This file is used as a template to generate code for regular memories or for 18 | // shared memories. For this, the file must be included after defining either 19 | // WASM_RT_MEM_OPS or WASM_RT_MEM_OPS_SHARED. 20 | 21 | #if defined(WASM_RT_MEM_OPS) && defined(WASM_RT_MEM_OPS_SHARED) 22 | #error \ 23 | "Expected only one of { WASM_RT_MEM_OPS, WASM_RT_MEM_OPS_SHARED } to be defined" 24 | #elif !defined(WASM_RT_MEM_OPS) && !defined(WASM_RT_MEM_OPS_SHARED) 25 | #error \ 26 | "Expected one of { WASM_RT_MEM_OPS, WASM_RT_MEM_OPS_SHARED } to be defined" 27 | #endif 28 | 29 | // Shared memory operations are defined only if we have C11 30 | #if defined(WASM_RT_MEM_OPS) || \ 31 | (defined(WASM_RT_MEM_OPS_SHARED) && defined(WASM_RT_C11_AVAILABLE)) 32 | 33 | #ifdef WASM_RT_MEM_OPS 34 | 35 | // Memory operations on wasm_rt_memory_t 36 | #define MEMORY_TYPE wasm_rt_memory_t 37 | #define MEMORY_API_NAME(name) name 38 | #define MEMORY_CELL_TYPE uint8_t* 39 | #define MEMORY_LOCK_VAR_INIT(name) 40 | #define MEMORY_LOCK_AQUIRE(name) 41 | #define MEMORY_LOCK_RELEASE(name) 42 | 43 | #else 44 | 45 | // Memory operations on wasm_rt_shared_memory_t 46 | #define MEMORY_TYPE wasm_rt_shared_memory_t 47 | #define MEMORY_API_NAME(name) name##_shared 48 | #define MEMORY_CELL_TYPE _Atomic volatile uint8_t* 49 | 50 | #if WASM_RT_USE_C11THREADS 51 | #define MEMORY_LOCK_VAR_INIT(name) C11_MEMORY_LOCK_VAR_INIT(name) 52 | #define MEMORY_LOCK_AQUIRE(name) C11_MEMORY_LOCK_AQUIRE(name) 53 | #define MEMORY_LOCK_RELEASE(name) C11_MEMORY_LOCK_RELEASE(name) 54 | #elif WASM_RT_USE_PTHREADS 55 | #define MEMORY_LOCK_VAR_INIT(name) PTHREAD_MEMORY_LOCK_VAR_INIT(name) 56 | #define MEMORY_LOCK_AQUIRE(name) PTHREAD_MEMORY_LOCK_AQUIRE(name) 57 | #define MEMORY_LOCK_RELEASE(name) PTHREAD_MEMORY_LOCK_RELEASE(name) 58 | #elif WASM_RT_USE_CRITICALSECTION 59 | #define MEMORY_LOCK_VAR_INIT(name) WIN_MEMORY_LOCK_VAR_INIT(name) 60 | #define MEMORY_LOCK_AQUIRE(name) WIN_MEMORY_LOCK_AQUIRE(name) 61 | #define MEMORY_LOCK_RELEASE(name) WIN_MEMORY_LOCK_RELEASE(name) 62 | #endif 63 | 64 | #endif 65 | 66 | void MEMORY_API_NAME(wasm_rt_allocate_memory)(MEMORY_TYPE* memory, 67 | uint64_t initial_pages, 68 | uint64_t max_pages, 69 | bool is64) { 70 | uint64_t byte_length = initial_pages * WASM_PAGE_SIZE; 71 | memory->size = byte_length; 72 | memory->pages = initial_pages; 73 | memory->max_pages = max_pages; 74 | memory->is64 = is64; 75 | MEMORY_LOCK_VAR_INIT(memory->mem_lock); 76 | 77 | #if WASM_RT_USE_MMAP 78 | const uint64_t mmap_size = 79 | get_alloc_size_for_mmap(memory->max_pages, memory->is64); 80 | void* addr = os_mmap(mmap_size); 81 | if (!addr) { 82 | os_print_last_error("os_mmap failed."); 83 | abort(); 84 | } 85 | int ret = os_mprotect(addr, byte_length); 86 | if (ret != 0) { 87 | os_print_last_error("os_mprotect failed."); 88 | abort(); 89 | } 90 | memory->data = addr; 91 | #else 92 | void* addr = calloc(byte_length, 1); 93 | if (!addr) { 94 | os_print_last_error("memory allocation failed."); 95 | abort(); 96 | } 97 | memory->data = addr; 98 | #endif 99 | } 100 | 101 | static uint64_t MEMORY_API_NAME(grow_memory_impl)(MEMORY_TYPE* memory, 102 | uint64_t delta) { 103 | uint64_t old_pages = memory->pages; 104 | uint64_t new_pages = memory->pages + delta; 105 | if (new_pages == 0) { 106 | return 0; 107 | } 108 | if (new_pages < old_pages || new_pages > memory->max_pages) { 109 | return (uint64_t)-1; 110 | } 111 | uint64_t old_size = old_pages * WASM_PAGE_SIZE; 112 | uint64_t new_size = new_pages * WASM_PAGE_SIZE; 113 | uint64_t delta_size = delta * WASM_PAGE_SIZE; 114 | #if WASM_RT_USE_MMAP 115 | MEMORY_CELL_TYPE new_data = memory->data; 116 | int ret = os_mprotect((void*)(new_data + old_size), delta_size); 117 | if (ret != 0) { 118 | return (uint64_t)-1; 119 | } 120 | #else 121 | MEMORY_CELL_TYPE new_data = realloc((void*)memory->data, new_size); 122 | if (new_data == NULL) { 123 | return (uint64_t)-1; 124 | } 125 | #if !WABT_BIG_ENDIAN 126 | memset((void*)(new_data + old_size), 0, delta_size); 127 | #endif 128 | #endif 129 | #if WABT_BIG_ENDIAN 130 | memmove((void*)(new_data + new_size - old_size), (void*)new_data, old_size); 131 | memset((void*)new_data, 0, delta_size); 132 | #endif 133 | memory->pages = new_pages; 134 | memory->size = new_size; 135 | memory->data = new_data; 136 | return old_pages; 137 | } 138 | 139 | uint64_t MEMORY_API_NAME(wasm_rt_grow_memory)(MEMORY_TYPE* memory, 140 | uint64_t delta) { 141 | MEMORY_LOCK_AQUIRE(memory->mem_lock); 142 | uint64_t ret = MEMORY_API_NAME(grow_memory_impl)(memory, delta); 143 | MEMORY_LOCK_RELEASE(memory->mem_lock); 144 | #ifdef WASM_RT_GROW_FAILED_HANDLER 145 | if (ret == (uint64_t)-1) { 146 | WASM_RT_GROW_FAILED_HANDLER(); 147 | } 148 | #endif 149 | return ret; 150 | } 151 | 152 | void MEMORY_API_NAME(wasm_rt_free_memory)(MEMORY_TYPE* memory) { 153 | #if WASM_RT_USE_MMAP 154 | const uint64_t mmap_size = 155 | get_alloc_size_for_mmap(memory->max_pages, memory->is64); 156 | os_munmap((void*)memory->data, mmap_size); // ignore error 157 | #else 158 | free((void*)memory->data); 159 | #endif 160 | } 161 | 162 | #undef MEMORY_LOCK_RELEASE 163 | #undef MEMORY_LOCK_AQUIRE 164 | #undef MEMORY_LOCK_VAR_INIT 165 | #undef MEMORY_CELL_TYPE 166 | #undef MEMORY_API_NAME 167 | #undef MEMORY_TYPE 168 | 169 | #endif 170 | -------------------------------------------------------------------------------- /apps/coremark/core_util.c: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2018 Embedded Microprocessor Benchmark Consortium (EEMBC) 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | 16 | Original Author: Shay Gal-on 17 | */ 18 | 19 | #include "coremark.h" 20 | /* Function: get_seed 21 | Get a values that cannot be determined at compile time. 22 | 23 | Since different embedded systems and compilers are used, 3 different 24 | methods are provided: 1 - Using a volatile variable. This method is only 25 | valid if the compiler is forced to generate code that reads the value of a 26 | volatile variable from memory at run time. Please note, if using this method, 27 | you would need to modify core_portme.c to generate training profile. 2 - 28 | Command line arguments. This is the preferred method if command line 29 | arguments are supported. 3 - System function. If none of the first 2 methods 30 | is available on the platform, a system function which is not a stub can be 31 | used. 32 | 33 | e.g. read the value on GPIO pins connected to switches, or invoke 34 | special simulator functions. 35 | */ 36 | #if (SEED_METHOD == SEED_VOLATILE) 37 | extern volatile ee_s32 seed1_volatile; 38 | extern volatile ee_s32 seed2_volatile; 39 | extern volatile ee_s32 seed3_volatile; 40 | extern volatile ee_s32 seed4_volatile; 41 | extern volatile ee_s32 seed5_volatile; 42 | ee_s32 43 | get_seed_32(int i) 44 | { 45 | ee_s32 retval; 46 | switch (i) 47 | { 48 | case 1: 49 | retval = seed1_volatile; 50 | break; 51 | case 2: 52 | retval = seed2_volatile; 53 | break; 54 | case 3: 55 | retval = seed3_volatile; 56 | break; 57 | case 4: 58 | retval = seed4_volatile; 59 | break; 60 | case 5: 61 | retval = seed5_volatile; 62 | break; 63 | default: 64 | retval = 0; 65 | break; 66 | } 67 | return retval; 68 | } 69 | #elif (SEED_METHOD == SEED_ARG) 70 | ee_s32 71 | parseval(char *valstring) 72 | { 73 | ee_s32 retval = 0; 74 | ee_s32 neg = 1; 75 | int hexmode = 0; 76 | if (*valstring == '-') 77 | { 78 | neg = -1; 79 | valstring++; 80 | } 81 | if ((valstring[0] == '0') && (valstring[1] == 'x')) 82 | { 83 | hexmode = 1; 84 | valstring += 2; 85 | } 86 | /* first look for digits */ 87 | if (hexmode) 88 | { 89 | while (((*valstring >= '0') && (*valstring <= '9')) 90 | || ((*valstring >= 'a') && (*valstring <= 'f'))) 91 | { 92 | ee_s32 digit = *valstring - '0'; 93 | if (digit > 9) 94 | digit = 10 + *valstring - 'a'; 95 | retval *= 16; 96 | retval += digit; 97 | valstring++; 98 | } 99 | } 100 | else 101 | { 102 | while ((*valstring >= '0') && (*valstring <= '9')) 103 | { 104 | ee_s32 digit = *valstring - '0'; 105 | retval *= 10; 106 | retval += digit; 107 | valstring++; 108 | } 109 | } 110 | /* now add qualifiers */ 111 | if (*valstring == 'K') 112 | retval *= 1024; 113 | if (*valstring == 'M') 114 | retval *= 1024 * 1024; 115 | 116 | retval *= neg; 117 | return retval; 118 | } 119 | 120 | ee_s32 121 | get_seed_args(int i, int argc, char *argv[]) 122 | { 123 | if (argc > i) 124 | return parseval(argv[i]); 125 | return 0; 126 | } 127 | 128 | #elif (SEED_METHOD == SEED_FUNC) 129 | /* If using OS based function, you must define and implement the functions below 130 | * in core_portme.h and core_portme.c ! */ 131 | ee_s32 132 | get_seed_32(int i) 133 | { 134 | ee_s32 retval; 135 | switch (i) 136 | { 137 | case 1: 138 | retval = portme_sys1(); 139 | break; 140 | case 2: 141 | retval = portme_sys2(); 142 | break; 143 | case 3: 144 | retval = portme_sys3(); 145 | break; 146 | case 4: 147 | retval = portme_sys4(); 148 | break; 149 | case 5: 150 | retval = portme_sys5(); 151 | break; 152 | default: 153 | retval = 0; 154 | break; 155 | } 156 | return retval; 157 | } 158 | #endif 159 | 160 | /* Function: crc* 161 | Service functions to calculate 16b CRC code. 162 | 163 | */ 164 | ee_u16 165 | crcu8(ee_u8 data, ee_u16 crc) 166 | { 167 | ee_u8 i = 0, x16 = 0, carry = 0; 168 | 169 | for (i = 0; i < 8; i++) 170 | { 171 | x16 = (ee_u8)((data & 1) ^ ((ee_u8)crc & 1)); 172 | data >>= 1; 173 | 174 | if (x16 == 1) 175 | { 176 | crc ^= 0x4002; 177 | carry = 1; 178 | } 179 | else 180 | carry = 0; 181 | crc >>= 1; 182 | if (carry) 183 | crc |= 0x8000; 184 | else 185 | crc &= 0x7fff; 186 | } 187 | return crc; 188 | } 189 | ee_u16 190 | crcu16(ee_u16 newval, ee_u16 crc) 191 | { 192 | crc = crcu8((ee_u8)(newval), crc); 193 | crc = crcu8((ee_u8)((newval) >> 8), crc); 194 | return crc; 195 | } 196 | ee_u16 197 | crcu32(ee_u32 newval, ee_u16 crc) 198 | { 199 | crc = crc16((ee_s16)newval, crc); 200 | crc = crc16((ee_s16)(newval >> 16), crc); 201 | return crc; 202 | } 203 | ee_u16 204 | crc16(ee_s16 newval, ee_u16 crc) 205 | { 206 | return crcu16((ee_u16)newval, crc); 207 | } 208 | 209 | ee_u8 210 | check_data_types() 211 | { 212 | ee_u8 retval = 0; 213 | if (sizeof(ee_u8) != 1) 214 | { 215 | ee_printf("ERROR: ee_u8 is not an 8b datatype!\n"); 216 | retval++; 217 | } 218 | if (sizeof(ee_u16) != 2) 219 | { 220 | ee_printf("ERROR: ee_u16 is not a 16b datatype!\n"); 221 | retval++; 222 | } 223 | if (sizeof(ee_s16) != 2) 224 | { 225 | ee_printf("ERROR: ee_s16 is not a 16b datatype!\n"); 226 | retval++; 227 | } 228 | if (sizeof(ee_s32) != 4) 229 | { 230 | ee_printf("ERROR: ee_s32 is not a 32b datatype!\n"); 231 | retval++; 232 | } 233 | if (sizeof(ee_u32) != 4) 234 | { 235 | ee_printf("ERROR: ee_u32 is not a 32b datatype!\n"); 236 | retval++; 237 | } 238 | if (sizeof(ee_ptr_int) != sizeof(int *)) 239 | { 240 | ee_printf( 241 | "ERROR: ee_ptr_int is not a datatype that holds an int pointer!\n"); 242 | retval++; 243 | } 244 | if (retval > 0) 245 | { 246 | ee_printf("ERROR: Please modify the datatypes in core_portme.h!\n"); 247 | } 248 | return retval; 249 | } 250 | -------------------------------------------------------------------------------- /apps/coremark/core_portme.h: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2018 Embedded Microprocessor Benchmark Consortium (EEMBC) 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | 16 | Original Author: Shay Gal-on 17 | */ 18 | 19 | /* Topic : Description 20 | This file contains configuration constants required to execute on 21 | different platforms 22 | */ 23 | #ifndef CORE_PORTME_H 24 | #define CORE_PORTME_H 25 | 26 | #include 27 | #include 28 | 29 | #define WASM_EXPORT __attribute__((used)) __attribute__((visibility ("default"))) 30 | #define WASM_EXPORT_AS(NAME) WASM_EXPORT __attribute__((export_name(NAME))) 31 | #define WASM_IMPORT(MODULE,NAME) __attribute__((import_module(MODULE))) __attribute__((import_name(NAME))) 32 | 33 | // remove all prints 34 | #define ee_printf(...) do {} while(0) 35 | 36 | // a minor hack to rename the main function, so we can call it from our setup() 37 | #define main(...) coremark_main(void) 38 | 39 | float coremark_main(void); 40 | 41 | WASM_IMPORT("wiring","millis") 42 | uint32_t wiring_millis(void); 43 | 44 | WASM_IMPORT("wiring","delay") 45 | void wiring_delay(uint32_t ms); 46 | 47 | WASM_IMPORT("wiring","print") 48 | void wiring_print(const char* buf, uint32_t len); 49 | 50 | WASM_IMPORT("wiring","stopWdt") 51 | void wiring_stopWdt(); 52 | 53 | WASM_EXPORT_AS("setup") 54 | void wiring_setup(void); 55 | 56 | WASM_EXPORT_AS("loop") 57 | void wiring_loop(void); 58 | 59 | 60 | #ifndef ITERATIONS 61 | // 0 means auto-detect number of iterations for 10 second test 62 | #define ITERATIONS 0 63 | #endif 64 | 65 | /************************/ 66 | /* Data types and settings */ 67 | /************************/ 68 | /* Configuration : HAS_FLOAT 69 | Define to 1 if the platform supports floating point. 70 | */ 71 | #ifndef HAS_FLOAT 72 | #define HAS_FLOAT 1 73 | #endif 74 | /* Configuration : HAS_TIME_H 75 | Define to 1 if platform has the time.h header file, 76 | and implementation of functions thereof. 77 | */ 78 | #ifndef HAS_TIME_H 79 | #define HAS_TIME_H 0 80 | #endif 81 | /* Configuration : USE_CLOCK 82 | Define to 1 if platform has the time.h header file, 83 | and implementation of functions thereof. 84 | */ 85 | #ifndef USE_CLOCK 86 | #define USE_CLOCK 0 87 | #endif 88 | /* Configuration : HAS_STDIO 89 | Define to 1 if the platform has stdio.h. 90 | */ 91 | #ifndef HAS_STDIO 92 | #define HAS_STDIO 0 93 | #endif 94 | /* Configuration : HAS_PRINTF 95 | Define to 1 if the platform has stdio.h and implements the printf 96 | function. 97 | */ 98 | #ifndef HAS_PRINTF 99 | #define HAS_PRINTF 0 100 | #endif 101 | 102 | 103 | /* Definitions : COMPILER_VERSION, COMPILER_FLAGS, MEM_LOCATION 104 | Initialize these strings per platform 105 | */ 106 | #ifndef COMPILER_VERSION 107 | #if defined(__clang__) 108 | #define COMPILER_VERSION __VERSION__ 109 | #elif defined(__GNUC__) 110 | #define COMPILER_VERSION "GCC"__VERSION__ 111 | #else 112 | #define COMPILER_VERSION "Please put compiler version here (e.g. gcc 4.1)" 113 | #endif 114 | #endif 115 | #ifndef COMPILER_FLAGS 116 | #define COMPILER_FLAGS \ 117 | FLAGS_STR /* "Please put compiler flags here (e.g. -o3)" */ 118 | #endif 119 | #ifndef MEM_LOCATION 120 | #define MEM_LOCATION "STATIC" 121 | #endif 122 | 123 | /* Data Types : 124 | To avoid compiler issues, define the data types that need ot be used for 125 | 8b, 16b and 32b in . 126 | 127 | *Imprtant* : 128 | ee_ptr_int needs to be the data type used to hold pointers, otherwise 129 | coremark may fail!!! 130 | */ 131 | typedef int16_t ee_s16; 132 | typedef uint16_t ee_u16; 133 | typedef int32_t ee_s32; 134 | typedef double ee_f32; 135 | typedef uint8_t ee_u8; 136 | typedef uint32_t ee_u32; 137 | typedef uintptr_t ee_ptr_int; 138 | typedef size_t ee_size_t; 139 | 140 | /* align_mem : 141 | This macro is used to align an offset to point to a 32b value. It is 142 | used in the Matrix algorithm to initialize the input memory blocks. 143 | */ 144 | #define align_mem(x) (void *)(4 + (((ee_ptr_int)(x)-1) & ~3)) 145 | 146 | /* Configuration : CORE_TICKS 147 | Define type of return from the timing functions. 148 | */ 149 | #define CORETIMETYPE uint32_t 150 | typedef uint32_t CORE_TICKS; 151 | 152 | /* Configuration : SEED_METHOD 153 | Defines method to get seed values that cannot be computed at compile 154 | time. 155 | 156 | Valid values : 157 | SEED_ARG - from command line. 158 | SEED_FUNC - from a system function. 159 | SEED_VOLATILE - from volatile variables. 160 | */ 161 | #ifndef SEED_METHOD 162 | #define SEED_METHOD SEED_VOLATILE 163 | #endif 164 | 165 | /* Configuration : MEM_METHOD 166 | Defines method to get a block of memry. 167 | 168 | Valid values : 169 | MEM_MALLOC - for platforms that implement malloc and have malloc.h. 170 | MEM_STATIC - to use a static memory array. 171 | MEM_STACK - to allocate the data block on the stack (NYI). 172 | */ 173 | #ifndef MEM_METHOD 174 | #define MEM_METHOD MEM_STATIC 175 | #endif 176 | 177 | /* Configuration : MULTITHREAD 178 | Define for parallel execution 179 | 180 | Valid values : 181 | 1 - only one context (default). 182 | N>1 - will execute N copies in parallel. 183 | 184 | Note : 185 | If this flag is defined to more then 1, an implementation for launching 186 | parallel contexts must be defined. 187 | 188 | Two sample implementations are provided. Use or 189 | to enable them. 190 | 191 | It is valid to have a different implementation of 192 | and in , to fit a particular architecture. 193 | */ 194 | #ifndef MULTITHREAD 195 | #define MULTITHREAD 1 196 | #define USE_PTHREAD 0 197 | #define USE_FORK 0 198 | #define USE_SOCKET 0 199 | #endif 200 | 201 | /* Configuration : MAIN_HAS_NOARGC 202 | Needed if platform does not support getting arguments to main. 203 | 204 | Valid values : 205 | 0 - argc/argv to main is supported 206 | 1 - argc/argv to main is not supported 207 | 208 | Note : 209 | This flag only matters if MULTITHREAD has been defined to a value 210 | greater then 1. 211 | */ 212 | #ifndef MAIN_HAS_NOARGC 213 | #define MAIN_HAS_NOARGC 1 214 | #endif 215 | 216 | /* Configuration : MAIN_HAS_NORETURN 217 | Needed if platform does not support returning a value from main. 218 | 219 | Valid values : 220 | 0 - main returns an int, and return value will be 0. 221 | 1 - platform does not support returning a value from main 222 | */ 223 | #ifndef MAIN_HAS_NORETURN 224 | #define MAIN_HAS_NORETURN 0 225 | #endif 226 | 227 | #define MAIN_HAS_FLOATRETURN 1 228 | 229 | /* Variable : default_num_contexts 230 | Not used for this simple port, must cintain the value 1. 231 | */ 232 | extern ee_u32 default_num_contexts; 233 | 234 | typedef struct CORE_PORTABLE_S 235 | { 236 | ee_u8 portable_id; 237 | } core_portable; 238 | 239 | /* target specific init/fini */ 240 | void portable_init(core_portable *p, int *argc, char *argv[]); 241 | void portable_fini(core_portable *p); 242 | 243 | #if !defined(PROFILE_RUN) && !defined(PERFORMANCE_RUN) \ 244 | && !defined(VALIDATION_RUN) 245 | #if (TOTAL_DATA_SIZE == 1200) 246 | #define PROFILE_RUN 1 247 | #elif (TOTAL_DATA_SIZE == 2000) 248 | #define PERFORMANCE_RUN 1 249 | #else 250 | #define VALIDATION_RUN 1 251 | #endif 252 | #endif 253 | 254 | #endif /* CORE_PORTME_H */ 255 | -------------------------------------------------------------------------------- /src/wasm-rt-impl.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2018 WebAssembly Community Group participants 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | #include "wasm-rt-impl.h" 18 | 19 | #include 20 | #include 21 | #include 22 | #include 23 | #include 24 | #include 25 | #include 26 | #include 27 | 28 | #if WASM_RT_INSTALL_SIGNAL_HANDLER && !defined(_WIN32) 29 | #include 30 | #include 31 | #endif 32 | 33 | #ifdef _WIN32 34 | #include 35 | #else 36 | //#include 37 | #endif 38 | 39 | #ifndef NDEBUG 40 | #define DEBUG_PRINTF(...) fprintf(stderr, __VA_ARGS__); 41 | #else 42 | #define DEBUG_PRINTF(...) 43 | #endif 44 | 45 | #if WASM_RT_INSTALL_SIGNAL_HANDLER 46 | static bool g_signal_handler_installed = false; 47 | #ifdef _WIN32 48 | static void* g_sig_handler_handle = 0; 49 | #endif 50 | #endif 51 | 52 | #if WASM_RT_STACK_DEPTH_COUNT 53 | WASM_RT_THREAD_LOCAL uint32_t wasm_rt_call_stack_depth; 54 | WASM_RT_THREAD_LOCAL uint32_t wasm_rt_saved_call_stack_depth; 55 | #elif WASM_RT_STACK_EXHAUSTION_HANDLER 56 | static WASM_RT_THREAD_LOCAL void* g_alt_stack = NULL; 57 | #endif 58 | 59 | WASM_RT_THREAD_LOCAL wasm_rt_jmp_buf g_wasm_rt_jmp_buf; 60 | 61 | #ifdef WASM_RT_TRAP_HANDLER 62 | extern void WASM_RT_TRAP_HANDLER(wasm_rt_trap_t code); 63 | #endif 64 | 65 | void wasm_rt_trap(wasm_rt_trap_t code) { 66 | assert(code != WASM_RT_TRAP_NONE); 67 | #if WASM_RT_STACK_DEPTH_COUNT 68 | wasm_rt_call_stack_depth = wasm_rt_saved_call_stack_depth; 69 | #endif 70 | 71 | #ifdef WASM_RT_TRAP_HANDLER 72 | WASM_RT_TRAP_HANDLER(code); 73 | wasm_rt_unreachable(); 74 | #else 75 | WASM_RT_LONGJMP(g_wasm_rt_jmp_buf, code); 76 | #endif 77 | } 78 | 79 | #ifdef _WIN32 80 | 81 | #if WASM_RT_INSTALL_SIGNAL_HANDLER 82 | 83 | static LONG os_signal_handler(PEXCEPTION_POINTERS info) { 84 | if (info->ExceptionRecord->ExceptionCode == EXCEPTION_ACCESS_VIOLATION) { 85 | wasm_rt_trap(WASM_RT_TRAP_OOB); 86 | } else if (info->ExceptionRecord->ExceptionCode == EXCEPTION_STACK_OVERFLOW) { 87 | wasm_rt_trap(WASM_RT_TRAP_EXHAUSTION); 88 | } 89 | return EXCEPTION_CONTINUE_SEARCH; 90 | } 91 | 92 | static void os_install_signal_handler(void) { 93 | g_sig_handler_handle = 94 | AddVectoredExceptionHandler(1 /* CALL_FIRST */, os_signal_handler); 95 | } 96 | 97 | static void os_cleanup_signal_handler(void) { 98 | RemoveVectoredExceptionHandler(g_sig_handler_handle); 99 | } 100 | 101 | #endif 102 | 103 | #else 104 | 105 | #if WASM_RT_INSTALL_SIGNAL_HANDLER 106 | static void os_signal_handler(int sig, siginfo_t* si, void* unused) { 107 | if (si->si_code == SEGV_ACCERR) { 108 | wasm_rt_trap(WASM_RT_TRAP_OOB); 109 | } else { 110 | wasm_rt_trap(WASM_RT_TRAP_EXHAUSTION); 111 | } 112 | } 113 | 114 | static void os_install_signal_handler(void) { 115 | struct sigaction sa; 116 | memset(&sa, '\0', sizeof(sa)); 117 | sa.sa_flags = SA_SIGINFO; 118 | #if WASM_RT_STACK_EXHAUSTION_HANDLER 119 | sa.sa_flags |= SA_ONSTACK; 120 | #endif 121 | sigemptyset(&sa.sa_mask); 122 | sa.sa_sigaction = os_signal_handler; 123 | 124 | /* Install SIGSEGV and SIGBUS handlers, since macOS seems to use SIGBUS. */ 125 | if (sigaction(SIGSEGV, &sa, NULL) != 0 || sigaction(SIGBUS, &sa, NULL) != 0) { 126 | perror("sigaction failed"); 127 | abort(); 128 | } 129 | } 130 | 131 | static void os_cleanup_signal_handler(void) { 132 | /* Undo what was done in os_install_signal_handler */ 133 | struct sigaction sa; 134 | memset(&sa, '\0', sizeof(sa)); 135 | sa.sa_handler = SIG_DFL; 136 | if (sigaction(SIGSEGV, &sa, NULL) != 0 || sigaction(SIGBUS, &sa, NULL)) { 137 | perror("sigaction failed"); 138 | abort(); 139 | } 140 | } 141 | #endif 142 | 143 | #if WASM_RT_STACK_EXHAUSTION_HANDLER 144 | static bool os_has_altstack_installed() { 145 | /* check for altstack already in place */ 146 | stack_t ss; 147 | if (sigaltstack(NULL, &ss) != 0) { 148 | perror("sigaltstack failed"); 149 | abort(); 150 | } 151 | 152 | return !(ss.ss_flags & SS_DISABLE); 153 | } 154 | 155 | /* These routines set up an altstack to handle SIGSEGV from stack overflow. */ 156 | static void os_allocate_and_install_altstack(void) { 157 | /* verify altstack not already allocated */ 158 | assert(!g_alt_stack && 159 | "wasm-rt error: tried to re-allocate thread-local alternate stack"); 160 | 161 | /* We could check and warn if an altstack is already installed, but some 162 | * sanitizers install their own altstack, so this warning would fire 163 | * spuriously and break the test outputs. */ 164 | 165 | /* allocate altstack */ 166 | g_alt_stack = malloc(SIGSTKSZ); 167 | if (g_alt_stack == NULL) { 168 | perror("malloc failed"); 169 | abort(); 170 | } 171 | 172 | /* install altstack */ 173 | stack_t ss; 174 | ss.ss_sp = g_alt_stack; 175 | ss.ss_flags = 0; 176 | ss.ss_size = SIGSTKSZ; 177 | if (sigaltstack(&ss, NULL) != 0) { 178 | perror("sigaltstack failed"); 179 | abort(); 180 | } 181 | } 182 | 183 | static void os_disable_and_deallocate_altstack(void) { 184 | /* in debug build, verify altstack allocated */ 185 | assert(g_alt_stack && 186 | "wasm-rt error: thread-local alternate stack not allocated"); 187 | 188 | /* verify altstack was still in place */ 189 | stack_t ss; 190 | if (sigaltstack(NULL, &ss) != 0) { 191 | perror("sigaltstack failed"); 192 | abort(); 193 | } 194 | 195 | if ((!g_alt_stack) || (ss.ss_flags & SS_DISABLE) || 196 | (ss.ss_sp != g_alt_stack) || (ss.ss_size != SIGSTKSZ)) { 197 | DEBUG_PRINTF( 198 | "wasm-rt warning: alternate stack was modified unexpectedly\n"); 199 | return; 200 | } 201 | 202 | /* disable and free */ 203 | ss.ss_flags = SS_DISABLE; 204 | if (sigaltstack(&ss, NULL) != 0) { 205 | perror("sigaltstack failed"); 206 | abort(); 207 | } 208 | assert(!os_has_altstack_installed()); 209 | free(g_alt_stack); 210 | } 211 | #endif 212 | 213 | #endif 214 | 215 | void wasm_rt_init(void) { 216 | wasm_rt_init_thread(); 217 | #if WASM_RT_INSTALL_SIGNAL_HANDLER 218 | if (!g_signal_handler_installed) { 219 | g_signal_handler_installed = true; 220 | os_install_signal_handler(); 221 | } 222 | #endif 223 | assert(wasm_rt_is_initialized()); 224 | } 225 | 226 | bool wasm_rt_is_initialized(void) { 227 | #if WASM_RT_STACK_EXHAUSTION_HANDLER 228 | if (!os_has_altstack_installed()) { 229 | return false; 230 | } 231 | #endif 232 | #if WASM_RT_INSTALL_SIGNAL_HANDLER 233 | return g_signal_handler_installed; 234 | #else 235 | return true; 236 | #endif 237 | } 238 | 239 | void wasm_rt_free(void) { 240 | assert(wasm_rt_is_initialized()); 241 | #if WASM_RT_INSTALL_SIGNAL_HANDLER 242 | os_cleanup_signal_handler(); 243 | g_signal_handler_installed = false; 244 | #endif 245 | wasm_rt_free_thread(); 246 | } 247 | 248 | void wasm_rt_init_thread(void) { 249 | #if WASM_RT_STACK_EXHAUSTION_HANDLER 250 | os_allocate_and_install_altstack(); 251 | #endif 252 | } 253 | 254 | void wasm_rt_free_thread(void) { 255 | #if WASM_RT_STACK_EXHAUSTION_HANDLER 256 | os_disable_and_deallocate_altstack(); 257 | #endif 258 | } 259 | 260 | // Include table operations for funcref 261 | #define WASM_RT_TABLE_OPS_FUNCREF 262 | #include "wasm-rt-impl-tableops.inc" 263 | #undef WASM_RT_TABLE_OPS_FUNCREF 264 | 265 | // Include table operations for externref 266 | #define WASM_RT_TABLE_OPS_EXTERNREF 267 | #include "wasm-rt-impl-tableops.inc" 268 | #undef WASM_RT_TABLE_OPS_EXTERNREF 269 | 270 | const char* wasm_rt_strerror(wasm_rt_trap_t trap) { 271 | switch (trap) { 272 | case WASM_RT_TRAP_NONE: 273 | return "No error"; 274 | case WASM_RT_TRAP_OOB: 275 | #if WASM_RT_MERGED_OOB_AND_EXHAUSTION_TRAPS 276 | return "Out-of-bounds access in linear memory or a table, or call stack " 277 | "exhausted"; 278 | #else 279 | return "Out-of-bounds access in linear memory or a table"; 280 | case WASM_RT_TRAP_EXHAUSTION: 281 | return "Call stack exhausted"; 282 | #endif 283 | case WASM_RT_TRAP_INT_OVERFLOW: 284 | return "Integer overflow on divide or truncation"; 285 | case WASM_RT_TRAP_DIV_BY_ZERO: 286 | return "Integer divide by zero"; 287 | case WASM_RT_TRAP_INVALID_CONVERSION: 288 | return "Conversion from NaN to integer"; 289 | case WASM_RT_TRAP_UNREACHABLE: 290 | return "Unreachable instruction executed"; 291 | case WASM_RT_TRAP_CALL_INDIRECT: 292 | return "Invalid call_indirect or return_call_indirect"; 293 | case WASM_RT_TRAP_UNCAUGHT_EXCEPTION: 294 | return "Uncaught exception"; 295 | case WASM_RT_TRAP_UNALIGNED: 296 | return "Unaligned atomic memory access"; 297 | } 298 | return "invalid trap code"; 299 | } 300 | -------------------------------------------------------------------------------- /apps/coremark/core_portme.c: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2018 Embedded Microprocessor Benchmark Consortium (EEMBC) 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | 16 | Original Author: Shay Gal-on 17 | */ 18 | 19 | #include "coremark.h" 20 | #include "core_portme.h" 21 | 22 | #if VALIDATION_RUN 23 | volatile ee_s32 seed1_volatile = 0x3415; 24 | volatile ee_s32 seed2_volatile = 0x3415; 25 | volatile ee_s32 seed3_volatile = 0x66; 26 | #endif 27 | #if PERFORMANCE_RUN 28 | volatile ee_s32 seed1_volatile = 0x0; 29 | volatile ee_s32 seed2_volatile = 0x0; 30 | volatile ee_s32 seed3_volatile = 0x66; 31 | #endif 32 | #if PROFILE_RUN 33 | volatile ee_s32 seed1_volatile = 0x8; 34 | volatile ee_s32 seed2_volatile = 0x8; 35 | volatile ee_s32 seed3_volatile = 0x8; 36 | #endif 37 | volatile ee_s32 seed4_volatile = ITERATIONS; 38 | volatile ee_s32 seed5_volatile = 0; 39 | /* Porting : Timing functions 40 | How to capture time and convert to seconds must be ported to whatever is 41 | supported by the platform. e.g. Read value from on board RTC, read value from 42 | cpu clock cycles performance counter etc. Sample implementation for standard 43 | time.h and windows.h definitions included. 44 | */ 45 | /* Define : TIMER_RES_DIVIDER 46 | Divider to trade off timer resolution and total time that can be 47 | measured. 48 | 49 | Use lower values to increase resolution, but make sure that overflow 50 | does not occur. If there are issues with the return value overflowing, 51 | increase this value. 52 | */ 53 | #define NSECS_PER_SEC 1000.0 54 | #define GETMYTIME(_t) (*_t = wiring_millis()) 55 | #define MYTIMEDIFF(fin, ini) ((fin) - (ini)) 56 | #define TIMER_RES_DIVIDER 1 57 | #define SAMPLE_TIME_IMPLEMENTATION 1 58 | #define EE_TICKS_PER_SEC (NSECS_PER_SEC / TIMER_RES_DIVIDER) 59 | 60 | 61 | void * __attribute__((weak)) memset(void * dest, int c, size_t n) 62 | { 63 | unsigned char *s = dest; 64 | size_t k; 65 | 66 | /* Fill head and tail with minimal branching. Each 67 | * conditional ensures that all the subsequently used 68 | * offsets are well-defined and in the dest region. */ 69 | 70 | if (!n) return dest; 71 | s[0] = s[n-1] = c; 72 | if (n <= 2) return dest; 73 | s[1] = s[n-2] = c; 74 | s[2] = s[n-3] = c; 75 | if (n <= 6) return dest; 76 | s[3] = s[n-4] = c; 77 | if (n <= 8) return dest; 78 | 79 | /* Advance pointer to align it at a 4-byte boundary, 80 | * and truncate n to a multiple of 4. The previous code 81 | * already took care of any head/tail that get cut off 82 | * by the alignment. */ 83 | 84 | k = -(uintptr_t)s & 3; 85 | s += k; 86 | n -= k; 87 | n &= -4; 88 | n /= 4; 89 | 90 | uint32_t *ws = (uint32_t *)s; 91 | uint32_t wc = c & 0xFF; 92 | wc |= ((wc << 8) | (wc << 16) | (wc << 24)); 93 | 94 | /* Pure C fallback with no aliasing violations. */ 95 | for (; n; n--, ws++) *ws = wc; 96 | 97 | return dest; 98 | } 99 | 100 | /** Define Host specific (POSIX), or target specific global time variables. */ 101 | static CORETIMETYPE start_time_val, stop_time_val; 102 | 103 | /* Function : start_time 104 | This function will be called right before starting the timed portion of 105 | the benchmark. 106 | 107 | Implementation may be capturing a system timer (as implemented in the 108 | example code) or zeroing some system parameters - e.g. setting the cpu clocks 109 | cycles to 0. 110 | */ 111 | void 112 | start_time(void) 113 | { 114 | GETMYTIME(&start_time_val); 115 | } 116 | /* Function : stop_time 117 | This function will be called right after ending the timed portion of the 118 | benchmark. 119 | 120 | Implementation may be capturing a system timer (as implemented in the 121 | example code) or other system parameters - e.g. reading the current value of 122 | cpu cycles counter. 123 | */ 124 | void 125 | stop_time(void) 126 | { 127 | GETMYTIME(&stop_time_val); 128 | } 129 | /* Function : get_time 130 | Return an abstract "ticks" number that signifies time on the system. 131 | 132 | Actual value returned may be cpu cycles, milliseconds or any other 133 | value, as long as it can be converted to seconds by . This 134 | methodology is taken to accomodate any hardware or simulated platform. The 135 | sample implementation returns millisecs by default, and the resolution is 136 | controlled by 137 | */ 138 | CORE_TICKS 139 | get_time(void) 140 | { 141 | CORE_TICKS elapsed 142 | = (CORE_TICKS)(MYTIMEDIFF(stop_time_val, start_time_val)); 143 | return elapsed; 144 | } 145 | /* Function : time_in_secs 146 | Convert the value returned by get_time to seconds. 147 | 148 | The type is used to accomodate systems with no support for 149 | floating point. Default implementation implemented by the EE_TICKS_PER_SEC 150 | macro above. 151 | */ 152 | secs_ret 153 | time_in_secs(CORE_TICKS ticks) 154 | { 155 | secs_ret retval = ((secs_ret)ticks) / (secs_ret)EE_TICKS_PER_SEC; 156 | return retval; 157 | } 158 | 159 | ee_u32 default_num_contexts = 1; 160 | 161 | /* Function : portable_init 162 | Target specific initialization code 163 | Test for some common mistakes. 164 | */ 165 | void 166 | portable_init(core_portable *p, int *argc, char *argv[]) 167 | { 168 | if (sizeof(ee_ptr_int) != sizeof(ee_u8 *)) 169 | { 170 | ee_printf( 171 | "ERROR! Please define ee_ptr_int to a type that holds a " 172 | "pointer!\n"); 173 | } 174 | if (sizeof(ee_u32) != 4) 175 | { 176 | ee_printf("ERROR! Please define ee_u32 to a 32b unsigned type!\n"); 177 | } 178 | p->portable_id = 1; 179 | } 180 | /* Function : portable_fini 181 | Target specific final code 182 | */ 183 | void 184 | portable_fini(core_portable *p) 185 | { 186 | p->portable_id = 0; 187 | } 188 | 189 | 190 | 191 | 192 | 193 | char * ecvtbuf(double arg, int ndigits, int *decpt, int *sign, char *buf); 194 | char * fcvtbuf(double arg, int ndigits, int *decpt, int *sign, char *buf); 195 | static void ee_bufcpy(char *d, char *s, int count); 196 | 197 | void 198 | ee_bufcpy(char *pd, char *ps, int count) 199 | { 200 | char *pe = ps + count; 201 | while (ps != pe) 202 | *pd++ = *ps++; 203 | } 204 | 205 | size_t 206 | ee_strlen(const char *str) 207 | { 208 | const char *s; 209 | for (s = str; *s; ++s) { } 210 | return (s - str); 211 | } 212 | 213 | 214 | static void 215 | parse_float(double value, char *buffer, char fmt, int precision) 216 | { 217 | int decpt, sign, exp, pos; 218 | char *digits = NULL; 219 | char cvtbuf[80]; 220 | int capexp = 0; 221 | int magnitude; 222 | 223 | if (fmt == 'G' || fmt == 'E') 224 | { 225 | capexp = 1; 226 | fmt += 'a' - 'A'; 227 | } 228 | 229 | if (fmt == 'g') 230 | { 231 | digits = ecvtbuf(value, precision, &decpt, &sign, cvtbuf); 232 | magnitude = decpt - 1; 233 | if (magnitude < -4 || magnitude > precision - 1) 234 | { 235 | fmt = 'e'; 236 | precision -= 1; 237 | } 238 | else 239 | { 240 | fmt = 'f'; 241 | precision -= decpt; 242 | } 243 | } 244 | 245 | if (fmt == 'e') 246 | { 247 | digits = ecvtbuf(value, precision + 1, &decpt, &sign, cvtbuf); 248 | 249 | if (sign) 250 | *buffer++ = '-'; 251 | *buffer++ = *digits; 252 | if (precision > 0) 253 | *buffer++ = '.'; 254 | ee_bufcpy(buffer, digits + 1, precision); 255 | buffer += precision; 256 | *buffer++ = capexp ? 'E' : 'e'; 257 | 258 | if (decpt == 0) 259 | { 260 | if (value == 0.0) 261 | exp = 0; 262 | else 263 | exp = -1; 264 | } 265 | else 266 | exp = decpt - 1; 267 | 268 | if (exp < 0) 269 | { 270 | *buffer++ = '-'; 271 | exp = -exp; 272 | } 273 | else 274 | *buffer++ = '+'; 275 | 276 | buffer[2] = (exp % 10) + '0'; 277 | exp = exp / 10; 278 | buffer[1] = (exp % 10) + '0'; 279 | exp = exp / 10; 280 | buffer[0] = (exp % 10) + '0'; 281 | buffer += 3; 282 | } 283 | else if (fmt == 'f') 284 | { 285 | digits = fcvtbuf(value, precision, &decpt, &sign, cvtbuf); 286 | if (sign) 287 | *buffer++ = '-'; 288 | if (*digits) 289 | { 290 | if (decpt <= 0) 291 | { 292 | *buffer++ = '0'; 293 | *buffer++ = '.'; 294 | for (pos = 0; pos < -decpt; pos++) 295 | *buffer++ = '0'; 296 | while (*digits) 297 | *buffer++ = *digits++; 298 | } 299 | else 300 | { 301 | pos = 0; 302 | while (*digits) 303 | { 304 | if (pos++ == decpt) 305 | *buffer++ = '.'; 306 | *buffer++ = *digits++; 307 | } 308 | } 309 | } 310 | else 311 | { 312 | *buffer++ = '0'; 313 | if (precision > 0) 314 | { 315 | *buffer++ = '.'; 316 | for (pos = 0; pos < precision; pos++) 317 | *buffer++ = '0'; 318 | } 319 | } 320 | } 321 | 322 | *buffer = '\0'; 323 | } 324 | 325 | 326 | static const char msg_running[] = "Running CoreMark 1.0...\n"; 327 | static const char msg_result[] = "Result: "; 328 | 329 | void wiring_setup(void) { 330 | wiring_print(msg_running, sizeof(msg_running)-1); 331 | 332 | wiring_stopWdt(); 333 | float result = coremark_main(); 334 | 335 | char buff[32]; 336 | wiring_print(msg_result, sizeof(msg_result)-1); 337 | parse_float(result, buff, 'f', 3); 338 | wiring_print(buff, ee_strlen(buff)); 339 | wiring_print("\n", 1); 340 | } 341 | 342 | void wiring_loop(void) { 343 | wiring_delay(100); 344 | } 345 | -------------------------------------------------------------------------------- /apps/coremark/core_state.c: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2018 Embedded Microprocessor Benchmark Consortium (EEMBC) 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | 16 | Original Author: Shay Gal-on 17 | */ 18 | 19 | #include "coremark.h" 20 | /* local functions */ 21 | enum CORE_STATE core_state_transition(ee_u8 **instr, ee_u32 *transition_count); 22 | 23 | /* 24 | Topic: Description 25 | Simple state machines like this one are used in many embedded products. 26 | 27 | For more complex state machines, sometimes a state transition table 28 | implementation is used instead, trading speed of direct coding for ease of 29 | maintenance. 30 | 31 | Since the main goal of using a state machine in CoreMark is to excercise 32 | the switch/if behaviour, we are using a small moore machine. 33 | 34 | In particular, this machine tests type of string input, 35 | trying to determine whether the input is a number or something else. 36 | (see core_state.png). 37 | */ 38 | 39 | /* Function: core_bench_state 40 | Benchmark function 41 | 42 | Go over the input twice, once direct, and once after introducing some 43 | corruption. 44 | */ 45 | ee_u16 46 | core_bench_state(ee_u32 blksize, 47 | ee_u8 *memblock, 48 | ee_s16 seed1, 49 | ee_s16 seed2, 50 | ee_s16 step, 51 | ee_u16 crc) 52 | { 53 | ee_u32 final_counts[NUM_CORE_STATES]; 54 | ee_u32 track_counts[NUM_CORE_STATES]; 55 | ee_u8 *p = memblock; 56 | ee_u32 i; 57 | 58 | #if CORE_DEBUG 59 | ee_printf("State Bench: %d,%d,%d,%04x\n", seed1, seed2, step, crc); 60 | #endif 61 | for (i = 0; i < NUM_CORE_STATES; i++) 62 | { 63 | final_counts[i] = track_counts[i] = 0; 64 | } 65 | /* run the state machine over the input */ 66 | while (*p != 0) 67 | { 68 | enum CORE_STATE fstate = core_state_transition(&p, track_counts); 69 | final_counts[fstate]++; 70 | #if CORE_DEBUG 71 | ee_printf("%d,", fstate); 72 | } 73 | ee_printf("\n"); 74 | #else 75 | } 76 | #endif 77 | p = memblock; 78 | while (p < (memblock + blksize)) 79 | { /* insert some corruption */ 80 | if (*p != ',') 81 | *p ^= (ee_u8)seed1; 82 | p += step; 83 | } 84 | p = memblock; 85 | /* run the state machine over the input again */ 86 | while (*p != 0) 87 | { 88 | enum CORE_STATE fstate = core_state_transition(&p, track_counts); 89 | final_counts[fstate]++; 90 | #if CORE_DEBUG 91 | ee_printf("%d,", fstate); 92 | } 93 | ee_printf("\n"); 94 | #else 95 | } 96 | #endif 97 | p = memblock; 98 | while (p < (memblock + blksize)) 99 | { /* undo corruption is seed1 and seed2 are equal */ 100 | if (*p != ',') 101 | *p ^= (ee_u8)seed2; 102 | p += step; 103 | } 104 | /* end timing */ 105 | for (i = 0; i < NUM_CORE_STATES; i++) 106 | { 107 | crc = crcu32(final_counts[i], crc); 108 | crc = crcu32(track_counts[i], crc); 109 | } 110 | return crc; 111 | } 112 | 113 | /* Default initialization patterns */ 114 | static ee_u8 *intpat[4] 115 | = { (ee_u8 *)"5012", (ee_u8 *)"1234", (ee_u8 *)"-874", (ee_u8 *)"+122" }; 116 | static ee_u8 *floatpat[4] = { (ee_u8 *)"35.54400", 117 | (ee_u8 *)".1234500", 118 | (ee_u8 *)"-110.700", 119 | (ee_u8 *)"+0.64400" }; 120 | static ee_u8 *scipat[4] = { (ee_u8 *)"5.500e+3", 121 | (ee_u8 *)"-.123e-2", 122 | (ee_u8 *)"-87e+832", 123 | (ee_u8 *)"+0.6e-12" }; 124 | static ee_u8 *errpat[4] = { (ee_u8 *)"T0.3e-1F", 125 | (ee_u8 *)"-T.T++Tq", 126 | (ee_u8 *)"1T3.4e4z", 127 | (ee_u8 *)"34.0e-T^" }; 128 | 129 | /* Function: core_init_state 130 | Initialize the input data for the state machine. 131 | 132 | Populate the input with several predetermined strings, interspersed. 133 | Actual patterns chosen depend on the seed parameter. 134 | 135 | Note: 136 | The seed parameter MUST be supplied from a source that cannot be 137 | determined at compile time 138 | */ 139 | void 140 | core_init_state(ee_u32 size, ee_s16 seed, ee_u8 *p) 141 | { 142 | ee_u32 total = 0, next = 0, i; 143 | ee_u8 *buf = 0; 144 | #if CORE_DEBUG 145 | ee_u8 *start = p; 146 | ee_printf("State: %d,%d\n", size, seed); 147 | #endif 148 | size--; 149 | next = 0; 150 | while ((total + next + 1) < size) 151 | { 152 | if (next > 0) 153 | { 154 | for (i = 0; i < next; i++) 155 | *(p + total + i) = buf[i]; 156 | *(p + total + i) = ','; 157 | total += next + 1; 158 | } 159 | seed++; 160 | switch (seed & 0x7) 161 | { 162 | case 0: /* int */ 163 | case 1: /* int */ 164 | case 2: /* int */ 165 | buf = intpat[(seed >> 3) & 0x3]; 166 | next = 4; 167 | break; 168 | case 3: /* float */ 169 | case 4: /* float */ 170 | buf = floatpat[(seed >> 3) & 0x3]; 171 | next = 8; 172 | break; 173 | case 5: /* scientific */ 174 | case 6: /* scientific */ 175 | buf = scipat[(seed >> 3) & 0x3]; 176 | next = 8; 177 | break; 178 | case 7: /* invalid */ 179 | buf = errpat[(seed >> 3) & 0x3]; 180 | next = 8; 181 | break; 182 | default: /* Never happen, just to make some compilers happy */ 183 | break; 184 | } 185 | } 186 | size++; 187 | while (total < size) 188 | { /* fill the rest with 0 */ 189 | *(p + total) = 0; 190 | total++; 191 | } 192 | #if CORE_DEBUG 193 | ee_printf("State Input: %s\n", start); 194 | #endif 195 | } 196 | 197 | static ee_u8 198 | ee_isdigit(ee_u8 c) 199 | { 200 | ee_u8 retval; 201 | retval = ((c >= '0') & (c <= '9')) ? 1 : 0; 202 | return retval; 203 | } 204 | 205 | /* Function: core_state_transition 206 | Actual state machine. 207 | 208 | The state machine will continue scanning until either: 209 | 1 - an invalid input is detcted. 210 | 2 - a valid number has been detected. 211 | 212 | The input pointer is updated to point to the end of the token, and the 213 | end state is returned (either specific format determined or invalid). 214 | */ 215 | 216 | enum CORE_STATE 217 | core_state_transition(ee_u8 **instr, ee_u32 *transition_count) 218 | { 219 | ee_u8 * str = *instr; 220 | ee_u8 NEXT_SYMBOL; 221 | enum CORE_STATE state = CORE_START; 222 | for (; *str && state != CORE_INVALID; str++) 223 | { 224 | NEXT_SYMBOL = *str; 225 | if (NEXT_SYMBOL == ',') /* end of this input */ 226 | { 227 | str++; 228 | break; 229 | } 230 | switch (state) 231 | { 232 | case CORE_START: 233 | if (ee_isdigit(NEXT_SYMBOL)) 234 | { 235 | state = CORE_INT; 236 | } 237 | else if (NEXT_SYMBOL == '+' || NEXT_SYMBOL == '-') 238 | { 239 | state = CORE_S1; 240 | } 241 | else if (NEXT_SYMBOL == '.') 242 | { 243 | state = CORE_FLOAT; 244 | } 245 | else 246 | { 247 | state = CORE_INVALID; 248 | transition_count[CORE_INVALID]++; 249 | } 250 | transition_count[CORE_START]++; 251 | break; 252 | case CORE_S1: 253 | if (ee_isdigit(NEXT_SYMBOL)) 254 | { 255 | state = CORE_INT; 256 | transition_count[CORE_S1]++; 257 | } 258 | else if (NEXT_SYMBOL == '.') 259 | { 260 | state = CORE_FLOAT; 261 | transition_count[CORE_S1]++; 262 | } 263 | else 264 | { 265 | state = CORE_INVALID; 266 | transition_count[CORE_S1]++; 267 | } 268 | break; 269 | case CORE_INT: 270 | if (NEXT_SYMBOL == '.') 271 | { 272 | state = CORE_FLOAT; 273 | transition_count[CORE_INT]++; 274 | } 275 | else if (!ee_isdigit(NEXT_SYMBOL)) 276 | { 277 | state = CORE_INVALID; 278 | transition_count[CORE_INT]++; 279 | } 280 | break; 281 | case CORE_FLOAT: 282 | if (NEXT_SYMBOL == 'E' || NEXT_SYMBOL == 'e') 283 | { 284 | state = CORE_S2; 285 | transition_count[CORE_FLOAT]++; 286 | } 287 | else if (!ee_isdigit(NEXT_SYMBOL)) 288 | { 289 | state = CORE_INVALID; 290 | transition_count[CORE_FLOAT]++; 291 | } 292 | break; 293 | case CORE_S2: 294 | if (NEXT_SYMBOL == '+' || NEXT_SYMBOL == '-') 295 | { 296 | state = CORE_EXPONENT; 297 | transition_count[CORE_S2]++; 298 | } 299 | else 300 | { 301 | state = CORE_INVALID; 302 | transition_count[CORE_S2]++; 303 | } 304 | break; 305 | case CORE_EXPONENT: 306 | if (ee_isdigit(NEXT_SYMBOL)) 307 | { 308 | state = CORE_SCIENTIFIC; 309 | transition_count[CORE_EXPONENT]++; 310 | } 311 | else 312 | { 313 | state = CORE_INVALID; 314 | transition_count[CORE_EXPONENT]++; 315 | } 316 | break; 317 | case CORE_SCIENTIFIC: 318 | if (!ee_isdigit(NEXT_SYMBOL)) 319 | { 320 | state = CORE_INVALID; 321 | transition_count[CORE_INVALID]++; 322 | } 323 | break; 324 | default: 325 | break; 326 | } 327 | } 328 | *instr = str; 329 | return state; 330 | } 331 | -------------------------------------------------------------------------------- /apps/coremark/core_matrix.c: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2018 Embedded Microprocessor Benchmark Consortium (EEMBC) 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | 16 | Original Author: Shay Gal-on 17 | */ 18 | 19 | #include "coremark.h" 20 | /* 21 | Topic: Description 22 | Matrix manipulation benchmark 23 | 24 | This very simple algorithm forms the basis of many more complex 25 | algorithms. 26 | 27 | The tight inner loop is the focus of many optimizations (compiler as 28 | well as hardware based) and is thus relevant for embedded processing. 29 | 30 | The total available data space will be divided to 3 parts: 31 | NxN Matrix A - initialized with small values (upper 3/4 of the bits all 32 | zero). NxN Matrix B - initialized with medium values (upper half of the bits all 33 | zero). NxN Matrix C - used for the result. 34 | 35 | The actual values for A and B must be derived based on input that is not 36 | available at compile time. 37 | */ 38 | ee_s16 matrix_test(ee_u32 N, MATRES *C, MATDAT *A, MATDAT *B, MATDAT val); 39 | ee_s16 matrix_sum(ee_u32 N, MATRES *C, MATDAT clipval); 40 | void matrix_mul_const(ee_u32 N, MATRES *C, MATDAT *A, MATDAT val); 41 | void matrix_mul_vect(ee_u32 N, MATRES *C, MATDAT *A, MATDAT *B); 42 | void matrix_mul_matrix(ee_u32 N, MATRES *C, MATDAT *A, MATDAT *B); 43 | void matrix_mul_matrix_bitextract(ee_u32 N, MATRES *C, MATDAT *A, MATDAT *B); 44 | void matrix_add_const(ee_u32 N, MATDAT *A, MATDAT val); 45 | 46 | #define matrix_test_next(x) (x + 1) 47 | #define matrix_clip(x, y) ((y) ? (x)&0x0ff : (x)&0x0ffff) 48 | #define matrix_big(x) (0xf000 | (x)) 49 | #define bit_extract(x, from, to) (((x) >> (from)) & (~(0xffffffff << (to)))) 50 | 51 | #if CORE_DEBUG 52 | void 53 | printmat(MATDAT *A, ee_u32 N, char *name) 54 | { 55 | ee_u32 i, j; 56 | ee_printf("Matrix %s [%dx%d]:\n", name, N, N); 57 | for (i = 0; i < N; i++) 58 | { 59 | for (j = 0; j < N; j++) 60 | { 61 | if (j != 0) 62 | ee_printf(","); 63 | ee_printf("%d", A[i * N + j]); 64 | } 65 | ee_printf("\n"); 66 | } 67 | } 68 | void 69 | printmatC(MATRES *C, ee_u32 N, char *name) 70 | { 71 | ee_u32 i, j; 72 | ee_printf("Matrix %s [%dx%d]:\n", name, N, N); 73 | for (i = 0; i < N; i++) 74 | { 75 | for (j = 0; j < N; j++) 76 | { 77 | if (j != 0) 78 | ee_printf(","); 79 | ee_printf("%d", C[i * N + j]); 80 | } 81 | ee_printf("\n"); 82 | } 83 | } 84 | #endif 85 | /* Function: core_bench_matrix 86 | Benchmark function 87 | 88 | Iterate N times, 89 | changing the matrix values slightly by a constant amount each time. 90 | */ 91 | ee_u16 92 | core_bench_matrix(mat_params *p, ee_s16 seed, ee_u16 crc) 93 | { 94 | ee_u32 N = p->N; 95 | MATRES *C = p->C; 96 | MATDAT *A = p->A; 97 | MATDAT *B = p->B; 98 | MATDAT val = (MATDAT)seed; 99 | 100 | crc = crc16(matrix_test(N, C, A, B, val), crc); 101 | 102 | return crc; 103 | } 104 | 105 | /* Function: matrix_test 106 | Perform matrix manipulation. 107 | 108 | Parameters: 109 | N - Dimensions of the matrix. 110 | C - memory for result matrix. 111 | A - input matrix 112 | B - operator matrix (not changed during operations) 113 | 114 | Returns: 115 | A CRC value that captures all results calculated in the function. 116 | In particular, crc of the value calculated on the result matrix 117 | after each step by . 118 | 119 | Operation: 120 | 121 | 1 - Add a constant value to all elements of a matrix. 122 | 2 - Multiply a matrix by a constant. 123 | 3 - Multiply a matrix by a vector. 124 | 4 - Multiply a matrix by a matrix. 125 | 5 - Add a constant value to all elements of a matrix. 126 | 127 | After the last step, matrix A is back to original contents. 128 | */ 129 | ee_s16 130 | matrix_test(ee_u32 N, MATRES *C, MATDAT *A, MATDAT *B, MATDAT val) 131 | { 132 | ee_u16 crc = 0; 133 | MATDAT clipval = matrix_big(val); 134 | 135 | matrix_add_const(N, A, val); /* make sure data changes */ 136 | #if CORE_DEBUG 137 | printmat(A, N, "matrix_add_const"); 138 | #endif 139 | matrix_mul_const(N, C, A, val); 140 | crc = crc16(matrix_sum(N, C, clipval), crc); 141 | #if CORE_DEBUG 142 | printmatC(C, N, "matrix_mul_const"); 143 | #endif 144 | matrix_mul_vect(N, C, A, B); 145 | crc = crc16(matrix_sum(N, C, clipval), crc); 146 | #if CORE_DEBUG 147 | printmatC(C, N, "matrix_mul_vect"); 148 | #endif 149 | matrix_mul_matrix(N, C, A, B); 150 | crc = crc16(matrix_sum(N, C, clipval), crc); 151 | #if CORE_DEBUG 152 | printmatC(C, N, "matrix_mul_matrix"); 153 | #endif 154 | matrix_mul_matrix_bitextract(N, C, A, B); 155 | crc = crc16(matrix_sum(N, C, clipval), crc); 156 | #if CORE_DEBUG 157 | printmatC(C, N, "matrix_mul_matrix_bitextract"); 158 | #endif 159 | 160 | matrix_add_const(N, A, -val); /* return matrix to initial value */ 161 | return crc; 162 | } 163 | 164 | /* Function : matrix_init 165 | Initialize the memory block for matrix benchmarking. 166 | 167 | Parameters: 168 | blksize - Size of memory to be initialized. 169 | memblk - Pointer to memory block. 170 | seed - Actual values chosen depend on the seed parameter. 171 | p - pointers to containing initialized matrixes. 172 | 173 | Returns: 174 | Matrix dimensions. 175 | 176 | Note: 177 | The seed parameter MUST be supplied from a source that cannot be 178 | determined at compile time 179 | */ 180 | ee_u32 181 | core_init_matrix(ee_u32 blksize, void *memblk, ee_s32 seed, mat_params *p) 182 | { 183 | ee_u32 N = 0; 184 | MATDAT *A; 185 | MATDAT *B; 186 | ee_s32 order = 1; 187 | MATDAT val; 188 | ee_u32 i = 0, j = 0; 189 | if (seed == 0) 190 | seed = 1; 191 | while (j < blksize) 192 | { 193 | i++; 194 | j = i * i * 2 * 4; 195 | } 196 | N = i - 1; 197 | A = (MATDAT *)align_mem(memblk); 198 | B = A + N * N; 199 | 200 | for (i = 0; i < N; i++) 201 | { 202 | for (j = 0; j < N; j++) 203 | { 204 | seed = ((order * seed) % 65536); 205 | val = (seed + order); 206 | val = matrix_clip(val, 0); 207 | B[i * N + j] = val; 208 | val = (val + order); 209 | val = matrix_clip(val, 1); 210 | A[i * N + j] = val; 211 | order++; 212 | } 213 | } 214 | 215 | p->A = A; 216 | p->B = B; 217 | p->C = (MATRES *)align_mem(B + N * N); 218 | p->N = N; 219 | #if CORE_DEBUG 220 | printmat(A, N, "A"); 221 | printmat(B, N, "B"); 222 | #endif 223 | return N; 224 | } 225 | 226 | /* Function: matrix_sum 227 | Calculate a function that depends on the values of elements in the 228 | matrix. 229 | 230 | For each element, accumulate into a temporary variable. 231 | 232 | As long as this value is under the parameter clipval, 233 | add 1 to the result if the element is bigger then the previous. 234 | 235 | Otherwise, reset the accumulator and add 10 to the result. 236 | */ 237 | ee_s16 238 | matrix_sum(ee_u32 N, MATRES *C, MATDAT clipval) 239 | { 240 | MATRES tmp = 0, prev = 0, cur = 0; 241 | ee_s16 ret = 0; 242 | ee_u32 i, j; 243 | for (i = 0; i < N; i++) 244 | { 245 | for (j = 0; j < N; j++) 246 | { 247 | cur = C[i * N + j]; 248 | tmp += cur; 249 | if (tmp > clipval) 250 | { 251 | ret += 10; 252 | tmp = 0; 253 | } 254 | else 255 | { 256 | ret += (cur > prev) ? 1 : 0; 257 | } 258 | prev = cur; 259 | } 260 | } 261 | return ret; 262 | } 263 | 264 | /* Function: matrix_mul_const 265 | Multiply a matrix by a constant. 266 | This could be used as a scaler for instance. 267 | */ 268 | void 269 | matrix_mul_const(ee_u32 N, MATRES *C, MATDAT *A, MATDAT val) 270 | { 271 | ee_u32 i, j; 272 | for (i = 0; i < N; i++) 273 | { 274 | for (j = 0; j < N; j++) 275 | { 276 | C[i * N + j] = (MATRES)A[i * N + j] * (MATRES)val; 277 | } 278 | } 279 | } 280 | 281 | /* Function: matrix_add_const 282 | Add a constant value to all elements of a matrix. 283 | */ 284 | void 285 | matrix_add_const(ee_u32 N, MATDAT *A, MATDAT val) 286 | { 287 | ee_u32 i, j; 288 | for (i = 0; i < N; i++) 289 | { 290 | for (j = 0; j < N; j++) 291 | { 292 | A[i * N + j] += val; 293 | } 294 | } 295 | } 296 | 297 | /* Function: matrix_mul_vect 298 | Multiply a matrix by a vector. 299 | This is common in many simple filters (e.g. fir where a vector of 300 | coefficients is applied to the matrix.) 301 | */ 302 | void 303 | matrix_mul_vect(ee_u32 N, MATRES *C, MATDAT *A, MATDAT *B) 304 | { 305 | ee_u32 i, j; 306 | for (i = 0; i < N; i++) 307 | { 308 | C[i] = 0; 309 | for (j = 0; j < N; j++) 310 | { 311 | C[i] += (MATRES)A[i * N + j] * (MATRES)B[j]; 312 | } 313 | } 314 | } 315 | 316 | /* Function: matrix_mul_matrix 317 | Multiply a matrix by a matrix. 318 | Basic code is used in many algorithms, mostly with minor changes such as 319 | scaling. 320 | */ 321 | void 322 | matrix_mul_matrix(ee_u32 N, MATRES *C, MATDAT *A, MATDAT *B) 323 | { 324 | ee_u32 i, j, k; 325 | for (i = 0; i < N; i++) 326 | { 327 | for (j = 0; j < N; j++) 328 | { 329 | C[i * N + j] = 0; 330 | for (k = 0; k < N; k++) 331 | { 332 | C[i * N + j] += (MATRES)A[i * N + k] * (MATRES)B[k * N + j]; 333 | } 334 | } 335 | } 336 | } 337 | 338 | /* Function: matrix_mul_matrix_bitextract 339 | Multiply a matrix by a matrix, and extract some bits from the result. 340 | Basic code is used in many algorithms, mostly with minor changes such as 341 | scaling. 342 | */ 343 | void 344 | matrix_mul_matrix_bitextract(ee_u32 N, MATRES *C, MATDAT *A, MATDAT *B) 345 | { 346 | ee_u32 i, j, k; 347 | for (i = 0; i < N; i++) 348 | { 349 | for (j = 0; j < N; j++) 350 | { 351 | C[i * N + j] = 0; 352 | for (k = 0; k < N; k++) 353 | { 354 | MATRES tmp = (MATRES)A[i * N + k] * (MATRES)B[k * N + j]; 355 | C[i * N + j] += bit_extract(tmp, 2, 4) * bit_extract(tmp, 5, 7); 356 | } 357 | } 358 | } 359 | } 360 | -------------------------------------------------------------------------------- /apps/coremark/core_main.c: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2018 Embedded Microprocessor Benchmark Consortium (EEMBC) 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | 16 | Original Author: Shay Gal-on 17 | */ 18 | 19 | /* File: core_main.c 20 | This file contains the framework to acquire a block of memory, seed 21 | initial parameters, tun t he benchmark and report the results. 22 | */ 23 | #include "coremark.h" 24 | 25 | /* Function: iterate 26 | Run the benchmark for a specified number of iterations. 27 | 28 | Operation: 29 | For each type of benchmarked algorithm: 30 | a - Initialize the data block for the algorithm. 31 | b - Execute the algorithm N times. 32 | 33 | Returns: 34 | NULL. 35 | */ 36 | static ee_u16 list_known_crc[] = { (ee_u16)0xd4b0, 37 | (ee_u16)0x3340, 38 | (ee_u16)0x6a79, 39 | (ee_u16)0xe714, 40 | (ee_u16)0xe3c1 }; 41 | static ee_u16 matrix_known_crc[] = { (ee_u16)0xbe52, 42 | (ee_u16)0x1199, 43 | (ee_u16)0x5608, 44 | (ee_u16)0x1fd7, 45 | (ee_u16)0x0747 }; 46 | static ee_u16 state_known_crc[] = { (ee_u16)0x5e47, 47 | (ee_u16)0x39bf, 48 | (ee_u16)0xe5a4, 49 | (ee_u16)0x8e3a, 50 | (ee_u16)0x8d84 }; 51 | void * 52 | iterate(void *pres) 53 | { 54 | ee_u32 i; 55 | ee_u16 crc; 56 | core_results *res = (core_results *)pres; 57 | ee_u32 iterations = res->iterations; 58 | res->crc = 0; 59 | res->crclist = 0; 60 | res->crcmatrix = 0; 61 | res->crcstate = 0; 62 | 63 | for (i = 0; i < iterations; i++) 64 | { 65 | crc = core_bench_list(res, 1); 66 | res->crc = crcu16(crc, res->crc); 67 | crc = core_bench_list(res, -1); 68 | res->crc = crcu16(crc, res->crc); 69 | if (i == 0) 70 | res->crclist = res->crc; 71 | } 72 | return NULL; 73 | } 74 | 75 | #if (SEED_METHOD == SEED_ARG) 76 | ee_s32 get_seed_args(int i, int argc, char *argv[]); 77 | #define get_seed(x) (ee_s16) get_seed_args(x, argc, argv) 78 | #define get_seed_32(x) get_seed_args(x, argc, argv) 79 | #else /* via function or volatile */ 80 | ee_s32 get_seed_32(int i); 81 | #define get_seed(x) (ee_s16) get_seed_32(x) 82 | #endif 83 | 84 | #if (MEM_METHOD == MEM_STATIC) 85 | ee_u8 static_memblk[TOTAL_DATA_SIZE]; 86 | #endif 87 | char *mem_name[3] = { "Static", "Heap", "Stack" }; 88 | /* Function: main 89 | Main entry routine for the benchmark. 90 | This function is responsible for the following steps: 91 | 92 | 1 - Initialize input seeds from a source that cannot be determined at 93 | compile time. 2 - Initialize memory block for use. 3 - Run and time the 94 | benchmark. 4 - Report results, testing the validity of the output if the 95 | seeds are known. 96 | 97 | Arguments: 98 | 1 - first seed : Any value 99 | 2 - second seed : Must be identical to first for iterations to be 100 | identical 3 - third seed : Any value, should be at least an order of 101 | magnitude less then the input size, but bigger then 32. 4 - Iterations : 102 | Special, if set to 0, iterations will be automatically determined such that 103 | the benchmark will run between 10 to 100 secs 104 | 105 | */ 106 | 107 | #if MAIN_HAS_NOARGC 108 | MAIN_RETURN_TYPE 109 | main(void) 110 | { 111 | int argc = 0; 112 | char *argv[1]; 113 | #else 114 | MAIN_RETURN_TYPE 115 | main(int argc, char *argv[]) 116 | { 117 | #endif 118 | ee_u16 i, j = 0, num_algorithms = 0; 119 | ee_s16 known_id = -1, total_errors = 0; 120 | ee_u16 seedcrc = 0; 121 | CORE_TICKS total_time; 122 | core_results results[MULTITHREAD]; 123 | #if (MEM_METHOD == MEM_STACK) 124 | ee_u8 stack_memblock[TOTAL_DATA_SIZE * MULTITHREAD]; 125 | #endif 126 | /* first call any initializations needed */ 127 | portable_init(&(results[0].port), &argc, argv); 128 | /* First some checks to make sure benchmark will run ok */ 129 | if (sizeof(struct list_head_s) > 128) 130 | { 131 | ee_printf("list_head structure too big for comparable data!\n"); 132 | return MAIN_RETURN_VAL; 133 | } 134 | results[0].seed1 = get_seed(1); 135 | results[0].seed2 = get_seed(2); 136 | results[0].seed3 = get_seed(3); 137 | results[0].iterations = get_seed_32(4); 138 | #if CORE_DEBUG 139 | results[0].iterations = 1; 140 | #endif 141 | results[0].execs = get_seed_32(5); 142 | if (results[0].execs == 0) 143 | { /* if not supplied, execute all algorithms */ 144 | results[0].execs = ALL_ALGORITHMS_MASK; 145 | } 146 | /* put in some default values based on one seed only for easy testing */ 147 | if ((results[0].seed1 == 0) && (results[0].seed2 == 0) 148 | && (results[0].seed3 == 0)) 149 | { /* perfromance run */ 150 | results[0].seed1 = 0; 151 | results[0].seed2 = 0; 152 | results[0].seed3 = 0x66; 153 | } 154 | if ((results[0].seed1 == 1) && (results[0].seed2 == 0) 155 | && (results[0].seed3 == 0)) 156 | { /* validation run */ 157 | results[0].seed1 = 0x3415; 158 | results[0].seed2 = 0x3415; 159 | results[0].seed3 = 0x66; 160 | } 161 | #if (MEM_METHOD == MEM_STATIC) 162 | results[0].memblock[0] = (void *)static_memblk; 163 | results[0].size = TOTAL_DATA_SIZE; 164 | results[0].err = 0; 165 | #if (MULTITHREAD > 1) 166 | #error "Cannot use a static data area with multiple contexts!" 167 | #endif 168 | #elif (MEM_METHOD == MEM_MALLOC) 169 | for (i = 0; i < MULTITHREAD; i++) 170 | { 171 | ee_s32 malloc_override = get_seed(7); 172 | if (malloc_override != 0) 173 | results[i].size = malloc_override; 174 | else 175 | results[i].size = TOTAL_DATA_SIZE; 176 | results[i].memblock[0] = portable_malloc(results[i].size); 177 | results[i].seed1 = results[0].seed1; 178 | results[i].seed2 = results[0].seed2; 179 | results[i].seed3 = results[0].seed3; 180 | results[i].err = 0; 181 | results[i].execs = results[0].execs; 182 | } 183 | #elif (MEM_METHOD == MEM_STACK) 184 | for (i = 0; i < MULTITHREAD; i++) 185 | { 186 | results[i].memblock[0] = stack_memblock + i * TOTAL_DATA_SIZE; 187 | results[i].size = TOTAL_DATA_SIZE; 188 | results[i].seed1 = results[0].seed1; 189 | results[i].seed2 = results[0].seed2; 190 | results[i].seed3 = results[0].seed3; 191 | results[i].err = 0; 192 | results[i].execs = results[0].execs; 193 | } 194 | #else 195 | #error "Please define a way to initialize a memory block." 196 | #endif 197 | /* Data init */ 198 | /* Find out how space much we have based on number of algorithms */ 199 | for (i = 0; i < NUM_ALGORITHMS; i++) 200 | { 201 | if ((1 << (ee_u32)i) & results[0].execs) 202 | num_algorithms++; 203 | } 204 | for (i = 0; i < MULTITHREAD; i++) 205 | results[i].size = results[i].size / num_algorithms; 206 | /* Assign pointers */ 207 | for (i = 0; i < NUM_ALGORITHMS; i++) 208 | { 209 | ee_u32 ctx; 210 | if ((1 << (ee_u32)i) & results[0].execs) 211 | { 212 | for (ctx = 0; ctx < MULTITHREAD; ctx++) 213 | results[ctx].memblock[i + 1] 214 | = (char *)(results[ctx].memblock[0]) + results[0].size * j; 215 | j++; 216 | } 217 | } 218 | /* call inits */ 219 | for (i = 0; i < MULTITHREAD; i++) 220 | { 221 | if (results[i].execs & ID_LIST) 222 | { 223 | results[i].list = core_list_init( 224 | results[0].size, results[i].memblock[1], results[i].seed1); 225 | } 226 | if (results[i].execs & ID_MATRIX) 227 | { 228 | core_init_matrix(results[0].size, 229 | results[i].memblock[2], 230 | (ee_s32)results[i].seed1 231 | | (((ee_s32)results[i].seed2) << 16), 232 | &(results[i].mat)); 233 | } 234 | if (results[i].execs & ID_STATE) 235 | { 236 | core_init_state( 237 | results[0].size, results[i].seed1, results[i].memblock[3]); 238 | } 239 | } 240 | 241 | /* automatically determine number of iterations if not set */ 242 | if (results[0].iterations == 0) 243 | { 244 | secs_ret secs_passed = 0; 245 | ee_u32 divisor; 246 | results[0].iterations = 1; 247 | while (secs_passed < (secs_ret)1) 248 | { 249 | results[0].iterations *= 10; 250 | start_time(); 251 | iterate(&results[0]); 252 | stop_time(); 253 | secs_passed = time_in_secs(get_time()); 254 | } 255 | /* now we know it executes for at least 1 sec, set actual run time at 256 | * about 10 secs */ 257 | divisor = (ee_u32)secs_passed; 258 | if (divisor == 0) /* some machines cast float to int as 0 since this 259 | conversion is not defined by ANSI, but we know at 260 | least one second passed */ 261 | divisor = 1; 262 | results[0].iterations *= 1 + 10 / divisor; 263 | } 264 | /* perform actual benchmark */ 265 | start_time(); 266 | #if (MULTITHREAD > 1) 267 | if (default_num_contexts > MULTITHREAD) 268 | { 269 | default_num_contexts = MULTITHREAD; 270 | } 271 | for (i = 0; i < default_num_contexts; i++) 272 | { 273 | results[i].iterations = results[0].iterations; 274 | results[i].execs = results[0].execs; 275 | core_start_parallel(&results[i]); 276 | } 277 | for (i = 0; i < default_num_contexts; i++) 278 | { 279 | core_stop_parallel(&results[i]); 280 | } 281 | #else 282 | iterate(&results[0]); 283 | #endif 284 | stop_time(); 285 | total_time = get_time(); 286 | /* get a function of the input to report */ 287 | seedcrc = crc16(results[0].seed1, seedcrc); 288 | seedcrc = crc16(results[0].seed2, seedcrc); 289 | seedcrc = crc16(results[0].seed3, seedcrc); 290 | seedcrc = crc16(results[0].size, seedcrc); 291 | 292 | switch (seedcrc) 293 | { /* test known output for common seeds */ 294 | case 0x8a02: /* seed1=0, seed2=0, seed3=0x66, size 2000 per algorithm */ 295 | known_id = 0; 296 | ee_printf("6k performance run parameters for coremark.\n"); 297 | break; 298 | case 0x7b05: /* seed1=0x3415, seed2=0x3415, seed3=0x66, size 2000 per 299 | algorithm */ 300 | known_id = 1; 301 | ee_printf("6k validation run parameters for coremark.\n"); 302 | break; 303 | case 0x4eaf: /* seed1=0x8, seed2=0x8, seed3=0x8, size 400 per algorithm 304 | */ 305 | known_id = 2; 306 | ee_printf("Profile generation run parameters for coremark.\n"); 307 | break; 308 | case 0xe9f5: /* seed1=0, seed2=0, seed3=0x66, size 666 per algorithm */ 309 | known_id = 3; 310 | ee_printf("2K performance run parameters for coremark.\n"); 311 | break; 312 | case 0x18f2: /* seed1=0x3415, seed2=0x3415, seed3=0x66, size 666 per 313 | algorithm */ 314 | known_id = 4; 315 | ee_printf("2K validation run parameters for coremark.\n"); 316 | break; 317 | default: 318 | total_errors = -1; 319 | break; 320 | } 321 | if (known_id >= 0) 322 | { 323 | for (i = 0; i < default_num_contexts; i++) 324 | { 325 | results[i].err = 0; 326 | if ((results[i].execs & ID_LIST) 327 | && (results[i].crclist != list_known_crc[known_id])) 328 | { 329 | ee_printf("[%u]ERROR! list crc 0x%04x - should be 0x%04x\n", 330 | i, 331 | results[i].crclist, 332 | list_known_crc[known_id]); 333 | results[i].err++; 334 | } 335 | if ((results[i].execs & ID_MATRIX) 336 | && (results[i].crcmatrix != matrix_known_crc[known_id])) 337 | { 338 | ee_printf("[%u]ERROR! matrix crc 0x%04x - should be 0x%04x\n", 339 | i, 340 | results[i].crcmatrix, 341 | matrix_known_crc[known_id]); 342 | results[i].err++; 343 | } 344 | if ((results[i].execs & ID_STATE) 345 | && (results[i].crcstate != state_known_crc[known_id])) 346 | { 347 | ee_printf("[%u]ERROR! state crc 0x%04x - should be 0x%04x\n", 348 | i, 349 | results[i].crcstate, 350 | state_known_crc[known_id]); 351 | results[i].err++; 352 | } 353 | total_errors += results[i].err; 354 | } 355 | } 356 | total_errors += check_data_types(); 357 | /* and report results */ 358 | ee_printf("CoreMark Size : %lu\n", (long unsigned)results[0].size); 359 | ee_printf("Total ticks : %lu\n", (long unsigned)total_time); 360 | #if HAS_FLOAT 361 | ee_printf("Total time (secs): %f\n", time_in_secs(total_time)); 362 | if (time_in_secs(total_time) > 0) 363 | ee_printf("Iterations/Sec : %f\n", 364 | default_num_contexts * results[0].iterations 365 | / time_in_secs(total_time)); 366 | #else 367 | ee_printf("Total time (secs): %d\n", time_in_secs(total_time)); 368 | if (time_in_secs(total_time) > 0) 369 | ee_printf("Iterations/Sec : %d\n", 370 | default_num_contexts * results[0].iterations 371 | / time_in_secs(total_time)); 372 | #endif 373 | if (time_in_secs(total_time) < 10) 374 | { 375 | ee_printf( 376 | "ERROR! Must execute for at least 10 secs for a valid result!\n"); 377 | total_errors++; 378 | } 379 | 380 | ee_printf("Iterations : %lu\n", 381 | (long unsigned)default_num_contexts * results[0].iterations); 382 | ee_printf("Compiler version : %s\n", COMPILER_VERSION); 383 | ee_printf("Compiler flags : %s\n", COMPILER_FLAGS); 384 | #if (MULTITHREAD > 1) 385 | ee_printf("Parallel %s : %d\n", PARALLEL_METHOD, default_num_contexts); 386 | #endif 387 | ee_printf("Memory location : %s\n", MEM_LOCATION); 388 | /* output for verification */ 389 | ee_printf("seedcrc : 0x%04x\n", seedcrc); 390 | if (results[0].execs & ID_LIST) 391 | for (i = 0; i < default_num_contexts; i++) 392 | ee_printf("[%d]crclist : 0x%04x\n", i, results[i].crclist); 393 | if (results[0].execs & ID_MATRIX) 394 | for (i = 0; i < default_num_contexts; i++) 395 | ee_printf("[%d]crcmatrix : 0x%04x\n", i, results[i].crcmatrix); 396 | if (results[0].execs & ID_STATE) 397 | for (i = 0; i < default_num_contexts; i++) 398 | ee_printf("[%d]crcstate : 0x%04x\n", i, results[i].crcstate); 399 | for (i = 0; i < default_num_contexts; i++) 400 | ee_printf("[%d]crcfinal : 0x%04x\n", i, results[i].crc); 401 | if (total_errors == 0) 402 | { 403 | ee_printf( 404 | "Correct operation validated. See README.md for run and reporting " 405 | "rules.\n"); 406 | #if HAS_FLOAT 407 | if (known_id == 3) 408 | { 409 | ee_printf("CoreMark 1.0 : %f / %s %s", 410 | default_num_contexts * results[0].iterations 411 | / time_in_secs(total_time), 412 | COMPILER_VERSION, 413 | COMPILER_FLAGS); 414 | #if defined(MEM_LOCATION) && !defined(MEM_LOCATION_UNSPEC) 415 | ee_printf(" / %s", MEM_LOCATION); 416 | #else 417 | ee_printf(" / %s", mem_name[MEM_METHOD]); 418 | #endif 419 | 420 | #if (MULTITHREAD > 1) 421 | ee_printf(" / %d:%s", default_num_contexts, PARALLEL_METHOD); 422 | #endif 423 | ee_printf("\n"); 424 | } 425 | #endif 426 | } 427 | if (total_errors > 0) 428 | ee_printf("Errors detected\n"); 429 | if (total_errors < 0) 430 | ee_printf( 431 | "Cannot validate operation for these seed values, please compare " 432 | "with results on a known platform.\n"); 433 | 434 | #if (MEM_METHOD == MEM_MALLOC) 435 | for (i = 0; i < MULTITHREAD; i++) 436 | portable_free(results[i].memblock[0]); 437 | #endif 438 | /* And last call any target specific code for finalizing */ 439 | portable_fini(&(results[0].port)); 440 | 441 | #if MAIN_HAS_FLOATRETURN 442 | if (total_errors == 0) { 443 | return default_num_contexts * results[0].iterations / time_in_secs(total_time); 444 | } 445 | #endif 446 | 447 | return MAIN_RETURN_VAL; 448 | } 449 | -------------------------------------------------------------------------------- /apps/coremark/LICENSE.md: -------------------------------------------------------------------------------- 1 | # COREMARK® ACCEPTABLE USE AGREEMENT 2 | 3 | This ACCEPTABLE USE AGREEMENT (this “Agreement”) is offered by Embedded Microprocessor Benchmark Consortium, a California nonprofit corporation (“Licensor”), to users of its CoreMark® software (“Licensee”) exclusively on the following terms. 4 | 5 | Licensor offers benchmarking software (“Software”) pursuant to an open source license, but carefully controls use of its benchmarks and their associated goodwill. Licensor has registered its trademark in one of the benchmarks available through the Software, COREMARK, Ser. No. 85/487,290; Reg. No. 4,179,307 (the “Trademark”), and promotes the use of a standard metric as a benchmark for assessing the performance of embedded systems. Solely on the terms described herein, Licensee may use and display the Trademark in connection with the generation of data regarding measurement and analysis of computer and embedded system benchmarking via the Software (the “Licensed Use”). 6 | 7 | ## Article 1 – License Grant. 8 | 1.1. License. Subject to the terms and conditions of this Agreement, Licensor hereby grants to Licensee, and Licensee hereby accepts from Licensor, a personal, non-exclusive, royalty-free, revocable right and license to use and display the Trademark during the term of this Agreement (the “Term”), solely and exclusively in connection with the Licensed Use. During the Term, Licensee (i) shall not modify or otherwise create derivative works of the Trademark, and (ii) may use the Trademark only to the extent permitted under this License. Neither Licensee nor any affiliate or agent thereof shall otherwise use the Trademark without the prior express written consent of Licensor, which may be withheld in its sole and absolute discretion. All rights not expressly granted to Licensee hereunder shall remain the exclusive property of Licensor. 9 | 10 | 1.2. Modifications to the Software. Licensee shall not use the Trademark in connection with any use of a modified, derivative, or otherwise altered copy of the Software. 11 | 12 | 1.3. Licensor’s Use. Nothing in this Agreement shall preclude Licensor or any of its successors or assigns from using or permitting other entities to use the Trademark, whether or not such entity directly or indirectly competes or conflicts with Licensee’s Licensed Use in any manner. 13 | 14 | 1.4. Term and Termination. This Agreement is perpetual unless terminated by either of the parties. Licensee may terminate this Agreement for convenience, without cause or liability, for any reason or for no reason whatsoever, upon ten (10) business days written notice. Licensor may terminate this Agreement effective immediately upon notice of breach. Upon termination, Licensee shall immediately remove all implementations of the Trademark from the Licensed Use, and delete all digitals files and records of all materials related to the Trademark. 15 | 16 | ## Article 2 – Ownership. 17 | 2.1. Ownership. Licensee acknowledges and agrees that Licensor is the owner of all right, title, and interest in and to the Trademark, and all such right, title, and interest shall remain with Licensor. Licensee shall not contest, dispute, challenge, oppose, or seek to cancel Licensor’s right, title, and interest in and to the Trademark. Licensee shall not prosecute any application for registration of the Trademark. Licensee shall display appropriate notices regarding ownership of the Trademark in connection with the Licensed Use. 18 | 19 | 2.2. Goodwill. Licensee acknowledges that Licensee shall not acquire any right, title, or interest in the Trademark by virtue of this Agreement other than the license granted hereunder, and disclaims any such right, title, interest, or ownership. All goodwill and reputation generated by Licensee’s use of the Trademark shall inure to the exclusive benefit of Licensor. Licensee shall not by any act or omission use the Trademark in any manner that disparages or reflects adversely on Licensor or its Licensed Use or reputation. Licensee shall not take any action that would interfere with or prejudice Licensor’s ownership or registration of the Trademark, the validity of the Trademark or the validity of the license granted by this Agreement. If Licensor determines and notifies Licensee that any act taken in connection with the Licensed Use (i) is inaccurate, unlawful or offensive to good taste; (ii) fails to provide for proper trademark notices, or (iii) otherwise violates Licensee’s obligations under this Agreement, the license granted under this Agreement shall terminate. 20 | 21 | ## Article 3 – Indemnification. 22 | 3.1. Indemnification Generally. Licensee agrees to indemnify, defend, and hold harmless (collectively “indemnify” or “indemnification”) Licensor, including Licensor’s members, managers, officers, and employees (collectively “Related Persons”), from and against, and pay or reimburse Licensor and such Related Persons for, any and all third-party actions, claims, demands, proceedings, investigations, inquiries (collectively, “Claims”), and any and all liabilities, obligations, fines, deficiencies, costs, expenses, royalties, losses, and damages (including reasonable outside counsel fees and expenses) associated with such Claims, to the extent that such Claim arises out of (i) Licensee’s material breach of this Agreement, or (ii) any allegation(s) that Licensee’s actions infringe or violate any third-party intellectual property right, including without limitation, any U.S. copyright, patent, or trademark, or are otherwise found to be tortious or criminal (whether or not such indemnified person is a named party in a legal proceeding). 23 | 24 | 3.2. Notice and Defense of Claims. Licensor shall promptly notify Licensee of any Claim for which indemnification is sought, following actual knowledge of such Claim, provided however that the failure to give such notice shall not relieve Licensee of its obligations hereunder except to the extent that Licensee is materially prejudiced by such failure. In the event that any third-party Claim is brought, Licensee shall have the right and option to undertake and control the defense of such action with counsel of its choice, provided however that (i) Licensor at its own expense may participate and appear on an equal footing with Licensee in the defense of any such Claim, (ii) Licensor may undertake and control such defense in the event of the material failure of Licensee to undertake and control the same; and (iii) the defense of any Claim relating to the intellectual property rights of Licensor or its licensors and any related counterclaims shall be solely controlled by Licensor with counsel of its choice. Licensee shall not consent to judgment or concede or settle or compromise any Claim without the prior written approval of Licensor (whose approval shall not be unreasonably withheld), unless such concession or settlement or compromise includes a full and unconditional release of Licensor and any applicable Related Persons from all liabilities in respect of such Claim. 25 | 26 | ## Article 4 – Miscellaneous. 27 | 4.1. Relationship of the Parties. This Agreement does not create a partnership, franchise, joint venture, agency, fiduciary, or employment relationship between the parties. 28 | 29 | 4.2. No Third-Party Beneficiaries. Except for the rights of Related Persons under Article 3 (Indemnification), there are no third-party beneficiaries to this Agreement. 30 | 31 | 4.3. Assignment. Licensee’s rights hereunder are non-assignable, and may not be sublicensed. 32 | 33 | 4.4. Equitable Relief. Licensee acknowledges that the remedies available at law for any breach of this Agreement will, by their nature, be inadequate. Accordingly, Licensor may obtain injunctive relief or other equitable relief to restrain a breach or threatened breach of this Agreement or to specifically enforce this Agreement, without proving that any monetary damages have been sustained, and without the requirement of posting of a bond prior to obtaining such equitable relief. 34 | 35 | 4.5. Governing Law. This Agreement will be interpreted, construed, and enforced in all respects in accordance with the laws of the State of California, without reference to its conflict of law principles. 36 | 37 | 4.6. Attorneys’ Fees. If any legal action, arbitration or other proceeding is brought for the enforcement of this Agreement, or because of an alleged dispute, breach, default, or misrepresentation in connection with any of the provisions of this Agreement, the successful or prevailing party shall be entitled to recover its reasonable attorneys’ fees and other reasonable costs incurred in that action or proceeding, in addition to any other relief to which it may be entitled. 38 | 39 | 4.7. Amendment; Waiver. This Agreement may not be amended, nor may any rights under it be waived, except in writing by Licensor. 40 | 41 | 4.8. Severability. If any provision of this Agreement is held by a court of competent jurisdiction to be contrary to law, the provision shall be modified by the court and interpreted so as best to accomplish the objectives of the original provision to the fullest extent 42 | permitted by law, and the remaining provisions of this Agreement shall remain in effect. 43 | 44 | 4.9. Entire Agreement. This Agreement constitutes the entire agreement between the parties and supersedes all prior and contemporaneous agreements, proposals or representations, written or oral, concerning its subject matter. 45 | 46 | 47 | # Apache License 48 | 49 | Version 2.0, January 2004 50 | 51 | http://www.apache.org/licenses/ 52 | 53 | ## TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 54 | 55 | 1. Definitions. 56 | 57 | "License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document. 58 | 59 | "Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License. 60 | 61 | "Legal Entity" shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity. 62 | 63 | "You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License. 64 | 65 | "Source" form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files. 66 | 67 | "Object" form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types. 68 | 69 | "Work" shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is included in or attached to the work (an example is provided in the Appendix below). 70 | 71 | "Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof. 72 | 73 | "Contribution" shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as "Not a Contribution." 74 | 75 | "Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work. 76 | 77 | 2. Grant of Copyright License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form. 78 | 79 | 3. Grant of Patent License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed. 80 | 81 | 4. Redistribution. You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions: 82 | 83 | You must give any other recipients of the Work or Derivative Works a copy of this License; and 84 | You must cause any modified files to carry prominent notices stating that You changed the files; and 85 | You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and 86 | If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License. 87 | 88 | You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License. 89 | 90 | 5. Submission of Contributions. Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions. 91 | 92 | 6. Trademarks. This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file. 93 | 94 | 7. Disclaimer of Warranty. Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License. 95 | 96 | 8. Limitation of Liability. In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages. 97 | 98 | 9. Accepting Warranty or Additional Liability. While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability. 99 | 100 | END OF TERMS AND CONDITIONS 101 | -------------------------------------------------------------------------------- /apps/coremark/core_list_join.c: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2018 Embedded Microprocessor Benchmark Consortium (EEMBC) 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | 16 | Original Author: Shay Gal-on 17 | */ 18 | 19 | #include "coremark.h" 20 | /* 21 | Topic: Description 22 | Benchmark using a linked list. 23 | 24 | Linked list is a common data structure used in many applications. 25 | 26 | For our purposes, this will excercise the memory units of the processor. 27 | In particular, usage of the list pointers to find and alter data. 28 | 29 | We are not using Malloc since some platforms do not support this 30 | library. 31 | 32 | Instead, the memory block being passed in is used to create a list, 33 | and the benchmark takes care not to add more items then can be 34 | accomodated by the memory block. The porting layer will make sure 35 | that we have a valid memory block. 36 | 37 | All operations are done in place, without using any extra memory. 38 | 39 | The list itself contains list pointers and pointers to data items. 40 | Data items contain the following: 41 | 42 | idx - An index that captures the initial order of the list. 43 | data - Variable data initialized based on the input parameters. The 16b 44 | are divided as follows: o Upper 8b are backup of original data. o Bit 7 45 | indicates if the lower 7 bits are to be used as is or calculated. o Bits 0-2 46 | indicate type of operation to perform to get a 7b value. o Bits 3-6 provide 47 | input for the operation. 48 | 49 | */ 50 | 51 | /* local functions */ 52 | 53 | list_head *core_list_find(list_head *list, list_data *info); 54 | list_head *core_list_reverse(list_head *list); 55 | list_head *core_list_remove(list_head *item); 56 | list_head *core_list_undo_remove(list_head *item_removed, 57 | list_head *item_modified); 58 | list_head *core_list_insert_new(list_head * insert_point, 59 | list_data * info, 60 | list_head **memblock, 61 | list_data **datablock, 62 | list_head * memblock_end, 63 | list_data * datablock_end); 64 | typedef ee_s32 (*list_cmp)(list_data *a, list_data *b, core_results *res); 65 | list_head *core_list_mergesort(list_head * list, 66 | list_cmp cmp, 67 | core_results *res); 68 | 69 | ee_s16 70 | calc_func(ee_s16 *pdata, core_results *res) 71 | { 72 | ee_s16 data = *pdata; 73 | ee_s16 retval; 74 | ee_u8 optype 75 | = (data >> 7) 76 | & 1; /* bit 7 indicates if the function result has been cached */ 77 | if (optype) /* if cached, use cache */ 78 | return (data & 0x007f); 79 | else 80 | { /* otherwise calculate and cache the result */ 81 | ee_s16 flag = data & 0x7; /* bits 0-2 is type of function to perform */ 82 | ee_s16 dtype 83 | = ((data >> 3) 84 | & 0xf); /* bits 3-6 is specific data for the operation */ 85 | dtype |= dtype << 4; /* replicate the lower 4 bits to get an 8b value */ 86 | switch (flag) 87 | { 88 | case 0: 89 | if (dtype < 0x22) /* set min period for bit corruption */ 90 | dtype = 0x22; 91 | retval = core_bench_state(res->size, 92 | res->memblock[3], 93 | res->seed1, 94 | res->seed2, 95 | dtype, 96 | res->crc); 97 | if (res->crcstate == 0) 98 | res->crcstate = retval; 99 | break; 100 | case 1: 101 | retval = core_bench_matrix(&(res->mat), dtype, res->crc); 102 | if (res->crcmatrix == 0) 103 | res->crcmatrix = retval; 104 | break; 105 | default: 106 | retval = data; 107 | break; 108 | } 109 | res->crc = crcu16(retval, res->crc); 110 | retval &= 0x007f; 111 | *pdata = (data & 0xff00) | 0x0080 | retval; /* cache the result */ 112 | return retval; 113 | } 114 | } 115 | /* Function: cmp_complex 116 | Compare the data item in a list cell. 117 | 118 | Can be used by mergesort. 119 | */ 120 | ee_s32 121 | cmp_complex(list_data *a, list_data *b, core_results *res) 122 | { 123 | ee_s16 val1 = calc_func(&(a->data16), res); 124 | ee_s16 val2 = calc_func(&(b->data16), res); 125 | return val1 - val2; 126 | } 127 | 128 | /* Function: cmp_idx 129 | Compare the idx item in a list cell, and regen the data. 130 | 131 | Can be used by mergesort. 132 | */ 133 | ee_s32 134 | cmp_idx(list_data *a, list_data *b, core_results *res) 135 | { 136 | if (res == NULL) 137 | { 138 | a->data16 = (a->data16 & 0xff00) | (0x00ff & (a->data16 >> 8)); 139 | b->data16 = (b->data16 & 0xff00) | (0x00ff & (b->data16 >> 8)); 140 | } 141 | return a->idx - b->idx; 142 | } 143 | 144 | void 145 | copy_info(list_data *to, list_data *from) 146 | { 147 | to->data16 = from->data16; 148 | to->idx = from->idx; 149 | } 150 | 151 | /* Benchmark for linked list: 152 | - Try to find multiple data items. 153 | - List sort 154 | - Operate on data from list (crc) 155 | - Single remove/reinsert 156 | * At the end of this function, the list is back to original state 157 | */ 158 | ee_u16 159 | core_bench_list(core_results *res, ee_s16 finder_idx) 160 | { 161 | ee_u16 retval = 0; 162 | ee_u16 found = 0, missed = 0; 163 | list_head *list = res->list; 164 | ee_s16 find_num = res->seed3; 165 | list_head *this_find; 166 | list_head *finder, *remover; 167 | list_data info; 168 | ee_s16 i; 169 | 170 | info.idx = finder_idx; 171 | /* find values in the list, and change the list each time 172 | * (reverse and cache if value found) */ 173 | for (i = 0; i < find_num; i++) 174 | { 175 | info.data16 = (i & 0xff); 176 | this_find = core_list_find(list, &info); 177 | list = core_list_reverse(list); 178 | if (this_find == NULL) 179 | { 180 | missed++; 181 | retval += (list->next->info->data16 >> 8) & 1; 182 | } 183 | else 184 | { 185 | found++; 186 | if (this_find->info->data16 & 0x1) /* use found value */ 187 | retval += (this_find->info->data16 >> 9) & 1; 188 | /* and cache next item at the head of the list (if any) */ 189 | if (this_find->next != NULL) 190 | { 191 | finder = this_find->next; 192 | this_find->next = finder->next; 193 | finder->next = list->next; 194 | list->next = finder; 195 | } 196 | } 197 | if (info.idx >= 0) 198 | info.idx++; 199 | #if CORE_DEBUG 200 | ee_printf("List find %d: [%d,%d,%d]\n", i, retval, missed, found); 201 | #endif 202 | } 203 | retval += found * 4 - missed; 204 | /* sort the list by data content and remove one item*/ 205 | if (finder_idx > 0) 206 | list = core_list_mergesort(list, cmp_complex, res); 207 | remover = core_list_remove(list->next); 208 | /* CRC data content of list from location of index N forward, and then undo 209 | * remove */ 210 | finder = core_list_find(list, &info); 211 | if (!finder) 212 | finder = list->next; 213 | while (finder) 214 | { 215 | retval = crc16(list->info->data16, retval); 216 | finder = finder->next; 217 | } 218 | #if CORE_DEBUG 219 | ee_printf("List sort 1: %04x\n", retval); 220 | #endif 221 | remover = core_list_undo_remove(remover, list->next); 222 | /* sort the list by index, in effect returning the list to original state */ 223 | list = core_list_mergesort(list, cmp_idx, NULL); 224 | /* CRC data content of list */ 225 | finder = list->next; 226 | while (finder) 227 | { 228 | retval = crc16(list->info->data16, retval); 229 | finder = finder->next; 230 | } 231 | #if CORE_DEBUG 232 | ee_printf("List sort 2: %04x\n", retval); 233 | #endif 234 | return retval; 235 | } 236 | /* Function: core_list_init 237 | Initialize list with data. 238 | 239 | Parameters: 240 | blksize - Size of memory to be initialized. 241 | memblock - Pointer to memory block. 242 | seed - Actual values chosen depend on the seed parameter. 243 | The seed parameter MUST be supplied from a source that cannot be 244 | determined at compile time 245 | 246 | Returns: 247 | Pointer to the head of the list. 248 | 249 | */ 250 | list_head * 251 | core_list_init(ee_u32 blksize, list_head *memblock, ee_s16 seed) 252 | { 253 | /* calculated pointers for the list */ 254 | ee_u32 per_item = 16 + sizeof(struct list_data_s); 255 | ee_u32 size = (blksize / per_item) 256 | - 2; /* to accomodate systems with 64b pointers, and make sure 257 | same code is executed, set max list elements */ 258 | list_head *memblock_end = memblock + size; 259 | list_data *datablock = (list_data *)(memblock_end); 260 | list_data *datablock_end = datablock + size; 261 | /* some useful variables */ 262 | ee_u32 i; 263 | list_head *finder, *list = memblock; 264 | list_data info; 265 | 266 | /* create a fake items for the list head and tail */ 267 | list->next = NULL; 268 | list->info = datablock; 269 | list->info->idx = 0x0000; 270 | list->info->data16 = (ee_s16)0x8080; 271 | memblock++; 272 | datablock++; 273 | info.idx = 0x7fff; 274 | info.data16 = (ee_s16)0xffff; 275 | core_list_insert_new( 276 | list, &info, &memblock, &datablock, memblock_end, datablock_end); 277 | 278 | /* then insert size items */ 279 | for (i = 0; i < size; i++) 280 | { 281 | ee_u16 datpat = ((ee_u16)(seed ^ i) & 0xf); 282 | ee_u16 dat 283 | = (datpat << 3) | (i & 0x7); /* alternate between algorithms */ 284 | info.data16 = (dat << 8) | dat; /* fill the data with actual data and 285 | upper bits with rebuild value */ 286 | core_list_insert_new( 287 | list, &info, &memblock, &datablock, memblock_end, datablock_end); 288 | } 289 | /* and now index the list so we know initial seed order of the list */ 290 | finder = list->next; 291 | i = 1; 292 | while (finder->next != NULL) 293 | { 294 | if (i < size / 5) /* first 20% of the list in order */ 295 | finder->info->idx = i++; 296 | else 297 | { 298 | ee_u16 pat = (ee_u16)(i++ ^ seed); /* get a pseudo random number */ 299 | finder->info->idx = 0x3fff 300 | & (((i & 0x07) << 8) 301 | | pat); /* make sure the mixed items end up 302 | after the ones in sequence */ 303 | } 304 | finder = finder->next; 305 | } 306 | list = core_list_mergesort(list, cmp_idx, NULL); 307 | #if CORE_DEBUG 308 | ee_printf("Initialized list:\n"); 309 | finder = list; 310 | while (finder) 311 | { 312 | ee_printf( 313 | "[%04x,%04x]", finder->info->idx, (ee_u16)finder->info->data16); 314 | finder = finder->next; 315 | } 316 | ee_printf("\n"); 317 | #endif 318 | return list; 319 | } 320 | 321 | /* Function: core_list_insert 322 | Insert an item to the list 323 | 324 | Parameters: 325 | insert_point - where to insert the item. 326 | info - data for the cell. 327 | memblock - pointer for the list header 328 | datablock - pointer for the list data 329 | memblock_end - end of region for list headers 330 | datablock_end - end of region for list data 331 | 332 | Returns: 333 | Pointer to new item. 334 | */ 335 | list_head * 336 | core_list_insert_new(list_head * insert_point, 337 | list_data * info, 338 | list_head **memblock, 339 | list_data **datablock, 340 | list_head * memblock_end, 341 | list_data * datablock_end) 342 | { 343 | list_head *newitem; 344 | 345 | if ((*memblock + 1) >= memblock_end) 346 | return NULL; 347 | if ((*datablock + 1) >= datablock_end) 348 | return NULL; 349 | 350 | newitem = *memblock; 351 | (*memblock)++; 352 | newitem->next = insert_point->next; 353 | insert_point->next = newitem; 354 | 355 | newitem->info = *datablock; 356 | (*datablock)++; 357 | copy_info(newitem->info, info); 358 | 359 | return newitem; 360 | } 361 | 362 | /* Function: core_list_remove 363 | Remove an item from the list. 364 | 365 | Operation: 366 | For a singly linked list, remove by copying the data from the next item 367 | over to the current cell, and unlinking the next item. 368 | 369 | Note: 370 | since there is always a fake item at the end of the list, no need to 371 | check for NULL. 372 | 373 | Returns: 374 | Removed item. 375 | */ 376 | list_head * 377 | core_list_remove(list_head *item) 378 | { 379 | list_data *tmp; 380 | list_head *ret = item->next; 381 | /* swap data pointers */ 382 | tmp = item->info; 383 | item->info = ret->info; 384 | ret->info = tmp; 385 | /* and eliminate item */ 386 | item->next = item->next->next; 387 | ret->next = NULL; 388 | return ret; 389 | } 390 | 391 | /* Function: core_list_undo_remove 392 | Undo a remove operation. 393 | 394 | Operation: 395 | Since we want each iteration of the benchmark to be exactly the same, 396 | we need to be able to undo a remove. 397 | Link the removed item back into the list, and switch the info items. 398 | 399 | Parameters: 400 | item_removed - Return value from the 401 | item_modified - List item that was modified during 402 | 403 | Returns: 404 | The item that was linked back to the list. 405 | 406 | */ 407 | list_head * 408 | core_list_undo_remove(list_head *item_removed, list_head *item_modified) 409 | { 410 | list_data *tmp; 411 | /* swap data pointers */ 412 | tmp = item_removed->info; 413 | item_removed->info = item_modified->info; 414 | item_modified->info = tmp; 415 | /* and insert item */ 416 | item_removed->next = item_modified->next; 417 | item_modified->next = item_removed; 418 | return item_removed; 419 | } 420 | 421 | /* Function: core_list_find 422 | Find an item in the list 423 | 424 | Operation: 425 | Find an item by idx (if not 0) or specific data value 426 | 427 | Parameters: 428 | list - list head 429 | info - idx or data to find 430 | 431 | Returns: 432 | Found item, or NULL if not found. 433 | */ 434 | list_head * 435 | core_list_find(list_head *list, list_data *info) 436 | { 437 | if (info->idx >= 0) 438 | { 439 | while (list && (list->info->idx != info->idx)) 440 | list = list->next; 441 | return list; 442 | } 443 | else 444 | { 445 | while (list && ((list->info->data16 & 0xff) != info->data16)) 446 | list = list->next; 447 | return list; 448 | } 449 | } 450 | /* Function: core_list_reverse 451 | Reverse a list 452 | 453 | Operation: 454 | Rearrange the pointers so the list is reversed. 455 | 456 | Parameters: 457 | list - list head 458 | info - idx or data to find 459 | 460 | Returns: 461 | Found item, or NULL if not found. 462 | */ 463 | 464 | list_head * 465 | core_list_reverse(list_head *list) 466 | { 467 | list_head *next = NULL, *tmp; 468 | while (list) 469 | { 470 | tmp = list->next; 471 | list->next = next; 472 | next = list; 473 | list = tmp; 474 | } 475 | return next; 476 | } 477 | /* Function: core_list_mergesort 478 | Sort the list in place without recursion. 479 | 480 | Description: 481 | Use mergesort, as for linked list this is a realistic solution. 482 | Also, since this is aimed at embedded, care was taken to use iterative 483 | rather then recursive algorithm. The sort can either return the list to 484 | original order (by idx) , or use the data item to invoke other other 485 | algorithms and change the order of the list. 486 | 487 | Parameters: 488 | list - list to be sorted. 489 | cmp - cmp function to use 490 | 491 | Returns: 492 | New head of the list. 493 | 494 | Note: 495 | We have a special header for the list that will always be first, 496 | but the algorithm could theoretically modify where the list starts. 497 | 498 | */ 499 | list_head * 500 | core_list_mergesort(list_head *list, list_cmp cmp, core_results *res) 501 | { 502 | list_head *p, *q, *e, *tail; 503 | ee_s32 insize, nmerges, psize, qsize, i; 504 | 505 | insize = 1; 506 | 507 | while (1) 508 | { 509 | p = list; 510 | list = NULL; 511 | tail = NULL; 512 | 513 | nmerges = 0; /* count number of merges we do in this pass */ 514 | 515 | while (p) 516 | { 517 | nmerges++; /* there exists a merge to be done */ 518 | /* step `insize' places along from p */ 519 | q = p; 520 | psize = 0; 521 | for (i = 0; i < insize; i++) 522 | { 523 | psize++; 524 | q = q->next; 525 | if (!q) 526 | break; 527 | } 528 | 529 | /* if q hasn't fallen off end, we have two lists to merge */ 530 | qsize = insize; 531 | 532 | /* now we have two lists; merge them */ 533 | while (psize > 0 || (qsize > 0 && q)) 534 | { 535 | 536 | /* decide whether next element of merge comes from p or q */ 537 | if (psize == 0) 538 | { 539 | /* p is empty; e must come from q. */ 540 | e = q; 541 | q = q->next; 542 | qsize--; 543 | } 544 | else if (qsize == 0 || !q) 545 | { 546 | /* q is empty; e must come from p. */ 547 | e = p; 548 | p = p->next; 549 | psize--; 550 | } 551 | else if (cmp(p->info, q->info, res) <= 0) 552 | { 553 | /* First element of p is lower (or same); e must come from 554 | * p. */ 555 | e = p; 556 | p = p->next; 557 | psize--; 558 | } 559 | else 560 | { 561 | /* First element of q is lower; e must come from q. */ 562 | e = q; 563 | q = q->next; 564 | qsize--; 565 | } 566 | 567 | /* add the next element to the merged list */ 568 | if (tail) 569 | { 570 | tail->next = e; 571 | } 572 | else 573 | { 574 | list = e; 575 | } 576 | tail = e; 577 | } 578 | 579 | /* now p has stepped `insize' places along, and q has too */ 580 | p = q; 581 | } 582 | 583 | tail->next = NULL; 584 | 585 | /* If we have done only one merge, we're finished. */ 586 | if (nmerges <= 1) /* allow for nmerges==0, the empty list case */ 587 | return list; 588 | 589 | /* Otherwise repeat, merging lists twice the size */ 590 | insize *= 2; 591 | } 592 | #if COMPILER_REQUIRES_SORT_RETURN 593 | return list; 594 | #endif 595 | } 596 | -------------------------------------------------------------------------------- /apps/coremark/README.md: -------------------------------------------------------------------------------- 1 | 2 | # Introduction 3 | 4 | CoreMark's primary goals are simplicity and providing a method for testing only a processor's core features. For more information about EEMBC's comprehensive embedded benchmark suites, please see www.eembc.org. 5 | 6 | For a more compute-intensive version of CoreMark that uses larger datasets and execution loops taken from common applications, please check out EEMBC's [CoreMark-PRO](https://www.github.com/eembc/coremark-pro) benchmark, also on GitHub. 7 | 8 | # Building and Running 9 | 10 | To build and run the benchmark, type 11 | 12 | `> make` 13 | 14 | Full results are available in the files `run1.log` and `run2.log`. CoreMark result can be found in `run1.log`. 15 | 16 | ## Cross Compiling 17 | 18 | For cross compile platforms please adjust `core_portme.mak`, `core_portme.h` (and possibly `core_portme.c`) according to the specific platform used. When porting to a new platform, it is recommended to copy one of the default port folders (e.g. `mkdir && cp linux/* `), adjust the porting files, and run: 19 | ~~~ 20 | % make PORT_DIR= 21 | ~~~ 22 | 23 | ## Make Targets 24 | `run` - Default target, creates `run1.log` and `run2.log`. 25 | `run1.log` - Run the benchmark with performance parameters, and output to `run1.log` 26 | `run2.log` - Run the benchmark with validation parameters, and output to `run2.log` 27 | `run3.log` - Run the benchmark with profile generation parameters, and output to `run3.log` 28 | `compile` - compile the benchmark executable 29 | `link` - link the benchmark executable 30 | `check` - test MD5 of sources that may not be modified 31 | `clean` - clean temporary files 32 | 33 | ### Make flag: `ITERATIONS` 34 | By default, the benchmark will run between 10-100 seconds. To override, use `ITERATIONS=N` 35 | ~~~ 36 | % make ITERATIONS=10 37 | ~~~ 38 | Will run the benchmark for 10 iterations. It is recommended to set a specific number of iterations in certain situations e.g.: 39 | 40 | * Running with a simulator 41 | * Measuring power/energy 42 | * Timing cannot be restarted 43 | 44 | Minimum required run time: **Results are only valid for reporting if the benchmark ran for at least 10 secs!** 45 | 46 | ### Make flag: `XCFLAGS` 47 | To add compiler flags from the command line, use `XCFLAGS` e.g.: 48 | 49 | ~~~ 50 | % make XCFLAGS="-DMULTITHREAD=4 -DUSE_FORK" 51 | ~~~ 52 | 53 | ### Make flag: `CORE_DEBUG` 54 | 55 | Define to compile for a debug run if you get incorrect CRC. 56 | 57 | ~~~ 58 | % make XCFLAGS="-DCORE_DEBUG=1" 59 | ~~~ 60 | 61 | ### Make flag: `REBUILD` 62 | 63 | Force a rebuild of the executable. 64 | 65 | ## Systems Without `make` 66 | The following files need to be compiled: 67 | * `core_list_join.c` 68 | * `core_main.c` 69 | * `core_matrix.c` 70 | * `core_state.c` 71 | * `core_util.c` 72 | * `PORT_DIR/core_portme.c` 73 | 74 | For example: 75 | ~~~ 76 | % gcc -O2 -o coremark.exe core_list_join.c core_main.c core_matrix.c core_state.c core_util.c simple/core_portme.c -DPERFORMANCE_RUN=1 -DITERATIONS=1000 77 | % ./coremark.exe > run1.log 78 | ~~~ 79 | The above will compile the benchmark for a performance run and 1000 iterations. Output is redirected to `run1.log`. 80 | 81 | # Parallel Execution 82 | Use `XCFLAGS=-DMULTITHREAD=N` where N is number of threads to run in parallel. Several implementations are available to execute in multiple contexts, or you can implement your own in `core_portme.c`. 83 | 84 | ~~~ 85 | % make XCFLAGS="-DMULTITHREAD=4 -DUSE_PTHREAD -pthread" 86 | ~~~ 87 | 88 | The above will compile the benchmark for execution on 4 cores, using POSIX Threads API. Forking is also supported: 89 | 90 | ~~~ 91 | % make XCFLAGS="-DMULTITHREAD=4 -DUSE_FORK" 92 | ~~~ 93 | 94 | Note: linking may fail on the previous command if your linker does not automatically add the `pthread` library. If you encounter `undefined reference` errors, please modify the `core_portme.mak` file for your platform, (e.g. `linux/core_portme.mak`) and add `-pthread` to the `LFLAGS_END` parameter. 95 | 96 | # Run Parameters for the Benchmark Executable 97 | CoreMark's executable takes several parameters as follows (but only if `main()` accepts arguments): 98 | 1st - A seed value used for initialization of data. 99 | 2nd - A seed value used for initialization of data. 100 | 3rd - A seed value used for initialization of data. 101 | 4th - Number of iterations (0 for auto : default value) 102 | 5th - Reserved for internal use. 103 | 6th - Reserved for internal use. 104 | 7th - For malloc users only, ovreride the size of the input data buffer. 105 | 106 | The run target from make will run coremark with 2 different data initialization seeds. 107 | 108 | ## Alternative parameters: 109 | If not using `malloc` or command line arguments are not supported, the buffer size 110 | for the algorithms must be defined via the compiler define `TOTAL_DATA_SIZE`. 111 | `TOTAL_DATA_SIZE` must be set to 2000 bytes (default) for standard runs. 112 | The default for such a target when testing different configurations could be: 113 | 114 | ~~~ 115 | % make XCFLAGS="-DTOTAL_DATA_SIZE=6000 -DMAIN_HAS_NOARGC=1" 116 | ~~~ 117 | 118 | # Submitting Results 119 | 120 | CoreMark results can be submitted on the web. Open a web browser and go to the [submission page](https://www.eembc.org/coremark/submit.php). After registering an account you may enter a score. 121 | 122 | # Run Rules 123 | What is and is not allowed. 124 | 125 | ## Required 126 | 1. The benchmark needs to run for at least 10 seconds. 127 | 2. All validation must succeed for seeds `0,0,0x66` and `0x3415,0x3415,0x66`, buffer size of 2000 bytes total. 128 | * If not using command line arguments to main: 129 | ~~~ 130 | % make XCFLAGS="-DPERFORMANCE_RUN=1" REBUILD=1 run1.log 131 | % make XCFLAGS="-DVALIDATION_RUN=1" REBUILD=1 run2.log 132 | ~~~ 133 | 3. If using profile guided optimization, profile must be generated using seeds of `8,8,8`, and buffer size of 1200 bytes total. 134 | ~~~ 135 | % make XCFLAGS="-DTOTAL_DATA_SIZE=1200 -DPROFILE_RUN=1" REBUILD=1 run3.log 136 | ~~~ 137 | 4. All source files must be compiled with the same flags. 138 | 5. All data type sizes must match size in bits such that: 139 | * `ee_u8` is an unsigned 8-bit datatype. 140 | * `ee_s16` is a signed 16-bit datatype. 141 | * `ee_u16` is an unsigned 16-bit datatype. 142 | * `ee_s32` is a signed 32-bit datatype. 143 | * `ee_u32` is an unsigned 32-bit datatype. 144 | 145 | ## Allowed 146 | 147 | 1. Changing number of iterations 148 | 2. Changing toolchain and build/load/run options 149 | 3. Changing method of acquiring a data memory block 150 | 5. Changing the method of acquiring seed values 151 | 6. Changing implementation `in core_portme.c` 152 | 7. Changing configuration values in `core_portme.h` 153 | 8. Changing `core_portme.mak` 154 | 155 | ## NOT ALLOWED 156 | 1. Changing of source file other then `core_portme*` (use `make check` to validate) 157 | 158 | # Reporting rules 159 | Use the following syntax to report results on a data sheet: 160 | 161 | CoreMark 1.0 : N / C [/ P] [/ M] 162 | 163 | N - Number of iterations per second with seeds 0,0,0x66,size=2000) 164 | 165 | C - Compiler version and flags 166 | 167 | P - Parameters such as data and code allocation specifics 168 | 169 | * This parameter *may* be omitted if all data was allocated on the heap in RAM. 170 | * This parameter *may not* be omitted when reporting CoreMark/MHz 171 | 172 | M - Type of parallel execution (if used) and number of contexts 173 | * This parameter may be omitted if parallel execution was not used. 174 | 175 | e.g.: 176 | 177 | ~~~ 178 | CoreMark 1.0 : 128 / GCC 4.1.2 -O2 -fprofile-use / Heap in TCRAM / FORK:2 179 | ~~~ 180 | or 181 | ~~~ 182 | CoreMark 1.0 : 1400 / GCC 3.4 -O4 183 | ~~~ 184 | 185 | If reporting scaling results, the results must be reported as follows: 186 | 187 | CoreMark/MHz 1.0 : N / C / P [/ M] 188 | 189 | P - When reporting scaling results, memory parameter must also indicate memory frequency:core frequency ratio. 190 | 1. If the core has cache and cache frequency to core frequency ratio is configurable, that must also be included. 191 | 192 | e.g.: 193 | 194 | ~~~ 195 | CoreMark/MHz 1.0 : 1.47 / GCC 4.1.2 -O2 / DDR3(Heap) 30:1 Memory 1:1 Cache 196 | ~~~ 197 | 198 | # Log File Format 199 | The log files have the following format 200 | 201 | ~~~ 202 | 2K performance run parameters for coremark. (Run type) 203 | CoreMark Size : 666 (Buffer size) 204 | Total ticks : 25875 (platform dependent value) 205 | Total time (secs) : 25.875000 (actual time in seconds) 206 | Iterations/Sec : 3864.734300 (Performance value to report) 207 | Iterations : 100000 (number of iterations used) 208 | Compiler version : GCC3.4.4 (Compiler and version) 209 | Compiler flags : -O2 (Compiler and linker flags) 210 | Memory location : Code in flash, data in on chip RAM 211 | seedcrc : 0xe9f5 (identifier for the input seeds) 212 | [0]crclist : 0xe714 (validation for list part) 213 | [0]crcmatrix : 0x1fd7 (validation for matrix part) 214 | [0]crcstate : 0x8e3a (validation for state part) 215 | [0]crcfinal : 0x33ff (iteration dependent output) 216 | Correct operation validated. See README.md for run and reporting rules. (*Only when run is successful*) 217 | CoreMark 1.0 : 6508.490622 / GCC3.4.4 -O2 / Heap (*Only on a successful performance run*) 218 | ~~~ 219 | 220 | # Theory of Operation 221 | 222 | This section describes the initial goals of CoreMark and their implementation. 223 | 224 | ## Small and easy to understand 225 | 226 | * X number of source code lines for timed portion of the benchmark. 227 | * Meaningful names for variables and functions. 228 | * Comments for each block of code more than 10 lines long. 229 | 230 | ## Portability 231 | 232 | A thin abstraction layer will be provided for I/O and timing in a separate file. All I/O and timing of the benchmark will be done through this layer. 233 | 234 | ### Code / data size 235 | 236 | * Compile with gcc on x86 and make sure all sizes are according to requirements. 237 | * If dynamic memory allocation is used, take total memory allocated into account as well. 238 | * Avoid recursive functions and keep track of stack usage. 239 | * Use the same memory block as data site for all algorithms, and initialize the data before each algorithm – while this means that initialization with data happens during the timed portion, it will only happen once during the timed portion and so have negligible effect on the results. 240 | 241 | ## Controlled output 242 | 243 | This may be the most difficult goal. Compilers are constantly improving and getting better at analyzing code. To create work that cannot be computed at compile time and must be computed at run time, we will rely on two assumptions: 244 | 245 | * Some system functions (e.g. time, scanf) and parameters cannot be computed at compile time. In most cases, marking a variable volatile means the compiler is force to read this variable every time it is read. This will be used to introduce a factor into the input that cannot be precomputed at compile time. Since the results are input dependent, that will make sure that computation has to happen at run time. 246 | 247 | * Either a system function or I/O (e.g. scanf) or command line parameters or volatile variables will be used before the timed portion to generate data which is not available at compile time. Specific method used is not relevant as long as it can be controlled, and that it cannot be computed or eliminated by the compiler at compile time. E.g. if the clock() functions is a compiler stub, it may not be used. The derived values will be reported on the output so that verification can be done on a different machine. 248 | 249 | * We cannot rely on command line parameters since some embedded systems do not have the capability to provide command line parameters. All 3 methods above will be implemented (time based, scanf and command line parameters) and all 3 are valid if the compiler cannot determine the value at compile time. 250 | 251 | * It is important to note that The actual values that are to be supplied at run time will be standardized. The methodology is not intended to provide random data, but simply to provide controlled data that cannot be precomputed at compile time. 252 | 253 | * Printed results must be valid at run time. This will be used to make sure the computation has been executed. 254 | 255 | * Some embedded systems do not provide “printf” or other I/O functionality. All I/O will be done through a thin abstraction interface to allow execution on such systems (e.g. allow output via JTAG). 256 | 257 | ## Key Algorithms 258 | 259 | ### Linked List 260 | 261 | The following linked list structure will be used: 262 | 263 | ~~~ 264 | typedef struct list_data_s { 265 | ee_s16 data16; 266 | ee_s16 idx; 267 | } list_data; 268 | 269 | typedef struct list_head_s { 270 | struct list_head_s *next; 271 | struct list_data_s *info; 272 | } list_head; 273 | ~~~ 274 | 275 | While adding a level of indirection accessing the data, this structure is realistic and used in many embedded applications for small to medium lists. 276 | 277 | The list itself will be initialized on a block of memory that will be passed in to the initialization function. While in general linked lists use malloc for new nodes, embedded applications sometime control the memory for small data structures such as arrays and lists directly to avoid the overhead of system calls, so this approach is realistic. 278 | 279 | The linked list will be initialized such that 1/4 of the list pointers point to sequential areas in memory, and 3/4 of the list pointers are distributed in a non sequential manner. This is done to emulate a linked list that had add/remove happen for a while disrupting the neat order, and then a series of adds that are likely to come from sequential memory locations. 280 | 281 | For the benchmark itself: 282 | - Multiple find operations are going to be performed. These find operations may result in the whole list being traversed. The result of each find will become part of the output chain. 283 | - The list will be sorted using merge sort based on the data16 value, and then derive CRC of the data16 item in order for part of the list. The CRC will become part of the output chain. 284 | - The list will be sorted again using merge sort based on the idx value. This sort will guarantee that the list is returned to the primary state before leaving the function, so that multiple iterations of the function will have the same result. CRC of the data16 for part of the list will again be calculated and become part of the output chain. 285 | 286 | The actual `data16` in each cell will be pseudo random based on a single 16b input that cannot be determined at compile time. In addition, the part of the list which is used for CRC will also be passed to the function, and determined based on an input that cannot be determined at run time. 287 | 288 | ### Matrix Multiply 289 | 290 | This very simple algorithm forms the basis of many more complex algorithms. The tight inner loop is the focus of many optimizations (compiler as well as hardware based) and is thus relevant for embedded processing. 291 | 292 | The total available data space will be divided to 3 parts: 293 | 1. NxN matrix A. 294 | 2. NxN matrix B. 295 | 3. NxN matrix C. 296 | 297 | E.g. for 2K we will have 3 12x12 matrices (assuming data type of 32b 12(len)*12(wid)*4(size)*3(num) =1728 bytes). 298 | 299 | Matrix A will be initialized with small values (upper 3/4 of the bits all zero). 300 | Matrix B will be initialized with medium values (upper half of the bits all zero). 301 | Matrix C will be used for the result. 302 | 303 | For the benchmark itself: 304 | - Multiple A by a constant into C, add the upper bits of each of the values in the result matrix. The result will become part of the output chain. 305 | - Multiple A by column X of B into C, add the upper bits of each of the values in the result matrix. The result will become part of the output chain. 306 | - Multiple A by B into C, add the upper bits of each of the values in the result matrix. The result will become part of the output chain. 307 | 308 | The actual values for A and B must be derived based on input that is not available at compile time. 309 | 310 | ### State Machine 311 | 312 | This part of the code needs to exercise switch and if statements. As such, we will use a small Moore state machine. In particular, this will be a state machine that identifies string input as numbers and divides them according to format. 313 | 314 | The state machine will parse the input string until either a “,” separator or end of input is encountered. An invalid number will cause the state machine to return invalid state and a valid number will cause the state machine to return with type of number format (int/float/scientific). 315 | 316 | This code will perform a realistic task, be small enough to easily understand, and exercise the required functionality. The other option used in embedded systems is a mealy based state machine, which is driven by a table. The table then determines the number of states and complexity of transitions. This approach, however, tests mainly the load/store and function call mechanisms and less the handling of branches. If analysis of the final results shows that the load/store functionality of the processor is not exercised thoroughly, it may be a good addition to the benchmark (codesize allowing). 317 | 318 | For input, the memory block will be initialized with comma separated values of mixed formats, as well as invalid inputs. 319 | 320 | For the benchmark itself: 321 | - Invoke the state machine on all of the input and count final states and state transitions. CRC of all final states and transitions will become part of the output chain. 322 | - Modify the input at intervals (inject errors) and repeat the state machine operation. 323 | - Modify the input back to original form. 324 | 325 | The actual input must be initialized based on data that cannot be determined at compile time. In addition the intervals for modification of the input and the actual modification must be based on input that cannot be determined at compile time. 326 | 327 | # Validation 328 | 329 | This release was tested on the following platforms: 330 | * x86 cygwin and gcc 3.4 (Quad, dual and single core systems) 331 | * x86 linux (Ubuntu/Fedora) and gcc (4.2/4.1) (Quad and single core systems) 332 | * MIPS64 BE linux and gcc 3.4 16 cores system 333 | * MIPS32 BE linux with CodeSourcery compiler 4.2-177 on Malta/Linux with a 1004K 3-core system 334 | * PPC simulator with gcc 4.2.2 (No OS) 335 | * PPC 64b BE linux (yellowdog) with gcc 3.4 and 4.1 (Dual core system) 336 | * BF533 with VDSP50 337 | * Renesas R8C/H8 MCU with HEW 4.05 338 | * NXP LPC1700 armcc v4.0.0.524 339 | * NEC 78K with IAR v4.61 340 | * ARM simulator with armcc v4 341 | 342 | # Memory Analysis 343 | 344 | Valgrind 3.4.0 used and no errors reported. 345 | 346 | # Balance Analysis 347 | 348 | Number of instructions executed for each function tested with cachegrind and found balanced with gcc and -O0. 349 | 350 | # Statistics 351 | 352 | Lines: 353 | ~~~ 354 | Lines Blank Cmnts Source AESL 355 | ===== ===== ===== ===== ========== ======================================= 356 | 469 66 170 251 627.5 core_list_join.c (C) 357 | 330 18 54 268 670.0 core_main.c (C) 358 | 256 32 80 146 365.0 core_matrix.c (C) 359 | 240 16 51 186 465.0 core_state.c (C) 360 | 165 11 20 134 335.0 core_util.c (C) 361 | 150 23 36 98 245.0 coremark.h (C) 362 | 1610 166 411 1083 2707.5 ----- Benchmark ----- (6 files) 363 | 293 15 74 212 530.0 linux/core_portme.c (C) 364 | 235 30 104 104 260.0 linux/core_portme.h (C) 365 | 528 45 178 316 790.0 ----- Porting ----- (2 files) 366 | 367 | * For comparison, here are the stats for Dhrystone 368 | Lines Blank Cmnts Source AESL 369 | ===== ===== ===== ===== ========== ======================================= 370 | 311 15 242 54 135.0 dhry.h (C) 371 | 789 132 119 553 1382.5 dhry_1.c (C) 372 | 186 26 68 107 267.5 dhry_2.c (C) 373 | 1286 173 429 714 1785.0 ----- C ----- (3 files) 374 | ~~~ 375 | 376 | # Credits 377 | Many thanks to all of the individuals who helped with the development or testing of CoreMark including (Sorted by company name; note that company names may no longer be accurate as this was written in 2009). 378 | * Alan Anderson, ADI 379 | * Adhikary Rajiv, ADI 380 | * Elena Stohr, ARM 381 | * Ian Rickards, ARM 382 | * Andrew Pickard, ARM 383 | * Trent Parker, CAVIUM 384 | * Shay Gal-On, EEMBC 385 | * Markus Levy, EEMBC 386 | * Peter Torelli, EEMBC 387 | * Ron Olson, IBM 388 | * Eyal Barzilay, MIPS 389 | * Jens Eltze, NEC 390 | * Hirohiko Ono, NEC 391 | * Ulrich Drees, NEC 392 | * Frank Roscheda, NEC 393 | * Rob Cosaro, NXP 394 | * Shumpei Kawasaki, RENESAS 395 | 396 | # Legal 397 | Please refer to LICENSE.md in this repository for a description of your rights to use this code. 398 | 399 | # Copyright 400 | Copyright © 2009 EEMBC All rights reserved. 401 | CoreMark is a trademark of EEMBC and EEMBC is a registered trademark of the Embedded Microprocessor Benchmark Consortium. 402 | 403 | -------------------------------------------------------------------------------- /src/wasm-rt.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2018 WebAssembly Community Group participants 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | #ifndef WASM_RT_H_ 18 | #define WASM_RT_H_ 19 | 20 | #include 21 | #include 22 | #include 23 | #include 24 | #include 25 | 26 | #ifdef __cplusplus 27 | extern "C" { 28 | #endif 29 | 30 | #ifndef __has_builtin 31 | #define __has_builtin(x) 0 /** Compatibility with non-clang compilers. */ 32 | #endif 33 | 34 | #if __has_builtin(__builtin_expect) 35 | #define UNLIKELY(x) __builtin_expect(!!(x), 0) 36 | #define LIKELY(x) __builtin_expect(!!(x), 1) 37 | #else 38 | #define UNLIKELY(x) (x) 39 | #define LIKELY(x) (x) 40 | #endif 41 | 42 | #if __has_builtin(__builtin_memcpy) 43 | #define wasm_rt_memcpy __builtin_memcpy 44 | #else 45 | #define wasm_rt_memcpy memcpy 46 | #endif 47 | 48 | #if __has_builtin(__builtin_unreachable) 49 | #define wasm_rt_unreachable __builtin_unreachable 50 | #else 51 | #define wasm_rt_unreachable abort 52 | #endif 53 | 54 | #ifdef __STDC_VERSION__ 55 | #if __STDC_VERSION__ >= 201112L 56 | //#define WASM_RT_C11_AVAILABLE 57 | #endif 58 | #endif 59 | 60 | /** 61 | * Many devices don't implement the C11 threads.h. We use CriticalSection APIs 62 | * for Windows and pthreads on other platforms where threads are not available. 63 | */ 64 | #ifdef WASM_RT_C11_AVAILABLE 65 | 66 | #if defined(_WIN32) 67 | #include 68 | #define WASM_RT_MUTEX CRITICAL_SECTION 69 | #define WASM_RT_USE_CRITICALSECTION 1 70 | #elif defined(__APPLE__) || defined(__STDC_NO_THREADS__) 71 | #include 72 | #define WASM_RT_MUTEX pthread_mutex_t 73 | #define WASM_RT_USE_PTHREADS 1 74 | #else 75 | #include 76 | #define WASM_RT_MUTEX mtx_t 77 | #define WASM_RT_USE_C11THREADS 1 78 | #endif 79 | 80 | #endif 81 | 82 | #ifdef _MSC_VER 83 | #define WASM_RT_THREAD_LOCAL __declspec(thread) 84 | #elif defined(WASM_RT_C11_AVAILABLE) 85 | #define WASM_RT_THREAD_LOCAL _Thread_local 86 | #else 87 | #define WASM_RT_THREAD_LOCAL 88 | #endif 89 | 90 | /** 91 | * If enabled, perform additional sanity checks in the generated wasm2c code and 92 | * wasm2c runtime. This is useful to enable on debug builds. 93 | */ 94 | #ifndef WASM_RT_SANITY_CHECKS 95 | #define WASM_RT_SANITY_CHECKS 0 96 | #endif 97 | 98 | /** 99 | * Backward compatibility: Convert the previously exposed 100 | * WASM_RT_MEMCHECK_SIGNAL_HANDLER macro to the ALLOCATION and CHECK macros that 101 | * are now used. 102 | */ 103 | #if defined(WASM_RT_MEMCHECK_SIGNAL_HANDLER) 104 | 105 | #if WASM_RT_MEMCHECK_SIGNAL_HANDLER 106 | #define WASM_RT_USE_MMAP 1 107 | #define WASM_RT_MEMCHECK_GUARD_PAGES 1 108 | #else 109 | #define WASM_RT_USE_MMAP 0 110 | #define WASM_RT_MEMCHECK_BOUNDS_CHECK 1 111 | #endif 112 | 113 | #warning \ 114 | "WASM_RT_MEMCHECK_SIGNAL_HANDLER has been deprecated in favor of WASM_RT_USE_MMAP and WASM_RT_MEMORY_CHECK_* macros" 115 | #endif 116 | 117 | /** 118 | * Specify if we use OR mmap/mprotect (+ Windows equivalents) OR malloc/realloc 119 | * for the Wasm memory allocation and growth. mmap/mprotect guarantees memory 120 | * will grow without being moved, while malloc ensures the virtual memory is 121 | * consumed only as needed, but may relocate the memory to handle memory 122 | * fragmentation. 123 | * 124 | * This defaults to malloc on 32-bit platforms or if memory64 support is needed. 125 | * It defaults to mmap on 64-bit platforms assuming memory64 support is not 126 | * needed (so we can use the guard based range checks below). 127 | */ 128 | #ifndef WASM_RT_USE_MMAP 129 | #if UINTPTR_MAX > 0xffffffff && !SUPPORT_MEMORY64 130 | #define WASM_RT_USE_MMAP 1 131 | #else 132 | #define WASM_RT_USE_MMAP 0 133 | #endif 134 | #endif 135 | 136 | /** 137 | * Set the range checking strategy for Wasm memories. 138 | * 139 | * GUARD_PAGES: memory accesses rely on unmapped pages/guard pages to trap 140 | * out-of-bound accesses. 141 | * 142 | * BOUNDS_CHECK: memory accesses are checked with explicit bounds checks. 143 | * 144 | * This defaults to GUARD_PAGES as this is the fasest option, iff the 145 | * requirements of GUARD_PAGES --- 64-bit platforms, MMAP allocation strategy, 146 | * no 64-bit memories, no big-endian --- are met. This falls back to BOUNDS 147 | * otherwise. 148 | */ 149 | 150 | /** Check if Guard checks are supported */ 151 | #if UINTPTR_MAX > 0xffffffff && WASM_RT_USE_MMAP && !SUPPORT_MEMORY64 && \ 152 | !WABT_BIG_ENDIAN 153 | #define WASM_RT_GUARD_PAGES_SUPPORTED 1 154 | #else 155 | #define WASM_RT_GUARD_PAGES_SUPPORTED 0 156 | #endif 157 | 158 | /** Specify defaults for memory checks if unspecified */ 159 | #if !defined(WASM_RT_MEMCHECK_GUARD_PAGES) && \ 160 | !defined(WASM_RT_MEMCHECK_BOUNDS_CHECK) 161 | #if WASM_RT_GUARD_PAGES_SUPPORTED 162 | #define WASM_RT_MEMCHECK_GUARD_PAGES 1 163 | #else 164 | #define WASM_RT_MEMCHECK_BOUNDS_CHECK 1 165 | #endif 166 | #endif 167 | 168 | /** Ensure the macros are defined */ 169 | #ifndef WASM_RT_MEMCHECK_GUARD_PAGES 170 | #define WASM_RT_MEMCHECK_GUARD_PAGES 0 171 | #endif 172 | #ifndef WASM_RT_MEMCHECK_BOUNDS_CHECK 173 | #define WASM_RT_MEMCHECK_BOUNDS_CHECK 0 174 | #endif 175 | 176 | /** Sanity check the use of guard pages */ 177 | #if WASM_RT_MEMCHECK_GUARD_PAGES && !WASM_RT_GUARD_PAGES_SUPPORTED 178 | #error \ 179 | "WASM_RT_MEMCHECK_GUARD_PAGES not supported on this platform/configuration" 180 | #endif 181 | 182 | #if WASM_RT_MEMCHECK_GUARD_PAGES && WASM_RT_MEMCHECK_BOUNDS_CHECK 183 | #error \ 184 | "Cannot use both WASM_RT_MEMCHECK_GUARD_PAGES and WASM_RT_MEMCHECK_BOUNDS_CHECK" 185 | 186 | #elif !WASM_RT_MEMCHECK_GUARD_PAGES && !WASM_RT_MEMCHECK_BOUNDS_CHECK 187 | #error \ 188 | "Must choose at least one from WASM_RT_MEMCHECK_GUARD_PAGES and WASM_RT_MEMCHECK_BOUNDS_CHECK" 189 | #endif 190 | 191 | /** 192 | * Some configurations above require the Wasm runtime to install a signal 193 | * handler. However, this can be explicitly disallowed by the host using 194 | * WASM_RT_SKIP_SIGNAL_RECOVERY. In this case, when the wasm code encounters an 195 | * OOB access, it may either trap or abort. 196 | */ 197 | #ifndef WASM_RT_SKIP_SIGNAL_RECOVERY 198 | #define WASM_RT_SKIP_SIGNAL_RECOVERY 0 199 | #endif 200 | 201 | #if WASM_RT_MEMCHECK_GUARD_PAGES && !WASM_RT_SKIP_SIGNAL_RECOVERY 202 | #define WASM_RT_INSTALL_SIGNAL_HANDLER 1 203 | #else 204 | #define WASM_RT_INSTALL_SIGNAL_HANDLER 0 205 | #endif 206 | 207 | /** 208 | * This macro, if defined to 1 (i.e., allows the "segue" optimization), allows 209 | * Wasm2c to use segment registers to speedup access to the linear heap. Note 210 | * that even if allowed in this way, the segment registers would only be used if 211 | * Wasm2c output is compiled for a suitable architecture and OS and the produces 212 | * C file is compiled by supported compilers. The extact restrictions are listed 213 | * in detail in src/template/wasm2c.declarations.c 214 | */ 215 | #ifndef WASM_RT_ALLOW_SEGUE 216 | #define WASM_RT_ALLOW_SEGUE 0 217 | #endif 218 | 219 | /** 220 | * This macro, if defined, allows the embedder to disable all stack exhaustion 221 | * checks. This a non conformant configuration, i.e., this does not respect 222 | * Wasm's specification, and may compromise security. Use with caution. 223 | */ 224 | #ifndef WASM_RT_NONCONFORMING_UNCHECKED_STACK_EXHAUSTION 225 | #define WASM_RT_NONCONFORMING_UNCHECKED_STACK_EXHAUSTION 0 226 | #endif 227 | 228 | /** 229 | * We need to detect and trap stack overflows. If we use a signal handler on 230 | * POSIX systems, this can detect call stack overflows. On windows, or platforms 231 | * without a signal handler, we use stack depth counting. 232 | */ 233 | #if !defined(WASM_RT_STACK_DEPTH_COUNT) && \ 234 | !defined(WASM_RT_STACK_EXHAUSTION_HANDLER) && \ 235 | !WASM_RT_NONCONFORMING_UNCHECKED_STACK_EXHAUSTION 236 | 237 | #if WASM_RT_INSTALL_SIGNAL_HANDLER && !defined(_WIN32) 238 | #define WASM_RT_STACK_EXHAUSTION_HANDLER 1 239 | #else 240 | #define WASM_RT_STACK_DEPTH_COUNT 1 241 | #endif 242 | 243 | #endif 244 | 245 | /** Ensure the stack macros are defined */ 246 | #ifndef WASM_RT_STACK_DEPTH_COUNT 247 | #define WASM_RT_STACK_DEPTH_COUNT 0 248 | #endif 249 | #ifndef WASM_RT_STACK_EXHAUSTION_HANDLER 250 | #define WASM_RT_STACK_EXHAUSTION_HANDLER 0 251 | #endif 252 | 253 | #if WASM_RT_NONCONFORMING_UNCHECKED_STACK_EXHAUSTION 254 | 255 | #if (WASM_RT_STACK_EXHAUSTION_HANDLER + WASM_RT_STACK_DEPTH_COUNT) != 0 256 | #error \ 257 | "Cannot specify WASM_RT_NONCONFORMING_UNCHECKED_STACK_EXHAUSTION along with WASM_RT_STACK_EXHAUSTION_HANDLER or WASM_RT_STACK_DEPTH_COUNT" 258 | #endif 259 | 260 | #else 261 | 262 | #if (WASM_RT_STACK_EXHAUSTION_HANDLER + WASM_RT_STACK_DEPTH_COUNT) > 1 263 | #error \ 264 | "Cannot specify multiple options from WASM_RT_STACK_EXHAUSTION_HANDLER , WASM_RT_STACK_DEPTH_COUNT" 265 | #elif (WASM_RT_STACK_EXHAUSTION_HANDLER + WASM_RT_STACK_DEPTH_COUNT) == 0 266 | #error \ 267 | "Must specify one of WASM_RT_STACK_EXHAUSTION_HANDLER , WASM_RT_STACK_DEPTH_COUNT" 268 | #endif 269 | 270 | #endif 271 | 272 | #if WASM_RT_STACK_EXHAUSTION_HANDLER && !WASM_RT_INSTALL_SIGNAL_HANDLER 273 | #error \ 274 | "WASM_RT_STACK_EXHAUSTION_HANDLER can only be used if WASM_RT_INSTALL_SIGNAL_HANDLER is enabled" 275 | #endif 276 | 277 | #if WASM_RT_STACK_DEPTH_COUNT 278 | /** 279 | * When the signal handler cannot be used to detect stack overflows, stack depth 280 | * is limited explicitly. The maximum stack depth before trapping can be 281 | * configured by defining this symbol before including wasm-rt when building the 282 | * generated c files, for example: 283 | * 284 | * ``` 285 | * cc -c -DWASM_RT_MAX_CALL_STACK_DEPTH=100 my_module.c -o my_module.o 286 | * ``` 287 | */ 288 | #ifndef WASM_RT_MAX_CALL_STACK_DEPTH 289 | #define WASM_RT_MAX_CALL_STACK_DEPTH 500 290 | #endif 291 | 292 | /** Current call stack depth. */ 293 | extern WASM_RT_THREAD_LOCAL uint32_t wasm_rt_call_stack_depth; 294 | 295 | #endif 296 | 297 | #if defined(_MSC_VER) 298 | #define WASM_RT_NO_RETURN __declspec(noreturn) 299 | #else 300 | #define WASM_RT_NO_RETURN __attribute__((noreturn)) 301 | #endif 302 | 303 | #if defined(__APPLE__) && WASM_RT_STACK_EXHAUSTION_HANDLER 304 | #define WASM_RT_MERGED_OOB_AND_EXHAUSTION_TRAPS 1 305 | #else 306 | #define WASM_RT_MERGED_OOB_AND_EXHAUSTION_TRAPS 0 307 | #endif 308 | 309 | /** Reason a trap occurred. Provide this to `wasm_rt_trap`. */ 310 | typedef enum { 311 | WASM_RT_TRAP_NONE, /** No error. */ 312 | WASM_RT_TRAP_OOB, /** Out-of-bounds access in linear memory or a table. */ 313 | WASM_RT_TRAP_INT_OVERFLOW, /** Integer overflow on divide or truncation. */ 314 | WASM_RT_TRAP_DIV_BY_ZERO, /** Integer divide by zero. */ 315 | WASM_RT_TRAP_INVALID_CONVERSION, /** Conversion from NaN to integer. */ 316 | WASM_RT_TRAP_UNREACHABLE, /** Unreachable instruction executed. */ 317 | WASM_RT_TRAP_CALL_INDIRECT, /** Invalid call_indirect, for any reason. */ 318 | WASM_RT_TRAP_UNCAUGHT_EXCEPTION, /** Exception thrown and not caught. */ 319 | WASM_RT_TRAP_UNALIGNED, /** Unaligned atomic instruction executed. */ 320 | #if WASM_RT_MERGED_OOB_AND_EXHAUSTION_TRAPS 321 | WASM_RT_TRAP_EXHAUSTION = WASM_RT_TRAP_OOB, 322 | #else 323 | WASM_RT_TRAP_EXHAUSTION, /** Call stack exhausted. */ 324 | #endif 325 | } wasm_rt_trap_t; 326 | 327 | /** Value types. Used to define function signatures. */ 328 | enum { 329 | WASM_RT_I32, 330 | WASM_RT_I64, 331 | WASM_RT_F32, 332 | WASM_RT_F64, 333 | WASM_RT_V128, 334 | WASM_RT_FUNCREF, 335 | WASM_RT_EXTERNREF, 336 | }; 337 | 338 | typedef int wasm_rt_type_t; 339 | 340 | /** 341 | * A generic function pointer type, both for Wasm functions (`code`) 342 | * and host functions (`hostcode`). All function pointers are stored 343 | * in this canonical form, but must be cast to their proper signature 344 | * to call. 345 | */ 346 | typedef void (*wasm_rt_function_ptr_t)(void); 347 | 348 | /** 349 | * A pointer to a "tail-callee" function, called by a tail-call 350 | * trampoline or by another tail-callee function. (The definition uses a 351 | * single-member struct to allow a recursive definition.) 352 | */ 353 | typedef struct wasm_rt_tailcallee_t { 354 | void (*fn)(void** instance_ptr, 355 | void* tail_call_stack, 356 | struct wasm_rt_tailcallee_t* next); 357 | } wasm_rt_tailcallee_t; 358 | 359 | /** 360 | * The type of a function (an arbitrary number of param and result types). 361 | * This is represented as an opaque 256-bit ID. 362 | */ 363 | typedef const char* wasm_rt_func_type_t; 364 | 365 | /** 366 | * A function instance (the runtime representation of a function). 367 | * These can be stored in tables of type funcref, or used as values. 368 | */ 369 | typedef struct { 370 | /** The function's type. */ 371 | wasm_rt_func_type_t func_type; 372 | /** 373 | * The function. The embedder must know the actual C signature of the function 374 | * and cast to it before calling. 375 | */ 376 | wasm_rt_function_ptr_t func; 377 | /** An alternate version of the function to be used when tail-called. */ 378 | wasm_rt_tailcallee_t func_tailcallee; 379 | /** 380 | * A function instance is a closure of the function over an instance 381 | * of the originating module. The module_instance element will be passed into 382 | * the function at runtime. 383 | */ 384 | void* module_instance; 385 | } wasm_rt_funcref_t; 386 | 387 | /** Default (null) value of a funcref */ 388 | #define wasm_rt_funcref_null_value \ 389 | ((wasm_rt_funcref_t){NULL, NULL, {NULL}, NULL}) 390 | 391 | /** The type of an external reference (opaque to WebAssembly). */ 392 | typedef void* wasm_rt_externref_t; 393 | 394 | /** Default (null) value of an externref */ 395 | #define wasm_rt_externref_null_value ((wasm_rt_externref_t){NULL}) 396 | 397 | /** A Memory object. */ 398 | typedef struct { 399 | /** The linear memory data, with a byte length of `size`. */ 400 | uint8_t* data; 401 | /** The current page count for this Memory object. */ 402 | uint64_t pages; 403 | /** 404 | * The maximum page count for this Memory object. If there is no maximum, 405 | * `max_pages` is 0xffffffffu (i.e. UINT32_MAX). 406 | */ 407 | uint64_t max_pages; 408 | /** The current size of the linear memory, in bytes. */ 409 | uint64_t size; 410 | /** Is this memory indexed by u64 (as opposed to default u32) */ 411 | bool is64; 412 | } wasm_rt_memory_t; 413 | 414 | #ifdef WASM_RT_C11_AVAILABLE 415 | /** A shared Memory object. */ 416 | typedef struct { 417 | /** 418 | * The linear memory data, with a byte length of `size`. The memory is marked 419 | * atomic as it is shared and may have to be accessed with different memory 420 | * orders --- sequential when being accessed atomically, relaxed otherwise. 421 | * Unfortunately, the C standard does not state what happens if there are 422 | * overlaps in two memory accesses which have a memory order, e.g., an 423 | * atomic32 being read from the same location an atomic64 is read. One way to 424 | * prevent optimizations from assuming non-overlapping behavior as typically 425 | * done in C is to mark the memory as volatile. Thus the memory is atomic and 426 | * volatile. 427 | */ 428 | _Atomic volatile uint8_t* data; 429 | /** The current page count for this Memory object. */ 430 | uint64_t pages; 431 | /** 432 | * The maximum page count for this Memory object. If there is no maximum, 433 | * `max_pages` is 0xffffffffu (i.e. UINT32_MAX). 434 | */ 435 | uint64_t max_pages; 436 | /** The current size of the linear memory, in bytes. */ 437 | uint64_t size; 438 | /** Is this memory indexed by u64 (as opposed to default u32) */ 439 | bool is64; 440 | /** Lock used to ensure operations such as memory grow are threadsafe */ 441 | WASM_RT_MUTEX mem_lock; 442 | } wasm_rt_shared_memory_t; 443 | #endif 444 | 445 | /** A Table of type funcref. */ 446 | typedef struct { 447 | /** The table element data, with an element count of `size`. */ 448 | wasm_rt_funcref_t* data; 449 | /** 450 | * The maximum element count of this Table object. If there is no maximum, 451 | * `max_size` is 0xffffffffu (i.e. UINT32_MAX). 452 | */ 453 | uint32_t max_size; 454 | /** The current element count of the table. */ 455 | uint32_t size; 456 | } wasm_rt_funcref_table_t; 457 | 458 | /** A Table of type externref. */ 459 | typedef struct { 460 | /** The table element data, with an element count of `size`. */ 461 | wasm_rt_externref_t* data; 462 | /** 463 | * The maximum element count of this Table object. If there is no maximum, 464 | * `max_size` is 0xffffffffu (i.e. UINT32_MAX). 465 | */ 466 | uint32_t max_size; 467 | /** The current element count of the table. */ 468 | uint32_t size; 469 | } wasm_rt_externref_table_t; 470 | 471 | /** Initialize the runtime. */ 472 | void wasm_rt_init(void); 473 | 474 | /** Is the runtime initialized? */ 475 | bool wasm_rt_is_initialized(void); 476 | 477 | /** Free the runtime's state. */ 478 | void wasm_rt_free(void); 479 | 480 | /* 481 | * Initialize the multithreaded runtime for a given thread. Must be 482 | * called by each thread (other than the one that called wasm_rt_init) 483 | * before initializing a Wasm module or calling an exported 484 | * function. 485 | */ 486 | void wasm_rt_init_thread(void); 487 | 488 | /* 489 | * Free the individual thread's state. 490 | */ 491 | void wasm_rt_free_thread(void); 492 | 493 | /** A hardened jmp_buf that allows checking for initialization before use */ 494 | typedef struct { 495 | /** Is the jmp buf intialized? */ 496 | bool initialized; 497 | /** jmp_buf contents */ 498 | jmp_buf buffer; 499 | } wasm_rt_jmp_buf; 500 | 501 | //#ifndef _WIN32 502 | //#define WASM_RT_SETJMP_SETBUF(buf) sigsetjmp(buf, 1) 503 | //#else 504 | #define WASM_RT_SETJMP_SETBUF(buf) setjmp(buf) 505 | //#endif 506 | 507 | #define WASM_RT_SETJMP(buf) \ 508 | ((buf).initialized = true, WASM_RT_SETJMP_SETBUF((buf).buffer)) 509 | 510 | //#ifndef _WIN32 511 | //#define WASM_RT_LONGJMP_UNCHECKED(buf, val) siglongjmp(buf, val) 512 | //#else 513 | #define WASM_RT_LONGJMP_UNCHECKED(buf, val) longjmp(buf, val) 514 | //#endif 515 | 516 | #define WASM_RT_LONGJMP(buf, val) \ 517 | /** Abort on failure as this may be called in the trap handler */ \ 518 | if (!((buf).initialized)) \ 519 | abort(); \ 520 | (buf).initialized = false; \ 521 | WASM_RT_LONGJMP_UNCHECKED((buf).buffer, val) 522 | 523 | /** 524 | * Stop execution immediately and jump back to the call to `wasm_rt_impl_try`. 525 | * The result of `wasm_rt_impl_try` will be the provided trap reason. 526 | * 527 | * This is typically called by the generated code, and not the embedder. 528 | */ 529 | WASM_RT_NO_RETURN void wasm_rt_trap(wasm_rt_trap_t); 530 | 531 | /** Return a human readable error string based on a trap type. */ 532 | const char* wasm_rt_strerror(wasm_rt_trap_t trap); 533 | 534 | #define wasm_rt_try(target) WASM_RT_SETJMP(target) 535 | 536 | /** 537 | * Initialize a Memory object with an initial page size of `initial_pages` and 538 | * a maximum page size of `max_pages`, indexed with an i32 or i64. 539 | * 540 | * ``` 541 | * wasm_rt_memory_t my_memory; 542 | * // 1 initial page (65536 bytes), and a maximum of 2 pages, 543 | * // indexed with an i32 544 | * wasm_rt_allocate_memory(&my_memory, 1, 2, false); 545 | * ``` 546 | */ 547 | void wasm_rt_allocate_memory(wasm_rt_memory_t*, 548 | uint64_t initial_pages, 549 | uint64_t max_pages, 550 | bool is64); 551 | 552 | /** 553 | * Grow a Memory object by `pages`, and return the previous page count. If 554 | * this new page count is greater than the maximum page count, the grow fails 555 | * and 0xffffffffu (UINT32_MAX) is returned instead. 556 | * 557 | * ``` 558 | * wasm_rt_memory_t my_memory; 559 | * ... 560 | * // Grow memory by 10 pages. 561 | * uint32_t old_page_size = wasm_rt_grow_memory(&my_memory, 10); 562 | * if (old_page_size == UINT32_MAX) { 563 | * // Failed to grow memory. 564 | * } 565 | * ``` 566 | */ 567 | uint64_t wasm_rt_grow_memory(wasm_rt_memory_t*, uint64_t pages); 568 | 569 | /** Free a Memory object. */ 570 | void wasm_rt_free_memory(wasm_rt_memory_t*); 571 | 572 | #ifdef WASM_RT_C11_AVAILABLE 573 | /** Shared memory version of wasm_rt_allocate_memory */ 574 | void wasm_rt_allocate_memory_shared(wasm_rt_shared_memory_t*, 575 | uint64_t initial_pages, 576 | uint64_t max_pages, 577 | bool is64); 578 | 579 | /** Shared memory version of wasm_rt_grow_memory */ 580 | uint64_t wasm_rt_grow_memory_shared(wasm_rt_shared_memory_t*, uint64_t pages); 581 | 582 | /** Shared memory version of wasm_rt_free_memory */ 583 | void wasm_rt_free_memory_shared(wasm_rt_shared_memory_t*); 584 | #endif 585 | 586 | /** 587 | * Initialize a funcref Table object with an element count of `elements` and a 588 | * maximum size of `max_elements`. 589 | * 590 | * ``` 591 | * wasm_rt_funcref_table_t my_table; 592 | * // 5 elements and a maximum of 10 elements. 593 | * wasm_rt_allocate_funcref_table(&my_table, 5, 10); 594 | * ``` 595 | */ 596 | void wasm_rt_allocate_funcref_table(wasm_rt_funcref_table_t*, 597 | uint32_t elements, 598 | uint32_t max_elements); 599 | 600 | /** Free a funcref Table object. */ 601 | void wasm_rt_free_funcref_table(wasm_rt_funcref_table_t*); 602 | 603 | /** 604 | * Initialize an externref Table object with an element count 605 | * of `elements` and a maximum size of `max_elements`. 606 | * Usage as per wasm_rt_allocate_funcref_table. 607 | */ 608 | void wasm_rt_allocate_externref_table(wasm_rt_externref_table_t*, 609 | uint32_t elements, 610 | uint32_t max_elements); 611 | 612 | /** Free an externref Table object. */ 613 | void wasm_rt_free_externref_table(wasm_rt_externref_table_t*); 614 | 615 | /** 616 | * Grow a Table object by `delta` elements (giving the new elements the value 617 | * `init`), and return the previous element count. If this new element count is 618 | * greater than the maximum element count, the grow fails and 0xffffffffu 619 | * (UINT32_MAX) is returned instead. 620 | */ 621 | uint32_t wasm_rt_grow_funcref_table(wasm_rt_funcref_table_t*, 622 | uint32_t delta, 623 | wasm_rt_funcref_t init); 624 | uint32_t wasm_rt_grow_externref_table(wasm_rt_externref_table_t*, 625 | uint32_t delta, 626 | wasm_rt_externref_t init); 627 | 628 | void os_print_last_error(const char* msg); 629 | 630 | #ifdef __cplusplus 631 | } 632 | #endif 633 | 634 | #endif /* WASM_RT_H_ */ 635 | --------------------------------------------------------------------------------