Enable support for multiple boards and architectures
diff --git a/.cargo/config b/.cargo/config
index 98ba621..6849bb7 100644
--- a/.cargo/config
+++ b/.cargo/config
@@ -1,33 +1,19 @@
-# Target configuration for the example apps on the nRF52-DK
-[target.thumbv7em-none-eabi]
-rustflags = [
-  "-C", "link-arg=-Tnrf52_layout.ld",
-  "-C", "relocation-model=static",
-  "-D", "warnings",
-]
+[alias]
+rriscv32iamc = "run --release --target=riscv32iamc-unknown-none-elf --example"
+rrv32iamc = "rriscv32iamc"
+rriscv32imc = "run --release --target=riscv32imc-unknown-none-elf --example"
+rrv32imc = "rriscv32imc"
+rthumbv7em = "run --release --target=thumbv7em-none-eabi --example"
+rtv7em = "rthumbv7em"
 
-[target.riscv32imac-unknown-none-elf]
-rustflags = [
-  "-C", "link-arg=-Triscv32_layout.ld",
-  "-C", "relocation-model=static",
-  "-D", "warnings",
-]
+# Deny warnings on all architectures. build.rustflags cannot be used here as the lower section would override its effect.
+[target.'cfg(all())']
+rustflags = ["-D", "warnings"]
 
-[target.riscv32imc-unknown-none-elf]
+# Common settings for all embedded targets
+[target.'cfg(any(target_arch = "arm", target_arch = "riscv32"))']
 rustflags = [
-  "-C", "link-arg=-Topentitan_layout.ld",
-  "-C", "relocation-model=static",
-  "-D", "warnings",
+    "-C", "relocation-model=static",
+    "-C", "link-arg=-Tlayout.ld",
 ]
-
-# Target configuration for the travis CI Linux build
-[target.x86_64-unknown-linux-gnu]
-rustflags = [
-  "-D", "warnings",
-]
-
-# Target configuration for the travis CI OS-X build
-[target.x86_64-apple-darwin]
-rustflags = [
-  "-D", "warnings",
-]
+runner = "./flash.sh"
diff --git a/.gitignore b/.gitignore
index 3a78405..da66475 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,3 +1,4 @@
-target
 Cargo.lock
+layout.ld
+platform
 target
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 0ab5997..9325962 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -36,6 +36,9 @@
 
 ### Miscellaneous
 
+- Flashing examples is no longer restricted to the nRF52 DK board
+  - `./run_example.sh` has been deleted
+  - Instead, use `PLATFORM=<platform> cargo r<arch> <your_app>`. This will build the app for your CPU architecture and platform-specific memory layout and flash it via J-Link to your board
 - Targets without support for atomics can be built
 
 ## a8bb4fa9be504517d5533511fd8e607ea61f1750 (0.1.0)
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
index aa9d1fb..dd09bf1 100644
--- a/CONTRIBUTING.md
+++ b/CONTRIBUTING.md
@@ -15,9 +15,13 @@
 
 ## Compilation
 
-`libtock-rs` currently has two compilation targets: `riscv32imac-unknown-none-elf`
-and `thumbv7em-none-eabi`. You can build the library and the examples
-using the script `build_examples.sh`.
+`libtock-rs` currently has the following compilation targets
+
+- `riscv32imac-unknown-none-elf`
+- `riscv32imc-unknown-none-elf`
+- `thumbv7em-none-eabi`
+
+You can trigger a test build of the library and the examples using the script `build_examples.sh`.
 
 ## Unit Testing and Linting
 
@@ -26,14 +30,12 @@
 
 ## Integration tests
 
-If you have a `nRF52-dk` you can run the integration tests as follows.
-The pins P0.03 and P0.04 need to be connected (on a nRF52-DK). Then do the following:
+If you have an nRF52 DK you can run the integration tests as follows.
+The pins P0.03 and P0.04 need to be connected (on an nRF52 DK). Then do the following:
 
 - connect your device to your computer
 - open a console, e.g. `tockloader listen`
-- run the tests `./run_hardware_test.sh
-
-The desired test output is:
+- run the tests: `PLATFORM=nrf52 cargo rtv7em hardware_test`
 
 The expected output on the UART console will be as follows.
 
diff --git a/README.md b/README.md
index b1e1202..e58223e 100644
--- a/README.md
+++ b/README.md
@@ -26,44 +26,40 @@
 
 1.  Ensure you have [rustup](https://www.rustup.rs/) installed.
 
-1.  Clone the repository.
+1.  Clone the repository:
 
     ```bash
     git clone https://github.com/tock/libtock-rs
     cd libtock-rs
     ```
 
-1.  Install `elf2tab`.
+1.  Install `elf2tab`:
 
     ```bash
     cargo install -f elf2tab --version 0.4.0
     ```
 
-1.  Add dependencies for cross-compilation.
+1.  Add dependencies for cross-compilation. Currently, only few platforms have been configured, e.g.:
 
     ```bash
-    rustup target add thumbv7em-none-eabi
+    rustup target add thumbv7em-none-eabi # For an nRF52 DK board
     ```
 
-1.  Use the `run_example` script to compile and run the example app you want
-    to use:
-
     ```bash
-    ./run_example.sh blink
+    rustup target add riscv32imc-unknown-none-elf # For an OpenTitan board
     ```
 
-    Due to bug #28 this will currently only work if you are using the nRF52-DK platform.
+1.  Use `cargo r<arch>` to compile and run an example app. The full command is platform dependent and looks as follows for the `blink` example:
 
-    If you have a nRF52840-DK you must change `link-arg=-Tnrf52_layout.ld` in
-    `.cargo/config` to `link-arg=-Tnrf52840_layout.ld`
+    ```bash
+    PLATFORM=nrf52 cargo rthumbv7em blink # For an nRF52 DK board
+    ```
 
-    If you have a hail board you can flash your device as follows:
+    ```bash
+    PLATFORM=opentitan cargo rriscv32imc blink # For an OpenTitan board
+    ```
 
-    - set the environment variable `hail` to `1`
-    - change `link-arg=-Tnrf52_layout.ld` in `.cargo/config` to `link-arg=-Thail_layout.ld`
-    - run `run_example.sh` as above.
-
-    For other platforms, you may have to create your own memory layout definition.
+    For an unknown platform, you may have to create your own memory layout definition. Place the layout definition file at `layout_<platform>.ld` and do not forget to enhance the `tockloader_flags` dispatching section in `flash.sh`. You are welcome to create a PR, s.t. the number of supported platforms grows.
 
 ## Using libtock-rs
 
@@ -92,14 +88,20 @@
 To run on the code on your board you can use
 
 ```bash
-./run_example.sh <your app>
+PLATFORM=<platform> cargo r<arch> <your_app>
 ```
 
 This script does the following steps for you:
 
 - cross-compile your program
 - create a TAB (tock application bundle)
-- if you have a nRF52-DK board connected: flash this TAB to your board (using tockloader)
+- if you have a J-Link compatible board connected: flash this TAB to your board (using tockloader)
+
+Instead of specifying an environment variable each time you can permanently configure your platform by writing its name into a file named `platform`, e.g.
+
+```bash
+echo nrf52 > platform
+```
 
 ## License
 
diff --git a/build.rs b/build.rs
new file mode 100644
index 0000000..c370bd9
--- /dev/null
+++ b/build.rs
@@ -0,0 +1,55 @@
+use std::env;
+use std::fs;
+use std::fs::File;
+use std::io::BufRead;
+use std::io::BufReader;
+use std::path::Path;
+use std::process;
+
+fn main() {
+    static ENV_VAR: &str = "PLATFORM";
+    static FILE_NAME: &str = "platform";
+
+    let platform_name = read_board_name_from_env_var(ENV_VAR)
+        .or_else(|| read_board_name_from_file(FILE_NAME))
+        .unwrap_or_else(|| {
+            println!(
+                "No platform specified. Either set the environment \
+                 variable {} or create a file named `{}`",
+                ENV_VAR, FILE_NAME
+            );
+            process::exit(1);
+        });
+
+    println!("cargo:rustc-env={}={}", ENV_VAR, platform_name);
+
+    copy_linker_file(&platform_name.trim());
+}
+
+fn read_board_name_from_env_var(env_var: &str) -> Option<String> {
+    env::var_os(env_var).map(|os_string| os_string.into_string().unwrap())
+}
+
+fn read_board_name_from_file(file_name: &str) -> Option<String> {
+    let path = Path::new(file_name);
+    if !path.exists() {
+        return None;
+    }
+
+    let board_file = File::open(path).unwrap();
+    let mut board_name = String::new();
+    BufReader::new(board_file)
+        .read_line(&mut board_name)
+        .unwrap();
+    Some(board_name)
+}
+
+fn copy_linker_file(platform_name: &str) {
+    let linker_file_name = format!("layout_{}.ld", platform_name);
+    let path = Path::new(&linker_file_name);
+    if !path.exists() {
+        println!("Cannot find layout file {:?}", path);
+        process::exit(1);
+    }
+    fs::copy(linker_file_name, "layout.ld").unwrap();
+}
diff --git a/build_examples.sh b/build_examples.sh
index dbaeb56..c094db9 100755
--- a/build_examples.sh
+++ b/build_examples.sh
@@ -2,5 +2,5 @@
 
 set -eux
 
-cargo build --release --target=thumbv7em-none-eabi --examples
-cargo build --release --target=riscv32imc-unknown-none-elf --examples # Important for tests: This target does not support atomics
+PLATFORM=nrf52 cargo build --release --target=thumbv7em-none-eabi --examples
+PLATFORM=riscv32 cargo build --release --target=riscv32imc-unknown-none-elf --examples # Important for testing: This target does not support atomics
diff --git a/flash.sh b/flash.sh
new file mode 100755
index 0000000..a67312c
--- /dev/null
+++ b/flash.sh
@@ -0,0 +1,30 @@
+#!/usr/bin/env bash
+
+set -eux
+
+artifact="$(basename $1)"
+rust_target_folder="$(readlink -f $(dirname $1)/../..)"
+libtock_target_path="${rust_target_folder}/tab/${PLATFORM}/${artifact}"
+elf_file_name="${libtock_target_path}/cortex-m4.elf"
+tab_file_name="${libtock_target_path}.tab"
+
+mkdir -p "${libtock_target_path}"
+cp "$1" "${elf_file_name}"
+
+elf2tab -n "${artifact}" -o "${tab_file_name}" "${elf_file_name}" --stack 2048 --app-heap 1024 --kernel-heap 1024 --protected-region-size=64
+
+case "${PLATFORM}" in
+    "nrf52"|"nrf52840")
+        tockloader_flags="--jlink --arch cortex-m4 --board nrf52dk --jtag-device nrf52"
+        ;;
+    "hail")
+        tockloader_flags=""
+        ;;
+    *)
+        echo "Tockloader flags unknown for platform \"${PLATFORM}\""
+        exit 1
+        ;;
+esac
+
+tockloader uninstall ${tockloader_flags} || true
+tockloader install ${tockloader_flags} "${tab_file_name}"
diff --git a/layout.ld b/layout_generic.ld
similarity index 100%
rename from layout.ld
rename to layout_generic.ld
diff --git a/hail_layout.ld b/layout_hail.ld
similarity index 93%
rename from hail_layout.ld
rename to layout_hail.ld
index 786548c..f5473ee 100644
--- a/hail_layout.ld
+++ b/layout_hail.ld
@@ -14,4 +14,4 @@
 
 MPU_MIN_ALIGN = 8K;
 
-INCLUDE layout.ld
+INCLUDE layout_generic.ld
diff --git a/nrf52_layout.ld b/layout_nrf52.ld
similarity index 93%
rename from nrf52_layout.ld
rename to layout_nrf52.ld
index 7c96869..419a0bc 100644
--- a/nrf52_layout.ld
+++ b/layout_nrf52.ld
@@ -14,4 +14,4 @@
 
 MPU_MIN_ALIGN = 8K;
 
-INCLUDE layout.ld
+INCLUDE layout_generic.ld
diff --git a/nrf52840_layout.ld b/layout_nrf52840.ld
similarity index 93%
rename from nrf52840_layout.ld
rename to layout_nrf52840.ld
index 0ac2b5c..d99efa0 100644
--- a/nrf52840_layout.ld
+++ b/layout_nrf52840.ld
@@ -14,4 +14,4 @@
 
 MPU_MIN_ALIGN = 8K;
 
-INCLUDE layout.ld
+INCLUDE layout_generic.ld
diff --git a/opentitan_layout.ld b/layout_opentitan.ld
similarity index 93%
rename from opentitan_layout.ld
rename to layout_opentitan.ld
index d2d09ba..ab475fc 100644
--- a/opentitan_layout.ld
+++ b/layout_opentitan.ld
@@ -14,4 +14,4 @@
 
 MPU_MIN_ALIGN = 1K;
 
-INCLUDE layout.ld
+INCLUDE layout_generic.ld
diff --git a/riscv32_layout.ld b/layout_riscv32.ld
similarity index 93%
rename from riscv32_layout.ld
rename to layout_riscv32.ld
index b7067fd..e3aba2c 100644
--- a/riscv32_layout.ld
+++ b/layout_riscv32.ld
@@ -14,4 +14,4 @@
 
 MPU_MIN_ALIGN = 1K;
 
-INCLUDE layout.ld
+INCLUDE layout_generic.ld
diff --git a/run_all_checks.sh b/run_all_checks.sh
index 7d96180..c445608 100755
--- a/run_all_checks.sh
+++ b/run_all_checks.sh
@@ -2,6 +2,8 @@
 
 set -eux
 
+export PLATFORM=nrf52 # The specific platform doesn't matter for tests
+
 cargo fmt --all -- --check
 cargo test --workspace
 cargo clippy --workspace --all-targets
diff --git a/run_example.sh b/run_example.sh
deleted file mode 100755
index 92bd574..0000000
--- a/run_example.sh
+++ /dev/null
@@ -1,38 +0,0 @@
-#!/usr/bin/env bash
-
-# Examples only run on a nRF52-DK board
-
-set -eux
-
-cargo build --release --target=thumbv7em-none-eabi --example "$1"
-
-
-elf_file_name="target/tab/$1/cortex-m4.elf"
-tab_file_name="target/tab/$1.tab"
-
-# Default value for nRF52-DK
-tockloader_flags="--jlink --arch cortex-m4 --board nrf52dk --jtag-device nrf52"
-
-hail_defined=${hail:-}
-if [ -n "$hail_defined" ]
-then
-    tockloader_flags=""
-fi
-
-mkdir -p "target/tab/$1"
-cp "target/thumbv7em-none-eabi/release/examples/$1" "$elf_file_name"
-
-elf2tab -n "$1" -o "$tab_file_name" "$elf_file_name" --stack 2048 --app-heap 1024 --kernel-heap 1024 --protected-region-size=64
-
-if [ "$#" -ge "2" ]
-then
-    if [ "$2" = "--dont-clear-apps" ]
-    then
-        echo "do not delete apps from board."
-    else
-        tockloader uninstall $tockloader_flags || true
-    fi
-else
-    tockloader uninstall $tockloader_flags || true
-fi
-tockloader install $tockloader_flags "$tab_file_name"
diff --git a/run_hardware_test.sh b/run_hardware_test.sh
deleted file mode 100755
index 70fdc75..0000000
--- a/run_hardware_test.sh
+++ /dev/null
@@ -1,9 +0,0 @@
-#!/usr/bin/env bash
-
-# Tests only run on a nRF52-DK board
-
-set -eux
-
-yes 0|tockloader uninstall --jlink --arch cortex-m4 --board nrf52dk --jtag-device nrf52 || true
-
-./run_example.sh hardware_test --dont-clear-apps